hidclass.sys: Validate report IDs in hid_device_xfer_report.
[wine.git] / dlls / ntoskrnl.exe / pnp.c
blobd8eb62bc17a9b3aa74559feb4e9bef636d477485
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 #define NONAMELESSUNION
25 #include "ntoskrnl_private.h"
26 #include "winreg.h"
27 #include "winuser.h"
28 #include "setupapi.h"
29 #include "cfgmgr32.h"
30 #include "dbt.h"
31 #include "wine/exception.h"
32 #include "wine/heap.h"
34 #include "plugplay.h"
36 #include "initguid.h"
37 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
39 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
41 static inline const char *debugstr_propkey( const DEVPROPKEY *id )
43 if (!id) return "(null)";
44 return wine_dbg_sprintf( "{%s,%04x}", wine_dbgstr_guid( &id->fmtid ), id->pid );
47 #define MAX_SERVICE_NAME 260
49 struct device_interface
51 struct wine_rb_entry entry;
53 UNICODE_STRING symbolic_link;
54 DEVICE_OBJECT *device;
55 GUID interface_class;
56 BOOL enabled;
59 static int interface_rb_compare( const void *key, const struct wine_rb_entry *entry)
61 const struct device_interface *iface = WINE_RB_ENTRY_VALUE( entry, const struct device_interface, entry );
62 const UNICODE_STRING *k = key;
64 return RtlCompareUnicodeString( k, &iface->symbolic_link, FALSE );
67 static struct wine_rb_tree device_interfaces = { interface_rb_compare };
69 static NTSTATUS get_device_id( DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR **id )
71 IO_STACK_LOCATION *irpsp;
72 IO_STATUS_BLOCK irp_status;
73 KEVENT event;
74 IRP *irp;
76 device = IoGetAttachedDevice( device );
78 KeInitializeEvent( &event, NotificationEvent, FALSE );
79 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, &event, &irp_status )))
80 return STATUS_NO_MEMORY;
82 irpsp = IoGetNextIrpStackLocation( irp );
83 irpsp->MinorFunction = IRP_MN_QUERY_ID;
84 irpsp->Parameters.QueryId.IdType = type;
86 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
87 if (IoCallDriver( device, irp ) == STATUS_PENDING)
88 KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
90 *id = (WCHAR *)irp_status.Information;
91 return irp_status.u.Status;
94 static NTSTATUS send_pnp_irp( DEVICE_OBJECT *device, UCHAR minor )
96 IO_STACK_LOCATION *irpsp;
97 IO_STATUS_BLOCK irp_status;
98 KEVENT event;
99 IRP *irp;
101 device = IoGetAttachedDevice( device );
103 KeInitializeEvent( &event, NotificationEvent, FALSE );
104 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status )))
105 return STATUS_NO_MEMORY;
107 irpsp = IoGetNextIrpStackLocation( irp );
108 irpsp->MinorFunction = minor;
110 irpsp->Parameters.StartDevice.AllocatedResources = NULL;
111 irpsp->Parameters.StartDevice.AllocatedResourcesTranslated = NULL;
113 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
114 if (IoCallDriver( device, irp ) == STATUS_PENDING)
115 KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
117 return irp_status.u.Status;
120 static NTSTATUS get_device_instance_id( DEVICE_OBJECT *device, WCHAR *buffer )
122 static const WCHAR backslashW[] = {'\\',0};
123 NTSTATUS status;
124 WCHAR *id;
126 if ((status = get_device_id( device, BusQueryDeviceID, &id )))
128 ERR("Failed to get device ID, status %#x.\n", status);
129 return status;
132 lstrcpyW( buffer, id );
133 ExFreePool( id );
135 if ((status = get_device_id( device, BusQueryInstanceID, &id )))
137 ERR("Failed to get instance ID, status %#x.\n", status);
138 return status;
141 lstrcatW( buffer, backslashW );
142 lstrcatW( buffer, id );
143 ExFreePool( id );
145 TRACE("Returning ID %s.\n", debugstr_w(buffer));
147 return STATUS_SUCCESS;
150 static NTSTATUS get_device_caps( DEVICE_OBJECT *device, DEVICE_CAPABILITIES *caps )
152 IO_STACK_LOCATION *irpsp;
153 IO_STATUS_BLOCK irp_status;
154 KEVENT event;
155 IRP *irp;
157 memset( caps, 0, sizeof(*caps) );
158 caps->Size = sizeof(*caps);
159 caps->Version = 1;
160 caps->Address = 0xffffffff;
161 caps->UINumber = 0xffffffff;
163 device = IoGetAttachedDevice( device );
165 KeInitializeEvent( &event, NotificationEvent, FALSE );
166 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status )))
167 return STATUS_NO_MEMORY;
169 irpsp = IoGetNextIrpStackLocation( irp );
170 irpsp->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
171 irpsp->Parameters.DeviceCapabilities.Capabilities = caps;
173 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
174 if (IoCallDriver( device, irp ) == STATUS_PENDING)
175 KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
177 return irp_status.u.Status;
180 static void load_function_driver( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
182 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
183 WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(servicesW)];
184 WCHAR driver[MAX_SERVICE_NAME] = {0};
185 DRIVER_OBJECT *driver_obj;
186 UNICODE_STRING string;
187 NTSTATUS status;
189 if (!SetupDiGetDeviceRegistryPropertyW( set, sp_device, SPDRP_SERVICE,
190 NULL, (BYTE *)driver, sizeof(driver), NULL ))
192 WARN("No driver registered for device %p.\n", device);
193 return;
196 lstrcpyW( buffer, servicesW );
197 lstrcatW( buffer, driver );
198 RtlInitUnicodeString( &string, buffer );
199 status = ZwLoadDriver( &string );
200 if (status != STATUS_SUCCESS && status != STATUS_IMAGE_ALREADY_LOADED)
202 ERR("Failed to load driver %s, status %#x.\n", debugstr_w(driver), status);
203 return;
206 lstrcpyW( buffer, driverW );
207 lstrcatW( buffer, driver );
208 RtlInitUnicodeString( &string, buffer );
209 if (ObReferenceObjectByName( &string, OBJ_CASE_INSENSITIVE, NULL,
210 0, NULL, KernelMode, NULL, (void **)&driver_obj ) != STATUS_SUCCESS)
212 ERR("Failed to locate loaded driver %s.\n", debugstr_w(driver));
213 return;
216 TRACE("Calling AddDevice routine %p.\n", driver_obj->DriverExtension->AddDevice);
217 if (driver_obj->DriverExtension->AddDevice)
218 status = driver_obj->DriverExtension->AddDevice( driver_obj, device );
219 else
220 status = STATUS_NOT_IMPLEMENTED;
221 TRACE("AddDevice routine %p returned %#x.\n", driver_obj->DriverExtension->AddDevice, status);
223 ObDereferenceObject( driver_obj );
225 if (status != STATUS_SUCCESS)
226 ERR("AddDevice failed for driver %s, status %#x.\n", debugstr_w(driver), status);
229 /* Return the total number of characters in a REG_MULTI_SZ string, including
230 * the final terminating null. */
231 static size_t sizeof_multiszW( const WCHAR *str )
233 const WCHAR *p;
234 for (p = str; *p; p += lstrlenW(p) + 1);
235 return p + 1 - str;
238 /* This does almost the same thing as UpdateDriverForPlugAndPlayDevices(),
239 * except that we don't know the INF path beforehand. */
240 static BOOL install_device_driver( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
242 static const DWORD dif_list[] =
244 DIF_REGISTERDEVICE,
245 DIF_SELECTBESTCOMPATDRV,
246 DIF_ALLOW_INSTALL,
247 DIF_INSTALLDEVICEFILES,
248 DIF_REGISTER_COINSTALLERS,
249 DIF_INSTALLINTERFACES,
250 DIF_INSTALLDEVICE,
251 DIF_NEWDEVICEWIZARD_FINISHINSTALL,
254 NTSTATUS status;
255 unsigned int i;
256 WCHAR *ids;
258 if ((status = get_device_id( device, BusQueryHardwareIDs, &ids )) || !ids)
260 ERR("Failed to get hardware IDs, status %#x.\n", status);
261 return FALSE;
264 SetupDiSetDeviceRegistryPropertyW( set, sp_device, SPDRP_HARDWAREID, (BYTE *)ids,
265 sizeof_multiszW( ids ) * sizeof(WCHAR) );
266 ExFreePool( ids );
268 if ((status = get_device_id( device, BusQueryCompatibleIDs, &ids )) || !ids)
270 ERR("Failed to get compatible IDs, status %#x.\n", status);
271 return FALSE;
274 SetupDiSetDeviceRegistryPropertyW( set, sp_device, SPDRP_COMPATIBLEIDS, (BYTE *)ids,
275 sizeof_multiszW( ids ) * sizeof(WCHAR) );
276 ExFreePool( ids );
278 if (!SetupDiBuildDriverInfoList( set, sp_device, SPDIT_COMPATDRIVER ))
280 ERR("Failed to build compatible driver list, error %#x.\n", GetLastError());
281 return FALSE;
284 for (i = 0; i < ARRAY_SIZE(dif_list); ++i)
286 if (!SetupDiCallClassInstaller(dif_list[i], set, sp_device) && GetLastError() != ERROR_DI_DO_DEFAULT)
288 WARN("Install function %#x failed, error %#x.\n", dif_list[i], GetLastError());
289 return FALSE;
293 return TRUE;
296 /* Load the function driver for a newly created PDO, if one is present, and
297 * send IRPs to start the device. */
298 static void start_device( DEVICE_OBJECT *device, HDEVINFO set, SP_DEVINFO_DATA *sp_device )
300 load_function_driver( device, set, sp_device );
301 if (device->DriverObject)
302 send_pnp_irp( device, IRP_MN_START_DEVICE );
305 static void enumerate_new_device( DEVICE_OBJECT *device, HDEVINFO set )
307 static const WCHAR infpathW[] = {'I','n','f','P','a','t','h',0};
309 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
310 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
311 DEVICE_CAPABILITIES caps;
312 BOOL need_driver = TRUE;
313 NTSTATUS status;
314 HKEY key;
316 if (get_device_instance_id( device, device_instance_id ))
317 return;
319 if (!SetupDiCreateDeviceInfoW( set, device_instance_id, &GUID_NULL, NULL, NULL, 0, &sp_device )
320 && !SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device ))
322 ERR("Failed to create or open device %s, error %#x.\n", debugstr_w(device_instance_id), GetLastError());
323 return;
326 TRACE("Creating new device %s.\n", debugstr_w(device_instance_id));
328 /* Check if the device already has a driver registered; if not, find one
329 * and install it. */
330 key = SetupDiOpenDevRegKey( set, &sp_device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ );
331 if (key != INVALID_HANDLE_VALUE)
333 if (!RegQueryValueExW( key, infpathW, NULL, NULL, NULL, NULL ))
334 need_driver = FALSE;
335 RegCloseKey( key );
338 if ((status = get_device_caps( device, &caps )))
340 ERR("Failed to get caps for device %s, status %#x.\n", debugstr_w(device_instance_id), status);
341 return;
344 if (need_driver && !install_device_driver( device, set, &sp_device ) && !caps.RawDeviceOK)
346 ERR("Unable to install a function driver for device %s.\n", debugstr_w(device_instance_id));
347 return;
350 start_device( device, set, &sp_device );
353 static void send_remove_device_irp( DEVICE_OBJECT *device, UCHAR code )
355 struct wine_device *wine_device = CONTAINING_RECORD(device, struct wine_device, device_obj);
357 TRACE( "Removing device %p, code %x.\n", device, code );
359 if (wine_device->children)
361 ULONG i;
362 for (i = 0; i < wine_device->children->Count; ++i)
363 send_remove_device_irp( wine_device->children->Objects[i], code );
366 send_pnp_irp( device, code );
369 static BOOL device_in_list( const DEVICE_RELATIONS *list, const DEVICE_OBJECT *device )
371 ULONG i;
372 for (i = 0; i < list->Count; ++i)
374 if (list->Objects[i] == device)
375 return TRUE;
377 return FALSE;
380 static void handle_bus_relations( DEVICE_OBJECT *parent )
382 struct wine_device *wine_parent = CONTAINING_RECORD(parent, struct wine_device, device_obj);
383 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
384 DEVICE_RELATIONS *relations;
385 IO_STATUS_BLOCK irp_status;
386 IO_STACK_LOCATION *irpsp;
387 HDEVINFO set;
388 KEVENT event;
389 IRP *irp;
390 ULONG i;
392 TRACE( "(%p)\n", parent );
394 set = SetupDiCreateDeviceInfoList( NULL, NULL );
396 parent = IoGetAttachedDevice( parent );
398 KeInitializeEvent( &event, NotificationEvent, FALSE );
399 if (!(irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, parent, NULL, 0, NULL, &event, &irp_status )))
401 SetupDiDestroyDeviceInfoList( set );
402 return;
405 irpsp = IoGetNextIrpStackLocation( irp );
406 irpsp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
407 irpsp->Parameters.QueryDeviceRelations.Type = BusRelations;
409 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
410 if (IoCallDriver( parent, irp ) == STATUS_PENDING)
411 KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
413 relations = (DEVICE_RELATIONS *)irp_status.Information;
414 if (irp_status.u.Status)
416 ERR("Failed to enumerate child devices, status %#x.\n", irp_status.u.Status);
417 SetupDiDestroyDeviceInfoList( set );
418 return;
421 TRACE("Got %u devices.\n", relations->Count);
423 for (i = 0; i < relations->Count; ++i)
425 DEVICE_OBJECT *child = relations->Objects[i];
427 if (!wine_parent->children || !device_in_list( wine_parent->children, child ))
429 TRACE("Adding new device %p.\n", child);
430 enumerate_new_device( child, set );
434 if (wine_parent->children)
436 for (i = 0; i < wine_parent->children->Count; ++i)
438 DEVICE_OBJECT *child = wine_parent->children->Objects[i];
440 if (!device_in_list( relations, child ))
442 TRACE("Removing device %p.\n", child);
443 send_remove_device_irp( child, IRP_MN_SURPRISE_REMOVAL );
444 send_remove_device_irp( child, IRP_MN_REMOVE_DEVICE );
446 ObDereferenceObject( child );
450 ExFreePool( wine_parent->children );
451 wine_parent->children = relations;
453 SetupDiDestroyDeviceInfoList( set );
456 /***********************************************************************
457 * IoInvalidateDeviceRelations (NTOSKRNL.EXE.@)
459 void WINAPI IoInvalidateDeviceRelations( DEVICE_OBJECT *device_object, DEVICE_RELATION_TYPE type )
461 TRACE("device %p, type %#x.\n", device_object, type);
463 switch (type)
465 case BusRelations:
466 handle_bus_relations( device_object );
467 break;
468 default:
469 FIXME("Unhandled relation %#x.\n", type);
470 break;
474 /***********************************************************************
475 * IoGetDeviceProperty (NTOSKRNL.EXE.@)
477 NTSTATUS WINAPI IoGetDeviceProperty( DEVICE_OBJECT *device, DEVICE_REGISTRY_PROPERTY property,
478 ULONG length, void *buffer, ULONG *needed )
480 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
481 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
482 DWORD sp_property = -1;
483 NTSTATUS status;
484 HDEVINFO set;
486 TRACE("device %p, property %u, length %u, buffer %p, needed %p.\n",
487 device, property, length, buffer, needed);
489 switch (property)
491 case DevicePropertyEnumeratorName:
493 WCHAR *id, *ptr;
495 status = get_device_id( device, BusQueryInstanceID, &id );
496 if (status != STATUS_SUCCESS)
498 ERR("Failed to get instance ID, status %#x.\n", status);
499 break;
502 wcsupr( id );
503 ptr = wcschr( id, '\\' );
504 if (ptr) *ptr = 0;
506 *needed = sizeof(WCHAR) * (lstrlenW(id) + 1);
507 if (length >= *needed)
508 memcpy( buffer, id, *needed );
509 else
510 status = STATUS_BUFFER_TOO_SMALL;
512 ExFreePool( id );
513 return status;
515 case DevicePropertyPhysicalDeviceObjectName:
517 ULONG used_len, len = length + sizeof(OBJECT_NAME_INFORMATION);
518 OBJECT_NAME_INFORMATION *name = HeapAlloc(GetProcessHeap(), 0, len);
519 HANDLE handle;
521 status = ObOpenObjectByPointer( device, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &handle );
522 if (!status)
524 status = NtQueryObject( handle, ObjectNameInformation, name, len, &used_len );
525 NtClose( handle );
527 if (status == STATUS_SUCCESS)
529 /* Ensure room for NULL termination */
530 if (length >= name->Name.MaximumLength)
531 memcpy(buffer, name->Name.Buffer, name->Name.MaximumLength);
532 else
533 status = STATUS_BUFFER_TOO_SMALL;
534 *needed = name->Name.MaximumLength;
536 else
538 if (status == STATUS_INFO_LENGTH_MISMATCH ||
539 status == STATUS_BUFFER_OVERFLOW)
541 status = STATUS_BUFFER_TOO_SMALL;
542 *needed = used_len - sizeof(OBJECT_NAME_INFORMATION);
544 else
545 *needed = 0;
547 HeapFree(GetProcessHeap(), 0, name);
548 return status;
550 case DevicePropertyDeviceDescription:
551 sp_property = SPDRP_DEVICEDESC;
552 break;
553 case DevicePropertyHardwareID:
554 sp_property = SPDRP_HARDWAREID;
555 break;
556 case DevicePropertyCompatibleIDs:
557 sp_property = SPDRP_COMPATIBLEIDS;
558 break;
559 case DevicePropertyClassName:
560 sp_property = SPDRP_CLASS;
561 break;
562 case DevicePropertyClassGuid:
563 sp_property = SPDRP_CLASSGUID;
564 break;
565 case DevicePropertyManufacturer:
566 sp_property = SPDRP_MFG;
567 break;
568 case DevicePropertyFriendlyName:
569 sp_property = SPDRP_FRIENDLYNAME;
570 break;
571 case DevicePropertyLocationInformation:
572 sp_property = SPDRP_LOCATION_INFORMATION;
573 break;
574 case DevicePropertyBusTypeGuid:
575 sp_property = SPDRP_BUSTYPEGUID;
576 break;
577 case DevicePropertyLegacyBusType:
578 sp_property = SPDRP_LEGACYBUSTYPE;
579 break;
580 case DevicePropertyBusNumber:
581 sp_property = SPDRP_BUSNUMBER;
582 break;
583 case DevicePropertyAddress:
584 sp_property = SPDRP_ADDRESS;
585 break;
586 case DevicePropertyUINumber:
587 sp_property = SPDRP_UI_NUMBER;
588 break;
589 case DevicePropertyInstallState:
590 sp_property = SPDRP_INSTALL_STATE;
591 break;
592 case DevicePropertyRemovalPolicy:
593 sp_property = SPDRP_REMOVAL_POLICY;
594 break;
595 default:
596 FIXME("Unhandled property %u.\n", property);
597 return STATUS_NOT_IMPLEMENTED;
600 if ((status = get_device_instance_id( device, device_instance_id )))
601 return status;
603 if ((set = SetupDiCreateDeviceInfoList( &GUID_NULL, NULL )) == INVALID_HANDLE_VALUE)
605 ERR("Failed to create device list, error %#x.\n", GetLastError());
606 return GetLastError();
609 if (!SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device))
611 ERR("Failed to open device, error %#x.\n", GetLastError());
612 SetupDiDestroyDeviceInfoList( set );
613 return GetLastError();
616 if (SetupDiGetDeviceRegistryPropertyW( set, &sp_device, sp_property, NULL, buffer, length, needed ))
617 status = STATUS_SUCCESS;
618 else
619 status = GetLastError();
621 SetupDiDestroyDeviceInfoList( set );
623 return status;
626 static NTSTATUS create_device_symlink( DEVICE_OBJECT *device, UNICODE_STRING *symlink_name )
628 UNICODE_STRING device_nameU;
629 WCHAR *device_name;
630 ULONG len = 0;
631 NTSTATUS ret;
633 ret = IoGetDeviceProperty( device, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &len );
634 if (ret != STATUS_BUFFER_TOO_SMALL)
635 return ret;
637 device_name = heap_alloc( len );
638 ret = IoGetDeviceProperty( device, DevicePropertyPhysicalDeviceObjectName, len, device_name, &len );
639 if (ret)
641 heap_free( device_name );
642 return ret;
645 RtlInitUnicodeString( &device_nameU, device_name );
646 ret = IoCreateSymbolicLink( symlink_name, &device_nameU );
647 heap_free( device_name );
648 return ret;
651 void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
653 return heap_alloc( len );
656 void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
658 heap_free( ptr );
661 static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr )
663 return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode );
666 static void send_devicechange( DWORD code, void *data, unsigned int size )
668 __TRY
670 plugplay_send_event( code, data, size );
672 __EXCEPT(rpc_filter)
674 WARN("Failed to send event, exception %#x.\n", GetExceptionCode());
676 __ENDTRY
679 /***********************************************************************
680 * IoSetDeviceInterfaceState (NTOSKRNL.EXE.@)
682 NTSTATUS WINAPI IoSetDeviceInterfaceState( UNICODE_STRING *name, BOOLEAN enable )
684 static const WCHAR DeviceClassesW[] = {'\\','R','E','G','I','S','T','R','Y','\\',
685 'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
686 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
687 'C','o','n','t','r','o','l','\\',
688 'D','e','v','i','c','e','C','l','a','s','s','e','s','\\',0};
689 static const WCHAR controlW[] = {'C','o','n','t','r','o','l',0};
690 static const WCHAR linkedW[] = {'L','i','n','k','e','d',0};
691 static const WCHAR slashW[] = {'\\',0};
692 static const WCHAR hashW[] = {'#',0};
694 size_t namelen = name->Length / sizeof(WCHAR);
695 DEV_BROADCAST_DEVICEINTERFACE_W *broadcast;
696 struct device_interface *iface;
697 HANDLE iface_key, control_key;
698 OBJECT_ATTRIBUTES attr = {0};
699 struct wine_rb_entry *entry;
700 WCHAR *path, *refstr, *p;
701 UNICODE_STRING string;
702 DWORD data = enable;
703 NTSTATUS ret;
704 ULONG len;
706 TRACE("device %s, enable %u.\n", debugstr_us(name), enable);
708 entry = wine_rb_get( &device_interfaces, name );
709 if (!entry)
710 return STATUS_OBJECT_NAME_NOT_FOUND;
712 iface = WINE_RB_ENTRY_VALUE( entry, struct device_interface, entry );
714 if (!enable && !iface->enabled)
715 return STATUS_OBJECT_NAME_NOT_FOUND;
717 if (enable && iface->enabled)
718 return STATUS_OBJECT_NAME_EXISTS;
720 for (p = name->Buffer + 4, refstr = NULL; p < name->Buffer + namelen; p++)
721 if (*p == '\\') refstr = p;
722 if (!refstr) refstr = p;
724 len = lstrlenW(DeviceClassesW) + 38 + 1 + namelen + 2 + 1;
726 if (!(path = heap_alloc( len * sizeof(WCHAR) )))
727 return STATUS_NO_MEMORY;
729 lstrcpyW( path, DeviceClassesW );
730 lstrcpynW( path + lstrlenW( path ), refstr - 38, 39 );
731 lstrcatW( path, slashW );
732 p = path + lstrlenW( path );
733 lstrcpynW( path + lstrlenW( path ), name->Buffer, (refstr - name->Buffer) + 1 );
734 p[0] = p[1] = p[3] = '#';
735 lstrcatW( path, slashW );
736 lstrcatW( path, hashW );
737 if (refstr < name->Buffer + namelen)
738 lstrcpynW( path + lstrlenW( path ), refstr, name->Buffer + namelen - refstr + 1 );
740 attr.Length = sizeof(attr);
741 attr.ObjectName = &string;
742 RtlInitUnicodeString( &string, path );
743 ret = NtOpenKey( &iface_key, KEY_CREATE_SUB_KEY, &attr );
744 heap_free(path);
745 if (ret)
746 return ret;
748 attr.RootDirectory = iface_key;
749 RtlInitUnicodeString( &string, controlW );
750 ret = NtCreateKey( &control_key, KEY_SET_VALUE, &attr, 0, NULL, REG_OPTION_VOLATILE, NULL );
751 NtClose( iface_key );
752 if (ret)
753 return ret;
755 RtlInitUnicodeString( &string, linkedW );
756 ret = NtSetValueKey( control_key, &string, 0, REG_DWORD, &data, sizeof(data) );
757 if (ret)
759 NtClose( control_key );
760 return ret;
763 if (enable)
764 ret = create_device_symlink( iface->device, name );
765 else
766 ret = IoDeleteSymbolicLink( name );
767 if (ret)
769 NtDeleteValueKey( control_key, &string );
770 NtClose( control_key );
771 return ret;
774 iface->enabled = enable;
776 len = offsetof(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name[namelen + 1]);
778 if ((broadcast = heap_alloc( len )))
780 broadcast->dbcc_size = len;
781 broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
782 broadcast->dbcc_reserved = 0;
783 broadcast->dbcc_classguid = iface->interface_class;
784 lstrcpynW( broadcast->dbcc_name, name->Buffer, namelen + 1 );
785 if (namelen > 1) broadcast->dbcc_name[1] = '\\';
786 send_devicechange( enable ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, broadcast, len );
787 heap_free( broadcast );
789 return ret;
792 /***********************************************************************
793 * IoSetDevicePropertyData (NTOSKRNL.EXE.@)
795 NTSTATUS WINAPI IoSetDevicePropertyData( DEVICE_OBJECT *device, const DEVPROPKEY *property_key, LCID lcid,
796 ULONG flags, DEVPROPTYPE type, ULONG size, void *data )
798 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
799 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
800 NTSTATUS status;
801 HDEVINFO set;
803 TRACE( "device %p, property_key %s, lcid %#x, flags %#x, type %#x, size %u, data %p.\n",
804 device, debugstr_propkey(property_key), lcid, flags, type, size, data );
806 /* flags is always treated as PLUGPLAY_PROPERTY_PERSISTENT starting with Win 8 / 2012 */
808 if (lcid != LOCALE_NEUTRAL) FIXME( "only LOCALE_NEUTRAL is supported\n" );
810 if ((status = get_device_instance_id( device, device_instance_id ))) return status;
812 if ((set = SetupDiCreateDeviceInfoList( &GUID_NULL, NULL )) == INVALID_HANDLE_VALUE)
814 ERR( "Failed to create device list, error %#x.\n", GetLastError() );
815 return GetLastError();
818 if (!SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device ))
820 ERR( "Failed to open device, error %#x.\n", GetLastError() );
821 SetupDiDestroyDeviceInfoList( set );
822 return GetLastError();
825 if (!SetupDiSetDevicePropertyW( set, &sp_device, property_key, type, data, size, 0 ))
827 ERR( "Failed to set property, error %#x.\n", GetLastError() );
828 SetupDiDestroyDeviceInfoList( set );
829 return GetLastError();
832 SetupDiDestroyDeviceInfoList( set );
834 return STATUS_SUCCESS;
837 /***********************************************************************
838 * IoRegisterDeviceInterface (NTOSKRNL.EXE.@)
840 NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *class_guid,
841 UNICODE_STRING *refstr, UNICODE_STRING *symbolic_link)
843 SP_DEVICE_INTERFACE_DATA sp_iface = {sizeof(sp_iface)};
844 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
845 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
846 SP_DEVICE_INTERFACE_DETAIL_DATA_W *data;
847 NTSTATUS status = STATUS_SUCCESS;
848 UNICODE_STRING device_path;
849 struct device_interface *iface;
850 struct wine_rb_entry *entry;
851 DWORD required;
852 HDEVINFO set;
854 TRACE("device %p, class_guid %s, refstr %s, symbolic_link %p.\n",
855 device, debugstr_guid(class_guid), debugstr_us(refstr), symbolic_link);
857 if ((status = get_device_instance_id( device, device_instance_id )))
858 return status;
860 set = SetupDiGetClassDevsW( class_guid, NULL, NULL, DIGCF_DEVICEINTERFACE );
861 if (set == INVALID_HANDLE_VALUE) return STATUS_UNSUCCESSFUL;
863 if (!SetupDiCreateDeviceInfoW( set, device_instance_id, class_guid, NULL, NULL, 0, &sp_device )
864 && !SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device ))
866 ERR("Failed to create device %s, error %#x.\n", debugstr_w(device_instance_id), GetLastError());
867 return GetLastError();
870 if (!SetupDiCreateDeviceInterfaceW( set, &sp_device, class_guid, refstr ? refstr->Buffer : NULL, 0, &sp_iface ))
871 return STATUS_UNSUCCESSFUL;
873 required = 0;
874 SetupDiGetDeviceInterfaceDetailW( set, &sp_iface, NULL, 0, &required, NULL );
875 if (required == 0) return STATUS_UNSUCCESSFUL;
877 data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, required );
878 data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
880 if (!SetupDiGetDeviceInterfaceDetailW( set, &sp_iface, data, required, NULL, NULL ))
882 HeapFree( GetProcessHeap(), 0, data );
883 return STATUS_UNSUCCESSFUL;
886 data->DevicePath[1] = '?';
887 TRACE("Returning path %s.\n", debugstr_w(data->DevicePath));
888 RtlCreateUnicodeString( &device_path, data->DevicePath);
890 entry = wine_rb_get( &device_interfaces, &device_path );
891 if (entry)
893 iface = WINE_RB_ENTRY_VALUE( entry, struct device_interface, entry );
894 if (iface->enabled)
895 ERR("Device interface %s is still enabled.\n", debugstr_us(&iface->symbolic_link));
897 else
899 iface = heap_alloc_zero( sizeof(struct device_interface) );
900 RtlCreateUnicodeString(&iface->symbolic_link, data->DevicePath);
901 if (wine_rb_put( &device_interfaces, &iface->symbolic_link, &iface->entry ))
902 ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface->symbolic_link));
905 iface->device = device;
906 iface->interface_class = *class_guid;
907 if (symbolic_link)
908 RtlCreateUnicodeString( symbolic_link, data->DevicePath);
910 HeapFree( GetProcessHeap(), 0, data );
912 RtlFreeUnicodeString( &device_path );
914 return status;
917 /***********************************************************************
918 * IoOpenDeviceRegistryKey (NTOSKRNL.EXE.@)
920 NTSTATUS WINAPI IoOpenDeviceRegistryKey( DEVICE_OBJECT *device, ULONG type, ACCESS_MASK access, HANDLE *key )
922 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
923 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
924 NTSTATUS status;
925 HDEVINFO set;
927 TRACE("device %p, type %#x, access %#x, key %p.\n", device, type, access, key);
929 if ((status = get_device_instance_id( device, device_instance_id )))
931 ERR("Failed to get device instance ID, error %#x.\n", status);
932 return status;
935 set = SetupDiCreateDeviceInfoList( &GUID_NULL, NULL );
937 SetupDiOpenDeviceInfoW( set, device_instance_id, NULL, 0, &sp_device );
939 *key = SetupDiOpenDevRegKey( set, &sp_device, DICS_FLAG_GLOBAL, 0, type, access );
940 SetupDiDestroyDeviceInfoList( set );
941 if (*key == INVALID_HANDLE_VALUE)
942 return GetLastError();
943 return STATUS_SUCCESS;
946 /***********************************************************************
947 * PoSetPowerState (NTOSKRNL.EXE.@)
949 POWER_STATE WINAPI PoSetPowerState( DEVICE_OBJECT *device, POWER_STATE_TYPE type, POWER_STATE state)
951 FIXME("device %p, type %u, state %u, stub!\n", device, type, state.DeviceState);
952 return state;
955 /*****************************************************
956 * PoStartNextPowerIrp (NTOSKRNL.EXE.@)
958 void WINAPI PoStartNextPowerIrp( IRP *irp )
960 FIXME("irp %p, stub!\n", irp);
963 /*****************************************************
964 * PoCallDriver (NTOSKRNL.EXE.@)
966 NTSTATUS WINAPI PoCallDriver( DEVICE_OBJECT *device, IRP *irp )
968 TRACE("device %p, irp %p.\n", device, irp);
969 return IoCallDriver( device, irp );
972 static DRIVER_OBJECT *pnp_manager;
974 struct root_pnp_device
976 WCHAR id[MAX_DEVICE_ID_LEN];
977 struct list entry;
978 DEVICE_OBJECT *device;
981 static struct root_pnp_device *find_root_pnp_device( struct wine_driver *driver, const WCHAR *id )
983 struct root_pnp_device *device;
985 LIST_FOR_EACH_ENTRY( device, &driver->root_pnp_devices, struct root_pnp_device, entry )
987 if (!wcsicmp( id, device->id ))
988 return device;
991 return NULL;
994 static NTSTATUS WINAPI pnp_manager_device_pnp( DEVICE_OBJECT *device, IRP *irp )
996 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
997 struct root_pnp_device *root_device = device->DeviceExtension;
998 NTSTATUS status;
1000 TRACE("device %p, irp %p, minor function %#x.\n", device, irp, stack->MinorFunction);
1002 switch (stack->MinorFunction)
1004 case IRP_MN_QUERY_DEVICE_RELATIONS:
1005 /* The FDO above already handled this, so return the same status. */
1006 break;
1007 case IRP_MN_START_DEVICE:
1008 case IRP_MN_SURPRISE_REMOVAL:
1009 /* Nothing to do. */
1010 irp->IoStatus.u.Status = STATUS_SUCCESS;
1011 break;
1012 case IRP_MN_REMOVE_DEVICE:
1013 list_remove( &root_device->entry );
1014 irp->IoStatus.u.Status = STATUS_SUCCESS;
1015 break;
1016 case IRP_MN_QUERY_CAPABILITIES:
1017 irp->IoStatus.u.Status = STATUS_SUCCESS;
1018 break;
1019 case IRP_MN_QUERY_ID:
1021 BUS_QUERY_ID_TYPE type = stack->Parameters.QueryId.IdType;
1022 WCHAR *id, *p;
1024 TRACE("Received IRP_MN_QUERY_ID, type %#x.\n", type);
1026 switch (type)
1028 case BusQueryDeviceID:
1029 p = wcsrchr( root_device->id, '\\' );
1030 if ((id = ExAllocatePool( NonPagedPool, (p - root_device->id + 1) * sizeof(WCHAR) )))
1032 memcpy( id, root_device->id, (p - root_device->id) * sizeof(WCHAR) );
1033 id[p - root_device->id] = 0;
1034 irp->IoStatus.Information = (ULONG_PTR)id;
1035 irp->IoStatus.u.Status = STATUS_SUCCESS;
1037 else
1039 irp->IoStatus.Information = 0;
1040 irp->IoStatus.u.Status = STATUS_NO_MEMORY;
1042 break;
1043 case BusQueryInstanceID:
1044 p = wcsrchr( root_device->id, '\\' );
1045 if ((id = ExAllocatePool( NonPagedPool, (wcslen( p + 1 ) + 1) * sizeof(WCHAR) )))
1047 wcscpy( id, p + 1 );
1048 irp->IoStatus.Information = (ULONG_PTR)id;
1049 irp->IoStatus.u.Status = STATUS_SUCCESS;
1051 else
1053 irp->IoStatus.Information = 0;
1054 irp->IoStatus.u.Status = STATUS_NO_MEMORY;
1056 break;
1057 default:
1058 FIXME("Unhandled IRP_MN_QUERY_ID type %#x.\n", type);
1060 break;
1062 default:
1063 FIXME("Unhandled PnP request %#x.\n", stack->MinorFunction);
1066 status = irp->IoStatus.u.Status;
1067 IoCompleteRequest( irp, IO_NO_INCREMENT );
1068 return status;
1071 static NTSTATUS WINAPI pnp_manager_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *keypath )
1073 pnp_manager = driver;
1074 driver->MajorFunction[IRP_MJ_PNP] = pnp_manager_device_pnp;
1075 return STATUS_SUCCESS;
1078 void pnp_manager_start(void)
1080 static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','P','n','p','M','a','n','a','g','e','r',0};
1081 WCHAR endpoint[] = L"\\pipe\\wine_plugplay";
1082 WCHAR protseq[] = L"ncalrpc";
1083 UNICODE_STRING driver_nameU;
1084 RPC_WSTR binding_str;
1085 NTSTATUS status;
1086 RPC_STATUS err;
1088 RtlInitUnicodeString( &driver_nameU, driver_nameW );
1089 if ((status = IoCreateDriver( &driver_nameU, pnp_manager_driver_entry )))
1090 ERR("Failed to create PnP manager driver, status %#x.\n", status);
1092 if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
1094 ERR("RpcStringBindingCompose() failed, error %#x\n", err);
1095 return;
1097 err = RpcBindingFromStringBindingW( binding_str, &plugplay_binding_handle );
1098 RpcStringFreeW( &binding_str );
1099 if (err)
1100 ERR("RpcBindingFromStringBinding() failed, error %#x\n", err);
1103 void pnp_manager_stop_driver( struct wine_driver *driver )
1105 struct root_pnp_device *device, *next;
1107 LIST_FOR_EACH_ENTRY_SAFE( device, next, &driver->root_pnp_devices, struct root_pnp_device, entry )
1109 send_remove_device_irp( device->device, IRP_MN_SURPRISE_REMOVAL );
1110 send_remove_device_irp( device->device, IRP_MN_REMOVE_DEVICE );
1114 void pnp_manager_stop(void)
1116 IoDeleteDriver( pnp_manager );
1117 RpcBindingFree( &plugplay_binding_handle );
1120 void CDECL wine_enumerate_root_devices( const WCHAR *driver_name )
1122 static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
1123 static const WCHAR rootW[] = {'R','O','O','T',0};
1124 WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(driverW)], id[MAX_DEVICE_ID_LEN];
1125 SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
1126 struct list new_list = LIST_INIT(new_list);
1127 struct root_pnp_device *pnp_device, *next;
1128 struct wine_driver *driver;
1129 DEVICE_OBJECT *device;
1130 NTSTATUS status;
1131 unsigned int i;
1132 HDEVINFO set;
1134 TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name));
1136 driver = get_driver( driver_name );
1138 set = SetupDiGetClassDevsW( NULL, rootW, NULL, DIGCF_ALLCLASSES );
1139 if (set == INVALID_HANDLE_VALUE)
1141 ERR("Failed to build device set, error %#x.\n", GetLastError());
1142 return;
1145 for (i = 0; SetupDiEnumDeviceInfo( set, i, &sp_device ); ++i)
1147 if (!SetupDiGetDeviceRegistryPropertyW( set, &sp_device, SPDRP_SERVICE,
1148 NULL, (BYTE *)buffer, sizeof(buffer), NULL )
1149 || lstrcmpiW( buffer, driver_name ))
1151 continue;
1154 SetupDiGetDeviceInstanceIdW( set, &sp_device, id, ARRAY_SIZE(id), NULL );
1156 if ((pnp_device = find_root_pnp_device( driver, id )))
1158 TRACE("Found device %s already enumerated.\n", debugstr_w(id));
1159 list_remove( &pnp_device->entry );
1160 list_add_tail( &new_list, &pnp_device->entry );
1161 continue;
1164 TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id));
1166 if ((status = IoCreateDevice( pnp_manager, sizeof(struct root_pnp_device), NULL,
1167 FILE_DEVICE_CONTROLLER, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &device )))
1169 ERR("Failed to create root-enumerated PnP device %s, status %#x.\n", debugstr_w(id), status);
1170 continue;
1173 pnp_device = device->DeviceExtension;
1174 wcscpy( pnp_device->id, id );
1175 pnp_device->device = device;
1176 list_add_tail( &new_list, &pnp_device->entry );
1178 start_device( device, set, &sp_device );
1181 LIST_FOR_EACH_ENTRY_SAFE( pnp_device, next, &driver->root_pnp_devices, struct root_pnp_device, entry )
1183 TRACE("Removing device %s.\n", debugstr_w(pnp_device->id));
1185 send_remove_device_irp( pnp_device->device, IRP_MN_SURPRISE_REMOVAL );
1186 send_remove_device_irp( pnp_device->device, IRP_MN_REMOVE_DEVICE );
1189 list_move_head( &driver->root_pnp_devices, &new_list );
1191 SetupDiDestroyDeviceInfoList(set);