1 // Copyright 2018 The Fuchsia 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 5 #pragma once 6 7 #include <fbl/intrusive_double_list.h> 8 #include <fbl/intrusive_wavl_tree.h> 9 #include <fbl/unique_ptr.h> 10 #include <zircon/hw/usb/audio.h> 11 12 #include "usb-audio-descriptors.h" 13 #include "usb-audio-path.h" 14 #include "usb-audio-units.h" 15 16 namespace audio { 17 namespace usb { 18 19 class UsbAudioDevice; 20 21 class UsbAudioControlInterface { 22 public: 23 // Note that UsbAudioControlInterfaces are entirely owned by UsbAudioDevice 24 // instances. The control interface needs to hold a pointer to its parent, 25 // so it is critically important that the owning parent is certain that the 26 // control interface (and all of its children) have been properly shut down 27 // before exiting. At all times, the lifetime of the control interface 28 // needs to be a subset of the lifetime of the device parent. 29 static fbl::unique_ptr<UsbAudioControlInterface> Create(UsbAudioDevice* parent); 30 zx_status_t Initialize(DescriptorListMemory::Iterator* iter); 31 32 const char* log_prefix() const; 33 34 // Extract the AudioPath whose streaming terminal interface link ID matches 35 // the users request, if any. Otherwise, simply return nullptr. ExtractPath(uint8_t term_link,Direction direction)36 fbl::unique_ptr<AudioPath> ExtractPath(uint8_t term_link, Direction direction) { 37 return paths_.erase_if( 38 [term_link, direction](const AudioPath& path) -> bool { 39 return (path.stream_terminal().id() == term_link) && 40 (path.direction() == direction); 41 }); 42 } 43 44 45 private: 46 friend class fbl::unique_ptr<UsbAudioControlInterface>; 47 using UnitMap = fbl::WAVLTree<uint32_t, fbl::RefPtr<AudioUnit>>; 48 49 UsbAudioControlInterface(UsbAudioDevice* parent); 50 ~UsbAudioControlInterface(); 51 52 // A recursive method used to find interesting audio paths in the 53 // unit/terminal graph. See the comment at the end of the Init 54 // implementation for details about the algorithm used to find these paths. 55 fbl::unique_ptr<AudioPath> TracePath(const OutputTerminal& out_term, 56 const UnitMap::iterator& current, 57 uint32_t level = 0); 58 59 // The reference to our parent. Note, because of this unmanaged reference, 60 // it is critically important that the surrounding code ensure that we never 61 // outlive our parent device. 62 UsbAudioDevice& parent_; 63 64 // Cached, unmanaged pointers to our interface and class descriptors. The 65 // memory which backs these descriptors is kept alive by the top level 66 // desc_list_ reference. 67 // 68 // TODO(johngro) : this desc_list_ memory is contained in our parent 69 // UsbAudioDevice. Since we have already committed to having a lifetime 70 // which is strictly <= the lifetime of our parent, we should probably just 71 // access the descriptor memory using our parent instead of holding our own 72 // reference to it. 73 fbl::RefPtr<DescriptorListMemory> desc_list_; 74 const usb_interface_descriptor_t* interface_hdr_ = nullptr; 75 const usb_audio_ac_header_desc* class_hdr_ = nullptr; 76 77 // All unit/terminal IDs for a given Audio Control Interface 78 // 79 // TODO(johngro): Strictly speaking, we don't really need to hold onto this. 80 // If we wanted, we could just keep this as a local variable used during 81 // Init and discard it afterwards. 82 UnitMap units_; 83 84 // The complete set of valid paths we have discovered. 85 fbl::DoublyLinkedList<fbl::unique_ptr<AudioPath>> paths_; 86 }; 87 88 } // namespace usb 89 } // namespace audio 90