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

svn path=/trunk/; revision=14491
This commit is contained in:
Hervé Poussineau 2005-04-04 23:00:52 +00:00
parent d9bef42fde
commit e0dfaf1c5b
6 changed files with 107 additions and 22 deletions

View file

@ -674,13 +674,14 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Null","Type",0x00010001,0x00000001
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

View file

@ -74,11 +74,12 @@ SerialDetectUartType(
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 @@ DetectLegacyDevice(
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 @@ DetectLegacyDevice(
&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 @@ DetectLegacyDevice(
&ConflictDetected);
Status = STATUS_DEVICE_NOT_CONNECTED;
}
ExFreePoolWithTag(ResourceList, SERIAL_TAG);
return Status;
}
@ -168,13 +177,14 @@ DetectLegacyDevices(
{
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);

View file

@ -18,6 +18,7 @@ SerialAddDeviceInternal(
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 @@ SerialAddDeviceInternal(
UNICODE_STRING DeviceName;
//UNICODE_STRING SymbolicLinkName;
static ULONG DeviceNumber = 0;
static ULONG ComPortNumber = 1;
DPRINT("Serial: SerialAddDeviceInternal called\n");
@ -68,6 +70,10 @@ SerialAddDeviceInternal(
#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 @@ SerialAddDevice(
/* 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 @@ SerialPnpStartDevice(
ASSERT(DeviceExtension->PnpState == dsStopped);
DeviceExtension->ComPort = DeviceExtension->SerialPortNumber + 1;
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
DeviceExtension->BaseAddress = 0;
Dirql = 0;
@ -330,15 +331,16 @@ SerialPnp(
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 @@ SerialPnp(
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 @@ SerialPnp(
&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;

View file

@ -41,6 +41,18 @@ DriverEntry(
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;
}
}

View file

@ -313,6 +313,7 @@ SerialAddDeviceInternal(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo,
IN UART_TYPE UartType,
IN PULONG pComPortNumber OPTIONAL,
OUT PDEVICE_OBJECT* pFdo OPTIONAL);
NTSTATUS STDCALL

View file

@ -80,8 +80,49 @@ IoReportResourceForDetection(
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;
}