/**
 * Close an endpoint.
 *
 * @returns VBox status code.
 */
static int usbProxyFreeBSDEndpointClose(PUSBPROXYDEV pProxyDev, int Endpoint)
{
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    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;
}
/**
 * Uninit USB subsystem.
 */
static int usbProxyFreeBSDFsUnInit(PUSBPROXYDEV pProxyDev)
{
    struct usb_fs_uninit UsbFsUninit;
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    int rc;

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

    /* Sanity check */
    AssertPtrReturn(pDevFBSD, VERR_INVALID_PARAMETER);

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

    /* Close any open endpoints. */
    for (unsigned 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 (RT_SUCCESS(rc))
        pDevFBSD->fInit = false;

    return rc;
}
/**
 * Claims all the interfaces and figures out the
 * current configuration.
 *
 * @returns VINF_SUCCESS.
 * @param   pProxyDev       The proxy device.
 */
static DECLCALLBACK(int) usbProxyFreeBSDInit(PUSBPROXYDEV pProxyDev)
{
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    int rc;

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

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

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

    return rc;
}
Example #4
0
/**
 * Copy the device and free resources associated with the backend.
 */
static DECLCALLBACK(void) usbProxyWinClose(PUSBPROXYDEV pProxyDev)
{
    /* Here we just close the device and free up p->priv
     * there is no need to do anything like cancel outstanding requests
     * that will have been done already
     */
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
    Assert(pPriv);
    if (!pPriv)
        return;
    Log(("usbProxyWinClose: %p\n", pPriv->hDev));

    if (pPriv->hDev != INVALID_HANDLE_VALUE)
    {
        Assert(pPriv->fClaimed);

        USBSUP_RELEASEDEV in;
        DWORD cbReturned = 0;
        in.bInterfaceNumber = pPriv->bInterfaceNumber;
        if (!DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_RELEASE_DEVICE, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
        {
            Log(("usbproxy: usbProxyWinClose: DeviceIoControl %#x failed with %#x!!\n", pPriv->hDev, GetLastError()));
        }
        if (!CloseHandle(pPriv->hDev))
            AssertLogRelMsgFailed(("usbproxy: usbProxyWinClose: CloseHandle %#x failed with %#x!!\n", pPriv->hDev, GetLastError()));
        pPriv->hDev = INVALID_HANDLE_VALUE;
    }

    CloseHandle(pPriv->hEventWakeup);
    RTCritSectDelete(&pPriv->CritSect);

    RTMemFree(pPriv->paQueuedUrbs);
    RTMemFree(pPriv->paHandles);
}
Example #5
0
static DECLCALLBACK(int) usbProxyWinWakeup(PUSBPROXYDEV pProxyDev)
{
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);

    SetEvent(pPriv->hEventWakeup);
    return VINF_SUCCESS;
}
Example #6
0
/**
 * Cancels an in-flight URB.
 *
 * The URB requires reaping, so we don't change its state.
 *
 * @remark  There isn't a way to cancel a specific URB on Windows.
 *          on darwin. The interface only supports the aborting of
 *          all URBs pending on an endpoint. Luckily that is usually
 *          exactly what the guest wants to do.
 */
static DECLCALLBACK(int) usbProxyWinUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
{
    PPRIV_USBW32      pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
    PQUEUED_URB       pQUrbWin  = (PQUEUED_URB)pUrb->Dev.pvPrivate;
    USBSUP_CLEAR_ENDPOINT   in;
    DWORD                   cbReturned;

    AssertPtrReturn(pQUrbWin, VERR_INVALID_PARAMETER);

    in.bEndpoint = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0);
    Log(("Cancel urb %p, endpoint %x\n", pUrb, in.bEndpoint));

    cbReturned = 0;
    if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_ABORT_ENDPOINT, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
        return VINF_SUCCESS;

    DWORD dwErr = GetLastError();
    if (   dwErr == ERROR_INVALID_HANDLE_STATE
        || dwErr == ERROR_BAD_COMMAND)
    {
        Log(("usbproxy: device %x unplugged!!\n", pPriv->hDev));
        pProxyDev->fDetached = true;
        return VINF_SUCCESS; /* Fake success and deal with the unplugged device elsewhere. */
    }

    AssertMsgFailed(("lastErr=%ld\n", dwErr));
    return RTErrConvertFromWin32(dwErr);
}
/**
 * Wrapper for the ioctl call.
 *
 * This wrapper will repeat 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 = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);

    LogFlow(("usbProxyFreeBSDDoIoCtl: iCmd=%#x\n", iCmd));

    do
    {
        rc = ioctl(RTFileToNative(pDevFBSD->hFile), 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);
}
Example #8
0
static DECLCALLBACK(int) usbProxyWinSetConfig(PUSBPROXYDEV pProxyDev, int cfg)
{
    /* Send a SET_CONFIGURATION command to the device. We don't do this
     * as a normal control message, because the OS might not want to
     * be left out of the loop on such a thing.
     *
     * It would be OK to send a SET_CONFIGURATION control URB at this
     * point but it has to be synchronous.
    */
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
    USBSUP_SET_CONFIG in;
    DWORD cbReturned;

    Assert(pPriv);

    Log(("usbproxy: Set config of %p to %d\n", pPriv->hDev, cfg));
    in.bConfigurationValue = cfg;

    /* Here we just need to assert reset signalling on the USB device */
    cbReturned = 0;
    if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_SET_CONFIG, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
        return VINF_SUCCESS;

    return usbProxyWinHandleUnpluggedDevice(pProxyDev, GetLastError());
}
/**
 * Init USB subsystem.
 */
