ReactOS  0.4.13-dev-92-gf251225
misc.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: Serial port driver
4  * FILE: drivers/dd/serial/misc.c
5  * PURPOSE: Miscellaneous operations
6  *
7  * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8  */
9 /* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */
10 
11 #include "serial.h"
12 
13 #include <debug.h>
14 
15 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion;
16 
17 static NTSTATUS NTAPI
20  IN PIRP Irp,
22 {
23  if (Irp->PendingReturned)
26 }
27 
31  IN PIRP Irp)
32 {
34  KEVENT Event;
36 
37  ASSERT(LowerDevice);
38 
41 
42  TRACE_(SERIAL, "Calling lower device %p\n", LowerDevice);
44 
45  Status = IoCallDriver(LowerDevice, Irp);
46  if (Status == STATUS_PENDING)
47  {
49  if (NT_SUCCESS(Status))
50  Status = Irp->IoStatus.Status;
51  }
52 
53  return Status;
54 }
55 
59  IN PIRP Irp)
60 {
62 
63  ASSERT(LowerDevice);
64 
66  return IoCallDriver(LowerDevice, Irp);
67 }
68 
69 VOID NTAPI
71  IN PKDPC Dpc,
72  IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION
73  IN PVOID Unused1,
74  IN PVOID Unused2)
75 {
76  PSERIAL_DEVICE_EXTENSION DeviceExtension;
77  PUCHAR ComPortBase;
78  UCHAR Byte;
79  KIRQL Irql;
80  UCHAR IER;
82 
83  DeviceExtension = (PSERIAL_DEVICE_EXTENSION)pDeviceExtension;
84  ComPortBase = ULongToPtr(DeviceExtension->BaseAddress);
85 
86  KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
87  while (READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DATA_RECEIVED)
88  {
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++;
95  else
96  DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++;
97  }
98  KeSetEvent(&DeviceExtension->InputBufferNotEmpty, 0, FALSE);
99  KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
100 
101  /* allow new interrupts */
102  IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
104 }
105 
106 VOID NTAPI
108  IN PKDPC Dpc,
109  IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION
110  IN PVOID Unused1,
111  IN PVOID Unused2)
112 {
113  PSERIAL_DEVICE_EXTENSION DeviceExtension;
114  PUCHAR ComPortBase;
115  UCHAR Byte;
116  KIRQL Irql;
117  UCHAR IER;
119 
120  DeviceExtension = (PSERIAL_DEVICE_EXTENSION)pDeviceExtension;
121  ComPortBase = ULongToPtr(DeviceExtension->BaseAddress);
122 
123  KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
124  while (!IsCircularBufferEmpty(&DeviceExtension->OutputBuffer)
125  && READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_THR_EMPTY)
126  {
127  Status = PopCircularBufferEntry(&DeviceExtension->OutputBuffer, &Byte);
128  if (!NT_SUCCESS(Status))
129  break;
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++;
134  }
135  if (!IsCircularBufferEmpty(&DeviceExtension->OutputBuffer))
136  {
137  /* allow new interrupts */
138  IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
139  WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER | SR_IER_THR_EMPTY);
140  }
141  KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
142 }
143 
144 VOID NTAPI
146  IN PKDPC Dpc,
147  IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION
148  IN PVOID pIrp, // real type PIRP
149  IN PVOID Unused)
150 {
152 }
153 
156  IN PKINTERRUPT Interrupt,
158 {
160  PSERIAL_DEVICE_EXTENSION DeviceExtension;
161  PUCHAR ComPortBase;
162  UCHAR Iir;
163  ULONG Events = 0;
164  BOOLEAN ret = FALSE;
165 
166  /* FIXME: sometimes, produce SERIAL_EV_RXFLAG event */
167 
170  ComPortBase = ULongToPtr(DeviceExtension->BaseAddress);
171 
172  Iir = READ_PORT_UCHAR(SER_IIR(ComPortBase));
173  if (Iir == 0xff)
174  return TRUE;
175  Iir &= SR_IIR_ID_MASK;
176  if ((Iir & SR_IIR_SELF) != 0) { return FALSE; }
177 
178  switch (Iir)
179  {
180  case SR_IIR_MSR_CHANGE:
181  {
182  UCHAR MSR, IER;
183  TRACE_(SERIAL, "SR_IIR_MSR_CHANGE\n");
184 
185  MSR = READ_PORT_UCHAR(SER_MSR(ComPortBase));
186  if (MSR & SR_MSR_CTS_CHANGED)
187  {
188  if (MSR & SR_MSR_CTS)
189  KeInsertQueueDpc(&DeviceExtension->SendByteDpc, NULL, NULL);
190  else
191  {
192  ; /* FIXME: stop transmission */
193  }
195  }
196  if (MSR & SR_MSR_DSR_CHANGED)
197  {
198  if (MSR & SR_MSR_DSR)
199  KeInsertQueueDpc(&DeviceExtension->ReceivedByteDpc, NULL, NULL);
200  else
201  {
202  ; /* FIXME: stop reception */
203  }
205  }
206  if (MSR & SR_MSR_RI_CHANGED)
207  {
208  INFO_(SERIAL, "SR_MSR_RI_CHANGED changed: now %d\n", MSR & SI_MSR_RI);
210  }
211  if (MSR & SR_MSR_DCD_CHANGED)
212  {
213  INFO_(SERIAL, "SR_MSR_DCD_CHANGED changed: now %d\n", MSR & SR_MSR_DCD);
215  }
216  IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
218 
219  ret = TRUE;
220  goto done;
221  }
222  case SR_IIR_THR_EMPTY:
223  {
224  TRACE_(SERIAL, "SR_IIR_THR_EMPTY\n");
225 
226  KeInsertQueueDpc(&DeviceExtension->SendByteDpc, NULL, NULL);
228 
229  ret = TRUE;
230  goto done;
231  }
233  {
234  ULONG AlreadyReceivedBytes, Limit;
235  TRACE_(SERIAL, "SR_IIR_DATA_RECEIVED\n");
236 
237  KeInsertQueueDpc(&DeviceExtension->ReceivedByteDpc, NULL, NULL);
239 
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)
245  {
246  /* Buffer is full at 80% */
248  }
249 
250  ret = TRUE;
251  goto done;
252  }
253  case SR_IIR_ERROR:
254  {
255  UCHAR LSR;
256  TRACE_(SERIAL, "SR_IIR_ERROR\n");
257 
258  LSR = READ_PORT_UCHAR(SER_LSR(ComPortBase));
260  {
263  }
264  if (LSR & SR_LSR_PARITY_ERROR)
265  {
268  }
270  {
273  }
274  if (LSR & SR_LSR_BREAK_INT)
275  {
278  }
279 
280  ret = TRUE;
281  goto done;
282  }
283  }
284 
285 done:
286  if (!ret)
287  return FALSE;
288  if (DeviceExtension->WaitOnMaskIrp && (Events & DeviceExtension->WaitMask))
289  {
290  /* Finish pending IRP */
291  PULONG pEvents = (PULONG)DeviceExtension->WaitOnMaskIrp->AssociatedIrp.SystemBuffer;
292 
293  DeviceExtension->WaitOnMaskIrp->IoStatus.Status = STATUS_SUCCESS;
294  DeviceExtension->WaitOnMaskIrp->IoStatus.Information = sizeof(ULONG);
295  *pEvents = Events;
296  KeInsertQueueDpc(&DeviceExtension->CompleteIrpDpc, DeviceExtension->WaitOnMaskIrp, NULL);
297 
298  /* We are now ready to handle another IRP, even if this one is not completed */
299  DeviceExtension->WaitOnMaskIrp = NULL;
300  return TRUE;
301  }
302  return TRUE;
303 }
static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion
Definition: misc.c:15
_Must_inspect_result_ typedef _In_ PVOID Unused
Definition: iotypes.h:1128
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
#define ULongToPtr(ul)
Definition: basetsd.h:92
CIRCULAR_BUFFER OutputBuffer
Definition: serial.h:77
#define SERIAL_EV_RING
Definition: serial.c:107
#define INFO_(ch,...)
Definition: debug.h:159
#define SER_RBR(x)
Definition: serial.h:109
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:63
unsigned char Byte
Definition: zconf.h:391
_In_ PIRP Irp
Definition: csq.h:116
struct _DEVICE_OBJECT * PDEVICE_OBJECT
#define SR_IER_MSR_CHANGE
Definition: serial.h:116
ULONG BufferOverrunErrorCount
Definition: ntddser.h:298
VOID NTAPI SerialCompleteIrp(IN PKDPC Dpc, IN PVOID pDeviceExtension, IN PVOID pIrp, IN PVOID Unused)
Definition: misc.c:145
unsigned char * PUCHAR
Definition: retypes.h:3
UCHAR NTAPI READ_PORT_UCHAR(PUCHAR Address)
Definition: mach.c:535
BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:724
LONG NTSTATUS
Definition: precomp.h:26
#define SERIAL_EV_DSR
Definition: serial.c:103
ULONG GetNumberOfElementsInCircularBuffer(IN PCIRCULAR_BUFFER pBuffer)
#define SR_MSR_DCD_CHANGED
Definition: serial.h:165
#define SR_IER_THR_EMPTY
Definition: serial.h:114
KSPIN_LOCK InputBufferLock
Definition: serial.h:76
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
_Out_ PKIRQL Irql
Definition: csq.h:179
#define SERIAL_EV_TXEMPTY
Definition: serial.c:101
NTSTATUS NTAPI ForwardIrpAndWait(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: misc.c:33
#define SERIAL_EV_RX80FULL
Definition: serial.c:109
#define SERIAL_EV_RLSD
Definition: serial.c:104
#define SERIAL_EV_ERR
Definition: serial.c:106
#define SER_MSR(x)
Definition: serial.h:161
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:515
KEVENT InputBufferNotEmpty
Definition: serial.h:74
FORCEINLINE VOID IoCopyCurrentIrpStackLocationToNext(_Inout_ PIRP Irp)
Definition: iofuncs.h:2820
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define SR_LSR_DATA_RECEIVED
Definition: serial.h:153
KSPIN_LOCK OutputBufferLock
Definition: serial.h:78
#define SR_MSR_DSR_CHANGED
Definition: serial.h:163
#define SR_MSR_RI_CHANGED
Definition: serial.h:164
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define SR_IER_DATA_RECEIVED
Definition: serial.h:113
#define SR_LSR_PARITY_ERROR
Definition: serial.h:155
SERIALPERF_STATS SerialPerfStats
Definition: serial.h:71
BOOLEAN IsCircularBufferEmpty(IN PCIRCULAR_BUFFER pBuffer)
#define SR_MSR_DCD
Definition: serial.h:169
#define IER
Definition: serial_port.h:62
_In_ PVOID _In_ ULONG Event
Definition: iotypes.h:434
#define SR_MSR_CTS_CHANGED
Definition: serial.h:162
PVOID DeviceExtension
Definition: env_spec_w32.h:418
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define IoCompleteRequest
Definition: irp.c:1240
#define LSR
Definition: serial_port.h:67
ULONG SerialOverrunErrorCount
Definition: ntddser.h:297
#define SER_THR(x)
Definition: serial.h:110
#define SR_IIR_ID_MASK
Definition: serial.h:122
#define TRACE_(x)
Definition: compat.h:66
ULONG BreakInterruptErrorCount
Definition: serial.h:70
#define SERIAL_EV_CTS
Definition: serial.c:102
#define MSR
Definition: serial_port.h:68
#define SR_LSR_OVERRUN_ERROR
Definition: serial.h:154
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:524
#define SR_LSR_THR_EMPTY
Definition: serial.h:158
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define SER_IIR(x)
Definition: serial.h:120
#define SI_MSR_RI
Definition: serial.h:168
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
NTSTATUS PushCircularBufferEntry(IN PCIRCULAR_BUFFER pBuffer, IN UCHAR Entry)
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID ServiceContext
Definition: iofuncs.h:798
ULONG Length
Definition: serial.h:43
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
unsigned char UCHAR
Definition: xmlstorage.h:181
#define SERIAL_EV_BREAK
Definition: serial.c:105
int ret
#define SR_LSR_FRAMING_ERROR
Definition: serial.h:156
VOID NTAPI SerialReceiveByte(IN PKDPC Dpc, IN PVOID pDeviceExtension, IN PVOID Unused1, IN PVOID Unused2)
Definition: misc.c:70
Definition: ketypes.h:687
BOOLEAN NTAPI SerialInterruptService(IN PKINTERRUPT Interrupt, IN OUT PVOID ServiceContext)
Definition: misc.c:155
#define SR_IIR_MSR_CHANGE
Definition: serial.h:123
Status
Definition: gdiplustypes.h:24
#define SR_MSR_CTS
Definition: serial.h:166
#define SER_LSR(x)
Definition: serial.h:152
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
#define SR_IIR_DATA_RECEIVED
Definition: serial.h:125
NTSTATUS PopCircularBufferEntry(IN PCIRCULAR_BUFFER pBuffer, OUT PUCHAR Entry)
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InterlockedIncrement
Definition: armddk.h:53
#define SR_LSR_BREAK_INT
Definition: serial.h:157
struct _SERIAL_DEVICE_EXTENSION * PSERIAL_DEVICE_EXTENSION
HANDLE Events[2]
Definition: schedsvc.c:40
ULONG TransmittedCount
Definition: ntddser.h:295
unsigned int * PULONG
Definition: retypes.h:1
NTSTATUS NTAPI ForwardIrpAndForget(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: misc.c:59
NTSTATUS NTAPI IoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1218
#define SER_IER(x)
Definition: serial.h:112
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define IoSkipCurrentIrpStackLocation(Irp)
Definition: ntifs_ex.h:421
ULONG FrameErrorCount
Definition: ntddser.h:296
VOID NTAPI SerialSendByte(IN PKDPC Dpc, IN PVOID pDeviceExtension, IN PVOID Unused1, IN PVOID Unused2)
Definition: misc.c:107
#define SR_IIR_THR_EMPTY
Definition: serial.h:124
CIRCULAR_BUFFER InputBuffer
Definition: serial.h:75
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value)
Definition: mach.c:539
#define SR_IIR_ERROR
Definition: serial.h:126
#define SERIAL_EV_RXCHAR
Definition: serial.c:99
ULONG ParityErrorCount
Definition: ntddser.h:299
return STATUS_SUCCESS
Definition: btrfs.c:2725
signed int * PLONG
Definition: retypes.h:5
_In_ LONG _In_ LONG Limit
Definition: kefuncs.h:328
ULONG ReceivedCount
Definition: ntddser.h:294
#define SR_MSR_DSR
Definition: serial.h:167
#define SR_IIR_SELF
Definition: serial.h:121