Replace polling mode in IRP_MJ_READ by an interrupt mode.
It is a lot less CPU consuming...
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
_____
Modified: trunk/reactos/drivers/dd/serial/misc.c
--- trunk/reactos/drivers/dd/serial/misc.c 2005-04-03 21:31:41 UTC
(rev 14484)
+++ trunk/reactos/drivers/dd/serial/misc.c 2005-04-03 21:36:15 UTC
(rev 14485)
@@ -64,29 +64,37 @@
SerialReceiveByte(
IN PKDPC Dpc,
IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION
- IN PVOID pByte, // real type UCHAR
- IN PVOID Unused)
+ IN PVOID Unused1,
+ IN PVOID Unused2)
{
PSERIAL_DEVICE_EXTENSION DeviceExtension;
+ PUCHAR ComPortBase;
UCHAR Byte;
KIRQL Irql;
+ UCHAR IER;
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);
+ ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
- Status = PushCircularBufferEntry(&DeviceExtension->InputBuffer,
Byte);
- if (!NT_SUCCESS(Status))
+ while (READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR)
{
- /* FIXME: count buffer overflow */
- return;
+ Byte = READ_PORT_UCHAR(SER_RBR(ComPortBase));
+ DPRINT("Serial: Byte received on COM%lu: 0x%02x\n",
+ DeviceExtension->ComPort, Byte);
+ Status =
PushCircularBufferEntry(&DeviceExtension->InputBuffer, Byte);
+ if (NT_SUCCESS(Status))
+
DeviceExtension->SerialPerfStats.ReceivedCount++;
+ else
+
DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++;
}
- DPRINT1("Serial: push to buffer done\n");
+ KeSetEvent(&DeviceExtension->InputBufferNotEmpty, 0, FALSE);
KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
-
InterlockedIncrement(&DeviceExtension->SerialPerfStats.ReceivedCount);
+
+ /* allow new interrupts */
+ IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
+ WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER |
SR_IER_DATA_RECEIVED);
}
VOID STDCALL
@@ -100,6 +108,7 @@
PUCHAR ComPortBase;
UCHAR Byte;
KIRQL Irql;
+ UCHAR IER;
NTSTATUS Status;
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)pDeviceExtension;
@@ -113,9 +122,15 @@
if (!NT_SUCCESS(Status))
break;
WRITE_PORT_UCHAR(SER_THR(ComPortBase), Byte);
+ DPRINT("Serial: Byte sent to COM%lu: 0x%02x\n",
+ DeviceExtension->ComPort, Byte);
DeviceExtension->SerialPerfStats.TransmittedCount++;
- }
+ }
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
+
+ /* allow new interrupts */
+ IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
+ WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER | SR_IER_THR_EMPTY);
}
BOOLEAN STDCALL
@@ -125,7 +140,6 @@
{
PDEVICE_OBJECT DeviceObject;
PSERIAL_DEVICE_EXTENSION DeviceExtension;
- UCHAR Byte;
PUCHAR ComPortBase;
UCHAR Iir;
@@ -139,32 +153,32 @@
Iir &= SR_IIR_ID_MASK;
if ((Iir & SR_IIR_SELF) != 0) { return FALSE; }
- /* FIXME: sometimes, update DeviceExtension->IER */
/* FIXME: sometimes, update DeviceExtension->MCR */
switch (Iir)
{
case SR_IIR_MSR_CHANGE:
{
+ UCHAR IER;
DPRINT1("Serial: SR_IIR_MSR_CHANGE\n");
+
DeviceExtension->MSR =
READ_PORT_UCHAR(SER_MSR(ComPortBase));
/* FIXME: what to do? */
+ IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
+ WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER |
SR_IER_MSR_CHANGE);
return TRUE;
}
case SR_IIR_THR_EMPTY:
{
DPRINT("Serial: SR_IIR_THR_EMPTY\n");
- return
KeInsertQueueDpc(&DeviceExtension->SendByteDpc, NULL, NULL);
+
+ KeInsertQueueDpc(&DeviceExtension->SendByteDpc,
NULL, NULL);
+ return TRUE;
}
case SR_IIR_DATA_RECEIVED:
{
- DPRINT1("Serial: SR_IIR_DATA_RECEIVED\n");
- while (READ_PORT_UCHAR(SER_LSR(ComPortBase)) &
SR_LSR_DR)
- {
- Byte =
READ_PORT_UCHAR(SER_RBR(ComPortBase));
- DPRINT1("Serial: Byte received: 0x%02x
(%c)\n", Byte, Byte);
- if
(!KeInsertQueueDpc(&DeviceExtension->ReceivedByteDpc,
(PVOID)(ULONG_PTR)Byte, NULL))
- break;
- }
+ DPRINT("Serial: SR_IIR_DATA_RECEIVED\n");
+
+
KeInsertQueueDpc(&DeviceExtension->ReceivedByteDpc, NULL, NULL);
return TRUE;
}
case SR_IIR_ERROR:
_____
Modified: trunk/reactos/drivers/dd/serial/pnp.c
--- trunk/reactos/drivers/dd/serial/pnp.c 2005-04-03 21:31:41 UTC
(rev 14484)
+++ trunk/reactos/drivers/dd/serial/pnp.c 2005-04-03 21:36:15 UTC
(rev 14485)
@@ -78,6 +78,7 @@
IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERIAL_TAG,
0, 0);
KeInitializeSpinLock(&DeviceExtension->InputBufferLock);
KeInitializeSpinLock(&DeviceExtension->OutputBufferLock);
+ KeInitializeEvent(&DeviceExtension->InputBufferNotEmpty,
NotificationEvent, FALSE);
KeInitializeDpc(&DeviceExtension->ReceivedByteDpc,
SerialReceiveByte, DeviceExtension);
KeInitializeDpc(&DeviceExtension->SendByteDpc, SerialSendByte,
DeviceExtension);
Fdo->Flags |= DO_POWER_PAGABLE;
@@ -144,6 +145,7 @@
UNICODE_STRING ComPort;
ULONG Vector = 0;
ULONG i, j;
+ UCHAR IER;
KIRQL Dirql;
KAFFINITY Affinity = 0;
KINTERRUPT_MODE InterruptMode = Latched;
@@ -195,8 +197,6 @@
DeviceExtension->BaseAddress, Dirql);
if (!DeviceExtension->BaseAddress)
return STATUS_INSUFFICIENT_RESOURCES;
- /* FIXME: we should be able to continue and use polling method
- * for read/write if we don't have an interrupt */
if (!Dirql)
return STATUS_INSUFFICIENT_RESOURCES;
ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
@@ -205,7 +205,6 @@
DeviceExtension->UartType =
SerialDetectUartType(ComPortBase);
/* Get current settings */
- DeviceExtension->IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
DeviceExtension->MCR = READ_PORT_UCHAR(SER_MCR(ComPortBase));
DeviceExtension->MSR = READ_PORT_UCHAR(SER_MSR(ComPortBase));
DeviceExtension->WaitMask = 0;
@@ -279,11 +278,13 @@
DeviceExtension->PnpState = dsStarted;
- DeviceExtension->IER |= 0x1f; /* Activate interrupt mode */
- DeviceExtension->IER &= ~1; /* FIXME: Disable receive byte
interrupt */
- WRITE_PORT_UCHAR(SER_IER(ComPortBase), DeviceExtension->IER);
+ /* Activate interrupt modes */
+ IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
+ IER |= SR_IER_DATA_RECEIVED | SR_IER_THR_EMPTY |
SR_IER_LSR_CHANGE | SR_IER_MSR_CHANGE;
+ WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER);
- DeviceExtension->MCR |= 0x03; /* Activate DTR, RTS */
+ /* Activate DTR, RTS */
+ DeviceExtension->MCR |= SR_MCR_DTR | SR_MCR_RTS;
WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
return STATUS_SUCCESS;
@@ -331,11 +332,19 @@
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;
+ switch
(((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->SerialPortNu
mber)
+ {
+ case 0:
+ ComPortBase = 0x3f8;
+ Irq = 4;
+ break;
+ case 1:
+ ComPortBase = 0x2f8;
+ Irq = 3;
+ break;
+ default:
+ ComPortBase = Irq = 0;
+ }
/* Create resource list */
ResourceListSize =
sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
_____
Modified: trunk/reactos/drivers/dd/serial/rw.c
--- trunk/reactos/drivers/dd/serial/rw.c 2005-04-03 21:31:41 UTC
(rev 14484)
+++ trunk/reactos/drivers/dd/serial/rw.c 2005-04-03 21:36:15 UTC
(rev 14485)
@@ -7,7 +7,6 @@
*
* PROGRAMMERS: HervÚ Poussineau (poussine(a)freesurf.fr)
*/
-/* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O
operation */
#define NDEBUG
#include "serial.h"
@@ -30,84 +29,81 @@
PUCHAR ComPortBase;
ULONG Length;
PUCHAR Buffer;
- ULONG Information = 0;
- LARGE_INTEGER SystemTime, ByteTimeoutTime;
UCHAR ReceivedByte;
- BOOLEAN IsByteReceived;
- //KIRQL Irql;
+ KTIMER TotalTimeoutTimer;
+ KIRQL Irql;
+ ULONG ObjectCount;
+ PVOID ObjectsArray[2];
+ ULONG Information = 0;
+ NTSTATUS Status;
- 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);
+ DPRINT("Serial: UseIntervalTimeout = %s, IntervalTimeout =
%lu\n",
+ WorkItemData->UseIntervalTimeout ? "YES" : "NO",
+ WorkItemData->UseIntervalTimeout ?
WorkItemData->IntervalTimeout.QuadPart : 0);
+ DPRINT("Serial: UseTotalTimeout = %s\n",
+ WorkItemData->UseTotalTimeout ? "YES" : "NO");
+
+ ObjectCount = 1;
+ ObjectsArray[0] = &DeviceExtension->InputBufferNotEmpty;
+ if (WorkItemData->UseTotalTimeout)
+ {
+ KeInitializeTimer(&TotalTimeoutTimer);
+ KeSetTimer(&TotalTimeoutTimer,
WorkItemData->TotalTimeoutTime, NULL);
+ ObjectsArray[ObjectCount] = &TotalTimeoutTimer;
+ ObjectCount++;
+ }
+
+ /* while buffer is not fully filled */
while (Length > 0)
{
- /* Calculate dead line to receive the next byte */
- KeQuerySystemTime(&SystemTime);
- ByteTimeoutTime.QuadPart = SystemTime.QuadPart +
- WorkItemData->IntervalTimeout * 10000;
+ /* read already received bytes from buffer */
+ KeAcquireSpinLock(&DeviceExtension->InputBufferLock,
&Irql);
+ while
(!IsCircularBufferEmpty(&DeviceExtension->InputBuffer)
+ && Length > 0)
+ {
+
PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
+ DPRINT("Serial: reading byte from buffer:
0x%02x\n", ReceivedByte);
+
+ Buffer[Information++] = ReceivedByte;
+ Length--;
+ }
+ KeClearEvent(&DeviceExtension->InputBufferNotEmpty);
+ KeReleaseSpinLock(&DeviceExtension->InputBufferLock,
Irql);
- IsByteReceived = FALSE;
- while (TRUE)
+ if (WorkItemData->DontWait
+ && !(WorkItemData->ReadAtLeastOneByte &&
Information == 0))
{
-#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;
- }
+ DPRINT("Serial: buffer empty. Don't wait more
bytes\n");
+ break;
}
- if (!IsByteReceived) break;
- Buffer[Information++] = ReceivedByte;
- Length--;
+
+ Status = KeWaitForMultipleObjects(
+ ObjectCount,
+ ObjectsArray,
+ WaitAny,
+ Executive,
+ KernelMode,
+ FALSE,
+ (WorkItemData->UseIntervalTimeout && Information
0) ? &WorkItemData->IntervalTimeout : NULL,
+ NULL);
+
+ if (Status == STATUS_TIMEOUT /* interval timeout */
+ || Status == STATUS_WAIT_1) /* total timeout */
+ {
+ DPRINT("Serial: timeout when reading bytes.
Status = 0x%08lx\n", Status);
+ break;
+ }
}
- /* FIXME: remove enabling interrupts */
- WRITE_PORT_UCHAR(SER_IER(ComPortBase), DeviceExtension->IER);
+ /* stop total timeout timer */
+ if (WorkItemData->UseTotalTimeout)
+ KeCancelTimer(&TotalTimeoutTimer);
+
Irp->IoStatus.Information = Information;
if (Information == 0)
Irp->IoStatus.Status = STATUS_TIMEOUT;
@@ -148,8 +144,6 @@
DPRINT("Serial: IRP_MJ_READ\n");
- /* FIXME: pend operation if possible */
-
Stack = IoGetCurrentIrpStackLocation(Irp);
Length = Stack->Parameters.Read.Length;
Buffer = SerialGetUserBuffer(Irp);
@@ -200,7 +194,7 @@
if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout
!= 0)
{
WorkItemData->UseIntervalTimeout = TRUE;
- WorkItemData->IntervalTimeout =
DeviceExtension->SerialTimeOuts.ReadIntervalTimeout;
+ WorkItemData->IntervalTimeout.QuadPart =
DeviceExtension->SerialTimeOuts.ReadIntervalTimeout;
}
if
(DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier != 0 ||
DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant != 0)
_____
Modified: trunk/reactos/drivers/dd/serial/serial.h
--- trunk/reactos/drivers/dd/serial/serial.h 2005-04-03 21:31:41 UTC
(rev 14484)
+++ trunk/reactos/drivers/dd/serial/serial.h 2005-04-03 21:36:15 UTC
(rev 14485)
@@ -54,10 +54,12 @@
typedef enum
{
UartUnknown,
- Uart8250,
- Uart16450,
- Uart16550,
- Uart16550A
+ Uart8250, /* initial version */
+ Uart16450, /* + 38.4 Kbps */
+ Uart16550, /* + 115 Kbps */
+ Uart16550A,/* + FIFO 16 bytes */
+ Uart16650, /* + FIFO 32 bytes, 230 Kbps, power management,
auto-flow */
+ Uart16750 /* + FIFO 64 bytes, 460 Kbps */
} UART_TYPE;
typedef struct _CIRCULAR_BUFFER
@@ -90,14 +92,14 @@
SERIALPERF_STATS SerialPerfStats;
SERIAL_TIMEOUTS SerialTimeOuts;
- BOOLEAN IsOpened;
+ BOOLEAN IsOpened;
+ KEVENT InputBufferNotEmpty;
CIRCULAR_BUFFER InputBuffer;
KSPIN_LOCK InputBufferLock;
CIRCULAR_BUFFER OutputBuffer;
KSPIN_LOCK OutputBufferLock;
/* Current values */
- UCHAR IER; /* Base+1, Interrupt Enable Register */
UCHAR MCR; /* Base+4, Modem Control Register */
UCHAR MSR; /* Base+6, Modem Status Register */
} SERIAL_DEVICE_EXTENSION, *PSERIAL_DEVICE_EXTENSION;
@@ -108,7 +110,7 @@
BOOLEAN UseIntervalTimeout;
BOOLEAN UseTotalTimeout;
- ULONG IntervalTimeout;
+ LARGE_INTEGER IntervalTimeout;
LARGE_INTEGER TotalTimeoutTime;
BOOLEAN DontWait;
BOOLEAN ReadAtLeastOneByte;
@@ -120,22 +122,28 @@
/* Baud master clock */
#define BAUD_CLOCK 1843200
-#define CLOCKS_PER_BIT 16
+#define CLOCKS_PER_BIT 16
/* UART registers and bits */
-#define SER_RBR(x) ((x)+0)
-#define SER_THR(x) ((x)+0)
-#define SER_DLL(x) ((x)+0)
-#define SER_IER(x) ((x)+1)
-#define SER_DLM(x) ((x)+1)
-#define SER_IIR(x) ((x)+2)
+#define SER_RBR(x) ((x)+0) /* Receive Register */
+#define SER_THR(x) ((x)+0) /* Transmit Register */
+#define SER_DLL(x) ((x)+0) /* Baud Rate Divisor LSB */
+#define SER_IER(x) ((x)+1) /* Interrupt Enable Register */
+#define SR_IER_DATA_RECEIVED 0x01
+#define SR_IER_THR_EMPTY 0x02
+#define SR_IER_LSR_CHANGE 0x04
+#define SR_IER_MSR_CHANGE 0x08
+#define SR_IER_SLEEP_MODE 0x10 /* Uart >= 16750 */
+#define SR_IER_LOW_POWER 0x20 /* Uart >= 16750 */
+#define SER_DLM(x) ((x)+1) /* Baud Rate Divisor MSB */
+#define SER_IIR(x) ((x)+2) /* Interrupt Identification Register */
#define SR_IIR_SELF 0x00
#define SR_IIR_ID_MASK 0x07
#define SR_IIR_MSR_CHANGE SR_IIR_SELF
#define SR_IIR_THR_EMPTY (SR_IIR_SELF | 2)
#define SR_IIR_DATA_RECEIVED (SR_IIR_SELF | 4)
#define SR_IIR_ERROR (SR_IIR_SELF | 6)
-#define SER_FCR(x) ((x)+2)
+#define SER_FCR(x) ((x)+2) /* FIFO Control Register (Uart >=
16550A) */
#define SR_FCR_ENABLE_FIFO 0x01
#define SR_FCR_CLEAR_RCVR (0x02 | SR_FCR_ENABLE_FIFO)
#define SR_FCR_CLEAR_XMIT (0x04 | SR_FCR_ENABLE_FIFO)
@@ -143,7 +151,7 @@
#define SR_FCR_4_BYTES (0x40 | SR_FCR_ENABLE_FIFO)
#define SR_FCR_8_BYTES (0x80 | SR_FCR_ENABLE_FIFO)
#define SR_FCR_14_BYTES (0xC0 | SR_FCR_ENABLE_FIFO)
-#define SER_LCR(x) ((x)+3)
+#define SER_LCR(x) ((x)+3) /* Line Control Register */
#define SR_LCR_CS5 0x00
#define SR_LCR_CS6 0x01
#define SR_LCR_CS7 0x02
@@ -157,16 +165,16 @@
#define SR_LCR_PSP 0x38
#define SR_LCR_BRK 0x40
#define SR_LCR_DLAB 0x80
-#define SER_MCR(x) ((x)+4)
+#define SER_MCR(x) ((x)+4) /* Modem Control Register */
#define SR_MCR_DTR 0x01
#define SR_MCR_RTS 0x02
-#define SER_LSR(x) ((x)+5)
+#define SER_LSR(x) ((x)+5) /* Line Status Register */
#define SR_LSR_DR 0x01
#define SR_LSR_TBE 0x20
-#define SER_MSR(x) ((x)+6)
+#define SER_MSR(x) ((x)+6) /* Modem Status Register */
#define SR_MSR_CTS 0x10
#define SR_MSR_DSR 0x20
-#define SER_SCR(x) ((x)+7)
+#define SER_SCR(x) ((x)+7) /* Scratch Pad Register */
/************************************ circularbuffer.c */