usb_device_handle_mac.cc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/device/usb/usb_device_handle_mac.h"
  5. #include <IOKit/IOCFBundle.h>
  6. #include <IOKit/IOCFPlugIn.h>
  7. #include <IOKit/IOKitLib.h>
  8. #include <IOKit/IOReturn.h>
  9. #include <IOKit/IOTypes.h>
  10. #include <IOKit/usb/IOUSBLib.h>
  11. #include <MacTypes.h>
  12. #include <memory>
  13. #include <numeric>
  14. #include <utility>
  15. #include "base/mac/scoped_ioobject.h"
  16. #include "base/mac/scoped_ioplugininterface.h"
  17. #include "base/memory/ref_counted.h"
  18. #include "base/memory/ref_counted_memory.h"
  19. #include "base/strings/string_number_conversions.h"
  20. #include "components/device_event_log/device_event_log.h"
  21. #include "services/device/public/cpp/usb/usb_utils.h"
  22. #include "services/device/usb/usb_device_mac.h"
  23. namespace device {
  24. struct Transfer {
  25. UsbDeviceHandleMac::TransferCallback generic_callback;
  26. scoped_refptr<UsbDeviceHandleMac> handle;
  27. scoped_refptr<base::RefCountedBytes> buffer;
  28. std::vector<uint32_t> packet_lengths;
  29. std::vector<IOUSBIsocFrame> frame_list;
  30. mojom::UsbTransferType type;
  31. UsbDeviceHandleMac::IsochronousTransferCallback isochronous_callback;
  32. };
  33. namespace {
  34. // This is the bit 7 of the request type.
  35. enum class EndpointDirection : uint8_t { kIn = 0x80, kOut = 0x00 };
  36. // These are bits 5 and 6 of the request type.
  37. enum class RequestType : uint8_t {
  38. kStandard = 0x00,
  39. kClass = 0x20,
  40. kVendor = 0x40,
  41. kReserved = 0x60
  42. };
  43. // These are bits 0 and 1 of the request type.
  44. enum class RequestRecipient : uint8_t {
  45. kDevice = 0x00,
  46. kInterface = 0x01,
  47. kEndpoint = 0x02,
  48. kOther = 0x03,
  49. };
  50. mojom::UsbTransferStatus ConvertTransferStatus(IOReturn status) {
  51. switch (status) {
  52. // kIOReturnUnderrun can be ignored because the lower-than-expected transfer
  53. // size is reported alongside the COMPLETED status.
  54. case kIOReturnUnderrun:
  55. case kIOReturnSuccess:
  56. return mojom::UsbTransferStatus::COMPLETED;
  57. case kIOUSBTransactionTimeout:
  58. return mojom::UsbTransferStatus::TIMEOUT;
  59. case kIOUSBPipeStalled:
  60. return mojom::UsbTransferStatus::STALLED;
  61. case kIOReturnOverrun:
  62. return mojom::UsbTransferStatus::BABBLE;
  63. case kIOReturnAborted:
  64. return mojom::UsbTransferStatus::CANCELLED;
  65. default:
  66. return mojom::UsbTransferStatus::TRANSFER_ERROR;
  67. }
  68. }
  69. uint8_t ConvertTransferDirection(mojom::UsbTransferDirection direction) {
  70. switch (direction) {
  71. case mojom::UsbTransferDirection::INBOUND:
  72. return static_cast<uint8_t>(EndpointDirection::kIn);
  73. case mojom::UsbTransferDirection::OUTBOUND:
  74. return static_cast<uint8_t>(EndpointDirection::kOut);
  75. }
  76. NOTREACHED();
  77. return 0;
  78. }
  79. uint8_t CreateRequestType(mojom::UsbTransferDirection direction,
  80. mojom::UsbControlTransferType request_type,
  81. mojom::UsbControlTransferRecipient recipient) {
  82. uint8_t result = ConvertTransferDirection(direction);
  83. switch (request_type) {
  84. case mojom::UsbControlTransferType::STANDARD:
  85. result |= static_cast<uint8_t>(RequestType::kStandard);
  86. break;
  87. case mojom::UsbControlTransferType::CLASS:
  88. result |= static_cast<uint8_t>(RequestType::kClass);
  89. break;
  90. case mojom::UsbControlTransferType::VENDOR:
  91. result |= static_cast<uint8_t>(RequestType::kVendor);
  92. break;
  93. case mojom::UsbControlTransferType::RESERVED:
  94. result |= static_cast<uint8_t>(RequestType::kReserved);
  95. break;
  96. }
  97. switch (recipient) {
  98. case mojom::UsbControlTransferRecipient::DEVICE:
  99. result |= static_cast<uint8_t>(RequestRecipient::kDevice);
  100. break;
  101. case mojom::UsbControlTransferRecipient::INTERFACE:
  102. result |= static_cast<uint8_t>(RequestRecipient::kInterface);
  103. break;
  104. case mojom::UsbControlTransferRecipient::ENDPOINT:
  105. result |= static_cast<uint8_t>(RequestRecipient::kEndpoint);
  106. break;
  107. case mojom::UsbControlTransferRecipient::OTHER:
  108. result |= static_cast<uint8_t>(RequestRecipient::kOther);
  109. break;
  110. }
  111. return result;
  112. }
  113. } // namespace
  114. UsbDeviceHandleMac::UsbDeviceHandleMac(
  115. scoped_refptr<UsbDeviceMac> device,
  116. ScopedIOUSBDeviceInterface device_interface)
  117. : device_interface_(std::move(device_interface)),
  118. device_(std::move(device)) {}
  119. scoped_refptr<UsbDevice> UsbDeviceHandleMac::GetDevice() const {
  120. return device_;
  121. }
  122. void UsbDeviceHandleMac::Close() {
  123. if (!device_)
  124. return;
  125. if (device_source_) {
  126. CFRunLoopRemoveSource(CFRunLoopGetCurrent(), device_source_.get(),
  127. kCFRunLoopDefaultMode);
  128. }
  129. for (const auto& source : sources_) {
  130. CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source.second.get(),
  131. kCFRunLoopDefaultMode);
  132. }
  133. IOReturn kr = (*device_interface_)->USBDeviceClose(device_interface_);
  134. if (kr != kIOReturnSuccess) {
  135. USB_LOG(DEBUG) << "Failed to close device: " << std::hex << kr;
  136. }
  137. Clear();
  138. device_->HandleClosed(this);
  139. device_ = nullptr;
  140. }
  141. void UsbDeviceHandleMac::SetConfiguration(int configuration_value,
  142. ResultCallback callback) {
  143. if (!device_) {
  144. std::move(callback).Run(false);
  145. return;
  146. }
  147. if (!base::IsValueInRangeForNumericType<uint8_t>(configuration_value)) {
  148. std::move(callback).Run(false);
  149. return;
  150. }
  151. Clear();
  152. IOReturn kr =
  153. (*device_interface_)
  154. ->SetConfiguration(device_interface_,
  155. static_cast<uint8_t>(configuration_value));
  156. if (kr != kIOReturnSuccess) {
  157. std::move(callback).Run(false);
  158. return;
  159. }
  160. device_->ActiveConfigurationChanged(configuration_value);
  161. std::move(callback).Run(true);
  162. }
  163. void UsbDeviceHandleMac::ClaimInterface(int interface_number,
  164. ResultCallback callback) {
  165. if (!device_) {
  166. std::move(callback).Run(false);
  167. return;
  168. }
  169. if (!base::IsValueInRangeForNumericType<uint8_t>(interface_number)) {
  170. std::move(callback).Run(false);
  171. return;
  172. }
  173. IOUSBFindInterfaceRequest request;
  174. request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
  175. request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
  176. request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
  177. request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
  178. base::mac::ScopedIOObject<io_iterator_t> interface_iterator;
  179. IOReturn kr =
  180. (*device_interface_)
  181. ->CreateInterfaceIterator(device_interface_, &request,
  182. interface_iterator.InitializeInto());
  183. if (kr != kIOReturnSuccess) {
  184. std::move(callback).Run(false);
  185. return;
  186. }
  187. base::mac::ScopedIOObject<io_service_t> usb_interface;
  188. while (usb_interface.reset(IOIteratorNext(interface_iterator)),
  189. usb_interface) {
  190. base::mac::ScopedIOPluginInterface<IOCFPlugInInterface> plugin_interface;
  191. int32_t score;
  192. kr = IOCreatePlugInInterfaceForService(
  193. usb_interface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID,
  194. plugin_interface.InitializeInto(), &score);
  195. if (kr != kIOReturnSuccess || !plugin_interface) {
  196. USB_LOG(ERROR) << "Unable to create a plug-in: " << std::hex << kr;
  197. continue;
  198. }
  199. ScopedIOUSBInterfaceInterface interface_interface;
  200. kr = (*plugin_interface)
  201. ->QueryInterface(plugin_interface.get(),
  202. CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
  203. reinterpret_cast<LPVOID*>(
  204. interface_interface.InitializeInto()));
  205. if (kr != kIOReturnSuccess || !interface_interface) {
  206. USB_LOG(ERROR) << "Could not create a device interface: " << std::hex
  207. << kr;
  208. continue;
  209. }
  210. uint8_t retrieved_interface_number;
  211. kr = (*interface_interface)
  212. ->GetInterfaceNumber(interface_interface,
  213. &retrieved_interface_number);
  214. if (kr != kIOReturnSuccess) {
  215. USB_LOG(ERROR) << "Could not retrieve an interface number: " << std::hex
  216. << kr;
  217. continue;
  218. }
  219. if (retrieved_interface_number != interface_number)
  220. continue;
  221. kr = (*interface_interface)->USBInterfaceOpen(interface_interface);
  222. if (kr != kIOReturnSuccess) {
  223. USB_LOG(ERROR) << "Could not open interface: " << std::hex << kr;
  224. break;
  225. }
  226. interfaces_[interface_number] = interface_interface;
  227. base::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source;
  228. kr = (*interface_interface)
  229. ->CreateInterfaceAsyncEventSource(
  230. interface_interface, run_loop_source.InitializeInto());
  231. if (kr != kIOReturnSuccess) {
  232. USB_LOG(ERROR) << "Could not retrieve port: " << std::hex << kr;
  233. (*interface_interface)->USBInterfaceClose(interface_interface);
  234. break;
  235. }
  236. RefreshEndpointMap();
  237. CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source.get(),
  238. kCFRunLoopDefaultMode);
  239. sources_[interface_number] = run_loop_source;
  240. std::move(callback).Run(true);
  241. return;
  242. }
  243. std::move(callback).Run(false);
  244. USB_LOG(ERROR) << "Could not find interface matching number: "
  245. << interface_number;
  246. }
  247. void UsbDeviceHandleMac::ReleaseInterface(int interface_number,
  248. ResultCallback callback) {
  249. if (!device_) {
  250. std::move(callback).Run(false);
  251. return;
  252. }
  253. auto interface_it = interfaces_.find(static_cast<uint8_t>(interface_number));
  254. if (interface_it == interfaces_.end()) {
  255. std::move(callback).Run(false);
  256. return;
  257. }
  258. auto released_interface = std::move(interface_it->second);
  259. interfaces_.erase(interface_it);
  260. auto source_it = sources_.find(interface_number);
  261. if (source_it != sources_.end()) {
  262. CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source_it->second.get(),
  263. kCFRunLoopDefaultMode);
  264. sources_.erase(source_it);
  265. }
  266. IOReturn kr = (*released_interface)->USBInterfaceClose(released_interface);
  267. if (kr != kIOReturnSuccess) {
  268. std::move(callback).Run(false);
  269. return;
  270. }
  271. RefreshEndpointMap();
  272. std::move(callback).Run(true);
  273. }
  274. void UsbDeviceHandleMac::SetInterfaceAlternateSetting(int interface_number,
  275. int alternate_setting,
  276. ResultCallback callback) {
  277. if (!device_) {
  278. std::move(callback).Run(false);
  279. return;
  280. }
  281. auto interface_it = interfaces_.find(interface_number);
  282. if (interface_it == interfaces_.end()) {
  283. std::move(callback).Run(false);
  284. return;
  285. }
  286. const auto& interface_interface = interface_it->second;
  287. IOReturn kr =
  288. (*interface_interface)
  289. ->SetAlternateInterface(interface_interface, alternate_setting);
  290. if (kr != kIOReturnSuccess) {
  291. std::move(callback).Run(false);
  292. return;
  293. }
  294. RefreshEndpointMap();
  295. std::move(callback).Run(true);
  296. }
  297. void UsbDeviceHandleMac::ResetDevice(ResultCallback callback) {
  298. if (!device_) {
  299. std::move(callback).Run(false);
  300. return;
  301. }
  302. // TODO(https://crbug.com/1096743): Figure out if open interfaces need to be
  303. // closed as well.
  304. IOReturn kr = (*device_interface_)
  305. ->USBDeviceReEnumerate(device_interface_, /*options=*/0);
  306. if (kr != kIOReturnSuccess) {
  307. std::move(callback).Run(false);
  308. return;
  309. }
  310. Clear();
  311. std::move(callback).Run(true);
  312. }
  313. void UsbDeviceHandleMac::ClearHalt(mojom::UsbTransferDirection direction,
  314. uint8_t endpoint_number,
  315. ResultCallback callback) {
  316. if (!device_) {
  317. std::move(callback).Run(false);
  318. return;
  319. }
  320. uint8_t endpoint_address =
  321. ConvertTransferDirection(direction) | endpoint_number;
  322. auto* mojom_interface = FindInterfaceByEndpoint(endpoint_address);
  323. uint8_t interface_number = mojom_interface->interface_number;
  324. auto interface_it = interfaces_.find(interface_number);
  325. if (interface_it == interfaces_.end()) {
  326. std::move(callback).Run(false);
  327. return;
  328. }
  329. const auto endpoint_it = endpoint_map_.find(endpoint_address);
  330. if (endpoint_it == endpoint_map_.end()) {
  331. std::move(callback).Run(false);
  332. return;
  333. }
  334. const auto& interface_interface = interface_it->second;
  335. IOReturn kr = (*interface_interface)
  336. ->ClearPipeStall(interface_interface,
  337. endpoint_it->second.pipe_reference);
  338. if (kr != kIOReturnSuccess) {
  339. std::move(callback).Run(false);
  340. return;
  341. }
  342. std::move(callback).Run(true);
  343. }
  344. void UsbDeviceHandleMac::ControlTransfer(
  345. mojom::UsbTransferDirection direction,
  346. mojom::UsbControlTransferType request_type,
  347. mojom::UsbControlTransferRecipient recipient,
  348. uint8_t request,
  349. uint16_t value,
  350. uint16_t index,
  351. scoped_refptr<base::RefCountedBytes> buffer,
  352. unsigned int timeout,
  353. TransferCallback callback) {
  354. if (!device_) {
  355. std::move(callback).Run(mojom::UsbTransferStatus::DISCONNECT,
  356. std::move(buffer), 0);
  357. return;
  358. }
  359. if (!base::IsValueInRangeForNumericType<uint16_t>(buffer->size())) {
  360. USB_LOG(ERROR) << "Transfer too long.";
  361. std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR,
  362. std::move(buffer), 0);
  363. return;
  364. }
  365. if (!device_source_) {
  366. IOReturn kr = (*device_interface_)
  367. ->CreateDeviceAsyncEventSource(
  368. device_interface_, device_source_.InitializeInto());
  369. if (kr != kIOReturnSuccess) {
  370. USB_LOG(ERROR) << "Unable to create device async event source: "
  371. << std::hex << kr;
  372. std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR,
  373. std::move(buffer), 0);
  374. }
  375. CFRunLoopAddSource(CFRunLoopGetCurrent(), device_source_.get(),
  376. kCFRunLoopDefaultMode);
  377. }
  378. IOUSBDevRequestTO device_request;
  379. device_request.bRequest = request;
  380. device_request.wValue = value;
  381. device_request.wIndex = index;
  382. device_request.bmRequestType =
  383. CreateRequestType(direction, request_type, recipient);
  384. device_request.pData = buffer->front_as<void*>();
  385. device_request.wLength = static_cast<uint16_t>(buffer->size());
  386. device_request.completionTimeout = timeout;
  387. device_request.noDataTimeout = timeout;
  388. auto transfer = std::make_unique<Transfer>();
  389. transfer->generic_callback = std::move(callback);
  390. transfer->handle = this;
  391. transfer->buffer = std::move(buffer);
  392. Transfer* transfer_ptr = transfer.get();
  393. auto result = transfers_.insert(std::move(transfer));
  394. IOReturn kr = (*device_interface_)
  395. ->DeviceRequestAsyncTO(
  396. device_interface_, &device_request, &AsyncIoCallback,
  397. reinterpret_cast<void*>(transfer_ptr));
  398. if (kr != kIOReturnSuccess) {
  399. USB_LOG(ERROR) << "Failed to send control request: " << std::hex << kr;
  400. std::move((*result.first)->generic_callback)
  401. .Run(mojom::UsbTransferStatus::TRANSFER_ERROR,
  402. std::move((*result.first)->buffer), 0);
  403. transfers_.erase(result.first);
  404. }
  405. }
  406. void UsbDeviceHandleMac::IsochronousTransferIn(
  407. uint8_t endpoint,
  408. const std::vector<uint32_t>& packet_lengths,
  409. unsigned int timeout,
  410. IsochronousTransferCallback callback) {
  411. if (!device_) {
  412. ReportIsochronousTransferError(std::move(callback), packet_lengths,
  413. mojom::UsbTransferStatus::DISCONNECT);
  414. return;
  415. }
  416. uint8_t endpoint_address =
  417. ConvertTransferDirection(mojom::UsbTransferDirection::INBOUND) | endpoint;
  418. const auto endpoint_it = endpoint_map_.find(endpoint_address);
  419. if (endpoint_it == endpoint_map_.end()) {
  420. USB_LOG(ERROR) << "Failed to submit transfer because endpoint "
  421. << int{endpoint_address}
  422. << " is not part of a claimed interface.";
  423. ReportIsochronousTransferError(std::move(callback), packet_lengths,
  424. mojom::UsbTransferStatus::TRANSFER_ERROR);
  425. return;
  426. }
  427. size_t length =
  428. std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
  429. auto buffer = base::MakeRefCounted<base::RefCountedBytes>(length);
  430. auto interface_it =
  431. interfaces_.find(endpoint_it->second.interface->interface_number);
  432. if (interface_it == interfaces_.end()) {
  433. ReportIsochronousTransferError(std::move(callback), packet_lengths,
  434. mojom::UsbTransferStatus::TRANSFER_ERROR);
  435. return;
  436. }
  437. const auto& interface_interface = interface_it->second;
  438. uint64_t bus_frame;
  439. AbsoluteTime time;
  440. IOReturn kr = (*interface_interface)
  441. ->GetBusFrameNumber(interface_interface, &bus_frame, &time);
  442. if (kr != kIOReturnSuccess) {
  443. ReportIsochronousTransferError(std::move(callback), packet_lengths,
  444. mojom::UsbTransferStatus::TRANSFER_ERROR);
  445. return;
  446. }
  447. auto transfer = std::make_unique<Transfer>();
  448. transfer->isochronous_callback = std::move(callback);
  449. transfer->handle = this;
  450. transfer->buffer = buffer;
  451. transfer->type = mojom::UsbTransferType::ISOCHRONOUS;
  452. Transfer* transfer_data = transfer.get();
  453. auto result = transfers_.insert(std::move(transfer));
  454. std::vector<IOUSBIsocFrame> frame_list;
  455. for (const auto& size : packet_lengths) {
  456. if (!base::IsValueInRangeForNumericType<uint16_t>(size)) {
  457. USB_LOG(ERROR) << "Transfer too long.";
  458. ReportIsochronousTransferError(
  459. std::move(transfer_data->isochronous_callback), packet_lengths,
  460. mojom::UsbTransferStatus::TRANSFER_ERROR);
  461. return;
  462. }
  463. IOUSBIsocFrame frame_entry;
  464. frame_entry.frReqCount = static_cast<uint16_t>(size);
  465. frame_list.push_back(frame_entry);
  466. }
  467. transfer_data->frame_list = frame_list;
  468. kr = (*interface_interface)
  469. ->ReadIsochPipeAsync(interface_interface,
  470. endpoint_it->second.pipe_reference,
  471. buffer->front_as<void*>(), bus_frame,
  472. static_cast<uint32_t>(packet_lengths.size()),
  473. transfer->frame_list.data(), &AsyncIoCallback,
  474. reinterpret_cast<void*>(transfer_data));
  475. if (kr != kIOReturnSuccess) {
  476. USB_LOG(ERROR) << "Isochrnous read failed.";
  477. ReportIsochronousTransferError(
  478. std::move((*result.first)->isochronous_callback), packet_lengths,
  479. mojom::UsbTransferStatus::TRANSFER_ERROR);
  480. transfers_.erase(result.first);
  481. return;
  482. }
  483. }
  484. void UsbDeviceHandleMac::IsochronousTransferOut(
  485. uint8_t endpoint,
  486. scoped_refptr<base::RefCountedBytes> buffer,
  487. const std::vector<uint32_t>& packet_lengths,
  488. unsigned int timeout,
  489. IsochronousTransferCallback callback) {
  490. if (!device_) {
  491. ReportIsochronousTransferError(std::move(callback), packet_lengths,
  492. mojom::UsbTransferStatus::DISCONNECT);
  493. return;
  494. }
  495. uint8_t endpoint_address =
  496. ConvertTransferDirection(mojom::UsbTransferDirection::INBOUND) | endpoint;
  497. const auto endpoint_it = endpoint_map_.find(endpoint_address);
  498. if (endpoint_it == endpoint_map_.end()) {
  499. USB_LOG(ERROR) << "Failed to submit transfer because endpoint "
  500. << int{endpoint_address}
  501. << " is not part of a claimed interface.";
  502. ReportIsochronousTransferError(std::move(callback), packet_lengths,
  503. mojom::UsbTransferStatus::TRANSFER_ERROR);
  504. return;
  505. }
  506. auto interface_it =
  507. interfaces_.find(endpoint_it->second.interface->interface_number);
  508. if (interface_it == interfaces_.end()) {
  509. ReportIsochronousTransferError(std::move(callback), packet_lengths,
  510. mojom::UsbTransferStatus::TRANSFER_ERROR);
  511. return;
  512. }
  513. const auto& interface_interface = interface_it->second;
  514. uint64_t bus_frame;
  515. AbsoluteTime time;
  516. IOReturn kr = (*interface_interface)
  517. ->GetBusFrameNumber(interface_interface, &bus_frame, &time);
  518. if (kr != kIOReturnSuccess) {
  519. ReportIsochronousTransferError(std::move(callback), packet_lengths,
  520. mojom::UsbTransferStatus::TRANSFER_ERROR);
  521. return;
  522. }
  523. auto transfer = std::make_unique<Transfer>();
  524. transfer->isochronous_callback = std::move(callback);
  525. transfer->handle = this;
  526. transfer->buffer = buffer;
  527. transfer->type = mojom::UsbTransferType::ISOCHRONOUS;
  528. Transfer* transfer_data = transfer.get();
  529. auto result = transfers_.insert(std::move(transfer));
  530. std::vector<IOUSBIsocFrame> frame_list;
  531. for (const auto& size : packet_lengths) {
  532. if (!base::IsValueInRangeForNumericType<uint16_t>(size)) {
  533. USB_LOG(ERROR) << "Transfer too long.";
  534. ReportIsochronousTransferError(
  535. std::move(transfer_data->isochronous_callback), packet_lengths,
  536. mojom::UsbTransferStatus::TRANSFER_ERROR);
  537. return;
  538. }
  539. IOUSBIsocFrame frame_entry;
  540. frame_entry.frReqCount = static_cast<uint16_t>(size);
  541. frame_list.push_back(frame_entry);
  542. }
  543. transfer_data->frame_list = frame_list;
  544. kr = (*interface_interface)
  545. ->WriteIsochPipeAsync(interface_interface,
  546. endpoint_it->second.pipe_reference,
  547. buffer->front_as<void*>(), bus_frame,
  548. static_cast<uint32_t>(packet_lengths.size()),
  549. transfer->frame_list.data(), &AsyncIoCallback,
  550. reinterpret_cast<void*>(transfer_data));
  551. if (kr != kIOReturnSuccess) {
  552. USB_LOG(ERROR) << "Isochrnous write failed.";
  553. ReportIsochronousTransferError(
  554. std::move((*result.first)->isochronous_callback), packet_lengths,
  555. mojom::UsbTransferStatus::TRANSFER_ERROR);
  556. transfers_.erase(result.first);
  557. }
  558. }
  559. void UsbDeviceHandleMac::GenericTransfer(
  560. mojom::UsbTransferDirection direction,
  561. uint8_t endpoint_number,
  562. scoped_refptr<base::RefCountedBytes> buffer,
  563. unsigned int timeout,
  564. TransferCallback callback) {
  565. if (!device_) {
  566. std::move(callback).Run(mojom::UsbTransferStatus::DISCONNECT, buffer, 0);
  567. return;
  568. }
  569. uint8_t endpoint_address =
  570. ConvertEndpointNumberToAddress(endpoint_number, direction);
  571. const auto endpoint_it = endpoint_map_.find(endpoint_address);
  572. if (endpoint_it == endpoint_map_.end()) {
  573. USB_LOG(ERROR) << "Failed to submit transfer because endpoint "
  574. << int{endpoint_address}
  575. << " is not part of a claimed interface.";
  576. std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer,
  577. 0);
  578. return;
  579. }
  580. if (!base::IsValueInRangeForNumericType<uint32_t>(buffer->size())) {
  581. USB_LOG(ERROR) << "Transfer too long.";
  582. std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer,
  583. 0);
  584. return;
  585. }
  586. auto interface_it =
  587. interfaces_.find(endpoint_it->second.interface->interface_number);
  588. if (interface_it == interfaces_.end()) {
  589. std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer,
  590. 0);
  591. return;
  592. }
  593. const auto& interface_interface = interface_it->second;
  594. auto transfer = std::make_unique<Transfer>();
  595. transfer->generic_callback = std::move(callback);
  596. transfer->handle = this;
  597. transfer->buffer = buffer;
  598. mojom::UsbTransferType transfer_type = endpoint_it->second.endpoint->type;
  599. transfer->type = transfer_type;
  600. switch (transfer_type) {
  601. case mojom::UsbTransferType::BULK:
  602. switch (direction) {
  603. case mojom::UsbTransferDirection::INBOUND:
  604. BulkIn(std::move(interface_interface),
  605. endpoint_it->second.pipe_reference, buffer,
  606. static_cast<uint32_t>(timeout), std::move(transfer));
  607. return;
  608. case mojom::UsbTransferDirection::OUTBOUND:
  609. BulkOut(std::move(interface_interface),
  610. endpoint_it->second.pipe_reference, buffer,
  611. static_cast<uint32_t>(timeout), std::move(transfer));
  612. return;
  613. }
  614. case mojom::UsbTransferType::INTERRUPT:
  615. switch (direction) {
  616. case mojom::UsbTransferDirection::INBOUND:
  617. InterruptIn(interface_interface, endpoint_it->second.pipe_reference,
  618. buffer, std::move(transfer));
  619. return;
  620. case mojom::UsbTransferDirection::OUTBOUND:
  621. InterruptOut(interface_interface, endpoint_it->second.pipe_reference,
  622. buffer, std::move(transfer));
  623. return;
  624. }
  625. default:
  626. std::move(transfer->generic_callback)
  627. .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
  628. }
  629. }
  630. const mojom::UsbInterfaceInfo* UsbDeviceHandleMac::FindInterfaceByEndpoint(
  631. uint8_t endpoint_address) {
  632. const auto endpoint_it = endpoint_map_.find(endpoint_address);
  633. if (endpoint_it != endpoint_map_.end())
  634. return endpoint_it->second.interface;
  635. return nullptr;
  636. }
  637. UsbDeviceHandleMac::~UsbDeviceHandleMac() {}
  638. void UsbDeviceHandleMac::BulkIn(
  639. const ScopedIOUSBInterfaceInterface& interface_interface,
  640. uint8_t pipe_reference,
  641. scoped_refptr<base::RefCountedBytes> buffer,
  642. uint32_t timeout,
  643. std::unique_ptr<Transfer> transfer) {
  644. Transfer* transfer_data = transfer.get();
  645. auto result = transfers_.insert(std::move(transfer));
  646. IOReturn kr = (*interface_interface)
  647. ->ReadPipeAsyncTO(interface_interface, pipe_reference,
  648. buffer->front_as<void*>(),
  649. static_cast<uint32_t>(buffer->size()),
  650. timeout, timeout, &AsyncIoCallback,
  651. reinterpret_cast<void*>(transfer_data));
  652. if (kr != kIOReturnSuccess) {
  653. USB_LOG(ERROR) << "Failed to read from device: " << std::hex << kr;
  654. std::move((*result.first)->generic_callback)
  655. .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
  656. transfers_.erase(result.first);
  657. }
  658. }
  659. void UsbDeviceHandleMac::BulkOut(
  660. const ScopedIOUSBInterfaceInterface& interface_interface,
  661. uint8_t pipe_reference,
  662. scoped_refptr<base::RefCountedBytes> buffer,
  663. uint32_t timeout,
  664. std::unique_ptr<Transfer> transfer) {
  665. Transfer* transfer_data = transfer.get();
  666. auto result = transfers_.insert(std::move(transfer));
  667. IOReturn kr = (*interface_interface)
  668. ->WritePipeAsyncTO(interface_interface, pipe_reference,
  669. buffer->front_as<void*>(),
  670. static_cast<uint32_t>(buffer->size()),
  671. timeout, timeout, &AsyncIoCallback,
  672. reinterpret_cast<void*>(transfer_data));
  673. if (kr != kIOReturnSuccess) {
  674. USB_LOG(ERROR) << "Failed to write to device: " << std::hex << kr;
  675. std::move((*result.first)->generic_callback)
  676. .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
  677. transfers_.erase(result.first);
  678. }
  679. }
  680. void UsbDeviceHandleMac::InterruptIn(
  681. const ScopedIOUSBInterfaceInterface& interface_interface,
  682. uint8_t pipe_reference,
  683. scoped_refptr<base::RefCountedBytes> buffer,
  684. std::unique_ptr<Transfer> transfer) {
  685. Transfer* transfer_data = transfer.get();
  686. auto result = transfers_.insert(std::move(transfer));
  687. IOReturn kr = (*interface_interface)
  688. ->ReadPipeAsync(interface_interface, pipe_reference,
  689. buffer->front_as<void*>(),
  690. static_cast<uint32_t>(buffer->size()),
  691. &AsyncIoCallback,
  692. reinterpret_cast<void*>(transfer_data));
  693. if (kr != kIOReturnSuccess) {
  694. USB_LOG(ERROR) << "Failed to read from device: " << std::hex << kr;
  695. std::move(transfer_data->generic_callback)
  696. .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
  697. transfers_.erase(result.first);
  698. }
  699. }
  700. void UsbDeviceHandleMac::InterruptOut(
  701. const ScopedIOUSBInterfaceInterface& interface_interface,
  702. uint8_t pipe_reference,
  703. scoped_refptr<base::RefCountedBytes> buffer,
  704. std::unique_ptr<Transfer> transfer) {
  705. Transfer* transfer_data = transfer.get();
  706. auto result = transfers_.insert(std::move(transfer));
  707. IOReturn kr = (*interface_interface)
  708. ->WritePipeAsync(interface_interface, pipe_reference,
  709. buffer->front_as<void*>(),
  710. static_cast<uint32_t>(buffer->size()),
  711. &AsyncIoCallback,
  712. reinterpret_cast<void*>(transfer_data));
  713. if (kr != kIOReturnSuccess) {
  714. USB_LOG(ERROR) << "Failed to write to device: " << std::hex << kr;
  715. std::move(transfer_data->generic_callback)
  716. .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
  717. transfers_.erase(result.first);
  718. }
  719. }
  720. void UsbDeviceHandleMac::RefreshEndpointMap() {
  721. endpoint_map_.clear();
  722. const mojom::UsbConfigurationInfo* config = device_->GetActiveConfiguration();
  723. if (!config)
  724. return;
  725. for (const auto& map_entry : interfaces_) {
  726. uint8_t alternate_setting;
  727. IOReturn kr =
  728. (*map_entry.second)
  729. ->GetAlternateSetting(map_entry.second, &alternate_setting);
  730. if (kr != kIOReturnSuccess)
  731. continue;
  732. CombinedInterfaceInfo interface_info =
  733. FindInterfaceInfoFromConfig(config, map_entry.first, alternate_setting);
  734. if (!interface_info.IsValid())
  735. continue;
  736. // macOS references an interface's endpoint via an index number of the
  737. // endpoint we want in the given interface. It is called a pipe reference.
  738. // The indices start at 1 for each interface.
  739. uint8_t pipe_reference = 1;
  740. for (const auto& endpoint : interface_info.alternate->endpoints) {
  741. endpoint_map_[ConvertEndpointNumberToAddress(*endpoint)] = {
  742. interface_info.interface, endpoint.get(), pipe_reference};
  743. pipe_reference++;
  744. }
  745. }
  746. }
  747. void UsbDeviceHandleMac::ReportIsochronousTransferError(
  748. UsbDeviceHandle::IsochronousTransferCallback callback,
  749. std::vector<uint32_t> packet_lengths,
  750. mojom::UsbTransferStatus status) {
  751. std::vector<mojom::UsbIsochronousPacketPtr> packets;
  752. packets.reserve(packet_lengths.size());
  753. for (const auto& packet_length : packet_lengths) {
  754. auto packet = mojom::UsbIsochronousPacket::New();
  755. packet->length = packet_length;
  756. packet->transferred_length = 0;
  757. packet->status = status;
  758. packets.push_back(std::move(packet));
  759. }
  760. std::move(callback).Run(nullptr, std::move(packets));
  761. }
  762. void UsbDeviceHandleMac::Clear() {
  763. base::flat_set<std::unique_ptr<Transfer>, base::UniquePtrComparator>
  764. transfers;
  765. transfers.swap(transfers_);
  766. for (auto& transfer : transfers) {
  767. DCHECK(transfer);
  768. if (transfer->type == mojom::UsbTransferType::ISOCHRONOUS) {
  769. ReportIsochronousTransferError(std::move(transfer->isochronous_callback),
  770. transfer->packet_lengths,
  771. mojom::UsbTransferStatus::TRANSFER_ERROR);
  772. } else {
  773. std::move(transfer->generic_callback)
  774. .Run(mojom::UsbTransferStatus::TRANSFER_ERROR,
  775. std::move(transfer->buffer), 0);
  776. }
  777. }
  778. transfers.clear();
  779. interfaces_.clear();
  780. sources_.clear();
  781. }
  782. void UsbDeviceHandleMac::OnAsyncGeneric(IOReturn result,
  783. size_t size,
  784. Transfer* transfer) {
  785. auto transfer_it = transfers_.find(transfer);
  786. if (transfer_it == transfers_.end())
  787. return;
  788. auto transfer_ptr = std::move(*transfer_it);
  789. std::move(transfer_ptr->generic_callback)
  790. .Run(mojom::UsbTransferStatus::COMPLETED, transfer_ptr->buffer,
  791. transfer_ptr->buffer->size());
  792. transfers_.erase(transfer_it);
  793. }
  794. void UsbDeviceHandleMac::OnAsyncIsochronous(IOReturn result,
  795. size_t size,
  796. Transfer* transfer) {
  797. auto transfer_it = transfers_.find(transfer);
  798. if (transfer_it == transfers_.end())
  799. return;
  800. auto transfer_ptr = std::move(*transfer_it);
  801. std::vector<mojom::UsbIsochronousPacketPtr> packets;
  802. packets.reserve(transfer_ptr->frame_list.size());
  803. for (const auto& frame : transfer_ptr->frame_list) {
  804. auto packet = mojom::UsbIsochronousPacket::New();
  805. packet->length = frame.frReqCount;
  806. packet->transferred_length = frame.frActCount;
  807. packet->status = ConvertTransferStatus(frame.frStatus);
  808. packets.push_back(std::move(packet));
  809. }
  810. std::move(transfer_ptr->isochronous_callback)
  811. .Run(transfer_ptr->buffer, std::move(packets));
  812. transfers_.erase(transfer_it);
  813. }
  814. // static
  815. void UsbDeviceHandleMac::AsyncIoCallback(void* refcon,
  816. IOReturn result,
  817. void* arg0) {
  818. auto* transfer = reinterpret_cast<Transfer*>(refcon);
  819. DCHECK(transfer);
  820. DCHECK(transfer->handle);
  821. if (transfer->type == mojom::UsbTransferType::ISOCHRONOUS) {
  822. transfer->handle->OnAsyncIsochronous(result, reinterpret_cast<size_t>(arg0),
  823. transfer);
  824. return;
  825. }
  826. transfer->handle->OnAsyncGeneric(result, reinterpret_cast<size_t>(arg0),
  827. transfer);
  828. }
  829. } // namespace device