/* Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA"). * All rights reserved. * * This software is supplied "AS IS" without any warranties. * RDA assumes no responsibility or liability for the use of the software, * conveys no license or title under any patent, copyright, or mask work * right to the product. RDA reserves the right to make changes in the * software without notification. RDA also make no representation or * warranty that such application will be suitable for the specified use * without further testing or modification. */ #ifndef _USB__DEVICE_H_ #define _USB__DEVICE_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include "usb/usb_ch9.h" typedef enum { EP0_SETUP = 0, #define EP0_STATE_DIRIN_MASK 0b10 #define EP0_STATE_DATA_MASK 0b1 EP0_DATA_IN = 0b111, EP0_DATA_OUT = 0b101, EP0_STATUS_IN = 0b110, EP0_STATUS_OUT = 0b100, } ep0State_t; typedef enum { UDC_IDLE = 0, UDC_CONNECTED, UDC_DISCONNECT, } udcEvent_t; typedef void (*udcNotifier_t)(void *param, udcEvent_t event); /** * @brief USB device controller */ typedef struct udc_s udc_t; /** * @brief USB device driver * * Such as a specific class, or a composite driver */ typedef struct usb_dev_driver_s udevDrv_t; /** * @brief usb endpoint */ typedef struct usb_ep { union { struct { uint8_t num : 7; uint8_t dirin : 1; }; uint8_t address; }; uint16_t mps; } usbEp_t; /** * @brief usb string */ typedef struct usb_string { uint8_t id; uint8_t ref_count; const char *s; } usbString_t; /** * @brief the usb transfer request */ typedef struct usb_xfer { void *buf; ///< transfer buffer uint32_t length; ///< transfer data length uint32_t actual; ///< actual transfered length, udc set it, caller only read int status; ///< transfer status, (0 - success; other negative - fail) uint8_t zlp; ///< may send zero packet or not, in transfer only uint8_t uncached; ///< address is uncached void *param; ///< caller context void (*complete)(usbEp_t *ep, struct usb_xfer *xfer); ///< transfer done callback } usbXfer_t; typedef struct { void (*setclk)(udc_t *udc, bool on); ///< set controller clock void (*setpower)(udc_t *udc, bool on); ///< set controller power void (*enable)(udc_t *udc); ///< enable the usb controller void (*disable)(udc_t *udc); ///< disable the usb controller void (*suspend)(udc_t *udc); ///< suspend the usb controller void (*resume)(udc_t *udc); ///< resume the usb controller } udcPlatOps_t; /** * @brief struct for udc operations */ typedef struct { void (*start)(udc_t *udc); ///< start the udc void (*stop)(udc_t *udc); ///< stop the udc bool (*remote_wakeup)(udc_t *udc); ///< remote wakeup int (*enqueue)(udc_t *udc, usbEp_t *ep, usbXfer_t *req); ///< enqueue an usb request void (*dequeue)(udc_t *udc, usbEp_t *ep, usbXfer_t *req); ///< dequeue an usb request void (*dequeue_all)(udc_t *udc, usbEp_t *ep); ///< dequeue all for specific endpoint usbEp_t *(*ep_alloc)(udc_t *udc, usb_endpoint_descriptor_t *desc); ///< allocate an usb endpoint void (*ep_free)(udc_t *udc, usbEp_t *ep); ///< free an usb endpoint int (*ep_enable)(udc_t *udc, usbEp_t *ep); ///< enable the endpoint void (*ep_disable)(udc_t *udc, usbEp_t *ep); ///< disable the endpoint void (*ep_stall)(udc_t *udc, usbEp_t *ep, bool halt); ///< stall or clear stall for an endpoint usbXfer_t *(*xfer_alloc)(udc_t *udc); ///< allocate an usb xfer void (*xfer_free)(udc_t *udc, usbXfer_t *xfer); ///< free the usb xfer // gdb mode void (*gdb_poll)(udc_t *udc); ///< poll intr in gdb mode } udcOps_t; enum udc_feature { #define UDC_FEATURE_ATTRIBUTE_MASK 0xff /// UC Attribute UDC_FEATURE_REMOTE_WAKEUP = UC_REMOTE_WAKEUP, UDC_FEATURE_SELF_POWERED = UC_SELF_POWERED, UDC_FEATURE_BUS_POWERED = UC_BUS_POWERED, /// Software defined UDC_FEATURE_WAKEUP_ON_WRITE = (1 << 8), }; #ifdef CONFIG_SOC_8850 typedef struct musbFifo { void *data; ///< FIFO buffer size_t size; ///< FIFO buffer size size_t rd; ///< FIFO read pointer size_t wr; ///< FIFO write pointer } musbFifo_t; typedef struct { uint32_t addr; uint16_t frag_len; uint16_t blk_len; uint32_t link_end : 1; uint32_t sp : 1; uint32_t ioc : 1; uint32_t : 5; uint32_t haddr : 4; uint32_t : 20; uint32_t : 32; // This word is needed } UdcLinkList_t; #endif struct udc_s { int speed; ///< controller speed, from controller int feature; ///< controller feature defined in udc_feature udcPlatOps_t plat_ops; ///< operates for specific platform udcOps_t ops; ///< controller operates unsigned long platform_priv; ///< platform private data unsigned long controller_priv; ///< controller private data usbEp_t *ep0; ///< ep0, from controller #ifdef CONFIG_SOC_8850 bool is_configured; void *rx_dma_buf; void *tx_dma_buf; UdcLinkList_t rx_linklist[15]; ///RX_dma linklist UdcLinkList_t tx_linklist[15]; ///TX_dma linklist musbFifo_t rx_fifo; musbFifo_t tx_fifo; unsigned int node_start; #endif }; typedef struct { int (*bind)(udevDrv_t *driver); void (*unbind)(udevDrv_t *driver); int (*setup)(udevDrv_t *driver, const usb_device_request_t *setup); void (*start)(udevDrv_t *driver); void (*stop)(udevDrv_t *driver); void (*connect)(udevDrv_t *driver); void (*disconnect)(udevDrv_t *driver); void (*resume)(udevDrv_t *driver); void (*suspend)(udevDrv_t *driver); } udevDrvOps_t; struct usb_dev_driver_s { udc_t *udc; udevDrvOps_t ops; }; #define USB_DUMMY_RX_BUF_SIZE (512) extern char gDummyUsbRxBuf[USB_DUMMY_RX_BUF_SIZE]; /** * @brief Create the usb device controller instance * * @param name the controller device name * @return * - NULL fail * - the usb device controller */ udc_t *udcCreate(uint32_t name); /** * @brief Destroy the udc * * @param udc the udc */ void udcDestroy(udc_t *udc); /** * @brief Bind the udc driver to the udc * * @param udc the udc * @param drv the udc driver */ void udcBindDriver(udc_t *udc, udevDrv_t *drv); /** * @brief Get the binding driver * * @param udc the udc * @return * - NULL No driver bind to this udc * - other the udc driver */ udevDrv_t *udcGetDriver(udc_t *udc); /** * @brief udc set event notifier * * @param udc the udc * @param n the notifier * @param param caller context */ void udcSetNotifier(udc_t *udc, udcNotifier_t n, void *param); /** * @brief udc connect * @param udc the udc */ void udcConnect(udc_t *udc); /** * @brief udc disconnect * @param udc the udc */ void udcDisconnect(udc_t *udc); /** * @brief udc suspend * @param udc the udc */ void udcSuspend(udc_t *udc); /** * @brief udc resume * @param udc the udc */ void udcResume(udc_t *udc); /** * @brief udc remote wakeup * @param udc the udc */ bool udcRemoteWakeup(udc_t *udc); /** * @brief usb suspend or other status * * @param udc the udc * @return * - NULL fail * - the usb device controller */ bool udcUsbIsSuspend(udc_t *udc); #define CHECK_UDC_PLAT_OPS(u, o) ((u) != NULL && (u)->plat_ops.o != NULL) #define CHECK_UDC_OPS(u, o) ((u) != NULL && (u)->ops.o != NULL) #define CHECK_DRV_OPS(d, o) ((d) != NULL && (d)->ops.o != NULL) /** * @brief The platform turn on/off usb power * * @param udc the udc * @param on on or off the power */ static inline void udcPlatSetPower(udc_t *udc, bool on) { if (CHECK_UDC_PLAT_OPS(udc, setpower)) return udc->plat_ops.setpower(udc, on); } /** * @brief The platform turn on/off clock * * @param udc the udc * @param on on or off the clock */ static inline void udcPlatSetClock(udc_t *udc, bool on) { if (CHECK_UDC_PLAT_OPS(udc, setclk)) return udc->plat_ops.setclk(udc, on); } /** * @brief The platform process on usb controller suspend * * @param udc the udc */ static inline void udcPlatSuspend(udc_t *udc) { if (CHECK_UDC_PLAT_OPS(udc, suspend)) udc->plat_ops.suspend(udc); } /** * @brief The platform process on usb controller resume * * @param udc the udc */ static inline void udcPlatResume(udc_t *udc) { if (CHECK_UDC_PLAT_OPS(udc, resume)) udc->plat_ops.resume(udc); } /** * @brief The platform enable usb module * * Init usb phy and others * @param udc the udc */ static inline void udcPlatEnable(udc_t *udc) { if (CHECK_UDC_PLAT_OPS(udc, enable)) return udc->plat_ops.enable(udc); } /** * @brief The platform disable usb module * * @param udc the udc */ static inline void udcPlatDisable(udc_t *udc) { if (CHECK_UDC_PLAT_OPS(udc, disable)) return udc->plat_ops.disable(udc); } /** * @brief Start udc, make the controller works * * @param udc the udc */ void udcStart(udc_t *udc); /** * @brief Stop udc, the controller will be closed * * @param udc the udc */ void udcStop(udc_t *udc); /** * @brief Enqueue an usb transfer * * Before call the method, caller should be sure ep is a valid * usb endpoint, and make sure full fill the usb transfer. * * @param udc the udc * @param ep the usb endpoint * @param xfer the usb transfer * @return * - 0 success * - (-1) fail */ static inline int udcEpQueue(udc_t *udc, usbEp_t *ep, usbXfer_t *xfer) { if (CHECK_UDC_OPS(udc, enqueue) && ep != NULL && xfer != NULL) return udc->ops.enqueue(udc, ep, xfer); return -1; } /** * @brief Dequeue an usb transfer * * @param udc the udc * @param ep the usb endpoint * @param xfer the usb transfer */ static inline void udcEpDequeue(udc_t *udc, usbEp_t *ep, usbXfer_t *xfer) { if (CHECK_UDC_OPS(udc, dequeue) && ep != NULL && xfer != NULL) udc->ops.dequeue(udc, ep, xfer); } /** * @brief Dequeue all transfers for an usb endpoint * * @param udc the udc * @param ep the usb endpoint */ static inline void udcEpDequeueAll(udc_t *udc, usbEp_t *ep) { if (CHECK_UDC_OPS(udc, dequeue_all) && ep != NULL) udc->ops.dequeue_all(udc, ep); } /** * @brief Allocate an usb endpoint * * @param udc the udc * @param desc the usb endpoint descriptor * @return * - NULL fail * - other usb endpoint */ static inline usbEp_t *udcEpAlloc(udc_t *udc, usb_endpoint_descriptor_t *desc) { if (CHECK_UDC_OPS(udc, ep_alloc) && desc != NULL) return udc->ops.ep_alloc(udc, desc); return NULL; } /** * @brief Free an usb endpoint * * @param udc the udc * @param ep the usb endpoint */ static inline void udcEpFree(udc_t *udc, usbEp_t *ep) { if (CHECK_UDC_OPS(udc, ep_free) && ep != NULL) return udc->ops.ep_free(udc, ep); } /** * @brief Allocate an usb xfer * * @param udc the udc * @return * - NULL fail * - other the xfer */ static inline usbXfer_t *udcXferAlloc(udc_t *udc) { if (CHECK_UDC_OPS(udc, xfer_alloc)) return udc->ops.xfer_alloc(udc); return NULL; } /** * @brief Free an usb xfer * * @param udc the udc * @param xfer the xfer */ static inline void udcXferFree(udc_t *udc, usbXfer_t *xfer) { if (CHECK_UDC_OPS(udc, xfer_free) && xfer) return udc->ops.xfer_free(udc, xfer); } /** * @brief Enable the endpoint * * @param udc the udc * @param ep the endpoint * @return * - (-1) fail * - other success */ static inline int udcEpEnable(udc_t *udc, usbEp_t *ep) { if (CHECK_UDC_OPS(udc, ep_enable) && ep != NULL) return udc->ops.ep_enable(udc, ep); return -1; } /** * @brief Disable the endpoint * * @param udc the udc * @param ep the endpoint */ static inline void udcEpDisable(udc_t *udc, usbEp_t *ep) { if (CHECK_UDC_OPS(udc, ep_disable) && ep != NULL) return udc->ops.ep_disable(udc, ep); } /** * @brief Stall an endpoint * * @param udc the udc * @param ep the usb endpoint * @param halt true: stall; false: clear stall */ static inline void udcEpStall(udc_t *udc, usbEp_t *ep, bool halt) { if (CHECK_UDC_OPS(udc, ep_stall) && ep != NULL) udc->ops.ep_stall(udc, ep, halt); } /** * @brief Poll usb interrupt in gdb mode * * @param udc the usb device controller */ static inline void udcGdbPollIntr(udc_t *udc) { if (CHECK_UDC_OPS(udc, gdb_poll)) udc->ops.gdb_poll(udc); } /** * @brief usb deivce driver process setup packet * * @param drv the driver * @param setup the setup packet * @return * - (-1) process failed * - 0 success */ static inline int udevDriverSetup(udevDrv_t *drv, const usb_device_request_t *setup) { if (CHECK_DRV_OPS(drv, setup)) return drv->ops.setup(drv, setup); return -1; } /** * @brief usb device driver bind the usb controller * * @param drv the driver * @return * - (-1) failed * - 0 success */ static inline int udevDriverBind(udevDrv_t *drv) { if (CHECK_DRV_OPS(drv, bind)) return drv->ops.bind(drv); return -1; } /** * @brief usb device driver unbind the controller * * @param drv the driver */ static inline void udevDriverUnbind(udevDrv_t *drv) { if (CHECK_DRV_OPS(drv, unbind)) drv->ops.unbind(drv); } /** * @brief usb device driver start. * * Prepare environment, etc. * * @param drv the driver */ static inline void udevDriverStart(udevDrv_t *drv) { if (CHECK_DRV_OPS(drv, start)) drv->ops.start(drv); } /** * @brief usb device driver stop. * * Release resource and etc. * * @param drv the driver */ static inline void udevDriverStop(udevDrv_t *drv) { if (CHECK_DRV_OPS(drv, stop)) drv->ops.stop(drv); } /** * @brief usb device connect to a host * * @param drv the driver */ static inline void udevDriverConnect(udevDrv_t *drv) { if (CHECK_DRV_OPS(drv, connect)) drv->ops.connect(drv); } /** * @brief usb device disconnect to a host * * @param drv the driver */ static inline void udevDriverDisconnect(udevDrv_t *drv) { if (CHECK_DRV_OPS(drv, disconnect)) drv->ops.disconnect(drv); } /** * @brief usb device suspend to a host * * @param drv the driver */ static inline void udevDriverSuspend(udevDrv_t *drv) { if (CHECK_DRV_OPS(drv, suspend)) drv->ops.suspend(drv); } /** * @brief usb device resume to a host * * @param drv the driver */ static inline void udevDriverResume(udevDrv_t *drv) { if (CHECK_DRV_OPS(drv, resume)) drv->ops.resume(drv); } #ifdef __cplusplus } #endif #endif