ReactOS 0.4.16-dev-319-g6cf4263
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
14static IO_WORKITEM_ROUTINE SerialReadWorkItem;
15
16static PVOID
18{
19 ASSERT(Irp);
20
21 if (Irp->MdlAddress)
22 return Irp->MdlAddress;
23 else
24 return Irp->AssociatedIrp.SystemBuffer;
25}
26
27static VOID
30 IN PIRP Irp,
31 PWORKITEM_DATA WorkItemData)
32{
33 PSERIAL_DEVICE_EXTENSION DeviceExtension;
36 UCHAR ReceivedByte;
37 KTIMER TotalTimeoutTimer;
38 KIRQL Irql;
40 PVOID ObjectsArray[2];
43
45 ASSERT(WorkItemData);
46
47 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
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;
65 }
66
67 /* while buffer is not fully filled */
68 while (TRUE)
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 (Length == 0)
85 {
86 INFO_(SERIAL, "All bytes read\n");
87 break;
88 }
89
90 if (WorkItemData->DontWait
91 && !(WorkItemData->ReadAtLeastOneByte && Information == 0))
92 {
93 INFO_(SERIAL, "Buffer empty. Don't wait more bytes\n");
94 break;
95 }
96
99 ObjectsArray,
100 WaitAny,
101 Executive,
103 FALSE,
104 (WorkItemData->UseIntervalTimeout && Information > 0) ? &WorkItemData->IntervalTimeout : NULL,
105 NULL);
106
107 if (Status == STATUS_TIMEOUT /* interval timeout */
108 || Status == STATUS_WAIT_1) /* total timeout */
109 {
110 TRACE_(SERIAL, "Timeout when reading bytes. Status = 0x%08lx\n", Status);
111 break;
112 }
113 }
114
115 /* stop total timeout timer */
116 if (WorkItemData->UseTotalTimeout)
117 KeCancelTimer(&TotalTimeoutTimer);
118
119 Irp->IoStatus.Information = Information;
120 if (Information == 0)
121 Irp->IoStatus.Status = STATUS_TIMEOUT;
122 else
123 Irp->IoStatus.Status = STATUS_SUCCESS;
124}
125
126static VOID NTAPI
129 IN PVOID pWorkItemData /* real type PWORKITEM_DATA */)
130{
131 PWORKITEM_DATA WorkItemData;
132 PIRP Irp;
133
134 TRACE_(SERIAL, "SerialReadWorkItem() called\n");
135
136 WorkItemData = (PWORKITEM_DATA)pWorkItemData;
137 Irp = WorkItemData->Irp;
138
139 ReadBytes(DeviceObject, Irp, WorkItemData);
140
142
143 IoFreeWorkItem(WorkItemData->IoWorkItem);
144 ExFreePoolWithTag(pWorkItemData, SERIAL_TAG);
145}
146
150 IN PIRP Irp)
151{
153 PSERIAL_DEVICE_EXTENSION DeviceExtension;
156 PWORKITEM_DATA WorkItemData;
159
160 TRACE_(SERIAL, "IRP_MJ_READ\n");
161
163 Length = Stack->Parameters.Read.Length;
165 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
166
167 if (Stack->Parameters.Read.ByteOffset.QuadPart != 0 || Buffer == NULL)
168 {
170 goto ByeBye;
171 }
172
173 if (Length == 0)
174 {
176 goto ByeBye;
177 }
178
179 /* Allocate memory for parameters */
181 if (!WorkItemData)
182 {
184 goto ByeBye;
185 }
186 RtlZeroMemory(WorkItemData, sizeof(WORKITEM_DATA));
187 WorkItemData->Irp = Irp;
188
189 /* Calculate time outs */
190 if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE &&
192 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant > 0 &&
194 {
195 /* read at least one byte, and at most bytes already received */
196 WorkItemData->DontWait = TRUE;
197 WorkItemData->ReadAtLeastOneByte = TRUE;
198 }
199 else if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE &&
200 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0 &&
201 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0)
202 {
203 /* read only bytes that are already in buffer */
204 WorkItemData->DontWait = TRUE;
205 }
206 else
207 {
208 /* use timeouts */
209 if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout != 0)
210 {
211 WorkItemData->UseIntervalTimeout = TRUE;
212 WorkItemData->IntervalTimeout.QuadPart = DeviceExtension->SerialTimeOuts.ReadIntervalTimeout;
213 }
214 if (DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier != 0 ||
215 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant != 0)
216 {
217 ULONG TotalTimeout;
218 LARGE_INTEGER SystemTime;
219
220 WorkItemData->UseTotalTimeout = TRUE;
221 TotalTimeout = DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant +
223 KeQuerySystemTime(&SystemTime);
224 WorkItemData->TotalTimeoutTime.QuadPart = SystemTime.QuadPart +
225 TotalTimeout * 10000;
226 }
227 }
228
229 /* Pend IRP */
231 if (WorkItem)
232 {
233 WorkItemData->IoWorkItem = WorkItem;
236 return STATUS_PENDING;
237 }
238
239 /* Insufficient resources, we can't pend the Irp */
240 INFO_(SERIAL, "Insufficient resources\n");
241 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
242 if (!NT_SUCCESS(Status))
243 {
244 ExFreePoolWithTag(WorkItemData, SERIAL_TAG);
245 goto ByeBye;
246 }
247 ReadBytes(DeviceObject, Irp, WorkItemData);
248 Status = Irp->IoStatus.Status;
249
250 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
251
252ByeBye:
253 Irp->IoStatus.Status = Status;
255 return Status;
256}
257
261 IN PIRP Irp)
262{
264 PSERIAL_DEVICE_EXTENSION DeviceExtension;
268 KIRQL Irql;
270
271 TRACE_(SERIAL, "IRP_MJ_WRITE\n");
272
273 /* FIXME: pend operation if possible */
274 /* FIXME: use write timeouts */
275
277 Length = Stack->Parameters.Write.Length;
279 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
280
281 if (Stack->Parameters.Write.ByteOffset.QuadPart != 0 || Buffer == NULL)
282 {
284 goto ByeBye;
285 }
286
287 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
288 if (!NT_SUCCESS(Status))
289 goto ByeBye;
290
291 /* push bytes into output buffer */
292 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
293 while (Information < Length)
294 {
296 if (!NT_SUCCESS(Status))
297 {
299 {
300 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
301 SerialSendByte(NULL, DeviceExtension, NULL, NULL);
302 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
303 continue;
304 }
305 else
306 {
307 WARN_(SERIAL, "Buffer overrun on COM%lu\n", DeviceExtension->ComPort);
308 DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++;
309 break;
310 }
311 }
312 Information++;
313 }
314 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
315 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
316
317 /* send bytes */
318 SerialSendByte(NULL, DeviceExtension, NULL, NULL);
319
320ByeBye:
321 Irp->IoStatus.Information = Information;
322 Irp->IoStatus.Status = Status;
324 return Status;
325}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
LONG NTSTATUS
Definition: precomp.h:26
#define ULongToPtr(ul)
Definition: basetsd.h:92
NTSTATUS PushCircularBufferEntry(IN PCIRCULAR_BUFFER pBuffer, IN UCHAR Entry)
BOOLEAN IsCircularBufferEmpty(IN PCIRCULAR_BUFFER pBuffer)
NTSTATUS PopCircularBufferEntry(IN PCIRCULAR_BUFFER pBuffer, OUT PUCHAR Entry)
Definition: bufpool.h:45
LONG ObjectCount
Definition: comsup.c:7
_In_ PIRP Irp
Definition: csq.h:116
_Out_ PKIRQL Irql
Definition: csq.h:179
#define STATUS_TIMEOUT
Definition: d3dkmdt.h:49
#define STATUS_PENDING
Definition: d3dkmdt.h:43
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define TRACE_(x)
Definition: compat.h:76
VOID NTAPI SerialSendByte(IN PKDPC Dpc, IN PVOID pDeviceExtension, IN PVOID Unused1, IN PVOID Unused2)
Definition: misc.c:67
static VOID ReadBytes(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, PWORKITEM_DATA WorkItemData)
Definition: rw.c:28
static PVOID SerialGetUserBuffer(IN PIRP Irp)
Definition: rw.c:17
static IO_WORKITEM_ROUTINE SerialReadWorkItem
Definition: rw.c:14
struct _SERIAL_DEVICE_EXTENSION * PSERIAL_DEVICE_EXTENSION
#define SERIAL_TAG
Definition: serial.h:100
struct _WORKITEM_DATA * PWORKITEM_DATA
#define INFINITE
Definition: serial.h:102
DRIVER_DISPATCH SerialRead
Definition: serial.h:296
DRIVER_DISPATCH SerialWrite
Definition: serial.h:297
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define PagedPool
Definition: env_spec_w32.h:308
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
Status
Definition: gdiplustypes.h:25
VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
Definition: iowork.c:40
VOID NTAPI IoFreeWorkItem(IN PIO_WORKITEM IoWorkItem)
Definition: iowork.c:64
PIO_WORKITEM NTAPI IoAllocateWorkItem(IN PDEVICE_OBJECT DeviceObject)
Definition: iowork.c:75
IoMarkIrpPending(Irp)
if(dx< 0)
Definition: linetemp.h:194
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define KernelMode
Definition: asm.h:34
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
@ WaitAny
#define IoCompleteRequest
Definition: irp.c:1240
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
#define STATUS_WAIT_1
Definition: ntstatus.h:71
#define INFO_(ch,...)
Definition: debug.h:159
#define WARN_(ch,...)
Definition: debug.h:157
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
struct _IO_STACK_LOCATION::@3979::@3983 Read
union _IO_STACK_LOCATION::@1580 Parameters
ULONG BufferOverrunErrorCount
Definition: ntddser.h:298
KSPIN_LOCK OutputBufferLock
Definition: serial.h:78
KSPIN_LOCK InputBufferLock
Definition: serial.h:76
IO_REMOVE_LOCK RemoveLock
Definition: serial.h:53
KEVENT InputBufferNotEmpty
Definition: serial.h:74
CIRCULAR_BUFFER InputBuffer
Definition: serial.h:75
CIRCULAR_BUFFER OutputBuffer
Definition: serial.h:77
SERIALPERF_STATS SerialPerfStats
Definition: serial.h:71
SERIAL_TIMEOUTS SerialTimeOuts
Definition: serial.h:72
ULONG ReadTotalTimeoutConstant
Definition: ntddser.h:305
ULONG ReadTotalTimeoutMultiplier
Definition: ntddser.h:304
ULONG ReadIntervalTimeout
Definition: ntddser.h:303
LARGE_INTEGER TotalTimeoutTime
Definition: serial.h:95
LARGE_INTEGER IntervalTimeout
Definition: serial.h:94
BOOLEAN ReadAtLeastOneByte
Definition: serial.h:97
BOOLEAN UseTotalTimeout
Definition: serial.h:93
PIRP Irp
Definition: serial.h:89
BOOLEAN UseIntervalTimeout
Definition: serial.h:92
PIO_WORKITEM IoWorkItem
Definition: serial.h:90
BOOLEAN DontWait
Definition: serial.h:96
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
#define NTAPI
Definition: typedefs.h:36
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1049
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:115
@ DelayedWorkQueue
Definition: extypes.h:190
#define IoAcquireRemoveLock(RemoveLock, Tag)
#define IoReleaseRemoveLock(_RemoveLock, _Tag)
Definition: iofuncs.h:2764
#define IO_NO_INCREMENT
Definition: iotypes.h:598
@ Executive
Definition: ketypes.h:415
unsigned char UCHAR
Definition: xmlstorage.h:181