blob: a20faf967c28ff5de02040f4c25faf46d336e771 [file] [log] [blame]
// 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
// Standard Includes
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <unistd.h>
// DDK includes
#include <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/device.h>
#include <ddk/protocol/astro-usb.h>
#include <ddk/protocol/platform-defs.h>
#include <ddk/protocol/platform-device.h>
#include <ddk/protocol/usb-bus.h>
#include <ddk/protocol/usb-dci.h>
#include <ddk/protocol/usb-hci.h>
#include <ddk/protocol/usb-mode-switch.h>
#include <ddk/protocol/usb.h>
// Zircon USB includes
#include <zircon/hw/usb.h>
#include <zircon/listnode.h>
#include <zircon/process.h>
#include "usb_dwc_regs.h"
#define MMIO_INDEX 0
#define IRQ_INDEX 0
//#define SINGLE_EP_IN_QUEUE 1
typedef enum dwc_ep0_state {
EP0_STATE_DISCONNECTED,
EP0_STATE_IDLE,
EP0_STATE_DATA_OUT,
EP0_STATE_DATA_IN,
EP0_STATE_STATUS,
EP0_STATE_STALL,
} dwc_ep0_state_t;
typedef struct {
list_node_t queued_reqs; // requests waiting to be processed
usb_request_t* current_req; // request currently being processed
uint8_t* req_buffer;
uint32_t req_offset;
uint32_t req_length;
// Used for synchronizing endpoint state
// and ep specific hardware registers
// This should be acquired before dwc_usb_t.lock
// if acquiring both locks.
mtx_t lock;
uint16_t max_packet_size;
uint8_t ep_num;
bool enabled;
uint8_t type; // control, bulk, interrupt or isochronous
uint8_t interval;
bool send_zlp;
bool stalled;
} dwc_endpoint_t;
typedef struct {
zx_device_t* zxdev;
usb_bus_interface_t bus;
zx_handle_t irq_handle;
zx_handle_t bti_handle;
thrd_t irq_thread;
zx_device_t* parent;
platform_device_protocol_t pdev;
usb_mode_switch_protocol_t ums;
astro_usb_protocol_t astro_usb;
usb_mode_t usb_mode;
dwc_regs_t* regs;
// device stuff
dwc_endpoint_t eps[DWC_MAX_EPS];
usb_dci_interface_t dci_intf;
#if SINGLE_EP_IN_QUEUE
list_node_t queued_in_reqs;
usb_request_t* current_in_req;
#endif
// Used for synchronizing global state
// and non ep specific hardware registers.
// dwc_endpoint_t.lock should be acquired first
// if acquiring both locks.
mtx_t lock;
bool configured;
usb_setup_t cur_setup;
dwc_ep0_state_t ep0_state;
uint8_t ep0_buffer[UINT16_MAX];
bool got_setup;
} dwc_usb_t;
// dwc-endpoints.c
bool dwc_ep_write_packet(dwc_usb_t* dwc, int ep_num);
void dwc_ep_start_transfer(dwc_usb_t* dwc, unsigned ep_num, bool is_in, size_t length);
void dwc_complete_ep(dwc_usb_t* dwc, uint32_t ep_num);
void dwc_reset_configuration(dwc_usb_t* dwc);
void dwc_start_eps(dwc_usb_t* dwc);
void dwc_ep_queue(dwc_usb_t* dwc, unsigned ep_num, usb_request_t* req);
zx_status_t dwc_ep_config(dwc_usb_t* dwc, usb_endpoint_descriptor_t* ep_desc,
usb_ss_ep_comp_descriptor_t* ss_comp_desc);
zx_status_t dwc_ep_disable(dwc_usb_t* dwc, uint8_t ep_addr);
zx_status_t dwc_ep_set_stall(dwc_usb_t* dwc, unsigned ep_num, bool stall);
// dwc-interrupts.c
zx_status_t dwc_irq_start(dwc_usb_t* dwc);
void dwc_irq_stop(dwc_usb_t* dwc);
void dwc_flush_fifo(dwc_usb_t* dwc, const int num);