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 "ntoskrnl_private.h"
29 #include "wine/exception.h"
30 #include "wine/heap.h"
35 DEFINE_GUID(GUID_NULL
,0,0,0,0,0,0,0,0,0,0,0);
37 WINE_DEFAULT_DEBUG_CHANNEL(plugplay
);
39 DECLARE_CRITICAL_SECTION(invalidated_devices_cs
);
40 static CONDITION_VARIABLE invalidated_devices_cv
= CONDITION_VARIABLE_INIT
;
42 static DEVICE_OBJECT
**invalidated_devices
;
43 static size_t invalidated_devices_count
;
45 static inline const char *debugstr_propkey( const DEVPROPKEY
*id
)
47 if (!id
) return "(null)";
48 return wine_dbg_sprintf( "{%s,%04lx}", wine_dbgstr_guid( &id
->fmtid
), id
->pid
);
51 #define MAX_SERVICE_NAME 260
53 struct device_interface
55 struct wine_rb_entry entry
;
57 UNICODE_STRING symbolic_link
;
58 DEVICE_OBJECT
*device
;
63 static int interface_rb_compare( const void *key
, const struct wine_rb_entry
*entry
)
65 const struct device_interface
*iface
= WINE_RB_ENTRY_VALUE( entry
, const struct device_interface
, entry
);
66 const UNICODE_STRING
*k
= key
;
68 return RtlCompareUnicodeString( k
, &iface
->symbolic_link
, FALSE
);
71 static struct wine_rb_tree device_interfaces
= { interface_rb_compare
};
73 static NTSTATUS
get_device_id( DEVICE_OBJECT
*device
, BUS_QUERY_ID_TYPE type
, WCHAR
**id
)
75 IO_STACK_LOCATION
*irpsp
;
76 IO_STATUS_BLOCK irp_status
;
80 device
= IoGetAttachedDevice( device
);
82 KeInitializeEvent( &event
, NotificationEvent
, FALSE
);
83 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_PNP
, device
, NULL
, 0, NULL
, &event
, &irp_status
)))
84 return STATUS_NO_MEMORY
;
86 irpsp
= IoGetNextIrpStackLocation( irp
);
87 irpsp
->MinorFunction
= IRP_MN_QUERY_ID
;
88 irpsp
->Parameters
.QueryId
.IdType
= type
;
90 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
91 if (IoCallDriver( device
, irp
) == STATUS_PENDING
)
92 KeWaitForSingleObject( &event
, Executive
, KernelMode
, FALSE
, NULL
);
94 *id
= (WCHAR
*)irp_status
.Information
;
95 return irp_status
.Status
;
98 static NTSTATUS
send_pnp_irp( DEVICE_OBJECT
*device
, UCHAR minor
)
100 IO_STACK_LOCATION
*irpsp
;
101 IO_STATUS_BLOCK irp_status
;
105 device
= IoGetAttachedDevice( device
);
107 KeInitializeEvent( &event
, NotificationEvent
, FALSE
);
108 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_PNP
, device
, NULL
, 0, NULL
, NULL
, &irp_status
)))
109 return STATUS_NO_MEMORY
;
111 irpsp
= IoGetNextIrpStackLocation( irp
);
112 irpsp
->MinorFunction
= minor
;
114 irpsp
->Parameters
.StartDevice
.AllocatedResources
= NULL
;
115 irpsp
->Parameters
.StartDevice
.AllocatedResourcesTranslated
= NULL
;
117 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
118 if (IoCallDriver( device
, irp
) == STATUS_PENDING
)
119 KeWaitForSingleObject( &event
, Executive
, KernelMode
, FALSE
, NULL
);
121 return irp_status
.Status
;
124 static NTSTATUS
get_device_instance_id( DEVICE_OBJECT
*device
, WCHAR
*buffer
)
126 static const WCHAR backslashW
[] = {'\\',0};
130 if ((status
= get_device_id( device
, BusQueryDeviceID
, &id
)))
132 ERR("Failed to get device ID, status %#lx.\n", status
);
136 lstrcpyW( buffer
, id
);
139 if ((status
= get_device_id( device
, BusQueryInstanceID
, &id
)))
141 ERR("Failed to get instance ID, status %#lx.\n", status
);
145 lstrcatW( buffer
, backslashW
);
146 lstrcatW( buffer
, id
);
149 TRACE("Returning ID %s.\n", debugstr_w(buffer
));
151 return STATUS_SUCCESS
;
154 static NTSTATUS
get_device_caps( DEVICE_OBJECT
*device
, DEVICE_CAPABILITIES
*caps
)
156 IO_STACK_LOCATION
*irpsp
;
157 IO_STATUS_BLOCK irp_status
;
161 memset( caps
, 0, sizeof(*caps
) );
162 caps
->Size
= sizeof(*caps
);
164 caps
->Address
= 0xffffffff;
165 caps
->UINumber
= 0xffffffff;
167 device
= IoGetAttachedDevice( device
);
169 KeInitializeEvent( &event
, NotificationEvent
, FALSE
);
170 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_PNP
, device
, NULL
, 0, NULL
, NULL
, &irp_status
)))
171 return STATUS_NO_MEMORY
;
173 irpsp
= IoGetNextIrpStackLocation( irp
);
174 irpsp
->MinorFunction
= IRP_MN_QUERY_CAPABILITIES
;
175 irpsp
->Parameters
.DeviceCapabilities
.Capabilities
= caps
;
177 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
178 if (IoCallDriver( device
, irp
) == STATUS_PENDING
)
179 KeWaitForSingleObject( &event
, Executive
, KernelMode
, FALSE
, NULL
);
181 return irp_status
.Status
;
184 static void load_function_driver( DEVICE_OBJECT
*device
, HDEVINFO set
, SP_DEVINFO_DATA
*sp_device
)
186 static const WCHAR driverW
[] = {'\\','D','r','i','v','e','r','\\',0};
187 WCHAR buffer
[MAX_SERVICE_NAME
+ ARRAY_SIZE(servicesW
)];
188 WCHAR driver
[MAX_SERVICE_NAME
] = {0};
189 DRIVER_OBJECT
*driver_obj
;
190 UNICODE_STRING string
;
193 if (!SetupDiGetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_SERVICE
,
194 NULL
, (BYTE
*)driver
, sizeof(driver
), NULL
))
196 WARN("No driver registered for device %p.\n", device
);
200 lstrcpyW( buffer
, servicesW
);
201 lstrcatW( buffer
, driver
);
202 RtlInitUnicodeString( &string
, buffer
);
203 status
= ZwLoadDriver( &string
);
204 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_IMAGE_ALREADY_LOADED
)
206 ERR("Failed to load driver %s, status %#lx.\n", debugstr_w(driver
), status
);
210 lstrcpyW( buffer
, driverW
);
211 lstrcatW( buffer
, driver
);
212 RtlInitUnicodeString( &string
, buffer
);
213 if (ObReferenceObjectByName( &string
, OBJ_CASE_INSENSITIVE
, NULL
,
214 0, NULL
, KernelMode
, NULL
, (void **)&driver_obj
) != STATUS_SUCCESS
)
216 ERR("Failed to locate loaded driver %s.\n", debugstr_w(driver
));
220 TRACE("Calling AddDevice routine %p.\n", driver_obj
->DriverExtension
->AddDevice
);
221 if (driver_obj
->DriverExtension
->AddDevice
)
222 status
= driver_obj
->DriverExtension
->AddDevice( driver_obj
, device
);
224 status
= STATUS_NOT_IMPLEMENTED
;
225 TRACE("AddDevice routine %p returned %#lx.\n", driver_obj
->DriverExtension
->AddDevice
, status
);
227 ObDereferenceObject( driver_obj
);
229 if (status
!= STATUS_SUCCESS
)
230 ERR("AddDevice failed for driver %s, status %#lx.\n", debugstr_w(driver
), status
);
233 /* Return the total number of characters in a REG_MULTI_SZ string, including
234 * the final terminating null. */
235 static size_t sizeof_multiszW( const WCHAR
*str
)
238 for (p
= str
; *p
; p
+= lstrlenW(p
) + 1);
242 /* This does almost the same thing as UpdateDriverForPlugAndPlayDevices(),
243 * except that we don't know the INF path beforehand. */
244 static BOOL
install_device_driver( DEVICE_OBJECT
*device
, HDEVINFO set
, SP_DEVINFO_DATA
*sp_device
)
246 static const DWORD dif_list
[] =
249 DIF_SELECTBESTCOMPATDRV
,
251 DIF_INSTALLDEVICEFILES
,
252 DIF_REGISTER_COINSTALLERS
,
253 DIF_INSTALLINTERFACES
,
255 DIF_NEWDEVICEWIZARD_FINISHINSTALL
,
257 static const DWORD config_flags
= 0;
263 if ((status
= get_device_id( device
, BusQueryHardwareIDs
, &ids
)) || !ids
)
265 ERR("Failed to get hardware IDs, status %#lx.\n", status
);
269 SetupDiSetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_HARDWAREID
, (BYTE
*)ids
,
270 sizeof_multiszW( ids
) * sizeof(WCHAR
) );
273 if ((status
= get_device_id( device
, BusQueryCompatibleIDs
, &ids
)) || !ids
)
275 ERR("Failed to get compatible IDs, status %#lx.\n", status
);
279 SetupDiSetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_COMPATIBLEIDS
, (BYTE
*)ids
,
280 sizeof_multiszW( ids
) * sizeof(WCHAR
) );
283 /* Set the config flags. setupapi won't do this for us if we couldn't find
284 * a driver to install, but raw devices should still have this key
287 if (!SetupDiSetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_CONFIGFLAGS
,
288 (BYTE
*)&config_flags
, sizeof(config_flags
) ))
289 ERR("Failed to set config flags, error %#lx.\n", GetLastError());
291 if (!SetupDiBuildDriverInfoList( set
, sp_device
, SPDIT_COMPATDRIVER
))
293 ERR("Failed to build compatible driver list, error %#lx.\n", GetLastError());
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 %#lx failed, error %#lx.\n", dif_list
[i
], GetLastError());
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
)
315 send_pnp_irp( device
, IRP_MN_START_DEVICE
);
318 static void enumerate_new_device( DEVICE_OBJECT
*device
, HDEVINFO set
)
320 static const WCHAR infpathW
[] = {'I','n','f','P','a','t','h',0};
322 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
323 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
324 DEVICE_CAPABILITIES caps
;
325 BOOL need_driver
= TRUE
;
330 if (get_device_instance_id( device
, device_instance_id
))
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 %#lx.\n", debugstr_w(device_instance_id
), GetLastError());
340 TRACE("Creating new device %s.\n", debugstr_w(device_instance_id
));
342 /* Check if the device already has a driver registered; if not, find one
344 key
= SetupDiOpenDevRegKey( set
, &sp_device
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, KEY_READ
);
345 if (key
!= INVALID_HANDLE_VALUE
)
347 if (!RegQueryValueExW( key
, infpathW
, NULL
, NULL
, NULL
, NULL
))
352 if ((status
= get_device_caps( device
, &caps
)))
354 ERR("Failed to get caps for device %s, status %#lx.\n", debugstr_w(device_instance_id
), status
);
358 if (!get_device_id(device
, BusQueryContainerID
, &id
) && id
)
360 SetupDiSetDeviceRegistryPropertyW( set
, &sp_device
, SPDRP_BASE_CONTAINERID
, (BYTE
*)id
,
361 (lstrlenW( id
) + 1) * sizeof(WCHAR
) );
365 if (need_driver
&& !install_device_driver( device
, set
, &sp_device
) && !caps
.RawDeviceOK
)
367 ERR("Unable to install a function driver for device %s.\n", debugstr_w(device_instance_id
));
371 start_device( device
, set
, &sp_device
);
374 static void send_remove_device_irp( DEVICE_OBJECT
*device
, UCHAR code
)
376 struct wine_device
*wine_device
= CONTAINING_RECORD(device
, struct wine_device
, device_obj
);
378 TRACE( "Removing device %p, code %x.\n", device
, code
);
380 if (wine_device
->children
)
383 for (i
= 0; i
< wine_device
->children
->Count
; ++i
)
384 send_remove_device_irp( wine_device
->children
->Objects
[i
], code
);
387 send_pnp_irp( device
, code
);
390 static void remove_device( DEVICE_OBJECT
*device
)
392 send_remove_device_irp( device
, IRP_MN_SURPRISE_REMOVAL
);
393 send_remove_device_irp( device
, IRP_MN_REMOVE_DEVICE
);
396 static BOOL
device_in_list( const DEVICE_RELATIONS
*list
, const DEVICE_OBJECT
*device
)
399 for (i
= 0; i
< list
->Count
; ++i
)
401 if (list
->Objects
[i
] == device
)
407 static void handle_bus_relations( DEVICE_OBJECT
*parent
)
409 struct wine_device
*wine_parent
= CONTAINING_RECORD(parent
, struct wine_device
, device_obj
);
410 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
411 DEVICE_RELATIONS
*relations
;
412 IO_STATUS_BLOCK irp_status
;
413 IO_STACK_LOCATION
*irpsp
;
419 TRACE( "(%p)\n", parent
);
421 set
= SetupDiCreateDeviceInfoList( NULL
, NULL
);
423 parent
= IoGetAttachedDevice( parent
);
425 KeInitializeEvent( &event
, NotificationEvent
, FALSE
);
426 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_PNP
, parent
, NULL
, 0, NULL
, &event
, &irp_status
)))
428 SetupDiDestroyDeviceInfoList( set
);
432 irpsp
= IoGetNextIrpStackLocation( irp
);
433 irpsp
->MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
434 irpsp
->Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
436 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
437 if (IoCallDriver( parent
, irp
) == STATUS_PENDING
)
438 KeWaitForSingleObject( &event
, Executive
, KernelMode
, FALSE
, NULL
);
440 relations
= (DEVICE_RELATIONS
*)irp_status
.Information
;
441 if (irp_status
.Status
)
443 ERR("Failed to enumerate child devices, status %#lx.\n", irp_status
.Status
);
444 SetupDiDestroyDeviceInfoList( set
);
448 TRACE("Got %lu devices.\n", relations
->Count
);
450 for (i
= 0; i
< relations
->Count
; ++i
)
452 DEVICE_OBJECT
*child
= relations
->Objects
[i
];
454 if (!wine_parent
->children
|| !device_in_list( wine_parent
->children
, child
))
456 TRACE("Adding new device %p.\n", child
);
457 enumerate_new_device( child
, set
);
461 if (wine_parent
->children
)
463 for (i
= 0; i
< wine_parent
->children
->Count
; ++i
)
465 DEVICE_OBJECT
*child
= wine_parent
->children
->Objects
[i
];
467 if (!device_in_list( relations
, child
))
469 TRACE("Removing device %p.\n", child
);
470 remove_device( child
);
472 ObDereferenceObject( child
);
476 ExFreePool( wine_parent
->children
);
477 wine_parent
->children
= relations
;
479 SetupDiDestroyDeviceInfoList( set
);
482 /***********************************************************************
483 * IoInvalidateDeviceRelations (NTOSKRNL.EXE.@)
485 void WINAPI
IoInvalidateDeviceRelations( DEVICE_OBJECT
*device_object
, DEVICE_RELATION_TYPE type
)
487 TRACE("device %p, type %#x.\n", device_object
, type
);
492 EnterCriticalSection( &invalidated_devices_cs
);
493 invalidated_devices
= realloc( invalidated_devices
,
494 (invalidated_devices_count
+ 1) * sizeof(*invalidated_devices
) );
495 invalidated_devices
[invalidated_devices_count
++] = device_object
;
496 LeaveCriticalSection( &invalidated_devices_cs
);
497 WakeConditionVariable( &invalidated_devices_cv
);
501 FIXME("Unhandled relation %#x.\n", type
);
506 /***********************************************************************
507 * IoGetDeviceProperty (NTOSKRNL.EXE.@)
509 NTSTATUS WINAPI
IoGetDeviceProperty( DEVICE_OBJECT
*device
, DEVICE_REGISTRY_PROPERTY property
,
510 ULONG length
, void *buffer
, ULONG
*needed
)
512 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
513 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
514 DWORD sp_property
= -1;
518 TRACE("device %p, property %u, length %lu, buffer %p, needed %p.\n",
519 device
, property
, length
, buffer
, needed
);
523 case DevicePropertyEnumeratorName
:
527 status
= get_device_id( device
, BusQueryInstanceID
, &id
);
528 if (status
!= STATUS_SUCCESS
)
530 ERR("Failed to get instance ID, status %#lx.\n", status
);
535 ptr
= wcschr( id
, '\\' );
538 *needed
= sizeof(WCHAR
) * (lstrlenW(id
) + 1);
539 if (length
>= *needed
)
540 memcpy( buffer
, id
, *needed
);
542 status
= STATUS_BUFFER_TOO_SMALL
;
547 case DevicePropertyPhysicalDeviceObjectName
:
549 ULONG used_len
, len
= length
+ sizeof(OBJECT_NAME_INFORMATION
);
550 OBJECT_NAME_INFORMATION
*name
= HeapAlloc(GetProcessHeap(), 0, len
);
553 status
= ObOpenObjectByPointer( device
, OBJ_KERNEL_HANDLE
, NULL
, 0, NULL
, KernelMode
, &handle
);
556 status
= NtQueryObject( handle
, ObjectNameInformation
, name
, len
, &used_len
);
559 if (status
== STATUS_SUCCESS
)
561 /* Ensure room for NULL termination */
562 if (length
>= name
->Name
.MaximumLength
)
563 memcpy(buffer
, name
->Name
.Buffer
, name
->Name
.MaximumLength
);
565 status
= STATUS_BUFFER_TOO_SMALL
;
566 *needed
= name
->Name
.MaximumLength
;
570 if (status
== STATUS_INFO_LENGTH_MISMATCH
||
571 status
== STATUS_BUFFER_OVERFLOW
)
573 status
= STATUS_BUFFER_TOO_SMALL
;
574 *needed
= used_len
- sizeof(OBJECT_NAME_INFORMATION
);
579 HeapFree(GetProcessHeap(), 0, name
);
582 case DevicePropertyDeviceDescription
:
583 sp_property
= SPDRP_DEVICEDESC
;
585 case DevicePropertyHardwareID
:
586 sp_property
= SPDRP_HARDWAREID
;
588 case DevicePropertyCompatibleIDs
:
589 sp_property
= SPDRP_COMPATIBLEIDS
;
591 case DevicePropertyClassName
:
592 sp_property
= SPDRP_CLASS
;
594 case DevicePropertyClassGuid
:
595 sp_property
= SPDRP_CLASSGUID
;
597 case DevicePropertyManufacturer
:
598 sp_property
= SPDRP_MFG
;
600 case DevicePropertyFriendlyName
:
601 sp_property
= SPDRP_FRIENDLYNAME
;
603 case DevicePropertyLocationInformation
:
604 sp_property
= SPDRP_LOCATION_INFORMATION
;
606 case DevicePropertyBusTypeGuid
:
607 sp_property
= SPDRP_BUSTYPEGUID
;
609 case DevicePropertyLegacyBusType
:
610 sp_property
= SPDRP_LEGACYBUSTYPE
;
612 case DevicePropertyBusNumber
:
613 sp_property
= SPDRP_BUSNUMBER
;
615 case DevicePropertyAddress
:
616 sp_property
= SPDRP_ADDRESS
;
618 case DevicePropertyUINumber
:
619 sp_property
= SPDRP_UI_NUMBER
;
621 case DevicePropertyInstallState
:
622 sp_property
= SPDRP_INSTALL_STATE
;
624 case DevicePropertyRemovalPolicy
:
625 sp_property
= SPDRP_REMOVAL_POLICY
;
628 FIXME("Unhandled property %u.\n", property
);
629 return STATUS_NOT_IMPLEMENTED
;
632 if ((status
= get_device_instance_id( device
, device_instance_id
)))
635 if ((set
= SetupDiCreateDeviceInfoList( &GUID_NULL
, NULL
)) == INVALID_HANDLE_VALUE
)
637 ERR("Failed to create device list, error %#lx.\n", GetLastError());
638 return GetLastError();
641 if (!SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
))
643 ERR("Failed to open device, error %#lx.\n", GetLastError());
644 SetupDiDestroyDeviceInfoList( set
);
645 return GetLastError();
648 if (SetupDiGetDeviceRegistryPropertyW( set
, &sp_device
, sp_property
, NULL
, buffer
, length
, needed
))
649 status
= STATUS_SUCCESS
;
651 status
= GetLastError();
653 SetupDiDestroyDeviceInfoList( set
);
658 static NTSTATUS
create_device_symlink( DEVICE_OBJECT
*device
, UNICODE_STRING
*symlink_name
)
660 UNICODE_STRING device_nameU
;
665 ret
= IoGetDeviceProperty( device
, DevicePropertyPhysicalDeviceObjectName
, 0, NULL
, &len
);
666 if (ret
!= STATUS_BUFFER_TOO_SMALL
)
669 device_name
= heap_alloc( len
);
670 ret
= IoGetDeviceProperty( device
, DevicePropertyPhysicalDeviceObjectName
, len
, device_name
, &len
);
673 heap_free( device_name
);
677 RtlInitUnicodeString( &device_nameU
, device_name
);
678 ret
= IoCreateSymbolicLink( symlink_name
, &device_nameU
);
679 heap_free( device_name
);
683 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate( SIZE_T len
)
685 return heap_alloc( len
);
688 void __RPC_USER
MIDL_user_free( void __RPC_FAR
*ptr
)
693 static LONG WINAPI
rpc_filter( EXCEPTION_POINTERS
*eptr
)
695 return I_RpcExceptionFilter( eptr
->ExceptionRecord
->ExceptionCode
);
698 static void send_devicechange( DWORD code
, void *data
, unsigned int size
)
702 plugplay_send_event( code
, data
, size
);
706 WARN("Failed to send event, exception %#lx.\n", GetExceptionCode());
711 /***********************************************************************
712 * IoSetDeviceInterfaceState (NTOSKRNL.EXE.@)
714 NTSTATUS WINAPI
IoSetDeviceInterfaceState( UNICODE_STRING
*name
, BOOLEAN enable
)
716 static const WCHAR DeviceClassesW
[] = {'\\','R','E','G','I','S','T','R','Y','\\',
717 'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
718 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
719 'C','o','n','t','r','o','l','\\',
720 'D','e','v','i','c','e','C','l','a','s','s','e','s','\\',0};
721 static const WCHAR slashW
[] = {'\\',0};
722 static const WCHAR hashW
[] = {'#',0};
724 size_t namelen
= name
->Length
/ sizeof(WCHAR
);
725 DEV_BROADCAST_DEVICEINTERFACE_W
*broadcast
;
726 struct device_interface
*iface
;
727 HANDLE iface_key
, control_key
;
728 OBJECT_ATTRIBUTES attr
= {0};
729 struct wine_rb_entry
*entry
;
730 UNICODE_STRING control
= RTL_CONSTANT_STRING( L
"Control" );
731 UNICODE_STRING linked
= RTL_CONSTANT_STRING( L
"Linked" );
732 WCHAR
*path
, *refstr
, *p
;
733 UNICODE_STRING string
;
738 TRACE("device %s, enable %u.\n", debugstr_us(name
), enable
);
740 entry
= wine_rb_get( &device_interfaces
, name
);
742 return STATUS_OBJECT_NAME_NOT_FOUND
;
744 iface
= WINE_RB_ENTRY_VALUE( entry
, struct device_interface
, entry
);
746 if (!enable
&& !iface
->enabled
)
747 return STATUS_OBJECT_NAME_NOT_FOUND
;
749 if (enable
&& iface
->enabled
)
750 return STATUS_OBJECT_NAME_EXISTS
;
752 for (p
= name
->Buffer
+ 4, refstr
= NULL
; p
< name
->Buffer
+ namelen
; p
++)
753 if (*p
== '\\') refstr
= p
;
754 if (!refstr
) refstr
= p
;
756 len
= lstrlenW(DeviceClassesW
) + 38 + 1 + namelen
+ 2 + 1;
758 if (!(path
= heap_alloc( len
* sizeof(WCHAR
) )))
759 return STATUS_NO_MEMORY
;
761 lstrcpyW( path
, DeviceClassesW
);
762 lstrcpynW( path
+ lstrlenW( path
), refstr
- 38, 39 );
763 lstrcatW( path
, slashW
);
764 p
= path
+ lstrlenW( path
);
765 lstrcpynW( path
+ lstrlenW( path
), name
->Buffer
, (refstr
- name
->Buffer
) + 1 );
766 p
[0] = p
[1] = p
[3] = '#';
767 lstrcatW( path
, slashW
);
768 lstrcatW( path
, hashW
);
769 if (refstr
< name
->Buffer
+ namelen
)
770 lstrcpynW( path
+ lstrlenW( path
), refstr
, name
->Buffer
+ namelen
- refstr
+ 1 );
772 attr
.Length
= sizeof(attr
);
773 attr
.ObjectName
= &string
;
774 RtlInitUnicodeString( &string
, path
);
775 ret
= NtOpenKey( &iface_key
, KEY_CREATE_SUB_KEY
, &attr
);
780 attr
.RootDirectory
= iface_key
;
781 attr
.ObjectName
= &control
;
782 ret
= NtCreateKey( &control_key
, KEY_SET_VALUE
, &attr
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
783 NtClose( iface_key
);
787 attr
.ObjectName
= &linked
;
788 ret
= NtSetValueKey( control_key
, &linked
, 0, REG_DWORD
, &data
, sizeof(data
) );
791 NtClose( control_key
);
796 ret
= create_device_symlink( iface
->device
, name
);
798 ret
= IoDeleteSymbolicLink( name
);
801 NtDeleteValueKey( control_key
, &linked
);
802 NtClose( control_key
);
806 iface
->enabled
= enable
;
808 len
= offsetof(DEV_BROADCAST_DEVICEINTERFACE_W
, dbcc_name
[namelen
+ 1]);
810 if ((broadcast
= heap_alloc( len
)))
812 broadcast
->dbcc_size
= len
;
813 broadcast
->dbcc_devicetype
= DBT_DEVTYP_DEVICEINTERFACE
;
814 broadcast
->dbcc_reserved
= 0;
815 broadcast
->dbcc_classguid
= iface
->interface_class
;
816 lstrcpynW( broadcast
->dbcc_name
, name
->Buffer
, namelen
+ 1 );
817 if (namelen
> 1) broadcast
->dbcc_name
[1] = '\\';
818 send_devicechange( enable
? DBT_DEVICEARRIVAL
: DBT_DEVICEREMOVECOMPLETE
, broadcast
, len
);
819 heap_free( broadcast
);
824 /***********************************************************************
825 * IoSetDevicePropertyData (NTOSKRNL.EXE.@)
827 NTSTATUS WINAPI
IoSetDevicePropertyData( DEVICE_OBJECT
*device
, const DEVPROPKEY
*property_key
, LCID lcid
,
828 ULONG flags
, DEVPROPTYPE type
, ULONG size
, void *data
)
830 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
831 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
835 TRACE( "device %p, property_key %s, lcid %#lx, flags %#lx, type %#lx, size %lu, data %p.\n",
836 device
, debugstr_propkey(property_key
), lcid
, flags
, type
, size
, data
);
838 /* flags is always treated as PLUGPLAY_PROPERTY_PERSISTENT starting with Win 8 / 2012 */
840 if (lcid
!= LOCALE_NEUTRAL
) FIXME( "only LOCALE_NEUTRAL is supported\n" );
842 if ((status
= get_device_instance_id( device
, device_instance_id
))) return status
;
844 if ((set
= SetupDiCreateDeviceInfoList( &GUID_NULL
, NULL
)) == INVALID_HANDLE_VALUE
)
846 ERR( "Failed to create device list, error %#lx.\n", GetLastError() );
847 return GetLastError();
850 if (!SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
))
852 ERR( "Failed to open device, error %#lx.\n", GetLastError() );
853 SetupDiDestroyDeviceInfoList( set
);
854 return GetLastError();
857 if (!SetupDiSetDevicePropertyW( set
, &sp_device
, property_key
, type
, data
, size
, 0 ))
859 ERR( "Failed to set property, error %#lx.\n", GetLastError() );
860 SetupDiDestroyDeviceInfoList( set
);
861 return GetLastError();
864 SetupDiDestroyDeviceInfoList( set
);
866 return STATUS_SUCCESS
;
869 /***********************************************************************
870 * IoRegisterDeviceInterface (NTOSKRNL.EXE.@)
872 NTSTATUS WINAPI
IoRegisterDeviceInterface(DEVICE_OBJECT
*device
, const GUID
*class_guid
,
873 UNICODE_STRING
*refstr
, UNICODE_STRING
*symbolic_link
)
875 SP_DEVICE_INTERFACE_DATA sp_iface
= {sizeof(sp_iface
)};
876 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
877 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
878 NTSTATUS status
= STATUS_SUCCESS
;
879 UNICODE_STRING device_path
;
880 struct device_interface
*iface
;
881 struct wine_rb_entry
*entry
;
885 TRACE("device %p, class_guid %s, refstr %s, symbolic_link %p.\n",
886 device
, debugstr_guid(class_guid
), debugstr_us(refstr
), symbolic_link
);
888 if ((status
= get_device_instance_id( device
, device_instance_id
)))
891 set
= SetupDiGetClassDevsW( class_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
892 if (set
== INVALID_HANDLE_VALUE
) return STATUS_UNSUCCESSFUL
;
894 if (!SetupDiCreateDeviceInfoW( set
, device_instance_id
, class_guid
, NULL
, NULL
, 0, &sp_device
)
895 && !SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
))
897 ERR("Failed to create device %s, error %#lx.\n", debugstr_w(device_instance_id
), GetLastError());
898 return GetLastError();
901 if (!SetupDiCreateDeviceInterfaceW( set
, &sp_device
, class_guid
, refstr
? refstr
->Buffer
: NULL
, 0, &sp_iface
))
902 return STATUS_UNSUCCESSFUL
;
904 /* setupapi mangles the case; construct the interface path manually. */
906 device_path
.Length
= (4 + wcslen( device_instance_id
) + 1 + 38) * sizeof(WCHAR
);
908 device_path
.Length
+= sizeof(WCHAR
) + refstr
->Length
;
909 device_path
.MaximumLength
= device_path
.Length
+ sizeof(WCHAR
);
911 device_path
.Buffer
= RtlAllocateHeap( GetProcessHeap(), 0, device_path
.MaximumLength
);
912 swprintf( device_path
.Buffer
, device_path
.MaximumLength
/ sizeof(WCHAR
),
913 L
"\\??\\%s#{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
914 device_instance_id
, class_guid
->Data1
, class_guid
->Data2
, class_guid
->Data3
,
915 class_guid
->Data4
[0], class_guid
->Data4
[1], class_guid
->Data4
[2], class_guid
->Data4
[3],
916 class_guid
->Data4
[4], class_guid
->Data4
[5], class_guid
->Data4
[6], class_guid
->Data4
[7] );
917 for (p
= device_path
.Buffer
+ 4; *p
; p
++)
925 wcscpy( p
, refstr
->Buffer
);
928 TRACE("Returning path %s.\n", debugstr_us(&device_path
));
930 entry
= wine_rb_get( &device_interfaces
, &device_path
);
933 iface
= WINE_RB_ENTRY_VALUE( entry
, struct device_interface
, entry
);
935 ERR("Device interface %s is still enabled.\n", debugstr_us(&iface
->symbolic_link
));
939 iface
= heap_alloc_zero( sizeof(struct device_interface
) );
940 RtlDuplicateUnicodeString( 1, &device_path
, &iface
->symbolic_link
);
941 if (wine_rb_put( &device_interfaces
, &iface
->symbolic_link
, &iface
->entry
))
942 ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface
->symbolic_link
));
945 iface
->device
= device
;
946 iface
->interface_class
= *class_guid
;
948 RtlDuplicateUnicodeString( 1, &device_path
, symbolic_link
);
950 RtlFreeUnicodeString( &device_path
);
955 /***********************************************************************
956 * IoOpenDeviceRegistryKey (NTOSKRNL.EXE.@)
958 NTSTATUS WINAPI
IoOpenDeviceRegistryKey( DEVICE_OBJECT
*device
, ULONG type
, ACCESS_MASK access
, HANDLE
*key
)
960 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
961 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
965 TRACE("device %p, type %#lx, access %#lx, key %p.\n", device
, type
, access
, key
);
967 if ((status
= get_device_instance_id( device
, device_instance_id
)))
969 ERR("Failed to get device instance ID, error %#lx.\n", status
);
973 set
= SetupDiCreateDeviceInfoList( &GUID_NULL
, NULL
);
975 SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
);
977 *key
= SetupDiOpenDevRegKey( set
, &sp_device
, DICS_FLAG_GLOBAL
, 0, type
, access
);
978 SetupDiDestroyDeviceInfoList( set
);
979 if (*key
== INVALID_HANDLE_VALUE
)
980 return GetLastError();
981 return STATUS_SUCCESS
;
984 /***********************************************************************
985 * PoSetPowerState (NTOSKRNL.EXE.@)
987 POWER_STATE WINAPI
PoSetPowerState( DEVICE_OBJECT
*device
, POWER_STATE_TYPE type
, POWER_STATE state
)
989 FIXME("device %p, type %u, state %u, stub!\n", device
, type
, state
.DeviceState
);
993 /*****************************************************
994 * PoStartNextPowerIrp (NTOSKRNL.EXE.@)
996 void WINAPI
PoStartNextPowerIrp( IRP
*irp
)
998 FIXME("irp %p, stub!\n", irp
);
1001 /*****************************************************
1002 * PoCallDriver (NTOSKRNL.EXE.@)
1004 NTSTATUS WINAPI
PoCallDriver( DEVICE_OBJECT
*device
, IRP
*irp
)
1006 TRACE("device %p, irp %p.\n", device
, irp
);
1007 return IoCallDriver( device
, irp
);
1010 static DRIVER_OBJECT
*pnp_manager
;
1012 struct root_pnp_device
1014 WCHAR id
[MAX_DEVICE_ID_LEN
];
1016 DEVICE_OBJECT
*device
;
1019 static struct root_pnp_device
*find_root_pnp_device( struct wine_driver
*driver
, const WCHAR
*id
)
1021 struct root_pnp_device
*device
;
1023 LIST_FOR_EACH_ENTRY( device
, &driver
->root_pnp_devices
, struct root_pnp_device
, entry
)
1025 if (!wcsicmp( id
, device
->id
))
1032 static NTSTATUS WINAPI
pnp_manager_device_pnp( DEVICE_OBJECT
*device
, IRP
*irp
)
1034 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation( irp
);
1035 struct root_pnp_device
*root_device
= device
->DeviceExtension
;
1038 TRACE("device %p, irp %p, minor function %#x.\n", device
, irp
, stack
->MinorFunction
);
1040 switch (stack
->MinorFunction
)
1042 case IRP_MN_QUERY_DEVICE_RELATIONS
:
1043 /* The FDO above already handled this, so return the same status. */
1045 case IRP_MN_START_DEVICE
:
1046 case IRP_MN_SURPRISE_REMOVAL
:
1047 /* Nothing to do. */
1048 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1050 case IRP_MN_REMOVE_DEVICE
:
1051 list_remove( &root_device
->entry
);
1052 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1054 case IRP_MN_QUERY_CAPABILITIES
:
1055 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1057 case IRP_MN_QUERY_ID
:
1059 BUS_QUERY_ID_TYPE type
= stack
->Parameters
.QueryId
.IdType
;
1062 TRACE("Received IRP_MN_QUERY_ID, type %#x.\n", type
);
1066 case BusQueryDeviceID
:
1067 p
= wcsrchr( root_device
->id
, '\\' );
1068 if ((id
= ExAllocatePool( NonPagedPool
, (p
- root_device
->id
+ 1) * sizeof(WCHAR
) )))
1070 memcpy( id
, root_device
->id
, (p
- root_device
->id
) * sizeof(WCHAR
) );
1071 id
[p
- root_device
->id
] = 0;
1072 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
1073 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1077 irp
->IoStatus
.Information
= 0;
1078 irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
1081 case BusQueryInstanceID
:
1082 p
= wcsrchr( root_device
->id
, '\\' );
1083 if ((id
= ExAllocatePool( NonPagedPool
, (wcslen( p
+ 1 ) + 1) * sizeof(WCHAR
) )))
1085 wcscpy( id
, p
+ 1 );
1086 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
1087 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1091 irp
->IoStatus
.Information
= 0;
1092 irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
1096 FIXME("Unhandled IRP_MN_QUERY_ID type %#x.\n", type
);
1101 FIXME("Unhandled PnP request %#x.\n", stack
->MinorFunction
);
1104 status
= irp
->IoStatus
.Status
;
1105 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
1109 static NTSTATUS WINAPI
pnp_manager_driver_entry( DRIVER_OBJECT
*driver
, UNICODE_STRING
*keypath
)
1111 pnp_manager
= driver
;
1112 driver
->MajorFunction
[IRP_MJ_PNP
] = pnp_manager_device_pnp
;
1113 return STATUS_SUCCESS
;
1116 static DWORD CALLBACK
device_enum_thread_proc(void *arg
)
1120 DEVICE_OBJECT
*device
;
1122 EnterCriticalSection( &invalidated_devices_cs
);
1124 while (!invalidated_devices_count
)
1125 SleepConditionVariableCS( &invalidated_devices_cv
, &invalidated_devices_cs
, INFINITE
);
1127 device
= invalidated_devices
[--invalidated_devices_count
];
1129 /* Don't hold the CS while enumerating the device. Tests show that
1130 * calling IoInvalidateDeviceRelations() from another thread shouldn't
1131 * block, even if this thread is blocked in an IRP handler. */
1132 LeaveCriticalSection( &invalidated_devices_cs
);
1134 handle_bus_relations( device
);
1140 void pnp_manager_start(void)
1142 WCHAR endpoint
[] = L
"\\pipe\\wine_plugplay";
1143 WCHAR protseq
[] = L
"ncacn_np";
1144 UNICODE_STRING driver_nameU
= RTL_CONSTANT_STRING( L
"\\Driver\\PnpManager" );
1145 RPC_WSTR binding_str
;
1149 if ((status
= IoCreateDriver( &driver_nameU
, pnp_manager_driver_entry
)))
1150 ERR("Failed to create PnP manager driver, status %#lx.\n", status
);
1152 if ((err
= RpcStringBindingComposeW( NULL
, protseq
, NULL
, endpoint
, NULL
, &binding_str
)))
1154 ERR("RpcStringBindingCompose() failed, error %#lx\n", err
);
1157 err
= RpcBindingFromStringBindingW( binding_str
, &plugplay_binding_handle
);
1158 RpcStringFreeW( &binding_str
);
1160 ERR("RpcBindingFromStringBinding() failed, error %#lx\n", err
);
1162 CreateThread( NULL
, 0, device_enum_thread_proc
, NULL
, 0, NULL
);
1165 void pnp_manager_stop_driver( struct wine_driver
*driver
)
1167 struct root_pnp_device
*device
, *next
;
1169 LIST_FOR_EACH_ENTRY_SAFE( device
, next
, &driver
->root_pnp_devices
, struct root_pnp_device
, entry
)
1170 remove_device( device
->device
);
1173 void pnp_manager_stop(void)
1175 IoDeleteDriver( pnp_manager
);
1176 RpcBindingFree( &plugplay_binding_handle
);
1179 void CDECL
wine_enumerate_root_devices( const WCHAR
*driver_name
)
1181 static const WCHAR driverW
[] = {'\\','D','r','i','v','e','r','\\',0};
1182 static const WCHAR rootW
[] = {'R','O','O','T',0};
1183 WCHAR buffer
[MAX_SERVICE_NAME
+ ARRAY_SIZE(driverW
)], id
[MAX_DEVICE_ID_LEN
];
1184 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
1185 struct list new_list
= LIST_INIT(new_list
);
1186 struct root_pnp_device
*pnp_device
, *next
;
1187 struct wine_driver
*driver
;
1188 DEVICE_OBJECT
*device
;
1193 TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name
));
1195 driver
= get_driver( driver_name
);
1197 set
= SetupDiGetClassDevsW( NULL
, rootW
, NULL
, DIGCF_ALLCLASSES
);
1198 if (set
== INVALID_HANDLE_VALUE
)
1200 ERR("Failed to build device set, error %#lx.\n", GetLastError());
1204 for (i
= 0; SetupDiEnumDeviceInfo( set
, i
, &sp_device
); ++i
)
1206 if (!SetupDiGetDeviceRegistryPropertyW( set
, &sp_device
, SPDRP_SERVICE
,
1207 NULL
, (BYTE
*)buffer
, sizeof(buffer
), NULL
)
1208 || lstrcmpiW( buffer
, driver_name
))
1213 SetupDiGetDeviceInstanceIdW( set
, &sp_device
, id
, ARRAY_SIZE(id
), NULL
);
1215 if ((pnp_device
= find_root_pnp_device( driver
, id
)))
1217 TRACE("Found device %s already enumerated.\n", debugstr_w(id
));
1218 list_remove( &pnp_device
->entry
);
1219 list_add_tail( &new_list
, &pnp_device
->entry
);
1223 TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id
));
1225 if ((status
= IoCreateDevice( pnp_manager
, sizeof(struct root_pnp_device
), NULL
,
1226 FILE_DEVICE_CONTROLLER
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &device
)))
1228 ERR("Failed to create root-enumerated PnP device %s, status %#lx.\n", debugstr_w(id
), status
);
1232 pnp_device
= device
->DeviceExtension
;
1233 wcscpy( pnp_device
->id
, id
);
1234 pnp_device
->device
= device
;
1235 list_add_tail( &new_list
, &pnp_device
->entry
);
1237 start_device( device
, set
, &sp_device
);
1240 LIST_FOR_EACH_ENTRY_SAFE( pnp_device
, next
, &driver
->root_pnp_devices
, struct root_pnp_device
, entry
)
1242 TRACE("Removing device %s.\n", debugstr_w(pnp_device
->id
));
1243 remove_device( pnp_device
->device
);
1246 list_move_head( &driver
->root_pnp_devices
, &new_list
);
1248 SetupDiDestroyDeviceInfoList(set
);