2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Serial port driver
4 * FILE: drivers/dd/serial/misc.c
5 * PURPOSE: Misceallenous operations
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
9 /* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */
13 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion
;
16 ForwardIrpAndWaitCompletion(
17 IN PDEVICE_OBJECT DeviceObject
,
21 if (Irp
->PendingReturned
)
22 KeSetEvent((PKEVENT
)Context
, IO_NO_INCREMENT
, FALSE
);
23 return STATUS_MORE_PROCESSING_REQUIRED
;
28 IN PDEVICE_OBJECT DeviceObject
,
31 PDEVICE_OBJECT LowerDevice
= ((PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
37 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
38 IoCopyCurrentIrpStackLocationToNext(Irp
);
40 TRACE_(SERIAL
, "Calling lower device %p\n", LowerDevice
);
41 IoSetCompletionRoutine(Irp
, ForwardIrpAndWaitCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
43 Status
= IoCallDriver(LowerDevice
, Irp
);
44 if (Status
== STATUS_PENDING
)
46 Status
= KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
47 if (NT_SUCCESS(Status
))
48 Status
= Irp
->IoStatus
.Status
;
56 IN PDEVICE_OBJECT DeviceObject
,
59 PDEVICE_OBJECT LowerDevice
= ((PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
63 IoSkipCurrentIrpStackLocation(Irp
);
64 return IoCallDriver(LowerDevice
, Irp
);
70 IN PVOID pDeviceExtension
, // real type PSERIAL_DEVICE_EXTENSION
74 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
81 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)pDeviceExtension
;
82 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
84 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
85 while (READ_PORT_UCHAR(SER_LSR(ComPortBase
)) & SR_LSR_DATA_RECEIVED
)
87 Byte
= READ_PORT_UCHAR(SER_RBR(ComPortBase
));
88 INFO_(SERIAL
, "Byte received on COM%lu: 0x%02x\n",
89 DeviceExtension
->ComPort
, Byte
);
90 Status
= PushCircularBufferEntry(&DeviceExtension
->InputBuffer
, Byte
);
91 if (NT_SUCCESS(Status
))
92 DeviceExtension
->SerialPerfStats
.ReceivedCount
++;
94 DeviceExtension
->SerialPerfStats
.BufferOverrunErrorCount
++;
96 KeSetEvent(&DeviceExtension
->InputBufferNotEmpty
, 0, FALSE
);
97 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
99 /* allow new interrupts */
100 IER
= READ_PORT_UCHAR(SER_IER(ComPortBase
));
101 WRITE_PORT_UCHAR(SER_IER(ComPortBase
), IER
| SR_IER_DATA_RECEIVED
);
107 IN PVOID pDeviceExtension
, // real type PSERIAL_DEVICE_EXTENSION
111 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
118 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)pDeviceExtension
;
119 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
121 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
122 while (!IsCircularBufferEmpty(&DeviceExtension
->OutputBuffer
)
123 && READ_PORT_UCHAR(SER_LSR(ComPortBase
)) & SR_LSR_THR_EMPTY
)
125 Status
= PopCircularBufferEntry(&DeviceExtension
->OutputBuffer
, &Byte
);
126 if (!NT_SUCCESS(Status
))
128 WRITE_PORT_UCHAR(SER_THR(ComPortBase
), Byte
);
129 INFO_(SERIAL
, "Byte sent to COM%lu: 0x%02x\n",
130 DeviceExtension
->ComPort
, Byte
);
131 DeviceExtension
->SerialPerfStats
.TransmittedCount
++;
133 if (!IsCircularBufferEmpty(&DeviceExtension
->OutputBuffer
))
135 /* allow new interrupts */
136 IER
= READ_PORT_UCHAR(SER_IER(ComPortBase
));
137 WRITE_PORT_UCHAR(SER_IER(ComPortBase
), IER
| SR_IER_THR_EMPTY
);
139 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
145 IN PVOID pDeviceExtension
, // real type PSERIAL_DEVICE_EXTENSION
146 IN PVOID pIrp
, // real type PIRP
149 IoCompleteRequest((PIRP
)pIrp
, IO_NO_INCREMENT
);
153 SerialInterruptService(
154 IN PKINTERRUPT Interrupt
,
155 IN OUT PVOID ServiceContext
)
157 PDEVICE_OBJECT DeviceObject
;
158 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
164 /* FIXME: sometimes, produce SERIAL_EV_RXFLAG event */
166 DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
167 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
168 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
170 Iir
= READ_PORT_UCHAR(SER_IIR(ComPortBase
));
173 Iir
&= SR_IIR_ID_MASK
;
174 if ((Iir
& SR_IIR_SELF
) != 0) { return FALSE
; }
178 case SR_IIR_MSR_CHANGE
:
181 TRACE_(SERIAL
, "SR_IIR_MSR_CHANGE\n");
183 MSR
= READ_PORT_UCHAR(SER_MSR(ComPortBase
));
184 if (MSR
& SR_MSR_CTS_CHANGED
)
186 if (MSR
& SR_MSR_CTS
)
187 KeInsertQueueDpc(&DeviceExtension
->SendByteDpc
, NULL
, NULL
);
190 ; /* FIXME: stop transmission */
192 Events
|= SERIAL_EV_CTS
;
194 if (MSR
& SR_MSR_DSR_CHANGED
)
196 if (MSR
& SR_MSR_DSR
)
197 KeInsertQueueDpc(&DeviceExtension
->ReceivedByteDpc
, NULL
, NULL
);
200 ; /* FIXME: stop reception */
202 Events
|= SERIAL_EV_DSR
;
204 if (MSR
& SR_MSR_RI_CHANGED
)
206 INFO_(SERIAL
, "SR_MSR_RI_CHANGED changed: now %d\n", MSR
& SI_MSR_RI
);
207 Events
|= SERIAL_EV_RING
;
209 if (MSR
& SR_MSR_DCD_CHANGED
)
211 INFO_(SERIAL
, "SR_MSR_DCD_CHANGED changed: now %d\n", MSR
& SR_MSR_DCD
);
212 Events
|= SERIAL_EV_RLSD
;
214 IER
= READ_PORT_UCHAR(SER_IER(ComPortBase
));
215 WRITE_PORT_UCHAR(SER_IER(ComPortBase
), IER
| SR_IER_MSR_CHANGE
);
220 case SR_IIR_THR_EMPTY
:
222 TRACE_(SERIAL
, "SR_IIR_THR_EMPTY\n");
224 KeInsertQueueDpc(&DeviceExtension
->SendByteDpc
, NULL
, NULL
);
225 Events
|= SERIAL_EV_TXEMPTY
;
230 case SR_IIR_DATA_RECEIVED
:
232 ULONG AlreadyReceivedBytes
, Limit
;
233 TRACE_(SERIAL
, "SR_IIR_DATA_RECEIVED\n");
235 KeInsertQueueDpc(&DeviceExtension
->ReceivedByteDpc
, NULL
, NULL
);
236 Events
|= SERIAL_EV_RXCHAR
;
238 /* Check if buffer will be 80% full */
239 AlreadyReceivedBytes
= GetNumberOfElementsInCircularBuffer(
240 &DeviceExtension
->InputBuffer
) * 5;
241 Limit
= DeviceExtension
->InputBuffer
.Length
* 4;
242 if (AlreadyReceivedBytes
< Limit
&& AlreadyReceivedBytes
+ 1 >= Limit
)
244 /* Buffer is full at 80% */
245 Events
|= SERIAL_EV_RX80FULL
;
254 TRACE_(SERIAL
, "SR_IIR_ERROR\n");
256 LSR
= READ_PORT_UCHAR(SER_LSR(ComPortBase
));
257 if (LSR
& SR_LSR_OVERRUN_ERROR
)
259 InterlockedIncrement((PLONG
)&DeviceExtension
->SerialPerfStats
.SerialOverrunErrorCount
);
260 Events
|= SERIAL_EV_ERR
;
262 if (LSR
& SR_LSR_PARITY_ERROR
)
264 InterlockedIncrement((PLONG
)&DeviceExtension
->SerialPerfStats
.ParityErrorCount
);
265 Events
|= SERIAL_EV_ERR
;
267 if (LSR
& SR_LSR_FRAMING_ERROR
)
269 InterlockedIncrement((PLONG
)&DeviceExtension
->SerialPerfStats
.FrameErrorCount
);
270 Events
|= SERIAL_EV_ERR
;
272 if (LSR
& SR_LSR_BREAK_INT
)
274 InterlockedIncrement((PLONG
)&DeviceExtension
->BreakInterruptErrorCount
);
275 Events
|= SERIAL_EV_BREAK
;
286 if (DeviceExtension
->WaitOnMaskIrp
&& (Events
& DeviceExtension
->WaitMask
))
288 /* Finish pending IRP */
289 PULONG pEvents
= (PULONG
)DeviceExtension
->WaitOnMaskIrp
->AssociatedIrp
.SystemBuffer
;
291 DeviceExtension
->WaitOnMaskIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
292 DeviceExtension
->WaitOnMaskIrp
->IoStatus
.Information
= sizeof(ULONG
);
294 KeInsertQueueDpc(&DeviceExtension
->CompleteIrpDpc
, DeviceExtension
->WaitOnMaskIrp
, NULL
);
296 /* We are now ready to handle another IRP, even if this one is not completed */
297 DeviceExtension
->WaitOnMaskIrp
= NULL
;
298 return STATUS_SUCCESS
;