20#include "modules/system/usb/UsbDevice.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/ServiceManager.h"
23#include "pedigree/kernel/panic.h"
24#include "pedigree/kernel/time/Time.h"
25#include "pedigree/kernel/utilities/PointerGuard.h"
26#include "pedigree/kernel/utilities/assert.h"
27#include "pedigree/kernel/utilities/new"
29#include "modules/system/usb/Usb.h"
30#include "modules/system/usb/UsbConstants.h"
31#include "modules/system/usb/UsbDescriptors.h"
32#include "modules/system/usb/UsbHub.h"
33#include "modules/system/usb/UsbPnP.h"
35#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
41 m_ControlPacketSize(speed == SuperSpeed ? 512
42 : speed == HighSpeed ? 64
46 m_nRootPortGeneration(0),
48 m_UsbState(Connected),
57 m_nRootPortGeneration = connection.generation;
62 : m_nAddress(pDev->m_nAddress),
63 m_ControlPacketSize(pDev->m_ControlPacketSize),
64 m_nPort(pDev->m_nPort),
65 m_nRootPort(pDev->m_nRootPort),
66 m_nRootPortGeneration(pDev->m_nRootPortGeneration),
67 m_Speed(pDev->m_Speed),
68 m_UsbState(pDev->m_UsbState),
69 m_pDescriptor(pDev->m_pDescriptor),
70 m_pConfiguration(pDev->m_pConfiguration),
71 m_pInterface(pDev->m_pInterface),
73 m_pContainer(nullptr) {
84UsbDevice::DeviceDescriptor::DeviceDescriptor(
UsbDeviceDescriptor* pDescriptor) : m_References(1) {
85 nBcdUsbRelease = pDescriptor->nBcdUsbRelease;
86 nClass = pDescriptor->nClass;
87 nSubclass = pDescriptor->nSubclass;
88 nProtocol = pDescriptor->nProtocol;
89 nMaxControlPacketSize = pDescriptor->nMaxControlPacketSize;
90 nVendorId = pDescriptor->nVendorId;
91 nProductId = pDescriptor->nProductId;
92 nBcdDeviceRelease = pDescriptor->nBcdDeviceRelease;
93 nVendorString = pDescriptor->nVendorString;
94 nProductString = pDescriptor->nProductString;
95 nSerialString = pDescriptor->nSerialString;
96 nConfigurations = pDescriptor->nConfigurations;
98 delete[]
reinterpret_cast<uint8_t*
>(pDescriptor);
101UsbDevice::DeviceDescriptor::~DeviceDescriptor() {
102#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
103 g_HostedUsbDescriptorDestructions += 1;
105 for (
size_t i = 0; i < configList.count(); i++)
106 delete configList[i];
109void UsbDevice::DeviceDescriptor::retain() {
113void UsbDevice::DeviceDescriptor::release() {
114 const size_t remaining = m_References -= 1;
115 assert(remaining !=
static_cast<size_t>(-1));
120UsbDevice::ConfigDescriptor::ConfigDescriptor(
void* pConfigBuffer,
size_t nConfigLength,
122 : nConfig(0), nString(0), valid(false) {
123 auto* buffer =
static_cast<uint8_t*
>(pConfigBuffer);
127 buffer[1] != UsbDescriptor::Configuration)
130 nConfig = descriptor->nConfig;
131 nString = descriptor->nString;
132 Interface* current =
nullptr;
133 Endpoint* precedingEndpoint =
nullptr;
134 for (
size_t offset = buffer[0]; offset < nConfigLength;) {
135 if (nConfigLength - offset < 2)
137 const size_t length = buffer[offset];
138 const uint8_t type = buffer[offset + 1];
139 if (length < 2 || length > nConfigLength - offset)
141 if (speed == SuperSpeed && precedingEndpoint && !precedingEndpoint->hasCompanion &&
144 if (type == UsbDescriptor::Interface) {
148 interfaceList.pushBack(current);
149 }
else if (type == UsbDescriptor::Endpoint) {
154 const bool interrupt = endpoint->nTransferType == Endpoint::Interrupt;
155 const bool bulk = endpoint->nTransferType == Endpoint::Bulk;
156 const size_t maximum = speed == LowSpeed ? 8
158 ? (endpoint->nTransferType == Endpoint::Isochronus ? 1023 : 64)
160 const uint16_t packetField = buffer[offset + 4] | (uint16_t{buffer[offset + 5]} << 8);
161 if (!endpoint->nEndpoint || !endpoint->nMaxPacketSize || endpoint->nMaxPacketSize > maximum ||
162 (packetField & 0xe000U) || ((packetField & 0x1800U) == 0x1800U) ||
163 (speed == LowSpeed && !interrupt) ||
164 (bulk && speed == HighSpeed && endpoint->nMaxPacketSize != 512) ||
165 (bulk && speed == SuperSpeed && endpoint->nMaxPacketSize != 1024) ||
166 (speed == SuperSpeed && (packetField & 0x1800U)) ||
167 (interrupt && (!endpoint->nInterval || ((speed == HighSpeed || speed == SuperSpeed) &&
168 endpoint->nInterval > 16)))) {
172 current->endpointList.pushBack(endpoint);
173 precedingEndpoint = endpoint;
174 }
else if (type == 0x30 && speed == SuperSpeed) {
175 if (!precedingEndpoint || precedingEndpoint->hasCompanion || length < 6 ||
176 buffer[offset + 2] > 15)
178 const uint8_t attributes = buffer[offset + 3];
179 const uint16_t intervalBytes = buffer[offset + 4] | (uint16_t{buffer[offset + 5]} << 8);
180 const bool bulk = precedingEndpoint->nTransferType == Endpoint::Bulk;
181 const bool interrupt = precedingEndpoint->nTransferType == Endpoint::Interrupt;
182 if ((bulk && ((attributes & 0xe0U) || (attributes & 31U) > 16 || intervalBytes)) ||
184 (attributes || !intervalBytes ||
185 intervalBytes > (buffer[offset + 2] + 1U) * precedingEndpoint->nMaxPacketSize)))
187 precedingEndpoint->nMaxBurst = buffer[offset + 2];
188 precedingEndpoint->nStreams =
189 precedingEndpoint->nTransferType == Endpoint::Bulk ? buffer[offset + 3] & 31U : 0;
190 precedingEndpoint->nBytesPerInterval =
191 buffer[offset + 4] | (uint16_t{buffer[offset + 5]} << 8);
192 precedingEndpoint->hasCompanion =
true;
194 current->otherDescriptorList.pushBack(
new UnknownDescriptor(buffer + offset, type, length));
196 otherDescriptorList.pushBack(
new UnknownDescriptor(buffer + offset, type, length));
199 if (speed == SuperSpeed && precedingEndpoint && !precedingEndpoint->hasCompanion)
201 valid = nConfig && interfaceList.count();
204UsbDevice::ConfigDescriptor::~ConfigDescriptor() {
205 for (
size_t i = 0; i < interfaceList.count(); i++)
206 delete interfaceList[i];
207 for (
size_t i = 0; i < otherDescriptorList.count(); i++)
208 delete otherDescriptorList[i];
212 nInterface = pDescriptor->nInterface;
213 nAlternateSetting = pDescriptor->nAlternateSetting;
214 nClass = pDescriptor->nClass;
215 nSubclass = pDescriptor->nSubclass;
216 nProtocol = pDescriptor->nProtocol;
217 nString = pDescriptor->nString;
220UsbDevice::Interface::~Interface() {
221 for (
size_t i = 0; i < endpointList.count(); i++)
222 delete endpointList[i];
223 for (
size_t i = 0; i < otherDescriptorList.count(); i++)
224 delete otherDescriptorList[i];
228 : bDataToggle(false) {
229 nEndpoint = pDescriptor->nEndpoint;
230 bIn = pDescriptor->bDirection;
232 nTransferType = pDescriptor->nTransferType;
233 nMaxPacketSize = LITTLE_TO_HOST16(pDescriptor->nMaxPacketSize) & 0x7ff;
234 nInterval = pDescriptor->nInterval;
235 const auto* raw =
reinterpret_cast<const uint8_t*
>(pDescriptor);
236 nTransactions = ((raw[5] >> 3) & 3U) + 1;
243 "USB: UsbDevice::initialise called, but this device is already "
249 Time::delay(10 * Time::Multiplier::Millisecond);
252 control.nRootPortGeneration = m_nRootPortGeneration;
253 if (!
m_pHub || !
m_pHub->prepareDevice(nAddress, control))
256 auto* prefix =
static_cast<uint8_t*
>(
getDescriptor(UsbDescriptor::Device, 0, 8));
259 const uint8_t packetSize = prefix[7];
262 ((
m_Speed == HighSpeed && packetSize == 64) || (
m_Speed == LowSpeed && packetSize == 8) ||
263 (
m_Speed == SuperSpeed && packetSize == 9) ||
265 (packetSize == 8 || packetSize == 16 || packetSize == 32 || packetSize == 64)));
269 m_ControlPacketSize =
m_Speed == SuperSpeed ? 512 : packetSize;
270 control.nMaxPacketSize = m_ControlPacketSize;
271 if (
m_pHub->controllerAssignsAddresses()
272 ? !
m_pHub->addressDevice(nAddress, control)
277 Time::delay(2 * Time::Multiplier::Millisecond);
279 if (!pDeviceDescriptor)
283 WARNING(
"USB: external hubs are unsupported by this controller");
290 DEBUG_LOG(
"USB version: " <<
Dec << (
m_pDescriptor->nBcdUsbRelease >> 8) <<
"."
292 DEBUG_LOG(
"Device class/subclass/protocol: " <<
m_pDescriptor->nClass <<
"/"
295 DEBUG_LOG(
"Maximum control packet size is " <<
Dec <<
m_pDescriptor->nMaxControlPacketSize
296 <<
Hex <<
" bytes.");
297 DEBUG_LOG(
"Vendor and product IDs: " <<
m_pDescriptor->nVendorId <<
":"
299 DEBUG_LOG(
"Device version: " <<
Dec << (
m_pDescriptor->nBcdDeviceRelease >> 8) <<
"."
301 DEBUG_LOG(
"Number of configurations: " <<
m_pDescriptor->nConfigurations <<
".");
302 DEBUG_LOG(
"String indices: " <<
m_pDescriptor->nVendorString <<
", "
308 uint8_t nConfigDescriptor = UsbDescriptor::Configuration;
316 for (
size_t i = 0; i <
m_pDescriptor->nConfigurations; i++) {
319 WARNING(
"USB: Found a device with multiple configurations!");
324 uint16_t* pPartialConfig =
static_cast<uint16_t*
>(
getDescriptor(nConfigDescriptor, i, 4));
327 uint16_t configLength = LITTLE_TO_HOST16(pPartialConfig[1]);
328 delete[]
reinterpret_cast<uint8_t*
>(pPartialConfig);
336 if (!pConfig->valid) {
341 pConfig->sString =
getString(pConfig->nString);
344 for (
size_t j = 0; j < pConfig->interfaceList.count(); j++) {
346 Interface* pInterface = pConfig->interfaceList[j];
347 if (pInterface->nClass == 9 && !
m_pHub->supportsHubDevices()) {
348 WARNING(
"USB: external hubs are unsupported by this controller");
354 if (pConfig->interfaceList.count() == 1 &&
m_pDescriptor->nClass && !pInterface->nClass) {
361 pInterface->sString =
getString(pInterface->nString);
365 assert(pConfig->interfaceList.count());
379 size_t nBytes,
size_t timeout) {
380 if (!pEndpoint || !pEndpoint->nMaxPacketSize) {
381 ERROR(
"USB: UsbDevice::doSync called with invalid endpoint");
382 return -TransactionError;
387 ERROR(
"USB: Orphaned UsbDevice!");
388 return -TransactionError;
395 ERROR(
"USB: Input pointer wasn't properly aligned [" << pBuffer <<
", " << nBytes <<
"]");
396 return -TransactionError;
400 pEndpoint->nMaxPacketSize);
401 endpointInfo.nTransferType = pEndpoint->nTransferType;
402 endpointInfo.nIn = pEndpoint->bIn;
403 endpointInfo.nInterval = pEndpoint->nInterval;
404 endpointInfo.nMaxBurst = pEndpoint->nMaxBurst;
405 endpointInfo.nStreams = pEndpoint->nStreams;
406 endpointInfo.nBytesPerInterval = pEndpoint->nBytesPerInterval;
408 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
410 if (nTransaction ==
static_cast<uintptr_t
>(-1)) {
412 "UsbDevice: couldn't get a valid transaction to work with from "
414 return -TransactionError;
417 const bool initialToggle = pEndpoint->bDataToggle;
418 const size_t requested = nBytes;
419 size_t byteOffset = 0;
421 size_t nBytesThisTransaction =
422 nBytes > pEndpoint->nMaxPacketSize ? pEndpoint->nMaxPacketSize : nBytes;
425 pBuffer + byteOffset, nBytesThisTransaction);
426 byteOffset += nBytesThisTransaction;
427 nBytes -= nBytesThisTransaction;
429 pEndpoint->bDataToggle = !pEndpoint->bDataToggle;
432 const ssize_t result = pParentHub->
doSync(nTransaction, timeout);
433 if (pid == UsbPidIn && result >= 0 &&
static_cast<size_t>(result) < requested) {
435 const size_t packets = result / pEndpoint->nMaxPacketSize + 1;
436 pEndpoint->bDataToggle = initialToggle ^ bool(packets & 1);
441ssize_t UsbDevice::syncIn(Endpoint* pEndpoint, uintptr_t pBuffer,
size_t nBytes,
size_t timeout) {
442 return doSync(pEndpoint, UsbPidIn, pBuffer, nBytes, timeout);
445ssize_t UsbDevice::syncOut(Endpoint* pEndpoint, uintptr_t pBuffer,
size_t nBytes,
size_t timeout) {
446 return doSync(pEndpoint, UsbPidOut, pBuffer, nBytes, timeout);
449bool UsbDevice::addInterruptInHandler(Endpoint* pEndpoint, uintptr_t pBuffer, uint16_t nBytes,
450 void (*pCallback)(uintptr_t, ssize_t),
452 if (!pEndpoint || pEndpoint->nTransactions != 1) {
454 "USB: UsbDevice::addInterruptInHandler called with invalid "
461 ERROR(
"USB: Orphaned UsbDevice!");
469 ERROR(
"USB: Input pointer wasn't properly aligned [" << pBuffer <<
", " << nBytes <<
"]");
474 pEndpoint->nMaxPacketSize);
475 endpointInfo.nInterval = pEndpoint->nInterval;
476 endpointInfo.nTransferType = pEndpoint->nTransferType;
477 endpointInfo.nIn = pEndpoint->bIn;
478 endpointInfo.nMaxBurst = pEndpoint->nMaxBurst;
479 endpointInfo.nStreams = pEndpoint->nStreams;
480 endpointInfo.nBytesPerInterval = pEndpoint->nBytesPerInterval;
482 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
488 uint16_t nIndex, uint16_t nLength, uintptr_t pBuffer,
490 if (nLength && !pBuffer)
491 return -TransactionError;
493 Setup* pSetup =
new Setup(nRequestType, nRequest, nValue, nIndex, nLength);
498 ERROR(
"USB: Orphaned UsbDevice!");
499 return -TransactionError;
504 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
507 if (nTransaction ==
static_cast<uintptr_t
>(-1)) {
509 "UsbDevice: couldn't get a valid transaction to work with from "
511 return -TransactionError;
516 reinterpret_cast<uintptr_t
>(pSetup),
sizeof(
Setup));
518 const size_t nMaxSize = m_ControlPacketSize;
523 size_t nTransferLength = nLength;
525 while (nTransferLength) {
526 size_t sz = nTransferLength > nMaxSize ? nMaxSize : nTransferLength;
529 nTransaction, bToggle, nRequestType & UsbRequestDirection::In ? UsbPidIn : UsbPidOut,
530 pBuffer + nOffset, sz);
533 nTransferLength -= sz;
541 nTransaction,
true, nRequestType & UsbRequestDirection::In ? UsbPidOut : UsbPidIn, 0, 0);
544 ssize_t nResult = pParentHub->
doSync(nTransaction, timeout);
548 DEBUG_LOG(
"USB: Control request failure - status is " << nResult);
552 if (nResult <
static_cast<ssize_t
>(
sizeof(
Setup)) ||
553 nResult >
static_cast<ssize_t
>(
sizeof(
Setup) + nLength))
554 return -TransactionError;
555 return nResult -
sizeof(
Setup);
559 uint16_t nIndex, uint16_t nLength, uintptr_t pBuffer,
561 return controlRequestResult(nRequestType, nRequest, nValue, nIndex, nLength, pBuffer, timeout) ==
566 uint16_t* nStatus =
new uint16_t(0);
568 controlRequest(UsbRequestDirection::In, UsbRequest::GetStatus, 0, 0, 2,
569 reinterpret_cast<uintptr_t
>(nStatus));
574 const uint16_t endpointAddress =
575 pEndpoint->nEndpoint | (pEndpoint->bIn ? UsbRequestDirection::In : 0);
576 if (!
controlRequest(UsbRequestRecipient::Endpoint, UsbRequest::ClearFeature, 0,
581 pEndpoint->bDataToggle =
false;
583 pEndpoint->nMaxPacketSize);
584 endpoint.nIn = pEndpoint->bIn;
586 endpoint.nRootPortGeneration = m_nRootPortGeneration;
610 if (bWasAlternateSetting ||
m_pInterface->nAlternateSetting)
611 if (!
controlRequest(UsbRequestRecipient::Interface, UsbRequest::SetInterface,
623 uint8_t requestType) {
624 if (!nBytes || ((requestType & 0x1f) == UsbRequestRecipient::Interface && !
m_pInterface))
626 uint8_t* pBuffer =
new uint8_t[nBytes]();
628 (requestType & 0x1f) == UsbRequestRecipient::Interface ?
m_pInterface->nInterface : 0;
631 if (nDescriptor == UsbDescriptor::String)
634 if (!
controlRequest(UsbRequestDirection::In | requestType, UsbRequest::GetDescriptor,
635 (nDescriptor << 8) | nSubDescriptor, nIndex, nBytes,
636 reinterpret_cast<uintptr_t
>(pBuffer))) {
644 uint8_t requestType) {
645 if ((requestType & 0x1f) == UsbRequestRecipient::Interface && !
m_pInterface)
647 uint8_t* length =
new uint8_t(0);
650 (requestType & 0x1f) == UsbRequestRecipient::Interface ?
m_pInterface->nInterface : 0;
653 if (nDescriptor == UsbDescriptor::String)
656 controlRequest(UsbRequestDirection::In | requestType, UsbRequest::GetDescriptor,
657 (nDescriptor << 8) | nSubDescriptor, nIndex, 1,
658 reinterpret_cast<uintptr_t
>(length));
668 if (descriptorLength < 2 || descriptorLength % 2)
672 static_cast<uint8_t*
>(
getDescriptor(UsbDescriptor::String, nString, descriptorLength));
678 size_t nStrLength = (descriptorLength - 2) / 2;
679 char* pString =
new char[nStrLength + 1];
683 for (
size_t i = 0; i < nStrLength; i++)
684 pString[i] = pBuffer[2 + i * 2];
688 pString[nStrLength] = 0;
695UsbDeviceContainer::UsbDeviceContainer(
UsbDevice* pDev)
700 m_BindingRegistry(nullptr),
701 m_BindingOwner(nullptr),
703 m_PreviousBinding(nullptr),
704 m_NextBinding(nullptr) {
710UsbDeviceContainer::~UsbDeviceContainer() {
711 if (m_ProbeOperations.isOpen())
712 m_ProbeOperations.
close();
713 m_ProbeOperations.
wait();
714 UsbPnP* bindingRegistry = m_BindingRegistry;
716 bindingRegistry->detachBinding(
this);
724 m_pUsbDevice =
nullptr;
728 destroyUsbDevice(m_pUsbDevice);
729 m_pUsbDevice =
nullptr;
736void UsbDeviceContainer::closeProbeAdmission() {
737 m_ProbeOperations.
close();
740void UsbDeviceContainer::waitForProbes() {
741 m_ProbeOperations.
wait();
744UsbDevice* UsbDeviceContainer::getUsbDevice()
const {
749 if (!pDev || pDev == m_pUsbDevice)
758 panic(
"USB: couldn't withdraw filesystems before driver retirement");
784void UsbDeviceContainer::attachSubtree(
UsbDevice* pDev) {
795void UsbDeviceContainer::destroyUsbDevice(
UsbDevice* pDev) {
811 m_pUsbDevice->getUsbDeviceName(str);
819 str.assign(
"Generic USB Device", 19);
822#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
826class HostedOwnedUsbDevice :
public UsbDevice {
828 HostedOwnedUsbDevice() :
UsbDevice(nullptr, 1, FullSpeed) {
832 m_pDescriptor =
new DeviceDescriptor(descriptor);
837 ~HostedOwnedUsbDevice()
override {
838 g_HostedUsbDeviceDestructions += 1;
842class HostedSubtreeUsbDevice :
public Device,
public HostedOwnedUsbDevice {
844 explicit HostedSubtreeUsbDevice(
UsbDevice* device) :
Device(), HostedOwnedUsbDevice(device) {}
846 bool hasSubtree()
const override {
850 Device* getDevice()
override {
856bool runHostedUsbContainerOwnershipRegression() {
857 const size_t devicesBefore = g_HostedUsbDeviceDestructions;
858 const size_t descriptorsBefore = g_HostedUsbDescriptorDestructions;
860 auto* original =
new HostedOwnedUsbDevice;
861 auto* replacement =
new HostedSubtreeUsbDevice(original);
863 const bool replaced = container->replaceUsbDevice(replacement);
864 const bool replacementReachable = container->getUsbDevice() == replacement;
865 const bool oldDestroyedOnce =
866 g_HostedUsbDeviceDestructions ==
static_cast<size_t>(devicesBefore + 1);
867 const bool descriptorStillOwned =
868 g_HostedUsbDescriptorDestructions ==
static_cast<size_t>(descriptorsBefore);
873 replaced && replacementReachable && oldDestroyedOnce && descriptorStillOwned &&
874 g_HostedUsbDeviceDestructions ==
static_cast<size_t>(devicesBefore + 2) &&
875 g_HostedUsbDescriptorDestructions ==
static_cast<size_t>(descriptorsBefore + 1);
877 NOTICE(
"HOSTED-WAIT-TEST: PASS usb-container-owned-replacement");
880 "HOSTED-WAIT-TEST: FAIL usb-container-owned-replacement: container replacement or "
881 "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)
Service * getService(const String &serviceName)
bool serve(const String &serviceName, ServiceFeatures::Type type, void *data, size_t dataLen)
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
void EXPORTED_PUBLIC panic(const char *msg) NORETURN