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,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

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]