| // Copyright 2018 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. | 
 |  | 
 | #pragma once | 
 |  | 
 | #include <fbl/intrusive_double_list.h> | 
 | #include <fbl/intrusive_wavl_tree.h> | 
 | #include <fbl/unique_ptr.h> | 
 | #include <zircon/hw/usb-audio.h> | 
 |  | 
 | #include "usb-audio-descriptors.h" | 
 | #include "usb-audio-path.h" | 
 | #include "usb-audio-units.h" | 
 |  | 
 | namespace audio { | 
 | namespace usb { | 
 |  | 
 | class UsbAudioDevice; | 
 |  | 
 | class UsbAudioControlInterface { | 
 |   public: | 
 |     // Note that UsbAudioControlInterfaces are entirely owned by UsbAudioDevice | 
 |     // instances.  The control interface needs to hold a pointer to its parent, | 
 |     // so it is critically important that the owning parent is certain that the | 
 |     // control interface (and all of its children) have been properly shut down | 
 |     // before exiting.  At all times, the lifetime of the control interface | 
 |     // needs to be a subset of the lifetime of the device parent. | 
 |     static fbl::unique_ptr<UsbAudioControlInterface> Create(UsbAudioDevice* parent); | 
 |     zx_status_t Initialize(DescriptorListMemory::Iterator* iter); | 
 |  | 
 |     const char* log_prefix() const; | 
 |  | 
 |     // Extract the AudioPath whose streaming terminal interface link ID matches | 
 |     // the users request, if any.  Otherwise, simply return nullptr. | 
 |     fbl::unique_ptr<AudioPath> ExtractPath(uint8_t term_link, Direction direction) { | 
 |         return paths_.erase_if( | 
 |             [term_link, direction](const AudioPath& path) -> bool { | 
 |                 return (path.stream_terminal().id() == term_link) && | 
 |                        (path.direction() == direction); | 
 |             }); | 
 |     } | 
 |  | 
 |  | 
 |   private: | 
 |     friend class fbl::unique_ptr<UsbAudioControlInterface>; | 
 |     using UnitMap = fbl::WAVLTree<uint32_t, fbl::RefPtr<AudioUnit>>; | 
 |  | 
 |     UsbAudioControlInterface(UsbAudioDevice* parent); | 
 |     ~UsbAudioControlInterface(); | 
 |  | 
 |     // A recursive method used to find interesting audio paths in the | 
 |     // unit/terminal graph.  See the comment at the end of the Init | 
 |     // implementation for details about the algorithm used to find these paths. | 
 |     fbl::unique_ptr<AudioPath> TracePath(const OutputTerminal& out_term, | 
 |                                          const UnitMap::iterator& current, | 
 |                                          uint32_t level = 0); | 
 |  | 
 |     // The reference to our parent.  Note, because of this unmanaged reference, | 
 |     // it is critically important that the surrounding code ensure that we never | 
 |     // outlive our parent device. | 
 |     UsbAudioDevice& parent_; | 
 |  | 
 |     // Cached, unmanaged pointers to our interface and class descriptors.  The | 
 |     // memory which backs these descriptors is kept alive by the top level | 
 |     // desc_list_ reference. | 
 |     // | 
 |     // TODO(johngro) : this desc_list_ memory is contained in our parent | 
 |     // UsbAudioDevice.  Since we have already commited to having a lifetime | 
 |     // which is strictly <= the lifetime of our parent, we should probably just | 
 |     // access the descriptor memory using our parent instead of holding our own | 
 |     // reference to it. | 
 |     fbl::RefPtr<DescriptorListMemory> desc_list_; | 
 |     const usb_interface_descriptor_t* interface_hdr_ = nullptr; | 
 |     const usb_audio_ac_header_desc* class_hdr_ = nullptr; | 
 |  | 
 |     // All unit/terminal IDs for a given Audio Control Interface | 
 |     // | 
 |     // TODO(johngro): Strictly speaking, we don't really need to hold onto this. | 
 |     // If we wanted, we could just keep this as a local variable used during | 
 |     // Init and discard it afterwards. | 
 |     UnitMap units_; | 
 |  | 
 |     // The complete set of valid paths we have discovered. | 
 |     fbl::DoublyLinkedList<fbl::unique_ptr<AudioPath>> paths_; | 
 | }; | 
 |  | 
 | }  // namespace usb | 
 | }  // namespace audio |