xref: /reactos/drivers/bus/acpi/acpienum.c (revision c2c66aff)
1 /*
2  * PROJECT:         ReactOS ACPI bus driver
3  * FILE:            acpi/ospm/acpienum.c
4  * PURPOSE:         ACPI namespace enumerator
5  * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
6  * UPDATE HISTORY:
7  *      01-05-2001  CSH  Created
8  */
9 
10 #include "precomp.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define HAS_CHILDREN(d)		((d)->children.next != &((d)->children))
16 #define HAS_SIBLINGS(d)		(((d)->parent) && ((d)->node.next != &(d)->parent->children))
17 #define NODE_TO_DEVICE(n)	(list_entry(n, struct acpi_device, node))
18 
19 extern struct acpi_device		*acpi_root;
20 
21 NTSTATUS
Bus_PlugInDevice(struct acpi_device * Device,PFDO_DEVICE_DATA FdoData)22 Bus_PlugInDevice (
23     struct acpi_device *Device,
24     PFDO_DEVICE_DATA            FdoData
25     )
26 {
27     PDEVICE_OBJECT      pdo;
28     PPDO_DEVICE_DATA    pdoData;
29     NTSTATUS            status;
30     ULONG               index;
31 	WCHAR               temp[256];
32     PLIST_ENTRY         entry;
33 
34     PAGED_CODE ();
35 
36     //Don't enumerate the root device
37     if (Device->handle == ACPI_ROOT_OBJECT)
38         return STATUS_SUCCESS;
39 
40     /* Check we didnt add this already */
41     for (entry = FdoData->ListOfPDOs.Flink;
42         entry != &FdoData->ListOfPDOs; entry = entry->Flink)
43     {
44         struct acpi_device *CurrentDevice;
45 
46         pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
47 
48         //dont duplicate devices
49         if (pdoData->AcpiHandle == Device->handle)
50             return STATUS_SUCCESS;
51 
52         //check everything but fixed feature devices
53         if (pdoData->AcpiHandle)
54             acpi_bus_get_device(pdoData->AcpiHandle, &CurrentDevice);
55         else
56             continue;
57 
58         //check if the HID matches
59         if (!strcmp(Device->pnp.hardware_id, CurrentDevice->pnp.hardware_id))
60         {
61             //check if UID exists for both and matches
62             if (Device->flags.unique_id && CurrentDevice->flags.unique_id &&
63                 !strcmp(Device->pnp.unique_id, CurrentDevice->pnp.unique_id))
64             {
65                 /* We have a UID on both but they're the same so we have to ignore it */
66                 DPRINT1("Detected duplicate device: %hs %hs\n", Device->pnp.hardware_id, Device->pnp.unique_id);
67                 return STATUS_SUCCESS;
68             }
69             else if (!Device->flags.unique_id && !CurrentDevice->flags.unique_id)
70             {
71                 /* No UID so we can only legally have 1 of these devices */
72                 DPRINT1("Detected duplicate device: %hs\n", Device->pnp.hardware_id);
73                 return STATUS_SUCCESS;
74             }
75         }
76     }
77 
78     DPRINT("Exposing PDO\n"
79            "======AcpiHandle:   %p\n"
80            "======HardwareId:     %s\n",
81            Device->handle,
82            Device->pnp.hardware_id);
83 
84 
85     //
86     // Create the PDO
87     //
88 
89     DPRINT("FdoData->NextLowerDriver = 0x%p\n", FdoData->NextLowerDriver);
90 
91     status = IoCreateDevice(FdoData->Common.Self->DriverObject,
92                               sizeof(PDO_DEVICE_DATA),
93                               NULL,
94                               FILE_DEVICE_CONTROLLER,
95                               FILE_AUTOGENERATED_DEVICE_NAME,
96                               FALSE,
97                               &pdo);
98 
99     if (!NT_SUCCESS (status)) {
100         return status;
101     }
102 
103     pdoData = (PPDO_DEVICE_DATA) pdo->DeviceExtension;
104 	pdoData->AcpiHandle = Device->handle;
105 
106     //
107     // Copy the hardware IDs
108     //
109 		index = 0;
110 		index += swprintf(&temp[index],
111 							L"ACPI\\%hs",
112 							Device->pnp.hardware_id);
113 		temp[index++] = UNICODE_NULL;
114 
115 		index += swprintf(&temp[index],
116 							L"*%hs",
117 							Device->pnp.hardware_id);
118 		temp[index++] = UNICODE_NULL;
119 		temp[index++] = UNICODE_NULL;
120 
121 		pdoData->HardwareIDs = ExAllocatePoolWithTag(NonPagedPool, index*sizeof(WCHAR), 'DpcA');
122 
123 
124     if (!pdoData->HardwareIDs) {
125         IoDeleteDevice(pdo);
126         return STATUS_INSUFFICIENT_RESOURCES;
127     }
128 
129 	RtlCopyMemory (pdoData->HardwareIDs, temp, index*sizeof(WCHAR));
130     Bus_InitializePdo (pdo, FdoData);
131 
132     //
133     // Device Relation changes if a new pdo is created. So let
134     // the PNP system now about that. This forces it to send bunch of pnp
135     // queries and cause the function driver to be loaded.
136     //
137 
138     //IoInvalidateDeviceRelations (FdoData->UnderlyingPDO, BusRelations);
139 
140     return status;
141 }
142 
143 
144 /* looks alot like acpi_bus_walk doesnt it */
145 NTSTATUS
ACPIEnumerateDevices(PFDO_DEVICE_DATA DeviceExtension)146 ACPIEnumerateDevices(PFDO_DEVICE_DATA DeviceExtension)
147 {
148     ULONG Count = 0;
149     struct acpi_device *Device = acpi_root;
150 
151     while(Device)
152     {
153         if (Device->status.present && Device->status.enabled &&
154             Device->flags.hardware_id)
155         {
156             Bus_PlugInDevice(Device, DeviceExtension);
157             Count++;
158         }
159 
160         if (HAS_CHILDREN(Device)) {
161             Device = NODE_TO_DEVICE(Device->children.next);
162             continue;
163         }
164         if (HAS_SIBLINGS(Device)) {
165             Device = NODE_TO_DEVICE(Device->node.next);
166             continue;
167         }
168         while ((Device = Device->parent)) {
169             if (HAS_SIBLINGS(Device)) {
170                 Device = NODE_TO_DEVICE(Device->node.next);
171                 break;
172             }
173         }
174     }
175     DPRINT("acpi device count: %d\n", Count);
176     return STATUS_SUCCESS;
177 }
178 
179 /* EOF */
180