Hi,

Please find attached files and patches needed to make USB support fully work 
in VirtualBox under FreeBSD 8/9+. All patches and code is given under the MIT 
license, if that was not already clear to you.

I also want to thank all the people that sponsored me to do this "upgrade" of 
the existing FreeBSD USB code in VirtualBox with $500.

Instructions:

1) Replace the USBProxyDevice-freebsd.cpp found in the virtualbox 
sources by the one attached to this e-mail.

2) Apply the attached patches

Additional, how to automatically give VirtualBox rights to USB devices:

#
# /usr/local/etc/devd/virtualbox_dev_0x1234.conf
#
notify 50 {
        match "system"          "USB";
        match "subsystem"       "DEVICE";
        match "type"            "ATTACH";
        match "vendor"          "0x1234";
        action "chown virtualbox:virtualbox /dev/$cdev";
};

3) If USB 2.0 support is not present in VirtualBox, try:

sysctl hw.usb.ehci.no_hs=1

And then re-plug the device. Then the all USB HIGH speed USB devices will 
attach like FULL speed ones.

--HPS (one of the maintainers of the USB stack in FreeBSD 8+)
--- ./work/VirtualBox-3.2.51.r32802_OSE/src/VBox/Devices/USB/DevOHCI.cpp.orig	2010-10-20 20:57:31.000000000 +0200
+++ ./work/VirtualBox-3.2.51.r32802_OSE/src/VBox/Devices/USB/DevOHCI.cpp	2010-10-20 21:02:11.000000000 +0200
@@ -1110,6 +1110,7 @@
  */
 DECLINLINE(void) ohciPhysRead(POHCI pOhci, uint32_t Addr, void *pvBuf, size_t cbBuf)
 {
+    if (cbBuf == 0)	return;
     PDMDevHlpPhysRead(pOhci->CTX_SUFF(pDevIns), Addr, pvBuf, cbBuf);
 }
 
@@ -1118,6 +1119,7 @@
  */
 DECLINLINE(void) ohciPhysWrite(POHCI pOhci, uint32_t Addr, const void *pvBuf, size_t cbBuf)
 {
+    if (cbBuf == 0)	return;
     PDMDevHlpPhysWrite(pOhci->CTX_SUFF(pDevIns), Addr, pvBuf, cbBuf);
 }
 
/* $Id: USBProxyDevice-freebsd.cpp 31890 2010-08-24 07:50:47Z vboxsync $ */
/** @file
 * USB device proxy - the FreeBSD backend.
 */

/*
 * Copyright (C) 2006-2007 Oracle Corporation
 * Copyright (C) 2010 Hans Petter Selasky
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * 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
#ifdef VBOX
#include <iprt/stdint.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usb_ioctl.h>

#include <VBox/pdm.h>
#include <VBox/err.h>
#include <VBox/log.h>
#include <VBox/vusb.h>
#include <iprt/assert.h>
#include <iprt/stream.h>
#include <iprt/alloc.h>
#include <iprt/thread.h>
#include <iprt/time.h>
#include <iprt/asm.h>
#include <iprt/string.h>
#include <iprt/file.h>
#include "../USBProxyDevice.h"

/** Maximum endpoints supported. */
#define	USBFBSD_MAXENDPOINTS 127
#define	USBFBSD_MAXFRAMES 56

/** This really needs to be defined in vusb.h! */
#ifndef VUSB_DIR_TO_DEV
#define	VUSB_DIR_TO_DEV        0x00
#endif

#if 0
#define	PASS2(...) __VA_ARGS__
#define	PASS(...) PASS2(__VA_ARGS__)
#define	UN(...) __VA_ARGS__

static FILE *log_file;

static void
open_log_file(void)
{
	if (log_file)
		return;
	log_file = fopen("my_log.txt", "w+");
}

#undef Log
#define	Log(x) do {								\
		open_log_file();						\
		fprintf(log_file, PASS(UN x));			\
		} while (0)

#undef LogFlow
#define	LogFlow Log
#endif

/*******************************************************************************
*   Structures and Typedefs                                                    *
*******************************************************************************/
typedef struct USBENDPOINTFBSD {
	/** Flag whether it is opened. */
	bool	fOpen;
	/** Flag whether it is cancelling. */
	bool	fCancelling;
	/** Buffer pointers. */
	void   *apvData[USBFBSD_MAXFRAMES];
	/** Buffer lengths. */
	uint32_t acbData[USBFBSD_MAXFRAMES];
	/** Initial buffer length. */
	uint32_t cbData0;
	/** Pointer to the URB. */
	PVUSBURB pUrb;
	/** Copy of endpoint number. */
	unsigned iEpNum;
	/** Maximum transfer length. */
	unsigned cMaxIo;
	/** Maximum frame count. */
	unsigned cMaxFrames;
}	USBENDPOINTFBSD, *PUSBENDPOINTFBSD;

