| // Copyright 2020 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. |
| |
| #ifndef SRC_DEVICES_USB_TESTING_DESCRIPTOR_BUILDER_DESCRIPTOR_BUILDER_H_ |
| #define SRC_DEVICES_USB_TESTING_DESCRIPTOR_BUILDER_DESCRIPTOR_BUILDER_H_ |
| #include <zircon/hw/usb.h> |
| |
| #include <cstdint> |
| #include <vector> |
| |
| namespace usb { |
| static void VectorAppend(std::vector<uint8_t>& vector, const void* data, size_t size) { |
| vector.insert(vector.end(), static_cast<const uint8_t*>(data), |
| static_cast<const uint8_t*>(data) + size); |
| } |
| |
| template <typename T> |
| static void VectorAppend(std::vector<uint8_t>& vector, T value) { |
| VectorAppend(vector, &value, sizeof(value)); |
| } |
| |
| static inline uint8_t EpIndexToAddress(uint8_t index) { |
| return static_cast<uint8_t>((index & 0xF) | ((index & 0x10) << 3)); |
| } |
| |
| constexpr uint8_t kInEndpointStart = 17; |
| constexpr uint8_t kOutEndpointStart = 1; |
| |
| class EndpointBuilder { |
| public: |
| explicit EndpointBuilder(uint8_t config_num, uint8_t endpoint_type, uint8_t endpoint_index, |
| bool in) { |
| base_desc_.bmAttributes = endpoint_type; |
| base_desc_.bLength = sizeof(base_desc_); |
| base_desc_.bDescriptorType = USB_DT_ENDPOINT; |
| base_desc_.bEndpointAddress = |
| EpIndexToAddress(endpoint_index + (in ? kInEndpointStart : kOutEndpointStart)); |
| } |
| |
| std::vector<uint8_t> Generate() const { |
| size_t total = sizeof(base_desc_) + descriptors_.size(); |
| std::vector<uint8_t> data; |
| data.reserve(total); |
| VectorAppend(data, base_desc_); |
| VectorAppend(data, descriptors_.data(), descriptors_.size()); |
| return data; |
| } |
| |
| private: |
| std::vector<uint8_t> descriptors_; |
| usb_endpoint_descriptor_t base_desc_ = {}; |
| }; |
| |
| class InterfaceBuilder { |
| public: |
| explicit InterfaceBuilder(uint8_t config_num) { |
| base_desc_.bNumEndpoints = 0; |
| base_desc_.bLength = sizeof(base_desc_); |
| base_desc_.bDescriptorType = USB_DT_INTERFACE; |
| } |
| |
| void AddEndpoint(const EndpointBuilder& builder) { |
| auto data = builder.Generate(); |
| AddEndpoint(data.data(), data.size()); |
| } |
| void AddEndpoint(void* desc, size_t desc_length) { |
| VectorAppend(descriptors_, desc, desc_length); |
| base_desc_.bNumEndpoints++; |
| } |
| |
| std::vector<uint8_t> Generate() const { |
| size_t total = sizeof(base_desc_) + descriptors_.size(); |
| std::vector<uint8_t> data; |
| data.reserve(total); |
| VectorAppend(data, base_desc_); |
| VectorAppend(data, descriptors_.data(), descriptors_.size()); |
| return data; |
| } |
| |
| private: |
| std::vector<uint8_t> descriptors_; |
| usb_interface_descriptor_t base_desc_ = {}; |
| }; |
| |
| class ConfigurationBuilder { |
| public: |
| explicit ConfigurationBuilder(uint8_t config_num) { |
| base_desc_.bNumInterfaces = 0; |
| base_desc_.iConfiguration = config_num; |
| base_desc_.bLength = sizeof(base_desc_); |
| base_desc_.bDescriptorType = USB_DT_CONFIG; |
| } |
| |
| void AddInterface(const InterfaceBuilder& builder) { |
| auto data = builder.Generate(); |
| AddInterface(data.data(), data.size()); |
| } |
| void AddInterface(void* interface_desc, size_t interface_desc_length) { |
| VectorAppend(descriptors_, interface_desc, interface_desc_length); |
| base_desc_.bNumInterfaces++; |
| } |
| |
| std::vector<uint8_t> Generate() const { |
| size_t total = sizeof(base_desc_) + descriptors_.size(); |
| std::vector<uint8_t> data; |
| data.reserve(total); |
| VectorAppend(data, base_desc_); |
| VectorAppend(data, descriptors_.data(), descriptors_.size()); |
| return data; |
| } |
| |
| private: |
| std::vector<uint8_t> descriptors_; |
| usb_configuration_descriptor_t base_desc_ = {}; |
| }; |
| |
| class DeviceDescriptorBuilder { |
| public: |
| explicit DeviceDescriptorBuilder() { |
| base_desc_.bNumConfigurations = 0; |
| base_desc_.bLength = sizeof(base_desc_); |
| base_desc_.bDescriptorType = USB_DT_DEVICE; |
| } |
| |
| void AddConfiguration(const ConfigurationBuilder& builder) { |
| auto data = builder.Generate(); |
| AddConfiguration(data.data(), data.size()); |
| } |
| void AddConfiguration(void* config_desc, size_t config_desc_length) { |
| VectorAppend(descriptors_, config_desc, config_desc_length); |
| base_desc_.bNumConfigurations++; |
| } |
| |
| std::vector<uint8_t> Generate() { |
| size_t total = sizeof(base_desc_) + descriptors_.size(); |
| std::vector<uint8_t> data; |
| data.reserve(total); |
| VectorAppend(data, base_desc_); |
| VectorAppend(data, descriptors_.data(), descriptors_.size()); |
| return data; |
| } |
| |
| private: |
| std::vector<uint8_t> descriptors_; |
| usb_device_descriptor_t base_desc_ = {}; |
| }; |
| } // namespace usb |
| #endif // SRC_DEVICES_USB_TESTING_DESCRIPTOR_BUILDER_DESCRIPTOR_BUILDER_H_ |