FreeRDP
Loading...
Searching...
No Matches
libusb_udevman.c
1
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <errno.h>
25
26#include <winpr/crt.h>
27#include <winpr/cmdline.h>
28#include <winpr/collections.h>
29
30#include <freerdp/addin.h>
31
32#include "urbdrc_types.h"
33#include "urbdrc_main.h"
34
35#include "libusb_udevice.h"
36
37#include <libusb.h>
38
39#if !defined(LIBUSB_HOTPLUG_NO_FLAGS)
40#define LIBUSB_HOTPLUG_NO_FLAGS 0
41#endif
42
43#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \
44 static _type udevman_get_##_arg(IUDEVMAN* idevman) \
45 { \
46 UDEVMAN* udevman = (UDEVMAN*)idevman; \
47 return udevman->_arg; \
48 } \
49 static void udevman_set_##_arg(IUDEVMAN* idevman, _type _t) \
50 { \
51 UDEVMAN* udevman = (UDEVMAN*)idevman; \
52 udevman->_arg = _t; \
53 }
54
55#define BASIC_STATE_FUNC_REGISTER(_arg, _man) \
56 _man->iface.get_##_arg = udevman_get_##_arg; \
57 (_man)->iface.set_##_arg = udevman_set_##_arg
58
59typedef struct
60{
61 UINT16 vid;
62 UINT16 pid;
63} VID_PID_PAIR;
64
65typedef struct
66{
67 IUDEVMAN iface;
68
69 IUDEVICE* idev; /* iterator device */
70 IUDEVICE* head; /* head device in linked list */
71 IUDEVICE* tail; /* tail device in linked list */
72
73 LPCSTR devices_vid_pid;
74 LPCSTR devices_addr;
75 wArrayList* hotplug_vid_pids;
76 BOOL hotplug_class_filter_set;
77 BYTE hotplug_class_filter[256 / 8];
78 UINT16 flags;
79 UINT32 device_num;
80 UINT32 next_device_id;
81 UINT32 channel_id;
82
83 HANDLE devman_loading;
84 libusb_context* context;
85 HANDLE thread;
86 BOOL running;
87} UDEVMAN;
88typedef UDEVMAN* PUDEVMAN;
89
90static BOOL poll_libusb_events(UDEVMAN* udevman);
91
92static void udevman_rewind(IUDEVMAN* idevman)
93{
94 UDEVMAN* udevman = (UDEVMAN*)idevman;
95 udevman->idev = udevman->head;
96}
97
98static BOOL udevman_has_next(IUDEVMAN* idevman)
99{
100 UDEVMAN* udevman = (UDEVMAN*)idevman;
101
102 return !(!udevman || !udevman->idev);
103}
104
105static IUDEVICE* udevman_get_next(IUDEVMAN* idevman)
106{
107 UDEVMAN* udevman = (UDEVMAN*)idevman;
108 IUDEVICE* pdev = nullptr;
109 pdev = udevman->idev;
110 udevman->idev = (IUDEVICE*)((UDEVICE*)udevman->idev)->next;
111 return pdev;
112}
113
114static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number)
115{
116 IUDEVICE* dev = nullptr;
117
118 if (!idevman)
119 return nullptr;
120
121 idevman->loading_lock(idevman);
122 idevman->rewind(idevman);
123
124 while (idevman->has_next(idevman))
125 {
126 IUDEVICE* pdev = idevman->get_next(idevman);
127
128 if ((pdev->get_bus_number(pdev) == bus_number) &&
129 (pdev->get_dev_number(pdev) == dev_number))
130 {
131 dev = pdev;
132 break;
133 }
134 }
135
136 idevman->loading_unlock(idevman);
137 return dev;
138}
139
140static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number,
141 UINT16 idVendor, UINT16 idProduct, UINT32 flag)
142{
143 UDEVMAN* udevman = (UDEVMAN*)idevman;
144 IUDEVICE* pdev = nullptr;
145 IUDEVICE** devArray = nullptr;
146 URBDRC_PLUGIN* urbdrc = nullptr;
147 size_t num = 0;
148 size_t addnum = 0;
149
150 if (!idevman || !idevman->plugin)
151 return 0;
152
153 urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
154 pdev = udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
155
156 if (pdev != nullptr)
157 return 0;
158
159 if (flag & UDEVMAN_FLAG_ADD_BY_ADDR)
160 {
161 UINT32 id = 0;
162 IUDEVICE* tdev = udev_new_by_addr(urbdrc, udevman->context, bus_number, dev_number);
163
164 if (tdev == nullptr)
165 return 0;
166
167 id = idevman->get_next_device_id(idevman);
168 tdev->set_UsbDevice(tdev, id);
169 idevman->loading_lock(idevman);
170
171 if (udevman->head == nullptr)
172 {
173 /* linked list is empty */
174 udevman->head = tdev;
175 udevman->tail = tdev;
176 }
177 else
178 {
179 /* append device to the end of the linked list */
180 udevman->tail->set_p_next(udevman->tail, tdev);
181 tdev->set_p_prev(tdev, udevman->tail);
182 udevman->tail = tdev;
183 }
184
185 udevman->device_num += 1;
186 idevman->loading_unlock(idevman);
187 }
188 else if (flag & UDEVMAN_FLAG_ADD_BY_VID_PID)
189 {
190 addnum = 0;
191 /* register all device that match pid vid */
192 num = udev_new_by_id(urbdrc, udevman->context, idVendor, idProduct, &devArray);
193
194 if (num == 0)
195 {
196 WLog_Print(urbdrc->log, WLOG_WARN,
197 "Could not find or redirect any usb devices by id %04x:%04x", idVendor,
198 idProduct);
199 }
200
201 for (size_t i = 0; i < num; i++)
202 {
203 UINT32 id = 0;
204 IUDEVICE* tdev = devArray[i];
205
206 if (udevman_get_udevice_by_addr(idevman, tdev->get_bus_number(tdev),
207 tdev->get_dev_number(tdev)) != nullptr)
208 {
209 tdev->free(tdev);
210 devArray[i] = nullptr;
211 continue;
212 }
213
214 id = idevman->get_next_device_id(idevman);
215 tdev->set_UsbDevice(tdev, id);
216 idevman->loading_lock(idevman);
217
218 if (udevman->head == nullptr)
219 {
220 /* linked list is empty */
221 udevman->head = tdev;
222 udevman->tail = tdev;
223 }
224 else
225 {
226 /* append device to the end of the linked list */
227 udevman->tail->set_p_next(udevman->tail, tdev);
228 tdev->set_p_prev(tdev, udevman->tail);
229 udevman->tail = tdev;
230 }
231
232 udevman->device_num += 1;
233 idevman->loading_unlock(idevman);
234 addnum++;
235 }
236
237 free((void*)devArray);
238 return addnum;
239 }
240 else
241 {
242 WLog_Print(urbdrc->log, WLOG_ERROR, "udevman_register_udevice: Invalid flag=%08" PRIx32,
243 flag);
244 return 0;
245 }
246
247 return 1;
248}
249
250static BOOL udevman_unregister_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number)
251{
252 UDEVMAN* udevman = (UDEVMAN*)idevman;
253 UDEVICE* pdev = nullptr;
254 UDEVICE* dev = (UDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
255
256 if (!dev || !idevman)
257 return FALSE;
258
259 idevman->loading_lock(idevman);
260 idevman->rewind(idevman);
261
262 while (idevman->has_next(idevman))
263 {
264 pdev = (UDEVICE*)idevman->get_next(idevman);
265
266 if (pdev == dev) /* device exists */
267 {
268 /* set previous device to point to next device */
269 if (dev->prev != nullptr)
270 {
271 /* unregistered device is not the head */
272 pdev = dev->prev;
273 pdev->next = dev->next;
274 }
275 else
276 {
277 /* unregistered device is the head, update head */
278 udevman->head = (IUDEVICE*)dev->next;
279 }
280
281 /* set next device to point to previous device */
282
283 if (dev->next != nullptr)
284 {
285 /* unregistered device is not the tail */
286 pdev = (UDEVICE*)dev->next;
287 pdev->prev = dev->prev;
288 }
289 else
290 {
291 /* unregistered device is the tail, update tail */
292 udevman->tail = (IUDEVICE*)dev->prev;
293 }
294
295 udevman->device_num--;
296 break;
297 }
298 }
299
300 idevman->loading_unlock(idevman);
301
302 if (dev)
303 {
304 dev->iface.free(&dev->iface);
305 return TRUE; /* unregistration successful */
306 }
307
308 /* if we reach this point, the device wasn't found */
309 return FALSE;
310}
311
312static BOOL udevman_unregister_all_udevices(IUDEVMAN* idevman)
313{
314 UDEVMAN* udevman = (UDEVMAN*)idevman;
315
316 if (!idevman)
317 return FALSE;
318
319 if (!udevman->head)
320 return TRUE;
321
322 idevman->loading_lock(idevman);
323 idevman->rewind(idevman);
324
325 while (idevman->has_next(idevman))
326 {
327 UDEVICE* dev = (UDEVICE*)idevman->get_next(idevman);
328
329 if (!dev)
330 continue;
331
332 /* set previous device to point to next device */
333 if (dev->prev != nullptr)
334 {
335 /* unregistered device is not the head */
336 UDEVICE* pdev = dev->prev;
337 pdev->next = dev->next;
338 }
339 else
340 {
341 /* unregistered device is the head, update head */
342 udevman->head = (IUDEVICE*)dev->next;
343 }
344
345 /* set next device to point to previous device */
346
347 if (dev->next != nullptr)
348 {
349 /* unregistered device is not the tail */
350 UDEVICE* pdev = (UDEVICE*)dev->next;
351 pdev->prev = dev->prev;
352 }
353 else
354 {
355 /* unregistered device is the tail, update tail */
356 udevman->tail = (IUDEVICE*)dev->prev;
357 }
358
359 dev->iface.free(&dev->iface);
360 udevman->device_num--;
361 }
362
363 idevman->loading_unlock(idevman);
364
365 return TRUE;
366}
367
368static int udevman_is_auto_add(IUDEVMAN* idevman)
369{
370 UDEVMAN* udevman = (UDEVMAN*)idevman;
371 return (udevman->flags & UDEVMAN_FLAG_ADD_BY_AUTO) ? 1 : 0;
372}
373
374static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbDevice)
375{
376 UDEVICE* pdev = nullptr;
377 URBDRC_PLUGIN* urbdrc = nullptr;
378
379 if (!idevman || !idevman->plugin)
380 return nullptr;
381
382 /* Mask highest 2 bits, must be ignored */
383 UsbDevice = UsbDevice & INTERFACE_ID_MASK;
384 urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
385 idevman->loading_lock(idevman);
386 idevman->rewind(idevman);
387
388 while (idevman->has_next(idevman))
389 {
390 pdev = (UDEVICE*)idevman->get_next(idevman);
391
392 if (pdev->UsbDevice == UsbDevice)
393 {
394 idevman->loading_unlock(idevman);
395 return (IUDEVICE*)pdev;
396 }
397 }
398
399 idevman->loading_unlock(idevman);
400 WLog_Print(urbdrc->log, WLOG_WARN, "Failed to find a USB device mapped to deviceId=%08" PRIx32,
401 UsbDevice);
402 return nullptr;
403}
404
405static IUDEVICE* udevman_get_udevice_by_ChannelID(IUDEVMAN* idevman, UINT32 channelID)
406{
407 UDEVICE* pdev = nullptr;
408 URBDRC_PLUGIN* urbdrc = nullptr;
409
410 if (!idevman || !idevman->plugin)
411 return nullptr;
412
413 /* Mask highest 2 bits, must be ignored */
414 urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
415 idevman->loading_lock(idevman);
416 idevman->rewind(idevman);
417
418 while (idevman->has_next(idevman))
419 {
420 pdev = (UDEVICE*)idevman->get_next(idevman);
421
422 if (pdev->channelID == channelID)
423 {
424 idevman->loading_unlock(idevman);
425 return (IUDEVICE*)pdev;
426 }
427 }
428
429 idevman->loading_unlock(idevman);
430 WLog_Print(urbdrc->log, WLOG_WARN, "Failed to find a USB device mapped to channelID=%08" PRIx32,
431 channelID);
432 return nullptr;
433}
434
435static void udevman_loading_lock(IUDEVMAN* idevman)
436{
437 UDEVMAN* udevman = (UDEVMAN*)idevman;
438 (void)WaitForSingleObject(udevman->devman_loading, INFINITE);
439}
440
441static void udevman_loading_unlock(IUDEVMAN* idevman)
442{
443 UDEVMAN* udevman = (UDEVMAN*)idevman;
444 (void)ReleaseMutex(udevman->devman_loading);
445}
446
447BASIC_STATE_FUNC_DEFINED(device_num, UINT32)
448
449static UINT32 udevman_get_next_device_id(IUDEVMAN* idevman)
450{
451 UDEVMAN* udevman = (UDEVMAN*)idevman;
452 return udevman->next_device_id++;
453}
454
455static void udevman_set_next_device_id(IUDEVMAN* idevman, UINT32 _t)
456{
457 UDEVMAN* udevman = (UDEVMAN*)idevman;
458 udevman->next_device_id = _t;
459}
460
461static void udevman_free(UDEVMAN* udevman)
462{
463 if (!udevman)
464 return;
465
466 /* unregister all devices before tearing down the libusb handling.
467 */
468 udevman_unregister_all_udevices(&udevman->iface);
469
470 udevman->running = FALSE;
471 if (udevman->thread)
472 {
473 (void)WaitForSingleObject(udevman->thread, INFINITE);
474 (void)CloseHandle(udevman->thread);
475 }
476
477 if (udevman->devman_loading)
478 (void)CloseHandle(udevman->devman_loading);
479
480 libusb_exit(udevman->context);
481
482 ArrayList_Free(udevman->hotplug_vid_pids);
483 free(udevman);
484}
485
486static void idevman_free(IUDEVMAN* idevman)
487{
488 UDEVMAN* udevman = (UDEVMAN*)idevman;
489 udevman_free(udevman);
490}
491
492static BOOL filter_by_class(const UDEVMAN* udevman, uint8_t bDeviceClass, uint8_t bDeviceSubClass)
493{
494 WINPR_ASSERT(udevman);
495
496 /* user supplied list of classes (/usb:auto,filter:...) replaces the default */
497 if (udevman->hotplug_class_filter_set)
498 return (udevman->hotplug_class_filter[bDeviceClass / 8] & (1u << (bDeviceClass % 8))) != 0;
499
500 switch (bDeviceClass)
501 {
502 case LIBUSB_CLASS_AUDIO:
503 case LIBUSB_CLASS_HID:
504 case LIBUSB_CLASS_MASS_STORAGE:
505 case LIBUSB_CLASS_HUB:
506 case LIBUSB_CLASS_SMART_CARD:
507 return TRUE;
508 default:
509 break;
510 }
511
512 switch (bDeviceSubClass)
513 {
514 default:
515 break;
516 }
517
518 return FALSE;
519}
520
521static BOOL append(char* dst, size_t length, const char* src)
522{
523 return winpr_str_append(src, dst, length, nullptr);
524}
525
526static BOOL device_is_filtered(const UDEVMAN* udevman, struct libusb_device* dev,
527 const struct libusb_device_descriptor* desc,
528 libusb_hotplug_event event)
529{
530 char buffer[8192] = WINPR_C_ARRAY_INIT;
531 char* what = nullptr;
532 BOOL filtered = FALSE;
533 append(buffer, sizeof(buffer), usb_interface_class_to_string(desc->bDeviceClass));
534 if (filter_by_class(udevman, desc->bDeviceClass, desc->bDeviceSubClass))
535 filtered = TRUE;
536
537 switch (desc->bDeviceClass)
538 {
539 case LIBUSB_CLASS_PER_INTERFACE:
540 {
541 struct libusb_config_descriptor* config = nullptr;
542 int rc = libusb_get_active_config_descriptor(dev, &config);
543 if (rc == LIBUSB_SUCCESS)
544 {
545 for (uint8_t x = 0; x < config->bNumInterfaces; x++)
546 {
547 const struct libusb_interface* ifc = &config->interface[x];
548 for (int y = 0; y < ifc->num_altsetting; y++)
549 {
550 const struct libusb_interface_descriptor* const alt = &ifc->altsetting[y];
551 if (filter_by_class(udevman, alt->bInterfaceClass, alt->bInterfaceSubClass))
552 filtered = TRUE;
553
554 append(buffer, sizeof(buffer), "|");
555 append(buffer, sizeof(buffer),
556 usb_interface_class_to_string(alt->bInterfaceClass));
557 }
558 }
559 }
560 libusb_free_config_descriptor(config);
561 }
562 break;
563 default:
564 break;
565 }
566
567 if (filtered)
568 what = "Filtered";
569 else
570 {
571 switch (event)
572 {
573 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
574 what = "Hotplug remove";
575 break;
576 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
577 what = "Hotplug add";
578 break;
579 default:
580 what = "Hotplug unknown";
581 break;
582 }
583 }
584
585 WLog_DBG(TAG, "%s device VID=0x%04X,PID=0x%04X class %s", what, desc->idVendor, desc->idProduct,
586 buffer);
587 return filtered;
588}
589
590static int LIBUSB_CALL hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev,
591 libusb_hotplug_event event, void* user_data)
592{
593 VID_PID_PAIR pair;
594 struct libusb_device_descriptor desc;
595 UDEVMAN* udevman = (UDEVMAN*)user_data;
596 const uint8_t bus = libusb_get_bus_number(dev);
597 const uint8_t addr = libusb_get_device_address(dev);
598 int rc = libusb_get_device_descriptor(dev, &desc);
599
600 WINPR_UNUSED(ctx);
601
602 if (rc != LIBUSB_SUCCESS)
603 return rc;
604
605 switch (event)
606 {
607 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
608 pair.vid = desc.idVendor;
609 pair.pid = desc.idProduct;
610 if ((ArrayList_Contains(udevman->hotplug_vid_pids, &pair)) ||
611 (udevman->iface.isAutoAdd(&udevman->iface) &&
612 !device_is_filtered(udevman, dev, &desc, event)))
613 {
614 add_device(&udevman->iface, DEVICE_ADD_FLAG_ALL, bus, addr, desc.idVendor,
615 desc.idProduct);
616 }
617 break;
618
619 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
620 del_device(&udevman->iface, DEVICE_ADD_FLAG_ALL, bus, addr, desc.idVendor,
621 desc.idProduct);
622 break;
623
624 default:
625 break;
626 }
627
628 return 0;
629}
630
631static BOOL udevman_initialize(IUDEVMAN* idevman, UINT32 channelId)
632{
633 UDEVMAN* udevman = (UDEVMAN*)idevman;
634
635 if (!udevman)
636 return FALSE;
637
638 idevman->loading_lock(idevman);
639 idevman->status &= (uint32_t)~URBDRC_DEVICE_CHANNEL_CLOSED;
640 idevman->controlChannelId = channelId;
641 idevman->loading_unlock(idevman);
642 return TRUE;
643}
644
645static BOOL udevman_vid_pid_pair_equals(const void* objA, const void* objB)
646{
647 const VID_PID_PAIR* a = objA;
648 const VID_PID_PAIR* b = objB;
649
650 return (a->vid == b->vid) && (a->pid == b->pid);
651}
652
653static BOOL udevman_parse_device_id_addr(const char** str, UINT16* id1, UINT16* id2, UINT16 max,
654 char split_sign, char delimiter)
655{
656 char* mid = nullptr;
657 char* end = nullptr;
658 unsigned long rc = 0;
659
660 rc = strtoul(*str, &mid, 16);
661
662 if ((mid == *str) || (*mid != split_sign) || (rc > max))
663 return FALSE;
664
665 *id1 = (UINT16)rc;
666 rc = strtoul(++mid, &end, 16);
667
668 if ((end == mid) || (rc > max))
669 return FALSE;
670
671 *id2 = (UINT16)rc;
672
673 *str += end - *str;
674 if (*end == '\0')
675 return TRUE;
676 if (*end == delimiter)
677 {
678 (*str)++;
679 return TRUE;
680 }
681
682 return FALSE;
683}
684
685static UINT urbdrc_udevman_register_devices(UDEVMAN* udevman, const char* devices, BOOL add_by_addr)
686{
687 const char* pos = devices;
688
689 while (*pos != '\0')
690 {
691 UINT16 id1 = 0;
692 UINT16 id2 = 0;
693 if (!udevman_parse_device_id_addr(&pos, &id1, &id2, (add_by_addr) ? UINT8_MAX : UINT16_MAX,
694 ':', '#'))
695 {
696 WLog_ERR(TAG, "Invalid device argument: \"%s\"", devices);
697 return CHANNEL_RC_INITIALIZATION_ERROR;
698 }
699
700 if (add_by_addr)
701 {
702 if (!add_device(&udevman->iface, DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV, (UINT8)id1,
703 (UINT8)id2, 0, 0))
704 return CHANNEL_RC_INITIALIZATION_ERROR;
705 }
706 else
707 {
708 VID_PID_PAIR* idpair = calloc(1, sizeof(VID_PID_PAIR));
709 if (!idpair)
710 return CHANNEL_RC_NO_MEMORY;
711 idpair->vid = id1;
712 idpair->pid = id2;
713 if (!ArrayList_Append(udevman->hotplug_vid_pids, idpair))
714 {
715 free(idpair);
716 return CHANNEL_RC_NO_MEMORY;
717 }
718
719 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append owns idpair
720 (void)add_device(&udevman->iface, DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT, 0,
721 0, id1, id2);
722 }
723 }
724
725 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append owns idpair
726 return CHANNEL_RC_OK;
727}
728
729static BOOL urbdrc_udevman_parse_class_filter(UDEVMAN* udevman, const char* list)
730{
731 WINPR_ASSERT(udevman);
732 WINPR_ASSERT(list);
733
734 memset(udevman->hotplug_class_filter, 0, sizeof(udevman->hotplug_class_filter));
735 udevman->hotplug_class_filter_set = TRUE;
736
737 /* filter:none = every device class plugged in later is redirected */
738 if (_stricmp(list, "none") == 0)
739 return TRUE;
740
741 const char* pos = list;
742 while (*pos != '\0')
743 {
744 char* end = nullptr;
745 errno = 0;
746 const unsigned long cls = strtoul(pos, &end, 16);
747 if ((errno != 0) || (end == pos) || (cls > UINT8_MAX) || ((*end != '\0') && (*end != '#')))
748 {
749 WLog_ERR(TAG, "Invalid USB class filter: \"%s\"", list);
750 return FALSE;
751 }
752 udevman->hotplug_class_filter[cls / 8] |= (BYTE)(1u << (cls % 8));
753 pos = (*end == '#') ? end + 1 : end;
754 }
755
756 return TRUE;
757}
758
759static UINT urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, const ADDIN_ARGV* args)
760{
761 LPCSTR devices = nullptr;
762
763 for (int x = 0; x < args->argc; x++)
764 {
765 const char* arg = args->argv[x];
766 if (strcmp(arg, "dbg") == 0)
767 {
768 if (!WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE))
769 return ERROR_INTERNAL_ERROR;
770 }
771 else if (_strnicmp(arg, "device:", 7) == 0)
772 {
773 /* Redirect all local devices */
774 const char* val = &arg[7];
775 const size_t len = strlen(val);
776 if (strcmp(val, "*") == 0)
777 {
778 udevman->flags |= UDEVMAN_FLAG_ADD_BY_AUTO;
779 }
780 else if (_strnicmp(arg, "USBInstanceID:", 14) == 0)
781 {
782 // TODO: Usb instance ID
783 }
784 else if ((val[0] == '{') && (val[len - 1] == '}'))
785 {
786 // TODO: Usb device class
787 }
788 }
789 else if (_strnicmp(arg, "dev:", 4) == 0)
790 {
791 devices = &arg[4];
792 }
793 else if (_strnicmp(arg, "id", 2) == 0)
794 {
795 const char* p = strchr(arg, ':');
796 if (p)
797 udevman->devices_vid_pid = p + 1;
798 else
799 udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
800 }
801 else if (_strnicmp(arg, "addr", 4) == 0)
802 {
803 const char* p = strchr(arg, ':');
804 if (p)
805 udevman->devices_addr = p + 1;
806 else
807 udevman->flags = UDEVMAN_FLAG_ADD_BY_ADDR;
808 }
809 else if (strcmp(arg, "auto") == 0)
810 {
811 udevman->flags |= UDEVMAN_FLAG_ADD_BY_AUTO;
812 }
813 else if (_strnicmp(arg, "filter:", 7) == 0)
814 {
815 /* USB base classes (hex, '#' separated) that auto hotplug keeps local */
816 if (!urbdrc_udevman_parse_class_filter(udevman, &arg[7]))
817 return ERROR_INVALID_PARAMETER;
818 }
819 else
820 {
821 const size_t len = strlen(arg);
822 if ((arg[0] == '{') && (arg[len - 1] == '}'))
823 {
824 // TODO: Check for {Device Setup Class GUID}:
825 }
826 }
827 }
828 if (devices)
829 {
830 if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID)
831 udevman->devices_vid_pid = devices;
832 else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR)
833 udevman->devices_addr = devices;
834 }
835
836 return CHANNEL_RC_OK;
837}
838
839static UINT udevman_listener_created_callback(IUDEVMAN* iudevman)
840{
841 UDEVMAN* udevman = (UDEVMAN*)iudevman;
842 WINPR_ASSERT(udevman);
843
844 if (udevman->devices_vid_pid)
845 return urbdrc_udevman_register_devices(udevman, udevman->devices_vid_pid, FALSE);
846
847 if (udevman->devices_addr)
848 return urbdrc_udevman_register_devices(udevman, udevman->devices_addr, TRUE);
849
850 return CHANNEL_RC_OK;
851}
852
853static void udevman_load_interface(UDEVMAN* udevman)
854{
855 /* standard */
856 udevman->iface.free = idevman_free;
857 /* manage devices */
858 udevman->iface.rewind = udevman_rewind;
859 udevman->iface.get_next = udevman_get_next;
860 udevman->iface.has_next = udevman_has_next;
861 udevman->iface.register_udevice = udevman_register_udevice;
862 udevman->iface.unregister_udevice = udevman_unregister_udevice;
863 udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice;
864 udevman->iface.get_udevice_by_ChannelID = udevman_get_udevice_by_ChannelID;
865 /* Extension */
866 udevman->iface.isAutoAdd = udevman_is_auto_add;
867 /* Basic state */
868 BASIC_STATE_FUNC_REGISTER(device_num, udevman);
869 BASIC_STATE_FUNC_REGISTER(next_device_id, udevman);
870
871 /* control semaphore or mutex lock */
872 udevman->iface.loading_lock = udevman_loading_lock;
873 udevman->iface.loading_unlock = udevman_loading_unlock;
874 udevman->iface.initialize = udevman_initialize;
875 udevman->iface.listener_created_callback = udevman_listener_created_callback;
876}
877
878static BOOL poll_libusb_events(UDEVMAN* udevman)
879{
880 int rc = LIBUSB_SUCCESS;
881 struct timeval tv = { 0, 500 };
882 if (libusb_try_lock_events(udevman->context) == 0)
883 {
884 if (libusb_event_handling_ok(udevman->context))
885 {
886 rc = libusb_handle_events_locked(udevman->context, &tv);
887 if (rc != LIBUSB_SUCCESS)
888 WLog_WARN(TAG, "libusb_handle_events_locked %d", rc);
889 }
890 libusb_unlock_events(udevman->context);
891 }
892 else
893 {
894 libusb_lock_event_waiters(udevman->context);
895 if (libusb_event_handler_active(udevman->context))
896 {
897 rc = libusb_wait_for_event(udevman->context, &tv);
898 if (rc < LIBUSB_SUCCESS)
899 WLog_WARN(TAG, "libusb_wait_for_event %d", rc);
900 }
901 libusb_unlock_event_waiters(udevman->context);
902 }
903
904 return rc > 0;
905}
906
907static DWORD WINAPI poll_thread(LPVOID lpThreadParameter)
908{
909 libusb_hotplug_callback_handle handle = 0;
910 UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter;
911 BOOL hasHotplug = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG);
912
913 if (hasHotplug)
914 {
915 int rc = libusb_hotplug_register_callback(
916 udevman->context,
917 LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
918 LIBUSB_HOTPLUG_NO_FLAGS, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
919 LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, udevman, &handle);
920
921 if (rc != LIBUSB_SUCCESS)
922 {
923 WLog_WARN(TAG,
924 "Failed to register hotplug handler (%s). USB devices plugged in later "
925 "will not be detected.",
926 libusb_strerror(rc));
927 }
928 }
929 else
930 WLog_WARN(TAG, "Platform does not support libusb hotplug. USB devices plugged in later "
931 "will not be detected.");
932
933 while (udevman->running)
934 {
935 poll_libusb_events(udevman);
936 }
937
938 if (hasHotplug)
939 libusb_hotplug_deregister_callback(udevman->context, handle);
940
941 /* Process remaining usb events */
942 while (poll_libusb_events(udevman))
943 ;
944
945 ExitThread(0);
946 return 0;
947}
948
949FREERDP_ENTRY_POINT(UINT VCAPITYPE libusb_freerdp_urbdrc_client_subsystem_entry(
951{
952 wObject* obj = nullptr;
953 UINT status = 0;
954 const ADDIN_ARGV* args = pEntryPoints->args;
955 UDEVMAN* udevman = (PUDEVMAN)calloc(1, sizeof(UDEVMAN));
956
957 if (!udevman)
958 goto fail;
959
960 udevman->hotplug_vid_pids = ArrayList_New(TRUE);
961 if (!udevman->hotplug_vid_pids)
962 goto fail;
963 obj = ArrayList_Object(udevman->hotplug_vid_pids);
964 obj->fnObjectFree = free;
965 obj->fnObjectEquals = udevman_vid_pid_pair_equals;
966
967 udevman->next_device_id = BASE_USBDEVICE_NUM;
968 udevman->iface.plugin = pEntryPoints->plugin;
969
970 {
971 const int res = libusb_init(&udevman->context);
972 if (res != LIBUSB_SUCCESS)
973 goto fail;
974 }
975
976#ifdef _WIN32
977#if LIBUSB_API_VERSION >= 0x01000106
978 /* Prefer usbDK backend on windows. Not supported on other platforms. */
979 const int rc = libusb_set_option(udevman->context, LIBUSB_OPTION_USE_USBDK);
980 switch (rc)
981 {
982 case LIBUSB_SUCCESS:
983 break;
984 case LIBUSB_ERROR_NOT_FOUND:
985 case LIBUSB_ERROR_NOT_SUPPORTED:
986 WLog_WARN(TAG, "LIBUSB_OPTION_USE_USBDK %s [%d]", libusb_strerror(rc), rc);
987 break;
988 default:
989 WLog_ERR(TAG, "LIBUSB_OPTION_USE_USBDK %s [%d]", libusb_strerror(rc), rc);
990 goto fail;
991 }
992#endif
993#endif
994
995 udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
996 udevman->devman_loading = CreateMutexA(nullptr, FALSE, "devman_loading");
997
998 if (!udevman->devman_loading)
999 goto fail;
1000
1001 /* load usb device service management */
1002 udevman_load_interface(udevman);
1003 status = urbdrc_udevman_parse_addin_args(udevman, args);
1004
1005 if (status != CHANNEL_RC_OK)
1006 goto fail;
1007
1008 udevman->running = TRUE;
1009 udevman->thread = CreateThread(nullptr, 0, poll_thread, udevman, 0, nullptr);
1010
1011 if (!udevman->thread)
1012 goto fail;
1013
1014 if (!pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*)udevman))
1015 goto fail;
1016
1017 WLog_DBG(TAG, "UDEVMAN device registered.");
1018 return 0;
1019fail:
1020 udevman_free(udevman);
1021 return ERROR_INTERNAL_ERROR;
1022}
Definition urbdrc_main.h:75
This struct contains function pointer to initialize/free objects.
Definition collections.h:52
OBJECT_FREE_FN fnObjectFree
Definition collections.h:59
WINPR_ATTR_NODISCARD OBJECT_EQUALS_FN fnObjectEquals
Definition collections.h:61