/**
 * Data for the FreeBSD usb proxy backend.
 */
typedef struct USBPROXYDEVFBSD {
	/** The open file. */
	RTFILE	File;
	/** Software endpoint structures */
	USBENDPOINTFBSD aSwEndpoint[USBFBSD_MAXENDPOINTS];
	/** Flag whether an URB is cancelling. */
	bool	fCancelling;
	/** Flag whether initialised or not */
	bool	fInit;
	/** Kernel endpoint structures */
	struct usb_fs_endpoint aHwEndpoint[USBFBSD_MAXENDPOINTS];
}	USBPROXYDEVFBSD, *PUSBPROXYDEVFBSD;

/*******************************************************************************
*   Internal Functions                                                         *
*******************************************************************************/
static int usbProxyFreeBSDEndpointClose(PUSBPROXYDEV pProxyDev, int Endpoint);

/**
 * Wrapper for the ioctl call.
 *
 * This wrapper will repeate the call if we get an EINTR or EAGAIN. It can also
 * handle ENODEV (detached device) errors.
 *
 * @returns whatever ioctl returns.
 * @param   pProxyDev       The proxy device.
 * @param   iCmd            The ioctl command / function.
 * @param   pvArg           The ioctl argument / data.
 * @param   fHandleNoDev    Whether to handle ENXIO.
 * @internal
 */
static int
usbProxyFreeBSDDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd,
    void *pvArg, bool fHandleNoDev)
{
	int rc = VINF_SUCCESS;
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;

	LogFlow(("usbProxyFreeBSDDoIoCtl: iCmd=%p\n", (void *)iCmd));

	do {
		rc = ioctl(pDevFBSD->File, iCmd, pvArg);
		if (rc >= 0)
			return VINF_SUCCESS;
	} while (errno == EINTR);

	if (errno == ENXIO && fHandleNoDev) {
		Log(("usbProxyFreeBSDDoIoCtl: ENXIO -> unplugged. pProxyDev=%s\n",
		    pProxyDev->pUsbIns->pszName));
		errno = ENODEV;
	} else if (errno != EAGAIN) {
		LogFlow(("usbProxyFreeBSDDoIoCtl: Returned %d. pProxyDev=%s\n",
		    errno, pProxyDev->pUsbIns->pszName));
	}
	return RTErrConvertFromErrno(errno);
}

/**
 * Init USB subsystem.
 */
static int
usbProxyFreeBSDFsInit(PUSBPROXYDEV pProxyDev)
{
	struct usb_fs_init UsbFsInit;
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	int rc;

	LogFlow(("usbProxyFreeBSDFsInit: pProxyDev=%p\n", (void *)pProxyDev));

	/* Sanity check */
	if (pDevFBSD == NULL)
		return RTErrConvertFromErrno(EINVAL);

	if (pDevFBSD->fInit == true)
		return VINF_SUCCESS;

	/* Zero default */
	memset(&UsbFsInit, 0, sizeof(UsbFsInit));

	UsbFsInit.pEndpoints = pDevFBSD->aHwEndpoint;
	UsbFsInit.ep_index_max = USBFBSD_MAXENDPOINTS;

	/* Init USB subsystem */
	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_INIT, &UsbFsInit, false);

	if (rc == VINF_SUCCESS)
		pDevFBSD->fInit = true;

	return rc;
}

/**
 * Uninit USB subsystem.
 */
static int
usbProxyFreeBSDFsUnInit(PUSBPROXYDEV pProxyDev)
{
	struct usb_fs_uninit UsbFsUninit;
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	int rc;
	int n;

	LogFlow(("usbProxyFreeBSDFsUnInit: ProxyDev=%p\n", (void *)pProxyDev));

	/* Sanity check */
	if (pDevFBSD == NULL)
		return RTErrConvertFromErrno(EINVAL);

	if (pDevFBSD->fInit != true)
		return VINF_SUCCESS;

	/* Close any open endpoints. */
	for (n = 0; n != USBFBSD_MAXENDPOINTS; n++)
		usbProxyFreeBSDEndpointClose(pProxyDev, n);

	/* Zero default */
	memset(&UsbFsUninit, 0, sizeof(UsbFsUninit));

	/* Uninit USB subsystem */
	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_UNINIT, &UsbFsUninit, false);

	if (rc == VINF_SUCCESS)
		pDevFBSD->fInit = false;

	return rc;
}

/**
 * Setup a USB request packet.
 */
