Add serial port enumerator driver:

- Enumerate legacy mice
- Should also detect PnP serial devices even if they are not yet reported
It is implemented as an upper filter for serial port driver (serial.sys)
Add corresponding registry entries

svn path=/trunk/; revision=14512
This commit is contained in:
Hervé Poussineau 2005-04-05 19:04:07 +00:00
parent c6779bb5c2
commit 353bc6197c
12 changed files with 1578 additions and 3 deletions

View file

@ -34,8 +34,8 @@ COMPONENTS = ntoskrnl
HALS = halx86/up halx86/mp
# Bus drivers
# acpi isapnp pci
BUS = acpi isapnp pci
# acpi isapnp pci serenum
BUS = acpi isapnp pci serenum
# Filesystem libraries
# vfatlib

View file

@ -469,6 +469,19 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
; Serial port enumerator
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Group",0x00000000,"PNP Filter"
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ImagePath",0x00020000,"system32\drivers\serenum.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Start",0x00010001,0x00000003
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Type",0x00010001,0x00000001
;hard coded values
HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","0",0x00000000,"ACPI\PNP0501"
HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","Count",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","NextInstance",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\1","UpperFilters",0x00010000,"serenum"
HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\2","UpperFilters",0x00010000,"serenum"
; SB16 driver
HKLM,"SYSTEM\CurrentControlSet\Services\sndblst","Group",0x00000000,"Base"
HKLM,"SYSTEM\CurrentControlSet\Services\sndblst","ServiceType",0x00010001,0x00000001

View file

@ -29,6 +29,7 @@ Signature = "$ReactOS$"
drivers\bus\acpi\acpi.sys 2
drivers\bus\isapnp\isapnp.sys 2
drivers\bus\pci\pci.sys 2
drivers\bus\serenum\serenum.sys 2
drivers\dd\beep\beep.sys 2
drivers\dd\bootvid\bootvid.sys 2
drivers\dd\null\null.sys 2

View file

@ -6,7 +6,7 @@ PATH_TO_TOP = ../..
include $(PATH_TO_TOP)/rules.mak
DRIVERS = acpi isapnp pci
DRIVERS = acpi isapnp pci serenum
all: $(DRIVERS)

View file

