2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Serial port driver
4 * FILE: drivers/dd/serial/devctrl.c
5 * PURPOSE: Serial IRP_MJ_DEVICE_CONTROL operations
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
13 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
18 IN ULONG IoControlCode
,
26 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
29 *BufferIn
= *BufferOut
= Irp
->AssociatedIrp
.SystemBuffer
;
31 case METHOD_IN_DIRECT
:
32 case METHOD_OUT_DIRECT
:
33 *BufferIn
= Irp
->AssociatedIrp
.SystemBuffer
;
34 *BufferOut
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
37 *BufferIn
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.Type3InputBuffer
;
38 *BufferOut
= Irp
->UserBuffer
;
41 /* Should never happen */
50 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
,
55 PUCHAR ComPortBase
= (PUCHAR
)DeviceExtension
->BaseAddress
;
56 NTSTATUS Status
= STATUS_SUCCESS
;
58 divisor
= (USHORT
)(BAUD_CLOCK
/ (CLOCKS_PER_BIT
* NewBaudRate
));
59 BaudRate
= BAUD_CLOCK
/ (CLOCKS_PER_BIT
* divisor
);
61 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
62 if (NT_SUCCESS(Status
))
65 DPRINT("Serial: SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension
->ComPort
, BaudRate
);
66 /* Set Bit 7 of LCR to expose baud registers */
67 Lcr
= READ_PORT_UCHAR(SER_LCR(ComPortBase
));
68 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
| SR_LCR_DLAB
);
69 /* Write the baud rate */
70 WRITE_PORT_UCHAR(SER_DLL(ComPortBase
), divisor
& 0xff);
71 WRITE_PORT_UCHAR(SER_DLM(ComPortBase
), divisor
>> 8);
72 /* Switch back to normal registers */
73 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
);
75 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
78 if (NT_SUCCESS(Status
))
79 DeviceExtension
->BaudRate
= BaudRate
;
85 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
,
86 IN PSERIAL_LINE_CONTROL NewSettings
)
92 ASSERT(DeviceExtension
);
95 DPRINT("Serial: SerialSetLineControl(COM%lu, Settings { %lu %lu %lu })\n",
96 DeviceExtension
->ComPort
, NewSettings
->StopBits
, NewSettings
->Parity
, NewSettings
->WordLength
);
98 /* Verify parameters */
99 switch (NewSettings
->WordLength
)
101 case 5: Lcr
|= SR_LCR_CS5
; break;
102 case 6: Lcr
|= SR_LCR_CS6
; break;
103 case 7: Lcr
|= SR_LCR_CS7
; break;
104 case 8: Lcr
|= SR_LCR_CS8
; break;
105 default: return STATUS_INVALID_PARAMETER
;
108 if (NewSettings
->WordLength
< 5 || NewSettings
->WordLength
> 8)
109 return STATUS_INVALID_PARAMETER
;
111 switch (NewSettings
->Parity
)
113 case NO_PARITY
: Lcr
|= SR_LCR_PNO
; break;
114 case ODD_PARITY
: Lcr
|= SR_LCR_POD
; break;
115 case EVEN_PARITY
: Lcr
|= SR_LCR_PEV
; break;
116 case MARK_PARITY
: Lcr
|= SR_LCR_PMK
; break;
117 case SPACE_PARITY
: Lcr
|= SR_LCR_PSP
; break;
118 default: return STATUS_INVALID_PARAMETER
;
121 switch (NewSettings
->StopBits
)
127 if (NewSettings
->WordLength
!= 5)
128 return STATUS_INVALID_PARAMETER
;
132 if (NewSettings
->WordLength
< 6 || NewSettings
->WordLength
> 8)
133 return STATUS_INVALID_PARAMETER
;
137 return STATUS_INVALID_PARAMETER
;
140 /* Update current parameters */
141 ComPortBase
= (PUCHAR
)DeviceExtension
->BaseAddress
;
142 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
143 if (!NT_SUCCESS(Status
))
145 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
);
147 /* Read junk out of RBR */
148 READ_PORT_UCHAR(SER_RBR(ComPortBase
));
149 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
151 if (NT_SUCCESS(Status
))
152 DeviceExtension
->SerialLineControl
= *NewSettings
;
158 SerialClearPerfStats(
159 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
161 ASSERT(DeviceExtension
);
163 RtlZeroMemory(&DeviceExtension
->SerialPerfStats
, sizeof(SERIALPERF_STATS
));
164 DeviceExtension
->BreakInterruptErrorCount
= 0;
169 SerialGetPerfStats(IN PIRP pIrp
)
171 PSERIAL_DEVICE_EXTENSION pDeviceExtension
;
174 pDeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)
175 IoGetCurrentIrpStackLocation(pIrp
)->DeviceObject
->DeviceExtension
;
178 * we assume buffer is big enough to hold SerialPerfStats structure
179 * caller must verify this
182 pIrp
->AssociatedIrp
.SystemBuffer
,
183 &pDeviceExtension
->SerialPerfStats
,
184 sizeof(SERIALPERF_STATS
)
191 OUT PSERIAL_COMMPROP pCommProp
,
192 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
196 RtlZeroMemory(pCommProp
, sizeof(SERIAL_COMMPROP
));
198 if (!(pCommProp
->ProvSpec1
& COMMPROP_INITIALIZED
))
199 pCommProp
->PacketLength
= sizeof(SERIAL_COMMPROP
);
200 pCommProp
->PacketVersion
= 2;
201 pCommProp
->ServiceMask
= SERIAL_SP_SERIALCOMM
;
202 pCommProp
->MaxTxQueue
= pCommProp
->CurrentTxQueue
= DeviceExtension
->OutputBuffer
.Length
- 1;
203 pCommProp
->MaxRxQueue
= pCommProp
->CurrentRxQueue
= DeviceExtension
->InputBuffer
.Length
- 1;
204 pCommProp
->ProvSubType
= PST_RS232
;
205 pCommProp
->ProvCapabilities
= SERIAL_PCF_DTRDSR
| SERIAL_PCF_INTTIMEOUTS
| SERIAL_PCF_PARITY_CHECK
206 | SERIAL_PCF_RTSCTS
| SERIAL_PCF_SETXCHAR
| SERIAL_PCF_SPECIALCHARS
| SERIAL_PCF_TOTALTIMEOUTS
207 | SERIAL_PCF_XONXOFF
;
208 pCommProp
->SettableParams
= SERIAL_SP_BAUD
| SERIAL_SP_DATABITS
| SERIAL_SP_HANDSHAKING
209 | SERIAL_SP_PARITY
| SERIAL_SP_PARITY_CHECK
| SERIAL_SP_STOPBITS
;
211 /* SettableBaud is related to Uart type */
212 pCommProp
->SettableBaud
= SERIAL_BAUD_075
| SERIAL_BAUD_110
| SERIAL_BAUD_134_5
213 | SERIAL_BAUD_150
| SERIAL_BAUD_300
| SERIAL_BAUD_600
| SERIAL_BAUD_1200
214 | SERIAL_BAUD_1800
| SERIAL_BAUD_2400
| SERIAL_BAUD_4800
| SERIAL_BAUD_7200
215 | SERIAL_BAUD_9600
| SERIAL_BAUD_USER
;
216 pCommProp
->MaxBaud
= SERIAL_BAUD_USER
;
217 if (DeviceExtension
->UartType
>= Uart16450
)
219 pCommProp
->SettableBaud
|= SERIAL_BAUD_14400
| SERIAL_BAUD_19200
| SERIAL_BAUD_38400
;
221 if (DeviceExtension
->UartType
>= Uart16550
)
223 pCommProp
->SettableBaud
|= SERIAL_BAUD_56K
| SERIAL_BAUD_57600
| SERIAL_BAUD_115200
| SERIAL_BAUD_128K
;
226 pCommProp
->SettableData
= SERIAL_DATABITS_5
| SERIAL_DATABITS_6
| SERIAL_DATABITS_7
| SERIAL_DATABITS_8
;
227 pCommProp
->SettableStopParity
= SERIAL_STOPBITS_10
| SERIAL_STOPBITS_15
| SERIAL_STOPBITS_20
228 | SERIAL_PARITY_NONE
| SERIAL_PARITY_ODD
| SERIAL_PARITY_EVEN
| SERIAL_PARITY_MARK
| SERIAL_PARITY_SPACE
;
230 pCommProp
->ProvSpec2
= 0; /* Size of provider-specific data */
232 return STATUS_SUCCESS
;
237 OUT PSERIAL_STATUS pSerialStatus
,
238 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
242 ASSERT(pSerialStatus
);
243 RtlZeroMemory(pSerialStatus
, sizeof(SERIAL_STATUS
));
245 pSerialStatus
->Errors
= 0;
246 if (DeviceExtension
->BreakInterruptErrorCount
)
247 pSerialStatus
->Errors
|= SERIAL_ERROR_BREAK
;
248 if (DeviceExtension
->SerialPerfStats
.FrameErrorCount
)
249 pSerialStatus
->Errors
|= SERIAL_ERROR_FRAMING
;
250 if (DeviceExtension
->SerialPerfStats
.SerialOverrunErrorCount
)
251 pSerialStatus
->Errors
|= SERIAL_ERROR_OVERRUN
;
252 if (DeviceExtension
->SerialPerfStats
.BufferOverrunErrorCount
)
253 pSerialStatus
->Errors
|= SERIAL_ERROR_QUEUEOVERRUN
;
254 if (DeviceExtension
->SerialPerfStats
.ParityErrorCount
)
255 pSerialStatus
->Errors
|= SERIAL_ERROR_PARITY
;
257 pSerialStatus
->HoldReasons
= 0; /* FIXME */
259 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
260 pSerialStatus
->AmountInInQueue
= (DeviceExtension
->InputBuffer
.WritePosition
+ DeviceExtension
->InputBuffer
.Length
261 - DeviceExtension
->InputBuffer
.ReadPosition
) % DeviceExtension
->InputBuffer
.Length
;
262 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
264 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
265 pSerialStatus
->AmountInOutQueue
= (DeviceExtension
->OutputBuffer
.WritePosition
+ DeviceExtension
->OutputBuffer
.Length
266 - DeviceExtension
->OutputBuffer
.ReadPosition
) % DeviceExtension
->OutputBuffer
.Length
;
267 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
269 pSerialStatus
->EofReceived
= FALSE
; /* always FALSE */
270 pSerialStatus
->WaitForImmediate
= FALSE
; /* always FALSE */
272 return STATUS_SUCCESS
;
277 IN PDEVICE_OBJECT DeviceObject
,
280 PIO_STACK_LOCATION Stack
;
282 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
283 ULONG LengthIn
, LengthOut
;
284 ULONG_PTR Information
= 0;
285 PVOID BufferIn
, BufferOut
;
289 DPRINT("Serial: IRP_MJ_DEVICE_CONTROL dispatch\n");
291 Stack
= IoGetCurrentIrpStackLocation(Irp
);
292 LengthIn
= Stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
293 LengthOut
= Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
294 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
295 ComPortBase
= (PUCHAR
)DeviceExtension
->BaseAddress
;
296 IoControlCode
= Stack
->Parameters
.DeviceIoControl
.IoControlCode
;
297 SerialGetUserBuffers(Irp
, IoControlCode
, &BufferIn
, &BufferOut
);
299 /* FIXME: need to probe buffers */
300 /* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */
301 switch (IoControlCode
)
303 case IOCTL_SERIAL_CLEAR_STATS
:
305 DPRINT("Serial: IOCTL_SERIAL_CLEAR_STATS\n");
306 KeSynchronizeExecution(
307 DeviceExtension
->Interrupt
,
308 (PKSYNCHRONIZE_ROUTINE
)SerialClearPerfStats
,
310 Status
= STATUS_SUCCESS
;
313 case IOCTL_SERIAL_CLR_DTR
:
315 DPRINT("Serial: IOCTL_SERIAL_CLR_DTR\n");
316 /* FIXME: If the handshake flow control of the device is configured to
317 * automatically use DTR, return STATUS_INVALID_PARAMETER */
318 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
319 if (NT_SUCCESS(Status
))
321 DeviceExtension
->MCR
&= ~SR_MCR_DTR
;
322 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
323 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
327 case IOCTL_SERIAL_CLR_RTS
:
329 DPRINT("Serial: IOCTL_SERIAL_CLR_RTS\n");
330 /* FIXME: If the handshake flow control of the device is configured to
331 * automatically use RTS, return STATUS_INVALID_PARAMETER */
332 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
333 if (NT_SUCCESS(Status
))
335 DeviceExtension
->MCR
&= ~SR_MCR_RTS
;
336 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
337 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
341 case IOCTL_SERIAL_CONFIG_SIZE
:
343 /* Obsolete on Microsoft Windows 2000+ */
345 DPRINT("Serial: IOCTL_SERIAL_CONFIG_SIZE\n");
346 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
347 Status
= STATUS_INVALID_PARAMETER
;
350 pConfigSize
= (PULONG
)BufferOut
;
352 Status
= STATUS_SUCCESS
;
356 case IOCTL_SERIAL_GET_BAUD_RATE
:
358 DPRINT("Serial: IOCTL_SERIAL_GET_BAUD_RATE\n");
359 if (LengthOut
< sizeof(SERIAL_BAUD_RATE
))
360 Status
= STATUS_BUFFER_TOO_SMALL
;
361 else if (BufferOut
== NULL
)
362 Status
= STATUS_INVALID_PARAMETER
;
365 ((PSERIAL_BAUD_RATE
)BufferOut
)->BaudRate
= DeviceExtension
->BaudRate
;
366 Information
= sizeof(SERIAL_BAUD_RATE
);
367 Status
= STATUS_SUCCESS
;
371 case IOCTL_SERIAL_GET_CHARS
:
374 DPRINT1("Serial: IOCTL_SERIAL_GET_CHARS not implemented.\n");
375 Status
= STATUS_NOT_IMPLEMENTED
;
378 case IOCTL_SERIAL_GET_COMMSTATUS
:
380 DPRINT("Serial: IOCTL_SERIAL_GET_COMMSTATUS\n");
381 if (LengthOut
< sizeof(SERIAL_STATUS
))
383 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
384 Status
= STATUS_BUFFER_TOO_SMALL
;
386 else if (BufferOut
== NULL
)
388 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
389 Status
= STATUS_INVALID_PARAMETER
;
393 Status
= SerialGetCommStatus((PSERIAL_STATUS
)BufferOut
, DeviceExtension
);
394 Information
= sizeof(SERIAL_STATUS
);
398 case IOCTL_SERIAL_GET_DTRRTS
:
401 DPRINT("Serial: IOCTL_SERIAL_GET_DTRRTS\n");
402 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
403 Status
= STATUS_INVALID_PARAMETER
;
406 pDtrRts
= (PULONG
)BufferOut
;
408 if (DeviceExtension
->MCR
& SR_MCR_DTR
)
409 *pDtrRts
|= SERIAL_DTR_STATE
;
410 if (DeviceExtension
->MCR
& SR_MCR_RTS
)
411 *pDtrRts
|= SERIAL_RTS_STATE
;
412 Status
= STATUS_SUCCESS
;
416 case IOCTL_SERIAL_GET_HANDFLOW
:
419 DPRINT1("Serial: IOCTL_SERIAL_GET_HANDFLOW not implemented.\n");
420 Status
= STATUS_NOT_IMPLEMENTED
;
423 case IOCTL_SERIAL_GET_LINE_CONTROL
:
425 DPRINT("Serial: IOCTL_SERIAL_GET_LINE_CONTROL\n");
426 if (LengthOut
< sizeof(SERIAL_LINE_CONTROL
))
427 Status
= STATUS_BUFFER_TOO_SMALL
;
428 else if (BufferOut
== NULL
)
429 Status
= STATUS_INVALID_PARAMETER
;
432 *((PSERIAL_LINE_CONTROL
)BufferOut
) = DeviceExtension
->SerialLineControl
;
433 Information
= sizeof(SERIAL_LINE_CONTROL
);
434 Status
= STATUS_SUCCESS
;
438 case IOCTL_SERIAL_GET_MODEM_CONTROL
:
441 DPRINT("Serial: IOCTL_SERIAL_GET_MODEM_CONTROL\n");
442 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
443 Status
= STATUS_INVALID_PARAMETER
;
446 pMCR
= (PULONG
)BufferOut
;
447 *pMCR
= DeviceExtension
->MCR
;
448 Status
= STATUS_SUCCESS
;
452 case IOCTL_SERIAL_GET_MODEMSTATUS
:
455 DPRINT("Serial: IOCTL_SERIAL_GET_MODEMSTATUS\n");
456 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
457 Status
= STATUS_INVALID_PARAMETER
;
460 pMSR
= (PULONG
)BufferOut
;
461 *pMSR
= DeviceExtension
->MSR
;
462 Status
= STATUS_SUCCESS
;
466 case IOCTL_SERIAL_GET_PROPERTIES
:
468 DPRINT("Serial: IOCTL_SERIAL_GET_PROPERTIES\n");
469 if (LengthOut
< sizeof(SERIAL_COMMPROP
))
471 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
472 Status
= STATUS_BUFFER_TOO_SMALL
;
474 else if (BufferOut
== NULL
)
476 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
477 Status
= STATUS_INVALID_PARAMETER
;
481 Status
= SerialGetCommProp((PSERIAL_COMMPROP
)BufferOut
, DeviceExtension
);
482 Information
= sizeof(SERIAL_COMMPROP
);
486 case IOCTL_SERIAL_GET_STATS
:
488 DPRINT("Serial: IOCTL_SERIAL_GET_STATS\n");
489 if (LengthOut
< sizeof(SERIALPERF_STATS
))
491 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
492 Status
= STATUS_BUFFER_TOO_SMALL
;
494 else if (BufferOut
== NULL
)
496 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
497 Status
= STATUS_INVALID_PARAMETER
;
501 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
502 (PKSYNCHRONIZE_ROUTINE
)SerialGetPerfStats
, Irp
);
503 Status
= STATUS_SUCCESS
;
504 Information
= sizeof(SERIALPERF_STATS
);
508 case IOCTL_SERIAL_GET_TIMEOUTS
:
510 DPRINT("Serial: IOCTL_SERIAL_GET_TIMEOUTS\n");
511 if (LengthOut
!= sizeof(SERIAL_TIMEOUTS
) || BufferOut
== NULL
)
512 Status
= STATUS_INVALID_PARAMETER
;
515 *(PSERIAL_TIMEOUTS
)BufferOut
= DeviceExtension
->SerialTimeOuts
;
516 Status
= STATUS_SUCCESS
;
520 case IOCTL_SERIAL_GET_WAIT_MASK
:
523 DPRINT("Serial: IOCTL_SERIAL_GET_WAIT_MASK\n");
524 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
525 Status
= STATUS_INVALID_PARAMETER
;
528 pWaitMask
= (PULONG
)BufferOut
;
529 *pWaitMask
= DeviceExtension
->WaitMask
;
530 Status
= STATUS_SUCCESS
;
534 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
537 DPRINT1("Serial: IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n");
538 Status
= STATUS_NOT_IMPLEMENTED
;
541 case IOCTL_SERIAL_LSRMST_INSERT
:
544 DPRINT1("Serial: IOCTL_SERIAL_LSRMST_INSERT not implemented.\n");
545 Status
= STATUS_NOT_IMPLEMENTED
;
548 case IOCTL_SERIAL_PURGE
:
551 DPRINT("Serial: IOCTL_SERIAL_PURGE\n");
552 /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
553 * should stop current request */
554 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
555 Status
= STATUS_INVALID_PARAMETER
;
558 ULONG PurgeMask
= *(PULONG
)BufferIn
;
560 Status
= STATUS_SUCCESS
;
561 /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
562 if (PurgeMask
& SERIAL_PURGE_RXCLEAR
)
564 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
565 DeviceExtension
->InputBuffer
.ReadPosition
= DeviceExtension
->InputBuffer
.WritePosition
= 0;
566 if (DeviceExtension
->UartType
>= Uart16550A
)
568 /* Clear also Uart FIFO */
569 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
570 if (NT_SUCCESS(Status
))
572 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_RCVR
);
573 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
576 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
579 if (PurgeMask
& SERIAL_PURGE_TXCLEAR
)
581 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
582 DeviceExtension
->OutputBuffer
.ReadPosition
= DeviceExtension
->OutputBuffer
.WritePosition
= 0;
583 if (DeviceExtension
->UartType
>= Uart16550A
)
585 /* Clear also Uart FIFO */
586 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
587 if (NT_SUCCESS(Status
))
589 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_XMIT
);
590 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
593 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
598 case IOCTL_SERIAL_RESET_DEVICE
:
601 DPRINT1("Serial: IOCTL_SERIAL_RESET_DEVICE not implemented.\n");
602 Status
= STATUS_NOT_IMPLEMENTED
;
605 case IOCTL_SERIAL_SET_BAUD_RATE
:
608 DPRINT("Serial: IOCTL_SERIAL_SET_BAUD_RATE\n");
609 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
610 Status
= STATUS_INVALID_PARAMETER
;
613 pNewBaudRate
= (PULONG
)BufferIn
;
614 Status
= SerialSetBaudRate(DeviceExtension
, *pNewBaudRate
);
618 case IOCTL_SERIAL_SET_BREAK_OFF
:
621 DPRINT1("Serial: IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n");
622 Status
= STATUS_NOT_IMPLEMENTED
;
625 case IOCTL_SERIAL_SET_BREAK_ON
:
628 DPRINT1("Serial: IOCTL_SERIAL_SET_BREAK_ON not implemented.\n");
629 Status
= STATUS_NOT_IMPLEMENTED
;
632 case IOCTL_SERIAL_SET_CHARS
:
635 DPRINT1("Serial: IOCTL_SERIAL_SET_CHARS not implemented.\n");
636 Status
= STATUS_NOT_IMPLEMENTED
;
639 case IOCTL_SERIAL_SET_DTR
:
641 /* FIXME: If the handshake flow control of the device is configured to
642 * automatically use DTR, return STATUS_INVALID_PARAMETER */
643 DPRINT("Serial: IOCTL_SERIAL_SET_DTR\n");
644 if (!(DeviceExtension
->MCR
& SR_MCR_DTR
))
646 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
647 if (NT_SUCCESS(Status
))
649 DeviceExtension
->MCR
|= SR_MCR_DTR
;
650 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
651 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
655 Status
= STATUS_SUCCESS
;
658 case IOCTL_SERIAL_SET_FIFO_CONTROL
:
660 DPRINT("Serial: IOCTL_SERIAL_SET_FIFO_CONTROL\n");
661 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
662 Status
= STATUS_INVALID_PARAMETER
;
665 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
666 if (NT_SUCCESS(Status
))
668 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), (UCHAR
)((*(PULONG
)BufferIn
) & 0xff));
669 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
674 case IOCTL_SERIAL_SET_HANDFLOW
:
677 DPRINT1("Serial: IOCTL_SERIAL_SET_HANDFLOW not implemented.\n");
678 Status
= STATUS_NOT_IMPLEMENTED
;
681 case IOCTL_SERIAL_SET_LINE_CONTROL
:
683 DPRINT("Serial: IOCTL_SERIAL_SET_LINE_CONTROL\n");
684 if (LengthIn
< sizeof(SERIAL_LINE_CONTROL
))
685 Status
= STATUS_BUFFER_TOO_SMALL
;
686 else if (BufferIn
== NULL
)
687 Status
= STATUS_INVALID_PARAMETER
;
689 Status
= SerialSetLineControl(DeviceExtension
, (PSERIAL_LINE_CONTROL
)BufferIn
);
692 case IOCTL_SERIAL_SET_MODEM_CONTROL
:
695 DPRINT("Serial: IOCTL_SERIAL_SET_MODEM_CONTROL\n");
696 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
697 Status
= STATUS_INVALID_PARAMETER
;
700 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
701 if (NT_SUCCESS(Status
))
703 pMCR
= (PULONG
)BufferIn
;
704 DeviceExtension
->MCR
= (UCHAR
)(*pMCR
& 0xff);
705 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
706 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
711 case IOCTL_SERIAL_SET_QUEUE_SIZE
:
713 if (LengthIn
< sizeof(SERIAL_QUEUE_SIZE
))
714 return STATUS_BUFFER_TOO_SMALL
;
715 else if (BufferIn
== NULL
)
716 return STATUS_INVALID_PARAMETER
;
720 PSERIAL_QUEUE_SIZE NewQueueSize
= (PSERIAL_QUEUE_SIZE
)BufferIn
;
721 Status
= STATUS_SUCCESS
;
722 if (NewQueueSize
->InSize
> DeviceExtension
->InputBuffer
.Length
)
724 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
725 Status
= IncreaseCircularBufferSize(&DeviceExtension
->InputBuffer
, NewQueueSize
->InSize
);
726 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
728 if (NT_SUCCESS(Status
) && NewQueueSize
->OutSize
> DeviceExtension
->OutputBuffer
.Length
)
730 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
731 Status
= IncreaseCircularBufferSize(&DeviceExtension
->OutputBuffer
, NewQueueSize
->OutSize
);
732 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
737 case IOCTL_SERIAL_SET_RTS
:
739 /* FIXME: If the handshake flow control of the device is configured to
740 * automatically use DTR, return STATUS_INVALID_PARAMETER */
741 DPRINT("Serial: IOCTL_SERIAL_SET_RTS\n");
742 if (!(DeviceExtension
->MCR
& SR_MCR_RTS
))
744 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
745 if (NT_SUCCESS(Status
))
747 DeviceExtension
->MCR
|= SR_MCR_RTS
;
748 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
749 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, (PVOID
)DeviceExtension
->ComPort
);
753 Status
= STATUS_SUCCESS
;
756 case IOCTL_SERIAL_SET_TIMEOUTS
:
758 DPRINT("Serial: IOCTL_SERIAL_SET_TIMEOUTS\n");
759 if (LengthIn
!= sizeof(SERIAL_TIMEOUTS
) || BufferIn
== NULL
)
760 Status
= STATUS_INVALID_PARAMETER
;
763 DeviceExtension
->SerialTimeOuts
= *(PSERIAL_TIMEOUTS
)BufferIn
;
764 Status
= STATUS_SUCCESS
;
768 case IOCTL_SERIAL_SET_WAIT_MASK
:
771 DPRINT("Serial: IOCTL_SERIAL_SET_WAIT_MASK\n");
772 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
773 Status
= STATUS_INVALID_PARAMETER
;
776 pWaitMask
= (PULONG
)BufferIn
;
777 DeviceExtension
->WaitMask
= *pWaitMask
;
778 Status
= STATUS_SUCCESS
;
782 case IOCTL_SERIAL_SET_XOFF
:
785 DPRINT1("Serial: IOCTL_SERIAL_SET_XOFF not implemented.\n");
786 Status
= STATUS_NOT_IMPLEMENTED
;
789 case IOCTL_SERIAL_SET_XON
:
792 DPRINT1("Serial: IOCTL_SERIAL_SET_XON not implemented.\n");
793 Status
= STATUS_NOT_IMPLEMENTED
;
796 case IOCTL_SERIAL_WAIT_ON_MASK
:
799 DPRINT1("Serial: IOCTL_SERIAL_WAIT_ON_MASK not implemented.\n");
800 Status
= STATUS_NOT_IMPLEMENTED
;
803 case IOCTL_SERIAL_XOFF_COUNTER
:
806 DPRINT1("Serial: IOCTL_SERIAL_XOFF_COUNTER not implemented.\n");
807 Status
= STATUS_NOT_IMPLEMENTED
;
812 /* Pass Irp to lower driver */
813 DPRINT("Serial: Unknown IOCTL code 0x%x\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
814 IoSkipCurrentIrpStackLocation(Irp
);
815 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
819 Irp
->IoStatus
.Information
= Information
;
820 Irp
->IoStatus
.Status
= Status
;
821 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);