20#include "modules/system/usb/UsbDevice.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/time/Time.h"
23#include "pedigree/kernel/utilities/PointerGuard.h"
24#include "pedigree/kernel/utilities/assert.h"
25#include "pedigree/kernel/utilities/new"
27#include "modules/system/usb/Usb.h"
28#include "modules/system/usb/UsbConstants.h"
29#include "modules/system/usb/UsbDescriptors.h"
30#include "modules/system/usb/UsbHub.h"
31#include "modules/system/usb/UsbPnP.h"
33#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
39 m_ControlPacketSize(speed == SuperSpeed ? 512
40 : speed == HighSpeed ? 64
44 m_nRootPortGeneration(0),
46 m_UsbState(Connected),
55 m_nRootPortGeneration = connection.generation;
60 : m_nAddress(pDev->m_nAddress),
61 m_ControlPacketSize(pDev->m_ControlPacketSize),
62 m_nPort(pDev->m_nPort),
63 m_nRootPort(pDev->m_nRootPort),
64 m_nRootPortGeneration(pDev->m_nRootPortGeneration),
65 m_Speed(pDev->m_Speed),
66 m_UsbState(pDev->m_UsbState),
67 m_pDescriptor(pDev->m_pDescriptor),
68 m_pConfiguration(pDev->m_pConfiguration),
69 m_pInterface(pDev->m_pInterface),
71 m_pContainer(nullptr) {
82UsbDevice::DeviceDescriptor::DeviceDescriptor(
UsbDeviceDescriptor* pDescriptor) : m_References(1) {
83 nBcdUsbRelease = pDescriptor->nBcdUsbRelease;
84 nClass = pDescriptor->nClass;
85 nSubclass = pDescriptor->nSubclass;
86 nProtocol = pDescriptor->nProtocol;
87 nMaxControlPacketSize = pDescriptor->nMaxControlPacketSize;
88 nVendorId = pDescriptor->nVendorId;
89 nProductId = pDescriptor->nProductId;
90 nBcdDeviceRelease = pDescriptor->nBcdDeviceRelease;
91 nVendorString = pDescriptor->nVendorString;
92 nProductString = pDescriptor->nProductString;
93 nSerialString = pDescriptor->nSerialString;
94 nConfigurations = pDescriptor->nConfigurations;
96 delete[]
reinterpret_cast<uint8_t*
>(pDescriptor);
99UsbDevice::DeviceDescriptor::~DeviceDescriptor() {
100#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
101 g_HostedUsbDescriptorDestructions += 1;
103 for (
size_t i = 0; i < configList.count(); i++)
104 delete configList[i];
107void UsbDevice::DeviceDescriptor::retain() {
111void UsbDevice::DeviceDescriptor::release() {
112 const size_t remaining = m_References -= 1;
113 assert(remaining !=
static_cast<size_t>(-1));
118UsbDevice::ConfigDescriptor::ConfigDescriptor(
void* pConfigBuffer,
size_t nConfigLength,
120 : nConfig(0), nString(0), valid(false) {
121 auto* buffer =
static_cast<uint8_t*
>(pConfigBuffer);
125 buffer[1] != UsbDescriptor::Configuration)
128 nConfig = descriptor->nConfig;
129 nString = descriptor->nString;
130 Interface* current =
nullptr;
131 Endpoint* precedingEndpoint =
nullptr;
132 for (
size_t offset = buffer[0]; offset < nConfigLength;) {
133 if (nConfigLength - offset < 2)
135 const size_t length = buffer[offset];
136 const uint8_t type = buffer[offset + 1];
137 if (length < 2 || length > nConfigLength - offset)
139 if (speed == SuperSpeed && precedingEndpoint && !precedingEndpoint->hasCompanion &&
142 if (type == UsbDescriptor::Interface) {
146 interfaceList.pushBack(current);
147 }
else if (type == UsbDescriptor::Endpoint) {
152 const bool interrupt = endpoint->nTransferType == Endpoint::Interrupt;
153 const bool bulk = endpoint->nTransferType == Endpoint::Bulk;
154 const size_t maximum = speed == LowSpeed ? 8
156 ? (endpoint->nTransferType == Endpoint::Isochronus ? 1023 : 64)
158 const uint16_t packetField = buffer[offset + 4] | (uint16_t{buffer[offset + 5]} << 8);
159 if (!endpoint->nEndpoint || !endpoint->nMaxPacketSize || endpoint->nMaxPacketSize > maximum ||
160 (packetField & 0xe000U) || ((packetField & 0x1800U) == 0x1800U) ||
161 (speed == LowSpeed && !interrupt) ||
162 (bulk && speed == HighSpeed && endpoint->nMaxPacketSize != 512) ||
163 (bulk && speed == SuperSpeed && endpoint->nMaxPacketSize != 1024) ||
164 (speed == SuperSpeed && (packetField & 0x1800U)) ||
165 (interrupt && (!endpoint->nInterval || ((speed == HighSpeed || speed == SuperSpeed) &&
166 endpoint->nInterval > 16)))) {
170 current->endpointList.pushBack(endpoint);
171 precedingEndpoint = endpoint;
172 }
else if (type == 0x30 && speed == SuperSpeed) {
173 if (!precedingEndpoint || precedingEndpoint->hasCompanion || length < 6 ||
174 buffer[offset + 2] > 15)
176 const uint8_t attributes = buffer[offset + 3];
177 const uint16_t intervalBytes = buffer[offset + 4] | (uint16_t{buffer[offset + 5]} << 8);
178 const bool bulk = precedingEndpoint->nTransferType == Endpoint::Bulk;
179 const bool interrupt = precedingEndpoint->nTransferType == Endpoint::Interrupt;
180 if ((bulk && ((attributes & 0xe0U) || (attributes & 31U) > 16 || intervalBytes)) ||
182 (attributes || !intervalBytes ||
183 intervalBytes > (buffer[offset + 2] + 1U) * precedingEndpoint->nMaxPacketSize)))
185 precedingEndpoint->nMaxBurst = buffer[offset + 2];
186 precedingEndpoint->nStreams =
187 precedingEndpoint->nTransferType == Endpoint::Bulk ? buffer[offset + 3] & 31U : 0;
188 precedingEndpoint->nBytesPerInterval =
189 buffer[offset + 4] | (uint16_t{buffer[offset + 5]} << 8);
190 precedingEndpoint->hasCompanion =
true;
192 current->otherDescriptorList.pushBack(
new UnknownDescriptor(buffer + offset, type, length));
194 otherDescriptorList.pushBack(
new UnknownDescriptor(buffer + offset, type, length));
197 if (speed == SuperSpeed && precedingEndpoint && !precedingEndpoint->hasCompanion)
199 valid = nConfig && interfaceList.count();
202UsbDevice::ConfigDescriptor::~ConfigDescriptor() {
203 for (
size_t i = 0; i < interfaceList.count(); i++)
204 delete interfaceList[i];
205 for (
size_t i = 0; i < otherDescriptorList.count(); i++)
206 delete otherDescriptorList[i];
210 nInterface = pDescriptor->nInterface;
211 nAlternateSetting = pDescriptor->nAlternateSetting;
212 nClass = pDescriptor->nClass;
213 nSubclass = pDescriptor->nSubclass;
214 nProtocol = pDescriptor->nProtocol;
215 nString = pDescriptor->nString;
218UsbDevice::Interface::~Interface() {
219 for (
size_t i = 0; i < endpointList.count(); i++)
220 delete endpointList[i];
221 for (
size_t i = 0; i < otherDescriptorList.count(); i++)
222 delete otherDescriptorList[i];
226 : bDataToggle(false) {
227 nEndpoint = pDescriptor->nEndpoint;
228 bIn = pDescriptor->bDirection;
230 nTransferType = pDescriptor->nTransferType;
231 nMaxPacketSize = LITTLE_TO_HOST16(pDescriptor->nMaxPacketSize) & 0x7ff;
232 nInterval = pDescriptor->nInterval;
233 const auto* raw =
reinterpret_cast<const uint8_t*
>(pDescriptor);
234 nTransactions = ((raw[5] >> 3) & 3U) + 1;
241 "USB: UsbDevice::initialise called, but this device is already "
247 Time::delay(10 * Time::Multiplier::Millisecond);
250 control.nRootPortGeneration = m_nRootPortGeneration;
251 if (!
m_pHub || !
m_pHub->prepareDevice(nAddress, control))
254 auto* prefix =
static_cast<uint8_t*
>(
getDescriptor(UsbDescriptor::Device, 0, 8));
257 const uint8_t packetSize = prefix[7];
260 ((
m_Speed == HighSpeed && packetSize == 64) || (
m_Speed == LowSpeed && packetSize == 8) ||
261 (
m_Speed == SuperSpeed && packetSize == 9) ||
263 (packetSize == 8 || packetSize == 16 || packetSize == 32 || packetSize == 64)));
267 m_ControlPacketSize =
m_Speed == SuperSpeed ? 512 : packetSize;
268 control.nMaxPacketSize = m_ControlPacketSize;
269 if (
m_pHub->controllerAssignsAddresses()
270 ? !
m_pHub->addressDevice(nAddress, control)
275 Time::delay(2 * Time::Multiplier::Millisecond);
277 if (!pDeviceDescriptor)
281 WARNING(
"USB: external hubs are unsupported by this controller");
288 DEBUG_LOG(
"USB version: " <<
Dec << (
m_pDescriptor->nBcdUsbRelease >> 8) <<
"."
290 DEBUG_LOG(
"Device class/subclass/protocol: " <<
m_pDescriptor->nClass <<
"/"
293 DEBUG_LOG(
"Maximum control packet size is " <<
Dec <<
m_pDescriptor->nMaxControlPacketSize
294 <<
Hex <<
" bytes.");
295 DEBUG_LOG(
"Vendor and product IDs: " <<
m_pDescriptor->nVendorId <<
":"
297 DEBUG_LOG(
"Device version: " <<
Dec << (
m_pDescriptor->nBcdDeviceRelease >> 8) <<
"."
299 DEBUG_LOG(
"Number of configurations: " <<
m_pDescriptor->nConfigurations <<
".");
300 DEBUG_LOG(
"String indices: " <<
m_pDescriptor->nVendorString <<
", "
306 uint8_t nConfigDescriptor = UsbDescriptor::Configuration;
314 for (
size_t i = 0; i <
m_pDescriptor->nConfigurations; i++) {
317 WARNING(
"USB: Found a device with multiple configurations!");
322 uint16_t* pPartialConfig =
static_cast<uint16_t*
>(
getDescriptor(nConfigDescriptor, i, 4));
325 uint16_t configLength = LITTLE_TO_HOST16(pPartialConfig[1]);
326 delete[]
reinterpret_cast<uint8_t*
>(pPartialConfig);
334 if (!pConfig->valid) {
339 pConfig->sString =
getString(pConfig->nString);
342 for (
size_t j = 0; j < pConfig->interfaceList.count(); j++) {
344 Interface* pInterface = pConfig->interfaceList[j];
345 if (pInterface->nClass == 9 && !
m_pHub->supportsHubDevices()) {
346 WARNING(
"USB: external hubs are unsupported by this controller");
352 if (pConfig->interfaceList.count() == 1 &&
m_pDescriptor->nClass && !pInterface->nClass) {
359 pInterface->sString =
getString(pInterface->nString);
363 assert(pConfig->interfaceList.count());
377 size_t nBytes,
size_t timeout) {
378 if (!pEndpoint || !pEndpoint->nMaxPacketSize) {
379 ERROR(
"USB: UsbDevice::doSync called with invalid endpoint");
380 return -TransactionError;
385 ERROR(
"USB: Orphaned UsbDevice!");
386 return -TransactionError;
393 ERROR(
"USB: Input pointer wasn't properly aligned [" << pBuffer <<
", " << nBytes <<
"]");
394 return -TransactionError;
398 pEndpoint->nMaxPacketSize);
399 endpointInfo.nTransferType = pEndpoint->nTransferType;
400 endpointInfo.nIn = pEndpoint->bIn;
401 endpointInfo.nInterval = pEndpoint->nInterval;
402 endpointInfo.nMaxBurst = pEndpoint->nMaxBurst;
403 endpointInfo.nStreams = pEndpoint->nStreams;
404 endpointInfo.nBytesPerInterval = pEndpoint->nBytesPerInterval;
406 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
408 if (nTransaction ==
static_cast<uintptr_t
>(-1)) {
410 "UsbDevice: couldn't get a valid transaction to work with from "
412 return -TransactionError;
415 const bool initialToggle = pEndpoint->bDataToggle;
416 const size_t requested = nBytes;
417 size_t byteOffset = 0;
419 size_t nBytesThisTransaction =
420 nBytes > pEndpoint->nMaxPacketSize ? pEndpoint->nMaxPacketSize : nBytes;
423 pBuffer + byteOffset, nBytesThisTransaction);
424 byteOffset += nBytesThisTransaction;
425 nBytes -= nBytesThisTransaction;
427 pEndpoint->bDataToggle = !pEndpoint->bDataToggle;
430 const ssize_t result = pParentHub->
doSync(nTransaction, timeout);
431 if (pid == UsbPidIn && result >= 0 &&
static_cast<size_t>(result) < requested) {
433 const size_t packets = result / pEndpoint->nMaxPacketSize + 1;
434 pEndpoint->bDataToggle = initialToggle ^ bool(packets & 1);
439ssize_t UsbDevice::syncIn(Endpoint* pEndpoint, uintptr_t pBuffer,
size_t nBytes,
size_t timeout) {
440 return doSync(pEndpoint, UsbPidIn, pBuffer, nBytes, timeout);
443ssize_t UsbDevice::syncOut(Endpoint* pEndpoint, uintptr_t pBuffer,
size_t nBytes,
size_t timeout) {
444 return doSync(pEndpoint, UsbPidOut, pBuffer, nBytes, timeout);
447bool UsbDevice::addInterruptInHandler(Endpoint* pEndpoint, uintptr_t pBuffer, uint16_t nBytes,
448 void (*pCallback)(uintptr_t, ssize_t),
450 if (!pEndpoint || pEndpoint->nTransactions != 1) {
452 "USB: UsbDevice::addInterruptInHandler called with invalid "
459 ERROR(
"USB: Orphaned UsbDevice!");
467 ERROR(
"USB: Input pointer wasn't properly aligned [" << pBuffer <<
", " << nBytes <<
"]");
472 pEndpoint->nMaxPacketSize);
473 endpointInfo.nInterval = pEndpoint->nInterval;
474 endpointInfo.nTransferType = pEndpoint->nTransferType;
475 endpointInfo.nIn = pEndpoint->bIn;
476 endpointInfo.nMaxBurst = pEndpoint->nMaxBurst;
477 endpointInfo.nStreams = pEndpoint->nStreams;
478 endpointInfo.nBytesPerInterval = pEndpoint->nBytesPerInterval;
480 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
486 uint16_t nIndex, uint16_t nLength, uintptr_t pBuffer,
488 if (nLength && !pBuffer)
489 return -TransactionError;
491 Setup* pSetup =
new Setup(nRequestType, nRequest, nValue, nIndex, nLength);
496 ERROR(
"USB: Orphaned UsbDevice!");
497 return -TransactionError;
502 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
505 if (nTransaction ==
static_cast<uintptr_t
>(-1)) {
507 "UsbDevice: couldn't get a valid transaction to work with from "
509 return -TransactionError;
514 reinterpret_cast<uintptr_t
>(pSetup),
sizeof(
Setup));
516 const size_t nMaxSize = m_ControlPacketSize;
521 size_t nTransferLength = nLength;
523 while (nTransferLength) {
524 size_t sz = nTransferLength > nMaxSize ? nMaxSize : nTransferLength;
527 nTransaction, bToggle, nRequestType & UsbRequestDirection::In ? UsbPidIn : UsbPidOut,
528 pBuffer + nOffset, sz);
531 nTransferLength -= sz;
539 nTransaction,
true, nRequestType & UsbRequestDirection::In ? UsbPidOut : UsbPidIn, 0, 0);
542 ssize_t nResult = pParentHub->
doSync(nTransaction, timeout);
546 DEBUG_LOG(
"USB: Control request failure - status is " << nResult);
550 if (nResult <
static_cast<ssize_t
>(
sizeof(
Setup)) ||
551 nResult >
static_cast<ssize_t
>(
sizeof(
Setup) + nLength))
552 return -TransactionError;
553 return nResult -
sizeof(
Setup);
557 uint16_t nIndex, uint16_t nLength, uintptr_t pBuffer,
559 return controlRequestResult(nRequestType, nRequest, nValue, nIndex, nLength, pBuffer, timeout) ==
564 uint16_t* nStatus =
new uint16_t(0);
566 controlRequest(UsbRequestDirection::In, UsbRequest::GetStatus, 0, 0, 2,
567 reinterpret_cast<uintptr_t
>(nStatus));
572 const uint16_t endpointAddress =
573 pEndpoint->nEndpoint | (pEndpoint->bIn ? UsbRequestDirection::In : 0);
574 if (!
controlRequest(UsbRequestRecipient::Endpoint, UsbRequest::ClearFeature, 0,
579 pEndpoint->bDataToggle =
false;
581 pEndpoint->nMaxPacketSize);
582 endpoint.nIn = pEndpoint->bIn;
584 endpoint.nRootPortGeneration = m_nRootPortGeneration;
608 if (bWasAlternateSetting ||
m_pInterface->nAlternateSetting)
609 if (!
controlRequest(UsbRequestRecipient::Interface, UsbRequest::SetInterface,
621 uint8_t requestType) {
622 if (!nBytes || ((requestType & 0x1f) == UsbRequestRecipient::Interface && !
m_pInterface))
624 uint8_t* pBuffer =
new uint8_t[nBytes]();
626 (requestType & 0x1f) == UsbRequestRecipient::Interface ?
m_pInterface->nInterface : 0;
629 if (nDescriptor == UsbDescriptor::String)
632 if (!
controlRequest(UsbRequestDirection::In | requestType, UsbRequest::GetDescriptor,
633 (nDescriptor << 8) | nSubDescriptor, nIndex, nBytes,
634 reinterpret_cast<uintptr_t
>(pBuffer))) {
642 uint8_t requestType) {
643 if ((requestType & 0x1f) == UsbRequestRecipient::Interface && !
m_pInterface)
645 uint8_t* length =
new uint8_t(0);
648 (requestType & 0x1f) == UsbRequestRecipient::Interface ?
m_pInterface->nInterface : 0;
651 if (nDescriptor == UsbDescriptor::String)
654 controlRequest(UsbRequestDirection::In | requestType, UsbRequest::GetDescriptor,
655 (nDescriptor << 8) | nSubDescriptor, nIndex, 1,
656 reinterpret_cast<uintptr_t
>(length));
666 if (descriptorLength < 2 || descriptorLength % 2)
670 static_cast<uint8_t*
>(
getDescriptor(UsbDescriptor::String, nString, descriptorLength));
676 size_t nStrLength = (descriptorLength - 2) / 2;
677 char* pString =
new char[nStrLength + 1];
681 for (
size_t i = 0; i < nStrLength; i++)
682 pString[i] = pBuffer[2 + i * 2];
686 pString[nStrLength] = 0;
693UsbDeviceContainer::UsbDeviceContainer(
UsbDevice* pDev)
698 m_BindingRegistry(nullptr),
699 m_BindingOwner(nullptr),
701 m_PreviousBinding(nullptr),
702 m_NextBinding(nullptr) {
708UsbDeviceContainer::~UsbDeviceContainer() {
709 if (m_ProbeOperations.isOpen())
710 m_ProbeOperations.
close();
711 m_ProbeOperations.
wait();
712 UsbPnP* bindingRegistry = m_BindingRegistry;
714 bindingRegistry->detachBinding(
this);
722 m_pUsbDevice =
nullptr;
726 destroyUsbDevice(m_pUsbDevice);
727 m_pUsbDevice =
nullptr;
734void UsbDeviceContainer::closeProbeAdmission() {
735 m_ProbeOperations.
close();
738void UsbDeviceContainer::waitForProbes() {
739 m_ProbeOperations.
wait();
742UsbDevice* UsbDeviceContainer::getUsbDevice()
const {
747 if (!pDev || pDev == m_pUsbDevice)
771void UsbDeviceContainer::attachSubtree(
UsbDevice* pDev) {
782void UsbDeviceContainer::destroyUsbDevice(
UsbDevice* pDev) {
798 m_pUsbDevice->getUsbDeviceName(str);
806 str.assign(
"Generic USB Device", 19);
809#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
813class HostedOwnedUsbDevice :
public UsbDevice {
815 HostedOwnedUsbDevice() :
UsbDevice(nullptr, 1, FullSpeed) {
819 m_pDescriptor =
new DeviceDescriptor(descriptor);
824 ~HostedOwnedUsbDevice()
override {
825 g_HostedUsbDeviceDestructions += 1;
829class HostedSubtreeUsbDevice :
public Device,
public HostedOwnedUsbDevice {
831 explicit HostedSubtreeUsbDevice(
UsbDevice* device) :
Device(), HostedOwnedUsbDevice(device) {}
833 bool hasSubtree()
const override {
837 Device* getDevice()
override {
843bool runHostedUsbContainerOwnershipRegression() {
844 const size_t devicesBefore = g_HostedUsbDeviceDestructions;
845 const size_t descriptorsBefore = g_HostedUsbDescriptorDestructions;
847 auto* original =
new HostedOwnedUsbDevice;
848 auto* replacement =
new HostedSubtreeUsbDevice(original);
850 const bool replaced = container->replaceUsbDevice(replacement);
851 const bool replacementReachable = container->getUsbDevice() == replacement;
852 const bool oldDestroyedOnce =
853 g_HostedUsbDeviceDestructions ==
static_cast<size_t>(devicesBefore + 1);
854 const bool descriptorStillOwned =
855 g_HostedUsbDescriptorDestructions ==
static_cast<size_t>(descriptorsBefore);
860 replaced && replacementReachable && oldDestroyedOnce && descriptorStillOwned &&
861 g_HostedUsbDeviceDestructions ==
static_cast<size_t>(devicesBefore + 2) &&
862 g_HostedUsbDescriptorDestructions ==
static_cast<size_t>(descriptorsBefore + 1);
864 NOTICE(
"HOSTED-WAIT-TEST: PASS usb-container-owned-replacement");
867 "HOSTED-WAIT-TEST: FAIL usb-container-owned-replacement: container replacement or "
868 "shared-descriptor teardown was not exact");
void addChild(Device *pDevice)
void setParent(Device *p)
void removeChild(size_t n)
MUST_USE_RESULT bool tryAcquire(Lease &lease)
MUST_USE_RESULT bool replaceUsbDevice(UsbDevice *pDev)
virtual void getName(String &str)
virtual void dump(String &str)
virtual bool hasSubtree() const
Do we expose our own Device tree?
UsbHub * m_pHub
Parent USB hub.
void useConfiguration(uint8_t nConfig)
Switches to the given configuration.
bool clearEndpointHalt(Endpoint *pEndpoint)
Clears a halt on the given endpoint.
uint8_t m_nRootPort
Root-controller connection which owns this device generation.
UsbDeviceContainer * m_pContainer
Our current container.
virtual Device * getDevice()
UsbDevice(UsbHub *pHub, uint8_t nPort, UsbSpeed speed)
Default constructor.
uint16_t getStatus()
Gets device's current status.
void useInterface(uint8_t nInterface)
Switches to the given interface.
uint8_t m_nAddress
The current address of the device.
Interface * m_pInterface
Interface in use.
bool controlRequest(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue, uint16_t nIndex, uint16_t nLength=0, uintptr_t pBuffer=0, uint32_t timeout=5000)
Performs an USB control request.
String getString(uint8_t nString)
Gets a string.
UsbState m_UsbState
The current state of the device.
UsbSpeed m_Speed
The speed at which the device operates.
uint8_t m_nPort
The number of the port on which the device is connected.
ConfigDescriptor * m_pConfiguration
Configuration in use.
uint8_t getDescriptorLength(uint8_t nDescriptorType, uint8_t nDescriptorIndex, uint8_t requestType=0)
Gets a descriptor's length from the device.
DeviceDescriptor * m_pDescriptor
Device descriptor for this device.
ssize_t controlRequestResult(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue, uint16_t nIndex, uint16_t nLength=0, uintptr_t pBuffer=0, uint32_t timeout=5000)
Returns data bytes transferred, or a negative UsbError.
DeviceDescriptor * getDescriptor()
Returns the device descriptor of the device.
void initialise(uint8_t nAddress)
Initialises the device at the given address.
virtual ~UsbDevice()
Destructor.
virtual void addTransferToTransaction(uintptr_t pTransaction, bool bToggle, UsbPid pid, uintptr_t pBuffer, size_t nBytes)=0
Adds a new transfer to an existent transaction.
ssize_t doSync(uintptr_t nTransaction, uint32_t timeout=5000)
virtual uintptr_t createTransaction(UsbEndpoint endpointInfo)=0
Creates a new transaction with the given endpoint data.
virtual MUST_USE_RESULT bool addInterruptInHandler(UsbEndpoint endpointInfo, uintptr_t pBuffer, uint16_t nBytes, void(*pCallback)(uintptr_t, ssize_t), UsbInterruptInHandle &handle, uintptr_t pParam=0)=0
Adds an owned recurring interrupt-IN transaction.
RootConnection rootConnectionForChild(uint8_t childPort) const