Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenrw.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: Serial port driver 00004 * FILE: drivers/dd/serial/create.c 00005 * PURPOSE: Serial IRP_MJ_READ/IRP_MJ_WRITE operations 00006 * 00007 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) 00008 */ 00009 00010 #include "serial.h" 00011 00012 static IO_WORKITEM_ROUTINE SerialReadWorkItem; 00013 00014 static PVOID 00015 SerialGetUserBuffer(IN PIRP Irp) 00016 { 00017 ASSERT(Irp); 00018 00019 if (Irp->MdlAddress) 00020 return Irp->MdlAddress; 00021 else 00022 return Irp->AssociatedIrp.SystemBuffer; 00023 } 00024 00025 static VOID 00026 ReadBytes( 00027 IN PDEVICE_OBJECT DeviceObject, 00028 IN PIRP Irp, 00029 PWORKITEM_DATA WorkItemData) 00030 { 00031 PSERIAL_DEVICE_EXTENSION DeviceExtension; 00032 ULONG Length; 00033 PUCHAR Buffer; 00034 UCHAR ReceivedByte; 00035 KTIMER TotalTimeoutTimer; 00036 KIRQL Irql; 00037 ULONG ObjectCount; 00038 PVOID ObjectsArray[2]; 00039 ULONG_PTR Information = 0; 00040 NTSTATUS Status; 00041 00042 ASSERT(DeviceObject); 00043 ASSERT(WorkItemData); 00044 00045 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00046 Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length; 00047 Buffer = SerialGetUserBuffer(Irp); 00048 00049 INFO_(SERIAL, "UseIntervalTimeout = %s, IntervalTimeout = %lu\n", 00050 WorkItemData->UseIntervalTimeout ? "YES" : "NO", 00051 WorkItemData->UseIntervalTimeout ? WorkItemData->IntervalTimeout.QuadPart : 0); 00052 INFO_(SERIAL, "UseTotalTimeout = %s\n", 00053 WorkItemData->UseTotalTimeout ? "YES" : "NO"); 00054 00055 ObjectCount = 1; 00056 ObjectsArray[0] = &DeviceExtension->InputBufferNotEmpty; 00057 if (WorkItemData->UseTotalTimeout) 00058 { 00059 KeInitializeTimer(&TotalTimeoutTimer); 00060 KeSetTimer(&TotalTimeoutTimer, WorkItemData->TotalTimeoutTime, NULL); 00061 ObjectsArray[ObjectCount] = &TotalTimeoutTimer; 00062 ObjectCount++; 00063 } 00064 00065 /* while buffer is not fully filled */ 00066 while (Length > 0) 00067 { 00068 /* read already received bytes from buffer */ 00069 KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); 00070 while (!IsCircularBufferEmpty(&DeviceExtension->InputBuffer) 00071 && Length > 0) 00072 { 00073 PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte); 00074 INFO_(SERIAL, "Reading byte from buffer: 0x%02x\n", ReceivedByte); 00075 00076 Buffer[Information++] = ReceivedByte; 00077 Length--; 00078 } 00079 KeClearEvent(&DeviceExtension->InputBufferNotEmpty); 00080 KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); 00081 00082 if (WorkItemData->DontWait 00083 && !(WorkItemData->ReadAtLeastOneByte && Information == 0)) 00084 { 00085 INFO_(SERIAL, "Buffer empty. Don't wait more bytes\n"); 00086 break; 00087 } 00088 00089 Status = KeWaitForMultipleObjects( 00090 ObjectCount, 00091 ObjectsArray, 00092 WaitAny, 00093 Executive, 00094 KernelMode, 00095 FALSE, 00096 (WorkItemData->UseIntervalTimeout && Information > 0) ? &WorkItemData->IntervalTimeout : NULL, 00097 NULL); 00098 00099 if (Status == STATUS_TIMEOUT /* interval timeout */ 00100 || Status == STATUS_WAIT_1) /* total timeout */ 00101 { 00102 TRACE_(SERIAL, "Timeout when reading bytes. Status = 0x%08lx\n", Status); 00103 break; 00104 } 00105 } 00106 00107 /* stop total timeout timer */ 00108 if (WorkItemData->UseTotalTimeout) 00109 KeCancelTimer(&TotalTimeoutTimer); 00110 00111 Irp->IoStatus.Information = Information; 00112 if (Information == 0) 00113 Irp->IoStatus.Status = STATUS_TIMEOUT; 00114 else 00115 Irp->IoStatus.Status = STATUS_SUCCESS; 00116 } 00117 00118 static VOID NTAPI 00119 SerialReadWorkItem( 00120 IN PDEVICE_OBJECT DeviceObject, 00121 IN PVOID pWorkItemData /* real type PWORKITEM_DATA */) 00122 { 00123 PWORKITEM_DATA WorkItemData; 00124 PIRP Irp; 00125 00126 TRACE_(SERIAL, "SerialReadWorkItem() called\n"); 00127 00128 WorkItemData = (PWORKITEM_DATA)pWorkItemData; 00129 Irp = WorkItemData->Irp; 00130 00131 ReadBytes(DeviceObject, Irp, WorkItemData); 00132 00133 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00134 00135 IoFreeWorkItem(WorkItemData->IoWorkItem); 00136 ExFreePoolWithTag(pWorkItemData, SERIAL_TAG); 00137 } 00138 00139 NTSTATUS NTAPI 00140 SerialRead( 00141 IN PDEVICE_OBJECT DeviceObject, 00142 IN PIRP Irp) 00143 { 00144 PIO_STACK_LOCATION Stack; 00145 PSERIAL_DEVICE_EXTENSION DeviceExtension; 00146 ULONG Length; 00147 PUCHAR Buffer; 00148 PWORKITEM_DATA WorkItemData; 00149 PIO_WORKITEM WorkItem; 00150 NTSTATUS Status; 00151 00152 TRACE_(SERIAL, "IRP_MJ_READ\n"); 00153 00154 Stack = IoGetCurrentIrpStackLocation(Irp); 00155 Length = Stack->Parameters.Read.Length; 00156 Buffer = SerialGetUserBuffer(Irp); 00157 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00158 00159 if (Stack->Parameters.Read.ByteOffset.QuadPart != 0 || Buffer == NULL) 00160 { 00161 Status = STATUS_INVALID_PARAMETER; 00162 goto ByeBye; 00163 } 00164 00165 if (Length == 0) 00166 { 00167 Status = STATUS_SUCCESS; 00168 goto ByeBye; 00169 } 00170 00171 /* Allocate memory for parameters */ 00172 WorkItemData = ExAllocatePoolWithTag(PagedPool, sizeof(WORKITEM_DATA), SERIAL_TAG); 00173 if (!WorkItemData) 00174 { 00175 Status = STATUS_INSUFFICIENT_RESOURCES; 00176 goto ByeBye; 00177 } 00178 RtlZeroMemory(WorkItemData, sizeof(WORKITEM_DATA)); 00179 WorkItemData->Irp = Irp; 00180 00181 /* Calculate time outs */ 00182 if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE && 00183 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == INFINITE && 00184 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant > 0 && 00185 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant < INFINITE) 00186 { 00187 /* read at least one byte, and at most bytes already received */ 00188 WorkItemData->DontWait = TRUE; 00189 WorkItemData->ReadAtLeastOneByte = TRUE; 00190 } 00191 else if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE && 00192 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0 && 00193 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0) 00194 { 00195 /* read only bytes that are already in buffer */ 00196 WorkItemData->DontWait = TRUE; 00197 } 00198 else 00199 { 00200 /* use timeouts */ 00201 if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout != 0) 00202 { 00203 WorkItemData->UseIntervalTimeout = TRUE; 00204 WorkItemData->IntervalTimeout.QuadPart = DeviceExtension->SerialTimeOuts.ReadIntervalTimeout; 00205 } 00206 if (DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier != 0 || 00207 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant != 0) 00208 { 00209 ULONG TotalTimeout; 00210 LARGE_INTEGER SystemTime; 00211 00212 WorkItemData->UseTotalTimeout = TRUE; 00213 TotalTimeout = DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant + 00214 DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier * Length; 00215 KeQuerySystemTime(&SystemTime); 00216 WorkItemData->TotalTimeoutTime.QuadPart = SystemTime.QuadPart + 00217 TotalTimeout * 10000; 00218 } 00219 } 00220 00221 /* Pend IRP */ 00222 WorkItem = IoAllocateWorkItem(DeviceObject); 00223 if (WorkItem) 00224 { 00225 WorkItemData->IoWorkItem = WorkItem; 00226 IoMarkIrpPending(Irp); 00227 IoQueueWorkItem(WorkItem, SerialReadWorkItem, DelayedWorkQueue, WorkItemData); 00228 return STATUS_PENDING; 00229 } 00230 00231 /* Insufficient resources, we can't pend the Irp */ 00232 INFO_(SERIAL, "Insufficient resources\n"); 00233 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00234 if (!NT_SUCCESS(Status)) 00235 { 00236 ExFreePoolWithTag(WorkItemData, SERIAL_TAG); 00237 goto ByeBye; 00238 } 00239 ReadBytes(DeviceObject, Irp, WorkItemData); 00240 Status = Irp->IoStatus.Status; 00241 00242 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00243 00244 ByeBye: 00245 Irp->IoStatus.Status = Status; 00246 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00247 return Status; 00248 } 00249 00250 NTSTATUS NTAPI 00251 SerialWrite( 00252 IN PDEVICE_OBJECT DeviceObject, 00253 IN PIRP Irp) 00254 { 00255 PIO_STACK_LOCATION Stack; 00256 PSERIAL_DEVICE_EXTENSION DeviceExtension; 00257 ULONG Length; 00258 ULONG_PTR Information = 0; 00259 PUCHAR Buffer; 00260 KIRQL Irql; 00261 NTSTATUS Status = STATUS_SUCCESS; 00262 00263 TRACE_(SERIAL, "IRP_MJ_WRITE\n"); 00264 00265 /* FIXME: pend operation if possible */ 00266 /* FIXME: use write timeouts */ 00267 00268 Stack = IoGetCurrentIrpStackLocation(Irp); 00269 Length = Stack->Parameters.Write.Length; 00270 Buffer = SerialGetUserBuffer(Irp); 00271 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00272 00273 if (Stack->Parameters.Write.ByteOffset.QuadPart != 0 || Buffer == NULL) 00274 { 00275 Status = STATUS_INVALID_PARAMETER; 00276 goto ByeBye; 00277 } 00278 00279 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00280 if (!NT_SUCCESS(Status)) 00281 goto ByeBye; 00282 00283 /* push bytes into output buffer */ 00284 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); 00285 while (Information < Length) 00286 { 00287 Status = PushCircularBufferEntry(&DeviceExtension->OutputBuffer, Buffer[Information]); 00288 if (!NT_SUCCESS(Status)) 00289 { 00290 if (Status == STATUS_BUFFER_TOO_SMALL) 00291 { 00292 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); 00293 SerialSendByte(NULL, DeviceExtension, NULL, NULL); 00294 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); 00295 continue; 00296 } 00297 else 00298 { 00299 WARN_(SERIAL, "Buffer overrun on COM%lu\n", DeviceExtension->ComPort); 00300 DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++; 00301 break; 00302 } 00303 } 00304 Information++; 00305 } 00306 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); 00307 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00308 00309 /* send bytes */ 00310 SerialSendByte(NULL, DeviceExtension, NULL, NULL); 00311 00312 ByeBye: 00313 Irp->IoStatus.Information = Information; 00314 Irp->IoStatus.Status = Status; 00315 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00316 return Status; 00317 } Generated on Sun May 27 2012 04:24:27 for ReactOS by
1.7.6.1
|