mirror of
https://github.com/sakumisu/CherryUSB.git
synced 2025-05-09 00:21:44 +08:00
add pusb2 port, fix issue for rt-thread, add msc storage demo for rt-thread
This commit is contained in:
parent
9ce7b0ceb7
commit
aeffaea016
@ -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 |
|
||||
|
@ -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 |
|
||||
|
21
SConscript
21
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')
|
||||
|
||||
|
167
demo/msc_storage_template.c
Normal file
167
demo/msc_storage_template.c
Normal file
@ -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
|
7
port/pusb2/README.md
Normal file
7
port/pusb2/README.md
Normal file
@ -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` 获取
|
474
port/pusb2/usb_dc_pusb2.c
Normal file
474
port/pusb2/usb_dc_pusb2.c
Normal file
@ -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);
|
||||
}
|
684
port/pusb2/usb_hc_pusb2.c
Normal file
684
port/pusb2/usb_hc_pusb2.c
Normal file
@ -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 <assert.h>
|
||||
|
||||
#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;
|
||||
}
|
@ -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);
|
||||
|
@ -23,6 +23,8 @@
|
||||
* 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user