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 <ddk/protocol/usb.h>
8#include <fbl/ref_counted.h>
9#include <fbl/ref_ptr.h>
10#include <zircon/hw/usb.h>
11#include <zircon/types.h>
12#include <zircon/syscalls.h>
13
14#include <threads.h>
15#include <sys/types.h>
16
17namespace audio {
18namespace usb {
19
20// A small helper class for managing a device's descriptor list memory.
21class DescriptorListMemory : public fbl::RefCounted<DescriptorListMemory> {
22  public:
23    class Iterator {
24      public:
25        explicit Iterator(fbl::RefPtr<DescriptorListMemory> mem);
26
27        // Advance the iterator to the next valid header and return true.  If
28        // there are no more valid headers, simply return false.
29        bool Next();
30
31        bool valid() const { return (offset_ < mem_->size()); }
32        size_t offset() const { return offset_; }
33        const fbl::RefPtr<DescriptorListMemory>& desc_list() const { return mem_; }
34
35        const usb_descriptor_header_t* hdr() const {
36            if (!valid()) {
37                return nullptr;
38            }
39
40            auto tmp = reinterpret_cast<uintptr_t>(mem_->data());
41            return reinterpret_cast<const usb_descriptor_header_t*>(tmp + offset_);
42        }
43
44        template <typename T>
45        const T* hdr_as() const {
46            auto h = hdr();
47            ZX_DEBUG_ASSERT(offset_ <=  mem_->size());
48            return ((h != nullptr) && (h->bLength <= (mem_->size() - offset_)))
49                ? reinterpret_cast<const T*>(h)
50                : nullptr;
51        }
52
53      private:
54        DISALLOW_COPY_ASSIGN_AND_MOVE(Iterator);
55
56        // Validate that the current offset points at something which could be a
57        // valid descriptor which fits within the descriptor memory and return
58        // true.  Otherwise, invalidate the offset and return false.
59        bool ValidateOffset();
60
61        fbl::RefPtr<DescriptorListMemory> mem_;
62        size_t offset_ = 0;
63    };
64
65    static fbl::RefPtr<DescriptorListMemory> Create(usb_protocol_t* proto);
66    const void* data() const { return data_; }
67    size_t      size() const { return size_; }
68
69  private:
70    friend class fbl::RefPtr<DescriptorListMemory>;
71
72    DescriptorListMemory() = default;
73    ~DescriptorListMemory();
74
75    void*  data_ = nullptr;
76    size_t size_ = 0;
77};
78
79}  // namespace usb
80}  // namespace audio
81