diff options
| author | sakimisu <[email protected]> | 2023-02-05 17:22:07 +0800 |
|---|---|---|
| committer | sakimisu <[email protected]> | 2023-02-06 21:08:58 +0800 |
| commit | f99e03c850e658e89678f3728b06614853317cf8 (patch) | |
| tree | 15bd84980ac20454b592c19a0f86bb14964fe489 | |
| parent | 8abe7bcc2a2c8b5e15ba65c1dd33c82e22bd7c3c (diff) | |
update hc template
| -rw-r--r-- | port/template/usb_hc.c | 457 |
1 files changed, 235 insertions, 222 deletions
diff --git a/port/template/usb_hc.c b/port/template/usb_hc.c index c330a1e5..75980630 100644 --- a/port/template/usb_hc.c +++ b/port/template/usb_hc.c @@ -1,328 +1,341 @@ +/* + * Copyright (c) 2022, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "usbh_core.h" +#include "usbh_hub.h" +#include "usb_xxx_reg.h" #ifndef USBH_IRQHandler -#define USBH_IRQHandler USBH_IRQHandler +#define USBH_IRQHandler OTG_HS_IRQHandler #endif -struct xxx_pipe { - volatile int result; /* The result of the transfer */ - volatile uint32_t xfrd; /* Bytes transferred (at end of transfer) */ - volatile bool waiter; /* True: Thread is waiting for a channel event */ - usb_osal_sem_t waitsem; /* Channel wait semaphore */ - usb_osal_mutex_t exclsem; /* Support mutually exclusive access */ -#ifdef CONFIG_USBHOST_ASYNCH - usbh_asynch_callback_t callback; /* Transfer complete callback */ - void *arg; /* Argument that accompanies the callback */ +#ifndef USB_BASE +#define USB_BASE (0x40040000UL) #endif + +struct dwc2_pipe { + uint8_t dev_addr; + uint8_t ep_addr; + uint8_t ep_type; + uint8_t ep_interval; + uint8_t speed; + uint16_t ep_mps; + bool inuse; + uint32_t xfrd; + volatile bool waiter; + usb_osal_sem_t waitsem; + struct usbh_hubport *hport; + struct usbh_urb *urb; }; -struct xxx_hcd { - struct xxx_pipe chan[5]; -} g_xxx_hcd; +struct dwc2_hcd { + struct dwc2_pipe pipe_pool[CONFIG_USBHOST_PIPE_NUM]; +} g_dwc2_hcd; -static int xxx_pipe_alloc(void) +static int dwc2_pipe_alloc(void) { int chidx; - for (chidx = 0; chidx < HCD_MAX_ENDPOINT; chidx++) { - if (!g_xxx_hcd.chan[chidx].inuse) { - g_xxx_hcd.chan[chidx].inuse = true; + for (chidx = 0; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) { + if (!g_dwc2_hcd.pipe_pool[chidx].inuse) { + g_dwc2_hcd.pipe_pool[chidx].inuse = true; return chidx; } } - return -EBUSY; + return -1; } -static void xxx_pipe_free(struct xxx_pipe *chan) +static void dwc2_pipe_free(struct dwc2_pipe *pipe) { - chan->inuse = false; + pipe->inuse = false; } -static int xxx_pipe_waitsetup(struct xxx_pipe *chan) +static int usbh_reset_port(const uint8_t port) { - size_t flags; - int ret = -ENODEV; - - flags = usb_osal_enter_critical_section(); - - if (usbh_get_port_connect_status(1)) { - - chan->waiter = true; - chan->result = -EBUSY; - chan->xfrd = 0; -#ifdef CONFIG_USBHOST_ASYNCH - chan->callback = NULL; - chan->arg = NULL; -#endif - ret = 0; - } - usb_osal_leave_critical_section(flags); - return ret; + return 0; } -#ifdef CONFIG_USBHOST_ASYNCH -static int xxx_pipe_asynchsetup(struct xxx_pipe *chan, usbh_asynch_callback_t callback, void *arg) +static uint8_t usbh_get_port_speed(const uint8_t port) { - size_t flags; - int ret = -ENODEV; - - flags = usb_osal_enter_critical_section(); - - if (usbh_get_port_connect_status(1)) { - - chan->waiter = false; - chan->result = -EBUSY; - chan->xfrd = 0; - chan->callback = callback; - chan->arg = arg; - - ret = 0; - } - - usb_osal_leave_critical_section(flags); - return ret; + return USB_SPEED_UNKNOWN; } -#endif -static int xxx_pipe_wait(struct xxx_pipe *chan, uint32_t timeout) +__WEAK void usb_hc_low_level_init(void) { - int ret; - - if (chan->waiter) { - ret = usb_osal_sem_take(chan->waitsem, timeout); - if (ret < 0) { - return ret; - } - } - - ret = chan->result; - - if (ret < 0) { - return ret; - } - return chan->xfrd; } -static void xxx_pipe_wakeup(struct xxx_pipe *chan) +int usb_hc_init(void) { - usbh_asynch_callback_t callback; - void *arg; - int nbytes; + int ret; - if (chan->waiter) { - chan->waiter = false; - usb_osal_sem_give(chan->waitsem); - } -#ifdef CONFIG_USBHOST_ASYNCH - else if (chan->callback) { - callback = chan->callback; - arg = chan->arg; - nbytes = chan->xfrd; - chan->callback = NULL; - chan->arg = NULL; - if (chan->result < 0) { - nbytes = chan->result; - } + memset(&g_dwc2_hcd, 0, sizeof(struct dwc2_hcd)); - callback(arg, nbytes); + for (uint8_t chidx = 0; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) { + g_dwc2_hcd.pipe_pool[chidx].waitsem = usb_osal_sem_create(0); } -#endif -} - -__WEAK void usb_hc_low_level_init(void) -{ -} - -int usb_hc_sw_init(void) -{ - memset(&g_xxx_hcd, 0, sizeof(struct xxx_hcd)); - return 0; -} - -int usb_hc_hw_init(void) -{ usb_hc_low_level_init(); return 0; } -int usbh_reset_port(const uint8_t port) +uint16_t usbh_get_frame_number(void) { return 0; } -bool usbh_get_port_connect_status(const uint8_t port) +int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf) { - return false; -} + uint8_t nports; + uint8_t port; + uint32_t status; -uint8_t usbh_get_port_speed(const uint8_t port) -{ - return USB_SPEED_FULL; + nports = CONFIG_USBHOST_MAX_RHPORTS; + port = setup->wIndex; + if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) { + switch (setup->bRequest) { + case HUB_REQUEST_CLEAR_FEATURE: + switch (setup->wValue) { + case HUB_FEATURE_HUB_C_LOCALPOWER: + break; + case HUB_FEATURE_HUB_C_OVERCURRENT: + break; + default: + return -EPIPE; + } + break; + case HUB_REQUEST_SET_FEATURE: + switch (setup->wValue) { + case HUB_FEATURE_HUB_C_LOCALPOWER: + break; + case HUB_FEATURE_HUB_C_OVERCURRENT: + break; + default: + return -EPIPE; + } + break; + case HUB_REQUEST_GET_DESCRIPTOR: + break; + case HUB_REQUEST_GET_STATUS: + memset(buf, 0, 4); + break; + default: + break; + } + } else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) { + switch (setup->bRequest) { + case HUB_REQUEST_CLEAR_FEATURE: + if (!port || port > nports) { + return -EPIPE; + } + + switch (setup->wValue) { + case HUB_PORT_FEATURE_ENABLE: + break; + case HUB_PORT_FEATURE_SUSPEND: + break; + case HUB_PORT_FEATURE_C_SUSPEND: + break; + case HUB_PORT_FEATURE_POWER: + break; + case HUB_PORT_FEATURE_C_CONNECTION: + break; + case HUB_PORT_FEATURE_C_ENABLE: + break; + case HUB_PORT_FEATURE_C_OVER_CURREN: + break; + case HUB_PORT_FEATURE_C_RESET: + break; + default: + return -EPIPE; + } + break; + case HUB_REQUEST_SET_FEATURE: + if (!port || port > nports) { + return -EPIPE; + } + + switch (setup->wValue) { + case HUB_PORT_FEATURE_SUSPEND: + break; + case HUB_PORT_FEATURE_POWER: + break; + case HUB_PORT_FEATURE_RESET: + usbh_reset_port(port); + break; + + default: + return -EPIPE; + } + break; + case HUB_REQUEST_GET_STATUS: + if (!port || port > nports) { + return -EPIPE; + } + + memcpy(buf, &status, 4); + break; + default: + break; + } + } + return 0; } -int usbh_ep0_reconfigure(usbh_epinfo_t ep, uint8_t dev_addr, uint8_t ep_mps, uint8_t speed) +int usbh_ep0_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t ep_mps, uint8_t speed) { - struct xxx_pipe *chan; - int ret; + struct dwc2_pipe *chan; - chan = (struct xxx_pipe *)ep; + chan = (struct dwc2_pipe *)pipe; - ret = usb_osal_mutex_take(chan->exclsem); - if (ret < 0) { - return ret; - } + chan->dev_addr = dev_addr; + chan->ep_mps = ep_mps; + chan->speed = speed; - usb_osal_mutex_give(chan->exclsem); - return ret; + return 0; } -int usbh_ep_alloc(usbh_epinfo_t *ep, const struct usbh_endpoint_cfg *ep_cfg) +int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg) { - struct xxx_pipe *chan; - struct usbh_hubport *hport; + struct dwc2_pipe *chan; int chidx; - uint8_t speed; usb_osal_sem_t waitsem; - usb_osal_mutex_t exclsem; - chidx = xxx_pipe_alloc(); - chan = &g_xxx_hcd.chan[chidx]; + chidx = dwc2_pipe_alloc(); + if (chidx == -1) { + return -ENOMEM; + } + + chan = &g_dwc2_hcd.pipe_pool[chidx]; + /* store variables */ waitsem = chan->waitsem; - exclsem = chan->exclsem; - memset(chan, 0, sizeof(struct xxx_pipe)); + memset(chan, 0, sizeof(struct dwc2_pipe)); + + chan->ep_addr = ep_cfg->ep_addr; + chan->ep_type = ep_cfg->ep_type; + chan->ep_mps = ep_cfg->ep_mps; + chan->ep_interval = ep_cfg->ep_interval; + chan->speed = ep_cfg->hport->speed; + chan->dev_addr = ep_cfg->hport->dev_addr; + chan->hport = ep_cfg->hport; - /* restore variable */ + /* restore variables */ + chan->inuse = true; chan->waitsem = waitsem; - chan->exclsem = exclsem; - *ep = (usbh_epinfo_t)chan; + *pipe = (usbh_pipe_t)chan; + return 0; } -int usbh_ep_free(usbh_epinfo_t ep) +int usbh_pipe_free(usbh_pipe_t pipe) { - struct xxx_pipe *chan; - int ret; - - chan = (struct xxx_pipe *)ep; - - ret = usb_osal_mutex_take(chan->exclsem); - if (ret < 0) { - return ret; - } - - usb_osal_mutex_give(chan->exclsem); return 0; } -int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint8_t *buffer) +int usbh_submit_urb(struct usbh_urb *urb) { - struct xxx_pipe *chan; - int ret; + struct dwc2_pipe *chan; + size_t flags; + int ret = 0; + + if (!urb) { + return -EINVAL; + } - chan = (struct xxx_pipe *)ep; + chan = urb->pipe; - ret = usb_osal_mutex_take(chan->exclsem); - if (ret < 0) { - return ret; + if (!chan) { + return -EINVAL; } - ret = xxx_pipe_waitsetup(chan); - if (ret < 0) { - goto error_out; + if (!chan->hport->connected) { + return -ENODEV; } - usb_osal_mutex_give(chan->exclsem); - return ret; -error_out: - chan->waiter = false; - usb_osal_mutex_give(chan->exclsem); - return ret; -} + if (chan->urb) { + return -EBUSY; + } -int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, uint32_t timeout) -{ - struct xxx_pipe *chan; - int ret; + flags = usb_osal_enter_critical_section(); - chan = (struct xxx_pipe *)ep; + chan->waiter = false; + chan->xfrd = 0; + chan->urb = urb; + urb->errorcode = -EBUSY; + urb->actual_length = 0; - ret = usb_osal_mutex_take(chan->exclsem); - if (ret < 0) { - return ret; + if (urb->timeout > 0) { + chan->waiter = true; } + usb_osal_leave_critical_section(flags); - ret = xxx_pipe_waitsetup(chan); - if (ret < 0) { - goto error_out; + switch (chan->ep_type) { + case USB_ENDPOINT_TYPE_CONTROL: + break; + case USB_ENDPOINT_TYPE_BULK: + break; + case USB_ENDPOINT_TYPE_INTERRUPT: + break; + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + break; + default: + break; } + if (urb->timeout > 0) { + /* wait until timeout or sem give */ + ret = usb_osal_sem_take(chan->waitsem, urb->timeout); + if (ret < 0) { + goto errout_timeout; + } - usb_osal_mutex_give(chan->exclsem); + ret = urb->errorcode; + } return ret; -error_out: +errout_timeout: chan->waiter = false; - usb_osal_mutex_give(chan->exclsem); + usbh_kill_urb(urb); return ret; } -int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, uint32_t timeout) +int usbh_kill_urb(struct usbh_urb *urb) { - struct xxx_pipe *chan; - int ret; + struct dwc2_pipe *pipe; + size_t flags; - chan = (struct xxx_pipe *)ep; + pipe = urb->pipe; - ret = usb_osal_mutex_take(chan->exclsem); - if (ret < 0) { - return ret; + if (!urb || !pipe) { + return -EINVAL; } - usb_osal_mutex_give(chan->exclsem); - return ret; + return 0; } -int usbh_ep_bulk_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, usbh_asynch_callback_t callback, void *arg) +static inline void dwc2_pipe_waitup(struct dwc2_pipe *pipe) { - struct xxx_pipe *chan; - int ret; + struct usbh_urb *urb; - chan = (struct xxx_pipe *)ep; + urb = pipe->urb; + pipe->urb = NULL; - ret = usb_osal_mutex_take(chan->exclsem); - if (ret < 0) { - return ret; + if (pipe->waiter) { + pipe->waiter = false; + usb_osal_sem_give(pipe->waitsem); } - usb_osal_mutex_give(chan->exclsem); - - return ret; -} - -int usbh_ep_intr_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, usbh_asynch_callback_t callback, void *arg) -{ - struct xxx_pipe *chan; - int ret; - - chan = (struct xxx_pipe *)ep; - - ret = usb_osal_mutex_take(chan->exclsem); - if (ret < 0) { - return ret; + if (urb->complete) { + if (urb->errorcode < 0) { + urb->complete(urb->arg, urb->errorcode); + } else { + urb->complete(urb->arg, urb->actual_length); + } } - - usb_osal_mutex_give(chan->exclsem); - - return ret; -} - -int usb_ep_cancel(usbh_epinfo_t ep) -{ - return 0; } void USBH_IRQHandler(void) |
