[LT2013]
[reactos.git] / drivers / bus / pci / pdo.c
index f19e45c..644bffe 100644 (file)
@@ -23,29 +23,37 @@ PdoQueryDeviceText(
   PIO_STACK_LOCATION IrpSp)
 {
   PPDO_DEVICE_EXTENSION DeviceExtension;
+  UNICODE_STRING String;
   NTSTATUS Status;
 
   DPRINT("Called\n");
 
   DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
-  Status = STATUS_SUCCESS;
-
   switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType)
   {
     case DeviceTextDescription:
+      Status = PciDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+                                         &DeviceExtension->DeviceDescription,
+                                         &String);
+
       DPRINT("DeviceTextDescription\n");
-      Irp->IoStatus.Information = (ULONG_PTR)DeviceExtension->DeviceDescription.Buffer;
+      Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
       break;
 
     case DeviceTextLocationInformation:
+      Status = PciDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+                                         &DeviceExtension->DeviceLocation,
+                                         &String);
+
       DPRINT("DeviceTextLocationInformation\n");
-      Irp->IoStatus.Information = (ULONG_PTR)DeviceExtension->DeviceLocation.Buffer;
+      Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
       break;
 
     default:
       Irp->IoStatus.Information = 0;
       Status = STATUS_INVALID_PARAMETER;
+      break;
   }
 
   return Status;
