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