/**************************************************************************//** * * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-11-5 Wayne First version * ******************************************************************************/ #include #if defined(BSP_USING_USBH) #include #include #include "NuMicro.h" #include "usb.h" #include "usbh_lib.h" #define LOG_TAG "drv.usbhost" #define DBG_ENABLE #define DBG_SECTION_NAME LOG_TAG #define DBG_LEVEL LOG_LVL_DBG #define DBG_COLOR #include #if !defined(NU_USBHOST_HUB_POLLING_INTERVAL) #define NU_USBHOST_HUB_POLLING_INTERVAL (100) #endif #define NU_MAX_USBH_PORT (2+1) // 2* USB2.0 + 1*USB1.2 ports #define NU_MAX_USBH_PIPE 16 #define NU_USBH_THREAD_STACK_SIZE 2048 #define NU_MAX_USBH_HUB_PORT_DEV USB_HUB_PORT_NUM #define NU_USBHOST_HUB_POLLING_LOCK #if defined(NU_USBHOST_HUB_POLLING_LOCK) #define NU_USBHOST_MUTEX_INIT() { \ s_sUSBHDev.lock = rt_mutex_create("usbhost_lock", RT_IPC_FLAG_PRIO); \ RT_ASSERT(s_sUSBHDev.lock != RT_NULL); \ } #define NU_USBHOST_LOCK() { \ rt_err_t result = rt_mutex_take(s_sUSBHDev.lock, RT_WAITING_FOREVER); \ RT_ASSERT(result == RT_EOK); \ } #define NU_USBHOST_UNLOCK() { \ rt_err_t result = rt_mutex_release(s_sUSBHDev.lock); \ RT_ASSERT(result == RT_EOK); \ } #else #define NU_USBHOST_MUTEX_INIT() #define NU_USBHOST_LOCK() #define NU_USBHOST_UNLOCK() #endif /* Private typedef --------------------------------------------------------------*/ typedef struct nu_port_dev { rt_bool_t bRHParent; UDEV_T *pUDev; EP_INFO_T *apsEPInfo[NU_MAX_USBH_PIPE]; struct urequest asSetupReq[NU_MAX_USBH_PIPE]; uint32_t u32SentLength[NU_MAX_USBH_PIPE]; struct rt_completion utr_completion; int port_num; rt_bool_t bEnumDone; void *asPipePktBuf[NU_MAX_USBH_PIPE]; } S_NU_PORT_DEV; typedef struct nu_port_ctrl { S_NU_PORT_DEV sRHPortDev; S_NU_PORT_DEV asHubPortDev[NU_MAX_USBH_HUB_PORT_DEV]; } S_NU_RH_PORT_CTRL; struct nu_usbh_dev { struct uhcd uhcd; rt_thread_t polling_thread; rt_mutex_t lock; S_NU_RH_PORT_CTRL asPortCtrl[NU_MAX_USBH_PORT]; }; /* Private variables ------------------------------------------------------------*/ static struct nu_usbh_dev s_sUSBHDev; static S_NU_RH_PORT_CTRL * GetRHPortControlFromPipe( upipe_t pipe) { uinst_t inst; int port; if (!pipe || !pipe->inst || !pipe->inst->parent_hub) return RT_NULL; if (pipe->inst->parent_hub->is_roothub) { //case: device ---> root hub inst = pipe->inst; port = inst->port; } else { //case: device ---> hub ---> root hub inst = pipe->inst->parent_hub->self; port = inst->port; } if (port > NU_MAX_USBH_PORT) { RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: port index over NU_MAX_USBH_PORT\n")); return RT_NULL; } return &s_sUSBHDev.asPortCtrl[port - 1];; } static S_NU_PORT_DEV * GetPortDevFromPipe( upipe_t pipe) { S_NU_RH_PORT_CTRL *psRHPortCtrl = GetRHPortControlFromPipe(pipe); int i; if (psRHPortCtrl == RT_NULL) return RT_NULL; if (pipe->inst->parent_hub->is_roothub) { //case: device ---> root hub return &psRHPortCtrl->sRHPortDev; } //case: device ---> hub ---> root hub for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++) { if (psRHPortCtrl->asHubPortDev[i].port_num == pipe->inst->port) break; } if (i >= NU_MAX_USBH_HUB_PORT_DEV) return RT_NULL; return &psRHPortCtrl->asHubPortDev[i]; } static rt_err_t nu_reset_port(rt_uint8_t port) { S_NU_RH_PORT_CTRL *psPortCtrl; if (port > NU_MAX_USBH_PORT) { RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: port index over NU_MAX_USBH_PORT\n", __func__)); return -RT_EIO; } psPortCtrl = &s_sUSBHDev.asPortCtrl[port - 1]; if (psPortCtrl->sRHPortDev.pUDev == NULL) { RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__)); return -RT_EIO; } usbh_reset_port(psPortCtrl->sRHPortDev.pUDev); return RT_EOK; } static EP_INFO_T *GetFreePipe( S_NU_RH_PORT_CTRL *psPortCtrl, S_NU_PORT_DEV *psPortDev, rt_uint8_t *pu8PipeIndex) { if (psPortCtrl != NULL) { int i; /* Find free Pipe */ for (i = 0; i < NU_MAX_USBH_PIPE; i ++) { if (psPortDev->apsEPInfo[i] == NULL) break; } if (i < NU_MAX_USBH_PIPE) { EP_INFO_T *psEPInfo = rt_malloc(sizeof(EP_INFO_T)); if (psEPInfo != RT_NULL) { psPortDev->apsEPInfo[i] = psEPInfo; *pu8PipeIndex = i; return psEPInfo; } } } return RT_NULL; } static void FreePipe( S_NU_RH_PORT_CTRL *psPortCtrl, S_NU_PORT_DEV *psPortDev, rt_uint8_t u8PipeIndex) { if ((psPortCtrl != RT_NULL) && (u8PipeIndex < NU_MAX_USBH_PIPE) && (psPortDev->apsEPInfo[u8PipeIndex] != RT_NULL)) { rt_free(psPortDev->apsEPInfo[u8PipeIndex]); psPortDev->apsEPInfo[u8PipeIndex] = RT_NULL; } } static S_NU_PORT_DEV * AllocateNewUDev( S_NU_RH_PORT_CTRL *psRHPortCtrl) { if (psRHPortCtrl != RT_NULL) { int i; /* Find free Dev */ for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++) { if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL) break; } if (i < NU_MAX_USBH_HUB_PORT_DEV) { psRHPortCtrl->asHubPortDev[i].pUDev = alloc_device(); if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL) { return RT_NULL; } else { return &psRHPortCtrl->asHubPortDev[i]; } } } return RT_NULL; } static rt_err_t nu_open_pipe(upipe_t pipe) { S_NU_RH_PORT_CTRL *psPortCtrl; S_NU_PORT_DEV *psPortDev; psPortCtrl = GetRHPortControlFromPipe(pipe); if (psPortCtrl == RT_NULL) { RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: RHPort not found\n", __func__)); goto exit_nu_open_pipe; } if (psPortCtrl->sRHPortDev.pUDev == NULL) { RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__)); goto exit_nu_open_pipe; } psPortDev = GetPortDevFromPipe(pipe); if ((psPortDev == NULL) || (psPortDev->pUDev == NULL)) { //allocate new dev for hub device psPortDev = AllocateNewUDev(psPortCtrl); if (psPortDev == RT_NULL) { RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: udev allocate failed\n")); goto exit_nu_open_pipe; } if (pipe->inst->speed) { psPortDev->pUDev->speed = SPEED_FULL; } else { psPortDev->pUDev->speed = SPEED_HIGH; } psPortDev->pUDev->parent = NULL; psPortDev->pUDev->hc_driver = psPortCtrl->sRHPortDev.pUDev->hc_driver; psPortDev->port_num = pipe->inst->port; psPortDev->pUDev->port_num = pipe->inst->port; psPortDev->bEnumDone = FALSE; } //For ep0 control transfer if ((pipe->ep.bEndpointAddress & 0x7F) == 0) { pipe->pipe_index = 0; } else { int pksz; EP_INFO_T *psEPInfo = GetFreePipe(psPortCtrl, psPortDev, &pipe->pipe_index); if (psEPInfo == RT_NULL) { RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: get free pipe failed\n", __func__)); goto exit_nu_open_pipe; } psEPInfo->bEndpointAddress = pipe->ep.bEndpointAddress; psEPInfo->bmAttributes = pipe->ep.bmAttributes; pksz = pipe->ep.wMaxPacketSize; pksz = (pksz & 0x07ff) * (1 + ((pksz >> 11) & 3)); psEPInfo->wMaxPacketSize = pksz; psEPInfo->bInterval = pipe->ep.bInterval; psEPInfo->hw_pipe = NULL; psEPInfo->bToggle = 0; } if (!psPortDev->asPipePktBuf[pipe->pipe_index]) { psPortDev->asPipePktBuf[pipe->pipe_index] = rt_malloc_align(512ul, nu_cpu_dcache_line_size()); RT_ASSERT(psPortDev->asPipePktBuf[pipe->pipe_index] != RT_NULL); } return RT_EOK; exit_nu_open_pipe: return -RT_ERROR; } static rt_err_t nu_close_pipe(upipe_t pipe) { S_NU_RH_PORT_CTRL *psPortCtrl; S_NU_PORT_DEV *psPortDev; psPortCtrl = GetRHPortControlFromPipe(pipe); if (psPortCtrl == RT_NULL) { return -RT_EIO; } psPortDev = GetPortDevFromPipe(pipe); //For ep0 control transfer if ((pipe->ep.bEndpointAddress & 0x7F) == 0) { if ((psPortDev) && (psPortDev->bRHParent == FALSE) && (psPortDev->bEnumDone == TRUE)) { if (psPortDev->pUDev) { int i; for (i = 0; i < NU_MAX_USBH_PIPE; i++) { if (psPortDev->apsEPInfo[i] != NULL) { usbh_quit_xfer(psPortDev->pUDev, psPortDev->apsEPInfo[i]); } } free_device(psPortDev->pUDev); psPortDev->pUDev = NULL; } } } if (psPortDev != NULL) { if (psPortDev->asPipePktBuf[pipe->pipe_index]) { rt_free_align(psPortDev->asPipePktBuf[pipe->pipe_index]); psPortDev->asPipePktBuf[pipe->pipe_index] = RT_NULL; } FreePipe(psPortCtrl, psPortDev, pipe->pipe_index); } return RT_EOK; } static int nu_ctrl_xfer( S_NU_PORT_DEV *psPortDev, struct urequest *psSetup, void *buffer, int timeouts) { uint32_t xfer_len = 0; int ret; ret = usbh_ctrl_xfer(psPortDev->pUDev, psSetup->request_type, psSetup->bRequest, psSetup->wValue, psSetup->wIndex, psSetup->wLength, buffer, &xfer_len, timeouts * 10); if (ret < 0) { RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer failed %d\n", ret)); return ret; } if (xfer_len != psSetup->wLength) { RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer length %d %d\n", psSetup->wLength, xfer_len)); } if ((psSetup->bRequest == USB_REQ_SET_ADDRESS) && ((psSetup->request_type & 0x60) == REQ_TYPE_STD_DEV)) psPortDev->pUDev->dev_num = psSetup->wValue; if ((psSetup->bRequest == USB_REQ_SET_CONFIGURATION) && ((psSetup->request_type & 0x60) == REQ_TYPE_STD_DEV)) { psPortDev->pUDev->cur_conf = psSetup->wValue; psPortDev->bEnumDone = TRUE; } return xfer_len; } static int nu_bulk_xfer( S_NU_PORT_DEV *psPortDev, UTR_T *psUTR, int timeouts) { int ret = usbh_bulk_xfer(psUTR); if (ret < 0) return ret; //wait transfer done if (rt_completion_wait(&(psPortDev->utr_completion), timeouts) < 0) { rt_kprintf("Request Timeout in %d ms!! (bulk_xfer)\n", timeouts); rt_kprintf("psUTR->buff: %08x\n", psUTR->buff); rt_kprintf("psUTR->data_len: %d\n", psUTR->data_len); rt_kprintf("psUTR->xfer_len: %d\n", psUTR->xfer_len); rt_kprintf("psUTR->ep: %08x\n", psUTR->ep); rt_kprintf("psUTR->bIsTransferDone: %08x\n", psUTR->bIsTransferDone); rt_kprintf("psUTR->status: %08x\n", psUTR->status); rt_kprintf("psUTR->td_cnt: %08x\n", psUTR->td_cnt); return -1; } return 0; } static int nu_int_xfer( upipe_t pipe, S_NU_PORT_DEV *psPortDev, UTR_T *psUTR, int timeouts) { int ret; while (1) { ret = usbh_int_xfer(psUTR); if (ret < 0) return ret; if (rt_completion_wait(&(psPortDev->utr_completion), timeouts) != 0) { RT_DEBUG_LOG(RT_DEBUG_USB, ("Request %08x Timeout in %d ms!!\n", psUTR, timeouts)); usbh_quit_utr(psUTR); rt_completion_init(&(psPortDev->utr_completion)); rt_thread_mdelay(1); } else { RT_DEBUG_LOG(RT_DEBUG_USB, ("Transferring done %08x\n", psUTR)); usbh_quit_utr(psUTR); break; } } return 0; } static void xfer_done_cb(UTR_T *psUTR) { S_NU_PORT_DEV *psPortDev = (S_NU_PORT_DEV *)psUTR->context; //transfer done, signal utr_completion rt_completion_done(&(psPortDev->utr_completion)); } static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts) { S_NU_RH_PORT_CTRL *psPortCtrl; S_NU_PORT_DEV *psPortDev; UTR_T *psUTR = NULL; int i32XferLen = -1; void *buffer_nonch = buffer; NU_USBHOST_LOCK(); psPortCtrl = GetRHPortControlFromPipe(pipe); if (psPortCtrl == RT_NULL) { goto exit_nu_pipe_xfer; } psPortDev = GetPortDevFromPipe(pipe); if (psPortDev->pUDev == NULL) { RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: udev not found\n")); goto exit_nu_pipe_xfer; } if (buffer_nonch && nbytes) { buffer_nonch = psPortDev->asPipePktBuf[pipe->pipe_index]; if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_OUT) { rt_memcpy(buffer_nonch, buffer, nbytes); rt_hw_cpu_dcache_clean_and_invalidate((void *)buffer_nonch, nbytes); } } //ctrl xfer if (pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL) { int ret; if (token == USBH_PID_SETUP) { struct urequest *psSetup = (struct urequest *)buffer_nonch; RT_ASSERT(buffer_nonch != RT_NULL); psPortCtrl->asHubPortDev->u32SentLength[pipe->pipe_index] = 0; /* Read data from USB device. */ if (psSetup->request_type & USB_REQ_TYPE_DIR_IN) { //Store setup request rt_memcpy(&psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], psSetup, sizeof(struct urequest)); } else { /* Write data to USB device. */ //Trigger USBHostLib Ctrl_Xfer ret = nu_ctrl_xfer(psPortDev, psSetup, NULL, timeouts); if (ret != psSetup->wLength) goto exit_nu_pipe_xfer; } } else { //token == USBH_PID_DATA if (buffer_nonch && ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)) { struct urequest *psSetup = &psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index]; /* Read data from USB device. */ //Trigger USBHostLib Ctril_Xfer /* * Workaround: HCD driver can readback all bytes of setup.wLength, but not support single packet transferring. */ if (psPortCtrl->asHubPortDev->u32SentLength[pipe->pipe_index] == 0) { ret = nu_ctrl_xfer(psPortDev, psSetup, buffer_nonch, timeouts); psPortCtrl->asHubPortDev->u32SentLength[pipe->pipe_index] = ret; if (ret > 0) { rt_hw_cpu_dcache_invalidate((void *)buffer_nonch, ret); rt_memcpy(buffer, buffer_nonch, ret); } } else { if (psPortCtrl->asHubPortDev->u32SentLength[pipe->pipe_index] < nbytes) { ret = 0; } else { psPortCtrl->asHubPortDev->u32SentLength[pipe->pipe_index] -= nbytes; ret = nbytes; } } if (ret <= 0) goto exit_nu_pipe_xfer; } else { RT_DEBUG_LOG(RT_DEBUG_USB, ("%d == USBH_PID_DATA, nil buf-%d \n", token, nbytes)); } } //else i32XferLen = nbytes; goto exit_nu_pipe_xfer2; } // if ( pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL ) else { psUTR = alloc_utr(psPortDev->pUDev); if (!psUTR) { RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: unable alloc UTR\n")); goto exit_nu_pipe_xfer; } psUTR->ep = psPortDev->apsEPInfo[pipe->pipe_index]; psUTR->buff = buffer_nonch; psUTR->data_len = nbytes; psUTR->xfer_len = 0; psUTR->func = xfer_done_cb; psUTR->context = psPortDev; psUTR->bIsTransferDone = 0; psUTR->status = 0; //others xfer rt_completion_init(&(psPortDev->utr_completion)); if (pipe->ep.bmAttributes == USB_EP_ATTR_BULK) { if (nu_bulk_xfer(psPortDev, psUTR, timeouts) < 0) { RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: bulk transfer failed\n")); goto failreport_nu_pipe_xfer; } } else if (pipe->ep.bmAttributes == USB_EP_ATTR_INT) { if (nu_int_xfer(pipe, psPortDev, psUTR, timeouts) < 0) { RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: int transfer failed\n")); //goto exit_nu_pipe_xfer; } else { i32XferLen = nbytes; } goto exit_nu_pipe_xfer; } else if (pipe->ep.bmAttributes == USB_EP_ATTR_ISOC) { //TODO: ISO transfer RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: isoc transfer not support\n")); goto exit_nu_pipe_xfer; } } //else failreport_nu_pipe_xfer: if (psUTR->bIsTransferDone == 0) { //Timeout RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: timeout\n")); pipe->status = UPIPE_STATUS_ERROR; usbh_quit_utr(psUTR); } else { // Transfer Done. Get status if (psUTR->status == 0) { pipe->status = UPIPE_STATUS_OK; } else if (psUTR->status == USBH_ERR_STALL) { pipe->status = UPIPE_STATUS_STALL; } else { pipe->status = UPIPE_STATUS_ERROR; } } i32XferLen = psUTR->xfer_len; exit_nu_pipe_xfer: //Call callback if (pipe->callback != RT_NULL) { pipe->callback(pipe); } if (psUTR) free_utr(psUTR); if ((nbytes) && (buffer_nonch != buffer)) { if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) { rt_hw_cpu_dcache_invalidate((void *)buffer_nonch, nbytes); rt_memcpy(buffer, buffer_nonch, nbytes); } } exit_nu_pipe_xfer2: NU_USBHOST_UNLOCK(); return i32XferLen; } /* Polling USB root hub status task */ static void nu_usbh_rh_thread_entry(void *parameter) { while (1) { NU_USBHOST_LOCK(); usbh_polling_root_hubs(); NU_USBHOST_UNLOCK(); rt_thread_mdelay(NU_USBHOST_HUB_POLLING_INTERVAL); } } static void nu_hcd_connect_callback( struct udev_t *udev, int param) { int i; int port_index; S_NU_RH_PORT_CTRL *psPortCtrl; for (i = 0; i < NU_MAX_USBH_PORT; i++) { psPortCtrl = &s_sUSBHDev.asPortCtrl[i]; if (psPortCtrl->sRHPortDev.pUDev == NULL) break; } if (i >= NU_MAX_USBH_PORT) { RT_DEBUG_LOG(RT_DEBUG_USB, ("ERROR: port connect slot is full\n")); return; } port_index = i + 1; psPortCtrl->sRHPortDev.pUDev = udev; psPortCtrl->sRHPortDev.bRHParent = TRUE; RT_DEBUG_LOG(RT_DEBUG_USB, ("usb connected\n")); if (udev->speed == SPEED_HIGH) rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_TRUE); else rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_FALSE); } static void nu_hcd_disconnect_callback( struct udev_t *udev, int param) { int i; int port_index; S_NU_RH_PORT_CTRL *psPortCtrl; for (i = 0; i < NU_MAX_USBH_PORT; i++) { psPortCtrl = &s_sUSBHDev.asPortCtrl[i]; if (psPortCtrl->sRHPortDev.pUDev == udev) break; } if (i >= NU_MAX_USBH_PORT) { RT_DEBUG_LOG(RT_DEBUG_USB, ("ERROR: udev not found\n")); return; } port_index = i + 1; for (i = 0; i < NU_MAX_USBH_PIPE; i++) { if (psPortCtrl->sRHPortDev.apsEPInfo[i] != NULL) { usbh_quit_xfer(psPortCtrl->sRHPortDev.pUDev, psPortCtrl->sRHPortDev.apsEPInfo[i]); } } psPortCtrl->sRHPortDev.pUDev = NULL; RT_DEBUG_LOG(RT_DEBUG_USB, ("usb disconnect\n")); rt_usbh_root_hub_disconnect_handler(&s_sUSBHDev.uhcd, port_index); } /* USB host operations -----------------------------------------------------------*/ static struct uhcd_ops nu_uhcd_ops = { nu_reset_port, nu_pipe_xfer, nu_open_pipe, nu_close_pipe, }; static rt_err_t nu_hcd_init(rt_device_t device) { struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device; usbh_core_init(); //install connect/disconnect callback usbh_install_conn_callback(nu_hcd_connect_callback, nu_hcd_disconnect_callback); //create thread for polling usbh port status /* create usb hub thread */ pNuUSBHDev->polling_thread = rt_thread_create("usbh_drv", nu_usbh_rh_thread_entry, RT_NULL, NU_USBH_THREAD_STACK_SIZE, 8, 20); RT_ASSERT(pNuUSBHDev->polling_thread != RT_NULL); /* startup usb host thread */ rt_thread_startup(pNuUSBHDev->polling_thread); return RT_EOK; } /* global function for USB host library -----------------------------*/ uint32_t usbh_get_ticks(void) { return rt_tick_get(); } void usbh_delay_ms(int msec) { rt_thread_mdelay(msec); } uint32_t usbh_tick_from_millisecond(uint32_t msec) { return rt_tick_from_millisecond(msec); } #if defined(RT_USING_PM) /* device pm suspend() entry. */ static int usbhost_pm_suspend(const struct rt_device *device, rt_uint8_t mode) { rt_err_t result; struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device; RT_ASSERT(pNuUSBHDev != RT_NULL); switch (mode) { case PM_SLEEP_MODE_LIGHT: case PM_SLEEP_MODE_DEEP: pNuUSBHDev->polling_thread->stat = RT_THREAD_READY; result = rt_thread_suspend(pNuUSBHDev->polling_thread); RT_ASSERT(result == RT_EOK); break; default: break; } return (int)RT_EOK; } /* device pm resume() entry. */ static void usbhost_pm_resume(const struct rt_device *device, rt_uint8_t mode) { rt_err_t result; struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device; RT_ASSERT(pNuUSBHDev != RT_NULL); switch (mode) { case PM_SLEEP_MODE_LIGHT: case PM_SLEEP_MODE_DEEP: result = rt_thread_resume(pNuUSBHDev->polling_thread); RT_ASSERT(result == RT_EOK); break; default: break; } } static struct rt_device_pm_ops device_pm_ops = { .suspend = usbhost_pm_suspend, .resume = usbhost_pm_resume, .frequency_change = RT_NULL }; #endif int nu_usbh_register(void) { rt_err_t res; uhcd_t psUHCD; psUHCD = (uhcd_t)&s_sUSBHDev.uhcd; psUHCD->parent.type = RT_Device_Class_USBHost; psUHCD->parent.init = nu_hcd_init; psUHCD->parent.user_data = &s_sUSBHDev; psUHCD->ops = &nu_uhcd_ops; psUHCD->num_ports = NU_MAX_USBH_PORT; #if defined(BSP_USING_HSUSBH0) CLK_EnableModuleClock(HUSBH0_MODULE); SYS_ResetModule(HSUSBH0_RST); #endif #if defined(BSP_USING_HSUSBH1) CLK_EnableModuleClock(HUSBH1_MODULE); SYS_ResetModule(HSUSBH1_RST); #endif /* set UHOVRCURH(SYS_MISCFCR0[12]) 1 => USBH Host over-current detect is high-active */ /* 0 => USBH Host over-current detect is low-active */ //SYS->MISCFCR0 |= SYS_MISCFCR0_UHOVRCURH_Msk; SYS->MISCFCR0 &= ~SYS_MISCFCR0_UHOVRCURH_Msk; #if defined(BSP_USING_HSUSBH0) /* Clock engine clock Configuration */ SYS->USBPMISCR &= ~(SYS_USBPMISCR_PHY0POR_Msk | SYS_USBPMISCR_PHY0COMN_Msk); SYS->USBPMISCR |= SYS_USBPMISCR_PHY0SUSPEND_Msk; #endif #if defined(BSP_USING_HSUSBH1) /* Clock engine clock Configuration */ SYS->USBPMISCR &= ~(SYS_USBPMISCR_PHY1POR_Msk | SYS_USBPMISCR_PHY1COMN_Msk); SYS->USBPMISCR |= SYS_USBPMISCR_PHY1SUSPEND_Msk; #endif NU_USBHOST_MUTEX_INIT(); res = rt_device_register(&psUHCD->parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE); RT_ASSERT(res == RT_EOK); /*initialize the usb host function */ res = rt_usb_host_init("usbh"); RT_ASSERT(res == RT_EOK); #if defined(RT_USING_PM) rt_pm_device_register(&psUHCD->parent, &device_pm_ops); #endif return 0; } INIT_APP_EXPORT(nu_usbh_register); #endif