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