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 */
15 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion
;
18 ForwardIrpAndWaitCompletion(
19 IN PDEVICE_OBJECT DeviceObject
,
23 if (Irp
->PendingReturned
)
24 KeSetEvent((PKEVENT
)Context
, IO_NO_INCREMENT
, FALSE
);
25 return STATUS_MORE_PROCESSING_REQUIRED
;
30 IN PDEVICE_OBJECT DeviceObject
,
33 PDEVICE_OBJECT LowerDevice
= ((PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
39 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
40 IoCopyCurrentIrpStackLocationToNext(Irp
);
42 TRACE_(SERIAL
, "Calling lower device %p\n", LowerDevice
);
43 IoSetCompletionRoutine(Irp
, ForwardIrpAndWaitCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
45 Status
= IoCallDriver(LowerDevice
, Irp
);
46 if (Status
== STATUS_PENDING
)
48 Status
= KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
49 if (NT_SUCCESS(Status
))
50 Status
= Irp
->IoStatus
.Status
;
58 IN PDEVICE_OBJECT DeviceObject
,
61 PDEVICE_OBJECT LowerDevice
= ((PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
65 IoSkipCurrentIrpStackLocation(Irp
);
66 return IoCallDriver(LowerDevice
, Irp
);
72 IN PVOID pDeviceExtension
, // real type PSERIAL_DEVICE_EXTENSION
76 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
83 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)pDeviceExtension
;
84 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
86 KeAcquireSpinLock(&DeviceExtension
->InputBufferLock
, &Irql
);
87 while (READ_PORT_UCHAR(SER_LSR(ComPortBase
)) & SR_LSR_DATA_RECEIVED
)
89 Byte
= READ_PORT_UCHAR(SER_RBR(ComPortBase
));
90 INFO_(SERIAL
, "Byte received on COM%lu: 0x%02x\n",
91 DeviceExtension
->ComPort
, Byte
);
92 Status
= PushCircularBufferEntry(&DeviceExtension
->InputBuffer
, Byte
);
93 if (NT_SUCCESS(Status
))
94 DeviceExtension
->SerialPerfStats
.ReceivedCount
++;
96 DeviceExtension
->SerialPerfStats
.BufferOverrunErrorCount
++;
98 KeSetEvent(&DeviceExtension
->InputBufferNotEmpty
, 0, FALSE
);
99 KeReleaseSpinLock(&DeviceExtension
->InputBufferLock
, Irql
);
101 /* allow new interrupts */
102 IER
= READ_PORT_UCHAR(SER_IER(ComPortBase
));
103 WRITE_PORT_UCHAR(SER_IER(ComPortBase
), IER
| SR_IER_DATA_RECEIVED
);
109 IN PVOID pDeviceExtension
, // real type PSERIAL_DEVICE_EXTENSION
113 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
120 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)pDeviceExtension
;
121 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
123 KeAcquireSpinLock(&DeviceExtension
->OutputBufferLock
, &Irql
);
124 while (!IsCircularBufferEmpty(&DeviceExtension
->OutputBuffer
)
125 && READ_PORT_UCHAR(SER_LSR(ComPortBase
)) & SR_LSR_THR_EMPTY
)
127 Status
= PopCircularBufferEntry(&DeviceExtension
->OutputBuffer
, &Byte
);
128 if (!NT_SUCCESS(Status
))
130 WRITE_PORT_UCHAR(SER_THR(ComPortBase
), Byte
);
131 INFO_(SERIAL
, "Byte sent to COM%lu: 0x%02x\n",
132 DeviceExtension
->ComPort
, Byte
);
133 DeviceExtension
->SerialPerfStats
.TransmittedCount
++;
135 if (!IsCircularBufferEmpty(&DeviceExtension
->OutputBuffer
))
137 /* allow new interrupts */
138 IER
= READ_PORT_UCHAR(SER_IER(ComPortBase
));
139 WRITE_PORT_UCHAR(SER_IER(ComPortBase
), IER
| SR_IER_THR_EMPTY
);
141 KeReleaseSpinLock(&DeviceExtension
->OutputBufferLock
, Irql
);
147 IN PVOID pDeviceExtension
, // real type PSERIAL_DEVICE_EXTENSION
148 IN PVOID pIrp
, // real type PIRP
151 IoCompleteRequest((PIRP
)pIrp
, IO_NO_INCREMENT
);
155 SerialInterruptService(
156 IN PKINTERRUPT Interrupt
,
157 IN OUT PVOID ServiceContext
)
159 PDEVICE_OBJECT DeviceObject
;
160 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
166 /* FIXME: sometimes, produce SERIAL_EV_RXFLAG event */
168 DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
169 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
170 ComPortBase
= ULongToPtr(DeviceExtension
->BaseAddress
);
172 Iir
= READ_PORT_UCHAR(SER_IIR(ComPortBase
));
175 Iir
&= SR_IIR_ID_MASK
;
176 if ((Iir
& SR_IIR_SELF
) != 0) { return FALSE
; }
180 case SR_IIR_MSR_CHANGE
:
183 TRACE_(SERIAL
, "SR_IIR_MSR_CHANGE\n");
185 MSR
= READ_PORT_UCHAR(SER_MSR(ComPortBase
));
186 if (MSR
& SR_MSR_CTS_CHANGED
)
188 if (MSR
& SR_MSR_CTS
)
189 KeInsertQueueDpc(&DeviceExtension
->SendByteDpc
, NULL
, NULL
);
192 ; /* FIXME: stop transmission */
194 Events
|= SERIAL_EV_CTS
;
196 if (MSR
& SR_MSR_DSR_CHANGED
)
198 if (MSR
& SR_MSR_DSR
)
199 KeInsertQueueDpc(&DeviceExtension
->ReceivedByteDpc
, NULL
, NULL
);
202 ; /* FIXME: stop reception */
204 Events
|= SERIAL_EV_DSR
;
206 if (MSR
& SR_MSR_RI_CHANGED
)
208 INFO_(SERIAL
, "SR_MSR_RI_CHANGED changed: now %d\n", MSR
& SI_MSR_RI
);
209 Events
|= SERIAL_EV_RING
;
211 if (MSR
& SR_MSR_DCD_CHANGED
)
213 INFO_(SERIAL
, "SR_MSR_DCD_CHANGED changed: now %d\n", MSR
& SR_MSR_DCD
);
214 Events
|= SERIAL_EV_RLSD
;
216 IER
= READ_PORT_UCHAR(SER_IER(ComPortBase
));
217 WRITE_PORT_UCHAR(SER_IER(ComPortBase
), IER
| SR_IER_MSR_CHANGE
);
222 case SR_IIR_THR_EMPTY
:
224 TRACE_(SERIAL
, "SR_IIR_THR_EMPTY\n");
226 KeInsertQueueDpc(&DeviceExtension
->SendByteDpc
, NULL
, NULL
);
227 Events
|= SERIAL_EV_TXEMPTY
;
232 case SR_IIR_DATA_RECEIVED
:
234 ULONG AlreadyReceivedBytes
, Limit
;
235 TRACE_(SERIAL
, "SR_IIR_DATA_RECEIVED\n");
237 KeInsertQueueDpc(&DeviceExtension
->ReceivedByteDpc
, NULL
, NULL
);
238 Events
|= SERIAL_EV_RXCHAR
;
240 /* Check if buffer will be 80% full */
241 AlreadyReceivedBytes
= GetNumberOfElementsInCircularBuffer(
242 &DeviceExtension
->InputBuffer
) * 5;
243 Limit
= DeviceExtension
->InputBuffer
.Length
* 4;
244 if (AlreadyReceivedBytes
< Limit
&& AlreadyReceivedBytes
+ 1 >= Limit
)
246 /* Buffer is full at 80% */
247 Events
|= SERIAL_EV_RX80FULL
;
256 TRACE_(SERIAL
, "SR_IIR_ERROR\n");
258 LSR
= READ_PORT_UCHAR(SER_LSR(ComPortBase
));
259 if (LSR
& SR_LSR_OVERRUN_ERROR
)
261 InterlockedIncrement((PLONG
)&DeviceExtension
->SerialPerfStats
.SerialOverrunErrorCount
);
262 Events
|= SERIAL_EV_ERR
;
264 if (LSR
& SR_LSR_PARITY_ERROR
)
266 InterlockedIncrement((PLONG
)&DeviceExtension
->SerialPerfStats
.ParityErrorCount
);
267 Events
|= SERIAL_EV_ERR
;
269 if (LSR
& SR_LSR_FRAMING_ERROR
)
271 InterlockedIncrement((PLONG
)&DeviceExtension
->SerialPerfStats
.FrameErrorCount
);
272 Events
|= SERIAL_EV_ERR
;
274 if (LSR
& SR_LSR_BREAK_INT
)
276 InterlockedIncrement((PLONG
)&DeviceExtension
->BreakInterruptErrorCount
);
277 Events
|= SERIAL_EV_BREAK
;
288 if (DeviceExtension
->WaitOnMaskIrp
&& (Events
& DeviceExtension
->WaitMask
))
290 /* Finish pending IRP */
291 PULONG pEvents
= (PULONG
)DeviceExtension
->WaitOnMaskIrp
->AssociatedIrp
.SystemBuffer
;
293 DeviceExtension
->WaitOnMaskIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
294 DeviceExtension
->WaitOnMaskIrp
->IoStatus
.Information
= sizeof(ULONG
);
296 KeInsertQueueDpc(&DeviceExtension
->CompleteIrpDpc
, DeviceExtension
->WaitOnMaskIrp
, NULL
);
298 /* We are now ready to handle another IRP, even if this one is not completed */
299 DeviceExtension
->WaitOnMaskIrp
= NULL
;
300 return STATUS_SUCCESS
;