From ce4cbf5e57afa78202ea045096bd202cb87f4323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sat, 2 Apr 2005 14:16:47 +0000 Subject: [PATCH] Correct timeout issues when reading Pend read IRPs Lots of small issues svn path=/trunk/; revision=14440 --- reactos/drivers/dd/serial/devctrl.c | 107 +++++++--- reactos/drivers/dd/serial/legacy.c | 6 +- reactos/drivers/dd/serial/misc.c | 3 - reactos/drivers/dd/serial/pnp.c | 72 ++++++- reactos/drivers/dd/serial/rw.c | 315 ++++++++++++++++------------ reactos/drivers/dd/serial/serial.c | 1 - reactos/drivers/dd/serial/serial.h | 14 +- 7 files changed, 341 insertions(+), 177 deletions(-) diff --git a/reactos/drivers/dd/serial/devctrl.c b/reactos/drivers/dd/serial/devctrl.c index 3543a6b6b5d..12c2e61bda0 100644 --- a/reactos/drivers/dd/serial/devctrl.c +++ b/reactos/drivers/dd/serial/devctrl.c @@ -7,7 +7,6 @@ * * PROGRAMMERS: Hervé Poussineau (poussine@freesurf.fr) */ -/* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */ #define NDEBUG #include "serial.h" @@ -219,22 +218,30 @@ SerialGetCommProp( pCommProp->ServiceMask = SERIAL_SP_SERIALCOMM; pCommProp->MaxTxQueue = pCommProp->CurrentTxQueue = DeviceExtension->OutputBuffer.Length - 1; pCommProp->MaxRxQueue = pCommProp->CurrentRxQueue = DeviceExtension->InputBuffer.Length - 1; - pCommProp->MaxBaud = SERIAL_BAUD_115200; pCommProp->ProvSubType = 1; // PST_RS232; - /* FIXME: ProvCapabilities may be related to Uart type */ pCommProp->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_INTTIMEOUTS | SERIAL_PCF_PARITY_CHECK | SERIAL_PCF_RTSCTS | SERIAL_PCF_SETXCHAR | SERIAL_PCF_SPECIALCHARS | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_XONXOFF; - /* FIXME: SettableParams may be related to Uart type */ pCommProp->SettableParams = SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_PARITY | SERIAL_SP_PARITY_CHECK | SERIAL_SP_STOPBITS; - /* FIXME: SettableBaud may be related to Uart type */ + + /* SettableBaud is related to Uart type */ pCommProp->SettableBaud = SERIAL_BAUD_075 | SERIAL_BAUD_110 | SERIAL_BAUD_134_5 | SERIAL_BAUD_150 | SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_1800 | SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200 - | SERIAL_BAUD_9600 | SERIAL_BAUD_14400 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400 - | SERIAL_BAUD_56K | SERIAL_BAUD_57600 | SERIAL_BAUD_115200 | SERIAL_BAUD_128K - | SERIAL_BAUD_USER; + | SERIAL_BAUD_9600 | SERIAL_BAUD_USER; + pCommProp->MaxBaud = SERIAL_BAUD_9600; + if (DeviceExtension->UartType >= Uart16450) + { + pCommProp->SettableBaud |= SERIAL_BAUD_14400 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400; + pCommProp->MaxBaud = SERIAL_BAUD_38400; + } + if (DeviceExtension->UartType >= Uart16550) + { + pCommProp->SettableBaud |= SERIAL_BAUD_56K | SERIAL_BAUD_57600 | SERIAL_BAUD_115200 | SERIAL_BAUD_128K; + pCommProp->MaxBaud = SERIAL_BAUD_115200; + } + pCommProp->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8; pCommProp->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE; @@ -264,8 +271,8 @@ SerialGetCommStatus( - DeviceExtension->OutputBuffer.ReadPosition) % DeviceExtension->OutputBuffer.Length; KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); - pSerialStatus->EofReceived = FALSE; /* FIXME */ - pSerialStatus->WaitForImmediate = FALSE; /* FIXME */ + pSerialStatus->EofReceived = FALSE; /* always FALSE */ + pSerialStatus->WaitForImmediate = FALSE; /* always FALSE */ return STATUS_SUCCESS; } @@ -286,8 +293,6 @@ SerialDeviceControl( DPRINT("Serial: IRP_MJ_DEVICE_CONTROL dispatch\n"); - /* FIXME: pend operation if possible */ - Stack = IoGetCurrentIrpStackLocation(Irp); LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength; LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength; @@ -315,9 +320,13 @@ SerialDeviceControl( DPRINT("Serial: IOCTL_SERIAL_CLR_DTR\n"); /* FIXME: If the handshake flow control of the device is configured to * automatically use DTR, return STATUS_INVALID_PARAMETER */ - DeviceExtension->MCR &= ~SR_MCR_DTR; - WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); - Status = STATUS_SUCCESS; + Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + if (NT_SUCCESS(Status)) + { + DeviceExtension->MCR &= ~SR_MCR_DTR; + WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); + IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + } break; } case IOCTL_SERIAL_CLR_RTS: @@ -325,9 +334,13 @@ SerialDeviceControl( DPRINT("Serial: IOCTL_SERIAL_CLR_RTS\n"); /* FIXME: If the handshake flow control of the device is configured to * automatically use RTS, return STATUS_INVALID_PARAMETER */ - DeviceExtension->MCR &= ~SR_MCR_RTS; - WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); - Status = STATUS_SUCCESS; + Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + if (NT_SUCCESS(Status)) + { + DeviceExtension->MCR &= ~SR_MCR_RTS; + WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); + IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + } break; } case IOCTL_SERIAL_CONFIG_SIZE: @@ -546,14 +559,20 @@ SerialDeviceControl( DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0; DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0; /* Clear receive/transmit buffers */ - if (DeviceExtension->UartType >= Uart16550) + if (DeviceExtension->UartType >= Uart16550A) { - WRITE_PORT_UCHAR(SER_FCR(ComPortBase), - SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT); + /* 16550 UARTs also have FIFO queues, but they are unusable due to a bug */ + Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + if (NT_SUCCESS(Status)) + { + WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT); + IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + } } + else + Status = STATUS_SUCCESS; KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql2); KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql1); - Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_RESET_DEVICE: @@ -604,10 +623,16 @@ SerialDeviceControl( DPRINT("Serial: IOCTL_SERIAL_SET_DTR\n"); if (!(DeviceExtension->MCR & SR_MCR_DTR)) { - DeviceExtension->MCR |= SR_MCR_DTR; - WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); + Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + if (NT_SUCCESS(Status)) + { + DeviceExtension->MCR |= SR_MCR_DTR; + WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); + IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + } } - Status = STATUS_SUCCESS; + else + Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_SET_FIFO_CONTROL: @@ -617,8 +642,12 @@ SerialDeviceControl( Status = STATUS_INVALID_PARAMETER; else { - WRITE_PORT_UCHAR(SER_FCR(ComPortBase), (UCHAR)((*(PULONG)BufferIn) & 0xff)); - Status = STATUS_SUCCESS; + Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + if (NT_SUCCESS(Status)) + { + WRITE_PORT_UCHAR(SER_FCR(ComPortBase), (UCHAR)((*(PULONG)BufferIn) & 0xff)); + IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + } } break; } @@ -648,10 +677,14 @@ SerialDeviceControl( Status = STATUS_INVALID_PARAMETER; else { - pMCR = (PULONG)BufferIn; - DeviceExtension->MCR = (UCHAR)(*pMCR & 0xff); - WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); - Status = STATUS_SUCCESS; + Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + if (NT_SUCCESS(Status)) + { + pMCR = (PULONG)BufferIn; + DeviceExtension->MCR = (UCHAR)(*pMCR & 0xff); + WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); + IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + } } break; } @@ -688,10 +721,16 @@ SerialDeviceControl( DPRINT("Serial: IOCTL_SERIAL_SET_RTS\n"); if (!(DeviceExtension->MCR & SR_MCR_RTS)) { - DeviceExtension->MCR |= SR_MCR_RTS; - WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); + Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + if (NT_SUCCESS(Status)) + { + DeviceExtension->MCR |= SR_MCR_RTS; + WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); + IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); + } } - Status = STATUS_SUCCESS; + else + Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_SET_TIMEOUTS: diff --git a/reactos/drivers/dd/serial/legacy.c b/reactos/drivers/dd/serial/legacy.c index 721b8e63762..41df89d32c1 100644 --- a/reactos/drivers/dd/serial/legacy.c +++ b/reactos/drivers/dd/serial/legacy.c @@ -96,8 +96,8 @@ DetectLegacyDevice( if (!ResourceList) return STATUS_INSUFFICIENT_RESOURCES; ResourceList->Count = 1; - ResourceList->List[0].InterfaceType = Isa; - ResourceList->List[0].BusNumber = -1; /* FIXME */ + ResourceList->List[0].InterfaceType = InterfaceTypeUndefined; + ResourceList->List[0].BusNumber = -1; /* unknown */ ResourceList->List[0].PartialResourceList.Version = 1; ResourceList->List[0].PartialResourceList.Revision = 1; ResourceList->List[0].PartialResourceList.Count = 2; @@ -137,7 +137,7 @@ DetectLegacyDevice( { Status = IoReportDetectedDevice( DriverObject, - ResourceList->List[0].InterfaceType, ResourceList->List[0].BusNumber, -1/*FIXME*/, + ResourceList->List[0].InterfaceType, ResourceList->List[0].BusNumber, -1 /* unknown */, ResourceList, NULL, TRUE, &Pdo); diff --git a/reactos/drivers/dd/serial/misc.c b/reactos/drivers/dd/serial/misc.c index 889c121ddd9..654db30bfed 100644 --- a/reactos/drivers/dd/serial/misc.c +++ b/reactos/drivers/dd/serial/misc.c @@ -105,9 +105,6 @@ SerialSendByte( DeviceExtension = (PSERIAL_DEVICE_EXTENSION)pDeviceExtension; ComPortBase = (PUCHAR)DeviceExtension->BaseAddress; - DPRINT1("Serial: sending bytes (if any) on COM%lu\n", - DeviceExtension->ComPort); - KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); while (!IsCircularBufferEmpty(&DeviceExtension->OutputBuffer) && READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE) diff --git a/reactos/drivers/dd/serial/pnp.c b/reactos/drivers/dd/serial/pnp.c index 8ce9ef827f7..f1f2f39db59 100644 --- a/reactos/drivers/dd/serial/pnp.c +++ b/reactos/drivers/dd/serial/pnp.c @@ -80,7 +80,7 @@ SerialAddDeviceInternal( KeInitializeSpinLock(&DeviceExtension->OutputBufferLock); KeInitializeDpc(&DeviceExtension->ReceivedByteDpc, SerialReceiveByte, DeviceExtension); KeInitializeDpc(&DeviceExtension->SendByteDpc, SerialSendByte, DeviceExtension); - //Fdo->Flags |= DO_POWER_PAGEABLE (or DO_POWER_INRUSH?) + Fdo->Flags |= DO_POWER_PAGABLE; Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice); if (!NT_SUCCESS(Status)) { @@ -126,8 +126,8 @@ SerialAddDevice( * not called with a NULL Pdo. Block this call (blocks * unfortunately all the other PnP serial ports devices). */ - //return SerialAddDeviceInternal(DriverObject, Pdo, UartUnknown, NULL); - return STATUS_UNSUCCESSFUL; + return SerialAddDeviceInternal(DriverObject, Pdo, UartUnknown, NULL); + //return STATUS_UNSUCCESSFUL; } NTSTATUS STDCALL @@ -230,8 +230,9 @@ SerialPnpStartDevice( } /* Clear receive/transmit buffers */ - if (DeviceExtension->UartType >= Uart16550) + if (DeviceExtension->UartType >= Uart16550A) { + /* 16550 UARTs also have FIFO queues, but they are unusable due to a bug */ WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT); } @@ -307,6 +308,69 @@ SerialPnp( { DPRINT("Serial: IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); + /* FIXME: first HACK: PnP manager can send multiple + * IRP_MN_START_DEVICE for one device + */ + if (((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->PnpState != dsStopped) + { + DPRINT1("Serial: device already started. Ignoring this irp!\n"); + Status = STATUS_SUCCESS; + break; + } + /* FIXME: AllocatedResources MUST never be NULL ; + * that's the second HACK because resource arbitration + * doesn't exist in ReactOS yet... + */ + if (Stack->Parameters.StartDevice.AllocatedResources == NULL) + { + ULONG ResourceListSize; + PCM_RESOURCE_LIST ResourceList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; + KIRQL Dirql; + ULONG ComPortBase; + ULONG Irq; + + DPRINT1("Serial: no allocated resources for this device! Creating fake list\n"); + /* These values are resources of the ONLY serial + * port that will be managed by this driver + * (default is COM2) */ + ComPortBase = 0x2f8; + Irq = 3; + + /* Create resource list */ + ResourceListSize = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); + ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, ResourceListSize, SERIAL_TAG); + if (!ResourceList) + return STATUS_INSUFFICIENT_RESOURCES; + ResourceList->Count = 1; + ResourceList->List[0].InterfaceType = Isa; + ResourceList->List[0].BusNumber = -1; /* FIXME */ + ResourceList->List[0].PartialResourceList.Version = 1; + ResourceList->List[0].PartialResourceList.Revision = 1; + ResourceList->List[0].PartialResourceList.Count = 2; + ResourceDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0]; + ResourceDescriptor->Type = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = CmResourceShareDriverExclusive; + ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; + ResourceDescriptor->u.Port.Start.u.HighPart = 0; + ResourceDescriptor->u.Port.Start.u.LowPart = ComPortBase; + ResourceDescriptor->u.Port.Length = 8; + + ResourceDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[1]; + ResourceDescriptor->Type = CmResourceTypeInterrupt; + ResourceDescriptor->ShareDisposition = CmResourceShareShared; + ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; + ResourceDescriptor->u.Interrupt.Vector = HalGetInterruptVector( + Internal, 0, 0, Irq, + &Dirql, + &ResourceDescriptor->u.Interrupt.Affinity); + ResourceDescriptor->u.Interrupt.Level = (ULONG)Dirql; + + Stack->Parameters.StartDevice.AllocatedResources = + Stack->Parameters.StartDevice.AllocatedResourcesTranslated = + ResourceList; + } + /* Call lower driver */ Status = ForwardIrpAndWait(DeviceObject, Irp); if (NT_SUCCESS(Status)) diff --git a/reactos/drivers/dd/serial/rw.c b/reactos/drivers/dd/serial/rw.c index c69a93bec35..adb156a6669 100644 --- a/reactos/drivers/dd/serial/rw.c +++ b/reactos/drivers/dd/serial/rw.c @@ -15,9 +15,122 @@ static PVOID SerialGetUserBuffer(IN PIRP Irp) { - ASSERT(Irp); - - return Irp->AssociatedIrp.SystemBuffer; + ASSERT(Irp); + + return Irp->AssociatedIrp.SystemBuffer; +} + +static VOID +ReadBytes( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + PWORKITEM_DATA WorkItemData) +{ + PSERIAL_DEVICE_EXTENSION DeviceExtension; + PUCHAR ComPortBase; + ULONG Length; + PUCHAR Buffer; + ULONG Information = 0; + LARGE_INTEGER SystemTime, ByteTimeoutTime; + UCHAR ReceivedByte; + BOOLEAN IsByteReceived; + //KIRQL Irql; + + DPRINT("Serial: ReadBytes() called\n"); + + DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ComPortBase = (PUCHAR)DeviceExtension->BaseAddress; + Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length; + Buffer = SerialGetUserBuffer(Irp); + + /* FIXME: remove disabling interrupts */ + WRITE_PORT_UCHAR(SER_IER(ComPortBase), DeviceExtension->IER & ~1); + while (Length > 0) + { + /* Calculate dead line to receive the next byte */ + KeQuerySystemTime(&SystemTime); + ByteTimeoutTime.QuadPart = SystemTime.QuadPart + + WorkItemData->IntervalTimeout * 10000; + + IsByteReceived = FALSE; + while (TRUE) + { +#if 1 + if ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) != 0) + { + ReceivedByte = READ_PORT_UCHAR(ComPortBase); + DPRINT("Serial: received byte 0x%02x (%c)\n", ReceivedByte, ReceivedByte); + IsByteReceived = TRUE; + break; + } + else if (WorkItemData->DontWait && + !(WorkItemData->ReadAtLeastOneByte && Information == 0)) + { + DPRINT("Serial: read buffer empty\n"); + break; + } +#else + KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); + if (!IsCircularBufferEmpty(&DeviceExtension->InputBuffer)) + { + CHECKPOINT1; + PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte); + KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); + DPRINT("Serial: reading byte from buffer 0x%02x (%c)\n", ReceivedByte, ReceivedByte); + IsByteReceived = TRUE; + break; + } + else if (WorkItemData->DontWait && + !(WorkItemData->ReadAtLeastOneByte && Information == 0)) + { + DPRINT("Serial: read buffer empty\n"); + break; + } + KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); +#endif + if (IsByteReceived) break; + KeQuerySystemTime(&SystemTime); + if (WorkItemData->UseIntervalTimeout && Information > 0) + { + if (SystemTime.QuadPart >= ByteTimeoutTime.QuadPart) + break; + } + if (WorkItemData->UseTotalTimeout) + { + if (SystemTime.QuadPart >= WorkItemData->TotalTimeoutTime.QuadPart) + break; + } + } + if (!IsByteReceived) break; + Buffer[Information++] = ReceivedByte; + Length--; + } + /* FIXME: remove enabling interrupts */ + WRITE_PORT_UCHAR(SER_IER(ComPortBase), DeviceExtension->IER); + + Irp->IoStatus.Information = Information; + if (Information == 0) + Irp->IoStatus.Status = STATUS_TIMEOUT; + else + Irp->IoStatus.Status = STATUS_SUCCESS; +} + +static VOID STDCALL +SerialReadWorkItem( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID pWorkItemData /* real type PWORKITEM_DATA */) +{ + PWORKITEM_DATA WorkItemData; + PIRP Irp; + + DPRINT("Serial: SerialReadWorkItem() called\n"); + + WorkItemData = (PWORKITEM_DATA)pWorkItemData; + Irp = WorkItemData->Irp; + + ReadBytes(DeviceObject, Irp, WorkItemData); + ExFreePoolWithTag(pWorkItemData, SERIAL_TAG); + IoCompleteRequest(Irp, IO_NO_INCREMENT); } NTSTATUS STDCALL @@ -28,12 +141,10 @@ SerialRead( PIO_STACK_LOCATION Stack; PSERIAL_DEVICE_EXTENSION DeviceExtension; ULONG Length; - ULONG Information = 0; PUCHAR Buffer; - PUCHAR ComPortBase; - UCHAR ReceivedByte; - KIRQL Irql; - NTSTATUS Status = STATUS_SUCCESS; + PWORKITEM_DATA WorkItemData; + PIO_WORKITEM WorkItem; + NTSTATUS Status; DPRINT("Serial: IRP_MJ_READ\n"); @@ -43,7 +154,6 @@ SerialRead( Length = Stack->Parameters.Read.Length; Buffer = SerialGetUserBuffer(Irp); DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - ComPortBase = (PUCHAR)DeviceExtension->BaseAddress; if (Stack->Parameters.Read.ByteOffset.QuadPart != 0 || Buffer == NULL) { @@ -57,136 +167,79 @@ SerialRead( goto ByeBye; } + /* Allocate memory for parameters */ + WorkItemData = ExAllocatePoolWithTag(PagedPool, sizeof(WORKITEM_DATA), SERIAL_TAG); + if (!WorkItemData) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ByeBye; + } + RtlZeroMemory(WorkItemData, sizeof(WORKITEM_DATA)); + WorkItemData->Irp = Irp; + + /* Calculate time outs */ + if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE && + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == INFINITE && + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant > 0 && + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant < INFINITE) + { + /* read at least one byte, and at most bytes already received */ + WorkItemData->DontWait = TRUE; + WorkItemData->ReadAtLeastOneByte = TRUE; + } + else if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE && + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0 && + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0) + { + /* read only bytes that are already in buffer */ + WorkItemData->DontWait = TRUE; + } + else + { + /* use timeouts */ + if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout != 0) + { + WorkItemData->UseIntervalTimeout = TRUE; + WorkItemData->IntervalTimeout = DeviceExtension->SerialTimeOuts.ReadIntervalTimeout; + } + if (DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier != 0 || + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant != 0) + { + ULONG TotalTimeout; + LARGE_INTEGER SystemTime; + + WorkItemData->UseTotalTimeout = TRUE; + TotalTimeout = DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant + + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier * Length; + KeQuerySystemTime(&SystemTime); + WorkItemData->TotalTimeoutTime.QuadPart = SystemTime.QuadPart + + TotalTimeout * 10000; + } + } + + /* Pend IRP */ + WorkItem = IoAllocateWorkItem(DeviceObject); + if (WorkItem) + { + IoQueueWorkItem(WorkItem, SerialReadWorkItem, DelayedWorkQueue, WorkItemData); + IoMarkIrpPending(Irp); + return STATUS_PENDING; + } + + /* insufficient resources, we can't pend the Irp */ + CHECKPOINT; Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(WorkItemData, SERIAL_TAG); goto ByeBye; - - KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); - while (Length-- > 0) - { - Status = PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte); - if (!NT_SUCCESS(Status)) - break; - DPRINT("Serial: read from buffer 0x%x (%c)\n", ReceivedByte, ReceivedByte); - Buffer[Information++] = ReceivedByte; } - KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); - if (Length > 0 && - !(DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE && - DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0 && - DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0)) - { - ULONG IntervalTimeout = 0; - ULONG TotalTimeout = 0; - BOOLEAN UseIntervalTimeout = FALSE; - BOOLEAN UseTotalTimeout = FALSE; - ULONG ThisByteTimeout; - BOOLEAN IsByteReceived; - ULONG i; - /* Extract timeouts informations */ - if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE && - DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == INFINITE && - DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant > 0 && - DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant < INFINITE) - { - if (Information > 0) - { - /* don't read mode bytes */ - Length = 0; - } - else - { - /* read only one byte */ - UseTotalTimeout = TRUE; - TotalTimeout = DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant; - Length = 1; - } - } - else - { - if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout != 0) - { - UseIntervalTimeout = TRUE; - IntervalTimeout = DeviceExtension->SerialTimeOuts.ReadIntervalTimeout; - } - if (DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant != 0 || - DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier != 0) - { - UseTotalTimeout = TRUE; - TotalTimeout = DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant + - DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier * Length; - } - } - DPRINT("Serial: UseIntervalTimeout = %ws, IntervalTimeout = %lu\n", - UseIntervalTimeout ? L"YES" : L"NO", - UseIntervalTimeout ? IntervalTimeout : 0); - DPRINT("Serial: UseTotalTimeout = %ws, TotalTimeout = %lu\n", - UseTotalTimeout ? L"YES" : L"NO", - UseTotalTimeout ? TotalTimeout : 0); - - /* FIXME: it should be better to use input buffer instead of - * disabling interrupts, and try to directly read for port! */ - - /* FIXME: NtQueryPerformanceCounter gives a more accurate - * timer, but it is not available on all computers. First try - * NtQueryPerformanceCounter, and current method if it is not - * implemented. */ - - /* FIXME: remove disabling interrupts */ - WRITE_PORT_UCHAR(SER_IER(ComPortBase), DeviceExtension->IER & ~1); - while (Length > 0) - { - ThisByteTimeout = IntervalTimeout; - IsByteReceived = FALSE; - while (TRUE) - { - for (i = 0; i < 1000; i++) - { -#if 1 - if ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) != 0) - { - ReceivedByte = READ_PORT_UCHAR(ComPortBase); - DPRINT("Serial: received byte 0x%02x (%c)\n", ReceivedByte, ReceivedByte); - IsByteReceived = TRUE; - break; - } -#else - KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); - if (!IsCircularBufferEmpty(&DeviceExtension->InputBuffer)) - { - PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte); - KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); - DPRINT("Serial: reading byte from buffer 0x%02x (%c)\n", ReceivedByte, ReceivedByte); - IsByteReceived = TRUE; - break; - } - KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); -#endif - KeStallExecutionProcessor(1); - } - if (IsByteReceived) break; - if (UseIntervalTimeout) - { - if (ThisByteTimeout == 0) break; else ThisByteTimeout--; - } - if (UseTotalTimeout) - { - if (TotalTimeout == 0) break; else TotalTimeout--; - } - } - if (!IsByteReceived) break; - Buffer[Information++] = ReceivedByte; - Length--; - } - /* FIXME: remove enabling interrupts */ - WRITE_PORT_UCHAR(SER_IER(ComPortBase), DeviceExtension->IER); - } - Status = STATUS_SUCCESS; + ReadBytes(DeviceObject, Irp, WorkItemData); + Status = Irp->IoStatus.Status; IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort); ByeBye: - Irp->IoStatus.Information = Information; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; diff --git a/reactos/drivers/dd/serial/serial.c b/reactos/drivers/dd/serial/serial.c index 9b20b9a9061..7d414445462 100644 --- a/reactos/drivers/dd/serial/serial.c +++ b/reactos/drivers/dd/serial/serial.c @@ -7,7 +7,6 @@ * * PROGRAMMERS: Hervé Poussineau (poussine@freesurf.fr) */ -/* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */ //#define NDEBUG #include "serial.h" diff --git a/reactos/drivers/dd/serial/serial.h b/reactos/drivers/dd/serial/serial.h index fda1aa4aa10..4ea209aa938 100644 --- a/reactos/drivers/dd/serial/serial.h +++ b/reactos/drivers/dd/serial/serial.h @@ -20,7 +20,7 @@ #define STDCALL #define DPRINT1 DbgPrint("(%s:%d) ", __FILE__, __LINE__), DbgPrint - #define CHECKPOINT1 DbgPrint("(%s:%d)\n") + #define CHECKPOINT1 DbgPrint("(%s:%d)\n", __FILE__, __LINE__) #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) @@ -102,6 +102,18 @@ typedef struct _SERIAL_DEVICE_EXTENSION UCHAR MSR; /* Base+6, Modem Status Register */ } SERIAL_DEVICE_EXTENSION, *PSERIAL_DEVICE_EXTENSION; +typedef struct _WORKITEM_DATA +{ + PIRP Irp; + + BOOLEAN UseIntervalTimeout; + BOOLEAN UseTotalTimeout; + ULONG IntervalTimeout; + LARGE_INTEGER TotalTimeoutTime; + BOOLEAN DontWait; + BOOLEAN ReadAtLeastOneByte; +} WORKITEM_DATA, *PWORKITEM_DATA; + #define SERIAL_TAG TAG('S', 'e', 'r', 'l') #define INFINITE ((ULONG)-1)