VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/usbip/USBProxyDevice-usbip.cpp@ 57515

最後變更 在這個檔案從57515是 57406,由 vboxsync 提交於 10 年 前

USB/IP: Updates and fixes, implement support for isochronous transfers (not quite working yet)

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 55.4 KB
 
1/* $Id: USBProxyDevice-usbip.cpp 57406 2015-08-18 09:33:44Z vboxsync $ */
2/** @file
3 * USB device proxy - USB/IP backend.
4 */
5
6/*
7 * Copyright (C) 2014-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
23
24#include <VBox/log.h>
25#include <VBox/err.h>
26#include <VBox/vmm/pdm.h>
27
28#include <iprt/asm.h>
29#include <iprt/assert.h>
30#include <iprt/alloc.h>
31#include <iprt/string.h>
32#include <iprt/socket.h>
33#include <iprt/poll.h>
34#include <iprt/tcp.h>
35#include <iprt/pipe.h>
36#include <iprt/list.h>
37#include <iprt/semaphore.h>
38
39#include "../USBProxyDevice.h"
40
41
42/*********************************************************************************************************************************
43* Constants And Macros, Structures and Typedefs *
44*********************************************************************************************************************************/
45
46/** The USB version number used for the protocol. */
47#define USBIP_VERSION UINT16_C(0x0111)
48/** Request indicator in the command code. */
49#define USBIP_INDICATOR_REQ RT_BIT(15)
50
51/** Command/Reply code for OP_REQ/RET_DEVLIST. */
52#define USBIP_REQ_RET_DEVLIST UINT16_C(5)
53/** Command/Reply code for OP_REQ/REP_IMPORT. */
54#define USBIP_REQ_RET_IMPORT UINT16_C(3)
55/** USB submit command identifier. */
56#define USBIP_CMD_SUBMIT UINT32_C(1)
57/** USB submit status identifier. */
58#define USBIP_RET_SUBMIT UINT32_C(3)
59/** URB unlink (cancel) command identifier. */
60#define USBIP_CMD_UNLINK UINT32_C(2)
61/** URB unlink (cancel) reply identifier. */
62#define USBIP_RET_UNLINK UINT32_C(4)
63
64/** Short read is not okay for the specified URB. */
65#define USBIP_XFER_FLAGS_SHORT_NOT_OK RT_BIT_32(0)
66/** Queue the isochronous URB as soon as possible. */
67#define USBIP_XFER_FLAGS_ISO_ASAP RT_BIT_32(1)
68/** Don't use DMA mappings for this URB. */
69#define USBIP_XFER_FLAGS_NO_TRANSFER_DMA_MAP RT_BIT_32(2)
70/** Explain - only applies to UHCI. */
71#define USBIP_XFER_FLAGS_FSBR RT_BIT_32(4)
72
73/** URB direction - input. */
74#define USBIP_DIR_IN UINT32_C(1)
75/** URB direction - output. */
76#define USBIP_DIR_OUT UINT32_C(0)
77
78/** @name USB/IP error codes.
79 * @{ */
80/** Success indicator. */
81#define USBIP_STATUS_SUCCESS INT32_C(0)
82/** Pipe stalled. */
83#define USBIP_STATUS_PIPE_STALLED INT32_C(-32)
84/** @} */
85
86/**
87 * Exported device entry in the OP_RET_DEVLIST reply.
88 */
89#pragma pack(1)
90typedef struct UsbIpExportedDevice
91{
92 /** Path of the device, zero terminated string. */
93 char szPath[256];
94 /** Bus ID of the exported device, zero terminated string. */
95 char szBusId[32];
96 /** Bus number. */
97 uint32_t u32BusNum;
98 /** Device number. */
99 uint32_t u32DevNum;
100 /** Speed indicator of the device. */
101 uint32_t u32Speed;
102 /** Vendor ID of the device. */
103 uint16_t u16VendorId;
104 /** Product ID of the device. */
105 uint16_t u16ProductId;
106 /** Device release number. */
107 uint16_t u16BcdDevice;
108 /** Device class. */
109 uint8_t bDeviceClass;
110 /** Device Subclass. */
111 uint8_t bDeviceSubClass;
112 /** Device protocol. */
113 uint8_t bDeviceProtocol;
114 /** Configuration value. */
115 uint8_t bConfigurationValue;
116 /** Current configuration value of the device. */
117 uint8_t bNumConfigurations;
118 /** Number of interfaces for the device. */
119 uint8_t bNumInterfaces;
120} UsbIpExportedDevice;
121/** Pointer to a exported device entry. */
122typedef UsbIpExportedDevice *PUsbIpExportedDevice;
123#pragma pack()
124AssertCompileSize(UsbIpExportedDevice, 312);
125
126/**
127 * Interface descriptor entry for an exported device.
128 */
129#pragma pack(1)
130typedef struct UsbIpDeviceInterface
131{
132 /** Intefrace class. */
133 uint8_t bInterfaceClass;
134 /** Interface sub class. */
135 uint8_t bInterfaceSubClass;
136 /** Interface protocol identifier. */
137 uint8_t bInterfaceProtocol;
138 /** Padding byte for alignment. */
139 uint8_t bPadding;
140} UsbIpDeviceInterface;
141/** Pointer to an interface descriptor entry. */
142typedef UsbIpDeviceInterface *PUsbIpDeviceInterface;
143#pragma pack()
144
145/**
146 * USB/IP Import request.
147 */
148#pragma pack(1)
149typedef struct UsbIpReqImport
150{
151 /** Protocol version number. */
152 uint16_t u16Version;
153 /** Command code. */
154 uint16_t u16Cmd;
155 /** Status field, unused. */
156 int32_t u32Status;
157 /** Bus Id of the device as zero terminated string. */
158 char aszBusId[32];
159} UsbIpReqImport;
160/** Pointer to a import request. */
161typedef UsbIpReqImport *PUsbIpReqImport;
162#pragma pack()
163
164/**
165 * USB/IP Import reply.
166 *
167 * This is only the header, for successful
168 * imports the device details are sent to as
169 * defined in UsbIpExportedDevice.
170 */
171#pragma pack(1)
172typedef struct UsbIpRetImport
173{
174 /** Protocol version number. */
175 uint16_t u16Version;
176 /** Command code. */
177 uint16_t u16Cmd;
178 /** Status field, unused. */
179 int32_t u32Status;
180} UsbIpRetImport;
181/** Pointer to a import reply. */
182typedef UsbIpRetImport *PUsbIpRetImport;
183#pragma pack()
184
185/**
186 * Command/Reply header common to the submit and unlink commands
187 * replies.
188 */
189#pragma pack(1)
190typedef struct UsbIpReqRetHdr
191{
192 /** Request/Return code. */
193 uint32_t u32ReqRet;
194 /** Sequence number to identify the URB. */
195 uint32_t u32SeqNum;
196 /** Device id. */
197 uint32_t u32DevId;
198 /** Direction of the endpoint (host->device, device->host). */
199 uint32_t u32Direction;
200 /** Endpoint number. */
201 uint32_t u32Endpoint;
202} UsbIpReqRetHdr;
203/** Pointer to a request/reply header. */
204typedef UsbIpReqRetHdr *PUsbIpReqRetHdr;
205#pragma pack()
206
207/**
208 * USB/IP Submit request.
209 */
210#pragma pack(1)
211typedef struct UsbIpReqSubmit
212{
213 /** The request header. */
214 UsbIpReqRetHdr Hdr;
215 /** Transfer flags for the URB. */
216 uint32_t u32XferFlags;
217 /** Transfer buffer length. */
218 uint32_t u32TransferBufferLength;
219 /** Frame to transmit an ISO frame. */
220 uint32_t u32StartFrame;
221 /** Number of isochronous packets. */
222 uint32_t u32NumIsocPkts;
223 /** Maximum time for the request on the server side host controller. */
224 uint32_t u32Interval;
225 /** Setup data for a control URB. */
226 VUSBSETUP Setup;
227} UsbIpReqSubmit;
228/** Pointer to a submit request. */
229typedef UsbIpReqSubmit *PUsbIpReqSubmit;
230#pragma pack()
231
232/**
233 * USB/IP Submit reply.
234 */
235#pragma pack(1)
236typedef struct UsbIpRetSubmit
237{
238 /** The reply header. */
239 UsbIpReqRetHdr Hdr;
240 /** Status code. */
241 int32_t u32Status;
242 /** Actual length of the reply buffer. */
243 uint32_t u32ActualLength;
244 /** The actual selected frame for a isochronous transmit. */
245 uint32_t u32StartFrame;
246 /** Number of isochronous packets. */
247 uint32_t u32NumIsocPkts;
248 /** Number of failed isochronous packets. */
249 uint32_t u32ErrorCount;
250 /** Setup data for a control URB. */
251 VUSBSETUP Setup;
252} UsbIpRetSubmit;
253/** Pointer to a submit reply. */
254typedef UsbIpRetSubmit *PUsbIpRetSubmit;
255#pragma pack()
256
257/**
258 * Unlink URB request.
259 */
260#pragma pack(1)
261typedef struct UsbIpReqUnlink
262{
263 /** The request header. */
264 UsbIpReqRetHdr Hdr;
265 /** The sequence number to unlink. */
266 uint32_t u32SeqNum;
267} UsbIpReqUnlink;
268/** Pointer to a URB unlink request. */
269typedef UsbIpReqUnlink *PUsbIpReqUnlink;
270#pragma pack()
271
272/**
273 * Unlink URB reply.
274 */
275#pragma pack(1)
276typedef struct UsbIpRetUnlink
277{
278 /** The reply header. */
279 UsbIpReqRetHdr Hdr;
280 /** Status of the request. */
281 int32_t u32Status;
282} UsbIpRetUnlink;
283/** Pointer to a URB unlink request. */
284typedef UsbIpRetUnlink *PUsbIpRetUnlink;
285#pragma pack()
286
287/**
288 * Union of possible replies from the server during normal operation.
289 */
290#pragma pack(1)
291typedef union UsbIpRet
292{
293 /** The header. */
294 UsbIpReqRetHdr Hdr;
295 /** Submit reply. */
296 UsbIpRetSubmit RetSubmit;
297 /** Unlink reply. */
298 UsbIpRetUnlink RetUnlink;
299 /** Byte view. */
300 uint8_t abReply[1];
301} UsbIpRet;
302/** Pointer to a reply union. */
303typedef UsbIpRet *PUsbIpRet;
304#pragma pack()
305
306/**
307 * Isochronous packet descriptor.
308*/
309#pragma pack(1)
310typedef struct UsbIpIsocPktDesc
311{
312 /** Offset */
313 uint32_t u32Offset;
314 /** Length of the packet including padding. */
315 uint32_t u32Length;
316 /** Size of the transmitted data. */
317 uint32_t u32ActualLength;
318 /** Completion status for this packet. */
319 int32_t i32Status;
320} UsbIpIsocPktDesc;
321/** Pointer to a isochronous packet descriptor. */
322typedef UsbIpIsocPktDesc *PUsbIpIsocPktDesc;
323#pragma pack()
324
325/**
326 * USB/IP backend specific data for one URB.
327 * Required for tracking in flight and landed URBs.
328 */
329typedef struct USBPROXYURBUSBIP
330{
331 /** List node for the in flight or landed URB list. */
332 RTLISTNODE NodeList;
333 /** Sequence number the assigned URB is identified by. */
334 uint32_t u32SeqNumUrb;
335 /** Pointer to the VUSB URB. */
336 PVUSBURB pVUsbUrb;
337} USBPROXYURBUSBIP;
338/** Pointer to a USB/IP URB. */
339typedef USBPROXYURBUSBIP *PUSBPROXYURBUSBIP;
340
341/**
342 * USB/IP data receive states.
343 */
344typedef enum USBPROXYUSBIPRECVSTATE
345{
346 /** Invalid receive state. */
347 USBPROXYUSBIPRECVSTATE_INVALID = 0,
348 /** Currently receiving the common header structure. */
349 USBPROXYUSBIPRECVSTATE_HDR_COMMON,
350 /** Currently receieving the rest of the header structure. */
351 USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL,
352 /** Currently receiving data into the URB buffer. */
353 USBPROXYUSBIPRECVSTATE_URB_BUFFER,
354 /** Currently receiving the isochronous packet descriptors. */
355 USBPROXYUSBIPRECVSTATE_ISOC_PKT_DESCS,
356 /** Usual 32bit hack. */
357 USBPROXYUSBIPRECVSTATE_32BIT_HACK = 0x7fffffff
358} USBPROXYUSBIPRECVSTATE;
359/** Pointer to an receive state. */
360typedef USBPROXYUSBIPRECVSTATE *PUSBPROXYUSBIPRECVSTATE;
361
362/**
363 * Backend data for the USB/IP USB Proxy device backend.
364 */
365typedef struct USBPROXYDEVUSBIP
366{
367 /** IPRT socket handle. */
368 RTSOCKET hSocket;
369 /** Pollset with the wakeup pipe and socket. */
370 RTPOLLSET hPollSet;
371 /** Pipe endpoint - read (in the pollset). */
372 RTPIPE hPipeR;
373 /** Pipe endpoint - write. */
374 RTPIPE hPipeW;
375 /** Next sequence number to use for identifying submitted URBs. */
376 volatile uint32_t u32SeqNumNext;
377 /** Fast mutex protecting the lists below against concurrent access. */
378 RTSEMFASTMUTEX hMtxLists;
379 /** List of in flight URBs. */
380 RTLISTANCHOR ListUrbsInFlight;
381 /** List of landed URBs. */
382 RTLISTANCHOR ListUrbsLanded;
383 /** List of URBs to submit. */
384 RTLISTANCHOR ListUrbsToQueue;
385 /** Port of the USB/IP host to connect to. */
386 uint32_t uPort;
387 /** USB/IP host address. */
388 char *pszHost;
389 /** USB Bus ID of the device to capture. */
390 char *pszBusId;
391 /** The device ID to use to identify the device. */
392 uint32_t u32DevId;
393 /** Temporary buffer for the next reply header */
394 UsbIpRet BufRet;
395 /** Temporary buffer to hold all isochronous packet descriptors. */
396 UsbIpIsocPktDesc aIsocPktDesc[8];
397 /** Pointer to the current buffer to write received data to. */
398 uint8_t *pbRecv;
399 /** Number of bytes received so far. */
400 size_t cbRecv;
401 /** Number of bytes left to receive. until we advance the state machine and process the data */
402 size_t cbLeft;
403 /** The current receiving state. */
404 USBPROXYUSBIPRECVSTATE enmRecvState;
405 /** The URB we currently receive a response for. */
406 PUSBPROXYURBUSBIP pUrbUsbIp;
407} USBPROXYDEVUSBIP, *PUSBPROXYDEVUSBIP;
408
409/** Pollset id of the socket. */
410#define USBIP_POLL_ID_SOCKET 0
411/** Pollset id of the pipe. */
412#define USBIP_POLL_ID_PIPE 1
413
414/** USB/IP address prefix for identifcation. */
415#define USBIP_URI_PREFIX "usbip://"
416/** USB/IP address prefix length. */
417#define USBIP_URI_PREFIX_LEN (sizeof(USBIP_URI_PREFIX) - 1)
418
419/** Waking reason for the USB I/P reaper: New URBs to queue. */
420#define USBIP_REAPER_WAKEUP_REASON_QUEUE 'Q'
421/** Waking reason for the USB I/P reaper: External wakeup. */
422#define USBIP_REAPER_WAKEUP_REASON_EXTERNAL 'E'
423
424/**
425 * Converts a request/reply header from network to host endianness.
426 *
427 * @returns nothing.
428 * @param pHdr The header to convert.
429 */
430DECLINLINE(void) usbProxyUsbIpReqRetHdrN2H(PUsbIpReqRetHdr pHdr)
431{
432 pHdr->u32ReqRet = RT_H2N_U32(pHdr->u32ReqRet);
433 pHdr->u32SeqNum = RT_H2N_U32(pHdr->u32SeqNum);
434 pHdr->u32DevId = RT_H2N_U32(pHdr->u32DevId);
435 pHdr->u32Direction = RT_H2N_U32(pHdr->u32Direction);
436 pHdr->u32Endpoint = RT_H2N_U32(pHdr->u32Endpoint);
437}
438
439/**
440 * Converts a request/reply header from host to network endianness.
441 *
442 * @returns nothing.
443 * @param pHdr The header to convert.
444 */
445DECLINLINE(void) usbProxyUsbIpReqRetHdrH2N(PUsbIpReqRetHdr pHdr)
446{
447 pHdr->u32ReqRet = RT_N2H_U32(pHdr->u32ReqRet);
448 pHdr->u32SeqNum = RT_N2H_U32(pHdr->u32SeqNum);
449 pHdr->u32DevId = RT_N2H_U32(pHdr->u32DevId);
450 pHdr->u32Direction = RT_N2H_U32(pHdr->u32Direction);
451 pHdr->u32Endpoint = RT_N2H_U32(pHdr->u32Endpoint);
452}
453
454/**
455 * Converts a submit request from host to network endianness.
456 *
457 * @returns nothing.
458 * @param pReqSubmit The submit request to convert.
459 */
460DECLINLINE(void) usbProxyUsbIpReqSubmitH2N(PUsbIpReqSubmit pReqSubmit)
461{
462 usbProxyUsbIpReqRetHdrH2N(&pReqSubmit->Hdr);
463 pReqSubmit->u32XferFlags = RT_H2N_U32(pReqSubmit->u32XferFlags);
464 pReqSubmit->u32TransferBufferLength = RT_H2N_U32(pReqSubmit->u32TransferBufferLength);
465 pReqSubmit->u32StartFrame = RT_H2N_U32(pReqSubmit->u32StartFrame);
466 pReqSubmit->u32NumIsocPkts = RT_H2N_U32(pReqSubmit->u32NumIsocPkts);
467 pReqSubmit->u32Interval = RT_H2N_U32(pReqSubmit->u32Interval);
468}
469
470/**
471 * Converts a submit reply from network to host endianness.
472 *
473 * @returns nothing.
474 * @param pReqSubmit The submit reply to convert.
475 */
476DECLINLINE(void) usbProxyUsbIpRetSubmitN2H(PUsbIpRetSubmit pRetSubmit)
477{
478 usbProxyUsbIpReqRetHdrN2H(&pRetSubmit->Hdr);
479 pRetSubmit->u32Status = RT_N2H_U32(pRetSubmit->u32Status);
480 pRetSubmit->u32ActualLength = RT_N2H_U32(pRetSubmit->u32ActualLength);
481 pRetSubmit->u32StartFrame = RT_N2H_U32(pRetSubmit->u32StartFrame);
482 pRetSubmit->u32NumIsocPkts = RT_N2H_U32(pRetSubmit->u32NumIsocPkts);
483 pRetSubmit->u32ErrorCount = RT_N2H_U32(pRetSubmit->u32ErrorCount);
484}
485
486/**
487 * Converts a isochronous packet descriptor from host to network endianness.
488 *
489 * @returns nothing.
490 * @param pIsocPktDesc The packet descriptor to convert.
491 */
492DECLINLINE(void) usbProxyUsbIpIsocPktDescH2N(PUsbIpIsocPktDesc pIsocPktDesc)
493{
494 pIsocPktDesc->u32Offset = RT_H2N_U32(pIsocPktDesc->u32Offset);
495 pIsocPktDesc->u32Length = RT_H2N_U32(pIsocPktDesc->u32Length);
496 pIsocPktDesc->u32ActualLength = RT_H2N_U32(pIsocPktDesc->u32ActualLength);
497 pIsocPktDesc->i32Status = RT_H2N_U32(pIsocPktDesc->i32Status);
498}
499
500/**
501 * Converts a isochronous packet descriptor from network to host endianness.
502 *
503 * @returns nothing.
504 * @param pIsocPktDesc The packet descriptor to convert.
505 */
506DECLINLINE(void) usbProxyUsbIpIsocPktDescN2H(PUsbIpIsocPktDesc pIsocPktDesc)
507{
508 pIsocPktDesc->u32Offset = RT_N2H_U32(pIsocPktDesc->u32Offset);
509 pIsocPktDesc->u32Length = RT_N2H_U32(pIsocPktDesc->u32Length);
510 pIsocPktDesc->u32ActualLength = RT_N2H_U32(pIsocPktDesc->u32ActualLength);
511 pIsocPktDesc->i32Status = RT_N2H_U32(pIsocPktDesc->i32Status);
512}
513
514/**
515 * Converts a unlink request from host to network endianness.
516 *
517 * @returns nothing.
518 * @param pReqUnlink The unlink request to convert.
519 */
520DECLINLINE(void) usbProxyUsbIpReqUnlinkH2N(PUsbIpReqUnlink pReqUnlink)
521{
522 usbProxyUsbIpReqRetHdrH2N(&pReqUnlink->Hdr);
523 pReqUnlink->u32SeqNum = RT_H2N_U32(pReqUnlink->u32SeqNum);
524}
525
526/**
527 * Converts a unlink reply from network to host endianness.
528 *
529 * @returns nothing.
530 * @param pRetUnlink The unlink reply to convert.
531 */
532DECLINLINE(void) usbProxyUsbIpRetUnlinkN2H(PUsbIpRetUnlink pRetUnlink)
533{
534 usbProxyUsbIpReqRetHdrN2H(&pRetUnlink->Hdr);
535 pRetUnlink->u32Status = RT_N2H_U32(pRetUnlink->u32Status);
536}
537
538/**
539 * Convert the given exported device structure from host to network byte order.
540 *
541 * @returns nothing.
542 * @param pDevice The device structure to convert.
543 */
544DECLINLINE(void) usbProxyUsbIpExportedDeviceN2H(PUsbIpExportedDevice pDevice)
545{
546 pDevice->u32BusNum = RT_N2H_U32(pDevice->u32BusNum);
547 pDevice->u32DevNum = RT_N2H_U32(pDevice->u32DevNum);
548 pDevice->u32Speed = RT_N2H_U16(pDevice->u32Speed);
549 pDevice->u16VendorId = RT_N2H_U16(pDevice->u16VendorId);
550 pDevice->u16ProductId = RT_N2H_U16(pDevice->u16ProductId);
551 pDevice->u16BcdDevice = RT_N2H_U16(pDevice->u16BcdDevice);
552}
553
554/**
555 * Converts a USB/IP status code to a VBox status code.
556 *
557 * @returns VUSB status code.
558 * @param i32Status The USB/IP status code from the reply.
559 */
560DECLINLINE(int) usbProxyUsbIpStatusConvertFromStatus(int32_t i32Status)
561{
562 if (RT_LIKELY(i32Status == USBIP_STATUS_SUCCESS))
563 return VINF_SUCCESS;
564
565 switch (i32Status)
566 {
567 case USBIP_STATUS_PIPE_STALLED:
568 return VINF_SUCCESS;
569 default:
570 return VERR_INVALID_STATE;
571 }
572
573 return VERR_INVALID_STATE;
574}
575
576/**
577 * Converts a USB/IP status code to a VUSB status code.
578 *
579 * @returns VUSB status code.
580 * @param i32Status The USB/IP status code from the reply.
581 */
582DECLINLINE(VUSBSTATUS) usbProxyUsbIpVUsbStatusConvertFromStatus(int32_t i32Status)
583{
584 if (RT_LIKELY(i32Status == USBIP_STATUS_SUCCESS))
585 return VUSBSTATUS_OK;
586
587 switch (i32Status)
588 {
589 case USBIP_STATUS_PIPE_STALLED:
590 return VUSBSTATUS_STALL;
591 default:
592 return VUSBSTATUS_DNR;
593 }
594
595 return VUSBSTATUS_DNR;
596}
597
598/**
599 * Gets the next free sequence number.
600 *
601 * @returns Next free sequence number.
602 * @param pProxyDevUsbIp The USB/IP proxy device data.
603 */
604DECLINLINE(uint32_t) usbProxyUsbIpSeqNumGet(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
605{
606 return ASMAtomicIncU32(&pProxyDevUsbIp->u32SeqNumNext);
607}
608
609/**
610 * Links a given URB into the given list.
611 *
612 * @returns nothing.
613 * @param pProxyDevUsbIp The USB/IP proxy device data.
614 * @param pList The list to link the URB into.
615 * @param pUrbUsbIp The URB to link.
616 */
617DECLINLINE(void) usbProxyUsbIpLinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PRTLISTANCHOR pList, PUSBPROXYURBUSBIP pUrbUsbIp)
618{
619 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
620 AssertRC(rc);
621 RTListAppend(pList, &pUrbUsbIp->NodeList);
622 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
623}
624
625/**
626 * Unlinks a given URB from the current assigned list.
627 *
628 * @returns nothing.
629 * @param pProxyDevUsbIp The USB/IP proxy device data.
630 * @param pUrbUsbIp The URB to unlink.
631 */
632DECLINLINE(void) usbProxyUsbIpUnlinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
633{
634 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
635 AssertRC(rc);
636 RTListNodeRemove(&pUrbUsbIp->NodeList);
637 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
638}
639
640/**
641 * Allocates a USB/IP proxy specific URB state.
642 *
643 * @returns Pointer to the USB/IP specific URB data or NULL on failure.
644 * @param pProxyDevUsbIp The USB/IP proxy device data.
645 */
646static PUSBPROXYURBUSBIP usbProxyUsbIpUrbAlloc(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
647{
648 NOREF(pProxyDevUsbIp);
649 return (PUSBPROXYURBUSBIP)RTMemAllocZ(sizeof(USBPROXYURBUSBIP));
650}
651
652/**
653 * Frees the given USB/IP URB state.
654 *
655 * @returns nothing.
656 * @param pProxyDevUsbIp The USB/IP proxy device data.
657 * @param pUrbUsbIp The USB/IP speciic URB data.
658 */
659static void usbProxyUsbIpUrbFree(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
660{
661 NOREF(pProxyDevUsbIp);
662 RTMemFree(pUrbUsbIp);
663}
664
665/**
666 * Parse the string representation of the host address.
667 *
668 * @returns VBox status code.
669 * @param pProxyDevUsbIp The USB/IP proxy device data to parse the address for.
670 * @param pszAddress The address string to parse.
671 */
672static int usbProxyUsbIpParseAddress(PUSBPROXYDEVUSBIP pProxyDevUsbIp, const char *pszAddress)
673{
674 int rc = VINF_SUCCESS;
675
676 if (!RTStrNCmp(pszAddress, USBIP_URI_PREFIX, USBIP_URI_PREFIX_LEN))
677 {
678 pszAddress += USBIP_URI_PREFIX_LEN;
679
680 const char *pszPortStart = RTStrStr(pszAddress, ":");
681 if (pszPortStart)
682 {
683 pszPortStart++;
684
685 const char *pszBusIdStart = RTStrStr(pszPortStart, ":");
686 if (pszBusIdStart)
687 {
688 size_t cbHost = pszPortStart - pszAddress - 1;
689 size_t cbBusId = strlen(pszBusIdStart);
690
691 pszBusIdStart++;
692
693 rc = RTStrToUInt32Ex(pszPortStart, NULL, 10 /* uBase */, &pProxyDevUsbIp->uPort);
694 if ( rc == VINF_SUCCESS
695 || rc == VWRN_TRAILING_CHARS)
696 {
697 rc = RTStrAllocEx(&pProxyDevUsbIp->pszHost, cbHost + 1);
698 if (RT_SUCCESS(rc))
699 rc = RTStrAllocEx(&pProxyDevUsbIp->pszBusId, cbBusId + 1);
700 if (RT_SUCCESS(rc))
701 {
702 rc = RTStrCopyEx(pProxyDevUsbIp->pszHost, cbHost + 1, pszAddress, cbHost);
703 AssertRC(rc);
704
705 rc = RTStrCopyEx(pProxyDevUsbIp->pszBusId, cbBusId + 1, pszBusIdStart, cbBusId);
706 AssertRC(rc);
707
708 return VINF_SUCCESS;
709 }
710 }
711 else
712 rc = VERR_INVALID_PARAMETER;
713 }
714 else
715 rc = VERR_INVALID_PARAMETER;
716 }
717 else
718 rc = VERR_INVALID_PARAMETER;
719 }
720 else
721 rc = VERR_INVALID_PARAMETER;
722
723 return rc;
724}
725
726/**
727 * Connects to the USB/IP host and claims the device given in the proxy device data.
728 *
729 * @returns VBox status.
730 * @param pProxyDevUsbIp The USB/IP proxy device data.
731 */
732static int usbProxyUsbIpConnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
733{
734 int rc = VINF_SUCCESS;
735 rc = RTTcpClientConnect(pProxyDevUsbIp->pszHost, pProxyDevUsbIp->uPort, &pProxyDevUsbIp->hSocket);
736 if (RT_SUCCESS(rc))
737 {
738 /* Disable send coalescing. */
739 rc = RTTcpSetSendCoalescing(pProxyDevUsbIp->hSocket, false);
740 if (RT_FAILURE(rc))
741 LogRel(("UsbIp: Disabling send coalescing failed (rc=%Rrc), continuing nevertheless but expect reduced performance\n", rc));
742
743 /* Import the device, i.e. claim it for our use. */
744 UsbIpReqImport ReqImport;
745 ReqImport.u16Version = RT_H2N_U16(USBIP_VERSION);
746 ReqImport.u16Cmd = RT_H2N_U16(USBIP_INDICATOR_REQ | USBIP_REQ_RET_IMPORT);
747 ReqImport.u32Status = RT_H2N_U32(USBIP_STATUS_SUCCESS);
748 rc = RTStrCopy(&ReqImport.aszBusId[0], sizeof(ReqImport.aszBusId), pProxyDevUsbIp->pszBusId);
749 if (rc == VINF_SUCCESS)
750 {
751 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqImport, sizeof(ReqImport));
752 if (RT_SUCCESS(rc))
753 {
754 /* Read the reply. */
755 UsbIpRetImport RetImport;
756 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &RetImport, sizeof(RetImport), NULL);
757 if (RT_SUCCESS(rc))
758 {
759 RetImport.u16Version = RT_N2H_U16(RetImport.u16Version);
760 RetImport.u16Cmd = RT_N2H_U16(RetImport.u16Cmd);
761 RetImport.u32Status = RT_N2H_U32(RetImport.u32Status);
762 if ( RetImport.u16Version == USBIP_VERSION
763 && RetImport.u16Cmd == USBIP_REQ_RET_IMPORT
764 && RetImport.u32Status == USBIP_STATUS_SUCCESS)
765 {
766 /* Read the device data. */
767 UsbIpExportedDevice Device;
768 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &Device, sizeof(Device), NULL);
769 if (RT_SUCCESS(rc))
770 {
771 usbProxyUsbIpExportedDeviceN2H(&Device);
772 pProxyDevUsbIp->u32DevId = (Device.u32BusNum << 16) | Device.u32DevNum;
773
774 rc = RTPollSetAddSocket(pProxyDevUsbIp->hPollSet, pProxyDevUsbIp->hSocket,
775 RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, USBIP_POLL_ID_SOCKET);
776 }
777 }
778 else
779 {
780 /* Check what went wrong and leave a meaningful error message in the log. */
781 if (RetImport.u16Version != USBIP_VERSION)
782 LogRel(("UsbIp: Unexpected protocol version received from host (%#x vs. %#x)\n",
783 RetImport.u16Version, USBIP_VERSION));
784 else if (RetImport.u16Cmd != USBIP_REQ_RET_IMPORT)
785 LogRel(("UsbIp: Unexpected reply code received from host (%#x vs. %#x)\n",
786 RetImport.u16Cmd, USBIP_REQ_RET_IMPORT));
787 else if (RetImport.u32Status != 0)
788 LogRel(("UsbIp: Claiming the device has failed on the host with an unspecified error\n"));
789 else
790 AssertMsgFailed(("Something went wrong with if condition\n"));
791 }
792 }
793 }
794 }
795 else
796 {
797 LogRel(("UsbIp: Given bus ID is exceeds permitted protocol length: %u vs %u\n",
798 strlen(pProxyDevUsbIp->pszBusId) + 1, sizeof(ReqImport.aszBusId)));
799 rc = VERR_INVALID_PARAMETER;
800 }
801
802 if (RT_FAILURE(rc))
803 RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
804 }
805 if (RT_FAILURE(rc))
806 LogRel(("UsbIp: Connecting to the host %s failed with %Rrc\n", pProxyDevUsbIp->pszHost, rc));
807 return rc;
808}
809
810/**
811 * Disconnects from the USB/IP host releasing the device given in the proxy device data.
812 *
813 * @returns VBox status code.
814 * @param pProxyDevUsbIp The USB/IP proxy device data.
815 */
816static int usbProxyUsbIpDisconnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
817{
818 int rc = VINF_SUCCESS;
819
820 rc = RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
821 if (RT_SUCCESS(rc))
822 pProxyDevUsbIp->hSocket = NIL_RTSOCKET;
823 return rc;
824}
825
826/**
827 * Synchronously exchange a given control message with the remote device.
828 *
829 * @eturns VBox status code.
830 * @param pProxyDevUsbIp The USB/IP proxy device data.
831 * @param pSetup The setup message.
832 *
833 * @note This method is only used to implement the *SetConfig, *SetInterface and *ClearHaltedEp
834 * callbacks because the USB/IP protocol lacks dedicated requests for these.
835 * @remark It is assumed that this method is never called while usbProxyUsbIpUrbReap is called
836 * on another thread.
837 */
838static int usbProxyUsbIpCtrlUrbExchangeSync(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PVUSBSETUP pSetup)
839{
840 int rc = VINF_SUCCESS;
841
842 UsbIpReqSubmit ReqSubmit;
843 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
844 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
845 ReqSubmit.Hdr.u32SeqNum = u32SeqNum;
846 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
847 ReqSubmit.Hdr.u32Direction = USBIP_DIR_OUT;
848 ReqSubmit.Hdr.u32Endpoint = 0; /* Only default control endpoint is allowed for these kind of messages. */
849 ReqSubmit.u32XferFlags = 0;
850 ReqSubmit.u32TransferBufferLength = 0;
851 ReqSubmit.u32StartFrame = 0;
852 ReqSubmit.u32NumIsocPkts = 0;
853 ReqSubmit.u32Interval = 0;
854 memcpy(&ReqSubmit.Setup, pSetup, sizeof(ReqSubmit.Setup));
855 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
856
857 /* Send the command. */
858 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqSubmit, sizeof(ReqSubmit));
859 if (RT_SUCCESS(rc))
860 {
861 /* Wait for the response. */
862 /** @todo: Don't wait indefinitely long. */
863 UsbIpRetSubmit RetSubmit;
864 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &RetSubmit, sizeof(RetSubmit), NULL);
865 if (RT_SUCCESS(rc))
866 {
867 usbProxyUsbIpRetSubmitN2H(&RetSubmit);
868 rc = usbProxyUsbIpStatusConvertFromStatus(RetSubmit.u32Status);
869 }
870 }
871 return rc;
872}
873
874/**
875 * Returns the URB matching the given sequence number from the in flight list.
876 *
877 * @returns pointer to the URB matching the given sequence number or NULL
878 * @param pProxyDevUsbIp The USB/IP proxy device data.
879 * @param u32SeqNum The sequence number to search for.
880 */
881static PUSBPROXYURBUSBIP usbProxyUsbIpGetUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
882{
883 bool fFound = false;
884 PUSBPROXYURBUSBIP pIt;
885
886 RTListForEach(&pProxyDevUsbIp->ListUrbsInFlight, pIt, USBPROXYURBUSBIP, NodeList)
887 {
888 if (pIt->u32SeqNumUrb == u32SeqNum)
889 {
890 fFound = true;
891 break;
892 }
893 }
894
895 return fFound ? pIt : NULL;
896}
897
898/**
899 * Resets the receive state for a new reply.
900 *
901 * @returns nothing.
902 * @param pProxyDevUsbIp The USB/IP proxy device data.
903 */
904static void usbProxyUsbIpResetRecvState(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
905{
906 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_COMMON;
907 pProxyDevUsbIp->pbRecv = (uint8_t *)&pProxyDevUsbIp->BufRet;
908 pProxyDevUsbIp->cbRecv = 0;
909 pProxyDevUsbIp->cbLeft = sizeof(UsbIpReqRetHdr);
910}
911
912static void usbProxyUsbIpRecvStateAdvance(PUSBPROXYDEVUSBIP pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE enmState,
913 uint8_t *pbData, size_t cbData)
914{
915 pProxyDevUsbIp->enmRecvState = enmState;
916 pProxyDevUsbIp->cbRecv = 0;
917 pProxyDevUsbIp->cbLeft = cbData;
918 pProxyDevUsbIp->pbRecv = pbData;
919}
920
921/**
922 * Handles reception of a USB/IP PDU.
923 *
924 * @returns VBox status code.
925 * @param pProxyDevUsbIp The USB/IP proxy device data.
926 * @param ppUrbUsbIp Where to store the pointer to the USB/IP URB which completed.
927 * Will be NULL if the received PDU is not complete and we have
928 * have to wait for more data or on failure.
929 */
930static int usbProxyUsbIpRecvPdu(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP *ppUrbUsbIp)
931{
932 int rc = VINF_SUCCESS;
933 size_t cbRead = 0;
934 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
935
936 Assert(pProxyDevUsbIp->cbLeft);
937
938 /* Read any available data first. */
939 rc = RTTcpReadNB(pProxyDevUsbIp->hSocket, pProxyDevUsbIp->pbRecv, pProxyDevUsbIp->cbLeft, &cbRead);
940 if (RT_SUCCESS(rc))
941 {
942 pProxyDevUsbIp->cbRecv += cbRead;
943 pProxyDevUsbIp->cbLeft -= cbRead;
944 pProxyDevUsbIp->pbRecv += cbRead;
945
946 /* Process the received data if there is nothing to receive left for the current state. */
947 if (!pProxyDevUsbIp->cbLeft)
948 {
949 switch (pProxyDevUsbIp->enmRecvState)
950 {
951 case USBPROXYUSBIPRECVSTATE_HDR_COMMON:
952 {
953 Assert(pProxyDevUsbIp->cbRecv == sizeof(UsbIpReqRetHdr));
954
955 /*
956 * Determine the residual amount of data to receive until
957 * the complete reply header was received.
958 */
959 switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
960 {
961 case USBIP_RET_SUBMIT:
962 pProxyDevUsbIp->cbLeft = sizeof(UsbIpRetSubmit) - sizeof(UsbIpReqRetHdr);
963 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL;
964 break;
965 case USBIP_RET_UNLINK:
966 pProxyDevUsbIp->cbLeft = sizeof(UsbIpRetUnlink) - sizeof(UsbIpReqRetHdr);
967 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL;
968 break;
969 default:
970 AssertLogRelMsgFailed(("Invalid reply header received: %d\n",
971 pProxyDevUsbIp->BufRet.Hdr.u32ReqRet));
972 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
973 }
974
975 break;
976 }
977 case USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL:
978 {
979 /* Get the URB from the in flight list. */
980 pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
981 if (pProxyDevUsbIp->pUrbUsbIp)
982 {
983 /** @todo: Verify that the directions match, verify that the length doesn't exceed the buffer. */
984
985 switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
986 {
987 case USBIP_RET_SUBMIT:
988 usbProxyUsbIpRetSubmitN2H(&pProxyDevUsbIp->BufRet.RetSubmit);
989
990 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetSubmit.u32Status);
991 if ( pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmDir == VUSBDIRECTION_IN
992 && pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmStatus == VUSBSTATUS_OK)
993 {
994 uint8_t *pbData = NULL;
995
996 if (pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmType == VUSBXFERTYPE_MSG)
997 {
998 /* Preserve the setup request. */
999 pbData = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->abData[sizeof(VUSBSETUP)];
1000 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength + sizeof(VUSBSETUP);
1001 }
1002 else
1003 {
1004 pbData = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->abData[0];
1005 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength;
1006 }
1007
1008 usbProxyUsbIpRecvStateAdvance(pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE_URB_BUFFER,
1009 pbData, pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength);
1010 }
1011 else
1012 {
1013 Assert( pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmDir == VUSBDIRECTION_OUT
1014 || pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmStatus != VUSBSTATUS_OK);
1015 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1016 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1017 }
1018 break;
1019 case USBIP_RET_UNLINK:
1020 usbProxyUsbIpRetUnlinkN2H(&pProxyDevUsbIp->BufRet.RetUnlink);
1021 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1022 pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetUnlink.u32Status);
1023 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1024 break;
1025 }
1026 }
1027 else
1028 {
1029 LogRel(("USB/IP: Received reply with sequence number doesn't match any local URB\n", pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
1030 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1031 }
1032
1033 break;
1034 }
1035 case USBPROXYUSBIPRECVSTATE_URB_BUFFER:
1036 if (pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmType == VUSBXFERTYPE_ISOC)
1037 usbProxyUsbIpRecvStateAdvance(pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE_ISOC_PKT_DESCS,
1038 (uint8_t *)&pProxyDevUsbIp->aIsocPktDesc[0],
1039 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cIsocPkts * sizeof(UsbIpIsocPktDesc));
1040 else
1041 {
1042 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1043 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1044 }
1045 break;
1046 case USBPROXYUSBIPRECVSTATE_ISOC_PKT_DESCS:
1047 /* Process all received isochronous packet descriptors. */
1048 for (unsigned i = 0; i < pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cIsocPkts; i++)
1049 {
1050 PVUSBURBISOCPTK pIsocPkt = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->aIsocPkts[i];
1051 usbProxyUsbIpIsocPktDescN2H(&pProxyDevUsbIp->aIsocPktDesc[i]);
1052 pIsocPkt->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->aIsocPktDesc[i].i32Status);
1053 pIsocPkt->off = pProxyDevUsbIp->aIsocPktDesc[i].u32Offset;
1054 pIsocPkt->cb = pProxyDevUsbIp->aIsocPktDesc[i].u32ActualLength;
1055 }
1056
1057 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1058 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1059 break;
1060 default:
1061 AssertLogRelMsgFailed(("USB/IP: Invalid receive state %d\n", pProxyDevUsbIp->enmRecvState));
1062 }
1063 }
1064 }
1065 else
1066 {
1067 /** @todo: Complete all URBs with DNR error and mark device as unplugged. */
1068#if 0
1069 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1070 pUrbUsbIp->pVUsbUrb->enmStatus = VUSBSTATUS_DNR;
1071 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1072#endif
1073 }
1074
1075 if (RT_SUCCESS(rc))
1076 *ppUrbUsbIp = pUrbUsbIp;
1077
1078 return rc;
1079}
1080
1081/**
1082 * Worker for queueing an URB on the main I/O thread.
1083 *
1084 * @returns VBox status code.
1085 * @param pProxyDevUsbIp The USB/IP proxy device data.
1086 * @param pUrbUsbIp The USB/IP URB to queue.
1087 */
1088static int usbProxyUsbIpUrbQueueWorker(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
1089{
1090 PVUSBURB pUrb = pUrbUsbIp->pVUsbUrb;
1091
1092 pUrbUsbIp->u32SeqNumUrb = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1093
1094 UsbIpReqSubmit ReqSubmit;
1095 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
1096 ReqSubmit.Hdr.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1097 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1098 ReqSubmit.Hdr.u32Endpoint = pUrb->EndPt;
1099 ReqSubmit.Hdr.u32Direction = pUrb->enmDir == VUSBDIRECTION_IN ? USBIP_DIR_IN : USBIP_DIR_OUT;
1100 ReqSubmit.u32XferFlags = 0;
1101 if (pUrb->enmDir == VUSBDIRECTION_IN && pUrb->fShortNotOk)
1102 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_SHORT_NOT_OK;
1103
1104 ReqSubmit.u32TransferBufferLength = pUrb->cbData;
1105 ReqSubmit.u32StartFrame = 0;
1106 ReqSubmit.u32NumIsocPkts = 0;
1107 ReqSubmit.u32Interval = 0;
1108
1109 RTSGSEG aSegReq[3]; /* Maximum number of segments used for a Isochronous transfer. */
1110 UsbIpIsocPktDesc aIsocPktsDesc[8];
1111 unsigned cSegsUsed = 1;
1112 aSegReq[0].pvSeg = &ReqSubmit;
1113 aSegReq[0].cbSeg = sizeof(ReqSubmit);
1114
1115
1116 switch (pUrb->enmType)
1117 {
1118 case VUSBXFERTYPE_MSG:
1119 memcpy(&ReqSubmit.Setup, &pUrb->abData, sizeof(ReqSubmit.Setup));
1120 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1121 {
1122 ReqSubmit.u32TransferBufferLength -= sizeof(VUSBSETUP);
1123 aSegReq[cSegsUsed].cbSeg = pUrb->cbData - sizeof(VUSBSETUP);
1124 aSegReq[cSegsUsed].pvSeg = pUrb->abData + sizeof(VUSBSETUP);
1125 cSegsUsed++;
1126 }
1127 LogFlowFunc(("Message (Control) URB\n"));
1128 break;
1129 case VUSBXFERTYPE_ISOC:
1130 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_ISO_ASAP;
1131 ReqSubmit.u32NumIsocPkts = pUrb->cIsocPkts;
1132 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1133 {
1134 aSegReq[cSegsUsed].cbSeg = pUrb->cbData;
1135 aSegReq[cSegsUsed].pvSeg = pUrb->abData;
1136 cSegsUsed++;
1137 }
1138
1139 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
1140 {
1141 aIsocPktsDesc[i].u32Offset = pUrb->aIsocPkts[i].off;
1142 aIsocPktsDesc[i].u32Length = pUrb->aIsocPkts[i].cb;
1143 aIsocPktsDesc[i].u32ActualLength = 0; /** @todo */
1144 aIsocPktsDesc[i].i32Status = pUrb->aIsocPkts[i].enmStatus;
1145 usbProxyUsbIpIsocPktDescH2N(&aIsocPktsDesc[i]);
1146 }
1147
1148 if (pUrb->cIsocPkts)
1149 {
1150 aSegReq[cSegsUsed].cbSeg = pUrb->cIsocPkts * sizeof(UsbIpIsocPktDesc);
1151 aSegReq[cSegsUsed].pvSeg = &aIsocPktsDesc[0];
1152 cSegsUsed++;
1153 }
1154
1155 break;
1156 case VUSBXFERTYPE_BULK:
1157 case VUSBXFERTYPE_INTR:
1158 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1159 {
1160 aSegReq[cSegsUsed].cbSeg = pUrb->cbData;
1161 aSegReq[cSegsUsed].pvSeg = pUrb->abData;
1162 cSegsUsed++;
1163 }
1164 break;
1165 default:
1166 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1167 return VERR_INVALID_PARAMETER; /** @todo: better status code. */
1168 }
1169
1170 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
1171
1172 Assert(cSegsUsed <= RT_ELEMENTS(aSegReq));
1173
1174 /* Send the command. */
1175 RTSGBUF SgBufReq;
1176 RTSgBufInit(&SgBufReq, &aSegReq[0], cSegsUsed);
1177
1178 int rc = RTTcpSgWrite(pProxyDevUsbIp->hSocket, &SgBufReq);
1179 if (RT_SUCCESS(rc))
1180 {
1181 /* Link the URB into the list of in flight URBs. */
1182 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsInFlight, pUrbUsbIp);
1183 }
1184
1185 return rc;
1186}
1187
1188/**
1189 * Queues all pending URBs from the list.
1190 *
1191 * @returns VBox status code.
1192 * @param pProxyDevUsbIp The USB/IP proxy device data.
1193 */
1194static int usbProxyUsbIpUrbsQueuePending(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
1195{
1196 RTLISTANCHOR ListUrbsPending;
1197
1198 RTListInit(&ListUrbsPending);
1199 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1200 AssertRC(rc);
1201 RTListMove(&ListUrbsPending, &pProxyDevUsbIp->ListUrbsToQueue);
1202 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1203
1204 PUSBPROXYURBUSBIP pIter = NULL;
1205 PUSBPROXYURBUSBIP pIterNext = NULL;
1206 RTListForEachSafe(&ListUrbsPending, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1207 {
1208 RTListNodeRemove(&pIter->NodeList);
1209 rc = usbProxyUsbIpUrbQueueWorker(pProxyDevUsbIp, pIter);
1210 if (RT_FAILURE(rc))
1211 {
1212 /** @todo: Complete the URB with an error. */
1213 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pIter);
1214 }
1215 }
1216
1217 return VINF_SUCCESS;
1218}
1219
1220/**
1221 * Kick the reaper thread.
1222 *
1223 * @returns VBox status code.
1224 * @param pProxyDevUsbIp The USB/IP proxy device data.
1225 * @param bReason The wakeup reason.
1226 */
1227static char usbProxyReaperKick(PUSBPROXYDEVUSBIP pProxyDevUsbIp, char bReason)
1228{
1229 int rc = VINF_SUCCESS;
1230 size_t cbWritten = 0;
1231
1232 rc = RTPipeWrite(pProxyDevUsbIp->hPipeW, &bReason, 1, &cbWritten);
1233 Assert(RT_SUCCESS(rc) || cbWritten == 0);
1234
1235 return rc;
1236}
1237
1238/**
1239 * Drain the wakeup pipe.
1240 *
1241 * @returns Wakeup reason.
1242 * @param pProxyDevUsbIp The USB/IP proxy device data.
1243 */
1244static char usbProxyUsbIpWakeupPipeDrain(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
1245{
1246 char bRead = 0;
1247 size_t cbRead = 0;
1248
1249 int rc = RTPipeRead(pProxyDevUsbIp->hPipeR, &bRead, 1, &cbRead);
1250 Assert(RT_SUCCESS(rc) && cbRead == 1);
1251
1252 return bRead;
1253}
1254
1255/*
1256 * The USB proxy device functions.
1257 */
1258
1259static DECLCALLBACK(int) usbProxyUsbIpOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
1260{
1261 LogFlowFunc(("pProxyDev=%p pszAddress=%s, pvBackend=%p\n", pProxyDev, pszAddress, pvBackend));
1262
1263 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1264 int rc = VINF_SUCCESS;
1265
1266 RTListInit(&pDevUsbIp->ListUrbsInFlight);
1267 RTListInit(&pDevUsbIp->ListUrbsLanded);
1268 RTListInit(&pDevUsbIp->ListUrbsToQueue);
1269 pDevUsbIp->hSocket = NIL_RTSOCKET;
1270 pDevUsbIp->hPollSet = NIL_RTPOLLSET;
1271 pDevUsbIp->hPipeW = NIL_RTPIPE;
1272 pDevUsbIp->hPipeR = NIL_RTPIPE;
1273 pDevUsbIp->u32SeqNumNext = 0;
1274 pDevUsbIp->pszHost = NULL;
1275 pDevUsbIp->pszBusId = NULL;
1276 usbProxyUsbIpResetRecvState(pDevUsbIp);
1277
1278 pProxyDev->iActiveCfg = 1; /** @todo that may not be always true. */
1279 pProxyDev->cIgnoreSetConfigs = 1;
1280
1281 rc = RTSemFastMutexCreate(&pDevUsbIp->hMtxLists);
1282 if (RT_SUCCESS(rc))
1283 {
1284 /* Setup wakeup pipe and poll set first. */
1285 rc = RTPipeCreate(&pDevUsbIp->hPipeR, &pDevUsbIp->hPipeW, 0);
1286 if (RT_SUCCESS(rc))
1287 {
1288 rc = RTPollSetCreate(&pDevUsbIp->hPollSet);
1289 if (RT_SUCCESS(rc))
1290 {
1291 rc = RTPollSetAddPipe(pDevUsbIp->hPollSet, pDevUsbIp->hPipeR,
1292 RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE);
1293 if (RT_SUCCESS(rc))
1294 {
1295 /* Connect to the USB/IP host. */
1296 rc = usbProxyUsbIpParseAddress(pDevUsbIp, pszAddress);
1297 if (RT_SUCCESS(rc))
1298 rc = usbProxyUsbIpConnect(pDevUsbIp);
1299 }
1300
1301 if (RT_FAILURE(rc))
1302 {
1303 RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
1304 int rc2 = RTPollSetDestroy(pDevUsbIp->hPollSet);
1305 AssertRC(rc2);
1306 }
1307 }
1308
1309 if (RT_FAILURE(rc))
1310 {
1311 int rc2 = RTPipeClose(pDevUsbIp->hPipeR);
1312 AssertRC(rc2);
1313 rc2 = RTPipeClose(pDevUsbIp->hPipeW);
1314 AssertRC(rc2);
1315 }
1316 }
1317 }
1318
1319 return rc;
1320}
1321
1322static DECLCALLBACK(void) usbProxyUsbIpClose(PUSBPROXYDEV pProxyDev)
1323{
1324 int rc = VINF_SUCCESS;
1325 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
1326
1327 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1328 /* Destroy the pipe and pollset if necessary. */
1329 if (pDevUsbIp->hPollSet != NIL_RTPOLLSET)
1330 {
1331 if (pDevUsbIp->hSocket != NIL_RTSOCKET)
1332 {
1333 rc = RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_SOCKET);
1334 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
1335 }
1336 rc = RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
1337 AssertRC(rc);
1338 rc = RTPollSetDestroy(pDevUsbIp->hPollSet);
1339 AssertRC(rc);
1340 rc = RTPipeClose(pDevUsbIp->hPipeR);
1341 AssertRC(rc);
1342 rc = RTPipeClose(pDevUsbIp->hPipeW);
1343 AssertRC(rc);
1344 }
1345
1346 if (pDevUsbIp->hSocket != NIL_RTSOCKET)
1347 usbProxyUsbIpDisconnect(pDevUsbIp);
1348 if (pDevUsbIp->pszHost)
1349 RTStrFree(pDevUsbIp->pszHost);
1350 if (pDevUsbIp->pszBusId)
1351 RTStrFree(pDevUsbIp->pszBusId);
1352
1353 /* Clear the URB lists. */
1354 rc = RTSemFastMutexRequest(pDevUsbIp->hMtxLists);
1355 AssertRC(rc);
1356 PUSBPROXYURBUSBIP pIter = NULL;
1357 PUSBPROXYURBUSBIP pIterNext = NULL;
1358 RTListForEachSafe(&pDevUsbIp->ListUrbsInFlight, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1359 {
1360 RTListNodeRemove(&pIter->NodeList);
1361 RTMemFree(pIter);
1362 }
1363
1364 RTListForEachSafe(&pDevUsbIp->ListUrbsLanded, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1365 {
1366 RTListNodeRemove(&pIter->NodeList);
1367 RTMemFree(pIter);
1368 }
1369 RTSemFastMutexRelease(pDevUsbIp->hMtxLists);
1370 RTSemFastMutexDestroy(pDevUsbIp->hMtxLists);
1371}
1372
1373static DECLCALLBACK(int) usbProxyUsbIpReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
1374{
1375 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
1376
1377 int rc = VINF_SUCCESS;
1378 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1379 VUSBSETUP Setup;
1380
1381 if (fResetOnLinux)
1382 {
1383 Setup.bmRequestType = RT_BIT(5) | 0x03; /* Port request. */
1384 Setup.bRequest = 0x03; /* SET_FEATURE */
1385 Setup.wValue = 4; /* Port feature: Reset */
1386 Setup.wIndex = 0; /* Port number, irrelevant */
1387 Setup.wLength = 0;
1388 rc = usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1389 if (RT_SUCCESS(rc))
1390 {
1391 pProxyDev->iActiveCfg = -1;
1392 pProxyDev->cIgnoreSetConfigs = 2;
1393 }
1394 }
1395
1396 return rc;
1397}
1398
1399static DECLCALLBACK(int) usbProxyUsbIpSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
1400{
1401 LogFlowFunc(("pProxyDev=%s cfg=%#x\n", pProxyDev->pUsbIns->pszName, iCfg));
1402
1403 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1404 VUSBSETUP Setup;
1405
1406 Setup.bmRequestType = 0;
1407 Setup.bRequest = 0x09;
1408 Setup.wValue = iCfg;
1409 Setup.wIndex = 0;
1410 Setup.wLength = 0;
1411 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1412}
1413
1414static DECLCALLBACK(int) usbProxyUsbIpClaimInterface(PUSBPROXYDEV pProxyDev, int ifnum)
1415{
1416 LogFlowFunc(("pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, ifnum));
1417 return VINF_SUCCESS;
1418}
1419
1420static DECLCALLBACK(int) usbProxyUsbIpReleaseInterface(PUSBPROXYDEV pProxyDev, int ifnum)
1421{
1422 LogFlowFunc(("pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, ifnum));
1423 return VINF_SUCCESS;
1424}
1425
1426static DECLCALLBACK(int) usbProxyUsbIpSetInterface(PUSBPROXYDEV pProxyDev, int ifnum, int setting)
1427{
1428 LogFlowFunc(("pProxyDev=%p ifnum=%#x setting=%#x\n", pProxyDev, ifnum, setting));
1429
1430 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1431 VUSBSETUP Setup;
1432
1433 Setup.bmRequestType = 0x1;
1434 Setup.bRequest = 0x0b; /* SET_INTERFACE */
1435 Setup.wValue = setting;
1436 Setup.wIndex = ifnum;
1437 Setup.wLength = 0;
1438 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1439}
1440
1441static DECLCALLBACK(int) usbProxyUsbIpClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int iEp)
1442{
1443 LogFlowFunc(("pProxyDev=%s ep=%u\n", pProxyDev->pUsbIns->pszName, iEp));
1444
1445 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1446 VUSBSETUP Setup;
1447
1448 Setup.bmRequestType = 0x2;
1449 Setup.bRequest = 0x01; /* CLEAR_FEATURE */
1450 Setup.wValue = 0x00; /* ENDPOINT_HALT */
1451 Setup.wIndex = iEp;
1452 Setup.wLength = 0;
1453 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1454}
1455
1456static DECLCALLBACK(int) usbProxyUsbIpUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1457{
1458 LogFlowFunc(("pUrb=%p\n", pUrb));
1459
1460 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1461
1462 /* Allocate a USB/IP Urb. */
1463 PUSBPROXYURBUSBIP pUrbUsbIp = usbProxyUsbIpUrbAlloc(pProxyDevUsbIp);
1464 if (!pUrbUsbIp)
1465 return VERR_NO_MEMORY;
1466
1467 pUrbUsbIp->pVUsbUrb = pUrb;
1468 pUrb->Dev.pvPrivate = pUrbUsbIp;
1469
1470 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1471 AssertRC(rc);
1472 RTListAppend(&pProxyDevUsbIp->ListUrbsToQueue, &pUrbUsbIp->NodeList);
1473 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1474
1475 return usbProxyReaperKick(pProxyDevUsbIp, USBIP_REAPER_WAKEUP_REASON_QUEUE);
1476}
1477
1478static DECLCALLBACK(PVUSBURB) usbProxyUsbIpUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
1479{
1480 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1481
1482 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1483 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
1484 PVUSBURB pUrb = NULL;
1485 int rc = VINF_SUCCESS;
1486
1487 /* Queue new URBs first. */
1488 rc = usbProxyUsbIpUrbsQueuePending(pProxyDevUsbIp);
1489 AssertRC(rc);
1490
1491 /* Any URBs pending delivery? */
1492 if (!RTListIsEmpty(&pProxyDevUsbIp->ListUrbsLanded))
1493 pUrbUsbIp = RTListGetFirst(&pProxyDevUsbIp->ListUrbsLanded, USBPROXYURBUSBIP, NodeList);
1494
1495 while (!pUrbUsbIp && RT_SUCCESS(rc) && cMillies)
1496 {
1497 uint32_t uIdReady = 0;
1498 uint32_t fEventsRecv = 0;
1499 RTMSINTERVAL msStart = RTTimeMilliTS();
1500 RTMSINTERVAL msNow;
1501
1502 rc = RTPoll(pProxyDevUsbIp->hPollSet, cMillies, &fEventsRecv, &uIdReady);
1503 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1504 if (RT_SUCCESS(rc))
1505 {
1506 msNow = RTTimeMilliTS();
1507 cMillies = msNow - msStart >= cMillies ? 0 : cMillies - (msNow - msStart);
1508
1509 if (uIdReady == USBIP_POLL_ID_SOCKET)
1510 rc = usbProxyUsbIpRecvPdu(pProxyDevUsbIp, &pUrbUsbIp);
1511 else
1512 {
1513 AssertLogRelMsg(uIdReady == USBIP_POLL_ID_PIPE, ("Invalid pollset ID given\n"));
1514
1515 char bReason = usbProxyUsbIpWakeupPipeDrain(pProxyDevUsbIp);
1516 if (bReason == USBIP_REAPER_WAKEUP_REASON_QUEUE)
1517 usbProxyUsbIpUrbsQueuePending(pProxyDevUsbIp);
1518 else
1519 {
1520 Assert(bReason == USBIP_REAPER_WAKEUP_REASON_EXTERNAL);
1521 break;
1522 }
1523 }
1524 }
1525 }
1526
1527 if (pUrbUsbIp)
1528 {
1529 pUrb = pUrbUsbIp->pVUsbUrb;
1530
1531 /* unlink from the pending delivery list */
1532 usbProxyUsbIpUnlinkUrb(pProxyDevUsbIp, pUrbUsbIp);
1533 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1534 }
1535
1536 return pUrb;
1537}
1538
1539static DECLCALLBACK(int) usbProxyUsbIpUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1540{
1541 LogFlowFunc(("pUrb=%p\n", pUrb));
1542
1543 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1544 PUSBPROXYURBUSBIP pUrbUsbIp = (PUSBPROXYURBUSBIP)pUrb->Dev.pvPrivate;
1545 UsbIpReqUnlink ReqUnlink;
1546
1547 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1548 ReqUnlink.Hdr.u32ReqRet = USBIP_CMD_UNLINK;
1549 ReqUnlink.Hdr.u32SeqNum = u32SeqNum;
1550 ReqUnlink.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1551 ReqUnlink.Hdr.u32Direction = USBIP_DIR_OUT;
1552 ReqUnlink.Hdr.u32Endpoint = pUrb->EndPt;
1553 ReqUnlink.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1554
1555 usbProxyUsbIpReqUnlinkH2N(&ReqUnlink);
1556 return RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqUnlink, sizeof(ReqUnlink));
1557}
1558
1559static DECLCALLBACK(int) usbProxyUsbIpWakeup(PUSBPROXYDEV pProxyDev)
1560{
1561 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1562
1563 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1564 return usbProxyReaperKick(pProxyDevUsbIp, USBIP_REAPER_WAKEUP_REASON_EXTERNAL);
1565}
1566
1567/**
1568 * The USB/IP USB Proxy Backend operations.
1569 */
1570extern const USBPROXYBACK g_USBProxyDeviceUsbIp =
1571{
1572 /* pszName */
1573 "usbip",
1574 /* cbBackend */
1575 sizeof(USBPROXYDEVUSBIP),
1576 usbProxyUsbIpOpen,
1577 NULL,
1578 usbProxyUsbIpClose,
1579 usbProxyUsbIpReset,
1580 usbProxyUsbIpSetConfig,
1581 usbProxyUsbIpClaimInterface,
1582 usbProxyUsbIpReleaseInterface,
1583 usbProxyUsbIpSetInterface,
1584 usbProxyUsbIpClearHaltedEp,
1585 usbProxyUsbIpUrbQueue,
1586 usbProxyUsbIpUrbCancel,
1587 usbProxyUsbIpUrbReap,
1588 usbProxyUsbIpWakeup,
1589 0
1590};
1591
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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