osmo-asf4-dfu/hal/include/hpl_usb_host.h

619 lines
18 KiB
C

/**
* \file
*
* \brief SAM USB host HPL
*
* Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
*
* \asf_license_start
*
* \page License
*
* Subject to your compliance with these terms, you may use Microchip
* software and any derivatives exclusively with Microchip products.
* It is your responsibility to comply with third party license terms applicable
* to your use of third party software (including open source software) that
* may accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*
* \asf_license_stop
*
*/
#ifndef _HPL_USB_HOST_H_INCLUDED
#define _HPL_USB_HOST_H_INCLUDED
#include <hpl_usb.h>
#include <hpl_irq.h>
#include "hpl_usb_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Driver version */
#define USB_H_VERSION 0x00000001
/**
* @brief USB HCD callback types
*/
enum usb_h_cb_type {
/** SOF generated */
USB_H_CB_SOF,
/** Root Hub change detected */
USB_H_CB_ROOTHUB_CHANGE,
/** Number of USB HCD callback types */
USB_H_CB_N
};
/**
* @brief USB HCD resource strategy
*/
enum usb_h_rsc_strategy {
/** Normal resource allocation, e.g.,
* 1 bank for interrupt endpoint,
* 2 bank for bulk endpoint and normal iso endpoint,
* 3 bank for iso high bandwidth endpoint.
*/
USB_H_RSC_NORMAL = false,
/** Minimal resource allocation, e.g., only 1 bank for bulk endpoints */
USB_H_RSC_MINIMAL = true
};
/**
* @brief USB HCD pipe states
*/
enum usb_h_pipe_state {
/** Pipe is free to allocate */
USB_H_PIPE_S_FREE = 0x00,
/** Pipe is in configuration */
USB_H_PIPE_S_CFG = 0x01,
/** Pipe is allocated and idle */
USB_H_PIPE_S_IDLE = 0x02,
/** Pipe in control setup stage */
USB_H_PIPE_S_SETUP = 0x03,
/** Pipe in data IN stage */
USB_H_PIPE_S_DATI = 0x05,
/** Pipe in data OUT stage */
USB_H_PIPE_S_DATO = 0x06,
/** Pipe in data IN ZLP stage */
USB_H_PIPE_S_ZLPI = 0x07,
/** Pipe in data OUT ZLP stage */
USB_H_PIPE_S_ZLPO = 0x08,
/** Pipe in control status IN stage */
USB_H_PIPE_S_STATI = 0x09,
/** Pipe in control status OUT stage */
USB_H_PIPE_S_STATO = 0x0A,
/** Taken by physical pipe (in process) */
USB_H_PIPE_S_TAKEN = 0x10
};
/**
* @brief USB HCD status code
*/
enum usb_h_status {
/** OK */
USB_H_OK = ERR_NONE,
/** Busy */
USB_H_BUSY = ERR_BUSY,
/** Denied */
USB_H_DENIED = ERR_DENIED,
/** Timeout */
USB_H_TIMEOUT = ERR_TIMEOUT,
/** Abort */
USB_H_ABORT = ERR_ABORTED,
/** Stall protocol */
USB_H_STALL = ERR_PROTOCOL,
/** Transfer reset by pipe re-configure */
USB_H_RESET = ERR_REQ_FLUSHED,
/** Argument error */
USB_H_ERR_ARG = ERR_INVALID_ARG,
/** Operation not supported */
USB_H_ERR_UNSP_OP = ERR_UNSUPPORTED_OP,
/** No resource */
USB_H_ERR_NO_RSC = ERR_NO_RESOURCE,
/** Not initialized */
USB_H_ERR_NOT_INIT = ERR_NOT_INITIALIZED,
/** Some general error */
USB_H_ERR = ERR_IO
};
/** Forward declare for pipe structure */
struct usb_h_pipe;
/** Forward declare for driver descriptor structure */
struct usb_h_desc;
/**
* \brief Prototyping USB HCD callback of SOF
*/
typedef void (*usb_h_cb_sof_t)(struct usb_h_desc *drv);
/**
* \brief Prototyping USB HCD callback of root hub changing.
* According to the bitmap size, max port number is 31.
*/
typedef void (*usb_h_cb_roothub_t)(struct usb_h_desc *drv, uint8_t port, uint8_t ftr);
/**
* Prototyping USB HCD callback of pipe transfer done.
* For control pipe, it's forced to call even if there is no transfer
* in progress, since the pipe size could be changed at run time.
*/
typedef void (*usb_h_pipe_cb_xfer_t)(struct usb_h_pipe *pipe);
/** Access to max packet size of a pipe */
#define usb_h_pipe_max_pkt_size(p) (p->max_pkt_size)
/** Access to device address of a pipe */
#define usb_h_pipe_dev_addr(p) (p->dev)
/** Access to endpoint address of a pipe */
#define usb_h_pipe_ep_addr(p) (p->ep)
/** Access to state of a pipe */
#define usb_h_pipe_state(p) (p->x.general.state)
/** Access to status of a pipe */
#define usb_h_pipe_status(p) (p->x.general.status)
/**
* @brief USB Host Controller device structure
*/
struct usb_h_desc {
/** Pointer to hardware base */
void *hw;
/** Pointer to private data for Host Controller driver */
void *prvt;
/** Interrupt handling descriptor */
struct _irq_descriptor irq;
/** Callback of SOF */
usb_h_cb_sof_t sof_cb;
/** Callback of root hub change */
usb_h_cb_roothub_t rh_cb;
#if CONF_USB_H_INST_OWNER_SP
/** Extension for the driver owner (upper layer user) */
void *owner;
#endif
};
/**
* @brief Transfer descriptor for control transfer
*
* Timing in USB 2.0 spec.:
* - 9.2.6.1 : USB sets an upper limit of 5 seconds as the upper limit for any
* command to be processed.
* - 9.2.6.3 : if a device receives a SetAddress() request, the device must be
* able to complete processing of the request and be able to
* successfully complete the Status stage of the request within
* 50 ms.
* After successful completion of the Status stage, the device is
* allowed a SetAddress() recovery interval of 2 ms. At the end of
* this interval, the device must be able to accept Setup packets
* addressed to the new address.
* - 9.2.6.4 : For standard device requests that require no Data stage, a device
* must be able to complete the request and be able to successfully
* complete the Status stage of the request within 50 ms of receipt
* of the request. This limitation applies to requests to the
* device, interface, or endpoint.
* For standard device requests that require data stage transfer to
* the host, the device must be able to return the first data packet
* to the host within 500 ms of receipt of the request. For
* subsequent data packets, if any, the device must be able to
* return them within 500 ms of successful completion of the
* transmission of the previous packet. The device must then be
* able to successfully complete the status stage within 50 ms after
* returning the last data packet.
* For standard device requests that require a data stage transfer
* to the device, the 5-second limit applies.
* - 9.2.6.5 : Unless specifically exempted in the class document, all
* class-specific requests must meet the timing limitations for
* standard device requests.
*
* Conclusion:
* 1. Whole request with data: 5 seconds
* 2. Whole request without data: 50 ms
* 3. Data packets: 500 ms
*/
struct usb_h_ctrl_xfer {
/** Pointer to transfer data */
uint8_t *data;
/** Pointer to setup packet */
uint8_t *setup;
/** Expected transfer size */
uint16_t size;
/** Transfer count */
uint16_t count;
/** Timeout for request, -1 if disable timeout */
int16_t req_timeout;
/** Timeout between packets
* (500ms for data and 50ms for status), -1 if disabled */
int16_t pkt_timeout;
/** Packet size during transfer (<= allocate max packet size) */
uint16_t pkt_size;
/** Transfer state */
uint8_t state;
/** Last transfer status */
int8_t status;
};
/**
* @brief Transfer descriptor for bulk / interrupt / iso transfer
*/
struct usb_h_bulk_int_iso_xfer {
/** Expected transfer size */
uint32_t size;
/** Transfer count */
uint32_t count;
/** Pointer to transfer data */
uint8_t *data;
/** Reserved */
uint16_t reserved[3];
/** Transfer state */
uint8_t state;
/** Last transfer status */
int8_t status;
};
/**
* @brief Transfer descriptor for periodic high bandwidth transfer
*/
struct usb_h_high_bw_xfer {
/** Expected transfer size */
uint32_t size;
/** Transfer count */
uint32_t count;
/** Pointer to transfer data */
uint8_t *data;
/** Micro frame packet sizes */
uint16_t pkt_size[3];
/** Transfer state */
uint8_t state;
/** Last transfer status */
int8_t status;
};
/**
* @brief General transfer descriptor
*/
struct usb_h_xfer {
/** Reserved for different transfer */
union {
uint16_t u16[9];
uint8_t u8[18];
} reserved;
/** Transfer state */
uint8_t state;
/** Last transfer status */
int8_t status;
};
/**
* @brief USB Host Controller Driver Pipe structure
*/
struct usb_h_pipe {
/** Pointer to the USB Host Controller Driver */
struct usb_h_desc *hcd;
/** Pointer to the callback for transfer done */
usb_h_pipe_cb_xfer_t done;
#if CONF_USB_H_INST_OWNER_SP
/** Pointer to the pipe owner */
void *owner;
#endif
/** Endpoint max packet size (bits 10..0) */
uint16_t max_pkt_size;
/** Device address */
uint8_t dev;
/** Endpoint address */
uint8_t ep;
/** Endpoint interval */
uint8_t interval;
/** Endpoint type: Control, Isochronous, Bulk or Interrupt */
uint8_t type;
/** Current toggle (driver dependent) */
uint8_t toggle;
/** Endpoint number of banks (HW dependent) */
uint8_t bank : 2;
/** Transfer speed (HW dependent) */
uint8_t speed : 2;
/** High bandwidth periodic out */
uint8_t high_bw_out : 1;
/** Uses DMA (on transfer) */
uint8_t dma : 1;
/** Transfer ZLP support */
uint8_t zlp : 1;
/** Transfer periodic */
uint8_t periodic_start : 1;
/** Transfer status */
union {
/** General transfer info */
struct usb_h_xfer general;
/** Control transfer status */
struct usb_h_ctrl_xfer ctrl;
/** Bulk interrupt iso transfer status */
struct usb_h_bulk_int_iso_xfer bii;
/** Periodic high bandwidth transfer status */
struct usb_h_high_bw_xfer hbw;
} x;
};
/**
* @brief USB HCD Initialization
*
* @param drv Pointer to the HCD driver instance
* @param[in] hw Pointer to hardware base
* @param[in] prvt The private driver data (implement specific)
*
* @return Operation result status
* @retval ERR_DENIED Hardware has been enabled
* @retval ERR_NONE Operation done successfully
*/
int32_t _usb_h_init(struct usb_h_desc *drv, void *hw, void *prvt);
/**
* @brief USB HCD de-initialization
*
* @param drv The driver
*/
void _usb_h_deinit(struct usb_h_desc *drv);
/**
* @brief USB HCD enable
*
* @param drv The driver
*/
void _usb_h_enable(struct usb_h_desc *drv);
/**
* @brief USB HCD disable
*
* @param drv The driver
*/
void _usb_h_disable(struct usb_h_desc *drv);
/**
* @brief Register callbacks for USB HCD
*
* @param drv The driver
* @param[in] type The callback type
* @param[in] cb The callback function entry
*
* @return Operation result status
* @retval ERR_INVALID_ARG Argument error
* @retval ERR_NONE Operation done successfully
*/
int32_t _usb_h_register_callback(struct usb_h_desc *drv, enum usb_h_cb_type type, FUNC_PTR cb);
/**
* @brief Return current frame number
*
* @param drv The driver
*
* @return current frame number
*/
uint16_t _usb_h_get_frame_n(struct usb_h_desc *drv);
/**
* @brief Return current micro frame number
*
* @param drv The driver
*
* @return current micro frame number
*/
uint8_t _usb_h_get_microframe_n(struct usb_h_desc *drv);
/**
* @brief Suspend the USB bus
*
* @param drv The driver
*/
void _usb_h_suspend(struct usb_h_desc *drv);
/**
* @brief Resume the USB bus
*
* @param drv The driver
*/
void _usb_h_resume(struct usb_h_desc *drv);
/* Root hub related APIs */
/**
* \brief Reset the root hub port
*
* \param[in,out] drv Pointer to the USB HCD driver
* \param[in] port Root hub port, ignored if there is only one port
*/
void _usb_h_rh_reset(struct usb_h_desc *drv, uint8_t port);
/**
* \brief Suspend the root hub port
*
* \param[in,out] drv Pointer to the USB HCD driver
* \param[in] port Root hub port, ignored if there is only one port
*/
void _usb_h_rh_suspend(struct usb_h_desc *drv, uint8_t port);
/**
* \brief Resume the root hub port
*
* \param[in,out] drv Pointer to the USB HCD driver
* \param[in] port Root hub port, ignored if there is only one port
*/
void _usb_h_rh_resume(struct usb_h_desc *drv, uint8_t port);
/**
* \brief Root hub or port feature status check
*
* Check USB Spec. for hub status and feature selectors.
*
* \param[in] drv Pointer to the USB HCD driver
* \param[in] port Set to 0 to get hub status, otherwise to get port status
* \param[in] ftr Hub feature/status selector
* (0: connection, 2: suspend, 4: reset, 9: LS, 10: HS)
*
* \return \c true if the status bit is 1
*/
bool _usb_h_rh_check_status(struct usb_h_desc *drv, uint8_t port, uint8_t ftr);
/* Pipe transfer functions */
/**
* @brief Allocate a pipe for USB host communication
*
* @param drv The USB HCD driver
* @param[in] dev The device address
* @param[in] ep The endpoint address
* @param[in] max_pkt_size The endpoint maximum packet size
* @param[in] attr The endpoint attribute
* @param[in] interval The endpoint interval
* (bInterval of USB Endpoint Descriptor)
* @param[in] speed The transfer speed of the endpoint
* @param[in] minimum_rsc Minimum the resource usage, \sa usb_h_rsc_strategy
*
* @return Pointer to allocated pipe structure instance
* @retval NULL allocation fail
*/
struct usb_h_pipe *_usb_h_pipe_allocate(struct usb_h_desc *drv, uint8_t dev, uint8_t ep, uint16_t max_pkt_size,
uint8_t attr, uint8_t interval, uint8_t speed, bool minimum_rsc);
/**
* @brief Free an allocated pipe
*
* @param pipe The pipe
*
* @return Operation result status
* @retval ERR_BUSY Pipe is busy, use \ref _usb_h_pipe_abort to abort
* @retval ERR_NONE Operation done successfully
*/
int32_t _usb_h_pipe_free(struct usb_h_pipe *pipe);
/**
* @brief Modify parameters of an allocated control pipe
*
* @param pipe The pipe
* @param[in] dev The device address
* @param[in] ep The endpoint address
* @param[in] max_pkt_size The maximum packet size, must be equal or
* less than allocated size
* @param[in] speed The working speed
*
* @return Operation result status
* @retval ERR_NOT_INITIALIZED Pipe is not allocated
* @retval ERR_BUSY Pipe is busy transferring
* @retval ERR_INVALID_ARG Argument error
* @retval ERR_UNSUPPORTED_OP Pipe is not control pipe
* @retval ERR_NONE Operation done successfully
*/
int32_t _usb_h_pipe_set_control_param(struct usb_h_pipe *pipe, uint8_t dev, uint8_t ep, uint16_t max_pkt_size,
uint8_t speed);
/**
* @brief Register transfer callback on a pipe
*
* @param pipe The pipe
* @param[in] cb Transfer callback function
*
* @return Operation result status
* @retval ERR_INVALID_ARG Argument error
* @retval ERR_NONE Operation done successfully
*/
int32_t _usb_h_pipe_register_callback(struct usb_h_pipe *pipe, usb_h_pipe_cb_xfer_t cb);
/**
* @brief Issue a control transfer (request) on a pipe
*
* \note When there is data stage, timeout between data packets is 500ms, the
* timeout between last data packet and the status packet is 50ms.
*
* @param pipe The pipe
* @param[in] setup Pointer to the setup packet
* @param[in,out] data Pointer to the data buffer
* @param[in] length The data length
* @param[in] timeout Timeout for whole request in ms
*
* @return Operation result status
* @retval ERR_NOT_INITIALIZED Pipe is not allocated
* @retval ERR_BUSY Pipe is busy transferring
* @retval ERR_INVALID_ARG Argument error
* @retval ERR_UNSUPPORTED_OP Pipe is not control pipe
* @retval ERR_NONE Operation done successfully
*/
int32_t _usb_h_control_xfer(struct usb_h_pipe *pipe, uint8_t *setup, uint8_t *data, uint16_t length, int16_t timeout);
/**
* @brief Issue a bulk / interrupt / iso transfer on a pipe
*
* @param pipe The pipe
* @param[in,out] data Pointer to the data buffer
* @param[in] length The data length
* @param[in] auto_zlp Auto append ZLP for OUT
*
* @return Operation result status
* @retval ERR_NOT_INITIALIZED Pipe is not allocated
* @retval ERR_BUSY Pipe is busy transferring
* @retval ERR_INVALID_ARG Argument error
* @retval ERR_UNSUPPORTED_OP Pipe is control pipe
* @retval ERR_NONE Operation done successfully
*/
int32_t _usb_h_bulk_int_iso_xfer(struct usb_h_pipe *pipe, uint8_t *data, uint32_t length, bool auto_zlp);
/**
* @brief Issue a periodic high bandwidth output on a pipe
*
* @param pipe The pipe
* @param[in,out] data Pointer to the data buffer
* @param[in] length The data length
* @param[in] trans_pkt_size The transaction packet sizes in a micro frame,
* 0 to use endpoint max packet size
*
* @return Operation result status
* @retval ERR_NOT_INITIALIZED Pipe is not allocated
* @retval ERR_BUSY Pipe is busy transferring
* @retval ERR_INVALID_ARG Argument error
* @retval ERR_UNSUPPORTED_OP Pipe is not high bandwidth periodic pipe, or
* DMA feature not enabled, or
* high bandwidth not enabled
* @retval ERR_NONE Operation done successfully
*/
int32_t _usb_h_high_bw_out(struct usb_h_pipe *pipe, uint8_t *data, uint32_t length, uint16_t trans_pkt_size[3]);
/**
* @brief Check if pipe is busy transferring
*
* @param pipe The pipe
*
* @return \c true if pipe is busy
*/
bool _usb_h_pipe_is_busy(struct usb_h_pipe *pipe);
/**
* @brief Abort pending transfer on a pipe
*
* @param pipe The pipe
*/
void _usb_h_pipe_abort(struct usb_h_pipe *pipe);
#ifdef __cplusplus
}
#endif
#endif /* _HPL_USB_HOST_H_INCLUDED */