blob: e23268dc1a567fc639639972c5dc445de4cf4c73 [file] [log] [blame]
// Copyright 2019 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.
#include <ddktl/device.h>
#include <ddktl/protocol/usb/function.h>
#include <usb/request-cpp.h>
#include <usb/usb-request.h>
static constexpr size_t BULK_TX_COUNT = 16;
static constexpr size_t BULK_RX_COUNT = 16;
static constexpr size_t INTR_COUNT = 8;
static constexpr size_t BULK_MAX_PACKET = 512; // FIXME(voydanoff) USB 3.0 support.
// FIXME(voydanoff) Increase this when DCI drivers support
// non-contiguous DMA buffers.
static constexpr size_t BULK_REQ_SIZE = 4096;
static constexpr size_t INTR_REQ_SIZE = 1024;
static constexpr size_t INTR_MAX_PACKET = 64;
namespace usb_function_test {
class UsbTest;
using UsbTestType = ddk::Device<UsbTest, ddk::UnbindableNew>;
class UsbTest : public UsbTestType, public ddk::UsbFunctionInterfaceProtocol<UsbTest> {
public:
explicit UsbTest(zx_device_t* parent) : UsbTestType(parent) {}
zx_status_t Init();
size_t UsbFunctionInterfaceGetDescriptorsSize() { return sizeof(descriptors_); }
void UsbFunctionInterfaceGetDescriptors(void* buffer, size_t buffer_size, size_t* out_actual);
zx_status_t UsbFunctionInterfaceControl(const usb_setup_t* setup, const void* write_buffer,
size_t write_size, void* read_buffer, size_t read_size,
size_t* out_read_actual);
zx_status_t UsbFunctionInterfaceSetConfigured(bool configured, usb_speed_t speed);
zx_status_t UsbFunctionInterfaceSetInterface(uint8_t interface, uint8_t alt_setting);
void DdkUnbindNew(ddk::UnbindTxn txn);
size_t UsbFunctionGetRequestSize() { return parent_req_size_ + sizeof(usb_req_internal_t); }
void DdkRelease();
static zx_status_t Create(void* ctx, zx_device_t* parent);
private:
void TestIntrComplete(usb_request_t* req);
void TestBulkOutComplete(usb_request_t* req);
void TestBulkInComplete(usb_request_t* req);
ddk::UsbFunctionProtocolClient function_;
// These are lists of usb_request_t.
usb::RequestQueue<void> bulk_out_reqs_ __TA_GUARDED(lock_);
usb::RequestQueue<void> bulk_in_reqs_ __TA_GUARDED(lock_);
usb::RequestQueue<void> intr_reqs_ __TA_GUARDED(lock_);
usb::RequestQueue<void> requests_;
uint8_t test_data_[INTR_REQ_SIZE];
size_t test_data_length_;
bool configured_;
fbl::Mutex lock_;
uint8_t bulk_out_addr_;
uint8_t bulk_in_addr_;
uint8_t intr_addr_;
size_t parent_req_size_;
struct {
usb_interface_descriptor_t intf;
usb_endpoint_descriptor_t intr_ep;
usb_endpoint_descriptor_t bulk_out_ep;
usb_endpoint_descriptor_t bulk_in_ep;
} descriptors_ = {
.intf =
{
.bLength = sizeof(usb_interface_descriptor_t),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0, // set later
.bAlternateSetting = 0,
.bNumEndpoints = 3,
.bInterfaceClass = USB_CLASS_VENDOR,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 0,
},
.intr_ep =
{
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0, // set later
.bmAttributes = USB_ENDPOINT_INTERRUPT,
.wMaxPacketSize = htole16(INTR_MAX_PACKET),
.bInterval = 8,
},
.bulk_out_ep =
{
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0, // set later
.bmAttributes = USB_ENDPOINT_BULK,
.wMaxPacketSize = htole16(BULK_MAX_PACKET),
.bInterval = 0,
},
.bulk_in_ep =
{
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0, // set later
.bmAttributes = USB_ENDPOINT_BULK,
.wMaxPacketSize = htole16(BULK_MAX_PACKET),
.bInterval = 0,
},
};
};
} // namespace usb_function_test