kernel32: Get rid of the last parameter to PROFILE_CopyEntry().
[wine.git] / dlls / ntoskrnl.exe / pnp.c
blob91b825dffc6eb3b5bc7cb5c858cff2bad13363b4
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/exception.h"
43 #include "wine/heap.h"
44 #include "wine/rbtree.h"
46 #include "ntoskrnl_private.h"
47 #include "plugplay.h"
49 #include "initguid.h"
50 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
52 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
54 #define MAX_SERVICE_NAME 260
56 struct device_interface
58 struct wine_rb_entry entry;
60 UNICODE_STRING symbolic_link;
61 DEVICE_OBJECT *device;
62 GUID interface_class;
63 BOOL enabled;
66 static int interface_rb_compare( const void *key, const struct wine_rb_entry *entry)
68 const struct device_interface *iface = WINE_RB_ENTRY_VALUE( entry, const struct device_interface, entry );
69 const UNICODE_STRING *k = key;
71 return RtlCompareUnicodeString( k, &iface->symbolic_link, FALSE );
74 static struct wine_rb_tree device_interfaces = { interface_rb_compare };
76 static NTSTATUS WINAPI internal_complete( DEVICE_OBJECT *device, IRP *irp, void *context )
78 HANDLE event = context;
79 SetEvent( event );
80 return STATUS_MORE_PROCESSING_REQUIRED;
83 static NTSTATUS send_device_irp( DEVICE_OBJECT *device, IRP *irp, ULONG_PTR *info )
85 HANDLE event = CreateEventA( NULL, FALSE, FALSE, NULL );
86 DEVICE_OBJECT *toplevel_device;
87 NTSTATUS status;
89 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
90 IoSetCompletionRoutine( irp, internal_complete, event, TRUE, TRUE, TRUE );
92 toplevel_device = IoGetAttachedDeviceReference( device );
93 status = IoCallDriver( toplevel_device, irp );
95 if (status == STATUS_PENDING)
96 WaitForSingleObject( event, INFINITE );
98 status = irp->IoStatus.u.Status;
99 if (info)
100 *info = irp->IoStatus.Information;
101 IoCompleteRequest( irp, IO_NO_INCREMENT );
102 ObDereferenceObject( toplevel_device );
103 CloseHandle( event );
104 return status;
107 static NTSTATUS get_device_id( DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR **id )
109 IO_STACK_LOCATION *irpsp;
110 IO_STATUS_BLOCK irp_status;
111 IRP *irp;
113 device = IoGetAttachedDevice( device );
115 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status )))
116 return STATUS_NO_MEMORY;
118 irpsp = IoGetNextIrpStackLocation( irp );
119 irpsp->MinorFunction = IRP_MN_QUERY_ID;
120 irpsp->Parameters.QueryId.IdType = type;
122 return send_device_irp( device, irp, (ULONG_PTR *)id );
125 static NTSTATUS send_pnp_irp( DEVICE_OBJECT *device, UCHAR minor )
127 IO_STACK_LOCATION *irpsp;
128 IO_STATUS_BLOCK irp_status;
129 IRP *irp;
131 device = IoGetAttachedDevice( device );
133 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status )))
134 return STATUS_NO_MEMORY;
136 irpsp = IoGetNextIrpStackLocation( irp );
137 irpsp->MinorFunction = minor;
139 irpsp->Parameters.StartDevice.AllocatedResources = NULL;
140 irpsp->Parameters.StartDevice.AllocatedResourcesTranslated = NULL;
142 return send_device_irp( device, irp, NULL );
145 static NTSTATUS get_device_instance_id( DEVICE_OBJECT *device, WCHAR *buffer )
147 static const WCHAR backslashW[] = {'\\',0};
148 NTSTATUS status;
149 WCHAR *id;
151 if ((status = get_device_id( device, BusQueryDeviceID, &id )))
153 ERR("Failed to get device ID, status %#x.\n", status);
154 return status;
157 lstrcpyW( buffer, id );
158 ExFreePool( id );
160 if ((status = get_device_id( device, BusQueryInstanceID, &id )))
162 ERR("Failed to get instance ID, status %#x.\n", status);
163 return status;
166 lstrcatW( buffer, backslashW );
167 lstrcatW( buffer, id );
168 ExFreePool( id );
170 TRACE("Returning ID %s.\n", debugstr_w(buffer));
172 return STATUS_SUCCESS;
175 static NTSTATUS send_power_irp( DEVICE_OBJECT *device, DEVICE_POWER_STATE power )
177 IO_STATUS_BLOCK irp_status;
178 IO_STACK_LOCATION *irpsp;
179 IRP *irp;
181 device = IoGetAttachedDevice( device );
183 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_POWER, device, NULL, 0, NULL, NULL, &irp_status )))
184 return STATUS_NO_MEMORY;
186 irpsp = IoGetNextIrpStackLocation( irp );
187 irpsp->MinorFunction = IRP_MN_SET_POWER;
189 irpsp->Parameters.Power.Type = DevicePowerState;
190 irpsp->Parameters.Power.State.DeviceState = power;
192 return send_device_irp( device, irp, NULL );
195 static void load_function_driver( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
197 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
198 WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(servicesW)];
199 WCHAR driver[MAX_SERVICE_NAME] = {0};
200 DRIVER_OBJECT *driver_obj;
201 UNICODE_STRING string;
202 NTSTATUS status;
204 if (!SetupDiGetDeviceRegistryPropertyW( set, sp_device, SPDRP_SERVICE,
205 NULL, (BYTE *)driver, sizeof(driver), NULL ))
207 WARN("No driver registered for device %p.\n", device);
208 return;
211 lstrcpyW( buffer, servicesW );
212 lstrcatW( buffer, driver );
213 RtlInitUnicodeString( &string, buffer );
214 status = ZwLoadDriver( &string );
215 if (status != STATUS_SUCCESS && status != STATUS_IMAGE_ALREADY_LOADED)
217 ERR("Failed to load driver %s, status %#x.\n", debugstr_w(driver), status);
218 return;
221 lstrcpyW( buffer, driverW );
222 lstrcatW( buffer, driver );
223 RtlInitUnicodeString( &string, buffer );
224 if (ObReferenceObjectByName( &string, OBJ_CASE_INSENSITIVE, NULL,
225 0, NULL, KernelMode, NULL, (void **)&driver_obj ) != STATUS_SUCCESS)
227 ERR("Failed to locate loaded driver %s.\n", debugstr_w(driver));
228 return;
231 TRACE("Calling AddDevice routine %p.\n", driver_obj->DriverExtension->AddDevice);
232 if (driver_obj->DriverExtension->AddDevice)
233 status = driver_obj->DriverExtension->AddDevice( driver_obj, device );
234 else
235 status = STATUS_NOT_IMPLEMENTED;
236 TRACE("AddDevice routine %p returned %#x.\n", driver_obj->DriverExtension->AddDevice, status);
238 ObDereferenceObject( driver_obj );
240 if (status != STATUS_SUCCESS)
241 ERR("AddDevice failed for driver %s, status %#x.\n", debugstr_w(driver), status);
244 /* Return the total number of characters in a REG_MULTI_SZ string, including
245 * the final terminating null. */
246 static size_t sizeof_multiszW( const WCHAR *str )
248 const WCHAR *p;
249 for (p = str; *p; p += lstrlenW(p) + 1);
250 return p + 1 - str;
253 /* This does almost the same thing as UpdateDriverForPlugAndPlayDevices(),
254 * except that we don't know the INF path beforehand. */
255 static BOOL install_device_driver( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
257 static const DWORD dif_list[] =
259 DIF_REGISTERDEVICE,
260 DIF_SELECTBESTCOMPATDRV,
261 DIF_ALLOW_INSTALL,
262 DIF_INSTALLDEVICEFILES,
263 DIF_REGISTER_COINSTALLERS,
264 DIF_INSTALLINTERFACES,
265 DIF_INSTALLDEVICE,
266 DIF_NEWDEVICEWIZARD_FINISHINSTALL,
269 NTSTATUS status;
270 unsigned int i;
271 WCHAR *ids;
273 if ((status = get_device_id( device, BusQueryHardwareIDs, &ids )) || !ids)
275 ERR("Failed to get hardware IDs, status %#x.\n", status);
276 return FALSE;
279 SetupDiSetDeviceRegistryPropertyW( set, sp_device, SPDRP_HARDWAREID, (BYTE *)ids,
280 sizeof_multiszW( ids ) * sizeof(WCHAR) );
281 ExFreePool( ids );
283 if ((status = get_device_id( device, BusQueryCompatibleIDs, &ids )) || !ids)
285 ERR("Failed to get compatible IDs, status %#x.\n", status);
286 return FALSE;
289 SetupDiSetDeviceRegistryPropertyW( set, sp_device, SPDRP_COMPATIBLEIDS, (BYTE *)ids,
290 sizeof_multiszW( ids ) * sizeof(WCHAR) );
291 ExFreePool( ids );
293 if (!SetupDiBuildDriverInfoList( set, sp_device, SPDIT_COMPATDRIVER ))
295 ERR("Failed to build compatible driver list, error %#x.\n", GetLastError());
296 return FALSE;
299 for (i = 0; i < ARRAY_SIZE(dif_list); ++i)
301 if (!SetupDiCallClassInstaller(dif_list[i], set, sp_device) && GetLastError() != ERROR_DI_DO_DEFAULT)
303 WARN("Install function %#x failed, error %#x.\n", dif_list[i], GetLastError());
304 return FALSE;
308 return TRUE;
311 /* Load the function driver for a newly created PDO, if one is present, and
312 * send IRPs to start the device. */
313 static void start_device( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
315 load_function_driver( device, set, sp_device );
316 if (device->DriverObject)
318 send_pnp_irp( device, IRP_MN_START_DEVICE );
319 send_power_irp( device, PowerDeviceD0 );
323 static void enumerate_new_device( DEVICE_OBJECT *device, HDEVINFO set )
325 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
327 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
328 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
329 BOOL need_driver = TRUE;
330 HKEY key;
332 if (get_device_instance_id( device, device_instance_id ))
333 return;
335 if (!SetupDiCreateDeviceInfoW( set, device_instance_id, &GUID_NULL, NULL, NULL, 0, &sp_device )
336 && !SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device ))
338 ERR("Failed to create or open device %s, error %#x.\n", debugstr_w(device_instance_id), GetLastError());
339 SetupDiDestroyDeviceInfoList( set );
340 return;
343 TRACE("Creating new device %s.\n", debugstr_w(device_instance_id));
345 /* Check if the device already has a driver registered; if not, find one
346 * and install it. */
347 key = SetupDiOpenDevRegKey( set, &sp_device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ );
348 if (key != INVALID_HANDLE_VALUE)
350 if (!RegQueryValueExW( key, infpathW, NULL, NULL, NULL, NULL ))
351 need_driver = FALSE;
352 RegCloseKey( key );
355 if (need_driver && !install_device_driver( device, set, &sp_device ))
357 SetupDiDestroyDeviceInfoList( set );
358 return;
361 start_device( device, set, &sp_device );
364 static void remove_device( DEVICE_OBJECT *device )
366 struct wine_device *wine_device = CONTAINING_RECORD(device, struct wine_device, device_obj);
368 TRACE("Removing device %p.\n", device);
370 if (wine_device->children)
372 ULONG i;
373 for (i = 0; i < wine_device->children->Count; ++i)
374 remove_device( wine_device->children->Objects[i] );
377 send_power_irp( device, PowerDeviceD3 );
378 send_pnp_irp( device, IRP_MN_SURPRISE_REMOVAL );
379 send_pnp_irp( device, IRP_MN_REMOVE_DEVICE );
382 static BOOL device_in_list( const DEVICE_RELATIONS *list, const DEVICE_OBJECT *device )
384 ULONG i;
385 for (i = 0; i < list->Count; ++i)
387 if (list->Objects[i] == device)
388 return TRUE;
390 return FALSE;
393 static void handle_bus_relations( DEVICE_OBJECT *parent )
395 struct wine_device *wine_parent = CONTAINING_RECORD(parent, struct wine_device, device_obj);
396 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
397 DEVICE_RELATIONS *relations;
398 IO_STATUS_BLOCK irp_status;
399 IO_STACK_LOCATION *irpsp;
400 NTSTATUS status;
401 HDEVINFO set;
402 IRP *irp;
403 ULONG i;
405 TRACE( "(%p)\n", parent );
407 set = SetupDiCreateDeviceInfoList( NULL, NULL );
409 parent = IoGetAttachedDevice( parent );
411 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, parent, NULL, 0, NULL, NULL, &irp_status )))
413 SetupDiDestroyDeviceInfoList( set );
414 return;
417 irpsp = IoGetNextIrpStackLocation( irp );
418 irpsp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
419 irpsp->Parameters.QueryDeviceRelations.Type = BusRelations;
420 if ((status = send_device_irp( parent, irp, (ULONG_PTR *)&relations )))
422 ERR("Failed to enumerate child devices, status %#x.\n", status);
423 SetupDiDestroyDeviceInfoList( set );
424 return;
427 TRACE("Got %u devices.\n", relations->Count);
429 for (i = 0; i < relations->Count; ++i)
431 DEVICE_OBJECT *child = relations->Objects[i];
433 if (!wine_parent->children || !device_in_list( wine_parent->children, child ))
435 TRACE("Adding new device %p.\n", child);
436 enumerate_new_device( child, set );
440 if (wine_parent->children)
442 for (i = 0; i < wine_parent->children->Count; ++i)
444 DEVICE_OBJECT *child = wine_parent->children->Objects[i];
446 if (!device_in_list( relations, child ))
448 TRACE("Removing device %p.\n", child);
449 remove_device( child );
451 ObDereferenceObject( child );
455 ExFreePool( wine_parent->children );
456 wine_parent->children = relations;
458 SetupDiDestroyDeviceInfoList( set );
461 /***********************************************************************
462 * IoInvalidateDeviceRelations (NTOSKRNL.EXE.@)
464 void WINAPI IoInvalidateDeviceRelations( DEVICE_OBJECT *device_object, DEVICE_RELATION_TYPE type )
466 TRACE("device %p, type %#x.\n", device_object, type);
468 switch (type)
470 case BusRelations:
471 handle_bus_relations( device_object );
472 break;
473 default:
474 FIXME("Unhandled relation %#x.\n", type);
475 break;
479 /***********************************************************************
480 * IoGetDeviceProperty (NTOSKRNL.EXE.@)
482 NTSTATUS WINAPI IoGetDeviceProperty( DEVICE_OBJECT *device, DEVICE_REGISTRY_PROPERTY property,
483 ULONG length, void *buffer, ULONG *needed )
485 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
486 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
487 DWORD sp_property = -1;
488 NTSTATUS status;
489 HDEVINFO set;
491 TRACE("device %p, property %u, length %u, buffer %p, needed %p.\n",
492 device, property, length, buffer, needed);
494 switch (property)
496 case DevicePropertyEnumeratorName:
498 WCHAR *id, *ptr;
500 status = get_device_id( device, BusQueryInstanceID, &id );
501 if (status != STATUS_SUCCESS)
503 ERR("Failed to get instance ID, status %#x.\n", status);
504 break;
507 wcsupr( id );
508 ptr = wcschr( id, '\\' );
509 if (ptr) *ptr = 0;
511 *needed = sizeof(WCHAR) * (lstrlenW(id) + 1);
512 if (length >= *needed)
513 memcpy( buffer, id, *needed );
514 else
515 status = STATUS_BUFFER_TOO_SMALL;
517 ExFreePool( id );
518 return status;
520 case DevicePropertyPhysicalDeviceObjectName:
522 ULONG used_len, len = length + sizeof(OBJECT_NAME_INFORMATION);
523 OBJECT_NAME_INFORMATION *name = HeapAlloc(GetProcessHeap(), 0, len);
524 HANDLE handle;
526 status = ObOpenObjectByPointer( device, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &handle );
527 if (!status)
529 status = NtQueryObject( handle, ObjectNameInformation, name, len, &used_len );
530 NtClose( handle );
532 if (status == STATUS_SUCCESS)
534 /* Ensure room for NULL termination */
535 if (length >= name->Name.MaximumLength)
536 memcpy(buffer, name->Name.Buffer, name->Name.MaximumLength);
537 else
538 status = STATUS_BUFFER_TOO_SMALL;
539 *needed = name->Name.MaximumLength;
541 else
543 if (status == STATUS_INFO_LENGTH_MISMATCH ||
544 status == STATUS_BUFFER_OVERFLOW)
546 status = STATUS_BUFFER_TOO_SMALL;
547 *needed = used_len - sizeof(OBJECT_NAME_INFORMATION);
549 else
550 *needed = 0;
552 HeapFree(GetProcessHeap(), 0, name);
553 return status;
555 case DevicePropertyDeviceDescription:
556 sp_property = SPDRP_DEVICEDESC;
557 break;
558 case DevicePropertyHardwareID:
559 sp_property = SPDRP_HARDWAREID;
560 break;
561 case DevicePropertyCompatibleIDs:
562 sp_property = SPDRP_COMPATIBLEIDS;
563 break;
564 case DevicePropertyClassName:
565 sp_property = SPDRP_CLASS;
566 break;
567 case DevicePropertyClassGuid:
568 sp_property = SPDRP_CLASSGUID;
569 break;
570 case DevicePropertyManufacturer:
571 sp_property = SPDRP_MFG;
572 break;
573 case DevicePropertyFriendlyName:
574 sp_property = SPDRP_FRIENDLYNAME;
575 break;
576 case DevicePropertyLocationInformation:
577 sp_property = SPDRP_LOCATION_INFORMATION;
578 break;
579 case DevicePropertyBusTypeGuid:
580 sp_property = SPDRP_BUSTYPEGUID;
581 break;
582 case DevicePropertyLegacyBusType:
583 sp_property = SPDRP_LEGACYBUSTYPE;
584 break;
585 case DevicePropertyBusNumber:
586 sp_property = SPDRP_BUSNUMBER;
587 break;
588 case DevicePropertyAddress:
589 sp_property = SPDRP_ADDRESS;
590 break;
591 case DevicePropertyUINumber:
592 sp_property = SPDRP_UI_NUMBER;
593 break;
594 case DevicePropertyInstallState:
595 sp_property = SPDRP_INSTALL_STATE;
596 break;
597 case DevicePropertyRemovalPolicy:
598 sp_property = SPDRP_REMOVAL_POLICY;
599 break;
600 default:
601 FIXME("Unhandled property %u.\n", property);
602 return STATUS_NOT_IMPLEMENTED;
605 if ((status = get_device_instance_id( device, device_instance_id )))
606 return status;
608 if ((set = SetupDiCreateDeviceInfoList( &GUID_NULL, NULL )) == INVALID_HANDLE_VALUE)
610 ERR("Failed to create device list, error %#x.\n", GetLastError());
611 return GetLastError();
614 if (!SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device))
616 ERR("Failed to open device, error %#x.\n", GetLastError());
617 SetupDiDestroyDeviceInfoList( set );
618 return GetLastError();
621 if (SetupDiGetDeviceRegistryPropertyW( set, &sp_device, sp_property, NULL, buffer, length, needed ))
622 status = STATUS_SUCCESS;
623 else
624 status = GetLastError();
626 SetupDiDestroyDeviceInfoList( set );
628 return status;
631 static NTSTATUS create_device_symlink( DEVICE_OBJECT *device, UNICODE_STRING *symlink_name )
633 UNICODE_STRING device_nameU;
634 WCHAR *device_name;
635 ULONG len = 0;
636 NTSTATUS ret;
638 ret = IoGetDeviceProperty( device, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &len );
639 if (ret != STATUS_BUFFER_TOO_SMALL)
640 return ret;
642 device_name = heap_alloc( len );
643 ret = IoGetDeviceProperty( device, DevicePropertyPhysicalDeviceObjectName, len, device_name, &len );
644 if (ret)
646 heap_free( device_name );
647 return ret;
650 RtlInitUnicodeString( &device_nameU, device_name );
651 ret = IoCreateSymbolicLink( symlink_name, &device_nameU );
652 heap_free( device_name );
653 return ret;
656 void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
658 return heap_alloc( len );
661 void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
663 heap_free( ptr );
666 static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr )
668 return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode );
671 static void send_devicechange( DWORD code, void *data, unsigned int size )
673 __TRY
675 plugplay_send_event( code, data, size );
677 __EXCEPT(rpc_filter)
679 WARN("Failed to send event, exception %#x.\n", GetExceptionCode());
681 __ENDTRY
684 /***********************************************************************
685 * IoSetDeviceInterfaceState (NTOSKRNL.EXE.@)
687 NTSTATUS WINAPI IoSetDeviceInterfaceState( UNICODE_STRING *name, BOOLEAN enable )
689 static const WCHAR DeviceClassesW[] = {'\\','R','E','G','I','S','T','R','Y','\\',
690 'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
691 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
692 'C','o','n','t','r','o','l','\\',
693 'D','e','v','i','c','e','C','l','a','s','s','e','s','\\',0};
694 static const WCHAR controlW[] = {'C','o','n','t','r','o','l',0};
695 static const WCHAR linkedW[] = {'L','i','n','k','e','d',0};
696 static const WCHAR slashW[] = {'\\',0};
697 static const WCHAR hashW[] = {'#',0};
699 size_t namelen = name->Length / sizeof(WCHAR);
700 DEV_BROADCAST_DEVICEINTERFACE_W *broadcast;
701 struct device_interface *iface;
702 HANDLE iface_key, control_key;
703 OBJECT_ATTRIBUTES attr = {0};
704 struct wine_rb_entry *entry;
705 WCHAR *path, *refstr, *p;
706 UNICODE_STRING string;
707 DWORD data = enable;
708 NTSTATUS ret;
709 ULONG len;
711 TRACE("device %s, enable %u.\n", debugstr_us(name), enable);
713 entry = wine_rb_get( &device_interfaces, name );
714 if (!entry)
715 return STATUS_OBJECT_NAME_NOT_FOUND;
717 iface = WINE_RB_ENTRY_VALUE( entry, struct device_interface, entry );
719 if (!enable && !iface->enabled)
720 return STATUS_OBJECT_NAME_NOT_FOUND;
722 if (enable && iface->enabled)
723 return STATUS_OBJECT_NAME_EXISTS;
725 for (p = name->Buffer + 4, refstr = NULL; p < name->Buffer + namelen; p++)
726 if (*p == '\\') refstr = p;
727 if (!refstr) refstr = p;
729 len = lstrlenW(DeviceClassesW) + 38 + 1 + namelen + 2 + 1;
731 if (!(path = heap_alloc( len * sizeof(WCHAR) )))
732 return STATUS_NO_MEMORY;
734 lstrcpyW( path, DeviceClassesW );
735 lstrcpynW( path + lstrlenW( path ), refstr - 38, 39 );
736 lstrcatW( path, slashW );
737 p = path + lstrlenW( path );
738 lstrcpynW( path + lstrlenW( path ), name->Buffer, (refstr - name->Buffer) + 1 );
739 p[0] = p[1] = p[3] = '#';
740 lstrcatW( path, slashW );
741 lstrcatW( path, hashW );
742 if (refstr < name->Buffer + namelen)
743 lstrcpynW( path + lstrlenW( path ), refstr, name->Buffer + namelen - refstr + 1 );
745 attr.Length = sizeof(attr);
746 attr.ObjectName = &string;
747 RtlInitUnicodeString( &string, path );
748 ret = NtOpenKey( &iface_key, KEY_CREATE_SUB_KEY, &attr );
749 heap_free(path);
750 if (ret)
751 return ret;
753 attr.RootDirectory = iface_key;
754 RtlInitUnicodeString( &string, controlW );
755 ret = NtCreateKey( &control_key, KEY_SET_VALUE, &attr, 0, NULL, REG_OPTION_VOLATILE, NULL );
756 NtClose( iface_key );
757 if (ret)
758 return ret;
760 RtlInitUnicodeString( &string, linkedW );
761 ret = NtSetValueKey( control_key, &string, 0, REG_DWORD, &data, sizeof(data) );
762 if (ret)
764 NtClose( control_key );
765 return ret;
768 if (enable)
769 ret = create_device_symlink( iface->device, name );
770 else
771 ret = IoDeleteSymbolicLink( name );
772 if (ret)
774 NtDeleteValueKey( control_key, &string );
775 NtClose( control_key );
776 return ret;
779 iface->enabled = enable;
781 len = offsetof(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name[namelen + 1]);
783 if ((broadcast = heap_alloc( len )))
785 broadcast->dbcc_size = len;
786 broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
787 broadcast->dbcc_classguid = iface->interface_class;
788 lstrcpynW( broadcast->dbcc_name, name->Buffer, namelen + 1 );
789 send_devicechange( enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, broadcast, len );
790 heap_free( broadcast );
792 return ret;
795 /***********************************************************************
796 * IoRegisterDeviceInterface (NTOSKRNL.EXE.@)
798 NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *class_guid,
799 UNICODE_STRING *refstr, UNICODE_STRING *symbolic_link)
801 SP_DEVICE_INTERFACE_DATA sp_iface = {sizeof(sp_iface)};
802 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
803 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
804 SP_DEVICE_INTERFACE_DETAIL_DATA_W *data;
805 NTSTATUS status = STATUS_SUCCESS;
806 UNICODE_STRING device_path;
807 struct device_interface *iface;
808 struct wine_rb_entry *entry;
809 DWORD required;
810 HDEVINFO set;
812 TRACE("device %p, class_guid %s, refstr %s, symbolic_link %p.\n",
813 device, debugstr_guid(class_guid), debugstr_us(refstr), symbolic_link);
815 if ((status = get_device_instance_id( device, device_instance_id )))
816 return status;
818 set = SetupDiGetClassDevsW( class_guid, NULL, NULL, DIGCF_DEVICEINTERFACE );
819 if (set == INVALID_HANDLE_VALUE) return STATUS_UNSUCCESSFUL;
821 if (!SetupDiCreateDeviceInfoW( set, device_instance_id, class_guid, NULL, NULL, 0, &sp_device )
822 && !SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device ))
824 ERR("Failed to create device %s, error %#x.\n", debugstr_w(device_instance_id), GetLastError());
825 return GetLastError();
828 if (!SetupDiCreateDeviceInterfaceW( set, &sp_device, class_guid, refstr ? refstr->Buffer : NULL, 0, &sp_iface ))
829 return STATUS_UNSUCCESSFUL;
831 required = 0;
832 SetupDiGetDeviceInterfaceDetailW( set, &sp_iface, NULL, 0, &required, NULL );
833 if (required == 0) return STATUS_UNSUCCESSFUL;
835 data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, required );
836 data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
838 if (!SetupDiGetDeviceInterfaceDetailW( set, &sp_iface, data, required, NULL, NULL ))
840 HeapFree( GetProcessHeap(), 0, data );
841 return STATUS_UNSUCCESSFUL;
844 data->DevicePath[1] = '?';
845 TRACE("Returning path %s.\n", debugstr_w(data->DevicePath));
846 RtlCreateUnicodeString( &device_path, data->DevicePath);
848 entry = wine_rb_get( &device_interfaces, &device_path );
849 if (entry)
851 iface = WINE_RB_ENTRY_VALUE( entry, struct device_interface, entry );
852 if (iface->enabled)
853 ERR("Device interface %s is still enabled.\n", debugstr_us(&iface->symbolic_link));
855 else
857 iface = heap_alloc_zero( sizeof(struct device_interface) );
858 RtlCreateUnicodeString(&iface->symbolic_link, data->DevicePath);
859 if (wine_rb_put( &device_interfaces, &iface->symbolic_link, &iface->entry ))
860 ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface->symbolic_link));
863 iface->device = device;
864 iface->interface_class = *class_guid;
865 if (symbolic_link)
866 RtlCreateUnicodeString( symbolic_link, data->DevicePath);
868 HeapFree( GetProcessHeap(), 0, data );
870 RtlFreeUnicodeString( &device_path );
872 return status;
875 /***********************************************************************
876 * IoOpenDeviceRegistryKey (NTOSKRNL.EXE.@)
878 NTSTATUS WINAPI IoOpenDeviceRegistryKey( DEVICE_OBJECT *device, ULONG type, ACCESS_MASK access, HANDLE *key )
880 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
881 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
882 NTSTATUS status;
883 HDEVINFO set;
885 TRACE("device %p, type %#x, access %#x, key %p.\n", device, type, access, key);
887 if ((status = get_device_instance_id( device, device_instance_id )))
889 ERR("Failed to get device instance ID, error %#x.\n", status);
890 return status;
893 set = SetupDiCreateDeviceInfoList( &GUID_NULL, NULL );
895 SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device );
897 *key = SetupDiOpenDevRegKey( set, &sp_device, DICS_FLAG_GLOBAL, 0, type, access );
898 SetupDiDestroyDeviceInfoList( set );
899 if (*key == INVALID_HANDLE_VALUE)
900 return GetLastError();
901 return STATUS_SUCCESS;
904 /***********************************************************************
905 * PoSetPowerState (NTOSKRNL.EXE.@)
907 POWER_STATE WINAPI PoSetPowerState( DEVICE_OBJECT *device, POWER_STATE_TYPE type, POWER_STATE state)
909 FIXME("device %p, type %u, state %u, stub!\n", device, type, state.DeviceState);
910 return state;
913 /*****************************************************
914 * PoStartNextPowerIrp (NTOSKRNL.EXE.@)
916 void WINAPI PoStartNextPowerIrp( IRP *irp )
918 FIXME("irp %p, stub!\n", irp);
921 /*****************************************************
922 * PoCallDriver (NTOSKRNL.EXE.@)
924 NTSTATUS WINAPI PoCallDriver( DEVICE_OBJECT *device, IRP *irp )
926 TRACE("device %p, irp %p.\n", device, irp);
927 return IoCallDriver( device, irp );
930 static DRIVER_OBJECT *pnp_manager;
932 struct root_pnp_device
934 WCHAR id[MAX_DEVICE_ID_LEN];
935 struct wine_rb_entry entry;
936 DEVICE_OBJECT *device;
939 static int root_pnp_devices_rb_compare( const void *key, const struct wine_rb_entry *entry )
941 const struct root_pnp_device *device = WINE_RB_ENTRY_VALUE( entry, const struct root_pnp_device, entry );
942 const WCHAR *k = key;
944 return wcsicmp( k, device->id );
947 static struct wine_rb_tree root_pnp_devices = { root_pnp_devices_rb_compare };
949 static NTSTATUS WINAPI pnp_manager_device_pnp( DEVICE_OBJECT *device, IRP *irp )
951 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
952 struct root_pnp_device *root_device = device->DeviceExtension;
953 NTSTATUS status;
955 TRACE("device %p, irp %p, minor function %#x.\n", device, irp, stack->MinorFunction);
957 switch (stack->MinorFunction)
959 case IRP_MN_QUERY_DEVICE_RELATIONS:
960 /* The FDO above already handled this, so return the same status. */
961 break;
962 case IRP_MN_START_DEVICE:
963 case IRP_MN_SURPRISE_REMOVAL:
964 case IRP_MN_REMOVE_DEVICE:
965 /* Nothing to do. */
966 irp->IoStatus.u.Status = STATUS_SUCCESS;
967 break;
968 case IRP_MN_QUERY_CAPABILITIES:
969 irp->IoStatus.u.Status = STATUS_SUCCESS;
970 break;
971 case IRP_MN_QUERY_ID:
973 BUS_QUERY_ID_TYPE type = stack->Parameters.QueryId.IdType;
974 WCHAR *id, *p;
976 TRACE("Received IRP_MN_QUERY_ID, type %#x.\n", type);
978 switch (type)
980 case BusQueryDeviceID:
981 p = wcsrchr( root_device->id, '\\' );
982 if ((id = ExAllocatePool( NonPagedPool, (p - root_device->id + 1) * sizeof(WCHAR) )))
984 memcpy( id, root_device->id, (p - root_device->id) * sizeof(WCHAR) );
985 id[p - root_device->id] = 0;
986 irp->IoStatus.Information = (ULONG_PTR)id;
987 irp->IoStatus.u.Status = STATUS_SUCCESS;
989 else
991 irp->IoStatus.Information = 0;
992 irp->IoStatus.u.Status = STATUS_NO_MEMORY;
994 break;
995 case BusQueryInstanceID:
996 p = wcsrchr( root_device->id, '\\' );
997 if ((id = ExAllocatePool( NonPagedPool, (wcslen( p + 1 ) + 1) * sizeof(WCHAR) )))
999 wcscpy( id, p + 1 );
1000 irp->IoStatus.Information = (ULONG_PTR)id;
1001 irp->IoStatus.u.Status = STATUS_SUCCESS;
1003 else
1005 irp->IoStatus.Information = 0;
1006 irp->IoStatus.u.Status = STATUS_NO_MEMORY;
1008 break;
1009 default:
1010 FIXME("Unhandled IRP_MN_QUERY_ID type %#x.\n", type);
1012 break;
1014 default:
1015 FIXME("Unhandled PnP request %#x.\n", stack->MinorFunction);
1018 status = irp->IoStatus.u.Status;
1019 IoCompleteRequest( irp, IO_NO_INCREMENT );
1020 return status;
1023 static NTSTATUS WINAPI pnp_manager_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *keypath )
1025 pnp_manager = driver;
1026 driver->MajorFunction[IRP_MJ_PNP] = pnp_manager_device_pnp;
1027 return STATUS_SUCCESS;
1030 void pnp_manager_start(void)
1032 static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','P','n','p','M','a','n','a','g','e','r',0};
1033 WCHAR endpoint[] = L"\\pipe\\wine_plugplay";
1034 WCHAR protseq[] = L"ncalrpc";
1035 UNICODE_STRING driver_nameU;
1036 RPC_WSTR binding_str;
1037 NTSTATUS status;
1038 RPC_STATUS err;
1040 RtlInitUnicodeString( &driver_nameU, driver_nameW );
1041 if ((status = IoCreateDriver( &driver_nameU, pnp_manager_driver_entry )))
1042 ERR("Failed to create PnP manager driver, status %#x.\n", status);
1044 if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
1046 ERR("RpcStringBindingCompose() failed, error %#x\n", err);
1047 return;
1049 err = RpcBindingFromStringBindingW( binding_str, &plugplay_binding_handle );
1050 RpcStringFreeW( &binding_str );
1051 if (err)
1052 ERR("RpcBindingFromStringBinding() failed, error %#x\n", err);
1055 static void destroy_root_pnp_device( struct wine_rb_entry *entry, void *context )
1057 struct root_pnp_device *device = WINE_RB_ENTRY_VALUE(entry, struct root_pnp_device, entry);
1058 remove_device( device->device );
1061 void pnp_manager_stop(void)
1063 wine_rb_destroy( &root_pnp_devices, destroy_root_pnp_device, NULL );
1064 IoDeleteDriver( pnp_manager );
1065 RpcBindingFree( &plugplay_binding_handle );
1068 void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
1070 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
1071 static const WCHAR rootW[] = {'R','O','O','T',0};
1072 WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(driverW)], id[MAX_DEVICE_ID_LEN];
1073 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
1074 struct root_pnp_device *pnp_device;
1075 DEVICE_OBJECT *device;
1076 NTSTATUS status;
1077 unsigned int i;
1078 HDEVINFO set;
1080 TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name));
1082 set = SetupDiGetClassDevsW( NULL, rootW, NULL, DIGCF_ALLCLASSES );
1083 if (set == INVALID_HANDLE_VALUE)
1085 ERR("Failed to build device set, error %#x.\n", GetLastError());
1086 return;
1089 for (i = 0; SetupDiEnumDeviceInfo( set, i, &sp_device ); ++i)
1091 if (!SetupDiGetDeviceRegistryPropertyW( set, &sp_device, SPDRP_SERVICE,
1092 NULL, (BYTE *)buffer, sizeof(buffer), NULL )
1093 || lstrcmpiW( buffer, driver_name ))
1095 continue;
1098 SetupDiGetDeviceInstanceIdW( set, &sp_device, id, ARRAY_SIZE(id), NULL );
1100 if (wine_rb_get( &root_pnp_devices, id ))
1101 continue;
1103 TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id));
1105 if ((status = IoCreateDevice( pnp_manager, sizeof(struct root_pnp_device), NULL,
1106 FILE_DEVICE_CONTROLLER, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &device )))
1108 ERR("Failed to create root-enumerated PnP device %s, status %#x.\n", debugstr_w(id), status);
1109 continue;
1112 pnp_device = device->DeviceExtension;
1113 wcscpy( pnp_device->id, id );
1114 pnp_device->device = device;
1115 if (wine_rb_put( &root_pnp_devices, id, &pnp_device->entry ))
1117 ERR("Failed to insert device %s into tree.\n", debugstr_w(id));
1118 IoDeleteDevice( device );
1119 continue;
1122 start_device( device, set, &sp_device );
1125 SetupDiDestroyDeviceInfoList(set);