static void
usbProxyFreeBSDSetupReq(struct usb_device_request *pSetupData,
    uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue,
    uint16_t wIndex, uint16_t wLength)
{
	LogFlow(("usbProxyFreeBSDSetupReq: pSetupData=%p bmRequestType=%x "
	    "bRequest=%x wValue=%x wIndex=%x wLength=%x\n", (void *)pSetupData,
	    bmRequestType, bRequest, wValue, wIndex, wLength));

	pSetupData->bmRequestType = bmRequestType;
	pSetupData->bRequest = bRequest;

	/* Handle endianess here. Currently no swapping is needed. */
	pSetupData->wValue[0] = wValue & 0xff;
	pSetupData->wValue[1] = (wValue >> 8) & 0xff;
	pSetupData->wIndex[0] = wIndex & 0xff;
	pSetupData->wIndex[1] = (wIndex >> 8) & 0xff;
	pSetupData->wLength[0] = wLength & 0xff;
	pSetupData->wLength[1] = (wLength >> 8) & 0xff;
}

static int
usbProxyFreeBSDEndpointOpen(PUSBPROXYDEV pProxyDev, int Endpoint, int isIsoc, int index)
{
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	PUSBENDPOINTFBSD pEndpointFBSD;
	struct usb_fs_endpoint *pXferEndpoint;
	struct usb_fs_open UsbFsOpen;
	int rc;

	LogFlow(("usbProxyFreeBSDEndpointOpen: pProxyDev=%p Endpoint=%d\n",
	    (void *)pProxyDev, Endpoint));

	for (; index != USBFBSD_MAXENDPOINTS; index++) {
		pEndpointFBSD = &pDevFBSD->aSwEndpoint[index];
		if (pEndpointFBSD->fCancelling)
			continue;
		if (pEndpointFBSD->fOpen && pEndpointFBSD->pUrb == NULL &&
		    (int)pEndpointFBSD->iEpNum == Endpoint)
			return index;
	}

	if (index == USBFBSD_MAXENDPOINTS) {
		for (index = 0; index != USBFBSD_MAXENDPOINTS; index++) {
			pEndpointFBSD = &pDevFBSD->aSwEndpoint[index];
			if (pEndpointFBSD->fCancelling)
				continue;
			if (!pEndpointFBSD->fOpen)
				break;
		}
		if (index == USBFBSD_MAXENDPOINTS)
			return -1;
	}
	/* set ppBuffer and pLength */

	pXferEndpoint = &pDevFBSD->aHwEndpoint[index];
	pXferEndpoint->ppBuffer = &pEndpointFBSD->apvData[0];
	pXferEndpoint->pLength = &pEndpointFBSD->acbData[0];

	LogFlow(("usbProxyFreeBSDEndpointOpen: ep_index=%d "
	    "ep_num=%d\n", (int)index, (int)Endpoint));

	memset(&UsbFsOpen, 0, sizeof(UsbFsOpen));

	UsbFsOpen.ep_index = index;
	UsbFsOpen.ep_no = Endpoint;
	UsbFsOpen.max_bufsize = 256 * 1024;
	/* Hardcoded assumption about the URBs we get. */

	UsbFsOpen.max_frames = isIsoc ? USBFBSD_MAXFRAMES : 2;

	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_OPEN, &UsbFsOpen, true);
	if (rc != VINF_SUCCESS) {
		if (errno == EBUSY) {
			LogFlow(("usbProxyFreeBSDEndpointOpen: EBUSY\n"));
		}
		return -1;
	}
	pEndpointFBSD->fOpen = true;
	pEndpointFBSD->pUrb = NULL;
	pEndpointFBSD->iEpNum = Endpoint;
	pEndpointFBSD->cMaxIo = UsbFsOpen.max_bufsize;
	pEndpointFBSD->cMaxFrames = UsbFsOpen.max_frames;

	return index;
}

static int
usbProxyFreeBSDEndpointClose(PUSBPROXYDEV pProxyDev, int Endpoint)
{
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	PUSBENDPOINTFBSD pEndpointFBSD = &pDevFBSD->aSwEndpoint[Endpoint];
	struct usb_fs_close UsbFsClose;
	int rc = VINF_SUCCESS;

	LogFlow(("usbProxyFreeBSDEndpointClose: pProxyDev=%p Endpoint=%d\n",
	    (void *)pProxyDev, Endpoint));

	/* check for cancelling */
	if (pEndpointFBSD->pUrb != NULL) {
		pEndpointFBSD->fCancelling = true;
		pDevFBSD->fCancelling = true;
	}
	/* check for opened */
	if (pEndpointFBSD->fOpen) {
		pEndpointFBSD->fOpen = false;

		/* Zero default */
		memset(&UsbFsClose, 0, sizeof(UsbFsClose));

		/* Set endpoint index */
		UsbFsClose.ep_index = Endpoint;

		/* Close endpoint */
		rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_CLOSE, &UsbFsClose, true);
	}
	return rc;
}

