[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