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(IUDEVMAN* idevman)
460{
461 UDEVMAN* udevman = (UDEVMAN*)idevman;
462
463 if (!udevman)
464 return;
465
466 udevman->running = FALSE;
467 if (udevman->thread)
468 {
469 (void)WaitForSingleObject(udevman->thread, INFINITE);
470 (void)CloseHandle(udevman->thread);
471 }
472
473 udevman_unregister_all_udevices(idevman);
474
475 if (udevman->devman_loading)
476 (void)CloseHandle(udevman->devman_loading);
477
478 libusb_exit(udevman->context);
479
480 ArrayList_Free(udevman->hotplug_vid_pids);
481 free(udevman);
482}
483
484static BOOL filter_by_class(uint8_t bDeviceClass, uint8_t bDeviceSubClass)
485{
486 switch (bDeviceClass)
487 {
488 case LIBUSB_CLASS_AUDIO:
489 case LIBUSB_CLASS_HID:
490 case LIBUSB_CLASS_MASS_STORAGE:
491 case LIBUSB_CLASS_HUB:
492 case LIBUSB_CLASS_SMART_CARD:
493 return TRUE;
494 default:
495 break;
496 }
497
498 switch (bDeviceSubClass)
499 {
500 default:
501 break;
502 }
503
504 return FALSE;
505}
506
507static BOOL append(char* dst, size_t length, const char* src)
508{
509 return winpr_str_append(src, dst, length, nullptr);
510}
511
512static BOOL device_is_filtered(struct libusb_device* dev,
513 const struct libusb_device_descriptor* desc,
514 libusb_hotplug_event event)
515{
516 char buffer[8192] = WINPR_C_ARRAY_INIT;
517 char* what = nullptr;
518 BOOL filtered = FALSE;
519 append(buffer, sizeof(buffer), usb_interface_class_to_string(desc->bDeviceClass));
520 if (filter_by_class(desc->bDeviceClass, desc->bDeviceSubClass))
521 filtered = TRUE;
522
523 switch (desc->bDeviceClass)
524 {
525 case LIBUSB_CLASS_PER_INTERFACE:
526 {
527 struct libusb_config_descriptor* config = nullptr;
528 int rc = libusb_get_active_config_descriptor(dev, &config);
529 if (rc == LIBUSB_SUCCESS)
530 {
531 for (uint8_t x = 0; x < config->bNumInterfaces; x++)
532 {
533 const struct libusb_interface* ifc = &config->interface[x];
534 for (int y = 0; y < ifc->num_altsetting; y++)
535 {
536 const struct libusb_interface_descriptor* const alt = &ifc->altsetting[y];
537 if (filter_by_class(alt->bInterfaceClass, alt->bInterfaceSubClass))
538 filtered = TRUE;
539
540 append(buffer, sizeof(buffer), "|");
541 append(buffer, sizeof(buffer),
542 usb_interface_class_to_string(alt->bInterfaceClass));
543 }
544 }
545 }
546 libusb_free_config_descriptor(config);
547 }
548 break;
549 default:
550 break;
551 }
552
553 if (filtered)
554 what = "Filtered";
555 else
556 {
557 switch (event)
558 {
559 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
560 what = "Hotplug remove";
561 break;
562 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
563 what = "Hotplug add";
564 break;
565 default:
566 what = "Hotplug unknown";
567 break;
568 }
569 }
570
571 WLog_DBG(TAG, "%s device VID=0x%04X,PID=0x%04X class %s", what, desc->idVendor, desc->idProduct,
572 buffer);
573 return filtered;
574}
575
576static int LIBUSB_CALL hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev,
577 libusb_hotplug_event event, void* user_data)
578{
579 VID_PID_PAIR pair;
580 struct libusb_device_descriptor desc;
581 UDEVMAN* udevman = (UDEVMAN*)user_data;
582 const uint8_t bus = libusb_get_bus_number(dev);
583 const uint8_t addr = libusb_get_device_address(dev);
584 int rc = libusb_get_device_descriptor(dev, &desc);
585
586 WINPR_UNUSED(ctx);
587
588 if (rc != LIBUSB_SUCCESS)
589 return rc;
590
591 switch (event)
592 {
593 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
594 pair.vid = desc.idVendor;
595 pair.pid = desc.idProduct;
596 if ((ArrayList_Contains(udevman->hotplug_vid_pids, &pair)) ||
597 (udevman->iface.isAutoAdd(&udevman->iface) &&
598 !device_is_filtered(dev, &desc, event)))
599 {
600 add_device(&udevman->iface, DEVICE_ADD_FLAG_ALL, bus, addr, desc.idVendor,
601 desc.idProduct);
602 }
603 break;
604
605 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
606 del_device(&udevman->iface, DEVICE_ADD_FLAG_ALL, bus, addr, desc.idVendor,
607 desc.idProduct);
608 break;
609
610 default:
611 break;
612 }
613
614 return 0;
615}
616
617static BOOL udevman_initialize(IUDEVMAN* idevman, UINT32 channelId)
618{
619 UDEVMAN* udevman = (UDEVMAN*)idevman;
620
621 if (!udevman)
622 return FALSE;
623
624 idevman->status &= (uint32_t)~URBDRC_DEVICE_CHANNEL_CLOSED;
625 idevman->controlChannelId = channelId;
626 return TRUE;
627}
628
629static BOOL udevman_vid_pid_pair_equals(const void* objA, const void* objB)
630{
631 const VID_PID_PAIR* a = objA;
632 const VID_PID_PAIR* b = objB;
633
634 return (a->vid == b->vid) && (a->pid == b->pid);
635}
636
637static BOOL udevman_parse_device_id_addr(const char** str, UINT16* id1, UINT16* id2, UINT16 max,
638 char split_sign, char delimiter)
639{
640 char* mid = nullptr;
641 char* end = nullptr;
642 unsigned long rc = 0;
643
644 rc = strtoul(*str, &mid, 16);
645
646 if ((mid == *str) || (*mid != split_sign) || (rc > max))
647 return FALSE;
648
649 *id1 = (UINT16)rc;
650 rc = strtoul(++mid, &end, 16);
651
652 if ((end == mid) || (rc > max))
653 return FALSE;
654
655 *id2 = (UINT16)rc;
656
657 *str += end - *str;
658 if (*end == '\0')
659 return TRUE;
660 if (*end == delimiter)
661 {
662 (*str)++;
663 return TRUE;
664 }
665
666 return FALSE;
667}
668
669static UINT urbdrc_udevman_register_devices(UDEVMAN* udevman, const char* devices, BOOL add_by_addr)
670{
671 const char* pos = devices;
672
673 while (*pos != '\0')
674 {
675 UINT16 id1 = 0;
676 UINT16 id2 = 0;
677 if (!udevman_parse_device_id_addr(&pos, &id1, &id2, (add_by_addr) ? UINT8_MAX : UINT16_MAX,
678 ':', '#'))
679 {
680 WLog_ERR(TAG, "Invalid device argument: \"%s\"", devices);
681 return CHANNEL_RC_INITIALIZATION_ERROR;
682 }
683
684 if (add_by_addr)
685 {
686 if (!add_device(&udevman->iface, DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV, (UINT8)id1,
687 (UINT8)id2, 0, 0))
688 return CHANNEL_RC_INITIALIZATION_ERROR;
689 }
690 else
691 {
692 VID_PID_PAIR* idpair = calloc(1, sizeof(VID_PID_PAIR));
693 if (!idpair)
694 return CHANNEL_RC_NO_MEMORY;
695 idpair->vid = id1;
696 idpair->pid = id2;
697 if (!ArrayList_Append(udevman->hotplug_vid_pids, idpair))
698 {
699 free(idpair);
700 return CHANNEL_RC_NO_MEMORY;
701 }
702
703 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append owns idpair
704 if (!add_device(&udevman->iface, DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT, 0, 0,
705 id1, id2))
706 {
707 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append owns idpair
708 return CHANNEL_RC_INITIALIZATION_ERROR;
709 }
710 }
711 }
712
713 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append owns idpair
714 return CHANNEL_RC_OK;
715}
716
717static UINT urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, const ADDIN_ARGV* args)
718{
719 LPCSTR devices = nullptr;
720
721 for (int x = 0; x < args->argc; x++)
722 {
723 const char* arg = args->argv[x];
724 if (strcmp(arg, "dbg") == 0)
725 {
726 WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE);
727 }
728 else if (_strnicmp(arg, "device:", 7) == 0)
729 {
730 /* Redirect all local devices */
731 const char* val = &arg[7];
732 const size_t len = strlen(val);
733 if (strcmp(val, "*") == 0)
734 {
735 udevman->flags |= UDEVMAN_FLAG_ADD_BY_AUTO;
736 }
737 else if (_strnicmp(arg, "USBInstanceID:", 14) == 0)
738 {
739 // TODO: Usb instance ID
740 }
741 else if ((val[0] == '{') && (val[len - 1] == '}'))
742 {
743 // TODO: Usb device class
744 }
745 }
746 else if (_strnicmp(arg, "dev:", 4) == 0)
747 {
748 devices = &arg[4];
749 }
750 else if (_strnicmp(arg, "id", 2) == 0)
751 {
752 const char* p = strchr(arg, ':');
753 if (p)
754 udevman->devices_vid_pid = p + 1;
755 else
756 udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
757 }
758 else if (_strnicmp(arg, "addr", 4) == 0)
759 {
760 const char* p = strchr(arg, ':');
761 if (p)
762 udevman->devices_addr = p + 1;
763 else
764 udevman->flags = UDEVMAN_FLAG_ADD_BY_ADDR;
765 }
766 else if (strcmp(arg, "auto") == 0)
767 {
768 udevman->flags |= UDEVMAN_FLAG_ADD_BY_AUTO;
769 }
770 else
771 {
772 const size_t len = strlen(arg);
773 if ((arg[0] == '{') && (arg[len - 1] == '}'))
774 {
775 // TODO: Check for {Device Setup Class GUID}:
776 }
777 }
778 }
779 if (devices)
780 {
781 if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID)
782 udevman->devices_vid_pid = devices;
783 else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR)
784 udevman->devices_addr = devices;
785 }
786
787 return CHANNEL_RC_OK;
788}
789
790static UINT udevman_listener_created_callback(IUDEVMAN* iudevman)
791{
792 UDEVMAN* udevman = (UDEVMAN*)iudevman;
793 WINPR_ASSERT(udevman);
794
795 if (udevman->devices_vid_pid)
796 return urbdrc_udevman_register_devices(udevman, udevman->devices_vid_pid, FALSE);
797
798 if (udevman->devices_addr)
799 return urbdrc_udevman_register_devices(udevman, udevman->devices_addr, TRUE);
800
801 return CHANNEL_RC_OK;
802}
803
804static void udevman_load_interface(UDEVMAN* udevman)
805{
806 /* standard */
807 udevman->iface.free = udevman_free;
808 /* manage devices */
809 udevman->iface.rewind = udevman_rewind;
810 udevman->iface.get_next = udevman_get_next;
811 udevman->iface.has_next = udevman_has_next;
812 udevman->iface.register_udevice = udevman_register_udevice;
813 udevman->iface.unregister_udevice = udevman_unregister_udevice;
814 udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice;
815 udevman->iface.get_udevice_by_ChannelID = udevman_get_udevice_by_ChannelID;
816 /* Extension */
817 udevman->iface.isAutoAdd = udevman_is_auto_add;
818 /* Basic state */
819 BASIC_STATE_FUNC_REGISTER(device_num, udevman);
820 BASIC_STATE_FUNC_REGISTER(next_device_id, udevman);
821
822 /* control semaphore or mutex lock */
823 udevman->iface.loading_lock = udevman_loading_lock;
824 udevman->iface.loading_unlock = udevman_loading_unlock;
825 udevman->iface.initialize = udevman_initialize;
826 udevman->iface.listener_created_callback = udevman_listener_created_callback;
827}
828
829static BOOL poll_libusb_events(UDEVMAN* udevman)
830{
831 int rc = LIBUSB_SUCCESS;
832 struct timeval tv = { 0, 500 };
833 if (libusb_try_lock_events(udevman->context) == 0)
834 {
835 if (libusb_event_handling_ok(udevman->context))
836 {
837 rc = libusb_handle_events_locked(udevman->context, &tv);
838 if (rc != LIBUSB_SUCCESS)
839 WLog_WARN(TAG, "libusb_handle_events_locked %d", rc);
840 }
841 libusb_unlock_events(udevman->context);
842 }
843 else
844 {
845 libusb_lock_event_waiters(udevman->context);
846 if (libusb_event_handler_active(udevman->context))
847 {
848 rc = libusb_wait_for_event(udevman->context, &tv);
849 if (rc < LIBUSB_SUCCESS)
850 WLog_WARN(TAG, "libusb_wait_for_event %d", rc);
851 }
852 libusb_unlock_event_waiters(udevman->context);
853 }
854
855 return rc > 0;
856}
857
858static DWORD WINAPI poll_thread(LPVOID lpThreadParameter)
859{
860 libusb_hotplug_callback_handle handle = 0;
861 UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter;
862 BOOL hasHotplug = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG);
863
864 if (hasHotplug)
865 {
866 int rc = libusb_hotplug_register_callback(
867 udevman->context,
868 LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
869 LIBUSB_HOTPLUG_NO_FLAGS, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
870 LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, udevman, &handle);
871
872 if (rc != LIBUSB_SUCCESS)
873 udevman->running = FALSE;
874 }
875 else
876 WLog_WARN(TAG, "Platform does not support libusb hotplug. USB devices plugged in later "
877 "will not be detected.");
878
879 while (udevman->running)
880 {
881 poll_libusb_events(udevman);
882 }
883
884 if (hasHotplug)
885 libusb_hotplug_deregister_callback(udevman->context, handle);
886
887 /* Process remaining usb events */
888 while (poll_libusb_events(udevman))
889 ;
890
891 ExitThread(0);
892 return 0;
893}
894
895FREERDP_ENTRY_POINT(UINT VCAPITYPE libusb_freerdp_urbdrc_client_subsystem_entry(
897{
898 wObject* obj = nullptr;
899 UINT status = 0;
900 UDEVMAN* udevman = nullptr;
901 const ADDIN_ARGV* args = pEntryPoints->args;
902 udevman = (PUDEVMAN)calloc(1, sizeof(UDEVMAN));
903
904 if (!udevman)
905 goto fail;
906
907 udevman->hotplug_vid_pids = ArrayList_New(TRUE);
908 if (!udevman->hotplug_vid_pids)
909 goto fail;
910 obj = ArrayList_Object(udevman->hotplug_vid_pids);
911 obj->fnObjectFree = free;
912 obj->fnObjectEquals = udevman_vid_pid_pair_equals;
913
914 udevman->next_device_id = BASE_USBDEVICE_NUM;
915 udevman->iface.plugin = pEntryPoints->plugin;
916
917 {
918 const int res = libusb_init(&udevman->context);
919 if (res != LIBUSB_SUCCESS)
920 goto fail;
921 }
922
923#ifdef _WIN32
924#if LIBUSB_API_VERSION >= 0x01000106
925 /* Prefer usbDK backend on windows. Not supported on other platforms. */
926 const int rc = libusb_set_option(udevman->context, LIBUSB_OPTION_USE_USBDK);
927 switch (rc)
928 {
929 case LIBUSB_SUCCESS:
930 break;
931 case LIBUSB_ERROR_NOT_FOUND:
932 case LIBUSB_ERROR_NOT_SUPPORTED:
933 WLog_WARN(TAG, "LIBUSB_OPTION_USE_USBDK %s [%d]", libusb_strerror(rc), rc);
934 break;
935 default:
936 WLog_ERR(TAG, "LIBUSB_OPTION_USE_USBDK %s [%d]", libusb_strerror(rc), rc);
937 goto fail;
938 }
939#endif
940#endif
941
942 udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
943 udevman->devman_loading = CreateMutexA(nullptr, FALSE, "devman_loading");
944
945 if (!udevman->devman_loading)
946 goto fail;
947
948 /* load usb device service management */
949 udevman_load_interface(udevman);
950 status = urbdrc_udevman_parse_addin_args(udevman, args);
951
952 if (status != CHANNEL_RC_OK)
953 goto fail;
954
955 udevman->running = TRUE;
956 udevman->thread = CreateThread(nullptr, 0, poll_thread, udevman, 0, nullptr);
957
958 if (!udevman->thread)
959 goto fail;
960
961 if (!pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*)udevman))
962 goto fail;
963
964 WLog_DBG(TAG, "UDEVMAN device registered.");
965 return 0;
966fail:
967 udevman_free(&udevman->iface);
968 return ERROR_INTERNAL_ERROR;
969}
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