| /** |
| * \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 */ |