@ -0,0 +1,541 @@
/* $Id:
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Serial enumerator driver
* FILE: drivers/bus/serenum/detect.c
* PURPOSE: Detection of serial devices
*
* PROGRAMMERS: Jason Filby (jasonfilby@yahoo.com)
* Filip Navara (xnavara@volny.cz)
* Hervé Poussineau (hpoussin@reactos.com)
*/
#define NDEBUG
#include "serenum.h"
static NTSTATUS
SerenumDeviceIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG CtlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferSize,
IN OUT PVOID OutputBuffer OPTIONAL,
IN OUT PULONG OutputBufferSize)
{
KEVENT Event;
PIRP Irp;
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
KeInitializeEvent (&Event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(CtlCode,
DeviceObject,
InputBuffer,
InputBufferSize,
OutputBuffer,
(OutputBufferSize) ? *OutputBufferSize : 0,
FALSE,
&Event,
&IoStatus);
if (Irp == NULL)
{
DPRINT("Serenum: IoBuildDeviceIoControlRequest() failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
DPRINT("Serenum: Operation pending\n");
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
if (OutputBufferSize)
{
*OutputBufferSize = IoStatus.Information;
}
return Status;
}
static NTSTATUS
ReadBytes(
IN PDEVICE_OBJECT LowerDevice,
OUT PUCHAR Buffer,
IN ULONG BufferSize,
OUT PULONG FilledBytes)
{
PIRP Irp;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
NTSTATUS Status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
Irp = IoBuildSynchronousFsdRequest(
IRP_MJ_READ,
LowerDevice,
Buffer, BufferSize,
0,
&event,
&ioStatus);
if (!Irp)
return FALSE;
Status = IoCallDriver(LowerDevice, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
Status = ioStatus.Status;
}
DPRINT("Serenum: bytes received: %lu/%lu\n",
ioStatus.Information, BufferSize);
*FilledBytes = ioStatus.Information;
return Status;
}
static NTSTATUS
ReportDetectedDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PUNICODE_STRING DeviceDescription,
IN PUNICODE_STRING DeviceId,
IN PUNICODE_STRING HardwareIds,
IN PUNICODE_STRING CompatibleIds)
{
PDEVICE_OBJECT Pdo = NULL;
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
NTSTATUS Status;
DPRINT("Serenum: SerenumReportDetectedDevice() called with %wZ (%wZ) detected\n", DeviceId, DeviceDescription);
Status = IoCreateDevice(
DeviceObject->DriverObject,
sizeof(PDO_DEVICE_EXTENSION),
NULL,
FILE_DEVICE_CONTROLLER,
FILE_AUTOGENERATED_DEVICE_NAME,
FALSE,
&Pdo);
if (!NT_SUCCESS(Status)) goto ByeBye;
Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
Pdo->Flags |= DO_POWER_PAGABLE;
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
PdoDeviceExtension->Common.IsFDO = FALSE;
Status = SerenumDuplicateUnicodeString(&PdoDeviceExtension->DeviceDescription, DeviceDescription, PagedPool);
if (!NT_SUCCESS(Status)) goto ByeBye;
Status = SerenumDuplicateUnicodeString(&PdoDeviceExtension->DeviceId, DeviceId, PagedPool);
if (!NT_SUCCESS(Status)) goto ByeBye;
Status = SerenumDuplicateUnicodeString(&PdoDeviceExtension->HardwareIds, HardwareIds, PagedPool);
if (!NT_SUCCESS(Status)) goto ByeBye;
Status = SerenumDuplicateUnicodeString(&PdoDeviceExtension->CompatibleIds, CompatibleIds, PagedPool);
if (!NT_SUCCESS(Status)) goto ByeBye;
/* Device attached to serial port (Pdo) may delegate work to
* serial port stack (Fdo = DeviceObject variable) */
Pdo->StackSize = DeviceObject->StackSize + 1;
FdoDeviceExtension->AttachedPdo = Pdo;
PdoDeviceExtension->AttachedFdo = DeviceObject;
Pdo->Flags |= DO_BUFFERED_IO;
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
ByeBye:
if (Pdo)
{
if (PdoDeviceExtension->DeviceDescription.Buffer)
RtlFreeUnicodeString(&PdoDeviceExtension->DeviceDescription);
if (PdoDeviceExtension->DeviceId.Buffer)
RtlFreeUnicodeString(&PdoDeviceExtension->DeviceId);
if (PdoDeviceExtension->HardwareIds.Buffer)
RtlFreeUnicodeString(&PdoDeviceExtension->HardwareIds);
if (PdoDeviceExtension->CompatibleIds.Buffer)
RtlFreeUnicodeString(&PdoDeviceExtension->CompatibleIds);
IoDeleteDevice(Pdo);
}
return Status;
}
static BOOLEAN
SerenumIsValidPnpIdString(
IN PUCHAR Buffer,
IN ULONG BufferLength)
{
/* FIXME: SerenumIsValidPnpIdString not implemented */
DPRINT1("Serenum: SerenumIsValidPnpIdString() unimplemented\n");
return STATUS_SUCCESS;
}
static NTSTATUS
ReportDetectedPnpDevice(
IN PUCHAR Buffer,
IN ULONG BufferLength)
{
ULONG i;
/* FIXME: ReportDetectedPnpDevice not implemented */
DPRINT1("Serenum: ReportDetectedPnpDevice() unimplemented\n");
DPRINT1("");
for (i = 0; i < BufferLength; i++)
DbgPrint("%c", Buffer[i]);
DbgPrint("\n");
/* Call ReportDetectedDevice */
return STATUS_SUCCESS;
}
#define BEGIN_ID '('
#define END_ID ')'
static NTSTATUS
SerenumWait(ULONG milliseconds)
{
KTIMER Timer;
LARGE_INTEGER DueTime;
DueTime.QuadPart = -milliseconds * 10;
KeInitializeTimer(&Timer);
KeSetTimer(&Timer, DueTime, NULL);
return KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL);
}
NTSTATUS
SerenumDetectPnpDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT LowerDevice)
{
UCHAR Buffer[256];
ULONG BaudRate;
ULONG TotalBytesReceived = 0;
ULONG Size;
ULONG Msr, Purge;
ULONG i;
BOOLEAN BufferContainsBeginId, BufferContainsEndId;
SERIAL_LINE_CONTROL Lcr;
SERIAL_TIMEOUTS Timeouts;
SERIALPERF_STATS PerfStats;
NTSTATUS Status;
/* 1. COM port initialization, check for device enumerate */
CHECKPOINT;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
SerenumWait(200);
Size = sizeof(Msr);
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
NULL, 0, &Msr, &Size);
if (!NT_SUCCESS(Status)) return Status;
if ((Msr & SR_MSR_DSR) == 0) goto SerenumDisconnectIdle;
/* 2. COM port setup, 1st phase */
CHECKPOINT;
BaudRate = SERIAL_BAUD_1200;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
&BaudRate, sizeof(BaudRate), NULL, 0);
if (!NT_SUCCESS(Status)) return Status;
Lcr.WordLength = 7;
Lcr.Parity = NO_PARITY;
Lcr.StopBits = STOP_BIT_1;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
&Lcr, sizeof(Lcr), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
SerenumWait(200);
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
SerenumWait(200);
/* 3. Wait for response, 1st phase */
CHECKPOINT;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Timeouts.ReadIntervalTimeout = 0;
Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.ReadTotalTimeoutConstant = 200;
Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
&Timeouts, sizeof(Timeouts), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer), &Size);
if (!NT_SUCCESS(Status)) return Status;
if (Size != 0) goto SerenumCollectPnpComDeviceId;
/* 4. COM port setup, 2nd phase */
CHECKPOINT;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Purge = SERIAL_PURGE_RXABORT | SERIAL_PURGE_RXCLEAR;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_PURGE,
&Purge, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
SerenumWait(200);
/* 5. Wait for response, 2nd phase */
CHECKPOINT;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = ReadBytes(LowerDevice, Buffer, 1, &TotalBytesReceived);
if (!NT_SUCCESS(Status)) return Status;
if (TotalBytesReceived != 0) goto SerenumCollectPnpComDeviceId;
Size = sizeof(Msr);
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
NULL, 0, &Msr, &Size);
if (!NT_SUCCESS(Status)) return Status;
if ((Msr & SR_MSR_DSR) == 0) goto SerenumVerifyDisconnect; else goto SerenumConnectIdle;
/* 6. Collect PnP COM device ID */
SerenumCollectPnpComDeviceId:
CHECKPOINT;
Timeouts.ReadIntervalTimeout = 200;
Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.ReadTotalTimeoutConstant = 2200;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
&Timeouts, sizeof(Timeouts), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = ReadBytes(LowerDevice, &Buffer[TotalBytesReceived], sizeof(Buffer) - TotalBytesReceived, &Size);
if (!NT_SUCCESS(Status)) return Status;
TotalBytesReceived += Size;
Size = sizeof(PerfStats);
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_STATS,
NULL, 0, &PerfStats, &Size);
if (!NT_SUCCESS(Status)) return Status;
if (PerfStats.FrameErrorCount + PerfStats.ParityErrorCount != 0) goto SerenumConnectIdle;
BufferContainsBeginId = BufferContainsEndId = FALSE;
for (i = 0; i < TotalBytesReceived; i++)
{
if (Buffer[i] == BEGIN_ID) BufferContainsBeginId = TRUE;
if (Buffer[i] == END_ID) BufferContainsEndId = TRUE;
}
if (TotalBytesReceived == 1 || BufferContainsEndId)
{
if (SerenumIsValidPnpIdString(Buffer, TotalBytesReceived))
return ReportDetectedPnpDevice(Buffer, TotalBytesReceived);
goto SerenumConnectIdle;
}
if (!BufferContainsBeginId) goto SerenumConnectIdle;
if (!BufferContainsEndId) goto SerenumConnectIdle;
Size = sizeof(Msr);
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
NULL, 0, &Msr, &Size);
if (!NT_SUCCESS(Status)) return Status;
if ((Msr & SR_MSR_DSR) == 0) goto SerenumVerifyDisconnect;
/* 7. Verify disconnect */
SerenumVerifyDisconnect:
CHECKPOINT;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
SerenumWait(5000);
goto SerenumDisconnectIdle;
/* 8. Connect idle */
SerenumConnectIdle:
CHECKPOINT;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
BaudRate = SERIAL_BAUD_300;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
&BaudRate, sizeof(BaudRate), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Lcr.WordLength = 7;
Lcr.Parity = NO_PARITY;
Lcr.StopBits = STOP_BIT_1;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
&Lcr, sizeof(Lcr), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
if (TotalBytesReceived == 0)
return STATUS_DEVICE_NOT_CONNECTED;
else
return STATUS_SUCCESS;
/* 9. Disconnect idle */
SerenumDisconnectIdle:
CHECKPOINT;
/* FIXME: report to OS device removal, if it was present */
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
BaudRate = SERIAL_BAUD_300;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
&BaudRate, sizeof(BaudRate), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Lcr.WordLength = 7;
Lcr.Parity = NO_PARITY;
Lcr.StopBits = STOP_BIT_1;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
&Lcr, sizeof(Lcr), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
return STATUS_DEVICE_NOT_CONNECTED;
}
NTSTATUS
SerenumDetectLegacyDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT LowerDevice)
{
ULONG Fcr, Mcr;
ULONG BaudRate;
ULONG Command;
SERIAL_TIMEOUTS Timeouts;
SERIAL_LINE_CONTROL LCR;
ULONG i, Count;
UCHAR Buffer[16];
UNICODE_STRING DeviceDescription;
UNICODE_STRING DeviceId;
UNICODE_STRING HardwareIds;
UNICODE_STRING CompatibleIds;
NTSTATUS Status;
RtlZeroMemory(Buffer, sizeof(Buffer));
/* Reset UART */
CHECKPOINT;
Mcr = 0; /* MCR: DTR/RTS/OUT2 off */
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL,
&Mcr, sizeof(Mcr), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Set communications parameters */
CHECKPOINT;
/* DLAB off */
Fcr = 0;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL,
&Fcr, sizeof(Fcr), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Set serial port speed */
BaudRate = SERIAL_BAUD_1200;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
&BaudRate, sizeof(BaudRate), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Set LCR */
LCR.WordLength = 7;
LCR.Parity = NO_PARITY;
LCR.StopBits = STOP_BITS_2;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
&LCR, sizeof(LCR), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Flush receive buffer */
CHECKPOINT;
Command = SERIAL_PURGE_RXCLEAR;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL,
&Command, sizeof(Command), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Wait 100 ms */
SerenumWait(100);
/* Enable DTR/RTS */
CHECKPOINT;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Set timeout to 500 microseconds */
CHECKPOINT;
Timeouts.ReadIntervalTimeout = 100;
Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.ReadTotalTimeoutConstant = 500;
Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
&Timeouts, sizeof(Timeouts), NULL, NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Fill the read buffer */
CHECKPOINT;
Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), &Count);
if (!NT_SUCCESS(Status)) return Status;
for (i = 0; i < Count; i++)
{
if (Buffer[i] == 'B')
{
/* Sign for Microsoft Ballpoint */
/* Hardware id: *PNP0F09
* Compatible id: *PNP0F0F, SERIAL_MOUSE
*/
RtlInitUnicodeString(&DeviceDescription, L"Microsoft Ballpoint device");
RtlInitUnicodeString(&DeviceId, L"*PNP0F09");
SerenumInitMultiSzString(&HardwareIds, "*PNP0F09", NULL);
SerenumInitMultiSzString(&CompatibleIds, "*PNP0F0F", "SERIAL_MOUSE", NULL);
Status = ReportDetectedDevice(DeviceObject,
&DeviceDescription, &DeviceId, &HardwareIds, &CompatibleIds);
RtlFreeUnicodeString(&HardwareIds);
RtlFreeUnicodeString(&CompatibleIds);
return Status;
}
else if (Buffer[i] == 'M')
{
/* Sign for Microsoft Mouse protocol followed by button specifier */
if (i == sizeof(Buffer) - 1)
{
/* Overflow Error */
return STATUS_DEVICE_NOT_CONNECTED;
}
switch (Buffer[i + 1])
{
case '3':
/* Hardware id: *PNP0F08
* Compatible id: SERIAL_MOUSE
*/
RtlInitUnicodeString(&DeviceDescription, L"Microsoft Mouse with 3-buttons");
RtlInitUnicodeString(&DeviceId, L"*PNP0F08");
SerenumInitMultiSzString(&HardwareIds, "*PNP0F08", NULL);
SerenumInitMultiSzString(&CompatibleIds, "SERIAL_MOUSE", NULL);
default:
/* Hardware id: *PNP0F01
* Compatible id: SERIAL_MOUSE
*/
RtlInitUnicodeString(&DeviceDescription, L"Microsoft Mouse with 2-buttons or Microsoft Wheel Mouse");
RtlInitUnicodeString(&DeviceId, L"*PNP0F01");
SerenumInitMultiSzString(&HardwareIds, "*PNP0F01", NULL);
SerenumInitMultiSzString(&CompatibleIds, "SERIAL_MOUSE", NULL);
}
Status = ReportDetectedDevice(DeviceObject,
&DeviceDescription, &DeviceId, &HardwareIds, &CompatibleIds);
RtlFreeUnicodeString(&HardwareIds);
RtlFreeUnicodeString(&CompatibleIds);
return Status;
}
}
return STATUS_DEVICE_NOT_CONNECTED;
}

