Allow ACPI detection and legacy detection for serial ports
Detect serial debug port and prevent its management by serial driver
Activate serial driver in registry
Modified: trunk/reactos/bootdata/hivesys.inf
Modified: trunk/reactos/drivers/dd/serial/legacy.c
Modified: trunk/reactos/drivers/dd/serial/pnp.c
Modified: trunk/reactos/drivers/dd/serial/serial.c
Modified: trunk/reactos/drivers/dd/serial/serial.h
Modified: trunk/reactos/ntoskrnl/io/pnpreport.c

Modified: trunk/reactos/bootdata/hivesys.inf
--- trunk/reactos/bootdata/hivesys.inf	2005-04-04 22:48:51 UTC (rev 14490)
+++ trunk/reactos/bootdata/hivesys.inf	2005-04-04 23:00:52 UTC (rev 14491)
@@ -674,13 +674,14 @@
 HKLM,"SYSTEM\CurrentControlSet\Services\Serial","ErrorControl",0x00010001,0x00000000
 HKLM,"SYSTEM\CurrentControlSet\Services\Serial","Group",0x00000000,"Base"
 HKLM,"SYSTEM\CurrentControlSet\Services\Serial","ImagePath",0x00020000,"system32\drivers\serial.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\Serial","Start",0x00010001,0x00000004
+HKLM,"SYSTEM\CurrentControlSet\Services\Serial","Start",0x00010001,0x00000001
 HKLM,"SYSTEM\CurrentControlSet\Services\Serial","Type",0x00010001,0x00000001
 ;hard coded values
 HKLM,"SYSTEM\CurrentControlSet\Services\Serial\Enum","0",0x00000000,"ACPI\PNP0501"
 HKLM,"SYSTEM\CurrentControlSet\Services\Serial\Enum","Count",0x00010001,0x00000001
 HKLM,"SYSTEM\CurrentControlSet\Services\Serial\Enum","NextInstance",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\0000","Service",0x00000000,"serial"
+HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\1","Service",0x00000000,"serial"
+HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\2","Service",0x00000000,"serial"
 
 ; Packet driver
 HKLM,"SYSTEM\CurrentControlSet\Services\Packet","ErrorControl",0x00010001,0x00000001

Modified: trunk/reactos/drivers/dd/serial/legacy.c
--- trunk/reactos/drivers/dd/serial/legacy.c	2005-04-04 22:48:51 UTC (rev 14490)
+++ trunk/reactos/drivers/dd/serial/legacy.c	2005-04-04 23:00:52 UTC (rev 14491)
@@ -74,11 +74,12 @@
 	return Uart16550A;
 }
 
-NTSTATUS
+static NTSTATUS
 DetectLegacyDevice(
 	IN PDRIVER_OBJECT DriverObject,
 	IN ULONG ComPortBase,
-	IN ULONG Irq)
+	IN ULONG Irq,
+	IN PULONG pComPortNumber OPTIONAL)
 {
 	ULONG ResourceListSize;
 	PCM_RESOURCE_LIST ResourceList;
@@ -125,9 +126,16 @@
 		NULL, NULL, 0,
 		&ConflictDetected);
 	if (Status == STATUS_CONFLICTING_ADDRESSES)
+	{
+		DPRINT("Serial: conflict detected for serial port at 0x%lx (Irq %lu)\n", ComPortBase, Irq);
+		ExFreePoolWithTag(ResourceList, SERIAL_TAG);
 		return STATUS_DEVICE_NOT_CONNECTED;
+	}
 	if (!NT_SUCCESS(Status))
+	{
+		ExFreePoolWithTag(ResourceList, SERIAL_TAG);
 		return Status;
+	}
 	
 	/* Test if port exists */
 	UartType = SerialDetectUartType((PUCHAR)ComPortBase);
@@ -143,7 +151,7 @@
 			&Pdo);
 		if (NT_SUCCESS(Status))
 		{
-			Status = SerialAddDeviceInternal(DriverObject, Pdo, UartType, &Fdo);
+			Status = SerialAddDeviceInternal(DriverObject, Pdo, UartType, pComPortNumber, &Fdo);
 			if (NT_SUCCESS(Status))
 			{
 				Status = SerialPnpStartDevice(Fdo, ResourceList);
@@ -159,6 +167,7 @@
 			&ConflictDetected);
 		Status = STATUS_DEVICE_NOT_CONNECTED;
 	}
+	ExFreePoolWithTag(ResourceList, SERIAL_TAG);
 	return Status;
 }
 
