From: Aric Stewart Subject: [PATCH v2 2/8] wineplugplay.sys: Initialize device driver store Message-Id: Date: Mon, 22 Aug 2016 09:19:43 -0500 v2: Suggestions by Sebastian Lackner Move loading the driver to a dynamic method 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 --- dlls/wineplugplay.sys/Makefile.in | 5 +- dlls/wineplugplay.sys/main.c | 3 + dlls/wineplugplay.sys/pnp.h | 20 +++++ dlls/wineplugplay.sys/pnp_manager.c | 162 ++++++++++++++++++++++++++++++++++++ 4 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 dlls/wineplugplay.sys/pnp.h create mode 100644 dlls/wineplugplay.sys/pnp_manager.c diff --git a/dlls/wineplugplay.sys/Makefile.in b/dlls/wineplugplay.sys/Makefile.in index 4039a8d..618dac7 100644 --- a/dlls/wineplugplay.sys/Makefile.in +++ b/dlls/wineplugplay.sys/Makefile.in @@ -1,6 +1,7 @@ MODULE = wineplugplay.sys -IMPORTS = ntoskrnl +IMPORTS = ntoskrnl advapi32 EXTRADLLFLAGS = -Wb,--subsystem,native C_SRCS = \ - main.c + main.c \ + pnp_manager.c diff --git a/dlls/wineplugplay.sys/main.c b/dlls/wineplugplay.sys/main.c index 51b5d97..57cb9fb 100644 --- a/dlls/wineplugplay.sys/main.c +++ b/dlls/wineplugplay.sys/main.c @@ -30,11 +30,14 @@ #include "wine/unicode.h" #include "wine/debug.h" +#include "pnp.h" + WINE_DEFAULT_DEBUG_CHANNEL(plugplay); /* main entry point for the driver */ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) { TRACE("\n"); + Initialize_DriverStore(); return STATUS_SUCCESS; } diff --git a/dlls/wineplugplay.sys/pnp.h b/dlls/wineplugplay.sys/pnp.h new file mode 100644 index 0000000..db18202 --- /dev/null +++ b/dlls/wineplugplay.sys/pnp.h @@ -0,0 +1,20 @@ +/* + * Copyright 2016 Aric Stewart + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* Plug and Play Manager */ +void Initialize_DriverStore(void) DECLSPEC_HIDDEN; diff --git a/dlls/wineplugplay.sys/pnp_manager.c b/dlls/wineplugplay.sys/pnp_manager.c new file mode 100644 index 0000000..5620135 --- /dev/null +++ b/dlls/wineplugplay.sys/pnp_manager.c @@ -0,0 +1,162 @@ +/* HID plug and play Manager like functionality + * + * Copyright 2016 CodeWeavers, Aric Stewart + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "ddk/wdm.h" +#include "cfgmgr32.h" +#include "winsvc.h" +#include "winreg.h" +#include "wine/debug.h" +#include "wine/list.h" + +#include "pnp.h" + +WINE_DEFAULT_DEBUG_CHANNEL(plugplay); + +#define MAX_SERVICE_NAME 260 + +typedef struct _device_driver { + struct list entry; + + BOOL loaded; + + WCHAR **matching_ids; + INT id_count; + + WCHAR *driver_name; +} device_driver; + +struct list device_drivers = LIST_INIT(device_drivers); + +static inline LPWSTR strdupW(LPCWSTR src) +{ + LPWSTR dest; + + if (!src) + return NULL; + + dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR)); + if (dest) + lstrcpyW(dest, src); + + return dest; +} + +static device_driver* register_device_driver(const WCHAR *drivername, const WCHAR* match) +{ + device_driver *ptr; + + LIST_FOR_EACH_ENTRY(ptr, &device_drivers, device_driver, entry) + { + if (lstrcmpW(drivername, ptr->driver_name) == 0) + { + int i; + /* Check matching ids */ + for (i = 0; i < ptr->id_count; i++) + if (lstrcmpW(match, ptr->matching_ids[i]) == 0) + return ptr; + /* Add a new matching id, this should be reletivly rare, + no exponental growth needed */ + ptr->matching_ids = HeapReAlloc(GetProcessHeap(), 0, ptr->matching_ids, sizeof(WCHAR*) * (ptr->id_count+1)); + ptr->matching_ids[ptr->id_count] = strdupW(match); + ptr->id_count++; + + return ptr; + } + } + + ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ptr)); + ptr->driver_name = strdupW(drivername); + ptr->loaded = FALSE; + ptr->matching_ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR*)); + ptr->matching_ids[0] = strdupW(match); + ptr->id_count = 1; + list_add_tail(&device_drivers, &ptr->entry); + + return ptr; +} + +void Initialize_DriverStore(void) +{ + static const WCHAR criticalW[] = + { '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', 0}; + static const WCHAR serviceW[] = {'S','e','r','v','i','c','e',0}; + HKEY hkey_root; + WCHAR szMatch[MAX_DEVICE_ID_LEN]; + + int i; + + if (RegOpenKeyW(HKEY_LOCAL_MACHINE, criticalW, &hkey_root)) + { + TRACE("No drivers found\n"); + return; + } + + for (i = 0; TRUE; i++) + { + HKEY hkey_service; + DWORD rc; + device_driver *driver; + DWORD len = 0; + WCHAR szService[MAX_SERVICE_NAME]; + + rc = RegEnumKeyW(hkey_root, i, szMatch, MAX_DEVICE_ID_LEN); + if (rc == ERROR_NO_MORE_ITEMS) + break; + + if (rc != 0) + { + ERR("Error %d reading key %d - skipping\n", rc, i); + continue; + } + + if (RegOpenKeyW(hkey_root, szMatch, &hkey_service)) + { + ERR("Error opening key %s - skipping\n",debugstr_w(szMatch)); + continue; + } + + len = sizeof(szService); + rc = RegQueryValueExW(hkey_service, serviceW, NULL, NULL, (BYTE*)szService, &len); + if (rc != ERROR_SUCCESS) + { + ERR("Error querying service from key %s - skipping\n",debugstr_w(szMatch)); + RegCloseKey(hkey_service); + continue; + } + RegCloseKey(hkey_service); + + TRACE("Registering service '%s' to match '%s'\n", debugstr_w(szService), debugstr_w(szMatch)); + + driver = register_device_driver(szService, szMatch); + if (!driver) + ERR("failed to load driver %s\n", debugstr_w(szService)); + + } + + RegCloseKey(hkey_root); +}