| // 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 |