ReactOS  0.4.13-dev-92-gf251225
rw.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/create.c
5  * PURPOSE: Serial IRP_MJ_READ/IRP_MJ_WRITE operations
6  *
7  * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8  */
9 
10 #include "serial.h"
11 
12 #include <debug.h>
13 
14 static IO_WORKITEM_ROUTINE SerialReadWorkItem;
15 
16 static PVOID
18 {
19  ASSERT(Irp);
20 
21  if (Irp->MdlAddress)
22  return Irp->MdlAddress;
23  else
24  return Irp->AssociatedIrp.SystemBuffer;
25 }
26 
27 static VOID
30  IN PIRP Irp,
31  PWORKITEM_DATA WorkItemData)
32 {
33  PSERIAL_DEVICE_EXTENSION DeviceExtension;
34  ULONG Length;
35  PUCHAR Buffer;
36  UCHAR ReceivedByte;
37  KTIMER TotalTimeoutTimer;
38  KIRQL Irql;
40  PVOID ObjectsArray[2];
43 
45  ASSERT(WorkItemData);
46 
50 
51  INFO_(SERIAL, "UseIntervalTimeout = %s, IntervalTimeout = %lu\n",
52  WorkItemData->UseIntervalTimeout ? "YES" : "NO",
53  WorkItemData->UseIntervalTimeout ? WorkItemData->IntervalTimeout.QuadPart : 0);
54  INFO_(SERIAL, "UseTotalTimeout = %s\n",
55  WorkItemData->UseTotalTimeout ? "YES" : "NO");
56 
57  ObjectCount = 1;
58  ObjectsArray[0] = &DeviceExtension->InputBufferNotEmpty;
59  if (WorkItemData->UseTotalTimeout)
60  {
61  KeInitializeTimer(&TotalTimeoutTimer);
62  KeSetTimer(&TotalTimeoutTimer, WorkItemData->TotalTimeoutTime, NULL);
63  ObjectsArray[ObjectCount] = &TotalTimeoutTimer;
64  ObjectCount++;
65  }
66 
67  /* while buffer is not fully filled */
68  while (Length > 0)
69  {
70  /* read already received bytes from buffer */
71  KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
72  while (!IsCircularBufferEmpty(&DeviceExtension->InputBuffer)
73  && Length > 0)
74  {
75  PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
76  INFO_(SERIAL, "Reading byte from buffer: 0x%02x\n", ReceivedByte);
77 
78  Buffer[Information++] = ReceivedByte;
79  Length--;
80  }
81  KeClearEvent(&DeviceExtension->InputBufferNotEmpty);
82  KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
83 
84  if (WorkItemData->DontWait
85  && !(WorkItemData->ReadAtLeastOneByte && Information == 0))
86  {
87  INFO_(SERIAL, "Buffer empty. Don't wait more bytes\n");
88  break;
89  }
90 
93  ObjectsArray,
94  WaitAny,
95  Executive,
96  KernelMode,
97  FALSE,
98  (WorkItemData->UseIntervalTimeout && Information > 0) ? &WorkItemData->IntervalTimeout : NULL,
99  NULL);
100 
101  if (Status == STATUS_TIMEOUT /* interval timeout */
102  || Status == STATUS_WAIT_1) /* total timeout */
103  {
104  TRACE_(SERIAL, "Timeout when reading bytes. Status = 0x%08lx\n", Status);
105  break;
106  }
107  }
108 
109  /* stop total timeout timer */
110  if (WorkItemData->UseTotalTimeout)
111  KeCancelTimer(&TotalTimeoutTimer);
112 
113  Irp->IoStatus.Information = Information;
114  if (Information == 0)
115  Irp->IoStatus.Status = STATUS_TIMEOUT;
116  else
117  Irp->IoStatus.Status = STATUS_SUCCESS;
118 }
119 
120 static VOID NTAPI
123  IN PVOID pWorkItemData /* real type PWORKITEM_DATA */)
124 {
125  PWORKITEM_DATA WorkItemData;
126  PIRP Irp;
127 
128  TRACE_(SERIAL, "SerialReadWorkItem() called\n");
129 
130  WorkItemData = (PWORKITEM_DATA)pWorkItemData;
131  Irp = WorkItemData->Irp;
132 
133  ReadBytes(DeviceObject, Irp, WorkItemData);
134 
136 
137  IoFreeWorkItem(WorkItemData->IoWorkItem);
138  ExFreePoolWithTag(pWorkItemData, SERIAL_TAG);
139 }
140 
144  IN PIRP Irp)
145 {
146  PIO_STACK_LOCATION Stack;
147  PSERIAL_DEVICE_EXTENSION DeviceExtension;
148  ULONG Length;
149  PUCHAR Buffer;
150  PWORKITEM_DATA WorkItemData;
151  PIO_WORKITEM WorkItem;
153 
154  TRACE_(SERIAL, "IRP_MJ_READ\n");
155 
157  Length = Stack->Parameters.Read.Length;
160 
161  if (Stack->Parameters.Read.ByteOffset.QuadPart != 0 || Buffer == NULL)
162  {
164  goto ByeBye;
165  }
166 
167  if (Length == 0)
168  {
170  goto ByeBye;
171  }
172 
173  /* Allocate memory for parameters */
174  WorkItemData = ExAllocatePoolWithTag(PagedPool, sizeof(WORKITEM_DATA), SERIAL_TAG);
175  if (!WorkItemData)
176  {
178  goto ByeBye;
179  }
180  RtlZeroMemory(WorkItemData, sizeof(WORKITEM_DATA));
181  WorkItemData->Irp = Irp;
182 
183  /* Calculate time outs */
184  if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE &&
185  DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == INFINITE &&
186  DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant > 0 &&
188  {
189  /* read at least one byte, and at most bytes already received */
190  WorkItemData->DontWait = TRUE;
191  WorkItemData->ReadAtLeastOneByte = TRUE;
192  }
193  else if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE &&
194  DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0 &&
195  DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0)
196  {
197  /* read only bytes that are already in buffer */
198  WorkItemData->DontWait = TRUE;
199  }
200  else
201  {
202  /* use timeouts */
203  if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout != 0)
204  {
205  WorkItemData->UseIntervalTimeout = TRUE;
206  WorkItemData->IntervalTimeout.QuadPart = DeviceExtension->SerialTimeOuts.ReadIntervalTimeout;
207  }
208  if (DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier != 0 ||
209  DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant != 0)
210  {
211  ULONG TotalTimeout;
212  LARGE_INTEGER SystemTime;
213 
214  WorkItemData->UseTotalTimeout = TRUE;
215  TotalTimeout = DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant +
217  KeQuerySystemTime(&SystemTime);
218  WorkItemData->TotalTimeoutTime.QuadPart = SystemTime.QuadPart +
219  TotalTimeout * 10000;
220  }
221  }
222 
223  /* Pend IRP */
224  WorkItem = IoAllocateWorkItem(DeviceObject);
225  if (WorkItem)
226  {
227  WorkItemData->IoWorkItem = WorkItem;
229  IoQueueWorkItem(WorkItem, SerialReadWorkItem, DelayedWorkQueue, WorkItemData);
230  return STATUS_PENDING;
231  }
232 
233  /* Insufficient resources, we can't pend the Irp */
234  INFO_(SERIAL, "Insufficient resources\n");
235  Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
236  if (!NT_SUCCESS(Status))
237  {
238  ExFreePoolWithTag(WorkItemData, SERIAL_TAG);
239  goto ByeBye;
240  }
241  ReadBytes(DeviceObject, Irp, WorkItemData);
242  Status = Irp->IoStatus.Status;
243 
244  IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
245 
246 ByeBye:
247  Irp->IoStatus.Status = Status;
249  return Status;
250 }
251 
255  IN PIRP Irp)
256 {
257  PIO_STACK_LOCATION Stack;
258  PSERIAL_DEVICE_EXTENSION DeviceExtension;
259  ULONG Length;
261  PUCHAR Buffer;
262  KIRQL Irql;
264 
265  TRACE_(SERIAL, "IRP_MJ_WRITE\n");
266 
267  /* FIXME: pend operation if possible */
268  /* FIXME: use write timeouts */
269 
271  Length = Stack->Parameters.Write.Length;
274 
275  if (Stack->Parameters.Write.ByteOffset.QuadPart != 0 || Buffer == NULL)
276  {
278  goto ByeBye;
279  }
280 
281  Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
282  if (!NT_SUCCESS(Status))
283  goto ByeBye;
284 
285  /* push bytes into output buffer */
286  KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
287  while (Information < Length)
288  {
290  if (!NT_SUCCESS(Status))
291  {
293  {
294  KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
295  SerialSendByte(NULL, DeviceExtension, NULL, NULL);
296  KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
297  continue;
298  }
299  else
300  {
301  WARN_(SERIAL, "Buffer overrun on COM%lu\n", DeviceExtension->ComPort);
302  DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++;
303  break;
304  }
305  }
306  Information++;
307  }
308  KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
309  IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
310 
311  /* send bytes */
312  SerialSendByte(NULL, DeviceExtension, NULL, NULL);
313 
314 ByeBye:
315  Irp->IoStatus.Information = Information;
316  Irp->IoStatus.Status = Status;
318  return Status;
319 }
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
PIRP Irp
Definition: serial.h:89
NTSTATUS NTAPI SerialRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: rw.c:142
static VOID ReadBytes(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, PWORKITEM_DATA WorkItemData)
Definition: rw.c:28
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
#define ULongToPtr(ul)
Definition: basetsd.h:92
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
CIRCULAR_BUFFER OutputBuffer
Definition: serial.h:77
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
static PVOID SerialGetUserBuffer(IN PIRP Irp)
Definition: rw.c:17
PIO_WORKITEM IoWorkItem
Definition: serial.h:90
BOOLEAN UseTotalTimeout
Definition: serial.h:93
#define INFO_(ch,...)
Definition: debug.h:159
_In_ PIRP Irp
Definition: csq.h:116
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
ULONG BufferOverrunErrorCount
Definition: ntddser.h:298
unsigned char * PUCHAR
Definition: retypes.h:3
ULONG ReadTotalTimeoutConstant
Definition: ntddser.h:305
LONG NTSTATUS
Definition: precomp.h:26
#define IoReleaseRemoveLock(_RemoveLock, _Tag)
Definition: iofuncs.h:2716
struct _WORKITEM_DATA * PWORKITEM_DATA
KSPIN_LOCK InputBufferLock
Definition: serial.h:76
PIO_WORKITEM NTAPI IoAllocateWorkItem(IN PDEVICE_OBJECT DeviceObject)
Definition: iowork.c:75
_Out_ PKIRQL Irql
Definition: csq.h:179
VOID NTAPI IoFreeWorkItem(IN PIO_WORKITEM IoWorkItem)
Definition: iowork.c:64
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
SERIAL_TIMEOUTS SerialTimeOuts
Definition: serial.h:72
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
KEVENT InputBufferNotEmpty
Definition: serial.h:74
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define STATUS_WAIT_1
Definition: ntstatus.h:71
BOOLEAN DontWait
Definition: serial.h:96
KSPIN_LOCK OutputBufferLock
Definition: serial.h:78
LARGE_INTEGER IntervalTimeout
Definition: serial.h:94
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
SERIALPERF_STATS SerialPerfStats
Definition: serial.h:71
BOOLEAN IsCircularBufferEmpty(IN PCIRCULAR_BUFFER pBuffer)
LONG ObjectCount
Definition: comsup.c:7
PVOID DeviceExtension
Definition: env_spec_w32.h:418
ULONG ReadTotalTimeoutMultiplier
Definition: ntddser.h:304
smooth NULL
Definition: ftsmooth.c:416
#define IoCompleteRequest
Definition: irp.c:1240
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
Definition: bufpool.h:45
static IO_WORKITEM_ROUTINE SerialReadWorkItem
Definition: rw.c:14
#define SERIAL_TAG
Definition: serial.h:100
#define TRACE_(x)
Definition: compat.h:66
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
LARGE_INTEGER TotalTimeoutTime
Definition: serial.h:95
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
BOOLEAN ReadAtLeastOneByte
Definition: serial.h:97
ULONG ReadIntervalTimeout
Definition: ntddser.h:303
NTSTATUS PushCircularBufferEntry(IN PCIRCULAR_BUFFER pBuffer, IN UCHAR Entry)
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
NTSTATUS NTAPI KeWaitForMultipleObjects(IN ULONG Count, IN PVOID Object[], IN WAIT_TYPE WaitType, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL, OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL)
Definition: wait.c:586
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
unsigned char UCHAR
Definition: xmlstorage.h:181
IO_REMOVE_LOCK RemoveLock
Definition: serial.h:53
Status
Definition: gdiplustypes.h:24
VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
Definition: iowork.c:40
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
NTSTATUS PopCircularBufferEntry(IN PCIRCULAR_BUFFER pBuffer, OUT PUCHAR Entry)
struct _SERIAL_DEVICE_EXTENSION * PSERIAL_DEVICE_EXTENSION
BOOLEAN UseIntervalTimeout
Definition: serial.h:92
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
NTSTATUS NTAPI SerialWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: rw.c:253
VOID NTAPI SerialSendByte(IN PKDPC Dpc, IN PVOID pDeviceExtension, IN PVOID Unused1, IN PVOID Unused2)
Definition: misc.c:107
CIRCULAR_BUFFER InputBuffer
Definition: serial.h:75
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
#define INFINITE
Definition: serial.h:102
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
return STATUS_SUCCESS
Definition: btrfs.c:2725
IoMarkIrpPending(Irp)
#define WARN_(ch,...)
Definition: debug.h:157
#define IoAcquireRemoveLock(RemoveLock, Tag)
Iosb Information
Definition: create.c:4377
LONGLONG QuadPart
Definition: typedefs.h:112