Add legacy detection of COM3 and COM4

Be ready for PnP serial ports
Don't hardcode base addresses and irq twice

svn path=/trunk/; revision=14216
This commit is contained in:
Hervé Poussineau 2005-03-20 12:15:51 +00:00
parent fcc7d2acc7
commit abb9dfec3b
3 changed files with 117 additions and 80 deletions

View file

@ -77,7 +77,11 @@ DetectLegacyDevice(
{ {
ULONG ResourceListSize; ULONG ResourceListSize;
PCM_RESOURCE_LIST ResourceList; PCM_RESOURCE_LIST ResourceList;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
BOOLEAN ConflictDetected, FoundPort; BOOLEAN ConflictDetected, FoundPort;
PDEVICE_OBJECT Pdo = NULL;
PDEVICE_OBJECT Fdo;
KIRQL Dirql;
NTSTATUS Status; NTSTATUS Status;
/* Create resource list */ /* Create resource list */
@ -91,18 +95,23 @@ DetectLegacyDevice(
ResourceList->List[0].PartialResourceList.Version = 1; ResourceList->List[0].PartialResourceList.Version = 1;
ResourceList->List[0].PartialResourceList.Revision = 1; ResourceList->List[0].PartialResourceList.Revision = 1;
ResourceList->List[0].PartialResourceList.Count = 2; ResourceList->List[0].PartialResourceList.Count = 2;
ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort; ResourceDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
ResourceList->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive; ResourceDescriptor->Type = CmResourceTypePort;
ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO; ResourceDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
// FIXME ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start = ComPortBase; ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = 8; ResourceDescriptor->u.Port.Start.u.HighPart = 0;
ResourceDescriptor->u.Port.Start.u.LowPart = ComPortBase;
ResourceDescriptor->u.Port.Length = 8;
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].Type = CmResourceTypeInterrupt; ResourceDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[1];
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].ShareDisposition = CmResourceShareDriverExclusive; ResourceDescriptor->Type = CmResourceTypeInterrupt;
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].Flags = CM_RESOURCE_INTERRUPT_LATCHED; ResourceDescriptor->ShareDisposition = CmResourceShareShared;
/* FIXME: ResourceList->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Level = ; ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Vector = ; ResourceDescriptor->u.Interrupt.Vector = HalGetInterruptVector(
ResourceList->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Affinity = ;*/ Internal, 0, 0, Irq,
&Dirql,
&ResourceDescriptor->u.Interrupt.Affinity);
ResourceDescriptor->u.Interrupt.Level = (ULONG)Dirql;
/* Report resource list */ /* Report resource list */
Status = IoReportResourceForDetection( Status = IoReportResourceForDetection(
@ -125,7 +134,15 @@ DetectLegacyDevice(
ResourceList->List[0].InterfaceType, ResourceList->List[0].BusNumber, -1/*FIXME*/, ResourceList->List[0].InterfaceType, ResourceList->List[0].BusNumber, -1/*FIXME*/,
ResourceList, NULL, ResourceList, NULL,
TRUE, TRUE,
NULL); &Pdo);
if (NT_SUCCESS(Status))
{
Status = SerialAddDeviceInternal(DriverObject, Pdo, &Fdo);
if (NT_SUCCESS(Status))
{
Status = SerialPnpStartDevice(Fdo, ResourceList);
}
}
} }
else else
{ {
@ -143,20 +160,19 @@ NTSTATUS
DetectLegacyDevices( DetectLegacyDevices(
IN PDRIVER_OBJECT DriverObject) IN PDRIVER_OBJECT DriverObject)
{ {
ULONG ComPortBase[] = { 0x3f8, 0x2f8 }; ULONG ComPortBase[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
ULONG Irq[] = { 4, 3 }; ULONG Irq[] = { 4, 3, 4, 3 };
ULONG i; ULONG i;
NTSTATUS Status; NTSTATUS Status;
NTSTATUS ReturnedStatus = STATUS_SUCCESS;
for (i = 0; i < sizeof(ComPortBase)/sizeof(ComPortBase[0]); i++) for (i = 0; i < sizeof(ComPortBase)/sizeof(ComPortBase[0]); i++)
{ {
Status = DetectLegacyDevice(DriverObject, ComPortBase[i], Irq[i]); Status = DetectLegacyDevice(DriverObject, ComPortBase[i], Irq[i]);
DPRINT("Serial: Legacy device at 0x%x (IRQ %lu): status = 0x%08x\n", ComPortBase[i], Irq[i], Status); if (!NT_SUCCESS(Status) && Status != STATUS_DEVICE_NOT_CONNECTED)
if (Status == STATUS_DEVICE_NOT_CONNECTED) ReturnedStatus = Status;
Status = STATUS_SUCCESS; DPRINT("Serial: Legacy device at 0x%x (IRQ %lu): status = 0x%08lx\n", ComPortBase[i], Irq[i], Status);
else if (!NT_SUCCESS(Status))
break;
} }
return Status; return ReturnedStatus;
} }

View file

@ -14,9 +14,10 @@
#include "serial.h" #include "serial.h"
NTSTATUS STDCALL NTSTATUS STDCALL
SerialAddDevice( SerialAddDeviceInternal(
IN PDRIVER_OBJECT DriverObject, IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo) IN PDEVICE_OBJECT Pdo,
OUT PDEVICE_OBJECT* pFdo OPTIONAL)
{ {
PDEVICE_OBJECT Fdo = NULL; PDEVICE_OBJECT Fdo = NULL;
PSERIAL_DEVICE_EXTENSION DeviceExtension = NULL; PSERIAL_DEVICE_EXTENSION DeviceExtension = NULL;
@ -26,7 +27,7 @@ SerialAddDevice(
//UNICODE_STRING SymbolicLinkName; //UNICODE_STRING SymbolicLinkName;
static ULONG DeviceNumber = 0; static ULONG DeviceNumber = 0;
DPRINT("Serial: SerialAddDevice called\n"); DPRINT("Serial: SerialAddDeviceInternal called\n");
/* Create new device object */ /* Create new device object */
swprintf(DeviceNameBuffer, L"\\Device\\Serial%lu", DeviceNumber); swprintf(DeviceNameBuffer, L"\\Device\\Serial%lu", DeviceNumber);
@ -81,6 +82,10 @@ SerialAddDevice(
goto ByeBye; goto ByeBye;
} }
Fdo->Flags &= ~DO_DEVICE_INITIALIZING; Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
if (pFdo)
{
*pFdo = Fdo;
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -94,13 +99,35 @@ ByeBye:
return Status; return Status;
} }
NTSTATUS STDCALL
SerialAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo)
{
/* Serial.sys is a legacy driver. AddDevice is called once
* with a NULL Pdo just after the driver initialization.
* Detect this case and return success.
*/
if (Pdo == NULL)
return STATUS_SUCCESS;
/* 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, NULL);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS STDCALL NTSTATUS STDCALL
SerialPnpStartDevice( SerialPnpStartDevice(
IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp) IN PCM_RESOURCE_LIST ResourceList)
{ {
PIO_STACK_LOCATION Stack;
//PCM_RESOURCE_LIST ResourceList;
PSERIAL_DEVICE_EXTENSION DeviceExtension; PSERIAL_DEVICE_EXTENSION DeviceExtension;
WCHAR DeviceNameBuffer[32]; WCHAR DeviceNameBuffer[32];
UNICODE_STRING DeviceName; UNICODE_STRING DeviceName;
@ -108,16 +135,17 @@ SerialPnpStartDevice(
UNICODE_STRING LinkName; UNICODE_STRING LinkName;
WCHAR ComPortBuffer[32]; WCHAR ComPortBuffer[32];
UNICODE_STRING ComPort; UNICODE_STRING ComPort;
ULONG Vector; ULONG Vector = 0;
//ULONG i, j; ULONG i, j;
KIRQL Dirql; KIRQL Dirql;
KAFFINITY Affinity; KAFFINITY Affinity;
KINTERRUPT_MODE InterruptMode = Latched;
BOOLEAN ShareInterrupt = TRUE;
OBJECT_ATTRIBUTES objectAttributes; OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING KeyName; UNICODE_STRING KeyName;
HANDLE hKey; HANDLE hKey;
NTSTATUS Status; NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* FIXME: actually, IRP_MN_START_DEVICE is sent twice to each serial device: /* FIXME: actually, IRP_MN_START_DEVICE is sent twice to each serial device:
@ -128,66 +156,47 @@ SerialPnpStartDevice(
*/ */
if (DeviceExtension->PnpState == dsStarted) return STATUS_SUCCESS; if (DeviceExtension->PnpState == dsStarted) return STATUS_SUCCESS;
#if 1 DeviceExtension->ComPort = DeviceExtension->SerialPortNumber + 1;
/* FIXME: PnP isn't correctly implemented and doesn't give us a list DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
* of our own resources. Use default values instead. DeviceExtension->BaseAddress = 0;
*/ Dirql = 0;
switch (DeviceExtension->SerialPortNumber)
{
case 0:
DPRINT("Serial: creating COM1:\n");
DeviceExtension->ComPort = 1;
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
DeviceExtension->BaseAddress = 0x3F8;
DeviceExtension->Irq = 4;
break;
case 1:
DPRINT("Serial: creating COM2:\n");
DeviceExtension->ComPort = 2;
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
DeviceExtension->BaseAddress = 0x2F8;
DeviceExtension->Irq = 3;
break;
default:
DPRINT1("Serial: too much ports detected. Forgetting this one...\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
#else
DPRINT1("Serial: ResourceList %p, ResourceListTranslated %p\n",
Stack->Parameters.StartDevice.AllocatedResources,
Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
ResourceList = Stack->Parameters.StartDevice.AllocatedResourcesTranslated;
for (i = 0; i < ResourceList->Count; i++) for (i = 0; i < ResourceList->Count; i++)
{ {
DPRINT1("Serial: Interface type = 0x%x\n", ResourceList->List[i].InterfaceType); for (j = 0; j < ResourceList->List[i].PartialResourceList.Count; j++)
DPRINT1("Serial: Bus number = 0x%x\n", ResourceList->List[i].BusNumber);
for (j = 0; i < ResourceList->List[i].PartialResourceList.Count; j++)
{ {
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[i].PartialResourceList.PartialDescriptors[j]; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[i].PartialResourceList.PartialDescriptors[j];
DPRINT1("Serial: Type 0x%x, Share disposition 0x%x, Flags 0x%x\n",
PartialDescriptor->Type,
PartialDescriptor->ShareDisposition,
PartialDescriptor->Flags);
switch (PartialDescriptor->Type) switch (PartialDescriptor->Type)
{ {
case CmResourceTypePort: case CmResourceTypePort:
if (PartialDescriptor->u.Port.Length < 8)
return STATUS_INSUFFICIENT_RESOURCES;
if (DeviceExtension->BaseAddress != 0)
return STATUS_UNSUCCESSFUL;
DeviceExtension->BaseAddress = PartialDescriptor->u.Port.Start.u.LowPart; DeviceExtension->BaseAddress = PartialDescriptor->u.Port.Start.u.LowPart;
DPRINT1("Serial: CmResourceTypePort = %lu\n", DeviceExtension->BaseAddress);
break; break;
case CmResourceTypeInterrupt: case CmResourceTypeInterrupt:
/* FIXME: Detect if interrupt is shareable and/or latched */ if (Dirql != 0)
/* FIXME: use also ->u.Interrupt.Vector and ->u.Interrupt.Affinity return STATUS_UNSUCCESSFUL;
* to remove call to HalGetInterruptVector(...) */ Dirql = (KIRQL)PartialDescriptor->u.Interrupt.Level;
DeviceExtension->Irq = PartialDescriptor->u.Interrupt.Level; Vector = PartialDescriptor->u.Interrupt.Vector;
DPRINT1("Serial: Irq = %lu\n", DeviceExtension->Irq); Affinity = PartialDescriptor->u.Interrupt.Affinity;
if (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
InterruptMode = Latched;
else
InterruptMode = LevelSensitive;
ShareInterrupt = (PartialDescriptor->ShareDisposition == CmResourceShareShared);
break; break;
} }
} }
} }
DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER; DPRINT("Serial: New COM port. Base = 0x%lx, Irql = %u\n",
/* FIXME: use polling if no interrupt was found? */ DeviceExtension->BaseAddress, Dirql);
DeviceExtension->ComPort = 5; /* FIXME: use incremental value, or find it in resource list */ if (!DeviceExtension->BaseAddress)
#endif return STATUS_INSUFFICIENT_RESOURCES;
/* FIXME: we should be able to continue and use polling method
* for read/write if we don't have an interrupt */
if (!Dirql)
return STATUS_INSUFFICIENT_RESOURCES;
/* Get current settings */ /* Get current settings */
DeviceExtension->IER = READ_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress)); DeviceExtension->IER = READ_PORT_UCHAR(SER_IER((PUCHAR)DeviceExtension->BaseAddress));
@ -229,11 +238,11 @@ SerialPnpStartDevice(
} }
/* Connect interrupt and enable them */ /* Connect interrupt and enable them */
Vector = HalGetInterruptVector(Internal, 0, 0, DeviceExtension->Irq, &Dirql, &Affinity);
Status = IoConnectInterrupt( Status = IoConnectInterrupt(
&DeviceExtension->Interrupt, SerialInterruptService, &DeviceExtension->Interrupt, SerialInterruptService,
DeviceObject, NULL, Vector, Dirql, Dirql, Latched, DeviceObject, NULL,
FALSE /* FIXME: or TRUE to share interrupt on PCI bus? */, Vector, Dirql, Dirql,
InterruptMode, ShareInterrupt,
Affinity, FALSE); Affinity, FALSE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
@ -288,7 +297,9 @@ SerialPnp(
/* Call lower driver */ /* Call lower driver */
Status = ForwardIrpAndWait(DeviceObject, Irp); Status = ForwardIrpAndWait(DeviceObject, Irp);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
Status = SerialPnpStartDevice(DeviceObject, Irp); Status = SerialPnpStartDevice(
DeviceObject,
Stack->Parameters.StartDevice.AllocatedResources);
break; break;
} }
/* IRP_MN_QUERY_STOP_DEVICE (FIXME: required) */ /* IRP_MN_QUERY_STOP_DEVICE (FIXME: required) */

View file

@ -70,7 +70,6 @@ typedef struct _SERIAL_DEVICE_EXTENSION
ULONG ComPort; ULONG ComPort;
ULONG BaudRate; ULONG BaudRate;
ULONG BaseAddress; ULONG BaseAddress;
ULONG Irq;
PKINTERRUPT Interrupt; PKINTERRUPT Interrupt;
SERIAL_LINE_CONTROL SerialLineControl; SERIAL_LINE_CONTROL SerialLineControl;
@ -234,11 +233,22 @@ SerialInterruptService(
/************************************ pnp.c */ /************************************ pnp.c */
NTSTATUS STDCALL
SerialAddDeviceInternal(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo,
OUT PDEVICE_OBJECT* pFdo OPTIONAL);
NTSTATUS STDCALL NTSTATUS STDCALL
SerialAddDevice( SerialAddDevice(
IN PDRIVER_OBJECT DriverObject, IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo); IN PDEVICE_OBJECT Pdo);
NTSTATUS STDCALL
SerialPnpStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PCM_RESOURCE_LIST ResourceList);
NTSTATUS STDCALL NTSTATUS STDCALL
SerialPnp( SerialPnp(
IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_OBJECT DeviceObject,