The Pedigree Project 0.1
UsbDevice.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
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"
26
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"
32
33#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
34Atomic<size_t> g_HostedUsbDescriptorDestructions(0);
35#endif
36
37UsbDevice::UsbDevice(UsbHub* pHub, uint8_t nPort, UsbSpeed speed)
38 : m_nAddress(0),
39 m_ControlPacketSize(speed == SuperSpeed ? 512
40 : speed == HighSpeed ? 64
41 : 8),
42 m_nPort(nPort),
43 m_nRootPort(0xff),
44 m_nRootPortGeneration(0),
45 m_Speed(speed),
46 m_UsbState(Connected),
47 m_pDescriptor(0),
48 m_pConfiguration(0),
49 m_pInterface(0),
50 m_pHub(pHub),
51 m_pContainer(0) {
52 if (pHub) {
53 const auto connection = pHub->rootConnectionForChild(nPort);
54 m_nRootPort = connection.port;
55 m_nRootPortGeneration = connection.generation;
56 }
57}
58
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),
70 m_pHub(pDev->m_pHub),
71 m_pContainer(nullptr) {
72 // We have the same parent as pDev
73 if (m_pDescriptor)
74 m_pDescriptor->retain();
75}
76
78 if (m_pDescriptor)
79 m_pDescriptor->release();
80}
81
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;
95
96 delete[] reinterpret_cast<uint8_t*>(pDescriptor);
97}
98
99UsbDevice::DeviceDescriptor::~DeviceDescriptor() {
100#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
101 g_HostedUsbDescriptorDestructions += 1;
102#endif
103 for (size_t i = 0; i < configList.count(); i++)
104 delete configList[i];
105}
106
107void UsbDevice::DeviceDescriptor::retain() {
108 m_References += 1;
109}
110
111void UsbDevice::DeviceDescriptor::release() {
112 const size_t remaining = m_References -= 1;
113 assert(remaining != static_cast<size_t>(-1));
114 if (!remaining)
115 delete this;
116}
117
118UsbDevice::ConfigDescriptor::ConfigDescriptor(void* pConfigBuffer, size_t nConfigLength,
119 UsbSpeed speed)
120 : nConfig(0), nString(0), valid(false) {
121 auto* buffer = static_cast<uint8_t*>(pConfigBuffer);
122 PointerGuard<uint8_t> guard(buffer, true);
123 if (!buffer || nConfigLength < sizeof(UsbConfigurationDescriptor) ||
124 buffer[0] < sizeof(UsbConfigurationDescriptor) || buffer[0] > nConfigLength ||
125 buffer[1] != UsbDescriptor::Configuration)
126 return;
127 auto* descriptor = reinterpret_cast<UsbConfigurationDescriptor*>(buffer);
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)
134 return;
135 const size_t length = buffer[offset];
136 const uint8_t type = buffer[offset + 1];
137 if (length < 2 || length > nConfigLength - offset)
138 return;
139 if (speed == SuperSpeed && precedingEndpoint && !precedingEndpoint->hasCompanion &&
140 type != 0x30)
141 return;
142 if (type == UsbDescriptor::Interface) {
143 if (length < sizeof(UsbInterfaceDescriptor))
144 return;
145 current = new Interface(reinterpret_cast<UsbInterfaceDescriptor*>(buffer + offset));
146 interfaceList.pushBack(current);
147 } else if (type == UsbDescriptor::Endpoint) {
148 if (!current || length < sizeof(UsbEndpointDescriptor))
149 return;
150 auto* endpoint =
151 new Endpoint(reinterpret_cast<UsbEndpointDescriptor*>(buffer + offset), speed);
152 const bool interrupt = endpoint->nTransferType == Endpoint::Interrupt;
153 const bool bulk = endpoint->nTransferType == Endpoint::Bulk;
154 const size_t maximum = speed == LowSpeed ? 8
155 : speed == FullSpeed
156 ? (endpoint->nTransferType == Endpoint::Isochronus ? 1023 : 64)
157 : 1024;
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)))) {
167 delete endpoint;
168 return;
169 }
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)
175 return;
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)) ||
181 (interrupt &&
182 (attributes || !intervalBytes ||
183 intervalBytes > (buffer[offset + 2] + 1U) * precedingEndpoint->nMaxPacketSize)))
184 return;
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;
191 } else if (current)
192 current->otherDescriptorList.pushBack(new UnknownDescriptor(buffer + offset, type, length));
193 else
194 otherDescriptorList.pushBack(new UnknownDescriptor(buffer + offset, type, length));
195 offset += length;
196 }
197 if (speed == SuperSpeed && precedingEndpoint && !precedingEndpoint->hasCompanion)
198 return;
199 valid = nConfig && interfaceList.count();
200}
201
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];
207}
208
209UsbDevice::Interface::Interface(UsbInterfaceDescriptor* pDescriptor) {
210 nInterface = pDescriptor->nInterface;
211 nAlternateSetting = pDescriptor->nAlternateSetting;
212 nClass = pDescriptor->nClass;
213 nSubclass = pDescriptor->nSubclass;
214 nProtocol = pDescriptor->nProtocol;
215 nString = pDescriptor->nString;
216}
217
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];
223}
224
225UsbDevice::Endpoint::Endpoint(UsbEndpointDescriptor* pDescriptor, UsbSpeed speed)
226 : bDataToggle(false) {
227 nEndpoint = pDescriptor->nEndpoint;
228 bIn = pDescriptor->bDirection;
229 bOut = !bIn;
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;
235}
236
237void UsbDevice::initialise(uint8_t nAddress) {
238 // Check for late calls
239 if (m_UsbState > Connected) {
240 ERROR(
241 "USB: UsbDevice::initialise called, but this device is already "
242 "initialised!");
243 return;
244 }
245
246 // USB 2.0 9.2.6.2 requires recovery after reset has actually deasserted.
247 Time::delay(10 * Time::Multiplier::Millisecond);
248 UsbEndpoint control(0, m_nPort, 0, m_Speed, m_ControlPacketSize);
249 control.nRootPort = m_nRootPort;
250 control.nRootPortGeneration = m_nRootPortGeneration;
251 if (!m_pHub || !m_pHub->prepareDevice(nAddress, control))
252 return;
253 // Learn endpoint zero's packet size before asking for a full descriptor.
254 auto* prefix = static_cast<uint8_t*>(getDescriptor(UsbDescriptor::Device, 0, 8));
255 if (!prefix)
256 return;
257 const uint8_t packetSize = prefix[7];
258 const bool valid =
259 prefix[0] >= sizeof(UsbDeviceDescriptor) && prefix[1] == UsbDescriptor::Device &&
260 ((m_Speed == HighSpeed && packetSize == 64) || (m_Speed == LowSpeed && packetSize == 8) ||
261 (m_Speed == SuperSpeed && packetSize == 9) ||
262 (m_Speed == FullSpeed &&
263 (packetSize == 8 || packetSize == 16 || packetSize == 32 || packetSize == 64)));
264 delete[] prefix;
265 if (!valid)
266 return;
267 m_ControlPacketSize = m_Speed == SuperSpeed ? 512 : packetSize;
268 control.nMaxPacketSize = m_ControlPacketSize;
269 if (m_pHub->controllerAssignsAddresses()
270 ? !m_pHub->addressDevice(nAddress, control)
271 : !controlRequest(0, UsbRequest::SetAddress, nAddress, 0))
272 return;
273 m_nAddress = nAddress;
274 m_UsbState = Addressed;
275 Time::delay(2 * Time::Multiplier::Millisecond);
276 void* pDeviceDescriptor = getDescriptor(UsbDescriptor::Device, 0, sizeof(UsbDeviceDescriptor));
277 if (!pDeviceDescriptor)
278 return;
279 m_pDescriptor = new DeviceDescriptor(static_cast<UsbDeviceDescriptor*>(pDeviceDescriptor));
280 if (m_pDescriptor->nClass == 9 && !m_pHub->supportsHubDevices()) {
281 WARNING("USB: external hubs are unsupported by this controller");
282 return;
283 }
284 m_UsbState = HasDescriptors; // We now have the device descriptor
285
286 // Debug dump of the device descriptor
287 EMIT_IF(UsbVerboseDebug) {
288 DEBUG_LOG("USB version: " << Dec << (m_pDescriptor->nBcdUsbRelease >> 8) << "."
289 << (m_pDescriptor->nBcdUsbRelease & 0xFF) << ".");
290 DEBUG_LOG("Device class/subclass/protocol: " << m_pDescriptor->nClass << "/"
291 << m_pDescriptor->nSubclass << "/"
292 << m_pDescriptor->nProtocol);
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 << ":"
296 << m_pDescriptor->nProductId << ".");
297 DEBUG_LOG("Device version: " << Dec << (m_pDescriptor->nBcdDeviceRelease >> 8) << "."
298 << (m_pDescriptor->nBcdDeviceRelease & 0xFF) << Hex << ".");
299 DEBUG_LOG("Number of configurations: " << m_pDescriptor->nConfigurations << ".");
300 DEBUG_LOG("String indices: " << m_pDescriptor->nVendorString << ", "
301 << m_pDescriptor->nProductString << ", "
302 << m_pDescriptor->nSerialString);
303 }
304
305 // Descriptor number for the configuration descriptor
306 uint8_t nConfigDescriptor = UsbDescriptor::Configuration;
307
308 // Get the vendor, product and serial strings
309 m_pDescriptor->sVendor = getString(m_pDescriptor->nVendorString);
310 m_pDescriptor->sProduct = getString(m_pDescriptor->nProductString);
311 m_pDescriptor->sSerial = getString(m_pDescriptor->nSerialString);
312
313 // Grab each configuration from the device
314 for (size_t i = 0; i < m_pDescriptor->nConfigurations; i++) {
315 // Skip extra configurations
316 if (i) {
317 WARNING("USB: Found a device with multiple configurations!");
318 break;
319 }
320
321 // Get the total size of this configuration descriptor
322 uint16_t* pPartialConfig = static_cast<uint16_t*>(getDescriptor(nConfigDescriptor, i, 4));
323 if (!pPartialConfig)
324 return;
325 uint16_t configLength = LITTLE_TO_HOST16(pPartialConfig[1]);
326 delete[] reinterpret_cast<uint8_t*>(pPartialConfig);
327
328 if (configLength < sizeof(UsbConfigurationDescriptor))
329 return;
330 // Get our configuration descriptor
331 ConfigDescriptor* pConfig = new ConfigDescriptor(
332 getDescriptor(nConfigDescriptor, i, configLength), configLength, m_Speed);
333
334 if (!pConfig->valid) {
335 delete pConfig;
336 return;
337 }
338 // Get the associated string
339 pConfig->sString = getString(pConfig->nString);
340
341 // Go through the interface list
342 for (size_t j = 0; j < pConfig->interfaceList.count(); j++) {
343 // Get this interface, for minor adjustments
344 Interface* pInterface = pConfig->interfaceList[j];
345 if (pInterface->nClass == 9 && !m_pHub->supportsHubDevices()) {
346 WARNING("USB: external hubs are unsupported by this controller");
347 delete pConfig;
348 return;
349 }
350
351 // Just in case the class numbers are in the device descriptor
352 if (pConfig->interfaceList.count() == 1 && m_pDescriptor->nClass && !pInterface->nClass) {
353 pInterface->nClass = m_pDescriptor->nClass;
354 pInterface->nSubclass = m_pDescriptor->nSubclass;
355 pInterface->nProtocol = m_pDescriptor->nProtocol;
356 }
357
358 // Again, get the associated string
359 pInterface->sString = getString(pInterface->nString);
360 }
361
362 // Make sure it's not empty, then add it to our list of configurations
363 assert(pConfig->interfaceList.count());
364 m_pDescriptor->configList.pushBack(pConfig);
365 }
366
367 // Make sure we ended up with at least a configuration
368 if (!m_pDescriptor->configList.count())
369 return;
370
371 // Use the first configuration
374}
375
376ssize_t UsbDevice::doSync(UsbDevice::Endpoint* pEndpoint, UsbPid pid, uintptr_t pBuffer,
377 size_t nBytes, size_t timeout) {
378 if (!pEndpoint || !pEndpoint->nMaxPacketSize) {
379 ERROR("USB: UsbDevice::doSync called with invalid endpoint");
380 return -TransactionError;
381 }
382
383 UsbHub* pParentHub = m_pHub;
384 if (!pParentHub) {
385 ERROR("USB: Orphaned UsbDevice!");
386 return -TransactionError;
387 }
388
389 if (!nBytes)
390 return 0;
391
392 if (pBuffer & 0xF) {
393 ERROR("USB: Input pointer wasn't properly aligned [" << pBuffer << ", " << nBytes << "]");
394 return -TransactionError;
395 }
396
397 UsbEndpoint endpointInfo(m_nAddress, m_nPort, pEndpoint->nEndpoint, m_Speed,
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;
405 endpointInfo.nRootPort = m_nRootPort;
406 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
407 uintptr_t nTransaction = pParentHub->createTransaction(endpointInfo);
408 if (nTransaction == static_cast<uintptr_t>(-1)) {
409 ERROR(
410 "UsbDevice: couldn't get a valid transaction to work with from "
411 "the parent hub");
412 return -TransactionError;
413 }
414
415 const bool initialToggle = pEndpoint->bDataToggle;
416 const size_t requested = nBytes;
417 size_t byteOffset = 0;
418 while (nBytes) {
419 size_t nBytesThisTransaction =
420 nBytes > pEndpoint->nMaxPacketSize ? pEndpoint->nMaxPacketSize : nBytes;
421
422 pParentHub->addTransferToTransaction(nTransaction, pEndpoint->bDataToggle, pid,
423 pBuffer + byteOffset, nBytesThisTransaction);
424 byteOffset += nBytesThisTransaction;
425 nBytes -= nBytesThisTransaction;
426
427 pEndpoint->bDataToggle = !pEndpoint->bDataToggle;
428 }
429
430 const ssize_t result = pParentHub->doSync(nTransaction, timeout);
431 if (pid == UsbPidIn && result >= 0 && static_cast<size_t>(result) < requested) {
432 // A short IN ends with a short packet, including a ZLP after full packets.
433 const size_t packets = result / pEndpoint->nMaxPacketSize + 1;
434 pEndpoint->bDataToggle = initialToggle ^ bool(packets & 1);
435 }
436 return result;
437}
438
439ssize_t UsbDevice::syncIn(Endpoint* pEndpoint, uintptr_t pBuffer, size_t nBytes, size_t timeout) {
440 return doSync(pEndpoint, UsbPidIn, pBuffer, nBytes, timeout);
441}
442
443ssize_t UsbDevice::syncOut(Endpoint* pEndpoint, uintptr_t pBuffer, size_t nBytes, size_t timeout) {
444 return doSync(pEndpoint, UsbPidOut, pBuffer, nBytes, timeout);
445}
446
447bool UsbDevice::addInterruptInHandler(Endpoint* pEndpoint, uintptr_t pBuffer, uint16_t nBytes,
448 void (*pCallback)(uintptr_t, ssize_t),
449 UsbInterruptInHandle& handle, uintptr_t pParam) {
450 if (!pEndpoint || pEndpoint->nTransactions != 1) {
451 ERROR(
452 "USB: UsbDevice::addInterruptInHandler called with invalid "
453 "endpoint");
454 return false;
455 }
456
457 UsbHub* pParentHub = m_pHub;
458 if (!pParentHub) {
459 ERROR("USB: Orphaned UsbDevice!");
460 return false;
461 }
462
463 if (!nBytes)
464 return false;
465
466 if (pBuffer & 0xF) {
467 ERROR("USB: Input pointer wasn't properly aligned [" << pBuffer << ", " << nBytes << "]");
468 return false;
469 }
470
471 UsbEndpoint endpointInfo(m_nAddress, m_nPort, pEndpoint->nEndpoint, m_Speed,
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;
479 endpointInfo.nRootPort = m_nRootPort;
480 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
481 return pParentHub->addInterruptInHandler(endpointInfo, pBuffer, nBytes, pCallback, handle,
482 pParam);
483}
484
485ssize_t UsbDevice::controlRequestResult(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue,
486 uint16_t nIndex, uint16_t nLength, uintptr_t pBuffer,
487 uint32_t timeout) {
488 if (nLength && !pBuffer)
489 return -TransactionError;
490 // Setup structure - holds request details
491 Setup* pSetup = new Setup(nRequestType, nRequest, nValue, nIndex, nLength);
492 PointerGuard<Setup> guard(pSetup);
493
494 UsbHub* pParentHub = m_pHub;
495 if (!pParentHub) {
496 ERROR("USB: Orphaned UsbDevice!");
497 return -TransactionError;
498 }
499
500 UsbEndpoint endpointInfo(m_nAddress, m_nPort, 0, m_Speed, m_ControlPacketSize);
501 endpointInfo.nRootPort = m_nRootPort;
502 endpointInfo.nRootPortGeneration = m_nRootPortGeneration;
503
504 uintptr_t nTransaction = pParentHub->createTransaction(endpointInfo);
505 if (nTransaction == static_cast<uintptr_t>(-1)) {
506 ERROR(
507 "UsbDevice: couldn't get a valid transaction to work with from "
508 "the parent hub");
509 return -TransactionError;
510 }
511
512 // Setup Transfer - handles the SETUP phase of the transfer
513 pParentHub->addTransferToTransaction(nTransaction, false, UsbPidSetup,
514 reinterpret_cast<uintptr_t>(pSetup), sizeof(Setup));
515
516 const size_t nMaxSize = m_ControlPacketSize;
517
518 // Data Transfer - handles data transfer
519 if (nLength) {
520 bool bToggle = true;
521 size_t nTransferLength = nLength;
522 size_t nOffset = 0;
523 while (nTransferLength) {
524 size_t sz = nTransferLength > nMaxSize ? nMaxSize : nTransferLength;
525
526 pParentHub->addTransferToTransaction(
527 nTransaction, bToggle, nRequestType & UsbRequestDirection::In ? UsbPidIn : UsbPidOut,
528 pBuffer + nOffset, sz);
529 bToggle = !bToggle;
530
531 nTransferLength -= sz;
532 nOffset += sz;
533 }
534 }
535
536 // Handshake Transfer - IN when we send data to the device, OUT when we
537 // receive. Zero-length.
538 pParentHub->addTransferToTransaction(
539 nTransaction, true, nRequestType & UsbRequestDirection::In ? UsbPidOut : UsbPidIn, 0, 0);
540
541 // Wait for the transaction to complete
542 ssize_t nResult = pParentHub->doSync(nTransaction, timeout);
543
544 // Return false if we had an error, true otherwise
545 if (nResult < 0) {
546 DEBUG_LOG("USB: Control request failure - status is " << nResult);
547 }
548 if (nResult < 0)
549 return 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);
554}
555
556bool UsbDevice::controlRequest(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue,
557 uint16_t nIndex, uint16_t nLength, uintptr_t pBuffer,
558 uint32_t timeout) {
559 return controlRequestResult(nRequestType, nRequest, nValue, nIndex, nLength, pBuffer, timeout) ==
560 nLength;
561}
562
564 uint16_t* nStatus = new uint16_t(0);
565 PointerGuard<uint16_t> guard(nStatus);
566 controlRequest(UsbRequestDirection::In, UsbRequest::GetStatus, 0, 0, 2,
567 reinterpret_cast<uintptr_t>(nStatus));
568 return *nStatus;
569}
570
572 const uint16_t endpointAddress =
573 pEndpoint->nEndpoint | (pEndpoint->bIn ? UsbRequestDirection::In : 0);
574 if (!controlRequest(UsbRequestRecipient::Endpoint, UsbRequest::ClearFeature, 0,
575 endpointAddress)) {
576 return false;
577 }
578
579 pEndpoint->bDataToggle = false;
580 UsbEndpoint endpoint(m_nAddress, m_nPort, pEndpoint->nEndpoint, m_Speed,
581 pEndpoint->nMaxPacketSize);
582 endpoint.nIn = pEndpoint->bIn;
583 endpoint.nRootPort = m_nRootPort;
584 endpoint.nRootPortGeneration = m_nRootPortGeneration;
585 return m_pHub && m_pHub->resetEndpoint(endpoint);
586}
587
588void UsbDevice::useConfiguration(uint8_t nConfig) {
589 if (!m_pDescriptor || nConfig >= m_pDescriptor->configList.count())
590 return;
591 m_pConfiguration = m_pDescriptor->configList[nConfig];
592 if (!controlRequest(0, UsbRequest::SetConfiguration, m_pConfiguration->nConfig, 0))
593 return;
594 m_UsbState = Configured; // We now are configured
595}
596
597void UsbDevice::useInterface(uint8_t nInterface) {
598 if (!m_pConfiguration || nInterface >= m_pConfiguration->interfaceList.count())
599 return;
600 Interface* previous = m_pInterface;
601 // First check if the previous interface was an alternate setting
602 bool bWasAlternateSetting = m_pInterface && m_pInterface->nAlternateSetting;
603
604 // Set our interface to the new one
605 m_pInterface = m_pConfiguration->interfaceList[nInterface];
606
607 // If needed, change the alternate setting
608 if (bWasAlternateSetting || m_pInterface->nAlternateSetting)
609 if (!controlRequest(UsbRequestRecipient::Interface, UsbRequest::SetInterface,
610 m_pInterface->nAlternateSetting, m_pInterface->nInterface)) {
611 m_pInterface = previous;
612 return;
613 }
614
615 // Set our state to HasInterface, if it's not higher
616 if (m_UsbState < HasInterface)
617 m_UsbState = HasInterface;
618}
619
620void* UsbDevice::getDescriptor(uint8_t nDescriptor, uint8_t nSubDescriptor, uint16_t nBytes,
621 uint8_t requestType) {
622 if (!nBytes || ((requestType & 0x1f) == UsbRequestRecipient::Interface && !m_pInterface))
623 return nullptr;
624 uint8_t* pBuffer = new uint8_t[nBytes]();
625 uint16_t nIndex =
626 (requestType & 0x1f) == UsbRequestRecipient::Interface ? m_pInterface->nInterface : 0;
627
629 if (nDescriptor == UsbDescriptor::String)
630 nIndex = 0x0409; // English (US)
631
632 if (!controlRequest(UsbRequestDirection::In | requestType, UsbRequest::GetDescriptor,
633 (nDescriptor << 8) | nSubDescriptor, nIndex, nBytes,
634 reinterpret_cast<uintptr_t>(pBuffer))) {
635 delete[] pBuffer;
636 return 0;
637 }
638 return pBuffer;
639}
640
641uint8_t UsbDevice::getDescriptorLength(uint8_t nDescriptor, uint8_t nSubDescriptor,
642 uint8_t requestType) {
643 if ((requestType & 0x1f) == UsbRequestRecipient::Interface && !m_pInterface)
644 return 0;
645 uint8_t* length = new uint8_t(0);
646 PointerGuard<uint8_t> guard(length);
647 uint16_t nIndex =
648 (requestType & 0x1f) == UsbRequestRecipient::Interface ? m_pInterface->nInterface : 0;
649
651 if (nDescriptor == UsbDescriptor::String)
652 nIndex = 0x0409; // English (US)
653
654 controlRequest(UsbRequestDirection::In | requestType, UsbRequest::GetDescriptor,
655 (nDescriptor << 8) | nSubDescriptor, nIndex, 1,
656 reinterpret_cast<uintptr_t>(length));
657 return *length;
658}
659
660String UsbDevice::getString(uint8_t nString) {
661 // A value of zero means there's no string
662 if (!nString)
663 return String("");
664
665 uint8_t descriptorLength = getDescriptorLength(UsbDescriptor::String, nString);
666 if (descriptorLength < 2 || descriptorLength % 2)
667 return String("");
668
669 uint8_t* pBuffer =
670 static_cast<uint8_t*>(getDescriptor(UsbDescriptor::String, nString, descriptorLength));
671 if (!pBuffer)
672 return String("");
673
674 // Get the number of characters in the string and allocate a new buffer for
675 // the string
676 size_t nStrLength = (descriptorLength - 2) / 2;
677 char* pString = new char[nStrLength + 1];
678
679 // For each character, get the lower part of the UTF-16 value
681 for (size_t i = 0; i < nStrLength; i++)
682 pString[i] = pBuffer[2 + i * 2];
683
684 // Set the last byte of the string to 0, delete the old buffer and return
685 // the string
686 pString[nStrLength] = 0;
687 delete[] pBuffer;
688 String result(pString);
689 delete[] pString;
690 return result;
691}
692
693UsbDeviceContainer::UsbDeviceContainer(UsbDevice* pDev)
694 : Device(),
695 m_pUsbDevice(pDev),
696 m_ProbeOperations(),
697 m_ProbeLock(),
698 m_BindingRegistry(nullptr),
699 m_BindingOwner(nullptr),
700 m_BindingLease(),
701 m_PreviousBinding(nullptr),
702 m_NextBinding(nullptr) {
703 assert(pDev);
704 pDev->m_pContainer = this;
705 attachSubtree(pDev);
706}
707
708UsbDeviceContainer::~UsbDeviceContainer() {
709 if (m_ProbeOperations.isOpen())
710 m_ProbeOperations.close();
711 m_ProbeOperations.wait();
712 UsbPnP* bindingRegistry = m_BindingRegistry;
713 if (bindingRegistry)
714 bindingRegistry->detachBinding(this);
715
716 if (m_pUsbDevice && m_pUsbDevice->hasSubtree() && m_pUsbDevice->getDevice()) {
717 Device* child = m_pUsbDevice->getDevice();
718 removeChild(child);
719 child->setParent(nullptr);
720 m_pUsbDevice->m_pContainer = nullptr;
721 delete m_pUsbDevice;
722 m_pUsbDevice = nullptr;
723 return;
724 }
725
726 destroyUsbDevice(m_pUsbDevice);
727 m_pUsbDevice = nullptr;
728}
729
730bool UsbDeviceContainer::tryAcquireProbe(OperationBarrier::Lease& lease) {
731 return m_ProbeOperations.tryAcquire(lease);
732}
733
734void UsbDeviceContainer::closeProbeAdmission() {
735 m_ProbeOperations.close();
736}
737
738void UsbDeviceContainer::waitForProbes() {
739 m_ProbeOperations.wait();
740}
741
742UsbDevice* UsbDeviceContainer::getUsbDevice() const {
743 return m_pUsbDevice;
744}
745
747 if (!pDev || pDev == m_pUsbDevice)
748 return false;
749
750 UsbDevice* oldDevice = m_pUsbDevice;
751 {
752 Device::TreeLockGuard treeGuard;
753 if (oldDevice && oldDevice->hasSubtree()) {
754 Device* child = oldDevice->getDevice();
755 if (child) {
756 removeChild(child);
757 child->setParent(nullptr);
758 }
759 }
760 if (oldDevice)
761 oldDevice->m_pContainer = nullptr;
762
763 m_pUsbDevice = pDev;
764 pDev->m_pContainer = this;
765 attachSubtree(pDev);
766 }
767 delete oldDevice;
768 return true;
769}
770
771void UsbDeviceContainer::attachSubtree(UsbDevice* pDev) {
772 if (!pDev || !pDev->hasSubtree())
773 return;
774
775 Device* child = pDev->getDevice();
776 if (!child)
777 return;
778 addChild(child);
779 child->setParent(this);
780}
781
782void UsbDeviceContainer::destroyUsbDevice(UsbDevice* pDev) {
783 if (!pDev)
784 return;
785
786 if (pDev->hasSubtree()) {
787 Device* child = pDev->getDevice();
788 if (child) {
789 removeChild(child);
790 child->setParent(nullptr);
791 }
792 }
793 pDev->m_pContainer = nullptr;
794 delete pDev;
795}
796
798 m_pUsbDevice->getUsbDeviceName(str);
799}
800
804
806 str.assign("Generic USB Device", 19);
807}
808
809#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
810namespace {
811Atomic<size_t> g_HostedUsbDeviceDestructions(0);
812
813class HostedOwnedUsbDevice : public UsbDevice {
814 public:
815 HostedOwnedUsbDevice() : UsbDevice(nullptr, 1, FullSpeed) {
816 auto* descriptor =
817 reinterpret_cast<UsbDeviceDescriptor*>(new uint8_t[sizeof(UsbDeviceDescriptor)]);
818 ByteSet(descriptor, 0, sizeof(UsbDeviceDescriptor));
819 m_pDescriptor = new DeviceDescriptor(descriptor);
820 }
821
822 explicit HostedOwnedUsbDevice(UsbDevice* device) : UsbDevice(device) {}
823
824 ~HostedOwnedUsbDevice() override {
825 g_HostedUsbDeviceDestructions += 1;
826 }
827};
828
829class HostedSubtreeUsbDevice : public Device, public HostedOwnedUsbDevice {
830 public:
831 explicit HostedSubtreeUsbDevice(UsbDevice* device) : Device(), HostedOwnedUsbDevice(device) {}
832
833 bool hasSubtree() const override {
834 return true;
835 }
836
837 Device* getDevice() override {
838 return this;
839 }
840};
841} // namespace
842
843bool runHostedUsbContainerOwnershipRegression() {
844 const size_t devicesBefore = g_HostedUsbDeviceDestructions;
845 const size_t descriptorsBefore = g_HostedUsbDescriptorDestructions;
846
847 auto* original = new HostedOwnedUsbDevice;
848 auto* replacement = new HostedSubtreeUsbDevice(original);
849 auto* container = new UsbDeviceContainer(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);
856
857 delete container;
858
859 const bool passed =
860 replaced && replacementReachable && oldDestroyedOnce && descriptorStillOwned &&
861 g_HostedUsbDeviceDestructions == static_cast<size_t>(devicesBefore + 2) &&
862 g_HostedUsbDescriptorDestructions == static_cast<size_t>(descriptorsBefore + 1);
863 if (passed) {
864 NOTICE("HOSTED-WAIT-TEST: PASS usb-container-owned-replacement");
865 } else {
866 ERROR(
867 "HOSTED-WAIT-TEST: FAIL usb-container-owned-replacement: container replacement or "
868 "shared-descriptor teardown was not exact");
869 }
870 return passed;
871}
872#endif
@ UsbContainer
Definition Device.h:89
void addChild(Device *pDevice)
Definition Device.cc:135
void setParent(Device *p)
Definition Device.h:170
void removeChild(size_t n)
Definition Device.cc:147
MUST_USE_RESULT bool tryAcquire(Lease &lease)
MUST_USE_RESULT bool replaceUsbDevice(UsbDevice *pDev)
Definition UsbDevice.cc:746
virtual void getName(String &str)
Definition UsbDevice.cc:797
virtual Type getType()
Definition UsbDevice.cc:801
virtual void dump(String &str)
Definition UsbDevice.cc:805
virtual bool hasSubtree() const
Do we expose our own Device tree?
Definition UsbDevice.h:242
UsbHub * m_pHub
Parent USB hub.
Definition UsbDevice.h:317
void useConfiguration(uint8_t nConfig)
Switches to the given configuration.
Definition UsbDevice.cc:588
bool clearEndpointHalt(Endpoint *pEndpoint)
Clears a halt on the given endpoint.
Definition UsbDevice.cc:571
uint8_t m_nRootPort
Root-controller connection which owns this device generation.
Definition UsbDevice.h:298
UsbDeviceContainer * m_pContainer
Our current container.
Definition UsbDevice.h:320
virtual Device * getDevice()
Definition UsbDevice.h:248
UsbDevice(UsbHub *pHub, uint8_t nPort, UsbSpeed speed)
Default constructor.
Definition UsbDevice.cc:37
uint16_t getStatus()
Gets device's current status.
Definition UsbDevice.cc:563
void useInterface(uint8_t nInterface)
Switches to the given interface.
Definition UsbDevice.cc:597
uint8_t m_nAddress
The current address of the device.
Definition UsbDevice.h:291
Interface * m_pInterface
Interface in use.
Definition UsbDevice.h:314
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.
Definition UsbDevice.cc:556
String getString(uint8_t nString)
Gets a string.
Definition UsbDevice.cc:660
UsbState m_UsbState
The current state of the device.
Definition UsbDevice.h:305
UsbSpeed m_Speed
The speed at which the device operates.
Definition UsbDevice.h:302
uint8_t m_nPort
The number of the port on which the device is connected.
Definition UsbDevice.h:295
ConfigDescriptor * m_pConfiguration
Configuration in use.
Definition UsbDevice.h:311
uint8_t getDescriptorLength(uint8_t nDescriptorType, uint8_t nDescriptorIndex, uint8_t requestType=0)
Gets a descriptor's length from the device.
Definition UsbDevice.cc:641
DeviceDescriptor * m_pDescriptor
Device descriptor for this device.
Definition UsbDevice.h:308
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.
Definition UsbDevice.cc:485
DeviceDescriptor * getDescriptor()
Returns the device descriptor of the device.
Definition UsbDevice.h:216
void initialise(uint8_t nAddress)
Initialises the device at the given address.
Definition UsbDevice.cc:237
virtual ~UsbDevice()
Destructor.
Definition UsbDevice.cc:77
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)
Definition UsbHub.cc:733
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
Definition UsbHub.cc:200
#define assert(x)
Definition assert.h:39
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124