static int usbProxyFreeBSDFsInit(PUSBPROXYDEV pProxyDev)
{
    struct usb_fs_init UsbFsInit;
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    int rc;

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

    /* Sanity check */
    AssertPtrReturn(pDevFBSD, VERR_INVALID_PARAMETER);

    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 (RT_SUCCESS(rc))
        pDevFBSD->fInit = true;

    return rc;
}
Example #10
0
static DECLCALLBACK(int) usbProxyWinReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
{
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
    DWORD cbReturned;
    int  rc;

    Assert(pPriv);

    Log(("usbproxy: Reset %x\n", pPriv->hDev));

    /* Here we just need to assert reset signalling on the USB device */
    cbReturned = 0;
    if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_RESET, NULL, 0, NULL, 0, &cbReturned, NULL))
    {
#if 0 /** @todo this needs to be enabled if windows chooses a default config. Test with the TrekStor GO Stick. */
        pProxyDev->iActiveCfg = 1;
        pProxyDev->cIgnoreSetConfigs = 2;
#else
        pProxyDev->iActiveCfg = -1;
        pProxyDev->cIgnoreSetConfigs = 0;
#endif
        return VINF_SUCCESS;
    }

    rc = GetLastError();
    if (rc == ERROR_DEVICE_REMOVED)
    {
        Log(("usbproxy: device %p unplugged!!\n", pPriv->hDev));
        pProxyDev->fDetached = true;
    }
    return RTErrConvertFromWin32(rc);
}
/**
 * SET_INTERFACE.
 *
 * @returns success indicator.
 */
static DECLCALLBACK(int) usbProxyFreeBSDSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
{
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    struct usb_alt_interface UsbIntAlt;
    int rc;

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

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

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

    return usbProxyFreeBSDFsInit(pProxyDev);
}
Example #12
0
static DECLCALLBACK(int) usbProxyWinReleaseInterface(PUSBPROXYDEV pProxyDev, int ifnum)
{
    /* The opposite of claim_interface. */
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);

    Assert(pPriv);
    return VINF_SUCCESS;
}
static DECLCALLBACK(int) usbProxyFreeBSDWakeup(PUSBPROXYDEV pProxyDev)
{
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    size_t cbIgnored;

    LogFlowFunc(("pProxyDev=%p\n", pProxyDev));

    return RTPipeWrite(pDevFBSD->hPipeWakeupW, "", 1, &cbIgnored);
}
static DECLCALLBACK(int) usbProxySolarisWakeup(PUSBPROXYDEV pProxyDev)
{
    PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
    size_t cbIgnored;

    LogFlowFunc(("pProxyDev=%p\n", pProxyDev));

    return RTPipeWrite(pDevSol->hPipeWakeupW, "", 1, &cbIgnored);
}
/**
 * @copydoc USBPROXYBACK::pfnUrbQueue
 */
