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
;
162 SerialClearPerfStats(
163 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
165 ASSERT(DeviceExtension
);
167 RtlZeroMemory(&DeviceExtension
->SerialPerfStats
, sizeof(SERIALPERF_STATS
));
168 DeviceExtension
->BreakInterruptErrorCount
= 0;
173 SerialGetPerfStats(IN PIRP pIrp
)
175 PSERIAL_DEVICE_EXTENSION pDeviceExtension
;
178 pDeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)
179 IoGetCurrentIrpStackLocation(pIrp
)->DeviceObject
->DeviceExtension
;
182 * we assume buffer is big enough to hold SerialPerfStats structure
183 * caller must verify this
186 pIrp
->AssociatedIrp
.SystemBuffer
,
187 &pDeviceExtension
->SerialPerfStats
,
188 sizeof(SERIALPERF_STATS
)
195 OUT PSERIAL_COMMPROP pCommProp
,
196 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
200 RtlZeroMemory(pCommProp
, sizeof(SERIAL_COMMPROP
));
202 if (!(pCommProp
->ProvSpec1
& COMMPROP_INITIALIZED
))
203 pCommProp
->PacketLength
= sizeof(SERIAL_COMMPROP
);
204 pCommProp
->PacketVersion
= 2;
205 pCommProp
->ServiceMask
= SERIAL_SP_SERIALCOMM
;
206 pCommProp
->MaxTxQueue
= pCommProp
->CurrentTxQueue
= DeviceExtension
->OutputBuffer
.Length
- 1;
207 pCommProp
->MaxRxQueue
= pCommProp
->CurrentRxQueue
= DeviceExtension
->InputBuffer
.Length
- 1;
208 pCommProp
->ProvSubType
= PST_RS232
;
209 pCommProp
->ProvCapabilities
= SERIAL_PCF_DTRDSR
| SERIAL_PCF_INTTIMEOUTS
| SERIAL_PCF_PARITY_CHECK
210 | SERIAL_PCF_RTSCTS
| SERIAL_PCF_SETXCHAR
| SERIAL_PCF_SPECIALCHARS
| SERIAL_PCF_TOTALTIMEOUTS
211 | SERIAL_PCF_XONXOFF
;
212 pCommProp
->SettableParams
= SERIAL_SP_BAUD
| SERIAL_SP_DATABITS
| SERIAL_SP_HANDSHAKING
213 | SERIAL_SP_PARITY
| SERIAL_SP_PARITY_CHECK
| SERIAL_SP_STOPBITS
;
215 /* SettableBaud is related to Uart type */
216 pCommProp
->SettableBaud
= SERIAL_BAUD_075
| SERIAL_BAUD_110
| SERIAL_BAUD_134_5
217 | SERIAL_BAUD_150
| SERIAL_BAUD_300
| SERIAL_BAUD_600
| SERIAL_BAUD_1200
218 | SERIAL_BAUD_1800
| SERIAL_BAUD_2400
| SERIAL_BAUD_4800
| SERIAL_BAUD_7200
219 | SERIAL_BAUD_9600
| SERIAL_BAUD_USER
;
220 pCommProp
->MaxBaud
= SERIAL_BAUD_USER
;
221 if (DeviceExtension
->UartType
>= Uart16450
)
223 pCommProp
->SettableBaud
|= SERIAL_BAUD_14400
| SERIAL_BAUD_19200
| SERIAL_BAUD_38400
;
225 if (DeviceExtension
->UartType
>= Uart16550
)
227 pCommProp
->SettableBaud
|= SERIAL_BAUD_56K
| SERIAL_BAUD_57600
| SERIAL_BAUD_115200
| SERIAL_BAUD_128K
;
230 pCommProp
->SettableData
= SERIAL_DATABITS_5
| SERIAL_DATABITS_6
| SERIAL_DATABITS_7
| SERIAL_DATABITS_8
;
231 pCommProp
->SettableStopParity
= SERIAL_STOPBITS_10
| SERIAL_STOPBITS_15
| SERIAL_STOPBITS_20
232 | SERIAL_PARITY_NONE
| SERIAL_PARITY_ODD
| SERIAL_PARITY_EVEN
| SERIAL_PARITY_MARK
| SERIAL_PARITY_SPACE
;
234 pCommProp
->ProvSpec2
= 0; /* Size of provider-specific data */
236 return STATUS_SUCCESS
;
241 OUT PSERIAL_STATUS pSerialStatus
,
242 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
246 ASSERT(pSerialStatus
);
247 RtlZeroMemory(pSerialStatus
, sizeof(SERIAL_STATUS
));
249 pSerialStatus
->Errors
= 0;
250 if (DeviceExtension
->BreakInterruptErrorCount
)
251 pSerialStatus
->Errors
|= SERIAL_ERROR_BREAK
;
252 if (DeviceExtension
->SerialPerfStats
.FrameErrorCount
)
253 pSerialStatus
->Errors
|= SERIAL_ERROR_FRAMING
;
254 if (DeviceExtension
->SerialPerfStats
.SerialOverrunErrorCount
)
255 pSerialStatus
->Errors
|= SERIAL_ERROR_OVERRUN
;
256 if (DeviceExtension
->SerialPerfStats
.BufferOverrunErrorCount
)
257 pSerialStatus
->Errors
|= SERIAL_ERROR_QUEUEOVERRUN
;
258 if (DeviceExtension
->SerialPerfStats
.ParityErrorCount
)
259 pSerialStatus
->Errors
|= SERIAL_ERROR_PARITY
;
261 pSerialStatus
->HoldReasons
= 0; /* FIXME */
263 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
264 pSerialStatus
->AmountInInQueue
= (DeviceExtension
->InputBuffer
.WritePosition
+ DeviceExtension
->InputBuffer
.Length
265 - DeviceExtension
->InputBuffer
.ReadPosition
) % DeviceExtension
->InputBuffer
.Length
;
266 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
268 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
269 pSerialStatus
->AmountInOutQueue
= (DeviceExtension
->OutputBuffer
.WritePosition
+ DeviceExtension
->OutputBuffer
.Length
270 - DeviceExtension
->OutputBuffer
.ReadPosition
) % DeviceExtension
->OutputBuffer
.Length
;
271 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
273 pSerialStatus
->EofReceived
= FALSE
; /* always FALSE */
274 pSerialStatus
->WaitForImmediate
= FALSE
; /* always FALSE */
276 return STATUS_SUCCESS
;
281 IN PDEVICE_OBJECT DeviceObject
,
284 PIO_STACK_LOCATION Stack
;
286 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
287 ULONG LengthIn
, LengthOut
;
288 ULONG_PTR Information
= 0;
289 PVOID BufferIn
, BufferOut
;
293 TRACE_(SERIAL
, "IRP_MJ_DEVICE_CONTROL dispatch\n");
295 Stack
= IoGetCurrentIrpStackLocation(Irp
);
296 LengthIn
= Stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
297 LengthOut
= Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
298 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
299 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
300 IoControlCode
= Stack
->Parameters
.DeviceIoControl
.IoControlCode
;
301 SerialGetUserBuffers(Irp
, IoControlCode
, &BufferIn
, &BufferOut
);
303 /* FIXME: need to probe buffers */
304 /* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */
305 switch (IoControlCode
)
307 case IOCTL_SERIAL_CLEAR_STATS
:
309 TRACE_(SERIAL
, "IOCTL_SERIAL_CLEAR_STATS\n");
310 KeSynchronizeExecution(
311 DeviceExtension
->Interrupt
,
312 (PKSYNCHRONIZE_ROUTINE
)SerialClearPerfStats
,
314 Status
= STATUS_SUCCESS
;
317 case IOCTL_SERIAL_CLR_DTR
:
319 TRACE_(SERIAL
, "IOCTL_SERIAL_CLR_DTR\n");
320 /* FIXME: If the handshake flow control of the device is configured to
321 * automatically use DTR, return STATUS_INVALID_PARAMETER */
322 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
323 if (NT_SUCCESS(Status
))
325 DeviceExtension
->MCR
&= ~SR_MCR_DTR
;
326 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
327 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
331 case IOCTL_SERIAL_CLR_RTS
:
333 TRACE_(SERIAL
, "IOCTL_SERIAL_CLR_RTS\n");
334 /* FIXME: If the handshake flow control of the device is configured to
335 * automatically use RTS, return STATUS_INVALID_PARAMETER */
336 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
337 if (NT_SUCCESS(Status
))
339 DeviceExtension
->MCR
&= ~SR_MCR_RTS
;
340 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
341 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
345 case IOCTL_SERIAL_CONFIG_SIZE
:
347 /* Obsolete on Microsoft Windows 2000+ */
349 TRACE_(SERIAL
, "IOCTL_SERIAL_CONFIG_SIZE\n");
350 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
351 Status
= STATUS_INVALID_PARAMETER
;
354 pConfigSize
= (PULONG
)BufferOut
;
356 Information
= sizeof(ULONG
);
357 Status
= STATUS_SUCCESS
;
361 case IOCTL_SERIAL_GET_BAUD_RATE
:
363 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_BAUD_RATE\n");
364 if (LengthOut
< sizeof(SERIAL_BAUD_RATE
))
365 Status
= STATUS_BUFFER_TOO_SMALL
;
366 else if (BufferOut
== NULL
)
367 Status
= STATUS_INVALID_PARAMETER
;
370 ((PSERIAL_BAUD_RATE
)BufferOut
)->BaudRate
= DeviceExtension
->BaudRate
;
371 Information
= sizeof(SERIAL_BAUD_RATE
);
372 Status
= STATUS_SUCCESS
;
376 case IOCTL_SERIAL_GET_CHARS
:
379 PSERIAL_CHARS pSerialChars
;
380 ERR_(SERIAL
, "IOCTL_SERIAL_GET_CHARS not implemented.\n");
381 if (LengthOut
< sizeof(SERIAL_CHARS
))
382 Status
= STATUS_BUFFER_TOO_SMALL
;
383 else if (BufferOut
== NULL
)
384 Status
= STATUS_INVALID_PARAMETER
;
387 pSerialChars
= (PSERIAL_CHARS
)BufferOut
;
388 pSerialChars
->EofChar
= 0;
389 pSerialChars
->ErrorChar
= 0;
390 pSerialChars
->BreakChar
= 0;
391 pSerialChars
->EventChar
= 0;
392 pSerialChars
->XonChar
= 0;
393 pSerialChars
->XoffChar
= 0;
394 Information
= sizeof(SERIAL_CHARS
);
395 Status
= STATUS_SUCCESS
;
399 case IOCTL_SERIAL_GET_COMMSTATUS
:
401 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_COMMSTATUS\n");
402 if (LengthOut
< sizeof(SERIAL_STATUS
))
403 Status
= STATUS_BUFFER_TOO_SMALL
;
404 else if (BufferOut
== NULL
)
405 Status
= STATUS_INVALID_PARAMETER
;
408 Status
= SerialGetCommStatus((PSERIAL_STATUS
)BufferOut
, DeviceExtension
);
409 Information
= sizeof(SERIAL_STATUS
);
413 case IOCTL_SERIAL_GET_DTRRTS
:
416 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_DTRRTS\n");
417 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
418 Status
= STATUS_INVALID_PARAMETER
;
421 pDtrRts
= (PULONG
)BufferOut
;
423 if (DeviceExtension
->MCR
& SR_MCR_DTR
)
424 *pDtrRts
|= SERIAL_DTR_STATE
;
425 if (DeviceExtension
->MCR
& SR_MCR_RTS
)
426 *pDtrRts
|= SERIAL_RTS_STATE
;
427 Information
= sizeof(ULONG
);
428 Status
= STATUS_SUCCESS
;
432 case IOCTL_SERIAL_GET_HANDFLOW
:
435 PSERIAL_HANDFLOW pSerialHandflow
;
436 ERR_(SERIAL
, "IOCTL_SERIAL_GET_HANDFLOW not implemented.\n");
437 if (LengthOut
< sizeof(SERIAL_HANDFLOW
))
438 Status
= STATUS_BUFFER_TOO_SMALL
;
439 else if (BufferOut
== NULL
)
440 Status
= STATUS_INVALID_PARAMETER
;
443 pSerialHandflow
= (PSERIAL_HANDFLOW
)BufferOut
;
444 pSerialHandflow
->ControlHandShake
= 0;
445 pSerialHandflow
->FlowReplace
= 0;
446 pSerialHandflow
->XonLimit
= 0;
447 pSerialHandflow
->XoffLimit
= 0;
448 Information
= sizeof(SERIAL_HANDFLOW
);
449 Status
= STATUS_SUCCESS
;
453 case IOCTL_SERIAL_GET_LINE_CONTROL
:
455 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_LINE_CONTROL\n");
456 if (LengthOut
< sizeof(SERIAL_LINE_CONTROL
))
457 Status
= STATUS_BUFFER_TOO_SMALL
;
458 else if (BufferOut
== NULL
)
459 Status
= STATUS_INVALID_PARAMETER
;
462 *((PSERIAL_LINE_CONTROL
)BufferOut
) = DeviceExtension
->SerialLineControl
;
463 Information
= sizeof(SERIAL_LINE_CONTROL
);
464 Status
= STATUS_SUCCESS
;
468 case IOCTL_SERIAL_GET_MODEM_CONTROL
:
471 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_MODEM_CONTROL\n");
472 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
473 Status
= STATUS_INVALID_PARAMETER
;
476 pMCR
= (PULONG
)BufferOut
;
477 *pMCR
= DeviceExtension
->MCR
;
478 Information
= sizeof(ULONG
);
479 Status
= STATUS_SUCCESS
;
483 case IOCTL_SERIAL_GET_MODEMSTATUS
:
486 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_MODEMSTATUS\n");
487 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
488 Status
= STATUS_INVALID_PARAMETER
;
491 pMSR
= (PULONG
)BufferOut
;
492 *pMSR
= DeviceExtension
->MSR
;
493 Information
= sizeof(ULONG
);
494 Status
= STATUS_SUCCESS
;
498 case IOCTL_SERIAL_GET_PROPERTIES
:
500 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_PROPERTIES\n");
501 if (LengthOut
< sizeof(SERIAL_COMMPROP
))
502 Status
= STATUS_BUFFER_TOO_SMALL
;
503 else if (BufferOut
== NULL
)
504 Status
= STATUS_INVALID_PARAMETER
;
507 Status
= SerialGetCommProp((PSERIAL_COMMPROP
)BufferOut
, DeviceExtension
);
508 Information
= sizeof(SERIAL_COMMPROP
);
512 case IOCTL_SERIAL_GET_STATS
:
514 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_STATS\n");
515 if (LengthOut
< sizeof(SERIALPERF_STATS
))
516 Status
= STATUS_BUFFER_TOO_SMALL
;
517 else if (BufferOut
== NULL
)
518 Status
= STATUS_INVALID_PARAMETER
;
521 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
522 (PKSYNCHRONIZE_ROUTINE
)SerialGetPerfStats
, Irp
);
523 Information
= sizeof(SERIALPERF_STATS
);
524 Status
= STATUS_SUCCESS
;
528 case IOCTL_SERIAL_GET_TIMEOUTS
:
530 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_TIMEOUTS\n");
531 if (LengthOut
!= sizeof(SERIAL_TIMEOUTS
) || BufferOut
== NULL
)
532 Status
= STATUS_INVALID_PARAMETER
;
535 *(PSERIAL_TIMEOUTS
)BufferOut
= DeviceExtension
->SerialTimeOuts
;
536 Information
= sizeof(SERIAL_TIMEOUTS
);
537 Status
= STATUS_SUCCESS
;
541 case IOCTL_SERIAL_GET_WAIT_MASK
:
544 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_WAIT_MASK\n");
545 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
546 Status
= STATUS_INVALID_PARAMETER
;
549 pWaitMask
= (PULONG
)BufferOut
;
550 *pWaitMask
= DeviceExtension
->WaitMask
;
551 Information
= sizeof(ULONG
);
552 Status
= STATUS_SUCCESS
;
556 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
559 ERR_(SERIAL
, "IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n");
560 Status
= STATUS_NOT_IMPLEMENTED
;
563 case IOCTL_SERIAL_LSRMST_INSERT
:
566 ERR_(SERIAL
, "IOCTL_SERIAL_LSRMST_INSERT not implemented.\n");
567 Status
= STATUS_NOT_IMPLEMENTED
;
570 case IOCTL_SERIAL_PURGE
:
573 TRACE_(SERIAL
, "IOCTL_SERIAL_PURGE\n");
574 /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
575 * should stop current request */
576 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
577 Status
= STATUS_INVALID_PARAMETER
;
580 ULONG PurgeMask
= *(PULONG
)BufferIn
;
582 Status
= STATUS_SUCCESS
;
583 /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
584 if (PurgeMask
& SERIAL_PURGE_RXCLEAR
)
586 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
587 DeviceExtension
->InputBuffer
.ReadPosition
= DeviceExtension
->InputBuffer
.WritePosition
= 0;
588 if (DeviceExtension
->UartType
>= Uart16550A
)
590 /* Clear also Uart FIFO */
591 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
592 if (NT_SUCCESS(Status
))
594 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_RCVR
);
595 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
598 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
601 if (PurgeMask
& SERIAL_PURGE_TXCLEAR
)
603 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
604 DeviceExtension
->OutputBuffer
.ReadPosition
= DeviceExtension
->OutputBuffer
.WritePosition
= 0;
605 if (DeviceExtension
->UartType
>= Uart16550A
)
607 /* Clear also Uart FIFO */
608 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
609 if (NT_SUCCESS(Status
))
611 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_XMIT
);
612 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
615 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
620 case IOCTL_SERIAL_RESET_DEVICE
:
623 ERR_(SERIAL
, "IOCTL_SERIAL_RESET_DEVICE not implemented.\n");
624 Status
= STATUS_NOT_IMPLEMENTED
;
627 case IOCTL_SERIAL_SET_BAUD_RATE
:
630 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_BAUD_RATE\n");
631 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
632 Status
= STATUS_INVALID_PARAMETER
;
635 pNewBaudRate
= (PULONG
)BufferIn
;
636 Status
= SerialSetBaudRate(DeviceExtension
, *pNewBaudRate
);
640 case IOCTL_SERIAL_SET_BREAK_OFF
:
643 ERR_(SERIAL
, "IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n");
644 Status
= STATUS_NOT_IMPLEMENTED
;
647 case IOCTL_SERIAL_SET_BREAK_ON
:
650 ERR_(SERIAL
, "IOCTL_SERIAL_SET_BREAK_ON not implemented.\n");
651 Status
= STATUS_NOT_IMPLEMENTED
;
654 case IOCTL_SERIAL_SET_CHARS
:
657 ERR_(SERIAL
, "IOCTL_SERIAL_SET_CHARS not implemented.\n");
658 Status
= STATUS_SUCCESS
;
661 case IOCTL_SERIAL_SET_DTR
:
663 /* FIXME: If the handshake flow control of the device is configured to
664 * automatically use DTR, return STATUS_INVALID_PARAMETER */
665 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_DTR\n");
666 if (!(DeviceExtension
->MCR
& SR_MCR_DTR
))
668 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
669 if (NT_SUCCESS(Status
))
671 DeviceExtension
->MCR
|= SR_MCR_DTR
;
672 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
673 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
677 Status
= STATUS_SUCCESS
;
680 case IOCTL_SERIAL_SET_FIFO_CONTROL
:
682 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_FIFO_CONTROL\n");
683 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
684 Status
= STATUS_INVALID_PARAMETER
;
687 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
688 if (NT_SUCCESS(Status
))
690 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), (UCHAR
)((*(PULONG
)BufferIn
) & 0xff));
691 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
696 case IOCTL_SERIAL_SET_HANDFLOW
:
699 ERR_(SERIAL
, "IOCTL_SERIAL_SET_HANDFLOW not implemented.\n");
700 Status
= STATUS_SUCCESS
;
703 case IOCTL_SERIAL_SET_LINE_CONTROL
:
705 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_LINE_CONTROL\n");
706 if (LengthIn
< sizeof(SERIAL_LINE_CONTROL
))
707 Status
= STATUS_BUFFER_TOO_SMALL
;
708 else if (BufferIn
== NULL
)
709 Status
= STATUS_INVALID_PARAMETER
;
711 Status
= SerialSetLineControl(DeviceExtension
, (PSERIAL_LINE_CONTROL
)BufferIn
);
714 case IOCTL_SERIAL_SET_MODEM_CONTROL
:
717 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_MODEM_CONTROL\n");
718 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
719 Status
= STATUS_INVALID_PARAMETER
;
722 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
723 if (NT_SUCCESS(Status
))
725 pMCR
= (PULONG
)BufferIn
;
726 DeviceExtension
->MCR
= (UCHAR
)(*pMCR
& 0xff);
727 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
728 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
733 case IOCTL_SERIAL_SET_QUEUE_SIZE
:
735 if (LengthIn
< sizeof(SERIAL_QUEUE_SIZE
))
736 return STATUS_BUFFER_TOO_SMALL
;
737 else if (BufferIn
== NULL
)
738 return STATUS_INVALID_PARAMETER
;
742 PSERIAL_QUEUE_SIZE NewQueueSize
= (PSERIAL_QUEUE_SIZE
)BufferIn
;
743 Status
= STATUS_SUCCESS
;
744 if (NewQueueSize
->InSize
> DeviceExtension
->InputBuffer
.Length
)
746 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
747 Status
= IncreaseCircularBufferSize(&DeviceExtension
->InputBuffer
, NewQueueSize
->InSize
);
748 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
750 if (NT_SUCCESS(Status
) && NewQueueSize
->OutSize
> DeviceExtension
->OutputBuffer
.Length
)
752 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
753 Status
= IncreaseCircularBufferSize(&DeviceExtension
->OutputBuffer
, NewQueueSize
->OutSize
);
754 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
759 case IOCTL_SERIAL_SET_RTS
:
761 /* FIXME: If the handshake flow control of the device is configured to
762 * automatically use DTR, return STATUS_INVALID_PARAMETER */
763 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_RTS\n");
764 if (!(DeviceExtension
->MCR
& SR_MCR_RTS
))
766 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
767 if (NT_SUCCESS(Status
))
769 DeviceExtension
->MCR
|= SR_MCR_RTS
;
770 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
771 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
775 Status
= STATUS_SUCCESS
;
778 case IOCTL_SERIAL_SET_TIMEOUTS
:
780 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_TIMEOUTS\n");
781 if (LengthIn
!= sizeof(SERIAL_TIMEOUTS
) || BufferIn
== NULL
)
782 Status
= STATUS_INVALID_PARAMETER
;
785 DeviceExtension
->SerialTimeOuts
= *(PSERIAL_TIMEOUTS
)BufferIn
;
786 Status
= STATUS_SUCCESS
;
790 case IOCTL_SERIAL_SET_WAIT_MASK
:
792 PULONG pWaitMask
= (PULONG
)BufferIn
;
793 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_WAIT_MASK\n");
795 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
796 Status
= STATUS_INVALID_PARAMETER
;
797 else if (DeviceExtension
->WaitOnMaskIrp
) /* FIXME: Race condition ; field may be currently in modification */
799 WARN_(SERIAL
, "An IRP is already currently processed\n");
800 Status
= STATUS_INVALID_PARAMETER
;
804 DeviceExtension
->WaitMask
= *pWaitMask
;
805 Status
= STATUS_SUCCESS
;
809 case IOCTL_SERIAL_SET_XOFF
:
812 ERR_(SERIAL
, "IOCTL_SERIAL_SET_XOFF not implemented.\n");
813 Status
= STATUS_NOT_IMPLEMENTED
;
816 case IOCTL_SERIAL_SET_XON
:
819 ERR_(SERIAL
, "IOCTL_SERIAL_SET_XON not implemented.\n");
820 Status
= STATUS_NOT_IMPLEMENTED
;
823 case IOCTL_SERIAL_WAIT_ON_MASK
:
826 TRACE_(SERIAL
, "IOCTL_SERIAL_WAIT_ON_MASK\n");
828 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
829 Status
= STATUS_INVALID_PARAMETER
;
832 IoMarkIrpPending(Irp
);
834 WaitingIrp
= InterlockedCompareExchangePointer(
835 &DeviceExtension
->WaitOnMaskIrp
,
839 /* Check if an Irp is already pending */
840 if (WaitingIrp
!= NULL
)
842 /* Unable to have a 2nd pending IRP for this IOCTL */
843 WARN_(SERIAL
, "Unable to pend a second IRP for IOCTL_SERIAL_WAIT_ON_MASK\n");
844 Irp
->IoStatus
.Information
= 0;
845 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
846 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
848 return STATUS_PENDING
;
852 case IOCTL_SERIAL_XOFF_COUNTER
:
855 ERR_(SERIAL
, "IOCTL_SERIAL_XOFF_COUNTER not implemented.\n");
856 Status
= STATUS_NOT_IMPLEMENTED
;
861 /* Pass Irp to lower driver */
862 TRACE_(SERIAL
, "Unknown IOCTL code 0x%x\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
863 IoSkipCurrentIrpStackLocation(Irp
);
864 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
868 Irp
->IoStatus
.Status
= Status
;
869 if (Status
== STATUS_PENDING
)
871 IoMarkIrpPending(Irp
);
875 Irp
->IoStatus
.Information
= Information
;
876 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);