@@ -168,13 +177,14 @@
 {
 	ULONG ComPortBase[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
 	ULONG Irq[] = { 4, 3, 4, 3 };
+	ULONG ComPortNumber[] = { 1, 2, 3, 4 };
 	ULONG i;
 	NTSTATUS Status;
 	NTSTATUS ReturnedStatus = STATUS_SUCCESS;
 	
 	for (i = 0; i < sizeof(ComPortBase)/sizeof(ComPortBase[0]); i++)
 	{
-		Status = DetectLegacyDevice(DriverObject, ComPortBase[i], Irq[i]);
+		Status = DetectLegacyDevice(DriverObject, ComPortBase[i], Irq[i], &ComPortNumber[i]);
 		if (!NT_SUCCESS(Status) && Status != STATUS_DEVICE_NOT_CONNECTED)
 			ReturnedStatus = Status;
 		DPRINT("Serial: Legacy device at 0x%x (IRQ %lu): status = 0x%08lx\n", ComPortBase[i], Irq[i], Status);

Modified: trunk/reactos/drivers/dd/serial/pnp.c
--- trunk/reactos/drivers/dd/serial/pnp.c	2005-04-04 22:48:51 UTC (rev 14490)
+++ trunk/reactos/drivers/dd/serial/pnp.c	2005-04-04 23:00:52 UTC (rev 14491)
@@ -18,6 +18,7 @@
 	IN PDRIVER_OBJECT DriverObject,
 	IN PDEVICE_OBJECT Pdo,
 	IN UART_TYPE UartType,
+	IN PULONG pComPortNumber OPTIONAL,
 	OUT PDEVICE_OBJECT* pFdo OPTIONAL)
 {
 	PDEVICE_OBJECT Fdo = NULL;
@@ -27,6 +28,7 @@
 	UNICODE_STRING DeviceName;
 	//UNICODE_STRING SymbolicLinkName;
 	static ULONG DeviceNumber = 0;
+	static ULONG ComPortNumber = 1;
 
 	DPRINT("Serial: SerialAddDeviceInternal called\n");
    
@@ -68,6 +70,10 @@
 #endif
 
 	DeviceExtension->SerialPortNumber = DeviceNumber++;
+	if (pComPortNumber == NULL)
+		DeviceExtension->ComPort = ComPortNumber++;
+	else
+		DeviceExtension->ComPort = *pComPortNumber;
 	DeviceExtension->Pdo = Pdo;
 	DeviceExtension->PnpState = dsStopped;
 	DeviceExtension->UartType = UartType;
@@ -122,13 +128,9 @@
 	/* We have here a PDO that does not correspond to a legacy
 	 * serial port. So call the internal AddDevice function.
 	 */
-	DPRINT1("Serial: SerialAddDevice() called. Pdo 0x%p (should be NULL)\n", Pdo);
-	/* FIXME: due to a bug, previously described AddDevice is
-	 * not called with a NULL Pdo. Block this call (blocks
-	 * unfortunately all the other PnP serial ports devices).
-	 */
-	return SerialAddDeviceInternal(DriverObject, Pdo, UartUnknown, NULL);
-	//return STATUS_UNSUCCESSFUL;
+	return SerialAddDeviceInternal(DriverObject, Pdo, UartUnknown, NULL, NULL);
+
+
 }
 
 NTSTATUS STDCALL
@@ -160,7 +162,6 @@
 	
 	ASSERT(DeviceExtension->PnpState == dsStopped);
 	
-	DeviceExtension->ComPort = DeviceExtension->SerialPortNumber + 1;
 	DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
 	DeviceExtension->BaseAddress = 0;
 	Dirql = 0;
@@ -330,15 +331,16 @@
 				KIRQL Dirql;
 				ULONG ComPortBase;
 				ULONG Irq;
+				BOOLEAN ConflictDetected;
 				
 				DPRINT1("Serial: no allocated resources for this device! Creating fake list\n");
-				switch (((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->SerialPortNumber)
+				switch (((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ComPort)
 				{
-					case 0:
+					case 1:
 						ComPortBase = 0x3f8;
 						Irq = 4;
 						break;
-					case 1:
+					case 2:
 						ComPortBase = 0x2f8;
 						Irq = 3;
 						break;
@@ -350,10 +352,15 @@
 				ResourceListSize = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
 				ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, ResourceListSize, SERIAL_TAG);
 				if (!ResourceList)
+				{
+					Irp->IoStatus.Information = 0;
+					Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+					IoCompleteRequest(Irp, IO_NO_INCREMENT);
 					return STATUS_INSUFFICIENT_RESOURCES;
+				}
 				ResourceList->Count = 1;
-				ResourceList->List[0].InterfaceType = Isa;
-				ResourceList->List[0].BusNumber = -1; /* FIXME */
+				ResourceList->List[0].InterfaceType = InterfaceTypeUndefined;
+				ResourceList->List[0].BusNumber = -1; /* unknown */
 				ResourceList->List[0].PartialResourceList.Version = 1;
 				ResourceList->List[0].PartialResourceList.Revision = 1;
 				ResourceList->List[0].PartialResourceList.Count = 2;
@@ -375,6 +382,19 @@
 					&ResourceDescriptor->u.Interrupt.Affinity);
 				ResourceDescriptor->u.Interrupt.Level = (ULONG)Dirql;
 				
+				/* Verify that this COM port is not the serial debug port */
+				Status = IoReportResourceForDetection(
+					DeviceObject->DriverObject, ResourceList, 0,
+					NULL, NULL, 0,
+					&ConflictDetected);
+				if (!NT_SUCCESS(Status))
+				{
+					Irp->IoStatus.Information = 0;
+					Irp->IoStatus.Status = Status;
+					IoCompleteRequest(Irp, IO_NO_INCREMENT);
+					return Status;
+				}
+				
 				Stack->Parameters.StartDevice.AllocatedResources =
 					Stack->Parameters.StartDevice.AllocatedResourcesTranslated =
 					ResourceList;

Modified: trunk/reactos/drivers/dd/serial/serial.c
--- trunk/reactos/drivers/dd/serial/serial.c	2005-04-04 22:48:51 UTC (rev 14490)
+++ trunk/reactos/drivers/dd/serial/serial.c	2005-04-04 23:00:52 UTC (rev 14491)
@@ -41,6 +41,18 @@
 	DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = SerialQueryInformation;
 	DriverObject->MajorFunction[IRP_MJ_PNP] = SerialPnp;
 	DriverObject->MajorFunction[IRP_MJ_POWER] = SerialPower;
-
-	return DetectLegacyDevices(DriverObject);
+	
+	/* FIXME: It seems that DriverEntry function may be called more
+	 * than once. Do only legacy detection the first time. */
+	static BOOLEAN FirstTime = TRUE;
+	if (FirstTime)
+	{
+		FirstTime = FALSE;
+		return DetectLegacyDevices(DriverObject);
+	}
+	else
+	{
+		DPRINT1("Serial: DriverEntry called for the second time!\n");
+		return STATUS_SUCCESS;
+	}
 }

Modified: trunk/reactos/drivers/dd/serial/serial.h
--- trunk/reactos/drivers/dd/serial/serial.h	2005-04-04 22:48:51 UTC (rev 14490)
+++ trunk/reactos/drivers/dd/serial/serial.h	2005-04-04 23:00:52 UTC (rev 14491)
@@ -313,6 +313,7 @@
 	IN PDRIVER_OBJECT DriverObject,
 	IN PDEVICE_OBJECT Pdo,
 	IN UART_TYPE UartType,
+	IN PULONG pComPortNumber OPTIONAL,
 	OUT PDEVICE_OBJECT* pFdo OPTIONAL);
 
 NTSTATUS STDCALL

Modified: trunk/reactos/ntoskrnl/io/pnpreport.c
--- trunk/reactos/ntoskrnl/io/pnpreport.c	2005-04-04 22:48:51 UTC (rev 14490)
+++ trunk/reactos/ntoskrnl/io/pnpreport.c	2005-04-04 23:00:52 UTC (rev 14491)
@@ -80,8 +80,49 @@
   IN ULONG DeviceListSize   OPTIONAL,
   OUT PBOOLEAN ConflictDetected)
 {
-  DPRINT1("IoReportResourceForDetection UNIMPLEMENTED but returns success.\n");
   *ConflictDetected = FALSE;
+  DPRINT1("IoReportResourceForDetection unimplemented\n");
+  
+  if (PopSystemPowerDeviceNode != NULL && DriverListSize > 0)
+  {
+    /* We hope serial ports will be enumerated by ACPI */
+    *ConflictDetected = TRUE;
+    return STATUS_CONFLICTING_ADDRESSES;
+  }
+  
+  /* HACK: check if serial debug output is enabled. If yes,
+   * prevent serial port driver to detect this serial port
+   * by indicating a conflict
+   */
+  if ((KdDebugState & KD_DEBUG_SERIAL) && DriverList != NULL)
+  {
+    ULONG ComPortBase = 0;
+    ULONG i;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+    
+    switch (LogPortInfo.ComPort)
+    {
+      case 1: ComPortBase = 0x3f8; break;
+      case 2: ComPortBase = 0x2f8; break;
+      case 3: ComPortBase = 0x3e8; break;
+      case 4: ComPortBase = 0x2e8; break;
+    }
+    
+    /* search for this port address in DriverList */
+    for (i = 0; i < DriverList->List[0].PartialResourceList.Count; i++)
+    {
+      ResourceDescriptor = &DriverList->List[0].PartialResourceList.PartialDescriptors[i];
+      if (ResourceDescriptor->Type == CmResourceTypePort)
+      {
+        if (ResourceDescriptor->u.Port.Start.u.LowPart <= ComPortBase
+         && ResourceDescriptor->u.Port.Start.u.LowPart + ResourceDescriptor->u.Port.Length > ComPortBase)
+        {
+          *ConflictDetected = TRUE;
+          return STATUS_CONFLICTING_ADDRESSES;
+        }
+      }
+    }
+  }
   return STATUS_SUCCESS;
 }