static DECLCALLBACK(int) usbProxySolarisUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
{
    PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);

    LogFlowFunc((USBPROXY ": usbProxySolarisUrbQueue: pProxyDev=%s pUrb=%p EndPt=%#x enmDir=%d cbData=%d pvData=%p\n",
             pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, pUrb->enmDir, pUrb->cbData, pUrb->abData));

    PUSBPROXYURBSOL pUrbSol = usbProxySolarisUrbAlloc(pDevSol);
    if (RT_UNLIKELY(!pUrbSol))
    {
        LogRel((USBPROXY ":usbProxySolarisUrbQueue: Failed to allocate URB.\n"));
        return VERR_NO_MEMORY;
    }

    pUrbSol->pVUsbUrb = pUrb;
    pUrbSol->pDevSol = pDevSol;

    uint8_t EndPt = pUrb->EndPt;
    if (EndPt)
        EndPt |= pUrb->enmDir == VUSBDIRECTION_IN ? VUSB_DIR_TO_HOST : VUSB_DIR_TO_DEVICE;

    VBOXUSBREQ_URB UrbReq;
    UrbReq.pvUrbR3      = pUrbSol;
    UrbReq.bEndpoint    = EndPt;
    UrbReq.enmType      = pUrb->enmType;
    UrbReq.enmDir       = pUrb->enmDir;
    UrbReq.enmStatus    = pUrb->enmStatus;
    UrbReq.fShortOk     = !pUrb->fShortNotOk;
    UrbReq.cbData       = pUrb->cbData;
    UrbReq.pvData       = pUrb->abData;
    if (pUrb->enmType == VUSBXFERTYPE_ISOC)
    {
        UrbReq.cIsocPkts = pUrb->cIsocPkts;
        for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
        {
            UrbReq.aIsocPkts[i].cbPkt = pUrb->aIsocPkts[i].cb;
            UrbReq.aIsocPkts[i].cbActPkt = 0;
            UrbReq.aIsocPkts[i].enmStatus = VUSBSTATUS_INVALID;
        }
    }

    int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SEND_URB, &UrbReq, sizeof(UrbReq));
    if (RT_SUCCESS(rc))
    {
        if (pUrb->enmType == VUSBXFERTYPE_ISOC)
            LogFlow((USBPROXY ":usbProxySolarisUrbQueue success cbData=%d.\n", pUrb->cbData));
        pUrb->Dev.pvPrivate = pUrbSol;
        return VINF_SUCCESS;
    }

    if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
        LogRel((USBPROXY ":usbProxySolarisUrbQueue Failed!! pProxyDev=%s pUrb=%p EndPt=%#x bEndpoint=%#x enmType=%d enmDir=%d cbData=%u rc=%Rrc\n",
             pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, UrbReq.bEndpoint, pUrb->enmType, pUrb->enmDir, pUrb->cbData, rc));

    return rc;
}
Example #16
0
static DECLCALLBACK(int) usbProxyWinClaimInterface(PUSBPROXYDEV pProxyDev, int ifnum)
{
    /* Called just before we use an interface. Needed on Linux to claim
     * the interface from the OS, since even when proxying the host OS
     * might want to allow other programs to use the unused interfaces.
     * Not relevant for Windows.
     */
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);

    pPriv->bInterfaceNumber = ifnum;

    Assert(pPriv);
    return VINF_SUCCESS;
}
Example #17
0
/**
 * Converts the given Windows error code to VBox handling unplugged devices.
 *
 * @returns VBox status code.
 * @param   pProxDev    The USB proxy device instance.
 * @param   dwErr       Windows error code.
 */
static int usbProxyWinHandleUnpluggedDevice(PUSBPROXYDEV pProxyDev, DWORD dwErr)
{
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);

    if (   dwErr == ERROR_INVALID_HANDLE_STATE
        || dwErr == ERROR_BAD_COMMAND)
    {
        Log(("usbproxy: device %x unplugged!!\n", pPriv->hDev));
        pProxyDev->fDetached = true;
    }
    else
        AssertMsgFailed(("lasterr=%d\n", dwErr));
    return RTErrConvertFromWin32(dwErr);
}
/**
 * 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 DECLCALLBACK(int) usbProxyFreeBSDSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
{
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    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 (RT_FAILURE(rc))
    {
        LogFlow(("usbProxyFreeBSDSetInterface: Freeing kernel resources "
                 "failed failed rc=%d\n", rc));
        return rc;
    }

    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 VERR_NOT_FOUND;
        }
    }

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

    /* Allocate kernel ressources again. */
    return usbProxyFreeBSDFsInit(pProxyDev);
}
/**
 * Clears the halted endpoint 'EndPt'.
 */
