From aeffaea016f74cb5d6301b5ca5088c03e3dbe3a6 Mon Sep 17 00:00:00 2001 From: zhugengyu Date: Wed, 15 Nov 2023 15:18:51 +0800 Subject: [PATCH] add pusb2 port, fix issue for rt-thread, add msc storage demo for rt-thread --- README.md | 3 +- README_zh.md | 3 +- SConscript | 21 ++ demo/msc_storage_template.c | 167 +++++++++ port/pusb2/README.md | 7 + port/pusb2/usb_dc_pusb2.c | 474 +++++++++++++++++++++++++ port/pusb2/usb_hc_pusb2.c | 684 ++++++++++++++++++++++++++++++++++++ port/xhci/usb_hc_xhci.c | 4 +- port/xhci/xhci.c | 45 ++- 9 files changed, 1398 insertions(+), 10 deletions(-) create mode 100644 demo/msc_storage_template.c create mode 100644 port/pusb2/README.md create mode 100644 port/pusb2/usb_dc_pusb2.c create mode 100644 port/pusb2/usb_hc_pusb2.c diff --git a/README.md b/README.md index 05265d2c..2ccc0828 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,8 @@ USB basic concepts and how the CherryUSB Device stack is implemented, see [Cherr |HPMicro | HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/cherryusb_hpmicro)| v0.10.1 | |Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|≤ v0.10.1 | |AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|≤ v0.10.1 | -|Phytium | e2000 | xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.9.0 | +|Phytium | e2000 | xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.1 | +|Phytium | PhytiumPI | pusb2 |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.1 | |Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|≤ v0.10.1 | |WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|≤ v0.10.1 | |Nordicsemi | Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|≤ v0.10.1 | diff --git a/README_zh.md b/README_zh.md index 5fad1242..fc43cf61 100644 --- a/README_zh.md +++ b/README_zh.md @@ -168,7 +168,8 @@ USB 基本知识点与 CherryUSB Device 协议栈是如何编写的,参考 [Ch |HPMicro | HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/cherryusb_hpmicro)| v0.10.1 | |Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|≤ v0.10.1 | |AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|≤ v0.10.1 | -|Phytium | e2000 | xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.9.0 | +|Phytium | e2000 | xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.1 | +|Phytium | e2000 | pusb2 |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.1 | |Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|≤ v0.10.1 | |WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|≤ v0.10.1 | |Nordicsemi | Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|≤ v0.10.1 | diff --git a/SConscript b/SConscript index d9594298..fe7ac025 100644 --- a/SConscript +++ b/SConscript @@ -16,7 +16,9 @@ CPPDEFINES = [] # USB DEVICE if GetDepend(['PKG_CHERRYUSB_DEVICE']): + path += [cwd + '/osal'] src += Glob('core/usbd_core.c') + src += Glob('osal/usb_osal_rtthread.c') if GetDepend(['PKG_CHERRYUSB_DEVICE_HS']): CPPDEFINES+=['CONFIG_USB_HS'] @@ -44,6 +46,8 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']): src += Glob('demo/hid_keyboard_template.c') if GetDepend(['PKG_CHERRYUSB_DEVICE_MSC_TEMPLATE']): src += Glob('demo/msc_ram_template.c') + if GetDepend(['PKG_CHERRYUSB_DEVICE_MSC_STORAGE_TEMPLATE']): + src += Glob('demo/msc_storage_template.c') if GetDepend(['PKG_CHERRYUSB_DEVICE_AUDIO_V1_TEMPLATE']): src += Glob('demo/audio_v1_mic_speaker_multichan_template.c') if GetDepend(['PKG_CHERRYUSB_DEVICE_AUDIO_V2_TEMPLATE']): @@ -81,6 +85,12 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']): else: src += Glob('port/ch32/usb_dc_usbfs.c') + if GetDepend(['PKG_CHERRYUSB_DEVICE_PUSB2']): + path += [cwd + '/port/pusb2/common'] + path += [cwd + '/port/pusb2/fpusb2'] + src += Glob('port/pusb2/fpusb2' + '/*.c') + src += Glob('port/pusb2/usb_dc_pusb2.c') + # USB HOST if GetDepend(['PKG_CHERRYUSB_HOST']): path += [cwd + '/osal'] @@ -112,6 +122,17 @@ if GetDepend(['PKG_CHERRYUSB_HOST']): if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_HPM']): src += Glob('port/ehci/usb_glue_hpm.c') + if GetDepend(['PKG_CHERRYUSB_HOST_XHCI']): + src += Glob('port/xhci/usb_hc_xhci.c') + src += Glob('port/xhci/xhci_dbg.c') + src += Glob('port/xhci/xhci.c') + + if GetDepend(['PKG_CHERRYUSB_HOST_PUSB2']): + path += [cwd + '/port/pusb2/common'] + path += [cwd + '/port/pusb2/fpusb2'] + src += Glob('port/pusb2/fpusb2' + '/*.c') + src += Glob('port/pusb2/usb_hc_pusb2.c') + if GetDepend(['PKG_CHERRYUSB_HOST_TEMPLATE']): src += Glob('demo/usb_host.c') diff --git a/demo/msc_storage_template.c b/demo/msc_storage_template.c new file mode 100644 index 00000000..880c90e8 --- /dev/null +++ b/demo/msc_storage_template.c @@ -0,0 +1,167 @@ +#include "usbd_core.h" +#include "usbd_msc.h" + +#ifdef __RT_THREAD_H__ + +#define MSC_IN_EP 0x81 +#define MSC_OUT_EP 0x02 + +#define USBD_VID 0xFFFF +#define USBD_PID 0xFFFF +#define USBD_MAX_POWER 100 +#define USBD_LANGID_STRING 1033 + +#define USB_CONFIG_SIZE (9 + MSC_DESCRIPTOR_LEN) + +#ifdef CONFIG_USB_HS +#define MSC_MAX_MPS 512 +#else +#define MSC_MAX_MPS 64 +#endif + + +const uint8_t msc_storage_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_1_1, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01), + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02), + /////////////////////////////////////// + /// string0 descriptor + /////////////////////////////////////// + USB_LANGID_INIT(USBD_LANGID_STRING), + /////////////////////////////////////// + /// string1 descriptor + /////////////////////////////////////// + 0x14, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + /////////////////////////////////////// + /// string2 descriptor + /////////////////////////////////////// + 0x26, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + ' ', 0x00, /* wcChar9 */ + 'M', 0x00, /* wcChar10 */ + 'S', 0x00, /* wcChar11 */ + 'C', 0x00, /* wcChar12 */ + ' ', 0x00, /* wcChar13 */ + 'D', 0x00, /* wcChar14 */ + 'E', 0x00, /* wcChar15 */ + 'M', 0x00, /* wcChar16 */ + 'O', 0x00, /* wcChar17 */ + /////////////////////////////////////// + /// string3 descriptor + /////////////////////////////////////// + 0x16, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + '2', 0x00, /* wcChar0 */ + '0', 0x00, /* wcChar1 */ + '2', 0x00, /* wcChar2 */ + '2', 0x00, /* wcChar3 */ + '1', 0x00, /* wcChar4 */ + '2', 0x00, /* wcChar5 */ + '3', 0x00, /* wcChar6 */ + '4', 0x00, /* wcChar7 */ + '5', 0x00, /* wcChar8 */ + '6', 0x00, /* wcChar9 */ +#ifdef CONFIG_USB_HS + /////////////////////////////////////// + /// device qualifier descriptor + /////////////////////////////////////// + 0x0a, + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x01, + 0x00, +#endif + 0x00 +}; + +struct usbd_interface intf0; + +/* assume the block device is 512M */ +#define BLOCK_DEV_NAME "sd0" +#define BLOCK_SIZE 512U +#define BLOCK_COUNT 0x1024U * 0x1024U +static rt_device_t blk_dev = RT_NULL; + +void usbd_event_handler(uint8_t event) +{ + switch (event) { + case USBD_EVENT_RESET: + break; + case USBD_EVENT_CONNECTED: + break; + case USBD_EVENT_DISCONNECTED: + break; + case USBD_EVENT_RESUME: + break; + case USBD_EVENT_SUSPEND: + break; + case USBD_EVENT_CONFIGURED: + break; + case USBD_EVENT_SET_REMOTE_WAKEUP: + break; + case USBD_EVENT_CLR_REMOTE_WAKEUP: + break; + + default: + break; + } +} + +void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size) +{ + *block_num = BLOCK_COUNT; + *block_size = BLOCK_SIZE; +} + +int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length) +{ + rt_device_read(blk_dev, sector, buffer, length / BLOCK_SIZE); + return 0; +} + +int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length) +{ + rt_device_write(blk_dev, sector, buffer, length / BLOCK_SIZE); + return 0; +} + +void msc_storage_init(void) +{ + rt_err_t res; + + blk_dev = rt_device_find(BLOCK_DEV_NAME); + RT_ASSERT(blk_dev); + + res = rt_device_open(blk_dev, RT_DEVICE_OFLAG_RDWR); + RT_ASSERT(res == RT_EOK); + + usbd_desc_register(msc_storage_descriptor); + usbd_add_interface(usbd_msc_init_intf(&intf0, MSC_OUT_EP, MSC_IN_EP)); + + usbd_initialize(); +} +#endif \ No newline at end of file diff --git a/port/pusb2/README.md b/port/pusb2/README.md new file mode 100644 index 00000000..8bf95771 --- /dev/null +++ b/port/pusb2/README.md @@ -0,0 +1,7 @@ +# USB2.0 OTG 控制器 (PUSB2) + +- Phytium PI 和 Phyium E2000 系列开发板提供了兼容 USB2.0 的 OTG 接口 +- 当前 Port 在 [RT-Thread](https://github.com/RT-Thread/rt-thread/tree/master/bsp/phytium) 上完成测试,具体使用方法参考 RT-Thread Phytium BSP 中的说明 +- usb_dc_pusb2.c 主要实现 Device 模式,测试过 msc_ram_template.c 和 cdc_acm_template.c 两个 Demo +- usb_hc_pusb2.c 主要实现 Host 模式,测试过 usb_host.c,可以连接 USB Disk, HID 设备鼠标和键盘 +- PUSB2 的驱动代码欢迎联系 `opensource_embedded@phytium.com.cn` 获取 \ No newline at end of file diff --git a/port/pusb2/usb_dc_pusb2.c b/port/pusb2/usb_dc_pusb2.c new file mode 100644 index 00000000..d437783b --- /dev/null +++ b/port/pusb2/usb_dc_pusb2.c @@ -0,0 +1,474 @@ +/* + * Copyright : (C) 2023 Phytium Information Technology, Inc. + * All Rights Reserved. + * + * This program is OPEN SOURCE software: you can redistribute it and/or modify it + * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, + * either version 1.0 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the Phytium Public License for more details. + * + * + * FilePath: usb_dc_pusb2.c + * Date: 2021-08-25 14:53:42 + * LastEditTime: 2021-08-26 09:01:26 + * Description:  This file is for implementation of PUSB2 port to cherryusb for host mode + * + * Modify History: + * Ver   Who        Date         Changes + * ----- ------     --------    -------------------------------------- + * 1.0 zhugengyu 2023/7/19 first commit + */ + +#include "usbd_core.h" +#include "fpusb2.h" + +/* Endpoint state */ +struct pusb2_dc_ep_state { + uint16_t ep_mps; /* Endpoint max packet size */ + uint8_t ep_type; /* Endpoint type */ + uint8_t ep_stalled; /* Endpoint stall flag */ + const struct usb_endpoint_descriptor *desc; + FPUsb2DcEp *priv_ep; +}; + +/* Data IN/OUT request */ +struct pusb2_dc_request { + struct pusb2_dc_ep_state *ep; + FPUsb2DcReq *priv_req; + int status; +}; + +/* Driver state */ +struct pusb2_udc { + FPUsb2 pusb2; + int speed; + FPUsb2Config config; + volatile uint8_t dev_addr; + int ep0_init_finish; + struct pusb2_dc_ep_state in_ep[FPUSB2_DC_EP_NUM]; /*!< IN endpoint parameters*/ + struct pusb2_dc_ep_state out_ep[FPUSB2_DC_EP_NUM]; /*!< OUT endpoint parameters */ +} g_pusb2_udc; + +__WEAK void usb_dc_low_level_init(void) +{ +} + +__WEAK void usb_dc_low_level_deinit(void) +{ +} + +static void pusb2_dc_init_ep_state(struct pusb2_dc_ep_state *ep_state, + FPUsb2DcEp *priv_ep) +{ + /* reset ep state and attach priv ep */ + ep_state->ep_mps = 0U; + ep_state->ep_type = 0U; + ep_state->ep_stalled = 0U; + ep_state->desc = NULL; + ep_state->priv_ep = priv_ep; +} + +static void pusb2_dc_connect_handler(FPUsb2DcController *instance) +{ + FPUsb2DcDev *dc_dev = NULL; + extern void FPUsb2DcNoReset(FPUsb2DcController *instance); + + FPUsb2DcGetDevInstance(&g_pusb2_udc.pusb2.device_ctrl, &dc_dev); + USB_ASSERT(dc_dev); + + USB_LOG_DBG("%s \n", __func__); + + usbd_event_reset_handler(); + + /* update speed and max packet size when connect */ + g_pusb2_udc.speed = dc_dev->speed; + if (g_pusb2_udc.speed > USB_SPEED_HIGH) { + g_pusb2_udc.in_ep[0].ep_mps = 9; + g_pusb2_udc.out_ep[0].ep_mps = 9; + } else { + g_pusb2_udc.in_ep[0].ep_mps = dc_dev->ep0->max_packet; + g_pusb2_udc.out_ep[0].ep_mps = dc_dev->ep0->max_packet; + } + + FPUsb2DcNoReset(instance); +} + +static void pusb2_dc_disconnect_handler(FPUsb2DcController *instance) +{ + USB_LOG_DBG("%s \n", __func__); +} + +static void pusb2_dc_resume_handler(FPUsb2DcController *instance) +{ + USB_LOG_DBG("%s \n", __func__); +} + +static uint32_t pusb2_dc_receive_steup_handler(FPUsb2DcController *instance, FUsbSetup *setup) +{ + USB_LOG_DBG("%s 0x%x:0x%x:0x%x:0x%x:0x%x\n", + __func__, + setup->bmRequestType, + setup->bRequest, + setup->wIndex, + setup->wLength, + setup->wValue); + + usbd_event_ep0_setup_complete_handler((u8 *)setup); + + return 0; +} + +static void pusb2_dc_suspend_handler(FPUsb2DcController *instance) +{ + USB_LOG_DBG("%s \n", __func__); +} + +static void* pusb2_dc_allocate_request_handler(FPUsb2DcController *instance, uint32_t size) +{ + FPUsb2DcReq * cusbd_req = usb_malloc(size); + if (!cusbd_req) { + return NULL; + } + + memset(cusbd_req, 0, sizeof(*cusbd_req)); + + return cusbd_req; +} + +static void pusb2_dc_free_request_handler(FPUsb2DcController *instance, void *usb_request) +{ + if (!usb_request) + return; + + usb_free(usb_request); +} + +static void pusb2_dc_pre_start_handler(FPUsb2DcController *instance) +{ + FPUsb2DcEp *priv_epx = NULL; + FPUsb2DcDev *dc_dev = NULL; + FDListHead *list; + int ep_num; + + FPUsb2DcGetDevInstance(&g_pusb2_udc.pusb2.device_ctrl, &dc_dev); + USB_ASSERT(dc_dev); + + g_pusb2_udc.speed = dc_dev->max_speed; + + pusb2_dc_init_ep_state(&g_pusb2_udc.in_ep[0], dc_dev->ep0); + pusb2_dc_init_ep_state(&g_pusb2_udc.out_ep[0], dc_dev->ep0); + + for(list = dc_dev->ep_list.next; + list != &dc_dev->ep_list; + list = list->next) { + priv_epx = (FPUsb2DcEp*)list; + ep_num = USB_EP_GET_IDX(priv_epx->address); + + if (USB_EP_DIR_IS_IN(priv_epx->address)) { + pusb2_dc_init_ep_state(&g_pusb2_udc.in_ep[ep_num], priv_epx); + } else { + pusb2_dc_init_ep_state(&g_pusb2_udc.out_ep[ep_num], priv_epx); + } + } +} + +static void pusb2_dc_prepare_ctrl_config(FPUsb2Config *config) +{ + *config = *FPUsb2LookupConfig(CONFIG_USBDEV_PUSB2_CTRL_ID); + + config->mode = FPUSB2_MODE_PERIPHERAL; + + /* allocate DMA buffer for TRB transfer */ + config->trb_mem_addr = usb_align(64U, config->trb_mem_size); + USB_ASSERT(config->trb_mem_addr); + + /* hook up device callbacks */ + config->host_cb.givback_request = NULL; + config->host_cb.otg_state_change = NULL; + config->host_cb.port_status_change = NULL; + config->host_cb.set_ep_toggle = NULL; + config->host_cb.get_ep_toggle = NULL; + config->host_cb.pre_start = NULL; + + config->device_cb.connect = pusb2_dc_connect_handler; + config->device_cb.disconnect= pusb2_dc_disconnect_handler; + config->device_cb.resume = pusb2_dc_resume_handler; + config->device_cb.setup = pusb2_dc_receive_steup_handler; + config->device_cb.suspend = pusb2_dc_suspend_handler; + config->device_cb.usb_request_mem_alloc = pusb2_dc_allocate_request_handler; + config->device_cb.usb_request_mem_free = pusb2_dc_free_request_handler; + config->device_cb.pre_start = pusb2_dc_pre_start_handler; + + return; +} + +int usb_dc_init(void) +{ + memset(&g_pusb2_udc, 0, sizeof(struct pusb2_udc)); + + usb_dc_low_level_init(); + + pusb2_dc_prepare_ctrl_config(&g_pusb2_udc.config); + if (FPUSB2_SUCCESS != FPUsb2CfgInitialize(&g_pusb2_udc.pusb2, + &g_pusb2_udc.config)) { + USB_LOG_ERR("init pusb2 failed \n"); + return -1; + } + + USB_LOG_INFO("init pusb2 successed \n"); + return 0; +} + +int usb_dc_deinit(void) +{ + usb_dc_low_level_deinit(); + + FPUsb2DeInitialize(&g_pusb2_udc.pusb2); + return 0; +} + +int usbd_set_address(const uint8_t addr) +{ + g_pusb2_udc.dev_addr = addr; + return 0; +} + +static struct usb_endpoint_descriptor *usbd_get_ep0_desc(const struct usbd_endpoint_cfg *ep_cfg) +{ + static struct usb_endpoint_descriptor ep0_desc; + + /* Config EP0 mps from speed */ + ep0_desc.bEndpointAddress = ep_cfg->ep_addr; + ep0_desc.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT; + ep0_desc.bmAttributes = ep_cfg->ep_type; + ep0_desc.wMaxPacketSize = ep_cfg->ep_mps; + ep0_desc.bInterval = 0; + ep0_desc.bLength = 7; + + return &ep0_desc; +} + +int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep_cfg->ep_addr); + struct pusb2_dc_ep_state *ep_state; + uint32_t error; + + if (USB_EP_DIR_IS_OUT(ep_cfg->ep_addr)) { + ep_state = &g_pusb2_udc.out_ep[ep_idx]; + } else { + ep_state = &g_pusb2_udc.in_ep[ep_idx]; + } + + ep_state->ep_mps = ep_cfg->ep_mps; + ep_state->ep_type = ep_cfg->ep_type; + ep_state->desc = usbd_get_ep0_desc(ep_cfg); + + USB_ASSERT(ep_state->priv_ep != NULL); + USB_LOG_DBG("try to enable ep@0x%x 0x%x:0x%x\n", ep_cfg->ep_addr, + ep_state->priv_ep, ep_state->desc ); + error = FPUsb2DcEpEnable(&g_pusb2_udc.pusb2.device_ctrl, + ep_state->priv_ep, + (const FUsbEndpointDescriptor *)ep_state->desc); + if (FPUSB2_SUCCESS != error){ + USB_LOG_ERR("enable ep-%d failed, error = 0x%x\n", ep_cfg->ep_addr, error); + return -1; + } + + g_pusb2_udc.ep0_init_finish = 1; + + return 0; +} + +int usbd_ep_close(const uint8_t ep) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + struct pusb2_dc_ep_state *ep_state; + + if (USB_EP_DIR_IS_OUT(ep)) { + ep_state = &g_pusb2_udc.out_ep[ep_idx]; + } else { + ep_state = &g_pusb2_udc.in_ep[ep_idx]; + } + + ep_state->desc = NULL; + if (FPUSB2_SUCCESS != FPUsb2DcEpDisable(&g_pusb2_udc.pusb2.device_ctrl, + ep_state->priv_ep)){ + USB_LOG_ERR("disable ep@0x%x failed\n", ep); + return -1; + } + + return 0; +} + +int usbd_ep_set_stall(const uint8_t ep) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + struct pusb2_dc_ep_state *ep_state; + + if (USB_EP_DIR_IS_OUT(ep)) { + ep_state = &g_pusb2_udc.out_ep[ep_idx]; + } else { + ep_state = &g_pusb2_udc.in_ep[ep_idx]; + } + + if (FPUSB2_SUCCESS != FPUsb2DcEpSetHalt(&g_pusb2_udc.pusb2.device_ctrl, + ep_state->priv_ep, 1)){ + USB_LOG_ERR("stall ep@0x%x failed\n", ep); + return -1; + } + + ep_state->ep_stalled = 1; + return 0; +} + +int usbd_ep_clear_stall(const uint8_t ep) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + struct pusb2_dc_ep_state *ep_state; + + if (USB_EP_DIR_IS_OUT(ep)) { + ep_state = &g_pusb2_udc.out_ep[ep_idx]; + } else { + ep_state = &g_pusb2_udc.in_ep[ep_idx]; + } + + if (FPUSB2_SUCCESS != FPUsb2DcEpSetHalt(&g_pusb2_udc.pusb2.device_ctrl, + ep_state->priv_ep, 0)){ + USB_LOG_ERR("clear ep@0x%x stall status failed\n", ep); + return -1; + } + + ep_state->ep_stalled = 0; + return 0; +} + +int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + struct pusb2_dc_ep_state *ep_state; + + if (USB_EP_DIR_IS_OUT(ep)) { + ep_state = &g_pusb2_udc.out_ep[ep_idx]; + } else { + ep_state = &g_pusb2_udc.in_ep[ep_idx]; + } + + if (stalled) { + *stalled = ep_state->ep_stalled; + } + + return 0; +} + +static struct pusb2_dc_request *pusb2_dc_allocate_request(struct pusb2_dc_ep_state *ep_state) +{ + struct pusb2_dc_request *request = usb_malloc(sizeof(*request)); + if (!request) { + return NULL; + } + + memset(request, 0, sizeof(*request)); + + request->ep = ep_state; + request->priv_req = NULL; + + if (FPUSB2_SUCCESS != FPUsb2DcReqAlloc(&g_pusb2_udc.pusb2.device_ctrl, + ep_state->priv_ep, + &request->priv_req )){ + USB_LOG_ERR("allocate request failed\n"); + usb_free(request); + return NULL; + } + + return request; +} + +static void pusb2_dc_free_request(struct pusb2_dc_request *request) +{ + USB_ASSERT(request); + struct pusb2_dc_ep_state *ep_state = request->ep; + FPUsb2DcReqFree(&g_pusb2_udc.pusb2.device_ctrl, + ep_state->priv_ep, + request->priv_req); + + usb_free(request); +} + +void pusb2_dc_callback_complete(FPUsb2DcEp *priv_ep, FPUsb2DcReq *priv_request) +{ + USB_ASSERT(priv_ep && priv_request); + struct pusb2_dc_request *request; + + request = priv_request->context; + + if (USB_EP_DIR_IS_OUT(priv_ep->address)) { + usbd_event_ep_out_complete_handler(priv_ep->address, priv_request->actual); + } else { + usbd_event_ep_in_complete_handler(priv_ep->address, priv_request->actual); + } + + request->status = priv_request->status; + if (request->status != 0) { + USB_LOG_ERR("Request failed, status = %d\n", request->status); + } + + pusb2_dc_free_request(request); + priv_request->context = NULL; +} + +int pusb2_dc_ep_read_write(const uint8_t ep, uintptr data, uint32_t data_len) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + struct pusb2_dc_ep_state *ep_state; + struct pusb2_dc_request *request; + uint32_t error; + + if (USB_EP_DIR_IS_OUT(ep)) { + ep_state = &g_pusb2_udc.out_ep[ep_idx]; + } else { + ep_state = &g_pusb2_udc.in_ep[ep_idx]; + } + + request = pusb2_dc_allocate_request(ep_state); + if (!request) { + USB_LOG_ERR("failed to allocate request !!!\n"); + return -1; + } + + request->priv_req->dma = data; + request->priv_req->buf = (void *)data; + request->priv_req->length = data_len; + + request->priv_req->complete = pusb2_dc_callback_complete; + request->priv_req->context = request; + request->priv_req->status = 0; + + error = FPUsb2DcReqQueue(&g_pusb2_udc.pusb2.device_ctrl, + ep_state->priv_ep, + request->priv_req); + if (FPUSB2_SUCCESS != error){ + USB_LOG_ERR("send req to ep@0x%x failed, error = 0x%x\n", ep, error); + return -1; + } + + return 0; +} + +int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len) +{ + return pusb2_dc_ep_read_write(ep, (uintptr)data, data_len); +} + +int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len) +{ + return pusb2_dc_ep_read_write(ep, (uintptr)data, data_len); +} + +void USBD_IRQHandler(void) +{ + FPUsb2InterruptHandler(&g_pusb2_udc.pusb2); +} diff --git a/port/pusb2/usb_hc_pusb2.c b/port/pusb2/usb_hc_pusb2.c new file mode 100644 index 00000000..340aec32 --- /dev/null +++ b/port/pusb2/usb_hc_pusb2.c @@ -0,0 +1,684 @@ +/* + * Copyright : (C) 2023 Phytium Information Technology, Inc. + * All Rights Reserved. + * + * This program is OPEN SOURCE software: you can redistribute it and/or modify it + * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, + * either version 1.0 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the Phytium Public License for more details. + * + * + * FilePath: usb_hc_pusb2.c + * Date: 2021-08-25 14:53:42 + * LastEditTime: 2021-08-26 09:01:26 + * Description:  This file is for implementation of PUSB2 port to cherryusb for host mode + * + * Modify History: + * Ver   Who        Date         Changes + * ----- ------     --------    -------------------------------------- + * 1.0 zhugengyu 2023/7/19 first commit + * 1.1 zhugengyu 2023/11/14 sync with 0.11.1 port interface + */ + +#include + +#include "usbh_core.h" +#include "usbh_hub.h" +#include "fpusb2.h" + +struct pusb2_pipe; +struct pusb2_dev; +struct pusb2_hcd; + +struct pusb2_hcd { + FPUsb2 pusb2; + FPUsb2Config config; +}; + +struct pusb2_dev { + FPUsb2HcEp ep0; + FPUsb2HcEp *epx_in[FPUSB2_HC_EP_NUM]; + FPUsb2HcEp *epx_out[FPUSB2_HC_EP_NUM]; + FPUsb2HcDevice udev; + + /*one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints*/ + unsigned int toggle[2]; +#define PUSB2_GET_TOGGLE(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) +#define PUSB2_DO_TOGGLE(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) +#define PUSB2_SET_TOGGLE(dev, ep, out, bit) \ + ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \ + ((bit) << (ep))) +}; + +struct pusb2_pipe { + struct pusb2_hcd *hcd; + struct pusb2_dev *dev; + + uint8_t speed; + uint8_t dev_addr; + uint8_t ep_addr; + uint8_t ep_type; + uint8_t ep_num; + uint8_t ep_is_in; + uint8_t ep_interval; + uint16_t ep_mps; + + bool inuse; + volatile bool waiter; + usb_osal_sem_t waitsem; + struct usbh_hubport *hport; + struct usbh_urb *urb; + const struct usb_endpoint_descriptor *desc; +}; + +static int usb_id = CONFIG_USBDEV_PUSB2_CTRL_ID; +static struct pusb2_hcd g_pusb2_hcd[CONFIG_USBDEV_PUSB2_CTRL_NUM]; + +__WEAK void usb_hc_low_level_init(void) +{ +} + +__WEAK void *usb_hc_malloc(size_t size) +{ + return NULL; +} + +__WEAK void *usb_hc_malloc_align(size_t align, size_t size) +{ + return NULL; +} + +__WEAK void usb_hc_free() +{ +} + +/* one may get xhci register base address by PCIe bus emuration */ +__WEAK unsigned long usb_hc_get_register_base(uint32_t id) +{ + return 0U; +} + +static inline struct pusb2_dev *pusb2_hc_pipe_to_dev(struct pusb2_pipe *ppipe) +{ + USB_ASSERT(ppipe && ppipe->dev); + return ppipe->dev; +} + +static inline struct pusb2_hcd *pusb2_hc_get_hcd(void) +{ + return &g_pusb2_hcd[usb_id]; +} + +static void pusb2_pipe_waitup(struct pusb2_pipe *pipe) +{ + struct usbh_urb *urb; + + urb = pipe->urb; + pipe->urb = NULL; + + if (pipe->waiter) { + pipe->waiter = false; + usb_osal_sem_give(pipe->waitsem); + } + + if (urb->complete) { + if (urb->errorcode < 0) { + urb->complete(urb->arg, urb->errorcode); + } else { + urb->complete(urb->arg, urb->actual_length); + } + } +} + +static void pusb2_hc_request_giveback(FPUsb2HcController *instance, FPUsb2HcReq *req, u32 status) +{ + struct usbh_urb *urb; + struct pusb2_pipe *pipe; + int error = 0; + + urb = req->user_ext; + pipe = urb->pipe; + + switch(status) { + case FPUSB2_HC_ESTALL: + error = -EPIPE; + break; + case FPUSB2_HC_EUNHANDLED: + error = -EPROTO; + break; + case FPUSB2_HC_ESHUTDOWN: + error = -ESHUTDOWN; + break; + } + + urb->errorcode = error; + urb->actual_length = req->actual_length; + + pusb2_pipe_waitup(pipe); + return; +} + +static void pusb2_hc_otg_state_change(FPUsb2HcController *instance, int otg_state) +{ + return; +} + + +static int pusb2_hub_status_data(FPUsb2HcController *instance, char *buf) +{ + int retval = 0; + + retval = FPUsb2VHubStatusChangeData(instance, (u8 *)buf); + if(retval != 0) { + return 0; + } + + if(*buf == 0x02) { + return 1; + } else { + return 0; + } +} + +static void pusb2_hc_rh_port_status_change(FPUsb2HcController *instance) +{ + u32 status_hub = 0U; + u16 *status = (u16*)&status_hub; + FUsbSetup setup; + u32 retval = 0; + + pusb2_hub_status_data(instance, (char*)status); + + setup.bRequest = FUSB_REQ_GET_STATUS; + setup.bmRequestType = FUSB_REQ_TYPE_CLASS | FUSB_REQ_RECIPIENT_OTHER | FUSB_DIR_DEVICE_TO_HOST; + setup.wIndex = cpu_to_le16(1); /* port number */ + setup.wLength = cpu_to_le16(4); + setup.wValue = 0; + + retval = FPUsb2VHubControl(instance, &setup, (u8*)status); + if(retval) { + return; + } + + if(status[1] & FUSB_PSC_CONNECTION) { + if(status[0] & FUSB_PS_CONNECTION) { + USB_LOG_DBG("resume roothub \n"); + /* Report port status change */ + usbh_roothub_thread_wakeup ( 1U ); + } + } +} + +static u8 pusb2_hc_get_ep_toggle(void *instance, struct FPUsb2HcDevice *udev, u8 ep_num, u8 is_in) +{ + struct pusb2_dev *dev; + u8 toggle = 0; + + dev = (struct pusb2_dev*) udev->user_ext; + toggle = PUSB2_GET_TOGGLE(dev, ep_num, !is_in); + return toggle; +} + +static void pusb2_hc_set_ep_toggle(void *instance, struct FPUsb2HcDevice *udev, u8 ep_num, u8 is_in, u8 toggle) +{ + struct pusb2_dev *dev; + + dev = (struct pusb2_dev*) udev->user_ext; + PUSB2_SET_TOGGLE(dev, ep_num, !is_in, toggle); +} + +static void pusb2_hc_prepare_ctrl_config(uint32_t id, FPUsb2Config *config) +{ + *config = *FPUsb2LookupConfig(id); + + config->mode = FPUSB2_MODE_HOST; + + /* allocate DMA buffer for TRB transfer */ + config->trb_mem_addr = usb_align(64U, config->trb_mem_size); + USB_ASSERT(config->trb_mem_addr); + + /* hook up host callbacks */ + config->host_cb.givback_request = pusb2_hc_request_giveback; + config->host_cb.otg_state_change = pusb2_hc_otg_state_change; + config->host_cb.port_status_change = pusb2_hc_rh_port_status_change; + config->host_cb.set_ep_toggle = pusb2_hc_set_ep_toggle; + config->host_cb.get_ep_toggle = pusb2_hc_get_ep_toggle; + config->host_cb.pre_start = NULL; + config->host_cb.usb_dev_callbacks = &config->device_cb; + + config->device_cb.connect = NULL; + config->device_cb.disconnect= NULL; + config->device_cb.resume = NULL; + config->device_cb.setup = NULL; + config->device_cb.suspend = NULL; + config->device_cb.usb_request_mem_alloc = NULL; + config->device_cb.usb_request_mem_free = NULL; + config->device_cb.pre_start = NULL; + + return; +} + +int usb_hc_init(void) +{ + int rc; + struct pusb2_hcd *hcd = pusb2_hc_get_hcd(); + + size_t flag = usb_osal_enter_critical_section(); /* no interrupt when init hc */ + usb_hc_low_level_init(); /* set gic and memp */ + + memset(hcd, 0, sizeof(*hcd)); + + pusb2_hc_prepare_ctrl_config(usb_id, &hcd->config); + + if (FPUSB2_SUCCESS != FPUsb2CfgInitialize(&hcd->pusb2, + &hcd->config)) { + USB_LOG_ERR("init pusb2 failed \n"); + rc = -1; + } else { + USB_LOG_INFO("init pusb2 successed \n"); + } + + usb_osal_leave_critical_section(flag); + return rc; +} + +uint16_t usbh_get_frame_number(void) +{ + return 0; +} + +int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf) +{ + struct pusb2_hcd *hcd = pusb2_hc_get_hcd(); + int retval = 0; + + retval = FPUsb2VHubControl(&(hcd->pusb2.host_ctrl), (FUsbSetup *)setup, buf); + if(retval != 0) { + USB_LOG_ERR("%s failed, retval = %d \r\n", __func__, retval); + } + + return retval; +} + +static void pusb2_hc_update_device(struct pusb2_dev *dev, int dev_addr, int speed, int mps) +{ + dev->udev.speed = (FUsbSpeed)speed; + dev->udev.devnum = dev_addr; + dev->ep0.ep_desc.max_packet_size = mps; +} + +int usbh_ep_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t mtu, uint8_t speed) +{ + struct pusb2_pipe *ppipe = pipe; + struct usbh_hubport *hport = ppipe->hport; + struct pusb2_dev *dev = pusb2_hc_pipe_to_dev(ppipe); + + pusb2_hc_update_device(dev, dev_addr, hport->speed, mtu); + + return 0; +} + +static struct pusb2_dev *pusb2_hc_allocate_dev(void) +{ + struct pusb2_hcd *hcd = pusb2_hc_get_hcd(); + struct pusb2_dev *dev; + + dev = usb_malloc((sizeof *dev)+ FPUsb2HcGetPrivateDataSize(&(hcd->pusb2.host_ctrl))); + if (dev == NULL) + return NULL; + + dev->ep0.hc_priv = &((u8*)dev)[sizeof *dev]; /* ep private data */ + dev->udev.user_ext = (void*)dev; + + dev->ep0.ep_desc.bLength = FUSB_DS_ENDPOINT; + dev->ep0.ep_desc.bDescriptorType = FUSB_DT_ENDPOINT; + FDLIST_INIT_HEAD(&dev->ep0.reqList); + dev->epx_in[0] = &dev->ep0; + dev->epx_out[0] = &dev->ep0; + + return dev; +} + +static void pusb2_hc_free_ep(struct pusb2_pipe *ppipe) +{ + USB_ASSERT(ppipe && ppipe->hcd); + struct usbh_hubport *hport = ppipe->hport; + struct pusb2_hcd *hcd = ppipe->hcd; + struct pusb2_dev *dev = pusb2_hc_pipe_to_dev(ppipe); + int ep_num = USB_EP_GET_IDX(ppipe->ep_addr); + + if (USB_EP_DIR_IS_IN(ppipe->ep_addr)) { + dev->epx_in[ep_num]->user_ext = NULL; + usb_free(dev->epx_in[ep_num]); + dev->epx_in[ep_num] = NULL; + } else { + dev->epx_out[ep_num]->user_ext = NULL; + usb_free(dev->epx_out[ep_num]); + dev->epx_out[ep_num] = NULL; + } + + return; +} + +static void pusb2_hc_free_dev(struct pusb2_pipe *ppipe) +{ + USB_ASSERT(ppipe && ppipe->hcd); + struct usbh_hubport *hport = ppipe->hport; + struct pusb2_hcd *hcd = ppipe->hcd; + struct pusb2_dev *dev = pusb2_hc_pipe_to_dev(ppipe); + + dev->epx_in[0] = NULL; + dev->epx_out[0] = NULL; + + for (int i = 1; i < FPUSB2_HC_EP_NUM; i++) { + if (dev->epx_in[i]) { + dev->epx_in[i]->user_ext = NULL; + usb_free(dev->epx_in[i]); + dev->epx_in[i] = NULL; + } + + if (dev->epx_out[i]) { + dev->epx_out[i]->user_ext = NULL; + usb_free(dev->epx_out[i]); + dev->epx_out[i] = NULL; + } + } + + usb_free(dev); + return; +} + +int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg) +{ + struct usbh_hubport *hport = ep_cfg->hport; + struct pusb2_hcd *hcd = pusb2_hc_get_hcd(); + struct pusb2_pipe *ppipe = usb_malloc(sizeof(struct pusb2_pipe)); + struct pusb2_dev *dev; + + if (NULL == ppipe) { + return -ENOMEM; + } + + memset(ppipe, 0, sizeof(struct pusb2_pipe)); + + ppipe->waitsem = usb_osal_sem_create(0); + ppipe->waiter = false; + ppipe->urb = NULL; + ppipe->hport = hport; + + ppipe->ep_addr = ep_cfg->ep_addr; + ppipe->ep_type = ep_cfg->ep_type; + ppipe->ep_num = USB_EP_GET_IDX(ep_cfg->ep_addr); + ppipe->ep_is_in = USB_EP_DIR_IS_IN(ep_cfg->ep_addr); + ppipe->ep_mps = ep_cfg->ep_mps; + ppipe->ep_interval = ep_cfg->ep_interval; + ppipe->hcd = hcd; + + USB_LOG_DBG("allocate ep-%d\n", ppipe->ep_num); + if (ppipe->ep_addr == 0) { /* if try to allocate ctrl ep, open device first */ + dev = pusb2_hc_allocate_dev(); + if (NULL == dev) { + usb_free(ppipe); + return -ENOMEM; + } + + ppipe->desc = (const struct usb_endpoint_descriptor *)&(dev->ep0.ep_desc); + ppipe->dev = dev; + } else { + dev = pusb2_hc_pipe_to_dev((struct pusb2_pipe *)hport->ep0); + struct pusb2_pipe *ppipe_ctrl = hport->ep0; + + ppipe->desc = ppipe_ctrl->desc; + ppipe->dev = dev; + } + + *pipe = (usbh_pipe_t)ppipe; + return 0; +} + +int usbh_pipe_free(usbh_pipe_t pipe) +{ + USB_ASSERT(pipe); + struct pusb2_pipe *ppipe = (struct pusb2_pipe *)pipe; + struct usbh_urb *urb = ppipe->urb; + size_t flags; + + /* free any un-finished urb */ + if (ppipe->urb) { + usbh_kill_urb(urb); + } + + flags = usb_osal_enter_critical_section(); + if (USB_EP_GET_IDX(ppipe->ep_addr) == 0) { + /* free control ep means free device */ + pusb2_hc_free_dev(ppipe); + } else { + /* free work ep */ + pusb2_hc_free_ep(ppipe); + } + usb_osal_leave_critical_section(flags); + + return 0; +} + +static void pusb2_hc_update_endpoint(struct pusb2_hcd *hcd, struct pusb2_dev *dev, struct pusb2_pipe *pipe) +{ + USB_ASSERT(hcd && dev && pipe); + FPUsb2HcEp * priv_ep = NULL; + int epnum = pipe->ep_num; + int is_out = !pipe->ep_is_in; + + if (is_out) { + if (dev->epx_out[epnum] == NULL) { + priv_ep = usb_malloc(sizeof(FPUsb2HcEp) + FPUsb2HcGetPrivateDataSize(&(hcd->pusb2.host_ctrl))); + USB_ASSERT(priv_ep); + dev->epx_out[epnum] = priv_ep; + } else { + priv_ep = dev->epx_out[epnum]; + } + } else { + if (dev->epx_in[epnum] == NULL) { + priv_ep = usb_malloc(sizeof(FPUsb2HcEp) + FPUsb2HcGetPrivateDataSize(&(hcd->pusb2.host_ctrl))); + USB_ASSERT(priv_ep); + dev->epx_in[epnum] = priv_ep; + } else { + priv_ep = dev->epx_in[epnum]; + } + } + + priv_ep->ep_desc = *((FUsbEndpointDescriptor *)pipe->desc); + priv_ep->user_ext = (void *)pipe; + FDLIST_INIT_HEAD(&priv_ep->reqList); + priv_ep->hc_priv = &((u8*)priv_ep)[sizeof *priv_ep]; +} + +static int pusb2_hc_enqueue_urb(struct usbh_urb *urb) +{ + struct pusb2_pipe *pipe = urb->pipe; + struct usbh_hubport *hport = pipe->hport; + struct pusb2_hcd *hcd = pusb2_hc_get_hcd(); + struct pusb2_dev *dev; + + u32 iso_frame_size; + FPUsb2HcReq *priv_req; + int ret; + + if(!FPUsb2HcIsHostMode(&(hcd->pusb2.host_ctrl))) { + return -ENODEV; + } + + dev = pusb2_hc_pipe_to_dev(pipe); + if(!dev) + return -ENODEV; + + if (pipe->ep_is_in) { + if (!dev->epx_in[pipe->ep_num]) { + pusb2_hc_update_endpoint(hcd, dev, pipe); + } + } else { + if (!dev->epx_out[pipe->ep_num]) { + pusb2_hc_update_endpoint(hcd, dev, pipe); + } + } + + iso_frame_size = urb->num_of_iso_packets * sizeof(FPUsb2HcIsoFrameDesc); + priv_req = (FPUsb2HcReq*)usb_malloc((sizeof *priv_req) + iso_frame_size); + if (!priv_req) + return -ENOMEM; + + priv_req->iso_frames_desc = NULL; + priv_req->iso_frames_number = urb->num_of_iso_packets; + + FDLIST_INIT_HEAD(&priv_req->list); + priv_req->user_ext = (void*) urb; + + priv_req->actual_length = urb->actual_length; + priv_req->buf_address = urb->transfer_buffer; + priv_req->buf_dma = (uintptr_t)urb->transfer_buffer; + priv_req->buf_length = urb->transfer_buffer_length; + priv_req->ep_is_in = pipe->ep_is_in; + priv_req->ep_num = pipe->ep_num; + priv_req->ep_type = pipe->ep_type; + priv_req->faddress = dev->udev.devnum; + priv_req->interval = pipe->ep_interval; + priv_req->req_unlinked = 0; + priv_req->setup = (FUsbSetup*)urb->setup; + priv_req->setup_dma = (uintptr_t)urb->setup; + priv_req->status = FPUSB2_ERR_INPROGRESS; + priv_req->usb_dev = &dev->udev; + priv_req->usb_ep = priv_req->ep_is_in ? dev->epx_in[priv_req->ep_num]: + dev->epx_out[priv_req->ep_num]; + + if (priv_req->ep_num == 0) { + dev->ep0.ep_desc.max_packet_size = pipe->ep_mps; + } + + urb->hcpriv = priv_req; + + ret = FPUsb2HcReqQueue(&(hcd->pusb2.host_ctrl), priv_req); + if(ret) { + usb_free(priv_req); + return ret; + } + + return ret; +} + +int usbh_submit_urb(struct usbh_urb *urb) +{ + struct pusb2_pipe *pipe = (struct pusb2_pipe *)urb->pipe; + size_t flags; + int ret = 0; + + if (!urb) { + return -EINVAL; + } + + if (!pipe->hport->connected) { + return -ENODEV; + } + + if (pipe->urb) { + return -EBUSY; + } + + if (urb->timeout > 0) { + flags = usb_osal_enter_critical_section(); + } + + pipe->waiter = false; + pipe->urb = urb; + urb->errorcode = -EBUSY; + urb->actual_length = 0; + + if (urb->timeout > 0) { + pipe->waiter = true; + } + + if (urb->timeout > 0) { + usb_osal_leave_critical_section(flags); + } + + switch (pipe->ep_type) { + case USB_ENDPOINT_TYPE_CONTROL: + case USB_ENDPOINT_TYPE_BULK: + case USB_ENDPOINT_TYPE_INTERRUPT: + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + ret = pusb2_hc_enqueue_urb(urb); + break; + default: + break; + } + + if (urb->timeout > 0) { + /* wait until timeout or sem give */ + ret = usb_osal_sem_take(pipe->waitsem, urb->timeout); + if (ret < 0) { + USB_LOG_ERR("wait request timeout, ret = %d \n", ret); + goto errout_timeout; + } + + ret = urb->errorcode; + } + + return ret; +errout_timeout: + pipe->waiter = false; + usbh_kill_urb(urb); + return ret; +} + +static void pusb2_hc_dequeue_urb(struct usbh_urb *urb) +{ + USB_ASSERT(urb); + struct pusb2_pipe *pipe = urb->pipe; + struct usbh_hubport *hport = pipe->hport; + struct pusb2_hcd *hcd = pusb2_hc_get_hcd(); + struct pusb2_dev *dev; + FPUsb2HcReq *priv_req = urb->hcpriv; + + USB_ASSERT(priv_req); + if (FPUSB2_SUCCESS != FPUsb2HcReqDequeue(&(hcd->pusb2.host_ctrl), priv_req, 0)) { + USB_LOG_ERR("failed to dequeue urb \n"); + } + + usb_free(priv_req); + urb->hcpriv = NULL; + return; +} + +int usbh_kill_urb(struct usbh_urb *urb) +{ + size_t flags; + if (!urb) { + return -EINVAL; + } + + struct pusb2_pipe *pipe = urb->pipe; + + flags = usb_osal_enter_critical_section(); + + pusb2_hc_dequeue_urb(urb); + pipe->urb = NULL; + + if (pipe->waiter) { + pipe->waiter = false; + urb->errorcode = -ESHUTDOWN; + usb_osal_sem_give(pipe->waitsem); + } + + usb_osal_sem_delete(pipe->waitsem); + usb_osal_leave_critical_section(flags); + + return 0; +} + +void USBH_IRQHandler(void *param) +{ + struct pusb2_hcd *hcd = pusb2_hc_get_hcd(); + FPUsb2InterruptHandler(&hcd->pusb2); + return; +} \ No newline at end of file diff --git a/port/xhci/usb_hc_xhci.c b/port/xhci/usb_hc_xhci.c index 44b71ed7..3af541b0 100644 --- a/port/xhci/usb_hc_xhci.c +++ b/port/xhci/usb_hc_xhci.c @@ -299,9 +299,7 @@ int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf) uint8_t usbh_get_port_speed(struct usbh_hub *hub, const uint8_t port) { USB_ASSERT(hub); - struct usbh_bus *usb = hub->usb; - USB_ASSERT(usb && usb->priv); - struct xhci_host *xhci = usb->priv; + struct xhci_host *xhci = &(xhci_host); if (hub->is_roothub) { return xhci_root_speed(xhci, port); diff --git a/port/xhci/xhci.c b/port/xhci/xhci.c index 7af03a37..0acf2bd4 100644 --- a/port/xhci/xhci.c +++ b/port/xhci/xhci.c @@ -23,6 +23,8 @@ * 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub */ +#include + #include "usbh_core.h" #include "usbh_hub.h" @@ -31,6 +33,39 @@ extern struct usbh_hubport *usbh_get_roothub_port(unsigned int port); +#ifdef __aarch64__ +/* find last 64bit set, binary search */ +int xhci_fls(unsigned long v) +{ + int n = 64; + + if (!v) return -1; + if (!(v & 0xFFFFFFFF00000000)) { v <<= 32; n -= 32; } + if (!(v & 0xFFFF000000000000)) { v <<= 16; n -= 16; } + if (!(v & 0xFF00000000000000)) { v <<= 8; n -= 8; } + if (!(v & 0xF000000000000000)) { v <<= 4; n -= 4; } + if (!(v & 0xC000000000000000)) { v <<= 2; n -= 2; } + if (!(v & 0x8000000000000000)) { v <<= 1; n -= 1; } + + return n - 1; +} +#else +/* find first bit set, binary search */ +int xhci_fls(unsigned int v) +{ + int n = 32; + + if (!v) return -1; + if (!(v & 0xFFFF0000)) { v <<= 16; n -= 16; } + if (!(v & 0xFF000000)) { v <<= 8; n -= 8; } + if (!(v & 0xF0000000)) { v <<= 4; n -= 4; } + if (!(v & 0xC0000000)) { v <<= 2; n -= 2; } + if (!(v & 0x80000000)) { v <<= 1; n -= 1; } + + return n - 1; +} +#endif + /** * Get USB transaction translator * @@ -143,7 +178,7 @@ static inline size_t xhci_align ( size_t len ) { size_t align; /* Align to own length (rounded up to a power of two) */ - align = ( 1 << fls ( len - 1 ) ); + align = ( 1 << xhci_fls ( len - 1 ) ); /* Round up to XHCI_MIN_ALIGN if needed */ if ( align < XHCI_MIN_ALIGN ) @@ -2030,8 +2065,8 @@ static inline int xhci_configure_endpoint ( struct xhci_host *xhci, * @v input Input context */ static void -xhci_deconfigure_endpoint_input ( struct xhci_host *xhci __unused, - struct xhci_slot *slot __unused, +xhci_deconfigure_endpoint_input ( struct xhci_host *xhci, + struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input ) { struct xhci_control_context *control_ctx; @@ -2162,7 +2197,7 @@ int xhci_work_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, st /* Calculate interval */ if ( ctx_type & XHCI_EP_TYPE_PERIODIC ) { - ep->interval = ( fls ( ep->interval ) - 1 ); + ep->interval = ( xhci_fls ( ep->interval ) - 1 ); } ep->ctx_type = ctx_type; @@ -2337,7 +2372,7 @@ err_enqueue: * @v input Input context */ static void xhci_evaluate_context_input ( struct xhci_host *xhci, - struct xhci_slot *slot __unused, + struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input ) { struct xhci_control_context *control_ctx;