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.org)
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
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
38 *BufferIn
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.Type3InputBuffer
;
39 *BufferOut
= Irp
->UserBuffer
;
42 /* Should never happen */
51 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
,
56 PUCHAR ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
57 NTSTATUS Status
= STATUS_SUCCESS
;
60 return STATUS_INVALID_PARAMETER
;
62 divisor
= (USHORT
)(BAUD_CLOCK
/ (CLOCKS_PER_BIT
* NewBaudRate
));
63 BaudRate
= BAUD_CLOCK
/ (CLOCKS_PER_BIT
* divisor
);
65 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
66 if (NT_SUCCESS(Status
))
69 TRACE_(SERIAL
, "SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension
->ComPort
, BaudRate
);
70 /* Set Bit 7 of LCR to expose baud registers */
71 Lcr
= READ_PORT_UCHAR(SER_LCR(ComPortBase
));
72 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
| SR_LCR_DLAB
);
73 /* Write the baud rate */
74 WRITE_PORT_UCHAR(SER_DLL(ComPortBase
), divisor
& 0xff);
75 WRITE_PORT_UCHAR(SER_DLM(ComPortBase
), divisor
>> 8);
76 /* Switch back to normal registers */
77 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
);
79 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
82 if (NT_SUCCESS(Status
))
83 DeviceExtension
->BaudRate
= BaudRate
;
89 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
,
90 IN PSERIAL_LINE_CONTROL NewSettings
)
96 ASSERT(DeviceExtension
);
99 TRACE_(SERIAL
, "SerialSetLineControl(COM%lu, Settings { %lu %lu %lu })\n",
100 DeviceExtension
->ComPort
, NewSettings
->StopBits
, NewSettings
->Parity
, NewSettings
->WordLength
);
102 /* Verify parameters */
103 switch (NewSettings
->WordLength
)
105 case 5: Lcr
|= SR_LCR_CS5
; break;
106 case 6: Lcr
|= SR_LCR_CS6
; break;
107 case 7: Lcr
|= SR_LCR_CS7
; break;
108 case 8: Lcr
|= SR_LCR_CS8
; break;
109 default: return STATUS_INVALID_PARAMETER
;
112 if (NewSettings
->WordLength
< 5 || NewSettings
->WordLength
> 8)
113 return STATUS_INVALID_PARAMETER
;
115 switch (NewSettings
->Parity
)
117 case NO_PARITY
: Lcr
|= SR_LCR_PNO
; break;
118 case ODD_PARITY
: Lcr
|= SR_LCR_POD
; break;
119 case EVEN_PARITY
: Lcr
|= SR_LCR_PEV
; break;
120 case MARK_PARITY
: Lcr
|= SR_LCR_PMK
; break;
121 case SPACE_PARITY
: Lcr
|= SR_LCR_PSP
; break;
122 default: return STATUS_INVALID_PARAMETER
;
125 switch (NewSettings
->StopBits
)
131 if (NewSettings
->WordLength
!= 5)
132 return STATUS_INVALID_PARAMETER
;
136 if (NewSettings
->WordLength
< 6 || NewSettings
->WordLength
> 8)
137 return STATUS_INVALID_PARAMETER
;
141 return STATUS_INVALID_PARAMETER
;
144 /* Update current parameters */
145 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
146 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
147 if (!NT_SUCCESS(Status
))
149 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
);
151 /* Read junk out of RBR */
152 READ_PORT_UCHAR(SER_RBR(ComPortBase
));
153 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
155 if (NT_SUCCESS(Status
))
156 DeviceExtension
->SerialLineControl
= *NewSettings
;
164 SerialClearPerfStats(IN PVOID SynchronizeContext
)
166 PSERIAL_DEVICE_EXTENSION DeviceExtension
= SynchronizeContext
;
167 ASSERT(DeviceExtension
);
168 RtlZeroMemory(&DeviceExtension
->SerialPerfStats
, sizeof(SERIALPERF_STATS
));
169 DeviceExtension
->BreakInterruptErrorCount
= 0;
176 SerialGetPerfStats(IN PVOID SynchronizeContext
)
178 PIRP pIrp
= SynchronizeContext
;
179 PSERIAL_DEVICE_EXTENSION pDeviceExtension
;
182 pDeviceExtension
= IoGetCurrentIrpStackLocation(pIrp
)->DeviceObject
->DeviceExtension
;
185 * we assume buffer is big enough to hold SerialPerfStats structure
186 * caller must verify this
188 RtlCopyMemory(pIrp
->AssociatedIrp
.SystemBuffer
,
189 &pDeviceExtension
->SerialPerfStats
,
190 sizeof(SERIALPERF_STATS
));
196 OUT PSERIAL_COMMPROP pCommProp
,
197 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
201 RtlZeroMemory(pCommProp
, sizeof(SERIAL_COMMPROP
));
203 if (!(pCommProp
->ProvSpec1
& COMMPROP_INITIALIZED
))
204 pCommProp
->PacketLength
= sizeof(SERIAL_COMMPROP
);
205 pCommProp
->PacketVersion
= 2;
206 pCommProp
->ServiceMask
= SERIAL_SP_SERIALCOMM
;
207 pCommProp
->MaxTxQueue
= pCommProp
->CurrentTxQueue
= DeviceExtension
->OutputBuffer
.Length
- 1;
208 pCommProp
->MaxRxQueue
= pCommProp
->CurrentRxQueue
= DeviceExtension
->InputBuffer
.Length
- 1;
209 pCommProp
->ProvSubType
= PST_RS232
;
210 pCommProp
->ProvCapabilities
= SERIAL_PCF_DTRDSR
| SERIAL_PCF_INTTIMEOUTS
| SERIAL_PCF_PARITY_CHECK
211 | SERIAL_PCF_RTSCTS
| SERIAL_PCF_SETXCHAR
| SERIAL_PCF_SPECIALCHARS
| SERIAL_PCF_TOTALTIMEOUTS
212 | SERIAL_PCF_XONXOFF
;
213 pCommProp
->SettableParams
= SERIAL_SP_BAUD
| SERIAL_SP_DATABITS
| SERIAL_SP_HANDSHAKING
214 | SERIAL_SP_PARITY
| SERIAL_SP_PARITY_CHECK
| SERIAL_SP_STOPBITS
;
216 /* SettableBaud is related to Uart type */
217 pCommProp
->SettableBaud
= SERIAL_BAUD_075
| SERIAL_BAUD_110
| SERIAL_BAUD_134_5
218 | SERIAL_BAUD_150
| SERIAL_BAUD_300
| SERIAL_BAUD_600
| SERIAL_BAUD_1200
219 | SERIAL_BAUD_1800
| SERIAL_BAUD_2400
| SERIAL_BAUD_4800
| SERIAL_BAUD_7200
220 | SERIAL_BAUD_9600
| SERIAL_BAUD_USER
;
221 pCommProp
->MaxBaud
= SERIAL_BAUD_USER
;
222 if (DeviceExtension
->UartType
>= Uart16450
)
224 pCommProp
->SettableBaud
|= SERIAL_BAUD_14400
| SERIAL_BAUD_19200
| SERIAL_BAUD_38400
;
226 if (DeviceExtension
->UartType
>= Uart16550
)
228 pCommProp
->SettableBaud
|= SERIAL_BAUD_56K
| SERIAL_BAUD_57600
| SERIAL_BAUD_115200
| SERIAL_BAUD_128K
;
231 pCommProp
->SettableData
= SERIAL_DATABITS_5
| SERIAL_DATABITS_6
| SERIAL_DATABITS_7
| SERIAL_DATABITS_8
;
232 pCommProp
->SettableStopParity
= SERIAL_STOPBITS_10
| SERIAL_STOPBITS_15
| SERIAL_STOPBITS_20
233 | SERIAL_PARITY_NONE
| SERIAL_PARITY_ODD
| SERIAL_PARITY_EVEN
| SERIAL_PARITY_MARK
| SERIAL_PARITY_SPACE
;
235 pCommProp
->ProvSpec2
= 0; /* Size of provider-specific data */
237 return STATUS_SUCCESS
;
242 OUT PSERIAL_STATUS pSerialStatus
,
243 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
247 ASSERT(pSerialStatus
);
248 RtlZeroMemory(pSerialStatus
, sizeof(SERIAL_STATUS
));
250 pSerialStatus
->Errors
= 0;
251 if (DeviceExtension
->BreakInterruptErrorCount
)
252 pSerialStatus
->Errors
|= SERIAL_ERROR_BREAK
;
253 if (DeviceExtension
->SerialPerfStats
.FrameErrorCount
)
254 pSerialStatus
->Errors
|= SERIAL_ERROR_FRAMING
;
255 if (DeviceExtension
->SerialPerfStats
.SerialOverrunErrorCount
)
256 pSerialStatus
->Errors
|= SERIAL_ERROR_OVERRUN
;
257 if (DeviceExtension
->SerialPerfStats
.BufferOverrunErrorCount
)
258 pSerialStatus
->Errors
|= SERIAL_ERROR_QUEUEOVERRUN
;
259 if (DeviceExtension
->SerialPerfStats
.ParityErrorCount
)
260 pSerialStatus
->Errors
|= SERIAL_ERROR_PARITY
;
262 pSerialStatus
->HoldReasons
= 0; /* FIXME */
264 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
265 pSerialStatus
->AmountInInQueue
= (DeviceExtension
->InputBuffer
.WritePosition
+ DeviceExtension
->InputBuffer
.Length
266 - DeviceExtension
->InputBuffer
.ReadPosition
) % DeviceExtension
->InputBuffer
.Length
;
267 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
269 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
270 pSerialStatus
->AmountInOutQueue
= (DeviceExtension
->OutputBuffer
.WritePosition
+ DeviceExtension
->OutputBuffer
.Length
271 - DeviceExtension
->OutputBuffer
.ReadPosition
) % DeviceExtension
->OutputBuffer
.Length
;
272 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
274 pSerialStatus
->EofReceived
= FALSE
; /* always FALSE */
275 pSerialStatus
->WaitForImmediate
= FALSE
; /* always FALSE */
277 return STATUS_SUCCESS
;
282 IN PDEVICE_OBJECT DeviceObject
,
285 PIO_STACK_LOCATION Stack
;
287 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
288 ULONG LengthIn
, LengthOut
;
289 ULONG_PTR Information
= 0;
290 PVOID BufferIn
, BufferOut
;
294 TRACE_(SERIAL
, "IRP_MJ_DEVICE_CONTROL dispatch\n");
296 Stack
= IoGetCurrentIrpStackLocation(Irp
);
297 LengthIn
= Stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
298 LengthOut
= Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
299 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
300 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
301 IoControlCode
= Stack
->Parameters
.DeviceIoControl
.IoControlCode
;
302 SerialGetUserBuffers(Irp
, IoControlCode
, &BufferIn
, &BufferOut
);
304 /* FIXME: need to probe buffers */
305 /* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */
306 switch (IoControlCode
)
308 case IOCTL_SERIAL_CLEAR_STATS
:
310 TRACE_(SERIAL
, "IOCTL_SERIAL_CLEAR_STATS\n");
311 KeSynchronizeExecution(
312 DeviceExtension
->Interrupt
,
313 SerialClearPerfStats
,
315 Status
= STATUS_SUCCESS
;
318 case IOCTL_SERIAL_CLR_DTR
:
320 TRACE_(SERIAL
, "IOCTL_SERIAL_CLR_DTR\n");
321 /* FIXME: If the handshake flow control of the device is configured to
322 * automatically use DTR, return STATUS_INVALID_PARAMETER */
323 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
324 if (NT_SUCCESS(Status
))
326 DeviceExtension
->MCR
&= ~SR_MCR_DTR
;
327 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
328 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
332 case IOCTL_SERIAL_CLR_RTS
:
334 TRACE_(SERIAL
, "IOCTL_SERIAL_CLR_RTS\n");
335 /* FIXME: If the handshake flow control of the device is configured to
336 * automatically use RTS, return STATUS_INVALID_PARAMETER */
337 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
338 if (NT_SUCCESS(Status
))
340 DeviceExtension
->MCR
&= ~SR_MCR_RTS
;
341 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
342 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
346 case IOCTL_SERIAL_CONFIG_SIZE
:
348 /* Obsolete on Microsoft Windows 2000+ */
350 TRACE_(SERIAL
, "IOCTL_SERIAL_CONFIG_SIZE\n");
351 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
352 Status
= STATUS_INVALID_PARAMETER
;
355 pConfigSize
= (PULONG
)BufferOut
;
357 Information
= sizeof(ULONG
);
358 Status
= STATUS_SUCCESS
;
362 case IOCTL_SERIAL_GET_BAUD_RATE
:
364 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_BAUD_RATE\n");
365 if (LengthOut
< sizeof(SERIAL_BAUD_RATE
))
366 Status
= STATUS_BUFFER_TOO_SMALL
;
367 else if (BufferOut
== NULL
)
368 Status
= STATUS_INVALID_PARAMETER
;
371 ((PSERIAL_BAUD_RATE
)BufferOut
)->BaudRate
= DeviceExtension
->BaudRate
;
372 Information
= sizeof(SERIAL_BAUD_RATE
);
373 Status
= STATUS_SUCCESS
;
377 case IOCTL_SERIAL_GET_CHARS
:
380 PSERIAL_CHARS pSerialChars
;
381 ERR_(SERIAL
, "IOCTL_SERIAL_GET_CHARS not implemented.\n");
382 if (LengthOut
< sizeof(SERIAL_CHARS
))
383 Status
= STATUS_BUFFER_TOO_SMALL
;
384 else if (BufferOut
== NULL
)
385 Status
= STATUS_INVALID_PARAMETER
;
388 pSerialChars
= (PSERIAL_CHARS
)BufferOut
;
389 pSerialChars
->EofChar
= 0;
390 pSerialChars
->ErrorChar
= 0;
391 pSerialChars
->BreakChar
= 0;
392 pSerialChars
->EventChar
= 0;
393 pSerialChars
->XonChar
= 0;
394 pSerialChars
->XoffChar
= 0;
395 Information
= sizeof(SERIAL_CHARS
);
396 Status
= STATUS_SUCCESS
;
400 case IOCTL_SERIAL_GET_COMMSTATUS
:
402 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_COMMSTATUS\n");
403 if (LengthOut
< sizeof(SERIAL_STATUS
))
404 Status
= STATUS_BUFFER_TOO_SMALL
;
405 else if (BufferOut
== NULL
)
406 Status
= STATUS_INVALID_PARAMETER
;
409 Status
= SerialGetCommStatus((PSERIAL_STATUS
)BufferOut
, DeviceExtension
);
410 Information
= sizeof(SERIAL_STATUS
);
414 case IOCTL_SERIAL_GET_DTRRTS
:
417 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_DTRRTS\n");
418 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
419 Status
= STATUS_INVALID_PARAMETER
;
422 pDtrRts
= (PULONG
)BufferOut
;
424 if (DeviceExtension
->MCR
& SR_MCR_DTR
)
425 *pDtrRts
|= SERIAL_DTR_STATE
;
426 if (DeviceExtension
->MCR
& SR_MCR_RTS
)
427 *pDtrRts
|= SERIAL_RTS_STATE
;
428 Information
= sizeof(ULONG
);
429 Status
= STATUS_SUCCESS
;
433 case IOCTL_SERIAL_GET_HANDFLOW
:
436 PSERIAL_HANDFLOW pSerialHandflow
;
437 ERR_(SERIAL
, "IOCTL_SERIAL_GET_HANDFLOW not implemented.\n");
438 if (LengthOut
< sizeof(SERIAL_HANDFLOW
))
439 Status
= STATUS_BUFFER_TOO_SMALL
;
440 else if (BufferOut
== NULL
)
441 Status
= STATUS_INVALID_PARAMETER
;
444 pSerialHandflow
= (PSERIAL_HANDFLOW
)BufferOut
;
445 pSerialHandflow
->ControlHandShake
= 0;
446 pSerialHandflow
->FlowReplace
= 0;
447 pSerialHandflow
->XonLimit
= 0;
448 pSerialHandflow
->XoffLimit
= 0;
449 Information
= sizeof(SERIAL_HANDFLOW
);
450 Status
= STATUS_SUCCESS
;
454 case IOCTL_SERIAL_GET_LINE_CONTROL
:
456 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_LINE_CONTROL\n");
457 if (LengthOut
< sizeof(SERIAL_LINE_CONTROL
))
458 Status
= STATUS_BUFFER_TOO_SMALL
;
459 else if (BufferOut
== NULL
)
460 Status
= STATUS_INVALID_PARAMETER
;
463 *((PSERIAL_LINE_CONTROL
)BufferOut
) = DeviceExtension
->SerialLineControl
;
464 Information
= sizeof(SERIAL_LINE_CONTROL
);
465 Status
= STATUS_SUCCESS
;
469 case IOCTL_SERIAL_GET_MODEM_CONTROL
:
472 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_MODEM_CONTROL\n");
473 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
474 Status
= STATUS_INVALID_PARAMETER
;
477 pMCR
= (PULONG
)BufferOut
;
478 *pMCR
= DeviceExtension
->MCR
;
479 Information
= sizeof(ULONG
);
480 Status
= STATUS_SUCCESS
;
484 case IOCTL_SERIAL_GET_MODEMSTATUS
:
487 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_MODEMSTATUS\n");
488 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
489 Status
= STATUS_INVALID_PARAMETER
;
492 pMSR
= (PULONG
)BufferOut
;
493 *pMSR
= DeviceExtension
->MSR
;
494 Information
= sizeof(ULONG
);
495 Status
= STATUS_SUCCESS
;
499 case IOCTL_SERIAL_GET_PROPERTIES
:
501 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_PROPERTIES\n");
502 if (LengthOut
< sizeof(SERIAL_COMMPROP
))
503 Status
= STATUS_BUFFER_TOO_SMALL
;
504 else if (BufferOut
== NULL
)
505 Status
= STATUS_INVALID_PARAMETER
;
508 Status
= SerialGetCommProp((PSERIAL_COMMPROP
)BufferOut
, DeviceExtension
);
509 Information
= sizeof(SERIAL_COMMPROP
);
513 case IOCTL_SERIAL_GET_STATS
:
515 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_STATS\n");
516 if (LengthOut
< sizeof(SERIALPERF_STATS
))
517 Status
= STATUS_BUFFER_TOO_SMALL
;
518 else if (BufferOut
== NULL
)
519 Status
= STATUS_INVALID_PARAMETER
;
522 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
523 SerialGetPerfStats
, Irp
);
524 Information
= sizeof(SERIALPERF_STATS
);
525 Status
= STATUS_SUCCESS
;
529 case IOCTL_SERIAL_GET_TIMEOUTS
:
531 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_TIMEOUTS\n");
532 if (LengthOut
!= sizeof(SERIAL_TIMEOUTS
) || BufferOut
== NULL
)
533 Status
= STATUS_INVALID_PARAMETER
;
536 *(PSERIAL_TIMEOUTS
)BufferOut
= DeviceExtension
->SerialTimeOuts
;
537 Information
= sizeof(SERIAL_TIMEOUTS
);
538 Status
= STATUS_SUCCESS
;
542 case IOCTL_SERIAL_GET_WAIT_MASK
:
545 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_WAIT_MASK\n");
546 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
547 Status
= STATUS_INVALID_PARAMETER
;
550 pWaitMask
= (PULONG
)BufferOut
;
551 *pWaitMask
= DeviceExtension
->WaitMask
;
552 Information
= sizeof(ULONG
);
553 Status
= STATUS_SUCCESS
;
557 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
560 ERR_(SERIAL
, "IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n");
561 Status
= STATUS_NOT_IMPLEMENTED
;
564 case IOCTL_SERIAL_LSRMST_INSERT
:
567 ERR_(SERIAL
, "IOCTL_SERIAL_LSRMST_INSERT not implemented.\n");
568 Status
= STATUS_NOT_IMPLEMENTED
;
571 case IOCTL_SERIAL_PURGE
:
574 TRACE_(SERIAL
, "IOCTL_SERIAL_PURGE\n");
575 /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
576 * should stop current request */
577 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
578 Status
= STATUS_INVALID_PARAMETER
;
581 ULONG PurgeMask
= *(PULONG
)BufferIn
;
583 Status
= STATUS_SUCCESS
;
584 /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
585 if (PurgeMask
& SERIAL_PURGE_RXCLEAR
)
587 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
588 DeviceExtension
->InputBuffer
.ReadPosition
= DeviceExtension
->InputBuffer
.WritePosition
= 0;
589 if (DeviceExtension
->UartType
>= Uart16550A
)
591 /* Clear also Uart FIFO */
592 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
593 if (NT_SUCCESS(Status
))
595 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_RCVR
);
596 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
599 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
602 if (PurgeMask
& SERIAL_PURGE_TXCLEAR
)
604 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
605 DeviceExtension
->OutputBuffer
.ReadPosition
= DeviceExtension
->OutputBuffer
.WritePosition
= 0;
606 if (DeviceExtension
->UartType
>= Uart16550A
)
608 /* Clear also Uart FIFO */
609 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
610 if (NT_SUCCESS(Status
))
612 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_XMIT
);
613 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
616 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
621 case IOCTL_SERIAL_RESET_DEVICE
:
624 ERR_(SERIAL
, "IOCTL_SERIAL_RESET_DEVICE not implemented.\n");
625 Status
= STATUS_NOT_IMPLEMENTED
;
628 case IOCTL_SERIAL_SET_BAUD_RATE
:
631 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_BAUD_RATE\n");
632 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
633 Status
= STATUS_INVALID_PARAMETER
;
636 pNewBaudRate
= (PULONG
)BufferIn
;
637 Status
= SerialSetBaudRate(DeviceExtension
, *pNewBaudRate
);
641 case IOCTL_SERIAL_SET_BREAK_OFF
:
644 ERR_(SERIAL
, "IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n");
645 Status
= STATUS_NOT_IMPLEMENTED
;
648 case IOCTL_SERIAL_SET_BREAK_ON
:
651 ERR_(SERIAL
, "IOCTL_SERIAL_SET_BREAK_ON not implemented.\n");
652 Status
= STATUS_NOT_IMPLEMENTED
;
655 case IOCTL_SERIAL_SET_CHARS
:
658 ERR_(SERIAL
, "IOCTL_SERIAL_SET_CHARS not implemented.\n");
659 Status
= STATUS_SUCCESS
;
662 case IOCTL_SERIAL_SET_DTR
:
664 /* FIXME: If the handshake flow control of the device is configured to
665 * automatically use DTR, return STATUS_INVALID_PARAMETER */
666 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_DTR\n");
667 if (!(DeviceExtension
->MCR
& SR_MCR_DTR
))
669 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
670 if (NT_SUCCESS(Status
))
672 DeviceExtension
->MCR
|= SR_MCR_DTR
;
673 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
674 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
678 Status
= STATUS_SUCCESS
;
681 case IOCTL_SERIAL_SET_FIFO_CONTROL
:
683 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_FIFO_CONTROL\n");
684 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
685 Status
= STATUS_INVALID_PARAMETER
;
688 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
689 if (NT_SUCCESS(Status
))
691 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), (UCHAR
)((*(PULONG
)BufferIn
) & 0xff));
692 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
697 case IOCTL_SERIAL_SET_HANDFLOW
:
700 ERR_(SERIAL
, "IOCTL_SERIAL_SET_HANDFLOW not implemented.\n");
701 Status
= STATUS_SUCCESS
;
704 case IOCTL_SERIAL_SET_LINE_CONTROL
:
706 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_LINE_CONTROL\n");
707 if (LengthIn
< sizeof(SERIAL_LINE_CONTROL
))
708 Status
= STATUS_BUFFER_TOO_SMALL
;
709 else if (BufferIn
== NULL
)
710 Status
= STATUS_INVALID_PARAMETER
;
712 Status
= SerialSetLineControl(DeviceExtension
, (PSERIAL_LINE_CONTROL
)BufferIn
);
715 case IOCTL_SERIAL_SET_MODEM_CONTROL
:
718 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_MODEM_CONTROL\n");
719 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
720 Status
= STATUS_INVALID_PARAMETER
;
723 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
724 if (NT_SUCCESS(Status
))
726 pMCR
= (PULONG
)BufferIn
;
727 DeviceExtension
->MCR
= (UCHAR
)(*pMCR
& 0xff);
728 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
729 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
734 case IOCTL_SERIAL_SET_QUEUE_SIZE
:
736 if (LengthIn
< sizeof(SERIAL_QUEUE_SIZE
))
737 return STATUS_BUFFER_TOO_SMALL
;
738 else if (BufferIn
== NULL
)
739 return STATUS_INVALID_PARAMETER
;
743 PSERIAL_QUEUE_SIZE NewQueueSize
= (PSERIAL_QUEUE_SIZE
)BufferIn
;
744 Status
= STATUS_SUCCESS
;
745 if (NewQueueSize
->InSize
> DeviceExtension
->InputBuffer
.Length
)
747 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
748 Status
= IncreaseCircularBufferSize(&DeviceExtension
->InputBuffer
, NewQueueSize
->InSize
);
749 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
751 if (NT_SUCCESS(Status
) && NewQueueSize
->OutSize
> DeviceExtension
->OutputBuffer
.Length
)
753 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
754 Status
= IncreaseCircularBufferSize(&DeviceExtension
->OutputBuffer
, NewQueueSize
->OutSize
);
755 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
760 case IOCTL_SERIAL_SET_RTS
:
762 /* FIXME: If the handshake flow control of the device is configured to
763 * automatically use DTR, return STATUS_INVALID_PARAMETER */
764 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_RTS\n");
765 if (!(DeviceExtension
->MCR
& SR_MCR_RTS
))
767 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
768 if (NT_SUCCESS(Status
))
770 DeviceExtension
->MCR
|= SR_MCR_RTS
;
771 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
772 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
776 Status
= STATUS_SUCCESS
;
779 case IOCTL_SERIAL_SET_TIMEOUTS
:
781 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_TIMEOUTS\n");
782 if (LengthIn
!= sizeof(SERIAL_TIMEOUTS
) || BufferIn
== NULL
)
783 Status
= STATUS_INVALID_PARAMETER
;
786 DeviceExtension
->SerialTimeOuts
= *(PSERIAL_TIMEOUTS
)BufferIn
;
787 Status
= STATUS_SUCCESS
;
791 case IOCTL_SERIAL_SET_WAIT_MASK
:
793 PULONG pWaitMask
= (PULONG
)BufferIn
;
794 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_WAIT_MASK\n");
796 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
797 Status
= STATUS_INVALID_PARAMETER
;
798 else if (DeviceExtension
->WaitOnMaskIrp
) /* FIXME: Race condition ; field may be currently in modification */
800 WARN_(SERIAL
, "An IRP is already currently processed\n");
801 Status
= STATUS_INVALID_PARAMETER
;
805 DeviceExtension
->WaitMask
= *pWaitMask
;
806 Status
= STATUS_SUCCESS
;
810 case IOCTL_SERIAL_SET_XOFF
:
813 ERR_(SERIAL
, "IOCTL_SERIAL_SET_XOFF not implemented.\n");
814 Status
= STATUS_NOT_IMPLEMENTED
;
817 case IOCTL_SERIAL_SET_XON
:
820 ERR_(SERIAL
, "IOCTL_SERIAL_SET_XON not implemented.\n");
821 Status
= STATUS_NOT_IMPLEMENTED
;
824 case IOCTL_SERIAL_WAIT_ON_MASK
:
827 TRACE_(SERIAL
, "IOCTL_SERIAL_WAIT_ON_MASK\n");
829 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
830 Status
= STATUS_INVALID_PARAMETER
;
833 IoMarkIrpPending(Irp
);
835 WaitingIrp
= InterlockedCompareExchangePointer(
836 (PVOID
*)&DeviceExtension
->WaitOnMaskIrp
,
840 /* Check if an Irp is already pending */
841 if (WaitingIrp
!= NULL
)
843 /* Unable to have a 2nd pending IRP for this IOCTL */
844 WARN_(SERIAL
, "Unable to pend a second IRP for IOCTL_SERIAL_WAIT_ON_MASK\n");
845 Irp
->IoStatus
.Information
= 0;
846 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
847 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
849 return STATUS_PENDING
;
853 case IOCTL_SERIAL_XOFF_COUNTER
:
856 ERR_(SERIAL
, "IOCTL_SERIAL_XOFF_COUNTER not implemented.\n");
857 Status
= STATUS_NOT_IMPLEMENTED
;
862 /* Pass Irp to lower driver */
863 TRACE_(SERIAL
, "Unknown IOCTL code 0x%x\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
864 IoSkipCurrentIrpStackLocation(Irp
);
865 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
869 Irp
->IoStatus
.Status
= Status
;
870 if (Status
== STATUS_PENDING
)
872 IoMarkIrpPending(Irp
);
876 Irp
->IoStatus
.Information
= Information
;
877 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);