/**
 * Opens the device file.
 *
 * @returns VBox status code.
 * @param   pProxyDev       The device instance.
 * @param   pszAddress      If we are using usbfs, this is the path to the
 *                          device.  If we are using sysfs, this is a string of
 *                          the form "sysfs:<sysfs path>//device:<device node>".
 *                          In the second case, the two paths are guaranteed
 *                          not to contain the substring "//".
 * @param   pvBackend       Backend specific pointer, unused for the linux backend.
 */
static int
usbProxyFreeBSDOpen(PUSBPROXYDEV pProxyDev,
    const char *pszAddress, void *pvBackend)
{
	int rc;

	LogFlow(("usbProxyFreeBSDOpen: pProxyDev=%p pszAddress=%s\n",
	    (void *)pProxyDev, pszAddress));

	/*
	 * Try open the device node.
	 */
	RTFILE File;

	rc = RTFileOpen(&File, pszAddress, RTFILE_O_READWRITE |
	    RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
	if (RT_SUCCESS(rc)) {
		/*
	         * Allocate and initialize the linux backend data.
	         */
		PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)
		RTMemAllocZ(sizeof(USBPROXYDEVFBSD));

		if (pDevFBSD) {
			pDevFBSD->File = File;
			pProxyDev->Backend.pv = pDevFBSD;

			rc = usbProxyFreeBSDFsInit(pProxyDev);
			if (!rc) {
				LogFlow(("usbProxyFreeBSDOpen(%p, %s): returns "
				    "successfully File=%d iActiveCfg=%d\n",
				    (void *)pProxyDev, pszAddress,
				    pDevFBSD->File, pProxyDev->iActiveCfg));

				return VINF_SUCCESS;
			}
			RTMemFree(pDevFBSD);
		} else {
			rc = VERR_NO_MEMORY;
		}
		RTFileClose(File);
	} else if (rc == VERR_ACCESS_DENIED)
		rc = VERR_VUSB_USBFS_PERMISSION;

	Log(("usbProxyFreeBSDOpen(%p, %s) failed, rc=%d!\n",
	    (void *)pProxyDev, pszAddress, rc));
	pProxyDev->Backend.pv = NULL;

	NOREF(pvBackend);
	return rc;
}


/**
 * Claims all the interfaces and figures out the
 * current configuration.
 *
 * @returns VINF_SUCCESS.
 * @param   pProxyDev       The proxy device.
 */
static int
usbProxyFreeBSDInit(PUSBPROXYDEV pProxyDev)
{
	LogFlow(("usbProxyFreeBSDInit: pProxyDev=%s\n",
	    pProxyDev->pUsbIns->pszName));
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	int rc;

	/* Retrieve current active configuration. */
	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_GET_CONFIG,
	    &pProxyDev->iActiveCfg, true);
	if (rc != VINF_SUCCESS || pProxyDev->iActiveCfg == 255) {
		pProxyDev->cIgnoreSetConfigs = 0;
		pProxyDev->iActiveCfg = -1;
	} else {
		pProxyDev->cIgnoreSetConfigs = 1;
		pProxyDev->iActiveCfg++;
	}

	Log(("usbProxyFreeBSDInit: iActiveCfg=%d\n", pProxyDev->iActiveCfg));

	return rc;
}

/**
 * Closes the proxy device.
 */
static void
usbProxyFreeBSDClose(PUSBPROXYDEV pProxyDev)
{
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;

	LogFlow(("usbProxyFreeBSDClose: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));

	/* sanity check */
	if (pDevFBSD == NULL)
		return;

	usbProxyFreeBSDFsUnInit(pProxyDev);

	RTFileClose(pDevFBSD->File);

	pDevFBSD->File = NIL_RTFILE;

	RTMemFree(pDevFBSD);

	pProxyDev->Backend.pv = NULL;

	LogFlow(("usbProxyFreeBSDClose: returns\n"));
}

/**
 * Reset a device.
 *
 * @returns VBox status code.
 * @param   pDev    The device to reset.
 */
static int
usbProxyFreeBSDReset(PUSBPROXYDEV pProxyDev, bool fResetOnFreeBSD)
{
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	int iParm;
	int rc = VINF_SUCCESS;

	LogFlow(("usbProxyFreeBSDReset: pProxyDev=%s\n",
	    pProxyDev->pUsbIns->pszName));

	if (!fResetOnFreeBSD)
		goto done;

	/* We need to release kernel ressources first. */
	rc = usbProxyFreeBSDFsUnInit(pProxyDev);
	if (rc)
		goto done;

	/* Resetting is only possible as super-user, ignore any failures: */
	iParm = 0;
	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DEVICEENUMERATE, &iParm, true);
	if (rc != VINF_SUCCESS) {
		/* Set the config instead of bus reset */
		iParm = 255;
		rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG,
		    &iParm, true);
		if (rc == VINF_SUCCESS) {
			iParm = 0;
			rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG,
			    &iParm, true);
		}
	}
	usleep(10000);			/* nice it! */

	/* Allocate kernel ressources again. */
	rc = usbProxyFreeBSDFsInit(pProxyDev);
	if (rc != VINF_SUCCESS)
		goto done;

	/* Retrieve current active configuration. */
	rc = usbProxyFreeBSDInit(pProxyDev);

