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
32 #ifdef HAVE_SYS_POLL_H
33 # include <sys/poll.h>
38 #ifdef HAVE_LINUX_HIDRAW_H
39 # include <linux/hidraw.h>
41 #ifdef HAVE_SYS_IOCTL_H
42 # include <sys/ioctl.h>
45 #define NONAMELESSUNION
48 #define WIN32_NO_STATUS
54 #include "ddk/hidtypes.h"
55 #include "wine/debug.h"
56 #include "wine/unicode.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(plugplay
);
64 WINE_DECLARE_DEBUG_CHANNEL(hid_report
);
66 static struct udev
*udev_context
= NULL
;
67 static DRIVER_OBJECT
*udev_driver_obj
= NULL
;
69 static const WCHAR hidraw_busidW
[] = {'H','I','D','R','A','W',0};
72 DEFINE_GUID(GUID_DEVCLASS_HIDRAW
, 0x3def44ad,0x242e,0x46e5,0x82,0x6d,0x70,0x72,0x13,0xf3,0xaa,0x81);
74 struct platform_private
76 struct udev_device
*udev_device
;
83 static inline struct platform_private
*impl_from_DEVICE_OBJECT(DEVICE_OBJECT
*device
)
85 return (struct platform_private
*)get_platform_private(device
);
88 static inline WCHAR
*strdupAtoW(const char *src
)
92 if (!src
) return NULL
;
93 len
= MultiByteToWideChar(CP_UNIXCP
, 0, src
, -1, NULL
, 0);
94 if ((dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
95 MultiByteToWideChar(CP_UNIXCP
, 0, src
, -1, dst
, len
);
99 static DWORD
get_sysattr_dword(struct udev_device
*dev
, const char *sysattr
, int base
)
101 const char *attr
= udev_device_get_sysattr_value(dev
, sysattr
);
104 WARN("Could not get %s from device\n", sysattr
);
107 return strtol(attr
, NULL
, base
);
110 static WCHAR
*get_sysattr_string(struct udev_device
*dev
, const char *sysattr
)
112 const char *attr
= udev_device_get_sysattr_value(dev
, sysattr
);
115 WARN("Could not get %s from device\n", sysattr
);
118 return strdupAtoW(attr
);
121 static int compare_platform_device(DEVICE_OBJECT
*device
, void *platform_dev
)
123 struct udev_device
*dev1
= impl_from_DEVICE_OBJECT(device
)->udev_device
;
124 struct udev_device
*dev2
= platform_dev
;
125 return strcmp(udev_device_get_syspath(dev1
), udev_device_get_syspath(dev2
));
128 static NTSTATUS
hidraw_get_reportdescriptor(DEVICE_OBJECT
*device
, BYTE
*buffer
, DWORD length
, DWORD
*out_length
)
130 #ifdef HAVE_LINUX_HIDRAW_H
131 struct hidraw_report_descriptor descriptor
;
132 struct platform_private
*private = impl_from_DEVICE_OBJECT(device
);
134 if (ioctl(private->device_fd
, HIDIOCGRDESCSIZE
, &descriptor
.size
) == -1)
136 WARN("ioctl(HIDIOCGRDESCSIZE) failed: %d %s\n", errno
, strerror(errno
));
137 return STATUS_UNSUCCESSFUL
;
140 *out_length
= descriptor
.size
;
142 if (length
< descriptor
.size
)
143 return STATUS_BUFFER_TOO_SMALL
;
144 if (!descriptor
.size
)
145 return STATUS_SUCCESS
;
147 if (ioctl(private->device_fd
, HIDIOCGRDESC
, &descriptor
) == -1)
149 WARN("ioctl(HIDIOCGRDESC) failed: %d %s\n", errno
, strerror(errno
));
150 return STATUS_UNSUCCESSFUL
;
153 memcpy(buffer
, descriptor
.value
, descriptor
.size
);
154 return STATUS_SUCCESS
;
156 return STATUS_NOT_IMPLEMENTED
;
160 static NTSTATUS
hidraw_get_string(DEVICE_OBJECT
*device
, DWORD index
, WCHAR
*buffer
, DWORD length
)
162 struct udev_device
*usbdev
;
163 struct platform_private
*private = impl_from_DEVICE_OBJECT(device
);
166 usbdev
= udev_device_get_parent_with_subsystem_devtype(private->udev_device
, "usb", "usb_device");
171 case HID_STRING_ID_IPRODUCT
:
172 str
= get_sysattr_string(usbdev
, "product");
174 case HID_STRING_ID_IMANUFACTURER
:
175 str
= get_sysattr_string(usbdev
, "manufacturer");
177 case HID_STRING_ID_ISERIALNUMBER
:
178 str
= get_sysattr_string(usbdev
, "serial");
181 ERR("Unhandled string index %08x\n", index
);
182 return STATUS_NOT_IMPLEMENTED
;
187 #ifdef HAVE_LINUX_HIDRAW_H
190 case HID_STRING_ID_IPRODUCT
:
193 if (ioctl(private->device_fd
, HIDIOCGRAWNAME(MAX_PATH
), buf
) == -1)
194 WARN("ioctl(HIDIOCGRAWNAME) failed: %d %s\n", errno
, strerror(errno
));
196 str
= strdupAtoW(buf
);
199 case HID_STRING_ID_IMANUFACTURER
:
201 case HID_STRING_ID_ISERIALNUMBER
:
204 ERR("Unhandled string index %08x\n", index
);
205 return STATUS_NOT_IMPLEMENTED
;
208 return STATUS_NOT_IMPLEMENTED
;
214 if (!length
) return STATUS_BUFFER_TOO_SMALL
;
216 return STATUS_SUCCESS
;
219 if (length
<= strlenW(str
))
221 HeapFree(GetProcessHeap(), 0, str
);
222 return STATUS_BUFFER_TOO_SMALL
;
225 strcpyW(buffer
, str
);
226 HeapFree(GetProcessHeap(), 0, str
);
227 return STATUS_SUCCESS
;
230 static DWORD CALLBACK
device_report_thread(void *args
)
232 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
233 struct platform_private
*private = impl_from_DEVICE_OBJECT(device
);
234 struct pollfd plfds
[2];
236 plfds
[0].fd
= private->device_fd
;
237 plfds
[0].events
= POLLIN
;
238 plfds
[0].revents
= 0;
239 plfds
[1].fd
= private->control_pipe
[0];
240 plfds
[1].events
= POLLIN
;
241 plfds
[1].revents
= 0;
246 BYTE report_buffer
[1024];
248 if (poll(plfds
, 2, -1) <= 0) continue;
249 if (plfds
[1].revents
)
251 size
= read(plfds
[0].fd
, report_buffer
, sizeof(report_buffer
));
253 TRACE_(hid_report
)("Read failed. Likely an unplugged device\n");
255 TRACE_(hid_report
)("Failed to read report\n");
257 process_hid_report(device
, report_buffer
, size
);
262 static NTSTATUS
begin_report_processing(DEVICE_OBJECT
*device
)
264 struct platform_private
*private = impl_from_DEVICE_OBJECT(device
);
266 if (private->report_thread
)
267 return STATUS_SUCCESS
;
269 if (pipe(private->control_pipe
) != 0)
271 ERR("Control pipe creation failed\n");
272 return STATUS_UNSUCCESSFUL
;
275 private->report_thread
= CreateThread(NULL
, 0, device_report_thread
, device
, 0, NULL
);
276 if (!private->report_thread
)
278 ERR("Unable to create device report thread\n");
279 close(private->control_pipe
[0]);
280 close(private->control_pipe
[1]);
281 return STATUS_UNSUCCESSFUL
;
284 return STATUS_SUCCESS
;
287 static NTSTATUS
hidraw_set_output_report(DEVICE_OBJECT
*device
, UCHAR id
, BYTE
*report
, DWORD length
, ULONG_PTR
*written
)
289 struct platform_private
* ext
= impl_from_DEVICE_OBJECT(device
);
293 rc
= write(ext
->device_fd
, report
, length
);
296 BYTE report_buffer
[1024];
298 if (length
+ 1 > sizeof(report_buffer
))
300 ERR("Output report buffer too small\n");
301 return STATUS_UNSUCCESSFUL
;
304 report_buffer
[0] = 0;
305 memcpy(&report_buffer
[1], report
, length
);
306 rc
= write(ext
->device_fd
, report_buffer
, length
+ 1);
311 return STATUS_SUCCESS
;
316 return STATUS_UNSUCCESSFUL
;
320 static NTSTATUS
hidraw_get_feature_report(DEVICE_OBJECT
*device
, UCHAR id
, BYTE
*report
, DWORD length
, ULONG_PTR
*read
)
322 #if defined(HAVE_LINUX_HIDRAW_H) && defined(HIDIOCGFEATURE)
324 struct platform_private
* ext
= impl_from_DEVICE_OBJECT(device
);
326 length
= min(length
, 0x1fff);
327 rc
= ioctl(ext
->device_fd
, HIDIOCGFEATURE(length
), report
);
331 return STATUS_SUCCESS
;
336 return STATUS_UNSUCCESSFUL
;
340 return STATUS_NOT_IMPLEMENTED
;
344 static NTSTATUS
hidraw_set_feature_report(DEVICE_OBJECT
*device
, UCHAR id
, BYTE
*report
, DWORD length
, ULONG_PTR
*written
)
346 #if defined(HAVE_LINUX_HIDRAW_H) && defined(HIDIOCSFEATURE)
348 struct platform_private
* ext
= impl_from_DEVICE_OBJECT(device
);
349 BYTE
*feature_buffer
;
354 if (length
+ 1 > sizeof(buffer
))
356 ERR("Output feature buffer too small\n");
357 return STATUS_UNSUCCESSFUL
;
360 memcpy(&buffer
[1], report
, length
);
361 feature_buffer
= buffer
;
365 feature_buffer
= report
;
366 length
= min(length
, 0x1fff);
367 rc
= ioctl(ext
->device_fd
, HIDIOCSFEATURE(length
), feature_buffer
);
371 return STATUS_SUCCESS
;
376 return STATUS_UNSUCCESSFUL
;
380 return STATUS_NOT_IMPLEMENTED
;
384 static const platform_vtbl hidraw_vtbl
=
386 compare_platform_device
,
387 hidraw_get_reportdescriptor
,
389 begin_report_processing
,
390 hidraw_set_output_report
,
391 hidraw_get_feature_report
,
392 hidraw_set_feature_report
,
395 static void try_add_device(struct udev_device
*dev
)
397 DWORD vid
= 0, pid
= 0, version
= 0;
398 struct udev_device
*usbdev
;
399 DEVICE_OBJECT
*device
= NULL
;
400 const char *subsystem
;
402 WCHAR
*serial
= NULL
;
405 if (!(devnode
= udev_device_get_devnode(dev
)))
408 if ((fd
= open(devnode
, O_RDWR
)) == -1)
410 WARN("Unable to open udev device %s: %s\n", debugstr_a(devnode
), strerror(errno
));
414 usbdev
= udev_device_get_parent_with_subsystem_devtype(dev
, "usb", "usb_device");
417 vid
= get_sysattr_dword(usbdev
, "idVendor", 16);
418 pid
= get_sysattr_dword(usbdev
, "idProduct", 16);
419 version
= get_sysattr_dword(usbdev
, "version", 10);
420 serial
= get_sysattr_string(usbdev
, "serial");
423 TRACE("Found udev device %s (vid %04x, pid %04x, version %u, serial %s)\n",
424 debugstr_a(devnode
), vid
, pid
, version
, debugstr_w(serial
));
426 subsystem
= udev_device_get_subsystem(dev
);
427 if (strcmp(subsystem
, "hidraw") == 0)
429 device
= bus_create_hid_device(udev_driver_obj
, hidraw_busidW
, vid
, pid
, version
, 0, serial
, FALSE
,
430 &GUID_DEVCLASS_HIDRAW
, &hidraw_vtbl
, sizeof(struct platform_private
));
435 struct platform_private
*private = impl_from_DEVICE_OBJECT(device
);
436 private->udev_device
= udev_device_ref(dev
);
437 private->device_fd
= fd
;
438 IoInvalidateDeviceRelations(device
, BusRelations
);
442 WARN("Ignoring device %s with subsystem %s\n", debugstr_a(devnode
), subsystem
);
446 HeapFree(GetProcessHeap(), 0, serial
);
449 static void try_remove_device(struct udev_device
*dev
)
451 DEVICE_OBJECT
*device
= bus_find_hid_device(&hidraw_vtbl
, dev
);
452 struct platform_private
*private;
455 IoInvalidateDeviceRelations(device
, RemovalRelations
);
457 private = impl_from_DEVICE_OBJECT(device
);
459 if (private->report_thread
)
461 write(private->control_pipe
[1], "q", 1);
462 WaitForSingleObject(private->report_thread
, INFINITE
);
463 close(private->control_pipe
[0]);
464 close(private->control_pipe
[1]);
465 CloseHandle(private->report_thread
);
468 dev
= private->udev_device
;
469 close(private->device_fd
);
470 bus_remove_hid_device(device
);
471 udev_device_unref(dev
);
474 static void build_initial_deviceset(void)
476 struct udev_enumerate
*enumerate
;
477 struct udev_list_entry
*devices
, *dev_list_entry
;
479 enumerate
= udev_enumerate_new(udev_context
);
482 WARN("Unable to create udev enumeration object\n");
486 if (udev_enumerate_add_match_subsystem(enumerate
, "hidraw") < 0)
487 WARN("Failed to add subsystem 'hidraw' to enumeration\n");
489 if (udev_enumerate_scan_devices(enumerate
) < 0)
490 WARN("Enumeration scan failed\n");
492 devices
= udev_enumerate_get_list_entry(enumerate
);
493 udev_list_entry_foreach(dev_list_entry
, devices
)
495 struct udev_device
*dev
;
498 path
= udev_list_entry_get_name(dev_list_entry
);
499 if ((dev
= udev_device_new_from_syspath(udev_context
, path
)))
502 udev_device_unref(dev
);
506 udev_enumerate_unref(enumerate
);
509 static struct udev_monitor
*create_monitor(struct pollfd
*pfd
)
511 struct udev_monitor
*monitor
;
513 monitor
= udev_monitor_new_from_netlink(udev_context
, "udev");
516 WARN("Unable to get udev monitor object\n");
520 if (udev_monitor_filter_add_match_subsystem_devtype(monitor
, "hidraw", NULL
) < 0)
521 WARN("Failed to add subsystem 'hidraw' to monitor\n");
523 if (udev_monitor_enable_receiving(monitor
) < 0)
526 if ((pfd
->fd
= udev_monitor_get_fd(monitor
)) >= 0)
528 pfd
->events
= POLLIN
;
533 WARN("Failed to start monitoring\n");
534 udev_monitor_unref(monitor
);
538 static void process_monitor_event(struct udev_monitor
*monitor
)
540 struct udev_device
*dev
;
543 dev
= udev_monitor_receive_device(monitor
);
546 FIXME("Failed to get device that has changed\n");
550 action
= udev_device_get_action(dev
);
551 TRACE("Received action %s for udev device %s\n", debugstr_a(action
),
552 debugstr_a(udev_device_get_devnode(dev
)));
555 WARN("No action received\n");
556 else if (strcmp(action
, "add") == 0)
558 else if (strcmp(action
, "remove") == 0)
559 try_remove_device(dev
);
561 WARN("Unhandled action %s\n", debugstr_a(action
));
563 udev_device_unref(dev
);
566 static DWORD CALLBACK
deviceloop_thread(void *args
)
568 struct udev_monitor
*monitor
;
569 HANDLE init_done
= args
;
572 monitor
= create_monitor(&pfd
);
573 build_initial_deviceset();
578 if (poll(&pfd
, 1, -1) <= 0) continue;
579 process_monitor_event(monitor
);
582 TRACE("Monitor thread exiting\n");
584 udev_monitor_unref(monitor
);
588 NTSTATUS WINAPI
udev_driver_init(DRIVER_OBJECT
*driver
, UNICODE_STRING
*registry_path
)
593 TRACE("(%p, %s)\n", driver
, debugstr_w(registry_path
->Buffer
));
595 if (!(udev_context
= udev_new()))
597 ERR("Can't create udev object\n");
598 return STATUS_UNSUCCESSFUL
;
601 udev_driver_obj
= driver
;
602 driver
->MajorFunction
[IRP_MJ_PNP
] = common_pnp_dispatch
;
603 driver
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = hid_internal_dispatch
;
605 if (!(events
[0] = CreateEventW(NULL
, TRUE
, FALSE
, NULL
)))
607 if (!(events
[1] = CreateThread(NULL
, 0, deviceloop_thread
, events
[0], 0, NULL
)))
609 CloseHandle(events
[0]);
613 result
= WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
614 CloseHandle(events
[0]);
615 CloseHandle(events
[1]);
616 if (result
== WAIT_OBJECT_0
)
618 TRACE("Initialization successful\n");
619 return STATUS_SUCCESS
;
623 ERR("Failed to initialize udev device thread\n");
624 udev_unref(udev_context
);
626 udev_driver_obj
= NULL
;
627 return STATUS_UNSUCCESSFUL
;
632 NTSTATUS WINAPI
udev_driver_init(DRIVER_OBJECT
*driver
, UNICODE_STRING
*registry_path
)
634 WARN("Wine was compiled without UDEV support\n");
635 return STATUS_NOT_IMPLEMENTED
;
638 #endif /* HAVE_UDEV */