ntoskrnl: Quiet down failed class installer debug message.
[wine.git] / dlls / ntoskrnl.exe / pnp.c
blob9e4c2c1416a6dd886d500758465d3f43e4d62f3b
1 /*
2 * Plug and Play
4 * Copyright 2016 Sebastian Lackner
5 * Copyright 2016 Aric Stewart for CodeWeavers
6 * Copyright 2019 Zebediah Figura
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #define NONAMELESSUNION
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winioctl.h"
32 #include "winreg.h"
33 #include "winuser.h"
34 #include "winsvc.h"
35 #include "winternl.h"
36 #include "setupapi.h"
37 #include "cfgmgr32.h"
38 #include "dbt.h"
39 #include "ddk/wdm.h"
40 #include "ddk/ntifs.h"
41 #include "wine/debug.h"
42 #include "wine/heap.h"
43 #include "wine/rbtree.h"
45 #include "ntoskrnl_private.h"
47 #include "initguid.h"
48 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
50 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
52 #define MAX_SERVICE_NAME 260
54 struct device_interface
56 struct wine_rb_entry entry;
58 UNICODE_STRING symbolic_link;
59 DEVICE_OBJECT *device;
60 GUID interface_class;
61 BOOL enabled;
64 static int interface_rb_compare( const void *key, const struct wine_rb_entry *entry)
66 const struct device_interface *iface = WINE_RB_ENTRY_VALUE( entry, const struct device_interface, entry );
67 const UNICODE_STRING *k = key;
69 return RtlCompareUnicodeString( k, &iface->symbolic_link, FALSE );
72 static struct wine_rb_tree device_interfaces = { interface_rb_compare };
74 static NTSTATUS WINAPI internal_complete( DEVICE_OBJECT *device, IRP *irp, void *context )
76 HANDLE event = context;
77 SetEvent( event );
78 return STATUS_MORE_PROCESSING_REQUIRED;
81 static NTSTATUS send_device_irp( DEVICE_OBJECT *device, IRP *irp, ULONG_PTR *info )
83 HANDLE event = CreateEventA( NULL, FALSE, FALSE, NULL );
84 DEVICE_OBJECT *toplevel_device;
85 NTSTATUS status;
87 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
88 IoSetCompletionRoutine( irp, internal_complete, event, TRUE, TRUE, TRUE );
90 toplevel_device = IoGetAttachedDeviceReference( device );
91 status = IoCallDriver( toplevel_device, irp );
93 if (status == STATUS_PENDING)
94 WaitForSingleObject( event, INFINITE );
96 status = irp->IoStatus.u.Status;
97 if (info)
98 *info = irp->IoStatus.Information;
99 IoCompleteRequest( irp, IO_NO_INCREMENT );
100 ObDereferenceObject( toplevel_device );
101 CloseHandle( event );
102 return status;
105 static NTSTATUS get_device_id( DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR **id )
107 IO_STACK_LOCATION *irpsp;
108 IO_STATUS_BLOCK irp_status;
109 IRP *irp;
111 device = IoGetAttachedDevice( device );
113 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status )))
114 return STATUS_NO_MEMORY;
116 irpsp = IoGetNextIrpStackLocation( irp );
117 irpsp->MinorFunction = IRP_MN_QUERY_ID;
118 irpsp->Parameters.QueryId.IdType = type;
120 return send_device_irp( device, irp, (ULONG_PTR *)id );
123 static NTSTATUS send_pnp_irp( DEVICE_OBJECT *device, UCHAR minor )
125 IO_STACK_LOCATION *irpsp;
126 IO_STATUS_BLOCK irp_status;
127 IRP *irp;
129 device = IoGetAttachedDevice( device );
131 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status )))
132 return STATUS_NO_MEMORY;
134 irpsp = IoGetNextIrpStackLocation( irp );
135 irpsp->MinorFunction = minor;
137 irpsp->Parameters.StartDevice.AllocatedResources = NULL;
138 irpsp->Parameters.StartDevice.AllocatedResourcesTranslated = NULL;
140 return send_device_irp( device, irp, NULL );
143 static NTSTATUS get_device_instance_id( DEVICE_OBJECT *device, WCHAR *buffer )
145 static const WCHAR backslashW[] = {'\\',0};
146 NTSTATUS status;
147 WCHAR *id;
149 if ((status = get_device_id( device, BusQueryDeviceID, &id )))
151 ERR("Failed to get device ID, status %#x.\n", status);
152 return status;
155 lstrcpyW( buffer, id );
156 ExFreePool( id );
158 if ((status = get_device_id( device, BusQueryInstanceID, &id )))
160 ERR("Failed to get instance ID, status %#x.\n", status);
161 return status;
164 lstrcatW( buffer, backslashW );
165 lstrcatW( buffer, id );
166 ExFreePool( id );
168 TRACE("Returning ID %s.\n", debugstr_w(buffer));
170 return STATUS_SUCCESS;
173 static NTSTATUS send_power_irp( DEVICE_OBJECT *device, DEVICE_POWER_STATE power )
175 IO_STATUS_BLOCK irp_status;
176 IO_STACK_LOCATION *irpsp;
177 IRP *irp;
179 device = IoGetAttachedDevice( device );
181 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_POWER, device, NULL, 0, NULL, NULL, &irp_status )))
182 return STATUS_NO_MEMORY;
184 irpsp = IoGetNextIrpStackLocation( irp );
185 irpsp->MinorFunction = IRP_MN_SET_POWER;
187 irpsp->Parameters.Power.Type = DevicePowerState;
188 irpsp->Parameters.Power.State.DeviceState = power;
190 return send_device_irp( device, irp, NULL );
193 static void load_function_driver( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
195 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
196 WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(servicesW)];
197 WCHAR driver[MAX_SERVICE_NAME] = {0};
198 DRIVER_OBJECT *driver_obj;
199 UNICODE_STRING string;
200 NTSTATUS status;
202 if (!SetupDiGetDeviceRegistryPropertyW( set, sp_device, SPDRP_SERVICE,
203 NULL, (BYTE *)driver, sizeof(driver), NULL ))
205 WARN("No driver registered for device %p.\n", device);
206 return;
209 lstrcpyW( buffer, servicesW );
210 lstrcatW( buffer, driver );
211 RtlInitUnicodeString( &string, buffer );
212 status = ZwLoadDriver( &string );
213 if (status != STATUS_SUCCESS && status != STATUS_IMAGE_ALREADY_LOADED)
215 ERR("Failed to load driver %s, status %#x.\n", debugstr_w(driver), status);
216 return;
219 lstrcpyW( buffer, driverW );
220 lstrcatW( buffer, driver );
221 RtlInitUnicodeString( &string, buffer );
222 if (ObReferenceObjectByName( &string, OBJ_CASE_INSENSITIVE, NULL,
223 0, NULL, KernelMode, NULL, (void **)&driver_obj ) != STATUS_SUCCESS)
225 ERR("Failed to locate loaded driver %s.\n", debugstr_w(driver));
226 return;
229 TRACE("Calling AddDevice routine %p.\n", driver_obj->DriverExtension->AddDevice);
230 if (driver_obj->DriverExtension->AddDevice)
231 status = driver_obj->DriverExtension->AddDevice( driver_obj, device );
232 else
233 status = STATUS_NOT_IMPLEMENTED;
234 TRACE("AddDevice routine %p returned %#x.\n", driver_obj->DriverExtension->AddDevice, status);
236 ObDereferenceObject( driver_obj );
238 if (status != STATUS_SUCCESS)
239 ERR("AddDevice failed for driver %s, status %#x.\n", debugstr_w(driver), status);
242 /* Return the total number of characters in a REG_MULTI_SZ string, including
243 * the final terminating null. */
244 static size_t sizeof_multiszW( const WCHAR *str )
246 const WCHAR *p;
247 for (p = str; *p; p += lstrlenW(p) + 1);
248 return p + 1 - str;
251 /* This does almost the same thing as UpdateDriverForPlugAndPlayDevices(),
252 * except that we don't know the INF path beforehand. */
253 static BOOL install_device_driver( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
255 static const DWORD dif_list[] =
257 DIF_REGISTERDEVICE,
258 DIF_SELECTBESTCOMPATDRV,
259 DIF_ALLOW_INSTALL,
260 DIF_INSTALLDEVICEFILES,
261 DIF_REGISTER_COINSTALLERS,
262 DIF_INSTALLINTERFACES,
263 DIF_INSTALLDEVICE,
264 DIF_NEWDEVICEWIZARD_FINISHINSTALL,
267 NTSTATUS status;
268 unsigned int i;
269 WCHAR *ids;
271 if ((status = get_device_id( device, BusQueryHardwareIDs, &ids )) || !ids)
273 ERR("Failed to get hardware IDs, status %#x.\n", status);
274 return FALSE;
277 SetupDiSetDeviceRegistryPropertyW( set, sp_device, SPDRP_HARDWAREID, (BYTE *)ids,
278 sizeof_multiszW( ids ) * sizeof(WCHAR) );
279 ExFreePool( ids );
281 if ((status = get_device_id( device, BusQueryCompatibleIDs, &ids )) || !ids)
283 ERR("Failed to get compatible IDs, status %#x.\n", status);
284 return FALSE;
287 SetupDiSetDeviceRegistryPropertyW( set, sp_device, SPDRP_COMPATIBLEIDS, (BYTE *)ids,
288 sizeof_multiszW( ids ) * sizeof(WCHAR) );
289 ExFreePool( ids );
291 if (!SetupDiBuildDriverInfoList( set, sp_device, SPDIT_COMPATDRIVER ))
293 ERR("Failed to build compatible driver list, error %#x.\n", GetLastError());
294 return FALSE;
297 for (i = 0; i < ARRAY_SIZE(dif_list); ++i)
299 if (!SetupDiCallClassInstaller(dif_list[i], set, sp_device) && GetLastError() != ERROR_DI_DO_DEFAULT)
301 WARN("Install function %#x failed, error %#x.\n", dif_list[i], GetLastError());
302 return FALSE;
306 return TRUE;
309 /* Load the function driver for a newly created PDO, if one is present, and
310 * send IRPs to start the device. */
311 static void start_device( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
313 load_function_driver( device, set, sp_device );
314 if (device->DriverObject)
316 send_pnp_irp( device, IRP_MN_START_DEVICE );
317 send_power_irp( device, PowerDeviceD0 );
321 static void enumerate_new_device( DEVICE_OBJECT *device, HDEVINFO set )
323 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
325 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
326 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
327 BOOL need_driver = TRUE;
328 HKEY key;
330 if (get_device_instance_id( device, device_instance_id ))
331 return;
333 if (!SetupDiCreateDeviceInfoW( set, device_instance_id, &GUID_NULL, NULL, NULL, 0, &sp_device )
334 && !SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device ))
336 ERR("Failed to create or open device %s, error %#x.\n", debugstr_w(device_instance_id), GetLastError());
337 SetupDiDestroyDeviceInfoList( set );
338 return;
341 TRACE("Creating new device %s.\n", debugstr_w(device_instance_id));
343 /* Check if the device already has a driver registered; if not, find one
344 * and install it. */
345 key = SetupDiOpenDevRegKey( set, &sp_device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ );
346 if (key != INVALID_HANDLE_VALUE)
348 if (!RegQueryValueExW( key, infpathW, NULL, NULL, NULL, NULL ))
349 need_driver = FALSE;
350 RegCloseKey( key );
353 if (need_driver && !install_device_driver( device, set, &sp_device ))
355 SetupDiDestroyDeviceInfoList( set );
356 return;
359 start_device( device, set, &sp_device );
362 static void remove_device( DEVICE_OBJECT *device )
364 struct wine_device *wine_device = CONTAINING_RECORD(device, struct wine_device, device_obj);
366 TRACE("Removing device %p.\n", device);
368 if (wine_device->children)
370 ULONG i;
371 for (i = 0; i < wine_device->children->Count; ++i)
372 remove_device( wine_device->children->Objects[i] );
375 send_power_irp( device, PowerDeviceD3 );
376 send_pnp_irp( device, IRP_MN_SURPRISE_REMOVAL );
377 send_pnp_irp( device, IRP_MN_REMOVE_DEVICE );
380 static BOOL device_in_list( const DEVICE_RELATIONS *list, const DEVICE_OBJECT *device )
382 ULONG i;
383 for (i = 0; i < list->Count; ++i)
385 if (list->Objects[i] == device)
386 return TRUE;
388 return FALSE;
391 static void handle_bus_relations( DEVICE_OBJECT *parent )
393 struct wine_device *wine_parent = CONTAINING_RECORD(parent, struct wine_device, device_obj);
394 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
395 DEVICE_RELATIONS *relations;
396 IO_STATUS_BLOCK irp_status;
397 IO_STACK_LOCATION *irpsp;
398 NTSTATUS status;
399 HDEVINFO set;
400 IRP *irp;
401 ULONG i;
403 TRACE( "(%p)\n", parent );
405 set = SetupDiCreateDeviceInfoList( NULL, NULL );
407 parent = IoGetAttachedDevice( parent );
409 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, parent, NULL, 0, NULL, NULL, &irp_status )))
411 SetupDiDestroyDeviceInfoList( set );
412 return;
415 irpsp = IoGetNextIrpStackLocation( irp );
416 irpsp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
417 irpsp->Parameters.QueryDeviceRelations.Type = BusRelations;
418 if ((status = send_device_irp( parent, irp, (ULONG_PTR *)&relations )))
420 ERR("Failed to enumerate child devices, status %#x.\n", status);
421 SetupDiDestroyDeviceInfoList( set );
422 return;
425 TRACE("Got %u devices.\n", relations->Count);
427 for (i = 0; i < relations->Count; ++i)
429 DEVICE_OBJECT *child = relations->Objects[i];
431 if (!wine_parent->children || !device_in_list( wine_parent->children, child ))
433 TRACE("Adding new device %p.\n", child);
434 enumerate_new_device( child, set );
438 if (wine_parent->children)
440 for (i = 0; i < wine_parent->children->Count; ++i)
442 DEVICE_OBJECT *child = wine_parent->children->Objects[i];
444 if (!device_in_list( relations, child ))
446 TRACE("Removing device %p.\n", child);
447 remove_device( child );
449 ObDereferenceObject( child );
453 ExFreePool( wine_parent->children );
454 wine_parent->children = relations;
456 SetupDiDestroyDeviceInfoList( set );
459 /***********************************************************************
460 * IoInvalidateDeviceRelations (NTOSKRNL.EXE.@)
462 void WINAPI IoInvalidateDeviceRelations( DEVICE_OBJECT *device_object, DEVICE_RELATION_TYPE type )
464 TRACE("device %p, type %#x.\n", device_object, type);
466 switch (type)
468 case BusRelations:
469 handle_bus_relations( device_object );
470 break;
471 default:
472 FIXME("Unhandled relation %#x.\n", type);
473 break;
477 /***********************************************************************
478 * IoGetDeviceProperty (NTOSKRNL.EXE.@)
480 NTSTATUS WINAPI IoGetDeviceProperty( DEVICE_OBJECT *device, DEVICE_REGISTRY_PROPERTY property,
481 ULONG length, void *buffer, ULONG *needed )
483 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
484 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
485 DWORD sp_property = -1;
486 NTSTATUS status;
487 HDEVINFO set;
489 TRACE("device %p, property %u, length %u, buffer %p, needed %p.\n",
490 device, property, length, buffer, needed);
492 switch (property)
494 case DevicePropertyEnumeratorName:
496 WCHAR *id, *ptr;
498 status = get_device_id( device, BusQueryInstanceID, &id );
499 if (status != STATUS_SUCCESS)
501 ERR("Failed to get instance ID, status %#x.\n", status);
502 break;
505 wcsupr( id );
506 ptr = wcschr( id, '\\' );
507 if (ptr) *ptr = 0;
509 *needed = sizeof(WCHAR) * (lstrlenW(id) + 1);
510 if (length >= *needed)
511 memcpy( buffer, id, *needed );
512 else
513 status = STATUS_BUFFER_TOO_SMALL;
515 ExFreePool( id );
516 return status;
518 case DevicePropertyPhysicalDeviceObjectName:
520 ULONG used_len, len = length + sizeof(OBJECT_NAME_INFORMATION);
521 OBJECT_NAME_INFORMATION *name = HeapAlloc(GetProcessHeap(), 0, len);
522 HANDLE handle;
524 status = ObOpenObjectByPointer( device, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &handle );
525 if (!status)
527 status = NtQueryObject( handle, ObjectNameInformation, name, len, &used_len );
528 NtClose( handle );
530 if (status == STATUS_SUCCESS)
532 /* Ensure room for NULL termination */
533 if (length >= name->Name.MaximumLength)
534 memcpy(buffer, name->Name.Buffer, name->Name.MaximumLength);
535 else
536 status = STATUS_BUFFER_TOO_SMALL;
537 *needed = name->Name.MaximumLength;
539 else
541 if (status == STATUS_INFO_LENGTH_MISMATCH ||
542 status == STATUS_BUFFER_OVERFLOW)
544 status = STATUS_BUFFER_TOO_SMALL;
545 *needed = used_len - sizeof(OBJECT_NAME_INFORMATION);
547 else
548 *needed = 0;
550 HeapFree(GetProcessHeap(), 0, name);
551 return status;
553 case DevicePropertyDeviceDescription:
554 sp_property = SPDRP_DEVICEDESC;
555 break;
556 case DevicePropertyHardwareID:
557 sp_property = SPDRP_HARDWAREID;
558 break;
559 case DevicePropertyCompatibleIDs:
560 sp_property = SPDRP_COMPATIBLEIDS;
561 break;
562 case DevicePropertyClassName:
563 sp_property = SPDRP_CLASS;
564 break;
565 case DevicePropertyClassGuid:
566 sp_property = SPDRP_CLASSGUID;
567 break;
568 case DevicePropertyManufacturer:
569 sp_property = SPDRP_MFG;
570 break;
571 case DevicePropertyFriendlyName:
572 sp_property = SPDRP_FRIENDLYNAME;
573 break;
574 case DevicePropertyLocationInformation:
575 sp_property = SPDRP_LOCATION_INFORMATION;
576 break;
577 case DevicePropertyBusTypeGuid:
578 sp_property = SPDRP_BUSTYPEGUID;
579 break;
580 case DevicePropertyLegacyBusType:
581 sp_property = SPDRP_LEGACYBUSTYPE;
582 break;
583 case DevicePropertyBusNumber:
584 sp_property = SPDRP_BUSNUMBER;
585 break;
586 case DevicePropertyAddress:
587 sp_property = SPDRP_ADDRESS;
588 break;
589 case DevicePropertyUINumber:
590 sp_property = SPDRP_UI_NUMBER;
591 break;
592 case DevicePropertyInstallState:
593 sp_property = SPDRP_INSTALL_STATE;
594 break;
595 case DevicePropertyRemovalPolicy:
596 sp_property = SPDRP_REMOVAL_POLICY;
597 break;
598 default:
599 FIXME("Unhandled property %u.\n", property);
600 return STATUS_NOT_IMPLEMENTED;
603 if ((status = get_device_instance_id( device, device_instance_id )))
604 return status;
606 if ((set = SetupDiCreateDeviceInfoList( &GUID_NULL, NULL )) == INVALID_HANDLE_VALUE)
608 ERR("Failed to create device list, error %#x.\n", GetLastError());
609 return GetLastError();
612 if (!SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device))
614 ERR("Failed to open device, error %#x.\n", GetLastError());
615 SetupDiDestroyDeviceInfoList( set );
616 return GetLastError();
619 if (SetupDiGetDeviceRegistryPropertyW( set, &sp_device, sp_property, NULL, buffer, length, needed ))
620 status = STATUS_SUCCESS;
621 else
622 status = GetLastError();
624 SetupDiDestroyDeviceInfoList( set );
626 return status;
629 static NTSTATUS create_device_symlink( DEVICE_OBJECT *device, UNICODE_STRING *symlink_name )
631 UNICODE_STRING device_nameU;
632 WCHAR *device_name;
633 ULONG len = 0;
634 NTSTATUS ret;
636 ret = IoGetDeviceProperty( device, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &len );
637 if (ret != STATUS_BUFFER_TOO_SMALL)
638 return ret;
640 device_name = heap_alloc( len );
641 ret = IoGetDeviceProperty( device, DevicePropertyPhysicalDeviceObjectName, len, device_name, &len );
642 if (ret)
644 heap_free( device_name );
645 return ret;
648 RtlInitUnicodeString( &device_nameU, device_name );
649 ret = IoCreateSymbolicLink( symlink_name, &device_nameU );
650 heap_free( device_name );
651 return ret;
654 /***********************************************************************
655 * IoSetDeviceInterfaceState (NTOSKRNL.EXE.@)
657 NTSTATUS WINAPI IoSetDeviceInterfaceState( UNICODE_STRING *name, BOOLEAN enable )
659 static const WCHAR DeviceClassesW[] = {'\\','R','E','G','I','S','T','R','Y','\\',
660 'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
661 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
662 'C','o','n','t','r','o','l','\\',
663 'D','e','v','i','c','e','C','l','a','s','s','e','s','\\',0};
664 static const WCHAR controlW[] = {'C','o','n','t','r','o','l',0};
665 static const WCHAR linkedW[] = {'L','i','n','k','e','d',0};
666 static const WCHAR slashW[] = {'\\',0};
667 static const WCHAR hashW[] = {'#',0};
669 size_t namelen = name->Length / sizeof(WCHAR);
670 DEV_BROADCAST_DEVICEINTERFACE_W *broadcast;
671 struct device_interface *iface;
672 HANDLE iface_key, control_key;
673 OBJECT_ATTRIBUTES attr = {0};
674 struct wine_rb_entry *entry;
675 WCHAR *path, *refstr, *p;
676 UNICODE_STRING string;
677 DWORD data = enable;
678 NTSTATUS ret;
679 ULONG len;
681 TRACE("device %s, enable %u.\n", debugstr_us(name), enable);
683 entry = wine_rb_get( &device_interfaces, name );
684 if (!entry)
685 return STATUS_OBJECT_NAME_NOT_FOUND;
687 iface = WINE_RB_ENTRY_VALUE( entry, struct device_interface, entry );
689 if (!enable && !iface->enabled)
690 return STATUS_OBJECT_NAME_NOT_FOUND;
692 if (enable && iface->enabled)
693 return STATUS_OBJECT_NAME_EXISTS;
695 for (p = name->Buffer + 4, refstr = NULL; p < name->Buffer + namelen; p++)
696 if (*p == '\\') refstr = p;
697 if (!refstr) refstr = p;
699 len = lstrlenW(DeviceClassesW) + 38 + 1 + namelen + 2 + 1;
701 if (!(path = heap_alloc( len * sizeof(WCHAR) )))
702 return STATUS_NO_MEMORY;
704 lstrcpyW( path, DeviceClassesW );
705 lstrcpynW( path + lstrlenW( path ), refstr - 38, 39 );
706 lstrcatW( path, slashW );
707 p = path + lstrlenW( path );
708 lstrcpynW( path + lstrlenW( path ), name->Buffer, (refstr - name->Buffer) + 1 );
709 p[0] = p[1] = p[3] = '#';
710 lstrcatW( path, slashW );
711 lstrcatW( path, hashW );
712 if (refstr < name->Buffer + namelen)
713 lstrcpynW( path + lstrlenW( path ), refstr, name->Buffer + namelen - refstr + 1 );
715 attr.Length = sizeof(attr);
716 attr.ObjectName = &string;
717 RtlInitUnicodeString( &string, path );
718 ret = NtOpenKey( &iface_key, KEY_CREATE_SUB_KEY, &attr );
719 heap_free(path);
720 if (ret)
721 return ret;
723 attr.RootDirectory = iface_key;
724 RtlInitUnicodeString( &string, controlW );
725 ret = NtCreateKey( &control_key, KEY_SET_VALUE, &attr, 0, NULL, REG_OPTION_VOLATILE, NULL );
726 NtClose( iface_key );
727 if (ret)
728 return ret;
730 RtlInitUnicodeString( &string, linkedW );
731 ret = NtSetValueKey( control_key, &string, 0, REG_DWORD, &data, sizeof(data) );
732 if (ret)
734 NtClose( control_key );
735 return ret;
738 if (enable)
739 ret = create_device_symlink( iface->device, name );
740 else
741 ret = IoDeleteSymbolicLink( name );
742 if (ret)
744 NtDeleteValueKey( control_key, &string );
745 NtClose( control_key );
746 return ret;
749 iface->enabled = enable;
751 len = offsetof(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name[namelen + 1]);
753 if ((broadcast = heap_alloc( len )))
755 broadcast->dbcc_size = len;
756 broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
757 broadcast->dbcc_classguid = iface->interface_class;
758 lstrcpynW( broadcast->dbcc_name, name->Buffer, namelen + 1 );
759 BroadcastSystemMessageW( BSF_FORCEIFHUNG | BSF_QUERY, NULL, WM_DEVICECHANGE,
760 enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, (LPARAM)broadcast );
762 heap_free( broadcast );
764 return ret;
767 /***********************************************************************
768 * IoRegisterDeviceInterface (NTOSKRNL.EXE.@)
770 NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *class_guid,
771 UNICODE_STRING *refstr, UNICODE_STRING *symbolic_link)
773 SP_DEVICE_INTERFACE_DATA sp_iface = {sizeof(sp_iface)};
774 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
775 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
776 SP_DEVICE_INTERFACE_DETAIL_DATA_W *data;
777 NTSTATUS status = STATUS_SUCCESS;
778 UNICODE_STRING device_path;
779 struct device_interface *iface;
780 struct wine_rb_entry *entry;
781 DWORD required;
782 HDEVINFO set;
784 TRACE("device %p, class_guid %s, refstr %s, symbolic_link %p.\n",
785 device, debugstr_guid(class_guid), debugstr_us(refstr), symbolic_link);
787 if ((status = get_device_instance_id( device, device_instance_id )))
788 return status;
790 set = SetupDiGetClassDevsW( class_guid, NULL, NULL, DIGCF_DEVICEINTERFACE );
791 if (set == INVALID_HANDLE_VALUE) return STATUS_UNSUCCESSFUL;
793 if (!SetupDiCreateDeviceInfoW( set, device_instance_id, class_guid, NULL, NULL, 0, &sp_device )
794 && !SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device ))
796 ERR("Failed to create device %s, error %#x.\n", debugstr_w(device_instance_id), GetLastError());
797 return GetLastError();
800 if (!SetupDiCreateDeviceInterfaceW( set, &sp_device, class_guid, refstr ? refstr->Buffer : NULL, 0, &sp_iface ))
801 return STATUS_UNSUCCESSFUL;
803 required = 0;
804 SetupDiGetDeviceInterfaceDetailW( set, &sp_iface, NULL, 0, &required, NULL );
805 if (required == 0) return STATUS_UNSUCCESSFUL;
807 data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, required );
808 data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
810 if (!SetupDiGetDeviceInterfaceDetailW( set, &sp_iface, data, required, NULL, NULL ))
812 HeapFree( GetProcessHeap(), 0, data );
813 return STATUS_UNSUCCESSFUL;
816 data->DevicePath[1] = '?';
817 TRACE("Returning path %s.\n", debugstr_w(data->DevicePath));
818 RtlCreateUnicodeString( &device_path, data->DevicePath);
820 entry = wine_rb_get( &device_interfaces, &device_path );
821 if (entry)
823 iface = WINE_RB_ENTRY_VALUE( entry, struct device_interface, entry );
824 if (iface->enabled)
825 ERR("Device interface %s is still enabled.\n", debugstr_us(&iface->symbolic_link));
827 else
829 iface = heap_alloc_zero( sizeof(struct device_interface) );
830 RtlCreateUnicodeString(&iface->symbolic_link, data->DevicePath);
831 if (wine_rb_put( &device_interfaces, &iface->symbolic_link, &iface->entry ))
832 ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface->symbolic_link));
835 iface->device = device;
836 iface->interface_class = *class_guid;
837 if (symbolic_link)
838 RtlCreateUnicodeString( symbolic_link, data->DevicePath);
840 HeapFree( GetProcessHeap(), 0, data );
842 RtlFreeUnicodeString( &device_path );
844 return status;
847 /***********************************************************************
848 * IoOpenDeviceRegistryKey (NTOSKRNL.EXE.@)
850 NTSTATUS WINAPI IoOpenDeviceRegistryKey( DEVICE_OBJECT *device, ULONG type, ACCESS_MASK access, HANDLE *key )
852 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
853 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
854 NTSTATUS status;
855 HDEVINFO set;
857 TRACE("device %p, type %#x, access %#x, key %p.\n", device, type, access, key);
859 if ((status = get_device_instance_id( device, device_instance_id )))
861 ERR("Failed to get device instance ID, error %#x.\n", status);
862 return status;
865 set = SetupDiCreateDeviceInfoList( &GUID_NULL, NULL );
867 SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device );
869 *key = SetupDiOpenDevRegKey( set, &sp_device, DICS_FLAG_GLOBAL, 0, type, access );
870 SetupDiDestroyDeviceInfoList( set );
871 if (*key == INVALID_HANDLE_VALUE)
872 return GetLastError();
873 return STATUS_SUCCESS;
876 /***********************************************************************
877 * PoSetPowerState (NTOSKRNL.EXE.@)
879 POWER_STATE WINAPI PoSetPowerState( DEVICE_OBJECT *device, POWER_STATE_TYPE type, POWER_STATE state)
881 FIXME("device %p, type %u, state %u, stub!\n", device, type, state.DeviceState);
882 return state;
885 /*****************************************************
886 * PoStartNextPowerIrp (NTOSKRNL.EXE.@)
888 void WINAPI PoStartNextPowerIrp( IRP *irp )
890 FIXME("irp %p, stub!\n", irp);
893 /*****************************************************
894 * PoCallDriver (NTOSKRNL.EXE.@)
896 NTSTATUS WINAPI PoCallDriver( DEVICE_OBJECT *device, IRP *irp )
898 TRACE("device %p, irp %p.\n", device, irp);
899 return IoCallDriver( device, irp );
902 static DRIVER_OBJECT *pnp_manager;
904 struct root_pnp_device
906 WCHAR id[MAX_DEVICE_ID_LEN];
907 struct wine_rb_entry entry;
908 DEVICE_OBJECT *device;
911 static int root_pnp_devices_rb_compare( const void *key, const struct wine_rb_entry *entry )
913 const struct root_pnp_device *device = WINE_RB_ENTRY_VALUE( entry, const struct root_pnp_device, entry );
914 const WCHAR *k = key;
916 return wcsicmp( k, device->id );
919 static struct wine_rb_tree root_pnp_devices = { root_pnp_devices_rb_compare };
921 static NTSTATUS WINAPI pnp_manager_device_pnp( DEVICE_OBJECT *device, IRP *irp )
923 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
924 struct root_pnp_device *root_device = device->DeviceExtension;
925 NTSTATUS status;
927 TRACE("device %p, irp %p, minor function %#x.\n", device, irp, stack->MinorFunction);
929 switch (stack->MinorFunction)
931 case IRP_MN_QUERY_DEVICE_RELATIONS:
932 /* The FDO above already handled this, so return the same status. */
933 break;
934 case IRP_MN_START_DEVICE:
935 case IRP_MN_SURPRISE_REMOVAL:
936 case IRP_MN_REMOVE_DEVICE:
937 /* Nothing to do. */
938 irp->IoStatus.u.Status = STATUS_SUCCESS;
939 break;
940 case IRP_MN_QUERY_CAPABILITIES:
941 irp->IoStatus.u.Status = STATUS_SUCCESS;
942 break;
943 case IRP_MN_QUERY_ID:
945 BUS_QUERY_ID_TYPE type = stack->Parameters.QueryId.IdType;
946 WCHAR *id, *p;
948 TRACE("Received IRP_MN_QUERY_ID, type %#x.\n", type);
950 switch (type)
952 case BusQueryDeviceID:
953 p = wcsrchr( root_device->id, '\\' );
954 if ((id = ExAllocatePool( NonPagedPool, (p - root_device->id + 1) * sizeof(WCHAR) )))
956 memcpy( id, root_device->id, (p - root_device->id) * sizeof(WCHAR) );
957 id[p - root_device->id] = 0;
958 irp->IoStatus.Information = (ULONG_PTR)id;
959 irp->IoStatus.u.Status = STATUS_SUCCESS;
961 else
963 irp->IoStatus.Information = 0;
964 irp->IoStatus.u.Status = STATUS_NO_MEMORY;
966 break;
967 case BusQueryInstanceID:
968 p = wcsrchr( root_device->id, '\\' );
969 if ((id = ExAllocatePool( NonPagedPool, (wcslen( p + 1 ) + 1) * sizeof(WCHAR) )))
971 wcscpy( id, p + 1 );
972 irp->IoStatus.Information = (ULONG_PTR)id;
973 irp->IoStatus.u.Status = STATUS_SUCCESS;
975 else
977 irp->IoStatus.Information = 0;
978 irp->IoStatus.u.Status = STATUS_NO_MEMORY;
980 break;
981 default:
982 FIXME("Unhandled IRP_MN_QUERY_ID type %#x.\n", type);
984 break;
986 default:
987 FIXME("Unhandled PnP request %#x.\n", stack->MinorFunction);
990 status = irp->IoStatus.u.Status;
991 IoCompleteRequest( irp, IO_NO_INCREMENT );
992 return status;
995 static NTSTATUS WINAPI pnp_manager_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *keypath )
997 pnp_manager = driver;
998 driver->MajorFunction[IRP_MJ_PNP] = pnp_manager_device_pnp;
999 return STATUS_SUCCESS;
1002 void pnp_manager_start(void)
1004 static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','P','n','p','M','a','n','a','g','e','r',0};
1005 UNICODE_STRING driver_nameU;
1006 NTSTATUS status;
1008 RtlInitUnicodeString( &driver_nameU, driver_nameW );
1009 if ((status = IoCreateDriver( &driver_nameU, pnp_manager_driver_entry )))
1010 ERR("Failed to create PnP manager driver, status %#x.\n", status);
1013 static void destroy_root_pnp_device( struct wine_rb_entry *entry, void *context )
1015 struct root_pnp_device *device = WINE_RB_ENTRY_VALUE(entry, struct root_pnp_device, entry);
1016 remove_device( device->device );
1019 void pnp_manager_stop(void)
1021 wine_rb_destroy( &root_pnp_devices, destroy_root_pnp_device, NULL );
1022 IoDeleteDriver( pnp_manager );
1025 void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
1027 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
1028 static const WCHAR rootW[] = {'R','O','O','T',0};
1029 WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(driverW)], id[MAX_DEVICE_ID_LEN];
1030 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
1031 struct root_pnp_device *pnp_device;
1032 DEVICE_OBJECT *device;
1033 NTSTATUS status;
1034 unsigned int i;
1035 HDEVINFO set;
1037 TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name));
1039 set = SetupDiGetClassDevsW( NULL, rootW, NULL, DIGCF_ALLCLASSES );
1040 if (set == INVALID_HANDLE_VALUE)
1042 ERR("Failed to build device set, error %#x.\n", GetLastError());
1043 return;
1046 for (i = 0; SetupDiEnumDeviceInfo( set, i, &sp_device ); ++i)
1048 if (!SetupDiGetDeviceRegistryPropertyW( set, &sp_device, SPDRP_SERVICE,
1049 NULL, (BYTE *)buffer, sizeof(buffer), NULL )
1050 || lstrcmpiW( buffer, driver_name ))
1052 continue;
1055 SetupDiGetDeviceInstanceIdW( set, &sp_device, id, ARRAY_SIZE(id), NULL );
1057 if (wine_rb_get( &root_pnp_devices, id ))
1058 continue;
1060 TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id));
1062 if ((status = IoCreateDevice( pnp_manager, sizeof(struct root_pnp_device), NULL,
1063 FILE_DEVICE_CONTROLLER, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &device )))
1065 ERR("Failed to create root-enumerated PnP device %s, status %#x.\n", debugstr_w(id), status);
1066 continue;
1069 pnp_device = device->DeviceExtension;
1070 wcscpy( pnp_device->id, id );
1071 pnp_device->device = device;
1072 if (wine_rb_put( &root_pnp_devices, id, &pnp_device->entry ))
1074 ERR("Failed to insert device %s into tree.\n", debugstr_w(id));
1075 IoDeleteDevice( device );
1076 continue;
1079 start_device( device, set, &sp_device );
1082 SetupDiDestroyDeviceInfoList(set);