-/* $Id: fdo.c,v 1.4 2003/11/24 16:15:00 gvg Exp $\r
- *\r
- * PROJECT: ReactOS PCI bus driver\r
- * FILE: fdo.c\r
- * PURPOSE: PCI device object dispatch routines\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * UPDATE HISTORY:\r
- * 10-09-2001 CSH Created\r
- */\r
-#include <pci.h>\r
-\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/*** PRIVATE *****************************************************************/\r
-\r
-NTSTATUS\r
-FdoLocateChildDevice(\r
- PPCI_DEVICE *Device,\r
- PFDO_DEVICE_EXTENSION DeviceExtension,\r
- PPCI_COMMON_CONFIG PciConfig)\r
-{\r
- PLIST_ENTRY CurrentEntry;\r
- PPCI_DEVICE CurrentDevice;\r
-\r
- CurrentEntry = DeviceExtension->DeviceListHead.Flink;\r
- while (CurrentEntry != &DeviceExtension->DeviceListHead) {\r
- CurrentDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);\r
-\r
- /* If both vendor ID and device ID match, it is the same device */\r
- if ((PciConfig->VendorID == CurrentDevice->PciConfig.VendorID) &&\r
- (PciConfig->DeviceID == CurrentDevice->PciConfig.DeviceID)) {\r
- *Device = CurrentDevice;\r
- return STATUS_SUCCESS;\r
- }\r
-\r
- CurrentEntry = CurrentEntry->Flink;\r
- }\r
-\r
- *Device = NULL;\r
- return STATUS_UNSUCCESSFUL;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoEnumerateDevices(\r
- PDEVICE_OBJECT DeviceObject)\r
-{\r
- PFDO_DEVICE_EXTENSION DeviceExtension;\r
- PCI_COMMON_CONFIG PciConfig;\r
- PLIST_ENTRY CurrentEntry;\r
- PPCI_DEVICE Device;\r
- NTSTATUS Status;\r
- ULONG Slot;\r
- ULONG Size;\r
-\r
- DPRINT("Called\n");\r
-\r
- DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
- /* Mark all devices to be removed. If we don't discover them again during\r
- enumeration, assume that they have been surprise removed */\r
- CurrentEntry = DeviceExtension->DeviceListHead.Flink;\r
- while (CurrentEntry != &DeviceExtension->DeviceListHead) {\r
- Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);\r
- Device->RemovePending = TRUE;\r
- CurrentEntry = CurrentEntry->Flink;\r
- }\r
-\r
- DeviceExtension->DeviceListCount = 0;\r
-\r
- /* Enumerate devices on the PCI bus */\r
- for (Slot = 0; Slot < 256; Slot++)\r
- {\r
- Size = PciGetBusData(\r
- DeviceExtension->BusNumber,\r
- Slot,\r
- &PciConfig,\r
- 0,\r
- sizeof(PCI_COMMON_CONFIG));\r
- if (Size != 0)\r
- {\r
- DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",\r
- DeviceExtension->BusNumber,\r
- Slot>>3,\r
- Slot & 0x07,\r
- PciConfig.VendorID,\r
- PciConfig.DeviceID);\r
-\r
- Status = FdoLocateChildDevice(&Device, DeviceExtension, &PciConfig);\r
- if (!NT_SUCCESS(Status)) {\r
- Device = (PPCI_DEVICE)ExAllocatePool(PagedPool, sizeof(PCI_DEVICE));\r
- if (!Device)\r
- {\r
- /* FIXME: Cleanup resources for already discovered devices */\r
- return STATUS_INSUFFICIENT_RESOURCES;\r
- }\r
-\r
- RtlZeroMemory(Device, sizeof(PCI_DEVICE));\r
-\r
- RtlMoveMemory(&Device->PciConfig, &PciConfig, sizeof(PCI_COMMON_CONFIG));\r
-\r
- ExInterlockedInsertTailList(\r
- &DeviceExtension->DeviceListHead,\r
- &Device->ListEntry,\r
- &DeviceExtension->DeviceListLock);\r
- }\r
-\r
- /* Don't remove this device */\r
- Device->RemovePending = FALSE;\r
-\r
- DeviceExtension->DeviceListCount++;\r
- }\r
- }\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoQueryBusRelations(\r
- IN PDEVICE_OBJECT DeviceObject,\r
- IN PIRP Irp,\r
- PIO_STACK_LOCATION IrpSp)\r
-{\r
- PPDO_DEVICE_EXTENSION PdoDeviceExtension;\r
- PFDO_DEVICE_EXTENSION DeviceExtension;\r
- PDEVICE_RELATIONS Relations;\r
- PLIST_ENTRY CurrentEntry;\r
- PPCI_DEVICE Device;\r
- NTSTATUS Status;\r
- BOOLEAN ErrorOccurred;\r
- NTSTATUS ErrorStatus;\r
- WCHAR Buffer[MAX_PATH];\r
- ULONG Size;\r
- ULONG i;\r
-\r
- DPRINT("Called\n");\r
-\r
- ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;\r
-\r
- Status = STATUS_SUCCESS;\r
-\r
- ErrorOccurred = FALSE;\r
-\r
- FdoEnumerateDevices(DeviceObject);\r
-\r
- DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
- if (Irp->IoStatus.Information) {\r
- /* FIXME: Another bus driver has already created a DEVICE_RELATIONS \r
- structure so we must merge this structure with our own */\r
- }\r
-\r
- Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *\r
- (DeviceExtension->DeviceListCount - 1);\r
- Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);\r
- if (!Relations)\r
- return STATUS_INSUFFICIENT_RESOURCES;\r
-\r
- Relations->Count = DeviceExtension->DeviceListCount;\r
-\r
- i = 0;\r
- CurrentEntry = DeviceExtension->DeviceListHead.Flink;\r
- while (CurrentEntry != &DeviceExtension->DeviceListHead) {\r
- Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);\r
-\r
- PdoDeviceExtension = NULL;\r
-\r
- if (!Device->Pdo) {\r
- /* Create a physical device object for the\r
- device as it does not already have one */\r
- Status = IoCreateDevice(\r
- DeviceObject->DriverObject,\r
- sizeof(PDO_DEVICE_EXTENSION),\r
- NULL,\r
- FILE_DEVICE_CONTROLLER,\r
- 0,\r
- FALSE,\r
- &Device->Pdo);\r
- if (!NT_SUCCESS(Status)) {\r
- DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);\r
- ErrorStatus = Status;\r
- ErrorOccurred = TRUE;\r
- break;\r
- }\r
-\r
- Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
-\r
- Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;\r
-\r
- //Device->Pdo->Flags |= DO_POWER_PAGABLE;\r
-\r
- PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;\r
-\r
- RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));\r
-\r
- PdoDeviceExtension->Common.IsFDO = FALSE;\r
-\r
- PdoDeviceExtension->Common.DeviceObject = Device->Pdo;\r
-\r
- PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;\r
-\r
- /* FIXME: Get device properties (Hardware IDs, etc.) */\r
-\r
- swprintf(\r
- Buffer,\r
- L"PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",\r
- Device->PciConfig.VendorID,\r
- Device->PciConfig.DeviceID,\r
- (Device->PciConfig.u.type0.SubSystemID << 16) +\r
- Device->PciConfig.u.type0.SubVendorID,\r
- Device->PciConfig.RevisionID);\r
-\r
- if (!PciCreateUnicodeString(\r
- &PdoDeviceExtension->DeviceID,\r
- Buffer,\r
- PagedPool)) {\r
- ErrorOccurred = TRUE;\r
- break;\r
- }\r
-\r
- DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer);\r
- }\r
-\r
- if (!Device->RemovePending) {\r
- /* Reference the physical device object. The PnP manager\r
- will dereference it again when it is no longer needed */\r
- ObReferenceObject(Device->Pdo);\r
-\r
- Relations->Objects[i] = Device->Pdo;\r
-\r
- i++;\r
- }\r
-\r
- CurrentEntry = CurrentEntry->Flink;\r
- }\r
-\r
- if (ErrorOccurred) {\r
- /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */\r
- /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */\r
- if (PdoDeviceExtension) {\r
- RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID);\r
- ExFreePool(PdoDeviceExtension);\r
- }\r
-\r
- ExFreePool(Relations);\r
- return ErrorStatus;\r
- }\r
-\r
- Irp->IoStatus.Information = (ULONG_PTR)Relations;\r
-\r
- return Status;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoStartDevice(\r
- IN PDEVICE_OBJECT DeviceObject,\r
- IN PIRP Irp)\r
-{\r
- PFDO_DEVICE_EXTENSION DeviceExtension;\r
-\r
- DPRINT("Called\n");\r
-\r
- DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
- assert(DeviceExtension->State == dsStopped);\r
-\r
- InitializeListHead(&DeviceExtension->DeviceListHead);\r
- KeInitializeSpinLock(&DeviceExtension->DeviceListLock);\r
- DeviceExtension->DeviceListCount = 0;\r
-\r
- PciBusConfigType = PciGetBusConfigType();\r
-\r
- DPRINT("Bus configuration is %d\n", PciBusConfigType);\r
-\r
- if (PciBusConfigType != pbtUnknown) {\r
- /* At least one PCI bus is found */\r
- }\r
-\r
- /* FIXME: Find a way to get this information */\r
- DeviceExtension->BusNumber = 0;\r
-\r
- DeviceExtension->State = dsStarted;\r
-\r
- //Irp->IoStatus.Information = 0;\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoSetPower(\r
- IN PDEVICE_OBJECT DeviceObject,\r
- IN PIRP Irp,\r
- PIO_STACK_LOCATION IrpSp)\r
-{\r
- PFDO_DEVICE_EXTENSION DeviceExtension;\r
- NTSTATUS Status;\r
-\r
- DPRINT("Called\n");\r
-\r
- DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
- if (IrpSp->Parameters.Power.Type == DevicePowerState) {\r
- /* FIXME: Set device power state for the device */\r
- Status = STATUS_UNSUCCESSFUL;\r
- } else {\r
- Status = STATUS_UNSUCCESSFUL;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/*** PUBLIC ******************************************************************/\r
-\r
-NTSTATUS\r
-FdoPnpControl(\r
- PDEVICE_OBJECT DeviceObject,\r
- PIRP Irp)\r
-/*\r
- * FUNCTION: Handle Plug and Play IRPs for the PCI device object\r
- * ARGUMENTS:\r
- * DeviceObject = Pointer to functional device object of the PCI driver\r
- * Irp = Pointer to IRP that should be handled\r
- * RETURNS:\r
- * Status\r
- */\r
-{\r
- PFDO_DEVICE_EXTENSION DeviceExtension;\r
- PIO_STACK_LOCATION IrpSp;\r
- NTSTATUS Status;\r
-\r
- DPRINT("Called\n");\r
-\r
- DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
- IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
- switch (IrpSp->MinorFunction) {\r
-#if 0\r
- case IRP_MN_CANCEL_REMOVE_DEVICE:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-\r
- case IRP_MN_CANCEL_STOP_DEVICE:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-\r
- case IRP_MN_DEVICE_USAGE_NOTIFICATION:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-\r
- case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-#endif\r
- case IRP_MN_QUERY_DEVICE_RELATIONS:\r
- Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);\r
- break;\r
-#if 0\r
- case IRP_MN_QUERY_PNP_DEVICE_STATE:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-\r
- case IRP_MN_QUERY_REMOVE_DEVICE:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-\r
- case IRP_MN_QUERY_STOP_DEVICE:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-\r
- case IRP_MN_REMOVE_DEVICE:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-#endif\r
- case IRP_MN_START_DEVICE:\r
- DPRINT("IRP_MN_START_DEVICE received\n");\r
- Status = FdoStartDevice(DeviceObject, Irp);\r
- break;\r
- case IRP_MN_STOP_DEVICE:\r
- /* Currently not supported */\r
- Status = STATUS_UNSUCCESSFUL;\r
- break;\r
-#if 0\r
- case IRP_MN_SURPRISE_REMOVAL:\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
-#endif\r
- default:\r
- DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);\r
-\r
- /*\r
- * Do NOT complete the IRP as it will be processed by the lower\r
- * device object, which will complete the IRP\r
- */\r
- IoSkipCurrentIrpStackLocation(Irp);\r
- Status = IoCallDriver(DeviceExtension->Ldo, Irp);\r
- return Status;\r
- break;\r
- }\r
-\r
-\r
- if (Status != STATUS_PENDING) {\r
- if (Status != STATUS_NOT_IMPLEMENTED)\r
- Irp->IoStatus.Status = Status;\r
- IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
- }\r
-\r
- DPRINT("Leaving. Status 0x%X\n", Status);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-NTSTATUS\r
-FdoPowerControl(\r
- PDEVICE_OBJECT DeviceObject,\r
- PIRP Irp)\r
-/*\r
- * FUNCTION: Handle power management IRPs for the PCI device object\r
- * ARGUMENTS:\r
- * DeviceObject = Pointer to functional device object of the PCI driver\r
- * Irp = Pointer to IRP that should be handled\r
- * RETURNS:\r
- * Status\r
- */\r
-{\r
- PIO_STACK_LOCATION IrpSp;\r
- NTSTATUS Status;\r
-\r
- DPRINT("Called\n");\r
-\r
- IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-\r
- switch (IrpSp->MinorFunction) {\r
- case IRP_MN_SET_POWER:\r
- Status = FdoSetPower(DeviceObject, Irp, IrpSp);\r
- break;\r
-\r
- default:\r
- DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);\r
- Status = STATUS_NOT_IMPLEMENTED;\r
- break;\r
- }\r
-\r
- if (Status != STATUS_PENDING) {\r
- Irp->IoStatus.Status = Status;\r
- IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
- }\r
-\r
- DPRINT("Leaving. Status 0x%X\n", Status);\r
-\r
- return Status;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * PROJECT: ReactOS PCI bus driver
+ * FILE: fdo.c
+ * PURPOSE: PCI device object dispatch routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ * 10-09-2001 CSH Created
+ */
+
+#include "pci.h"
+
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+#include <debug.h>
+
+/*** PRIVATE *****************************************************************/
+
+static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion;
+
+static NTSTATUS NTAPI
+ForwardIrpAndWaitCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ UNREFERENCED_PARAMETER(DeviceObject);
+ if (Irp->PendingReturned)
+ KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS NTAPI
+ForwardIrpAndWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ KEVENT Event;
+ NTSTATUS Status;
+ PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Ldo;
+ ASSERT(LowerDevice);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
+
+ Status = IoCallDriver(LowerDevice, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+ if (NT_SUCCESS(Status))
+ Status = Irp->IoStatus.Status;
+ }
+
+ return Status;
+}
+
+static NTSTATUS
+FdoLocateChildDevice(
+ PPCI_DEVICE *Device,
+ PFDO_DEVICE_EXTENSION DeviceExtension,
+ PCI_SLOT_NUMBER SlotNumber,
+ PPCI_COMMON_CONFIG PciConfig)
+{
+ PLIST_ENTRY CurrentEntry;
+ PPCI_DEVICE CurrentDevice;
+
+ DPRINT("Called\n");
+
+ CurrentEntry = DeviceExtension->DeviceListHead.Flink;
+ while (CurrentEntry != &DeviceExtension->DeviceListHead) {
+ CurrentDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
+
+ /* If both vendor ID and device ID match, it is the same device */
+ if ((PciConfig->VendorID == CurrentDevice->PciConfig.VendorID) &&
+ (PciConfig->DeviceID == CurrentDevice->PciConfig.DeviceID) &&
+ (SlotNumber.u.AsULONG == CurrentDevice->SlotNumber.u.AsULONG)) {
+ *Device = CurrentDevice;
+ DPRINT("Done\n");
+ return STATUS_SUCCESS;
+ }
+
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ *Device = NULL;
+ DPRINT("Done\n");
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+static NTSTATUS
+FdoEnumerateDevices(
+ PDEVICE_OBJECT DeviceObject)
+{
+ PFDO_DEVICE_EXTENSION DeviceExtension;
+ PCI_COMMON_CONFIG PciConfig;
+ PLIST_ENTRY CurrentEntry;
+ PPCI_DEVICE Device;
+ PCI_SLOT_NUMBER SlotNumber;
+ ULONG DeviceNumber;
+ ULONG FunctionNumber;
+ ULONG Size;
+ NTSTATUS Status;
+
+ DPRINT("Called\n");
+
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ /* Mark all devices to be removed. If we don't discover them again during
+ enumeration, assume that they have been surprise removed */
+ CurrentEntry = DeviceExtension->DeviceListHead.Flink;
+ while (CurrentEntry != &DeviceExtension->DeviceListHead) {
+ Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
+ Device->RemovePending = TRUE;
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ DeviceExtension->DeviceListCount = 0;
+
+ /* Enumerate devices on the PCI bus */
+ SlotNumber.u.AsULONG = 0;
+ for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+ {
+ SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+ for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+ {
+ SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+
+ DPRINT("Bus %1lu Device %2lu Func %1lu\n",
+ DeviceExtension->BusNumber,
+ DeviceNumber,
+ FunctionNumber);
+
+ RtlZeroMemory(&PciConfig,
+ sizeof(PCI_COMMON_CONFIG));
+
+ Size = HalGetBusData(PCIConfiguration,
+ DeviceExtension->BusNumber,
+ SlotNumber.u.AsULONG,
+ &PciConfig,
+ PCI_COMMON_HDR_LENGTH);
+ DPRINT("Size %lu\n", Size);
+ if (Size < PCI_COMMON_HDR_LENGTH)
+ {
+ if (FunctionNumber == 0)
+ {
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
+ DeviceExtension->BusNumber,
+ DeviceNumber,
+ FunctionNumber,
+ PciConfig.VendorID,
+ PciConfig.DeviceID);
+
+ Status = FdoLocateChildDevice(&Device, DeviceExtension, SlotNumber, &PciConfig);
+ if (!NT_SUCCESS(Status))
+ {
+ Device = (PPCI_DEVICE)ExAllocatePoolWithTag(NonPagedPool, sizeof(PCI_DEVICE),TAG_PCI);
+ if (!Device)
+ {
+ /* FIXME: Cleanup resources for already discovered devices */
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(Device,
+ sizeof(PCI_DEVICE));
+
+ Device->BusNumber = DeviceExtension->BusNumber;
+
+ RtlCopyMemory(&Device->SlotNumber,
+ &SlotNumber,
+ sizeof(PCI_SLOT_NUMBER));
+
+ RtlCopyMemory(&Device->PciConfig,
+ &PciConfig,
+ sizeof(PCI_COMMON_CONFIG));
+
+ ExInterlockedInsertTailList(
+ &DeviceExtension->DeviceListHead,
+ &Device->ListEntry,
+ &DeviceExtension->DeviceListLock);
+ }
+
+ /* Don't remove this device */
+ Device->RemovePending = FALSE;
+
+ DeviceExtension->DeviceListCount++;
+
+ /* Skip to next device if the current one is not a multifunction device */
+ if ((FunctionNumber == 0) &&
+ ((PciConfig.HeaderType & 0x80) == 0))
+ {
+ break;
+ }
+ }
+ }
+
+ DPRINT("Done\n");
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+FdoQueryBusRelations(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+{
+ PPDO_DEVICE_EXTENSION PdoDeviceExtension = NULL;
+ PFDO_DEVICE_EXTENSION DeviceExtension;
+ PDEVICE_RELATIONS Relations;
+ PLIST_ENTRY CurrentEntry;
+ PPCI_DEVICE Device;
+ NTSTATUS Status;
+ BOOLEAN ErrorOccurred;
+ NTSTATUS ErrorStatus;
+ ULONG Size;
+ ULONG i;
+
+ UNREFERENCED_PARAMETER(IrpSp);
+
+ DPRINT("Called\n");
+
+ ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ Status = STATUS_SUCCESS;
+
+ ErrorOccurred = FALSE;
+
+ FdoEnumerateDevices(DeviceObject);
+
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ if (Irp->IoStatus.Information) {
+ /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
+ structure so we must merge this structure with our own */
+ }
+
+ Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
+ (DeviceExtension->DeviceListCount - 1);
+ Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
+ if (!Relations)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ Relations->Count = DeviceExtension->DeviceListCount;
+
+ i = 0;
+ CurrentEntry = DeviceExtension->DeviceListHead.Flink;
+ while (CurrentEntry != &DeviceExtension->DeviceListHead) {
+ Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
+
+ PdoDeviceExtension = NULL;
+
+ if (!Device->Pdo) {
+ /* Create a physical device object for the
+ device as it does not already have one */
+ Status = IoCreateDevice(
+ DeviceObject->DriverObject,
+ sizeof(PDO_DEVICE_EXTENSION),
+ NULL,
+ FILE_DEVICE_CONTROLLER,
+ FILE_AUTOGENERATED_DEVICE_NAME,
+ FALSE,
+ &Device->Pdo);
+ if (!NT_SUCCESS(Status)) {
+ DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
+ ErrorStatus = Status;
+ ErrorOccurred = TRUE;
+ break;
+ }
+
+ Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ //Device->Pdo->Flags |= DO_POWER_PAGABLE;
+
+ PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
+
+ RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
+
+ PdoDeviceExtension->Common.IsFDO = FALSE;
+
+ PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
+
+ PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
+
+ PdoDeviceExtension->Fdo = DeviceObject;
+
+ PdoDeviceExtension->PciDevice = Device;
+
+ /* Add Device ID string */
+ Status = PciCreateDeviceIDString(&PdoDeviceExtension->DeviceID, Device);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorStatus = Status;
+ ErrorOccurred = TRUE;
+ break;
+ }
+
+ DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer);
+
+ /* Add Instance ID string */
+ Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceID, Device);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorStatus = Status;
+ ErrorOccurred = TRUE;
+ break;
+ }
+
+ /* Add Hardware IDs string */
+ Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIDs, Device);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorStatus = Status;
+ ErrorOccurred = TRUE;
+ break;
+ }
+
+ /* Add Compatible IDs string */
+ Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIDs, Device);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorStatus = Status;
+ ErrorOccurred = TRUE;
+ break;
+ }
+
+ /* Add device description string */
+ Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorStatus = Status;
+ ErrorOccurred = TRUE;
+ break;
+ }
+
+ /* Add device location string */
+ Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorStatus = Status;
+ ErrorOccurred = TRUE;
+ break;
+ }
+ }
+
+ if (!Device->RemovePending) {
+ /* Reference the physical device object. The PnP manager
+ will dereference it again when it is no longer needed */
+ ObReferenceObject(Device->Pdo);
+
+ Relations->Objects[i] = Device->Pdo;
+
+ i++;
+ }
+
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ if (ErrorOccurred) {
+ /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
+ /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
+ if (PdoDeviceExtension) {
+ RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID);
+ RtlFreeUnicodeString(&PdoDeviceExtension->InstanceID);
+ RtlFreeUnicodeString(&PdoDeviceExtension->HardwareIDs);
+ RtlFreeUnicodeString(&PdoDeviceExtension->CompatibleIDs);
+ RtlFreeUnicodeString(&PdoDeviceExtension->DeviceDescription);
+ RtlFreeUnicodeString(&PdoDeviceExtension->DeviceLocation);
+ }
+
+ ExFreePool(Relations);
+ return ErrorStatus;
+ }
+
+ Irp->IoStatus.Information = (ULONG_PTR)Relations;
+
+ DPRINT("Done\n");
+
+ return Status;
+}
+
+
+static NTSTATUS
+FdoStartDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PFDO_DEVICE_EXTENSION DeviceExtension;
+ PCM_RESOURCE_LIST AllocatedResources;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+ ULONG FoundBusNumber = FALSE;
+ ULONG i;
+
+ DPRINT("Called\n");
+
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ AllocatedResources = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources;
+ if (!AllocatedResources)
+ {
+ DPRINT("No allocated resources sent to driver\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ if (AllocatedResources->Count < 1)
+ {
+ DPRINT("Not enough allocated resources sent to driver\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ if (AllocatedResources->List[0].PartialResourceList.Version != 1
+ || AllocatedResources->List[0].PartialResourceList.Revision != 1)
+ return STATUS_REVISION_MISMATCH;
+
+ ASSERT(DeviceExtension->State == dsStopped);
+
+ /* By default, use the bus number in the resource list header */
+ DeviceExtension->BusNumber = AllocatedResources->List[0].BusNumber;
+
+ for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++)
+ {
+ ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
+ switch (ResourceDescriptor->Type)
+ {
+ case CmResourceTypeBusNumber:
+ {
+ if (FoundBusNumber || ResourceDescriptor->u.BusNumber.Length != 1)
+ return STATUS_INVALID_PARAMETER;
+ /* Use this one instead */
+ ASSERT(AllocatedResources->List[0].BusNumber == ResourceDescriptor->u.BusNumber.Start);
+ DeviceExtension->BusNumber = ResourceDescriptor->u.BusNumber.Start;
+ DPRINT("Found bus number resource: %lu\n", DeviceExtension->BusNumber);
+ FoundBusNumber = TRUE;
+ break;
+ }
+ default:
+ DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
+ }
+ }
+
+ InitializeListHead(&DeviceExtension->DeviceListHead);
+ KeInitializeSpinLock(&DeviceExtension->DeviceListLock);
+ DeviceExtension->DeviceListCount = 0;
+ DeviceExtension->State = dsStarted;
+
+ ExInterlockedInsertTailList(
+ &DriverExtension->BusListHead,
+ &DeviceExtension->ListEntry,
+ &DriverExtension->BusListLock);
+
+ Irp->IoStatus.Information = 0;
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+FdoSetPower(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+{
+ PFDO_DEVICE_EXTENSION DeviceExtension;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(Irp);
+
+ DPRINT("Called\n");
+
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ if (IrpSp->Parameters.Power.Type == DevicePowerState) {
+ /* FIXME: Set device power state for the device */
+ Status = STATUS_UNSUCCESSFUL;
+ } else {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ return Status;
+}
+
+
+/*** PUBLIC ******************************************************************/
+
+NTSTATUS
+FdoPnpControl(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+/*
+ * FUNCTION: Handle Plug and Play IRPs for the PCI device object
+ * ARGUMENTS:
+ * DeviceObject = Pointer to functional device object of the PCI driver
+ * Irp = Pointer to IRP that should be handled
+ * RETURNS:
+ * Status
+ */
+{
+ PFDO_DEVICE_EXTENSION DeviceExtension;
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status = Irp->IoStatus.Status;
+
+ DPRINT("Called\n");
+
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ switch (IrpSp->MinorFunction) {
+#if 0
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case IRP_MN_CANCEL_STOP_DEVICE:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+#endif
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations)
+ break;
+
+ Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+#if 0
+ case IRP_MN_QUERY_PNP_DEVICE_STATE:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case IRP_MN_QUERY_STOP_DEVICE:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case IRP_MN_REMOVE_DEVICE:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+#endif
+ case IRP_MN_START_DEVICE:
+ DPRINT("IRP_MN_START_DEVICE received\n");
+ Status = ForwardIrpAndWait(DeviceObject, Irp);
+ if (NT_SUCCESS(Status))
+ Status = FdoStartDevice(DeviceObject, Irp);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ case IRP_MN_STOP_DEVICE:
+ /* Currently not supported */
+ Status = STATUS_UNSUCCESSFUL;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+#if 0
+ case IRP_MN_SURPRISE_REMOVAL:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+#endif
+ case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+ break;
+ case IRP_MN_REMOVE_DEVICE:
+ DPRINT1("IRP_MN_REMOVE_DEVICE is UNIMPLEMENTED!\n");
+ break;
+ default:
+ DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ IoSkipCurrentIrpStackLocation(Irp);
+ Status = IoCallDriver(DeviceExtension->Ldo, Irp);
+
+ DPRINT("Leaving. Status 0x%X\n", Status);
+
+ return Status;
+}
+
+
+NTSTATUS
+FdoPowerControl(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+/*
+ * FUNCTION: Handle power management IRPs for the PCI device object
+ * ARGUMENTS:
+ * DeviceObject = Pointer to functional device object of the PCI driver
+ * Irp = Pointer to IRP that should be handled
+ * RETURNS:
+ * Status
+ */
+{
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status;
+
+ DPRINT("Called\n");
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (IrpSp->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ Status = FdoSetPower(DeviceObject, Irp, IrpSp);
+ break;
+
+ default:
+ DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (Status != STATUS_PENDING) {
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+
+ DPRINT("Leaving. Status 0x%X\n", Status);
+
+ return Status;
+}
+
+/* EOF */