done:
	pProxyDev->cIgnoreSetConfigs = 2;

	return rc;
}

/**
 * SET_CONFIGURATION.
 *
 * The caller makes sure that it's not called first time after open or reset
 * with the active interface.
 *
 * @returns success indicator.
 * @param   pProxyDev       The device instance data.
 * @param   iCfg            The configuration to set.
 */
static int
usbProxyFreeBSDSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
{
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	int iCfgIndex;
	int rc;

	LogFlow(("usbProxyFreeBSDSetConfig: pProxyDev=%s cfg=%x\n",
	    pProxyDev->pUsbIns->pszName, iCfg));

	/* We need to release kernel ressources first. */
	rc = usbProxyFreeBSDFsUnInit(pProxyDev);
	if (rc != VINF_SUCCESS) {
		LogFlow(("usbProxyFreeBSDSetInterface: Freeing kernel resources "
		    "failed failed rc=%d\n", rc));
		return false;
	}
	if (iCfg == 0) {
		/* Unconfigure */
		iCfgIndex = 255;
	} else {
		/* Get the configuration index matching the value. */
		for (iCfgIndex = 0; iCfgIndex <
		    pProxyDev->DevDesc.bNumConfigurations; iCfgIndex++) {
			if (pProxyDev->paCfgDescs[iCfgIndex].Core.
			    bConfigurationValue == iCfg)
				break;
		}
		if (iCfgIndex == pProxyDev->DevDesc.bNumConfigurations) {
			LogFlow(("usbProxyFreeBSDSetConfig: configuration "
			    "%d not found\n", iCfg));
			return false;
		}
	}

	/* Set the config */
	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iCfgIndex, true);
	if (rc != VINF_SUCCESS)
		return false;

	/* Allocate kernel ressources again. */
	rc = usbProxyFreeBSDFsInit(pProxyDev);
	if (rc != VINF_SUCCESS)
		return false;

	return true;
}

/**
 * Claims an interface.
 * @returns success indicator.
 */
static int
usbProxyFreeBSDClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
{
	int rc;

	LogFlow(("usbProxyFreeBSDClaimInterface: pProxyDev=%s "
	    "ifnum=%x\n", pProxyDev->pUsbIns->pszName, iIf));

	/*
	 * Try to detach kernel driver on this interface, ignore any
	 * failures
	 */
	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_IFACE_DRIVER_DETACH, &iIf, true);

	/* Try to claim interface */
	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_CLAIM_INTERFACE, &iIf, true);
	if (rc != VINF_SUCCESS)
		return false;

	return true;
}

/**
 * Releases an interface.
 * @returns success indicator.
 */
static int
usbProxyFreeBSDReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
{
	int rc;

	LogFlow(("usbProxyFreeBSDReleaseInterface: pProxyDev=%s "
	    "ifnum=%x\n", pProxyDev->pUsbIns->pszName, iIf));

	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_RELEASE_INTERFACE, &iIf, true);
	if (rc != VINF_SUCCESS)
		return false;

	return true;
}

/**
 * SET_INTERFACE.
 *
 * @returns success indicator.
 */
static int
usbProxyFreeBSDSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
{
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	struct usb_alt_interface UsbIntAlt;
	int n;
	int rc;

	LogFlow(("usbProxyFreeBSDSetInterface: pProxyDev=%p iIf=%x iAlt=%x\n",
	    (void *)pProxyDev, iIf, iAlt));

	/* We need to release kernel ressources first. */
	rc = usbProxyFreeBSDFsUnInit(pProxyDev);
	if (rc != VINF_SUCCESS) {
		LogFlow(("usbProxyFreeBSDSetInterface: Freeing kernel resources "
		    "failed failed rc=%d\n", rc));
		return false;
	}
	memset(&UsbIntAlt, 0, sizeof(UsbIntAlt));
	UsbIntAlt.uai_interface_index = iIf;
	UsbIntAlt.uai_alt_index = iAlt;

	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_ALTINTERFACE, &UsbIntAlt, true);
	if (rc != VINF_SUCCESS) {
		LogFlow(("usbProxyFreeBSDSetInterface: Setting interface %d %d "
		    "failed rc=%d\n", iIf, iAlt, rc));
		return false;
	}
	rc = usbProxyFreeBSDFsInit(pProxyDev);
	if (rc != VINF_SUCCESS)
		return false;

	return true;
}

