xref: /reactos/drivers/bus/acpi/buspdo.c (revision f69e2563)
1 #ifndef UNIT_TEST
2 #include "precomp.h"
3 
4 #include <initguid.h>
5 #include <poclass.h>
6 
7 #define NDEBUG
8 #include <debug.h>
9 
10 #ifdef ALLOC_PRAGMA
11 #pragma alloc_text (PAGE, Bus_PDO_PnP)
12 #pragma alloc_text (PAGE, Bus_PDO_QueryDeviceCaps)
13 #pragma alloc_text (PAGE, Bus_PDO_QueryDeviceId)
14 #pragma alloc_text (PAGE, Bus_PDO_QueryDeviceText)
15 #pragma alloc_text (PAGE, Bus_PDO_QueryResources)
16 #pragma alloc_text (PAGE, Bus_PDO_QueryResourceRequirements)
17 #pragma alloc_text (PAGE, Bus_PDO_QueryDeviceRelations)
18 #pragma alloc_text (PAGE, Bus_PDO_QueryBusInformation)
19 #pragma alloc_text (PAGE, Bus_GetDeviceCapabilities)
20 #endif
21 
22 NTSTATUS
Bus_PDO_PnP(PDEVICE_OBJECT DeviceObject,PIRP Irp,PIO_STACK_LOCATION IrpStack,PPDO_DEVICE_DATA DeviceData)23 Bus_PDO_PnP (
24      PDEVICE_OBJECT       DeviceObject,
25      PIRP                 Irp,
26      PIO_STACK_LOCATION   IrpStack,
27      PPDO_DEVICE_DATA     DeviceData
28     )
29 {
30     NTSTATUS                status;
31     POWER_STATE             state;
32     struct acpi_device      *device = NULL;
33 
34     PAGED_CODE ();
35 
36     if (DeviceData->AcpiHandle)
37         acpi_bus_get_device(DeviceData->AcpiHandle, &device);
38 
39     //
40     // NB: Because we are a bus enumerator, we have no one to whom we could
41     // defer these irps.  Therefore we do not pass them down but merely
42     // return them.
43     //
44 
45     switch (IrpStack->MinorFunction) {
46 
47     case IRP_MN_START_DEVICE:
48         //
49         // Here we do what ever initialization and ``turning on'' that is
50         // required to allow others to access this device.
51         // Power up the device.
52         //
53         if (DeviceData->AcpiHandle && acpi_bus_power_manageable(DeviceData->AcpiHandle) &&
54             !ACPI_SUCCESS(acpi_bus_set_power(DeviceData->AcpiHandle, ACPI_STATE_D0)))
55         {
56             DPRINT1("Device %x failed to start!\n", DeviceData->AcpiHandle);
57             status = STATUS_UNSUCCESSFUL;
58             break;
59         }
60 
61         DeviceData->InterfaceName.Length = 0;
62         status = STATUS_SUCCESS;
63 
64         if (!device)
65         {
66             status = IoRegisterDeviceInterface(DeviceData->Common.Self,
67                                                &GUID_DEVICE_SYS_BUTTON,
68                                                NULL,
69                                                &DeviceData->InterfaceName);
70         }
71         else if (device->flags.hardware_id &&
72                  strstr(device->pnp.hardware_id, ACPI_THERMAL_HID))
73         {
74             status = IoRegisterDeviceInterface(DeviceData->Common.Self,
75                                                &GUID_DEVICE_THERMAL_ZONE,
76                                                NULL,
77                                                &DeviceData->InterfaceName);
78         }
79         else if (device->flags.hardware_id &&
80                  strstr(device->pnp.hardware_id, ACPI_FAN_HID))
81         {
82             status = IoRegisterDeviceInterface(DeviceData->Common.Self,
83                                                &GUID_DEVICE_FAN,
84                                                NULL,
85                                                &DeviceData->InterfaceName);
86         }
87         else if (device->flags.hardware_id &&
88                  strstr(device->pnp.hardware_id, ACPI_BUTTON_HID_LID))
89         {
90             status = IoRegisterDeviceInterface(DeviceData->Common.Self,
91                                                &GUID_DEVICE_LID,
92                                                NULL,
93                                                &DeviceData->InterfaceName);
94         }
95         else if (device->flags.hardware_id &&
96                  strstr(device->pnp.hardware_id, ACPI_PROCESSOR_HID))
97         {
98             status = IoRegisterDeviceInterface(DeviceData->Common.Self,
99                                                &GUID_DEVICE_PROCESSOR,
100                                                NULL,
101                                                &DeviceData->InterfaceName);
102         }
103 
104         /* Failure to register an interface is not a fatal failure so don't return a failure status */
105         if (NT_SUCCESS(status) && DeviceData->InterfaceName.Length != 0)
106             IoSetDeviceInterfaceState(&DeviceData->InterfaceName, TRUE);
107 
108         state.DeviceState = PowerDeviceD0;
109         PoSetPowerState(DeviceData->Common.Self, DevicePowerState, state);
110         DeviceData->Common.DevicePowerState = PowerDeviceD0;
111         SET_NEW_PNP_STATE(DeviceData->Common, Started);
112         status = STATUS_SUCCESS;
113         break;
114 
115     case IRP_MN_STOP_DEVICE:
116 
117         if (DeviceData->InterfaceName.Length != 0)
118             IoSetDeviceInterfaceState(&DeviceData->InterfaceName, FALSE);
119 
120         //
121         // Here we shut down the device and give up and unmap any resources
122         // we acquired for the device.
123         //
124         if (DeviceData->AcpiHandle && acpi_bus_power_manageable(DeviceData->AcpiHandle) &&
125             !ACPI_SUCCESS(acpi_bus_set_power(DeviceData->AcpiHandle, ACPI_STATE_D3)))
126         {
127             DPRINT1("Device %x failed to stop!\n", DeviceData->AcpiHandle);
128             status = STATUS_UNSUCCESSFUL;
129             break;
130         }
131 
132         state.DeviceState = PowerDeviceD3;
133         PoSetPowerState(DeviceData->Common.Self, DevicePowerState, state);
134         DeviceData->Common.DevicePowerState = PowerDeviceD3;
135         SET_NEW_PNP_STATE(DeviceData->Common, Stopped);
136         status = STATUS_SUCCESS;
137         break;
138 
139 
140     case IRP_MN_QUERY_STOP_DEVICE:
141 
142         //
143         // No reason here why we can't stop the device.
144         // If there were a reason we should speak now, because answering success
145         // here may result in a stop device irp.
146         //
147 
148         SET_NEW_PNP_STATE(DeviceData->Common, StopPending);
149         status = STATUS_SUCCESS;
150         break;
151 
152     case IRP_MN_CANCEL_STOP_DEVICE:
153 
154         //
155         // The stop was canceled.  Whatever state we set, or resources we put
156         // on hold in anticipation of the forthcoming STOP device IRP should be
157         // put back to normal.  Someone, in the long list of concerned parties,
158         // has failed the stop device query.
159         //
160 
161         //
162         // First check to see whether you have received cancel-stop
163         // without first receiving a query-stop. This could happen if someone
164         // above us fails a query-stop and passes down the subsequent
165         // cancel-stop.
166         //
167 
168         if (StopPending == DeviceData->Common.DevicePnPState)
169         {
170             //
171             // We did receive a query-stop, so restore.
172             //
173             RESTORE_PREVIOUS_PNP_STATE(DeviceData->Common);
174         }
175         status = STATUS_SUCCESS;// We must not fail this IRP.
176         break;
177 
178     case IRP_MN_REMOVE_DEVICE:
179         //
180         // We handle REMOVE_DEVICE just like STOP_DEVICE. This is because
181         // the device is still physically present (or at least we don't know any better)
182         // so we have to retain the PDO after stopping and removing power from it.
183         //
184         if (DeviceData->InterfaceName.Length != 0)
185             IoSetDeviceInterfaceState(&DeviceData->InterfaceName, FALSE);
186 
187         if (DeviceData->AcpiHandle && acpi_bus_power_manageable(DeviceData->AcpiHandle) &&
188             !ACPI_SUCCESS(acpi_bus_set_power(DeviceData->AcpiHandle, ACPI_STATE_D3)))
189         {
190             DPRINT1("Device %x failed to enter D3!\n", DeviceData->AcpiHandle);
191             state.DeviceState = PowerDeviceD3;
192             PoSetPowerState(DeviceData->Common.Self, DevicePowerState, state);
193             DeviceData->Common.DevicePowerState = PowerDeviceD3;
194         }
195 
196         SET_NEW_PNP_STATE(DeviceData->Common, Stopped);
197         status = STATUS_SUCCESS;
198         break;
199 
200     case IRP_MN_QUERY_REMOVE_DEVICE:
201         SET_NEW_PNP_STATE(DeviceData->Common, RemovalPending);
202         status = STATUS_SUCCESS;
203         break;
204 
205     case IRP_MN_CANCEL_REMOVE_DEVICE:
206         if (RemovalPending == DeviceData->Common.DevicePnPState)
207         {
208             RESTORE_PREVIOUS_PNP_STATE(DeviceData->Common);
209         }
210         status = STATUS_SUCCESS;
211         break;
212 
213     case IRP_MN_QUERY_CAPABILITIES:
214 
215         //
216         // Return the capabilities of a device, such as whether the device
217         // can be locked or ejected..etc
218         //
219 
220         status = Bus_PDO_QueryDeviceCaps(DeviceData, Irp);
221 
222         break;
223 
224     case IRP_MN_QUERY_ID:
225 
226         // Query the IDs of the device
227         status = Bus_PDO_QueryDeviceId(DeviceData, Irp);
228 
229         break;
230 
231     case IRP_MN_QUERY_DEVICE_RELATIONS:
232 
233         DPRINT("\tQueryDeviceRelation Type: %s\n",DbgDeviceRelationString(\
234                     IrpStack->Parameters.QueryDeviceRelations.Type));
235 
236         status = Bus_PDO_QueryDeviceRelations(DeviceData, Irp);
237 
238         break;
239 
240     case IRP_MN_QUERY_DEVICE_TEXT:
241 
242         status = Bus_PDO_QueryDeviceText(DeviceData, Irp);
243 
244         break;
245 
246     case IRP_MN_QUERY_RESOURCES:
247 
248         status = Bus_PDO_QueryResources(DeviceData, Irp);
249 
250         break;
251 
252     case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
253 
254         status = Bus_PDO_QueryResourceRequirements(DeviceData, Irp);
255 
256         break;
257 
258     case IRP_MN_QUERY_BUS_INFORMATION:
259 
260         status = Bus_PDO_QueryBusInformation(DeviceData, Irp);
261 
262         break;
263 
264     case IRP_MN_QUERY_INTERFACE:
265 
266         status = Bus_PDO_QueryInterface(DeviceData, Irp);
267 
268         break;
269 
270 
271     case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
272 
273         //
274         // OPTIONAL for bus drivers.
275         // The PnP Manager sends this IRP to a device
276         // stack so filter and function drivers can adjust the
277         // resources required by the device, if appropriate.
278         //
279 
280         //break;
281 
282     //case IRP_MN_QUERY_PNP_DEVICE_STATE:
283 
284         //
285         // OPTIONAL for bus drivers.
286         // The PnP Manager sends this IRP after the drivers for
287         // a device return success from the IRP_MN_START_DEVICE
288         // request. The PnP Manager also sends this IRP when a
289         // driver for the device calls IoInvalidateDeviceState.
290         //
291 
292         // break;
293 
294     //case IRP_MN_READ_CONFIG:
295     //case IRP_MN_WRITE_CONFIG:
296 
297         //
298         // Bus drivers for buses with configuration space must handle
299         // this request for their child devices. Our devices don't
300         // have a config space.
301         //
302 
303         // break;
304 
305     //case IRP_MN_SET_LOCK:
306 
307         // break;
308 
309     default:
310 
311         //
312         // For PnP requests to the PDO that we do not understand we should
313         // return the IRP WITHOUT setting the status or information fields.
314         // These fields may have already been set by a filter (eg acpi).
315         status = Irp->IoStatus.Status;
316 
317         break;
318     }
319 
320     Irp->IoStatus.Status = status;
321     IoCompleteRequest (Irp, IO_NO_INCREMENT);
322 
323     return status;
324 }
325 
326 NTSTATUS
Bus_PDO_QueryDeviceCaps(PPDO_DEVICE_DATA DeviceData,PIRP Irp)327 Bus_PDO_QueryDeviceCaps(
328      PPDO_DEVICE_DATA     DeviceData,
329       PIRP   Irp )
330 {
331 
332     PIO_STACK_LOCATION      stack;
333     PDEVICE_CAPABILITIES    deviceCapabilities;
334     struct acpi_device *device = NULL;
335     ULONG i;
336 
337     PAGED_CODE ();
338 
339     if (DeviceData->AcpiHandle)
340         acpi_bus_get_device(DeviceData->AcpiHandle, &device);
341 
342     stack = IoGetCurrentIrpStackLocation (Irp);
343 
344     //
345     // Get the packet.
346     //
347     deviceCapabilities=stack->Parameters.DeviceCapabilities.Capabilities;
348 
349     //
350     // Set the capabilities.
351     //
352 
353     if (deviceCapabilities->Version != 1 ||
354             deviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES))
355     {
356        return STATUS_UNSUCCESSFUL;
357     }
358 
359     deviceCapabilities->D1Latency = 0;
360     deviceCapabilities->D2Latency = 0;
361     deviceCapabilities->D3Latency = 0;
362 
363     deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
364     deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
365     deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
366     deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
367 
368     for (i = 0; i < ACPI_D_STATE_COUNT && device; i++)
369     {
370         if (!device->power.states[i].flags.valid)
371             continue;
372 
373         switch (i)
374         {
375            case ACPI_STATE_D0:
376               deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
377               break;
378 
379            case ACPI_STATE_D1:
380               deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
381               deviceCapabilities->D1Latency = device->power.states[i].latency;
382               break;
383 
384            case ACPI_STATE_D2:
385               deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
386               deviceCapabilities->D2Latency = device->power.states[i].latency;
387               break;
388 
389            case ACPI_STATE_D3:
390               deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
391               deviceCapabilities->D3Latency = device->power.states[i].latency;
392               break;
393         }
394     }
395 
396     // We can wake the system from D1
397     deviceCapabilities->DeviceWake = PowerDeviceD1;
398 
399 
400     deviceCapabilities->DeviceD1 =
401         (deviceCapabilities->DeviceState[PowerSystemSleeping1] == PowerDeviceD1) ? TRUE : FALSE;
402     deviceCapabilities->DeviceD2 =
403         (deviceCapabilities->DeviceState[PowerSystemSleeping2] == PowerDeviceD2) ? TRUE : FALSE;
404 
405     deviceCapabilities->WakeFromD0 = FALSE;
406     deviceCapabilities->WakeFromD1 = TRUE; //Yes we can
407     deviceCapabilities->WakeFromD2 = FALSE;
408     deviceCapabilities->WakeFromD3 = FALSE;
409 
410     if (device)
411     {
412        deviceCapabilities->LockSupported = device->flags.lockable;
413        deviceCapabilities->EjectSupported = device->flags.ejectable;
414        deviceCapabilities->HardwareDisabled = !device->status.enabled && !device->status.functional;
415        deviceCapabilities->Removable = device->flags.removable;
416        deviceCapabilities->SurpriseRemovalOK = device->flags.surprise_removal_ok;
417        deviceCapabilities->UniqueID = device->flags.unique_id;
418        deviceCapabilities->NoDisplayInUI = !device->status.show_in_ui;
419        deviceCapabilities->Address = device->pnp.bus_address;
420     }
421 
422     if (!device ||
423         (device->flags.hardware_id &&
424          (strstr(device->pnp.hardware_id, ACPI_BUTTON_HID_LID) ||
425           strstr(device->pnp.hardware_id, ACPI_THERMAL_HID) ||
426           strstr(device->pnp.hardware_id, ACPI_PROCESSOR_HID))))
427     {
428         /* Allow ACPI to control the device if it is a lid button,
429          * a thermal zone, a processor, or a fixed feature button */
430         deviceCapabilities->RawDeviceOK = TRUE;
431     }
432 
433     deviceCapabilities->SilentInstall = FALSE;
434     deviceCapabilities->UINumber = (ULONG)-1;
435 
436     return STATUS_SUCCESS;
437 
438 }
439 
440 NTSTATUS
Bus_PDO_QueryDeviceId(PPDO_DEVICE_DATA DeviceData,PIRP Irp)441 Bus_PDO_QueryDeviceId(
442      PPDO_DEVICE_DATA     DeviceData,
443       PIRP   Irp )
444 {
445     PIO_STACK_LOCATION      stack;
446     PWCHAR                  buffer, src;
447     WCHAR                   temp[256];
448     ULONG                   length, i;
449     NTSTATUS                status = STATUS_SUCCESS;
450     struct acpi_device *Device;
451 
452     PAGED_CODE ();
453 
454     stack = IoGetCurrentIrpStackLocation (Irp);
455 
456     switch (stack->Parameters.QueryId.IdType) {
457 
458     case BusQueryDeviceID:
459 
460         /* This is a REG_SZ value */
461 
462         if (DeviceData->AcpiHandle)
463         {
464             acpi_bus_get_device(DeviceData->AcpiHandle, &Device);
465 
466             if (strcmp(Device->pnp.hardware_id, "Processor") == 0)
467             {
468                 length = wcslen(ProcessorIdString);
469                 wcscpy(temp, ProcessorIdString);
470             }
471             else
472             {
473                 length = swprintf(temp,
474                                   L"ACPI\\%hs",
475                                   Device->pnp.hardware_id);
476             }
477         }
478         else
479         {
480             /* We know it's a fixed feature button because
481              * these are direct children of the ACPI root device
482              * and therefore have no handle
483              */
484             length = swprintf(temp,
485                               L"ACPI\\FixedButton");
486         }
487 
488         temp[length++] = UNICODE_NULL;
489 
490         NT_ASSERT(length * sizeof(WCHAR) <= sizeof(temp));
491 
492         buffer = ExAllocatePoolWithTag(PagedPool, length * sizeof(WCHAR), 'IpcA');
493 
494         if (!buffer) {
495            status = STATUS_INSUFFICIENT_RESOURCES;
496            break;
497         }
498 
499         RtlCopyMemory (buffer, temp, length * sizeof(WCHAR));
500         Irp->IoStatus.Information = (ULONG_PTR) buffer;
501         DPRINT("BusQueryDeviceID: %ls\n",buffer);
502         break;
503 
504     case BusQueryInstanceID:
505 
506         /* This is a REG_SZ value */
507 
508         /* See comment in BusQueryDeviceID case */
509         if(DeviceData->AcpiHandle)
510         {
511            acpi_bus_get_device(DeviceData->AcpiHandle, &Device);
512 
513            if (Device->flags.unique_id)
514               length = swprintf(temp,
515                                 L"%hs",
516                                 Device->pnp.unique_id);
517            else
518               /* FIXME: Generate unique id! */
519               length = swprintf(temp, L"%ls", L"0");
520         }
521         else
522         {
523            /* FIXME: Generate unique id! */
524            length = swprintf(temp, L"%ls", L"0");
525         }
526 
527         temp[length++] = UNICODE_NULL;
528 
529         NT_ASSERT(length * sizeof(WCHAR) <= sizeof(temp));
530 
531         buffer = ExAllocatePoolWithTag(PagedPool, length * sizeof(WCHAR), 'IpcA');
532         if (!buffer) {
533            status = STATUS_INSUFFICIENT_RESOURCES;
534            break;
535         }
536 
537         RtlCopyMemory (buffer, temp, length * sizeof (WCHAR));
538         DPRINT("BusQueryInstanceID: %ls\n",buffer);
539         Irp->IoStatus.Information = (ULONG_PTR) buffer;
540         break;
541 
542     case BusQueryHardwareIDs:
543 
544         /* This is a REG_MULTI_SZ value */
545         length = 0;
546         status = STATUS_NOT_SUPPORTED;
547 
548         /* See comment in BusQueryDeviceID case */
549         if (DeviceData->AcpiHandle)
550         {
551             acpi_bus_get_device(DeviceData->AcpiHandle, &Device);
552 
553             if (!Device->flags.hardware_id)
554             {
555                 /* We don't have the ID to satisfy this request */
556                 break;
557             }
558 
559             DPRINT("Device name: %s\n", Device->pnp.device_name);
560             DPRINT("Hardware ID: %s\n", Device->pnp.hardware_id);
561 
562             if (strcmp(Device->pnp.hardware_id, "Processor") == 0)
563             {
564                 length = ProcessorHardwareIds.Length / sizeof(WCHAR);
565                 src = ProcessorHardwareIds.Buffer;
566             }
567             else
568             {
569                 length += swprintf(&temp[length],
570                                    L"ACPI\\%hs",
571                                    Device->pnp.hardware_id);
572                 temp[length++] = UNICODE_NULL;
573 
574                 length += swprintf(&temp[length],
575                                    L"*%hs",
576                                    Device->pnp.hardware_id);
577                 temp[length++] = UNICODE_NULL;
578                 temp[length++] = UNICODE_NULL;
579                 src = temp;
580             }
581         }
582         else
583         {
584             length += swprintf(&temp[length],
585                                L"ACPI\\FixedButton");
586             temp[length++] = UNICODE_NULL;
587 
588             length += swprintf(&temp[length],
589                                L"*FixedButton");
590             temp[length++] = UNICODE_NULL;
591             temp[length++] = UNICODE_NULL;
592             src = temp;
593         }
594 
595         NT_ASSERT(length * sizeof(WCHAR) <= sizeof(temp));
596 
597         buffer = ExAllocatePoolWithTag(PagedPool, length * sizeof(WCHAR), 'IpcA');
598 
599         if (!buffer) {
600            status = STATUS_INSUFFICIENT_RESOURCES;
601            break;
602         }
603 
604         RtlCopyMemory (buffer, src, length * sizeof(WCHAR));
605         Irp->IoStatus.Information = (ULONG_PTR) buffer;
606         DPRINT("BusQueryHardwareIDs: %ls\n",buffer);
607         status = STATUS_SUCCESS;
608         break;
609 
610     case BusQueryCompatibleIDs:
611 
612         /* This is a REG_MULTI_SZ value */
613         length = 0;
614         status = STATUS_NOT_SUPPORTED;
615 
616         /* See comment in BusQueryDeviceID case */
617         if (DeviceData->AcpiHandle)
618         {
619             acpi_bus_get_device(DeviceData->AcpiHandle, &Device);
620 
621             if (!Device->flags.hardware_id)
622             {
623                 /* We don't have the ID to satisfy this request */
624                 break;
625             }
626 
627             DPRINT("Device name: %s\n", Device->pnp.device_name);
628             DPRINT("Hardware ID: %s\n", Device->pnp.hardware_id);
629 
630             if (strcmp(Device->pnp.hardware_id, "Processor") == 0)
631             {
632                 length += swprintf(&temp[length],
633                                    L"ACPI\\%hs",
634                                    Device->pnp.hardware_id);
635                 temp[length++] = UNICODE_NULL;
636 
637                 length += swprintf(&temp[length],
638                                    L"*%hs",
639                                    Device->pnp.hardware_id);
640                 temp[length++] = UNICODE_NULL;
641                 temp[length++] = UNICODE_NULL;
642             }
643             else if (Device->flags.compatible_ids)
644             {
645                 for (i = 0; i < Device->pnp.cid_list->Count; i++)
646                 {
647                     length += swprintf(&temp[length],
648                                    L"ACPI\\%hs",
649                                    Device->pnp.cid_list->Ids[i].String);
650                     temp[length++] = UNICODE_NULL;
651 
652                     length += swprintf(&temp[length],
653                                    L"*%hs",
654                                    Device->pnp.cid_list->Ids[i].String);
655                     temp[length++] = UNICODE_NULL;
656                 }
657 
658                 temp[length++] = UNICODE_NULL;
659             }
660             else
661             {
662                 /* No compatible IDs */
663                 break;
664             }
665 
666             NT_ASSERT(length * sizeof(WCHAR) <= sizeof(temp));
667 
668             buffer = ExAllocatePoolWithTag(PagedPool, length * sizeof(WCHAR), 'IpcA');
669             if (!buffer)
670             {
671                 status = STATUS_INSUFFICIENT_RESOURCES;
672                 break;
673             }
674 
675             RtlCopyMemory (buffer, temp, length * sizeof(WCHAR));
676             Irp->IoStatus.Information = (ULONG_PTR) buffer;
677             DPRINT("BusQueryCompatibleIDs: %ls\n",buffer);
678             status = STATUS_SUCCESS;
679         }
680         break;
681 
682     default:
683         status = Irp->IoStatus.Status;
684     }
685     return status;
686 }
687 
688 NTSTATUS
Bus_PDO_QueryDeviceText(PPDO_DEVICE_DATA DeviceData,PIRP Irp)689 Bus_PDO_QueryDeviceText(
690      PPDO_DEVICE_DATA     DeviceData,
691       PIRP   Irp )
692 {
693     PWCHAR  Buffer, Temp;
694     PIO_STACK_LOCATION   stack;
695     NTSTATUS    status = Irp->IoStatus.Status;
696     PAGED_CODE ();
697 
698     stack = IoGetCurrentIrpStackLocation (Irp);
699 
700     switch (stack->Parameters.QueryDeviceText.DeviceTextType) {
701 
702     case DeviceTextDescription:
703 
704         if (!Irp->IoStatus.Information) {
705             if (wcsstr (DeviceData->HardwareIDs, L"PNP000") != 0)
706                 Temp = L"Programmable interrupt controller";
707             else if (wcsstr(DeviceData->HardwareIDs, L"PNP010") != 0)
708                 Temp = L"System timer";
709             else if (wcsstr(DeviceData->HardwareIDs, L"PNP020") != 0)
710                 Temp = L"DMA controller";
711             else if (wcsstr(DeviceData->HardwareIDs, L"PNP03") != 0)
712                 Temp = L"Keyboard";
713             else if (wcsstr(DeviceData->HardwareIDs, L"PNP040") != 0)
714                 Temp = L"Parallel port";
715             else if (wcsstr(DeviceData->HardwareIDs, L"PNP05") != 0)
716                 Temp = L"Serial port";
717             else if (wcsstr(DeviceData->HardwareIDs, L"PNP06") != 0)
718                 Temp = L"Disk controller";
719             else if (wcsstr(DeviceData->HardwareIDs, L"PNP07") != 0)
720                 Temp = L"Disk controller";
721             else if (wcsstr(DeviceData->HardwareIDs, L"PNP09") != 0)
722                 Temp = L"Display adapter";
723             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0A0") != 0)
724                 Temp = L"Bus controller";
725             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0E0") != 0)
726                 Temp = L"PCMCIA controller";
727             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0F") != 0)
728                 Temp = L"Mouse device";
729             else if (wcsstr(DeviceData->HardwareIDs, L"PNP8") != 0)
730                 Temp = L"Network adapter";
731             else if (wcsstr(DeviceData->HardwareIDs, L"PNPA0") != 0)
732                 Temp = L"SCSI controller";
733             else if (wcsstr(DeviceData->HardwareIDs, L"PNPB0") != 0)
734                 Temp = L"Multimedia device";
735             else if (wcsstr(DeviceData->HardwareIDs, L"PNPC00") != 0)
736                 Temp = L"Modem";
737             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0C") != 0)
738                 Temp = L"Power Button";
739             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0E") != 0)
740                 Temp = L"Sleep Button";
741             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0D") != 0)
742                 Temp = L"Lid Switch";
743             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C09") != 0)
744                 Temp = L"ACPI Embedded Controller";
745             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0B") != 0)
746                 Temp = L"ACPI Fan";
747             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0A03") != 0 ||
748                      wcsstr(DeviceData->HardwareIDs, L"PNP0A08") != 0)
749                 Temp = L"PCI Root Bridge";
750             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0A") != 0)
751                 Temp = L"ACPI Battery";
752             else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0F") != 0)
753                 Temp = L"PCI Interrupt Link";
754             else if (wcsstr(DeviceData->HardwareIDs, L"ACPI_PWR") != 0)
755                 Temp = L"ACPI Power Resource";
756             else if (wcsstr(DeviceData->HardwareIDs, L"Processor") != 0)
757             {
758                 if (ProcessorNameString != NULL)
759                     Temp = ProcessorNameString;
760                 else
761                     Temp = L"Processor";
762             }
763             else if (wcsstr(DeviceData->HardwareIDs, L"ThermalZone") != 0)
764                 Temp = L"ACPI Thermal Zone";
765             else if (wcsstr(DeviceData->HardwareIDs, L"ACPI0002") != 0)
766                 Temp = L"Smart Battery";
767             else if (wcsstr(DeviceData->HardwareIDs, L"ACPI0003") != 0)
768                 Temp = L"AC Adapter";
769             /* Simply checking if AcpiHandle is NULL eliminates the need to check
770              * for the 4 different names that ACPI knows the fixed feature button as internally
771              */
772             else if (!DeviceData->AcpiHandle)
773                 Temp = L"ACPI Fixed Feature Button";
774             else
775                 Temp = L"Other ACPI device";
776 
777             Buffer = ExAllocatePoolWithTag(PagedPool, (wcslen(Temp) + 1) * sizeof(WCHAR), 'IpcA');
778 
779             if (!Buffer) {
780                 status = STATUS_INSUFFICIENT_RESOURCES;
781                 break;
782             }
783 
784             RtlCopyMemory (Buffer, Temp, (wcslen(Temp) + 1) * sizeof(WCHAR));
785 
786             DPRINT("\tDeviceTextDescription :%ws\n", Buffer);
787 
788             Irp->IoStatus.Information = (ULONG_PTR) Buffer;
789             status = STATUS_SUCCESS;
790         }
791         break;
792 
793     default:
794         break;
795     }
796 
797     return status;
798 
799 }
800 
801 NTSTATUS
Bus_PDO_QueryResources(PPDO_DEVICE_DATA DeviceData,PIRP Irp)802 Bus_PDO_QueryResources(
803      PPDO_DEVICE_DATA     DeviceData,
804       PIRP   Irp )
805 {
806     ULONG NumberOfResources = 0;
807     PCM_RESOURCE_LIST ResourceList;
808     PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
809     ACPI_STATUS AcpiStatus;
810     ACPI_BUFFER Buffer;
811     ACPI_RESOURCE* resource;
812     ULONG ResourceListSize;
813     ULONG i;
814     ULONGLONG BusNumber;
815     struct acpi_device *device;
816 
817     if (!DeviceData->AcpiHandle)
818     {
819         return Irp->IoStatus.Status;
820     }
821 
822     /* A bus number resource is not included in the list of current resources
823      * for the root PCI bus so we manually query one here and if we find it
824      * we create a resource list and add a bus number descriptor to it */
825     if (wcsstr(DeviceData->HardwareIDs, L"PNP0A03") != 0 ||
826         wcsstr(DeviceData->HardwareIDs, L"PNP0A08") != 0)
827     {
828         acpi_bus_get_device(DeviceData->AcpiHandle, &device);
829 
830         AcpiStatus = acpi_evaluate_integer(DeviceData->AcpiHandle, "_BBN", NULL, &BusNumber);
831         if (AcpiStatus != AE_OK)
832         {
833 #if 0
834             if (device->flags.unique_id)
835             {
836                 /* FIXME: Try the unique ID */
837             }
838             else
839 #endif
840             {
841                 BusNumber = 0;
842                 DPRINT1("Failed to find a bus number\n");
843             }
844         }
845         else
846         {
847             DPRINT("Using _BBN for bus number\n");
848         }
849 
850         DPRINT("Found PCI root hub: %d\n", BusNumber);
851 
852         ResourceListSize = sizeof(CM_RESOURCE_LIST);
853         ResourceList = ExAllocatePoolWithTag(PagedPool, ResourceListSize, 'RpcA');
854         if (!ResourceList)
855             return STATUS_INSUFFICIENT_RESOURCES;
856 
857         ResourceList->Count = 1;
858         ResourceList->List[0].InterfaceType = Internal;
859         ResourceList->List[0].BusNumber = 0;
860         ResourceList->List[0].PartialResourceList.Version = 1;
861         ResourceList->List[0].PartialResourceList.Revision = 1;
862         ResourceList->List[0].PartialResourceList.Count = 1;
863         ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
864 
865         ResourceDescriptor->Type = CmResourceTypeBusNumber;
866         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
867         ResourceDescriptor->u.BusNumber.Start = BusNumber;
868         ResourceDescriptor->u.BusNumber.Length = 1;
869 
870         Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
871         return STATUS_SUCCESS;
872     }
873 
874     /* Get current resources */
875     Buffer.Length = 0;
876     AcpiStatus = AcpiGetCurrentResources(DeviceData->AcpiHandle, &Buffer);
877     if ((!ACPI_SUCCESS(AcpiStatus) && AcpiStatus != AE_BUFFER_OVERFLOW) ||
878         Buffer.Length == 0)
879     {
880       return Irp->IoStatus.Status;
881     }
882 
883     Buffer.Pointer = ExAllocatePoolWithTag(PagedPool, Buffer.Length, 'BpcA');
884     if (!Buffer.Pointer)
885       return STATUS_INSUFFICIENT_RESOURCES;
886 
887     AcpiStatus = AcpiGetCurrentResources(DeviceData->AcpiHandle, &Buffer);
888     if (!ACPI_SUCCESS(AcpiStatus))
889     {
890       DPRINT1("AcpiGetCurrentResources #2 failed (0x%x)\n", AcpiStatus);
891       ASSERT(FALSE);
892       return STATUS_UNSUCCESSFUL;
893     }
894 
895     resource= Buffer.Pointer;
896     /* Count number of resources */
897     while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG)
898     {
899         switch (resource->Type)
900         {
901             case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
902             {
903                 ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data;
904                 if (irq_data->ProducerConsumer == ACPI_PRODUCER)
905                     break;
906                 NumberOfResources += irq_data->InterruptCount;
907                 break;
908             }
909             case ACPI_RESOURCE_TYPE_IRQ:
910             {
911                 ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data;
912                 NumberOfResources += irq_data->InterruptCount;
913                 break;
914             }
915             case ACPI_RESOURCE_TYPE_DMA:
916             {
917                 ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &resource->Data;
918                 NumberOfResources += dma_data->ChannelCount;
919                 break;
920             }
921             case ACPI_RESOURCE_TYPE_ADDRESS16:
922             case ACPI_RESOURCE_TYPE_ADDRESS32:
923             case ACPI_RESOURCE_TYPE_ADDRESS64:
924             case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
925             {
926                 ACPI_RESOURCE_ADDRESS *addr_res = (ACPI_RESOURCE_ADDRESS*) &resource->Data;
927                 if (addr_res->ProducerConsumer == ACPI_PRODUCER)
928                     break;
929                 NumberOfResources++;
930                 break;
931             }
932             case ACPI_RESOURCE_TYPE_MEMORY24:
933             case ACPI_RESOURCE_TYPE_MEMORY32:
934             case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
935             case ACPI_RESOURCE_TYPE_FIXED_IO:
936             case ACPI_RESOURCE_TYPE_IO:
937             {
938                 NumberOfResources++;
939                 break;
940             }
941             default:
942             {
943                 DPRINT1("Unknown resource type: %d\n", resource->Type);
944                 break;
945             }
946         }
947         resource = ACPI_NEXT_RESOURCE(resource);
948     }
949 
950     /* Allocate memory */
951     ResourceListSize = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (NumberOfResources - 1);
952     ResourceList = ExAllocatePoolWithTag(PagedPool, ResourceListSize, 'RpcA');
953 
954     if (!ResourceList)
955     {
956         ExFreePoolWithTag(Buffer.Pointer, 'BpcA');
957         return STATUS_INSUFFICIENT_RESOURCES;
958     }
959     ResourceList->Count = 1;
960     ResourceList->List[0].InterfaceType = Internal; /* FIXME */
961     ResourceList->List[0].BusNumber = 0; /* We're the only ACPI bus device in the system */
962     ResourceList->List[0].PartialResourceList.Version = 1;
963     ResourceList->List[0].PartialResourceList.Revision = 1;
964     ResourceList->List[0].PartialResourceList.Count = NumberOfResources;
965     ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
966 
967     /* Fill resources list structure */
968         resource = Buffer.Pointer;
969     while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG)
970     {
971         switch (resource->Type)
972         {
973             case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
974             {
975                 ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data;
976                 if (irq_data->ProducerConsumer == ACPI_PRODUCER)
977                     break;
978                 for (i = 0; i < irq_data->InterruptCount; i++)
979                 {
980                     ResourceDescriptor->Type = CmResourceTypeInterrupt;
981 
982                     ResourceDescriptor->ShareDisposition =
983                     (irq_data->Shareable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive);
984                     ResourceDescriptor->Flags =
985                     (irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED);
986                     ResourceDescriptor->u.Interrupt.Level =
987                     ResourceDescriptor->u.Interrupt.Vector = irq_data->Interrupts[i];
988                     ResourceDescriptor->u.Interrupt.Affinity = (KAFFINITY)(-1);
989 
990                     ResourceDescriptor++;
991                 }
992                 break;
993             }
994             case ACPI_RESOURCE_TYPE_IRQ:
995             {
996                 ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data;
997                 for (i = 0; i < irq_data->InterruptCount; i++)
998                 {
999                     ResourceDescriptor->Type = CmResourceTypeInterrupt;
1000 
1001                     ResourceDescriptor->ShareDisposition =
1002                     (irq_data->Shareable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive);
1003                     ResourceDescriptor->Flags =
1004                     (irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED);
1005                     ResourceDescriptor->u.Interrupt.Level =
1006                     ResourceDescriptor->u.Interrupt.Vector = irq_data->Interrupts[i];
1007                     ResourceDescriptor->u.Interrupt.Affinity = (KAFFINITY)(-1);
1008 
1009                     ResourceDescriptor++;
1010                 }
1011                 break;
1012             }
1013             case ACPI_RESOURCE_TYPE_DMA:
1014             {
1015                 ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &resource->Data;
1016                 for (i = 0; i < dma_data->ChannelCount; i++)
1017                 {
1018                     ResourceDescriptor->Type = CmResourceTypeDma;
1019                     ResourceDescriptor->Flags = 0;
1020                     switch (dma_data->Type)
1021                     {
1022                         case ACPI_TYPE_A: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
1023                         case ACPI_TYPE_B: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
1024                         case ACPI_TYPE_F: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
1025                     }
1026                     if (dma_data->BusMaster == ACPI_BUS_MASTER)
1027                         ResourceDescriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
1028                     switch (dma_data->Transfer)
1029                     {
1030                         case ACPI_TRANSFER_8: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8; break;
1031                         case ACPI_TRANSFER_16: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16; break;
1032                         case ACPI_TRANSFER_8_16: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break;
1033                     }
1034                     ResourceDescriptor->u.Dma.Channel = dma_data->Channels[i];
1035 
1036                     ResourceDescriptor++;
1037                 }
1038                 break;
1039             }
1040             case ACPI_RESOURCE_TYPE_IO:
1041             {
1042                 ACPI_RESOURCE_IO *io_data = (ACPI_RESOURCE_IO*) &resource->Data;
1043                 ResourceDescriptor->Type = CmResourceTypePort;
1044                 ResourceDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
1045                 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1046                 if (io_data->IoDecode == ACPI_DECODE_16)
1047                     ResourceDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
1048                 else
1049                     ResourceDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
1050                 ResourceDescriptor->u.Port.Start.QuadPart = io_data->Minimum;
1051                 ResourceDescriptor->u.Port.Length = io_data->AddressLength;
1052 
1053                 ResourceDescriptor++;
1054                 break;
1055             }
1056             case ACPI_RESOURCE_TYPE_FIXED_IO:
1057             {
1058                 ACPI_RESOURCE_FIXED_IO *io_data = (ACPI_RESOURCE_FIXED_IO*) &resource->Data;
1059                 ResourceDescriptor->Type = CmResourceTypePort;
1060                 ResourceDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
1061                 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1062                 ResourceDescriptor->u.Port.Start.QuadPart = io_data->Address;
1063                 ResourceDescriptor->u.Port.Length = io_data->AddressLength;
1064 
1065                 ResourceDescriptor++;
1066                 break;
1067             }
1068             case ACPI_RESOURCE_TYPE_ADDRESS16:
1069             {
1070                 ACPI_RESOURCE_ADDRESS16 *addr16_data = (ACPI_RESOURCE_ADDRESS16*) &resource->Data;
1071                 if (addr16_data->ProducerConsumer == ACPI_PRODUCER)
1072                     break;
1073                 if (addr16_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
1074                 {
1075                     ResourceDescriptor->Type = CmResourceTypeBusNumber;
1076                     ResourceDescriptor->ShareDisposition = CmResourceShareShared;
1077                     ResourceDescriptor->Flags = 0;
1078                     ResourceDescriptor->u.BusNumber.Start = addr16_data->Address.Minimum;
1079                     ResourceDescriptor->u.BusNumber.Length = addr16_data->Address.AddressLength;
1080                 }
1081                 else if (addr16_data->ResourceType == ACPI_IO_RANGE)
1082                 {
1083                     ResourceDescriptor->Type = CmResourceTypePort;
1084                     ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1085                     ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1086                     if (addr16_data->Decode == ACPI_POS_DECODE)
1087                         ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
1088                     ResourceDescriptor->u.Port.Start.QuadPart = addr16_data->Address.Minimum;
1089                     ResourceDescriptor->u.Port.Length = addr16_data->Address.AddressLength;
1090                 }
1091                 else
1092                 {
1093                     ResourceDescriptor->Type = CmResourceTypeMemory;
1094                     ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1095                     ResourceDescriptor->Flags = 0;
1096                     if (addr16_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
1097                         ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1098                     else
1099                         ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1100                     switch (addr16_data->Info.Mem.Caching)
1101                     {
1102                         case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
1103                         case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
1104                         case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
1105                     }
1106                     ResourceDescriptor->u.Memory.Start.QuadPart = addr16_data->Address.Minimum;
1107                     ResourceDescriptor->u.Memory.Length = addr16_data->Address.AddressLength;
1108                 }
1109                 ResourceDescriptor++;
1110                 break;
1111             }
1112             case ACPI_RESOURCE_TYPE_ADDRESS32:
1113             {
1114                 ACPI_RESOURCE_ADDRESS32 *addr32_data = (ACPI_RESOURCE_ADDRESS32*) &resource->Data;
1115                 if (addr32_data->ProducerConsumer == ACPI_PRODUCER)
1116                     break;
1117                 if (addr32_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
1118                 {
1119                     ResourceDescriptor->Type = CmResourceTypeBusNumber;
1120                     ResourceDescriptor->ShareDisposition = CmResourceShareShared;
1121                     ResourceDescriptor->Flags = 0;
1122                     ResourceDescriptor->u.BusNumber.Start = addr32_data->Address.Minimum;
1123                     ResourceDescriptor->u.BusNumber.Length = addr32_data->Address.AddressLength;
1124                 }
1125                 else if (addr32_data->ResourceType == ACPI_IO_RANGE)
1126                 {
1127                     ResourceDescriptor->Type = CmResourceTypePort;
1128                     ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1129                     ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1130                     if (addr32_data->Decode == ACPI_POS_DECODE)
1131                         ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
1132                     ResourceDescriptor->u.Port.Start.QuadPart = addr32_data->Address.Minimum;
1133                     ResourceDescriptor->u.Port.Length = addr32_data->Address.AddressLength;
1134                 }
1135                 else
1136                 {
1137                     ResourceDescriptor->Type = CmResourceTypeMemory;
1138                     ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1139                     ResourceDescriptor->Flags = 0;
1140                     if (addr32_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
1141                         ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1142                     else
1143                         ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1144                     switch (addr32_data->Info.Mem.Caching)
1145                     {
1146                         case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
1147                         case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
1148                         case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
1149                     }
1150                     ResourceDescriptor->u.Memory.Start.QuadPart = addr32_data->Address.Minimum;
1151                     ResourceDescriptor->u.Memory.Length = addr32_data->Address.AddressLength;
1152                 }
1153                 ResourceDescriptor++;
1154                 break;
1155             }
1156             case ACPI_RESOURCE_TYPE_ADDRESS64:
1157             {
1158                 ACPI_RESOURCE_ADDRESS64 *addr64_data = (ACPI_RESOURCE_ADDRESS64*) &resource->Data;
1159                 if (addr64_data->ProducerConsumer == ACPI_PRODUCER)
1160                     break;
1161                 if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
1162                 {
1163                     DPRINT1("64-bit bus address is not supported!\n");
1164                     ResourceDescriptor->Type = CmResourceTypeBusNumber;
1165                     ResourceDescriptor->ShareDisposition = CmResourceShareShared;
1166                     ResourceDescriptor->Flags = 0;
1167                     ResourceDescriptor->u.BusNumber.Start = (ULONG)addr64_data->Address.Minimum;
1168                     ResourceDescriptor->u.BusNumber.Length = addr64_data->Address.AddressLength;
1169                 }
1170                 else if (addr64_data->ResourceType == ACPI_IO_RANGE)
1171                 {
1172                     ResourceDescriptor->Type = CmResourceTypePort;
1173                     ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1174                     ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1175                     if (addr64_data->Decode == ACPI_POS_DECODE)
1176                         ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
1177                     ResourceDescriptor->u.Port.Start.QuadPart = addr64_data->Address.Minimum;
1178                     ResourceDescriptor->u.Port.Length = addr64_data->Address.AddressLength;
1179                 }
1180                 else
1181                 {
1182                     ResourceDescriptor->Type = CmResourceTypeMemory;
1183                     ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1184                     ResourceDescriptor->Flags = 0;
1185                     if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
1186                         ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1187                     else
1188                         ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1189                     switch (addr64_data->Info.Mem.Caching)
1190                     {
1191                         case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
1192                         case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
1193                         case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
1194                     }
1195                     ResourceDescriptor->u.Memory.Start.QuadPart = addr64_data->Address.Minimum;
1196                     ResourceDescriptor->u.Memory.Length = addr64_data->Address.AddressLength;
1197                 }
1198                 ResourceDescriptor++;
1199                 break;
1200             }
1201             case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
1202             {
1203                 ACPI_RESOURCE_EXTENDED_ADDRESS64 *addr64_data = (ACPI_RESOURCE_EXTENDED_ADDRESS64*) &resource->Data;
1204                 if (addr64_data->ProducerConsumer == ACPI_PRODUCER)
1205                     break;
1206                 if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
1207                 {
1208                     DPRINT1("64-bit bus address is not supported!\n");
1209                     ResourceDescriptor->Type = CmResourceTypeBusNumber;
1210                     ResourceDescriptor->ShareDisposition = CmResourceShareShared;
1211                     ResourceDescriptor->Flags = 0;
1212                     ResourceDescriptor->u.BusNumber.Start = (ULONG)addr64_data->Address.Minimum;
1213                     ResourceDescriptor->u.BusNumber.Length = addr64_data->Address.AddressLength;
1214                 }
1215                 else if (addr64_data->ResourceType == ACPI_IO_RANGE)
1216                 {
1217                     ResourceDescriptor->Type = CmResourceTypePort;
1218                     ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1219                     ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1220                     if (addr64_data->Decode == ACPI_POS_DECODE)
1221                         ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
1222                     ResourceDescriptor->u.Port.Start.QuadPart = addr64_data->Address.Minimum;
1223                     ResourceDescriptor->u.Port.Length = addr64_data->Address.AddressLength;
1224                 }
1225                 else
1226                 {
1227                     ResourceDescriptor->Type = CmResourceTypeMemory;
1228                     ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1229                     ResourceDescriptor->Flags = 0;
1230                     if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
1231                         ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1232                     else
1233                         ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1234                     switch (addr64_data->Info.Mem.Caching)
1235                     {
1236                         case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
1237                         case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
1238                         case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
1239                     }
1240                     ResourceDescriptor->u.Memory.Start.QuadPart = addr64_data->Address.Minimum;
1241                     ResourceDescriptor->u.Memory.Length = addr64_data->Address.AddressLength;
1242                 }
1243                 ResourceDescriptor++;
1244                 break;
1245             }
1246             case ACPI_RESOURCE_TYPE_MEMORY24:
1247             {
1248                 ACPI_RESOURCE_MEMORY24 *mem24_data = (ACPI_RESOURCE_MEMORY24*) &resource->Data;
1249                 ResourceDescriptor->Type = CmResourceTypeMemory;
1250                 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1251                 ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_24;
1252                 if (mem24_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
1253                     ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1254                 else
1255                     ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1256                 ResourceDescriptor->u.Memory.Start.QuadPart = mem24_data->Minimum;
1257                 ResourceDescriptor->u.Memory.Length = mem24_data->AddressLength;
1258 
1259                 ResourceDescriptor++;
1260                 break;
1261             }
1262             case ACPI_RESOURCE_TYPE_MEMORY32:
1263             {
1264                 ACPI_RESOURCE_MEMORY32 *mem32_data = (ACPI_RESOURCE_MEMORY32*) &resource->Data;
1265                 ResourceDescriptor->Type = CmResourceTypeMemory;
1266                 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1267                 ResourceDescriptor->Flags = 0;
1268                 if (mem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
1269                     ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1270                 else
1271                     ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1272                 ResourceDescriptor->u.Memory.Start.QuadPart = mem32_data->Minimum;
1273                 ResourceDescriptor->u.Memory.Length = mem32_data->AddressLength;
1274 
1275                 ResourceDescriptor++;
1276                 break;
1277             }
1278             case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
1279             {
1280                 ACPI_RESOURCE_FIXED_MEMORY32 *memfixed32_data = (ACPI_RESOURCE_FIXED_MEMORY32*) &resource->Data;
1281                 ResourceDescriptor->Type = CmResourceTypeMemory;
1282                 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1283                 ResourceDescriptor->Flags = 0;
1284                 if (memfixed32_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
1285                     ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1286                 else
1287                     ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1288                 ResourceDescriptor->u.Memory.Start.QuadPart = memfixed32_data->Address;
1289                 ResourceDescriptor->u.Memory.Length = memfixed32_data->AddressLength;
1290 
1291                 ResourceDescriptor++;
1292                 break;
1293             }
1294             default:
1295             {
1296                 break;
1297             }
1298         }
1299         resource = ACPI_NEXT_RESOURCE(resource);
1300     }
1301 
1302     ExFreePoolWithTag(Buffer.Pointer, 'BpcA');
1303     Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
1304     return STATUS_SUCCESS;
1305 }
1306 #endif /* UNIT_TEST */
1307 
1308 NTSTATUS
Bus_PDO_QueryResourceRequirements(PPDO_DEVICE_DATA DeviceData,PIRP Irp)1309 Bus_PDO_QueryResourceRequirements(
1310      PPDO_DEVICE_DATA     DeviceData,
1311       PIRP   Irp )
1312 {
1313     ULONG NumberOfResources = 0;
1314     ACPI_STATUS AcpiStatus;
1315     ACPI_BUFFER Buffer;
1316     ACPI_RESOURCE* resource;
1317     ULONG i, RequirementsListSize;
1318     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
1319     PIO_RESOURCE_DESCRIPTOR RequirementDescriptor;
1320     BOOLEAN CurrentRes = FALSE;
1321     BOOLEAN SeenStartDependent;
1322 
1323     PAGED_CODE ();
1324 
1325     if (!DeviceData->AcpiHandle)
1326     {
1327         return Irp->IoStatus.Status;
1328     }
1329 
1330     /* Handle the PCI root manually */
1331     if (wcsstr(DeviceData->HardwareIDs, L"PNP0A03") != 0 ||
1332         wcsstr(DeviceData->HardwareIDs, L"PNP0A08") != 0)
1333     {
1334         return Irp->IoStatus.Status;
1335     }
1336 
1337     /* Get current resources */
1338     while (TRUE)
1339     {
1340         Buffer.Length = 0;
1341         if (CurrentRes)
1342         AcpiStatus = AcpiGetCurrentResources(DeviceData->AcpiHandle, &Buffer);
1343         else
1344             AcpiStatus = AcpiGetPossibleResources(DeviceData->AcpiHandle, &Buffer);
1345         if ((!ACPI_SUCCESS(AcpiStatus) && AcpiStatus != AE_BUFFER_OVERFLOW) ||
1346             Buffer.Length == 0)
1347         {
1348             if (!CurrentRes)
1349                 CurrentRes = TRUE;
1350             else
1351                 return Irp->IoStatus.Status;
1352         }
1353         else
1354             break;
1355     }
1356 
1357     Buffer.Pointer = ExAllocatePoolWithTag(PagedPool, Buffer.Length, 'BpcA');
1358     if (!Buffer.Pointer)
1359       return STATUS_INSUFFICIENT_RESOURCES;
1360 
1361     if (CurrentRes)
1362         AcpiStatus = AcpiGetCurrentResources(DeviceData->AcpiHandle, &Buffer);
1363     else
1364         AcpiStatus = AcpiGetPossibleResources(DeviceData->AcpiHandle, &Buffer);
1365     if (!ACPI_SUCCESS(AcpiStatus))
1366     {
1367       DPRINT1("AcpiGetCurrentResources #2 failed (0x%x)\n", AcpiStatus);
1368       ASSERT(FALSE);
1369       return STATUS_UNSUCCESSFUL;
1370     }
1371 
1372     SeenStartDependent = FALSE;
1373     resource = Buffer.Pointer;
1374     /* Count number of resources */
1375     while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG && resource->Type != ACPI_RESOURCE_TYPE_END_DEPENDENT)
1376     {
1377         if (resource->Type == ACPI_RESOURCE_TYPE_START_DEPENDENT)
1378         {
1379             if (SeenStartDependent)
1380             {
1381                 break;
1382             }
1383             SeenStartDependent = TRUE;
1384         }
1385         switch (resource->Type)
1386         {
1387             case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1388             {
1389                 ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data;
1390                 if (irq_data->ProducerConsumer == ACPI_PRODUCER)
1391                     break;
1392                 NumberOfResources += irq_data->InterruptCount;
1393                 break;
1394             }
1395             case ACPI_RESOURCE_TYPE_IRQ:
1396             {
1397                 ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data;
1398                 NumberOfResources += irq_data->InterruptCount;
1399                 break;
1400             }
1401             case ACPI_RESOURCE_TYPE_DMA:
1402             {
1403                 ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &resource->Data;
1404                 NumberOfResources += dma_data->ChannelCount;
1405                 break;
1406             }
1407             case ACPI_RESOURCE_TYPE_ADDRESS16:
1408             case ACPI_RESOURCE_TYPE_ADDRESS32:
1409             case ACPI_RESOURCE_TYPE_ADDRESS64:
1410             case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
1411             {
1412                 ACPI_RESOURCE_ADDRESS *res_addr = (ACPI_RESOURCE_ADDRESS*) &resource->Data;
1413                 if (res_addr->ProducerConsumer == ACPI_PRODUCER)
1414                     break;
1415                 NumberOfResources++;
1416                 break;
1417             }
1418             case ACPI_RESOURCE_TYPE_MEMORY24:
1419             case ACPI_RESOURCE_TYPE_MEMORY32:
1420             case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
1421             case ACPI_RESOURCE_TYPE_FIXED_IO:
1422             case ACPI_RESOURCE_TYPE_IO:
1423             {
1424                 NumberOfResources++;
1425                 break;
1426             }
1427             default:
1428             {
1429                 break;
1430             }
1431         }
1432         resource = ACPI_NEXT_RESOURCE(resource);
1433     }
1434 
1435     RequirementsListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR) * (NumberOfResources - 1);
1436     RequirementsList = ExAllocatePoolWithTag(PagedPool, RequirementsListSize, 'RpcA');
1437 
1438     if (!RequirementsList)
1439     {
1440         ExFreePoolWithTag(Buffer.Pointer, 'BpcA');
1441         return STATUS_INSUFFICIENT_RESOURCES;
1442     }
1443     RequirementsList->ListSize = RequirementsListSize;
1444     RequirementsList->InterfaceType = Internal;
1445     RequirementsList->BusNumber = 0;
1446     RequirementsList->SlotNumber = 0; /* Not used by WDM drivers */
1447     RequirementsList->AlternativeLists = 1;
1448     RequirementsList->List[0].Version = 1;
1449     RequirementsList->List[0].Revision = 1;
1450     RequirementsList->List[0].Count = NumberOfResources;
1451     RequirementDescriptor = RequirementsList->List[0].Descriptors;
1452 
1453     /* Fill resources list structure */
1454     SeenStartDependent = FALSE;
1455     resource = Buffer.Pointer;
1456     while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG && resource->Type != ACPI_RESOURCE_TYPE_END_DEPENDENT)
1457     {
1458         if (resource->Type == ACPI_RESOURCE_TYPE_START_DEPENDENT)
1459         {
1460             if (SeenStartDependent)
1461             {
1462                 break;
1463             }
1464             SeenStartDependent = TRUE;
1465         }
1466         switch (resource->Type)
1467         {
1468             case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1469             {
1470                 ACPI_RESOURCE_EXTENDED_IRQ *irq_data = &resource->Data.ExtendedIrq;
1471                 if (irq_data->ProducerConsumer == ACPI_PRODUCER)
1472                     break;
1473                 for (i = 0; i < irq_data->InterruptCount; i++)
1474                 {
1475                     RequirementDescriptor->Option = (i == 0) ? IO_RESOURCE_PREFERRED : IO_RESOURCE_ALTERNATIVE;
1476                     RequirementDescriptor->Type = CmResourceTypeInterrupt;
1477                     RequirementDescriptor->ShareDisposition = (irq_data->Shareable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive);
1478                     RequirementDescriptor->Flags =(irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED);
1479                     RequirementDescriptor->u.Interrupt.MinimumVector =
1480                     RequirementDescriptor->u.Interrupt.MaximumVector = irq_data->Interrupts[i];
1481 
1482                     RequirementDescriptor++;
1483                 }
1484                 break;
1485             }
1486             case ACPI_RESOURCE_TYPE_IRQ:
1487             {
1488                 ACPI_RESOURCE_IRQ *irq_data = &resource->Data.Irq;
1489                 for (i = 0; i < irq_data->InterruptCount; i++)
1490                 {
1491                     RequirementDescriptor->Option = (i == 0) ? IO_RESOURCE_PREFERRED : IO_RESOURCE_ALTERNATIVE;
1492                     RequirementDescriptor->Type = CmResourceTypeInterrupt;
1493                     RequirementDescriptor->ShareDisposition = (irq_data->Shareable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive);
1494                     RequirementDescriptor->Flags =(irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED);
1495                     RequirementDescriptor->u.Interrupt.MinimumVector =
1496                     RequirementDescriptor->u.Interrupt.MaximumVector = irq_data->Interrupts[i];
1497 
1498                     RequirementDescriptor++;
1499                 }
1500                 break;
1501             }
1502             case ACPI_RESOURCE_TYPE_DMA:
1503             {
1504                 ACPI_RESOURCE_DMA *dma_data = &resource->Data.Dma;
1505                 for (i = 0; i < dma_data->ChannelCount; i++)
1506                 {
1507                     RequirementDescriptor->Type = CmResourceTypeDma;
1508                     RequirementDescriptor->Flags = 0;
1509                     switch (dma_data->Type)
1510                     {
1511                         case ACPI_TYPE_A: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
1512                         case ACPI_TYPE_B: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
1513                         case ACPI_TYPE_F: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
1514                     }
1515                     if (dma_data->BusMaster == ACPI_BUS_MASTER)
1516                         RequirementDescriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
1517                     switch (dma_data->Transfer)
1518                     {
1519                         case ACPI_TRANSFER_8: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_8; break;
1520                         case ACPI_TRANSFER_16: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_16; break;
1521                         case ACPI_TRANSFER_8_16: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break;
1522                     }
1523 
1524                     RequirementDescriptor->Option = (i == 0) ? IO_RESOURCE_PREFERRED : IO_RESOURCE_ALTERNATIVE;
1525                     RequirementDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
1526                     RequirementDescriptor->u.Dma.MinimumChannel =
1527                     RequirementDescriptor->u.Dma.MaximumChannel = dma_data->Channels[i];
1528                     RequirementDescriptor++;
1529                 }
1530                 break;
1531             }
1532             case ACPI_RESOURCE_TYPE_IO:
1533             {
1534                 ACPI_RESOURCE_IO *io_data = &resource->Data.Io;
1535                 RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
1536                 if (io_data->IoDecode == ACPI_DECODE_16)
1537                     RequirementDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
1538                 else
1539                     RequirementDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
1540                 RequirementDescriptor->u.Port.Length = io_data->AddressLength;
1541                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1542                 RequirementDescriptor->Type = CmResourceTypePort;
1543                 RequirementDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
1544                 RequirementDescriptor->u.Port.Alignment = io_data->Alignment;
1545                 RequirementDescriptor->u.Port.MinimumAddress.QuadPart = io_data->Minimum;
1546                 RequirementDescriptor->u.Port.MaximumAddress.QuadPart = io_data->Maximum + io_data->AddressLength - 1;
1547 
1548                 RequirementDescriptor++;
1549                 break;
1550             }
1551             case ACPI_RESOURCE_TYPE_FIXED_IO:
1552             {
1553                 ACPI_RESOURCE_FIXED_IO *io_data = &resource->Data.FixedIo;
1554                 RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
1555                 RequirementDescriptor->u.Port.Length = io_data->AddressLength;
1556                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1557                 RequirementDescriptor->Type = CmResourceTypePort;
1558                 RequirementDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
1559                 RequirementDescriptor->u.Port.Alignment = 1;
1560                 RequirementDescriptor->u.Port.MinimumAddress.QuadPart = io_data->Address;
1561                 RequirementDescriptor->u.Port.MaximumAddress.QuadPart = io_data->Address + io_data->AddressLength - 1;
1562 
1563                 RequirementDescriptor++;
1564                 break;
1565             }
1566             case ACPI_RESOURCE_TYPE_ADDRESS16:
1567             {
1568                 ACPI_RESOURCE_ADDRESS16 *addr16_data = &resource->Data.Address16;
1569                 if (addr16_data->ProducerConsumer == ACPI_PRODUCER)
1570                     break;
1571                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1572                 if (addr16_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
1573                 {
1574                     RequirementDescriptor->Type = CmResourceTypeBusNumber;
1575                     RequirementDescriptor->ShareDisposition = CmResourceShareShared;
1576                     RequirementDescriptor->Flags = 0;
1577                     RequirementDescriptor->u.BusNumber.MinBusNumber = addr16_data->Address.Minimum;
1578                     RequirementDescriptor->u.BusNumber.MaxBusNumber = addr16_data->Address.Maximum + addr16_data->Address.AddressLength - 1;
1579                     RequirementDescriptor->u.BusNumber.Length = addr16_data->Address.AddressLength;
1580                 }
1581                 else if (addr16_data->ResourceType == ACPI_IO_RANGE)
1582                 {
1583                     RequirementDescriptor->Type = CmResourceTypePort;
1584                     RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1585                     RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
1586                     if (addr16_data->Decode == ACPI_POS_DECODE)
1587                         RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
1588                     RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr16_data->Address.Minimum;
1589                     RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr16_data->Address.Maximum + addr16_data->Address.AddressLength - 1;
1590                     RequirementDescriptor->u.Port.Length = addr16_data->Address.AddressLength;
1591                 }
1592                 else
1593                 {
1594                     RequirementDescriptor->Type = CmResourceTypeMemory;
1595                     RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1596                     RequirementDescriptor->Flags = 0;
1597                     if (addr16_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
1598                         RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1599                     else
1600                         RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1601                     switch (addr16_data->Info.Mem.Caching)
1602                     {
1603                         case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
1604                         case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
1605                         case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
1606                     }
1607                     RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr16_data->Address.Minimum;
1608                     RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr16_data->Address.Maximum + addr16_data->Address.AddressLength - 1;
1609                     RequirementDescriptor->u.Memory.Length = addr16_data->Address.AddressLength;
1610                 }
1611                 RequirementDescriptor++;
1612                 break;
1613             }
1614             case ACPI_RESOURCE_TYPE_ADDRESS32:
1615             {
1616                 ACPI_RESOURCE_ADDRESS32 *addr32_data = &resource->Data.Address32;
1617                 if (addr32_data->ProducerConsumer == ACPI_PRODUCER)
1618                     break;
1619                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1620                 if (addr32_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
1621                 {
1622                     RequirementDescriptor->Type = CmResourceTypeBusNumber;
1623                     RequirementDescriptor->ShareDisposition = CmResourceShareShared;
1624                     RequirementDescriptor->Flags = 0;
1625                     RequirementDescriptor->u.BusNumber.MinBusNumber = addr32_data->Address.Minimum;
1626                     RequirementDescriptor->u.BusNumber.MaxBusNumber = addr32_data->Address.Maximum + addr32_data->Address.AddressLength - 1;
1627                     RequirementDescriptor->u.BusNumber.Length = addr32_data->Address.AddressLength;
1628                 }
1629                 else if (addr32_data->ResourceType == ACPI_IO_RANGE)
1630                 {
1631                     RequirementDescriptor->Type = CmResourceTypePort;
1632                     RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1633                     RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
1634                     if (addr32_data->Decode == ACPI_POS_DECODE)
1635                         RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
1636                     RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr32_data->Address.Minimum;
1637                     RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr32_data->Address.Maximum + addr32_data->Address.AddressLength - 1;
1638                     RequirementDescriptor->u.Port.Length = addr32_data->Address.AddressLength;
1639                 }
1640                 else
1641                 {
1642                     RequirementDescriptor->Type = CmResourceTypeMemory;
1643                     RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1644                     RequirementDescriptor->Flags = 0;
1645                     if (addr32_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
1646                         RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1647                     else
1648                         RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1649                     switch (addr32_data->Info.Mem.Caching)
1650                     {
1651                         case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
1652                         case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
1653                         case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
1654                     }
1655                     RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr32_data->Address.Minimum;
1656                     RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr32_data->Address.Maximum + addr32_data->Address.AddressLength - 1;
1657                     RequirementDescriptor->u.Memory.Length = addr32_data->Address.AddressLength;
1658                 }
1659                 RequirementDescriptor++;
1660                 break;
1661             }
1662             case ACPI_RESOURCE_TYPE_ADDRESS64:
1663             {
1664                 ACPI_RESOURCE_ADDRESS64 *addr64_data = &resource->Data.Address64;
1665                 if (addr64_data->ProducerConsumer == ACPI_PRODUCER)
1666                     break;
1667                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1668                 if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
1669                 {
1670                     DPRINT1("64-bit bus address is not supported!\n");
1671                     RequirementDescriptor->Type = CmResourceTypeBusNumber;
1672                     RequirementDescriptor->ShareDisposition = CmResourceShareShared;
1673                     RequirementDescriptor->Flags = 0;
1674                     RequirementDescriptor->u.BusNumber.MinBusNumber = (ULONG)addr64_data->Address.Minimum;
1675                     RequirementDescriptor->u.BusNumber.MaxBusNumber = (ULONG)addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
1676                     RequirementDescriptor->u.BusNumber.Length = addr64_data->Address.AddressLength;
1677                 }
1678                 else if (addr64_data->ResourceType == ACPI_IO_RANGE)
1679                 {
1680                     RequirementDescriptor->Type = CmResourceTypePort;
1681                     RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1682                     RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
1683                     if (addr64_data->Decode == ACPI_POS_DECODE)
1684                         RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
1685                     RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr64_data->Address.Minimum;
1686                     RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
1687                     RequirementDescriptor->u.Port.Length = addr64_data->Address.AddressLength;
1688                 }
1689                 else
1690                 {
1691                     RequirementDescriptor->Type = CmResourceTypeMemory;
1692                     RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1693                     RequirementDescriptor->Flags = 0;
1694                     if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
1695                         RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1696                     else
1697                         RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1698                     switch (addr64_data->Info.Mem.Caching)
1699                     {
1700                         case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
1701                         case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
1702                         case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
1703                     }
1704                     RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr64_data->Address.Minimum;
1705                     RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
1706                     RequirementDescriptor->u.Memory.Length = addr64_data->Address.AddressLength;
1707                 }
1708                 RequirementDescriptor++;
1709                 break;
1710             }
1711             case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
1712             {
1713                 ACPI_RESOURCE_EXTENDED_ADDRESS64 *addr64_data = &resource->Data.ExtAddress64;
1714                 if (addr64_data->ProducerConsumer == ACPI_PRODUCER)
1715                     break;
1716                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1717                 if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
1718                 {
1719                     DPRINT1("64-bit bus address is not supported!\n");
1720                     RequirementDescriptor->Type = CmResourceTypeBusNumber;
1721                     RequirementDescriptor->ShareDisposition = CmResourceShareShared;
1722                     RequirementDescriptor->Flags = 0;
1723                     RequirementDescriptor->u.BusNumber.MinBusNumber = (ULONG)addr64_data->Address.Minimum;
1724                     RequirementDescriptor->u.BusNumber.MaxBusNumber = (ULONG)addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
1725                     RequirementDescriptor->u.BusNumber.Length = addr64_data->Address.AddressLength;
1726                 }
1727                 else if (addr64_data->ResourceType == ACPI_IO_RANGE)
1728                 {
1729                     RequirementDescriptor->Type = CmResourceTypePort;
1730                     RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1731                     RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
1732                     if (addr64_data->Decode == ACPI_POS_DECODE)
1733                         RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
1734                     RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr64_data->Address.Minimum;
1735                     RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
1736                     RequirementDescriptor->u.Port.Length = addr64_data->Address.AddressLength;
1737                 }
1738                 else
1739                 {
1740                     RequirementDescriptor->Type = CmResourceTypeMemory;
1741                     RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1742                     RequirementDescriptor->Flags = 0;
1743                     if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
1744                         RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1745                     else
1746                         RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1747                     switch (addr64_data->Info.Mem.Caching)
1748                     {
1749                         case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
1750                         case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
1751                         case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
1752                     }
1753                     RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr64_data->Address.Minimum;
1754                     RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
1755                     RequirementDescriptor->u.Memory.Length = addr64_data->Address.AddressLength;
1756                 }
1757                 RequirementDescriptor++;
1758                 break;
1759             }
1760             case ACPI_RESOURCE_TYPE_MEMORY24:
1761             {
1762                 ACPI_RESOURCE_MEMORY24 *mem24_data = &resource->Data.Memory24;
1763                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1764                 RequirementDescriptor->Type = CmResourceTypeMemory;
1765                 RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1766                 RequirementDescriptor->Flags = CM_RESOURCE_MEMORY_24;
1767                 if (mem24_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
1768                     RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1769                 else
1770                     RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1771                 RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = mem24_data->Minimum;
1772                 RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = mem24_data->Maximum + mem24_data->AddressLength - 1;
1773                 RequirementDescriptor->u.Memory.Length = mem24_data->AddressLength;
1774 
1775                 RequirementDescriptor++;
1776                 break;
1777             }
1778             case ACPI_RESOURCE_TYPE_MEMORY32:
1779             {
1780                 ACPI_RESOURCE_MEMORY32 *mem32_data = &resource->Data.Memory32;
1781                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1782                 RequirementDescriptor->Type = CmResourceTypeMemory;
1783                 RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1784                 RequirementDescriptor->Flags = 0;
1785                 if (mem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
1786                     RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1787                 else
1788                     RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1789                 RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = mem32_data->Minimum;
1790                 RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = mem32_data->Maximum + mem32_data->AddressLength - 1;
1791                 RequirementDescriptor->u.Memory.Length = mem32_data->AddressLength;
1792 
1793                 RequirementDescriptor++;
1794                 break;
1795             }
1796             case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
1797             {
1798                 ACPI_RESOURCE_FIXED_MEMORY32 *fixedmem32_data = &resource->Data.FixedMemory32;
1799                 RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
1800                 RequirementDescriptor->Type = CmResourceTypeMemory;
1801                 RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1802                 RequirementDescriptor->Flags = 0;
1803                 if (fixedmem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
1804                     RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
1805                 else
1806                     RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
1807                 RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = fixedmem32_data->Address;
1808                 RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = fixedmem32_data->Address + fixedmem32_data->AddressLength - 1;
1809                 RequirementDescriptor->u.Memory.Length = fixedmem32_data->AddressLength;
1810 
1811                 RequirementDescriptor++;
1812                 break;
1813             }
1814             default:
1815             {
1816                 break;
1817             }
1818         }
1819         resource = ACPI_NEXT_RESOURCE(resource);
1820     }
1821     ExFreePoolWithTag(Buffer.Pointer, 'BpcA');
1822 
1823     Irp->IoStatus.Information = (ULONG_PTR)RequirementsList;
1824 
1825     return STATUS_SUCCESS;
1826 }
1827 
1828 #ifndef UNIT_TEST
1829 NTSTATUS
Bus_PDO_QueryDeviceRelations(PPDO_DEVICE_DATA DeviceData,PIRP Irp)1830 Bus_PDO_QueryDeviceRelations(
1831      PPDO_DEVICE_DATA     DeviceData,
1832       PIRP   Irp )
1833 /*++
1834 
1835 Routine Description:
1836 
1837     The PnP Manager sends this IRP to gather information about
1838     devices with a relationship to the specified device.
1839     Bus drivers must handle this request for TargetDeviceRelation
1840     for their child devices (child PDOs).
1841 
1842     If a driver returns relations in response to this IRP,
1843     it allocates a DEVICE_RELATIONS structure from paged
1844     memory containing a count and the appropriate number of
1845     device object pointers. The PnP Manager frees the structure
1846     when it is no longer needed. If a driver replaces a
1847     DEVICE_RELATIONS structure allocated by another driver,
1848     it must free the previous structure.
1849 
1850     A driver must reference the PDO of any device that it
1851     reports in this IRP (ObReferenceObject). The PnP Manager
1852     removes the reference when appropriate.
1853 
1854 Arguments:
1855 
1856     DeviceData - Pointer to the PDO's device extension.
1857     Irp          - Pointer to the irp.
1858 
1859 Return Value:
1860 
1861     NT STATUS
1862 
1863 --*/
1864 {
1865 
1866     PIO_STACK_LOCATION   stack;
1867     PDEVICE_RELATIONS deviceRelations;
1868     NTSTATUS status;
1869 
1870     PAGED_CODE ();
1871 
1872     stack = IoGetCurrentIrpStackLocation (Irp);
1873 
1874     switch (stack->Parameters.QueryDeviceRelations.Type) {
1875 
1876     case TargetDeviceRelation:
1877 
1878         deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
1879         if (deviceRelations) {
1880             //
1881             // Only PDO can handle this request. Somebody above
1882             // is not playing by rule.
1883             //
1884             ASSERTMSG("Someone above is handling TargetDeviceRelation\n", !deviceRelations);
1885         }
1886 
1887         deviceRelations = ExAllocatePoolWithTag(PagedPool,
1888                                                 sizeof(DEVICE_RELATIONS),
1889                                                 'IpcA');
1890         if (!deviceRelations) {
1891                 status = STATUS_INSUFFICIENT_RESOURCES;
1892                 break;
1893         }
1894 
1895         //
1896         // There is only one PDO pointer in the structure
1897         // for this relation type. The PnP Manager removes
1898         // the reference to the PDO when the driver or application
1899         // un-registers for notification on the device.
1900         //
1901 
1902         deviceRelations->Count = 1;
1903         deviceRelations->Objects[0] = DeviceData->Common.Self;
1904         ObReferenceObject(DeviceData->Common.Self);
1905 
1906         status = STATUS_SUCCESS;
1907         Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
1908         break;
1909 
1910     case BusRelations: // Not handled by PDO
1911     case EjectionRelations: // optional for PDO
1912     case RemovalRelations: // // optional for PDO
1913     default:
1914         status = Irp->IoStatus.Status;
1915     }
1916 
1917     return status;
1918 }
1919 
1920 NTSTATUS
Bus_PDO_QueryBusInformation(PPDO_DEVICE_DATA DeviceData,PIRP Irp)1921 Bus_PDO_QueryBusInformation(
1922      PPDO_DEVICE_DATA     DeviceData,
1923       PIRP   Irp )
1924 /*++
1925 
1926 Routine Description:
1927 
1928     The PnP Manager uses this IRP to request the type and
1929     instance number of a device's parent bus. Bus drivers
1930     should handle this request for their child devices (PDOs).
1931 
1932 Arguments:
1933 
1934     DeviceData - Pointer to the PDO's device extension.
1935     Irp          - Pointer to the irp.
1936 
1937 Return Value:
1938 
1939     NT STATUS
1940 
1941 --*/
1942 {
1943 
1944     PPNP_BUS_INFORMATION busInfo;
1945 
1946     PAGED_CODE ();
1947 
1948     busInfo = ExAllocatePoolWithTag(PagedPool,
1949                                     sizeof(PNP_BUS_INFORMATION),
1950                                     'IpcA');
1951 
1952     if (busInfo == NULL) {
1953       return STATUS_INSUFFICIENT_RESOURCES;
1954     }
1955 
1956     busInfo->BusTypeGuid = GUID_ACPI_INTERFACE_STANDARD;
1957 
1958     busInfo->LegacyBusType = InternalPowerBus;
1959 
1960     busInfo->BusNumber = 0; //fixme
1961 
1962     Irp->IoStatus.Information = (ULONG_PTR)busInfo;
1963 
1964     return STATUS_SUCCESS;
1965 }
1966 
1967 
1968 NTSTATUS
Bus_GetDeviceCapabilities(PDEVICE_OBJECT DeviceObject,PDEVICE_CAPABILITIES DeviceCapabilities)1969 Bus_GetDeviceCapabilities(
1970       PDEVICE_OBJECT          DeviceObject,
1971       PDEVICE_CAPABILITIES    DeviceCapabilities
1972     )
1973 {
1974     IO_STATUS_BLOCK     ioStatus;
1975     KEVENT              pnpEvent;
1976     NTSTATUS            status;
1977     PDEVICE_OBJECT      targetObject;
1978     PIO_STACK_LOCATION  irpStack;
1979     PIRP                pnpIrp;
1980 
1981     PAGED_CODE();
1982 
1983     //
1984     // Initialize the capabilities that we will send down
1985     //
1986     RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
1987     DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
1988     DeviceCapabilities->Version = 1;
1989     DeviceCapabilities->Address = -1;
1990     DeviceCapabilities->UINumber = -1;
1991 
1992     //
1993     // Initialize the event
1994     //
1995     KeInitializeEvent( &pnpEvent, NotificationEvent, FALSE );
1996 
1997     targetObject = IoGetAttachedDeviceReference( DeviceObject );
1998 
1999     //
2000     // Build an Irp
2001     //
2002     pnpIrp = IoBuildSynchronousFsdRequest(
2003         IRP_MJ_PNP,
2004         targetObject,
2005         NULL,
2006         0,
2007         NULL,
2008         &pnpEvent,
2009         &ioStatus
2010         );
2011     if (pnpIrp == NULL) {
2012 
2013         status = STATUS_INSUFFICIENT_RESOURCES;
2014         goto GetDeviceCapabilitiesExit;
2015 
2016     }
2017 
2018     //
2019     // Pnp Irps all begin life as STATUS_NOT_SUPPORTED;
2020     //
2021     pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
2022 
2023     //
2024     // Get the top of stack
2025     //
2026     irpStack = IoGetNextIrpStackLocation( pnpIrp );
2027 
2028     //
2029     // Set the top of stack
2030     //
2031     RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) );
2032     irpStack->MajorFunction = IRP_MJ_PNP;
2033     irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
2034     irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
2035 
2036     //
2037     // Call the driver
2038     //
2039     status = IoCallDriver( targetObject, pnpIrp );
2040     if (status == STATUS_PENDING) {
2041 
2042         //
2043         // Block until the irp comes back.
2044         // Important thing to note here is when you allocate
2045         // the memory for an event in the stack you must do a
2046         // KernelMode wait instead of UserMode to prevent
2047         // the stack from getting paged out.
2048         //
2049 
2050         KeWaitForSingleObject(
2051             &pnpEvent,
2052             Executive,
2053             KernelMode,
2054             FALSE,
2055             NULL
2056             );
2057         status = ioStatus.Status;
2058 
2059     }
2060 
2061 GetDeviceCapabilitiesExit:
2062     //
2063     // Done with reference
2064     //
2065     ObDereferenceObject( targetObject );
2066 
2067     //
2068     // Done
2069     //
2070     return status;
2071 
2072 }
2073 #endif /* UNIT_TEST */
2074