mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 01:24:38 +00:00
Correct timeout issues when reading
Pend read IRPs Lots of small issues svn path=/trunk/; revision=14440
This commit is contained in:
parent
11fe38608b
commit
ce4cbf5e57
7 changed files with 341 additions and 177 deletions
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*
|
||||
* PROGRAMMERS: Hervé Poussineau (poussine@freesurf.fr)
|
||||
*/
|
||||
/* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */
|
||||
|
||||
//#define NDEBUG
|
||||
#include "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)
|
||||
|
|
Loading…
Reference in a new issue