/**
 * Clears the halted endpoint 'ep_num'.
 */
static	bool
usbProxyFreeBSDClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int ep_num)
{
	struct usb_ctl_request Req;
	int rc;

	LogFlow(("usbProxyFreeBSDClearHaltedEp: "
	    "pProxyDev=%s ep_num=%u\n", pProxyDev->pUsbIns->pszName, ep_num));

	/*
	 * Clearing the zero control pipe doesn't make sense.
	 * Just ignore it.
	 */
	if ((ep_num & 0xF) == 0)
		return true;

	memset(&Req, 0, sizeof(Req));

	usbProxyFreeBSDSetupReq(&Req.ucr_request, VUSB_DIR_TO_DEV |
	    VUSB_TO_ENDPOINT, VUSB_REQ_CLEAR_FEATURE, 0, ep_num, 0);

	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DO_REQUEST, &Req, true);

	LogFlow(("usbProxyFreeBSDClearHaltedEp: rc=%d\n", rc));

	if (rc != VINF_SUCCESS)
		return false;

	return true;
}

/**
 * @copydoc USBPROXYBACK::pfnUrbQueue
 */
static int
usbProxyFreeBSDUrbQueue(PVUSBURB pUrb)
{
	PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	PUSBENDPOINTFBSD pEndpointFBSD;
	struct usb_fs_endpoint *pXferEndpoint;
	struct usb_fs_start UsbFsStart;
	unsigned cFrames;
	uint8_t *ptr;
	int index;
	int ep_num;
	int n;
	int rc;

	LogFlow(("usbProxyFreeBSDUrbQueue: pUrb=%p EndPt=%u Dir=%u\n",
	    (void *)pUrb, (unsigned)pUrb->EndPt, (unsigned)pUrb->enmDir));

	ep_num = pUrb->EndPt;

	if ((pUrb->enmType != VUSBXFERTYPE_MSG) && (pUrb->enmDir == VUSBDIRECTION_IN))
		ep_num |= 0x80;

	index = 0;

retry:

	index = usbProxyFreeBSDEndpointOpen(pProxyDev, ep_num,
	    (pUrb->enmType == VUSBXFERTYPE_ISOC), index);

	if (index < 0)
		return false;

	pEndpointFBSD = &pDevFBSD->aSwEndpoint[index];
	pXferEndpoint = &pDevFBSD->aHwEndpoint[index];

	ptr = pUrb->abData;

	switch (pUrb->enmType) {
	case VUSBXFERTYPE_MSG:
		pEndpointFBSD->apvData[0] = ptr;
		pEndpointFBSD->acbData[0] = 8;

		/* check wLength */
		if (ptr[6] || ptr[7]) {
			pEndpointFBSD->apvData[1] = ptr + 8;
			pEndpointFBSD->acbData[1] = ptr[6] | (ptr[7] << 8);
			cFrames = 2;
		} else {
			pEndpointFBSD->apvData[1] = NULL;
			pEndpointFBSD->acbData[1] = 0;
			cFrames = 1;
		}

		LogFlow(("usbProxyFreeBSDUrbQueue: pUrb->cbData=%u, 0x%02x, "
		    "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
		    pUrb->cbData, ptr[0], ptr[1], ptr[2], ptr[3],
		    ptr[4], ptr[5], ptr[6], ptr[7]));

		pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
		pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK;
		break;

	case VUSBXFERTYPE_ISOC:
		for (n = 0; n < (int)pUrb->cIsocPkts; n++) {
			if (n >= (int)pEndpointFBSD->cMaxFrames)
				break;
			pEndpointFBSD->apvData[n] = ptr + pUrb->aIsocPkts[n].off;
			pEndpointFBSD->acbData[n] = pUrb->aIsocPkts[n].cb;
		}
		/* Timeout handling will be done during reap. */
		pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
		pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK;
		cFrames = n;
		break;

	default:
		pEndpointFBSD->apvData[0] = ptr;
		pEndpointFBSD->cbData0 = pUrb->cbData;

		/* XXX maybe we have to loop */
		if (pUrb->cbData > pEndpointFBSD->cMaxIo)
			pEndpointFBSD->acbData[0] = pEndpointFBSD->cMaxIo;
		else
			pEndpointFBSD->acbData[0] = pUrb->cbData;

		/* Timeout handling will be done during reap. */
		pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
		pXferEndpoint->flags = pUrb->fShortNotOk ? 0 : USB_FS_FLAG_MULTI_SHORT_OK;
		cFrames = 1;
		break;
	}

	/* store number of frames */
	pXferEndpoint->nFrames = cFrames;

	/* zero-default */
	memset(&UsbFsStart, 0, sizeof(UsbFsStart));

	/* Start the transfer */
	UsbFsStart.ep_index = index;

	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_START, &UsbFsStart, true);

	LogFlow(("usbProxyFreeBSDUrbQueue: USB_FS_START returned rc=%d "
	    "len[0]=%u len[1]=%u cbData=%u index=%u ep_num=%u\n", rc,
	    (unsigned)pEndpointFBSD->acbData[0],
	    (unsigned)pEndpointFBSD->acbData[1],
	    (unsigned)pUrb->cbData,
	    (unsigned)index, (unsigned)ep_num));

	if (rc != VINF_SUCCESS) {
		if (errno == EBUSY) {
			index++;
			goto retry;
		}
		return false;
	}
	pUrb->Dev.pvPrivate = (void *)(long)(index + 1);
	pEndpointFBSD->pUrb = pUrb;

	return true;
}

