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
25 #define NONAMELESSUNION
28 #define WIN32_NO_STATUS
40 #include "ddk/ntifs.h"
41 #include "wine/debug.h"
42 #include "wine/heap.h"
43 #include "wine/rbtree.h"
45 #include "ntoskrnl_private.h"
48 DEFINE_GUID(GUID_NULL
,0,0,0,0,0,0,0,0,0,0,0);
50 WINE_DEFAULT_DEBUG_CHANNEL(plugplay
);
52 #define MAX_SERVICE_NAME 260
54 struct device_interface
56 struct wine_rb_entry entry
;
58 UNICODE_STRING symbolic_link
;
59 DEVICE_OBJECT
*device
;
64 static int interface_rb_compare( const void *key
, const struct wine_rb_entry
*entry
)
66 const struct device_interface
*iface
= WINE_RB_ENTRY_VALUE( entry
, const struct device_interface
, entry
);
67 const UNICODE_STRING
*k
= key
;
69 return RtlCompareUnicodeString( k
, &iface
->symbolic_link
, FALSE
);
72 static struct wine_rb_tree device_interfaces
= { interface_rb_compare
};
74 static NTSTATUS WINAPI
internal_complete( DEVICE_OBJECT
*device
, IRP
*irp
, void *context
)
76 HANDLE event
= context
;
78 return STATUS_MORE_PROCESSING_REQUIRED
;
81 static NTSTATUS
send_device_irp( DEVICE_OBJECT
*device
, IRP
*irp
, ULONG_PTR
*info
)
83 HANDLE event
= CreateEventA( NULL
, FALSE
, FALSE
, NULL
);
84 DEVICE_OBJECT
*toplevel_device
;
87 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
88 IoSetCompletionRoutine( irp
, internal_complete
, event
, TRUE
, TRUE
, TRUE
);
90 toplevel_device
= IoGetAttachedDeviceReference( device
);
91 status
= IoCallDriver( toplevel_device
, irp
);
93 if (status
== STATUS_PENDING
)
94 WaitForSingleObject( event
, INFINITE
);
96 status
= irp
->IoStatus
.u
.Status
;
98 *info
= irp
->IoStatus
.Information
;
99 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
100 ObDereferenceObject( toplevel_device
);
101 CloseHandle( event
);
105 static NTSTATUS
get_device_id( DEVICE_OBJECT
*device
, BUS_QUERY_ID_TYPE type
, WCHAR
**id
)
107 IO_STACK_LOCATION
*irpsp
;
108 IO_STATUS_BLOCK irp_status
;
111 device
= IoGetAttachedDevice( device
);
113 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_PNP
, device
, NULL
, 0, NULL
, NULL
, &irp_status
)))
114 return STATUS_NO_MEMORY
;
116 irpsp
= IoGetNextIrpStackLocation( irp
);
117 irpsp
->MinorFunction
= IRP_MN_QUERY_ID
;
118 irpsp
->Parameters
.QueryId
.IdType
= type
;
120 return send_device_irp( device
, irp
, (ULONG_PTR
*)id
);
123 static NTSTATUS
send_pnp_irp( DEVICE_OBJECT
*device
, UCHAR minor
)
125 IO_STACK_LOCATION
*irpsp
;
126 IO_STATUS_BLOCK irp_status
;
129 device
= IoGetAttachedDevice( device
);
131 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_PNP
, device
, NULL
, 0, NULL
, NULL
, &irp_status
)))
132 return STATUS_NO_MEMORY
;
134 irpsp
= IoGetNextIrpStackLocation( irp
);
135 irpsp
->MinorFunction
= minor
;
137 irpsp
->Parameters
.StartDevice
.AllocatedResources
= NULL
;
138 irpsp
->Parameters
.StartDevice
.AllocatedResourcesTranslated
= NULL
;
140 return send_device_irp( device
, irp
, NULL
);
143 static NTSTATUS
get_device_instance_id( DEVICE_OBJECT
*device
, WCHAR
*buffer
)
145 static const WCHAR backslashW
[] = {'\\',0};
149 if ((status
= get_device_id( device
, BusQueryDeviceID
, &id
)))
151 ERR("Failed to get device ID, status %#x.\n", status
);
155 lstrcpyW( buffer
, id
);
158 if ((status
= get_device_id( device
, BusQueryInstanceID
, &id
)))
160 ERR("Failed to get instance ID, status %#x.\n", status
);
164 lstrcatW( buffer
, backslashW
);
165 lstrcatW( buffer
, id
);
168 TRACE("Returning ID %s.\n", debugstr_w(buffer
));
170 return STATUS_SUCCESS
;
173 static NTSTATUS
send_power_irp( DEVICE_OBJECT
*device
, DEVICE_POWER_STATE power
)
175 IO_STATUS_BLOCK irp_status
;
176 IO_STACK_LOCATION
*irpsp
;
179 device
= IoGetAttachedDevice( device
);
181 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_POWER
, device
, NULL
, 0, NULL
, NULL
, &irp_status
)))
182 return STATUS_NO_MEMORY
;
184 irpsp
= IoGetNextIrpStackLocation( irp
);
185 irpsp
->MinorFunction
= IRP_MN_SET_POWER
;
187 irpsp
->Parameters
.Power
.Type
= DevicePowerState
;
188 irpsp
->Parameters
.Power
.State
.DeviceState
= power
;
190 return send_device_irp( device
, irp
, NULL
);
193 static void load_function_driver( DEVICE_OBJECT
*device
, HDEVINFO set
, SP_DEVINFO_DATA
*sp_device
)
195 static const WCHAR driverW
[] = {'\\','D','r','i','v','e','r','\\',0};
196 WCHAR buffer
[MAX_SERVICE_NAME
+ ARRAY_SIZE(servicesW
)];
197 WCHAR driver
[MAX_SERVICE_NAME
] = {0};
198 DRIVER_OBJECT
*driver_obj
;
199 UNICODE_STRING string
;
202 if (!SetupDiGetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_SERVICE
,
203 NULL
, (BYTE
*)driver
, sizeof(driver
), NULL
))
205 WARN("No driver registered for device %p.\n", device
);
209 lstrcpyW( buffer
, servicesW
);
210 lstrcatW( buffer
, driver
);
211 RtlInitUnicodeString( &string
, buffer
);
212 status
= ZwLoadDriver( &string
);
213 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_IMAGE_ALREADY_LOADED
)
215 ERR("Failed to load driver %s, status %#x.\n", debugstr_w(driver
), status
);
219 lstrcpyW( buffer
, driverW
);
220 lstrcatW( buffer
, driver
);
221 RtlInitUnicodeString( &string
, buffer
);
222 if (ObReferenceObjectByName( &string
, OBJ_CASE_INSENSITIVE
, NULL
,
223 0, NULL
, KernelMode
, NULL
, (void **)&driver_obj
) != STATUS_SUCCESS
)
225 ERR("Failed to locate loaded driver %s.\n", debugstr_w(driver
));
229 TRACE("Calling AddDevice routine %p.\n", driver_obj
->DriverExtension
->AddDevice
);
230 if (driver_obj
->DriverExtension
->AddDevice
)
231 status
= driver_obj
->DriverExtension
->AddDevice( driver_obj
, device
);
233 status
= STATUS_NOT_IMPLEMENTED
;
234 TRACE("AddDevice routine %p returned %#x.\n", driver_obj
->DriverExtension
->AddDevice
, status
);
236 ObDereferenceObject( driver_obj
);
238 if (status
!= STATUS_SUCCESS
)
239 ERR("AddDevice failed for driver %s, status %#x.\n", debugstr_w(driver
), status
);
242 /* Return the total number of characters in a REG_MULTI_SZ string, including
243 * the final terminating null. */
244 static size_t sizeof_multiszW( const WCHAR
*str
)
247 for (p
= str
; *p
; p
+= lstrlenW(p
) + 1);
251 /* This does almost the same thing as UpdateDriverForPlugAndPlayDevices(),
252 * except that we don't know the INF path beforehand. */
253 static BOOL
install_device_driver( DEVICE_OBJECT
*device
, HDEVINFO set
, SP_DEVINFO_DATA
*sp_device
)
255 static const DWORD dif_list
[] =
258 DIF_SELECTBESTCOMPATDRV
,
260 DIF_INSTALLDEVICEFILES
,
261 DIF_REGISTER_COINSTALLERS
,
262 DIF_INSTALLINTERFACES
,
264 DIF_NEWDEVICEWIZARD_FINISHINSTALL
,
271 if ((status
= get_device_id( device
, BusQueryHardwareIDs
, &ids
)) || !ids
)
273 ERR("Failed to get hardware IDs, status %#x.\n", status
);
277 SetupDiSetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_HARDWAREID
, (BYTE
*)ids
,
278 sizeof_multiszW( ids
) * sizeof(WCHAR
) );
281 if ((status
= get_device_id( device
, BusQueryCompatibleIDs
, &ids
)) || !ids
)
283 ERR("Failed to get compatible IDs, status %#x.\n", status
);
287 SetupDiSetDeviceRegistryPropertyW( set
, sp_device
, SPDRP_COMPATIBLEIDS
, (BYTE
*)ids
,
288 sizeof_multiszW( ids
) * sizeof(WCHAR
) );
291 if (!SetupDiBuildDriverInfoList( set
, sp_device
, SPDIT_COMPATDRIVER
))
293 ERR("Failed to build compatible driver list, error %#x.\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 %#x failed, error %#x.\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
)
316 send_pnp_irp( device
, IRP_MN_START_DEVICE
);
317 send_power_irp( device
, PowerDeviceD0
);
321 static void enumerate_new_device( DEVICE_OBJECT
*device
, HDEVINFO set
)
323 static const WCHAR infpathW
[] = {'I','n','f','P','a','t','h',0};
325 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
326 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
327 BOOL need_driver
= TRUE
;
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 %#x.\n", debugstr_w(device_instance_id
), GetLastError());
337 SetupDiDestroyDeviceInfoList( set
);
341 TRACE("Creating new device %s.\n", debugstr_w(device_instance_id
));
343 /* Check if the device already has a driver registered; if not, find one
345 key
= SetupDiOpenDevRegKey( set
, &sp_device
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, KEY_READ
);
346 if (key
!= INVALID_HANDLE_VALUE
)
348 if (!RegQueryValueExW( key
, infpathW
, NULL
, NULL
, NULL
, NULL
))
353 if (need_driver
&& !install_device_driver( device
, set
, &sp_device
))
355 SetupDiDestroyDeviceInfoList( set
);
359 start_device( device
, set
, &sp_device
);
362 static void remove_device( DEVICE_OBJECT
*device
)
364 struct wine_device
*wine_device
= CONTAINING_RECORD(device
, struct wine_device
, device_obj
);
366 TRACE("Removing device %p.\n", device
);
368 if (wine_device
->children
)
371 for (i
= 0; i
< wine_device
->children
->Count
; ++i
)
372 remove_device( wine_device
->children
->Objects
[i
] );
375 send_power_irp( device
, PowerDeviceD3
);
376 send_pnp_irp( device
, IRP_MN_SURPRISE_REMOVAL
);
377 send_pnp_irp( device
, IRP_MN_REMOVE_DEVICE
);
380 static BOOL
device_in_list( const DEVICE_RELATIONS
*list
, const DEVICE_OBJECT
*device
)
383 for (i
= 0; i
< list
->Count
; ++i
)
385 if (list
->Objects
[i
] == device
)
391 static void handle_bus_relations( DEVICE_OBJECT
*parent
)
393 struct wine_device
*wine_parent
= CONTAINING_RECORD(parent
, struct wine_device
, device_obj
);
394 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
395 DEVICE_RELATIONS
*relations
;
396 IO_STATUS_BLOCK irp_status
;
397 IO_STACK_LOCATION
*irpsp
;
403 TRACE( "(%p)\n", parent
);
405 set
= SetupDiCreateDeviceInfoList( NULL
, NULL
);
407 parent
= IoGetAttachedDevice( parent
);
409 if (!(irp
= IoBuildSynchronousFsdRequest( IRP_MJ_PNP
, parent
, NULL
, 0, NULL
, NULL
, &irp_status
)))
411 SetupDiDestroyDeviceInfoList( set
);
415 irpsp
= IoGetNextIrpStackLocation( irp
);
416 irpsp
->MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
417 irpsp
->Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
418 if ((status
= send_device_irp( parent
, irp
, (ULONG_PTR
*)&relations
)))
420 ERR("Failed to enumerate child devices, status %#x.\n", status
);
421 SetupDiDestroyDeviceInfoList( set
);
425 TRACE("Got %u devices.\n", relations
->Count
);
427 for (i
= 0; i
< relations
->Count
; ++i
)
429 DEVICE_OBJECT
*child
= relations
->Objects
[i
];
431 if (!wine_parent
->children
|| !device_in_list( wine_parent
->children
, child
))
433 TRACE("Adding new device %p.\n", child
);
434 enumerate_new_device( child
, set
);
438 if (wine_parent
->children
)
440 for (i
= 0; i
< wine_parent
->children
->Count
; ++i
)
442 DEVICE_OBJECT
*child
= wine_parent
->children
->Objects
[i
];
444 if (!device_in_list( relations
, child
))
446 TRACE("Removing device %p.\n", child
);
447 remove_device( child
);
449 ObDereferenceObject( child
);
453 ExFreePool( wine_parent
->children
);
454 wine_parent
->children
= relations
;
456 SetupDiDestroyDeviceInfoList( set
);
459 /***********************************************************************
460 * IoInvalidateDeviceRelations (NTOSKRNL.EXE.@)
462 void WINAPI
IoInvalidateDeviceRelations( DEVICE_OBJECT
*device_object
, DEVICE_RELATION_TYPE type
)
464 TRACE("device %p, type %#x.\n", device_object
, type
);
469 handle_bus_relations( device_object
);
472 FIXME("Unhandled relation %#x.\n", type
);
477 /***********************************************************************
478 * IoGetDeviceProperty (NTOSKRNL.EXE.@)
480 NTSTATUS WINAPI
IoGetDeviceProperty( DEVICE_OBJECT
*device
, DEVICE_REGISTRY_PROPERTY property
,
481 ULONG length
, void *buffer
, ULONG
*needed
)
483 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
484 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
485 DWORD sp_property
= -1;
489 TRACE("device %p, property %u, length %u, buffer %p, needed %p.\n",
490 device
, property
, length
, buffer
, needed
);
494 case DevicePropertyEnumeratorName
:
498 status
= get_device_id( device
, BusQueryInstanceID
, &id
);
499 if (status
!= STATUS_SUCCESS
)
501 ERR("Failed to get instance ID, status %#x.\n", status
);
506 ptr
= wcschr( id
, '\\' );
509 *needed
= sizeof(WCHAR
) * (lstrlenW(id
) + 1);
510 if (length
>= *needed
)
511 memcpy( buffer
, id
, *needed
);
513 status
= STATUS_BUFFER_TOO_SMALL
;
518 case DevicePropertyPhysicalDeviceObjectName
:
520 ULONG used_len
, len
= length
+ sizeof(OBJECT_NAME_INFORMATION
);
521 OBJECT_NAME_INFORMATION
*name
= HeapAlloc(GetProcessHeap(), 0, len
);
524 status
= ObOpenObjectByPointer( device
, OBJ_KERNEL_HANDLE
, NULL
, 0, NULL
, KernelMode
, &handle
);
527 status
= NtQueryObject( handle
, ObjectNameInformation
, name
, len
, &used_len
);
530 if (status
== STATUS_SUCCESS
)
532 /* Ensure room for NULL termination */
533 if (length
>= name
->Name
.MaximumLength
)
534 memcpy(buffer
, name
->Name
.Buffer
, name
->Name
.MaximumLength
);
536 status
= STATUS_BUFFER_TOO_SMALL
;
537 *needed
= name
->Name
.MaximumLength
;
541 if (status
== STATUS_INFO_LENGTH_MISMATCH
||
542 status
== STATUS_BUFFER_OVERFLOW
)
544 status
= STATUS_BUFFER_TOO_SMALL
;
545 *needed
= used_len
- sizeof(OBJECT_NAME_INFORMATION
);
550 HeapFree(GetProcessHeap(), 0, name
);
553 case DevicePropertyDeviceDescription
:
554 sp_property
= SPDRP_DEVICEDESC
;
556 case DevicePropertyHardwareID
:
557 sp_property
= SPDRP_HARDWAREID
;
559 case DevicePropertyCompatibleIDs
:
560 sp_property
= SPDRP_COMPATIBLEIDS
;
562 case DevicePropertyClassName
:
563 sp_property
= SPDRP_CLASS
;
565 case DevicePropertyClassGuid
:
566 sp_property
= SPDRP_CLASSGUID
;
568 case DevicePropertyManufacturer
:
569 sp_property
= SPDRP_MFG
;
571 case DevicePropertyFriendlyName
:
572 sp_property
= SPDRP_FRIENDLYNAME
;
574 case DevicePropertyLocationInformation
:
575 sp_property
= SPDRP_LOCATION_INFORMATION
;
577 case DevicePropertyBusTypeGuid
:
578 sp_property
= SPDRP_BUSTYPEGUID
;
580 case DevicePropertyLegacyBusType
:
581 sp_property
= SPDRP_LEGACYBUSTYPE
;
583 case DevicePropertyBusNumber
:
584 sp_property
= SPDRP_BUSNUMBER
;
586 case DevicePropertyAddress
:
587 sp_property
= SPDRP_ADDRESS
;
589 case DevicePropertyUINumber
:
590 sp_property
= SPDRP_UI_NUMBER
;
592 case DevicePropertyInstallState
:
593 sp_property
= SPDRP_INSTALL_STATE
;
595 case DevicePropertyRemovalPolicy
:
596 sp_property
= SPDRP_REMOVAL_POLICY
;
599 FIXME("Unhandled property %u.\n", property
);
600 return STATUS_NOT_IMPLEMENTED
;
603 if ((status
= get_device_instance_id( device
, device_instance_id
)))
606 if ((set
= SetupDiCreateDeviceInfoList( &GUID_NULL
, NULL
)) == INVALID_HANDLE_VALUE
)
608 ERR("Failed to create device list, error %#x.\n", GetLastError());
609 return GetLastError();
612 if (!SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
))
614 ERR("Failed to open device, error %#x.\n", GetLastError());
615 SetupDiDestroyDeviceInfoList( set
);
616 return GetLastError();
619 if (SetupDiGetDeviceRegistryPropertyW( set
, &sp_device
, sp_property
, NULL
, buffer
, length
, needed
))
620 status
= STATUS_SUCCESS
;
622 status
= GetLastError();
624 SetupDiDestroyDeviceInfoList( set
);
629 static NTSTATUS
create_device_symlink( DEVICE_OBJECT
*device
, UNICODE_STRING
*symlink_name
)
631 UNICODE_STRING device_nameU
;
636 ret
= IoGetDeviceProperty( device
, DevicePropertyPhysicalDeviceObjectName
, 0, NULL
, &len
);
637 if (ret
!= STATUS_BUFFER_TOO_SMALL
)
640 device_name
= heap_alloc( len
);
641 ret
= IoGetDeviceProperty( device
, DevicePropertyPhysicalDeviceObjectName
, len
, device_name
, &len
);
644 heap_free( device_name
);
648 RtlInitUnicodeString( &device_nameU
, device_name
);
649 ret
= IoCreateSymbolicLink( symlink_name
, &device_nameU
);
650 heap_free( device_name
);
654 /***********************************************************************
655 * IoSetDeviceInterfaceState (NTOSKRNL.EXE.@)
657 NTSTATUS WINAPI
IoSetDeviceInterfaceState( UNICODE_STRING
*name
, BOOLEAN enable
)
659 static const WCHAR DeviceClassesW
[] = {'\\','R','E','G','I','S','T','R','Y','\\',
660 'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
661 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
662 'C','o','n','t','r','o','l','\\',
663 'D','e','v','i','c','e','C','l','a','s','s','e','s','\\',0};
664 static const WCHAR controlW
[] = {'C','o','n','t','r','o','l',0};
665 static const WCHAR linkedW
[] = {'L','i','n','k','e','d',0};
666 static const WCHAR slashW
[] = {'\\',0};
667 static const WCHAR hashW
[] = {'#',0};
669 size_t namelen
= name
->Length
/ sizeof(WCHAR
);
670 DEV_BROADCAST_DEVICEINTERFACE_W
*broadcast
;
671 struct device_interface
*iface
;
672 HANDLE iface_key
, control_key
;
673 OBJECT_ATTRIBUTES attr
= {0};
674 struct wine_rb_entry
*entry
;
675 WCHAR
*path
, *refstr
, *p
;
676 UNICODE_STRING string
;
681 TRACE("device %s, enable %u.\n", debugstr_us(name
), enable
);
683 entry
= wine_rb_get( &device_interfaces
, name
);
685 return STATUS_OBJECT_NAME_NOT_FOUND
;
687 iface
= WINE_RB_ENTRY_VALUE( entry
, struct device_interface
, entry
);
689 if (!enable
&& !iface
->enabled
)
690 return STATUS_OBJECT_NAME_NOT_FOUND
;
692 if (enable
&& iface
->enabled
)
693 return STATUS_OBJECT_NAME_EXISTS
;
695 for (p
= name
->Buffer
+ 4, refstr
= NULL
; p
< name
->Buffer
+ namelen
; p
++)
696 if (*p
== '\\') refstr
= p
;
697 if (!refstr
) refstr
= p
;
699 len
= lstrlenW(DeviceClassesW
) + 38 + 1 + namelen
+ 2 + 1;
701 if (!(path
= heap_alloc( len
* sizeof(WCHAR
) )))
702 return STATUS_NO_MEMORY
;
704 lstrcpyW( path
, DeviceClassesW
);
705 lstrcpynW( path
+ lstrlenW( path
), refstr
- 38, 39 );
706 lstrcatW( path
, slashW
);
707 p
= path
+ lstrlenW( path
);
708 lstrcpynW( path
+ lstrlenW( path
), name
->Buffer
, (refstr
- name
->Buffer
) + 1 );
709 p
[0] = p
[1] = p
[3] = '#';
710 lstrcatW( path
, slashW
);
711 lstrcatW( path
, hashW
);
712 if (refstr
< name
->Buffer
+ namelen
)
713 lstrcpynW( path
+ lstrlenW( path
), refstr
, name
->Buffer
+ namelen
- refstr
+ 1 );
715 attr
.Length
= sizeof(attr
);
716 attr
.ObjectName
= &string
;
717 RtlInitUnicodeString( &string
, path
);
718 ret
= NtOpenKey( &iface_key
, KEY_CREATE_SUB_KEY
, &attr
);
723 attr
.RootDirectory
= iface_key
;
724 RtlInitUnicodeString( &string
, controlW
);
725 ret
= NtCreateKey( &control_key
, KEY_SET_VALUE
, &attr
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
726 NtClose( iface_key
);
730 RtlInitUnicodeString( &string
, linkedW
);
731 ret
= NtSetValueKey( control_key
, &string
, 0, REG_DWORD
, &data
, sizeof(data
) );
734 NtClose( control_key
);
739 ret
= create_device_symlink( iface
->device
, name
);
741 ret
= IoDeleteSymbolicLink( name
);
744 NtDeleteValueKey( control_key
, &string
);
745 NtClose( control_key
);
749 iface
->enabled
= enable
;
751 len
= offsetof(DEV_BROADCAST_DEVICEINTERFACE_W
, dbcc_name
[namelen
+ 1]);
753 if ((broadcast
= heap_alloc( len
)))
755 broadcast
->dbcc_size
= len
;
756 broadcast
->dbcc_devicetype
= DBT_DEVTYP_DEVICEINTERFACE
;
757 broadcast
->dbcc_classguid
= iface
->interface_class
;
758 lstrcpynW( broadcast
->dbcc_name
, name
->Buffer
, namelen
+ 1 );
759 BroadcastSystemMessageW( BSF_FORCEIFHUNG
| BSF_QUERY
, NULL
, WM_DEVICECHANGE
,
760 enable
? DBT_DEVICEARRIVAL
: DBT_DEVICEREMOVECOMPLETE
, (LPARAM
)broadcast
);
762 heap_free( broadcast
);
767 /***********************************************************************
768 * IoRegisterDeviceInterface (NTOSKRNL.EXE.@)
770 NTSTATUS WINAPI
IoRegisterDeviceInterface(DEVICE_OBJECT
*device
, const GUID
*class_guid
,
771 UNICODE_STRING
*refstr
, UNICODE_STRING
*symbolic_link
)
773 SP_DEVICE_INTERFACE_DATA sp_iface
= {sizeof(sp_iface
)};
774 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
775 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
776 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*data
;
777 NTSTATUS status
= STATUS_SUCCESS
;
778 UNICODE_STRING device_path
;
779 struct device_interface
*iface
;
780 struct wine_rb_entry
*entry
;
784 TRACE("device %p, class_guid %s, refstr %s, symbolic_link %p.\n",
785 device
, debugstr_guid(class_guid
), debugstr_us(refstr
), symbolic_link
);
787 if ((status
= get_device_instance_id( device
, device_instance_id
)))
790 set
= SetupDiGetClassDevsW( class_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
791 if (set
== INVALID_HANDLE_VALUE
) return STATUS_UNSUCCESSFUL
;
793 if (!SetupDiCreateDeviceInfoW( set
, device_instance_id
, class_guid
, NULL
, NULL
, 0, &sp_device
)
794 && !SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
))
796 ERR("Failed to create device %s, error %#x.\n", debugstr_w(device_instance_id
), GetLastError());
797 return GetLastError();
800 if (!SetupDiCreateDeviceInterfaceW( set
, &sp_device
, class_guid
, refstr
? refstr
->Buffer
: NULL
, 0, &sp_iface
))
801 return STATUS_UNSUCCESSFUL
;
804 SetupDiGetDeviceInterfaceDetailW( set
, &sp_iface
, NULL
, 0, &required
, NULL
);
805 if (required
== 0) return STATUS_UNSUCCESSFUL
;
807 data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, required
);
808 data
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
);
810 if (!SetupDiGetDeviceInterfaceDetailW( set
, &sp_iface
, data
, required
, NULL
, NULL
))
812 HeapFree( GetProcessHeap(), 0, data
);
813 return STATUS_UNSUCCESSFUL
;
816 data
->DevicePath
[1] = '?';
817 TRACE("Returning path %s.\n", debugstr_w(data
->DevicePath
));
818 RtlCreateUnicodeString( &device_path
, data
->DevicePath
);
820 entry
= wine_rb_get( &device_interfaces
, &device_path
);
823 iface
= WINE_RB_ENTRY_VALUE( entry
, struct device_interface
, entry
);
825 ERR("Device interface %s is still enabled.\n", debugstr_us(&iface
->symbolic_link
));
829 iface
= heap_alloc_zero( sizeof(struct device_interface
) );
830 RtlCreateUnicodeString(&iface
->symbolic_link
, data
->DevicePath
);
831 if (wine_rb_put( &device_interfaces
, &iface
->symbolic_link
, &iface
->entry
))
832 ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface
->symbolic_link
));
835 iface
->device
= device
;
836 iface
->interface_class
= *class_guid
;
838 RtlCreateUnicodeString( symbolic_link
, data
->DevicePath
);
840 HeapFree( GetProcessHeap(), 0, data
);
842 RtlFreeUnicodeString( &device_path
);
847 /***********************************************************************
848 * IoOpenDeviceRegistryKey (NTOSKRNL.EXE.@)
850 NTSTATUS WINAPI
IoOpenDeviceRegistryKey( DEVICE_OBJECT
*device
, ULONG type
, ACCESS_MASK access
, HANDLE
*key
)
852 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
853 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
857 TRACE("device %p, type %#x, access %#x, key %p.\n", device
, type
, access
, key
);
859 if ((status
= get_device_instance_id( device
, device_instance_id
)))
861 ERR("Failed to get device instance ID, error %#x.\n", status
);
865 set
= SetupDiCreateDeviceInfoList( &GUID_NULL
, NULL
);
867 SetupDiOpenDeviceInfoW( set
, device_instance_id
, NULL
, 0, &sp_device
);
869 *key
= SetupDiOpenDevRegKey( set
, &sp_device
, DICS_FLAG_GLOBAL
, 0, type
, access
);
870 SetupDiDestroyDeviceInfoList( set
);
871 if (*key
== INVALID_HANDLE_VALUE
)
872 return GetLastError();
873 return STATUS_SUCCESS
;
876 /***********************************************************************
877 * PoSetPowerState (NTOSKRNL.EXE.@)
879 POWER_STATE WINAPI
PoSetPowerState( DEVICE_OBJECT
*device
, POWER_STATE_TYPE type
, POWER_STATE state
)
881 FIXME("device %p, type %u, state %u, stub!\n", device
, type
, state
.DeviceState
);
885 /*****************************************************
886 * PoStartNextPowerIrp (NTOSKRNL.EXE.@)
888 void WINAPI
PoStartNextPowerIrp( IRP
*irp
)
890 FIXME("irp %p, stub!\n", irp
);
893 /*****************************************************
894 * PoCallDriver (NTOSKRNL.EXE.@)
896 NTSTATUS WINAPI
PoCallDriver( DEVICE_OBJECT
*device
, IRP
*irp
)
898 TRACE("device %p, irp %p.\n", device
, irp
);
899 return IoCallDriver( device
, irp
);
902 static DRIVER_OBJECT
*pnp_manager
;
904 struct root_pnp_device
906 WCHAR id
[MAX_DEVICE_ID_LEN
];
907 struct wine_rb_entry entry
;
908 DEVICE_OBJECT
*device
;
911 static int root_pnp_devices_rb_compare( const void *key
, const struct wine_rb_entry
*entry
)
913 const struct root_pnp_device
*device
= WINE_RB_ENTRY_VALUE( entry
, const struct root_pnp_device
, entry
);
914 const WCHAR
*k
= key
;
916 return wcsicmp( k
, device
->id
);
919 static struct wine_rb_tree root_pnp_devices
= { root_pnp_devices_rb_compare
};
921 static NTSTATUS WINAPI
pnp_manager_device_pnp( DEVICE_OBJECT
*device
, IRP
*irp
)
923 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation( irp
);
924 struct root_pnp_device
*root_device
= device
->DeviceExtension
;
927 TRACE("device %p, irp %p, minor function %#x.\n", device
, irp
, stack
->MinorFunction
);
929 switch (stack
->MinorFunction
)
931 case IRP_MN_QUERY_DEVICE_RELATIONS
:
932 /* The FDO above already handled this, so return the same status. */
934 case IRP_MN_START_DEVICE
:
935 case IRP_MN_SURPRISE_REMOVAL
:
936 case IRP_MN_REMOVE_DEVICE
:
938 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
940 case IRP_MN_QUERY_CAPABILITIES
:
941 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
943 case IRP_MN_QUERY_ID
:
945 BUS_QUERY_ID_TYPE type
= stack
->Parameters
.QueryId
.IdType
;
948 TRACE("Received IRP_MN_QUERY_ID, type %#x.\n", type
);
952 case BusQueryDeviceID
:
953 p
= wcsrchr( root_device
->id
, '\\' );
954 if ((id
= ExAllocatePool( NonPagedPool
, (p
- root_device
->id
+ 1) * sizeof(WCHAR
) )))
956 memcpy( id
, root_device
->id
, (p
- root_device
->id
) * sizeof(WCHAR
) );
957 id
[p
- root_device
->id
] = 0;
958 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
959 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
963 irp
->IoStatus
.Information
= 0;
964 irp
->IoStatus
.u
.Status
= STATUS_NO_MEMORY
;
967 case BusQueryInstanceID
:
968 p
= wcsrchr( root_device
->id
, '\\' );
969 if ((id
= ExAllocatePool( NonPagedPool
, (wcslen( p
+ 1 ) + 1) * sizeof(WCHAR
) )))
972 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
973 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
977 irp
->IoStatus
.Information
= 0;
978 irp
->IoStatus
.u
.Status
= STATUS_NO_MEMORY
;
982 FIXME("Unhandled IRP_MN_QUERY_ID type %#x.\n", type
);
987 FIXME("Unhandled PnP request %#x.\n", stack
->MinorFunction
);
990 status
= irp
->IoStatus
.u
.Status
;
991 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
995 static NTSTATUS WINAPI
pnp_manager_driver_entry( DRIVER_OBJECT
*driver
, UNICODE_STRING
*keypath
)
997 pnp_manager
= driver
;
998 driver
->MajorFunction
[IRP_MJ_PNP
] = pnp_manager_device_pnp
;
999 return STATUS_SUCCESS
;
1002 void pnp_manager_start(void)
1004 static const WCHAR driver_nameW
[] = {'\\','D','r','i','v','e','r','\\','P','n','p','M','a','n','a','g','e','r',0};
1005 UNICODE_STRING driver_nameU
;
1008 RtlInitUnicodeString( &driver_nameU
, driver_nameW
);
1009 if ((status
= IoCreateDriver( &driver_nameU
, pnp_manager_driver_entry
)))
1010 ERR("Failed to create PnP manager driver, status %#x.\n", status
);
1013 static void destroy_root_pnp_device( struct wine_rb_entry
*entry
, void *context
)
1015 struct root_pnp_device
*device
= WINE_RB_ENTRY_VALUE(entry
, struct root_pnp_device
, entry
);
1016 remove_device( device
->device
);
1019 void pnp_manager_stop(void)
1021 wine_rb_destroy( &root_pnp_devices
, destroy_root_pnp_device
, NULL
);
1022 IoDeleteDriver( pnp_manager
);
1025 void pnp_manager_enumerate_root_devices( const WCHAR
*driver_name
)
1027 static const WCHAR driverW
[] = {'\\','D','r','i','v','e','r','\\',0};
1028 static const WCHAR rootW
[] = {'R','O','O','T',0};
1029 WCHAR buffer
[MAX_SERVICE_NAME
+ ARRAY_SIZE(driverW
)], id
[MAX_DEVICE_ID_LEN
];
1030 SP_DEVINFO_DATA sp_device
= {sizeof(sp_device
)};
1031 struct root_pnp_device
*pnp_device
;
1032 DEVICE_OBJECT
*device
;
1037 TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name
));
1039 set
= SetupDiGetClassDevsW( NULL
, rootW
, NULL
, DIGCF_ALLCLASSES
);
1040 if (set
== INVALID_HANDLE_VALUE
)
1042 ERR("Failed to build device set, error %#x.\n", GetLastError());
1046 for (i
= 0; SetupDiEnumDeviceInfo( set
, i
, &sp_device
); ++i
)
1048 if (!SetupDiGetDeviceRegistryPropertyW( set
, &sp_device
, SPDRP_SERVICE
,
1049 NULL
, (BYTE
*)buffer
, sizeof(buffer
), NULL
)
1050 || lstrcmpiW( buffer
, driver_name
))
1055 SetupDiGetDeviceInstanceIdW( set
, &sp_device
, id
, ARRAY_SIZE(id
), NULL
);
1057 if (wine_rb_get( &root_pnp_devices
, id
))
1060 TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id
));
1062 if ((status
= IoCreateDevice( pnp_manager
, sizeof(struct root_pnp_device
), NULL
,
1063 FILE_DEVICE_CONTROLLER
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &device
)))
1065 ERR("Failed to create root-enumerated PnP device %s, status %#x.\n", debugstr_w(id
), status
);
1069 pnp_device
= device
->DeviceExtension
;
1070 wcscpy( pnp_device
->id
, id
);
1071 pnp_device
->device
= device
;
1072 if (wine_rb_put( &root_pnp_devices
, id
, &pnp_device
->entry
))
1074 ERR("Failed to insert device %s into tree.\n", debugstr_w(id
));
1075 IoDeleteDevice( device
);
1079 start_device( device
, set
, &sp_device
);
1082 SetupDiDestroyDeviceInfoList(set
);