winebus.sys: Implement udev device enumeration.
[wine.git] / dlls / winebus.sys / bus_udev.c
blobd47a556d2df8671eeb09bc88149f108cc7957cc8
1 /*
2 * Plug and Play support for hid devices found through udev
4 * Copyright 2016 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #ifdef HAVE_LIBUDEV_H
30 # include <libudev.h>
31 #endif
33 #define NONAMELESSUNION
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winternl.h"
41 #include "ddk/wdm.h"
42 #include "wine/debug.h"
44 #include "bus.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
48 #ifdef HAVE_UDEV
50 static struct udev *udev_context = NULL;
51 static DRIVER_OBJECT *udev_driver_obj = NULL;
53 static DWORD get_sysattr_dword(struct udev_device *dev, const char *sysattr, int base)
55 const char *attr = udev_device_get_sysattr_value(dev, sysattr);
56 if (!attr)
58 WARN("Could not get %s from device\n", sysattr);
59 return 0;
61 return strtol(attr, NULL, base);
64 static WCHAR *get_sysattr_string(struct udev_device *dev, const char *sysattr)
66 const char *attr = udev_device_get_sysattr_value(dev, sysattr);
67 WCHAR *dst;
68 DWORD len;
69 if (!attr)
71 WARN("Could not get %s from device\n", sysattr);
72 return NULL;
74 len = MultiByteToWideChar(CP_UNIXCP, 0, attr, -1, NULL, 0);
75 if ((dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
76 MultiByteToWideChar(CP_UNIXCP, 0, attr, -1, dst, len);
77 return dst;
80 static void try_add_device(struct udev_device *dev)
82 DWORD vid = 0, pid = 0, version = 0;
83 struct udev_device *usbdev;
84 const char *devnode;
85 WCHAR *serial = NULL;
86 int fd;
88 if (!(devnode = udev_device_get_devnode(dev)))
89 return;
91 if ((fd = open(devnode, O_RDWR)) == -1)
93 WARN("Unable to open udev device %s: %s\n", debugstr_a(devnode), strerror(errno));
94 return;
96 close(fd);
98 usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
99 if (usbdev)
101 vid = get_sysattr_dword(usbdev, "idVendor", 16);
102 pid = get_sysattr_dword(usbdev, "idProduct", 16);
103 version = get_sysattr_dword(usbdev, "version", 10);
104 serial = get_sysattr_string(usbdev, "serial");
107 TRACE("Found udev device %s (vid %04x, pid %04x, version %u, serial %s)\n",
108 debugstr_a(devnode), vid, pid, version, debugstr_w(serial));
110 HeapFree(GetProcessHeap(), 0, serial);
113 static void build_initial_deviceset(void)
115 struct udev_enumerate *enumerate;
116 struct udev_list_entry *devices, *dev_list_entry;
118 enumerate = udev_enumerate_new(udev_context);
119 if (!enumerate)
121 WARN("Unable to create udev enumeration object\n");
122 return;
125 if (udev_enumerate_add_match_subsystem(enumerate, "hidraw") < 0)
126 WARN("Failed to add subsystem 'hidraw' to enumeration\n");
128 if (udev_enumerate_scan_devices(enumerate) < 0)
129 WARN("Enumeration scan failed\n");
131 devices = udev_enumerate_get_list_entry(enumerate);
132 udev_list_entry_foreach(dev_list_entry, devices)
134 struct udev_device *dev;
135 const char *path;
137 path = udev_list_entry_get_name(dev_list_entry);
138 if ((dev = udev_device_new_from_syspath(udev_context, path)))
140 try_add_device(dev);
141 udev_device_unref(dev);
145 udev_enumerate_unref(enumerate);
148 NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_path)
150 TRACE("(%p, %s)\n", driver, debugstr_w(registry_path->Buffer));
152 if (!(udev_context = udev_new()))
154 ERR("Can't create udev object\n");
155 return STATUS_UNSUCCESSFUL;
158 udev_driver_obj = driver;
159 driver->MajorFunction[IRP_MJ_PNP] = common_pnp_dispatch;
161 build_initial_deviceset();
162 return STATUS_SUCCESS;
165 #else
167 NTSTATUS WINAPI udev_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_path)
169 WARN("Wine was compiled without UDEV support\n");
170 return STATUS_NOT_IMPLEMENTED;
173 #endif /* HAVE_UDEV */