static DECLCALLBACK(int) usbProxySolarisClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
{
    LogFlowFunc((USBPROXY ":usbProxySolarisClearHaltedEp pProxyDev=%p EndPt=%#x\n", pProxyDev, EndPt));

    PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
    AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);

    VBOXUSBREQ_CLEAR_EP ClearEpReq;
    ClearEpReq.bEndpoint = EndPt;
    int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLEAR_EP, &ClearEpReq, sizeof(ClearEpReq));
    if (   RT_FAILURE(rc)
        && rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
        LogRel((USBPROXY ":usbProxySolarisClearHaltedEp failed! rc=%Rrc\n", rc));

    return rc;
}
/**
 * Set the active 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 value to set.
 */
static DECLCALLBACK(int) usbProxySolarisSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
{
    LogFlowFunc((USBPROXY ":usbProxySolarisSetConfig: pProxyDev=%p iCfg=%#x\n", pProxyDev, iCfg));

    PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
    AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);

    VBOXUSBREQ_SET_CONFIG SetConfigReq;
    SetConfigReq.bConfigValue = iCfg;
    int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SET_CONFIG, &SetConfigReq, sizeof(SetConfigReq));
    if (   RT_FAILURE(rc)
        && rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
        LogRel((USBPROXY ":usbProxySolarisSetConfig failed to switch configuration. rc=%Rrc\n", rc));

    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 DECLCALLBACK(int) usbProxyFreeBSDOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress,
                                             void *pvBackend)
{
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    int rc;

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

    NOREF(pvBackend);

    /*
     * Try open the device node.
     */
    RTFILE hFile;
    rc = RTFileOpen(&hFile, pszAddress, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    if (RT_SUCCESS(rc))
    {
        /*
         * Initialize the FreeBSD backend data.
         */
        pDevFBSD->hFile = hFile;
        rc = usbProxyFreeBSDFsInit(pProxyDev);
        if (RT_SUCCESS(rc))
        {
            /*
             * Create wakeup pipe.
             */
            rc = RTPipeCreate(&pDevFBSD->hPipeWakeupR, &pDevFBSD->hPipeWakeupW, 0);
            if (RT_SUCCESS(rc))
            {
                LogFlow(("usbProxyFreeBSDOpen(%p, %s): returns successfully hFile=%RTfile iActiveCfg=%d\n",
                         pProxyDev, pszAddress, pDevFBSD->hFile, pProxyDev->iActiveCfg));

                return VINF_SUCCESS;
            }
        }

        RTFileClose(hFile);
    }
    else if (rc == VERR_ACCESS_DENIED)
        rc = VERR_VUSB_USBFS_PERMISSION;

    Log(("usbProxyFreeBSDOpen(%p, %s) failed, rc=%d!\n",
         pProxyDev, pszAddress, rc));

    return rc;
}
/**
 * Specify an alternate setting for the specified interface of the current configuration.
 *
 * @returns success indicator.
 */
static DECLCALLBACK(int) usbProxySolarisSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
{
    LogFlowFunc((USBPROXY ":usbProxySolarisSetInterface: pProxyDev=%p iIf=%d iAlt=%d\n", pProxyDev, iIf, iAlt));

    PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
    AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);

    VBOXUSBREQ_SET_INTERFACE SetInterfaceReq;
    SetInterfaceReq.bInterface = iIf;
    SetInterfaceReq.bAlternate = iAlt;
    int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SET_INTERFACE, &SetInterfaceReq, sizeof(SetInterfaceReq));
    if (   RT_FAILURE(rc)
        && rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
        LogRel((USBPROXY ":usbProxySolarisSetInterface failed to set interface. rc=%Rrc\n", rc));

    return rc;
}
/**
 * Reset a device.
 *
 * @returns VBox status code.
 * @param   pDev    The device to reset.
 */
static DECLCALLBACK(int) usbProxyFreeBSDReset(PUSBPROXYDEV pProxyDev, bool fResetOnFreeBSD)
{
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    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 (RT_FAILURE(rc))
        goto done;

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

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

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

done:
    pProxyDev->cIgnoreSetConfigs = 2;

    return rc;
}
Example #24
0
/**
 * Clears the halted endpoint 'ep'.
 */
