Add serial port enumerator driver: - Enumerate legacy mice - Should also detect PnP serial devices even if they are not yet reported It is implemented as an upper filter for serial port driver (serial.sys) Add corresponding registry entries Modified: trunk/reactos/Makefile Modified: trunk/reactos/bootdata/hivesys.inf Modified: trunk/reactos/bootdata/packages/reactos.dff Modified: trunk/reactos/drivers/bus/Makefile Added: trunk/reactos/drivers/bus/serenum/ Added: trunk/reactos/drivers/bus/serenum/detect.c Added: trunk/reactos/drivers/bus/serenum/fdo.c Added: trunk/reactos/drivers/bus/serenum/makefile Added: trunk/reactos/drivers/bus/serenum/misc.c Added: trunk/reactos/drivers/bus/serenum/pdo.c Added: trunk/reactos/drivers/bus/serenum/serenum.c Added: trunk/reactos/drivers/bus/serenum/serenum.h Added: trunk/reactos/drivers/bus/serenum/serenum.rc _____
Modified: trunk/reactos/Makefile --- trunk/reactos/Makefile 2005-04-05 18:59:56 UTC (rev 14511) +++ trunk/reactos/Makefile 2005-04-05 19:04:07 UTC (rev 14512) @@ -34,8 +34,8 @@
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 _____
Modified: trunk/reactos/bootdata/hivesys.inf --- trunk/reactos/bootdata/hivesys.inf 2005-04-05 18:59:56 UTC (rev 14511) +++ trunk/reactos/bootdata/hivesys.inf 2005-04-05 19:04:07 UTC (rev 14512) @@ -469,6 +469,19 @@
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x0 0000001
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00 000001
+; Serial port enumerator +HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x00010 001,0x00000001 +HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Group",0x00000000,"PN P Filter" +HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ImagePath",0x00020000 ,"system32\drivers\serenum.sys" +HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Start",0x00010001,0x0 0000003 +HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Type",0x00010001,0x00 000001 +;hard coded values +HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","0",0x00000000,"A CPI\PNP0501" +HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","Count",0x0001000 1,0x00000001 +HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","NextInstance",0x 00010001,0x00000001 +HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\1","UpperFilters",0x00 010000,"serenum" +HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\2","UpperFilters",0x00 010000,"serenum" + ; SB16 driver
HKLM,"SYSTEM\CurrentControlSet\Services\sndblst","Group",0x00000000,"Bas e"
HKLM,"SYSTEM\CurrentControlSet\Services\sndblst","ServiceType",0x0001000 1,0x00000001 _____
Modified: trunk/reactos/bootdata/packages/reactos.dff --- trunk/reactos/bootdata/packages/reactos.dff 2005-04-05 18:59:56 UTC (rev 14511) +++ trunk/reactos/bootdata/packages/reactos.dff 2005-04-05 19:04:07 UTC (rev 14512) @@ -29,6 +29,7 @@
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 _____
Modified: trunk/reactos/drivers/bus/Makefile --- trunk/reactos/drivers/bus/Makefile 2005-04-05 18:59:56 UTC (rev 14511) +++ trunk/reactos/drivers/bus/Makefile 2005-04-05 19:04:07 UTC (rev 14512) @@ -6,7 +6,7 @@
include $(PATH_TO_TOP)/rules.mak
-DRIVERS = acpi isapnp pci +DRIVERS = acpi isapnp pci serenum
all: $(DRIVERS)
_____
Added: trunk/reactos/drivers/bus/serenum/detect.c --- trunk/reactos/drivers/bus/serenum/detect.c 2005-04-05 18:59:56 UTC (rev 14511) +++ trunk/reactos/drivers/bus/serenum/detect.c 2005-04-05 19:04:07 UTC (rev 14512) @@ -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; +} Property changes on: trunk/reactos/drivers/bus/serenum/detect.c ___________________________________________________________________ Name: svn:keywords + author date id revision Name: svn:eol-style + native _____
Added: trunk/reactos/drivers/bus/serenum/fdo.c --- trunk/reactos/drivers/bus/serenum/fdo.c 2005-04-05 18:59:56 UTC (rev 14511) +++ trunk/reactos/drivers/bus/serenum/fdo.c 2005-04-05 19:04:07 UTC (rev 14512) @@ -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; +} Property changes on: trunk/reactos/drivers/bus/serenum/fdo.c ___________________________________________________________________ Name: svn:keywords + author date id revision Name: svn:eol-style + native _____
Added: trunk/reactos/drivers/bus/serenum/makefile --- trunk/reactos/drivers/bus/serenum/makefile 2005-04-05 18:59:56 UTC (rev 14511) +++ trunk/reactos/drivers/bus/serenum/makefile 2005-04-05 19:04:07 UTC (rev 14512) @@ -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 Property changes on: trunk/reactos/drivers/bus/serenum/makefile ___________________________________________________________________ Name: svn:eol-style + native _____
Added: trunk/reactos/drivers/bus/serenum/misc.c --- trunk/reactos/drivers/bus/serenum/misc.c 2005-04-05 18:59:56 UTC (rev 14511) +++ trunk/reactos/drivers/bus/serenum/misc.c 2005-04-05 19:04:07 UTC (rev 14512) @@ -0,0 +1,201 @@
+/* $Id: + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Serial enumerator driver + * FILE: drivers/dd/serenum/misc.c + * PURPOSE: Misceallenous operations + * + * PROGRAMMERS: HervÚ Poussineau (hpoussin@reactos.com) + */ + +#define NDEBUG +#include "serenum.h" +#include <stdarg.h> + +NTSTATUS +SerenumDuplicateUnicodeString( + OUT PUNICODE_STRING Destination, + IN PUNICODE_STRING Source, + IN POOL_TYPE PoolType) +{ + if (Source == NULL) + { + RtlInitUnicodeString(Destination, NULL); + return STATUS_SUCCESS; + } + + Destination->Buffer = ExAllocatePool(PoolType, Source->MaximumLength); + if (Destination->Buffer == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + Destination->MaximumLength = Source->MaximumLength; + Destination->Length = Source->Length; + RtlCopyMemory(Destination->Buffer, Source->Buffer, Source->MaximumLength); + + return STATUS_SUCCESS; +} + +/* I really want ANSI strings as last arguments because + * PnP ids are ANSI-encoded in PnP device string + * identification */ +NTSTATUS +SerenumInitMultiSzString( + OUT PUNICODE_STRING Destination, + ... /* list of PCSZ */) +{ + va_list args; + PCSZ Source; + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + ULONG DestinationSize = 0; + NTSTATUS Status = STATUS_SUCCESS; + + /* Calculate length needed for destination unicode string */ + va_start(args, Destination); + Source = va_arg(args, PCSZ); + while (Source != NULL) + { + RtlInitAnsiString(&AnsiString, Source); + DestinationSize += RtlAnsiStringToUnicodeSize(&AnsiString) + + sizeof(WCHAR) /* final NULL */; + Source = va_arg(args, PCSZ); + } + va_end(args); + if (DestinationSize == 0) + { + RtlInitUnicodeString(Destination, NULL); + return STATUS_SUCCESS; + } + + /* Initialize destination string */ + DestinationSize += sizeof(WCHAR); // final NULL + Destination->Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, DestinationSize, SERENUM_TAG); + if (!Destination->Buffer) + return STATUS_INSUFFICIENT_RESOURCES; + Destination->Length = 0; + Destination->MaximumLength = (USHORT)DestinationSize; + + /* Copy arguments to destination string */ + /* Use a temporary unicode string, which buffer is shared with + * destination string, to copy arguments */ + UnicodeString.Length = Destination->Length; + UnicodeString.MaximumLength = Destination->MaximumLength; + UnicodeString.Buffer = Destination->Buffer; + va_start(args, Destination); + Source = va_arg(args, PCSZ); + while (Source != NULL) + { + RtlInitAnsiString(&AnsiString, Source); + Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE); + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(Destination->Buffer, SERENUM_TAG); + break; + } + Destination->Length += UnicodeString.Length + sizeof(WCHAR); + UnicodeString.MaximumLength -= UnicodeString.Length + sizeof(WCHAR); + UnicodeString.Buffer += UnicodeString.Length / sizeof(WCHAR) + 1; + UnicodeString.Length = 0; + Source = va_arg(args, PCSZ); + } + va_end(args); + if (NT_SUCCESS(Status)) + { + /* Finish multi-sz string */ + Destination->Buffer[Destination->Length / sizeof(WCHAR)] = L'\0'; + Destination->Length += sizeof(WCHAR); + } + return Status; +} + +NTSTATUS STDCALL +ForwardIrpAndWaitCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + if (Irp->PendingReturned) + KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +ForwardIrpAndWait( + IN PDEVICE_OBJECT DeviceObject, [truncated at 1000 lines; 711 more skipped]