@@ -129,14 +137,12 @@ PdoQueryBusInformation(
   PIO_STACK_LOCATION IrpSp)
 {
   PPDO_DEVICE_EXTENSION DeviceExtension;
-  PFDO_DEVICE_EXTENSION FdoDeviceExtension;
   PPNP_BUS_INFORMATION BusInformation;
 
   UNREFERENCED_PARAMETER(IrpSp);
   DPRINT("Called\n");
 
   DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-  FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->Fdo->DeviceExtension;
   BusInformation = ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
   Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
   if (BusInformation != NULL)
@@ -208,7 +214,9 @@ PdoGetRangeLength(PPDO_DEVICE_EXTENSION DeviceExtension,
     return FALSE;
   }
 
-  BaseValue = (OrigValue & 0x00000001) ? (OrigValue & ~0x3) : (OrigValue & ~0xF);
+  BaseValue = (OrigValue & PCI_ADDRESS_IO_SPACE)
+              ? (OrigValue & PCI_ADDRESS_IO_ADDRESS_MASK)
+              : (OrigValue & PCI_ADDRESS_MEMORY_ADDRESS_MASK);
 
   *Base = BaseValue;
 
@@ -261,33 +269,35 @@ PdoGetRangeLength(PPDO_DEVICE_EXTENSION DeviceExtension,
      return TRUE;
   }
 
-  XLength = ~((NewValue & 0x00000001) ? (NewValue & ~0x3) : (NewValue & ~0xF)) + 1;
+  XLength = ~((NewValue & PCI_ADDRESS_IO_SPACE)
+              ? (NewValue & PCI_ADDRESS_IO_ADDRESS_MASK)
+              : (NewValue & PCI_ADDRESS_MEMORY_ADDRESS_MASK)) + 1;
 
 #if 0
   DbgPrint("BaseAddress 0x%08lx  Length 0x%08lx",
            BaseValue, XLength);
 
-  if (NewValue & 0x00000001)
+  if (NewValue & PCI_ADDRESS_IO_SPACE)
   {
     DbgPrint("  IO range");
   }
   else
   {
     DbgPrint("  Memory range");
-    if ((NewValue & 0x00000006) == 0)
+    if ((NewValue & PCI_ADDRESS_MEMORY_TYPE_MASK) == 0)
     {
       DbgPrint(" in 32-Bit address space");
     }
-    else if ((NewValue & 0x00000006) == 2)
+    else if ((NewValue & PCI_ADDRESS_MEMORY_TYPE_MASK) == 2)
     {
       DbgPrint(" below 1BM ");
     }
-    else if ((NewValue & 0x00000006) == 4)
+    else if ((NewValue & PCI_ADDRESS_MEMORY_TYPE_MASK) == 4)
     {
       DbgPrint(" in 64-Bit address space");
     }
 
-    if (NewValue & 0x00000008)
+    if (NewValue & PCI_ADDRESS_MEMORY_PREFETCHABLE)
     {
       DbgPrint(" prefetchable");
     }
@@ -297,7 +307,9 @@ PdoGetRangeLength(PPDO_DEVICE_EXTENSION DeviceExtension,
 #endif
 
   *Length = XLength;
-  *Flags = (NewValue & 0x00000001) ? (NewValue & 0x3) : (NewValue & 0xF);
+  *Flags = (NewValue & PCI_ADDRESS_IO_SPACE)
+           ? (NewValue & ~PCI_ADDRESS_IO_ADDRESS_MASK)
+           : (NewValue & ~PCI_ADDRESS_MEMORY_ADDRESS_MASK);
 
   return TRUE;
 }
@@ -413,8 +425,8 @@ PdoQueryResourceRequirements(
   RtlZeroMemory(ResourceList, ListSize);
   ResourceList->ListSize = ListSize;
   ResourceList->InterfaceType = PCIBus;
-  ResourceList->BusNumber = 0;
-  ResourceList->SlotNumber = 0;
+  ResourceList->BusNumber = DeviceExtension->PciDevice->BusNumber;
+  ResourceList->SlotNumber = DeviceExtension->PciDevice->SlotNumber.u.AsULONG;
   ResourceList->AlternativeLists = 1;
 
   ResourceList->List[0].Version = 1;
@@ -669,6 +681,7 @@ PdoQueryResources(
     }
 
     if ((PciConfig.u.type0.InterruptPin != 0) &&
+        (PciConfig.u.type0.InterruptLine != 0) &&
         (PciConfig.u.type0.InterruptLine != 0xFF))
       ResCount++;
   }
@@ -717,7 +730,7 @@ PdoQueryResources(
   RtlZeroMemory(ResourceList, ListSize);
   ResourceList->Count = 1;
   ResourceList->List[0].InterfaceType = PCIBus;
-  ResourceList->List[0].BusNumber = 0;
+  ResourceList->List[0].BusNumber = DeviceExtension->PciDevice->BusNumber;
 
   PartialList = &ResourceList->List[0].PartialResourceList;
   PartialList->Version = 1;
@@ -753,6 +766,9 @@ PdoQueryResources(
         Descriptor->u.Port.Start.QuadPart =
           (ULONGLONG)Base;
         Descriptor->u.Port.Length = Length;
+
+        /* Enable IO space access */
+        DeviceExtension->PciDevice->EnableIoSpace = TRUE;
       }
       else
       {
@@ -762,6 +778,9 @@ PdoQueryResources(
         Descriptor->u.Memory.Start.QuadPart =
           (ULONGLONG)Base;
         Descriptor->u.Memory.Length = Length;
+
+        /* Enable memory space access */
+        DeviceExtension->PciDevice->EnableMemorySpace = TRUE;
       }
 
       Descriptor++;
@@ -769,15 +788,19 @@ PdoQueryResources(
 
     /* Add interrupt resource */
     if ((PciConfig.u.type0.InterruptPin != 0) &&
+        (PciConfig.u.type0.InterruptLine != 0) &&
         (PciConfig.u.type0.InterruptLine != 0xFF))
     {
       Descriptor->Type = CmResourceTypeInterrupt;
       Descriptor->ShareDisposition = CmResourceShareShared;
       Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
       Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine;
-      Descriptor->u.Interrupt.Vector = 0;
+      Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine;
       Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
     }
+
+    /* Allow bus master mode */
+    DeviceExtension->PciDevice->EnableBusMaster = TRUE;
   }
   else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
   {
@@ -807,6 +830,9 @@ PdoQueryResources(
         Descriptor->u.Port.Start.QuadPart =
           (ULONGLONG)Base;
         Descriptor->u.Port.Length = Length;
+
+        /* Enable IO space access */
+        DeviceExtension->PciDevice->EnableIoSpace = TRUE;
       }
       else
       {
@@ -816,6 +842,9 @@ PdoQueryResources(
         Descriptor->u.Memory.Start.QuadPart =
           (ULONGLONG)Base;
         Descriptor->u.Memory.Length = Length;
+
+        /* Enable memory space access */
+        DeviceExtension->PciDevice->EnableMemorySpace = TRUE;
       }
 
       Descriptor++;
@@ -1186,6 +1215,95 @@ PdoQueryInterface(
   return Status;
 }
 
+static NTSTATUS
+PdoStartDevice(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+    PCM_RESOURCE_LIST RawResList = IrpSp->Parameters.StartDevice.AllocatedResources;
+    PCM_FULL_RESOURCE_DESCRIPTOR RawFullDesc;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR RawPartialDesc;
+    ULONG i, ii;
+    PPDO_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+    UCHAR Irq;
+    USHORT Command;
+
+    if (!RawResList)
+        return STATUS_SUCCESS;
+
+    /* TODO: Assign the other resources we get to the card */
+
+    for (i = 0; i < RawResList->Count; i++)
+    {
+        RawFullDesc = &RawResList->List[i];
+
+        for (ii = 0; ii < RawFullDesc->PartialResourceList.Count; ii++)
+        {
+            RawPartialDesc = &RawFullDesc->PartialResourceList.PartialDescriptors[ii];
+
+            if (RawPartialDesc->Type == CmResourceTypeInterrupt)
+            {
+                DPRINT1("Assigning IRQ %d to PCI device 0x%x on bus 0x%x\n",
+                        RawPartialDesc->u.Interrupt.Vector,
+                        DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                        DeviceExtension->PciDevice->BusNumber);
+
+                Irq = (UCHAR)RawPartialDesc->u.Interrupt.Vector;
+                HalSetBusDataByOffset(PCIConfiguration,
+                                      DeviceExtension->PciDevice->BusNumber,
+                                      DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                                      &Irq,
+                                      0x3c /* PCI_INTERRUPT_LINE */,
+                                      sizeof(UCHAR));
+            }
+        }
+    }
+
+    Command = 0;
+
+    DPRINT1("Enabling command flags for PCI device 0x%x on bus 0x%x: ",
+            DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+            DeviceExtension->PciDevice->BusNumber);
+    if (DeviceExtension->PciDevice->EnableBusMaster)
+    {
+        Command |= PCI_ENABLE_BUS_MASTER;
+        DbgPrint("[Bus master] ");
+    }
+
+    if (DeviceExtension->PciDevice->EnableMemorySpace)
+    {
+        Command |= PCI_ENABLE_MEMORY_SPACE;
+        DbgPrint("[Memory space enable] ");
+    }
+
+    if (DeviceExtension->PciDevice->EnableIoSpace)
+    {
+        Command |= PCI_ENABLE_IO_SPACE;
+        DbgPrint("[I/O space enable] ");
+    }
+
+    if (Command != 0)
+    {
+        DbgPrint("\n");
+
+        /* OR with the previous value */
+        Command |= DeviceExtension->PciDevice->PciConfig.Command;
+
+        HalSetBusDataByOffset(PCIConfiguration,
+                              DeviceExtension->PciDevice->BusNumber,
+                              DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
+                              &Command,
+                              FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
+                              sizeof(USHORT));
+    }
+    else
+    {
+        DbgPrint("None\n");
+    }
+
+    return STATUS_SUCCESS;
+}
 
 static NTSTATUS
 PdoReadConfig(
@@ -1247,6 +1365,33 @@ PdoWriteConfig(
   return STATUS_SUCCESS;
 }
 
+static NTSTATUS
+PdoQueryDeviceRelations(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp,
+  PIO_STACK_LOCATION IrpSp)
+{
+  PDEVICE_RELATIONS DeviceRelations;
+
+  /* We only support TargetDeviceRelation for child PDOs */
+  if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
+      return Irp->IoStatus.Status;
+
+  /* We can do this because we only return 1 PDO for TargetDeviceRelation */
+  DeviceRelations = ExAllocatePool(PagedPool, sizeof(*DeviceRelations));
+  if (!DeviceRelations)
+      return STATUS_INSUFFICIENT_RESOURCES;
+
+  DeviceRelations->Count = 1;
+  DeviceRelations->Objects[0] = DeviceObject;
+
+  /* The PnP manager will remove this when it is done with the PDO */
+  ObReferenceObject(DeviceObject);
+
+  Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
+
+  return STATUS_SUCCESS;
+}
 
 static NTSTATUS
 PdoSetPower(
@@ -1254,14 +1399,11 @@ PdoSetPower(
   IN PIRP Irp,
   PIO_STACK_LOCATION IrpSp)
 {
-  PPDO_DEVICE_EXTENSION DeviceExtension;
   NTSTATUS Status;
 
   UNREFERENCED_PARAMETER(Irp);
   DPRINT("Called\n");
 
-  DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
   if (IrpSp->Parameters.Power.Type == DevicePowerState) {
     Status = STATUS_SUCCESS;
     switch (IrpSp->Parameters.Power.State.SystemState) {
@@ -1319,8 +1461,7 @@ PdoPnpControl(
     break;
 
   case IRP_MN_QUERY_DEVICE_RELATIONS:
-    /* FIXME: Possibly handle for RemovalRelations */
-    DPRINT("Unimplemented IRP_MN_QUERY_DEVICE_RELATIONS received\n");
+    Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
     break;
 
   case IRP_MN_QUERY_DEVICE_TEXT:
@@ -1352,16 +1493,42 @@ PdoPnpControl(
     break;
 
   case IRP_MN_START_DEVICE:
+    Status = PdoStartDevice(DeviceObject, Irp, IrpSp);
+    break;
+
   case IRP_MN_QUERY_STOP_DEVICE:
   case IRP_MN_CANCEL_STOP_DEVICE:
   case IRP_MN_STOP_DEVICE:
   case IRP_MN_QUERY_REMOVE_DEVICE:
   case IRP_MN_CANCEL_REMOVE_DEVICE:
-  case IRP_MN_REMOVE_DEVICE:
   case IRP_MN_SURPRISE_REMOVAL:
     Status = STATUS_SUCCESS;
     break;
 
+  case IRP_MN_REMOVE_DEVICE:
+  {
+    PPDO_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+    PFDO_DEVICE_EXTENSION FdoDeviceExtension = DeviceExtension->Fdo->DeviceExtension;
+    KIRQL OldIrql;
+
+    /* Remove it from the device list */
+    KeAcquireSpinLock(&FdoDeviceExtension->DeviceListLock, &OldIrql);
+    RemoveEntryList(&DeviceExtension->PciDevice->ListEntry);
+    FdoDeviceExtension->DeviceListCount--;
+    KeReleaseSpinLock(&FdoDeviceExtension->DeviceListLock, OldIrql);
+
+    /* Free the device */
+    ExFreePool(DeviceExtension->PciDevice);
+
+    /* Complete the IRP */
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    /* Delete the DO */
+    IoDeleteDevice(DeviceObject);
+    return STATUS_SUCCESS;
+  }
+
   case IRP_MN_QUERY_INTERFACE:
     DPRINT("IRP_MN_QUERY_INTERFACE received\n");
     Status = PdoQueryInterface(DeviceObject, Irp, IrpSp);