[prev in list] [next in list] [prev in thread] [next in thread] 

List:       wine-patches
Subject:    [PATCH v2 04/11] winebus.sys: Build initial hidraw device set
From:       Aric Stewart <aric () codeweavers ! com>
Date:       2016-08-31 19:01:54
Message-ID: 0e02fcae-36dc-2991-f3c1-7bb9e9442ea0 () codeweavers ! com
[Download RAW message or body]

v2: style changes

Includes implementation of common HID_PNP_CreateDevice

Signed-off-by: Aric Stewart <aric@codeweavers.com>
---
 dlls/winebus.sys/Makefile.in      |   3 +-
 dlls/winebus.sys/bus.h            |   2 +
 dlls/winebus.sys/bus_hid_common.c | 146 +++++++++++++++++++++++++++++++++++---
 dlls/winebus.sys/bus_udev.c       | 125 ++++++++++++++++++++++++++++++++
 loader/wine.inf.in                |   1 +
 5 files changed, 267 insertions(+), 10 deletions(-)



["v2-0004-winebus.sys-Build-initial-hidraw-device-set.txt" (text/x-patch)]

diff --git a/dlls/winebus.sys/Makefile.in b/dlls/winebus.sys/Makefile.in
index f9555dd..81e739f 100644
--- a/dlls/winebus.sys/Makefile.in
+++ b/dlls/winebus.sys/Makefile.in
@@ -1,5 +1,6 @@
 MODULE    = winebus.sys
-IMPORTS = ntoskrnl
+IMPORTS = ntoskrnl advapi32 setupapi
+EXTRALIBS = $(UDEV_LIBS)
 EXTRADLLFLAGS = -Wb,--subsystem,native
 
 C_SRCS = \
diff --git a/dlls/winebus.sys/bus.h b/dlls/winebus.sys/bus.h
index a6f08b2..0f8af8b 100644
--- a/dlls/winebus.sys/bus.h
+++ b/dlls/winebus.sys/bus.h
@@ -22,3 +22,5 @@ NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, \
UNICODE_STRING *registry  /* HID Plug and Play Bus */
 NTSTATUS WINAPI common_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) \
DECLSPEC_HIDDEN;  DWORD check_bus_disabled(UNICODE_STRING *registry_path) \
DECLSPEC_HIDDEN; +DEVICE_OBJECT *bus_create_hid_device(DRIVER_OBJECT *driver, const \
WCHAR *busidW, LPVOID native, WORD vid, WORD pid, DWORD version, DWORD uid, const \
WCHAR *serial, BOOL is_gamepad, const GUID *class) DECLSPEC_HIDDEN; +DWORD \
check_bus_option(UNICODE_STRING *registry_path, const UNICODE_STRING *option) \
                DECLSPEC_HIDDEN;
diff --git a/dlls/winebus.sys/bus_hid_common.c b/dlls/winebus.sys/bus_hid_common.c
index 2128784..2a30647 100644
--- a/dlls/winebus.sys/bus_hid_common.c
+++ b/dlls/winebus.sys/bus_hid_common.c
@@ -17,6 +17,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
 #define NONAMELESSUNION
 #include <stdarg.h>
 #include "ntstatus.h"
@@ -39,6 +40,129 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
 
+static const WCHAR hwidfmtW[] =  \
{'%','s','\\','V','i','d','_','%','0','4','x','&','P','i','d','_','%','0','4','x','&','%','s','\\','%','i','&','%','s','&','%','p',0};
 +static const WCHAR im_fmtW[] = {'I','M','_','%','i',0};
