3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: drivers/dd/serial/devctrl.c
6 * PURPOSE: Serial IRP_MJ_DEVICE_CONTROL operations
8 * PROGRAMMERS: Hervé Poussineau (poussine@freesurf.fr)
14 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
19 IN ULONG IoControlCode
,
27 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
30 *BufferIn
= *BufferOut
= Irp
->AssociatedIrp
.SystemBuffer
;
32 case METHOD_IN_DIRECT
:
33 case METHOD_OUT_DIRECT
:
34 *BufferIn
= Irp
->AssociatedIrp
.SystemBuffer
;
35 *BufferOut
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
38 *BufferIn
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.Type3InputBuffer
;
39 *BufferOut
= Irp
->UserBuffer
;
43 /* Should never happen */
48 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
,
52 PUCHAR ComPortBase
= (PUCHAR
)DeviceExtension
->BaseAddress
;
54 NTSTATUS Status
= STATUS_SUCCESS
;
56 if (NewBaudRate
& SERIAL_BAUD_USER
)
58 BaudRate
= NewBaudRate
& ~SERIAL_BAUD_USER
;
59 divisor
= (USHORT
)(BAUD_CLOCK
/ (CLOCKS_PER_BIT
* BaudRate
));
65 case SERIAL_BAUD_075
: divisor
= 0x600; BaudRate
= 75; break;
66 case SERIAL_BAUD_110
: divisor
= 0x400; BaudRate
= 110; break;
67 case SERIAL_BAUD_134_5
: divisor
= 0x360; BaudRate
= 134; break;
68 case SERIAL_BAUD_150
: divisor
= 0x300; BaudRate
= 150; break;
69 case SERIAL_BAUD_300
: divisor
= 0x180; BaudRate
= 300; break;
70 case SERIAL_BAUD_600
: divisor
= 0xc0; BaudRate
= 600; break;
71 case SERIAL_BAUD_1200
: divisor
= 0x60; BaudRate
= 1200; break;
72 case SERIAL_BAUD_1800
: divisor
= 0x40; BaudRate
= 1800; break;
73 case SERIAL_BAUD_2400
: divisor
= 0x30; BaudRate
= 2400; break;
74 case SERIAL_BAUD_4800
: divisor
= 0x18; BaudRate
= 4800; break;
75 case SERIAL_BAUD_7200
: divisor
= 0x10; BaudRate
= 7200; break;
76 case SERIAL_BAUD_9600
: divisor
= 0xc; BaudRate
= 9600; break;
77 case SERIAL_BAUD_14400
: divisor
= 0x8; BaudRate
= 14400; break;
78 case SERIAL_BAUD_38400
: divisor
= 0x3; BaudRate
= 38400; break;
79 case SERIAL_BAUD_57600
: divisor
= 0x2; BaudRate
= 57600; break;
80 case SERIAL_BAUD_115200
: divisor
= 0x1; BaudRate
= 115200; break;
81 case SERIAL_BAUD_56K
: divisor
= 0x2; BaudRate
= 57600; break;
82 case SERIAL_BAUD_128K
: divisor
= 0x1; BaudRate
= 115200; break;
83 default: Status
= STATUS_INVALID_PARAMETER
;
87 if (NT_SUCCESS(Status
))
89 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
90 if (NT_SUCCESS(Status
))
93 DPRINT("Serial: SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension
->ComPort
, BaudRate
);
94 /* Set Bit 7 of LCR to expose baud registers */
95 Lcr
= READ_PORT_UCHAR(SER_LCR(ComPortBase
));
96 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
| SR_LCR_DLAB
);
97 /* Write the baud rate */
98 WRITE_PORT_UCHAR(SER_DLL(ComPortBase
), divisor
& 0xff);
99 WRITE_PORT_UCHAR(SER_DLM(ComPortBase
), divisor
>> 8);
100 /* Switch back to normal registers */
101 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
);
103 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
107 if (NT_SUCCESS(Status
))
108 DeviceExtension
->BaudRate
= BaudRate
;
113 SerialSetLineControl(
114 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
,
115 IN PSERIAL_LINE_CONTROL NewSettings
)
121 ASSERT(DeviceExtension
);
124 DPRINT("Serial: SerialSetLineControl(COM%lu, Settings { %lu %lu %lu })\n",
125 DeviceExtension
->ComPort
, NewSettings
->StopBits
, NewSettings
->Parity
, NewSettings
->WordLength
);
127 /* Verify parameters */
128 switch (NewSettings
->WordLength
)
130 case 5: Lcr
|= SR_LCR_CS5
; break;
131 case 6: Lcr
|= SR_LCR_CS6
; break;
132 case 7: Lcr
|= SR_LCR_CS7
; break;
133 case 8: Lcr
|= SR_LCR_CS8
; break;
134 default: return STATUS_INVALID_PARAMETER
;
137 if (NewSettings
->WordLength
< 5 || NewSettings
->WordLength
> 8)
138 return STATUS_INVALID_PARAMETER
;
140 switch (NewSettings
->Parity
)
142 case NO_PARITY
: Lcr
|= SR_LCR_PNO
; break;
143 case ODD_PARITY
: Lcr
|= SR_LCR_POD
; break;
144 case EVEN_PARITY
: Lcr
|= SR_LCR_PEV
; break;
145 case MARK_PARITY
: Lcr
|= SR_LCR_PMK
; break;
146 case SPACE_PARITY
: Lcr
|= SR_LCR_PSP
; break;
147 default: return STATUS_INVALID_PARAMETER
;
150 switch (NewSettings
->StopBits
)
156 if (NewSettings
->WordLength
!= 5)
157 return STATUS_INVALID_PARAMETER
;
161 if (NewSettings
->WordLength
< 6 || NewSettings
->WordLength
> 8)
162 return STATUS_INVALID_PARAMETER
;
166 return STATUS_INVALID_PARAMETER
;
169 /* Update current parameters */
170 ComPortBase
= (PUCHAR
)DeviceExtension
->BaseAddress
;
171 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
172 if (!NT_SUCCESS(Status
))
174 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
);
176 /* Read junk out of RBR */
177 READ_PORT_UCHAR(SER_RBR(ComPortBase
));
178 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
180 if (NT_SUCCESS(Status
))
181 DeviceExtension
->SerialLineControl
= *NewSettings
;
187 SerialClearPerfStats(
188 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
190 ASSERT(DeviceExtension
);
192 RtlZeroMemory(&DeviceExtension
->SerialPerfStats
, sizeof(SERIALPERF_STATS
));
193 DeviceExtension
->BreakInterruptErrorCount
= 0;
198 SerialGetPerfStats(IN PIRP pIrp
)
200 PSERIAL_DEVICE_EXTENSION pDeviceExtension
;
201 pDeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)
202 IoGetCurrentIrpStackLocation(pIrp
)->DeviceObject
->DeviceExtension
;
203 ASSERT(DeviceExtension
);
205 * we assume buffer is big enough to hold SerialPerfStats structure
206 * caller must verify this
209 pIrp
->AssociatedIrp
.SystemBuffer
,
210 &pDeviceExtension
->SerialPerfStats
,
211 sizeof(SERIALPERF_STATS
)
218 OUT PSERIAL_COMMPROP pCommProp
,
219 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
223 RtlZeroMemory(pCommProp
, sizeof(SERIAL_COMMPROP
));
225 pCommProp
->PacketLength
= sizeof(SERIAL_COMMPROP
);
226 pCommProp
->PacketVersion
= 2;
227 pCommProp
->ServiceMask
= SERIAL_SP_SERIALCOMM
;
228 pCommProp
->MaxTxQueue
= pCommProp
->CurrentTxQueue
= DeviceExtension
->OutputBuffer
.Length
- 1;
229 pCommProp
->MaxRxQueue
= pCommProp
->CurrentRxQueue
= DeviceExtension
->InputBuffer
.Length
- 1;
230 pCommProp
->ProvSubType
= 1; // PST_RS232;
231 pCommProp
->ProvCapabilities
= SERIAL_PCF_DTRDSR
| SERIAL_PCF_INTTIMEOUTS
| SERIAL_PCF_PARITY_CHECK
232 | SERIAL_PCF_RTSCTS
| SERIAL_PCF_SETXCHAR
| SERIAL_PCF_SPECIALCHARS
| SERIAL_PCF_TOTALTIMEOUTS
233 | SERIAL_PCF_XONXOFF
;
234 pCommProp
->SettableParams
= SERIAL_SP_BAUD
| SERIAL_SP_DATABITS
| SERIAL_SP_HANDSHAKING
235 | SERIAL_SP_PARITY
| SERIAL_SP_PARITY_CHECK
| SERIAL_SP_STOPBITS
;
237 /* SettableBaud is related to Uart type */
238 pCommProp
->SettableBaud
= SERIAL_BAUD_075
| SERIAL_BAUD_110
| SERIAL_BAUD_134_5
239 | SERIAL_BAUD_150
| SERIAL_BAUD_300
| SERIAL_BAUD_600
| SERIAL_BAUD_1200
240 | SERIAL_BAUD_1800
| SERIAL_BAUD_2400
| SERIAL_BAUD_4800
| SERIAL_BAUD_7200
241 | SERIAL_BAUD_9600
| SERIAL_BAUD_USER
;
242 pCommProp
->MaxBaud
= SERIAL_BAUD_9600
;
243 if (DeviceExtension
->UartType
>= Uart16450
)
245 pCommProp
->SettableBaud
|= SERIAL_BAUD_14400
| SERIAL_BAUD_19200
| SERIAL_BAUD_38400
;
246 pCommProp
->MaxBaud
= SERIAL_BAUD_38400
;
248 if (DeviceExtension
->UartType
>= Uart16550
)
250 pCommProp
->SettableBaud
|= SERIAL_BAUD_56K
| SERIAL_BAUD_57600
| SERIAL_BAUD_115200
| SERIAL_BAUD_128K
;
251 pCommProp
->MaxBaud
= SERIAL_BAUD_115200
;
254 pCommProp
->SettableData
= SERIAL_DATABITS_5
| SERIAL_DATABITS_6
| SERIAL_DATABITS_7
| SERIAL_DATABITS_8
;
255 pCommProp
->SettableStopParity
= SERIAL_STOPBITS_10
| SERIAL_STOPBITS_15
| SERIAL_STOPBITS_20
256 | SERIAL_PARITY_NONE
| SERIAL_PARITY_ODD
| SERIAL_PARITY_EVEN
| SERIAL_PARITY_MARK
| SERIAL_PARITY_SPACE
;
258 return STATUS_SUCCESS
;
263 OUT PSERIAL_STATUS pSerialStatus
,
264 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
268 ASSERT(pSerialStatus
);
269 RtlZeroMemory(pSerialStatus
, sizeof(SERIAL_STATUS
));
271 pSerialStatus
->Errors
= 0;
272 if (DeviceExtension
->BreakInterruptErrorCount
)
273 pSerialStatus
->Errors
|= SERIAL_ERROR_BREAK
;
274 if (DeviceExtension
->SerialPerfStats
.FrameErrorCount
)
275 pSerialStatus
->Errors
|= SERIAL_ERROR_FRAMING
;
276 if (DeviceExtension
->SerialPerfStats
.SerialOverrunErrorCount
)
277 pSerialStatus
->Errors
|= SERIAL_ERROR_OVERRUN
;
278 if (DeviceExtension
->SerialPerfStats
.BufferOverrunErrorCount
)
279 pSerialStatus
->Errors
|= SERIAL_ERROR_QUEUEOVERRUN
;
280 if (DeviceExtension
->SerialPerfStats
.ParityErrorCount
)
281 pSerialStatus
->Errors
|= SERIAL_ERROR_PARITY
;
283 pSerialStatus
->HoldReasons
= 0; /* FIXME */
285 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
286 pSerialStatus
->AmountInInQueue
= (DeviceExtension
->InputBuffer
.WritePosition
+ DeviceExtension
->InputBuffer
.Length
287 - DeviceExtension
->InputBuffer
.ReadPosition
) % DeviceExtension
->InputBuffer
.Length
;
288 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
290 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
291 pSerialStatus
->AmountInOutQueue
= (DeviceExtension
->OutputBuffer
.WritePosition
+ DeviceExtension
->OutputBuffer
.Length
292 - DeviceExtension
->OutputBuffer
.ReadPosition
) % DeviceExtension
->OutputBuffer
.Length
;
293 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
295 pSerialStatus
->EofReceived
= FALSE
; /* always FALSE */
296 pSerialStatus
->WaitForImmediate
= FALSE
; /* always FALSE */
298 return STATUS_SUCCESS
;
303 IN PDEVICE_OBJECT DeviceObject
,
306 PIO_STACK_LOCATION Stack
;
308 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
309 ULONG LengthIn
, LengthOut
;
310 ULONG_PTR Information
= 0;
311 PVOID BufferIn
, BufferOut
;
315 DPRINT("Serial: IRP_MJ_DEVICE_CONTROL dispatch\n");
317 Stack
= IoGetCurrentIrpStackLocation(Irp
);
318 LengthIn
= Stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
319 LengthOut
= Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
320 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
321 ComPortBase
= (PUCHAR
)DeviceExtension
->BaseAddress
;
322 IoControlCode
= Stack
->Parameters
.DeviceIoControl
.IoControlCode
;
323 SerialGetUserBuffers(Irp
, IoControlCode
, &BufferIn
, &BufferOut
);
325 /* FIXME: need to probe buffers */
326 /* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */
327 switch (IoControlCode
)
329 case IOCTL_SERIAL_CLEAR_STATS
:
331 DPRINT("Serial: IOCTL_SERIAL_CLEAR_STATS\n");
332 KeSynchronizeExecution(
333 DeviceExtension
->Interrupt
,
334 (PKSYNCHRONIZE_ROUTINE
)SerialClearPerfStats
,
336 Status
= STATUS_SUCCESS
;
339 case IOCTL_SERIAL_CLR_DTR
:
341 DPRINT("Serial: IOCTL_SERIAL_CLR_DTR\n");
342 /* FIXME: If the handshake flow control of the device is configured to
343 * automatically use DTR, return STATUS_INVALID_PARAMETER */
344 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
345 if (NT_SUCCESS(Status
))
347 DeviceExtension
->MCR
&= ~SR_MCR_DTR
;
348 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
349 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
353 case IOCTL_SERIAL_CLR_RTS
:
355 DPRINT("Serial: IOCTL_SERIAL_CLR_RTS\n");
356 /* FIXME: If the handshake flow control of the device is configured to
357 * automatically use RTS, return STATUS_INVALID_PARAMETER */
358 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
359 if (NT_SUCCESS(Status
))
361 DeviceExtension
->MCR
&= ~SR_MCR_RTS
;
362 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
363 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
367 case IOCTL_SERIAL_CONFIG_SIZE
:
369 /* Obsolete on Microsoft Windows 2000+ */
371 DPRINT("Serial: IOCTL_SERIAL_CONFIG_SIZE\n");
372 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
373 Status
= STATUS_INVALID_PARAMETER
;
376 pConfigSize
= (PULONG
)BufferOut
;
378 Status
= STATUS_SUCCESS
;
382 case IOCTL_SERIAL_GET_BAUD_RATE
:
384 DPRINT("Serial: IOCTL_SERIAL_GET_BAUD_RATE\n");
385 if (LengthOut
< sizeof(SERIAL_BAUD_RATE
))
386 Status
= STATUS_BUFFER_TOO_SMALL
;
387 else if (BufferOut
== NULL
)
388 Status
= STATUS_INVALID_PARAMETER
;
391 ((PSERIAL_BAUD_RATE
)BufferOut
)->BaudRate
= DeviceExtension
->BaudRate
;
392 Information
= sizeof(SERIAL_BAUD_RATE
);
393 Status
= STATUS_SUCCESS
;
397 case IOCTL_SERIAL_GET_CHARS
:
400 DPRINT1("Serial: IOCTL_SERIAL_GET_CHARS not implemented.\n");
401 Status
= STATUS_NOT_IMPLEMENTED
;
404 case IOCTL_SERIAL_GET_COMMSTATUS
:
406 DPRINT("Serial: IOCTL_SERIAL_GET_COMMSTATUS\n");
407 if (LengthOut
< sizeof(SERIAL_STATUS
))
409 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
410 Status
= STATUS_BUFFER_TOO_SMALL
;
412 else if (BufferOut
== NULL
)
414 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
415 Status
= STATUS_INVALID_PARAMETER
;
419 Status
= SerialGetCommStatus((PSERIAL_STATUS
)BufferOut
, DeviceExtension
);
420 Information
= sizeof(SERIAL_STATUS
);
424 case IOCTL_SERIAL_GET_DTRRTS
:
427 DPRINT("Serial: IOCTL_SERIAL_GET_DTRRTS\n");
428 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
429 Status
= STATUS_INVALID_PARAMETER
;
432 pDtrRts
= (PULONG
)BufferOut
;
434 if (DeviceExtension
->MCR
& SR_MCR_DTR
)
435 *pDtrRts
|= SERIAL_DTR_STATE
;
436 if (DeviceExtension
->MCR
& SR_MCR_RTS
)
437 *pDtrRts
|= SERIAL_RTS_STATE
;
438 Status
= STATUS_SUCCESS
;
442 case IOCTL_SERIAL_GET_HANDFLOW
:
445 DPRINT1("Serial: IOCTL_SERIAL_GET_HANDFLOW not implemented.\n");
446 Status
= STATUS_NOT_IMPLEMENTED
;
449 case IOCTL_SERIAL_GET_LINE_CONTROL
:
451 DPRINT("Serial: IOCTL_SERIAL_GET_LINE_CONTROL\n");
452 if (LengthOut
< sizeof(SERIAL_LINE_CONTROL
))
453 Status
= STATUS_BUFFER_TOO_SMALL
;
454 else if (BufferOut
== NULL
)
455 Status
= STATUS_INVALID_PARAMETER
;
458 *((PSERIAL_LINE_CONTROL
)BufferOut
) = DeviceExtension
->SerialLineControl
;
459 Information
= sizeof(SERIAL_LINE_CONTROL
);
460 Status
= STATUS_SUCCESS
;
464 case IOCTL_SERIAL_GET_MODEM_CONTROL
:
467 DPRINT("Serial: IOCTL_SERIAL_GET_MODEM_CONTROL\n");
468 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
469 Status
= STATUS_INVALID_PARAMETER
;
472 pMCR
= (PULONG
)BufferOut
;
473 *pMCR
= DeviceExtension
->MCR
;
474 Status
= STATUS_SUCCESS
;
478 case IOCTL_SERIAL_GET_MODEMSTATUS
:
481 DPRINT("Serial: IOCTL_SERIAL_GET_MODEMSTATUS\n");
482 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
483 Status
= STATUS_INVALID_PARAMETER
;
486 pMSR
= (PULONG
)BufferOut
;
487 *pMSR
= DeviceExtension
->MSR
;
488 Status
= STATUS_SUCCESS
;
492 case IOCTL_SERIAL_GET_PROPERTIES
:
494 DPRINT("Serial: IOCTL_SERIAL_GET_PROPERTIES\n");
495 if (LengthOut
< sizeof(SERIAL_COMMPROP
))
497 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
498 Status
= STATUS_BUFFER_TOO_SMALL
;
500 else if (BufferOut
== NULL
)
502 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
503 Status
= STATUS_INVALID_PARAMETER
;
507 Status
= SerialGetCommProp((PSERIAL_COMMPROP
)BufferOut
, DeviceExtension
);
508 Information
= sizeof(SERIAL_COMMPROP
);
512 case IOCTL_SERIAL_GET_STATS
:
514 DPRINT("Serial: IOCTL_SERIAL_GET_STATS\n");
515 if (LengthOut
< sizeof(SERIALPERF_STATS
))
517 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
518 Status
= STATUS_BUFFER_TOO_SMALL
;
520 else if (BufferOut
== NULL
)
522 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
523 Status
= STATUS_INVALID_PARAMETER
;
527 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
528 (PKSYNCHRONIZE_ROUTINE
)SerialGetPerfStats
, Irp
);
529 Status
= STATUS_SUCCESS
;
530 Information
= sizeof(SERIALPERF_STATS
);
534 case IOCTL_SERIAL_GET_TIMEOUTS
:
536 DPRINT("Serial: IOCTL_SERIAL_GET_TIMEOUTS\n");
537 if (LengthOut
!= sizeof(SERIAL_TIMEOUTS
) || BufferOut
== NULL
)
538 Status
= STATUS_INVALID_PARAMETER
;
541 *(PSERIAL_TIMEOUTS
)BufferOut
= DeviceExtension
->SerialTimeOuts
;
542 Status
= STATUS_SUCCESS
;
546 case IOCTL_SERIAL_GET_WAIT_MASK
:
549 DPRINT("Serial: IOCTL_SERIAL_GET_WAIT_MASK\n");
550 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
551 Status
= STATUS_INVALID_PARAMETER
;
554 pWaitMask
= (PULONG
)BufferOut
;
555 *pWaitMask
= DeviceExtension
->WaitMask
;
556 Status
= STATUS_SUCCESS
;
560 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
563 DPRINT1("Serial: IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n");
564 Status
= STATUS_NOT_IMPLEMENTED
;
567 case IOCTL_SERIAL_LSRMST_INSERT
:
570 DPRINT1("Serial: IOCTL_SERIAL_LSRMST_INSERT not implemented.\n");
571 Status
= STATUS_NOT_IMPLEMENTED
;
574 case IOCTL_SERIAL_PURGE
:
577 DPRINT("Serial: IOCTL_SERIAL_PURGE\n");
578 /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
579 * should stop current request */
580 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
581 Status
= STATUS_INVALID_PARAMETER
;
584 ULONG PurgeMask
= *(PULONG
)BufferIn
;
586 Status
= STATUS_SUCCESS
;
587 /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
588 if (PurgeMask
& SERIAL_PURGE_RXCLEAR
)
590 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
591 DeviceExtension
->InputBuffer
.ReadPosition
= DeviceExtension
->InputBuffer
.WritePosition
= 0;
592 if (DeviceExtension
->UartType
>= Uart16550A
)
594 /* Clear also Uart FIFO */
595 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
596 if (NT_SUCCESS(Status
))
598 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_RCVR
);
599 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
602 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
605 if (PurgeMask
& SERIAL_PURGE_TXCLEAR
)
607 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
608 DeviceExtension
->OutputBuffer
.ReadPosition
= DeviceExtension
->OutputBuffer
.WritePosition
= 0;
609 if (DeviceExtension
->UartType
>= Uart16550A
)
611 /* Clear also Uart FIFO */
612 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
613 if (NT_SUCCESS(Status
))
615 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_XMIT
);
616 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
619 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
624 case IOCTL_SERIAL_RESET_DEVICE
:
627 DPRINT1("Serial: IOCTL_SERIAL_RESET_DEVICE not implemented.\n");
628 Status
= STATUS_NOT_IMPLEMENTED
;
631 case IOCTL_SERIAL_SET_BAUD_RATE
:
634 DPRINT("Serial: IOCTL_SERIAL_SET_BAUD_RATE\n");
635 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
636 Status
= STATUS_INVALID_PARAMETER
;
639 pNewBaudRate
= (PULONG
)BufferIn
;
640 Status
= SerialSetBaudRate(DeviceExtension
, *pNewBaudRate
);
644 case IOCTL_SERIAL_SET_BREAK_OFF
:
647 DPRINT1("Serial: IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n");
648 Status
= STATUS_NOT_IMPLEMENTED
;
651 case IOCTL_SERIAL_SET_BREAK_ON
:
654 DPRINT1("Serial: IOCTL_SERIAL_SET_BREAK_ON not implemented.\n");
655 Status
= STATUS_NOT_IMPLEMENTED
;
658 case IOCTL_SERIAL_SET_CHARS
:
661 DPRINT1("Serial: IOCTL_SERIAL_SET_CHARS not implemented.\n");
662 Status
= STATUS_NOT_IMPLEMENTED
;
665 case IOCTL_SERIAL_SET_DTR
:
667 /* FIXME: If the handshake flow control of the device is configured to
668 * automatically use DTR, return STATUS_INVALID_PARAMETER */
669 DPRINT("Serial: IOCTL_SERIAL_SET_DTR\n");
670 if (!(DeviceExtension
->MCR
& SR_MCR_DTR
))
672 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
673 if (NT_SUCCESS(Status
))
675 DeviceExtension
->MCR
|= SR_MCR_DTR
;
676 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
677 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
681 Status
= STATUS_SUCCESS
;
684 case IOCTL_SERIAL_SET_FIFO_CONTROL
:
686 DPRINT("Serial: IOCTL_SERIAL_SET_FIFO_CONTROL\n");
687 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
688 Status
= STATUS_INVALID_PARAMETER
;
691 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
692 if (NT_SUCCESS(Status
))
694 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), (UCHAR
)((*(PULONG
)BufferIn
) & 0xff));
695 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
700 case IOCTL_SERIAL_SET_HANDFLOW
:
703 DPRINT1("Serial: IOCTL_SERIAL_SET_HANDFLOW not implemented.\n");
704 Status
= STATUS_NOT_IMPLEMENTED
;
707 case IOCTL_SERIAL_SET_LINE_CONTROL
:
709 DPRINT("Serial: IOCTL_SERIAL_SET_LINE_CONTROL\n");
710 if (LengthIn
< sizeof(SERIAL_LINE_CONTROL
))
711 Status
= STATUS_BUFFER_TOO_SMALL
;
712 else if (BufferIn
== NULL
)
713 Status
= STATUS_INVALID_PARAMETER
;
715 Status
= SerialSetLineControl(DeviceExtension
, (PSERIAL_LINE_CONTROL
)BufferIn
);
718 case IOCTL_SERIAL_SET_MODEM_CONTROL
:
721 DPRINT("Serial: IOCTL_SERIAL_SET_MODEM_CONTROL\n");
722 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
723 Status
= STATUS_INVALID_PARAMETER
;
726 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
727 if (NT_SUCCESS(Status
))
729 pMCR
= (PULONG
)BufferIn
;
730 DeviceExtension
->MCR
= (UCHAR
)(*pMCR
& 0xff);
731 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
732 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
737 case IOCTL_SERIAL_SET_QUEUE_SIZE
:
739 if (LengthIn
< sizeof(SERIAL_QUEUE_SIZE
))
740 return STATUS_BUFFER_TOO_SMALL
;
741 else if (BufferIn
== NULL
)
742 return STATUS_INVALID_PARAMETER
;
746 PSERIAL_QUEUE_SIZE NewQueueSize
= (PSERIAL_QUEUE_SIZE
)BufferIn
;
747 Status
= STATUS_SUCCESS
;
748 if (NewQueueSize
->InSize
> DeviceExtension
->InputBuffer
.Length
)
750 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
751 Status
= IncreaseCircularBufferSize(&DeviceExtension
->InputBuffer
, NewQueueSize
->InSize
);
752 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
754 if (NT_SUCCESS(Status
) && NewQueueSize
->OutSize
> DeviceExtension
->OutputBuffer
.Length
)
756 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
757 Status
= IncreaseCircularBufferSize(&DeviceExtension
->OutputBuffer
, NewQueueSize
->OutSize
);
758 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
763 case IOCTL_SERIAL_SET_RTS
:
765 /* FIXME: If the handshake flow control of the device is configured to
766 * automatically use DTR, return STATUS_INVALID_PARAMETER */
767 DPRINT("Serial: IOCTL_SERIAL_SET_RTS\n");
768 if (!(DeviceExtension
->MCR
& SR_MCR_RTS
))
770 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
771 if (NT_SUCCESS(Status
))
773 DeviceExtension
->MCR
|= SR_MCR_RTS
;
774 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
775 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
779 Status
= STATUS_SUCCESS
;
782 case IOCTL_SERIAL_SET_TIMEOUTS
:
784 DPRINT("Serial: IOCTL_SERIAL_SET_TIMEOUTS\n");
785 if (LengthIn
!= sizeof(SERIAL_TIMEOUTS
) || BufferIn
== NULL
)
786 Status
= STATUS_INVALID_PARAMETER
;
789 DeviceExtension
->SerialTimeOuts
= *(PSERIAL_TIMEOUTS
)BufferIn
;
790 Status
= STATUS_SUCCESS
;
794 case IOCTL_SERIAL_SET_WAIT_MASK
:
797 DPRINT("Serial: IOCTL_SERIAL_SET_WAIT_MASK\n");
798 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
799 Status
= STATUS_INVALID_PARAMETER
;
802 pWaitMask
= (PULONG
)BufferIn
;
803 DeviceExtension
->WaitMask
= *pWaitMask
;
804 Status
= STATUS_SUCCESS
;
808 case IOCTL_SERIAL_SET_XOFF
:
811 DPRINT1("Serial: IOCTL_SERIAL_SET_XOFF not implemented.\n");
812 Status
= STATUS_NOT_IMPLEMENTED
;
815 case IOCTL_SERIAL_SET_XON
:
818 DPRINT1("Serial: IOCTL_SERIAL_SET_XON not implemented.\n");
819 Status
= STATUS_NOT_IMPLEMENTED
;
822 case IOCTL_SERIAL_WAIT_ON_MASK
:
825 DPRINT1("Serial: IOCTL_SERIAL_WAIT_ON_MASK not implemented.\n");
826 Status
= STATUS_NOT_IMPLEMENTED
;
829 case IOCTL_SERIAL_XOFF_COUNTER
:
832 DPRINT1("Serial: IOCTL_SERIAL_XOFF_COUNTER not implemented.\n");
833 Status
= STATUS_NOT_IMPLEMENTED
;
838 /* Pass Irp to lower driver */
839 DPRINT("Serial: Unknown IOCTL code 0x%x\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
840 IoSkipCurrentIrpStackLocation(Irp
);
841 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
845 Irp
->IoStatus
.Information
= Information
;
846 Irp
->IoStatus
.Status
= Status
;
847 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);