VUSBUrb.cpp revision 8fff4af98a6c0e8e4e61f788d4fd56070879ae40
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/* $Id$ */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/** @file
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Virtual USB - URBs.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2010 Oracle Corporation
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * available from http://www.virtualbox.org. This file is free software;
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * General Public License (GPL) as published by the Free Software
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/*******************************************************************************
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync* Header Files *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync*******************************************************************************/
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#define LOG_GROUP LOG_GROUP_DRV_VUSB
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdm.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/vmapi.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <VBox/err.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <iprt/alloc.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <VBox/log.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <iprt/time.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <iprt/thread.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <iprt/semaphore.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <iprt/string.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <iprt/assert.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <iprt/asm.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include <iprt/env.h>
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#include "VUSBInternal.h"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/*******************************************************************************
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync* Global Variables *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync*******************************************************************************/
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/** Strings for the CTLSTAGE enum values. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncconst char * const g_apszCtlStates[4] =
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "SETUP",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "DATA",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "STATUS",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "N/A"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync};
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/*******************************************************************************
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync* Internal Functions *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync*******************************************************************************/
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic PVUSBCTRLEXTRA vusbMsgAllocExtraData(PVUSBURB pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef LOG_ENABLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncDECLINLINE(const char *) vusbUrbStatusName(VUSBSTATUS enmStatus)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /** Strings for the URB statuses. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszNames[] =
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "OK",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "STALL",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "ERR_DNR",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "ERR_CRC",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "DATA_UNDERRUN",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "DATA_OVERRUN",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "NOT_ACCESSED",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "7", "8", "9", "10", "11", "12", "13", "14", "15"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return enmStatus < (int)RT_ELEMENTS(s_apszNames)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync ? s_apszNames[enmStatus]
600b0aeb7dd11b9cc436bf3a948a70353102fad9vboxsync : enmStatus == VUSBSTATUS_INVALID
600b0aeb7dd11b9cc436bf3a948a70353102fad9vboxsync ? "INVALID"
600b0aeb7dd11b9cc436bf3a948a70353102fad9vboxsync : "??";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncDECLINLINE(const char *) vusbUrbDirName(VUSBDIRECTION enmDir)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /** Strings for the URB directions. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszNames[] =
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "setup",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "in",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "out"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return enmDir < (int)RT_ELEMENTS(s_apszNames)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync ? s_apszNames[enmDir]
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync : "??";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncDECLINLINE(const char *) vusbUrbTypeName(VUSBXFERTYPE enmType)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /** Strings for the URB types. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszName[] =
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "control-part",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "isochronous",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "bulk",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "interrupt",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "control"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return enmType < (int)RT_ELEMENTS(s_apszName)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync ? s_apszName[enmType]
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync : "??";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncDECLINLINE(const char *) GetScsiErrCd(uint8_t ScsiErr)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (ScsiErr)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0: return "?";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "?";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncDECLINLINE(const char *) GetScsiKCQ(uint8_t Key, uint8_t ASC, uint8_t ASCQ)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (Key)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (RT_MAKE_U16(ASC, ASCQ))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case RT_MAKE_U16(0x00, 0x00): return "No error";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 1:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "Soft Error";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 2:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "Not Ready";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 3:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "Medium Error";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 4:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "Hard Error";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 5:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "Illegal Request";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 6:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "Unit Attention";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 7:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "Write Protected";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0xb:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "Aborted Command";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return "?";
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Logs an URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Note that pUrb->pUsbIns, pUrb->VUsb.pDev and pUrb->VUsb.pDev->pUsbIns can all be NULL.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncvoid vusbUrbTrace(PVUSBURB pUrb, const char *pszMsg, bool fComplete)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev; /* Can be NULL when called from usbProxyConstruct and friends. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const uint8_t *pbData = pUrb->abData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t cbData = pUrb->cbData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PCVUSBSETUP pSetup = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync bool fDescriptors = false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static size_t s_cchMaxMsg = 10;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync size_t cchMsg = strlen(pszMsg);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cchMsg > s_cchMaxMsg)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg = cchMsg;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("%s: %*s: pDev=%p[%s] rc=%s a=%i e=%u d=%s t=%s cb=%#x(%d) Ed=%08x cTds=%d Td0=%08x ts=%RU64 (%RU64 ns ago) %s\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pDev,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pUsbIns ? pUrb->pUsbIns->pszName : "",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbStatusName(pUrb->enmStatus),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pDev ? pDev->u8Address : -1,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->EndPt,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbDirName(pUrb->enmDir),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbTypeName(pUrb->enmType),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->cbData,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->cbData,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->Hci.EdAddr,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->Hci.cTds,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->Hci.cTds ? pUrb->Hci.paTds[0].TdAddr : ~(uint32_t)0,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.u64SubmitTS,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RTTimeNanoTS() - pUrb->VUsb.u64SubmitTS,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->fShortNotOk ? "ShortNotOk" : "ShortOk"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifndef DEBUG_bird
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pUrb->enmType == VUSBXFERTYPE_CTRL
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmStatus == VUSBSTATUS_OK)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pUrb->enmType == VUSBXFERTYPE_MSG
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || ( pUrb->enmDir == VUSBDIRECTION_SETUP
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmType == VUSBXFERTYPE_CTRL
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && cbData))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszReqDirs[] = {"host2dev", "dev2host"};
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszReqTypes[] = {"std", "class", "vendor", "reserved"};
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszReqRecipients[] = {"dev", "if", "endpoint", "other"};
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszRequests[] =
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "GET_STATUS", "CLEAR_FEATURE", "2?", "SET_FEATURE",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "4?", "SET_ADDRESS", "GET_DESCRIPTOR", "SET_DESCRIPTOR",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "GET_CONFIGURATION", "SET_CONFIGURATION", "GET_INTERFACE", "SET_INTERFACE",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "SYNCH_FRAME"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup = (PVUSBSETUP)pUrb->abData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pbData += sizeof(*pSetup);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync cbData -= sizeof(*pSetup);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("%s: %*s: CTRL: bmRequestType=0x%.2x (%s %s %s) bRequest=0x%.2x (%s) wValue=0x%.4x wIndex=0x%.4x wLength=0x%.4x\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->bmRequestType, s_apszReqDirs[pSetup->bmRequestType >> 7], s_apszReqTypes[(pSetup->bmRequestType >> 5) & 0x3],
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync (unsigned)(pSetup->bmRequestType & 0xf) < RT_ELEMENTS(s_apszReqRecipients) ? s_apszReqRecipients[pSetup->bmRequestType & 0xf] : "??",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->bRequest, pSetup->bRequest < RT_ELEMENTS(s_apszRequests) ? s_apszRequests[pSetup->bRequest] : "??",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->wValue, pSetup->wIndex, pSetup->wLength));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pSetup->bRequest == VUSB_REQ_GET_DESCRIPTOR
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && fComplete
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmStatus == VUSBSTATUS_OK
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && ((pSetup->bmRequestType >> 5) & 0x3) < 2 /* vendor */)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync fDescriptors = true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if ( fComplete
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmDir == VUSBDIRECTION_IN
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmType == VUSBXFERTYPE_CTRL
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmStatus == VUSBSTATUS_OK
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pPipe->pCtrl
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pPipe->pCtrl->enmStage == CTLSTAGE_DATA
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && cbData > 0)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup = pPipe->pCtrl->pMsg;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pSetup->bRequest == VUSB_REQ_GET_DESCRIPTOR)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync fDescriptors = true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Dump descriptors.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (fDescriptors)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const uint8_t *pb = pbData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const uint8_t *pbEnd = pbData + cbData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync while (pb + 1 < pbEnd)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const unsigned cbLeft = pbEnd - pb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const unsigned cbLength = *pb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync unsigned cb = cbLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDescriptorType = pb[1];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* length out of bounds? */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cbLength > cbLeft)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync cb = cbLeft;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cbLength != 0xff) /* ignore this */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: DESC: warning descriptor length goes beyond the end of the URB! cbLength=%d cbLeft=%d\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, cbLength, cbLeft));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb >= 2)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: DESC: %04x: %25s = %#04x (%d)\n"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "URB: %*s: %04x: %25s = %#04x (",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb - pbData, "bLength", cbLength, cbLength,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb - pbData + 1, "bDescriptorType", bDescriptorType));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #pragma pack(1)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #define BYTE_FIELD(strct, memb) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ((unsigned)RT_OFFSETOF(strct, memb) < cb) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: %25s = %#04x\n", s_cchMaxMsg, pszMsg, \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb + RT_OFFSETOF(strct, memb) - pbData, #memb, pb[RT_OFFSETOF(strct, memb)]))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #define BYTE_FIELD_START(strct, memb) do { \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ((unsigned)RT_OFFSETOF(strct, memb) < cb) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync { \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: %25s = %#04x", s_cchMaxMsg, pszMsg, \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb + RT_OFFSETOF(strct, memb) - pbData, #memb, pb[RT_OFFSETOF(strct, memb)]))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #define BYTE_FIELD_END(strct, memb) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("\n")); \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } } while (0)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #define WORD_FIELD(strct, memb) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ((unsigned)RT_OFFSETOF(strct, memb) + 1 < cb) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: %25s = %#06x\n", s_cchMaxMsg, pszMsg, \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb + RT_OFFSETOF(strct, memb) - pbData, #memb, *(uint16_t *)&pb[RT_OFFSETOF(strct, memb)]))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #define BCD_FIELD(strct, memb) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ((unsigned)RT_OFFSETOF(strct, memb) + 1 < cb) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: %25s = %#06x (%02x.%02x)\n", s_cchMaxMsg, pszMsg, \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb + RT_OFFSETOF(strct, memb) - pbData, #memb, *(uint16_t *)&pb[RT_OFFSETOF(strct, memb)], \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[RT_OFFSETOF(strct, memb) + 1], pb[RT_OFFSETOF(strct, memb)]))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #define SIZE_CHECK(strct) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb > sizeof(strct)) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: WARNING %d extra byte(s) %.*Rhxs\n", s_cchMaxMsg, pszMsg, \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb + sizeof(strct) - pbData, cb - sizeof(strct), cb - sizeof(strct), pb + sizeof(strct))); \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if (cb < sizeof(strct)) \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: WARNING %d missing byte(s)! Expected size %d.\n", s_cchMaxMsg, pszMsg, \
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb + cb - pbData, sizeof(strct) - cb, sizeof(strct)))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* on type */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (bDescriptorType)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_DEVICE:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync struct dev_desc
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDescriptorType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t bcdUSB;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDeviceClass;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDeviceSubClass;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDeviceProtocol;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bMaxPacketSize0;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t idVendor;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t idProduct;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t bcdDevice;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t iManufacturer;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t iProduct;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t iSerialNumber;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bNumConfigurations;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pDesc = (struct dev_desc *)pb; NOREF(pDesc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("DEV)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BCD_FIELD( struct dev_desc, bcdUSB);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dev_desc, bDeviceClass);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dev_desc, bDeviceSubClass);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dev_desc, bDeviceProtocol);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dev_desc, bMaxPacketSize0);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync WORD_FIELD(struct dev_desc, idVendor);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync WORD_FIELD(struct dev_desc, idProduct);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BCD_FIELD( struct dev_desc, bcdDevice);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dev_desc, iManufacturer);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dev_desc, iProduct);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dev_desc, iSerialNumber);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dev_desc, bNumConfigurations);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync SIZE_CHECK(struct dev_desc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_CONFIG:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync struct cfg_desc
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDescriptorType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t wTotalLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bNumInterfaces;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bConfigurationValue;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t iConfiguration;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bmAttributes;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t MaxPower;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pDesc = (struct cfg_desc *)pb; NOREF(pDesc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("CFG)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync WORD_FIELD(struct cfg_desc, wTotalLength);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct cfg_desc, bNumInterfaces);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct cfg_desc, bConfigurationValue);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct cfg_desc, iConfiguration);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD_START(struct cfg_desc, bmAttributes);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszTransType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszSyncType[4] = { "NoSync", "Asynchronous", "Adaptive", "Synchronous" };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszUsageType[4] = { "Data ep", "Feedback ep.", "Implicit feedback Data ep.", "Reserved" };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log((" %s - %s - %s", s_apszTransType[(pDesc->bmAttributes & 0x3)],
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_apszSyncType[((pDesc->bmAttributes >> 2) & 0x3)], s_apszUsageType[((pDesc->bmAttributes >> 4) & 0x3)]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD_END(struct cfg_desc, bmAttributes);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct cfg_desc, MaxPower);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync SIZE_CHECK(struct cfg_desc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_STRING:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pSetup->wIndex)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* langid array */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t *pu16 = (uint16_t *)pb + 1;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("LANGIDs)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync while ((uintptr_t)pu16 + 2 - (uintptr_t)pb <= cb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: wLANGID[%#x] = %#06x\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, (uint8_t *)pu16 - pbData, pu16 - (uint16_t *)pb, *pu16));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pu16++;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb & 1)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: WARNING descriptor size is odd! extra byte: %02\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, (uint8_t *)pu16 - pbData, *(uint8_t *)pu16));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /** a string. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("STRING)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb > 2)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: Length=%d String=%.*ls\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb - pbData, cb - 2, cb / 2 - 1, pb + 2));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: %04x: Length=0!\n", s_cchMaxMsg, pszMsg, pb - pbData));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_INTERFACE:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync struct if_desc
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDescriptorType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bInterfaceNumber;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bAlternateSetting;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bNumEndpoints;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bInterfaceClass;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bInterfaceSubClass;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bInterfaceProtocol;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t iInterface;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pDesc = (struct if_desc *)pb; NOREF(pDesc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("IF)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct if_desc, bInterfaceNumber);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct if_desc, bAlternateSetting);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct if_desc, bNumEndpoints);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct if_desc, bInterfaceClass);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct if_desc, bInterfaceSubClass);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct if_desc, bInterfaceProtocol);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct if_desc, iInterface);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync SIZE_CHECK(struct if_desc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_ENDPOINT:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync struct ep_desc
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDescriptorType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bEndpointAddress;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bmAttributes;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t wMaxPacketSize;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bInterval;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pDesc = (struct ep_desc *)pb; NOREF(pDesc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("EP)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct ep_desc, bEndpointAddress);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct ep_desc, bmAttributes);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync WORD_FIELD(struct ep_desc, wMaxPacketSize);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct ep_desc, bInterval);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync SIZE_CHECK(struct ep_desc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_DEVICE_QUALIFIER:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync struct dq_desc
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDescriptorType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t bcdUSB;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDeviceClass;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDeviceSubClass;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDeviceProtocol;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bMaxPacketSize0;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bNumConfigurations;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bReserved;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pDQDesc = (struct dq_desc *)pb; NOREF(pDQDesc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("DEVQ)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BCD_FIELD( struct dq_desc, bcdUSB);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dq_desc, bDeviceClass);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dq_desc, bDeviceSubClass);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dq_desc, bDeviceProtocol);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dq_desc, bMaxPacketSize0);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dq_desc, bNumConfigurations);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct dq_desc, bReserved);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync SIZE_CHECK(struct dq_desc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_OTHER_SPEED_CFG:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync struct oth_cfg_desc
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDescriptorType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t wTotalLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bNumInterfaces;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bConfigurationValue;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t iConfiguration;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bmAttributes;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t MaxPower;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pDesc = (struct oth_cfg_desc *)pb; NOREF(pDesc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("OCFG)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync WORD_FIELD(struct oth_cfg_desc, wTotalLength);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct oth_cfg_desc, bNumInterfaces);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct oth_cfg_desc, bConfigurationValue);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct oth_cfg_desc, iConfiguration);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD_START(struct oth_cfg_desc, bmAttributes);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszTransType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszSyncType[4] = { "NoSync", "Asynchronous", "Adaptive", "Synchronous" };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszUsageType[4] = { "Data ep", "Feedback ep.", "Implicit feedback Data ep.", "Reserved" };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log((" %s - %s - %s", s_apszTransType[(pDesc->bmAttributes & 0x3)],
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_apszSyncType[((pDesc->bmAttributes >> 2) & 0x3)], s_apszUsageType[((pDesc->bmAttributes >> 4) & 0x3)]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD_END(struct oth_cfg_desc, bmAttributes);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct oth_cfg_desc, MaxPower);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync SIZE_CHECK(struct oth_cfg_desc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x21:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync struct hid_desc
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bDescriptorType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t bcdHid;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bCountry;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bNumDescriptors;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t bReportType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint16_t wReportLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pDesc = (struct hid_desc *)pb; NOREF(pDesc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("EP)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BCD_FIELD( struct hid_desc, bcdHid);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct hid_desc, bCountry);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct hid_desc, bNumDescriptors);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync BYTE_FIELD(struct hid_desc, bReportType);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync WORD_FIELD(struct hid_desc, wReportLength);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync SIZE_CHECK(struct hid_desc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0xff:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("UNKNOWN-ignore)\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("UNKNOWN)!!!\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #undef BYTE_FIELD
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #undef WORD_FIELD
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #undef BCD_FIELD
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #undef SIZE_CHECK
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync #pragma pack()
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: DESC: %04x: bLength=%d bDescriptorType=%d - invalid length\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb - pbData, cb, bDescriptorType));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* next */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb += cb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * SCSI
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pUrb->enmType == VUSBXFERTYPE_BULK
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmDir == VUSBDIRECTION_OUT
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->cbData >= 12
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && !memcmp(pUrb->abData, "USBC", 4))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const struct usbc
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t Signature;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t Tag;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t DataTransferLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t Flags;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t Lun;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t Length;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t CDB[13];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pUsbC = (struct usbc *)pUrb->abData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: Tag=%#x DataTransferLength=%#x Flags=%#x Lun=%#x Length=%#x CDB=%.*Rhxs\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pUsbC->Tag, pUsbC->DataTransferLength, pUsbC->Flags, pUsbC->Lun,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUsbC->Length, pUsbC->Length, pUsbC->CDB));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const uint8_t *pb = &pUsbC->CDB[0];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pb[0])
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x00: /* test unit read */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: TEST_UNIT_READY LUN=%d Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[1] >> 5, pb[5]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x03: /* Request Sense command */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: REQUEST_SENSE LUN=%d AlcLen=%#RX16 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[1] >> 5, pb[4], pb[5]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x12: /* Inquiry command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: INQUIRY EVPD=%d LUN=%d PgCd=%#RX8 AlcLen=%#RX8 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[1] & 1, pb[1] >> 5, pb[2], pb[4], pb[5]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1a: /* Mode Sense(6) command */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: MODE_SENSE6 LUN=%d DBD=%d PC=%d PgCd=%#RX8 AlcLen=%#RX8 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[1] >> 5, !!(pb[1] & RT_BIT(3)), pb[2] >> 6, pb[2] & 0x3f, pb[4], pb[5]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x5a:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: MODE_SENSE10 LUN=%d DBD=%d PC=%d PgCd=%#RX8 AlcLen=%#RX16 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[1] >> 5, !!(pb[1] & RT_BIT(3)), pb[2] >> 6, pb[2] & 0x3f,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U16(pb[8], pb[7]), pb[9]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x25: /* Read Capacity(6) command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: READ_CAPACITY\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x28: /* Read(10) command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: READ10 RelAdr=%d FUA=%d DPO=%d LUN=%d LBA=%#RX32 Len=%#RX16 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[1] & 1, !!(pb[1] & RT_BIT(3)), !!(pb[1] & RT_BIT(4)), pb[1] >> 5,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U32_FROM_U8(pb[5], pb[4], pb[3], pb[2]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U16(pb[8], pb[7]), pb[9]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0xa8: /* Read(12) command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: READ12 RelAdr=%d FUA=%d DPO=%d LUN=%d LBA=%#RX32 Len=%#RX32 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[1] & 1, !!(pb[1] & RT_BIT(3)), !!(pb[1] & RT_BIT(4)), pb[1] >> 5,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U32_FROM_U8(pb[5], pb[4], pb[3], pb[2]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U32_FROM_U8(pb[9], pb[8], pb[7], pb[6]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[11]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x3e: /* Read Long command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: READ LONG RelAdr=%d Correct=%d LUN=%d LBA=%#RX16 ByteLen=%#RX16 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[1] & 1, !!(pb[1] & RT_BIT(1)), pb[1] >> 5,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U16(pb[3], pb[2]), RT_MAKE_U16(pb[6], pb[5]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[11]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x2a: /* Write(10) command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: WRITE10 RelAdr=%d EBP=%d FUA=%d DPO=%d LUN=%d LBA=%#RX32 Len=%#RX16 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[1] & 1, !!(pb[1] & RT_BIT(2)), !!(pb[1] & RT_BIT(3)),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync !!(pb[1] & RT_BIT(4)), pb[1] >> 5,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U32_FROM_U8(pb[5], pb[4], pb[3], pb[2]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U16(pb[8], pb[7]), pb[9]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0xaa: /* Write(12) command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: WRITE12 RelAdr=%d EBP=%d FUA=%d DPO=%d LUN=%d LBA=%#RX32 Len=%#RX32 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[1] & 1, !!(pb[1] & RT_BIT(3)), !!(pb[1] & RT_BIT(4)),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync !!(pb[1] & RT_BIT(4)), pb[1] >> 5,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U32_FROM_U8(pb[5], pb[4], pb[3], pb[2]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U32_FROM_U8(pb[9], pb[8], pb[7], pb[6]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[11]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x3f: /* Write Long command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: WRITE LONG RelAdr=%d LUN=%d LBA=%#RX16 ByteLen=%#RX16 Ctrl=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[1] & 1, pb[1] >> 5,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U16(pb[3], pb[2]), RT_MAKE_U16(pb[6], pb[5]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[11]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x35: /* Synchronize Cache(10) command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: SYNCHRONIZE_CACHE10\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0xa0: /* Report LUNs command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: REPORT_LUNS\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: cmd=%#x\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[0]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pDev)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pDev->Urb.u8ScsiCmd = pb[0];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if ( fComplete
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmType == VUSBXFERTYPE_BULK
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmDir == VUSBDIRECTION_IN
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->cbData >= 12
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && !memcmp(pUrb->abData, "USBS", 4))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const struct usbs
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t Signature;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t Tag;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t DataResidue;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t Status;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t CDB[3];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync } *pUsbS = (struct usbs *)pUrb->abData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync static const char * const s_apszStatuses[] = { "PASSED", "FAILED", "PHASE ERROR", "RESERVED" };
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: Tag=%#x DataResidue=%#RX32 Status=%#RX8 %s\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pUsbS->Tag, pUsbS->DataResidue, pUsbS->Status,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_apszStatuses[pUsbS->Status < RT_ELEMENTS(s_apszStatuses) ? pUsbS->Status : RT_ELEMENTS(s_apszStatuses) - 1]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pDev)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pDev->Urb.u8ScsiCmd = 0xff;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if ( fComplete
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmType == VUSBXFERTYPE_BULK
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pUrb->enmDir == VUSBDIRECTION_IN
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pDev
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pDev->Urb.u8ScsiCmd != 0xff)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const uint8_t *pb = pUrb->abData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pDev->Urb.u8ScsiCmd)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x03: /* REQUEST_SENSE */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: RESPONSE: REQUEST_SENSE (%s)\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[0] & 7 ? "scsi compliant" : "not scsi compliant"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: ErrCd=%#RX8 (%s) Seg=%#RX8 Filemark=%d EOM=%d ILI=%d\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[0] & 0x7f, GetScsiErrCd(pb[0] & 0x7f), pb[1],
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[2] >> 7, !!(pb[2] & RT_BIT(6)), !!(pb[2] & RT_BIT(5))));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: SenseKey=%#x ASC=%#RX8 ASCQ=%#RX8 : %s\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[2] & 0xf, pb[12], pb[13],
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync GetScsiKCQ(pb[2] & 0xf, pb[12], pb[13])));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /** @todo more later */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x12: /* INQUIRY. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync unsigned cb = pb[4] + 5;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: RESPONSE: INQUIRY\n"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "URB: %*s: SCSI: PeripheralQualifier=%d PeripheralType=%#RX8 RMB=%d DevTypeMod=%#RX8\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[0] >> 5, pb[0] & 0x1f, pb[1] >> 7, pb[1] & 0x7f));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: ISOVer=%d ECMAVer=%d ANSIVer=%d\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[2] >> 6, (pb[2] >> 3) & 7, pb[2] & 7));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: AENC=%d TrmlOP=%d RespDataFmt=%d (%s) AddLen=%d\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[3] >> 7, (pb[3] >> 6) & 1,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pb[3] & 0xf, pb[3] & 0xf ? "legacy" : "scsi", pb[4]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb < 8)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: RelAdr=%d WBus32=%d WBus16=%d Sync=%d Linked=%d CmdQue=%d SftRe=%d\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, pb[7] >> 7, !!(pb[7] >> 6), !!(pb[7] >> 5), !!(pb[7] >> 4),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync !!(pb[7] >> 3), !!(pb[7] >> 1), pb[7] & 1));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb < 16)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: VendorId=%.8s\n", s_cchMaxMsg, pszMsg, &pb[8]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb < 32)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: ProductId=%.16s\n", s_cchMaxMsg, pszMsg, &pb[16]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb < 36)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: ProdRevLvl=%.4s\n", s_cchMaxMsg, pszMsg, &pb[32]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb > 36)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: VendorSpecific=%.*s\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, RT_MIN(cb - 36, 20), &pb[36]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb > 96)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: VendorParam=%.*Rhxs\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, cb - 96, &pb[96]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x25: /* Read Capacity(6) command. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: SCSI: RESPONSE: READ_CAPACITY\n"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync "URB: %*s: SCSI: LBA=%#RX32 BlockLen=%#RX32\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg, s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U32_FROM_U8(pb[3], pb[2], pb[1], pb[0]),
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RT_MAKE_U32_FROM_U8(pb[7], pb[6], pb[5], pb[4])));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pDev->Urb.u8ScsiCmd = 0xff;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * The Quickcam control pipe.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pSetup
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && ((pSetup->bmRequestType >> 5) & 0x3) >= 2 /* vendor */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && (fComplete || !(pSetup->bmRequestType >> 7))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pDev
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync && pDev->pDescCache
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pDev->pDescCache->pDevice
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pDev->pDescCache->pDevice->idVendor == 0x046d
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && ( pDev->pDescCache->pDevice->idProduct == 0x8f6
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pDev->pDescCache->pDevice->idProduct == 0x8f5
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pDev->pDescCache->pDevice->idProduct == 0x8f0)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync )
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pbData = (const uint8_t *)(pSetup + 1);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync cbData = pUrb->cbData - sizeof(*pSetup);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pSetup->bRequest == 0x04
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pSetup->wIndex == 0
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && (cbData == 1 || cbData == 2))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* the value */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync unsigned uVal = pbData[0];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cbData > 1)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uVal |= (unsigned)pbData[1] << 8;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const char *pszReg = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pSetup->wValue)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0: pszReg = "i2c init"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x0423: pszReg = "STV_REG23"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x0509: pszReg = "RED something"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x050a: pszReg = "GREEN something"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x050b: pszReg = "BLUE something"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x143f: pszReg = "COMMIT? INIT DONE?"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1440: pszReg = "STV_ISO_ENABLE"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1442: pszReg = uVal & (RT_BIT(7)|RT_BIT(5)) ? "BUTTON PRESSED" : "BUTTON" ; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1443: pszReg = "STV_SCAN_RATE"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1445: pszReg = "LED?"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1500: pszReg = "STV_REG00"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1501: pszReg = "STV_REG01"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1502: pszReg = "STV_REG02"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1503: pszReg = "STV_REG03"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1504: pszReg = "STV_REG04"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x15c1: pszReg = "STV_ISO_SIZE"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x15c3: pszReg = "STV_Y_CTRL"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0x1680: pszReg = "STV_X_CTRL"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case 0xe00a: pszReg = "ProductId"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default: pszReg = "[no clue]"; break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pszReg)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("URB: %*s: QUICKCAM: %s %#x (%d) %s '%s' (%#x)\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync (pSetup->bmRequestType >> 7) ? "read" : "write", uVal, uVal, (pSetup->bmRequestType >> 7) ? "from" : "to",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pszReg, pSetup->wValue));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if (cbData)
d72aa6b0dab3e9b60aa78bfca99c767c48a406b0vboxsync Log(("URB: %*s: QUICKCAM: Unknown request: bRequest=%#x bmRequestType=%#x wValue=%#x wIndex=%#x: %.*Rhxs\n", s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->bRequest, pSetup->bmRequestType, pSetup->wValue, pSetup->wIndex, cbData, pbData));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
d72aa6b0dab3e9b60aa78bfca99c767c48a406b0vboxsync Log(("URB: %*s: QUICKCAM: Unknown request: bRequest=%#x bmRequestType=%#x wValue=%#x wIndex=%#x: (no data)\n", s_cchMaxMsg, pszMsg,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->bRequest, pSetup->bmRequestType, pSetup->wValue, pSetup->wIndex));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#if 1
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( cbData /** @todo Fix RTStrFormatV to communicate .* so formatter doesn't apply defaults when cbData=0. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && (fComplete
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync ? pUrb->enmDir != VUSBDIRECTION_OUT
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync : pUrb->enmDir == VUSBDIRECTION_OUT))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log3(("%16.*Rhxd\n", cbData, pbData));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmType == VUSBXFERTYPE_MSG && pUrb->VUsb.pCtrlUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbTrace(pUrb->VUsb.pCtrlUrb, "NESTED MSG", fComplete);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif /* LOG_ENABLED */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Complete a SETUP stage URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * This is used both for dev2host and host2dev kind of transfers.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * It is used by both the sync and async control paths.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic void vusbMsgSetupCompletion(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBSETUP pSetup = pExtra->pMsg;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgSetupCompletion: cbData=%d wLength=%#x cbLeft=%d pPipe=%p stage %s->DATA\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pUrb->cbData, pSetup->wLength, pExtra->cbLeft, pPipe, g_apszCtlStates[pExtra->enmStage])); NOREF(pSetup);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->enmStage = CTLSTAGE_DATA;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_OK;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Complete a DATA stage URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * This is used both for dev2host and host2dev kind of transfers.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * It is used by both the sync and async control paths.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic void vusbMsgDataCompletion(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBSETUP pSetup = pExtra->pMsg;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgDataCompletion: cbData=%d wLength=%#x cbLeft=%d pPipe=%p stage DATA\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pUrb->cbData, pSetup->wLength, pExtra->cbLeft, pPipe)); NOREF(pSetup);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_OK;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Complete a STATUS stage URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * This is used both for dev2host and host2dev kind of transfers.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * It is used by both the sync and async control paths.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic void vusbMsgStatusCompletion(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pExtra->fOk)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * vusbDevStdReqSetAddress requests are deferred.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pDev->u8NewAddress != VUSB_INVALID_ADDRESS)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbDevSetAddress(pDev, pDev->u8NewAddress);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgStatusCompletion: pDev=%p[%s] pPipe=%p err=OK stage %s->SETUP\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, pPipe, g_apszCtlStates[pExtra->enmStage]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_OK;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgStatusCompletion: pDev=%p[%s] pPipe=%p err=STALL stage %s->SETUP\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, pPipe, g_apszCtlStates[pExtra->enmStage]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_STALL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Done with this message sequence.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->pbCur = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->enmStage = CTLSTAGE_SETUP;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * This is a worker function for vusbMsgCompletion and
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * vusbMsgSubmitSynchronously used to complete the original URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB originating from the HCI.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic void vusbCtrlCompletion(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbCtrlCompletion: pDev=%p[%s]\n", pUrb->pszDesc, pDev, pDev->pUsbIns->pszName));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pExtra->enmStage)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case CTLSTAGE_SETUP:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgSetupCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case CTLSTAGE_DATA:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgDataCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case CTLSTAGE_STATUS:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgStatusCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Called from vusbUrbCompletionRh when it encounters a
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * message type URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB within the control pipe extra state data.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic void vusbMsgCompletion(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef LOG_ENABLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgCompletion: pDev=%p[%s]\n", pUrb->pszDesc, pDev, pDev->pUsbIns->pszName));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbTrace(pUrb, "vusbMsgCompletion", true);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(&pExtra->Urb == pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmStatus == VUSBSTATUS_OK)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->fOk = true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->fOk = false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->cbLeft = pUrb->cbData - sizeof(VUSBSETUP);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Complete the original URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBURB pCtrlUrb = pUrb->VUsb.pCtrlUrb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pCtrlUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbCtrlCompletion(pCtrlUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * 'Free' the message URB, i.e. put it back to the allocated state.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert( pUrb->enmState == VUSBURBSTATE_REAPED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pUrb->enmState == VUSBURBSTATE_CANCELLED);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmState != VUSBURBSTATE_CANCELLED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_ALLOCATED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Deal with URB errors, talking thru the RH to the HCI.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns true if it could be retried.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns false if it should be completed with failure.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB in question.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic int vusbUrbErrorRh(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbErrorRh: pDev=%p[%s] rh=%p\n", pUrb->pszDesc, pDev, pDev->pUsbIns ? pDev->pUsbIns->pszName : "", pRh));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return pRh->pIRhPort->pfnXferError(pRh->pIRhPort, pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Does URB completion on roothub level.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB to complete.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncvoid vusbUrbCompletionRh(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbCompletionRh: type=%s status=%s\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, vusbUrbTypeName(pUrb->enmType), vusbUrbStatusName(pUrb->enmStatus)));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync AssertMsg( pUrb->enmState == VUSBURBSTATE_REAPED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pUrb->enmState == VUSBURBSTATE_CANCELLED, ("%d\n", pUrb->enmState));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef VBOX_WITH_STATISTICS
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Total and per-type submit statistics.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->VUsb.pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmType != VUSBXFERTYPE_MSG)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pUrb->enmStatus == VUSBSTATUS_OK
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pUrb->enmStatus == VUSBSTATUS_DATA_UNDERRUN
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pUrb->enmStatus == VUSBSTATUS_DATA_OVERRUN)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmType == VUSBXFERTYPE_ISOC)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const unsigned cb = pUrb->aIsocPkts[i].cb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->Total.StatActBytes, cb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->aTypes[VUSBXFERTYPE_ISOC].StatActBytes, cb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->aStatIsocDetails[i].Bytes, cb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmDir == VUSBDIRECTION_IN)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->Total.StatActReadBytes, cb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->aTypes[VUSBXFERTYPE_ISOC].StatActReadBytes, cb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->Total.StatActWriteBytes, cb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->aTypes[VUSBXFERTYPE_ISOC].StatActWriteBytes, cb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->StatIsocActPkts);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->StatIsocActReadPkts);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].Pkts);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pUrb->aIsocPkts[i].enmStatus)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBSTATUS_OK:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb) STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].Ok);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].Ok0); break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBSTATUS_DATA_UNDERRUN:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cb) STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].DataUnderrun);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].DataUnderrun0); break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBSTATUS_DATA_OVERRUN: STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].DataOverrun); break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBSTATUS_NOT_ACCESSED: STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].NotAccessed); break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default: STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].Misc); break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->Total.StatActBytes, pUrb->cbData);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatActBytes, pUrb->cbData);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmDir == VUSBDIRECTION_IN)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->Total.StatActReadBytes, pUrb->cbData);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatActReadBytes, pUrb->cbData);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->Total.StatActWriteBytes, pUrb->cbData);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatActWriteBytes, pUrb->cbData);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* (Note. this also counts the cancelled packets) */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->Total.StatUrbsFailed);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsFailed);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif /* VBOX_WITH_STATISTICS */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Msg transfers are special virtual transfers associated with
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * vusb, not the roothub
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pUrb->enmType)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBXFERTYPE_MSG:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBXFERTYPE_ISOC:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* Don't bother with error callback for isochronous URBs. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#if 1 /** @todo r=bird: OHCI say "If the Transfer Descriptor is being
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * retired because of an error, the Host Controller must update
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * the Halt bit of the Endpoint Descriptor."
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * So, I'll subject all transfertypes to the same halt stuff now. It could
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * just happen to fix the logitech disconnect trap in win2k.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBXFERTYPE_BULK:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmStatus != VUSBSTATUS_OK)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbErrorRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef LOG_ENABLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbTrace(pUrb, "vusbUrbCompletionRh", true);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifndef VBOX_WITH_STATISTICS
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->VUsb.pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /** @todo explain why we do this pDev change. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pTmp = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.pDev = &pRh->Hub.Dev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pRh->pIRhPort->pfnXferCompletion(pRh->pIRhPort, pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.pDev = pTmp;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmState == VUSBURBSTATE_REAPED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbCompletionRh: Freeing URB\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.pfnFree(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Certain control requests must not ever be forwarded to the device because
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * they are required by the vusb core in order to maintain the vusb internal
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * data structures.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncDECLINLINE(bool) vusbUrbIsRequestSafe(PCVUSBSETUP pSetup, PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ((pSetup->bmRequestType & VUSB_REQ_MASK) != VUSB_REQ_STANDARD)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pSetup->bRequest)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_REQ_CLEAR_FEATURE:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return pUrb->EndPt != 0 /* not default control pipe */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pSetup->wValue != 0 /* not ENDPOINT_HALT */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || !pUrb->pUsbIns->pReg->pfnUsbClearHaltedEndpoint; /* not special need for backend */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_REQ_SET_ADDRESS:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_REQ_SET_CONFIGURATION:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_REQ_GET_CONFIGURATION:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_REQ_SET_INTERFACE:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_REQ_GET_INTERFACE:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If the device wishes it, we'll use the cached device and
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * configuration descriptors. (We return false when we want to use the
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * cache. Yeah, it's a bit weird to read.)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_REQ_GET_DESCRIPTOR:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( !pUrb->VUsb.pDev->pDescCache->fUseCachedDescriptors
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || (pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pSetup->wValue >> 8)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_DEVICE:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_CONFIG:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSB_DT_STRING:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return !pUrb->VUsb.pDev->pDescCache->fUseCachedStringsDescriptors;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Queues an URB for asynchronous transfer.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * A list of asynchronous URBs is kept by the roothub.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns VBox status code (from pfnUrbQueue).
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncint vusbUrbQueueAsyncRh(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef LOG_ENABLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbTrace(pUrb, "vusbUrbQueueAsyncRh", false);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* Immediately return in case of error.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * XXX There is still a race: The Rh might vanish after this point! */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pRh)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("vusbUrbQueueAsyncRh returning VERR_OBJECT_DESTROYED\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return VERR_OBJECT_DESTROYED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync int rc = pUrb->pUsbIns->pReg->pfnUrbQueue(pUrb->pUsbIns, pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (RT_FAILURE(rc))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbQueueAsyncRh: returns %Rrc (queue_urb)\n", pUrb->pszDesc, rc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return rc;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pDev->aPipes[pUrb->EndPt].async++;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* Queue the pUrb on the roothub */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RTCritSectEnter(&pRh->CritSect);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.pNext = pRh->pAsyncUrbHead;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pRh->pAsyncUrbHead)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pRh->pAsyncUrbHead->VUsb.ppPrev = &pUrb->VUsb.pNext;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pRh->pAsyncUrbHead = pUrb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.ppPrev = &pRh->pAsyncUrbHead;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RTCritSectLeave(&pRh->CritSect);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return rc;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Send a control message *synchronously*.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @return
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic void vusbMsgSubmitSynchronously(PVUSBURB pUrb, bool fSafeRequest)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBSETUP pSetup = pExtra->pMsg;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgSubmitSynchronously: pDev=%p[%s]\n", pUrb->pszDesc, pDev, pDev->pUsbIns ? pDev->pUsbIns->pszName : ""));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t *pbData = (uint8_t *)pExtra->pMsg + sizeof(*pSetup);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t cbData = pSetup->wLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync bool fOk = false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!fSafeRequest)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync fOk = vusbDevStandardRequest(pDev, pUrb->EndPt, pSetup, pbData, &cbData);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync AssertMsgFailed(("oops\n"));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (fOk)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->wLength = cbData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_OK;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->fOk = true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_STALL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->fOk = false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->cbLeft = cbData; /* used by IN only */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbCtrlCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * 'Free' the message URB, i.e. put it back to the allocated state.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Callback for dealing with device reset.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncvoid vusbMsgResetExtraData(PVUSBCTRLEXTRA pExtra)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pExtra)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->enmStage = CTLSTAGE_SETUP;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pExtra->Urb.enmState != VUSBURBSTATE_CANCELLED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Callback to free a cancelled message URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * This is yet another place we're we have to performance acrobatics to
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * deal with cancelled URBs. sigh.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * The deal here is that we never free message URBs since they are integrated
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * into the message pipe state. But since cancel can leave URBs unreaped and in
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * a state which require them not to be freed, we'll have to do two things.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * First, if a new message URB is processed we'll have to get a new message
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * pipe state. Second, we cannot just free the damn state structure because
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * that might lead to heap corruption since it might still be in-flight.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * The URB embedded into the message pipe control structure will start in an
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * ALLOCATED state. When submitted it will be go to the IN-FLIGHT state. When
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * reaped it will go from REAPED to ALLOCATED. When completed in the CANCELLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * state it will remain in that state (as does normal URBs).
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If a new message urb comes up while it's in the CANCELLED state, we will
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * orphan it and it will be freed here in vusbMsgFreeUrb. We indicate this
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * by setting VUsb.pvFreeCtx to NULL.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If we have to free the message state structure because of device destruction,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * configuration changes, or similar, we will orphan the message pipe state in
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * the same way by setting VUsb.pvFreeCtx to NULL and let this function free it.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic DECLCALLBACK(void) vusbMsgFreeUrb(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbAssert(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = (PVUSBCTRLEXTRA)((uint8_t *)pUrb - RT_OFFSETOF(VUSBCTRLEXTRA, Urb));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pUrb->enmState == VUSBURBSTATE_CANCELLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && !pUrb->VUsb.pvFreeCtx)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("vusbMsgFreeUrb: Freeing orphan: %p (pUrb=%p)\n", pExtra, pUrb));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RTMemFree(pExtra);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pUrb->VUsb.pvFreeCtx == &pExtra->Urb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_ALLOCATED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Frees the extra state data associated with a message pipe.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pExtra The data.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncvoid vusbMsgFreeExtraData(PVUSBCTRLEXTRA pExtra)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pExtra)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pExtra->Urb.enmState != VUSBURBSTATE_CANCELLED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.u32Magic = 0;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmState = VUSBURBSTATE_FREE;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pExtra->Urb.pszDesc)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RTStrFree(pExtra->Urb.pszDesc);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RTMemFree(pExtra);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.VUsb.pvFreeCtx = NULL; /* see vusbMsgFreeUrb */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Allocates the extra state data required for a control pipe.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns Pointer to the allocated and initialized state data.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns NULL on out of memory condition.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb A URB we can copy default data from.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic PVUSBCTRLEXTRA vusbMsgAllocExtraData(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/** @todo reuse these? */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const size_t cbMax = sizeof(pExtra->Urb.abData) + sizeof(VUSBSETUP);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra = (PVUSBCTRLEXTRA)RTMemAllocZ(RT_OFFSETOF(VUSBCTRLEXTRA, Urb.abData[cbMax]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pExtra)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->enmStage = CTLSTAGE_SETUP;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->fOk = false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->pMsg = (PVUSBSETUP)pExtra->Urb.abData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->pbCur = (uint8_t *)(pExtra->pMsg + 1);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->cbLeft = 0;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->cbMax = cbMax;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->Urb.Dev.pvProxyUrb = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.u32Magic = VUSBURB_MAGIC;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef LOG_ENABLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync RTStrAPrintf(&pExtra->Urb.pszDesc, "URB %p msg->%p", &pExtra->Urb, pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->Urb.VUsb.pCtrlUrb = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->Urb.VUsb.pNext = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->Urb.VUsb.ppPrev = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.VUsb.pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.VUsb.pfnFree = vusbMsgFreeUrb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.VUsb.pvFreeCtx = &pExtra->Urb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->Urb.Hci = {0};
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->Urb.Dev.pvProxyUrb = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.pUsbIns = pUrb->pUsbIns;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.DstAddress = pUrb->DstAddress;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.EndPt = pUrb->EndPt;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmType = VUSBXFERTYPE_MSG;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmDir = VUSBDIRECTION_INVALID;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->Urb.fShortNotOk = false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmStatus = VUSBSTATUS_INVALID;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync //pExtra->Urb.cbData = 0;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbAssert(&pExtra->Urb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return pExtra;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Sets up the message.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * The message is associated with the pipe, in what's currently called
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * control pipe extra state data (pointed to by pPipe->pCtrl). If this
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * is a OUT message, we will no go on collecting data URB. If it's a
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * IN message, we'll send it and then queue any incoming data for the
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * URBs collecting it.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns Success indicator.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic bool vusbMsgSetup(PVUSBPIPE pPipe, const void *pvBuf, uint32_t cbBuf)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const VUSBSETUP *pSetupIn = (PVUSBSETUP)pvBuf;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Validate length.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (cbBuf < sizeof(VUSBSETUP))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("vusbMsgSetup: pPipe=%p cbBuf=%u < %u (failure) !!!\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pPipe, cbBuf, sizeof(VUSBSETUP)));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Check if we've got an cancelled message URB. Allocate a new one in that case.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pExtra->Urb.enmState == VUSBURBSTATE_CANCELLED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync void *pvNew = RTMemDup(pExtra, RT_OFFSETOF(VUSBCTRLEXTRA, Urb.abData[pExtra->cbMax]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pvNew)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("vusbMsgSetup: out of memory!!! cbReq=%u\n", RT_OFFSETOF(VUSBCTRLEXTRA, Urb.abData[pExtra->cbMax])));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.VUsb.pvFreeCtx = NULL;
d72aa6b0dab3e9b60aa78bfca99c767c48a406b0vboxsync LogFlow(("vusbMsgSetup: Replacing canceled pExtra=%p with %p.\n", pExtra, pvNew));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pPipe->pCtrl = pExtra = (PVUSBCTRLEXTRA)pvNew;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->pMsg = (PVUSBSETUP)pExtra->Urb.abData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Check that we've got sufficient space in the message URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pExtra->cbMax < cbBuf + pSetupIn->wLength)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint32_t cbReq = RT_ALIGN_32(cbBuf + pSetupIn->wLength, 1024);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pNew = (PVUSBCTRLEXTRA)RTMemRealloc(pExtra, RT_OFFSETOF(VUSBCTRLEXTRA, Urb.abData[cbReq]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pNew)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("vusbMsgSetup: out of memory!!! cbReq=%u %u\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync cbReq, RT_OFFSETOF(VUSBCTRLEXTRA, Urb.abData[cbReq])));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pExtra != pNew)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pNew->pMsg = (PVUSBSETUP)pNew->Urb.abData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra = pNew;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->cbMax = cbReq;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pExtra->Urb.enmState == VUSBURBSTATE_ALLOCATED);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Copy the setup data and prepare for data.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBSETUP pSetup = pExtra->pMsg;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->fSubmitted = false;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmState = VUSBURBSTATE_IN_FLIGHT;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->pbCur = (uint8_t *)(pSetup + 1);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->bmRequestType = pSetupIn->bmRequestType;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->bRequest = pSetupIn->bRequest;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->wValue = RT_LE2H_U16(pSetupIn->wValue);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->wIndex = RT_LE2H_U16(pSetupIn->wIndex);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->wLength = RT_LE2H_U16(pSetupIn->wLength);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("vusbMsgSetup(%p,,%d): bmRequestType=%#04x bRequest=%#04x wValue=%#06x wIndex=%#06x wLength=%d\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pPipe, cbBuf, pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Build the message URB from the given control URB and accompanying message
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * pipe state which we grab from the device for the URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB to submit.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic void vusbMsgDoTransfer(PVUSBURB pUrb, PVUSBSETUP pSetup, PVUSBCTRLEXTRA pExtra, PVUSBPIPE pPipe, PVUSBDEV pDev)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Mark this transfer as sent (cleared at setup time).
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(!pExtra->fSubmitted);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->fSubmitted = true;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Do we have to do this synchronously?
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync bool fSafeRequest = vusbUrbIsRequestSafe(pSetup, pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!fSafeRequest)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgSubmitSynchronously(pUrb, fSafeRequest);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Do it asynchronously.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgDoTransfer: ep=%d pMsgUrb=%p pPipe=%p stage=%s\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pUrb->EndPt, &pExtra->Urb, pPipe, g_apszCtlStates[pExtra->enmStage]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pExtra->Urb.enmType == VUSBXFERTYPE_MSG);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pExtra->Urb.EndPt == pUrb->EndPt);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmDir = (pSetup->bmRequestType & VUSB_DIR_TO_HOST) ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.cbData = pSetup->wLength + sizeof(*pSetup);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.VUsb.pCtrlUrb = pUrb;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync int rc = vusbUrbQueueAsyncRh(&pExtra->Urb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (RT_FAILURE(rc))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If we fail submitting it, will not retry but fail immediately.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * This keeps things simple. The host OS will have retried if
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * it's a proxied device, and if it's a virtual one it really means
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * it if it's failing a control message.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgDoTransfer: failed submitting urb! failing it with %s (rc=%Rrc)!!!\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, rc == VERR_VUSB_DEVICE_NOT_ATTACHED ? "DNR" : "CRC", rc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmStatus = rc == VERR_VUSB_DEVICE_NOT_ATTACHED ? VUSBSTATUS_DNR : VUSBSTATUS_CRC;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->Urb.enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgCompletion(&pExtra->Urb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Fails a URB request with a pipe STALL error.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns VINF_SUCCESS indicating that we've completed the URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB in question.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic int vusbMsgStall(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pUrb->VUsb.pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbMsgStall: pPipe=%p err=STALL stage %s->SETUP\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->pbCur = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->enmStage = CTLSTAGE_SETUP;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_STALL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return VINF_SUCCESS;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Submit a control message.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Here we implement the USB defined traffic that occurs in message pipes
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * (aka control endpoints). We want to provide a single function for device
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * drivers so that they don't all have to reimplement the usb logic for
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * themselves. This means we need to keep a little bit of state information
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * because control transfers occur over multiple bus transactions. We may
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * also need to buffer data over multiple data stages.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns VBox status code.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB to submit.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic int vusbUrbSubmitCtrl(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef LOG_ENABLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbTrace(pUrb, "vusbUrbSubmitCtrl", false);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pExtra && !(pExtra = pPipe->pCtrl = vusbMsgAllocExtraData(pUrb)))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return VERR_VUSB_NO_URB_MEMORY;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBSETUP pSetup = pExtra->pMsg;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync AssertMsgReturn(!pPipe->async, ("%u\n", pPipe->async), VERR_GENERAL_FAILURE);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * A setup packet always resets the transaction and the
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * end of data transmission is signified by change in
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * data direction.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmDir == VUSBDIRECTION_SETUP)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitCtrl: pPipe=%p state %s->SETUP\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->enmStage = CTLSTAGE_SETUP;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if ( pExtra->enmStage == CTLSTAGE_DATA
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* (the STATUS stage direction goes the other way) */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && !!(pSetup->bmRequestType & VUSB_DIR_TO_HOST) != (pUrb->enmDir == VUSBDIRECTION_IN))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitCtrl: pPipe=%p state %s->STATUS\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->enmStage = CTLSTAGE_STATUS;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Act according to the current message stage.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pExtra->enmStage)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case CTLSTAGE_SETUP:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * When stall handshake is returned, all subsequent packets
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * must generate stall until a setup packet arrives.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmDir != VUSBDIRECTION_SETUP)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("%s: vusbUrbSubmitCtrl: Stall at setup stage (dir=%#x)!!\n", pUrb->pszDesc, pUrb->enmDir));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbMsgStall(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* Store setup details, return DNR if corrupt */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!vusbMsgSetup(pPipe, pUrb->abData, pUrb->cbData))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_DNR;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return VINF_SUCCESS;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pPipe->pCtrl != pExtra)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra = pPipe->pCtrl;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup = pExtra->pMsg;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* pre-buffer our output if it's device-to-host */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe, pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if (pSetup->wLength)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitCtrl: stage=SETUP - to dev: need data\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgSetupCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If there is no DATA stage, we must send it now since there are
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * no requirement of a STATUS stage.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitCtrl: stage=SETUP - to dev: sending\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe, pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case CTLSTAGE_DATA:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If a data stage exceeds the target buffer indicated in
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * setup return stall, if data stage returns stall there
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * will be no status stage.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t *pbData = (uint8_t *)(pExtra->pMsg + 1);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (&pExtra->pbCur[pUrb->cbData] > &pbData[pSetup->wLength])
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pSetup->wLength) /* happens during iPhone detection with iTunes (correct?) */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("%s: vusbUrbSubmitCtrl: pSetup->wLength == 0!! (iPhone)\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pSetup->wLength = pUrb->cbData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* Variable length data transfers */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pSetup->wLength == 0
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || (pUrb->cbData % pSetup->wLength) == 0) /* magic which need explaining... */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync uint8_t *pbEnd = pbData + pSetup->wLength;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync int cbLeft = pbEnd - pExtra->pbCur;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitCtrl: Var DATA, pUrb->cbData %d -> %d\n", pUrb->pszDesc, pUrb->cbData, cbLeft));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->cbData = cbLeft;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("%s: vusbUrbSubmitCtrl: Stall at data stage!!\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbMsgStall(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmDir == VUSBDIRECTION_IN)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* put data received from the device. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const uint32_t cbRead = RT_MIN(pUrb->cbData, pExtra->cbLeft);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync memcpy(pUrb->abData, pExtra->pbCur, cbRead);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* advance */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->pbCur += cbRead;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->cbData == cbRead)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->cbLeft -= pUrb->cbData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* adjust the pUrb->cbData to reflect the number of bytes containing actual data. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitCtrl: adjusting last DATA pUrb->cbData, %d -> %d\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pUrb->cbData, pExtra->cbLeft));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->cbData = cbRead;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->cbLeft = 0;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* get data for sending when completed. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync memcpy(pExtra->pbCur, pUrb->abData, pUrb->cbData);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* advance */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pExtra->pbCur += pUrb->cbData;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If we've got the necessary data, we'll send it now since there are
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * no requirement of a STATUS stage.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( !pExtra->fSubmitted
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && pExtra->pbCur - pbData >= pSetup->wLength)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitCtrl: stage=DATA - to dev: sending\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe, pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgDataCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case CTLSTAGE_STATUS:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pExtra->fSubmitted)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pExtra->fSubmitted);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgStatusCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitCtrl: stage=STATUS - to dev: sending\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe, pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return VINF_SUCCESS;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Submit a interrupt URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns VBox status code.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB to submit.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic int vusbUrbSubmitInterrupt(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitInterrupt: (sync)\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbUrbQueueAsyncRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Submit a bulk URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns VBox status code.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB to submit.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic int vusbUrbSubmitBulk(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitBulk: (async)\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbUrbQueueAsyncRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Submit an isochronous URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @returns VBox status code.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB to submit.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic int vusbUrbSubmitIsochronous(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbSubmitIsochronous: (async)\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbUrbQueueAsyncRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Fail a URB with a 'hard-error' sort of error.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @return VINF_SUCCESS (the Urb status indicates the error).
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic int vusbUrbSubmitHardError(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* FIXME: Find out the correct return code from the spec */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_DNR;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return VINF_SUCCESS;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Submit a URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncint vusbUrbSubmit(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbAssert(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pUrb->enmState == VUSBURBSTATE_ALLOCATED);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBPIPE pPipe = NULL;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Check that the device is in a valid state.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync const VUSBDEVICESTATE enmState = pDev->enmState;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (enmState == VUSB_DEVICE_STATE_RESET)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_DNR;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* This will postpone the TDs until we're done with the resetting. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return VERR_VUSB_DEVICE_IS_RESETTING;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef LOG_ENABLED
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* stamp it */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.u64SubmitTS = RTTimeNanoTS();
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /** @todo Check max packet size here too? */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Validate the pipe.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->EndPt >= VUSB_PIPE_MAX)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("%s: pDev=%p[%s]: SUBMIT: ep %i >= %i!!!\n", pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, pUrb->EndPt, VUSB_PIPE_MAX));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbUrbSubmitHardError(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PCVUSBDESCENDPOINTEX pEndPtDesc;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pUrb->enmDir)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBDIRECTION_IN:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pEndPtDesc = pDev->aPipes[pUrb->EndPt].in;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pPipe = &pDev->aPipes[pUrb->EndPt];
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBDIRECTION_SETUP:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBDIRECTION_OUT:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pEndPtDesc = pDev->aPipes[pUrb->EndPt].out;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (!pEndPtDesc)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("%s: pDev=%p[%s]: SUBMIT: no endpoint!!! dir=%s e=%i\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, vusbUrbDirName(pUrb->enmDir), pUrb->EndPt));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbUrbSubmitHardError(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Check for correct transfer types.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Our type codes are the same - what a coincidence.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ((pEndPtDesc->Core.bmAttributes & 0x3) != pUrb->enmType)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Log(("%s: pDev=%p[%s]: SUBMIT: %s transfer requested for %#x endpoint on DstAddress=%i ep=%i dir=%s\n",
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, vusbUrbTypeName(pUrb->enmType), pEndPtDesc->Core.bmAttributes,
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->DstAddress, pUrb->EndPt, vusbUrbDirName(pUrb->enmDir)));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbUrbSubmitHardError(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If there's a URB in the read-ahead buffer, use it.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync int rc;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef VBOX_WITH_USB
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pPipe && pPipe->pBuffUrbHead)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync rc = vusbUrbSubmitBufferedRead(pUrb, pPipe);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return rc;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Take action based on type.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_IN_FLIGHT;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync switch (pUrb->enmType)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBXFERTYPE_CTRL:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync rc = vusbUrbSubmitCtrl(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBXFERTYPE_BULK:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync rc = vusbUrbSubmitBulk(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBXFERTYPE_INTR:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync rc = vusbUrbSubmitInterrupt(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync case VUSBXFERTYPE_ISOC:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync rc = vusbUrbSubmitIsochronous(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync break;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync default:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync AssertMsgFailed(("Unexpected pUrb type %d\n", pUrb->enmType));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return vusbUrbSubmitHardError(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * The device was detached, so we fail everything.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * (We should really detach and destroy the device, but we'll have to wait till Main reacts.)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (rc == VERR_VUSB_DEVICE_NOT_ATTACHED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync rc = vusbUrbSubmitHardError(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * We don't increment error count if async URBs are in flight, in
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * this case we just assume we need to throttle back, this also
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * makes sure we don't halt bulk endpoints at the wrong time.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if ( RT_FAILURE(rc)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && !pDev->aPipes[pUrb->EndPt].async
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* && pUrb->enmType == VUSBXFERTYPE_BULK ?? */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync && !vusbUrbErrorRh(pUrb))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* don't retry it anymore. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_CRC;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return VINF_SUCCESS;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync return rc;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Reap in-flight URBs.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pHead Pointer to the head of the URB list.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param cMillies Number of milliseconds to block in each reap operation.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Use 0 to not block at all.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncvoid vusbUrbDoReapAsync(PVUSBURB pHead, RTMSINTERVAL cMillies)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBURB pUrb = pHead;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync while (pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbAssert(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBURB pUrbNext = pUrb->VUsb.pNext;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBDEV pDev = pUrb->VUsb.pDev;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* Don't touch resetting devices - paranoid safety precaution. */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pDev->enmState != VUSB_DEVICE_STATE_RESET)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Reap most URBs pending on a single device.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBURB pRipe;
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync /**
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync * This is workaround for race(should be fixed) detach on one EMT thread and frame boundary timer on other
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync * and leaked URBs (shouldn't be affected by leaked URBs).
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync */
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync Assert(pDev->pUsbIns);
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync while ( pDev->pUsbIns
8fff4af98a6c0e8e4e61f788d4fd56070879ae40vboxsync && ((pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, cMillies)) != NULL))
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbAssert(pRipe);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pRipe == pUrbNext)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrbNext = pUrbNext->VUsb.pNext;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbRipe(pRipe);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync /* next */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb = pUrbNext;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Completes the URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncstatic void vusbUrbCompletion(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pUrb->VUsb.pDev->aPipes);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.pDev->aPipes[pUrb->EndPt].async--;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmState == VUSBURBSTATE_REAPED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbUnlink(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef VBOX_WITH_USB
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync // Read-ahead URBs are handled differently
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->Hci.pNext != NULL)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionReadAhead(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletionRh(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Cancels an URB with CRC failure.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Cancelling an URB is a tricky thing. The USBProxy backend can not
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * all cancel it and we must keep the URB around until it's ripe and
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * can be reaped the normal way. However, we must complete the URB
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * now, before leaving this function. This is not nice. sigh.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * This function will cancel the URB if it's in-flight and complete
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * it. The device will in its pfnCancel method be given the chance to
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * say that the URB doesn't need reaping and should be unlinked.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * An URB which is in the cancel state after pfnCancel will remain in that
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * state and in the async list until its reaped. When it's finally reaped
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * it will be unlinked and freed without doing any completion.
b35e3948f1287430503b6b432945b8cf4bfd3a23vboxsync *
abe2f4a16e43726264648542b029e782337fbc9cvboxsync * There are different modes of canceling an URB. When devices are being
abe2f4a16e43726264648542b029e782337fbc9cvboxsync * disconnected etc., they will be completed with an error (CRC). However,
abe2f4a16e43726264648542b029e782337fbc9cvboxsync * when the HC needs to temporarily halt communication with a device, the
abe2f4a16e43726264648542b029e782337fbc9cvboxsync * URB/TD must be left alone if possible.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB to cancel.
abe2f4a16e43726264648542b029e782337fbc9cvboxsync * @param mode The way the URB should be canceled.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
abe2f4a16e43726264648542b029e782337fbc9cvboxsyncvoid vusbUrbCancel(PVUSBURB pUrb, CANCELMODE mode)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbAssert(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#ifdef VBOX_WITH_STATISTICS
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->VUsb.pDev);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync#endif
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmState == VUSBURBSTATE_IN_FLIGHT)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbCancel: Canceling in-flight\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->Total.StatUrbsCancelled);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmType != VUSBXFERTYPE_MSG)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_STATS({Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));});
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsCancelled);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_CANCELLED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync PPDMUSBINS pUsbIns = pUrb->pUsbIns;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUsbIns->pReg->pfnUrbCancel(pUsbIns, pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync Assert(pUrb->enmState == VUSBURBSTATE_CANCELLED || pUrb->enmState == VUSBURBSTATE_REAPED);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_CRC;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if (pUrb->enmState == VUSBURBSTATE_REAPED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbCancel: Canceling reaped urb\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->Total.StatUrbsCancelled);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if (pUrb->enmType != VUSBXFERTYPE_MSG)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_STATS({Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));});
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsCancelled);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmStatus = VUSBSTATUS_CRC;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync AssertMsg(pUrb->enmState == VUSBURBSTATE_CANCELLED, ("Invalid state %d, pUrb=%p\n", pUrb->enmState, pUrb));
abe2f4a16e43726264648542b029e782337fbc9cvboxsync switch (mode)
abe2f4a16e43726264648542b029e782337fbc9cvboxsync {
abe2f4a16e43726264648542b029e782337fbc9cvboxsync default:
abe2f4a16e43726264648542b029e782337fbc9cvboxsync AssertMsgFailed(("Invalid cancel mode\n"));
abe2f4a16e43726264648542b029e782337fbc9cvboxsync case CANCELMODE_FAIL:
abe2f4a16e43726264648542b029e782337fbc9cvboxsync pUrb->enmStatus = VUSBSTATUS_CRC;
abe2f4a16e43726264648542b029e782337fbc9cvboxsync break;
abe2f4a16e43726264648542b029e782337fbc9cvboxsync case CANCELMODE_UNDO:
abe2f4a16e43726264648542b029e782337fbc9cvboxsync pUrb->enmStatus = VUSBSTATUS_UNDO;
abe2f4a16e43726264648542b029e782337fbc9cvboxsync break;
abe2f4a16e43726264648542b029e782337fbc9cvboxsync
abe2f4a16e43726264648542b029e782337fbc9cvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/**
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Deals with a ripe URB (i.e. after reaping it).
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * If an URB is in the reaped or in-flight state, we'll
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * complete it. If it's cancelled, we'll simply free it.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Any other states should never get here.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync *
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * @param pUrb The URB.
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsyncvoid vusbUrbRipe(PVUSBURB pUrb)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync{
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync if ( pUrb->enmState == VUSBURBSTATE_IN_FLIGHT
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync || pUrb->enmState == VUSBURBSTATE_REAPED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->enmState = VUSBURBSTATE_REAPED;
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbCompletion(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else if (pUrb->enmState == VUSBURBSTATE_CANCELLED)
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync {
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync vusbUrbUnlink(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync LogFlow(("%s: vusbUrbRipe: Freeing cancelled URB\n", pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync pUrb->VUsb.pfnFree(pUrb);
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync }
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync else
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync AssertMsgFailed(("Invalid URB state %d; %s\n", pUrb->enmState, pUrb->pszDesc));
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync}
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync/*
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * Local Variables:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * mode: c
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * c-file-style: "bsd"
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * c-basic-offset: 4
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * tab-width: 4
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * indent-tabs-mode: s
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync * End:
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync */
cb4a18edeb5422163b264fe5a66276769cfe864dvboxsync