+static const WCHAR ig_fmtW[] = {'I','G','_','%','i',0};
+
+typedef struct _pnp_device {
+    struct list entry;
+
+    DEVICE_OBJECT *device;
+    DWORD vidpid;
+} pnp_device;
+
+typedef struct {
+    LPVOID native;  /* Must be the first member of the structure */
+
+    DWORD vid, pid, version, uid;
+    BOOL is_gamepad;
+    WCHAR serial[255];
+    WCHAR const *busidW; /* Expected to be a static constant */
+} extension;
+
+static struct list pnp_devset = LIST_INIT(pnp_devset);
+
+static void add_device(DEVICE_OBJECT *device, DWORD vidpid)
+{
+    pnp_device *pnp_dev;
+
+    pnp_dev = HeapAlloc(GetProcessHeap(), 0, sizeof(*pnp_dev));
+    pnp_dev->device = device;
+    pnp_dev->vidpid = vidpid;
+    list_add_tail(&pnp_devset, &pnp_dev->entry);
+}
+
+static INT get_vidpid_index(DEVICE_OBJECT *device, DWORD vidpid)
+{
+    pnp_device *ptr;
+    int index = 0;
+    LIST_FOR_EACH_ENTRY(ptr, &pnp_devset, pnp_device, entry)
+    {
+        if (ptr->vidpid == vidpid)
+            index++;
+        if (ptr->device == device)
+            return index;
+    }
+    ERR("Device not found in list\n");
+    return 0;
+}
+
+static int get_instance_id(DEVICE_OBJECT *device, WCHAR *id)
+{
+    int idx;
+    WCHAR index_string[256];
+
+    extension *ext = (extension*)device->DeviceExtension;
+
+    idx = get_vidpid_index(device, MAKELONG(ext->vid,ext->pid));
+
+    if (ext->is_gamepad)
+        sprintfW(index_string, ig_fmtW, idx);
+    else
+        sprintfW(index_string, im_fmtW, idx);
+
+    return sprintfW(id, hwidfmtW, ext->busidW, ext->vid, ext->pid, index_string, \
ext->version, ext->serial, ext->uid); +}
+
+DEVICE_OBJECT* bus_create_hid_device(DRIVER_OBJECT *driver, const WCHAR *busidW, \
LPVOID native, WORD vid, WORD pid, DWORD version, DWORD uid, const WCHAR *serial, \
BOOL is_gamepad, const GUID *class) +{
+    NTSTATUS status;
+    DEVICE_OBJECT *device;
+    static const WCHAR device_name_fmtW[] = {'\\','D','e','v','i','c','e',
+    '\\','%','s','#','%','p',0};
+    static const WCHAR zero_serialW[]= {'0','0','0','0',0};
+    WCHAR dev_name[255];
+    UNICODE_STRING nameW;
+    HDEVINFO devinfo;
+    extension *ext;
+
+    TRACE("Create HID bus device for native device %p\n", native);
+
+    sprintfW(dev_name, device_name_fmtW, busidW, native);
+    RtlInitUnicodeString(&nameW, dev_name);
+    status = IoCreateDevice(driver, sizeof(extension), &nameW, 0, 0, FALSE, \
&device); +    if (status)
+    {
+        FIXME( "failed to create device error %x\n", status );
+        return NULL;
+    }
+
+    ext = (extension*)device->DeviceExtension;
+    ext->native = native;
+    ext->vid = vid;
+    ext->pid = pid;
+    ext->uid = uid;
+    ext->is_gamepad = is_gamepad;
+    ext->version = version;
+    ext->busidW = busidW;
+    if (serial)
+        lstrcpyW(ext->serial, serial);
+    else
+        lstrcpyW(ext->serial, zero_serialW);
+
+    add_device(device, MAKELONG(vid, pid));
+
+    devinfo = SetupDiGetClassDevsW(class, NULL, NULL, DIGCF_DEVICEINTERFACE);
+    if (!devinfo)
+        FIXME( "failed to get ClassDevs %x\n", GetLastError());
+    else
+    {
+        SP_DEVINFO_DATA Data;
+        WCHAR id[MAX_DEVICE_ID_LEN];
+
+        get_instance_id(device, id);
+        Data.cbSize = sizeof(Data);
+        SetupDiCreateDeviceInfoW(devinfo, id, class, NULL, NULL, \
DICD_INHERIT_CLASSDRVS, &Data); +        if (!SetupDiRegisterDeviceInfo(devinfo, \
&Data, 0, NULL, NULL, NULL )) +            FIXME( "failed to Register Device Info \
%x\n", GetLastError()); +        SetupDiDestroyDeviceInfoList(devinfo);
+    }
+
+    IoInvalidateDeviceRelations(device, BusRelations);
+
+    return device;
+}
+
 NTSTATUS WINAPI common_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
 {
     NTSTATUS rc = STATUS_NOT_SUPPORTED;
@@ -62,13 +186,11 @@ NTSTATUS WINAPI common_pnp_dispatch(DEVICE_OBJECT *device, IRP \
*irp)  return rc;
 }
 
