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 (void)add_device(&udevman->iface, DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT, 0,
709 0, id1, id2);
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 if (!WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE))
727 return ERROR_INTERNAL_ERROR;
728 }
729 else if (_strnicmp(arg, "device:", 7) == 0)
730 {
731 /* Redirect all local devices */
732 const char* val = &arg[7];
733 const size_t len = strlen(val);
734 if (strcmp(val, "*") == 0)
735 {
736 udevman->flags |= UDEVMAN_FLAG_ADD_BY_AUTO;
737 }
738 else if (_strnicmp(arg, "USBInstanceID:", 14) == 0)
739 {
740 // TODO: Usb instance ID
741 }
742 else if ((val[0] == '{') && (val[len - 1] == '}'))
743 {
744 // TODO: Usb device class
745 }
746 }
747 else if (_strnicmp(arg, "dev:", 4) == 0)
748 {
749 devices = &arg[4];
750 }
751 else if (_strnicmp(arg, "id", 2) == 0)
752 {
753 const char* p = strchr(arg, ':');
754 if (p)
755 udevman->devices_vid_pid = p + 1;
756 else
757 udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
758 }
759 else if (_strnicmp(arg, "addr", 4) == 0)
760 {
761 const char* p = strchr(arg, ':');
762 if (p)
763 udevman->devices_addr = p + 1;
764 else
765 udevman->flags = UDEVMAN_FLAG_ADD_BY_ADDR;
766 }
767 else if (strcmp(arg, "auto") == 0)
768 {
769 udevman->flags |= UDEVMAN_FLAG_ADD_BY_AUTO;
770 }
771 else
772 {
773 const size_t len = strlen(arg);
774 if ((arg[0] == '{') && (arg[len - 1] == '}'))
775 {
776 // TODO: Check for {Device Setup Class GUID}:
777 }
778 }
779 }
780 if (devices)
781 {
782 if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID)
783 udevman->devices_vid_pid = devices;
784 else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR)
785 udevman->devices_addr = devices;
786 }
787
788 return CHANNEL_RC_OK;
789}
790
791static UINT udevman_listener_created_callback(IUDEVMAN* iudevman)
792{
793 UDEVMAN* udevman = (UDEVMAN*)iudevman;
794 WINPR_ASSERT(udevman);
795
796 if (udevman->devices_vid_pid)
797 return urbdrc_udevman_register_devices(udevman, udevman->devices_vid_pid, FALSE);
798
799 if (udevman->devices_addr)
800 return urbdrc_udevman_register_devices(udevman, udevman->devices_addr, TRUE);
801
802 return CHANNEL_RC_OK;
803}
804
805static void udevman_load_interface(UDEVMAN* udevman)
806{
807 /* standard */
808 udevman->iface.free = idevman_free;
809 /* manage devices */
810 udevman->iface.rewind = udevman_rewind;
811 udevman->iface.get_next = udevman_get_next;
812 udevman->iface.has_next = udevman_has_next;
813 udevman->iface.register_udevice = udevman_register_udevice;
814 udevman->iface.unregister_udevice = udevman_unregister_udevice;
815 udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice;
816 udevman->iface.get_udevice_by_ChannelID = udevman_get_udevice_by_ChannelID;
817 /* Extension */
818 udevman->iface.isAutoAdd = udevman_is_auto_add;
819 /* Basic state */
820 BASIC_STATE_FUNC_REGISTER(device_num, udevman);
821 BASIC_STATE_FUNC_REGISTER(next_device_id, udevman);
822
823 /* control semaphore or mutex lock */
824 udevman->iface.loading_lock = udevman_loading_lock;
825 udevman->iface.loading_unlock = udevman_loading_unlock;
826 udevman->iface.initialize = udevman_initialize;
827 udevman->iface.listener_created_callback = udevman_listener_created_callback;
828}
829
830static BOOL poll_libusb_events(UDEVMAN* udevman)
831{
832 int rc = LIBUSB_SUCCESS;
833 struct timeval tv = { 0, 500 };
834 if (libusb_try_lock_events(udevman->context) == 0)
835 {
836 if (libusb_event_handling_ok(udevman->context))
837 {
838 rc = libusb_handle_events_locked(udevman->context, &tv);
839 if (rc != LIBUSB_SUCCESS)
840 WLog_WARN(TAG, "libusb_handle_events_locked %d", rc);
841 }
842 libusb_unlock_events(udevman->context);
843 }
844 else
845 {
846 libusb_lock_event_waiters(udevman->context);
847 if (libusb_event_handler_active(udevman->context))
848 {
849 rc = libusb_wait_for_event(udevman->context, &tv);
850 if (rc < LIBUSB_SUCCESS)
851 WLog_WARN(TAG, "libusb_wait_for_event %d", rc);
852 }
853 libusb_unlock_event_waiters(udevman->context);
854 }
855
856 return rc > 0;
857}
858
859static DWORD WINAPI poll_thread(LPVOID lpThreadParameter)
860{
861 libusb_hotplug_callback_handle handle = 0;
862 UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter;
863 BOOL hasHotplug = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG);
864
865 if (hasHotplug)
866 {
867 int rc = libusb_hotplug_register_callback(
868 udevman->context,
869 LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
870 LIBUSB_HOTPLUG_NO_FLAGS, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
871 LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, udevman, &handle);
872
873 if (rc != LIBUSB_SUCCESS)
874 udevman->running = FALSE;
875 }
876 else
877 WLog_WARN(TAG, "Platform does not support libusb hotplug. USB devices plugged in later "
878 "will not be detected.");
879
880 while (udevman->running)
881 {
882 poll_libusb_events(udevman);
883 }
884
885 if (hasHotplug)
886 libusb_hotplug_deregister_callback(udevman->context, handle);
887
888 /* Process remaining usb events */
889 while (poll_libusb_events(udevman))
890 ;
891
892 ExitThread(0);
893 return 0;
894}
895
896FREERDP_ENTRY_POINT(UINT VCAPITYPE libusb_freerdp_urbdrc_client_subsystem_entry(
898{
899 wObject* obj = nullptr;
900 UINT status = 0;
901 const ADDIN_ARGV* args = pEntryPoints->args;
902 UDEVMAN* 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);
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:59
WINPR_ATTR_NODISCARD OBJECT_EQUALS_FN fnObjectEquals
Definition collections.h:61