/**
 * Reap URBs in-flight on a device.
 *
 * @returns Pointer to a completed URB.
 * @returns NULL if no URB was completed.
 * @param   pProxyDev   The device.
 * @param   cMillies    Number of milliseconds to wait. Use 0 to not wait at all.
 */
static	PVUSBURB
usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
{
	struct usb_fs_endpoint *pXferEndpoint;
	PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv;
	PUSBENDPOINTFBSD pEndpointFBSD;
	PVUSBURB pUrb;
	struct usb_fs_complete UsbFsComplete;
	struct pollfd PollFd;
	int n;
	int rc;

	LogFlow(("usbProxyFreeBSDUrbReap: pProxyDev=%p, cMillies=%u\n",
	    (void *)pProxyDev, cMillies));

repeat:

	pUrb = NULL;

	/* check for cancelled transfers */
	if (pDevFBSD->fCancelling) {
		for (n = 0; n != USBFBSD_MAXENDPOINTS; n++) {
			pEndpointFBSD = &pDevFBSD->aSwEndpoint[n];
			if (pEndpointFBSD->fCancelling) {
				pEndpointFBSD->fCancelling = false;
				pUrb = pEndpointFBSD->pUrb;
				pEndpointFBSD->pUrb = NULL;
				if (pUrb != NULL)
					break;
			}
		}
		if (pUrb != NULL) {
			pUrb->enmStatus = VUSBSTATUS_INVALID;
			pUrb->Dev.pvPrivate = NULL;

			switch (pUrb->enmType) {
			case VUSBXFERTYPE_MSG:
				pUrb->cbData = 0;
				break;
			case VUSBXFERTYPE_ISOC:
				pUrb->cbData = 0;
				for (n = 0; n < (int)pUrb->cIsocPkts; n++)
					pUrb->aIsocPkts[n].cb = 0;
				break;
			default:
				pUrb->cbData = 0;
				break;
			}
			return (pUrb);
		}
		pDevFBSD->fCancelling = false;
	}
	/* Zero default */

	memset(&UsbFsComplete, 0, sizeof(UsbFsComplete));

	/* Check if any endpoints are complete */
	rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true);
	if (rc == VINF_SUCCESS) {
		pXferEndpoint = &pDevFBSD->aHwEndpoint[UsbFsComplete.ep_index];
		pEndpointFBSD = &pDevFBSD->aSwEndpoint[UsbFsComplete.ep_index];

		LogFlow(("usbProxyFreeBSDUrbReap: Reaped "
		    "URB %p\n", (void *)pEndpointFBSD->pUrb));

		if (pXferEndpoint->status == USB_ERR_CANCELLED)
			goto repeat;

		pUrb = pEndpointFBSD->pUrb;
		pEndpointFBSD->pUrb = NULL;
		if (pUrb == NULL)
			goto repeat;

		switch (pXferEndpoint->status) {
		case USB_ERR_NORMAL_COMPLETION:
			pUrb->enmStatus = VUSBSTATUS_OK;
			break;
		case USB_ERR_STALLED:
			pUrb->enmStatus = VUSBSTATUS_STALL;
			break;
		default:
			pUrb->enmStatus = VUSBSTATUS_INVALID;
			break;
		}

		pUrb->Dev.pvPrivate = NULL;

		switch (pUrb->enmType) {
		case VUSBXFERTYPE_MSG:
			pUrb->cbData = pEndpointFBSD->acbData[0] +
			    pEndpointFBSD->acbData[1];
			break;
		case VUSBXFERTYPE_ISOC:
			if (pUrb->enmDir == VUSBDIRECTION_OUT)
				break;
			pUrb->cbData = 0;
			for (n = 0; n < (int)pUrb->cIsocPkts; n++) {
				if (n >= (int)pEndpointFBSD->cMaxFrames)
					break;
				pUrb->cbData += pEndpointFBSD->acbData[n];
				pUrb->aIsocPkts[n].cb = pEndpointFBSD->acbData[n];
			}
			for (; n < (int)pUrb->cIsocPkts; n++)
				pUrb->aIsocPkts[n].cb = 0;

			break;
		default:
			pUrb->cbData = pEndpointFBSD->acbData[0];
			break;
		}

		LogFlow(("usbProxyFreeBSDUrbReap: Status=%d epindex=%u "
		    "len[0]=%d len[1]=%d\n",
		    (int)pXferEndpoint->status,
		    (unsigned)UsbFsComplete.ep_index,
		    (unsigned)pEndpointFBSD->acbData[0],
		    (unsigned)pEndpointFBSD->acbData[1]));

	} else if (cMillies && errno == EBUSY) {

		/* Poll for finished transfers */

		PollFd.fd = (int)pDevFBSD->File;
		PollFd.events = POLLIN | POLLRDNORM;
		PollFd.revents = 0;

		rc = poll(&PollFd, 1, (cMillies == RT_INDEFINITE_WAIT) ?
		    INFTIM : cMillies);
		if (rc >= 1) {
			goto repeat;
		} else {
			LogFlow(("usbProxyFreeBSDUrbReap: "
			    "poll returned rc=%d\n", rc));
		}
	}
	return pUrb;
}

