diff --git a/dlls/winebus.sys/Makefile.in b/dlls/winebus.sys/Makefile.in index 99ff4d22749..b24416b1606 100644 --- a/dlls/winebus.sys/Makefile.in +++ b/dlls/winebus.sys/Makefile.in @@ -1,5 +1,7 @@ MODULE = winebus.sys IMPORTS = ntoskrnl +EXTRALIBS = $(UDEV_LIBS) +EXTRAINCL = $(UDEV_CFLAGS) EXTRADLLFLAGS = -Wb,--subsystem,native C_SRCS = \ diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index f040e60e3e1..d47a556d2df 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -19,7 +19,16 @@ */ #include "config.h" +#include +#include #include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_LIBUDEV_H +# include +#endif #define NONAMELESSUNION @@ -27,6 +36,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "winnls.h" #include "winternl.h" #include "ddk/wdm.h" #include "wine/debug.h" @@ -37,15 +47,118 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay); #ifdef HAVE_UDEV +static struct udev *udev_context = NULL; static DRIVER_OBJECT *udev_driver_obj = NULL; +static DWORD get_sysattr_dword(struct udev_device *dev, const char *sysattr, int base) +{ + const char *attr = udev_device_get_sysattr_value(dev, sysattr); + if (!attr) + { + WARN("Could not get %s from device\n", sysattr); + return 0; + } + return strtol(attr, NULL, base); +} + +static WCHAR *get_sysattr_string(struct udev_device *dev, const char *sysattr) +{ + const char *attr = udev_device_get_sysattr_value(dev, sysattr); + WCHAR *dst; + DWORD len; + if (!attr) + { + WARN("Could not get %s from device\n", sysattr); + return NULL; + } + len = MultiByteToWideChar(CP_UNIXCP, 0, attr, -1, NULL, 0); + if ((dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) + MultiByteToWideChar(CP_UNIXCP, 0, attr, -1, dst, len); + return dst; +} + +static void try_add_device(struct udev_device *dev) +{ + DWORD vid = 0, pid = 0, version = 0; + struct udev_device *usbdev; + const char *devnode; + WCHAR *serial = NULL; + int fd; + + if (!(devnode = udev_device_get_devnode(dev))) + return; + + if ((fd = open(devnode, O_RDWR)) == -1) + { + WARN("Unable to open udev device %s: %s\n", debugstr_a(devnode), strerror(errno)); + return; + } + close(fd); + + usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"); + if (usbdev) + { + vid = get_sysattr_dword(usbdev, "idVendor", 16); + pid = get_sysattr_dword(usbdev, "idProduct", 16); + version = get_sysattr_dword(usbdev, "version", 10); + serial = get_sysattr_string(usbdev, "serial"); + } + + TRACE("Found udev device %s (vid %04x, pid %04x, version %u, serial %s)\n", + debugstr_a(devnode), vid, pid, version, debugstr_w(serial)); + + HeapFree(GetProcessHeap(), 0, serial); +} + +static void build_initial_deviceset(void) +{ + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + + enumerate = udev_enumerate_new(udev_context); + if (!enumerate) + { + WARN("Unable to create udev enumeration object\n"); + return; + } + + if (udev_enumerate_add_match_subsystem(enumerate, "hidraw") < 0) + WARN("Failed to add subsystem 'hidraw' to enumeration\n"); + + if (udev_enumerate_scan_devices(enumerate) < 0) + WARN("Enumeration scan failed\n"); + + devices = udev_enumerate_get_list_entry(enumerate); + udev_list_entry_foreach(dev_list_entry, devices) + { + struct udev_device *dev; + const char *path; + + path = udev_list_entry_get_name(dev_list_entry); + if ((dev = udev_device_new_from_syspath(udev_context, path))) + { + try_add_device(dev); + udev_device_unref(dev); + } + } + + udev_enumerate_unref(enumerate); +} + NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_path) { TRACE("(%p, %s)\n", driver, debugstr_w(registry_path->Buffer)); + if (!(udev_context = udev_new())) + { + ERR("Can't create udev object\n"); + return STATUS_UNSUCCESSFUL; + } + udev_driver_obj = driver; driver->MajorFunction[IRP_MJ_PNP] = common_pnp_dispatch; + build_initial_deviceset(); return STATUS_SUCCESS; }