ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

rw.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.