-DWORD check_bus_disabled(UNICODE_STRING *registry_path)
+DWORD check_bus_option(UNICODE_STRING *registry_path, const UNICODE_STRING *option)
 {
     OBJECT_ATTRIBUTES attr;
     HANDLE key;
-    DWORD disabled = 0;
-    static const WCHAR disabledW[] = {'D','i','s','a','b','l','e','d',0};
-    static const UNICODE_STRING disabled_str = {sizeof(disabledW) - sizeof(WCHAR), \
sizeof(disabledW), (WCHAR*)disabledW}; +    DWORD output = 0;
 
     InitializeObjectAttributes(&attr, registry_path, OBJ_CASE_INSENSITIVE, NULL, \
NULL);  if (ZwOpenKey(&key, KEY_ALL_ACCESS, &attr) == STATUS_SUCCESS)
@@ -76,13 +198,19 @@ DWORD check_bus_disabled(UNICODE_STRING *registry_path)
         DWORD size;
         KEY_VALUE_PARTIAL_INFORMATION info;
 
-        if (ZwQueryValueKey(key, &disabled_str, KeyValuePartialInformation, &info, \
                sizeof(info), &size) == STATUS_SUCCESS)
-        {
-            disabled = *(DWORD*)&info.Data;
-        }
+        if (ZwQueryValueKey(key, option, KeyValuePartialInformation, &info, \
sizeof(info), &size) == STATUS_SUCCESS) +            output = *(DWORD*)&info.Data;
 
         ZwClose(key);
     }
 
-    return disabled;
+    return output;
+}
+
+DWORD check_bus_disabled(UNICODE_STRING *registry_path)
+{
+    static const WCHAR disabledW[] = {'D','i','s','a','b','l','e','d',0};
+    static const UNICODE_STRING disabled_str = {sizeof(disabledW) - sizeof(WCHAR), \
sizeof(disabledW), (WCHAR*)disabledW}; +
+    return check_bus_option(registry_path, &disabled_str);
 }
diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c
index 101bdeb..1866b4c 100644
--- a/dlls/winebus.sys/bus_udev.c
+++ b/dlls/winebus.sys/bus_udev.c
@@ -25,6 +25,10 @@
 # include <sys/ioctl.h>
 #endif
 
+#ifdef HAVE_LIBUDEV_H
+# include <libudev.h>
+#endif
+
 #include <errno.h>
 
 #define NONAMELESSUNION
@@ -45,13 +49,129 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
 
 static DRIVER_OBJECT *udev_driver_obj = NULL;
 
