VirtualBox

source: vbox/trunk/src/VBox/RDP/client/vrdp/rdpusb.c@ 34817

Last change on this file since 34817 was 34341, checked in by vboxsync, 14 years ago

Main/linux/USB and RDP/client/vrdp: clean up the handling of the USB device tree path and get rid of data duplication

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.7 KB
Line 
1/** @file
2 *
3 * Remote Desktop Protocol client:
4 * USB Channel Process Functions
5 *
6 */
7
8/*
9 * Copyright (C) 2006-2007 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include "../rdesktop.h"
21
22#include "vrdpusb.h"
23#include "USBProxyDevice.h"
24#include "USBGetDevices.h"
25
26#include <iprt/cdefs.h>
27#include <iprt/types.h>
28#include <iprt/err.h>
29#include <iprt/log.h>
30
31#include <unistd.h>
32#include <ctype.h>
33#include <fcntl.h>
34
35
36#define RDPUSB_REQ_OPEN (0)
37#define RDPUSB_REQ_CLOSE (1)
38#define RDPUSB_REQ_RESET (2)
39#define RDPUSB_REQ_SET_CONFIG (3)
40#define RDPUSB_REQ_CLAIM_INTERFACE (4)
41#define RDPUSB_REQ_RELEASE_INTERFACE (5)
42#define RDPUSB_REQ_INTERFACE_SETTING (6)
43#define RDPUSB_REQ_QUEUE_URB (7)
44#define RDPUSB_REQ_REAP_URB (8)
45#define RDPUSB_REQ_CLEAR_HALTED_EP (9)
46#define RDPUSB_REQ_CANCEL_URB (10)
47#define RDPUSB_REQ_DEVICE_LIST (11)
48#define RDPUSB_REQ_NEGOTIATE (12)
49
50static VCHANNEL *rdpusb_channel;
51
52/** Well-known locations for the Linux Usbfs virtual file system */
53static const struct
54{
55 /** Expected mount location for Usbfs */
56 const char *pcszRoot;
57 /** Expected location of the "devices" file */
58 const char *pcszDevices;
59} g_usbfsPaths[] =
60{
61 { "/proc/bus/usb", "/proc/bus/usb/devices" },
62 { "/dev/bus/usb", "/dev/bus/usb/devices" }
63};
64
65/** Location at which the USB device tree was found. NULL means not
66 * found. */
67static const char *g_pcszDevicesRoot = NULL;
68static bool g_fUseSysfs = false;
69
70static PUSBDEVICE g_pUsbDevices = NULL;
71
72/* A device list entry */
73#pragma pack (1)
74typedef struct _DevListEntry
75{
76 uint16_t oNext; /* Offset of the next structure. 0 if last. */
77 uint32_t id; /* Identifier of the device assigned by the client. */
78 uint16_t bcdUSB; /* USB verion number. */
79 uint8_t bDeviceClass; /* Device class. */
80 uint8_t bDeviceSubClass; /* Device subclass. */
81 uint8_t bDeviceProtocol; /* Device protocol. */
82 uint16_t idVendor; /* Vendor id. */
83 uint16_t idProduct; /* Product id. */
84 uint16_t bcdRev; /* Revision. */
85 uint16_t oManufacturer; /* Offset of manufacturer string. */
86 uint16_t oProduct; /* Offset of product string. */
87 uint16_t oSerialNumber; /* Offset of serial string. */
88 uint16_t idPort; /* Physical USB port the device is connected to. */
89} DevListEntry;
90#pragma pack ()
91
92static inline int op_usbproxy_back_open(PUSBPROXYDEV p, const char *pszAddress)
93{
94 return g_USBProxyDeviceHost.pfnOpen (p, pszAddress, NULL);
95}
96
97static inline void op_usbproxy_back_close(PUSBPROXYDEV pDev)
98{
99 return g_USBProxyDeviceHost.pfnClose (pDev);
100}
101
102static inline int op_usbproxy_back_reset(PUSBPROXYDEV pDev)
103{
104 return g_USBProxyDeviceHost.pfnReset (pDev, false);
105}
106
107static inline int op_usbproxy_back_set_config(PUSBPROXYDEV pDev, int cfg)
108{
109 return g_USBProxyDeviceHost.pfnSetConfig (pDev, cfg);
110}
111
112static inline int op_usbproxy_back_claim_interface(PUSBPROXYDEV pDev, int ifnum)
113{
114 return g_USBProxyDeviceHost.pfnClaimInterface (pDev, ifnum);
115}
116
117static inline int op_usbproxy_back_release_interface(PUSBPROXYDEV pDev, int ifnum)
118{
119 return g_USBProxyDeviceHost.pfnReleaseInterface (pDev, ifnum);
120}
121
122static inline int op_usbproxy_back_interface_setting(PUSBPROXYDEV pDev, int ifnum, int setting)
123{
124 return g_USBProxyDeviceHost.pfnSetInterface (pDev, ifnum, setting);
125}
126
127static inline int op_usbproxy_back_queue_urb(PVUSBURB pUrb)
128{
129 return g_USBProxyDeviceHost.pfnUrbQueue(pUrb);
130}
131
132static inline PVUSBURB op_usbproxy_back_reap_urb(PUSBPROXYDEV pDev, unsigned cMillies)
133{
134 return g_USBProxyDeviceHost.pfnUrbReap (pDev, cMillies);
135}
136
137static inline bool op_usbproxy_back_clear_halted_ep(PUSBPROXYDEV pDev, unsigned EndPoint)
138{
139 return g_USBProxyDeviceHost.pfnClearHaltedEndpoint (pDev, EndPoint);
140}
141
142static inline void op_usbproxy_back_cancel_urb(PVUSBURB pUrb)
143{
144 return g_USBProxyDeviceHost.pfnUrbCancel (pUrb);
145}
146
147
148/** Count the USB devices in a linked list of PUSBDEVICE structures. */
149unsigned countUSBDevices(PUSBDEVICE pDevices)
150{
151 unsigned i;
152 PUSBDEVICE pDevice;
153 for (i = 0, pDevice = pDevices; pDevices->pNext;
154 ++i, pDevices = pDevices->pNext);
155 return i;
156}
157
158
159enum {
160 /** The space we set aside for the USB strings. Should always be enough,
161 * as a USB device contains up to 256 characters of UTF-16 string data. */
162 MAX_STRINGS_LEN = 1024,
163 /** The space we reserve for each wire format device entry */
164 DEV_ENTRY_SIZE = sizeof(DevListEntry) + MAX_STRINGS_LEN
165};
166
167
168/**
169 * Add a string to the end of a wire format device entry.
170 * @param pBuf the start of the buffer containing the entry
171 * @param iBuf the index into the buffer to add the string at
172 * @param pcsz the string to add - optional
173 * @param piString where to write back @a iBuf or zero if there is no string
174 * @param piNext where to write back the index where the next string may
175 * start
176 */
177static void addStringToEntry(char *pBuf, uint16_t iBuf, const char *pcsz,
178 uint16_t *piString, uint16_t *piNext)
179{
180 size_t cch;
181
182 *piString = 0;
183 *piNext = iBuf;
184 if (!pcsz)
185 return;
186 cch = strlen(pcsz) + 1;
187 if (cch > DEV_ENTRY_SIZE - iBuf)
188 return;
189 strcpy(pBuf + iBuf, pcsz);
190 *piString = iBuf;
191 *piNext = iBuf + cch;
192}
193
194
195/** Fill in a device list entry in wire format from a PUSBDEVICE and return an
196 * index to where the next string should start */
197static void fillWireListEntry(char *pBuf, PUSBDEVICE pDevice,
198 uint16_t *piNext)
199{
200 DevListEntry *pEntry;
201 uint16_t iNextString = sizeof(DevListEntry);
202
203 pEntry = (DevListEntry *)pBuf;
204 pEntry->id = (pDevice->bPort << 8) + pDevice->bBus;
205 pEntry->bcdUSB = pDevice->bcdUSB;
206 pEntry->bDeviceClass = pDevice->bDeviceClass;
207 pEntry->bDeviceSubClass = pDevice->bDeviceSubClass;
208 pEntry->idVendor = pDevice->idVendor;
209 pEntry->idProduct = pDevice->idProduct;
210 pEntry->bcdRev = pDevice->bcdDevice;
211 pEntry->idPort = pDevice->bPort;
212 addStringToEntry(pBuf, iNextString, pDevice->pszManufacturer,
213 &pEntry->oManufacturer, &iNextString);
214 addStringToEntry(pBuf, iNextString, pDevice->pszProduct,
215 &pEntry->oProduct, &iNextString);
216 addStringToEntry(pBuf, iNextString, pDevice->pszSerialNumber,
217 &pEntry->oSerialNumber, &pEntry->oNext);
218 *piNext = pEntry->oNext;
219}
220
221
222/** Allocate (and return) a buffer for a device list in VRDP wire format,
223 * and populate from a PUSBDEVICE linked list. @a pLen takes the length of
224 * the new list. */
225static void *buildWireListFromDevices(PUSBDEVICE pDevices, int *pLen)
226{
227 char *pBuf;
228 unsigned cbBuf, iCurrent;
229 uint16_t iNext;
230 PUSBDEVICE pCurrent;
231
232 cbBuf = countUSBDevices(pDevices) * DEV_ENTRY_SIZE + 2;
233 pBuf = (char *)xmalloc(cbBuf);
234 memset(pBuf, 0, cbBuf);
235 for (pCurrent = pDevices, iCurrent = 0; pCurrent;
236 pCurrent = pCurrent->pNext, iCurrent += iNext)
237 fillWireListEntry(pBuf + iCurrent, pCurrent, &iNext);
238 *pLen = iCurrent + iNext + 2;
239 return pBuf;
240}
241
242
243/** Build a list of the usable USB devices currently connected to the client
244 * system using the VRDP wire protocol. The structure returned must be freed
245 * using free(3) when it is no longer needed; returns NULL and sets *pLen to
246 * zero on failure. */
247static void *build_device_list (int *pLen)
248{
249 void *pvDeviceList;
250
251 Log(("RDPUSB build_device_list"));
252 *pLen = 0;
253 if (g_pUsbDevices)
254 deviceListFree(&g_pUsbDevices);
255 g_pUsbDevices = USBProxyLinuxGetDevices(g_pcszDevicesRoot, g_fUseSysfs);
256 if (!g_pUsbDevices)
257 return NULL;
258 pvDeviceList = buildWireListFromDevices(g_pUsbDevices, pLen);
259 return pvDeviceList;
260}
261
262
263static STREAM
264rdpusb_init_packet(uint32 len, uint8 code)
265{
266 STREAM s;
267
268 s = channel_init(rdpusb_channel, len + 5);
269 out_uint32_le (s, len + sizeof (code)); /* The length of data after the 'len' field. */
270 out_uint8(s, code);
271 return s;
272}
273
274static void
275rdpusb_send(STREAM s)
276{
277#ifdef RDPUSB_DEBUG
278 Log(("RDPUSB send:\n"));
279 hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
280#endif
281
282 channel_send(s, rdpusb_channel);
283}
284
285static void
286rdpusb_send_reply (uint8_t code, uint8_t status, uint32_t devid)
287{
288 STREAM s = rdpusb_init_packet(1, code);
289 out_uint8(s, status);
290 out_uint32_le(s, devid);
291 s_mark_end(s);
292 rdpusb_send(s);
293}
294
295static void
296rdpusb_send_access_denied (uint8_t code, uint32_t devid)
297{
298 rdpusb_send_reply (code, VRDP_USB_STATUS_ACCESS_DENIED, devid);
299}
300
301static inline int
302vrdp_usb_status (int rc, VUSBDEV *pdev)
303{
304 if (!rc || usbProxyFromVusbDev(pdev)->fDetached)
305 {
306 return VRDP_USB_STATUS_DEVICE_REMOVED;
307 }
308
309 return VRDP_USB_STATUS_SUCCESS;
310}
311
312static PUSBPROXYDEV g_proxies = NULL;
313
314static PUSBPROXYDEV
315devid2proxy (uint32_t devid)
316{
317 PUSBPROXYDEV proxy = g_proxies;
318
319 while (proxy && proxy->devid != devid)
320 {
321 proxy = proxy->pNext;
322 }
323
324 return proxy;
325}
326
327static void
328rdpusb_reap_urbs (void)
329{
330 STREAM s;
331
332 PVUSBURB pUrb = NULL;
333
334 PUSBPROXYDEV proxy = g_proxies;
335
336 while (proxy)
337 {
338 pUrb = op_usbproxy_back_reap_urb(proxy, 0);
339
340 if (pUrb)
341 {
342 int datalen = 0;
343
344 Log(("RDPUSB: rdpusb_reap_urbs: cbData = %d, enmStatus = %d\n", pUrb->cbData, pUrb->enmStatus));
345
346 if (pUrb->enmDir == VUSB_DIRECTION_IN)
347 {
348 datalen = pUrb->cbData;
349 }
350
351 s = rdpusb_init_packet(14 + datalen, RDPUSB_REQ_REAP_URB);
352 out_uint32_le(s, proxy->devid);
353 out_uint8(s, VRDP_USB_REAP_FLAG_LAST);
354 out_uint8(s, pUrb->enmStatus);
355 out_uint32_le(s, pUrb->handle);
356 out_uint32_le(s, pUrb->cbData);
357
358 if (datalen)
359 {
360 out_uint8a (s, pUrb->abData, datalen);
361 }
362
363 s_mark_end(s);
364 rdpusb_send(s);
365
366 if (pUrb->pPrev || pUrb->pNext || pUrb == proxy->pUrbs)
367 {
368 /* Remove the URB from list. */
369 if (pUrb->pPrev)
370 {
371 pUrb->pPrev->pNext = pUrb->pNext;
372 }
373 else
374 {
375 proxy->pUrbs = pUrb->pNext;
376 }
377
378 if (pUrb->pNext)
379 {
380 pUrb->pNext->pPrev = pUrb->pPrev;
381 }
382 }
383
384#ifdef RDPUSB_DEBUG
385 Log(("Going to free %p\n", pUrb));
386#endif
387 xfree (pUrb);
388#ifdef RDPUSB_DEBUG
389 Log(("freed %p\n", pUrb));
390#endif
391 }
392
393 proxy = proxy->pNext;
394 }
395
396 return;
397}
398
399static void
400rdpusb_process(STREAM s)
401{
402 int rc;
403
404 uint32 len;
405 uint8 code;
406 uint32 devid;
407
408 PUSBPROXYDEV proxy = NULL;
409
410#ifdef RDPUSB_DEBUG
411 Log(("RDPUSB recv:\n"));
412 hexdump(s->p, s->end - s->p);
413#endif
414
415 in_uint32_le (s, len);
416 if (len > s->end - s->p)
417 {
418 error("RDPUSB: not enough data len = %d, bytes left %d\n", len, s->end - s->p);
419 return;
420 }
421
422 in_uint8(s, code);
423
424 Log(("RDPUSB recv: len = %d, code = %d\n", len, code));
425
426 switch (code)
427 {
428 case RDPUSB_REQ_OPEN:
429 {
430 PUSBDEVICE pDevice;
431
432 in_uint32_le(s, devid);
433
434 proxy = (PUSBPROXYDEV )xmalloc (sizeof (USBPROXYDEV));
435
436 memset (proxy, 0, sizeof (USBPROXYDEV));
437
438 proxy->Dev.pszName = "Remote device";
439 proxy->devid = devid;
440
441 for (pDevice = g_pUsbDevices; pDevice; pDevice = pDevice->pNext)
442 if ((pDevice->bPort << 8) + pDevice->bBus == devid)
443 break;
444
445 rc = pDevice ? op_usbproxy_back_open(proxy, pDevice->pszAddress)
446 : VERR_NOT_FOUND;
447
448 if (rc != VINF_SUCCESS)
449 {
450 rdpusb_send_access_denied (code, devid);
451 xfree (proxy);
452 proxy = NULL;
453 }
454 else
455 {
456 if (g_proxies)
457 {
458 g_proxies->pPrev = proxy;
459 }
460
461 proxy->pNext = g_proxies;
462 g_proxies = proxy;
463 }
464 } break;
465
466 case RDPUSB_REQ_CLOSE:
467 {
468 in_uint32_le(s, devid);
469 proxy = devid2proxy (devid);
470
471 if (proxy)
472 {
473 op_usbproxy_back_close(proxy);
474
475 if (proxy->pPrev)
476 {
477 proxy->pPrev->pNext = proxy->pNext;
478 }
479 else
480 {
481 g_proxies = proxy->pNext;
482 }
483
484 if (proxy->pNext)
485 {
486 proxy->pNext->pPrev = proxy->pPrev;
487 }
488
489 xfree (proxy);
490 proxy = NULL;
491 }
492
493 /* No reply. */
494 } break;
495
496 case RDPUSB_REQ_RESET:
497 {
498 in_uint32_le(s, devid);
499 proxy = devid2proxy (devid);
500
501 if (!proxy)
502 {
503 rdpusb_send_access_denied (code, devid);
504 break;
505 }
506
507 rc = op_usbproxy_back_reset(proxy);
508
509 if (rc != VINF_SUCCESS)
510 {
511 rdpusb_send_reply (code, vrdp_usb_status (!rc, &proxy->Dev), devid);
512 }
513 } break;
514
515 case RDPUSB_REQ_SET_CONFIG:
516 {
517 uint8 cfg;
518
519 in_uint32_le(s, devid);
520 proxy = devid2proxy (devid);
521
522 if (!proxy)
523 {
524 rdpusb_send_access_denied (code, devid);
525 break;
526 }
527
528 in_uint8(s, cfg);
529
530 rc = op_usbproxy_back_set_config(proxy, cfg);
531
532 if (!rc)
533 {
534 rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
535 }
536 } break;
537
538 case RDPUSB_REQ_CLAIM_INTERFACE:
539 {
540 uint8 ifnum;
541
542 in_uint32_le(s, devid);
543 proxy = devid2proxy (devid);
544
545 if (!proxy)
546 {
547 rdpusb_send_access_denied (code, devid);
548 break;
549 }
550
551 in_uint8(s, ifnum);
552
553 rc = op_usbproxy_back_claim_interface(proxy, ifnum);
554
555 if (!rc)
556 {
557 rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
558 }
559 } break;
560
561 case RDPUSB_REQ_RELEASE_INTERFACE:
562 {
563 uint8 ifnum;
564
565 in_uint32_le(s, devid);
566 proxy = devid2proxy (devid);
567
568 if (!proxy)
569 {
570 rdpusb_send_access_denied (code, devid);
571 break;
572 }
573
574 in_uint8(s, ifnum);
575
576 rc = op_usbproxy_back_release_interface(proxy, ifnum);
577
578 if (!rc)
579 {
580 rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
581 }
582 } break;
583
584 case RDPUSB_REQ_INTERFACE_SETTING:
585 {
586 uint8 ifnum;
587 uint8 setting;
588
589 in_uint32_le(s, devid);
590 proxy = devid2proxy (devid);
591
592 if (!proxy)
593 {
594 rdpusb_send_access_denied (code, devid);
595 break;
596 }
597
598 in_uint8(s, ifnum);
599 in_uint8(s, setting);
600
601 rc = op_usbproxy_back_interface_setting(proxy, ifnum, setting);
602
603 if (!rc)
604 {
605 rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
606 }
607 } break;
608
609 case RDPUSB_REQ_QUEUE_URB:
610 {
611 uint32 handle;
612 uint8 type;
613 uint8 ep;
614 uint8 dir;
615 uint32 urblen;
616 uint32 datalen;
617
618 PVUSBURB pUrb; // struct vusb_urb *urb;
619
620 in_uint32_le(s, devid);
621 proxy = devid2proxy (devid);
622
623 if (!proxy)
624 {
625 /* No reply. */
626 break;
627 }
628
629 in_uint32(s, handle);
630 in_uint8(s, type);
631 in_uint8(s, ep);
632 in_uint8(s, dir);
633 in_uint32(s, urblen);
634 in_uint32(s, datalen);
635
636 /* Allocate a single block for URB description and data buffer */
637 pUrb = (PVUSBURB)xmalloc (sizeof (VUSBURB) +
638 (urblen <= sizeof (pUrb->abData)? 0: urblen - sizeof (pUrb->abData))
639 );
640 memset (pUrb, 0, sizeof (VUSBURB));
641 pUrb->pDev = &proxy->Dev;
642 pUrb->handle = handle;
643 pUrb->enmType = type;
644 pUrb->enmStatus = 0;
645 pUrb->EndPt = ep;
646 pUrb->enmDir = dir;
647 pUrb->cbData = urblen;
648
649 Log(("RDPUSB: queued URB handle = %d\n", handle));
650
651 if (datalen)
652 {
653 in_uint8a (s, pUrb->abData, datalen);
654 }
655
656 rc = op_usbproxy_back_queue_urb(pUrb);
657
658 /* No reply required. */
659
660 if (rc)
661 {
662 if (proxy->pUrbs)
663 {
664 proxy->pUrbs->pPrev = pUrb;
665 }
666
667 pUrb->pNext = proxy->pUrbs;
668 proxy->pUrbs = pUrb;
669 }
670 else
671 {
672 xfree (pUrb);
673 }
674 } break;
675
676 case RDPUSB_REQ_REAP_URB:
677 {
678 rdpusb_reap_urbs ();
679 } break;
680
681 case RDPUSB_REQ_CLEAR_HALTED_EP:
682 {
683 uint8 ep;
684
685 in_uint32_le(s, devid);
686 proxy = devid2proxy (devid);
687
688 if (!proxy)
689 {
690 rdpusb_send_access_denied (code, devid);
691 break;
692 }
693
694 in_uint8(s, ep);
695
696 rc = op_usbproxy_back_clear_halted_ep(proxy, ep);
697
698 if (!rc)
699 {
700 rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
701 }
702 } break;
703
704 case RDPUSB_REQ_CANCEL_URB:
705 {
706 uint32 handle;
707 PVUSBURB pUrb = NULL;
708
709 in_uint32_le(s, devid);
710 proxy = devid2proxy (devid);
711
712 if (!proxy)
713 {
714 rdpusb_send_access_denied (code, devid);
715 break;
716 }
717
718 in_uint32_le(s, handle);
719
720 pUrb = proxy->pUrbs;
721
722 while (pUrb && pUrb->handle != handle)
723 {
724 pUrb = pUrb->pNext;
725 }
726
727 if (pUrb)
728 {
729 op_usbproxy_back_cancel_urb(pUrb);
730
731 /* No reply required. */
732
733 /* Remove URB from list. */
734 if (pUrb->pPrev)
735 {
736 pUrb->pPrev->pNext = pUrb->pNext;
737 }
738 else
739 {
740 proxy->pUrbs = pUrb->pNext;
741 }
742
743 if (pUrb->pNext)
744 {
745 pUrb->pNext->pPrev = pUrb->pPrev;
746 }
747
748 pUrb->pNext = pUrb->pPrev = NULL;
749
750 Log(("Cancelled URB %p\n", pUrb));
751
752 // xfree (pUrb);
753 }
754 } break;
755
756 case RDPUSB_REQ_DEVICE_LIST:
757 {
758 void *buf = NULL;
759 int len = 0;
760
761 buf = build_device_list (&len);
762
763 s = rdpusb_init_packet(len? len: 2, code);
764 if (len)
765 {
766 out_uint8p (s, buf, len);
767 }
768 else
769 {
770 out_uint16_le(s, 0);
771 }
772 s_mark_end(s);
773 rdpusb_send(s);
774
775 if (buf)
776 {
777 free (buf);
778 }
779 } break;
780
781 case RDPUSB_REQ_NEGOTIATE:
782 {
783 s = rdpusb_init_packet(1, code);
784 out_uint8(s, VRDP_USB_CAPS_FLAG_ASYNC);
785 s_mark_end(s);
786 rdpusb_send(s);
787 } break;
788
789 default:
790 unimpl("RDPUSB code %d\n", code);
791 break;
792 }
793}
794
795void
796rdpusb_add_fds(int *n, fd_set * rfds, fd_set * wfds)
797{
798 PUSBPROXYDEV proxy = g_proxies;
799
800// Log(("RDPUSB: rdpusb_add_fds: begin *n = %d\n", *n));
801
802 while (proxy)
803 {
804 int fd = USBProxyDeviceLinuxGetFD(proxy);
805
806 if (fd != -1)
807 {
808// Log(("RDPUSB: rdpusb_add_fds: adding %d\n", proxy->priv.File));
809
810 FD_SET(fd, rfds);
811 FD_SET(fd, wfds);
812 *n = MAX(*n, fd);
813 }
814
815 proxy = proxy->pNext;
816 }
817
818// Log(("RDPUSB: rdpusb_add_fds: end *n = %d\n", *n));
819
820 return;
821}
822
823void
824rdpusb_check_fds(fd_set * rfds, fd_set * wfds)
825{
826 PUSBPROXYDEV proxy = g_proxies;
827 unsigned found = 0;
828
829 while (proxy)
830 {
831 int fd = USBProxyDeviceLinuxGetFD(proxy);
832
833 if (fd != -1)
834 {
835 if (FD_ISSET(fd, rfds))
836 found = 1;
837 if (FD_ISSET(fd, wfds))
838 found = 1;
839 }
840
841 proxy = proxy->pNext;
842 }
843
844// Log(("RDPUSB: rdpusb_check_fds: begin\n"));
845
846 if (found)
847 rdpusb_reap_urbs ();
848
849// Log(("RDPUSB: rdpusb_check_fds: end\n"));
850
851 return;
852}
853
854
855RD_BOOL
856rdpusb_init(void)
857{
858 PCUSBDEVTREELOCATION pcLocation = USBProxyLinuxGetDeviceRoot(false);
859 g_fUseSysfs = pcLocation->fUseSysfs;
860 g_pcszDevicesRoot = pcLocation->szDevicesRoot;
861 rdpusb_channel =
862 channel_register("vrdpusb", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
863 rdpusb_process);
864 return (rdpusb_channel != NULL);
865}
866
867void
868rdpusb_close (void)
869{
870 PUSBPROXYDEV proxy = g_proxies;
871
872 while (proxy)
873 {
874 PUSBPROXYDEV pNext = proxy->pNext;
875
876 Log(("RDPUSB: closing proxy %p\n", proxy));
877
878 op_usbproxy_back_close(proxy);
879 xfree (proxy);
880
881 proxy = pNext;
882 }
883
884 return;
885}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette