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"
31 #include "wine/exception.h"
32 #include "wine/heap.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,%04lx}", 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
;
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
;
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
;
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};
126 if ((status
= get_device_id( device
, BusQueryDeviceID
, &id
)))
128 ERR("Failed to get device ID, status %#lx.\n", status
);
132 lstrcpyW( buffer
, id
);
135 if ((status
= get_device_id( device
, BusQueryInstanceID
, &id
)))
137 ERR("Failed to get instance ID, status %#lx.\n", status
);
141 lstrcatW( buffer
, backslashW
);
142 lstrcatW( buffer
, 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
;
157 memset( caps
, 0, sizeof(*caps
) );
158 caps
->Size
= sizeof(*caps
);
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
;
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
);
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 %#lx.\n", debugstr_w(driver
), status
);
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
));
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
);
220 status
= STATUS_NOT_IMPLEMENTED
;
221 TRACE("AddDevice routine %p returned %#lx.\n", driver_obj
->DriverExtension
->AddDevice
, status
);
223 ObDereferenceObject( driver_obj
);
225 if (status
!= STATUS_SUCCESS
)
226 ERR("AddDevice failed for driver %s, status %#lx.\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
)
234 for (p
= str
; *p
; p
+= lstrlenW(p
) + 1);
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
[] =
245 DIF_SELECTBESTCOMPATDRV
,
247 DIF_INSTALLDEVICEFILES
,
248 DIF_REGISTER_COINSTALLERS
,
249 DIF_INSTALLINTERFACES
,
251 DIF_NEWDEVICEWIZARD_FINISHINSTALL
,
258 if ((status
= get_device_id( device
, BusQueryHardwareIDs
, &ids
)) || !ids
)
260 ERR("Failed to get hardware IDs, status %#lx.\n", status
);
264 SetupDiSetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_HARDWAREID
, (BYTE
*)ids
,
265 sizeof_multiszW( ids
) * sizeof(WCHAR
) );
268 if ((status
= get_device_id( device
, BusQueryCompatibleIDs
, &ids
)) || !ids
)
270 ERR("Failed to get compatible IDs, status %#lx.\n", status
);
274 SetupDiSetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_COMPATIBLEIDS
, (BYTE
*)ids
,
275 sizeof_multiszW( ids
) * sizeof(WCHAR
) );
278 if (!SetupDiBuildDriverInfoList( set
, sp_device
, SPDIT_COMPATDRIVER
))
280 ERR("Failed to build compatible driver list, error %#lx.\n", GetLastError());
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 %#lx failed, error %#lx.\n", dif_list
[i
], GetLastError());
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
;
316 if (get_device_instance_id( device
, device_instance_id
))
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 %#lx.\n", debugstr_w(device_instance_id
), GetLastError());
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
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
))
338 if ((status
= get_device_caps( device
, &caps
)))
340 ERR("Failed to get caps for device %s, status %#lx.\n", debugstr_w(device_instance_id
), status
);
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
));
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
)
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 void remove_device( DEVICE_OBJECT
*device
)
371 send_remove_device_irp( device
, IRP_MN_SURPRISE_REMOVAL
);
372 send_remove_device_irp( device
, IRP_MN_REMOVE_DEVICE
);
375 static BOOL
device_in_list( const DEVICE_RELATIONS
*list
, const DEVICE_OBJECT
*device
)
378 for (i
= 0; i
< list
->Count
; ++i
)
380 if (list
->Objects
[i
] == device
)
386 static void handle_bus_relations( DEVICE_OBJECT
*parent
)
388 struct wine_device
*wine_parent
= CONTAINING_RECORD(parent
, struct wine_device
, device_obj
);
389 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
390 DEVICE_RELATIONS
*relations
;
391 IO_STATUS_BLOCK irp_status
;
392 IO_STACK_LOCATION
*irpsp
;
398 TRACE( "(%p)\n", parent
);
400 set
= SetupDiCreateDeviceInfoList( NULL
, NULL
);
402 parent
= IoGetAttachedDevice( parent
);
404 KeInitializeEvent( &event
, NotificationEvent
, FALSE
);
405 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_PNP
, parent
, NULL
, 0, NULL
, &event
, &irp_status
)))
407 SetupDiDestroyDeviceInfoList( set
);
411 irpsp
= IoGetNextIrpStackLocation( irp
);
412 irpsp
->MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
413 irpsp
->Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
415 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
416 if (IoCallDriver( parent
, irp
) == STATUS_PENDING
)
417 KeWaitForSingleObject( &event
, Executive
, KernelMode
, FALSE
, NULL
);
419 relations
= (DEVICE_RELATIONS
*)irp_status
.Information
;
420 if (irp_status
.u
.Status
)
422 ERR("Failed to enumerate child devices, status %#lx.\n", irp_status
.u
.Status
);
423 SetupDiDestroyDeviceInfoList( set
);
427 TRACE("Got %lu 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
);
471 handle_bus_relations( device_object
);
474 FIXME("Unhandled relation %#x.\n", type
);
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;
491 TRACE("device %p, property %u, length %lu, buffer %p, needed %p.\n",
492 device
, property
, length
, buffer
, needed
);
496 case DevicePropertyEnumeratorName
:
500 status
= get_device_id( device
, BusQueryInstanceID
, &id
);
501 if (status
!= STATUS_SUCCESS
)
503 ERR("Failed to get instance ID, status %#lx.\n", status
);
508 ptr
= wcschr( id
, '\\' );
511 *needed
= sizeof(WCHAR
) * (lstrlenW(id
) + 1);
512 if (length
>= *needed
)
513 memcpy( buffer
, id
, *needed
);
515 status
= STATUS_BUFFER_TOO_SMALL
;
520 case DevicePropertyPhysicalDeviceObjectName
:
522 ULONG used_len
, len
= length
+ sizeof(OBJECT_NAME_INFORMATION
);
523 OBJECT_NAME_INFORMATION
*name
= HeapAlloc(GetProcessHeap(), 0, len
);
526 status
= ObOpenObjectByPointer( device
, OBJ_KERNEL_HANDLE
, NULL
, 0, NULL
, KernelMode
, &handle
);
529 status
= NtQueryObject( handle
, ObjectNameInformation
, name
, len
, &used_len
);
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
);
538 status
= STATUS_BUFFER_TOO_SMALL
;
539 *needed
= name
->Name
.MaximumLength
;
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
);
552 HeapFree(GetProcessHeap(), 0, name
);
555 case DevicePropertyDeviceDescription
:
556 sp_property
= SPDRP_DEVICEDESC
;
558 case DevicePropertyHardwareID
:
559 sp_property
= SPDRP_HARDWAREID
;
561 case DevicePropertyCompatibleIDs
:
562 sp_property
= SPDRP_COMPATIBLEIDS
;
564 case DevicePropertyClassName
:
565 sp_property
= SPDRP_CLASS
;
567 case DevicePropertyClassGuid
:
568 sp_property
= SPDRP_CLASSGUID
;
570 case DevicePropertyManufacturer
:
571 sp_property
= SPDRP_MFG
;
573 case DevicePropertyFriendlyName
:
574 sp_property
= SPDRP_FRIENDLYNAME
;
576 case DevicePropertyLocationInformation
:
577 sp_property
= SPDRP_LOCATION_INFORMATION
;
579 case DevicePropertyBusTypeGuid
:
580 sp_property
= SPDRP_BUSTYPEGUID
;
582 case DevicePropertyLegacyBusType
:
583 sp_property
= SPDRP_LEGACYBUSTYPE
;
585 case DevicePropertyBusNumber
:
586 sp_property
= SPDRP_BUSNUMBER
;
588 case DevicePropertyAddress
:
589 sp_property
= SPDRP_ADDRESS
;
591 case DevicePropertyUINumber
:
592 sp_property
= SPDRP_UI_NUMBER
;
594 case DevicePropertyInstallState
:
595 sp_property
= SPDRP_INSTALL_STATE
;
597 case DevicePropertyRemovalPolicy
:
598 sp_property
= SPDRP_REMOVAL_POLICY
;
601 FIXME("Unhandled property %u.\n", property
);
602 return STATUS_NOT_IMPLEMENTED
;
605 if ((status
= get_device_instance_id( device
, device_instance_id
)))
608 if ((set
= SetupDiCreateDeviceInfoList( &GUID_NULL
, NULL
)) == INVALID_HANDLE_VALUE
)
610 ERR("Failed to create device list, error %#lx.\n", GetLastError());
611 return GetLastError();
614 if (!SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
))
616 ERR("Failed to open device, error %#lx.\n", GetLastError());
617 SetupDiDestroyDeviceInfoList( set
);
618 return GetLastError();
621 if (SetupDiGetDeviceRegistryPropertyW( set
, &sp_device
, sp_property
, NULL
, buffer
, length
, needed
))
622 status
= STATUS_SUCCESS
;
624 status
= GetLastError();
626 SetupDiDestroyDeviceInfoList( set
);
631 static NTSTATUS
create_device_symlink( DEVICE_OBJECT
*device
, UNICODE_STRING
*symlink_name
)
633 UNICODE_STRING device_nameU
;
638 ret
= IoGetDeviceProperty( device
, DevicePropertyPhysicalDeviceObjectName
, 0, NULL
, &len
);
639 if (ret
!= STATUS_BUFFER_TOO_SMALL
)
642 device_name
= heap_alloc( len
);
643 ret
= IoGetDeviceProperty( device
, DevicePropertyPhysicalDeviceObjectName
, len
, device_name
, &len
);
646 heap_free( device_name
);
650 RtlInitUnicodeString( &device_nameU
, device_name
);
651 ret
= IoCreateSymbolicLink( symlink_name
, &device_nameU
);
652 heap_free( device_name
);
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
)
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
)
675 plugplay_send_event( code
, data
, size
);
679 WARN("Failed to send event, exception %#lx.\n", GetExceptionCode());
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 WCHAR
*path
, *refstr
, *p
, *upper_end
;
702 struct device_interface
*iface
;
703 HANDLE iface_key
, control_key
;
704 OBJECT_ATTRIBUTES attr
= {0};
705 struct wine_rb_entry
*entry
;
706 UNICODE_STRING string
;
711 TRACE("device %s, enable %u.\n", debugstr_us(name
), enable
);
713 entry
= wine_rb_get( &device_interfaces
, name
);
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
);
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
);
760 RtlInitUnicodeString( &string
, linkedW
);
761 ret
= NtSetValueKey( control_key
, &string
, 0, REG_DWORD
, &data
, sizeof(data
) );
764 NtClose( control_key
);
769 ret
= create_device_symlink( iface
->device
, name
);
771 ret
= IoDeleteSymbolicLink( name
);
774 NtDeleteValueKey( control_key
, &string
);
775 NtClose( control_key
);
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_reserved
= 0;
788 broadcast
->dbcc_classguid
= iface
->interface_class
;
789 lstrcpynW( broadcast
->dbcc_name
, name
->Buffer
, namelen
+ 1 );
790 if (namelen
> 1) broadcast
->dbcc_name
[1] = '\\';
792 upper_end
= wcschr( broadcast
->dbcc_name
, '#' );
793 if (upper_end
) upper_end
= wcschr( upper_end
+ 1, '#' );
794 while (upper_end
&& upper_end
-- != broadcast
->dbcc_name
)
795 *upper_end
= towupper( *upper_end
);
797 send_devicechange( enable
? DBT_DEVICEARRIVAL
: DBT_DEVICEREMOVECOMPLETE
, broadcast
, len
);
798 heap_free( broadcast
);
803 /***********************************************************************
804 * IoSetDevicePropertyData (NTOSKRNL.EXE.@)
806 NTSTATUS WINAPI
IoSetDevicePropertyData( DEVICE_OBJECT
*device
, const DEVPROPKEY
*property_key
, LCID lcid
,
807 ULONG flags
, DEVPROPTYPE type
, ULONG size
, void *data
)
809 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
810 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
814 TRACE( "device %p, property_key %s, lcid %#lx, flags %#lx, type %#lx, size %lu, data %p.\n",
815 device
, debugstr_propkey(property_key
), lcid
, flags
, type
, size
, data
);
817 /* flags is always treated as PLUGPLAY_PROPERTY_PERSISTENT starting with Win 8 / 2012 */
819 if (lcid
!= LOCALE_NEUTRAL
) FIXME( "only LOCALE_NEUTRAL is supported\n" );
821 if ((status
= get_device_instance_id( device
, device_instance_id
))) return status
;
823 if ((set
= SetupDiCreateDeviceInfoList( &GUID_NULL
, NULL
)) == INVALID_HANDLE_VALUE
)
825 ERR( "Failed to create device list, error %#lx.\n", GetLastError() );
826 return GetLastError();
829 if (!SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
))
831 ERR( "Failed to open device, error %#lx.\n", GetLastError() );
832 SetupDiDestroyDeviceInfoList( set
);
833 return GetLastError();
836 if (!SetupDiSetDevicePropertyW( set
, &sp_device
, property_key
, type
, data
, size
, 0 ))
838 ERR( "Failed to set property, error %#lx.\n", GetLastError() );
839 SetupDiDestroyDeviceInfoList( set
);
840 return GetLastError();
843 SetupDiDestroyDeviceInfoList( set
);
845 return STATUS_SUCCESS
;
848 /***********************************************************************
849 * IoRegisterDeviceInterface (NTOSKRNL.EXE.@)
851 NTSTATUS WINAPI
IoRegisterDeviceInterface(DEVICE_OBJECT
*device
, const GUID
*class_guid
,
852 UNICODE_STRING
*refstr
, UNICODE_STRING
*symbolic_link
)
854 SP_DEVICE_INTERFACE_DATA sp_iface
= {sizeof(sp_iface
)};
855 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
856 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
857 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*data
;
858 NTSTATUS status
= STATUS_SUCCESS
;
859 UNICODE_STRING device_path
;
860 struct device_interface
*iface
;
861 struct wine_rb_entry
*entry
;
865 TRACE("device %p, class_guid %s, refstr %s, symbolic_link %p.\n",
866 device
, debugstr_guid(class_guid
), debugstr_us(refstr
), symbolic_link
);
868 if ((status
= get_device_instance_id( device
, device_instance_id
)))
871 set
= SetupDiGetClassDevsW( class_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
872 if (set
== INVALID_HANDLE_VALUE
) return STATUS_UNSUCCESSFUL
;
874 if (!SetupDiCreateDeviceInfoW( set
, device_instance_id
, class_guid
, NULL
, NULL
, 0, &sp_device
)
875 && !SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
))
877 ERR("Failed to create device %s, error %#lx.\n", debugstr_w(device_instance_id
), GetLastError());
878 return GetLastError();
881 if (!SetupDiCreateDeviceInterfaceW( set
, &sp_device
, class_guid
, refstr
? refstr
->Buffer
: NULL
, 0, &sp_iface
))
882 return STATUS_UNSUCCESSFUL
;
885 SetupDiGetDeviceInterfaceDetailW( set
, &sp_iface
, NULL
, 0, &required
, NULL
);
886 if (required
== 0) return STATUS_UNSUCCESSFUL
;
888 data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, required
);
889 data
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
);
891 if (!SetupDiGetDeviceInterfaceDetailW( set
, &sp_iface
, data
, required
, NULL
, NULL
))
893 HeapFree( GetProcessHeap(), 0, data
);
894 return STATUS_UNSUCCESSFUL
;
897 data
->DevicePath
[1] = '?';
898 TRACE("Returning path %s.\n", debugstr_w(data
->DevicePath
));
899 RtlCreateUnicodeString( &device_path
, data
->DevicePath
);
901 entry
= wine_rb_get( &device_interfaces
, &device_path
);
904 iface
= WINE_RB_ENTRY_VALUE( entry
, struct device_interface
, entry
);
906 ERR("Device interface %s is still enabled.\n", debugstr_us(&iface
->symbolic_link
));
910 iface
= heap_alloc_zero( sizeof(struct device_interface
) );
911 RtlCreateUnicodeString(&iface
->symbolic_link
, data
->DevicePath
);
912 if (wine_rb_put( &device_interfaces
, &iface
->symbolic_link
, &iface
->entry
))
913 ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface
->symbolic_link
));
916 iface
->device
= device
;
917 iface
->interface_class
= *class_guid
;
919 RtlCreateUnicodeString( symbolic_link
, data
->DevicePath
);
921 HeapFree( GetProcessHeap(), 0, data
);
923 RtlFreeUnicodeString( &device_path
);
928 /***********************************************************************
929 * IoOpenDeviceRegistryKey (NTOSKRNL.EXE.@)
931 NTSTATUS WINAPI
IoOpenDeviceRegistryKey( DEVICE_OBJECT
*device
, ULONG type
, ACCESS_MASK access
, HANDLE
*key
)
933 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
934 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
938 TRACE("device %p, type %#lx, access %#lx, key %p.\n", device
, type
, access
, key
);
940 if ((status
= get_device_instance_id( device
, device_instance_id
)))
942 ERR("Failed to get device instance ID, error %#lx.\n", status
);
946 set
= SetupDiCreateDeviceInfoList( &GUID_NULL
, NULL
);
948 SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
);
950 *key
= SetupDiOpenDevRegKey( set
, &sp_device
, DICS_FLAG_GLOBAL
, 0, type
, access
);
951 SetupDiDestroyDeviceInfoList( set
);
952 if (*key
== INVALID_HANDLE_VALUE
)
953 return GetLastError();
954 return STATUS_SUCCESS
;
957 /***********************************************************************
958 * PoSetPowerState (NTOSKRNL.EXE.@)
960 POWER_STATE WINAPI
PoSetPowerState( DEVICE_OBJECT
*device
, POWER_STATE_TYPE type
, POWER_STATE state
)
962 FIXME("device %p, type %u, state %u, stub!\n", device
, type
, state
.DeviceState
);
966 /*****************************************************
967 * PoStartNextPowerIrp (NTOSKRNL.EXE.@)
969 void WINAPI
PoStartNextPowerIrp( IRP
*irp
)
971 FIXME("irp %p, stub!\n", irp
);
974 /*****************************************************
975 * PoCallDriver (NTOSKRNL.EXE.@)
977 NTSTATUS WINAPI
PoCallDriver( DEVICE_OBJECT
*device
, IRP
*irp
)
979 TRACE("device %p, irp %p.\n", device
, irp
);
980 return IoCallDriver( device
, irp
);
983 static DRIVER_OBJECT
*pnp_manager
;
985 struct root_pnp_device
987 WCHAR id
[MAX_DEVICE_ID_LEN
];
989 DEVICE_OBJECT
*device
;
992 static struct root_pnp_device
*find_root_pnp_device( struct wine_driver
*driver
, const WCHAR
*id
)
994 struct root_pnp_device
*device
;
996 LIST_FOR_EACH_ENTRY( device
, &driver
->root_pnp_devices
, struct root_pnp_device
, entry
)
998 if (!wcsicmp( id
, device
->id
))
1005 static NTSTATUS WINAPI
pnp_manager_device_pnp( DEVICE_OBJECT
*device
, IRP
*irp
)
1007 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation( irp
);
1008 struct root_pnp_device
*root_device
= device
->DeviceExtension
;
1011 TRACE("device %p, irp %p, minor function %#x.\n", device
, irp
, stack
->MinorFunction
);
1013 switch (stack
->MinorFunction
)
1015 case IRP_MN_QUERY_DEVICE_RELATIONS
:
1016 /* The FDO above already handled this, so return the same status. */
1018 case IRP_MN_START_DEVICE
:
1019 case IRP_MN_SURPRISE_REMOVAL
:
1020 /* Nothing to do. */
1021 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
1023 case IRP_MN_REMOVE_DEVICE
:
1024 list_remove( &root_device
->entry
);
1025 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
1027 case IRP_MN_QUERY_CAPABILITIES
:
1028 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
1030 case IRP_MN_QUERY_ID
:
1032 BUS_QUERY_ID_TYPE type
= stack
->Parameters
.QueryId
.IdType
;
1035 TRACE("Received IRP_MN_QUERY_ID, type %#x.\n", type
);
1039 case BusQueryDeviceID
:
1040 p
= wcsrchr( root_device
->id
, '\\' );
1041 if ((id
= ExAllocatePool( NonPagedPool
, (p
- root_device
->id
+ 1) * sizeof(WCHAR
) )))
1043 memcpy( id
, root_device
->id
, (p
- root_device
->id
) * sizeof(WCHAR
) );
1044 id
[p
- root_device
->id
] = 0;
1045 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
1046 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
1050 irp
->IoStatus
.Information
= 0;
1051 irp
->IoStatus
.u
.Status
= STATUS_NO_MEMORY
;
1054 case BusQueryInstanceID
:
1055 p
= wcsrchr( root_device
->id
, '\\' );
1056 if ((id
= ExAllocatePool( NonPagedPool
, (wcslen( p
+ 1 ) + 1) * sizeof(WCHAR
) )))
1058 wcscpy( id
, p
+ 1 );
1059 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
1060 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
1064 irp
->IoStatus
.Information
= 0;
1065 irp
->IoStatus
.u
.Status
= STATUS_NO_MEMORY
;
1069 FIXME("Unhandled IRP_MN_QUERY_ID type %#x.\n", type
);
1074 FIXME("Unhandled PnP request %#x.\n", stack
->MinorFunction
);
1077 status
= irp
->IoStatus
.u
.Status
;
1078 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
1082 static NTSTATUS WINAPI
pnp_manager_driver_entry( DRIVER_OBJECT
*driver
, UNICODE_STRING
*keypath
)
1084 pnp_manager
= driver
;
1085 driver
->MajorFunction
[IRP_MJ_PNP
] = pnp_manager_device_pnp
;
1086 return STATUS_SUCCESS
;
1089 void pnp_manager_start(void)
1091 static const WCHAR driver_nameW
[] = {'\\','D','r','i','v','e','r','\\','P','n','p','M','a','n','a','g','e','r',0};
1092 WCHAR endpoint
[] = L
"\\pipe\\wine_plugplay";
1093 WCHAR protseq
[] = L
"ncacn_np";
1094 UNICODE_STRING driver_nameU
;
1095 RPC_WSTR binding_str
;
1099 RtlInitUnicodeString( &driver_nameU
, driver_nameW
);
1100 if ((status
= IoCreateDriver( &driver_nameU
, pnp_manager_driver_entry
)))
1101 ERR("Failed to create PnP manager driver, status %#lx.\n", status
);
1103 if ((err
= RpcStringBindingComposeW( NULL
, protseq
, NULL
, endpoint
, NULL
, &binding_str
)))
1105 ERR("RpcStringBindingCompose() failed, error %#lx\n", err
);
1108 err
= RpcBindingFromStringBindingW( binding_str
, &plugplay_binding_handle
);
1109 RpcStringFreeW( &binding_str
);
1111 ERR("RpcBindingFromStringBinding() failed, error %#lx\n", err
);
1114 void pnp_manager_stop_driver( struct wine_driver
*driver
)
1116 struct root_pnp_device
*device
, *next
;
1118 LIST_FOR_EACH_ENTRY_SAFE( device
, next
, &driver
->root_pnp_devices
, struct root_pnp_device
, entry
)
1119 remove_device( device
->device
);
1122 void pnp_manager_stop(void)
1124 IoDeleteDriver( pnp_manager
);
1125 RpcBindingFree( &plugplay_binding_handle
);
1128 void CDECL
wine_enumerate_root_devices( const WCHAR
*driver_name
)
1130 static const WCHAR driverW
[] = {'\\','D','r','i','v','e','r','\\',0};
1131 static const WCHAR rootW
[] = {'R','O','O','T',0};
1132 WCHAR buffer
[MAX_SERVICE_NAME
+ ARRAY_SIZE(driverW
)], id
[MAX_DEVICE_ID_LEN
];
1133 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
1134 struct list new_list
= LIST_INIT(new_list
);
1135 struct root_pnp_device
*pnp_device
, *next
;
1136 struct wine_driver
*driver
;
1137 DEVICE_OBJECT
*device
;
1142 TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name
));
1144 driver
= get_driver( driver_name
);
1146 set
= SetupDiGetClassDevsW( NULL
, rootW
, NULL
, DIGCF_ALLCLASSES
);
1147 if (set
== INVALID_HANDLE_VALUE
)
1149 ERR("Failed to build device set, error %#lx.\n", GetLastError());
1153 for (i
= 0; SetupDiEnumDeviceInfo( set
, i
, &sp_device
); ++i
)
1155 if (!SetupDiGetDeviceRegistryPropertyW( set
, &sp_device
, SPDRP_SERVICE
,
1156 NULL
, (BYTE
*)buffer
, sizeof(buffer
), NULL
)
1157 || lstrcmpiW( buffer
, driver_name
))
1162 SetupDiGetDeviceInstanceIdW( set
, &sp_device
, id
, ARRAY_SIZE(id
), NULL
);
1164 if ((pnp_device
= find_root_pnp_device( driver
, id
)))
1166 TRACE("Found device %s already enumerated.\n", debugstr_w(id
));
1167 list_remove( &pnp_device
->entry
);
1168 list_add_tail( &new_list
, &pnp_device
->entry
);
1172 TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id
));
1174 if ((status
= IoCreateDevice( pnp_manager
, sizeof(struct root_pnp_device
), NULL
,
1175 FILE_DEVICE_CONTROLLER
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &device
)))
1177 ERR("Failed to create root-enumerated PnP device %s, status %#lx.\n", debugstr_w(id
), status
);
1181 pnp_device
= device
->DeviceExtension
;
1182 wcscpy( pnp_device
->id
, id
);
1183 pnp_device
->device
= device
;
1184 list_add_tail( &new_list
, &pnp_device
->entry
);
1186 start_device( device
, set
, &sp_device
);
1189 LIST_FOR_EACH_ENTRY_SAFE( pnp_device
, next
, &driver
->root_pnp_devices
, struct root_pnp_device
, entry
)
1191 TRACE("Removing device %s.\n", debugstr_w(pnp_device
->id
));
1192 remove_device( pnp_device
->device
);
1195 list_move_head( &driver
->root_pnp_devices
, &new_list
);
1197 SetupDiDestroyDeviceInfoList(set
);