diff --git a/reactos/Makefile b/reactos/Makefile index 005116e0533..e823ac2cf65 100644 --- a/reactos/Makefile +++ b/reactos/Makefile @@ -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 diff --git a/reactos/bootdata/hivesys.inf b/reactos/bootdata/hivesys.inf index e69d8b601aa..71a302b9c32 100644 --- a/reactos/bootdata/hivesys.inf +++ b/reactos/bootdata/hivesys.inf @@ -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 diff --git a/reactos/bootdata/packages/reactos.dff b/reactos/bootdata/packages/reactos.dff index bd96d983eec..b05c05f3f4c 100755 --- a/reactos/bootdata/packages/reactos.dff +++ b/reactos/bootdata/packages/reactos.dff @@ -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 diff --git a/reactos/drivers/bus/Makefile b/reactos/drivers/bus/Makefile index 808ee461948..d75290a8c89 100644 --- a/reactos/drivers/bus/Makefile +++ b/reactos/drivers/bus/Makefile @@ -6,7 +6,7 @@ PATH_TO_TOP = ../.. include $(PATH_TO_TOP)/rules.mak -DRIVERS = acpi isapnp pci +DRIVERS = acpi isapnp pci serenum all: $(DRIVERS) diff --git a/reactos/drivers/bus/serenum/detect.c b/reactos/drivers/bus/serenum/detect.c new file mode 100644 index 00000000000..8ca0f2619d4 --- /dev/null +++ b/reactos/drivers/bus/serenum/detect.c @@ -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; +} diff --git a/reactos/drivers/bus/serenum/fdo.c b/reactos/drivers/bus/serenum/fdo.c new file mode 100644 index 00000000000..8084cd1a6e0 --- /dev/null +++ b/reactos/drivers/bus/serenum/fdo.c @@ -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; +} diff --git a/reactos/drivers/bus/serenum/makefile b/reactos/drivers/bus/serenum/makefile new file mode 100644 index 00000000000..8c3c924f9db --- /dev/null +++ b/reactos/drivers/bus/serenum/makefile @@ -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 diff --git a/reactos/drivers/bus/serenum/misc.c b/reactos/drivers/bus/serenum/misc.c new file mode 100644 index 00000000000..94eb3933474 --- /dev/null +++ b/reactos/drivers/bus/serenum/misc.c @@ -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 + +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); +} diff --git a/reactos/drivers/bus/serenum/pdo.c b/reactos/drivers/bus/serenum/pdo.c new file mode 100644 index 00000000000..54ade591a6c --- /dev/null +++ b/reactos/drivers/bus/serenum/pdo.c @@ -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; +} diff --git a/reactos/drivers/bus/serenum/serenum.c b/reactos/drivers/bus/serenum/serenum.c new file mode 100644 index 00000000000..ead4e826458 --- /dev/null +++ b/reactos/drivers/bus/serenum/serenum.c @@ -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; +} diff --git a/reactos/drivers/bus/serenum/serenum.h b/reactos/drivers/bus/serenum/serenum.h new file mode 100644 index 00000000000..cab635a72da --- /dev/null +++ b/reactos/drivers/bus/serenum/serenum.h @@ -0,0 +1,152 @@ +#if defined(__GNUC__) + #include + #include + #include + #include + + #include + + #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 + #include + #include + #include + + #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); diff --git a/reactos/drivers/bus/serenum/serenum.rc b/reactos/drivers/bus/serenum/serenum.rc new file mode 100644 index 00000000000..a88af0f20f3 --- /dev/null +++ b/reactos/drivers/bus/serenum/serenum.rc @@ -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