USBProxyDevice-usbip.cpp revision 2b114c590cf5a19f8047cd7bde9c7e5ae00aa22b
/* $Id$ */
/** @file
*/
/*
* Copyright (C) 2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
#include <iprt/semaphore.h>
#include "../USBProxyDevice.h"
/*******************************************************************************
* Constants And Macros, Structures and Typedefs *
*******************************************************************************/
/** The USB version number used for the protocol. */
/** Request indicator in the command code. */
/** Command/Reply code for OP_REQ/RET_DEVLIST. */
/** Command/Reply code for OP_REQ/REP_IMPORT. */
/** USB submit command identifier. */
/** USB submit status identifier. */
/** URB unlink (cancel) command identifier. */
/** URB unlink (cancel) reply identifier. */
/** Short read is not okay for the specified URB. */
#define USBIP_XFER_FLAGS_SHORT_NOT_OK RT_BIT_32(0)
/** Queue the isochronous URB as soon as possible. */
/** Don't use DMA mappings for this URB. */
/** Explain - only applies to UHCI. */
/** URB direction - input. */
#define USBIP_DIR_IN UINT32_C(0)
/** URB direction - output. */
/**
* Exported device entry in the OP_RET_DEVLIST reply.
*/
#pragma pack(1)
typedef struct UsbIpExportedDevice
{
/** Path of the device, zero terminated string. */
char szPath[256];
/** Bus ID of the exported device, zero terminated string. */
char szBusId[32];
/** Bus number. */
/** Device number. */
/** Speed indicator of the device. */
/** Vendor ID of the device. */
/** Product ID of the device. */
/** Device release number. */
/** Device class. */
/** Device Subclass. */
/** Device protocol. */
/** Current configuration value of the device. */
/** Number of interfaces for the device. */
/** Pointer to a exported device entry. */
typedef UsbIpExportedDevice *PUsbIpExportedDevice;
#pragma pack()
/**
* Interface descriptor entry for an exported device.
*/
#pragma pack(1)
typedef struct UsbIpDeviceInterface
{
/** Intefrace class. */
/** Interface sub class. */
/** Interface protocol identifier. */
/** Padding byte for alignment. */
/** Pointer to an interface descriptor entry. */
typedef UsbIpDeviceInterface *PUsbIpDeviceInterface;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct UsbIpReqImport
{
/** Protocol version number. */
/** Command code. */
/** Status field, unused. */
/** Bus Id of the device as zero terminated string. */
char aszBusId[32];
/** Pointer to a import request. */
typedef UsbIpReqImport *PUsbIpReqImport;
#pragma pack()
/**
*
* This is only the header, for successful
* imports the device details are sent to as
* defined in UsbIpExportedDevice.
*/
#pragma pack(1)
typedef struct UsbIpRetImport
{
/** Protocol version number. */
/** Command code. */
/** Status field, unused. */
/** Pointer to a import reply. */
typedef UsbIpRetImport *PUsbIpRetImport;
#pragma pack()
/**
* replies.
*/
#pragma pack(1)
typedef struct UsbIpReqRetHdr
{
/** Sequence number to identify the URB. */
/** Device id. */
/** Direction of the endpoint (host->device, device->host). */
/** Endpoint number. */
typedef UsbIpReqRetHdr *PUsbIpReqRetHdr;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct UsbIpReqSubmit
{
/** The request header. */
/** Transfer flags for the URB. */
/** Transfer buffer length. */
/** Frame to transmit an ISO frame. */
/** Number of isochronous packets. */
/** Maximum time for the request on the server side host controller. */
/** Setup data for a control URB. */
/** Pointer to a submit request. */
typedef UsbIpReqSubmit *PUsbIpReqSubmit;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct UsbIpRetSubmit
{
/** The reply header. */
/** Status code. */
/** Actual length of the reply buffer. */
/** The actual selected frame for a isochronous transmit. */
/** Number of isochronous packets. */
/** Number of failed isochronous packets. */
/** Setup data for a control URB. */
/** Pointer to a submit reply. */
typedef UsbIpRetSubmit *PUsbIpRetSubmit;
#pragma pack()
/**
* Unlink URB request.
*/
#pragma pack(1)
typedef struct UsbIpReqUnlink
{
/** The request header. */
/** The sequence number to unlink. */
/** Pointer to a URB unlink request. */
typedef UsbIpReqUnlink *PUsbIpReqUnlink;
#pragma pack()
/**
* Unlink URB reply.
*/
#pragma pack(1)
typedef struct UsbIpRetUnlink
{
/** The reply header. */
/** Status of the request. */
/** Pointer to a URB unlink request. */
typedef UsbIpRetUnlink *PUsbIpRetUnlink;
#pragma pack()
/**
* Union of possible replies from the server during normal operation.
*/
#pragma pack(1)
typedef union UsbIpRet
{
/** The header. */
/** Submit reply. */
/** Unlink reply. */
/** Byte view. */
} UsbIpRet;
/** Pointer to a reply union. */
#pragma pack()
/**
* Required for tracking in flight and landed URBs.
*/
typedef struct USBPROXYURBUSBIP
{
/** List node for the in flight or landed URB list. */
/** Sequence number the assigned URB is identified by. */
/** Pointer to the VUSB URB. */
typedef USBPROXYURBUSBIP *PUSBPROXYURBUSBIP;
/**
*/
typedef struct USBPROXYDEVUSBIP
{
/** IPRT socket handle. */
/** Pollset with the wakeup pipe and socket. */
/** Pipe endpoint - read (in the pollset). */
/** Pipe endpoint - write. */
/** Flag whether the reaper thread was woken up. */
volatile bool fWokenUp;
/** Next sequence number to use for identifying submitted URBs. */
volatile uint32_t u32SeqNumNext;
/** Fast mutex protecting the lists below against concurrent access. */
/** List of in flight URBs. */
/** List of landed URBs. */
char *pszHost;
/** USB Bus ID of the device to capture. */
char *pszBusId;
/** The device ID to use to identify the device. */
/** Pollset id of the socket. */
#define USBIP_POLL_ID_SOCKET 0
/** Pollset id of the pipe. */
#define USBIP_POLL_ID_PIPE 1
/**
*
* @returns nothing.
* @param pHdr The header to convert.
*/
{
}
/**
*
* @returns nothing.
* @param pHdr The header to convert.
*/
{
}
/**
* Converts a submit request from host to network endianness.
*
* @returns nothing.
* @param pReqSubmit The submit request to convert.
*/
{
}
/**
* Converts a submit reply from network to host endianness.
*
* @returns nothing.
* @param pReqSubmit The submit reply to convert.
*/
{
}
/**
* Converts a unlink request from host to network endianness.
*
* @returns nothing.
* @param pReqUnlink The unlink request to convert.
*/
{
}
/**
* Converts a unlink reply from network to host endianness.
*
* @returns nothing.
* @param pRetUnlink The unlink reply to convert.
*/
{
}
/**
* Convert the given exported device structure from host to network byte order.
*
* @returns nothing.
* @param pDevice The device structure to convert.
*/
{
}
/**
*
* @returns VBox status code.
*/
{
return VINF_SUCCESS;
return VERR_NOT_IMPLEMENTED;
}
/**
* Gets the next free sequence number.
*
* @returns Next free sequence number.
*/
{
}
/**
* Links a given URB into the given list.
*
* @returns nothing.
* @param pList The list to link the URB into.
* @param pUrbUsbIp The URB to link.
*/
DECLINLINE(void) usbProxyUsbIpLinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PRTLISTANCHOR pList, PUSBPROXYURBUSBIP pUrbUsbIp)
{
}
/**
* Unlinks a given URB from the current assigned list.
*
* @returns nothing.
* @param pUrbUsbIp The URB to unlink.
*/
DECLINLINE(void) usbProxyUsbIpUnlinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
{
}
/**
*
*/
{
}
/**
*
* @returns nothing.
*/
{
}
/**
* Parse the string representation of the host address.
*
* @returns VBox status code.
* @param pszAddress The address string to parse.
*/
{
int rc = VINF_SUCCESS;
if (pszPortStart)
{
pszPortStart++;
if ( rc == VINF_SUCCESS
|| cbHost == 0)
{
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
else
}
else
return rc;
}
/**
*
* @returns VBox status.
*/
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
/* Disable send coalescing. */
if (RT_FAILURE(rc))
LogRel(("UsbIp: Disabling send coalescing failed (rc=%Rrc), continuing nevertheless but expect reduced performance\n", rc));
/* Import the device, i.e. claim it for our use. */
if (rc == VINF_SUCCESS)
{
if (RT_SUCCESS(rc))
{
/* Read the reply. */
if (RT_SUCCESS(rc))
{
{
/* Read the device data. */
if (RT_SUCCESS(rc))
{
}
}
else
{
/* Check what went wrong and leave a meaningful error message in the log. */
LogRel(("UsbIp: Unexpected protocol version received from host (%#x vs. %#x)\n",
LogRel(("UsbIp: Unexpected reply code received from host (%#x vs. %#x)\n",
LogRel(("UsbIp: Claiming the device has failed on the host with an unspecified error\n"));
else
AssertMsgFailed(("Something went wrong with if condition\n"));
}
}
}
}
else
{
LogRel(("UsbIp: Given bus ID is exceeds permitted protocol length: %u vs %u\n",
}
if (RT_FAILURE(rc))
}
if (RT_FAILURE(rc))
return rc;
}
/**
*
* @returns VBox status code.
*/
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
return rc;
}
/**
* Synchronously exchange a given control message with the remote device.
*
* @eturns VBox status code.
* @param pSetup The setup message.
*
* @note This method is only used to implement the *SetConfig, *SetInterface and *ClearHaltedEp
* @remark It is assumed that this method is never called while usbProxyUsbIpUrbReap is called
* on another thread.
*/
{
int rc = VINF_SUCCESS;
ReqSubmit.Hdr.u32Endpoint = 0; /* Only default control endpoint is allowed for these kind of messages. */
ReqSubmit.u32XferFlags = 0;
ReqSubmit.u32StartFrame = 0;
ReqSubmit.u32NumIsocPkts = 0;
ReqSubmit.u32Interval = 0;
/* Send the command. */
if (RT_SUCCESS(rc))
{
/* Wait for the response. */
/** @todo: Don't wait indefinitely long. */
if (RT_SUCCESS(rc))
{
}
}
return rc;
}
/*
* The USB proxy device functions.
*/
static DECLCALLBACK(int) usbProxyUsbIpOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
{
int rc = VINF_SUCCESS;
pDevUsbIp->u32SeqNumNext = 0;
/* Setup wakeup pipe and poll set first. */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
}
if (RT_FAILURE(rc))
{
}
}
if (RT_FAILURE(rc))
{
}
}
return rc;
}
{
int rc = VINF_SUCCESS;
/* Destroy the pipe and pollset if necessary. */
{
{
}
}
/* Clear the URB lists. */
{
}
{
}
}
{
return VINF_SUCCESS; /* No way to reset the device with the current protocol. */
}
{
Setup.bmRequestType = 0;
}
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
{
}
{
}
{
if (!pUrbUsbIp)
return VERR_NO_MEMORY;
ReqSubmit.u32XferFlags = 0;
ReqSubmit.u32StartFrame = 0;
ReqSubmit.u32NumIsocPkts = 0;
ReqSubmit.u32Interval = 0;
{
case VUSBXFERTYPE_MSG:
LogFlowFunc(("Message (Control) URB\n"));
break;
case VUSBXFERTYPE_ISOC:
#if 0
{
}
#else /** @todo: Implement isochronous support */
return VERR_NOT_SUPPORTED;
#endif
break;
case VUSBXFERTYPE_BULK:
case VUSBXFERTYPE_INTR:
break;
default:
return VERR_INVALID_PARAMETER; /** @todo: better status code. */
}
/* Send the command. */
if (RT_SUCCESS(rc))
{
/* Link the URB into the list of in flight URBs. */
}
else
return rc;
}
{
/* Any URBs pending delivery? */
{
if (pUrbUsbIp)
{
/* unlink from the pending delivery list */
}
}
if (!pUrbUsbIp)
{
uint32_t fEventsRecv = 0;
{
}
}
if (pUrbUsbIp)
{
}
return pUrb;
}
{
/* Wait for the reply. */
return rc;
}
{
int rc = VINF_SUCCESS;
{
}
return rc;
}
/**
*/
extern const USBPROXYBACK g_USBProxyDeviceUsbIp =
{
/* pszName */
"usbip",
/* cbBackend */
sizeof(USBPROXYDEVUSBIP),
NULL,
0
};