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