[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnpreport.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpreport.c
5 * PURPOSE: Device Changes Reporting Functions
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 NTSTATUS
16 NTAPI
17 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
18 OUT PHANDLE Handle);
19
20 NTSTATUS
21 IopAssignDeviceResources(
22 IN PDEVICE_NODE DeviceNode,
23 OUT ULONG *pRequiredSize);
24
25 NTSTATUS
26 IopSetDeviceInstanceData(HANDLE InstanceKey,
27 PDEVICE_NODE DeviceNode);
28
29 NTSTATUS
30 IopTranslateDeviceResources(
31 IN PDEVICE_NODE DeviceNode,
32 IN ULONG RequiredSize);
33
34 NTSTATUS
35 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
36 PVOID Context);
37
38 /* PRIVATE FUNCTIONS *********************************************************/
39
40 PWCHAR
41 IopGetInterfaceTypeString(INTERFACE_TYPE IfType)
42 {
43 switch (IfType)
44 {
45 case Internal:
46 return L"Internal";
47
48 case Isa:
49 return L"Isa";
50
51 case Eisa:
52 return L"Eisa";
53
54 case MicroChannel:
55 return L"MicroChannel";
56
57 case TurboChannel:
58 return L"TurboChannel";
59
60 case PCIBus:
61 return L"PCIBus";
62
63 case VMEBus:
64 return L"VMEBus";
65
66 case NuBus:
67 return L"NuBus";
68
69 case PCMCIABus:
70 return L"PCMCIABus";
71
72 case CBus:
73 return L"CBus";
74
75 case MPIBus:
76 return L"MPIBus";
77
78 case MPSABus:
79 return L"MPSABus";
80
81 case ProcessorInternal:
82 return L"ProcessorInternal";
83
84 case PNPISABus:
85 return L"PNPISABus";
86
87 case PNPBus:
88 return L"PNPBus";
89
90 case Vmcs:
91 return L"Vmcs";
92
93 default:
94 DPRINT1("Invalid bus type: %d\n", IfType);
95 return NULL;
96 }
97 }
98
99 /* PUBLIC FUNCTIONS **********************************************************/
100
101 /*
102 * @implemented
103 */
104 NTSTATUS
105 NTAPI
106 IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
107 IN INTERFACE_TYPE LegacyBusType,
108 IN ULONG BusNumber,
109 IN ULONG SlotNumber,
110 IN PCM_RESOURCE_LIST ResourceList,
111 IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements OPTIONAL,
112 IN BOOLEAN ResourceAssigned,
113 IN OUT PDEVICE_OBJECT *DeviceObject OPTIONAL)
114 {
115 PDEVICE_NODE DeviceNode;
116 PDEVICE_OBJECT Pdo;
117 NTSTATUS Status;
118 HANDLE InstanceKey;
119 ULONG RequiredLength;
120 UNICODE_STRING ValueName, ServiceName;
121 WCHAR HardwareId[256];
122 PWCHAR IfString;
123 ULONG IdLength;
124
125 DPRINT("IoReportDetectedDevice (DeviceObject %p, *DeviceObject %p)\n",
126 DeviceObject, DeviceObject ? *DeviceObject : NULL);
127
128 /* Create the service name (eg. ACPI_HAL) */
129 ServiceName.Buffer = DriverObject->DriverName.Buffer +
130 sizeof(DRIVER_ROOT_NAME) / sizeof(WCHAR) - 1;
131 ServiceName.Length = DriverObject->DriverName.Length -
132 sizeof(DRIVER_ROOT_NAME) + sizeof(WCHAR);
133 ServiceName.MaximumLength = ServiceName.Length;
134
135 /* If the interface type is unknown, treat it as internal */
136 if (LegacyBusType == InterfaceTypeUndefined)
137 LegacyBusType = Internal;
138
139 /* Get the string equivalent of the interface type */
140 IfString = IopGetInterfaceTypeString(LegacyBusType);
141
142 /* If NULL is returned then it's a bad type */
143 if (!IfString)
144 return STATUS_INVALID_PARAMETER;
145
146 /* We use the caller's PDO if they supplied one */
147 if (DeviceObject && *DeviceObject)
148 {
149 Pdo = *DeviceObject;
150 DeviceNode = IopGetDeviceNode(*DeviceObject);
151 }
152 else
153 {
154 /* Create the PDO */
155 Status = PnpRootCreateDevice(&ServiceName,
156 &Pdo);
157 if (!NT_SUCCESS(Status))
158 {
159 DPRINT("PnpRootCreateDevice() failed (Status 0x%08lx)\n", Status);
160 return Status;
161 }
162
163 /* Create the device node for the new PDO */
164 Status = IopCreateDeviceNode(IopRootDeviceNode,
165 Pdo,
166 NULL,
167 &DeviceNode);
168
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT("IopCreateDeviceNode() failed (Status 0x%08lx)\n", Status);
172 return Status;
173 }
174 }
175
176 /* We don't call AddDevice for devices reported this way */
177 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
178
179 /* We don't send IRP_MN_START_DEVICE */
180 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
181
182 /* This is a legacy driver for this device */
183 IopDeviceNodeSetFlag(DeviceNode, DNF_LEGACY_DRIVER);
184
185 /* Perform a manual configuration of our device */
186 IopActionInterrogateDeviceStack(DeviceNode, DeviceNode->Parent);
187 IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
188
189 /* Open a handle to the instance path key */
190 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, &InstanceKey);
191 if (!NT_SUCCESS(Status))
192 return Status;
193
194 /* Add DETECTEDInterfaceType\DriverName */
195 IdLength = 0;
196 IdLength += swprintf(&HardwareId[IdLength],
197 L"DETECTED%ls\\%wZ",
198 IfString,
199 &ServiceName);
200 HardwareId[IdLength++] = UNICODE_NULL;
201
202 /* Add DETECTED\DriverName */
203 IdLength += swprintf(&HardwareId[IdLength],
204 L"DETECTED\\%wZ",
205 &ServiceName);
206 HardwareId[IdLength++] = UNICODE_NULL;
207
208 /* Terminate the string with another null */
209 HardwareId[IdLength] = UNICODE_NULL;
210
211 /* Store the value for CompatibleIDs */
212 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
213 Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR));
214 if (!NT_SUCCESS(Status))
215 {
216 DPRINT("Failed to write the compatible IDs: 0x%x\n", Status);
217 ZwClose(InstanceKey);
218 return Status;
219 }
220
221 /* Add a hardware ID if the driver didn't report one */
222 RtlInitUnicodeString(&ValueName, L"HardwareID");
223 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
224 {
225 /* Just use our most specific compatible ID */
226 IdLength = 0;
227 IdLength += swprintf(&HardwareId[IdLength],
228 L"DETECTED%ls\\%wZ",
229 IfString,
230 &ServiceName);
231 HardwareId[++IdLength] = UNICODE_NULL;
232
233 /* Write the value to the registry */
234 Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_SZ, HardwareId, IdLength * sizeof(WCHAR));
235 if (!NT_SUCCESS(Status))
236 {
237 DPRINT("Failed to write the hardware ID: 0x%x\n", Status);
238 ZwClose(InstanceKey);
239 return Status;
240 }
241 }
242
243 /* Assign the resources to the device node */
244 DeviceNode->BootResources = ResourceList;
245 DeviceNode->ResourceRequirements = ResourceRequirements;
246
247 /* Set appropriate flags */
248 if (DeviceNode->BootResources)
249 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
250
251 if (DeviceNode->ResourceRequirements)
252 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_REPORTED);
253 else
254 IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED);
255
256 /* Write the resource information to the registry */
257 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
258
259 /* Close the instance key handle */
260 ZwClose(InstanceKey);
261
262 /* If the caller didn't get the resources assigned for us, do it now */
263 if (!ResourceAssigned)
264 {
265 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
266 Status = IopAssignDeviceResources(DeviceNode, &RequiredLength);
267 if (NT_SUCCESS(Status))
268 {
269 Status = IopTranslateDeviceResources(DeviceNode, RequiredLength);
270 if (NT_SUCCESS(Status))
271 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
272 }
273 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
274
275 /* See if we failed */
276 if (!NT_SUCCESS(Status))
277 {
278 DPRINT("Assigning resources failed: 0x%x\n", Status);
279 return Status;
280 }
281 }
282
283 /* Report the device's enumeration to umpnpmgr */
284 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
285 &DeviceNode->InstancePath);
286
287 /* Report the device's arrival to umpnpmgr */
288 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
289 &DeviceNode->InstancePath);
290
291 DPRINT1("Reported device: %S (%wZ)\n", HardwareId, &DeviceNode->InstancePath);
292
293 /* Return the PDO */
294 if (DeviceObject) *DeviceObject = Pdo;
295
296 return STATUS_SUCCESS;
297 }
298
299 /*
300 * @unimplemented
301 */
302 NTSTATUS
303 NTAPI
304 IoReportResourceForDetection(IN PDRIVER_OBJECT DriverObject,
305 IN PCM_RESOURCE_LIST DriverList OPTIONAL,
306 IN ULONG DriverListSize OPTIONAL,
307 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
308 IN PCM_RESOURCE_LIST DeviceList OPTIONAL,
309 IN ULONG DeviceListSize OPTIONAL,
310 OUT PBOOLEAN ConflictDetected)
311 {
312 static int warned = 0;
313 if (!warned)
314 {
315 DPRINT1("IoReportResourceForDetection partly implemented\n");
316 warned = 1;
317 }
318
319 *ConflictDetected = FALSE;
320
321 if (PopSystemPowerDeviceNode && DriverListSize > 0)
322 {
323 /* We hope legacy devices will be enumerated by ACPI */
324 *ConflictDetected = TRUE;
325 return STATUS_CONFLICTING_ADDRESSES;
326 }
327
328 return STATUS_SUCCESS;
329 }
330
331 VOID
332 NTAPI
333 IopSetEvent(IN PVOID Context)
334 {
335 PKEVENT Event = Context;
336
337 /* Set the event */
338 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
339 }
340
341 /*
342 * @unimplemented
343 */
344 NTSTATUS
345 NTAPI
346 IoReportTargetDeviceChange(IN PDEVICE_OBJECT PhysicalDeviceObject,
347 IN PVOID NotificationStructure)
348 {
349 UNIMPLEMENTED;
350 return STATUS_NOT_IMPLEMENTED;
351 }
352
353 /*
354 * @unimplemented
355 */
356 NTSTATUS
357 NTAPI
358 IoReportTargetDeviceChangeAsynchronous(IN PDEVICE_OBJECT PhysicalDeviceObject,
359 IN PVOID NotificationStructure,
360 IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL,
361 IN PVOID Context OPTIONAL)
362 {
363 UNIMPLEMENTED;
364 return STATUS_NOT_IMPLEMENTED;
365 }