View file

@ -0,0 +1,213 @@
/* $Id:
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Serial enumerator driver
* FILE: drivers/bus/serenum/fdo.c
* PURPOSE: IRP_MJ_PNP operations for FDOs
*
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
*/
#define NDEBUG
#include "serenum.h"
NTSTATUS STDCALL
SerenumAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo)
{
PDEVICE_OBJECT Fdo;
PFDO_DEVICE_EXTENSION DeviceExtension;
//UNICODE_STRING SymbolicLinkName;
NTSTATUS Status;
DPRINT("Serenum: SerenumAddDevice called. Pdo = %p\n", Pdo);
/* Create new device object */
Status = IoCreateDevice(DriverObject,
sizeof(FDO_DEVICE_EXTENSION),
NULL,
FILE_DEVICE_BUS_EXTENDER,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&Fdo);
if (!NT_SUCCESS(Status))
{
DPRINT("Serenum: IoCreateDevice() failed with status 0x%08lx\n", Status);
return Status;
}
/* Register device interface */
#if 0 /* FIXME: activate */
Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, NULL, &SymbolicLinkName);
if (!NT_SUCCESS(Status))
{
DPRINT("Serenum: IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
goto ByeBye;
}
DPRINT1("Serenum: IoRegisterDeviceInterface() returned '%wZ'\n", &SymbolicLinkName);
Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT("Serenum: IoSetDeviceInterfaceState() failed with status 0x%08lx\n", Status);
goto ByeBye;
}
RtlFreeUnicodeString(&SymbolicLinkName);
#endif
DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
DeviceExtension->Common.IsFDO = TRUE;
DeviceExtension->Common.PnpState = dsStopped;
DeviceExtension->Pdo = Pdo;
IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERENUM_TAG, 0, 0);
Fdo->Flags |= DO_POWER_PAGABLE;
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
if (!NT_SUCCESS(Status))
{
DPRINT("Serenum: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
IoDeleteDevice(Fdo);
return Status;
}
Fdo->Flags |= DO_BUFFERED_IO;
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
SerenumFdoStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PCOMMON_DEVICE_EXTENSION DeviceExtension;
DPRINT("Serenum: SerenumFdoStartDevice() called\n");
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->PnpState == dsStopped);
DeviceExtension->PnpState = dsStarted;
return STATUS_SUCCESS;
}
NTSTATUS
SerenumFdoQueryBusRelations(
IN PDEVICE_OBJECT DeviceObject,
OUT PDEVICE_RELATIONS* pDeviceRelations)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
PDEVICE_RELATIONS DeviceRelations;
ULONG NumPDO;
ULONG i;
NTSTATUS Status;
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->Common.IsFDO);
/* Do enumeration if needed */
if (!(DeviceExtension->Flags & FLAG_ENUMERATION_DONE))
{
ASSERT(DeviceExtension->AttachedPdo == NULL);
/* Detect plug-and-play devices */
Status = SerenumDetectPnpDevice(DeviceObject, DeviceExtension->LowerDevice);
if (Status == STATUS_DEVICE_NOT_CONNECTED)
{
/* Detect legacy devices */
Status = SerenumDetectLegacyDevice(DeviceObject, DeviceExtension->LowerDevice);
if (Status == STATUS_DEVICE_NOT_CONNECTED)
Status = STATUS_SUCCESS;
}
DeviceExtension->Flags |= FLAG_ENUMERATION_DONE;
}
NumPDO = (DeviceExtension->AttachedPdo != NULL ? 1 : 0);
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(
PagedPool,
sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (NumPDO - 1),
SERENUM_TAG);
if (!DeviceRelations)
return STATUS_INSUFFICIENT_RESOURCES;
/* Fill returned structure */
DeviceRelations->Count = NumPDO;
for (i = 0; i < NumPDO; i++)
{
ObReferenceObject(DeviceExtension->AttachedPdo);
DeviceRelations->Objects[i] = DeviceExtension->AttachedPdo;
}
*pDeviceRelations = DeviceRelations;
return Status;
}
NTSTATUS
SerenumFdoPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
ULONG MinorFunction;
PIO_STACK_LOCATION Stack;
ULONG_PTR Information = 0;
NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
MinorFunction = Stack->MinorFunction;
switch (MinorFunction)
{
/* FIXME: do all these minor functions
IRP_MN_QUERY_REMOVE_DEVICE 0x1
IRP_MN_REMOVE_DEVICE 0x2
IRP_MN_CANCEL_REMOVE_DEVICE 0x3
IRP_MN_STOP_DEVICE 0x4
IRP_MN_QUERY_STOP_DEVICE 0x5
IRP_MN_CANCEL_STOP_DEVICE 0x6
IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
IRP_MN_QUERY_INTERFACE (optional) 0x8
IRP_MN_QUERY_CAPABILITIES (optional) 0x9
IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional or required) 0xb
IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
IRP_MN_SURPRISE_REMOVAL 0x17
*/
case IRP_MN_START_DEVICE: /* 0x0 */
{
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
/* Call lower driver */
Status = ForwardIrpAndWait(DeviceObject, Irp);
if (NT_SUCCESS(Status))
Status = SerenumFdoStartDevice(DeviceObject, Irp);
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
{
switch (Stack->Parameters.QueryDeviceRelations.Type)
{
case BusRelations:
{
PDEVICE_RELATIONS DeviceRelations;
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
Status = SerenumFdoQueryBusRelations(DeviceObject, &DeviceRelations);
Information = (ULONG_PTR)DeviceRelations;
break;
}
default:
DPRINT1("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
Stack->Parameters.QueryDeviceRelations.Type);
return ForwardIrpAndForget(DeviceObject, Irp);
}
break;
}
default:
{
DPRINT1("Serenum: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}

View file

@ -0,0 +1,20 @@
# $Id: makefile 12852 2005-01-06 13:58:04Z mf $
PATH_TO_TOP = ../../..
TARGET_TYPE = driver
TARGET_NAME = serenum
TARGET_CFLAGS = -Wall -Werror -D__USE_W32API
TARGET_OBJECTS = \
detect.o \
fdo.o \
misc.o \
pdo.o \
serenum.o
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk

View file

@ -0,0 +1,201 @@
/* $Id:
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Serial enumerator driver
* FILE: drivers/dd/serenum/misc.c
* PURPOSE: Misceallenous operations
*
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
*/
#define NDEBUG
#include "serenum.h"
#include <stdarg.h>
NTSTATUS
SerenumDuplicateUnicodeString(
OUT PUNICODE_STRING Destination,
IN PUNICODE_STRING Source,
IN POOL_TYPE PoolType)
{
if (Source == NULL)
{
RtlInitUnicodeString(Destination, NULL);
return STATUS_SUCCESS;
}
Destination->Buffer = ExAllocatePool(PoolType, Source->MaximumLength);
if (Destination->Buffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
Destination->MaximumLength = Source->MaximumLength;
Destination->Length = Source->Length;
RtlCopyMemory(Destination->Buffer, Source->Buffer, Source->MaximumLength);
return STATUS_SUCCESS;
}
/* I really want ANSI strings as last arguments because
* PnP ids are ANSI-encoded in PnP device string
* identification */
NTSTATUS
SerenumInitMultiSzString(
OUT PUNICODE_STRING Destination,
... /* list of PCSZ */)
{
va_list args;
PCSZ Source;
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
ULONG DestinationSize = 0;
NTSTATUS Status = STATUS_SUCCESS;
/* Calculate length needed for destination unicode string */
va_start(args, Destination);
Source = va_arg(args, PCSZ);
while (Source != NULL)
{
RtlInitAnsiString(&AnsiString, Source);
DestinationSize += RtlAnsiStringToUnicodeSize(&AnsiString)
+ sizeof(WCHAR) /* final NULL */;
Source = va_arg(args, PCSZ);
}
va_end(args);
if (DestinationSize == 0)
{
RtlInitUnicodeString(Destination, NULL);
return STATUS_SUCCESS;
}
/* Initialize destination string */
DestinationSize += sizeof(WCHAR); // final NULL
Destination->Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, DestinationSize, SERENUM_TAG);
if (!Destination->Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
Destination->Length = 0;
Destination->MaximumLength = (USHORT)DestinationSize;
/* Copy arguments to destination string */
/* Use a temporary unicode string, which buffer is shared with
* destination string, to copy arguments */
UnicodeString.Length = Destination->Length;
UnicodeString.MaximumLength = Destination->MaximumLength;
UnicodeString.Buffer = Destination->Buffer;
va_start(args, Destination);
Source = va_arg(args, PCSZ);
while (Source != NULL)
{
RtlInitAnsiString(&AnsiString, Source);
Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(Destination->Buffer, SERENUM_TAG);
break;
}
Destination->Length += UnicodeString.Length + sizeof(WCHAR);
UnicodeString.MaximumLength -= UnicodeString.Length + sizeof(WCHAR);
UnicodeString.Buffer += UnicodeString.Length / sizeof(WCHAR) + 1;
UnicodeString.Length = 0;
Source = va_arg(args, PCSZ);
}
va_end(args);
if (NT_SUCCESS(Status))
{
/* Finish multi-sz string */
Destination->Buffer[Destination->Length / sizeof(WCHAR)] = L'\0';
Destination->Length += sizeof(WCHAR);
}
return Status;
}
NTSTATUS STDCALL
ForwardIrpAndWaitCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
if (Irp->PendingReturned)
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
ForwardIrpAndWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_OBJECT LowerDevice;
KEVENT Event;
NTSTATUS Status;
ASSERT(((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO);
LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
DPRINT("Serenum: Calling lower device %p [%wZ]\n", LowerDevice, &LowerDevice->DriverObject->DriverName);
IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
Status = IoCallDriver(LowerDevice, Irp);
if (Status == STATUS_PENDING)
{
Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
if (NT_SUCCESS(Status))
Status = Irp->IoStatus.Status;
}
return Status;
}
NTSTATUS STDCALL
ForwardIrpToLowerDeviceAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
PDEVICE_OBJECT LowerDevice;
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->Common.IsFDO);
LowerDevice = DeviceExtension->LowerDevice;
DPRINT("Serenum: calling lower device 0x%p [%wZ]\n",
LowerDevice, &LowerDevice->DriverObject->DriverName);
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(LowerDevice, Irp);
}
NTSTATUS STDCALL
ForwardIrpToAttachedFdoAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
PDEVICE_OBJECT Fdo;
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(!DeviceExtension->Common.IsFDO);
Fdo = DeviceExtension->AttachedFdo;
DPRINT("Serenum: calling attached Fdo 0x%p [%wZ]\n",
Fdo, &Fdo->DriverObject->DriverName);
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(Fdo, Irp);
}
NTSTATUS STDCALL
ForwardIrpAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_OBJECT LowerDevice;
ASSERT(((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO);
LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(LowerDevice, Irp);
}

View file

@ -0,0 +1,313 @@
/* $Id:
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Serial enumerator driver
* FILE: drivers/bus/serenum/pdo.c
* PURPOSE: IRP_MJ_PNP operations for PDOs
*
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
*/
#define NDEBUG
#include "serenum.h"
static NTSTATUS
SerenumPdoStartDevice(
IN PDEVICE_OBJECT DeviceObject)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->Common.PnpState == dsStopped);
DeviceExtension->Common.PnpState = dsStarted;
return STATUS_SUCCESS;
}
static NTSTATUS
SerenumPdoQueryId(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
OUT ULONG_PTR* Information)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
ULONG IdType;
PUNICODE_STRING SourceString;
UNICODE_STRING String;
NTSTATUS Status;
IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
RtlInitUnicodeString(&String, NULL);
switch (IdType)
{
case BusQueryDeviceID:
{
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
SourceString = &DeviceExtension->DeviceId;
break;
}
case BusQueryHardwareIDs:
{
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
SourceString = &DeviceExtension->HardwareIds;
break;
}
case BusQueryCompatibleIDs:
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
SourceString = &DeviceExtension->CompatibleIds;
break;
case BusQueryInstanceID:
{
/* We don't have any instance id to report, and
* this query is optional, so ignore it.
*/
*Information = Irp->IoStatus.Information;
return Irp->IoStatus.Status;
}
default:
DPRINT1("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
return STATUS_NOT_SUPPORTED;
}
Status = SerenumDuplicateUnicodeString(
&String,
SourceString,
PagedPool);
*Information = (ULONG_PTR)String.Buffer;
return Status;
}
static NTSTATUS
SerenumPdoQueryDeviceRelations(
IN PDEVICE_OBJECT DeviceObject,
OUT PDEVICE_RELATIONS* pDeviceRelations)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
PDEVICE_RELATIONS DeviceRelations;
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->Common.IsFDO);
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(
PagedPool,
sizeof(DEVICE_RELATIONS),
SERENUM_TAG);
if (!DeviceRelations)
return STATUS_INSUFFICIENT_RESOURCES;
ObReferenceObject(DeviceObject);
DeviceRelations->Objects[0] = DeviceObject;
*pDeviceRelations = DeviceRelations;
return STATUS_SUCCESS;
}
NTSTATUS
SerenumPdoPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
ULONG MinorFunction;
PIO_STACK_LOCATION Stack;
ULONG_PTR Information = 0;
NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
MinorFunction = Stack->MinorFunction;
switch (MinorFunction)
{
/* FIXME: do all these minor functions
IRP_MN_QUERY_REMOVE_DEVICE 0x1
IRP_MN_REMOVE_DEVICE 0x2
IRP_MN_CANCEL_REMOVE_DEVICE 0x3
IRP_MN_STOP_DEVICE 0x4
IRP_MN_QUERY_STOP_DEVICE 0x5
IRP_MN_CANCEL_STOP_DEVICE 0x6
IRP_MN_QUERY_DEVICE_RELATIONS / EjectionRelations (optional) 0x7
IRP_MN_QUERY_INTERFACE (required or optional) 0x8
IRP_MN_READ_CONFIG (required or optional) 0xf
IRP_MN_WRITE_CONFIG (required or optional) 0x10
IRP_MN_EJECT (required or optional) 0x11
IRP_MN_SET_LOCK (required or optional) 0x12
IRP_MN_QUERY_ID / BusQueryDeviceID 0x13
IRP_MN_QUERY_ID / BusQueryCompatibleIDs (optional) 0x13
IRP_MN_QUERY_ID / BusQueryInstanceID (optional) 0x13
IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
IRP_MN_SURPRISE_REMOVAL 0x17
*/
case IRP_MN_START_DEVICE: /* 0x0 */
{
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
Status = SerenumPdoStartDevice(DeviceObject);
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
{
switch (Stack->Parameters.QueryDeviceRelations.Type)
{
case RemovalRelations:
{
return ForwardIrpToAttachedFdoAndForget(DeviceObject, Irp);
}
case TargetDeviceRelation:
{
PDEVICE_RELATIONS DeviceRelations;
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
Status = SerenumPdoQueryDeviceRelations(DeviceObject, &DeviceRelations);
Information = (ULONG_PTR)DeviceRelations;
break;
}
default:
{
DPRINT1("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
Stack->Parameters.QueryDeviceRelations.Type);
Status = STATUS_NOT_IMPLEMENTED;
break;
}
}
break;
}
case IRP_MN_QUERY_CAPABILITIES: /* 0x9 */
{
PDEVICE_CAPABILITIES DeviceCapabilities;
ULONG i;
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
DeviceCapabilities = (PDEVICE_CAPABILITIES)Stack->Parameters.DeviceCapabilities.Capabilities;
/* FIXME: capabilities can change with connected device */
DeviceCapabilities->LockSupported = FALSE;
DeviceCapabilities->EjectSupported = FALSE;
DeviceCapabilities->Removable = TRUE;
DeviceCapabilities->DockDevice = FALSE;
DeviceCapabilities->UniqueID = FALSE;
DeviceCapabilities->SilentInstall = FALSE;
DeviceCapabilities->RawDeviceOK = TRUE;
DeviceCapabilities->SurpriseRemovalOK = TRUE;
DeviceCapabilities->HardwareDisabled = FALSE; /* FIXME */
//DeviceCapabilities->NoDisplayInUI = FALSE; /* FIXME */
DeviceCapabilities->DeviceState[0] = PowerDeviceD0; /* FIXME */
for (i = 0; i < PowerSystemMaximum; i++)
DeviceCapabilities->DeviceState[i] = PowerDeviceD3; /* FIXME */
//DeviceCapabilities->DeviceWake = PowerDeviceUndefined; /* FIXME */
DeviceCapabilities->D1Latency = 0; /* FIXME */
DeviceCapabilities->D2Latency = 0; /* FIXME */
DeviceCapabilities->D3Latency = 0; /* FIXME */
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_RESOURCES: /* 0xa */
{
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
/* Serial devices don't need resources, except the ones of
* the serial port. This PDO is the serial device PDO, so
* report no resource by not changing Information and
* Status
*/
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
break;
}
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0xb */
{
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
/* Serial devices don't need resources, except the ones of
* the serial port. This PDO is the serial device PDO, so
* report no resource by not changing Information and
* Status
*/
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
break;
}
case IRP_MN_QUERY_DEVICE_TEXT: /* 0xc */
{
switch (Stack->Parameters.QueryDeviceText.DeviceTextType)
{
case DeviceTextDescription:
{
PUNICODE_STRING Source;
PWSTR Description;
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
Source = &((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceDescription;
Description = ExAllocatePool(PagedPool, Source->Length + sizeof(WCHAR));
if (!Description)
Status = STATUS_INSUFFICIENT_RESOURCES;
else
{
RtlCopyMemory(Description, Source->Buffer, Source->Length);
Description[Source->Length / sizeof(WCHAR)] = L'\0';
Information = (ULONG_PTR)Description;
Status = STATUS_SUCCESS;
}
break;
}
case DeviceTextLocationInformation:
{
/* We don't have any text location to report,
* and this query is optional, so ignore it.
*/
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
break;
}
default:
{
DPRINT1("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown type 0x%lx\n",
Stack->Parameters.QueryDeviceText.DeviceTextType);
Status = STATUS_NOT_SUPPORTED;
}
}
break;
}
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0xd */
{
return ForwardIrpToAttachedFdoAndForget(DeviceObject, Irp);
}
case IRP_MN_QUERY_ID: /* 0x13 */
{
Status = SerenumPdoQueryId(DeviceObject, Irp, &Information);
break;
}
case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
{
PPNP_BUS_INFORMATION BusInfo;
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
if (!BusInfo)
Status = STATUS_INSUFFICIENT_RESOURCES;
else
{
BusInfo->BusTypeGuid = GUID_BUS_TYPE_SERENUM;
/* FIXME: real value should be PNPBus, but PNPBus seems to be
* the only value in INTERFACE_TYPE enum that doesn't work...
*/
BusInfo->LegacyBusType = PNPISABus;
/* We're the only serial bus enumerator on the computer */
BusInfo->BusNumber = 0;
Information = (ULONG_PTR)BusInfo;
Status = STATUS_SUCCESS;
}
break;
}
default:
{
/* We can't forward request to the lower driver, because
* we are a Pdo, so we don't have lower driver... */
DPRINT1("Serenum: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
}
}
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}

View file

@ -0,0 +1,114 @@
/* $Id:
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Serial enumerator driver
* FILE: drivers/bus/serenum/serenum.c
* PURPOSE: Serial enumeration driver entry point
*
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
*/
//#define NDEBUG
#define INITGUID
#include "serenum.h"
NTSTATUS STDCALL
SerenumPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
if (((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
return SerenumFdoPnp(DeviceObject, Irp);
else
return SerenumPdoPnp(DeviceObject, Irp);
}
VOID STDCALL
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
// nothing to do here yet
}
NTSTATUS STDCALL
IrpStub(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
NTSTATUS Status = STATUS_NOT_SUPPORTED;
if (((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
{
/* Forward some IRPs to lower device */
switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
{
case IRP_MJ_CREATE:
case IRP_MJ_CLOSE:
case IRP_MJ_CLEANUP:
case IRP_MJ_READ:
case IRP_MJ_WRITE:
case IRP_MJ_DEVICE_CONTROL:
return ForwardIrpToLowerDeviceAndForget(DeviceObject, Irp);
default:
{
DPRINT1("Serenum: FDO stub for major function 0x%lx\n",
IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
DbgBreakPoint();
Status = Irp->IoStatus.Status;
}
}
}
else
{
/* Forward some IRPs to attached FDO */
switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
{
case IRP_MJ_CREATE:
case IRP_MJ_CLOSE:
case IRP_MJ_CLEANUP:
case IRP_MJ_READ:
case IRP_MJ_WRITE:
case IRP_MJ_DEVICE_CONTROL:
return ForwardIrpToAttachedFdoAndForget(DeviceObject, Irp);
default:
{
DPRINT1("Serenum: PDO stub for major function 0x%lx\n",
IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
DbgBreakPoint();
Status = Irp->IoStatus.Status;
}
}
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
/*
* Standard DriverEntry method.
*/
NTSTATUS STDCALL
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegPath)
{
ULONG i;
DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = SerenumAddDevice;
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = IrpStub;
/*DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialClose;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SerialCleanup;
DriverObject->MajorFunction[IRP_MJ_READ] = SerialRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = SerialWrite;*/
//DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Serenum;
//DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = SerialQueryInformation;
DriverObject->MajorFunction[IRP_MJ_PNP] = SerenumPnp;
//DriverObject->MajorFunction[IRP_MJ_POWER] = SerialPower;
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,152 @@
#if defined(__GNUC__)
#include <ddk/ntddk.h>
#include <ddk/ntddser.h>
#include <ddk/wdmguid.h>
#include <stdio.h>
#include <debug.h>
#define SR_MSR_DSR 0x20
#define ExFreePoolWithTag(p, tag) ExFreePool(p)
/* FIXME: these prototypes MUST NOT be here! */
NTSTATUS STDCALL
IoAttachDeviceToDeviceStackSafe(
IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
OUT PDEVICE_OBJECT *AttachedToDeviceObject);
#elif defined(_MSC_VER)
#include <ntddk.h>
#include <ntddser.h>
#include <c:/progra~1/winddk/inc/ddk/wdm/wxp/wdmguid.h>
#include <stdio.h>
#define STDCALL
#define DPRINT1 DbgPrint("(%s:%d) ", __FILE__, __LINE__), DbgPrint
#define CHECKPOINT1 DbgPrint("(%s:%d)\n")
#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
NTSTATUS STDCALL
IoAttachDeviceToDeviceStackSafe(
IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
OUT PDEVICE_OBJECT *AttachedToDeviceObject);
#define DPRINT DPRINT1
#define CHECKPOINT CHECKPOINT1
#define SR_MSR_DSR 0x20
#else
#error Unknown compiler!
#endif
typedef enum
{
dsStopped,
dsStarted,
dsPaused,
dsRemoved,
dsSurpriseRemoved
} SERENUM_DEVICE_STATE;
typedef struct _COMMON_DEVICE_EXTENSION
{
BOOLEAN IsFDO;
SERENUM_DEVICE_STATE PnpState;
} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
typedef struct _FDO_DEVICE_EXTENSION
{
COMMON_DEVICE_EXTENSION Common;
PDEVICE_OBJECT LowerDevice;
PDEVICE_OBJECT Pdo;
IO_REMOVE_LOCK RemoveLock;
PDEVICE_OBJECT AttachedPdo;
ULONG Flags;
} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
typedef struct _PDO_DEVICE_EXTENSION
{
COMMON_DEVICE_EXTENSION Common;
PDEVICE_OBJECT AttachedFdo;
UNICODE_STRING DeviceDescription; // REG_SZ
UNICODE_STRING DeviceId; // REG_SZ
UNICODE_STRING HardwareIds; // REG_MULTI_SZ
UNICODE_STRING CompatibleIds; // REG_MULTI_SZ
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
#define SERENUM_TAG TAG('S', 'e', 'r', 'e')
/* Flags */
#define FLAG_ENUMERATION_DONE 0x01
/************************************ detect.c */
NTSTATUS
SerenumDetectPnpDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT LowerDevice);
NTSTATUS
SerenumDetectLegacyDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT LowerDevice);
/************************************ fdo.c */
NTSTATUS STDCALL
SerenumAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo);
NTSTATUS
SerenumFdoPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
/************************************ misc.c */
NTSTATUS
SerenumDuplicateUnicodeString(
OUT PUNICODE_STRING Destination,
IN PUNICODE_STRING Source,
IN POOL_TYPE PoolType);
NTSTATUS
SerenumInitMultiSzString(
OUT PUNICODE_STRING Destination,
... /* list of ANSI_STRINGs */);
NTSTATUS
ForwardIrpAndWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS STDCALL
ForwardIrpToLowerDeviceAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS STDCALL
ForwardIrpToAttachedFdoAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS STDCALL
ForwardIrpAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
/************************************ pdo.c */
NTSTATUS
SerenumPdoPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

View file

@ -0,0 +1,7 @@
/* $Id$ */
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "Serial port enumerator\0"
#define REACTOS_STR_INTERNAL_NAME "serenum\0"
#define REACTOS_STR_ORIGINAL_FILENAME "serenum.sys\0"
#include <reactos/version.rc>