static DECLCALLBACK(int) usbProxyWinClearHaltedEndPt(PUSBPROXYDEV pProxyDev, unsigned int ep)
{
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
    USBSUP_CLEAR_ENDPOINT in;
    DWORD cbReturned;

    Assert(pPriv);

    Log(("usbproxy: Clear endpoint %d of %x\n", ep, pPriv->hDev));
    in.bEndpoint = ep;

    cbReturned = 0;
    if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_CLEAR_ENDPOINT, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
        return VINF_SUCCESS;

    return usbProxyWinHandleUnpluggedDevice(pProxyDev, GetLastError());
}
/**
 * Closes the proxy device.
 */
static DECLCALLBACK(void) usbProxyFreeBSDClose(PUSBPROXYDEV pProxyDev)
{
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);

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

    /* sanity check */
    AssertPtrReturnVoid(pDevFBSD);

    usbProxyFreeBSDFsUnInit(pProxyDev);

    RTPipeClose(pDevFBSD->hPipeWakeupR);
    RTPipeClose(pDevFBSD->hPipeWakeupW);

    RTFileClose(pDevFBSD->hFile);
    pDevFBSD->hFile = NIL_RTFILE;

    LogFlow(("usbProxyFreeBSDClose: returns\n"));
}
/**
 * Reset the device.
 *
 * @returns VBox status code.
 * @param   pProxyDev           The device to reset.
 * @param   fRootHubReset       Is this a root hub reset or device specific reset request.
 */
static DECLCALLBACK(int) usbProxySolarisReset(PUSBPROXYDEV pProxyDev, bool fRootHubReset)
{
    LogFlowFunc((USBPROXY ":usbProxySolarisReset pProxyDev=%s fRootHubReset=%d\n", pProxyDev->pUsbIns->pszName, fRootHubReset));

    /** Pass all resets to the device. The Trekstor USB (1.1) stick requires this to work. */
    PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);

    /* Soft reset the device. */
    VBOXUSBREQ_CLOSE_DEVICE CloseReq;
    CloseReq.ResetLevel = VBOXUSB_RESET_LEVEL_SOFT;
    int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLOSE_DEVICE, &CloseReq, sizeof(CloseReq));
    if (RT_SUCCESS(rc))
    {
        /* Get the active config. Solaris USBA sets a default config. */
        usbProxySolarisGetActiveConfig(pDevSol);
    }
    else if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
        LogRel((USBPROXY ":usbProxySolarisReset failed. rc=%d\n", rc));

    return rc;
}
/**
 * Close the USB device.
 *
 * @param   pProxyDev   The device instance.
 */
static DECLCALLBACK(void) usbProxySolarisClose(PUSBPROXYDEV pProxyDev)
{
    LogFlow((USBPROXY ":usbProxySolarisClose: pProxyDev=%p\n", pProxyDev));

    PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);

    /* Close the device (do not re-enumerate). */
    VBOXUSBREQ_CLOSE_DEVICE CloseReq;
    CloseReq.ResetLevel = VBOXUSB_RESET_LEVEL_CLOSE;
    usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLOSE_DEVICE, &CloseReq, sizeof(CloseReq));

    pProxyDev->fDetached = true;
    usbProxySolarisCloseFile(pDevSol);

    /*
     * Now we can close it and free all the resources.
     */
    RTCritSectDelete(&pDevSol->CritSect);

    PUSBPROXYURBSOL pUrbSol = NULL;
    while ((pUrbSol = pDevSol->pInFlightHead) != NULL)
    {
        pDevSol->pInFlightHead = pUrbSol->pNext;
        RTMemFree(pUrbSol);
    }

    while ((pUrbSol = pDevSol->pFreeHead) != NULL)
    {
        pDevSol->pFreeHead = pUrbSol->pNext;
        RTMemFree(pUrbSol);
    }

    RTPipeClose(pDevSol->hPipeWakeupR);
    RTPipeClose(pDevSol->hPipeWakeupW);

    RTStrFree(pDevSol->pszDevicePath);
    pDevSol->pszDevicePath = NULL;

    USBLibTerm();
}
/**
 * Cancels a URB.
 *
 * The URB requires reaping, so we don't change its state.
 * @remark  There isn't any way to cancel a specific asynchronous request
 *          on Solaris. So we just abort pending URBs on the pipe.
 */
