blob: 067b02cea1647981d7fdd95734c2b6c5238febe9 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 <fuchsia/hardware/usb/descriptor/c/banjo.h>
#include <stdio.h>
#include <memory>
#include <optional>
#include <usb/usb.h>
namespace usb {
zx_status_t InterfaceList::Create(const ddk::UsbProtocolClient& client, bool skip_alt,
std::optional<InterfaceList>* out) {
usb_protocol_t proto;
client.GetProto(&proto);
usb_desc_iter_t iter;
auto status = usb_desc_iter_init(&proto, &iter);
if (status != ZX_OK) {
return status;
}
out->emplace(iter, skip_alt);
return ZX_OK;
}
InterfaceList::iterator UnownedInterfaceList::begin() const {
if (!iter_.desc) {
return end();
}
usb_desc_iter_t iter = iter_;
usb_interface_assoc_descriptor_t* assoc = nullptr;
const usb_interface_descriptor_t* intf =
usb_desc_iter_next_interface_with_assoc(&iter, skip_alt_, &assoc);
return iterator(iter, skip_alt_, intf, assoc);
}
UnownedInterfaceList::const_iterator UnownedInterfaceList::cbegin() const {
return static_cast<UnownedInterfaceList::const_iterator>(begin());
}
UnownedInterfaceList::iterator UnownedInterfaceList::end() const {
usb_desc_iter_t init = {};
return iterator(init, skip_alt_, nullptr, nullptr);
}
UnownedInterfaceList::const_iterator UnownedInterfaceList::cend() const {
return static_cast<UnownedInterfaceList::const_iterator>(end());
}
void Interface::Next(bool skip_alt) {
usb_interface_assoc_descriptor_t* assoc = nullptr;
descriptor_ = usb_desc_iter_next_interface_with_assoc(&iter_, skip_alt, &assoc);
if (!descriptor_) {
return;
}
if (assoc) {
assoc_.emplace(
InterfaceAssociation{.assoc_desc = assoc, .interface_count = assoc->b_interface_count});
}
if (descriptor_->b_alternate_setting == 0) {
if (assoc_ && assoc_->interface_count == 0) {
assoc_.reset();
}
if (assoc_) {
assoc_->interface_count--;
}
}
}
EndpointList::iterator EndpointList::begin() const {
if (!iter_.desc) {
return end();
}
usb_desc_iter_t iter = iter_;
Endpoint endpoint = EndpointList::iterator::ReadEp(&iter);
return iterator(iter, endpoint);
}
EndpointList::const_iterator EndpointList::cbegin() const {
return static_cast<EndpointList::const_iterator>(begin());
}
EndpointList::iterator EndpointList::end() const {
Endpoint endpoint(/* descriptor = */ nullptr, /* ss_companion = */ std::nullopt);
return iterator(/* iter = */ {}, endpoint);
}
EndpointList::const_iterator EndpointList::cend() const {
return static_cast<EndpointList::const_iterator>(end());
}
Endpoint EndpointList::iterator::ReadEp(usb_desc_iter_t* iter) {
usb_endpoint_descriptor_t* descriptor = usb_desc_iter_next_endpoint(iter);
std::optional<const usb_ss_ep_comp_descriptor_t*> ss_companion = std::nullopt;
if (descriptor == nullptr) {
// If there's no descriptor, don't check for a SuperSpeed companion.
return Endpoint(descriptor, ss_companion);
}
// A SuperSpeed companion descriptor may optionally follow.
const usb_descriptor_header_t* header = usb_desc_iter_peek(iter);
if (header && header->b_descriptor_type == USB_DT_SS_EP_COMPANION) {
ss_companion = usb_desc_iter_next_ss_ep_comp(iter);
}
return Endpoint(descriptor, ss_companion);
}
EndpointList Interface::GetEndpointList() const { return EndpointList(iter_, descriptor_); }
DescriptorList Interface::GetDescriptorList() const { return DescriptorList(iter_, descriptor_); }
DescriptorList::iterator DescriptorList::begin() const {
if (!iter_.desc) {
return end();
}
usb_desc_iter_t iter = iter_;
const usb_descriptor_header_t* header;
DescriptorList::iterator::ReadHeader(&iter, &header);
return iterator(iter, header);
}
DescriptorList::const_iterator DescriptorList::cbegin() const {
return static_cast<DescriptorList::const_iterator>(begin());
}
DescriptorList::iterator DescriptorList::end() const {
usb_desc_iter_t init = {};
return iterator(init, nullptr);
}
DescriptorList::const_iterator DescriptorList::cend() const {
return static_cast<DescriptorList::const_iterator>(end());
}
void DescriptorList::iterator::ReadHeader(usb_desc_iter_t* iter,
const usb_descriptor_header_t** out) {
const usb_descriptor_header_t* ptr = usb_desc_iter_peek(iter);
usb_desc_iter_advance(iter);
if (ptr && ptr->b_descriptor_type != USB_DT_INTERFACE) {
*out = ptr;
} else {
*out = nullptr;
}
}
} // namespace usb