mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
- Add synchronization on input and output buffers
- Respect timeouts on IRP_MJ_READ - Get right buffer in read/write routines svn path=/trunk/; revision=14297
This commit is contained in:
parent
974ee62e85
commit
632a47580b
5 changed files with 209 additions and 79 deletions
|
@ -215,14 +215,23 @@ SerialGetCommStatus(
|
||||||
OUT PSERIAL_STATUS pSerialStatus,
|
OUT PSERIAL_STATUS pSerialStatus,
|
||||||
IN PSERIAL_DEVICE_EXTENSION DeviceExtension)
|
IN PSERIAL_DEVICE_EXTENSION DeviceExtension)
|
||||||
{
|
{
|
||||||
|
KIRQL Irql;
|
||||||
|
|
||||||
RtlZeroMemory(pSerialStatus, sizeof(SERIAL_STATUS));
|
RtlZeroMemory(pSerialStatus, sizeof(SERIAL_STATUS));
|
||||||
|
|
||||||
pSerialStatus->Errors = 0; /* FIXME */
|
pSerialStatus->Errors = 0; /* FIXME */
|
||||||
pSerialStatus->HoldReasons = 0; /* FIXME */
|
pSerialStatus->HoldReasons = 0; /* FIXME */
|
||||||
|
|
||||||
|
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
|
||||||
pSerialStatus->AmountInInQueue = (DeviceExtension->InputBuffer.WritePosition + DeviceExtension->InputBuffer.Length
|
pSerialStatus->AmountInInQueue = (DeviceExtension->InputBuffer.WritePosition + DeviceExtension->InputBuffer.Length
|
||||||
- DeviceExtension->InputBuffer.ReadPosition) % DeviceExtension->InputBuffer.Length;
|
- DeviceExtension->InputBuffer.ReadPosition) % DeviceExtension->InputBuffer.Length;
|
||||||
|
KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
|
||||||
|
|
||||||
|
KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
|
||||||
pSerialStatus->AmountInOutQueue = (DeviceExtension->OutputBuffer.WritePosition + DeviceExtension->OutputBuffer.Length
|
pSerialStatus->AmountInOutQueue = (DeviceExtension->OutputBuffer.WritePosition + DeviceExtension->OutputBuffer.Length
|
||||||
- DeviceExtension->OutputBuffer.ReadPosition) % DeviceExtension->OutputBuffer.Length;
|
- DeviceExtension->OutputBuffer.ReadPosition) % DeviceExtension->OutputBuffer.Length;
|
||||||
|
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
|
||||||
|
|
||||||
pSerialStatus->EofReceived = FALSE; /* FIXME */
|
pSerialStatus->EofReceived = FALSE; /* FIXME */
|
||||||
pSerialStatus->WaitForImmediate = FALSE; /* FIXME */
|
pSerialStatus->WaitForImmediate = FALSE; /* FIXME */
|
||||||
|
|
||||||
|
@ -497,8 +506,10 @@ SerialDeviceControl(
|
||||||
}
|
}
|
||||||
case IOCTL_SERIAL_PURGE:
|
case IOCTL_SERIAL_PURGE:
|
||||||
{
|
{
|
||||||
|
KIRQL Irql1, Irql2;
|
||||||
DPRINT("Serial: IOCTL_SERIAL_PURGE\n");
|
DPRINT("Serial: IOCTL_SERIAL_PURGE\n");
|
||||||
/* FIXME: lock input and output queues */
|
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql1);
|
||||||
|
KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql2);
|
||||||
DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0;
|
DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0;
|
||||||
DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0;
|
DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0;
|
||||||
/* Clear receive/transmit buffers */
|
/* Clear receive/transmit buffers */
|
||||||
|
@ -507,7 +518,8 @@ SerialDeviceControl(
|
||||||
WRITE_PORT_UCHAR(SER_FCR(ComPortBase),
|
WRITE_PORT_UCHAR(SER_FCR(ComPortBase),
|
||||||
SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT);
|
SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT);
|
||||||
}
|
}
|
||||||
/* FIXME: unlock input and output queues */
|
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql2);
|
||||||
|
KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql1);
|
||||||
Status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -618,18 +630,19 @@ SerialDeviceControl(
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
KIRQL Irql;
|
||||||
Status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
if (((PSERIAL_QUEUE_SIZE)Buffer)->InSize > DeviceExtension->InputBuffer.Length)
|
if (((PSERIAL_QUEUE_SIZE)Buffer)->InSize > DeviceExtension->InputBuffer.Length)
|
||||||
{
|
{
|
||||||
/* FIXME: lock input queue */
|
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
|
||||||
Status = IncreaseCircularBufferSize(&DeviceExtension->InputBuffer, ((PSERIAL_QUEUE_SIZE)Buffer)->InSize);
|
Status = IncreaseCircularBufferSize(&DeviceExtension->InputBuffer, ((PSERIAL_QUEUE_SIZE)Buffer)->InSize);
|
||||||
/* FIXME: unlock input queue */
|
KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
|
||||||
}
|
}
|
||||||
if (NT_SUCCESS(Status) && ((PSERIAL_QUEUE_SIZE)Buffer)->OutSize > DeviceExtension->OutputBuffer.Length)
|
if (NT_SUCCESS(Status) && ((PSERIAL_QUEUE_SIZE)Buffer)->OutSize > DeviceExtension->OutputBuffer.Length)
|
||||||
{
|
{
|
||||||
/* FIXME: lock output queue */
|
KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
|
||||||
Status = IncreaseCircularBufferSize(&DeviceExtension->OutputBuffer, ((PSERIAL_QUEUE_SIZE)Buffer)->OutSize);
|
Status = IncreaseCircularBufferSize(&DeviceExtension->OutputBuffer, ((PSERIAL_QUEUE_SIZE)Buffer)->OutSize);
|
||||||
/* FIXME: unlock output queue */
|
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -60,6 +60,67 @@ ForwardIrpAndForget(
|
||||||
return IoCallDriver(LowerDevice, Irp);
|
return IoCallDriver(LowerDevice, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID STDCALL
|
||||||
|
SerialReceiveByte(
|
||||||
|
IN PKDPC Dpc,
|
||||||
|
IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION
|
||||||
|
IN PVOID pByte, // real type UCHAR
|
||||||
|
IN PVOID Unused)
|
||||||
|
{
|
||||||
|
PSERIAL_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
UCHAR Byte;
|
||||||
|
KIRQL Irql;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)pDeviceExtension;
|
||||||
|
Byte = (UCHAR)(ULONG_PTR)pByte;
|
||||||
|
DPRINT1("Serial: received byte on COM%lu: 0x%02x (%c)\n",
|
||||||
|
DeviceExtension->ComPort, Byte, Byte);
|
||||||
|
|
||||||
|
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
|
||||||
|
Status = PushCircularBufferEntry(&DeviceExtension->InputBuffer, Byte);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* FIXME: count buffer overflow */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DPRINT1("Serial: push to buffer done\n");
|
||||||
|
KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
|
||||||
|
InterlockedIncrement(&DeviceExtension->SerialPerfStats.ReceivedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID STDCALL
|
||||||
|
SerialSendByte(
|
||||||
|
IN PKDPC Dpc,
|
||||||
|
IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION
|
||||||
|
IN PVOID Unused1,
|
||||||
|
IN PVOID Unused2)
|
||||||
|
{
|
||||||
|
PSERIAL_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
PUCHAR ComPortBase;
|
||||||
|
UCHAR Byte;
|
||||||
|
KIRQL Irql;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Status = PopCircularBufferEntry(&DeviceExtension->OutputBuffer, &Byte);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
break;
|
||||||
|
WRITE_PORT_UCHAR(SER_THR(ComPortBase), Byte);
|
||||||
|
DeviceExtension->SerialPerfStats.TransmittedCount++;
|
||||||
|
}
|
||||||
|
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
|
||||||
|
}
|
||||||
|
|
||||||
BOOLEAN STDCALL
|
BOOLEAN STDCALL
|
||||||
SerialInterruptService(
|
SerialInterruptService(
|
||||||
IN PKINTERRUPT Interrupt,
|
IN PKINTERRUPT Interrupt,
|
||||||
|
@ -70,7 +131,6 @@ SerialInterruptService(
|
||||||
UCHAR Byte;
|
UCHAR Byte;
|
||||||
PUCHAR ComPortBase;
|
PUCHAR ComPortBase;
|
||||||
UCHAR Iir;
|
UCHAR Iir;
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
DeviceObject = (PDEVICE_OBJECT)ServiceContext;
|
DeviceObject = (PDEVICE_OBJECT)ServiceContext;
|
||||||
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
@ -96,18 +156,7 @@ SerialInterruptService(
|
||||||
case SR_IIR_THR_EMPTY:
|
case SR_IIR_THR_EMPTY:
|
||||||
{
|
{
|
||||||
DPRINT("Serial: SR_IIR_THR_EMPTY\n");
|
DPRINT("Serial: SR_IIR_THR_EMPTY\n");
|
||||||
/* FIXME: lock OutputBuffer */
|
return KeInsertQueueDpc(&DeviceExtension->SendByteDpc, NULL, NULL);
|
||||||
while (!IsCircularBufferEmpty(&DeviceExtension->OutputBuffer)
|
|
||||||
&& READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE)
|
|
||||||
{
|
|
||||||
Status = PopCircularBufferEntry(&DeviceExtension->OutputBuffer, &Byte);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
break;
|
|
||||||
WRITE_PORT_UCHAR(SER_THR(ComPortBase), Byte);
|
|
||||||
DeviceExtension->SerialPerfStats.TransmittedCount++;
|
|
||||||
}
|
|
||||||
/* FIXME: unlock OutputBuffer */
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
case SR_IIR_DATA_RECEIVED:
|
case SR_IIR_DATA_RECEIVED:
|
||||||
{
|
{
|
||||||
|
@ -116,19 +165,10 @@ SerialInterruptService(
|
||||||
{
|
{
|
||||||
Byte = READ_PORT_UCHAR(SER_RBR(ComPortBase));
|
Byte = READ_PORT_UCHAR(SER_RBR(ComPortBase));
|
||||||
DPRINT1("Serial: Byte received: 0x%02x (%c)\n", Byte, Byte);
|
DPRINT1("Serial: Byte received: 0x%02x (%c)\n", Byte, Byte);
|
||||||
/* FIXME: lock InputBuffer */
|
if (!KeInsertQueueDpc(&DeviceExtension->ReceivedByteDpc, (PVOID)(ULONG_PTR)Byte, NULL))
|
||||||
Status = PushCircularBufferEntry(&DeviceExtension->InputBuffer, Byte);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
/* FIXME: count buffer overflow */
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
DPRINT1("Serial: push to buffer done\n");
|
|
||||||
/* FIXME: unlock InputBuffer */
|
|
||||||
DeviceExtension->SerialPerfStats.ReceivedCount++;
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case SR_IIR_ERROR:
|
case SR_IIR_ERROR:
|
||||||
{
|
{
|
||||||
|
|
|
@ -76,6 +76,10 @@ SerialAddDeviceInternal(
|
||||||
Status = InitializeCircularBuffer(&DeviceExtension->OutputBuffer, 16);
|
Status = InitializeCircularBuffer(&DeviceExtension->OutputBuffer, 16);
|
||||||
if (!NT_SUCCESS(Status)) goto ByeBye;
|
if (!NT_SUCCESS(Status)) goto ByeBye;
|
||||||
IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERIAL_TAG, 0, 0);
|
IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERIAL_TAG, 0, 0);
|
||||||
|
KeInitializeSpinLock(&DeviceExtension->InputBufferLock);
|
||||||
|
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_PAGEABLE (or DO_POWER_INRUSH?)
|
||||||
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
|
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
|
@ -152,13 +156,7 @@ SerialPnpStartDevice(
|
||||||
|
|
||||||
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
/* FIXME: actually, IRP_MN_START_DEVICE is sent twice to each serial device:
|
ASSERT(DeviceExtension->PnpState == dsStopped);
|
||||||
* - one when loading serial.sys
|
|
||||||
* - one when loading attached upper filter serenum.sys
|
|
||||||
* This behaviour MUST NOT exist.
|
|
||||||
* As PnP handling isn't right anyway, I didn't search how to correct this.
|
|
||||||
*/
|
|
||||||
if (DeviceExtension->PnpState == dsStarted) return STATUS_SUCCESS;
|
|
||||||
|
|
||||||
DeviceExtension->ComPort = DeviceExtension->SerialPortNumber + 1;
|
DeviceExtension->ComPort = DeviceExtension->SerialPortNumber + 1;
|
||||||
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
|
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
|
||||||
|
|
|
@ -16,12 +16,8 @@ static PVOID
|
||||||
SerialGetUserBuffer(IN PIRP Irp)
|
SerialGetUserBuffer(IN PIRP Irp)
|
||||||
{
|
{
|
||||||
ASSERT(Irp);
|
ASSERT(Irp);
|
||||||
|
|
||||||
if (Irp->MdlAddress)
|
return Irp->AssociatedIrp.SystemBuffer;
|
||||||
return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
|
|
||||||
else
|
|
||||||
/* FIXME: try buffer */
|
|
||||||
return Irp->UserBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS STDCALL
|
NTSTATUS STDCALL
|
||||||
|
@ -36,6 +32,7 @@ SerialRead(
|
||||||
PUCHAR Buffer;
|
PUCHAR Buffer;
|
||||||
PUCHAR ComPortBase;
|
PUCHAR ComPortBase;
|
||||||
UCHAR ReceivedByte;
|
UCHAR ReceivedByte;
|
||||||
|
KIRQL Irql;
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
DPRINT("Serial: IRP_MJ_READ\n");
|
DPRINT("Serial: IRP_MJ_READ\n");
|
||||||
|
@ -64,8 +61,8 @@ SerialRead(
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
goto ByeBye;
|
goto ByeBye;
|
||||||
|
|
||||||
/* FIXME: lock InputBuffer */
|
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
|
||||||
while (Length-- > 0 && !IsCircularBufferEmpty(&DeviceExtension->InputBuffer))
|
while (Length-- > 0)
|
||||||
{
|
{
|
||||||
Status = PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
|
Status = PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
|
@ -73,54 +70,117 @@ SerialRead(
|
||||||
DPRINT("Serial: read from buffer 0x%x (%c)\n", ReceivedByte, ReceivedByte);
|
DPRINT("Serial: read from buffer 0x%x (%c)\n", ReceivedByte, ReceivedByte);
|
||||||
Buffer[Information++] = ReceivedByte;
|
Buffer[Information++] = ReceivedByte;
|
||||||
}
|
}
|
||||||
|
KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
|
||||||
if (Length > 0 &&
|
if (Length > 0 &&
|
||||||
!(DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE &&
|
!(DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE &&
|
||||||
DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0 &&
|
DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0 &&
|
||||||
DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0))
|
DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0))
|
||||||
{
|
{
|
||||||
if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == 0
|
ULONG IntervalTimeout;
|
||||||
|| DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0)
|
ULONG TotalTimeout;
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
DPRINT("Serial: we must wait for %lu characters!\n", Length);
|
if (Information > 0)
|
||||||
#if 1
|
|
||||||
/* Disable interrupts */
|
|
||||||
WRITE_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress), DeviceExtension->IER & ~1);
|
|
||||||
|
|
||||||
/* Polling code */
|
|
||||||
while (Length > 0)
|
|
||||||
{
|
{
|
||||||
while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) == 0)
|
/* don't read mode bytes */
|
||||||
;
|
Length = 0;
|
||||||
ReceivedByte = READ_PORT_UCHAR(SER_RBR(ComPortBase));
|
|
||||||
Buffer[Information++] = ReceivedByte;
|
|
||||||
Length--;
|
|
||||||
}
|
}
|
||||||
/* Enable interrupts */
|
else
|
||||||
WRITE_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress), DeviceExtension->IER);
|
|
||||||
#else
|
|
||||||
while (Length > 0)
|
|
||||||
{
|
{
|
||||||
if (!IsCircularBufferEmpty(&DeviceExtension->InputBuffer))
|
/* read only one byte */
|
||||||
{
|
UseTotalTimeout = TRUE;
|
||||||
Status = PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
|
TotalTimeout = DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant;
|
||||||
if (!NT_SUCCESS(Status))
|
Length = 1;
|
||||||
break;
|
|
||||||
DPRINT1("Serial: read from buffer 0x%x (%c)\n", ReceivedByte, ReceivedByte);
|
|
||||||
Buffer[Information++] = ReceivedByte;
|
|
||||||
Length--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* FIXME: use ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant */
|
if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout != 0)
|
||||||
DPRINT1("Serial: we must wait for %lu characters at maximum within %lu milliseconds! UNIMPLEMENTED\n",
|
{
|
||||||
Length,
|
UseIntervalTimeout = TRUE;
|
||||||
Stack->Parameters.Read.Length * DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant);
|
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);
|
||||||
}
|
}
|
||||||
/* FIXME: unlock InputBuffer */
|
|
||||||
Status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||||
|
@ -143,6 +203,7 @@ SerialWrite(
|
||||||
ULONG Information = 0;
|
ULONG Information = 0;
|
||||||
PUCHAR Buffer;
|
PUCHAR Buffer;
|
||||||
PUCHAR ComPortBase;
|
PUCHAR ComPortBase;
|
||||||
|
KIRQL Irql;
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
DPRINT("Serial: IRP_MJ_WRITE\n");
|
DPRINT("Serial: IRP_MJ_WRITE\n");
|
||||||
|
@ -166,7 +227,7 @@ SerialWrite(
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
goto ByeBye;
|
goto ByeBye;
|
||||||
|
|
||||||
/* FIXME: lock OutputBuffer */
|
KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
|
||||||
if (IsCircularBufferEmpty(&DeviceExtension->OutputBuffer))
|
if (IsCircularBufferEmpty(&DeviceExtension->OutputBuffer))
|
||||||
{
|
{
|
||||||
/* Put the maximum amount of data in UART output buffer */
|
/* Put the maximum amount of data in UART output buffer */
|
||||||
|
@ -197,7 +258,7 @@ SerialWrite(
|
||||||
DPRINT1("Serial: write to buffer 0x%02x\n", Buffer[Information]);
|
DPRINT1("Serial: write to buffer 0x%02x\n", Buffer[Information]);
|
||||||
Information++;
|
Information++;
|
||||||
}
|
}
|
||||||
/* FIXME: unlock OutputBuffer */
|
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
|
||||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||||
|
|
||||||
ByeBye:
|
ByeBye:
|
||||||
|
|
|
@ -81,6 +81,8 @@ typedef struct _SERIAL_DEVICE_EXTENSION
|
||||||
ULONG BaudRate;
|
ULONG BaudRate;
|
||||||
ULONG BaseAddress;
|
ULONG BaseAddress;
|
||||||
PKINTERRUPT Interrupt;
|
PKINTERRUPT Interrupt;
|
||||||
|
KDPC ReceivedByteDpc;
|
||||||
|
KDPC SendByteDpc;
|
||||||
|
|
||||||
SERIAL_LINE_CONTROL SerialLineControl;
|
SERIAL_LINE_CONTROL SerialLineControl;
|
||||||
UART_TYPE UartType;
|
UART_TYPE UartType;
|
||||||
|
@ -90,7 +92,9 @@ typedef struct _SERIAL_DEVICE_EXTENSION
|
||||||
SERIAL_TIMEOUTS SerialTimeOuts;
|
SERIAL_TIMEOUTS SerialTimeOuts;
|
||||||
BOOLEAN IsOpened;
|
BOOLEAN IsOpened;
|
||||||
CIRCULAR_BUFFER InputBuffer;
|
CIRCULAR_BUFFER InputBuffer;
|
||||||
|
KSPIN_LOCK InputBufferLock;
|
||||||
CIRCULAR_BUFFER OutputBuffer;
|
CIRCULAR_BUFFER OutputBuffer;
|
||||||
|
KSPIN_LOCK OutputBufferLock;
|
||||||
|
|
||||||
/* Current values */
|
/* Current values */
|
||||||
UCHAR IER; /* Base+1, Interrupt Enable Register */
|
UCHAR IER; /* Base+1, Interrupt Enable Register */
|
||||||
|
@ -250,6 +254,20 @@ ForwardIrpAndForget(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN PIRP Irp);
|
IN PIRP Irp);
|
||||||
|
|
||||||
|
VOID STDCALL
|
||||||
|
SerialReceiveByte(
|
||||||
|
IN PKDPC Dpc,
|
||||||
|
IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION
|
||||||
|
IN PVOID pByte, // real type UCHAR
|
||||||
|
IN PVOID Unused);
|
||||||
|
|
||||||
|
VOID STDCALL
|
||||||
|
SerialSendByte(
|
||||||
|
IN PKDPC Dpc,
|
||||||
|
IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION
|
||||||
|
IN PVOID Unused1,
|
||||||
|
IN PVOID Unused2);
|
||||||
|
|
||||||
BOOLEAN STDCALL
|
BOOLEAN STDCALL
|
||||||
SerialInterruptService(
|
SerialInterruptService(
|
||||||
IN PKINTERRUPT Interrupt,
|
IN PKINTERRUPT Interrupt,
|
||||||
|
|
Loading…
Reference in a new issue