On 31.08.2016 18:38, Aric Stewart wrote:
v2: No longer maintaining a device store Suggestions from Sebastian Lackner
We are not handling installing drivers just yet, so we just make use of the critical device store. These are drivers that, on Windows, are automatically loaded on boot every time. This database is maintained in [CurrentControlSet/Control/CriticalDeviceDatabase] The keys in this registry key represent a HardwareID that match a device. We query the IDs from the bus device’s BusQueryHardwareIDs and if we find a match (from most specific to most general) we look at that registry key. The CriticalDeviceDatabase entry specify a [Service] value representing the driver.
Signed-off-by: Aric Stewart aric@codeweavers.com
dlls/ntoskrnl.exe/pnp_manager.c | 196 +++++++++++++++++++++++++++++++++++++++- include/ddk/wdm.h | 3 +- 2 files changed, 197 insertions(+), 2 deletions(-)
v2-0002-ntoskrnl.exe-Implement-loading-plug-and-play-device.txt
diff --git a/dlls/ntoskrnl.exe/pnp_manager.c b/dlls/ntoskrnl.exe/pnp_manager.c index 7ebd07d..04b218b 100644 --- a/dlls/ntoskrnl.exe/pnp_manager.c +++ b/dlls/ntoskrnl.exe/pnp_manager.c @@ -17,6 +17,7 @@
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#define NONAMELESSUNION #include <stdarg.h> #include "ntstatus.h" #define WIN32_NO_STATUS @@ -24,14 +25,207 @@ #include "winbase.h" #include "winternl.h" #include "ddk/wdm.h" +#include "wine/unicode.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
+#define MAX_SERVICE_NAME 260
+static NTSTATUS WINAPI internal_complete(DEVICE_OBJECT *deviceObject, IRP *irp, void *context) +{
- SetEvent(irp->UserEvent);
- return STATUS_MORE_PROCESSING_REQUIRED;
+}
+static NTSTATUS send_device_irp(DEVICE_OBJECT *device, IRP *irp, ULONG_PTR *info) +{
- NTSTATUS status;
- IO_STACK_LOCATION *irpsp;
- HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
- irp->UserEvent = event;
- irpsp = IoGetNextIrpStackLocation(irp);
- irpsp->CompletionRoutine = internal_complete;
- irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
- IoCallDriver(device, irp);
- if (irp->IoStatus.u.Status == STATUS_PENDING)
WaitForSingleObject(event, INFINITE);
- status = irp->IoStatus.u.Status;
- if (info)
*info = irp->IoStatus.Information;
- IoCompleteRequest(irp, IO_NO_INCREMENT);
- CloseHandle(event);
- return status;
+}
+static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR **id) +{
- IO_STACK_LOCATION *irpsp;
- IO_STATUS_BLOCK irp_status;
- IRP *irp;
- irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status);
- if (irp == NULL)
return STATUS_NO_MEMORY;
- irpsp = IoGetNextIrpStackLocation(irp);
- irpsp->MinorFunction = IRP_MN_QUERY_ID;
- irpsp->Parameters.QueryId.IdType = type;
- return send_device_irp(device, irp, (ULONG_PTR*)id);
+}
+static NTSTATUS find_driver_for_id(const WCHAR *id, WCHAR *driver) +{
- NTSTATUS rc;
- static const WCHAR critical_fmtW[] =
{'\\','R','e','g','i','s','t','r','y',
'\\','M','a','c','h','i','n','e',
'\\','S','y','s','t','e','m',
'\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
'\\','C','o','n','t','r','o','l',
'\\','C','r','i','t','i','c','a','l','D','e','v','i','c','e','D','a','t','a','b','a','s','e',
'\\','%','s',0};
- HANDLE hkey;
- WCHAR *regW;
- UNICODE_STRING key;
- OBJECT_ATTRIBUTES attr;
- regW = HeapAlloc(GetProcessHeap(), 0, sizeof(critical_fmtW) + strlenW(id) * sizeof(WCHAR));
- sprintfW(regW, critical_fmtW, id);
- RtlInitUnicodeString(&key, regW);
- InitializeObjectAttributes(&attr, &key, OBJ_CASE_INSENSITIVE, NULL, NULL);
- rc = ZwOpenKey(&hkey, KEY_ALL_ACCESS, &attr);
- if (rc == STATUS_SUCCESS)
- {
static const WCHAR serviceW[] = {'S','e','r','v','i','c','e',0};
static const UNICODE_STRING serviceStr = {sizeof(serviceW) - sizeof(WCHAR), sizeof(serviceW), (WCHAR*)serviceW};
KEY_VALUE_PARTIAL_INFORMATION *info;
DWORD total_size = sizeof(*info) + MAX_SERVICE_NAME * sizeof(WCHAR);
info = HeapAlloc(GetProcessHeap(), 0, total_size);
rc = ZwQueryValueKey(hkey, &serviceStr, KeyValuePartialInformation, info, total_size, &total_size);
if (rc == STATUS_SUCCESS && info->Type == REG_SZ && info->DataLength < MAX_SERVICE_NAME * sizeof(WCHAR))
{
WCHAR *service = (WCHAR*)info->Data;
TRACE("Got service %s\n",debugstr_w(service));
strcpyW(driver, service);
}
else
{
if (info->Type != REG_SZ)
ERR("Failed to get Service from registry entry, Bad type\n");
else if (info->DataLength >= MAX_SERVICE_NAME * sizeof(WCHAR))
ERR("Failed to get Service from registry entry, Buffer too small\n");
else
ERR("Failed to get Service from registry entry (%x)\n",rc);
I don't think it makes sense to trace this an error, especially when you use a TRACE for the lack of a critical device database key.
}
HeapFree(GetProcessHeap(), 0, info);
ZwClose(hkey);
- }
- else
TRACE("Failed to find Critical Device Database entry for %s\n",debugstr_w(id));
- HeapFree(GetProcessHeap(), 0, regW);
- return rc;
+}
+static void handle_bus_relations(DEVICE_OBJECT *device) +{
- static const WCHAR driverW[] = {'\','D','r','i','v','e','r','\',0};
- static const WCHAR servicesW[] = {'\','R','e','g','i','s','t','r','y',
'\\','M','a','c','h','i','n','e',
'\\','S','y','s','t','e','m',
'\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
'\\','S','e','r','v','i','c','e','s',
'\\',0};
- NTSTATUS status;
- WCHAR *id, *idptr;
- WCHAR driver[MAX_SERVICE_NAME] = {0};
- WCHAR fullname[MAX_PATH];
- DRIVER_OBJECT *driver_obj;
- UNICODE_STRING driverName;
- WCHAR driverKey[MAX_PATH];
- UNICODE_STRING driverPath;
You'll have to allocate bigger buffers for the concatenated strings. In fact, a single buffer should be sufficient for both the fullname and the driver key.
- TRACE("Device %p\n", device);
- /* We could(should?) do a full IRP_MN_QUERY_DEVICE_RELATIONS query,
* but we dont have to, We have the DEVICE_OBJECT of the new device
* so we can simply handle the process here */
- status = get_device_id(device, BusQueryCompatibleIDs, &id);
- if (status != ERROR_SUCCESS || !id)
- {
ERR("Failed to get device IDs\n");
return;
- }
- idptr = id;
- while(*idptr != 0)
- {
TRACE("Checking for id %s\n",debugstr_w(idptr));
if (find_driver_for_id(idptr, driver) == STATUS_SUCCESS)
break;
idptr += (strlenW(idptr) + 1);
- }
- HeapFree(GetProcessHeap(), 0, id);
- if (!driver[0])
- {
ERR("No matching driver found for device\n");
return;
- }
- strcpyW(driverKey, servicesW);
- strcatW(driverKey, driver);
- RtlInitUnicodeString(&driverPath, driverKey);
- if (ZwLoadDriver(&driverPath) != STATUS_SUCCESS)
- {
ERR("Failed to load driver %s\n", debugstr_w(driver));
return;
- }
- strcpyW(fullname, driverW);
- strcatW(fullname, driver);
- RtlInitUnicodeString(&driverName, fullname);
- if (ObReferenceObjectByName(&driverName, OBJ_CASE_INSENSITIVE, NULL,
0, NULL, KernelMode, NULL, (void**)&driver_obj) != STATUS_SUCCESS)
- {
ERR("Failed to locate loaded driver %s\n", debugstr_w(driver));
return;
- }
- if (!driver_obj->DriverExtension->AddDevice)
status = STATUS_NOT_IMPLEMENTED;
- else
status = driver_obj->DriverExtension->AddDevice(driver_obj, device);
- ObDereferenceObject(driver_obj);
- if (status != STATUS_SUCCESS)
ERR("AddDevice failed for driver %s\n", debugstr_w(driver));
+}
/***********************************************************************
IoInvalidateDeviceRelations(NTOSKRNL.EXE.@)
*/ void WINAPI IoInvalidateDeviceRelations(DEVICE_OBJECT *device_object, DEVICE_RELATION_TYPE type) {
- FIXME("(%p, %i): stub\n", device_object, type);
- TRACE("(%p, %i)\n", device_object, type);
- switch (type)
- {
case BusRelations:
handle_bus_relations(device_object);
break;
default:
FIXME("Unhandled Relation %i\n", type);
- }
} diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index bd3b323..e893ba2 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -48,6 +48,7 @@ typedef NTSTATUS (WINAPI *PDRIVER_INITIALIZE)(struct _DRIVER_OBJECT *, PUNICODE_ typedef NTSTATUS (WINAPI *PDRIVER_DISPATCH)(struct _DEVICE_OBJECT *, struct _IRP *); typedef void (WINAPI *PDRIVER_STARTIO)(struct _DEVICE_OBJECT *, struct _IRP *); typedef void (WINAPI *PDRIVER_UNLOAD)(struct _DRIVER_OBJECT *); +typedef NTSTATUS (WINAPI *PDRIVER_ADD_DEVICE)(struct _DRIVER_OBJECT *, struct _DEVICE_OBJECT *);
typedef struct _DISPATCHER_HEADER { UCHAR Type; @@ -336,7 +337,7 @@ typedef struct _DEVICE_RELATIONS *PDEVICE_RELATIONS;
typedef struct _DRIVER_EXTENSION { struct _DRIVER_OBJECT *DriverObject;
- PVOID AddDevice;
- PDRIVER_ADD_DEVICE AddDevice; ULONG Count; UNICODE_STRING ServiceKeyName;
} DRIVER_EXTENSION, *PDRIVER_EXTENSION;