Modified: trunk/reactos/drivers/dd/serial/devctrl.c
Modified: trunk/reactos/drivers/dd/serial/misc.c
Modified: trunk/reactos/drivers/dd/serial/pnp.c
Modified: trunk/reactos/drivers/dd/serial/rw.c
Modified: trunk/reactos/drivers/dd/serial/serial.h
--- trunk/reactos/drivers/dd/serial/devctrl.c 2005-03-23 22:11:20 UTC (rev 14296)
+++ trunk/reactos/drivers/dd/serial/devctrl.c 2005-03-24 07:50:41 UTC (rev 14297)
@@ -215,14 +215,23 @@
OUT PSERIAL_STATUS pSerialStatus,
IN PSERIAL_DEVICE_EXTENSION DeviceExtension)
{
+ KIRQL Irql;
+
RtlZeroMemory(pSerialStatus, sizeof(SERIAL_STATUS));
pSerialStatus->Errors = 0; /* FIXME */
pSerialStatus->HoldReasons = 0; /* FIXME */
+
+ KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
pSerialStatus->AmountInInQueue = (DeviceExtension->InputBuffer.WritePosition + 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
- DeviceExtension->OutputBuffer.ReadPosition) % DeviceExtension->OutputBuffer.Length;
+ KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
+
pSerialStatus->EofReceived = FALSE; /* FIXME */
pSerialStatus->WaitForImmediate = FALSE; /* FIXME */
@@ -497,8 +506,10 @@
}
case IOCTL_SERIAL_PURGE:
{
+ KIRQL Irql1, Irql2;
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->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0;
/* Clear receive/transmit buffers */
@@ -507,7 +518,8 @@
WRITE_PORT_UCHAR(SER_FCR(ComPortBase),
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;
break;
}
@@ -618,18 +630,19 @@
return STATUS_INVALID_PARAMETER;
else
{
+ KIRQL Irql;
Status = STATUS_SUCCESS;
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);
- /* FIXME: unlock input queue */
+ KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
}
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);
- /* FIXME: unlock output queue */
+ KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
}
}
break;
--- trunk/reactos/drivers/dd/serial/misc.c 2005-03-23 22:11:20 UTC (rev 14296)
+++ trunk/reactos/drivers/dd/serial/misc.c 2005-03-24 07:50:41 UTC (rev 14297)
@@ -60,6 +60,67 @@
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
SerialInterruptService(
IN PKINTERRUPT Interrupt,
@@ -70,7 +131,6 @@
UCHAR Byte;
PUCHAR ComPortBase;
UCHAR Iir;
- NTSTATUS Status;
DeviceObject = (PDEVICE_OBJECT)ServiceContext;
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
@@ -96,18 +156,7 @@
case SR_IIR_THR_EMPTY:
{
DPRINT("Serial: SR_IIR_THR_EMPTY\n");
- /* FIXME: lock OutputBuffer */
- 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;
+ return KeInsertQueueDpc(&DeviceExtension->SendByteDpc, NULL, NULL);
}
case SR_IIR_DATA_RECEIVED:
{
@@ -116,19 +165,10 @@
{
Byte = READ_PORT_UCHAR(SER_RBR(ComPortBase));
DPRINT1("Serial: Byte received: 0x%02x (%c)\n", Byte, Byte);
- /* FIXME: lock InputBuffer */
- Status = PushCircularBufferEntry(&DeviceExtension->InputBuffer, Byte);
- if (!NT_SUCCESS(Status))
- {
- /* FIXME: count buffer overflow */
+ if (!KeInsertQueueDpc(&DeviceExtension->ReceivedByteDpc, (PVOID)(ULONG_PTR)Byte, NULL))
break;
- }
- DPRINT1("Serial: push to buffer done\n");
- /* FIXME: unlock InputBuffer */
- DeviceExtension->SerialPerfStats.ReceivedCount++;
}
return TRUE;
- break;
}
case SR_IIR_ERROR:
{
--- trunk/reactos/drivers/dd/serial/pnp.c 2005-03-23 22:11:20 UTC (rev 14296)
+++ trunk/reactos/drivers/dd/serial/pnp.c 2005-03-24 07:50:41 UTC (rev 14297)
@@ -76,6 +76,10 @@
Status = InitializeCircularBuffer(&DeviceExtension->OutputBuffer, 16);
if (!NT_SUCCESS(Status)) goto ByeBye;
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?)
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
if (!NT_SUCCESS(Status))
@@ -152,13 +156,7 @@
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
- /* FIXME: actually, IRP_MN_START_DEVICE is sent twice to each serial device:
- * - 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;
+ ASSERT(DeviceExtension->PnpState == dsStopped);
DeviceExtension->ComPort = DeviceExtension->SerialPortNumber + 1;
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
--- trunk/reactos/drivers/dd/serial/rw.c 2005-03-23 22:11:20 UTC (rev 14296)
+++ trunk/reactos/drivers/dd/serial/rw.c 2005-03-24 07:50:41 UTC (rev 14297)
@@ -16,12 +16,8 @@
SerialGetUserBuffer(IN PIRP Irp)
{
ASSERT(Irp);
-
- if (Irp->MdlAddress)
- return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
- else
- /* FIXME: try buffer */
- return Irp->UserBuffer;
+
+ return Irp->AssociatedIrp.SystemBuffer;
}
NTSTATUS STDCALL
@@ -36,6 +32,7 @@
PUCHAR Buffer;
PUCHAR ComPortBase;
UCHAR ReceivedByte;
+ KIRQL Irql;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("Serial: IRP_MJ_READ\n");
@@ -64,8 +61,8 @@
if (!NT_SUCCESS(Status))
goto ByeBye;
- /* FIXME: lock InputBuffer */
- while (Length-- > 0 && !IsCircularBufferEmpty(&DeviceExtension->InputBuffer))
+ KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
+ while (Length-- > 0)
{
Status = PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
if (!NT_SUCCESS(Status))
@@ -73,54 +70,117 @@
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))
{
- if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == 0
- || DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0)
+ ULONG IntervalTimeout;
+ 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 1
- /* Disable interrupts */
- WRITE_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress), DeviceExtension->IER & ~1);
-
- /* Polling code */
- while (Length > 0)
+ if (Information > 0)
{
- while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) == 0)
- ;
- ReceivedByte = READ_PORT_UCHAR(SER_RBR(ComPortBase));
- Buffer[Information++] = ReceivedByte;
- Length--;
+ /* don't read mode bytes */
+ Length = 0;
}
- /* Enable interrupts */
- WRITE_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress), DeviceExtension->IER);
-#else
- while (Length > 0)
+ else
{
- if (!IsCircularBufferEmpty(&DeviceExtension->InputBuffer))
+ /* 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++)
{
- Status = PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
- if (!NT_SUCCESS(Status))
+#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;
- DPRINT1("Serial: read from buffer 0x%x (%c)\n", ReceivedByte, ReceivedByte);
- Buffer[Information++] = ReceivedByte;
- Length--;
+ }
+#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--;
+ }
}
-#endif
+ if (!IsByteReceived) break;
+ Buffer[Information++] = ReceivedByte;
+ Length--;
}
- else
- {
- /* FIXME: use ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant */
- DPRINT1("Serial: we must wait for %lu characters at maximum within %lu milliseconds! UNIMPLEMENTED\n",
- Length,
- Stack->Parameters.Read.Length * DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier + DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant);
- }
+ /* FIXME: remove enabling interrupts */
+ WRITE_PORT_UCHAR(SER_IER(ComPortBase), DeviceExtension->IER);
}
- /* FIXME: unlock InputBuffer */
Status = STATUS_SUCCESS;
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
@@ -143,6 +203,7 @@
ULONG Information = 0;
PUCHAR Buffer;
PUCHAR ComPortBase;
+ KIRQL Irql;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("Serial: IRP_MJ_WRITE\n");
@@ -166,7 +227,7 @@
if (!NT_SUCCESS(Status))
goto ByeBye;
- /* FIXME: lock OutputBuffer */
+ KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
if (IsCircularBufferEmpty(&DeviceExtension->OutputBuffer))
{
/* Put the maximum amount of data in UART output buffer */
@@ -197,7 +258,7 @@
DPRINT1("Serial: write to buffer 0x%02x\n", Buffer[Information]);
Information++;
}
- /* FIXME: unlock OutputBuffer */
+ KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
ByeBye:
--- trunk/reactos/drivers/dd/serial/serial.h 2005-03-23 22:11:20 UTC (rev 14296)
+++ trunk/reactos/drivers/dd/serial/serial.h 2005-03-24 07:50:41 UTC (rev 14297)
@@ -81,6 +81,8 @@
ULONG BaudRate;
ULONG BaseAddress;
PKINTERRUPT Interrupt;
+ KDPC ReceivedByteDpc;
+ KDPC SendByteDpc;
SERIAL_LINE_CONTROL SerialLineControl;
UART_TYPE UartType;
@@ -90,7 +92,9 @@
SERIAL_TIMEOUTS SerialTimeOuts;
BOOLEAN IsOpened;
CIRCULAR_BUFFER InputBuffer;
+ KSPIN_LOCK InputBufferLock;
CIRCULAR_BUFFER OutputBuffer;
+ KSPIN_LOCK OutputBufferLock;
/* Current values */
UCHAR IER; /* Base+1, Interrupt Enable Register */
@@ -250,6 +254,20 @@
IN PDEVICE_OBJECT DeviceObject,
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
SerialInterruptService(
IN PKINTERRUPT Interrupt,