static DECLCALLBACK(int) usbProxySolarisUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
{
    PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)pUrb->Dev.pvPrivate;
    PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
    AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);

    LogFlowFunc((USBPROXY ":usbProxySolarisUrbCancel pUrb=%p pUrbSol=%p pDevSol=%p\n", pUrb, pUrbSol, pUrbSol->pDevSol));

    /* Aborting the control pipe isn't supported, pretend success. */
    if (!pUrb->EndPt)
        return VINF_SUCCESS;

    VBOXUSBREQ_ABORT_PIPE AbortPipeReq;
    AbortPipeReq.bEndpoint = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? VUSB_DIR_TO_HOST : VUSB_DIR_TO_DEVICE);
    int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_ABORT_PIPE, &AbortPipeReq, sizeof(AbortPipeReq));
    if (   RT_FAILURE(rc)
        && rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
        LogRel((USBPROXY ":usbProxySolarisUrbCancel failed to abort pipe. rc=%Rrc\n", rc));

    LogFlow((USBPROXY ":usbProxySolarisUrbCancel: rc=%Rrc.\n", rc));
    return rc;
}
Example #29
0
static DECLCALLBACK(int) usbProxyWinSetInterface(PUSBPROXYDEV pProxyDev, int ifnum, int setting)
{
    /* Select an alternate setting for an interface, the same applies
     * here as for set_config, you may convert this in to a control
     * message if you want but it must be synchronous
     */
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
    USBSUP_SELECT_INTERFACE in;
    DWORD cbReturned;

    Assert(pPriv);

    Log(("usbproxy: Select interface of %x to %d/%d\n", pPriv->hDev, ifnum, setting));
    in.bInterfaceNumber  = ifnum;
    in.bAlternateSetting = setting;

    /* Here we just need to assert reset signalling on the USB device */
    cbReturned = 0;
    if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_SELECT_INTERFACE, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
        return VINF_SUCCESS;

    return usbProxyWinHandleUnpluggedDevice(pProxyDev, GetLastError());
}
/**
 * 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 DECLCALLBACK(PVUSBURB) usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
{
    struct usb_fs_endpoint *pXferEndpoint;
    PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
    PUSBENDPOINTFBSD pEndpointFBSD;
    PVUSBURB pUrb;
    struct usb_fs_complete UsbFsComplete;
    struct pollfd pfd[2];
    int rc;

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

repeat:

    pUrb = NULL;

    /* check for cancelled transfers */
    if (pDevFBSD->fCancelling)
    {
        for (unsigned 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 (int 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 (RT_SUCCESS(rc))
    {
        pXferEndpoint = &pDevFBSD->aHwEndpoint[UsbFsComplete.ep_index];
        pEndpointFBSD = &pDevFBSD->aSwEndpoint[UsbFsComplete.ep_index];

        LogFlow(("usbProxyFreeBSDUrbReap: Reaped "
                 "URB %#p\n", 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:
            {
                int n;

                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 != 0 && rc == VERR_RESOURCE_BUSY)
    {
        for (;;)
        {
            pfd[0].fd = RTFileToNative(pDevFBSD->hFile);
            pfd[0].events = POLLIN | POLLRDNORM;
            pfd[0].revents = 0;

            pfd[1].fd = RTPipeToNative(pDevFBSD->hPipeWakeupR);
            pfd[1].events = POLLIN | POLLRDNORM;
            pfd[1].revents = 0;

            rc = poll(pfd, 2, (cMillies == RT_INDEFINITE_WAIT) ? INFTIM : cMillies);
            if (rc > 0)
            {
                if (pfd[1].revents & POLLIN)
                {
                    /* Got woken up, drain pipe. */
                    uint8_t bRead;
                    size_t cbIgnored = 0;
                    RTPipeRead(pDevFBSD->hPipeWakeupR, &bRead, 1, &cbIgnored);
                    /* Make sure we return from this function */
                    cMillies = 0;
                }
                break;
            }
            if (rc == 0)
                return NULL;
            if (errno != EAGAIN)
                return NULL;
        }
        goto repeat;
    }
    return pUrb;
}