/**
 * Cancels the URB.
 * The URB requires reaping, so we don't change its state.
 */
static void
usbProxyFreeBSDUrbCancel(PVUSBURB pUrb)
{
	PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
	int index;

	index = (int)(long)pUrb->Dev.pvPrivate - 1;

	if (index < 0 || index >= USBFBSD_MAXENDPOINTS)
		return;

	LogFlow(("usbProxyFreeBSDUrbCancel: epindex=%u\n", (unsigned)index));

	usbProxyFreeBSDEndpointClose(pProxyDev, index);
}

/**
 * The FreeBSD USB Proxy Backend.
 */
extern const USBPROXYBACK g_USBProxyDeviceHost =
{
	"host",
	usbProxyFreeBSDOpen,
	usbProxyFreeBSDInit,
	usbProxyFreeBSDClose,
	usbProxyFreeBSDReset,
	usbProxyFreeBSDSetConfig,
	usbProxyFreeBSDClaimInterface,
	usbProxyFreeBSDReleaseInterface,
	usbProxyFreeBSDSetInterface,
	usbProxyFreeBSDClearHaltedEp,
	usbProxyFreeBSDUrbQueue,
	usbProxyFreeBSDUrbCancel,
	usbProxyFreeBSDUrbReap,
	0
};

/*
 * Local Variables:
 *  mode: c
 *  c-file-style: "bsd"
 *  c-basic-offset: 4
 *  tab-width: 4
 *  indent-tabs-mode: s
 * End:
 */
--- ./work/VirtualBox-3.2.51.r32802_OSE/src/VBox/Main/freebsd/USBProxyServiceFreeBSD.cpp.orig	2010-10-22 12:01:17.000000000 +0200
+++ ./work/VirtualBox-3.2.51.r32802_OSE/src/VBox/Main/freebsd/USBProxyServiceFreeBSD.cpp	2010-10-22 12:03:58.000000000 +0200
@@ -222,6 +222,7 @@
     int iAddr = 1;
     int rc = VINF_SUCCESS;
     char *pszDevicePath = NULL;
+    uint32_t PlugTime = 0;
 
     for (;;)
     {
@@ -286,7 +287,7 @@
                 break;
             }
 
-            pDevice->enmState           = USBDEVICESTATE_UNUSED;;
+            pDevice->enmState           = USBDEVICESTATE_UNUSED;
             pDevice->bBus               = UsbDevInfo.udi_bus;
             pDevice->bDeviceClass       = UsbDevInfo.udi_class;
             pDevice->bDeviceSubClass    = UsbDevInfo.udi_subclass;
@@ -324,6 +325,10 @@
                 pDevice->pszSerialNumber = RTStrDupN(UsbDevInfo.udi_serial, sizeof(UsbDevInfo.udi_serial));
                 pDevice->u64SerialHash   = USBLibHashSerial(pDevice->pszSerialNumber);
             }
+	    rc = ioctl(FileUsb, USB_GET_PLUGTIME, &PlugTime);
+	    if (rc == 0)
+                pDevice->u64SerialHash  += PlugTime;
+
             pDevice->pszAddress = RTStrDup(pszDevicePath);
             pDevice->enmState   = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
 
_______________________________________________
vbox-dev mailing list
vbox-dev@virtualbox.org
http://vbox.innotek.de/mailman/listinfo/vbox-dev

Reply via email to