+#include "initguid.h"
+DEFINE_GUID(GUID_DEVCLASS_HIDRAW, \
0x3def44ad,0x242e,0x46e5,0x82,0x6d,0x70,0x72,0x13,0xf3,0xaa,0x81); +
+static const WCHAR hidraw_busidW[] = {'H','I','D','R','A','W',0};
+
+/* udev based PNP support */
+static struct udev *udev = NULL;
+static BOOL disable_hidraw = FALSE;
+
+static void try_add_device(void *dev)
+{
+    const char *devnode;
+    int fd;
+    DWORD vid=0, pid=0, uid=0, version=0;
+    WCHAR serial[255] = {'0','0','0','0','0',0};
+    DEVICE_OBJECT *device = NULL;
+    struct udev_device *usbdev;
+    const char *subsystem;
+
+    devnode = udev_device_get_devnode(dev);
+    if ((fd = open(devnode, O_RDWR)) == -1)
+    {
+        TRACE("Unable to open udev device %s\n",devnode);
+        return;
+    }
+    close(fd);
+
+    TRACE("Got udev device %s\n", devnode);
+
+    usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
+             "usb_device");
+    if (usbdev)
+    {
+        char *endptr;
+        const char *srl = NULL;
+        vid = strtol(udev_device_get_sysattr_value(usbdev,"idVendor"), &endptr, 16);
+        pid = strtol(udev_device_get_sysattr_value(usbdev,"idProduct"), &endptr, \
16); +        version = strtol(udev_device_get_sysattr_value(usbdev,"version"), \
&endptr, 10); +        srl = udev_device_get_sysattr_value(usbdev,"serial");
+        if (srl)
+            MultiByteToWideChar(CP_UNIXCP, 0, srl, -1, serial, 255);
+    }
+
+    subsystem = udev_device_get_subsystem(dev);
+
+    if (strcmp(subsystem, "hidraw") == 0)
+        device = bus_create_hid_device(udev_driver_obj, hidraw_busidW, dev, vid, \
pid, version, uid, serial, FALSE, &GUID_DEVCLASS_HIDRAW); +    else
+        ERR("Device has unknown subsystem %s\n", subsystem);
+
+    if (!device)
+        ERR("Failed to create device\n");
+}
+
+static NTSTATUS build_initial_deviceset(void *udev, const char **subsystems, void \
(*fn_add_device)(void *udev_device)) +{
+    struct udev_enumerate *enumerate;
+    struct udev_list_entry *udevices, *dev_list_entry;
+    const char **p;
+
+    enumerate = udev_enumerate_new(udev);
+    p = subsystems;
+    while (*p)
+    {
+        udev_enumerate_add_match_subsystem(enumerate, *p);
+        p++;
+    }
+    udev_enumerate_scan_devices(enumerate);
+    udevices = udev_enumerate_get_list_entry(enumerate);
+
+    udev_list_entry_foreach(dev_list_entry, udevices) {
+        const char *path;
+        struct udev_device *dev;
+
+        path = udev_list_entry_get_name(dev_list_entry);
+        dev = udev_device_new_from_syspath(udev, path);
+        fn_add_device(dev);
+    }
+
+    udev_enumerate_unref(enumerate);
+    return STATUS_SUCCESS;
+}
+
 static VOID WINAPI unload(DRIVER_OBJECT *driver)
 {
     TRACE("Linux udev Driver Unload\n");
 }
 
+/* This is our main even loop for reading devices */
+static DWORD CALLBACK deviceloop_thread(VOID *args)
+{
+    static const char *hidraw = "hidraw";
+    static const char *subsystems[2] = {0, 0};
+
+    if (!disable_hidraw)
+        subsystems[0] = hidraw;
+
+    if (udev)
+    {
+        TRACE("Udev already initialized\n");
+        return 0;
+    }
+
+    udev = udev_new();
+
+    if (!udev)
+    {
+        ERR("Can't create udev\n");
+        return 0;
+    }
+
+    /* PNP Bus initialization */
+    if (subsystems[0])
+        build_initial_deviceset(udev, subsystems, try_add_device);
+
+    return 1;
+}
+
 NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING \
*registry_path)  {
+    static const WCHAR hidraw_disabledW[] = {'D','i','s','a','b','l','e',' \
','h','i','d','r','a','w',0}; +    static const UNICODE_STRING hidraw_disabled = \
{sizeof(hidraw_disabledW) - sizeof(WCHAR), sizeof(hidraw_disabledW), \
(WCHAR*)hidraw_disabledW}; +
     TRACE("Linux udev Driver Init\n");
 
     udev_driver_obj = driver;
@@ -63,6 +183,11 @@ NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, \
UNICODE_STRING *registry  TRACE("UDEV plug and play bus disabled in registry\n");
         return STATUS_SUCCESS;
     }
+    disable_hidraw = check_bus_option(registry_path, &hidraw_disabled);
+    if (disable_hidraw)
+        TRACE("UDEV hidraw devices disabled in registry\n");
+
+    CreateThread(NULL, 0, deviceloop_thread, NULL, 0, NULL);
 
     return STATUS_SUCCESS;
 }
diff --git a/loader/wine.inf.in b/loader/wine.inf.in
index 5fa7183..d2210d1 100644
--- a/loader/wine.inf.in
+++ b/loader/wine.inf.in
@@ -3390,3 +3390,4 @@ \
HKLM,Software\Wine\LicenseInformation,"Shell-PremiumInBoxGames-Chess-EnableGame"  
 [PlatformBus]
 HKLM,System\CurrentControlSet\Services\UDEV,"Disabled",0x10001,0x00000000
+HKLM,System\CurrentControlSet\Services\UDEV,"Disable hidraw",0x10001,0x00000000


[Attachment #4 (text/plain)]




[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic