mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
Implement legacy detection (it should be able to detect the first two serial ports)
Implement reading by polling (expect lots of bugs!) Use receive and send queues Better handling of some IRPs Lots of small bugs fixes svn path=/trunk/; revision=14177
This commit is contained in:
parent
343e3f7bdc
commit
08da4a07b0
12 changed files with 653 additions and 202 deletions
67
reactos/drivers/dd/serial/circularbuffer.c
Normal file
67
reactos/drivers/dd/serial/circularbuffer.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* $Id:
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: drivers/dd/serial/circularbuffer.c
|
||||
* PURPOSE: Operations on a circular buffer
|
||||
*
|
||||
* PROGRAMMERS: Hervé Poussineau (poussine@freesurf.fr)
|
||||
*/
|
||||
|
||||
//#define NDEBUG
|
||||
#include "serial.h"
|
||||
|
||||
NTSTATUS
|
||||
InitializeCircularBuffer(
|
||||
IN PCIRCULAR_BUFFER pBuffer,
|
||||
IN ULONG BufferSize)
|
||||
{
|
||||
pBuffer->Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize * sizeof(UCHAR), SERIAL_TAG);
|
||||
if (!pBuffer->Buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
pBuffer->Length = BufferSize;
|
||||
pBuffer->ReadPosition = pBuffer->WritePosition = 0;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FreeCircularBuffer(
|
||||
IN PCIRCULAR_BUFFER pBuffer)
|
||||
{
|
||||
ExFreePoolWithTag(pBuffer->Buffer, SERIAL_TAG);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
IsCircularBufferEmpty(
|
||||
IN PCIRCULAR_BUFFER pBuffer)
|
||||
{
|
||||
return (pBuffer->ReadPosition == pBuffer->WritePosition);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
PushCircularBufferEntry(
|
||||
IN PCIRCULAR_BUFFER pBuffer,
|
||||
IN UCHAR Entry)
|
||||
{
|
||||
ASSERT(pBuffer->Length);
|
||||
ULONG NextPosition = (pBuffer->WritePosition + 1) % pBuffer->Length;
|
||||
if (NextPosition == pBuffer->ReadPosition)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
pBuffer->Buffer[pBuffer->WritePosition] = Entry;
|
||||
pBuffer->WritePosition = NextPosition;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
PopCircularBufferEntry(
|
||||
IN PCIRCULAR_BUFFER pBuffer,
|
||||
OUT PUCHAR Entry)
|
||||
{
|
||||
ASSERT(pBuffer->Length);
|
||||
if (IsCircularBufferEmpty(pBuffer))
|
||||
return STATUS_ARRAY_BOUNDS_EXCEEDED;
|
||||
*Entry = pBuffer->Buffer[pBuffer->ReadPosition];
|
||||
pBuffer->ReadPosition = (pBuffer->ReadPosition + 1) % pBuffer->Length;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
|
@ -17,6 +17,8 @@ SerialCleanup(
|
|||
IN PIRP Irp)
|
||||
{
|
||||
DPRINT("Serial: IRP_MJ_CLEANUP\n");
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -19,34 +19,36 @@ SerialSetBaudRate(
|
|||
{
|
||||
USHORT divisor;
|
||||
PUCHAR ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
|
||||
ULONG BaudRate;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
if (NewBaudRate & SERIAL_BAUD_USER)
|
||||
{
|
||||
divisor = (USHORT)(BAUD_CLOCK / (CLOCKS_PER_BIT * (NewBaudRate & ~SERIAL_BAUD_USER)));
|
||||
BaudRate = NewBaudRate & ~SERIAL_BAUD_USER;
|
||||
divisor = (USHORT)(BAUD_CLOCK / (CLOCKS_PER_BIT * BaudRate));
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (NewBaudRate)
|
||||
{
|
||||
case SERIAL_BAUD_075: divisor = 0x600; break;
|
||||
case SERIAL_BAUD_110: divisor = 0x400; break;
|
||||
case SERIAL_BAUD_134_5: divisor = 0x360; break;
|
||||
case SERIAL_BAUD_150: divisor = 0x300; break;
|
||||
case SERIAL_BAUD_300: divisor = 0x180; break;
|
||||
case SERIAL_BAUD_600: divisor = 0xc0; break;
|
||||
case SERIAL_BAUD_1200: divisor = 0x60; break;
|
||||
case SERIAL_BAUD_1800: divisor = 0x40; break;
|
||||
case SERIAL_BAUD_2400: divisor = 0x30; break;
|
||||
case SERIAL_BAUD_4800: divisor = 0x18; break;
|
||||
case SERIAL_BAUD_7200: divisor = 0x10; break;
|
||||
case SERIAL_BAUD_9600: divisor = 0xc; break;
|
||||
case SERIAL_BAUD_14400: divisor = 0x8; break;
|
||||
case SERIAL_BAUD_38400: divisor = 0x3; break;
|
||||
case SERIAL_BAUD_57600: divisor = 0x2; break;
|
||||
case SERIAL_BAUD_115200: divisor = 0x1; break;
|
||||
case SERIAL_BAUD_56K: divisor = 0x2; break;
|
||||
case SERIAL_BAUD_128K: divisor = 0x1; break;
|
||||
case SERIAL_BAUD_075: divisor = 0x600; BaudRate = 75; break;
|
||||
case SERIAL_BAUD_110: divisor = 0x400; BaudRate = 110; break;
|
||||
case SERIAL_BAUD_134_5: divisor = 0x360; BaudRate = 134; break;
|
||||
case SERIAL_BAUD_150: divisor = 0x300; BaudRate = 150; break;
|
||||
case SERIAL_BAUD_300: divisor = 0x180; BaudRate = 300; break;
|
||||
case SERIAL_BAUD_600: divisor = 0xc0; BaudRate = 600; break;
|
||||
case SERIAL_BAUD_1200: divisor = 0x60; BaudRate = 1200; break;
|
||||
case SERIAL_BAUD_1800: divisor = 0x40; BaudRate = 1800; break;
|
||||
case SERIAL_BAUD_2400: divisor = 0x30; BaudRate = 2400; break;
|
||||
case SERIAL_BAUD_4800: divisor = 0x18; BaudRate = 4800; break;
|
||||
case SERIAL_BAUD_7200: divisor = 0x10; BaudRate = 7200; break;
|
||||
case SERIAL_BAUD_9600: divisor = 0xc; BaudRate = 9600; break;
|
||||
case SERIAL_BAUD_14400: divisor = 0x8; BaudRate = 14400; break;
|
||||
case SERIAL_BAUD_38400: divisor = 0x3; BaudRate = 38400; break;
|
||||
case SERIAL_BAUD_57600: divisor = 0x2; BaudRate = 57600; break;
|
||||
case SERIAL_BAUD_115200: divisor = 0x1; BaudRate = 115200; break;
|
||||
case SERIAL_BAUD_56K: divisor = 0x2; BaudRate = 57600; break;
|
||||
case SERIAL_BAUD_128K: divisor = 0x1; BaudRate = 115200; break;
|
||||
default: Status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +59,7 @@ SerialSetBaudRate(
|
|||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
UCHAR Lcr;
|
||||
DPRINT("Serial: SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension->ComPort, BAUD_CLOCK / (CLOCKS_PER_BIT * divisor));
|
||||
DPRINT("Serial: SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension->ComPort, BaudRate);
|
||||
/* FIXME: update DeviceExtension->LowerDevice when modifying LCR? */
|
||||
/* Set Bit 7 of LCR to expose baud registers */
|
||||
Lcr = READ_PORT_UCHAR(SER_LCR(ComPortBase));
|
||||
|
@ -84,6 +86,7 @@ SerialSetLineControl(
|
|||
IN PSERIAL_DEVICE_EXTENSION DeviceExtension,
|
||||
IN PSERIAL_LINE_CONTROL NewSettings)
|
||||
{
|
||||
PUCHAR ComPortBase;
|
||||
UCHAR Lcr = 0;
|
||||
NTSTATUS Status;
|
||||
|
||||
|
@ -133,10 +136,14 @@ SerialSetLineControl(
|
|||
}
|
||||
|
||||
/* Update current parameters */
|
||||
ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
|
||||
Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
WRITE_PORT_UCHAR(SER_LCR((PUCHAR)DeviceExtension->BaseAddress), Lcr);
|
||||
WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr);
|
||||
|
||||
/* Read junk out of RBR */
|
||||
READ_PORT_UCHAR(SER_RBR(ComPortBase));
|
||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
|
@ -145,7 +152,7 @@ SerialSetLineControl(
|
|||
return Status;
|
||||
}
|
||||
|
||||
BOOL
|
||||
BOOLEAN
|
||||
SerialClearPerfStats(
|
||||
IN PSERIALPERF_STATS pSerialPerfStats)
|
||||
{
|
||||
|
@ -153,7 +160,7 @@ SerialClearPerfStats(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
BOOLEAN
|
||||
SerialGetPerfStats(IN PIRP pIrp)
|
||||
{
|
||||
PSERIAL_DEVICE_EXTENSION pDeviceExtension;
|
||||
|
@ -349,7 +356,7 @@ SerialDeviceControl(
|
|||
}
|
||||
case IOCTL_SERIAL_GET_STATS:
|
||||
{
|
||||
DPRINT1("Serial: IOCTL_SERIAL_GET_STATS\n");
|
||||
DPRINT("Serial: IOCTL_SERIAL_GET_STATS\n");
|
||||
if (LengthOut < sizeof(SERIALPERF_STATS))
|
||||
{
|
||||
DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
|
||||
|
@ -364,16 +371,21 @@ SerialDeviceControl(
|
|||
{
|
||||
KeSynchronizeExecution(DeviceExtension->Interrupt,
|
||||
(PKSYNCHRONIZE_ROUTINE)SerialGetPerfStats, Irp);
|
||||
Status = STATUS_SUCCESS;
|
||||
Information = sizeof(SERIALPERF_STATS);
|
||||
Status = STATUS_SUCCESS;
|
||||
Information = sizeof(SERIALPERF_STATS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_TIMEOUTS:
|
||||
{
|
||||
/* FIXME */
|
||||
DPRINT1("Serial: IOCTL_SERIAL_GET_TIMEOUTS not implemented.\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
DPRINT("Serial: IOCTL_SERIAL_GET_TIMEOUTS\n");
|
||||
if (LengthOut != sizeof(SERIAL_TIMEOUTS) || Buffer == NULL)
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
else
|
||||
{
|
||||
*(PSERIAL_TIMEOUTS)Buffer = DeviceExtension->SerialTimeOuts;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_WAIT_MASK:
|
||||
|
@ -532,9 +544,14 @@ SerialDeviceControl(
|
|||
}
|
||||
case IOCTL_SERIAL_SET_TIMEOUTS:
|
||||
{
|
||||
/* FIXME */
|
||||
DPRINT1("Serial: IOCTL_SERIAL_SET_TIMEOUTS not implemented.\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
DPRINT("Serial: IOCTL_SERIAL_SET_TIMEOUTS\n");
|
||||
if (LengthIn != sizeof(SERIAL_TIMEOUTS) || Buffer == NULL)
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
else
|
||||
{
|
||||
DeviceExtension->SerialTimeOuts = *(PSERIAL_TIMEOUTS)Buffer;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_WAIT_MASK:
|
||||
|
|
|
@ -20,6 +20,7 @@ SerialQueryInformation(
|
|||
PIO_STACK_LOCATION Stack;
|
||||
PVOID SystemBuffer;
|
||||
ULONG BufferLength;
|
||||
ULONG Information = 0;
|
||||
NTSTATUS Status;
|
||||
|
||||
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
@ -45,9 +46,6 @@ SerialQueryInformation(
|
|||
StandardInfo->DeletePending = FALSE; /* FIXME: should be TRUE sometimes */
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
break;
|
||||
}
|
||||
case FilePositionInformation:
|
||||
|
@ -62,18 +60,17 @@ SerialQueryInformation(
|
|||
PositionInfo->CurrentByteOffset.QuadPart = 0;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DPRINT("Serial: IRP_MJ_QUERY_INFORMATION: Unexpected file information class 0x%02x\n", Stack->Parameters.QueryFile.FileInformationClass);
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
|
||||
return ForwardIrpAndForget(DeviceObject, Irp);
|
||||
}
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = Information;
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
||||
|
|
162
reactos/drivers/dd/serial/legacy.c
Normal file
162
reactos/drivers/dd/serial/legacy.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/* $Id:
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: drivers/bus/serial/legacy.c
|
||||
* PURPOSE: Legacy serial port enumeration
|
||||
*
|
||||
* PROGRAMMERS: Hervé Poussineau (poussine@freesurf.fr)
|
||||
*/
|
||||
|
||||
#define NDEBUG
|
||||
#include "serial.h"
|
||||
|
||||
static BOOLEAN
|
||||
SerialDoesPortExist(PUCHAR BaseAddress)
|
||||
{
|
||||
BOOLEAN Found;
|
||||
BYTE Mcr;
|
||||
BYTE Msr;
|
||||
|
||||
Found = FALSE;
|
||||
|
||||
/* save Modem Control Register (MCR) */
|
||||
Mcr = READ_PORT_UCHAR(SER_MCR(BaseAddress));
|
||||
|
||||
/* enable loop mode (set Bit 4 of the MCR) */
|
||||
WRITE_PORT_UCHAR(SER_MCR(BaseAddress), 0x10);
|
||||
|
||||
/* clear all modem output bits */
|
||||
WRITE_PORT_UCHAR(SER_MCR(BaseAddress), 0x10);
|
||||
|
||||
/* read the Modem Status Register */
|
||||
Msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
|
||||
|
||||
/*
|
||||
* the upper nibble of the MSR (modem output bits) must be
|
||||
* equal to the lower nibble of the MCR (modem input bits)
|
||||
*/
|
||||
if ((Msr & 0xf0) == 0x00)
|
||||
{
|
||||
/* set all modem output bits */
|
||||
WRITE_PORT_UCHAR(SER_MCR(BaseAddress), 0x1f);
|
||||
|
||||
/* read the Modem Status Register */
|
||||
Msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
|
||||
|
||||
/*
|
||||
* the upper nibble of the MSR (modem output bits) must be
|
||||
* equal to the lower nibble of the MCR (modem input bits)
|
||||
*/
|
||||
if ((Msr & 0xf0) == 0xf0)
|
||||
{
|
||||
/*
|
||||
* setup a resonable state for the port:
|
||||
* enable fifo and clear recieve/transmit buffers
|
||||
*/
|
||||
WRITE_PORT_UCHAR(SER_FCR(BaseAddress),
|
||||
(SR_FCR_ENABLE_FIFO | SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT));
|
||||
WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
|
||||
READ_PORT_UCHAR(SER_RBR(BaseAddress));
|
||||
WRITE_PORT_UCHAR(SER_IER(BaseAddress), 0);
|
||||
Found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* restore MCR */
|
||||
WRITE_PORT_UCHAR(SER_MCR(BaseAddress), Mcr);
|
||||
|
||||
return Found;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
DetectLegacyDevice(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN ULONG ComPortBase,
|
||||
IN ULONG Irq)
|
||||
{
|
||||
ULONG ResourceListSize;
|
||||
PCM_RESOURCE_LIST ResourceList;
|
||||
BOOLEAN ConflictDetected, FoundPort;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Create resource list */
|
||||
ResourceListSize = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||||
ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(NonPagedPool, 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;
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO;
|
||||
// FIXME ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start = ComPortBase;
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = 8;
|
||||
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].Type = CmResourceTypeInterrupt;
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].ShareDisposition = CmResourceShareDriverExclusive;
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
|
||||
/* FIXME: ResourceList->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Level = ;
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Vector = ;
|
||||
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Affinity = ;*/
|
||||
|
||||
/* Report resource list */
|
||||
Status = IoReportResourceForDetection(
|
||||
DriverObject, ResourceList, ResourceListSize,
|
||||
NULL, NULL, 0,
|
||||
&ConflictDetected);
|
||||
if (ConflictDetected)
|
||||
return STATUS_DEVICE_NOT_CONNECTED;
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
/* Test if port exists */
|
||||
FoundPort = SerialDoesPortExist((PUCHAR)ComPortBase);
|
||||
|
||||
/* Report device if detected... */
|
||||
if (FoundPort)
|
||||
{
|
||||
Status = IoReportDetectedDevice(
|
||||
DriverObject,
|
||||
ResourceList->List[0].InterfaceType, ResourceList->List[0].BusNumber, -1/*FIXME*/,
|
||||
ResourceList, NULL,
|
||||
TRUE,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Release resources */
|
||||
Status = IoReportResourceForDetection(
|
||||
DriverObject, NULL, 0,
|
||||
NULL, NULL, 0,
|
||||
&ConflictDetected);
|
||||
Status = STATUS_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
DetectLegacyDevices(
|
||||
IN PDRIVER_OBJECT DriverObject)
|
||||
{
|
||||
ULONG ComPortBase[] = { 0x3f8, 0x2f8 };
|
||||
ULONG Irq[] = { 4, 3 };
|
||||
ULONG i;
|
||||
NTSTATUS Status;
|
||||
|
||||
for (i = 0; i < sizeof(ComPortBase)/sizeof(ComPortBase[0]); i++)
|
||||
{
|
||||
Status = DetectLegacyDevice(DriverObject, ComPortBase[i], Irq[i]);
|
||||
DPRINT("Serial: Legacy device at 0x%x (IRQ %lu): status = 0x%08x\n", ComPortBase[i], Irq[i], Status);
|
||||
if (Status == STATUS_DEVICE_NOT_CONNECTED)
|
||||
Status = STATUS_SUCCESS;
|
||||
else if (!NT_SUCCESS(Status))
|
||||
break;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -7,11 +7,13 @@ TARGET_TYPE = driver
|
|||
TARGET_NAME = serial
|
||||
|
||||
TARGET_OBJECTS = \
|
||||
circularbuffer.o \
|
||||
cleanup.o \
|
||||
close.o \
|
||||
create.o \
|
||||
devctrl.o \
|
||||
info.o \
|
||||
legacy.o \
|
||||
misc.o \
|
||||
pnp.o \
|
||||
power.o \
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
*
|
||||
* PROGRAMMERS: Hervé Poussineau (poussine@freesurf.fr)
|
||||
*/
|
||||
/* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */
|
||||
|
||||
#define NDEBUG
|
||||
#include "serial.h"
|
||||
|
||||
NTSTATUS
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpAndWaitCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
|
@ -48,6 +49,17 @@ ForwardIrpAndWait(
|
|||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpAndForget(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PDEVICE_OBJECT LowerDevice = ((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
|
||||
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
return IoCallDriver(LowerDevice, Irp);
|
||||
}
|
||||
|
||||
BOOLEAN STDCALL
|
||||
SerialInterruptService(
|
||||
IN PKINTERRUPT Interrupt,
|
||||
|
@ -55,29 +67,23 @@ SerialInterruptService(
|
|||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
PSERIAL_DEVICE_EXTENSION DeviceExtension;
|
||||
UCHAR Byte;
|
||||
PUCHAR ComPortBase;
|
||||
UCHAR Iir;
|
||||
NTSTATUS Status;
|
||||
|
||||
DeviceObject = (PDEVICE_OBJECT)ServiceContext;
|
||||
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
|
||||
|
||||
DPRINT1("Serial: Maybe our interrupt?\n"); /* FIXME */
|
||||
|
||||
Iir = READ_PORT_UCHAR(SER_IIR(ComPortBase));
|
||||
#if 0
|
||||
if (Iir == 0xff)
|
||||
return TRUE;
|
||||
CHECKPOINT1;
|
||||
Iir &= SR_IIR_ID_MASK;
|
||||
if (!(Iir & SR_IIR_SELF)) { return FALSE; }
|
||||
CHECKPOINT1;
|
||||
#else
|
||||
Iir &= SR_IIR_ID_MASK;
|
||||
Iir |= SR_IIR_SELF;
|
||||
#endif
|
||||
DPRINT1("Serial: Iir = 0x%x\n", Iir);
|
||||
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:
|
||||
|
@ -85,46 +91,60 @@ SerialInterruptService(
|
|||
DPRINT1("Serial: SR_IIR_MSR_CHANGE\n");
|
||||
DeviceExtension->MSR = READ_PORT_UCHAR(SER_MSR(ComPortBase));
|
||||
/* FIXME: what to do? */
|
||||
//return KeInsertQueueDpc (&Self->MsrChangeDpc, Self, 0);
|
||||
//return TRUE;
|
||||
break;
|
||||
return TRUE;
|
||||
}
|
||||
case SR_IIR_THR_EMPTY:
|
||||
{
|
||||
DPRINT1("Serial: SR_IIR_THR_EMPTY\n");
|
||||
break;
|
||||
/*if (!Self->WaitingSendBytes.Empty() &&
|
||||
(READ_PORT_UCHAR( Self->Port + UART_LSR ) & LSR_THR_EMPTY) )
|
||||
WRITE_PORT_UCHAR( Self->Port + UART_THR,
|
||||
Self->WaitingSendBytes.PopFront() );
|
||||
return KeInsertQueueDpc( &Self->TransmitDpc, Self, 0 );*/
|
||||
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;
|
||||
}
|
||||
case SR_IIR_DATA_RECEIVED:
|
||||
{
|
||||
DPRINT1("Serial: SR_IIR_DATA_RECEIVED\n");
|
||||
if (READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR)
|
||||
while (READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR)
|
||||
{
|
||||
DPRINT1("Serial: Byte received: 0x%x\n", READ_PORT_UCHAR(SER_RBR(ComPortBase)));
|
||||
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 */
|
||||
break;
|
||||
}
|
||||
DPRINT1("Serial: push to buffer done\n");
|
||||
/* FIXME: unlock InputBuffer */
|
||||
DeviceExtension->SerialPerfStats.ReceivedCount++;
|
||||
return TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
break;
|
||||
/*if( READ_PORT_UCHAR( Self->Port + UART_LSR ) & LSR_DATA_RECEIVED )
|
||||
Self->WaitingReadBytes.PushBack
|
||||
( READ_PORT_UCHAR( Self->Port + UART_RDR ) );
|
||||
return KeInsertQueueDpc( &Self->DataInDpc, Self, 0 );*/
|
||||
}
|
||||
case SR_IIR_ERROR:
|
||||
{
|
||||
/* FIXME: what to do? */
|
||||
DPRINT1("Serial: SR_IIR_ERROR\n");
|
||||
break;
|
||||
/*Error = READ_PORT_UCHAR( Self->Port + UART_LSR );
|
||||
if( Error & LSR_OVERRUN )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::OVERRUN );
|
||||
DeviceExtension->SerialPerfStats.SerialOverrunErrorCount++;
|
||||
if( Error & LSR_PARITY_ERROR )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::PARITY );
|
||||
DeviceExtension->SerialPerfStats.ParityErrorCount++;
|
||||
if( Error & LSR_FRAMING_ERROR )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::FRAMING );
|
||||
DeviceExtension->SerialPerfStats.FrameErrorCount++;
|
||||
if( Error & LSR_BREAK )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::BREAK );
|
||||
if( Error & LSR_TIMEOUT )
|
||||
|
@ -133,44 +153,4 @@ SerialInterruptService(
|
|||
}
|
||||
}
|
||||
return FALSE;
|
||||
#if 0
|
||||
InterruptId = READ_PORT_UCHAR(SER_IIR(ComPortBase)) & SR_IIR_IID;
|
||||
DPRINT1("Serial: Interrupt catched: id = %x\n", InterruptId);
|
||||
/* FIXME: sometimes, update DeviceExtension->IER */
|
||||
/* FIXME: sometimes, update DeviceExtension->MCR */
|
||||
/* FIXME: sometimes, update DeviceExtension->MSR */
|
||||
switch (InterruptId)
|
||||
{
|
||||
case 3 << 1:
|
||||
{
|
||||
/* line status changed */
|
||||
DPRINT("Serial: Line status changed\n");
|
||||
break;
|
||||
}
|
||||
case 2 << 1:
|
||||
{
|
||||
/* data available */
|
||||
UCHAR ReceivedByte = READ_PORT_UCHAR(ComPortBase);
|
||||
DPRINT("Serial: Data available\n");
|
||||
DPRINT1("Serial: received %d\n", ReceivedByte);
|
||||
//Buffer[Information++] = ReceivedByte;
|
||||
}
|
||||
case 1 << 1:
|
||||
{
|
||||
/* transmit register empty */
|
||||
DPRINT("Serial: Transmit register empty\n");
|
||||
}
|
||||
case 0 << 1:
|
||||
{
|
||||
/* modem status change */
|
||||
UCHAR ReceivedByte = READ_PORT_UCHAR(SER_MSR(ComPortBase));
|
||||
DPRINT("Serial: Modem status change\n");
|
||||
DPRINT1("Serial: new status = 0x%02x\n", ReceivedByte);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
/* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */
|
||||
|
||||
#define INITGUID
|
||||
#define NDEBUG
|
||||
#include "serial.h"
|
||||
|
||||
|
@ -17,11 +18,12 @@ SerialAddDevice(
|
|||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT Pdo)
|
||||
{
|
||||
PDEVICE_OBJECT Fdo;
|
||||
PDEVICE_OBJECT Fdo = NULL;
|
||||
PSERIAL_DEVICE_EXTENSION DeviceExtension;
|
||||
NTSTATUS Status;
|
||||
WCHAR DeviceNameBuffer[32];
|
||||
UNICODE_STRING DeviceName;
|
||||
//UNICODE_STRING SymbolicLinkName;
|
||||
static ULONG DeviceNumber = 0;
|
||||
|
||||
DPRINT("Serial: SerialAddDevice called\n");
|
||||
|
@ -39,29 +41,57 @@ SerialAddDevice(
|
|||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serial: IoCreateDevice() failed with status 0x%08x\n", Status);
|
||||
return Status;
|
||||
Fdo = NULL;
|
||||
goto ByeBye;
|
||||
}
|
||||
|
||||
/* Register device interface */
|
||||
/* FIXME */
|
||||
|
||||
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
||||
RtlZeroMemory(DeviceExtension, sizeof(SERIAL_DEVICE_EXTENSION));
|
||||
|
||||
/* Register device interface */
|
||||
#if 0 /* FIXME: activate */
|
||||
Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_COMPORT, NULL, &SymbolicLinkName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serial: IoRegisterDeviceInterface() failed with status 0x%08x\n", Status);
|
||||
goto ByeBye;
|
||||
}
|
||||
DPRINT1("Serial: IoRegisterDeviceInterface() returned '%wZ'\n", &SymbolicLinkName);
|
||||
Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serial: IoSetDeviceInterfaceState() failed with status 0x%08x\n", Status);
|
||||
goto ByeBye;
|
||||
}
|
||||
RtlFreeUnicodeString(&SymbolicLinkName);
|
||||
#endif
|
||||
|
||||
DeviceExtension->SerialPortNumber = DeviceNumber++;
|
||||
DeviceExtension->Pdo = Pdo;
|
||||
DeviceExtension->PnpState = dsStopped;
|
||||
Status = InitializeCircularBuffer(&DeviceExtension->InputBuffer, 16);
|
||||
if (!NT_SUCCESS(Status)) goto ByeBye;
|
||||
Status = InitializeCircularBuffer(&DeviceExtension->OutputBuffer, 16);
|
||||
if (!NT_SUCCESS(Status)) goto ByeBye;
|
||||
IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERIAL_TAG, 0, 0);
|
||||
//Fdo->Flags |= DO_POWER_PAGEABLE (or DO_POWER_INRUSH?)
|
||||
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serial: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08x\n", Status);
|
||||
IoDeleteDevice(Fdo);
|
||||
return Status;
|
||||
goto ByeBye;
|
||||
}
|
||||
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
ByeBye:
|
||||
if (Fdo)
|
||||
{
|
||||
FreeCircularBuffer(&DeviceExtension->InputBuffer);
|
||||
FreeCircularBuffer(&DeviceExtension->OutputBuffer);
|
||||
IoDeleteDevice(Fdo);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
|
@ -70,20 +100,24 @@ SerialPnpStartDevice(
|
|||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION Stack;
|
||||
PCM_RESOURCE_LIST ResourceList;
|
||||
//PCM_RESOURCE_LIST ResourceList;
|
||||
PSERIAL_DEVICE_EXTENSION DeviceExtension;
|
||||
WCHAR DeviceNameBuffer[32];
|
||||
UNICODE_STRING DeviceName;
|
||||
WCHAR LinkNameBuffer[32];
|
||||
UNICODE_STRING LinkName;
|
||||
WCHAR ComPortBuffer[32];
|
||||
UNICODE_STRING ComPort;
|
||||
ULONG Vector;
|
||||
//ULONG i, j;
|
||||
KIRQL Dirql;
|
||||
KAFFINITY Affinity;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
UNICODE_STRING KeyName;
|
||||
HANDLE hKey;
|
||||
NTSTATUS Status;
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
ResourceList = Stack->Parameters.StartDevice.AllocatedResources/*Translated*/;
|
||||
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* FIXME: actually, IRP_MN_START_DEVICE is sent twice to each serial device:
|
||||
|
@ -94,77 +128,75 @@ SerialPnpStartDevice(
|
|||
*/
|
||||
if (DeviceExtension->PnpState == dsStarted) return STATUS_SUCCESS;
|
||||
|
||||
if (ResourceList == NULL)
|
||||
#if 1
|
||||
/* FIXME: PnP isn't correctly implemented and doesn't give us a list
|
||||
* of our own resources. Use default values instead.
|
||||
*/
|
||||
switch (DeviceExtension->SerialPortNumber)
|
||||
{
|
||||
/* FIXME: PnP isn't correctly implemented and doesn't give us a list
|
||||
* of our own resources. Use default values instead.
|
||||
*/
|
||||
switch (DeviceExtension->SerialPortNumber)
|
||||
{
|
||||
case 0:
|
||||
DPRINT("Serial: creating COM1:\n");
|
||||
DeviceExtension->ComPort = 3;
|
||||
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
|
||||
DeviceExtension->BaseAddress = 0x3F8;
|
||||
DeviceExtension->Irq = 4;
|
||||
break;
|
||||
case 1:
|
||||
DPRINT("Serial: creating COM2:\n");
|
||||
DeviceExtension->ComPort = 4;
|
||||
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
|
||||
DeviceExtension->BaseAddress = 0x2F8;
|
||||
DeviceExtension->Irq = 3;
|
||||
break;
|
||||
default:
|
||||
DPRINT1("Serial: unknown port?\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
case 0:
|
||||
DPRINT("Serial: creating COM1:\n");
|
||||
DeviceExtension->ComPort = 1;
|
||||
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
|
||||
DeviceExtension->BaseAddress = 0x3F8;
|
||||
DeviceExtension->Irq = 4;
|
||||
break;
|
||||
case 1:
|
||||
DPRINT("Serial: creating COM2:\n");
|
||||
DeviceExtension->ComPort = 2;
|
||||
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
|
||||
DeviceExtension->BaseAddress = 0x2F8;
|
||||
DeviceExtension->Irq = 3;
|
||||
break;
|
||||
default:
|
||||
DPRINT1("Serial: too much ports detected. Forgetting this one...\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
#else
|
||||
DPRINT1("Serial: ResourceList %p, ResourceListTranslated %p\n",
|
||||
Stack->Parameters.StartDevice.AllocatedResources,
|
||||
Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
|
||||
ResourceList = Stack->Parameters.StartDevice.AllocatedResourcesTranslated;
|
||||
for (i = 0; i < ResourceList->Count; i++)
|
||||
{
|
||||
DPRINT1("ResourceList %p, ResourceListTranslated %p\n", Stack->Parameters.StartDevice.AllocatedResources, Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
|
||||
for (i = 0; i < ResourceList->Count; i++)
|
||||
DPRINT1("Serial: Interface type = 0x%x\n", ResourceList->List[i].InterfaceType);
|
||||
DPRINT1("Serial: Bus number = 0x%x\n", ResourceList->List[i].BusNumber);
|
||||
for (j = 0; i < ResourceList->List[i].PartialResourceList.Count; j++)
|
||||
{
|
||||
DPRINT1("Interface type = 0x%x\n", ResourceList->List[i].InterfaceType);
|
||||
DPRINT1("Bus number = 0x%x\n", ResourceList->List[i].BusNumber);
|
||||
for (j = 0; i < ResourceList->List[i].PartialResourceList.Count; j++)
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[i].PartialResourceList.PartialDescriptors[j];
|
||||
DPRINT1("Serial: Type 0x%x, Share disposition 0x%x, Flags 0x%x\n",
|
||||
PartialDescriptor->Type,
|
||||
PartialDescriptor->ShareDisposition,
|
||||
PartialDescriptor->Flags);
|
||||
switch (PartialDescriptor->Type)
|
||||
{
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[i].PartialResourceList.PartialDescriptors[j];
|
||||
DPRINT1("Type 0x%x, Share disposition 0x%x, Flags 0x%x\n",
|
||||
PartialDescriptor->Type,
|
||||
PartialDescriptor->ShareDisposition,
|
||||
PartialDescriptor->Flags);
|
||||
switch (PartialDescriptor->Type)
|
||||
{
|
||||
case CmResourceTypePort:
|
||||
DeviceExtension->BaseAddress = PartialDescriptor->u.Port.Start.u.LowPart;
|
||||
break;
|
||||
case CmResourceTypeInterrupt:
|
||||
/* FIXME: Detect if interrupt is shareable and/or latched */
|
||||
/* FIXME: use also ->u.Interrupt.Vector and ->u.Interrupt.Affinity
|
||||
* to remove call to HalGetInterruptVector(...) */
|
||||
DeviceExtension->Irq = PartialDescriptor->u.Interrupt.Level;
|
||||
break;
|
||||
}
|
||||
case CmResourceTypePort:
|
||||
DeviceExtension->BaseAddress = PartialDescriptor->u.Port.Start.u.LowPart;
|
||||
DPRINT1("Serial: CmResourceTypePort = %lu\n", DeviceExtension->BaseAddress);
|
||||
break;
|
||||
case CmResourceTypeInterrupt:
|
||||
/* FIXME: Detect if interrupt is shareable and/or latched */
|
||||
/* FIXME: use also ->u.Interrupt.Vector and ->u.Interrupt.Affinity
|
||||
* to remove call to HalGetInterruptVector(...) */
|
||||
DeviceExtension->Irq = PartialDescriptor->u.Interrupt.Level;
|
||||
DPRINT1("Serial: Irq = %lu\n", DeviceExtension->Irq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* FIXME: use polling if no interrupt was found? */
|
||||
DeviceExtension->ComPort = 5; /* FIXME: use incremental value, or find it in resource list*/
|
||||
}
|
||||
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
|
||||
/* FIXME: use polling if no interrupt was found? */
|
||||
DeviceExtension->ComPort = 5; /* FIXME: use incremental value, or find it in resource list */
|
||||
#endif
|
||||
|
||||
/* Get current settings */
|
||||
DeviceExtension->IER = READ_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress));
|
||||
DeviceExtension->MCR = READ_PORT_UCHAR(SER_MCR((PUCHAR)DeviceExtension->BaseAddress));
|
||||
DeviceExtension->MSR = READ_PORT_UCHAR(SER_MSR((PUCHAR)DeviceExtension->BaseAddress));
|
||||
DeviceExtension->SerialLineControl.StopBits = STOP_BIT_1;
|
||||
DeviceExtension->SerialLineControl.Parity = NO_PARITY;
|
||||
DeviceExtension->SerialLineControl.WordLength = 8;
|
||||
DeviceExtension->WaitMask = 0;
|
||||
|
||||
/* Set baud rate */
|
||||
Status = SerialSetBaudRate(DeviceExtension, 19200 | SERIAL_BAUD_USER); /* FIXME: real default value? */
|
||||
Status = SerialSetBaudRate(DeviceExtension, DeviceExtension->BaudRate);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serial: SerialSetBaudRate() failed with status 0x%08x\n", Status);
|
||||
|
@ -172,6 +204,9 @@ SerialPnpStartDevice(
|
|||
}
|
||||
|
||||
/* Set line control */
|
||||
DeviceExtension->SerialLineControl.StopBits = STOP_BIT_1;
|
||||
DeviceExtension->SerialLineControl.Parity = NO_PARITY;
|
||||
DeviceExtension->SerialLineControl.WordLength = 8;
|
||||
Status = SerialSetLineControl(DeviceExtension, &DeviceExtension->SerialLineControl);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
|
@ -181,9 +216,11 @@ SerialPnpStartDevice(
|
|||
|
||||
/* Create link \DosDevices\COMX -> \Device\SerialX */
|
||||
swprintf(DeviceNameBuffer, L"\\Device\\Serial%lu", DeviceExtension->SerialPortNumber);
|
||||
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
|
||||
swprintf(LinkNameBuffer, L"\\DosDevices\\COM%lu", DeviceExtension->ComPort);
|
||||
swprintf(ComPortBuffer, L"COM%lu", DeviceExtension->ComPort);
|
||||
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
|
||||
RtlInitUnicodeString(&LinkName, LinkNameBuffer);
|
||||
RtlInitUnicodeString(&ComPort, ComPortBuffer);
|
||||
Status = IoCreateSymbolicLink(&LinkName, &DeviceName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
|
@ -204,12 +241,29 @@ SerialPnpStartDevice(
|
|||
IoDeleteSymbolicLink(&LinkName);
|
||||
return Status;
|
||||
}
|
||||
DeviceExtension->IER |= 0x1; /* Activate interrupt mode */
|
||||
WRITE_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress), DeviceExtension->IER);
|
||||
|
||||
/* Write an entry value under HKLM\HARDWARE\DeviceMap\SERIALCOMM */
|
||||
/* This step is not mandatory, so don't exit in case of error */
|
||||
RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\DeviceMap\\SERIALCOMM");
|
||||
InitializeObjectAttributes(&objectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
Status = ZwCreateKey(&hKey, KEY_SET_VALUE, &objectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Key = \Device\Serialx, Value = COMx */
|
||||
ZwSetValueKey(hKey, &DeviceName, 0, REG_SZ, &ComPortBuffer, ComPort.Length + sizeof(WCHAR));
|
||||
ZwClose(hKey);
|
||||
}
|
||||
|
||||
DeviceExtension->PnpState = dsStarted;
|
||||
|
||||
return Status;
|
||||
DeviceExtension->IER |= 0x1f; /* Activate interrupt mode */
|
||||
DeviceExtension->IER &= ~1; /* FIXME: Disable receive byte interrupt */
|
||||
WRITE_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress), DeviceExtension->IER);
|
||||
|
||||
DeviceExtension->MCR |= 0x03; /* Activate DTR, RTS */
|
||||
WRITE_PORT_UCHAR(SER_MCR((PUCHAR)DeviceExtension->BaseAddress), DeviceExtension->MCR);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
|
@ -220,12 +274,10 @@ SerialPnp(
|
|||
ULONG MinorFunction;
|
||||
PIO_STACK_LOCATION Stack;
|
||||
ULONG Information = 0;
|
||||
PDEVICE_OBJECT LowerDevice;
|
||||
NTSTATUS Status;
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
MinorFunction = Stack->MinorFunction;
|
||||
LowerDevice = ((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
|
||||
|
||||
switch (MinorFunction)
|
||||
{
|
||||
|
@ -264,9 +316,7 @@ SerialPnp(
|
|||
default:
|
||||
{
|
||||
DPRINT1("Serial: unknown minor function 0x%x\n", MinorFunction);
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
Status = IoCallDriver(LowerDevice, Irp);
|
||||
break;
|
||||
return ForwardIrpAndForget(DeviceObject, Irp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ SerialPower(
|
|||
IN PIRP Irp)
|
||||
{
|
||||
DPRINT("Serial: IRP_MJ_POWER dispatch\n");
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -29,11 +29,103 @@ SerialRead(
|
|||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION Stack;
|
||||
PSERIAL_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG Length;
|
||||
ULONG Information = 0;
|
||||
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
||||
PUCHAR Buffer;
|
||||
PUCHAR ComPortBase;
|
||||
UCHAR ReceivedByte;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
DPRINT1("Serial: IRP_MJ_READ unimplemented\n");
|
||||
DPRINT("Serial: IRP_MJ_READ\n");
|
||||
|
||||
/* FIXME: pend operation if possible */
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
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)
|
||||
{
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto ByeBye;
|
||||
}
|
||||
|
||||
if (Length == 0)
|
||||
{
|
||||
Status = STATUS_SUCCESS;
|
||||
goto ByeBye;
|
||||
}
|
||||
|
||||
Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
if (!NT_SUCCESS(Status))
|
||||
goto ByeBye;
|
||||
|
||||
/* FIXME: lock InputBuffer */
|
||||
while (Length-- > 0 && !IsCircularBufferEmpty(&DeviceExtension->InputBuffer))
|
||||
{
|
||||
Status = PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
|
||||
if (!NT_SUCCESS(Status))
|
||||
break;
|
||||
DPRINT("Serial: read from buffer 0x%x (%c)\n", ReceivedByte, ReceivedByte);
|
||||
Buffer[Information++] = ReceivedByte;
|
||||
}
|
||||
if (Length > 0 &&
|
||||
!(DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == INFINITE &&
|
||||
DeviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0 &&
|
||||
DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0))
|
||||
{
|
||||
if (DeviceExtension->SerialTimeOuts.ReadIntervalTimeout == 0
|
||||
|| DeviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) == 0)
|
||||
;
|
||||
ReceivedByte = READ_PORT_UCHAR(SER_RBR(ComPortBase));
|
||||
Buffer[Information++] = ReceivedByte;
|
||||
Length--;
|
||||
}
|
||||
/* Enable interrupts */
|
||||
WRITE_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress), DeviceExtension->IER);
|
||||
#else
|
||||
while (Length > 0)
|
||||
{
|
||||
if (!IsCircularBufferEmpty(&DeviceExtension->InputBuffer))
|
||||
{
|
||||
Status = PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte);
|
||||
if (!NT_SUCCESS(Status))
|
||||
break;
|
||||
DPRINT1("Serial: read from buffer 0x%x (%c)\n", ReceivedByte, ReceivedByte);
|
||||
Buffer[Information++] = ReceivedByte;
|
||||
Length--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
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: unlock InputBuffer */
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
|
||||
ByeBye:
|
||||
Irp->IoStatus.Information = Information;
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
@ -51,12 +143,12 @@ SerialWrite(
|
|||
ULONG Information = 0;
|
||||
PUCHAR Buffer;
|
||||
PUCHAR ComPortBase;
|
||||
ULONG i;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
DPRINT("Serial: IRP_MJ_WRITE\n");
|
||||
|
||||
/* FIXME: pend operation if possible */
|
||||
/* FIXME: use write timeouts */
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
Length = Stack->Parameters.Write.Length;
|
||||
|
@ -74,17 +166,39 @@ SerialWrite(
|
|||
if (!NT_SUCCESS(Status))
|
||||
goto ByeBye;
|
||||
|
||||
for (i = 0; i < Length; i++)
|
||||
/* FIXME: lock OutputBuffer */
|
||||
if (IsCircularBufferEmpty(&DeviceExtension->OutputBuffer))
|
||||
{
|
||||
/* verify if output buffer is not full */
|
||||
while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE) == 0)
|
||||
;
|
||||
WRITE_PORT_UCHAR(SER_THR(ComPortBase), Buffer[i]);
|
||||
DeviceExtension->SerialPerfStats.TransmittedCount++;
|
||||
/* Put the maximum amount of data in UART output buffer */
|
||||
while (Information < Length)
|
||||
{
|
||||
/* if UART output buffer is not full, directly write to it */
|
||||
if ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE) != 0)
|
||||
{
|
||||
DPRINT("Serial: direct write 0x%02x (%c)\n", Buffer[Information], Buffer[Information]);
|
||||
WRITE_PORT_UCHAR(SER_THR(ComPortBase), Buffer[Information]);
|
||||
DeviceExtension->SerialPerfStats.TransmittedCount++;
|
||||
Information++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* write remaining bytes into output buffer */
|
||||
while (Information < Length)
|
||||
{
|
||||
Status = PushCircularBufferEntry(&DeviceExtension->OutputBuffer, Buffer[Information]);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serial: buffer overrun on COM%lu\n", DeviceExtension->ComPort);
|
||||
DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++;
|
||||
break;
|
||||
}
|
||||
DPRINT1("Serial: write to buffer 0x%02x\n", Buffer[Information]);
|
||||
Information++;
|
||||
}
|
||||
/* FIXME: unlock OutputBuffer */
|
||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
|
||||
Information = Length;
|
||||
|
||||
ByeBye:
|
||||
Irp->IoStatus.Information = Information;
|
||||
|
|
|
@ -26,10 +26,13 @@ DriverEntry(
|
|||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegPath)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
DriverObject->DriverUnload = DriverUnload;
|
||||
DriverObject->DriverExtension->AddDevice = SerialAddDevice;
|
||||
|
||||
/* FIXME: send all other major functions to lower driver */
|
||||
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
|
||||
DriverObject->MajorFunction[i] = ForwardIrpAndForget;
|
||||
DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialCreate;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialClose;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SerialCleanup;
|
||||
|
@ -40,5 +43,5 @@ DriverEntry(
|
|||
DriverObject->MajorFunction[IRP_MJ_PNP] = SerialPnp;
|
||||
DriverObject->MajorFunction[IRP_MJ_POWER] = SerialPower;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return DetectLegacyDevices(DriverObject);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
|
||||
#include <debug.h>
|
||||
|
||||
/* FIXME: this prototype MUST NOT be here! */
|
||||
/* FIXME: these prototypes MUST NOT be here! */
|
||||
NTSTATUS STDCALL
|
||||
IoAttachDeviceToDeviceStackSafe(
|
||||
IN PDEVICE_OBJECT SourceDevice,
|
||||
IN PDEVICE_OBJECT TargetDevice,
|
||||
OUT PDEVICE_OBJECT *AttachedToDeviceObject);
|
||||
#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xc000008c
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#include <ntddk.h>
|
||||
#include <ntddser.h>
|
||||
|
@ -49,6 +51,14 @@ typedef enum {
|
|||
dsSurpriseRemoved
|
||||
} SERIAL_DEVICE_STATE;
|
||||
|
||||
typedef struct _CIRCULAR_BUFFER
|
||||
{
|
||||
PUCHAR Buffer;
|
||||
ULONG Length;
|
||||
ULONG ReadPosition;
|
||||
ULONG WritePosition;
|
||||
} CIRCULAR_BUFFER, *PCIRCULAR_BUFFER;
|
||||
|
||||
typedef struct _SERIAL_DEVICE_EXTENSION
|
||||
{
|
||||
PDEVICE_OBJECT Pdo;
|
||||
|
@ -58,7 +68,7 @@ typedef struct _SERIAL_DEVICE_EXTENSION
|
|||
|
||||
ULONG SerialPortNumber;
|
||||
|
||||
ULONG ComPort; /* FIXME: move to serenum */
|
||||
ULONG ComPort;
|
||||
ULONG BaudRate;
|
||||
ULONG BaseAddress;
|
||||
ULONG Irq;
|
||||
|
@ -68,7 +78,10 @@ typedef struct _SERIAL_DEVICE_EXTENSION
|
|||
ULONG WaitMask;
|
||||
|
||||
SERIALPERF_STATS SerialPerfStats;
|
||||
BOOL IsOpened;
|
||||
SERIAL_TIMEOUTS SerialTimeOuts;
|
||||
BOOLEAN IsOpened;
|
||||
CIRCULAR_BUFFER InputBuffer;
|
||||
CIRCULAR_BUFFER OutputBuffer;
|
||||
|
||||
/* Current values */
|
||||
UCHAR IER; /* Base+1, Interrupt Enable Register */
|
||||
|
@ -78,6 +91,8 @@ typedef struct _SERIAL_DEVICE_EXTENSION
|
|||
|
||||
#define SERIAL_TAG TAG('S', 'e', 'r', 'l')
|
||||
|
||||
#define INFINITE ((ULONG)-1)
|
||||
|
||||
/* Baud master clock */
|
||||
#define BAUD_CLOCK 1843200
|
||||
#define CLOCKS_PER_BIT 16
|
||||
|
@ -88,14 +103,17 @@ typedef struct _SERIAL_DEVICE_EXTENSION
|
|||
#define SER_DLL(x) ((x)+0)
|
||||
#define SER_IER(x) ((x)+1)
|
||||
#define SER_DLM(x) ((x)+1)
|
||||
#define SER_FCR(x) ((x)+1)
|
||||
#define SER_IIR(x) ((x)+2)
|
||||
#define SR_IIR_SELF 0x01
|
||||
#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 SR_FCR_ENABLE_FIFO 0x01
|
||||
#define SR_FCR_CLEAR_RCVR 0x02
|
||||
#define SR_FCR_CLEAR_XMIT 0x04
|
||||
#define SER_LCR(x) ((x)+3)
|
||||
#define SR_LCR_CS5 0x00
|
||||
#define SR_LCR_CS6 0x01
|
||||
|
@ -121,6 +139,32 @@ typedef struct _SERIAL_DEVICE_EXTENSION
|
|||
#define SR_MSR_DSR 0x20
|
||||
#define SER_SCR(x) ((x)+7)
|
||||
|
||||
/************************************ circularbuffer.c */
|
||||
|
||||
/* FIXME: transform these functions into #define? */
|
||||
NTSTATUS
|
||||
InitializeCircularBuffer(
|
||||
IN PCIRCULAR_BUFFER pBuffer,
|
||||
IN ULONG BufferSize);
|
||||
|
||||
NTSTATUS
|
||||
FreeCircularBuffer(
|
||||
IN PCIRCULAR_BUFFER pBuffer);
|
||||
|
||||
BOOLEAN
|
||||
IsCircularBufferEmpty(
|
||||
IN PCIRCULAR_BUFFER pBuffer);
|
||||
|
||||
NTSTATUS
|
||||
PushCircularBufferEntry(
|
||||
IN PCIRCULAR_BUFFER pBuffer,
|
||||
IN UCHAR Entry);
|
||||
|
||||
NTSTATUS
|
||||
PopCircularBufferEntry(
|
||||
IN PCIRCULAR_BUFFER pBuffer,
|
||||
OUT PUCHAR Entry);
|
||||
|
||||
/************************************ cleanup.c */
|
||||
|
||||
NTSTATUS STDCALL
|
||||
|
@ -166,6 +210,12 @@ SerialQueryInformation(
|
|||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
/************************************ legacy.c */
|
||||
|
||||
NTSTATUS
|
||||
DetectLegacyDevices(
|
||||
IN PDRIVER_OBJECT DriverObject);
|
||||
|
||||
/************************************ misc.c */
|
||||
|
||||
NTSTATUS
|
||||
|
@ -173,6 +223,11 @@ ForwardIrpAndWait(
|
|||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpAndForget(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
BOOLEAN STDCALL
|
||||
SerialInterruptService(
|
||||
IN PKINTERRUPT Interrupt,
|
||||
|
|
Loading…
Reference in a new issue