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