blob: 8c0087bc17a0b6baa6e56da58e5db7f485fa3a07 [file] [log] [blame]
// Copyright 2016 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 <ddk/protocol/usb.h>
#include <ddk/protocol/usb/composite.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/hw/usb.h>
#ifdef __cplusplus
#include <ddktl/protocol/usb.h>
#endif
__BEGIN_CDECLS
// helper function for claiming additional interfaces that satisfy the want_interface predicate,
// want_interface will be passed the supplied arg
zx_status_t usb_claim_additional_interfaces(
usb_composite_protocol_t* comp,
bool (*want_interface)(usb_interface_descriptor_t*, void*),
void* arg);
// Utilities for iterating through descriptors within a device's USB configuration descriptor
typedef struct {
uint8_t* desc; // start of configuration descriptor
uint8_t* desc_end; // end of configuration descriptor
uint8_t* current; // current position in configuration descriptor
} usb_desc_iter_t;
// initializes a usb_desc_iter_t
zx_status_t usb_desc_iter_init(usb_protocol_t* usb, usb_desc_iter_t* iter);
// Clones a usb_desc_iter_t
zx_status_t usb_desc_iter_clone(const usb_desc_iter_t* src, usb_desc_iter_t* dest);
// releases resources in a usb_desc_iter_t
void usb_desc_iter_release(usb_desc_iter_t* iter);
// resets iterator to the beginning
void usb_desc_iter_reset(usb_desc_iter_t* iter);
// returns the next descriptor
usb_descriptor_header_t* usb_desc_iter_next(usb_desc_iter_t* iter);
// returns the next descriptor without incrementing the iterator
usb_descriptor_header_t* usb_desc_iter_peek(usb_desc_iter_t* iter);
// returns the next interface descriptor, optionally skipping alternate interfaces
usb_interface_descriptor_t* usb_desc_iter_next_interface(usb_desc_iter_t* iter, bool skip_alt);
// returns the next endpoint descriptor within the current interface
usb_endpoint_descriptor_t* usb_desc_iter_next_endpoint(usb_desc_iter_t* iter);
static inline zx_status_t usb_get_descriptor(const usb_protocol_t* usb, uint8_t request_type,
uint16_t type, uint16_t index, void* data,
size_t length, zx_time_t timeout, size_t* out_length) {
return usb_control_in(usb, request_type | USB_DIR_IN, USB_REQ_GET_DESCRIPTOR,
(uint16_t)(type << 8 | index), 0, timeout, data, length, out_length);
}
static inline zx_status_t usb_get_status(const usb_protocol_t* usb, uint8_t request_type,
uint16_t index, void* data, size_t length,
zx_time_t timeout, size_t* out_length) {
return usb_control_in(usb, request_type | USB_DIR_IN, USB_REQ_GET_STATUS, 0, index, timeout,
data, length, out_length);
}
static inline zx_status_t usb_set_feature(const usb_protocol_t* usb, uint8_t request_type,
uint16_t feature, uint16_t index, zx_time_t timeout) {
return usb_control_out(usb, request_type, USB_REQ_SET_FEATURE, feature, index, timeout,
NULL, 0);
}
static inline zx_status_t usb_clear_feature(const usb_protocol_t* usb, uint8_t request_type,
uint16_t feature, uint16_t index, zx_time_t timeout) {
return usb_control_out(usb, request_type, USB_REQ_CLEAR_FEATURE, feature, index, timeout,
NULL, 0);
}
__END_CDECLS
#ifdef __cplusplus
namespace usb {
class UsbDevice : public ddk::UsbProtocolClient {
public:
UsbDevice() {}
UsbDevice(const usb_protocol_t* proto)
: UsbProtocolClient(proto) {}
UsbDevice(zx_device_t* parent)
: UsbProtocolClient(parent) {
}
zx_status_t ClearFeature(uint8_t request_type,
uint16_t feature, uint16_t index, zx_time_t timeout) {
usb_protocol_t proto;
GetProto(&proto);
return usb_clear_feature(&proto, request_type, feature, index, timeout);
}
zx_status_t GetDescriptor(uint8_t request_type,
uint16_t type, uint16_t index, void* data,
size_t length, zx_time_t timeout, size_t* out_length) {
usb_protocol_t proto;
GetProto(&proto);
return usb_get_descriptor(&proto, request_type, type, index, data, length, timeout,
out_length);
}
zx_status_t GetStatus(uint8_t request_type,
uint16_t index, void* data, size_t length,
zx_time_t timeout, size_t* out_length) {
usb_protocol_t proto;
GetProto(&proto);
return usb_get_status(&proto, request_type, index, data, length, timeout, out_length);
}
zx_status_t SetFeature(int8_t request_type,
uint16_t feature, uint16_t index, zx_time_t timeout) {
usb_protocol_t proto;
GetProto(&proto);
return usb_set_feature(&proto, request_type, feature, index, timeout);
}
};
// Usage and implementation notes
// Interface is owned by an iterator of an InterfaceList.
// It is possible to enumerate all USB endpoint descriptors
// by using the standard iterator interface, or a for loop
// such as for (auto endpoint:interface) { ... }
// where interface is an instance of an Interface.
// Interfaces must not outlive their original InterfaceLists.
class Interface {
private:
class iterator_impl;
public:
using const_iterator = iterator_impl;
const usb_interface_descriptor_t* descriptor() const {
return descriptor_;
}
const_iterator begin() const;
const const_iterator cbegin() const;
const_iterator end() const;
const const_iterator cend() const;
friend class InterfaceList;
private:
class iterator_impl {
public:
iterator_impl(const usb_desc_iter_t& iter);
bool operator==(const iterator_impl& other) const {
return endpoint_ == other.endpoint_;
}
bool operator!=(const iterator_impl& other) const {
return endpoint_ != other.endpoint_;
}
iterator_impl operator++(int);
iterator_impl& operator++();
const usb_endpoint_descriptor_t* endpoint() const {
return endpoint_;
}
const usb_endpoint_descriptor_t& operator*() const {
return *endpoint_;
}
const usb_endpoint_descriptor_t* operator->() const {
return endpoint_;
}
private:
const usb_endpoint_descriptor_t* endpoint_;
usb_desc_iter_t iter_;
};
Interface() {}
Interface(const usb_desc_iter_t& iter)
: iter_(iter), descriptor_(nullptr) {
}
void Next(bool skip_alt);
usb_desc_iter_t iter_;
const usb_interface_descriptor_t* descriptor_;
};
// Usage and implementation notes
// An InterfaceList can be used for enumerating USB interfaces and endpoints.
// It implements a standard C++ iterator interface, which can be used with a for loop.
// such as for(interface:interface_list) { ... }
// The InterfaceList constructor takes in a UsbProtocolClient as a parameter,
// and a boolean skip_alt parameter.
// The InterfaceList will enumerate interfaces in the client,
// and will skip any alternate interfaces if skip_alt is true.
// (see page 268 of the USB 2.0 specification for more information)
// The constructor may fail in the event of a memory allocation failure or other protocol error.
// After constructing this InterfaceList,
// it is recommended to use .check() to verify the operation succeeded.
// If check returns an error, it is still safe to call the iteration functions,
// but the resulting enumeration will return no values.
class InterfaceList {
private:
class iterator_impl;
public:
using const_iterator = iterator_impl;
const_iterator begin() const;
const const_iterator cbegin() const;
const_iterator end() const;
const const_iterator cend() const;
InterfaceList(const ddk::UsbProtocolClient& client, bool skip_alt = false);
zx_status_t check() const;
~InterfaceList();
private:
class iterator_impl {
public:
iterator_impl(const usb_desc_iter_t& iter, bool skip_alt_);
bool operator==(const iterator_impl& other) const {
return interface_.descriptor_ == other.interface_.descriptor_;
}
bool operator!=(const iterator_impl& other) const {
return interface_.descriptor_ != other.interface_.descriptor_;
}
iterator_impl operator++(int);
iterator_impl& operator++();
const Interface* get() const {
return &interface_;
}
const Interface& operator*() const {
return interface_;
}
const Interface* operator->() const {
return &interface_;
}
private:
Interface interface_;
const bool skip_alt_;
};
const bool skip_alt_;
zx_status_t status_;
usb_desc_iter_t iter_;
};
} // namespace usb
#endif