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)
12 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
17 IN ULONG IoControlCode
,
25 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
28 *BufferIn
= *BufferOut
= Irp
->AssociatedIrp
.SystemBuffer
;
30 case METHOD_IN_DIRECT
:
31 case METHOD_OUT_DIRECT
:
32 *BufferIn
= Irp
->AssociatedIrp
.SystemBuffer
;
33 *BufferOut
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
36 *BufferIn
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.Type3InputBuffer
;
37 *BufferOut
= Irp
->UserBuffer
;
40 /* Should never happen */
49 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
,
54 PUCHAR ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
55 NTSTATUS Status
= STATUS_SUCCESS
;
58 return STATUS_INVALID_PARAMETER
;
60 divisor
= (USHORT
)(BAUD_CLOCK
/ (CLOCKS_PER_BIT
* NewBaudRate
));
61 BaudRate
= BAUD_CLOCK
/ (CLOCKS_PER_BIT
* divisor
);
63 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
64 if (NT_SUCCESS(Status
))
67 TRACE_(SERIAL
, "SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension
->ComPort
, BaudRate
);
68 /* Set Bit 7 of LCR to expose baud registers */
69 Lcr
= READ_PORT_UCHAR(SER_LCR(ComPortBase
));
70 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
| SR_LCR_DLAB
);
71 /* Write the baud rate */
72 WRITE_PORT_UCHAR(SER_DLL(ComPortBase
), divisor
& 0xff);
73 WRITE_PORT_UCHAR(SER_DLM(ComPortBase
), divisor
>> 8);
74 /* Switch back to normal registers */
75 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
);
77 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
80 if (NT_SUCCESS(Status
))
81 DeviceExtension
->BaudRate
= BaudRate
;
87 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
,
88 IN PSERIAL_LINE_CONTROL NewSettings
)
94 ASSERT(DeviceExtension
);
97 TRACE_(SERIAL
, "SerialSetLineControl(COM%lu, Settings { %lu %lu %lu })\n",
98 DeviceExtension
->ComPort
, NewSettings
->StopBits
, NewSettings
->Parity
, NewSettings
->WordLength
);
100 /* Verify parameters */
101 switch (NewSettings
->WordLength
)
103 case 5: Lcr
|= SR_LCR_CS5
; break;
104 case 6: Lcr
|= SR_LCR_CS6
; break;
105 case 7: Lcr
|= SR_LCR_CS7
; break;
106 case 8: Lcr
|= SR_LCR_CS8
; break;
107 default: return STATUS_INVALID_PARAMETER
;
110 if (NewSettings
->WordLength
< 5 || NewSettings
->WordLength
> 8)
111 return STATUS_INVALID_PARAMETER
;
113 switch (NewSettings
->Parity
)
115 case NO_PARITY
: Lcr
|= SR_LCR_PNO
; break;
116 case ODD_PARITY
: Lcr
|= SR_LCR_POD
; break;
117 case EVEN_PARITY
: Lcr
|= SR_LCR_PEV
; break;
118 case MARK_PARITY
: Lcr
|= SR_LCR_PMK
; break;
119 case SPACE_PARITY
: Lcr
|= SR_LCR_PSP
; break;
120 default: return STATUS_INVALID_PARAMETER
;
123 switch (NewSettings
->StopBits
)
129 if (NewSettings
->WordLength
!= 5)
130 return STATUS_INVALID_PARAMETER
;
134 if (NewSettings
->WordLength
< 6 || NewSettings
->WordLength
> 8)
135 return STATUS_INVALID_PARAMETER
;
139 return STATUS_INVALID_PARAMETER
;
142 /* Update current parameters */
143 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
144 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
145 if (!NT_SUCCESS(Status
))
147 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), Lcr
);
149 /* Read junk out of RBR */
150 READ_PORT_UCHAR(SER_RBR(ComPortBase
));
151 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
153 if (NT_SUCCESS(Status
))
154 DeviceExtension
->SerialLineControl
= *NewSettings
;
160 SerialClearPerfStats(
161 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
163 ASSERT(DeviceExtension
);
165 RtlZeroMemory(&DeviceExtension
->SerialPerfStats
, sizeof(SERIALPERF_STATS
));
166 DeviceExtension
->BreakInterruptErrorCount
= 0;
171 SerialGetPerfStats(IN PIRP pIrp
)
173 PSERIAL_DEVICE_EXTENSION pDeviceExtension
;
176 pDeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)
177 IoGetCurrentIrpStackLocation(pIrp
)->DeviceObject
->DeviceExtension
;
180 * we assume buffer is big enough to hold SerialPerfStats structure
181 * caller must verify this
184 pIrp
->AssociatedIrp
.SystemBuffer
,
185 &pDeviceExtension
->SerialPerfStats
,
186 sizeof(SERIALPERF_STATS
)
193 OUT PSERIAL_COMMPROP pCommProp
,
194 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
198 RtlZeroMemory(pCommProp
, sizeof(SERIAL_COMMPROP
));
200 if (!(pCommProp
->ProvSpec1
& COMMPROP_INITIALIZED
))
201 pCommProp
->PacketLength
= sizeof(SERIAL_COMMPROP
);
202 pCommProp
->PacketVersion
= 2;
203 pCommProp
->ServiceMask
= SERIAL_SP_SERIALCOMM
;
204 pCommProp
->MaxTxQueue
= pCommProp
->CurrentTxQueue
= DeviceExtension
->OutputBuffer
.Length
- 1;
205 pCommProp
->MaxRxQueue
= pCommProp
->CurrentRxQueue
= DeviceExtension
->InputBuffer
.Length
- 1;
206 pCommProp
->ProvSubType
= PST_RS232
;
207 pCommProp
->ProvCapabilities
= SERIAL_PCF_DTRDSR
| SERIAL_PCF_INTTIMEOUTS
| SERIAL_PCF_PARITY_CHECK
208 | SERIAL_PCF_RTSCTS
| SERIAL_PCF_SETXCHAR
| SERIAL_PCF_SPECIALCHARS
| SERIAL_PCF_TOTALTIMEOUTS
209 | SERIAL_PCF_XONXOFF
;
210 pCommProp
->SettableParams
= SERIAL_SP_BAUD
| SERIAL_SP_DATABITS
| SERIAL_SP_HANDSHAKING
211 | SERIAL_SP_PARITY
| SERIAL_SP_PARITY_CHECK
| SERIAL_SP_STOPBITS
;
213 /* SettableBaud is related to Uart type */
214 pCommProp
->SettableBaud
= SERIAL_BAUD_075
| SERIAL_BAUD_110
| SERIAL_BAUD_134_5
215 | SERIAL_BAUD_150
| SERIAL_BAUD_300
| SERIAL_BAUD_600
| SERIAL_BAUD_1200
216 | SERIAL_BAUD_1800
| SERIAL_BAUD_2400
| SERIAL_BAUD_4800
| SERIAL_BAUD_7200
217 | SERIAL_BAUD_9600
| SERIAL_BAUD_USER
;
218 pCommProp
->MaxBaud
= SERIAL_BAUD_USER
;
219 if (DeviceExtension
->UartType
>= Uart16450
)
221 pCommProp
->SettableBaud
|= SERIAL_BAUD_14400
| SERIAL_BAUD_19200
| SERIAL_BAUD_38400
;
223 if (DeviceExtension
->UartType
>= Uart16550
)
225 pCommProp
->SettableBaud
|= SERIAL_BAUD_56K
| SERIAL_BAUD_57600
| SERIAL_BAUD_115200
| SERIAL_BAUD_128K
;
228 pCommProp
->SettableData
= SERIAL_DATABITS_5
| SERIAL_DATABITS_6
| SERIAL_DATABITS_7
| SERIAL_DATABITS_8
;
229 pCommProp
->SettableStopParity
= SERIAL_STOPBITS_10
| SERIAL_STOPBITS_15
| SERIAL_STOPBITS_20
230 | SERIAL_PARITY_NONE
| SERIAL_PARITY_ODD
| SERIAL_PARITY_EVEN
| SERIAL_PARITY_MARK
| SERIAL_PARITY_SPACE
;
232 pCommProp
->ProvSpec2
= 0; /* Size of provider-specific data */
234 return STATUS_SUCCESS
;
239 OUT PSERIAL_STATUS pSerialStatus
,
240 IN PSERIAL_DEVICE_EXTENSION DeviceExtension
)
244 ASSERT(pSerialStatus
);
245 RtlZeroMemory(pSerialStatus
, sizeof(SERIAL_STATUS
));
247 pSerialStatus
->Errors
= 0;
248 if (DeviceExtension
->BreakInterruptErrorCount
)
249 pSerialStatus
->Errors
|= SERIAL_ERROR_BREAK
;
250 if (DeviceExtension
->SerialPerfStats
.FrameErrorCount
)
251 pSerialStatus
->Errors
|= SERIAL_ERROR_FRAMING
;
252 if (DeviceExtension
->SerialPerfStats
.SerialOverrunErrorCount
)
253 pSerialStatus
->Errors
|= SERIAL_ERROR_OVERRUN
;
254 if (DeviceExtension
->SerialPerfStats
.BufferOverrunErrorCount
)
255 pSerialStatus
->Errors
|= SERIAL_ERROR_QUEUEOVERRUN
;
256 if (DeviceExtension
->SerialPerfStats
.ParityErrorCount
)
257 pSerialStatus
->Errors
|= SERIAL_ERROR_PARITY
;
259 pSerialStatus
->HoldReasons
= 0; /* FIXME */
261 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
262 pSerialStatus
->AmountInInQueue
= (DeviceExtension
->InputBuffer
.WritePosition
+ DeviceExtension
->InputBuffer
.Length
263 - DeviceExtension
->InputBuffer
.ReadPosition
) % DeviceExtension
->InputBuffer
.Length
;
264 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
266 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
267 pSerialStatus
->AmountInOutQueue
= (DeviceExtension
->OutputBuffer
.WritePosition
+ DeviceExtension
->OutputBuffer
.Length
268 - DeviceExtension
->OutputBuffer
.ReadPosition
) % DeviceExtension
->OutputBuffer
.Length
;
269 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
271 pSerialStatus
->EofReceived
= FALSE
; /* always FALSE */
272 pSerialStatus
->WaitForImmediate
= FALSE
; /* always FALSE */
274 return STATUS_SUCCESS
;
279 IN PDEVICE_OBJECT DeviceObject
,
282 PIO_STACK_LOCATION Stack
;
284 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
285 ULONG LengthIn
, LengthOut
;
286 ULONG_PTR Information
= 0;
287 PVOID BufferIn
, BufferOut
;
291 TRACE_(SERIAL
, "IRP_MJ_DEVICE_CONTROL dispatch\n");
293 Stack
= IoGetCurrentIrpStackLocation(Irp
);
294 LengthIn
= Stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
295 LengthOut
= Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
296 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
297 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
298 IoControlCode
= Stack
->Parameters
.DeviceIoControl
.IoControlCode
;
299 SerialGetUserBuffers(Irp
, IoControlCode
, &BufferIn
, &BufferOut
);
301 /* FIXME: need to probe buffers */
302 /* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */
303 switch (IoControlCode
)
305 case IOCTL_SERIAL_CLEAR_STATS
:
307 TRACE_(SERIAL
, "IOCTL_SERIAL_CLEAR_STATS\n");
308 KeSynchronizeExecution(
309 DeviceExtension
->Interrupt
,
310 (PKSYNCHRONIZE_ROUTINE
)SerialClearPerfStats
,
312 Status
= STATUS_SUCCESS
;
315 case IOCTL_SERIAL_CLR_DTR
:
317 TRACE_(SERIAL
, "IOCTL_SERIAL_CLR_DTR\n");
318 /* FIXME: If the handshake flow control of the device is configured to
319 * automatically use DTR, return STATUS_INVALID_PARAMETER */
320 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
321 if (NT_SUCCESS(Status
))
323 DeviceExtension
->MCR
&= ~SR_MCR_DTR
;
324 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
325 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
329 case IOCTL_SERIAL_CLR_RTS
:
331 TRACE_(SERIAL
, "IOCTL_SERIAL_CLR_RTS\n");
332 /* FIXME: If the handshake flow control of the device is configured to
333 * automatically use RTS, return STATUS_INVALID_PARAMETER */
334 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
335 if (NT_SUCCESS(Status
))
337 DeviceExtension
->MCR
&= ~SR_MCR_RTS
;
338 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
339 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
343 case IOCTL_SERIAL_CONFIG_SIZE
:
345 /* Obsolete on Microsoft Windows 2000+ */
347 TRACE_(SERIAL
, "IOCTL_SERIAL_CONFIG_SIZE\n");
348 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
349 Status
= STATUS_INVALID_PARAMETER
;
352 pConfigSize
= (PULONG
)BufferOut
;
354 Information
= sizeof(ULONG
);
355 Status
= STATUS_SUCCESS
;
359 case IOCTL_SERIAL_GET_BAUD_RATE
:
361 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_BAUD_RATE\n");
362 if (LengthOut
< sizeof(SERIAL_BAUD_RATE
))
363 Status
= STATUS_BUFFER_TOO_SMALL
;
364 else if (BufferOut
== NULL
)
365 Status
= STATUS_INVALID_PARAMETER
;
368 ((PSERIAL_BAUD_RATE
)BufferOut
)->BaudRate
= DeviceExtension
->BaudRate
;
369 Information
= sizeof(SERIAL_BAUD_RATE
);
370 Status
= STATUS_SUCCESS
;
374 case IOCTL_SERIAL_GET_CHARS
:
377 PSERIAL_CHARS pSerialChars
;
378 ERR_(SERIAL
, "IOCTL_SERIAL_GET_CHARS not implemented.\n");
379 if (LengthOut
< sizeof(SERIAL_CHARS
))
380 Status
= STATUS_BUFFER_TOO_SMALL
;
381 else if (BufferOut
== NULL
)
382 Status
= STATUS_INVALID_PARAMETER
;
385 pSerialChars
= (PSERIAL_CHARS
)BufferOut
;
386 pSerialChars
->EofChar
= 0;
387 pSerialChars
->ErrorChar
= 0;
388 pSerialChars
->BreakChar
= 0;
389 pSerialChars
->EventChar
= 0;
390 pSerialChars
->XonChar
= 0;
391 pSerialChars
->XoffChar
= 0;
392 Information
= sizeof(SERIAL_CHARS
);
393 Status
= STATUS_SUCCESS
;
397 case IOCTL_SERIAL_GET_COMMSTATUS
:
399 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_COMMSTATUS\n");
400 if (LengthOut
< sizeof(SERIAL_STATUS
))
401 Status
= STATUS_BUFFER_TOO_SMALL
;
402 else if (BufferOut
== NULL
)
403 Status
= STATUS_INVALID_PARAMETER
;
406 Status
= SerialGetCommStatus((PSERIAL_STATUS
)BufferOut
, DeviceExtension
);
407 Information
= sizeof(SERIAL_STATUS
);
411 case IOCTL_SERIAL_GET_DTRRTS
:
414 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_DTRRTS\n");
415 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
416 Status
= STATUS_INVALID_PARAMETER
;
419 pDtrRts
= (PULONG
)BufferOut
;
421 if (DeviceExtension
->MCR
& SR_MCR_DTR
)
422 *pDtrRts
|= SERIAL_DTR_STATE
;
423 if (DeviceExtension
->MCR
& SR_MCR_RTS
)
424 *pDtrRts
|= SERIAL_RTS_STATE
;
425 Information
= sizeof(ULONG
);
426 Status
= STATUS_SUCCESS
;
430 case IOCTL_SERIAL_GET_HANDFLOW
:
433 PSERIAL_HANDFLOW pSerialHandflow
;
434 ERR_(SERIAL
, "IOCTL_SERIAL_GET_HANDFLOW not implemented.\n");
435 if (LengthOut
< sizeof(SERIAL_HANDFLOW
))
436 Status
= STATUS_BUFFER_TOO_SMALL
;
437 else if (BufferOut
== NULL
)
438 Status
= STATUS_INVALID_PARAMETER
;
441 pSerialHandflow
= (PSERIAL_HANDFLOW
)BufferOut
;
442 pSerialHandflow
->ControlHandShake
= 0;
443 pSerialHandflow
->FlowReplace
= 0;
444 pSerialHandflow
->XonLimit
= 0;
445 pSerialHandflow
->XoffLimit
= 0;
446 Information
= sizeof(SERIAL_HANDFLOW
);
447 Status
= STATUS_SUCCESS
;
451 case IOCTL_SERIAL_GET_LINE_CONTROL
:
453 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_LINE_CONTROL\n");
454 if (LengthOut
< sizeof(SERIAL_LINE_CONTROL
))
455 Status
= STATUS_BUFFER_TOO_SMALL
;
456 else if (BufferOut
== NULL
)
457 Status
= STATUS_INVALID_PARAMETER
;
460 *((PSERIAL_LINE_CONTROL
)BufferOut
) = DeviceExtension
->SerialLineControl
;
461 Information
= sizeof(SERIAL_LINE_CONTROL
);
462 Status
= STATUS_SUCCESS
;
466 case IOCTL_SERIAL_GET_MODEM_CONTROL
:
469 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_MODEM_CONTROL\n");
470 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
471 Status
= STATUS_INVALID_PARAMETER
;
474 pMCR
= (PULONG
)BufferOut
;
475 *pMCR
= DeviceExtension
->MCR
;
476 Information
= sizeof(ULONG
);
477 Status
= STATUS_SUCCESS
;
481 case IOCTL_SERIAL_GET_MODEMSTATUS
:
484 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_MODEMSTATUS\n");
485 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
486 Status
= STATUS_INVALID_PARAMETER
;
489 pMSR
= (PULONG
)BufferOut
;
490 *pMSR
= DeviceExtension
->MSR
;
491 Information
= sizeof(ULONG
);
492 Status
= STATUS_SUCCESS
;
496 case IOCTL_SERIAL_GET_PROPERTIES
:
498 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_PROPERTIES\n");
499 if (LengthOut
< sizeof(SERIAL_COMMPROP
))
500 Status
= STATUS_BUFFER_TOO_SMALL
;
501 else if (BufferOut
== NULL
)
502 Status
= STATUS_INVALID_PARAMETER
;
505 Status
= SerialGetCommProp((PSERIAL_COMMPROP
)BufferOut
, DeviceExtension
);
506 Information
= sizeof(SERIAL_COMMPROP
);
510 case IOCTL_SERIAL_GET_STATS
:
512 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_STATS\n");
513 if (LengthOut
< sizeof(SERIALPERF_STATS
))
514 Status
= STATUS_BUFFER_TOO_SMALL
;
515 else if (BufferOut
== NULL
)
516 Status
= STATUS_INVALID_PARAMETER
;
519 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
520 (PKSYNCHRONIZE_ROUTINE
)SerialGetPerfStats
, Irp
);
521 Information
= sizeof(SERIALPERF_STATS
);
522 Status
= STATUS_SUCCESS
;
526 case IOCTL_SERIAL_GET_TIMEOUTS
:
528 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_TIMEOUTS\n");
529 if (LengthOut
!= sizeof(SERIAL_TIMEOUTS
) || BufferOut
== NULL
)
530 Status
= STATUS_INVALID_PARAMETER
;
533 *(PSERIAL_TIMEOUTS
)BufferOut
= DeviceExtension
->SerialTimeOuts
;
534 Information
= sizeof(SERIAL_TIMEOUTS
);
535 Status
= STATUS_SUCCESS
;
539 case IOCTL_SERIAL_GET_WAIT_MASK
:
542 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_WAIT_MASK\n");
543 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
544 Status
= STATUS_INVALID_PARAMETER
;
547 pWaitMask
= (PULONG
)BufferOut
;
548 *pWaitMask
= DeviceExtension
->WaitMask
;
549 Information
= sizeof(ULONG
);
550 Status
= STATUS_SUCCESS
;
554 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
557 ERR_(SERIAL
, "IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n");
558 Status
= STATUS_NOT_IMPLEMENTED
;
561 case IOCTL_SERIAL_LSRMST_INSERT
:
564 ERR_(SERIAL
, "IOCTL_SERIAL_LSRMST_INSERT not implemented.\n");
565 Status
= STATUS_NOT_IMPLEMENTED
;
568 case IOCTL_SERIAL_PURGE
:
571 TRACE_(SERIAL
, "IOCTL_SERIAL_PURGE\n");
572 /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
573 * should stop current request */
574 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
575 Status
= STATUS_INVALID_PARAMETER
;
578 ULONG PurgeMask
= *(PULONG
)BufferIn
;
580 Status
= STATUS_SUCCESS
;
581 /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
582 if (PurgeMask
& SERIAL_PURGE_RXCLEAR
)
584 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
585 DeviceExtension
->InputBuffer
.ReadPosition
= DeviceExtension
->InputBuffer
.WritePosition
= 0;
586 if (DeviceExtension
->UartType
>= Uart16550A
)
588 /* Clear also Uart FIFO */
589 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
590 if (NT_SUCCESS(Status
))
592 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_RCVR
);
593 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
596 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
599 if (PurgeMask
& SERIAL_PURGE_TXCLEAR
)
601 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
602 DeviceExtension
->OutputBuffer
.ReadPosition
= DeviceExtension
->OutputBuffer
.WritePosition
= 0;
603 if (DeviceExtension
->UartType
>= Uart16550A
)
605 /* Clear also Uart FIFO */
606 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
607 if (NT_SUCCESS(Status
))
609 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_XMIT
);
610 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
613 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
618 case IOCTL_SERIAL_RESET_DEVICE
:
621 ERR_(SERIAL
, "IOCTL_SERIAL_RESET_DEVICE not implemented.\n");
622 Status
= STATUS_NOT_IMPLEMENTED
;
625 case IOCTL_SERIAL_SET_BAUD_RATE
:
628 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_BAUD_RATE\n");
629 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
630 Status
= STATUS_INVALID_PARAMETER
;
633 pNewBaudRate
= (PULONG
)BufferIn
;
634 Status
= SerialSetBaudRate(DeviceExtension
, *pNewBaudRate
);
638 case IOCTL_SERIAL_SET_BREAK_OFF
:
641 ERR_(SERIAL
, "IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n");
642 Status
= STATUS_NOT_IMPLEMENTED
;
645 case IOCTL_SERIAL_SET_BREAK_ON
:
648 ERR_(SERIAL
, "IOCTL_SERIAL_SET_BREAK_ON not implemented.\n");
649 Status
= STATUS_NOT_IMPLEMENTED
;
652 case IOCTL_SERIAL_SET_CHARS
:
655 ERR_(SERIAL
, "IOCTL_SERIAL_SET_CHARS not implemented.\n");
656 Status
= STATUS_SUCCESS
;
659 case IOCTL_SERIAL_SET_DTR
:
661 /* FIXME: If the handshake flow control of the device is configured to
662 * automatically use DTR, return STATUS_INVALID_PARAMETER */
663 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_DTR\n");
664 if (!(DeviceExtension
->MCR
& SR_MCR_DTR
))
666 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
667 if (NT_SUCCESS(Status
))
669 DeviceExtension
->MCR
|= SR_MCR_DTR
;
670 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
671 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
675 Status
= STATUS_SUCCESS
;
678 case IOCTL_SERIAL_SET_FIFO_CONTROL
:
680 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_FIFO_CONTROL\n");
681 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
682 Status
= STATUS_INVALID_PARAMETER
;
685 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
686 if (NT_SUCCESS(Status
))
688 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), (UCHAR
)((*(PULONG
)BufferIn
) & 0xff));
689 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
694 case IOCTL_SERIAL_SET_HANDFLOW
:
697 ERR_(SERIAL
, "IOCTL_SERIAL_SET_HANDFLOW not implemented.\n");
698 Status
= STATUS_SUCCESS
;
701 case IOCTL_SERIAL_SET_LINE_CONTROL
:
703 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_LINE_CONTROL\n");
704 if (LengthIn
< sizeof(SERIAL_LINE_CONTROL
))
705 Status
= STATUS_BUFFER_TOO_SMALL
;
706 else if (BufferIn
== NULL
)
707 Status
= STATUS_INVALID_PARAMETER
;
709 Status
= SerialSetLineControl(DeviceExtension
, (PSERIAL_LINE_CONTROL
)BufferIn
);
712 case IOCTL_SERIAL_SET_MODEM_CONTROL
:
715 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_MODEM_CONTROL\n");
716 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
717 Status
= STATUS_INVALID_PARAMETER
;
720 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
721 if (NT_SUCCESS(Status
))
723 pMCR
= (PULONG
)BufferIn
;
724 DeviceExtension
->MCR
= (UCHAR
)(*pMCR
& 0xff);
725 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
726 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
731 case IOCTL_SERIAL_SET_QUEUE_SIZE
:
733 if (LengthIn
< sizeof(SERIAL_QUEUE_SIZE
))
734 return STATUS_BUFFER_TOO_SMALL
;
735 else if (BufferIn
== NULL
)
736 return STATUS_INVALID_PARAMETER
;
740 PSERIAL_QUEUE_SIZE NewQueueSize
= (PSERIAL_QUEUE_SIZE
)BufferIn
;
741 Status
= STATUS_SUCCESS
;
742 if (NewQueueSize
->InSize
> DeviceExtension
->InputBuffer
.Length
)
744 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
745 Status
= IncreaseCircularBufferSize(&DeviceExtension
->InputBuffer
, NewQueueSize
->InSize
);
746 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
748 if (NT_SUCCESS(Status
) && NewQueueSize
->OutSize
> DeviceExtension
->OutputBuffer
.Length
)
750 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
751 Status
= IncreaseCircularBufferSize(&DeviceExtension
->OutputBuffer
, NewQueueSize
->OutSize
);
752 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
757 case IOCTL_SERIAL_SET_RTS
:
759 /* FIXME: If the handshake flow control of the device is configured to
760 * automatically use DTR, return STATUS_INVALID_PARAMETER */
761 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_RTS\n");
762 if (!(DeviceExtension
->MCR
& SR_MCR_RTS
))
764 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
765 if (NT_SUCCESS(Status
))
767 DeviceExtension
->MCR
|= SR_MCR_RTS
;
768 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
769 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
773 Status
= STATUS_SUCCESS
;
776 case IOCTL_SERIAL_SET_TIMEOUTS
:
778 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_TIMEOUTS\n");
779 if (LengthIn
!= sizeof(SERIAL_TIMEOUTS
) || BufferIn
== NULL
)
780 Status
= STATUS_INVALID_PARAMETER
;
783 DeviceExtension
->SerialTimeOuts
= *(PSERIAL_TIMEOUTS
)BufferIn
;
784 Status
= STATUS_SUCCESS
;
788 case IOCTL_SERIAL_SET_WAIT_MASK
:
790 PULONG pWaitMask
= (PULONG
)BufferIn
;
791 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_WAIT_MASK\n");
793 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
794 Status
= STATUS_INVALID_PARAMETER
;
795 else if (DeviceExtension
->WaitOnMaskIrp
) /* FIXME: Race condition ; field may be currently in modification */
797 WARN_(SERIAL
, "An IRP is already currently processed\n");
798 Status
= STATUS_INVALID_PARAMETER
;
802 DeviceExtension
->WaitMask
= *pWaitMask
;
803 Status
= STATUS_SUCCESS
;
807 case IOCTL_SERIAL_SET_XOFF
:
810 ERR_(SERIAL
, "IOCTL_SERIAL_SET_XOFF not implemented.\n");
811 Status
= STATUS_NOT_IMPLEMENTED
;
814 case IOCTL_SERIAL_SET_XON
:
817 ERR_(SERIAL
, "IOCTL_SERIAL_SET_XON not implemented.\n");
818 Status
= STATUS_NOT_IMPLEMENTED
;
821 case IOCTL_SERIAL_WAIT_ON_MASK
:
824 TRACE_(SERIAL
, "IOCTL_SERIAL_WAIT_ON_MASK\n");
826 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
827 Status
= STATUS_INVALID_PARAMETER
;
830 /* FIXME: Race condition here:
831 * If an interrupt comes before we can mark the Irp
832 * as pending, it might be possible to complete the
833 * Irp before pending it, leading to a crash! */
834 WaitingIrp
= InterlockedCompareExchangePointer(
835 (PVOID
)&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 Status
= STATUS_INVALID_PARAMETER
;
848 Status
= STATUS_PENDING
;
849 /* FIXME: immediately return if a wait event already occurred */
854 case IOCTL_SERIAL_XOFF_COUNTER
:
857 ERR_(SERIAL
, "IOCTL_SERIAL_XOFF_COUNTER not implemented.\n");
858 Status
= STATUS_NOT_IMPLEMENTED
;
863 /* Pass Irp to lower driver */
864 TRACE_(SERIAL
, "Unknown IOCTL code 0x%x\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
865 IoSkipCurrentIrpStackLocation(Irp
);
866 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
870 Irp
->IoStatus
.Status
= Status
;
871 if (Status
== STATUS_PENDING
)
873 IoMarkIrpPending(Irp
);
877 Irp
->IoStatus
.Information
= Information
;
878 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);