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
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
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
include $(PATH_TO_TOP)/rules.mak
-DRIVERS = acpi isapnp pci
+DRIVERS = acpi isapnp pci serenum
all: $(DRIVERS)
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+# $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
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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;
+}
--- /dev/null
+#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);
--- /dev/null
+/* $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>