123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/device/usb/usb_device_handle_mac.h"
- #include <IOKit/IOCFBundle.h>
- #include <IOKit/IOCFPlugIn.h>
- #include <IOKit/IOKitLib.h>
- #include <IOKit/IOReturn.h>
- #include <IOKit/IOTypes.h>
- #include <IOKit/usb/IOUSBLib.h>
- #include <MacTypes.h>
- #include <memory>
- #include <numeric>
- #include <utility>
- #include "base/mac/scoped_ioobject.h"
- #include "base/mac/scoped_ioplugininterface.h"
- #include "base/memory/ref_counted.h"
- #include "base/memory/ref_counted_memory.h"
- #include "base/strings/string_number_conversions.h"
- #include "components/device_event_log/device_event_log.h"
- #include "services/device/public/cpp/usb/usb_utils.h"
- #include "services/device/usb/usb_device_mac.h"
- namespace device {
- struct Transfer {
- UsbDeviceHandleMac::TransferCallback generic_callback;
- scoped_refptr<UsbDeviceHandleMac> handle;
- scoped_refptr<base::RefCountedBytes> buffer;
- std::vector<uint32_t> packet_lengths;
- std::vector<IOUSBIsocFrame> frame_list;
- mojom::UsbTransferType type;
- UsbDeviceHandleMac::IsochronousTransferCallback isochronous_callback;
- };
- namespace {
- // This is the bit 7 of the request type.
- enum class EndpointDirection : uint8_t { kIn = 0x80, kOut = 0x00 };
- // These are bits 5 and 6 of the request type.
- enum class RequestType : uint8_t {
- kStandard = 0x00,
- kClass = 0x20,
- kVendor = 0x40,
- kReserved = 0x60
- };
- // These are bits 0 and 1 of the request type.
- enum class RequestRecipient : uint8_t {
- kDevice = 0x00,
- kInterface = 0x01,
- kEndpoint = 0x02,
- kOther = 0x03,
- };
- mojom::UsbTransferStatus ConvertTransferStatus(IOReturn status) {
- switch (status) {
- // kIOReturnUnderrun can be ignored because the lower-than-expected transfer
- // size is reported alongside the COMPLETED status.
- case kIOReturnUnderrun:
- case kIOReturnSuccess:
- return mojom::UsbTransferStatus::COMPLETED;
- case kIOUSBTransactionTimeout:
- return mojom::UsbTransferStatus::TIMEOUT;
- case kIOUSBPipeStalled:
- return mojom::UsbTransferStatus::STALLED;
- case kIOReturnOverrun:
- return mojom::UsbTransferStatus::BABBLE;
- case kIOReturnAborted:
- return mojom::UsbTransferStatus::CANCELLED;
- default:
- return mojom::UsbTransferStatus::TRANSFER_ERROR;
- }
- }
- uint8_t ConvertTransferDirection(mojom::UsbTransferDirection direction) {
- switch (direction) {
- case mojom::UsbTransferDirection::INBOUND:
- return static_cast<uint8_t>(EndpointDirection::kIn);
- case mojom::UsbTransferDirection::OUTBOUND:
- return static_cast<uint8_t>(EndpointDirection::kOut);
- }
- NOTREACHED();
- return 0;
- }
- uint8_t CreateRequestType(mojom::UsbTransferDirection direction,
- mojom::UsbControlTransferType request_type,
- mojom::UsbControlTransferRecipient recipient) {
- uint8_t result = ConvertTransferDirection(direction);
- switch (request_type) {
- case mojom::UsbControlTransferType::STANDARD:
- result |= static_cast<uint8_t>(RequestType::kStandard);
- break;
- case mojom::UsbControlTransferType::CLASS:
- result |= static_cast<uint8_t>(RequestType::kClass);
- break;
- case mojom::UsbControlTransferType::VENDOR:
- result |= static_cast<uint8_t>(RequestType::kVendor);
- break;
- case mojom::UsbControlTransferType::RESERVED:
- result |= static_cast<uint8_t>(RequestType::kReserved);
- break;
- }
- switch (recipient) {
- case mojom::UsbControlTransferRecipient::DEVICE:
- result |= static_cast<uint8_t>(RequestRecipient::kDevice);
- break;
- case mojom::UsbControlTransferRecipient::INTERFACE:
- result |= static_cast<uint8_t>(RequestRecipient::kInterface);
- break;
- case mojom::UsbControlTransferRecipient::ENDPOINT:
- result |= static_cast<uint8_t>(RequestRecipient::kEndpoint);
- break;
- case mojom::UsbControlTransferRecipient::OTHER:
- result |= static_cast<uint8_t>(RequestRecipient::kOther);
- break;
- }
- return result;
- }
- } // namespace
- UsbDeviceHandleMac::UsbDeviceHandleMac(
- scoped_refptr<UsbDeviceMac> device,
- ScopedIOUSBDeviceInterface device_interface)
- : device_interface_(std::move(device_interface)),
- device_(std::move(device)) {}
- scoped_refptr<UsbDevice> UsbDeviceHandleMac::GetDevice() const {
- return device_;
- }
- void UsbDeviceHandleMac::Close() {
- if (!device_)
- return;
- if (device_source_) {
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), device_source_.get(),
- kCFRunLoopDefaultMode);
- }
- for (const auto& source : sources_) {
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source.second.get(),
- kCFRunLoopDefaultMode);
- }
- IOReturn kr = (*device_interface_)->USBDeviceClose(device_interface_);
- if (kr != kIOReturnSuccess) {
- USB_LOG(DEBUG) << "Failed to close device: " << std::hex << kr;
- }
- Clear();
- device_->HandleClosed(this);
- device_ = nullptr;
- }
- void UsbDeviceHandleMac::SetConfiguration(int configuration_value,
- ResultCallback callback) {
- if (!device_) {
- std::move(callback).Run(false);
- return;
- }
- if (!base::IsValueInRangeForNumericType<uint8_t>(configuration_value)) {
- std::move(callback).Run(false);
- return;
- }
- Clear();
- IOReturn kr =
- (*device_interface_)
- ->SetConfiguration(device_interface_,
- static_cast<uint8_t>(configuration_value));
- if (kr != kIOReturnSuccess) {
- std::move(callback).Run(false);
- return;
- }
- device_->ActiveConfigurationChanged(configuration_value);
- std::move(callback).Run(true);
- }
- void UsbDeviceHandleMac::ClaimInterface(int interface_number,
- ResultCallback callback) {
- if (!device_) {
- std::move(callback).Run(false);
- return;
- }
- if (!base::IsValueInRangeForNumericType<uint8_t>(interface_number)) {
- std::move(callback).Run(false);
- return;
- }
- IOUSBFindInterfaceRequest request;
- request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
- request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
- request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
- request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
- base::mac::ScopedIOObject<io_iterator_t> interface_iterator;
- IOReturn kr =
- (*device_interface_)
- ->CreateInterfaceIterator(device_interface_, &request,
- interface_iterator.InitializeInto());
- if (kr != kIOReturnSuccess) {
- std::move(callback).Run(false);
- return;
- }
- base::mac::ScopedIOObject<io_service_t> usb_interface;
- while (usb_interface.reset(IOIteratorNext(interface_iterator)),
- usb_interface) {
- base::mac::ScopedIOPluginInterface<IOCFPlugInInterface> plugin_interface;
- int32_t score;
- kr = IOCreatePlugInInterfaceForService(
- usb_interface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID,
- plugin_interface.InitializeInto(), &score);
- if (kr != kIOReturnSuccess || !plugin_interface) {
- USB_LOG(ERROR) << "Unable to create a plug-in: " << std::hex << kr;
- continue;
- }
- ScopedIOUSBInterfaceInterface interface_interface;
- kr = (*plugin_interface)
- ->QueryInterface(plugin_interface.get(),
- CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
- reinterpret_cast<LPVOID*>(
- interface_interface.InitializeInto()));
- if (kr != kIOReturnSuccess || !interface_interface) {
- USB_LOG(ERROR) << "Could not create a device interface: " << std::hex
- << kr;
- continue;
- }
- uint8_t retrieved_interface_number;
- kr = (*interface_interface)
- ->GetInterfaceNumber(interface_interface,
- &retrieved_interface_number);
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Could not retrieve an interface number: " << std::hex
- << kr;
- continue;
- }
- if (retrieved_interface_number != interface_number)
- continue;
- kr = (*interface_interface)->USBInterfaceOpen(interface_interface);
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Could not open interface: " << std::hex << kr;
- break;
- }
- interfaces_[interface_number] = interface_interface;
- base::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source;
- kr = (*interface_interface)
- ->CreateInterfaceAsyncEventSource(
- interface_interface, run_loop_source.InitializeInto());
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Could not retrieve port: " << std::hex << kr;
- (*interface_interface)->USBInterfaceClose(interface_interface);
- break;
- }
- RefreshEndpointMap();
- CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source.get(),
- kCFRunLoopDefaultMode);
- sources_[interface_number] = run_loop_source;
- std::move(callback).Run(true);
- return;
- }
- std::move(callback).Run(false);
- USB_LOG(ERROR) << "Could not find interface matching number: "
- << interface_number;
- }
- void UsbDeviceHandleMac::ReleaseInterface(int interface_number,
- ResultCallback callback) {
- if (!device_) {
- std::move(callback).Run(false);
- return;
- }
- auto interface_it = interfaces_.find(static_cast<uint8_t>(interface_number));
- if (interface_it == interfaces_.end()) {
- std::move(callback).Run(false);
- return;
- }
- auto released_interface = std::move(interface_it->second);
- interfaces_.erase(interface_it);
- auto source_it = sources_.find(interface_number);
- if (source_it != sources_.end()) {
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source_it->second.get(),
- kCFRunLoopDefaultMode);
- sources_.erase(source_it);
- }
- IOReturn kr = (*released_interface)->USBInterfaceClose(released_interface);
- if (kr != kIOReturnSuccess) {
- std::move(callback).Run(false);
- return;
- }
- RefreshEndpointMap();
- std::move(callback).Run(true);
- }
- void UsbDeviceHandleMac::SetInterfaceAlternateSetting(int interface_number,
- int alternate_setting,
- ResultCallback callback) {
- if (!device_) {
- std::move(callback).Run(false);
- return;
- }
- auto interface_it = interfaces_.find(interface_number);
- if (interface_it == interfaces_.end()) {
- std::move(callback).Run(false);
- return;
- }
- const auto& interface_interface = interface_it->second;
- IOReturn kr =
- (*interface_interface)
- ->SetAlternateInterface(interface_interface, alternate_setting);
- if (kr != kIOReturnSuccess) {
- std::move(callback).Run(false);
- return;
- }
- RefreshEndpointMap();
- std::move(callback).Run(true);
- }
- void UsbDeviceHandleMac::ResetDevice(ResultCallback callback) {
- if (!device_) {
- std::move(callback).Run(false);
- return;
- }
- // TODO(https://crbug.com/1096743): Figure out if open interfaces need to be
- // closed as well.
- IOReturn kr = (*device_interface_)
- ->USBDeviceReEnumerate(device_interface_, /*options=*/0);
- if (kr != kIOReturnSuccess) {
- std::move(callback).Run(false);
- return;
- }
- Clear();
- std::move(callback).Run(true);
- }
- void UsbDeviceHandleMac::ClearHalt(mojom::UsbTransferDirection direction,
- uint8_t endpoint_number,
- ResultCallback callback) {
- if (!device_) {
- std::move(callback).Run(false);
- return;
- }
- uint8_t endpoint_address =
- ConvertTransferDirection(direction) | endpoint_number;
- auto* mojom_interface = FindInterfaceByEndpoint(endpoint_address);
- uint8_t interface_number = mojom_interface->interface_number;
- auto interface_it = interfaces_.find(interface_number);
- if (interface_it == interfaces_.end()) {
- std::move(callback).Run(false);
- return;
- }
- const auto endpoint_it = endpoint_map_.find(endpoint_address);
- if (endpoint_it == endpoint_map_.end()) {
- std::move(callback).Run(false);
- return;
- }
- const auto& interface_interface = interface_it->second;
- IOReturn kr = (*interface_interface)
- ->ClearPipeStall(interface_interface,
- endpoint_it->second.pipe_reference);
- if (kr != kIOReturnSuccess) {
- std::move(callback).Run(false);
- return;
- }
- std::move(callback).Run(true);
- }
- void UsbDeviceHandleMac::ControlTransfer(
- mojom::UsbTransferDirection direction,
- mojom::UsbControlTransferType request_type,
- mojom::UsbControlTransferRecipient recipient,
- uint8_t request,
- uint16_t value,
- uint16_t index,
- scoped_refptr<base::RefCountedBytes> buffer,
- unsigned int timeout,
- TransferCallback callback) {
- if (!device_) {
- std::move(callback).Run(mojom::UsbTransferStatus::DISCONNECT,
- std::move(buffer), 0);
- return;
- }
- if (!base::IsValueInRangeForNumericType<uint16_t>(buffer->size())) {
- USB_LOG(ERROR) << "Transfer too long.";
- std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR,
- std::move(buffer), 0);
- return;
- }
- if (!device_source_) {
- IOReturn kr = (*device_interface_)
- ->CreateDeviceAsyncEventSource(
- device_interface_, device_source_.InitializeInto());
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Unable to create device async event source: "
- << std::hex << kr;
- std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR,
- std::move(buffer), 0);
- }
- CFRunLoopAddSource(CFRunLoopGetCurrent(), device_source_.get(),
- kCFRunLoopDefaultMode);
- }
- IOUSBDevRequestTO device_request;
- device_request.bRequest = request;
- device_request.wValue = value;
- device_request.wIndex = index;
- device_request.bmRequestType =
- CreateRequestType(direction, request_type, recipient);
- device_request.pData = buffer->front_as<void*>();
- device_request.wLength = static_cast<uint16_t>(buffer->size());
- device_request.completionTimeout = timeout;
- device_request.noDataTimeout = timeout;
- auto transfer = std::make_unique<Transfer>();
- transfer->generic_callback = std::move(callback);
- transfer->handle = this;
- transfer->buffer = std::move(buffer);
- Transfer* transfer_ptr = transfer.get();
- auto result = transfers_.insert(std::move(transfer));
- IOReturn kr = (*device_interface_)
- ->DeviceRequestAsyncTO(
- device_interface_, &device_request, &AsyncIoCallback,
- reinterpret_cast<void*>(transfer_ptr));
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Failed to send control request: " << std::hex << kr;
- std::move((*result.first)->generic_callback)
- .Run(mojom::UsbTransferStatus::TRANSFER_ERROR,
- std::move((*result.first)->buffer), 0);
- transfers_.erase(result.first);
- }
- }
- void UsbDeviceHandleMac::IsochronousTransferIn(
- uint8_t endpoint,
- const std::vector<uint32_t>& packet_lengths,
- unsigned int timeout,
- IsochronousTransferCallback callback) {
- if (!device_) {
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::DISCONNECT);
- return;
- }
- uint8_t endpoint_address =
- ConvertTransferDirection(mojom::UsbTransferDirection::INBOUND) | endpoint;
- const auto endpoint_it = endpoint_map_.find(endpoint_address);
- if (endpoint_it == endpoint_map_.end()) {
- USB_LOG(ERROR) << "Failed to submit transfer because endpoint "
- << int{endpoint_address}
- << " is not part of a claimed interface.";
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- return;
- }
- size_t length =
- std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
- auto buffer = base::MakeRefCounted<base::RefCountedBytes>(length);
- auto interface_it =
- interfaces_.find(endpoint_it->second.interface->interface_number);
- if (interface_it == interfaces_.end()) {
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- return;
- }
- const auto& interface_interface = interface_it->second;
- uint64_t bus_frame;
- AbsoluteTime time;
- IOReturn kr = (*interface_interface)
- ->GetBusFrameNumber(interface_interface, &bus_frame, &time);
- if (kr != kIOReturnSuccess) {
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- return;
- }
- auto transfer = std::make_unique<Transfer>();
- transfer->isochronous_callback = std::move(callback);
- transfer->handle = this;
- transfer->buffer = buffer;
- transfer->type = mojom::UsbTransferType::ISOCHRONOUS;
- Transfer* transfer_data = transfer.get();
- auto result = transfers_.insert(std::move(transfer));
- std::vector<IOUSBIsocFrame> frame_list;
- for (const auto& size : packet_lengths) {
- if (!base::IsValueInRangeForNumericType<uint16_t>(size)) {
- USB_LOG(ERROR) << "Transfer too long.";
- ReportIsochronousTransferError(
- std::move(transfer_data->isochronous_callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- return;
- }
- IOUSBIsocFrame frame_entry;
- frame_entry.frReqCount = static_cast<uint16_t>(size);
- frame_list.push_back(frame_entry);
- }
- transfer_data->frame_list = frame_list;
- kr = (*interface_interface)
- ->ReadIsochPipeAsync(interface_interface,
- endpoint_it->second.pipe_reference,
- buffer->front_as<void*>(), bus_frame,
- static_cast<uint32_t>(packet_lengths.size()),
- transfer->frame_list.data(), &AsyncIoCallback,
- reinterpret_cast<void*>(transfer_data));
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Isochrnous read failed.";
- ReportIsochronousTransferError(
- std::move((*result.first)->isochronous_callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- transfers_.erase(result.first);
- return;
- }
- }
- void UsbDeviceHandleMac::IsochronousTransferOut(
- uint8_t endpoint,
- scoped_refptr<base::RefCountedBytes> buffer,
- const std::vector<uint32_t>& packet_lengths,
- unsigned int timeout,
- IsochronousTransferCallback callback) {
- if (!device_) {
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::DISCONNECT);
- return;
- }
- uint8_t endpoint_address =
- ConvertTransferDirection(mojom::UsbTransferDirection::INBOUND) | endpoint;
- const auto endpoint_it = endpoint_map_.find(endpoint_address);
- if (endpoint_it == endpoint_map_.end()) {
- USB_LOG(ERROR) << "Failed to submit transfer because endpoint "
- << int{endpoint_address}
- << " is not part of a claimed interface.";
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- return;
- }
- auto interface_it =
- interfaces_.find(endpoint_it->second.interface->interface_number);
- if (interface_it == interfaces_.end()) {
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- return;
- }
- const auto& interface_interface = interface_it->second;
- uint64_t bus_frame;
- AbsoluteTime time;
- IOReturn kr = (*interface_interface)
- ->GetBusFrameNumber(interface_interface, &bus_frame, &time);
- if (kr != kIOReturnSuccess) {
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- return;
- }
- auto transfer = std::make_unique<Transfer>();
- transfer->isochronous_callback = std::move(callback);
- transfer->handle = this;
- transfer->buffer = buffer;
- transfer->type = mojom::UsbTransferType::ISOCHRONOUS;
- Transfer* transfer_data = transfer.get();
- auto result = transfers_.insert(std::move(transfer));
- std::vector<IOUSBIsocFrame> frame_list;
- for (const auto& size : packet_lengths) {
- if (!base::IsValueInRangeForNumericType<uint16_t>(size)) {
- USB_LOG(ERROR) << "Transfer too long.";
- ReportIsochronousTransferError(
- std::move(transfer_data->isochronous_callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- return;
- }
- IOUSBIsocFrame frame_entry;
- frame_entry.frReqCount = static_cast<uint16_t>(size);
- frame_list.push_back(frame_entry);
- }
- transfer_data->frame_list = frame_list;
- kr = (*interface_interface)
- ->WriteIsochPipeAsync(interface_interface,
- endpoint_it->second.pipe_reference,
- buffer->front_as<void*>(), bus_frame,
- static_cast<uint32_t>(packet_lengths.size()),
- transfer->frame_list.data(), &AsyncIoCallback,
- reinterpret_cast<void*>(transfer_data));
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Isochrnous write failed.";
- ReportIsochronousTransferError(
- std::move((*result.first)->isochronous_callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- transfers_.erase(result.first);
- }
- }
- void UsbDeviceHandleMac::GenericTransfer(
- mojom::UsbTransferDirection direction,
- uint8_t endpoint_number,
- scoped_refptr<base::RefCountedBytes> buffer,
- unsigned int timeout,
- TransferCallback callback) {
- if (!device_) {
- std::move(callback).Run(mojom::UsbTransferStatus::DISCONNECT, buffer, 0);
- return;
- }
- uint8_t endpoint_address =
- ConvertEndpointNumberToAddress(endpoint_number, direction);
- const auto endpoint_it = endpoint_map_.find(endpoint_address);
- if (endpoint_it == endpoint_map_.end()) {
- USB_LOG(ERROR) << "Failed to submit transfer because endpoint "
- << int{endpoint_address}
- << " is not part of a claimed interface.";
- std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer,
- 0);
- return;
- }
- if (!base::IsValueInRangeForNumericType<uint32_t>(buffer->size())) {
- USB_LOG(ERROR) << "Transfer too long.";
- std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer,
- 0);
- return;
- }
- auto interface_it =
- interfaces_.find(endpoint_it->second.interface->interface_number);
- if (interface_it == interfaces_.end()) {
- std::move(callback).Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer,
- 0);
- return;
- }
- const auto& interface_interface = interface_it->second;
- auto transfer = std::make_unique<Transfer>();
- transfer->generic_callback = std::move(callback);
- transfer->handle = this;
- transfer->buffer = buffer;
- mojom::UsbTransferType transfer_type = endpoint_it->second.endpoint->type;
- transfer->type = transfer_type;
- switch (transfer_type) {
- case mojom::UsbTransferType::BULK:
- switch (direction) {
- case mojom::UsbTransferDirection::INBOUND:
- BulkIn(std::move(interface_interface),
- endpoint_it->second.pipe_reference, buffer,
- static_cast<uint32_t>(timeout), std::move(transfer));
- return;
- case mojom::UsbTransferDirection::OUTBOUND:
- BulkOut(std::move(interface_interface),
- endpoint_it->second.pipe_reference, buffer,
- static_cast<uint32_t>(timeout), std::move(transfer));
- return;
- }
- case mojom::UsbTransferType::INTERRUPT:
- switch (direction) {
- case mojom::UsbTransferDirection::INBOUND:
- InterruptIn(interface_interface, endpoint_it->second.pipe_reference,
- buffer, std::move(transfer));
- return;
- case mojom::UsbTransferDirection::OUTBOUND:
- InterruptOut(interface_interface, endpoint_it->second.pipe_reference,
- buffer, std::move(transfer));
- return;
- }
- default:
- std::move(transfer->generic_callback)
- .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
- }
- }
- const mojom::UsbInterfaceInfo* UsbDeviceHandleMac::FindInterfaceByEndpoint(
- uint8_t endpoint_address) {
- const auto endpoint_it = endpoint_map_.find(endpoint_address);
- if (endpoint_it != endpoint_map_.end())
- return endpoint_it->second.interface;
- return nullptr;
- }
- UsbDeviceHandleMac::~UsbDeviceHandleMac() {}
- void UsbDeviceHandleMac::BulkIn(
- const ScopedIOUSBInterfaceInterface& interface_interface,
- uint8_t pipe_reference,
- scoped_refptr<base::RefCountedBytes> buffer,
- uint32_t timeout,
- std::unique_ptr<Transfer> transfer) {
- Transfer* transfer_data = transfer.get();
- auto result = transfers_.insert(std::move(transfer));
- IOReturn kr = (*interface_interface)
- ->ReadPipeAsyncTO(interface_interface, pipe_reference,
- buffer->front_as<void*>(),
- static_cast<uint32_t>(buffer->size()),
- timeout, timeout, &AsyncIoCallback,
- reinterpret_cast<void*>(transfer_data));
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Failed to read from device: " << std::hex << kr;
- std::move((*result.first)->generic_callback)
- .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
- transfers_.erase(result.first);
- }
- }
- void UsbDeviceHandleMac::BulkOut(
- const ScopedIOUSBInterfaceInterface& interface_interface,
- uint8_t pipe_reference,
- scoped_refptr<base::RefCountedBytes> buffer,
- uint32_t timeout,
- std::unique_ptr<Transfer> transfer) {
- Transfer* transfer_data = transfer.get();
- auto result = transfers_.insert(std::move(transfer));
- IOReturn kr = (*interface_interface)
- ->WritePipeAsyncTO(interface_interface, pipe_reference,
- buffer->front_as<void*>(),
- static_cast<uint32_t>(buffer->size()),
- timeout, timeout, &AsyncIoCallback,
- reinterpret_cast<void*>(transfer_data));
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Failed to write to device: " << std::hex << kr;
- std::move((*result.first)->generic_callback)
- .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
- transfers_.erase(result.first);
- }
- }
- void UsbDeviceHandleMac::InterruptIn(
- const ScopedIOUSBInterfaceInterface& interface_interface,
- uint8_t pipe_reference,
- scoped_refptr<base::RefCountedBytes> buffer,
- std::unique_ptr<Transfer> transfer) {
- Transfer* transfer_data = transfer.get();
- auto result = transfers_.insert(std::move(transfer));
- IOReturn kr = (*interface_interface)
- ->ReadPipeAsync(interface_interface, pipe_reference,
- buffer->front_as<void*>(),
- static_cast<uint32_t>(buffer->size()),
- &AsyncIoCallback,
- reinterpret_cast<void*>(transfer_data));
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Failed to read from device: " << std::hex << kr;
- std::move(transfer_data->generic_callback)
- .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
- transfers_.erase(result.first);
- }
- }
- void UsbDeviceHandleMac::InterruptOut(
- const ScopedIOUSBInterfaceInterface& interface_interface,
- uint8_t pipe_reference,
- scoped_refptr<base::RefCountedBytes> buffer,
- std::unique_ptr<Transfer> transfer) {
- Transfer* transfer_data = transfer.get();
- auto result = transfers_.insert(std::move(transfer));
- IOReturn kr = (*interface_interface)
- ->WritePipeAsync(interface_interface, pipe_reference,
- buffer->front_as<void*>(),
- static_cast<uint32_t>(buffer->size()),
- &AsyncIoCallback,
- reinterpret_cast<void*>(transfer_data));
- if (kr != kIOReturnSuccess) {
- USB_LOG(ERROR) << "Failed to write to device: " << std::hex << kr;
- std::move(transfer_data->generic_callback)
- .Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
- transfers_.erase(result.first);
- }
- }
- void UsbDeviceHandleMac::RefreshEndpointMap() {
- endpoint_map_.clear();
- const mojom::UsbConfigurationInfo* config = device_->GetActiveConfiguration();
- if (!config)
- return;
- for (const auto& map_entry : interfaces_) {
- uint8_t alternate_setting;
- IOReturn kr =
- (*map_entry.second)
- ->GetAlternateSetting(map_entry.second, &alternate_setting);
- if (kr != kIOReturnSuccess)
- continue;
- CombinedInterfaceInfo interface_info =
- FindInterfaceInfoFromConfig(config, map_entry.first, alternate_setting);
- if (!interface_info.IsValid())
- continue;
- // macOS references an interface's endpoint via an index number of the
- // endpoint we want in the given interface. It is called a pipe reference.
- // The indices start at 1 for each interface.
- uint8_t pipe_reference = 1;
- for (const auto& endpoint : interface_info.alternate->endpoints) {
- endpoint_map_[ConvertEndpointNumberToAddress(*endpoint)] = {
- interface_info.interface, endpoint.get(), pipe_reference};
- pipe_reference++;
- }
- }
- }
- void UsbDeviceHandleMac::ReportIsochronousTransferError(
- UsbDeviceHandle::IsochronousTransferCallback callback,
- std::vector<uint32_t> packet_lengths,
- mojom::UsbTransferStatus status) {
- std::vector<mojom::UsbIsochronousPacketPtr> packets;
- packets.reserve(packet_lengths.size());
- for (const auto& packet_length : packet_lengths) {
- auto packet = mojom::UsbIsochronousPacket::New();
- packet->length = packet_length;
- packet->transferred_length = 0;
- packet->status = status;
- packets.push_back(std::move(packet));
- }
- std::move(callback).Run(nullptr, std::move(packets));
- }
- void UsbDeviceHandleMac::Clear() {
- base::flat_set<std::unique_ptr<Transfer>, base::UniquePtrComparator>
- transfers;
- transfers.swap(transfers_);
- for (auto& transfer : transfers) {
- DCHECK(transfer);
- if (transfer->type == mojom::UsbTransferType::ISOCHRONOUS) {
- ReportIsochronousTransferError(std::move(transfer->isochronous_callback),
- transfer->packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
- } else {
- std::move(transfer->generic_callback)
- .Run(mojom::UsbTransferStatus::TRANSFER_ERROR,
- std::move(transfer->buffer), 0);
- }
- }
- transfers.clear();
- interfaces_.clear();
- sources_.clear();
- }
- void UsbDeviceHandleMac::OnAsyncGeneric(IOReturn result,
- size_t size,
- Transfer* transfer) {
- auto transfer_it = transfers_.find(transfer);
- if (transfer_it == transfers_.end())
- return;
- auto transfer_ptr = std::move(*transfer_it);
- std::move(transfer_ptr->generic_callback)
- .Run(mojom::UsbTransferStatus::COMPLETED, transfer_ptr->buffer,
- transfer_ptr->buffer->size());
- transfers_.erase(transfer_it);
- }
- void UsbDeviceHandleMac::OnAsyncIsochronous(IOReturn result,
- size_t size,
- Transfer* transfer) {
- auto transfer_it = transfers_.find(transfer);
- if (transfer_it == transfers_.end())
- return;
- auto transfer_ptr = std::move(*transfer_it);
- std::vector<mojom::UsbIsochronousPacketPtr> packets;
- packets.reserve(transfer_ptr->frame_list.size());
- for (const auto& frame : transfer_ptr->frame_list) {
- auto packet = mojom::UsbIsochronousPacket::New();
- packet->length = frame.frReqCount;
- packet->transferred_length = frame.frActCount;
- packet->status = ConvertTransferStatus(frame.frStatus);
- packets.push_back(std::move(packet));
- }
- std::move(transfer_ptr->isochronous_callback)
- .Run(transfer_ptr->buffer, std::move(packets));
- transfers_.erase(transfer_it);
- }
- // static
- void UsbDeviceHandleMac::AsyncIoCallback(void* refcon,
- IOReturn result,
- void* arg0) {
- auto* transfer = reinterpret_cast<Transfer*>(refcon);
- DCHECK(transfer);
- DCHECK(transfer->handle);
- if (transfer->type == mojom::UsbTransferType::ISOCHRONOUS) {
- transfer->handle->OnAsyncIsochronous(result, reinterpret_cast<size_t>(arg0),
- transfer);
- return;
- }
- transfer->handle->OnAsyncGeneric(result, reinterpret_cast<size_t>(arg0),
- transfer);
- }
- } // namespace device
|