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 ERR_(SERIAL
, "IOCTL_SERIAL_GET_CHARS not implemented.\n");
378 Status
= STATUS_NOT_IMPLEMENTED
;
381 case IOCTL_SERIAL_GET_COMMSTATUS
:
383 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_COMMSTATUS\n");
384 if (LengthOut
< sizeof(SERIAL_STATUS
))
385 Status
= STATUS_BUFFER_TOO_SMALL
;
386 else if (BufferOut
== NULL
)
387 Status
= STATUS_INVALID_PARAMETER
;
390 Status
= SerialGetCommStatus((PSERIAL_STATUS
)BufferOut
, DeviceExtension
);
391 Information
= sizeof(SERIAL_STATUS
);
395 case IOCTL_SERIAL_GET_DTRRTS
:
398 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_DTRRTS\n");
399 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
400 Status
= STATUS_INVALID_PARAMETER
;
403 pDtrRts
= (PULONG
)BufferOut
;
405 if (DeviceExtension
->MCR
& SR_MCR_DTR
)
406 *pDtrRts
|= SERIAL_DTR_STATE
;
407 if (DeviceExtension
->MCR
& SR_MCR_RTS
)
408 *pDtrRts
|= SERIAL_RTS_STATE
;
409 Information
= sizeof(ULONG
);
410 Status
= STATUS_SUCCESS
;
414 case IOCTL_SERIAL_GET_HANDFLOW
:
417 ERR_(SERIAL
, "IOCTL_SERIAL_GET_HANDFLOW not implemented.\n");
418 Status
= STATUS_NOT_IMPLEMENTED
;
421 case IOCTL_SERIAL_GET_LINE_CONTROL
:
423 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_LINE_CONTROL\n");
424 if (LengthOut
< sizeof(SERIAL_LINE_CONTROL
))
425 Status
= STATUS_BUFFER_TOO_SMALL
;
426 else if (BufferOut
== NULL
)
427 Status
= STATUS_INVALID_PARAMETER
;
430 *((PSERIAL_LINE_CONTROL
)BufferOut
) = DeviceExtension
->SerialLineControl
;
431 Information
= sizeof(SERIAL_LINE_CONTROL
);
432 Status
= STATUS_SUCCESS
;
436 case IOCTL_SERIAL_GET_MODEM_CONTROL
:
439 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_MODEM_CONTROL\n");
440 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
441 Status
= STATUS_INVALID_PARAMETER
;
444 pMCR
= (PULONG
)BufferOut
;
445 *pMCR
= DeviceExtension
->MCR
;
446 Information
= sizeof(ULONG
);
447 Status
= STATUS_SUCCESS
;
451 case IOCTL_SERIAL_GET_MODEMSTATUS
:
454 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_MODEMSTATUS\n");
455 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
456 Status
= STATUS_INVALID_PARAMETER
;
459 pMSR
= (PULONG
)BufferOut
;
460 *pMSR
= DeviceExtension
->MSR
;
461 Information
= sizeof(ULONG
);
462 Status
= STATUS_SUCCESS
;
466 case IOCTL_SERIAL_GET_PROPERTIES
:
468 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_PROPERTIES\n");
469 if (LengthOut
< sizeof(SERIAL_COMMPROP
))
470 Status
= STATUS_BUFFER_TOO_SMALL
;
471 else if (BufferOut
== NULL
)
472 Status
= STATUS_INVALID_PARAMETER
;
475 Status
= SerialGetCommProp((PSERIAL_COMMPROP
)BufferOut
, DeviceExtension
);
476 Information
= sizeof(SERIAL_COMMPROP
);
480 case IOCTL_SERIAL_GET_STATS
:
482 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_STATS\n");
483 if (LengthOut
< sizeof(SERIALPERF_STATS
))
484 Status
= STATUS_BUFFER_TOO_SMALL
;
485 else if (BufferOut
== NULL
)
486 Status
= STATUS_INVALID_PARAMETER
;
489 KeSynchronizeExecution(DeviceExtension
->Interrupt
,
490 (PKSYNCHRONIZE_ROUTINE
)SerialGetPerfStats
, Irp
);
491 Information
= sizeof(SERIALPERF_STATS
);
492 Status
= STATUS_SUCCESS
;
496 case IOCTL_SERIAL_GET_TIMEOUTS
:
498 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_TIMEOUTS\n");
499 if (LengthOut
!= sizeof(SERIAL_TIMEOUTS
) || BufferOut
== NULL
)
500 Status
= STATUS_INVALID_PARAMETER
;
503 *(PSERIAL_TIMEOUTS
)BufferOut
= DeviceExtension
->SerialTimeOuts
;
504 Information
= sizeof(SERIAL_TIMEOUTS
);
505 Status
= STATUS_SUCCESS
;
509 case IOCTL_SERIAL_GET_WAIT_MASK
:
512 TRACE_(SERIAL
, "IOCTL_SERIAL_GET_WAIT_MASK\n");
513 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
514 Status
= STATUS_INVALID_PARAMETER
;
517 pWaitMask
= (PULONG
)BufferOut
;
518 *pWaitMask
= DeviceExtension
->WaitMask
;
519 Information
= sizeof(ULONG
);
520 Status
= STATUS_SUCCESS
;
524 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
527 ERR_(SERIAL
, "IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n");
528 Status
= STATUS_NOT_IMPLEMENTED
;
531 case IOCTL_SERIAL_LSRMST_INSERT
:
534 ERR_(SERIAL
, "IOCTL_SERIAL_LSRMST_INSERT not implemented.\n");
535 Status
= STATUS_NOT_IMPLEMENTED
;
538 case IOCTL_SERIAL_PURGE
:
541 TRACE_(SERIAL
, "IOCTL_SERIAL_PURGE\n");
542 /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
543 * should stop current request */
544 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
545 Status
= STATUS_INVALID_PARAMETER
;
548 ULONG PurgeMask
= *(PULONG
)BufferIn
;
550 Status
= STATUS_SUCCESS
;
551 /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
552 if (PurgeMask
& SERIAL_PURGE_RXCLEAR
)
554 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
555 DeviceExtension
->InputBuffer
.ReadPosition
= DeviceExtension
->InputBuffer
.WritePosition
= 0;
556 if (DeviceExtension
->UartType
>= Uart16550A
)
558 /* Clear also Uart FIFO */
559 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
560 if (NT_SUCCESS(Status
))
562 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_RCVR
);
563 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
566 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
569 if (PurgeMask
& SERIAL_PURGE_TXCLEAR
)
571 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
572 DeviceExtension
->OutputBuffer
.ReadPosition
= DeviceExtension
->OutputBuffer
.WritePosition
= 0;
573 if (DeviceExtension
->UartType
>= Uart16550A
)
575 /* Clear also Uart FIFO */
576 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
577 if (NT_SUCCESS(Status
))
579 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), SR_FCR_CLEAR_XMIT
);
580 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
583 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
588 case IOCTL_SERIAL_RESET_DEVICE
:
591 ERR_(SERIAL
, "IOCTL_SERIAL_RESET_DEVICE not implemented.\n");
592 Status
= STATUS_NOT_IMPLEMENTED
;
595 case IOCTL_SERIAL_SET_BAUD_RATE
:
598 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_BAUD_RATE\n");
599 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
600 Status
= STATUS_INVALID_PARAMETER
;
603 pNewBaudRate
= (PULONG
)BufferIn
;
604 Status
= SerialSetBaudRate(DeviceExtension
, *pNewBaudRate
);
608 case IOCTL_SERIAL_SET_BREAK_OFF
:
611 ERR_(SERIAL
, "IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n");
612 Status
= STATUS_NOT_IMPLEMENTED
;
615 case IOCTL_SERIAL_SET_BREAK_ON
:
618 ERR_(SERIAL
, "IOCTL_SERIAL_SET_BREAK_ON not implemented.\n");
619 Status
= STATUS_NOT_IMPLEMENTED
;
622 case IOCTL_SERIAL_SET_CHARS
:
625 ERR_(SERIAL
, "IOCTL_SERIAL_SET_CHARS not implemented.\n");
626 Status
= STATUS_NOT_IMPLEMENTED
;
629 case IOCTL_SERIAL_SET_DTR
:
631 /* FIXME: If the handshake flow control of the device is configured to
632 * automatically use DTR, return STATUS_INVALID_PARAMETER */
633 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_DTR\n");
634 if (!(DeviceExtension
->MCR
& SR_MCR_DTR
))
636 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
637 if (NT_SUCCESS(Status
))
639 DeviceExtension
->MCR
|= SR_MCR_DTR
;
640 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
641 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
645 Status
= STATUS_SUCCESS
;
648 case IOCTL_SERIAL_SET_FIFO_CONTROL
:
650 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_FIFO_CONTROL\n");
651 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
652 Status
= STATUS_INVALID_PARAMETER
;
655 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
656 if (NT_SUCCESS(Status
))
658 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
), (UCHAR
)((*(PULONG
)BufferIn
) & 0xff));
659 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
664 case IOCTL_SERIAL_SET_HANDFLOW
:
667 ERR_(SERIAL
, "IOCTL_SERIAL_SET_HANDFLOW not implemented.\n");
668 Status
= STATUS_NOT_IMPLEMENTED
;
671 case IOCTL_SERIAL_SET_LINE_CONTROL
:
673 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_LINE_CONTROL\n");
674 if (LengthIn
< sizeof(SERIAL_LINE_CONTROL
))
675 Status
= STATUS_BUFFER_TOO_SMALL
;
676 else if (BufferIn
== NULL
)
677 Status
= STATUS_INVALID_PARAMETER
;
679 Status
= SerialSetLineControl(DeviceExtension
, (PSERIAL_LINE_CONTROL
)BufferIn
);
682 case IOCTL_SERIAL_SET_MODEM_CONTROL
:
685 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_MODEM_CONTROL\n");
686 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
687 Status
= STATUS_INVALID_PARAMETER
;
690 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
691 if (NT_SUCCESS(Status
))
693 pMCR
= (PULONG
)BufferIn
;
694 DeviceExtension
->MCR
= (UCHAR
)(*pMCR
& 0xff);
695 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
696 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
701 case IOCTL_SERIAL_SET_QUEUE_SIZE
:
703 if (LengthIn
< sizeof(SERIAL_QUEUE_SIZE
))
704 return STATUS_BUFFER_TOO_SMALL
;
705 else if (BufferIn
== NULL
)
706 return STATUS_INVALID_PARAMETER
;
710 PSERIAL_QUEUE_SIZE NewQueueSize
= (PSERIAL_QUEUE_SIZE
)BufferIn
;
711 Status
= STATUS_SUCCESS
;
712 if (NewQueueSize
->InSize
> DeviceExtension
->InputBuffer
.Length
)
714 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
715 Status
= IncreaseCircularBufferSize(&DeviceExtension
->InputBuffer
, NewQueueSize
->InSize
);
716 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
718 if (NT_SUCCESS(Status
) && NewQueueSize
->OutSize
> DeviceExtension
->OutputBuffer
.Length
)
720 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
721 Status
= IncreaseCircularBufferSize(&DeviceExtension
->OutputBuffer
, NewQueueSize
->OutSize
);
722 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
727 case IOCTL_SERIAL_SET_RTS
:
729 /* FIXME: If the handshake flow control of the device is configured to
730 * automatically use DTR, return STATUS_INVALID_PARAMETER */
731 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_RTS\n");
732 if (!(DeviceExtension
->MCR
& SR_MCR_RTS
))
734 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
735 if (NT_SUCCESS(Status
))
737 DeviceExtension
->MCR
|= SR_MCR_RTS
;
738 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
739 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, ULongToPtr(DeviceExtension
->ComPort
));
743 Status
= STATUS_SUCCESS
;
746 case IOCTL_SERIAL_SET_TIMEOUTS
:
748 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_TIMEOUTS\n");
749 if (LengthIn
!= sizeof(SERIAL_TIMEOUTS
) || BufferIn
== NULL
)
750 Status
= STATUS_INVALID_PARAMETER
;
753 DeviceExtension
->SerialTimeOuts
= *(PSERIAL_TIMEOUTS
)BufferIn
;
754 Status
= STATUS_SUCCESS
;
758 case IOCTL_SERIAL_SET_WAIT_MASK
:
760 PULONG pWaitMask
= (PULONG
)BufferIn
;
761 TRACE_(SERIAL
, "IOCTL_SERIAL_SET_WAIT_MASK\n");
763 if (LengthIn
!= sizeof(ULONG
) || BufferIn
== NULL
)
764 Status
= STATUS_INVALID_PARAMETER
;
765 else if (DeviceExtension
->WaitOnMaskIrp
) /* FIXME: Race condition ; field may be currently in modification */
767 WARN_(SERIAL
, "An IRP is already currently processed\n");
768 Status
= STATUS_INVALID_PARAMETER
;
772 DeviceExtension
->WaitMask
= *pWaitMask
;
773 Status
= STATUS_SUCCESS
;
777 case IOCTL_SERIAL_SET_XOFF
:
780 ERR_(SERIAL
, "IOCTL_SERIAL_SET_XOFF not implemented.\n");
781 Status
= STATUS_NOT_IMPLEMENTED
;
784 case IOCTL_SERIAL_SET_XON
:
787 ERR_(SERIAL
, "IOCTL_SERIAL_SET_XON not implemented.\n");
788 Status
= STATUS_NOT_IMPLEMENTED
;
791 case IOCTL_SERIAL_WAIT_ON_MASK
:
794 TRACE_(SERIAL
, "IOCTL_SERIAL_WAIT_ON_MASK\n");
796 if (LengthOut
!= sizeof(ULONG
) || BufferOut
== NULL
)
797 Status
= STATUS_INVALID_PARAMETER
;
800 /* FIXME: Race condition here:
801 * If an interrupt comes before we can mark the Irp
802 * as pending, it might be possible to complete the
803 * Irp before pending it, leading to a crash! */
804 WaitingIrp
= InterlockedCompareExchangePointer(
805 (PVOID
)&DeviceExtension
->WaitOnMaskIrp
,
809 /* Check if an Irp is already pending */
810 if (WaitingIrp
!= NULL
)
812 /* Unable to have a 2nd pending IRP for this IOCTL */
813 WARN_(SERIAL
, "Unable to pend a second IRP for IOCTL_SERIAL_WAIT_ON_MASK\n");
814 Status
= STATUS_INVALID_PARAMETER
;
818 Status
= STATUS_PENDING
;
819 /* FIXME: immediately return if a wait event already occurred */
824 case IOCTL_SERIAL_XOFF_COUNTER
:
827 ERR_(SERIAL
, "IOCTL_SERIAL_XOFF_COUNTER not implemented.\n");
828 Status
= STATUS_NOT_IMPLEMENTED
;
833 /* Pass Irp to lower driver */
834 TRACE_(SERIAL
, "Unknown IOCTL code 0x%x\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
835 IoSkipCurrentIrpStackLocation(Irp
);
836 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
840 Irp
->IoStatus
.Status
= Status
;
841 if (Status
== STATUS_PENDING
)
843 IoMarkIrpPending(Irp
);
847 Irp
->IoStatus
.Information
= Information
;
848 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);