Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources

This commit is contained in:
2026-07-06 11:30:13 +08:00
commit e76462eeb7
3451 changed files with 1415300 additions and 0 deletions

View File

@@ -0,0 +1,368 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-10-30 ZYH the first version
*/
/*
针对 USB DMA RX , 需做的内存预留大小为 4 字节, 防止 DMA 内存越界引起的内存错误问题
USB1.1 SIE:
(1) rx len % 4 == 1 实际 dma sram 会少 1 byte , 即 rx len - 1 (USB1.1驱动已修复)
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
USB2.0 SIE:
(1) rx len % 4 == 1 实际 dma sram 会多 2 byte , 即 rx len + 2
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
*/
#include "drv_usb11d.h"
#include <rtthread.h>
#include "include/rttusb_device.h"
#include "dev/usb/usb11_v0/hgusb11_v0_dev_api.h"
static struct ep_id _ep_pool[] =
{
{0x0, USB_EP_ATTR_TYPE_MASK, USB_DIR_INOUT, 64, ID_ASSIGNED },
{0x1, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x1, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0x2, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x2, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0x3, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x3, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED },
};
struct usb_device * _hg_pdc11;
static struct udcd _hg_udc;
static rt_err_t _suspend(void);
static rt_err_t _wakeup(void);
static uint32 hal_pcd11_bus_irq(uint32 irq, uint32 param1, uint32 param2, uint32 param3)
{
struct usb_device *p_usb_d = (struct usb_device *)param1;
struct hgusb11_dev *p_dev = (struct hgusb11_dev *)p_usb_d;
uint32 ep_num = param2 & 0xF;
uint32 len = param3;
LOG_D("irq:%d %x %d %x\r\n", irq, param1, param2, param3);
int32 ret_val = 1;
switch (irq) {
case USB_CONNECT: //7
rt_usbd_connect_handler(&_hg_udc);
break;
case USB_DISCONNECT://8
rt_usbd_disconnect_handler(&_hg_udc);
break;
case USB_DEV_RESET_IRQ://0
rt_usbd_reset_handler(&_hg_udc);
break;
case USB_DEV_SUSPEND_IRQ://1
_suspend();
break;
case USB_DEV_RESUME_IRQ://2
_wakeup();
break;
case USB_DEV_SOF_IRQ://3
rt_usbd_sof_handler(&_hg_udc);
break;
case USB_DEV_CTL_IRQ://4
ret_val = 0;
rt_usbd_ep0_setup_handler(&_hg_udc, (struct urequest *)p_dev->ep0_ctrl.ep0_buf);
break;
case USB_EP_RX_IRQ://5
if (ep_num == 0) {
rt_usbd_ep0_out_handler(&_hg_udc, len);
} else {
rt_usbd_ep_out_handler(&_hg_udc, ep_num, len);
}
break;
case USB_EP_TX_IRQ://6
if (ep_num == 0) {
rt_usbd_ep0_in_handler(&_hg_udc);
} else {
rt_usbd_ep_in_handler(&_hg_udc, 0x80 | ep_num, len);
}
break;
default:
break;
}
return ret_val;
}
static rt_err_t _ep_set_stall(rt_uint8_t address)
{
LOG_D("rtt stall\r\n");
hgusb11_v0_dev_ep_set_stall((struct usb_device *)_hg_pdc11, address);
return RT_EOK;
}
static rt_err_t _ep_clear_stall(rt_uint8_t address)
{
hgusb11_v0_dev_ep_clear_stall((struct usb_device *)_hg_pdc11, address);
return RT_EOK;
}
static rt_err_t _set_address(rt_uint8_t address)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, address);
hgusb11_v0_dev_set_address((struct usb_device *)_hg_pdc11, address);
return RT_EOK;
}
static rt_err_t _set_config(rt_uint8_t address)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, address);
hgusb11_v0_dev_set_config((struct usb_device *)_hg_pdc11, address);
return RT_EOK;
}
static rt_err_t _ep_enable(uep_t ep)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, ep->ep_desc->bEndpointAddress, ep->ep_desc->wMaxPacketSize);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
hgusb11_v0_dev_ep_enable((struct usb_device *)_hg_pdc11,
ep->ep_desc->bEndpointAddress,
ep->ep_desc->wMaxPacketSize,
ep->ep_desc->bmAttributes);
return RT_EOK;
}
static rt_err_t _ep_disable(uep_t ep)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, ep->ep_desc->bEndpointAddress, ep->ep_desc->wMaxPacketSize);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
hgusb11_v0_dev_ep_disable((struct usb_device *)_hg_pdc11, ep->ep_desc->bEndpointAddress);
return RT_EOK;
}
static rt_size_t _ep_read(rt_uint8_t address, void *buffer)
{
RT_ASSERT(buffer != RT_NULL);
uint32 size = 0;
LOG_D("%s %d %d\r\n", __FUNCTION__, address, size);
size = hgusb11_v0_dev_ep_read((struct usb_device *)_hg_pdc11, address, buffer);
return size;
}
static rt_size_t _ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, address, size);
hgusb11_v0_dev_ep_read_prepare((struct usb_device *)_hg_pdc11, address, buffer, size);
return size;
}
static rt_size_t _ep_write(rt_uint8_t address, void *buffer, rt_size_t size)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, address, size);
hgusb11_v0_dev_ep_write((struct usb_device *)_hg_pdc11, address, buffer, size);
return size;
}
static rt_err_t _ep0_send_status(void)
{
LOG_D("%s\r\n", __FUNCTION__);
hgusb11_v0_dev_ep0_send_status((struct usb_device *)_hg_pdc11);
return RT_EOK;
}
static rt_err_t _suspend(void)
{
LOG_D("%s\r\n", __FUNCTION__);
return RT_EOK;
}
static rt_err_t _wakeup(void)
{
LOG_D("%s\r\n", __FUNCTION__);
return RT_EOK;
}
static rt_err_t _deinit(struct usb_device *usb)
{
hgusb11_v0_dev_close((struct usb_device *)usb);
return RT_EOK;
}
static rt_err_t _init(struct usb_device *usb)
{
//struct hgusb20_dev *dev = (struct hgusb20_dev *)usb;
//int32 ret = RET_OK;
// if (usb == NULL) {
// return NULL;
// }
//
// ret = pin_func(dev->dev.dev.dev_id, 1);
// if (ret) {
//// USB_DEV_ERR_PRINTF("hgsdio20 dev request io failed!\r\n");
// ASSERT(ret == RET_OK);
// return ret;
// }
//
// //SYSCTRL_REG_OPT(sysctrl_usb20_reset(););
// sysctrl_usb20_clk_open();
// hgusb20_dev_hw_init(dev);
usb_device_open(usb, (struct usb_device_cfg *)NULL);
//usb_device_ioctl(usb, USB_DEV_IO_CMD_AUTO_TX_NULL_PKT_ENABLE, USB_WIFI_TX_EP, 0);
usb_device_request_irq(usb, hal_pcd11_bus_irq, (uint32)usb);
return RT_EOK;
}
const static struct udcd_ops _udc_ops =
{
_set_address,
_set_config,
_ep_set_stall,
_ep_clear_stall,
_ep_enable,
_ep_disable,
_ep_read_prepare,
_ep_read,
_ep_write,
_ep0_send_status,
_suspend,
_wakeup,
};
/**
* usage :
* 1、reg usb device in device.c hgusb20_dev_attach(HG_USBDEV_DEVID, &usb20_dev);
* 2、main init in main.c
* rt_usbd_class_list_init
* rt_usbd_winusb_class_register
*
*
* hg_usbd_register(HG_USB_DEV_CONTROLLER_DEVID);
*/
void hg_usb11d_class_driver_register()
{
/* 若需同时注册多个device设备需定义宏RT_USB_DEVICE_COMPOSITE成复合设备 */
rt_uint32_t devid = HG_USB11_DEV_CONTROLLER_DEVID;
rt_usbd_class_list_init(devid);
#ifdef RT_USB_DEVICE_VIDEO
rt_usbd_uvc_device_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_AUDIO_MIC
rt_usbd_uac_mic_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_AUDIO_SPEAKER
audio_speaker_init();
rt_usbd_uac_speaker_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_MSTORAGE
rt_usbd_msc_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_RNDIS
rt_usbd_rndis_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_HID
rt_usbd_hid_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_WINUSB
rt_usbd_winusb_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_CDC
rt_usbd_vcom_class_register(devid);
#endif
}
int hg_usb11d_register(rt_uint32_t devid)
{
struct usb_device *usb = (struct usb_device *)dev_get(HG_USB11DEV_DEVID);
_hg_pdc11 = usb;
rt_memset((void *)&_hg_udc, 0, sizeof(struct udcd));
_hg_udc.ops = &_udc_ops;
/* Register endpoint infomation */
_hg_udc.ep_pool = _ep_pool;
_hg_udc.ep0.id = &_ep_pool[0];
_hg_udc.device_is_hs = 0;
dev_register(devid, (struct dev_obj *)&_hg_udc);
rt_usb_device_init(devid, "usb11_device");
_init(usb);
return RT_EOK;
}
int hg_usb11d_unregister(rt_uint32_t devid)
{
struct usb_device *usb = (struct usb_device *)dev_get(HG_USB11DEV_DEVID);
struct dev_obj *udc = (struct dev_obj *)dev_get(devid);
if(udc && _hg_pdc11 != RT_NULL){
printf("%s %d\n",__FUNCTION__,__LINE__);
// rt_usb_device_deinit(devid);
_deinit(usb);
//dev_unregister((struct dev_obj *)&_hg_udc);
_hg_pdc11 = RT_NULL;
}
return RT_EOK;
}
int hg_usb11d_recover(rt_uint32_t devid)
{
struct usb_device *usb = (struct usb_device *)dev_get(HG_USB11DEV_DEVID);
struct dev_obj *udc = (struct dev_obj *)dev_get(devid);
if(udc){
_hg_pdc11 = usb;
// rt_usbd_core_init();
_init(usb);
}
return 0;
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-10-30 ZYH the first version
*/
#ifndef __HG_USB11D_H__
#define __HG_USB11D_H__
#include <rtthread.h>
void hg_usb11d_class_driver_register();
int hg_usb11d_register(rt_uint32_t devid);
int hg_usb11d_unregister(rt_uint32_t devid);
int hg_usb11d_recover(rt_uint32_t devid);
#endif

View File

@@ -0,0 +1,427 @@
/*
针对 USB DMA RX , 需做的内存预留大小为 4 字节, 防止 DMA 内存越界引起的内存错误问题
USB1.1 SIE:
(1) rx len % 4 == 1 实际 dma sram 会少 1 byte , 即 rx len - 1 (USB1.1驱动已修复)
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
USB2.0 SIE:
(1) rx len % 4 == 1 实际 dma sram 会多 2 byte , 即 rx len + 2
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "hal/usb_device.h"
#include "dev/usb/usb11_v0/hgusb11_v0_host_api.h"
#ifdef RT_USBH_UVC
#include "usbh_video.h"
#endif
#ifdef RT_USBH_UAC
#include "usbh_audio.h"
#endif
#define USB11_HOST_MAX_PIPE 3
typedef struct {
struct usb_device *usb;
uhcd_t hcd;
rt_uint32_t pipe_in_index; // 按bit记录主控可用端点
rt_uint32_t pipe_out_index;
struct os_event trx_lock;
struct os_event trx_done;
} usb_core_instance;
static usb_core_instance _hg_usbh;
static volatile rt_bool_t connect_status = RT_FALSE;
#define USBH_REGISTER_FLAG BIT(1)
static volatile rt_uint32_t usbh_flag = 0;
static rt_uint32_t hg_usbh_irq_hdl(rt_uint32_t irq, rt_uint32_t param1, rt_uint32_t param2, rt_uint32_t param3)
{
#if defined(RT_USBH_UVC) || defined(RT_USBH_UAC)
struct hgusb11_host *p_dev = (struct hgusb11_host *)dev_get(HG_USB11HOST_DEVID);
#endif
usb_core_instance *core = (usb_core_instance *)param1;
rt_uint32_t usb_ep = param2 & 0xF;
switch (irq) {
case USB_DEV_RESET_IRQ:
break;
case USB_DEV_SUSPEND_IRQ:
break;
case USB_DEV_RESUME_IRQ:
break;
case USB_DEV_SOF_IRQ:
break;
case USB_DEV_CTL_IRQ:
break;
case USB_EP_RX_IRQ:
os_event_set(&core->trx_done, BIT(usb_ep+16), NULL);
if (connect_status) {
#ifdef RT_USBH_UVC
rtt_usbh_video_irq(p_dev, usb_ep, _hg_usbh.hcd);
#endif
#ifdef RT_USBH_UAC
//rtt_usbh_audio_irq(p_dev, irq, usb_ep);
#endif
} else {
hgusb11_v0_host_ep_abort(_hg_usbh.usb, USB_CORE_HOST_EP_RX, usb_ep);
hgusb11_v0_host_reset_ep_rxcsr(usb_ep);
rt_kprintf("usb11 connect status is NULL , stop in rx irq\n");
}
break;
case USB_EP_TX_IRQ:
os_event_set(&core->trx_done, BIT(usb_ep), NULL);
if (connect_status) {
#ifdef RT_USBH_UAC
//rtt_usbh_audio_irq(p_dev, irq, usb_ep);
#endif
} else {
hgusb11_v0_host_ep_abort(_hg_usbh.usb, USB_CORE_HOST_EP_TX, usb_ep);
hgusb11_v0_host_reset_ep_txcsr(usb_ep);
rt_kprintf("usb11 connect status is NULL , stop in tx irq\n");
}
break;
case USB_CONNECT:
if (hgusb11_v0_host_dev_speed_detect() && (usbh_flag & USBH_REGISTER_FLAG)) {
if (!connect_status) {
connect_status = RT_TRUE;
rt_kprintf("usb11 connected\r\n");
rt_usbh_root_hub_connect_handler(core->hcd, 1, RT_TRUE);
// hg_usb_connect_detect_using();
}
}
break;
case USB_DISCONNECT:
if (!hgusb11_v0_host_dev_speed_detect() && (usbh_flag & USBH_REGISTER_FLAG)) {
if (connect_status) {
connect_status = RT_FALSE;
rt_kprintf("usb11 disconnect\r\n");
rt_usbh_root_hub_disconnect_handler(core->hcd, 1);
// hg_usb_connect_detect_recfg();
}
}
break;
case USB_BABBLE:
break;
case USB_XACT_ERR:
break;
default:
break;
}
return 0;
}
static rt_err_t drv_reset_port(rt_uint8_t port)
{
rt_kprintf("usb11 reset port\r\n");
hgusb11_v0_host_reset();
hgusb11_v0_host_set_address( 0);
return RT_EOK;
}
static rt_uint8_t drv_get_free_pipe_index(rt_uint32_t *pipe_index)
{
rt_uint8_t idx;
for (idx = 1; idx <= USB11_HOST_MAX_PIPE; ++idx) {
if (!(*pipe_index & BIT(idx))) {
*pipe_index |= BIT(idx);
return idx;
}
}
return 0xff;
}
static inline void drv_free_pipe_index(rt_uint32_t *pipe_index, rt_uint8_t index)
{
*pipe_index &= ~BIT(index);
}
static inline rt_bool_t drv_pipe_index_check(rt_uint32_t *pipe_index, rt_uint8_t index)
{
return (*pipe_index & BIT(index)) ? RT_TRUE : RT_FALSE;
}
static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
{
struct usb_device *hgusb = (struct usb_device *)_hg_usbh.usb;
rt_int32_t ret = RET_OK;
int total_len = 0;
rt_size_t remain_size;
remain_size = nbytes;
rt_uint8_t * pbuffer = (rt_uint8_t *)buffer;
if (!connect_status) {
os_printf("connect_status is null\n");
return -RT_EIO;
}
if (pipe->pipe_index > USB11_HOST_MAX_PIPE) {
return -RT_EIO;
}
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
if (!drv_pipe_index_check(&_hg_usbh.pipe_in_index, pipe->pipe_index)) {
return -RT_EIO;
}
} else {
if (!drv_pipe_index_check(&_hg_usbh.pipe_out_index, pipe->pipe_index)) {
return -RT_EIO;
}
}
hgusb11_v0_host_set_address(pipe->inst->address);
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
// RX需要互斥
ret = os_event_wait(&_hg_usbh.trx_lock, BIT(16)/*BIT(pipe->pipe_index+16)*/, NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, osWaitForever);
if (ret) {
LOG_D("drv_pipe_xfer rx req timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
return RET_ERR;
}
// 端点0软件分包
if (pipe->pipe_index == 0) {
ret = hgusb11_v0_host_ep0_rx_kick(hgusb, pbuffer, remain_size);
if(ret == RET_OK) {
total_len = remain_size;
} else {
pipe->status = UPIPE_STATUS_ERROR;
total_len = ret;
}
} else {
os_event_clear(&_hg_usbh.trx_done, BIT(pipe->pipe_index+16), NULL);
hgusb11_v0_host_ep_rx_kick(hgusb, pipe->pipe_index, (rt_uint8_t*)buffer, remain_size);
ret = os_event_wait(&_hg_usbh.trx_done, BIT(pipe->pipe_index+16), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, (timeouts ? timeouts : osWaitForever));
if (ret) {
LOG_D("drv_pipe_xfer rx timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
hgusb11_v0_host_ep_abort(_hg_usbh.usb, USB_CORE_HOST_EP_RX, pipe->pipe_index);
}
else
{
usb_device_ioctl((struct usb_device *)hgusb, USB_HOST_GET_RX_DMA_LEN, pipe->pipe_index, (rt_uint32_t)&total_len);
if (hgusb11_v0_host_is_xact_err(pipe->pipe_index, USB_DIR_IN)
|| hgusb11_v0_host_is_rx_stall(pipe->pipe_index, USB_DIR_IN))
{
os_printf("%s usb1.1 rx dma err or stall, ep num is %d!!!!!\n",__FUNCTION__,pipe->pipe_index);
}
}
}
os_event_set(&_hg_usbh.trx_lock, BIT(16)/*BIT(pipe->pipe_index+16)*/, NULL);
} else {
ret = os_event_wait(&_hg_usbh.trx_lock, BIT(pipe->pipe_index), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, osWaitForever);
if (ret) {
LOG_D("drv_pipe_xfer tx req timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
return RET_ERR;
}
if (token == USBH_PID_SETUP) {
// setup包只会是ep0
ret = hgusb11_v0_host_ep0_tx_kick(hgusb, 1, buffer, remain_size);
if (ret != RET_OK) {
//TX ERROR
total_len = 0;
pipe->status = UPIPE_STATUS_ERROR;
} else {
total_len = 8;
}
} else {
// 端点0软件分包
if (pipe->pipe_index == 0) {
ret = hgusb11_v0_host_ep0_tx_kick(hgusb, 0, buffer, remain_size);
if(ret == RET_OK) {
total_len = remain_size;
} else {
total_len = ret;
pipe->status = UPIPE_STATUS_ERROR;
}
} else {
os_event_clear(&_hg_usbh.trx_done, BIT(pipe->pipe_index), NULL);
hgusb11_v0_host_ep_tx_kick(hgusb, pipe->pipe_index, (rt_uint8_t*)buffer, remain_size, 0);
ret = os_event_wait(&_hg_usbh.trx_done, BIT(pipe->pipe_index), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, (timeouts ? timeouts : osWaitForever));
if (ret) {
LOG_D("drv_pipe_xfer tx timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
hgusb11_v0_host_ep_abort(_hg_usbh.usb, USB_CORE_HOST_EP_TX, pipe->pipe_index);
total_len = RET_ERR;
} else {
total_len = remain_size;
if (hgusb11_v0_host_is_xact_err(pipe->pipe_index, USB_DIR_OUT)
|| hgusb11_v0_host_is_rx_stall(pipe->pipe_index, USB_DIR_OUT))
{
os_printf("%s usb1.1 tx dma err or stall, ep num is %d!!!!!\n",__FUNCTION__,pipe->pipe_index);
total_len = 0;
}
}
}
}
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index) | BIT(0), NULL);
}
if (pipe->callback != RT_NULL) pipe->callback(pipe);
// 其余情况都是和请求长度一致
return total_len;
}
static rt_err_t drv_open_pipe(upipe_t pipe)
{
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
if ((pipe->ep.bEndpointAddress & USB_EPNO_MASK) != 0) {
os_printf("drv open rx pipe\n");
pipe->pipe_index = drv_get_free_pipe_index(&_hg_usbh.pipe_in_index);
hgusb11_v0_host_ep_init(_hg_usbh.usb,
USB_CORE_HOST_EP_RX,
pipe->pipe_index,
(pipe->ep.bEndpointAddress & USB_EPNO_MASK),
(pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK),
pipe->ep.wMaxPacketSize);
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
{
hgusb11_v0_host_set_ep_interval(USB_CORE_HOST_EP_RX, pipe->pipe_index, pipe->ep.bInterval);
}
else
{
//NAK TIMEOUT
hgusb11_v0_host_set_ep_interval(USB_CORE_HOST_EP_RX, pipe->pipe_index, 0);
}
} else {
_hg_usbh.pipe_in_index |= BIT(0);
}
} else {
if ((pipe->ep.bEndpointAddress & USB_EPNO_MASK) != 0) {
os_printf("drv open tx pipe\n");
pipe->pipe_index = drv_get_free_pipe_index(&_hg_usbh.pipe_out_index);
hgusb11_v0_host_ep_init(_hg_usbh.usb,
USB_CORE_HOST_EP_TX,
pipe->pipe_index,
(pipe->ep.bEndpointAddress & USB_EPNO_MASK),
(pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK),
pipe->ep.wMaxPacketSize);
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
{
hgusb11_v0_host_set_ep_interval(USB_CORE_HOST_EP_TX, pipe->pipe_index, pipe->ep.bInterval);
}
else
{
//NAK TIMEOUT
hgusb11_v0_host_set_ep_interval(USB_CORE_HOST_EP_TX, pipe->pipe_index, 0);
}
} else {
_hg_usbh.pipe_out_index |= BIT(0);
}
}
rt_kprintf("open pipe idx:%d ep%d dir:%x\r\n",
pipe->pipe_index, (pipe->ep.bEndpointAddress & USB_EPNO_MASK), (pipe->ep.bEndpointAddress & USB_DIR_MASK));
return RT_EOK;
}
static rt_err_t drv_close_pipe(upipe_t pipe)
{
rt_kprintf("close pipe idx:%d\r\n", pipe->pipe_index);
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
drv_free_pipe_index(&_hg_usbh.pipe_in_index, pipe->pipe_index);
if (pipe->pipe_index != 0) {
hgusb11_v0_host_ep_abort(_hg_usbh.usb, USB_CORE_HOST_EP_RX, pipe->pipe_index);
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index+16), NULL);
}
} else {
drv_free_pipe_index(&_hg_usbh.pipe_out_index, pipe->pipe_index);
if (pipe->pipe_index != 0) {
hgusb11_v0_host_ep_abort(_hg_usbh.usb, USB_CORE_HOST_EP_TX, pipe->pipe_index);
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index), NULL);
}
}
return RT_EOK;
}
static const struct uhcd_ops _uhcd_ops = {
drv_reset_port,
drv_pipe_xfer,
drv_open_pipe,
drv_close_pipe,
};
rt_err_t hg_usb11h_register(rt_uint32_t devid)
{
uhcd_t uhcd = RT_NULL;
uhcd = (uhcd_t)dev_get(devid);
if (uhcd == RT_NULL) {
uhcd = (uhcd_t)os_zalloc(sizeof(struct uhcd));
if (uhcd == RT_NULL) {
rt_kprintf("uhcd malloc failed\r\n");
return -RT_ENOMEM;
}
os_printf("%s %d\n",__FUNCTION__,__LINE__);
uhcd->ops = (uhcd_ops_t)&_uhcd_ops;
uhcd->num_ports = 1;
dev_register(devid, (struct dev_obj *)uhcd);
os_memset(&_hg_usbh, 0, sizeof(usb_core_instance));
_hg_usbh.hcd = uhcd;
os_event_init(&_hg_usbh.trx_done);
os_event_init(&_hg_usbh.trx_lock);
os_event_set(&_hg_usbh.trx_lock, 0xffffffff, NULL);
_hg_usbh.usb = (struct usb_device *)dev_get(HG_USB11HOST_DEVID);
RT_ASSERT(_hg_usbh.usb);
usbh_flag |= USBH_REGISTER_FLAG;
usb_device_open(_hg_usbh.usb, NULL);
usb_device_request_irq(_hg_usbh.usb, hg_usbh_irq_hdl, (rt_uint32_t)&_hg_usbh);
rt_usb_host_init(devid, "usb11_host");
}
return RT_EOK;
}
rt_err_t hg_usb11h_unregister(rt_uint32_t devid)
{
uhcd_t uhc;
uhc = (uhcd_t)dev_get(devid);
if (uhc) {
printf("%s %d\n",__FUNCTION__,__LINE__);
usbh_flag &= ~USBH_REGISTER_FLAG;
if(connect_status) {
connect_status = RT_FALSE;
rt_usbh_root_hub_disconnect_handler(_hg_usbh.hcd, 1);
}
rt_usb_host_deinit(devid);
if(_hg_usbh.usb)
{
usb_device_close(_hg_usbh.usb);
os_event_del(&_hg_usbh.trx_done);
os_event_del(&_hg_usbh.trx_lock);
_hg_usbh.usb = RT_NULL;
}
if(_hg_usbh.hcd)
{
dev_unregister((struct dev_obj *)_hg_usbh.hcd);
os_free(_hg_usbh.hcd);
_hg_usbh.hcd = RT_NULL;
}
}
return RT_EOK;
}

View File

@@ -0,0 +1,408 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-10-30 ZYH the first version
*/
/*
针对 USB DMA RX , 需做的内存预留大小为 4 字节, 防止 DMA 内存越界引起的内存错误问题
USB1.1 SIE:
(1) rx len % 4 == 1 实际 dma sram 会少 1 byte , 即 rx len - 1 (USB1.1驱动已修复)
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
USB2.0 SIE:
(1) rx len % 4 == 1 实际 dma sram 会多 2 byte , 即 rx len + 2
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
*/
#include "drv_usbd.h"
#include <rtthread.h>
#include "include/rttusb_device.h"
#include "dev/usb/hgusb20_v1_dev_api.h"
static struct ep_id _ep_pool[] =
{
{0x0, USB_EP_ATTR_TYPE_MASK, USB_DIR_INOUT, 64, ID_ASSIGNED },
{0x1, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x1, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0x2, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x2, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0x3, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x3, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0x4, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x4, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0x5, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x5, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0x6, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_IN, 1024, ID_UNASSIGNED},
{0x6, USB_EP_ATTR_TYPE_MASK+1, USB_DIR_OUT, 1024, ID_UNASSIGNED},
{0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED },
};
struct usb_device * _hg_pdc;
static struct udcd _hg_udc;
static rt_err_t _suspend(void);
static rt_err_t _wakeup(void);
static uint32 hal_pcd_bus_irq(uint32 irq, uint32 param1, uint32 param2, uint32 param3)
{
struct usb_device *p_usb_d = (struct usb_device *)param1;
struct hgusb20_dev *p_dev = (struct hgusb20_dev *)p_usb_d;
uint32 ep_num = param2 & 0xF;
uint32 len = param3;
LOG_D("irq:%d %x %d %x\r\n", irq, param1, param2, param3);
int32 ret_val = 1;
switch (irq) {
case USB_CONNECT: //7
rt_usbd_connect_handler(&_hg_udc);
break;
case USB_DISCONNECT://8
rt_usbd_disconnect_handler(&_hg_udc);
break;
case USB_DEV_RESET_IRQ://0
rt_usbd_reset_handler(&_hg_udc);
break;
case USB_DEV_SUSPEND_IRQ://1
_suspend();
break;
case USB_DEV_RESUME_IRQ://2
_wakeup();
break;
case USB_DEV_SOF_IRQ://3
rt_usbd_sof_handler(&_hg_udc);
break;
case USB_DEV_CTL_IRQ://4
ret_val = 0;
rt_usbd_ep0_setup_handler(&_hg_udc, (struct urequest *)p_dev->usb_ep0_rxbuf);
break;
case USB_EP_RX_IRQ://5
if (ep_num == 0) {
rt_usbd_ep0_out_handler(&_hg_udc, len);
} else {
rt_usbd_ep_out_handler(&_hg_udc, ep_num, len);
}
break;
case USB_EP_TX_IRQ://6
if (ep_num == 0) {
rt_usbd_ep0_in_handler(&_hg_udc);
} else {
rt_usbd_ep_in_handler(&_hg_udc, 0x80 | ep_num, len);
}
break;
default:
break;
}
return ret_val;
}
static rt_err_t _ep_set_stall(rt_uint8_t address)
{
LOG_D("rtt stall\r\n");
hgusb20_dev_stall_ep((struct hgusb20_dev *)_hg_pdc, address);
return RT_EOK;
}
static rt_err_t _ep_clear_stall(rt_uint8_t address)
{
hgusb20_dev_clear_ep((struct hgusb20_dev *)_hg_pdc, address);
return RT_EOK;
}
static rt_err_t _set_address(rt_uint8_t address)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, address);
hgusb20_dev_ep0_set_address((struct hgusb20_dev *)_hg_pdc, address);
return RT_EOK;
}
static rt_err_t _set_config(rt_uint8_t address)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, address);
hgusb20_dev_state_config((struct hgusb20_dev *)_hg_pdc);
return RT_EOK;
}
static rt_err_t _ep_enable(uep_t ep)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, ep->ep_desc->bEndpointAddress, ep->ep_desc->wMaxPacketSize);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
hgusb20_dev_ep_init((struct hgusb20_dev *)_hg_pdc, ep->ep_desc->bEndpointAddress,
ep->ep_desc->wMaxPacketSize, ep->ep_desc->bmAttributes);
return RT_EOK;
}
static rt_err_t _ep_disable(uep_t ep)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, ep->ep_desc->bEndpointAddress, ep->ep_desc->wMaxPacketSize);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
uint8_t ep_num = ep->ep_desc->bEndpointAddress & 0x7F;
if (0 == ep) {
hgusb20_dev_ep0_rx_abort((struct hgusb20_dev *)_hg_pdc);
hgusb20_dev_ep0_tx_abort((struct hgusb20_dev *)_hg_pdc);
} else {
if (ep->ep_desc->bEndpointAddress & USB_DIR_IN) {
hgusb20_ep_tx_abort((struct hgusb20_dev *)_hg_pdc, ep_num);
} else {
hgusb20_ep_rx_abort((struct hgusb20_dev *)_hg_pdc, ep_num);
}
}
//hgusb20_dev_ep_deinit(_hg_pdc, ep->ep_desc->bEndpointAddress);
return RT_EOK;
}
static rt_size_t _ep_read(rt_uint8_t address, void *buffer)
{
rt_size_t size = hgusb20_ep_get_sie_rx_len((struct hgusb20_dev *)_hg_pdc, (address & 0x7F));
RT_ASSERT(buffer != RT_NULL);
LOG_D("%s %d %d\r\n", __FUNCTION__, address, size);
address &= 0x7F;
if (address) {
/* EP1.. data buffer handle */
} else {
/* EP0.. data buffer handle */
os_memcpy(buffer, ((struct hgusb20_dev *)_hg_pdc)->usb_ep0_rxbuf, size);
}
return size;
}
static rt_size_t _ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, address, size);
address &= 0x7F;
if (address) {
hgusb20_dev_read(_hg_pdc, address, (uint8 *)buffer, size, 0);
} else {
#if 0
if (NULL == buffer) {
buffer = (void *)(((struct hgusb20_dev *)_hg_pdc)->usb_ep0_rxbuf);
}
if (0 == size) {
size = 64-1;
}
hgusb20_dev_ep0_rx((struct hgusb20_dev *)_hg_pdc, buffer, size);
#else
if (buffer && size) {
hgusb20_dev_ep0_rx_rtt((struct hgusb20_dev *)_hg_pdc, buffer, size);
} else {
/* status not kick rx, the hardware auto control */
}
#endif
}
return size;
}
static rt_size_t _ep_write(rt_uint8_t address, void *buffer, rt_size_t size)
{
LOG_D("%s %d %d\r\n", __FUNCTION__, address, size);
address &= 0x7F;
//printf("address:%x buffer:%x size:%d\n",address,buffer,size);
if (address && buffer) {
hgusb20_dev_write(_hg_pdc, address, (uint8 *)buffer, size, 0);
} else {
hgusb20_dev_ep0_tx_rtt((struct hgusb20_dev *)_hg_pdc, buffer, size);
}
return size;
}
static rt_err_t _ep0_send_status(void)
{
LOG_D("%s\r\n", __FUNCTION__);
hgusb20_dev_ep0_clrrx_pkt0((struct hgusb20_dev *)_hg_pdc);
return RT_EOK;
}
static rt_err_t _suspend(void)
{
LOG_D("%s\r\n", __FUNCTION__);
return RT_EOK;
}
static rt_err_t _wakeup(void)
{
LOG_D("%s\r\n", __FUNCTION__);
return RT_EOK;
}
static rt_err_t _deinit(struct usb_device *usb)
{
hgusb20_dev_close(usb);
return RT_EOK;
}
static rt_err_t _init(struct usb_device *usb)
{
//struct hgusb20_dev *dev = (struct hgusb20_dev *)usb;
//int32 ret = RET_OK;
// if (usb == NULL) {
// return NULL;
// }
//
// ret = pin_func(dev->dev.dev.dev_id, 1);
// if (ret) {
//// USB_DEV_ERR_PRINTF("hgsdio20 dev request io failed!\r\n");
// ASSERT(ret == RET_OK);
// return ret;
// }
//
// //SYSCTRL_REG_OPT(sysctrl_usb20_reset(););
// sysctrl_usb20_clk_open();
// hgusb20_dev_hw_init(dev);
usb_device_open(usb, (struct usb_device_cfg *)NULL);
//usb_device_ioctl(usb, USB_DEV_IO_CMD_AUTO_TX_NULL_PKT_ENABLE, USB_WIFI_TX_EP, 0);
usb_device_request_irq(usb, hal_pcd_bus_irq, (uint32)usb);
return RT_EOK;
}
const static struct udcd_ops _udc_ops =
{
_set_address,
_set_config,
_ep_set_stall,
_ep_clear_stall,
_ep_enable,
_ep_disable,
_ep_read_prepare,
_ep_read,
_ep_write,
_ep0_send_status,
_suspend,
_wakeup,
};
/**
* usage :
* 1、reg usb device in device.c hgusb20_dev_attach(HG_USBDEV_DEVID, &usb20_dev);
* 2、main init in main.c
* rt_usbd_class_list_init
* rt_usbd_winusb_class_register
*
*
* hg_usbd_register(HG_USB_DEV_CONTROLLER_DEVID);
*/
void hg_usbd_class_driver_register()
{
/* 若需同时注册多个device设备需定义宏RT_USB_DEVICE_COMPOSITE成复合设备 */
rt_uint32_t devid = HG_USB_DEV_CONTROLLER_DEVID;
rt_usbd_class_list_init(devid);
#ifdef RT_USB_DEVICE_VIDEO
rt_usbd_uvc_device_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_AUDIO_MIC
rt_usbd_uac_mic_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_AUDIO_SPEAKER
audio_speaker_init();
rt_usbd_uac_speaker_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_MSTORAGE
rt_usbd_msc_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_RNDIS
rt_usbd_rndis_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_HID
rt_usbd_hid_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_WINUSB
rt_usbd_winusb_class_register(devid);
#endif
#ifdef RT_USB_DEVICE_CDC
rt_usbd_vcom_class_register(devid);
#endif
}
int hg_usbd_register(rt_uint32_t devid)
{
struct usb_device *usb = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
_hg_pdc = usb;
rt_memset((void *)&_hg_udc, 0, sizeof(struct udcd));
_hg_udc.ops = &_udc_ops;
/* Register endpoint infomation */
_hg_udc.ep_pool = _ep_pool;
_hg_udc.ep0.id = &_ep_pool[0];
_hg_udc.device_is_hs = 1;
dev_register(devid, (struct dev_obj *)&_hg_udc);
rt_usb_device_init(devid, "usb20_device");
_init(usb);
return RT_EOK;
}
int hg_usbd_unregister(rt_uint32_t devid)
{
struct usb_device *usb = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
struct dev_obj *udc = (struct dev_obj *)dev_get(devid);
if(udc && _hg_pdc != RT_NULL){
printf("%s %d\n",__FUNCTION__,__LINE__);
// rt_usb_device_deinit(devid);
_deinit(usb);
//dev_unregister((struct dev_obj *)&_hg_udc);
_hg_pdc = RT_NULL;
}
return RT_EOK;
}
int hg_usbd_recover(rt_uint32_t devid)
{
struct usb_device *usb = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
struct dev_obj *udc = (struct dev_obj *)dev_get(devid);
if(udc){
_hg_pdc = usb;
// rt_usbd_core_init();
_init(usb);
}
return 0;
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-10-30 ZYH the first version
*/
#ifndef __HG_USBD_H__
#define __HG_USBD_H__
#include <rtthread.h>
void hg_usbd_class_driver_register();
int hg_usbd_register(rt_uint32_t devid);
int hg_usbd_unregister(rt_uint32_t devid);
int hg_usbd_recover(rt_uint32_t devid);
#endif

View File

@@ -0,0 +1,45 @@
#include "rtthread.h"
#include "include/rttusb_device.h"
#include "cdc_vcom.h"
int usbd_cdc_putc(struct rt_serial_device *serial, char c)
{
if (serial) {
return ((const struct rt_uart_ops *)serial->ops)->putc(serial, c);
}
return -RT_ERROR;
}
int usbd_cdc_getc(struct rt_serial_device *serial)
{
if (serial) {
return ((const struct rt_uart_ops *)serial->ops)->getc(serial);
}
return -RT_ERROR;
}
rt_err_t usbd_cdc_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
if (serial) {
return ((const struct rt_uart_ops *)serial->ops)->configure(serial, cfg);
}
return -RT_ERROR;
}
rt_err_t usbd_cdc_control(struct rt_serial_device *serial, int cmd, void *arg)
{
if (serial) {
return ((const struct rt_uart_ops *)serial->ops)->control(serial, cmd, arg);
}
return -RT_ERROR;
}
rt_ssize_t usbd_cdc_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, rt_uint32_t tx_flag)
{
if (serial) {
os_printf("%s %d\n",__FUNCTION__,__LINE__);
return ((const struct rt_uart_ops *)serial->ops)->transmit(serial, buf, size, tx_flag);
}
return -RT_ERROR;
}

View File

@@ -0,0 +1,11 @@
#ifndef __DRV_USBD_CDC_H__
#define __DRV_USBD_CDC_H__
#include "rtthread.h"
int usbd_cdc_putc(struct rt_serial_device *serial, char c);
int usbd_cdc_getc(struct rt_serial_device *serial);
rt_err_t usbd_cdc_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
rt_err_t usbd_cdc_control(struct rt_serial_device *serial, int cmd, void *arg);
rt_ssize_t usbd_cdc_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, rt_uint32_t tx_flag);
#endif

View File

@@ -0,0 +1,496 @@
/*
针对 USB DMA RX , 需做的内存预留大小为 4 字节, 防止 DMA 内存越界引起的内存错误问题
USB1.1 SIE:
(1) rx len % 4 == 1 实际 dma sram 会少 1 byte , 即 rx len - 1 (USB1.1驱动已修复)
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
USB2.0 SIE:
(1) rx len % 4 == 1 实际 dma sram 会多 2 byte , 即 rx len + 2
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "hal/usb_device.h"
#include "dev/usb/hgusb20_v1_dev_api.h"
#include "math.h"
#define USB_HOST_MAX_PIPE 6
typedef struct {
struct usb_device *usb;
uhcd_t hcd;
rt_uint32_t pipe_in_index; // 按bit记录主控可用端点
rt_uint32_t pipe_out_index;
struct os_event trx_lock;
struct os_event trx_done;
} usb_core_instance;
static usb_core_instance _hg_usbh;
static volatile rt_bool_t connect_status = RT_FALSE;
#define USBH_REGISTER_FLAG BIT(1)
static volatile rt_uint32_t usbh_flag = 0;
static rt_uint32_t hg_usbh_irq_hdl(rt_uint32_t irq, rt_uint32_t param1, rt_uint32_t param2, rt_uint32_t param3)
{
struct hgusb20_dev *p_dev = (struct hgusb20_dev *)dev_get(HG_USBDEV_DEVID);
usb_core_instance *core = (usb_core_instance *)param1;
rt_uint32_t usb_ep = param2 & 0xF;
//_os_printf("irq:%d\r\n", irq);
switch (irq) {
case USB_DEV_RESET_IRQ:
break;
case USB_DEV_SUSPEND_IRQ:
break;
case USB_DEV_RESUME_IRQ:
break;
case USB_DEV_SOF_IRQ:
break;
case USB_DEV_CTL_IRQ:
break;
case USB_EP_RX_IRQ:
os_event_set(&core->trx_done, BIT(usb_ep+16), NULL);
break;
case USB_EP_TX_IRQ:
os_event_set(&core->trx_done, BIT(usb_ep), NULL);
break;
case USB_CONNECT:
if (hgusb20_is_device_online(p_dev) && (usbh_flag & USBH_REGISTER_FLAG)) {
if (!connect_status) {
connect_status = RT_TRUE;
rt_kprintf("usb connected\r\n");
rt_usbh_root_hub_connect_handler(core->hcd, 1, RT_TRUE);
hg_usb_connect_detect_using();
}
}
break;
case USB_DISCONNECT:
if (!hgusb20_is_device_online(p_dev) && (usbh_flag & USBH_REGISTER_FLAG)) {
if (connect_status) {
connect_status = RT_FALSE;
rt_kprintf("usb disconnect\r\n");
rt_usbh_root_hub_disconnect_handler(core->hcd, 1);
hg_usb_connect_detect_recfg();
}
}
break;
case USB_BABBLE:
break;
case USB_XACT_ERR:
break;
default:
break;
}
return 0;
}
static rt_err_t drv_reset_port(rt_uint8_t port)
{
rt_kprintf("reset port\r\n");
hgusb20_host_reset((struct hgusb20_dev *)_hg_usbh.usb);
hgusb20_set_address((struct hgusb20_dev *)_hg_usbh.usb, 0);
return RT_EOK;
}
static rt_uint8_t drv_get_free_pipe_index(rt_uint32_t *pipe_index)
{
rt_uint8_t idx;
for (idx = 1; idx <= USB_HOST_MAX_PIPE; ++idx) {
if (!(*pipe_index & BIT(idx))) {
*pipe_index |= BIT(idx);
return idx;
}
}
return 0xff;
}
static inline void drv_free_pipe_index(rt_uint32_t *pipe_index, rt_uint8_t index)
{
*pipe_index &= ~BIT(index);
}
static inline rt_bool_t drv_pipe_index_check(rt_uint32_t *pipe_index, rt_uint8_t index)
{
if (index == 0) {
return RT_TRUE;
}
return (*pipe_index & BIT(index)) ? RT_TRUE : RT_FALSE;
}
static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
{
struct hgusb20_dev *hgusb = (struct hgusb20_dev *)_hg_usbh.usb;
rt_int32_t ret = RET_OK;
rt_bool_t first_pkg = RT_TRUE;
int total_len = 0;
rt_size_t remain_size;
rt_size_t send_size;
rt_size_t ret_size;
remain_size = nbytes;
rt_uint8_t * pbuffer = (rt_uint8_t *)buffer;
if (!connect_status) {
os_printf("connect_status is null\n");
return -RT_EIO;
}
if (pipe->pipe_index > USB_HOST_MAX_PIPE) {
return -RT_EIO;
}
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
if (!drv_pipe_index_check(&_hg_usbh.pipe_in_index, pipe->pipe_index)) {
return -RT_EIO;
}
} else {
if (!drv_pipe_index_check(&_hg_usbh.pipe_out_index, pipe->pipe_index)) {
return -RT_EIO;
}
}
pipe->status = UPIPE_STATUS_OK;
hgusb20_set_address(hgusb, pipe->inst->address);
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
// RX不用互斥
ret = os_event_wait(&_hg_usbh.trx_lock, BIT(pipe->pipe_index+16), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, osWaitForever);
if (ret) {
LOG_D("drv_pipe_xfer rx req timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
return RET_ERR;
}
// 端点0软件分包
if (pipe->pipe_index == 0) {
do {
send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size;
ret = hgusb20_host_ep0_rx(hgusb, pbuffer, first_pkg);
if (ret) {
pipe->status = UPIPE_STATUS_ERROR;
break;
}
first_pkg = RT_FALSE;
ret_size = hgusb->ep0_ptr.rx_len;
total_len += hgusb->ep0_ptr.rx_len;
if (ret_size == send_size) {
remain_size -= send_size;
pbuffer += send_size;
} else {
// 收到包小于packet size即短包应该不会大于吧提前结束
break;
}
} while (remain_size > 0);
} else {
os_event_clear(&_hg_usbh.trx_done, BIT(pipe->pipe_index+16), NULL);
hgusb20_ep_rx_kick(hgusb, pipe->pipe_index, (rt_uint32_t)buffer, nbytes);
ret = os_event_wait(&_hg_usbh.trx_done, BIT(pipe->pipe_index+16), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, (timeouts ? timeouts : osWaitForever));
if (ret) {
LOG_D("drv_pipe_xfer rx timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
hgusb20_ep_rx_abort(hgusb, pipe->pipe_index);
}
else
{
usb_device_ioctl((struct usb_device *)hgusb, USB_HOST_GET_RX_DMA_LEN, pipe->pipe_index, (rt_uint32_t)&total_len);
if (hgusb20_host_is_xact_err(hgusb, pipe->pipe_index, USB_DIR_IN)
|| hgusb20_host_is_rx_stall(hgusb, pipe->pipe_index, USB_DIR_IN))
{
os_printf("%s usb2.0 rx dma err or stall, ep num is %d!!!!!\n",__FUNCTION__,pipe->pipe_index);
}
}
}
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index+16), NULL);
} else {
// TX需要互斥
ret = os_event_wait(&_hg_usbh.trx_lock, BIT(pipe->pipe_index), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, osWaitForever);
if (ret) {
LOG_D("drv_pipe_xfer tx req timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
return RET_ERR;
}
if (token == USBH_PID_SETUP) {
// setup包只会是ep0
os_memcpy(&hgusb->usb_ctrl.cmd, buffer, nbytes);
ret = hgusb20_host_ep0_setup(hgusb);
if (ret) {
//TX ERROR
total_len = 0;
pipe->status = UPIPE_STATUS_ERROR;
} else {
total_len = 8;
}
} else {
// 端点0软件分包
if (pipe->pipe_index == 0) {
do {
send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size;
ret = hgusb20_host_ep0_tx(hgusb, buffer, send_size);
if (ret) {
pipe->status = UPIPE_STATUS_ERROR;
break;
}
total_len += send_size;
remain_size -= send_size;
pbuffer += send_size;
} while (remain_size > 0);
} else {
os_event_clear(&_hg_usbh.trx_done, BIT(pipe->pipe_index), NULL);
hgusb20_ep_tx_kick(hgusb, pipe->pipe_index, (rt_uint32_t)buffer, nbytes);
ret = os_event_wait(&_hg_usbh.trx_done, BIT(pipe->pipe_index), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, (timeouts ? timeouts : osWaitForever));
if (ret) {
LOG_D("drv_pipe_xfer tx timeout!\r\n");
total_len = 0;
pipe->status = UPIPE_STATUS_ERROR;
hgusb20_ep_tx_abort(hgusb, pipe->pipe_index);
} else {
total_len = nbytes;
if (hgusb20_host_is_xact_err(hgusb, pipe->pipe_index, USB_DIR_OUT)
|| hgusb20_host_is_rx_stall(hgusb, pipe->pipe_index, USB_DIR_OUT))
{
os_printf("%s usb2.0 tx dma err or stall, ep num is %d!!!!!\n",__FUNCTION__,pipe->pipe_index);
total_len = 0;
}
}
}
}
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index), NULL);
}
if (pipe->callback != RT_NULL) pipe->callback(pipe);
// 其余情况都是和请求长度一致
return total_len;
}
static rt_err_t drv_open_pipe(upipe_t pipe)
{
rt_uint32_t m;
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
if ((pipe->ep.bEndpointAddress & USB_EPNO_MASK) != 0) {
os_printf("drv open rx pipe\n");
pipe->pipe_index = drv_get_free_pipe_index(&_hg_usbh.pipe_in_index);
hgusb20_pipe_attr usb_pipe;
usb_pipe.dev_addr = pipe->inst->address;
usb_pipe.dev_hub_port = pipe->inst->port;
usb_pipe.u_usb_hub_addr.dev_hub_addr = 0;//hub_set_addr;
usb_pipe.u_usb_hub_addr.hub_mtt_en = 0;//usb_sw->hub_mtt_en;
usb_pipe.ep_host = pipe->pipe_index;
usb_pipe.ep_dev = (pipe->ep.bEndpointAddress & USB_EPNO_MASK);
usb_pipe.ep_type = (pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK);
usb_pipe.ep_speed = 0;//usb_sw->child[usb_sw->current_connect_port].speed;
usb_pipe.max_pkt_size = pipe->ep.wMaxPacketSize;
hgusb20_host_rx_pipe_combine((struct hgusb20_dev *)_hg_usbh.usb, &usb_pipe);
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
{
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_INT)
{
if (((struct hgusb20_dev *)_hg_usbh.usb)->usb_ctrl.bus_high_speed) {
m = log2(pipe->ep.bInterval) + 1;
os_printf("m = %d\r\n",m);
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_RX, m);
} else {
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_RX, pipe->ep.bInterval);
}
}
else
{
m = log2(pipe->ep.bInterval) + 1;
os_printf("m = %d\r\n",m);
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_RX, m);
}
}
else
{
//NAK TIMEOUT
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_RX, 0);
}
} else {
_hg_usbh.pipe_in_index |= BIT(0);
}
} else {
if ((pipe->ep.bEndpointAddress & USB_EPNO_MASK) != 0) {
os_printf("drv open tx pipe\n");
pipe->pipe_index = drv_get_free_pipe_index(&_hg_usbh.pipe_out_index);
hgusb20_pipe_attr usb_pipe;
usb_pipe.dev_addr = pipe->inst->address;
usb_pipe.dev_hub_port = pipe->inst->port;
usb_pipe.u_usb_hub_addr.dev_hub_addr = 0;//hub_set_addr;
usb_pipe.u_usb_hub_addr.hub_mtt_en = 0;//usb_sw->hub_mtt_en;
usb_pipe.ep_host = pipe->pipe_index;
usb_pipe.ep_dev = (pipe->ep.bEndpointAddress & USB_EPNO_MASK);
usb_pipe.ep_type = (pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK);
usb_pipe.ep_speed = 0;//usb_sw->child[usb_sw->current_connect_port].speed;
usb_pipe.max_pkt_size = pipe->ep.wMaxPacketSize;
hgusb20_host_tx_pipe_combine((struct hgusb20_dev *)_hg_usbh.usb, &usb_pipe);
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
{
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_INT)
{
if (((struct hgusb20_dev *)_hg_usbh.usb)->usb_ctrl.bus_high_speed) {
m = log2(pipe->ep.bInterval) + 1;
os_printf("m = %d\r\n",m);
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_TX, m);
} else {
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_TX, pipe->ep.bInterval);
}
}
else
{
m = log2(pipe->ep.bInterval) + 1;
os_printf("m = %d\r\n",m);
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_TX, m);
}
}
else
{
//NAK TIMEOUT
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_TX, 0);
}
} else {
_hg_usbh.pipe_out_index |= BIT(0);
}
}
rt_kprintf("open pipe idx:%d ep%d dir:%x\r\n",
pipe->pipe_index, (pipe->ep.bEndpointAddress & USB_EPNO_MASK), (pipe->ep.bEndpointAddress & USB_DIR_MASK));
return RT_EOK;
}
static rt_err_t drv_close_pipe(upipe_t pipe)
{
rt_kprintf("close pipe idx:%d\r\n", pipe->pipe_index);
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
drv_free_pipe_index(&_hg_usbh.pipe_in_index, pipe->pipe_index);
if (pipe->pipe_index != 0) {
hgusb20_ep_rx_abort((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index);
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index+16), NULL);
}
} else {
drv_free_pipe_index(&_hg_usbh.pipe_out_index, pipe->pipe_index);
if (pipe->pipe_index != 0) {
hgusb20_ep_tx_abort((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index);
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index), NULL);
}
}
return RT_EOK;
}
static rt_err_t drv_hub_port_set(uhub_param_t param)
{
hgusb20_pipe_attr usb_ep0_pipe;
usb_ep0_pipe.u_usb_hub_addr.dev_hub_addr = param->hub_addr;
usb_ep0_pipe.u_usb_hub_addr.hub_mtt_en = param->hub_mtt_en;
usb_ep0_pipe.dev_addr = param->dev_addr;
usb_ep0_pipe.dev_hub_port = param->dev_port;
switch (param->dev_speed)
{
case RTTUSB_DEV_LowSpeed:
usb_ep0_pipe.ep_speed = 0xC0;
break;
case RTTUSB_DEV_FullSpeed:
usb_ep0_pipe.ep_speed = 0x80;
break;
case RTTUSB_DEV_HighSpeed:
usb_ep0_pipe.ep_speed = 0x40;
break;
default:
break;
}
hgusb20_host_hub_ep0_mange((struct hgusb20_dev *)_hg_usbh.usb, &usb_ep0_pipe);
return RT_EOK;
}
static const struct uhcd_ops _uhcd_ops = {
drv_reset_port,
drv_pipe_xfer,
drv_open_pipe,
drv_close_pipe,
drv_hub_port_set,
};
rt_err_t hg_usbh_register(rt_uint32_t devid)
{
uhcd_t uhcd = RT_NULL;
uhcd = (uhcd_t)dev_get(devid);
if (uhcd == RT_NULL) {
uhcd = (uhcd_t)os_zalloc(sizeof(struct uhcd));
if (uhcd == RT_NULL) {
rt_kprintf("uhcd malloc failed\r\n");
return -RT_ENOMEM;
}
os_printf("%s %d\n",__FUNCTION__,__LINE__);
uhcd->ops = &_uhcd_ops;
uhcd->num_ports = 1;
dev_register(devid, (struct dev_obj *)uhcd);
os_memset(&_hg_usbh, 0, sizeof(usb_core_instance));
_hg_usbh.hcd = uhcd;
os_event_init(&_hg_usbh.trx_done);
os_event_init(&_hg_usbh.trx_lock);
os_event_set(&_hg_usbh.trx_lock, 0xffffffff, NULL);
_hg_usbh.usb = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
RT_ASSERT(_hg_usbh.usb);
usbh_flag |= USBH_REGISTER_FLAG;
usb_device_open(_hg_usbh.usb, NULL);
usb_device_request_irq(_hg_usbh.usb, hg_usbh_irq_hdl, (rt_uint32_t)&_hg_usbh);
rt_usb_host_init(devid, "usb20_host");
}
return RT_EOK;
}
rt_err_t hg_usbh_unregister(rt_uint32_t devid)
{
uhcd_t uhc;
uhc = (uhcd_t)dev_get(devid);
if (uhc) {
printf("%s %d\n",__FUNCTION__,__LINE__);
usbh_flag &= ~USBH_REGISTER_FLAG;
if(connect_status) {
connect_status = RT_FALSE;
rt_usbh_root_hub_disconnect_handler(_hg_usbh.hcd, 1);
}
rt_usb_host_deinit(devid);
if(_hg_usbh.usb)
{
usb_device_close(_hg_usbh.usb);
os_event_del(&_hg_usbh.trx_done);
os_event_del(&_hg_usbh.trx_lock);
_hg_usbh.usb = RT_NULL;
}
if(_hg_usbh.hcd)
{
dev_unregister((struct dev_obj *)_hg_usbh.hcd);
os_free(_hg_usbh.hcd);
_hg_usbh.hcd = RT_NULL;
}
}
return RT_EOK;
}

View File

@@ -0,0 +1,550 @@
/*
针对 USB DMA RX , 需做的内存预留大小为 4 字节, 防止 DMA 内存越界引起的内存错误问题
USB1.1 SIE:
(1) rx len % 4 == 1 实际 dma sram 会少 1 byte , 即 rx len - 1 (USB1.1驱动已修复)
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
USB2.0 SIE:
(1) rx len % 4 == 1 实际 dma sram 会多 2 byte , 即 rx len + 2
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "hal/usb_device.h"
#include "dev/usb/hgusb20_v1_dev_api.h"
#include "math.h"
#ifdef RT_USBH_UVC
#include "usbh_video.h"
#endif
#ifdef RT_USBH_UAC
#include "usbh_audio.h"
#endif
#define USB_HOST_MAX_PIPE 6
typedef struct {
struct usb_device *usb;
uhcd_t hcd;
rt_uint32_t pipe_in_index; // 按bit记录主控可用端点
rt_uint32_t pipe_out_index;
struct os_event trx_lock;
struct os_event trx_done;
} usb_core_instance;
static usb_core_instance _hg_usbh;
static volatile rt_bool_t connect_status = RT_FALSE;
#define USBH_REGISTER_FLAG BIT(1)
static volatile rt_uint32_t usbh_flag = 0;
static rt_uint32_t hg_usbh_irq_hdl(rt_uint32_t irq, rt_uint32_t param1, rt_uint32_t param2, rt_uint32_t param3)
{
struct hgusb20_dev *p_dev = (struct hgusb20_dev *)dev_get(HG_USBDEV_DEVID);
usb_core_instance *core = (usb_core_instance *)param1;
rt_uint32_t usb_ep = param2 & 0xF;
switch (irq) {
case USB_DEV_RESET_IRQ:
break;
case USB_DEV_SUSPEND_IRQ:
break;
case USB_DEV_RESUME_IRQ:
break;
case USB_DEV_SOF_IRQ:
break;
case USB_DEV_CTL_IRQ:
break;
case USB_EP_RX_IRQ:
os_event_set(&core->trx_done, BIT(usb_ep+16), NULL);
if (connect_status) {
#ifdef RT_USBH_UVC
rtt_usbh_video_irq(p_dev, usb_ep, _hg_usbh.hcd);
#endif
#ifdef RT_USBH_UAC
rtt_usbh_audio_irq(p_dev, irq, usb_ep);
#endif
} else {
hgusb20_ep_rx_abort(p_dev, usb_ep);
hgusb20_host_reset_ep_rxcsr(p_dev, usb_ep);
rt_kprintf("connect status is NULL , stop in rx irq\n");
}
break;
case USB_EP_TX_IRQ:
os_event_set(&core->trx_done, BIT(usb_ep), NULL);
if (connect_status) {
#ifdef RT_USBH_UAC
rtt_usbh_audio_irq(p_dev, irq, usb_ep);
#endif
} else {
hgusb20_ep_tx_abort(p_dev, usb_ep);
hgusb20_host_reset_ep_txcsr(p_dev, usb_ep);
rt_kprintf("connect status is NULL , stop in tx irq\n");
}
break;
case USB_CONNECT:
if (hgusb20_is_device_online(p_dev) && (usbh_flag & USBH_REGISTER_FLAG)) {
if (!connect_status) {
connect_status = RT_TRUE;
rt_kprintf("usb connected\r\n");
rt_usbh_root_hub_connect_handler(core->hcd, 1, RT_TRUE);
hg_usb_connect_detect_using();
}
}
break;
case USB_DISCONNECT:
if (!hgusb20_is_device_online(p_dev) && (usbh_flag & USBH_REGISTER_FLAG)) {
if (connect_status) {
connect_status = RT_FALSE;
rt_kprintf("usb disconnect\r\n");
rt_usbh_root_hub_disconnect_handler(core->hcd, 1);
hg_usb_connect_detect_recfg();
}
}
break;
case USB_BABBLE:
break;
case USB_XACT_ERR:
break;
default:
break;
}
return 0;
}
static rt_err_t drv_reset_port(rt_uint8_t port)
{
rt_kprintf("reset port\r\n");
hgusb20_host_reset((struct hgusb20_dev *)_hg_usbh.usb);
hgusb20_set_address((struct hgusb20_dev *)_hg_usbh.usb, 0);
return RT_EOK;
}
static rt_uint8_t drv_get_free_pipe_index(rt_uint32_t *pipe_index)
{
rt_uint8_t idx;
for (idx = 1; idx <= USB_HOST_MAX_PIPE; ++idx) {
if (!(*pipe_index & BIT(idx))) {
*pipe_index |= BIT(idx);
return idx;
}
}
return 0xff;
}
static inline void drv_free_pipe_index(rt_uint32_t *pipe_index, rt_uint8_t index)
{
*pipe_index &= ~BIT(index);
}
static inline rt_bool_t drv_pipe_index_check(rt_uint32_t *pipe_index, rt_uint8_t index)
{
if (index == 0) {
return RT_TRUE;
}
return (*pipe_index & BIT(index)) ? RT_TRUE : RT_FALSE;
}
rt_uint8_t drv_get_specific_pipe(rt_uint8_t index, rt_uint8_t in_or_out)
{
if(index <= USB_HOST_MAX_PIPE && index >= 0){
if(in_or_out == USB_DIR_IN){
os_printf("drv_get_specific_pipe in:%d\r\n",index);
_hg_usbh.pipe_in_index |= BIT(index);
return index;
} else {
os_printf("drv_get_specific_pipe out:%d\r\n",index);
_hg_usbh.pipe_out_index |= BIT(index);
return index;
}
} else
return 0xff;
}
void drv_free_specific_pipe(rt_uint8_t index, rt_uint8_t in_or_out)
{
os_printf("drv_free_specific_pipe:%d\r\n",index);
if(index <= USB_HOST_MAX_PIPE && index >= 0){
if(in_or_out == USB_DIR_IN)
_hg_usbh.pipe_in_index &= ~BIT(index);
else
_hg_usbh.pipe_out_index &= ~BIT(index);
}
}
static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
{
struct hgusb20_dev *hgusb = (struct hgusb20_dev *)_hg_usbh.usb;
rt_int32_t ret = RET_OK;
rt_bool_t first_pkg = RT_TRUE;
int total_len = 0;
rt_size_t remain_size;
rt_size_t send_size;
rt_size_t ret_size;
remain_size = nbytes;
rt_uint8_t * pbuffer = (rt_uint8_t *)buffer;
if (!connect_status) {
os_printf("connect_status is null\n");
return -RT_EIO;
}
if (pipe->pipe_index > USB_HOST_MAX_PIPE) {
return -RT_EIO;
}
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
if (!drv_pipe_index_check(&_hg_usbh.pipe_in_index, pipe->pipe_index)) {
return -RT_EIO;
}
} else {
if (!drv_pipe_index_check(&_hg_usbh.pipe_out_index, pipe->pipe_index)) {
return -RT_EIO;
}
}
pipe->status = UPIPE_STATUS_OK;
hgusb20_set_address(hgusb, pipe->inst->address);
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
// RX不用互斥
ret = os_event_wait(&_hg_usbh.trx_lock, BIT(pipe->pipe_index+16), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, osWaitForever);
if (ret) {
LOG_D("drv_pipe_xfer rx req timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
return RET_ERR;
}
// 端点0软件分包
if (pipe->pipe_index == 0) {
do {
send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size;
ret = hgusb20_host_ep0_rx(hgusb, pbuffer, first_pkg);
if (ret) {
pipe->status = UPIPE_STATUS_ERROR;
break;
}
first_pkg = RT_FALSE;
ret_size = hgusb->ep0_ptr.rx_len;
total_len += hgusb->ep0_ptr.rx_len;
if (ret_size == send_size) {
remain_size -= send_size;
pbuffer += send_size;
} else {
// 收到包小于packet size即短包应该不会大于吧提前结束
break;
}
} while (remain_size > 0);
} else {
os_event_clear(&_hg_usbh.trx_done, BIT(pipe->pipe_index+16), NULL);
hgusb20_ep_rx_kick(hgusb, pipe->pipe_index, (rt_uint32_t)buffer, nbytes);
ret = os_event_wait(&_hg_usbh.trx_done, BIT(pipe->pipe_index+16), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, (timeouts ? timeouts : osWaitForever));
if (ret) {
LOG_D("drv_pipe_xfer rx timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
hgusb20_ep_rx_abort(hgusb, pipe->pipe_index);
}
else
{
usb_device_ioctl((struct usb_device *)hgusb, USB_HOST_GET_RX_DMA_LEN, pipe->pipe_index, (rt_uint32_t)&total_len);
if (hgusb20_host_is_xact_err(hgusb, pipe->pipe_index, USB_DIR_IN)
|| hgusb20_host_is_rx_stall(hgusb, pipe->pipe_index, USB_DIR_IN))
{
os_printf("%s usb2.0 rx dma err or stall, ep num is %d!!!!!\n",__FUNCTION__,pipe->pipe_index);
}
}
}
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index+16), NULL);
} else {
// TX需要互斥
ret = os_event_wait(&_hg_usbh.trx_lock, BIT(pipe->pipe_index), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, osWaitForever);
if (ret) {
LOG_D("drv_pipe_xfer tx req timeout!\r\n");
pipe->status = UPIPE_STATUS_ERROR;
return RET_ERR;
}
if (token == USBH_PID_SETUP) {
// setup包只会是ep0
os_memcpy(&hgusb->usb_ctrl.cmd, buffer, nbytes);
ret = hgusb20_host_ep0_setup(hgusb);
if (ret) {
//TX ERROR
total_len = 0;
pipe->status = UPIPE_STATUS_ERROR;
} else {
total_len = 8;
}
} else {
// 端点0软件分包
if (pipe->pipe_index == 0) {
do {
send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size;
ret = hgusb20_host_ep0_tx(hgusb, buffer, send_size);
if (ret) {
pipe->status = UPIPE_STATUS_ERROR;
break;
}
total_len += send_size;
remain_size -= send_size;
pbuffer += send_size;
} while (remain_size > 0);
} else {
os_event_clear(&_hg_usbh.trx_done, BIT(pipe->pipe_index), NULL);
hgusb20_ep_tx_kick(hgusb, pipe->pipe_index, (rt_uint32_t)buffer, nbytes);
ret = os_event_wait(&_hg_usbh.trx_done, BIT(pipe->pipe_index), NULL,
OS_EVENT_WMODE_AND|OS_EVENT_WMODE_CLEAR, (timeouts ? timeouts : osWaitForever));
if (ret) {
os_printf("drv_pipe_xfer tx timeout!\r\n");
total_len = 0;
pipe->status = UPIPE_STATUS_ERROR;
hgusb20_ep_tx_abort(hgusb, pipe->pipe_index);
} else {
total_len = nbytes;
if (hgusb20_host_is_xact_err(hgusb, pipe->pipe_index, USB_DIR_OUT)
|| hgusb20_host_is_rx_stall(hgusb, pipe->pipe_index, USB_DIR_OUT))
{
os_printf("%s usb2.0 tx dma err or stall, ep num is %d!!!!!\n",__FUNCTION__,pipe->pipe_index);
total_len = 0;
}
}
}
}
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index), NULL);
}
if (pipe->callback != RT_NULL) pipe->callback(pipe);
// 其余情况都是和请求长度一致
return total_len;
}
static rt_err_t drv_open_pipe(upipe_t pipe)
{
rt_uint32_t m;
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
if ((pipe->ep.bEndpointAddress & USB_EPNO_MASK) != 0) {
os_printf("drv open rx pipe\n");
pipe->pipe_index = drv_get_free_pipe_index(&_hg_usbh.pipe_in_index);
hgusb20_pipe_attr usb_pipe;
usb_pipe.dev_addr = pipe->inst->address;
usb_pipe.dev_hub_port = pipe->inst->port;
usb_pipe.u_usb_hub_addr.dev_hub_addr = 0;//hub_set_addr;
usb_pipe.u_usb_hub_addr.hub_mtt_en = 0;//usb_sw->hub_mtt_en;
usb_pipe.ep_host = pipe->pipe_index;
usb_pipe.ep_dev = (pipe->ep.bEndpointAddress & USB_EPNO_MASK);
usb_pipe.ep_type = (pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK);
usb_pipe.ep_speed = 0;//usb_sw->child[usb_sw->current_connect_port].speed;
usb_pipe.max_pkt_size = pipe->ep.wMaxPacketSize;
hgusb20_host_rx_pipe_combine((struct hgusb20_dev *)_hg_usbh.usb, &usb_pipe);
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
{
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_INT)
{
if (((struct hgusb20_dev *)_hg_usbh.usb)->usb_ctrl.bus_high_speed) {
m = log2(pipe->ep.bInterval) + 1;
os_printf("m = %d\r\n",m);
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_RX, m);
} else {
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_RX, pipe->ep.bInterval);
}
}
else
{
m = log2(pipe->ep.bInterval) + 1;
os_printf("m = %d\r\n",m);
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_RX, m);
}
}
else
{
//NAK TIMEOUT
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_RX, 0);
}
} else {
_hg_usbh.pipe_in_index |= BIT(0);
}
} else {
if ((pipe->ep.bEndpointAddress & USB_EPNO_MASK) != 0) {
os_printf("drv open tx pipe\n");
pipe->pipe_index = drv_get_free_pipe_index(&_hg_usbh.pipe_out_index);
hgusb20_pipe_attr usb_pipe;
usb_pipe.dev_addr = pipe->inst->address;
usb_pipe.dev_hub_port = pipe->inst->port;
usb_pipe.u_usb_hub_addr.dev_hub_addr = 0;//hub_set_addr;
usb_pipe.u_usb_hub_addr.hub_mtt_en = 0;//usb_sw->hub_mtt_en;
usb_pipe.ep_host = pipe->pipe_index;
usb_pipe.ep_dev = (pipe->ep.bEndpointAddress & USB_EPNO_MASK);
usb_pipe.ep_type = (pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK);
usb_pipe.ep_speed = 0;//usb_sw->child[usb_sw->current_connect_port].speed;
usb_pipe.max_pkt_size = pipe->ep.wMaxPacketSize;
hgusb20_host_tx_pipe_combine((struct hgusb20_dev *)_hg_usbh.usb, &usb_pipe);
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
{
if((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_INT)
{
if (((struct hgusb20_dev *)_hg_usbh.usb)->usb_ctrl.bus_high_speed) {
m = log2(pipe->ep.bInterval) + 1;
os_printf("m = %d\r\n",m);
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_TX, m);
} else {
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_TX, pipe->ep.bInterval);
}
}
else
{
m = log2(pipe->ep.bInterval) + 1;
os_printf("m = %d\r\n",m);
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_TX, m);
}
}
else
{
//NAK TIMEOUT
hgusb20_host_set_interval((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index, USB_CORE_HOST_EP_TX, 0);
}
} else {
_hg_usbh.pipe_out_index |= BIT(0);
}
}
rt_kprintf("open pipe idx:%d ep%d dir:%x\r\n",
pipe->pipe_index, (pipe->ep.bEndpointAddress & USB_EPNO_MASK), (pipe->ep.bEndpointAddress & USB_DIR_MASK));
return RT_EOK;
}
static rt_err_t drv_close_pipe(upipe_t pipe)
{
rt_kprintf("close pipe idx:%d\r\n", pipe->pipe_index);
if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
drv_free_pipe_index(&_hg_usbh.pipe_in_index, pipe->pipe_index);
if (pipe->pipe_index != 0) {
hgusb20_ep_rx_abort((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index);
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index+16), NULL);
}
} else {
drv_free_pipe_index(&_hg_usbh.pipe_out_index, pipe->pipe_index);
if (pipe->pipe_index != 0) {
hgusb20_ep_tx_abort((struct hgusb20_dev *)_hg_usbh.usb, pipe->pipe_index);
os_event_set(&_hg_usbh.trx_lock, BIT(pipe->pipe_index), NULL);
}
}
return RT_EOK;
}
static rt_err_t drv_hub_port_set(uhub_param_t param)
{
hgusb20_pipe_attr usb_ep0_pipe;
usb_ep0_pipe.u_usb_hub_addr.dev_hub_addr = param->hub_addr;
usb_ep0_pipe.u_usb_hub_addr.hub_mtt_en = param->hub_mtt_en;
usb_ep0_pipe.dev_addr = param->dev_addr;
usb_ep0_pipe.dev_hub_port = param->dev_port;
switch (param->dev_speed)
{
case RTTUSB_DEV_LowSpeed:
usb_ep0_pipe.ep_speed = 0x3;
break;
case RTTUSB_DEV_FullSpeed:
usb_ep0_pipe.ep_speed = 0x2;
break;
case RTTUSB_DEV_HighSpeed:
usb_ep0_pipe.ep_speed = 0x1;
break;
default:
break;
}
hgusb20_host_hub_ep0_mange((struct hgusb20_dev *)_hg_usbh.usb, &usb_ep0_pipe);
return RT_EOK;
}
static const struct uhcd_ops _uhcd_ops = {
drv_reset_port,
drv_pipe_xfer,
drv_open_pipe,
drv_close_pipe,
drv_hub_port_set,
};
rt_err_t hg_usbh_register(rt_uint32_t devid)
{
uhcd_t uhcd = RT_NULL;
uhcd = (uhcd_t)dev_get(devid);
if (uhcd == RT_NULL) {
uhcd = (uhcd_t)os_zalloc(sizeof(struct uhcd));
if (uhcd == RT_NULL) {
rt_kprintf("uhcd malloc failed\r\n");
return -RT_ENOMEM;
}
os_printf("%s %d\n",__FUNCTION__,__LINE__);
uhcd->ops = (uhcd_ops_t)&_uhcd_ops;
uhcd->num_ports = 1;
dev_register(devid, (struct dev_obj *)uhcd);
os_memset(&_hg_usbh, 0, sizeof(usb_core_instance));
_hg_usbh.hcd = uhcd;
os_event_init(&_hg_usbh.trx_done);
os_event_init(&_hg_usbh.trx_lock);
os_event_set(&_hg_usbh.trx_lock, 0xffffffff, NULL);
_hg_usbh.usb = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
RT_ASSERT(_hg_usbh.usb);
usbh_flag |= USBH_REGISTER_FLAG;
usb_device_open(_hg_usbh.usb, NULL);
usb_device_request_irq(_hg_usbh.usb, hg_usbh_irq_hdl, (rt_uint32_t)&_hg_usbh);
rt_usb_host_init(devid, "usb20_host");
}
return RT_EOK;
}
rt_err_t hg_usbh_unregister(rt_uint32_t devid)
{
uhcd_t uhc;
uhc = (uhcd_t)dev_get(devid);
if (uhc) {
printf("%s %d\n",__FUNCTION__,__LINE__);
usbh_flag &= ~USBH_REGISTER_FLAG;
if(connect_status) {
connect_status = RT_FALSE;
rt_usbh_root_hub_disconnect_handler(_hg_usbh.hcd, 1);
}
rt_usb_host_deinit(devid);
if(_hg_usbh.usb)
{
usb_device_close(_hg_usbh.usb);
os_event_del(&_hg_usbh.trx_done);
os_event_del(&_hg_usbh.trx_lock);
_hg_usbh.usb = RT_NULL;
}
if(_hg_usbh.hcd)
{
dev_unregister((struct dev_obj *)_hg_usbh.hcd);
os_free(_hg_usbh.hcd);
_hg_usbh.hcd = RT_NULL;
}
}
return RT_EOK;
}

View File

@@ -0,0 +1,214 @@
/*
USB 主从切换检测
*/
#include "sys_config.h"
#include "typesdef.h"
#include "list.h"
#include "dev.h"
#include "devid.h"
#include "dev/usb/hgusb20_v1_dev_api.h"
#include "osal/work.h"
#include "include/rttusb_host.h"
#include "include/rttusb_device.h"
#include "drv_usbd.h"
#include "lib/heap/sysheap.h"
enum {
USB_STATUS_NONE, //未连接
USB_STATUS_DEVICE, //当Device
USB_STATUS_HOST, //当Host
USB_STATUS_USING, //使用中
};
struct usb_connect_structure
{
struct os_work usb_detect_wk;
uint32_t usb_connect_status; //0无状态 1USB_STATUS_DEVICE 2USB_STATUS_HOST 3USB使用中
uint32_t usb_connect_last_status;
}hg_usb_detect;
rt_err_t hg_usbh_register(rt_uint32_t devid);
rt_err_t hg_usbh_unregister(rt_uint32_t devid);
extern struct hgusb20_dev usb20_dev;
static void hg_usb_detect_device_open()
{
uint32 mask = 0;
struct usb_device *p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
if(p_dev == NULL)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
mask = disable_irq();
hgusb20_dev_attach(HG_USBDEV_DEVID, &usb20_dev);
enable_irq(mask);
hg_usbd_recover(HG_USB_DEV_CONTROLLER_DEVID);
}else{
os_printf("%s p_dev is exist\n",__FUNCTION__);
}
}
static void hg_usb_detect_device_close()
{
struct usb_device *p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
if(p_dev)
{
os_printf("%s %d p_dev:%x\n",__FUNCTION__,__LINE__,p_dev);
dev_unregister((struct dev_obj *)p_dev);
}else{
os_printf("%s p_dev is NULL\n",__FUNCTION__);
}
}
static void hg_usb_detect_host_open()
{
uint32 mask = 0;
uint32_t ret;
struct usb_device *p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
if(p_dev == NULL)
{
mask = disable_irq();
ret = hgusb20_host_attach(HG_USBDEV_DEVID, &usb20_dev);
enable_irq(mask);
p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
hg_usbh_register(HG_USB_HOST_CONTROLLER_DEVID);
}else{
os_printf("%s p_dev is exist\n",__FUNCTION__);
}
}
static void hg_usb_detect_host_close()
{
struct usb_device *p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
if(p_dev)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
dev_unregister((struct dev_obj *)p_dev);
}else{
os_printf("%s p_dev is NULL\n",__FUNCTION__);
}
}
static void hg_usb_detect_init()
{
hg_usbh_unregister(HG_USB_HOST_CONTROLLER_DEVID);
hg_usbd_unregister(HG_USB_DEV_CONTROLLER_DEVID);
}
static int32 hg_usb_connect_detect_work(struct os_work *work)
{
uint8_t ret;
uint8_t detect_tem = USB_CONNECTED_NONE;
static uint32_t timeout = 0;
struct hgusb20_dev *p_dev = (struct hgusb20_dev *)dev_get(HG_USBDEV_DEVID);
if(p_dev == NULL)
{
os_printf("hg_usb_connect_detect_work: dev_get fail\n");
goto __exit;
}
if(hg_usb_detect.usb_connect_status == USB_STATUS_NONE)
{
timeout++;
}
else
{
timeout = 0;
}
switch(hg_usb_detect.usb_connect_status) {
case USB_STATUS_NONE:
if(timeout > 2)
{
hg_usb_detect_init(); //检测前关闭应用线程
while(1) //误检测判断
{
ret = hgusb20_connected(p_dev);
if(detect_tem != ret) {
detect_tem = ret;
} else {
break;
}
}
os_printf("USB_STATUS_NONE freemem:%d \r\n", sysheap_freesize(&sram_heap));
hg_usb_detect.usb_connect_status = detect_tem;
os_printf("===hgusb20_connected ret:%d===\n",detect_tem);
}
break;
case USB_STATUS_DEVICE: //检测到插入电脑,关闭主机模式,开启从机模式
hg_usb_detect_host_close();
hg_usb_detect_device_open();
os_printf("USB_STATUS_DEVICE freemem:%d \r\n", sysheap_freesize(&sram_heap));
hg_usb_detect.usb_connect_last_status = USB_STATUS_DEVICE;
hg_usb_detect.usb_connect_status = USB_STATUS_USING;
break;
case USB_STATUS_HOST: //检测到插入设备,关闭从机模式,开启主机模式
hg_usb_detect_device_close();
hg_usb_detect_host_open();
os_printf("USB_STATUS_HOST freemem:%d \r\n", sysheap_freesize(&sram_heap));
hg_usb_detect.usb_connect_last_status = USB_STATUS_HOST;
hg_usb_detect.usb_connect_status = USB_STATUS_USING;
break;
case USB_STATUS_USING:
if(hg_usb_detect.usb_connect_last_status == USB_STATUS_DEVICE) { //如果是从机模式,在这里检测是否脱离主机
ret = hgusb20_is_host_online(p_dev);
os_printf("hgusb20_is_host_online:%d\n",ret);
if(!ret) {
hg_usb_detect.usb_connect_status = USB_STATUS_NONE;
} else {
hg_usb_detect.usb_connect_status = USB_STATUS_USING;
}
}
os_sleep_ms(10);
break;
}
__exit:
os_run_work_delay(&hg_usb_detect.usb_detect_wk, 500); //重新检测的时间配置
return 0;
}
void hg_usb_connect_detect_using(void)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
hg_usb_detect.usb_connect_status = USB_STATUS_USING;
}
void hg_usb_connect_detect_recfg(void)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
hg_usb_detect.usb_connect_status = USB_STATUS_NONE;
}
void hg_usb_connect_detect_init(void)
{
/* RTT USB Device 未留有释放内存接口,避免重复申请空间,因而先初始化 USB Device */
/* 前面一定要在 devic.c 先调用 hgusb20_dev_attach */
/* 若需同时注册多个device设备需定义宏RT_USB_DEVICE_COMPOSITE成复合设备 */
/* 若要注册host设备请参考 usbhost.c 文件 */
hg_usbd_class_driver_register();
hg_usbd_register(HG_USB_DEV_CONTROLLER_DEVID);
OS_WORK_INIT(&hg_usb_detect.usb_detect_wk, hg_usb_connect_detect_work, 0);
os_run_work_delay(&hg_usb_detect.usb_detect_wk, 500);
}
void hg_usb_connect_detect_deinit(void)
{
os_work_cancle(&hg_usb_detect.usb_detect_wk, 1);
}

View File

@@ -0,0 +1,507 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-01 Yi Qiu first version
* 2012-12-12 heyuanjie87 change endpoint and function handler
* 2013-04-26 aozima add DEVICEQUALIFIER support.
* 2017-11-15 ZYH fix ep0 transform error
*/
#ifndef __USB_DEVICE_H__
#define __USB_DEVICE_H__
#include <rtthread.h>
#include "include/usb_common.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef RT_USB_DEVICE_COMPOSITE
#ifdef RT_USB_DEVICE_VIDEO
#define RT_USB_DEVICE_COMPOSITE
#endif
#endif
/* Vendor ID */
#ifdef USB_VENDOR_ID
#define _VENDOR_ID USB_VENDOR_ID
#else
#define _VENDOR_ID 0xA012
#endif
/* Product ID */
#ifdef USB_PRODUCT_ID
#define _PRODUCT_ID USB_PRODUCT_ID
#else
#define _PRODUCT_ID 0x8001
#endif
#ifndef MAX_INTF_STR
#define MAX_INTF_STR 20
#endif
#define USB_BCD_DEVICE 0x0200 /* USB Specification Release Number in Binary-Coded Decimal */
#define USB_BCD_VERSION 0x0200 /* USB 2.0 */
#define EP0_IN_ADDR 0x80
#define EP0_OUT_ADDR 0x00
#define EP_HANDLER(ep, func, size) RT_ASSERT(ep != RT_NULL); ep->handler(func, size)
#define EP_ADDRESS(ep) ep->ep_desc->bEndpointAddress
#define EP_MAXPACKET(ep) ep->ep_desc->wMaxPacketSize
#define FUNC_ENABLE(func) do{ \
if(func->ops->enable != RT_NULL && \
func->enabled == RT_FALSE) \
{ \
if(func->ops->enable(func) == RT_EOK) \
func->enabled = RT_TRUE; \
} \
}while(0)
#define FUNC_DISABLE(func) do{ \
if(func->ops->disable != RT_NULL && \
func->enabled == RT_TRUE) \
{ \
func->enabled = RT_FALSE; \
func->ops->disable(func); \
} \
}while(0)
#define RT_USBD_CLASS_CTRL_CONNECTED (RT_DEVICE_CTRL_BASE(USBDevice) + 0)
struct ufunction;
struct udevice;
struct uendpoint;
struct udevice;
struct uconfig;
typedef enum
{
/* request to read full count */
UIO_REQUEST_READ_FULL,
/* request to read any count */
UIO_REQUEST_READ_BEST,
/* request to write full count */
UIO_REQUEST_WRITE,
}UIO_REQUEST_TYPE;
struct udcd_ops
{
rt_err_t (*set_address)(rt_uint8_t address);
rt_err_t (*set_config)(rt_uint8_t address);
rt_err_t (*ep_set_stall)(rt_uint8_t address);
rt_err_t (*ep_clear_stall)(rt_uint8_t address);
rt_err_t (*ep_enable)(struct uendpoint* ep);
rt_err_t (*ep_disable)(struct uendpoint* ep);
rt_size_t (*ep_read_prepare)(rt_uint8_t address, void *buffer, rt_size_t size);
rt_size_t (*ep_read)(rt_uint8_t address, void *buffer);
rt_size_t (*ep_write)(rt_uint8_t address, void *buffer, rt_size_t size);
rt_err_t (*ep0_send_status)(void);
rt_err_t (*suspend)(void);
rt_err_t (*wakeup)(void);
};
struct ep_id
{
rt_uint8_t addr;
rt_uint8_t type;
rt_uint8_t dir;
rt_uint16_t maxpacket;
rt_uint8_t status;
};
typedef rt_err_t (*udep_handler_t)(struct ufunction* func, rt_size_t size);
struct uio_request
{
rt_list_t list;
UIO_REQUEST_TYPE req_type;
rt_uint8_t* buffer;
rt_size_t size;
rt_size_t remain_size;
};
typedef struct uio_request* uio_request_t;
struct uendpoint
{
rt_list_t list;
uep_desc_t ep_desc;
rt_list_t request_list;
struct uio_request request;
rt_uint8_t* buffer;
rt_bool_t stalled;
struct ep_id* id;
udep_handler_t handler;
rt_err_t (*rx_indicate)(struct udevice* dev, rt_size_t size);
};
typedef struct uendpoint* uep_t;
struct udcd
{
struct rt_device parent;
const struct udcd_ops* ops;
struct uendpoint ep0;
uep0_stage_t stage;
struct ep_id* ep_pool;
rt_uint8_t device_is_hs;
struct udevice* p_udevice;
struct uconfig* cfg;
rt_thread_t usb_thread;
struct rt_messagequeue usb_mq;
};
typedef struct udcd* udcd_t;
struct ualtsetting
{
rt_list_t list;
uintf_desc_t intf_desc;
void* desc;
rt_size_t desc_size;
rt_list_t ep_list;
};
typedef struct ualtsetting* ualtsetting_t;
typedef rt_err_t (*uintf_handler_t)(struct ufunction* func, ureq_t setup);
struct uinterface
{
rt_list_t list;
rt_uint8_t intf_num;
ualtsetting_t curr_setting;
rt_list_t setting_list;
uintf_handler_t handler;
};
typedef struct uinterface* uintf_t;
struct ufunction_ops
{
rt_err_t (*enable)(struct ufunction* func);
rt_err_t (*disable)(struct ufunction* func);
rt_err_t (*sof_handler)(struct ufunction* func);
};
typedef struct ufunction_ops* ufunction_ops_t;
struct ufunction
{
rt_list_t list;
ufunction_ops_t ops;
struct udevice* device;
udev_desc_t dev_desc;
void* user_data;
rt_bool_t enabled;
rt_list_t intf_list;
uintf_t intf[3];
ualtsetting_t setting[3];
uep_t ep[6];
};
typedef struct ufunction* ufunction_t;
struct uconfig
{
rt_list_t list;
struct uconfig_descriptor cfg_desc;
rt_list_t func_list;
};
typedef struct uconfig* uconfig_t;
struct udevice
{
rt_list_t list;
struct udevice_descriptor dev_desc;
struct usb_qualifier_descriptor * dev_qualifier;
usb_os_comp_id_desc_t os_comp_id_desc;
const char** str;
const char *str_intf[MAX_INTF_STR];
udevice_state_t state;
rt_list_t cfg_list;
uconfig_t curr_cfg;
rt_uint8_t nr_intf;
udcd_t dcd;
};
typedef struct udevice* udevice_t;
struct udclass
{
rt_list_t list;
ufunction_t (*rt_usbd_function_create)(udevice_t device);
void (*rt_usbd_function_delete)();
};
typedef struct udclass* udclass_t;
enum udev_msg_type
{
USB_MSG_SETUP_NOTIFY,
USB_MSG_DATA_NOTIFY,
USB_MSG_EP0_OUT,
USB_MSG_EP_CLEAR_FEATURE,
USB_MSG_SOF,
USB_MSG_RESET,
USB_MSG_PLUG_IN,
/* we don't need to add a "PLUG_IN" event because after the cable is
* plugged in(before any SETUP) the classed have nothing to do. If the host
* is ready, it will send RESET and we will have USB_MSG_RESET. So, a RESET
* should reset and run the class while plug_in is not. */
USB_MSG_PLUG_OUT,
};
typedef enum udev_msg_type udev_msg_type;
struct ep_msg
{
rt_size_t size;
rt_uint8_t ep_addr;
};
struct udev_msg
{
udev_msg_type type;
udcd_t dcd;
union
{
struct ep_msg ep_msg;
struct urequest setup;
} content;
};
typedef struct udev_msg* udev_msg_t;
int rt_usbd_class_list_init(rt_uint32_t devid);
int rt_usbd_class_list_deinit(rt_uint32_t devid);
udevice_t rt_usbd_device_new(void);
uconfig_t rt_usbd_config_new(void);
ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc,
ufunction_ops_t ops);
rt_err_t rt_usbd_function_release(ufunction_t func);
uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler);
uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler);
ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size);
rt_err_t rt_usbd_core_device_list_init();
rt_err_t rt_usbd_core_init(const char *dev, void **thread_t, void *usb_mq);
rt_err_t rt_usbd_core_deinit(void **thread_t, void *usb_mq);
rt_err_t rt_usb_device_init(rt_uint32_t devid, const char *dev);
rt_err_t rt_usb_device_deinit(rt_uint32_t devid);
rt_err_t rt_usbd_event_signal(struct udev_msg* msg);
rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd);
rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc);
rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring);
rt_err_t rt_usbd_device_set_interface_string(udevice_t device, int index, const char* string);
rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier);
rt_err_t rt_usbd_device_set_os_comp_id_desc(udevice_t device, usb_os_comp_id_desc_t os_comp_id_desc);
rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg);
rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func);
rt_err_t rt_usbd_class_register(udclass_t udclass, rt_uint32_t devid);
rt_err_t rt_usbd_class_driver_unregister(udclass_t udclass, rt_uint32_t devid);
udclass_t rt_usbd_class_driver_find(udclass_t udclass, rt_uint32_t devid);
rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf);
rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting);
rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep);
rt_err_t rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(usb_os_comp_id_desc_t os_comp_id_desc, usb_os_func_comp_id_desc_t os_func_comp_id_desc);
rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos);
rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value);
rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value);
udevice_t rt_usbd_find_device(udcd_t dcd);
uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value);
uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc);
uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr);
rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req);
rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size);
rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size,
rt_err_t (*rx_ind)(udevice_t device, rt_size_t size));
int audio_speaker_init(void);
int rt_usbd_uac_speaker_class_register(rt_uint32_t devid);
int rt_usbd_uac_mic_class_register(rt_uint32_t devid);
int rt_usbd_uvc_device_class_register(rt_uint32_t devid);
int rt_usbd_vcom_class_register(rt_uint32_t devid);
int rt_usbd_ecm_class_register(rt_uint32_t devid);
int rt_usbd_hid_class_register(rt_uint32_t devid);
int rt_usbd_msc_class_register(rt_uint32_t devid);
int rt_usbd_rndis_class_register(rt_uint32_t devid);
int rt_usbd_winusb_class_register(rt_uint32_t devid);
int rt_usbd_vcom_class_unregister(rt_uint32_t devid);
int rt_usbd_msc_class_unregister(rt_uint32_t devid);
#ifdef RT_USB_DEVICE_COMPOSITE
rt_err_t rt_usbd_function_set_iad(ufunction_t func, uiad_desc_t iad_desc);
#endif
rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index);
rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index);
rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep);
rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep);
rt_err_t rt_usbd_ep0_set_stall(udevice_t device);
rt_err_t rt_usbd_ep0_clear_stall(udevice_t device);
rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct urequest* setup);
rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd);
rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size);
rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size);
rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size);
rt_err_t rt_usbd_reset_handler(udcd_t dcd);
rt_err_t rt_usbd_connect_handler(udcd_t dcd);
rt_err_t rt_usbd_disconnect_handler(udcd_t dcd);
rt_err_t rt_usbd_sof_handler(udcd_t dcd);
rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep);
rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t address)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->set_address != RT_NULL);
return dcd->ops->set_address(address);
}
rt_inline rt_err_t dcd_set_config(udcd_t dcd, rt_uint8_t address)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->set_config != RT_NULL);
return dcd->ops->set_config(address);
}
rt_inline rt_err_t dcd_ep_enable(udcd_t dcd, uep_t ep)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_enable != RT_NULL);
return dcd->ops->ep_enable(ep);
}
rt_inline rt_err_t dcd_ep_disable(udcd_t dcd, uep_t ep)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_disable != RT_NULL);
return dcd->ops->ep_disable(ep);
}
rt_inline rt_size_t dcd_ep_read_prepare(udcd_t dcd, rt_uint8_t address, void *buffer,
rt_size_t size)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
if(dcd->ops->ep_read_prepare != RT_NULL)
{
return dcd->ops->ep_read_prepare(address, buffer, size);
}
else
{
return 0;
}
}
rt_inline rt_size_t dcd_ep_read(udcd_t dcd, rt_uint8_t address, void *buffer)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
if(dcd->ops->ep_read != RT_NULL)
{
return dcd->ops->ep_read(address, buffer);
}
else
{
return 0;
}
}
rt_inline rt_size_t dcd_ep_write(udcd_t dcd, rt_uint8_t address, void *buffer,
rt_size_t size)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_write != RT_NULL);
return dcd->ops->ep_write(address, buffer, size);
}
rt_inline rt_err_t dcd_ep0_send_status(udcd_t dcd)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep0_send_status != RT_NULL);
return dcd->ops->ep0_send_status();
}
rt_inline rt_err_t dcd_ep_set_stall(udcd_t dcd, rt_uint8_t address)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_set_stall != RT_NULL);
return dcd->ops->ep_set_stall(address);
}
rt_inline rt_err_t dcd_ep_clear_stall(udcd_t dcd, rt_uint8_t address)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_clear_stall != RT_NULL);
return dcd->ops->ep_clear_stall(address);
}
static rt_inline void usbd_os_proerty_descriptor_send(ufunction_t func, ureq_t setup, usb_os_proerty_t usb_os_proerty, rt_uint8_t number_of_proerty)
{
struct usb_os_property_header header;
static rt_uint8_t * data;
rt_uint8_t * pdata;
rt_uint8_t index,i;
if(data == RT_NULL)
{
header.dwLength = sizeof(struct usb_os_property_header);
header.bcdVersion = 0x0100;
header.wIndex = 0x05;
header.wCount = number_of_proerty;
for(index = 0;index < number_of_proerty;index++)
{
header.dwLength += usb_os_proerty[index].dwSize;
}
data = (rt_uint8_t *)rt_malloc(header.dwLength);
RT_ASSERT(data != RT_NULL);
pdata = data;
rt_memcpy((void *)pdata,(void *)&header,sizeof(struct usb_os_property_header));
pdata += sizeof(struct usb_os_property_header);
for(index = 0;index < number_of_proerty;index++)
{
rt_memcpy((void *)pdata,(void *)&usb_os_proerty[index],10);
pdata += 10;
for(i = 0;i < usb_os_proerty[index].wPropertyNameLength/2;i++)
{
*pdata = usb_os_proerty[index].bPropertyName[i];
pdata++;
*pdata = 0;
pdata++;
}
*((rt_uint32_t *)pdata) = usb_os_proerty[index].dwPropertyDataLength;
pdata += 4;
for(i = 0;i < usb_os_proerty[index].dwPropertyDataLength/2;i++)
{
*pdata = usb_os_proerty[index].bPropertyData[i];
pdata++;
*pdata = 0;
pdata++;
}
}
}
rt_usbd_ep0_write(func->device, data, setup->wLength);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,312 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-3-12 Yi Qiu first version
* 2021-02-23 Leslie Lee provide possibility for multi usb host
*/
#ifndef __RT_USB_HOST_H__
#define __RT_USB_HOST_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtthread.h>
#include "include/usb_common.h"
#define USB_MAX_DEVICE 0x05
#define USB_MAX_INTERFACE 0x08
#define USB_HUB_PORT_NUM 0x04
#define SIZEOF_USB_REQUEST 0x08
#define DEV_STATUS_IDLE 0x00
#define DEV_STATUS_BUSY 0x01
#define DEV_STATUS_ERROR 0x02
#define UPIPE_STATUS_OK 0x00
#define UPIPE_STATUS_STALL 0x01
#define UPIPE_STATUS_ERROR 0x02
#define USBH_PID_SETUP 0x00
#define USBH_PID_DATA 0x01
struct uhcd;
struct uhintf;
struct uhub;
struct upipe;
struct uclass_driver
{
rt_list_t list;
int class_code;
int subclass_code;
int vendor_id;
rt_err_t (*enable)(void* arg);
rt_err_t (*disable)(void* arg);
void* user_data;
};
typedef struct uclass_driver* ucd_t;
struct uprotocal
{
rt_list_t list;
int pro_id;
rt_err_t (*init)(void* arg);
rt_err_t (*callback)(void* arg);
};
typedef struct uprotocal* uprotocal_t;
struct uinstance
{
struct rt_device parent;
struct udevice_descriptor dev_desc;
ucfg_desc_t cfg_desc;
struct uhcd *hcd;
struct upipe * pipe_ep0_out;
struct upipe * pipe_ep0_in;
rt_list_t pipe;
rt_uint8_t status;
rt_uint8_t type;
rt_uint8_t index;
rt_uint8_t address;
rt_uint8_t speed;
rt_uint8_t max_packet_size;
rt_uint8_t port;
struct uhub* parent_hub;
struct uhintf* intf[USB_MAX_INTERFACE];
};
typedef struct uinstance* uinst_t;
struct uhintf
{
struct uinstance* device;
uintf_desc_t intf_desc;
ucd_t drv;
void *user_data;
};
struct upipe
{
rt_list_t list;
rt_uint8_t pipe_index;
rt_uint32_t status;
struct uendpoint_descriptor ep;
uinst_t inst;
func_callback callback;
void* user_data;
};
typedef struct upipe* upipe_t;
struct uhub
{
struct uhub_descriptor hub_desc;
rt_uint8_t num_ports;
rt_uint32_t port_status[USB_HUB_PORT_NUM];
struct uinstance* child[USB_HUB_PORT_NUM];
rt_bool_t is_roothub;
rt_uint8_t buffer[8];
struct uinstance* self;
struct uhcd *hcd;
};
typedef struct uhub* uhub_t;
struct uhub_param
{
rt_uint32_t hub_addr;
rt_uint32_t hub_mtt_en;
rt_uint32_t dev_addr;
rt_uint32_t dev_port;
rt_uint32_t dev_speed;
};
typedef struct uhub_param* uhub_param_t;
struct uhcd_ops
{
rt_err_t (*reset_port) (rt_uint8_t port);
int (*pipe_xfer) (upipe_t pipe, rt_uint8_t token, void* buffer, int nbytes, int timeout);
rt_err_t (*open_pipe) (upipe_t pipe);
rt_err_t (*close_pipe) (upipe_t pipe);
rt_err_t (*hub_port_set) (uhub_param_t param);
};
typedef struct uhcd_ops* uhcd_ops_t;
struct uhcd
{
struct rt_device parent;
uhcd_ops_t ops;
rt_uint8_t num_ports;
uhub_t roothub;
struct rt_messagequeue *usb_mq;
rt_thread_t thread;
rt_uint32_t thread_status;
rt_uint32_t devid;
};
typedef struct uhcd* uhcd_t;
enum uhost_msg_type
{
USB_MSG_CONNECT_CHANGE,
USB_MSG_CALLBACK,
USB_MSG_CONNECT_IRQ,
USB_MSG_DISCONNECT_IRQ,
USB_MSG_DELETE_THREAD,
};
typedef enum uhost_msg_type uhost_msg_type;
struct uhost_msg
{
uhost_msg_type type;
union
{
struct uhub* hub;
struct
{
func_callback function;
void *context;
}cb;
}content;
};
typedef struct uhost_msg* uhost_msg_t;
rt_err_t hg_usbh_register(rt_uint32_t devid);
rt_err_t hg_usbh_unregister(rt_uint32_t devid);
int hg_usbd_recover(rt_uint32_t devid);
/* usb host system interface */
rt_err_t rt_usb_host_init(uint32 devid, const char *dev);
rt_err_t rt_usb_host_deinit(uint32 devid);
void rt_usbh_hub_init(uhcd_t hcd, const char* dev);
void rt_usbh_hub_deinit(struct uhcd *hcd);
/* usb host core interface */
struct uinstance* rt_usbh_alloc_instance(uhcd_t uhcd);
rt_err_t rt_usbh_hub_alloc_ep0_pipe(uhub_t hub);
rt_err_t rt_usbh_attatch_instance(struct uinstance* device);
rt_err_t rt_usbh_detach_instance(struct uinstance* device);
rt_err_t rt_usbh_get_descriptor(struct uinstance* device, rt_uint8_t type, void* buffer, int nbytes);
rt_err_t rt_usbh_get_string_descriptor(uinst_t device, int intf, void* buffer, int nbytes);
rt_err_t rt_usbh_set_configure(struct uinstance* device, int config);
rt_err_t rt_usbh_set_address(struct uinstance* device);
rt_err_t rt_usbh_set_interface(struct uinstance* device, int intf);
rt_err_t rt_usbh_clear_feature(struct uinstance* device, int endpoint, int feature);
rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, uintf_desc_t* intf_desc);
rt_err_t rt_usbh_get_interface_associtaion_descriptor(ucfg_desc_t cfg_desc, int num, uiad_desc_t* iad_desc);
rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num, uep_desc_t* ep_desc);
/* usb class driver interface */
rt_err_t rt_usbh_class_driver_init(void);
rt_err_t rt_usbh_class_driver_register(ucd_t drv);
rt_err_t rt_usbh_class_driver_unregister(ucd_t drv);
rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args);
rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args);
ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code, int vendor_id);
/* usb class driver implement */
ucd_t rt_usbh_class_driver_hub(void);
ucd_t rt_usbh_class_driver_storage(void);
/* usb hub interface */
rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer,
rt_size_t size);
rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint32_t* buffer);
rt_err_t rt_usbh_hub_get_port_status(uhub_t uhub, rt_uint16_t port,
rt_uint32_t* buffer);
rt_err_t rt_usbh_hub_clear_port_feature(uhub_t uhub, rt_uint16_t port,
rt_uint16_t feature);
rt_err_t rt_usbh_hub_set_port_feature(uhub_t uhub, rt_uint16_t port,
rt_uint16_t feature);
rt_err_t rt_usbh_hub_reset_port(uhub_t uhub, rt_uint16_t port);
rt_err_t rt_usbh_event_signal(uhcd_t uhcd, struct uhost_msg* msg);
void rt_usbh_root_hub_connect_handler(struct uhcd *hcd, rt_uint8_t port, rt_bool_t isHS);
void rt_usbh_root_hub_disconnect_handler(struct uhcd *hcd, rt_uint8_t port);
void analysis_usb_dev_desc(udev_desc_t desc, uint32 desclen);
void analysis_usb_cfg_desc(ucfg_desc_t desc, uint32 desclen);
void analysis_usb_intf_desc(uintf_desc_t desc, uint32 desclen);
void analysis_usb_ep_desc(uep_desc_t ep_desc);
void analysis_usb_iad_desc(uiad_desc_t iad_desc);
/* usb host controller driver interface */
rt_inline rt_err_t rt_usb_instance_add_pipe(uinst_t inst, upipe_t pipe)
{
RT_ASSERT(inst != RT_NULL);
RT_ASSERT(pipe != RT_NULL);
rt_list_insert_before(&inst->pipe, &pipe->list);
return RT_EOK;
}
rt_inline upipe_t rt_usb_instance_find_pipe(uinst_t inst,rt_uint8_t ep_address)
{
rt_list_t * l;
for(l = inst->pipe.next;l != &inst->pipe;l = l->next)
{
if(rt_list_entry(l,struct upipe,list)->ep.bEndpointAddress == ep_address)
{
return rt_list_entry(l,struct upipe,list);
}
}
return RT_NULL;
}
rt_inline rt_err_t rt_usb_hub_ep0_open_pipe(uhcd_t hcd, uep_desc_t ep)
{
struct upipe pipe;
rt_memset(&pipe,0,sizeof(struct upipe));
rt_memcpy(&pipe.ep,ep,sizeof(struct uendpoint_descriptor));
return hcd->ops->open_pipe(&pipe);
}
rt_inline rt_err_t rt_usb_hcd_alloc_pipe(uhcd_t hcd, upipe_t* pipe, uinst_t inst, uep_desc_t ep)
{
*pipe = (upipe_t)rt_malloc(sizeof(struct upipe));
if(*pipe == RT_NULL)
{
return -RT_ERROR;
}
rt_memset(*pipe,0,sizeof(struct upipe));
(*pipe)->inst = inst;
rt_memcpy(&(*pipe)->ep,ep,sizeof(struct uendpoint_descriptor));
return hcd->ops->open_pipe(*pipe);
}
rt_inline void rt_usb_pipe_add_callback(upipe_t pipe, func_callback callback)
{
pipe->callback = callback;
}
rt_inline rt_err_t rt_usb_hcd_free_pipe(uhcd_t hcd, upipe_t pipe)
{
RT_ASSERT(pipe != RT_NULL);
hcd->ops->close_pipe(pipe);
rt_free(pipe);
return RT_EOK;
}
int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout);
rt_inline int rt_usb_hcd_setup_xfer(uhcd_t hcd, upipe_t pipe, ureq_t setup, int timeout)
{
return hcd->ops->pipe_xfer(pipe, USBH_PID_SETUP, (void *)setup, 8, timeout);
}
int rt_usb_hcd_hub_port_set(uhcd_t hcd, uhub_param_t param);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,627 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-01 Yi Qiu first version
* 2013-04-26 aozima add DEVICEQUALIFIER support.
* 2017-11-15 ZYH fix ep0 transform error
*/
#ifndef __USB_COMMON_H__
#define __USB_COMMON_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtthread.h>
#include "hal/usb_ch9.h"
#define RT_DEBUG_USB 0x00
#define USB_DYNAMIC 0x00
/*
针对 USB DMA RX , 需做的内存预留大小为 4 字节, 防止 DMA 内存越界引起的内存错误问题
USB1.1 SIE:
(1) rx len % 4 == 1 实际 dma sram 会少 1 byte , 即 rx len - 1 (USB1.1驱动已修复)
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
USB2.0 SIE:
(1) rx len % 4 == 1 实际 dma sram 会多 2 byte , 即 rx len + 2
(2) rx len % 4 == 2 实际 dma sram 会多 1 byte , 即 rx len + 1
(3) rx len % 4 == 0 || rx len % 4 == 3 实际 dma sram 长度与 rx len相同 , 即 rx len
*/
#define USB_RX_BUFF_RESERVE_SIZE (4) //接收缓存预留的大小(防止越界)
#define USB_CLASS_DEVICE 0x00
#ifndef _UAPI__LINUX_USB_CH9_H
//#define USB_CLASS_AUDIO 0x01
//#define USB_CLASS_HID 0x03
//#define USB_CLASS_PHYSICAL 0x05
#define USB_CLASS_IMAGE 0x06
//#define USB_CLASS_PRINTER 0x07
//#define USB_CLASS_MASS_STORAGE 0x08
#define USB_CLASS_HUB 0x09
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_MISC 0xef
#endif
#define USB_CLASS_CDC 0x02
#define USB_CLASS_APP_SPECIFIC 0xfe
#define USB_CLASS_WIRELESS 0xe0
#define USB_CLASS_DIAG_DEVICE 0xdc
#define USB_CLASS_HEALTHCARE 0x0f
#define USB_CLASS_SECURITY 0x0d
#define USB_CLASS_SMART_CARD 0x0b
#define USB_CLASS_VEND_SPECIFIC 0xff
#define USB_DESC_TYPE_DEVICE 0x01
#define USB_DESC_TYPE_CONFIGURATION 0x02
#define USB_DESC_TYPE_STRING 0x03
#define USB_DESC_TYPE_INTERFACE 0x04
#define USB_DESC_TYPE_ENDPOINT 0x05
#define USB_DESC_TYPE_DEVICEQUALIFIER 0x06
#define USB_DESC_TYPE_OTHERSPEED 0x07
#define USB_DESC_TYPE_IAD 0x0b
#define USB_DESC_TYPE_HID 0x21
#define USB_DESC_TYPE_REPORT 0x22
#define USB_DESC_TYPE_PHYSICAL 0x23
#define USB_DESC_TYPE_HUB 0x29
#define USB_DESC_LENGTH_DEVICE 0x12
#define USB_DESC_LENGTH_CONFIG 0x9
#define USB_DESC_LENGTH_IAD 0x8
#define USB_DESC_LENGTH_STRING 0x4
#define USB_DESC_LENGTH_INTERFACE 0x9
#define USB_DESC_LENGTH_ENDPOINT 0x7
#define USB_REQ_TYPE_STANDARD 0x00
#define USB_REQ_TYPE_CLASS 0x20
#define USB_REQ_TYPE_VENDOR 0x40
#define USB_REQ_TYPE_MASK 0x60
#define USB_REQ_TYPE_DIR_OUT 0x00
#define USB_REQ_TYPE_DIR_IN 0x80
#define USB_REQ_TYPE_DEVICE 0x00
#define USB_REQ_TYPE_INTERFACE 0x01
#define USB_REQ_TYPE_ENDPOINT 0x02
#define USB_REQ_TYPE_OTHER 0x03
#define USB_REQ_TYPE_RECIPIENT_MASK 0x1f
#define USB_FEATURE_ENDPOINT_HALT 0x00
#define USB_FEATURE_DEV_REMOTE_WAKEUP 0x01
#define USB_FEATURE_TEST_MODE 0x02
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_REQ_SET_ENCRYPTION 0x0D
#define USB_REQ_GET_ENCRYPTION 0x0E
#define USB_REQ_RPIPE_ABORT 0x0E
#define USB_REQ_SET_HANDSHAKE 0x0F
#define USB_REQ_RPIPE_RESET 0x0F
#define USB_REQ_GET_HANDSHAKE 0x10
#define USB_REQ_SET_CONNECTION 0x11
#define USB_REQ_SET_SECURITY_DATA 0x12
#define USB_REQ_GET_SECURITY_DATA 0x13
#define USB_REQ_SET_WUSB_DATA 0x14
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17
#define USB_STRING_LANGID_INDEX 0x00
#define USB_STRING_MANU_INDEX 0x01
#define USB_STRING_PRODUCT_INDEX 0x02
#define USB_STRING_SERIAL_INDEX 0x03
#define USB_STRING_CONFIG_INDEX 0x04
#define USB_STRING_INTERFACE_INDEX 0x05
#define USB_STRING_OS_INDEX 0x06
#define USB_STRING_MAX 0xff
#define USB_STRING_OS "MSFT100A"
#define USB_PID_OUT 0x01
#define USB_PID_ACK 0x02
#define USB_PID_DATA0 0x03
#define USB_PID_SOF 0x05
#define USB_PID_IN 0x09
#define USB_PID_NACK 0x0A
#define USB_PID_DATA1 0x0B
#define USB_PID_PRE 0x0C
#define USB_PID_SETUP 0x0D
#define USB_PID_STALL 0x0E
#define USB_EP_DESC_OUT 0x00
#define USB_EP_DESC_IN 0x80
#define USB_EP_DESC_NUM_MASK 0x0f
#define USB_EP_ATTR_CONTROL 0x00
#define USB_EP_ATTR_ISOC 0x01
#define USB_EP_ATTR_BULK 0x02
#define USB_EP_ATTR_INT 0x03
#define USB_EP_ATTR_TYPE_MASK 0x03
#define USB_EPNO_MASK 0x7f
#ifndef _UAPI__LINUX_USB_CH9_H
#define USB_DIR_OUT 0x00
#define USB_DIR_IN 0x80
#endif
#define USB_DIR_INOUT 0x40
#define USB_DIR_MASK 0x80
/* wMaxPacketSize in Endpoint Descriptor */
#define USB_MAXPACKETSIZE_SHIFT 0
#define USB_MAXPACKETSIZE_MASK (0x7ff << USB_MAXPACKETSIZE_SHIFT)
#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT 11
#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_NONE (0 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_ONE (1 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_TWO (2 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK (3 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
#define USB_GET_MAXPACKETSIZE(x) ((x & USB_MAXPACKETSIZE_MASK) >> USB_MAXPACKETSIZE_SHIFT)
#define USB_GET_MULT(x) ((x & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
#define ID_UNASSIGNED 0
#define ID_ASSIGNED 1
#define RH_GET_PORT_STATUS 0
#define RH_SET_PORT_STATUS 1
#define RH_CLEAR_PORT_FEATURE 2
#define RH_SET_PORT_FEATURE 3
#define USB_BUS_POWERED 0
#define USB_SELF_POWERED 1
#define USB_REMOTE_WAKEUP 1
#define USB_EP_HALT 0
/*
* Port feature numbers
*/
#define PORT_FEAT_CONNECTION 0
#define PORT_FEAT_ENABLE 1
#define PORT_FEAT_SUSPEND 2
#define PORT_FEAT_OVER_CURRENT 3
#define PORT_FEAT_RESET 4
#define PORT_FEAT_POWER 8
#define PORT_FEAT_LOWSPEED 9
#define PORT_FEAT_HIGHSPEED 10
#define PORT_FEAT_C_CONNECTION 16
#define PORT_FEAT_C_ENABLE 17
#define PORT_FEAT_C_SUSPEND 18
#define PORT_FEAT_C_OVER_CURRENT 19
#define PORT_FEAT_C_RESET 20
/*
The HcRhPortStatus[1:NDP] register is used to control and report port events on a per-port
basis. NumberDownstreamPorts represents the number of HcRhPortStatus registers that are
implemented in hardware. The lower word is used to reflect the port status, whereas the upper
word reflects the status change bits. Some status bits are implemented with special write behavior
(see below). If a transaction (token through handshake) is in progress when a write to change
port status occurs, the resulting port status change must be postponed until the transaction
completes. Reserved bits should always be written '0'.
*/
#define PORT_CCS 0x00000001UL /* R:CurrentConnectStatus - W:ClearPortEnable */
#define PORT_PES 0x00000002UL /* R:PortEnableStatus - W:SetPortEnable */
#define PORT_PSS 0x00000004UL /* R:PortSuspendStatus - W:SetPortSuspend */
#define PORT_POCI 0x00000008UL /* R:PortOverCurrentIndicator - W:ClearSuspendStatus */
#define PORT_PRS 0x00000010UL /* R:PortResetStatus - W: SetPortReset */
#define PORT_PPS 0x00000100UL /* R:PortPowerStatus - W: SetPortPower */
#define PORT_LSDA 0x00000200UL /* R:LowSpeedDeviceAttached - W:ClearPortPower */
#define PORT_HSDA 0x00000400UL /* R:HighSpeedDeviceAttached - W:ClearPortPower */
#define PORT_CCSC 0x00010000UL
#define PORT_PESC 0x00020000UL
#define PORT_PSSC 0x00040000UL
#define PORT_POCIC 0x00080000UL
#define PORT_PRSC 0x00100000UL
/*
*Hub Status & Hub Change bit masks
*/
#define HUB_STATUS_LOCAL_POWER 0x0001
#define HUB_STATUS_OVERCURRENT 0x0002
#define HUB_CHANGE_LOCAL_POWER 0x0001
#define HUB_CHANGE_OVERCURRENT 0x0002
#define USB_EP_ATTR(attr) (attr & USB_EP_ATTR_TYPE_MASK)
#define USB_EP_DESC_NUM(addr) (addr & USB_EP_DESC_NUM_MASK)
#define USB_EP_DIR(addr) ((addr & USB_DIR_MASK)>>7)
#define HID_REPORT_ID_KEYBOARD1 1
#define HID_REPORT_ID_KEYBOARD2 2
#define HID_REPORT_ID_KEYBOARD3 3
#define HID_REPORT_ID_KEYBOARD4 7
#define HID_REPORT_ID_MEDIA 4
#define HID_REPORT_ID_GENERAL 5
#define HID_REPORT_ID_MOUSE 6
/*
* Time of usb timeout
*/
#ifndef USB_TIMEOUT_BASIC
#define USB_TIMEOUT_BASIC (RT_TICK_PER_SECOND) /* 1s */
#endif
#ifndef USB_TIMEOUT_LONG
#define USB_TIMEOUT_LONG (RT_TICK_PER_SECOND * 5) /* 5s */
#endif
#ifndef USB_DEBOUNCE_TIME
#define USB_DEBOUNCE_TIME (RT_TICK_PER_SECOND / 5) /* 0.2s */
#endif
#define uswap_32(x) \
((((x) & 0xff000000) >> 24) | \
(((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | \
(((x) & 0x000000ff) << 24))
#define uswap_8(x) \
(((rt_uint16_t)(*((rt_uint8_t *)(x)))) + \
(((rt_uint16_t)(*(((rt_uint8_t *)(x)) + 1))) << 8))
typedef void (*func_callback)(void *context);
//typedef enum
//{
// USB_STATE_NOTATTACHED = 0,
// USB_STATE_ATTACHED,
// USB_STATE_POWERED,
// USB_STATE_RECONNECTING,
// USB_STATE_UNAUTHENTICATED,
// USB_STATE_DEFAULT,
// USB_STATE_ADDRESS,
// USB_STATE_CONFIGURED,
// USB_STATE_SUSPENDED
//}udevice_state_t;
typedef enum usb_device_state udevice_state_t;
typedef enum
{
STAGE_IDLE,
STAGE_SETUP,
STAGE_STATUS_IN,
STAGE_STATUS_OUT,
STAGE_DIN,
STAGE_DOUT
} uep0_stage_t;
#pragma pack(1)
struct usb_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
};
typedef struct usb_descriptor* udesc_t;
struct udevice_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint16_t bcdUSB;
rt_uint8_t bDeviceClass;
rt_uint8_t bDeviceSubClass;
rt_uint8_t bDeviceProtocol;
rt_uint8_t bMaxPacketSize0;
rt_uint16_t idVendor;
rt_uint16_t idProduct;
rt_uint16_t bcdDevice;
rt_uint8_t iManufacturer;
rt_uint8_t iProduct;
rt_uint8_t iSerialNumber;
rt_uint8_t bNumConfigurations;
};
typedef struct udevice_descriptor* udev_desc_t;
struct uconfig_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint16_t wTotalLength;
rt_uint8_t bNumInterfaces;
rt_uint8_t bConfigurationValue;
rt_uint8_t iConfiguration;
rt_uint8_t bmAttributes;
rt_uint8_t MaxPower;
rt_uint8_t data[2048];
};
typedef struct uconfig_descriptor* ucfg_desc_t;
struct uinterface_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint8_t bInterfaceNumber;
rt_uint8_t bAlternateSetting;
rt_uint8_t bNumEndpoints;
rt_uint8_t bInterfaceClass;
rt_uint8_t bInterfaceSubClass;
rt_uint8_t bInterfaceProtocol;
rt_uint8_t iInterface;
};
typedef struct uinterface_descriptor* uintf_desc_t;
/* Interface Association Descriptor (IAD) */
struct uiad_descriptor
{
rt_uint8_t bLength;
rt_uint8_t bDescriptorType;
rt_uint8_t bFirstInterface;
rt_uint8_t bInterfaceCount;
rt_uint8_t bFunctionClass;
rt_uint8_t bFunctionSubClass;
rt_uint8_t bFunctionProtocol;
rt_uint8_t iFunction;
};
typedef struct uiad_descriptor* uiad_desc_t;
struct uendpoint_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint8_t bEndpointAddress;
rt_uint8_t bmAttributes;
rt_uint16_t wMaxPacketSize;
rt_uint8_t bInterval;
};
typedef struct uendpoint_descriptor* uep_desc_t;
struct ustring_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint8_t String[64];
};
typedef struct ustring_descriptor* ustr_desc_t;
struct uhub_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t num_ports;
rt_uint16_t characteristics;
rt_uint8_t pwron_to_good; /* power on to power good */
rt_uint8_t current;
rt_uint8_t removable[8];
rt_uint8_t pwr_ctl[8];
};
typedef struct uhub_descriptor* uhub_desc_t;
/* USB_DESC_TYPE_DEVICEQUALIFIER: Device Qualifier descriptor */
//struct usb_qualifier_descriptor
//{
// rt_uint8_t bLength;
// rt_uint8_t bDescriptorType;
//
// rt_uint16_t bcdUSB; // TODO: big-endian.
// rt_uint8_t bDeviceClass;
// rt_uint8_t bDeviceSubClass;
// rt_uint8_t bDeviceProtocol;
// rt_uint8_t bMaxPacketSize0;
// rt_uint8_t bNumConfigurations;
// rt_uint8_t bRESERVED;
//} __attribute__ ((packed));
struct usb_os_header_comp_id_descriptor
{
rt_uint32_t dwLength;
rt_uint16_t bcdVersion;
rt_uint16_t wIndex;
rt_uint8_t bCount;
rt_uint8_t reserved[7];
};
typedef struct usb_os_header_comp_id_descriptor * usb_os_header_desc_t;
struct usb_os_property_header
{
rt_uint32_t dwLength;
rt_uint16_t bcdVersion;
rt_uint16_t wIndex;
rt_uint16_t wCount;
};
typedef struct usb_os_property_header * usb_os_property_header_t;
struct usb_os_proerty
{
rt_uint32_t dwSize;
rt_uint32_t dwPropertyDataType;
rt_uint16_t wPropertyNameLength;
const char * bPropertyName;
rt_uint32_t dwPropertyDataLength;
const char * bPropertyData;
};
typedef struct usb_os_proerty * usb_os_proerty_t;
// Value Description
// 1 A NULL-terminated Unicode String (REG_SZ)
// 2 A NULL-terminated Unicode String that includes environment variables (REG_EXPAND_SZ)
// 3 Free-form binary (REG_BINARY)
// 4 A little-endian 32-bit integer (REG_DWORD_LITTLE_ENDIAN)
// 5 A big-endian 32-bit integer (REG_DWORD_BIG_ENDIAN)
// 6 A NULL-terminated Unicode string that contains a symbolic link (REG_LINK)
// 7 Multiple NULL-terminated Unicode strings (REG_MULTI_SZ)
#define USB_OS_PROPERTY_TYPE_REG_SZ 0x01UL
#define USB_OS_PROPERTY_TYPE_REG_EXPAND_SZ 0x02UL
#define USB_OS_PROPERTY_TYPE_REG_BINARY 0x03UL
#define USB_OS_PROPERTY_TYPE_REG_DWORD_LITTLE_ENDIAN 0x04UL
#define USB_OS_PROPERTY_TYPE_REG_DWORD_BIG_ENDIAN 0x05UL
#define USB_OS_PROPERTY_TYPE_REG_LINK 0x06UL
#define USB_OS_PROPERTY_TYPE_REG_MULTI_SZ 0x07UL
#define USB_OS_PROPERTY_DESC(PropertyDataType,PropertyName,PropertyData) \
{\
.dwSize = sizeof(struct usb_os_proerty)-sizeof(const char *)*2\
+sizeof(PropertyName)*2+sizeof(PropertyData)*2,\
.dwPropertyDataType = PropertyDataType,\
.wPropertyNameLength = sizeof(PropertyName)*2,\
.bPropertyName = PropertyName,\
.dwPropertyDataLength = sizeof(PropertyData)*2,\
.bPropertyData = PropertyData\
}
#ifndef HID_SUB_DESCRIPTOR_MAX
#define HID_SUB_DESCRIPTOR_MAX 1
#endif
struct uhid_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint16_t bcdHID;
rt_uint8_t bCountryCode;
rt_uint8_t bNumDescriptors;
struct hid_descriptor_list
{
rt_uint8_t type;
rt_uint16_t wLength;
}Descriptor[HID_SUB_DESCRIPTOR_MAX];
};
typedef struct uhid_descriptor* uhid_desc_t;
struct hid_report
{
rt_uint8_t report_id;
rt_uint8_t report[63];
rt_uint8_t size;
};
typedef struct hid_report* hid_report_t;
extern void HID_Report_Received(hid_report_t report);
struct urequest
{
rt_uint8_t request_type;
rt_uint8_t bRequest;
rt_uint16_t wValue;
rt_uint16_t wIndex;
rt_uint16_t wLength;
};
typedef struct urequest* ureq_t;
#ifndef MIN
#define MIN(a, b) (a < b ? a : b)
#endif
#ifndef MAX
#define MAX(a, b) (a > b ? a : b)
#endif
/*
* the define related to mass storage
*/
#define USBREQ_GET_MAX_LUN 0xfe
#define USBREQ_MASS_STORAGE_RESET 0xff
#define SIZEOF_CSW 0x0d
#define SIZEOF_CBW 0x1f
#define SIZEOF_INQUIRY_CMD 0x24
#define SIZEOF_MODE_SENSE_6 0x4
#define SIZEOF_MODE_SENSE_10 0x4
#define SIZEOF_READ_CAPACITIES 0xc
#define SIZEOF_READ_CAPACITY 0x8
#define SIZEOF_REQUEST_SENSE 0x12
#define CBWFLAGS_DIR_M 0x80
#define CBWFLAGS_DIR_IN 0x80
#define CBWFLAGS_DIR_OUT 0x00
#define SCSI_TEST_UNIT_READY 0x00
#define SCSI_REQUEST_SENSE 0x03
#define SCSI_INQUIRY_CMD 0x12
#define SCSI_ALLOW_REMOVAL 0x1e
#define SCSI_MODE_SENSE_6 0x1a
#define SCSI_START_STOP 0x1b
#define SCSI_READ_CAPACITIES 0x23
#define SCSI_READ_CAPACITY 0x25
#define SCSI_READ_10 0x28
#define SCSI_WRITE_10 0x2a
#define SCSI_VERIFY_10 0x2f
#define SCSI_MODE_SENSE_10 0x5a
#define CBW_SIGNATURE 0x43425355
#define CSW_SIGNATURE 0x53425355
#define CBW_TAG_VALUE 0x12345678
struct ustorage_cbw
{
rt_uint32_t signature;
rt_uint32_t tag;
rt_uint32_t xfer_len;
rt_uint8_t dflags;
rt_uint8_t lun;
rt_uint8_t cb_len;
rt_uint8_t cb[16];
};
typedef struct ustorage_cbw* ustorage_cbw_t;
struct ustorage_csw
{
rt_uint32_t signature;
rt_uint32_t tag;
rt_int32_t data_reside;
rt_uint8_t status;
};
typedef struct ustorage_csw* ustorage_csw_t;
#pragma pack()
struct usb_os_comp_id_descriptor
{
struct usb_os_header_comp_id_descriptor head_desc;
rt_list_t func_desc;
};
typedef struct usb_os_comp_id_descriptor * usb_os_comp_id_desc_t;
struct usb_os_function_comp_id_descriptor
{
rt_list_t list;
rt_uint8_t bFirstInterfaceNumber;
rt_uint8_t reserved1;
rt_uint8_t compatibleID[8];
rt_uint8_t subCompatibleID[8];
rt_uint8_t reserved2[6];
};
typedef struct usb_os_function_comp_id_descriptor * usb_os_func_comp_id_desc_t;
/*
* USB device event loop thread configurations
*/
/* the stack size of USB thread */
#ifndef RT_USBD_THREAD_STACK_SZ
#define RT_USBD_THREAD_STACK_SZ 1024
#endif
/* the priority of USB thread */
#ifndef RT_USBD_THREAD_PRIO
#define RT_USBD_THREAD_PRIO (OS_TASK_PRIORITY_HIGH-1)
#endif
typedef enum
{
RTTUSB_DEV_NONE = 0,
RTTUSB_DEV_LowSpeed,
RTTUSB_DEV_FullSpeed,
RTTUSB_DEV_HighSpeed,
} usb_dev_speed_t;
void hg_usb_connect_detect_using(void);
void hg_usb_connect_detect_recfg(void);
void hg_usb_connect_detect_init(void);
void hg_usb_connect_detect_deinit(void);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
Import('RTT_ROOT')
from building import *
cwd = GetCurrentDir()
src = Split("""
core/usbdevice_core.c
core/usbdevice.c
""")
if GetDepend('RT_USB_DEVICE_CDC'):
src += Glob('class/cdc_vcom.c')
if GetDepend('RT_USB_DEVICE_HID'):
src += Glob('class/hid.c')
if GetDepend('RT_USB_DEVICE_MSTORAGE'):
src += Glob('class/mstorage.c')
if GetDepend('RT_USB_DEVICE_ECM'):
src += Glob('class/ecm.c')
if GetDepend('RT_USB_DEVICE_RNDIS'):
src += Glob('class/rndis.c')
if GetDepend('RT_USB_DEVICE_WINUSB'):
src += Glob('class/winusb.c')
if GetDepend('RT_USB_DEVICE_AUDIO_MIC'):
src += Glob('class/audio_mic.c')
if GetDepend('RT_USB_DEVICE_AUDIO_SPEAKER'):
src += Glob('class/audio_speaker.c')
CPPPATH = [cwd]
group = DefineGroup('rt_usbd', src, depend = ['RT_USING_USB_DEVICE'], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,651 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-09-07 flybreak the first version
*/
#include <rtthread.h>
#include "include/rttusb_device.h"
#ifdef RT_USB_DEVICE_AUDIO_MIC
#include "stream_define.h"
#include "lib/multimedia/msi.h"
#include "uaudioreg.h"
#define RECORD_SAMPLERATE 8000
#define RECORD_CHANNEL 1
#define RESOLUTION_BITS 16
#define RECORD_TIME 50 //ms
#define RESOLUTION_BYTE (RESOLUTION_BITS / 8)
#define RECORD_PER_MS_SZ ((RECORD_SAMPLERATE * RECORD_CHANNEL * RESOLUTION_BYTE) / 1000)
#define RECORD_BUFFER_SZ (RECORD_PER_MS_SZ * RECORD_TIME)
#if defined(RT_USBD_MIC_DEVICE_NAME)
#define MIC_DEVICE_NAME RT_USBD_MIC_DEVICE_NAME
#else
#define MIC_DEVICE_NAME "mic0"
#endif
#define UAC_USE_FEATURE_UNIT 1
#define EVENT_RECORD_START (1 << 0)
#define EVENT_RECORD_STOP (1 << 1)
#define EVENT_RECORD_DATA (1 << 2)
#define MIC_INTF_STR_INDEX 8
/*
* uac mic descriptor define
*/
#define UAC_CS_INTERFACE 0x24
#define UAC_CS_ENDPOINT 0x25
#define UAC_MAX_PACKET_SIZE RECORD_BUFFER_SZ
#define UAC_EP_MAX_PACKET_SIZE RECORD_PER_MS_SZ
#define UAC_CHANNEL_NUM RECORD_CHANNEL
struct uac_ac_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct usb_audio_control_descriptor hdr_desc;
struct usb_audio_input_terminal it_desc;
struct usb_audio_output_terminal ot_desc;
#if UAC_USE_FEATURE_UNIT
struct usb_audio_feature_unit feature_unit_desc;
#endif
};
struct uac_as_descriptor
{
struct uinterface_descriptor intf_desc;
struct usb_audio_streaming_interface_descriptor hdr_desc;
struct usb_audio_streaming_type1_descriptor format_type_desc;
struct uendpoint_descriptor ep_desc;
struct usb_audio_streaming_endpoint_descriptor as_ep_desc;
};
/*
* uac mic device type
*/
struct uac_audio_mic
{
rt_device_t dev;
rt_event_t event;
rt_uint8_t open_count;
rt_uint8_t *buffer;
rt_uint32_t buffer_index;
uep_t ep;
};
struct uac_audio_mic mic;
rt_align(4)
static struct udevice_descriptor dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
USB_CLASS_DEVICE, //bDeviceClass;
0x00, //bDeviceSubClass;
0x00, //bDeviceProtocol;
UAC_EP_MAX_PACKET_SIZE, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;Unused.
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_AUDIO, //bDeviceClass
0x00, //bDeviceSubClass
0x00, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
rt_align(4)
const static char *_ustring[] =
{
"Language",
"RT-Thread Team.",
"RT-Thread Audio Microphone",
"32021919830108",
"Configuration",
"Interface",
};
rt_align(4)
static struct uac_ac_descriptor ac_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x02,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOCONTROL,
0x00,
#ifdef RT_USB_DEVICE_COMPOSITE
MIC_INTF_STR_INDEX,
#else
0x00,
#endif
},
/* Header Descriptor */
{
sizeof(struct usb_audio_control_descriptor),
UAC_CS_INTERFACE,
UDESCSUB_AC_HEADER,
0x0100, /* Version: 1.00 */
0x001E, /* Total length: 30 */
0x01, /* Total number of interfaces: 1 */
{0x01}, /* Interface number: 1 */
},
/* Input Terminal Descriptor */
{
sizeof(struct usb_audio_input_terminal),
UAC_CS_INTERFACE,
UDESCSUB_AC_INPUT,
0x01, /* Terminal ID: 1 */
0x0201, /* Terminal Type: Microphone (0x0201) */
0x00, /* Assoc Terminal: 0 */
0x01, /* Number Channels: 1 */
0x0000, /* Channel Config: 0x0000 */
0x00, /* Channel Names: 0 */
0x00, /* Terminal: 0 */
},
/* Output Terminal Descriptor */
{
sizeof(struct usb_audio_output_terminal),
UAC_CS_INTERFACE,
UDESCSUB_AC_OUTPUT,
0x02, /* Terminal ID: 2 */
0x0101, /* Terminal Type: USB Streaming (0x0101) */
0x00, /* Assoc Terminal: 0 */
0x01, /* Source ID: 1 */
0x00, /* Terminal: 0 */
},
#if UAC_USE_FEATURE_UNIT
/* Feature unit Descriptor */
{
sizeof(struct usb_audio_feature_unit),
UAC_CS_INTERFACE,
UDESCSUB_AC_FEATURE,
0x02,
0x01,
0x01,
{0x43,0x00},
},
#endif
};
rt_align(4)
static struct uinterface_descriptor as_desc0 =
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
};
rt_align(4)
static struct uac_as_descriptor as_desc =
{
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x01,
0x01,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
},
/* General AS Descriptor */
{
sizeof(struct usb_audio_streaming_interface_descriptor),
UAC_CS_INTERFACE,
AS_GENERAL,
0x02, /* Terminal ID: 2 */
0x01, /* Interface delay in frames: 1 */
UA_FMT_PCM,
},
/* Format type i Descriptor */
{
sizeof(struct usb_audio_streaming_type1_descriptor),
UAC_CS_INTERFACE,
FORMAT_TYPE,
FORMAT_TYPE_I,
UAC_CHANNEL_NUM,
2, /* Subframe Size: 2 */
RESOLUTION_BITS,
0x01, /* Samples Frequence Type: 1 */
{0}, /* Samples Frequence */
},
/* Endpoint Descriptor */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
0x05,
UAC_EP_MAX_PACKET_SIZE,
0x04, //HS:0x04 FS:0x01
},
/* AS Endpoint Descriptor */
{
sizeof(struct usb_audio_streaming_endpoint_descriptor),
UAC_CS_ENDPOINT,
AS_GENERAL,
},
};
void mic_entry(void *parameter)
{
struct rt_audio_caps caps = {0};
rt_uint32_t e, index;
ufunction_t func = (ufunction_t)parameter;
void *buf = RT_NULL;
rt_uint32_t timeout = 0;
struct msi *audio_s = NULL;
struct framebuff *audio_f = NULL;
rt_uint32_t data_len = 0;
audio_s = msi_new(R_USB_AUDIO_MIC, 16, NULL);
if(!audio_s)
{
_os_printf("creat audio_s stream fail\n");
goto __exit;
}
audio_s->enable = 1;
while (1)
{
if (rt_event_recv(mic.event, EVENT_RECORD_START | EVENT_RECORD_STOP,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK)
{
continue;
}
if (e & EVENT_RECORD_START)
{
}else
{
continue;
}
os_printf("record start");
caps.udata.config.samplerate = RECORD_SAMPLERATE;
caps.udata.config.channels = RECORD_CHANNEL;
caps.udata.config.samplebits = RESOLUTION_BITS;
while (1)
{
audio_f = msi_get_fb(audio_s, 0);
if(audio_f)
{
data_len = audio_f->len;
buf = audio_f->data;
//os_printf("len:%d mid.buffer:%x\n",data_len,mic.buffer);
while(data_len)
{
if (rt_event_recv(mic.event, EVENT_RECORD_DATA | EVENT_RECORD_STOP,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK) {
printf("R");
continue;
}
if (e & EVENT_RECORD_STOP)
{
index = 0;
timeout = 0;
os_printf("EVENT RECORD STOP\n");
break;
}
if (e & EVENT_RECORD_DATA)
{
_os_printf("U");
if(data_len >= UAC_MAX_PACKET_SIZE)
{
os_memcpy(mic.buffer, buf + index, UAC_MAX_PACKET_SIZE);
mic.ep->request.buffer = mic.buffer;
mic.ep->request.size = UAC_MAX_PACKET_SIZE;
mic.ep->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
data_len -= UAC_MAX_PACKET_SIZE;
index += UAC_MAX_PACKET_SIZE;
}else{
os_memcpy(mic.buffer, buf + index, data_len);
mic.ep->request.buffer = mic.buffer;
mic.ep->request.size = data_len;
mic.ep->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
data_len = 0;
index = 0;
break;
}
}
}
if(audio_f)
{
msi_delete_fb(NULL, audio_f);
audio_f = RT_NULL;
}
index = 0;
timeout = 0;
if(e & EVENT_RECORD_STOP)
{
break;
}
}
else
{
timeout++;
_os_printf("n");
os_sleep_ms(1);
if(timeout > 100)
{
timeout = 0;
break;
}
}
}
LOG_D("record stop");
}
__exit:
if(audio_s)
{
msi_destroy(audio_s);
}
}
static rt_err_t _record_start(ufunction_t func)
{
rt_event_send(mic.event, EVENT_RECORD_START);
memset(mic.buffer, 1, 64);
mic.ep->request.buffer = mic.buffer;
mic.ep->request.size = RECORD_PER_MS_SZ;
mic.ep->request.req_type = UIO_REQUEST_WRITE;
os_printf("record start mic.buffer:%x ep.addr:%x\n",mic.buffer,EP_ADDRESS(mic.ep));
rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
mic.open_count = 0;
mic.open_count ++;
return 0;
}
static rt_err_t _record_stop(ufunction_t func)
{
mic.open_count --;
os_printf("%s mic.open_count:%d\n",__FUNCTION__,mic.open_count);
rt_event_send(mic.event, EVENT_RECORD_STOP);
return 0;
}
static rt_err_t _ep_data_in_handler(ufunction_t func, rt_size_t size)
{
RT_ASSERT(func != RT_NULL);
//os_printf("_ep_data_in_handler");
rt_event_send(mic.event, EVENT_RECORD_DATA);
return RT_EOK;
}
static rt_err_t _interface_as_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
os_printf("_interface_as_handler request_type:%x setup->bRequest:%x\n",(setup->request_type & USB_REQ_TYPE_MASK),setup->bRequest);
if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
switch (setup->bRequest)
{
case USB_REQ_GET_INTERFACE:
break;
case USB_REQ_SET_INTERFACE:
os_printf("set interface handler setup->wvalue:%d\n",setup->wValue);
if (setup->wValue == 1)
{
_record_start(func);
}
else if (setup->wValue == 0)
{
_record_stop(func);
}
break;
default:
LOG_D("unknown uac request 0x%x", setup->bRequest);
return -RT_ERROR;
}
}
return RT_EOK;
}
static rt_err_t _function_enable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
LOG_D("uac function enable");
return RT_EOK;
}
static rt_err_t _function_disable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
LOG_D("uac function disable");
_record_stop(func);
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure uac descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _uac_descriptor_config(struct uac_ac_descriptor *ac,
rt_uint8_t cintf_nr, struct uac_as_descriptor *as, rt_uint8_t sintf_nr)
{
ac->hdr_desc.baInterfaceNr[0] = sintf_nr;
#ifdef RT_USB_DEVICE_COMPOSITE
ac->iad_desc.bFirstInterface = cintf_nr;
#endif
return RT_EOK;
}
static rt_err_t _uac_samplerate_config(struct uac_as_descriptor *as, rt_uint32_t samplerate)
{
as->format_type_desc.tSamFreq[0 * 3 + 2] = samplerate >> 16 & 0xff;
as->format_type_desc.tSamFreq[0 * 3 + 1] = samplerate >> 8 & 0xff;
as->format_type_desc.tSamFreq[0 * 3 + 0] = samplerate & 0xff;
return RT_EOK;
}
/**
* This function will create a uac function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
ufunction_t rt_usbd_function_uac_mic_create(udevice_t device)
{
ufunction_t func;
uintf_t intf_ac, intf_as;
ualtsetting_t setting_as0;
ualtsetting_t setting_ac, setting_as;
struct uac_as_descriptor *as_desc_t;
/* parameter check */
RT_ASSERT(device != RT_NULL);
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, MIC_INTF_STR_INDEX, _ustring[2]);
#else
/* set usb device string description */
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a uac function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
//not support HS
//rt_usbd_device_set_qualifier(device, &dev_qualifier);
int audio_mic_init(ufunction_t func);
audio_mic_init(func);
/* create interface */
intf_ac = rt_usbd_interface_new(device, RT_NULL);
intf_as = rt_usbd_interface_new(device, _interface_as_handler);
/* create alternate setting */
setting_ac = rt_usbd_altsetting_new(sizeof(struct uac_ac_descriptor));
setting_as0 = rt_usbd_altsetting_new(sizeof(struct uinterface_descriptor));
setting_as = rt_usbd_altsetting_new(sizeof(struct uac_as_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(setting_ac, &ac_desc,
(rt_off_t) & ((struct uac_ac_descriptor *)0)->intf_desc);
rt_usbd_altsetting_config_descriptor(setting_as0, &as_desc0, 0);
rt_usbd_altsetting_config_descriptor(setting_as, &as_desc,
(rt_off_t) & ((struct uac_as_descriptor *)0)->intf_desc);
/* configure the uac interface descriptor */
_uac_descriptor_config(setting_ac->desc, intf_ac->intf_num, setting_as->desc, intf_as->intf_num);
_uac_samplerate_config(setting_as->desc, RECORD_SAMPLERATE);
/* create endpoint */
as_desc_t = (struct uac_as_descriptor *)setting_as->desc;
mic.ep = rt_usbd_endpoint_new(&as_desc_t->ep_desc, _ep_data_in_handler);
/* add the endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(setting_as, mic.ep);
/* add the alternate setting to the interface, then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_ac, setting_ac);
rt_usbd_set_altsetting(intf_ac, 0);
rt_usbd_interface_add_altsetting(intf_as, setting_as0);
rt_usbd_interface_add_altsetting(intf_as, setting_as);
rt_usbd_set_altsetting(intf_as, 0);
/* add the interface to the uac function */
rt_usbd_function_add_interface(func, intf_ac);
rt_usbd_function_add_interface(func, intf_as);
return func;
}
int audio_mic_init(ufunction_t func)
{
rt_thread_t mic_tid;
mic.event = rt_event_create("mic_event", RT_IPC_FLAG_FIFO);
if (mic.buffer == RT_NULL) {
mic.buffer = rt_malloc(RECORD_BUFFER_SZ);
}
if (mic.buffer == RT_NULL)
{
LOG_E("malloc failed");
return RT_ENOMEM;
}
mic_tid = rt_thread_create("mic_thread",
mic_entry, func,
1024,
OS_TASK_PRIORITY_NORMAL, 10);
if (mic_tid != RT_NULL)
rt_thread_startup(mic_tid);
return RT_EOK;
}
/*
* register uac class
*/
struct udclass uac_class =
{
.rt_usbd_function_create = rt_usbd_function_uac_mic_create
};
//需要初始化ADC的采样率与UAC一致
int rt_usbd_uac_mic_class_register(rt_uint32_t dev_id)
{
rt_usbd_class_register(&uac_class, dev_id);
return 0;
}
#endif

View File

@@ -0,0 +1,615 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-09-19 flybreak the first version
*/
//#include <rthw.h>
#include <rtthread.h>
#include "include/rttusb_device.h"
#ifdef RT_USB_DEVICE_AUDIO_SPEAKER
#include "stream_frame.h"
#include "uaudioreg.h"
#include "lib/multimedia/msi.h"
#define AUDIO_SAMPLERATE 8000
#define AUDIO_CHANNEL 1
#define RESOLUTION_BITS 16
#define AUDIO_INTERVAL_TIME 64 //ms
#define RESOLUTION_BYTE (RESOLUTION_BITS / 8)
#define AUDIO_PER_MS_SZ ((AUDIO_SAMPLERATE * AUDIO_CHANNEL * RESOLUTION_BYTE) / 1000)
#define AUDIO_BUFFER_SZ (AUDIO_PER_MS_SZ * AUDIO_INTERVAL_TIME)
#if defined(RT_USBD_SPEAKER_DEVICE_NAME)
#define SPEAKER_DEVICE_NAME RT_USBD_SPEAKER_DEVICE_NAME
#else
#define SPEAKER_DEVICE_NAME "sound0"
#endif
#define EVENT_AUDIO_START (1 << 0)
#define EVENT_AUDIO_STOP (1 << 1)
#define SPK_INTF_STR_INDEX 9
/*
* uac speaker descriptor define
*/
#define UAC_CS_INTERFACE 0x24
#define UAC_CS_ENDPOINT 0x25
#define UAC_MAX_PACKET_SIZE AUDIO_BUFFER_SZ
#define UAC_EP_MAX_PACKET_SIZE AUDIO_PER_MS_SZ
#define UAC_CHANNEL_NUM AUDIO_CHANNEL
struct uac_ac_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct usb_audio_control_descriptor hdr_desc;
struct usb_audio_input_terminal it_desc;
struct usb_audio_output_terminal ot_desc;
#if UAC_USE_FEATURE_UNIT
struct usb_audio_feature_unit feature_unit_desc;
#endif
};
struct uac_as_descriptor
{
struct uinterface_descriptor intf_desc;
struct usb_audio_streaming_interface_descriptor hdr_desc;
struct usb_audio_streaming_type1_descriptor format_type_desc;
struct uendpoint_descriptor ep_desc;
struct usb_audio_streaming_endpoint_descriptor as_ep_desc;
};
/*
* uac speaker device type
*/
struct uac_audio_speaker
{
rt_device_t dev;
rt_event_t event;
rt_uint8_t open_count;
rt_uint8_t *buffer;
rt_uint32_t buffer_index;
uep_t ep;
struct msi *msi;
struct fbpool tx_pool;
};
static struct uac_audio_speaker speaker;
rt_align(4)
static struct udevice_descriptor dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
USB_CLASS_DEVICE, //bDeviceClass;
0x00, //bDeviceSubClass;
0x00, //bDeviceProtocol;
UAC_EP_MAX_PACKET_SIZE, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;Unused.
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_AUDIO, //bDeviceClass
0x00, //bDeviceSubClass
0x00, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
rt_align(4)
const static char *_ustring[] =
{
"Language",
"RT-Thread Team.",
"RT-Thread Audio Speaker",
"32021919830108",
"Configuration",
"Interface",
};
rt_align(4)
static struct uac_ac_descriptor ac_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x02,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOCONTROL,
0x00,
#ifdef RT_USB_DEVICE_COMPOSITE
SPK_INTF_STR_INDEX,
#else
0x00,
#endif
},
/* Header Descriptor */
{
sizeof(struct usb_audio_control_descriptor),
UAC_CS_INTERFACE,
UDESCSUB_AC_HEADER,
0x0100, /* Version: 1.00 */
0x0027, /* Total length: 39 */
0x01, /* Total number of interfaces: 1 */
{0x01}, /* Interface number: 1 */
},
/* Input Terminal Descriptor */
{
sizeof(struct usb_audio_input_terminal),
UAC_CS_INTERFACE,
UDESCSUB_AC_INPUT,
0x01, /* Terminal ID: 1 */
0x0101, /* Terminal Type: USB Streaming (0x0101) */
0x00, /* Assoc Terminal: 0 */
0x01, /* Number Channels: 1 */
0x0000, /* Channel Config: 0x0000 */
0x00, /* Channel Names: 0 */
0x00, /* Terminal: 0 */
},
/* Output Terminal Descriptor */
{
sizeof(struct usb_audio_output_terminal),
UAC_CS_INTERFACE,
UDESCSUB_AC_OUTPUT,
0x02, /* Terminal ID: 2 */
0x0301, /* Terminal Type */
0x00, /* Assoc Terminal: 0 */
0x01, /* Source ID: 1 */
0x00, /* Terminal: 0 */
},
#if UAC_USE_FEATURE_UNIT
/* Feature unit Descriptor */
{
sizeof(struct usb_audio_feature_unit),
UAC_CS_INTERFACE,
UDESCSUB_AC_FEATURE,
0x02,
0x01
0x01,
0x00,
0x01,
},
#endif
};
rt_align(4)
static struct uinterface_descriptor as_desc0 =
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
};
rt_align(4)
static struct uac_as_descriptor as_desc =
{
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x01,
0x01,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
},
/* General AS Descriptor */
{
sizeof(struct usb_audio_streaming_interface_descriptor),
UAC_CS_INTERFACE,
AS_GENERAL,
0x01, /* Terminal ID: 1 */
0x01, /* Interface delay in frames: 1 */
UA_FMT_PCM,
},
/* Format type i Descriptor */
{
sizeof(struct usb_audio_streaming_type1_descriptor),
UAC_CS_INTERFACE,
FORMAT_TYPE,
FORMAT_TYPE_I,
UAC_CHANNEL_NUM,
2, /* Subframe Size: 2 */
RESOLUTION_BITS,
0x01, /* Samples Frequence Type: 1 */
{0}, /* Samples Frequence */
},
/* Endpoint Descriptor */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_OUT,
USB_EP_ATTR_ISOC,
UAC_EP_MAX_PACKET_SIZE,
0x04 , //HS:0x04 FS:0x01
},
/* AS Endpoint Descriptor */
{
sizeof(struct usb_audio_streaming_endpoint_descriptor),
UAC_CS_ENDPOINT,
AS_GENERAL,
},
};
static int32_t uac_speaker_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
{
int32_t ret = RET_OK;
struct uac_audio_speaker *speaker = (struct uac_msi_s *)msi->priv;
switch (cmd_id)
{
case MSI_CMD_POST_DESTROY:
{
fbpool_destroy(&speaker->tx_pool);
if(speaker) {
msi->priv = NULL;
}
}
break;
case MSI_CMD_PRE_DESTROY:
{
}
break;
case MSI_CMD_FREE_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
// os_printf("fb:%X\n",fb);
if (fb->data)
{
os_free(fb->data);
fb->data = NULL;
}
fbpool_put(&speaker->tx_pool, fb);
// 不需要内核去释放fb
ret = RET_OK + 1;
}
break;
}
return ret;
}
static int usbd_audio_spk_msi_init(struct uac_audio_speaker *speaker, rt_uint8_t fb_tx_num)
{
speaker->msi = msi_new(S_USB_MIC, 0, NULL);
if (!speaker->msi)
{
os_printf("creat speaker->msi stream fail\n");
return -RT_ERROR;
}
fbpool_init(&speaker->tx_pool, fb_tx_num);
speaker->msi->priv = speaker;
speaker->msi->action = uac_speaker_action;
speaker->msi->enable = 1;
/* MSI add output */
/* ... */
return RT_EOK;
}
static void usbd_audio_spk_msi_deinit(struct uac_audio_speaker *speaker)
{
if (speaker->msi)
{
msi_destroy(speaker->msi);
speaker->msi = NULL;
}
}
static int usbd_audio_spk_msi_output_fb(struct uac_audio_speaker *speaker, rt_uint8_t *buffer, rt_uint32_t size)
{
struct framebuff *fb = NULL;
fb = fbpool_get(&speaker->tx_pool, 0, speaker->msi);
if (fb)
{
fb->data = os_zalloc(size);
if (!fb->data)
{
os_printf("alloc fb data failed\n");
msi_delete_fb(NULL, fb);
fb = NULL;
return -RT_ERROR;
}
rt_memcpy(fb->data, buffer, size);
fb->mtype = SOUND;
fb->stype = SOUND_USB_SPK;
fb->len = size;
msi_output_fb(speaker->msi, fb);
}
else
{
os_printf("get src data_f failed\n");
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t _audio_start(ufunction_t func)
{
speaker.ep->request.buffer = speaker.buffer + speaker.buffer_index;
speaker.ep->request.size = UAC_MAX_PACKET_SIZE / 2;
speaker.ep->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(func->device, speaker.ep, &speaker.ep->request);
speaker.buffer_index += UAC_MAX_PACKET_SIZE / 2;
if (speaker.buffer_index >= UAC_MAX_PACKET_SIZE)
{
speaker.buffer_index = 0;
}
speaker.open_count ++;
rt_event_send(speaker.event, EVENT_AUDIO_START);
return 0;
}
static rt_err_t _audio_stop(ufunction_t func)
{
speaker.open_count --;
rt_event_send(speaker.event, EVENT_AUDIO_STOP);
return 0;
}
static rt_err_t _ep_data_handler(ufunction_t func, rt_size_t size)
{
RT_ASSERT(func != RT_NULL);
speaker.ep->request.buffer = speaker.buffer + speaker.buffer_index;
speaker.ep->request.size = UAC_MAX_PACKET_SIZE / 2;
speaker.ep->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(func->device, speaker.ep, &speaker.ep->request);
speaker.buffer_index += UAC_MAX_PACKET_SIZE / 2;
if (speaker.buffer_index >= UAC_MAX_PACKET_SIZE)
{
speaker.buffer_index = 0;
}
usbd_audio_spk_msi_output_fb(&speaker, speaker.buffer + speaker.buffer_index, UAC_MAX_PACKET_SIZE / 2);
return RT_EOK;
}
static rt_err_t _interface_as_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
LOG_D("_interface_as_handler");
if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
switch (setup->bRequest)
{
case USB_REQ_GET_INTERFACE:
break;
case USB_REQ_SET_INTERFACE:
LOG_D("set interface handler");
if (setup->wValue == 1)
{
_audio_start(func);
}
else if (setup->wValue == 0)
{
_audio_stop(func);
}
break;
default:
LOG_D("unknown uac request 0x%x", setup->bRequest);
return -RT_ERROR;
}
}
return RT_EOK;
}
static rt_err_t _function_enable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
LOG_D("uac function enable");
return RT_EOK;
}
static rt_err_t _function_disable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
LOG_D("uac function disable");
_audio_stop(func);
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure uac descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _uac_descriptor_config(struct uac_ac_descriptor *ac,
rt_uint8_t cintf_nr, struct uac_as_descriptor *as, rt_uint8_t sintf_nr)
{
ac->hdr_desc.baInterfaceNr[0] = sintf_nr;
#ifdef RT_USB_DEVICE_COMPOSITE
ac->iad_desc.bFirstInterface = cintf_nr;
#endif
return RT_EOK;
}
static rt_err_t _uac_samplerate_config(struct uac_as_descriptor *as, rt_uint32_t samplerate)
{
as->format_type_desc.tSamFreq[0 * 3 + 2] = samplerate >> 16 & 0xff;
as->format_type_desc.tSamFreq[0 * 3 + 1] = samplerate >> 8 & 0xff;
as->format_type_desc.tSamFreq[0 * 3 + 0] = samplerate & 0xff;
return RT_EOK;
}
/**
* This function will create a uac function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
ufunction_t rt_usbd_function_uac_speaker_create(udevice_t device)
{
ufunction_t func;
uintf_t intf_ac, intf_as;
ualtsetting_t setting_as0;
ualtsetting_t setting_ac, setting_as;
struct uac_as_descriptor *as_desc_t;
/* parameter check */
RT_ASSERT(device != RT_NULL);
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, SPK_INTF_STR_INDEX, _ustring[2]);
#else
/* set usb device string description */
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a uac function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
//not support HS
//rt_usbd_device_set_qualifier(device, &dev_qualifier);
/* create interface */
intf_ac = rt_usbd_interface_new(device, RT_NULL);
intf_as = rt_usbd_interface_new(device, _interface_as_handler);
/* create alternate setting */
setting_ac = rt_usbd_altsetting_new(sizeof(struct uac_ac_descriptor));
setting_as0 = rt_usbd_altsetting_new(sizeof(struct uinterface_descriptor));
setting_as = rt_usbd_altsetting_new(sizeof(struct uac_as_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(setting_ac, &ac_desc,
(rt_off_t) & ((struct uac_ac_descriptor *)0)->intf_desc);
rt_usbd_altsetting_config_descriptor(setting_as0, &as_desc0, 0);
rt_usbd_altsetting_config_descriptor(setting_as, &as_desc,
(rt_off_t) & ((struct uac_as_descriptor *)0)->intf_desc);
/* configure the uac interface descriptor */
_uac_descriptor_config(setting_ac->desc, intf_ac->intf_num, setting_as->desc, intf_as->intf_num);
_uac_samplerate_config(setting_as->desc, AUDIO_SAMPLERATE);
/* create endpoint */
as_desc_t = (struct uac_as_descriptor *)setting_as->desc;
speaker.ep = rt_usbd_endpoint_new(&as_desc_t->ep_desc, _ep_data_handler);
/* add the endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(setting_as, speaker.ep);
/* add the alternate setting to the interface, then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_ac, setting_ac);
rt_usbd_set_altsetting(intf_ac, 0);
rt_usbd_interface_add_altsetting(intf_as, setting_as0);
rt_usbd_interface_add_altsetting(intf_as, setting_as);
rt_usbd_set_altsetting(intf_as, 0);
/* add the interface to the uac function */
rt_usbd_function_add_interface(func, intf_ac);
rt_usbd_function_add_interface(func, intf_as);
return func;
}
int audio_speaker_init(void)
{
rt_thread_t speaker_tid;
if (speaker.buffer == RT_NULL)
speaker.buffer = rt_malloc(UAC_MAX_PACKET_SIZE + USB_RX_BUFF_RESERVE_SIZE);
if (speaker.buffer == RT_NULL)
{
os_printf("speaker buffer malloc failed\n");
}
speaker.buffer_index = 0;
speaker.event = rt_event_create("speaker_event", RT_IPC_FLAG_FIFO);
usbd_audio_spk_msi_init(&speaker, 8);
return RT_EOK;
}
/*
* register uac class
*/
static struct udclass uac_speaker_class =
{
.rt_usbd_function_create = rt_usbd_function_uac_speaker_create
};
//需要初始化DAC的采样率与UAC一致
int rt_usbd_uac_speaker_class_register(rt_uint32_t dev_id)
{
rt_usbd_class_register(&uac_speaker_class, dev_id);
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,334 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-03 Yi Qiu first version
* 2012-12-12 heyuanjie87 add CDC endpoints collection
*/
#ifndef __CDC_VCOM_H__
#define __CDC_VCOM_H__
#define USB_CDC_BUFSIZE 0x200
#define USB_CDC_CLASS_COMM 0x02
#define USB_CDC_CLASS_DATA 0x0A
#define USB_CDC_SUBCLASS_NONE 0x00
#define USB_CDC_SUBCLASS_DLCM 0x01
#define USB_CDC_SUBCLASS_ACM 0x02
#define USB_CDC_SUBCLASS_TCM 0x03
#define USB_CDC_SUBCLASS_MCCM 0x04
#define USB_CDC_SUBCLASS_CCM 0x05
#define USB_CDC_SUBCLASS_ETH 0x06
#define USB_CDC_SUBCLASS_ATM 0x07
#define USB_CDC_SUBCLASS_EEM 0x0C
#define USB_CDC_PROTOCOL_NONE 0x00
#define USB_CDC_PROTOCOL_V25TER 0x01
#define USB_CDC_PROTOCOL_I430 0x30
#define USB_CDC_PROTOCOL_HDLC 0x31
#define USB_CDC_PROTOCOL_TRANS 0x32
#define USB_CDC_PROTOCOL_Q921M 0x50
#define USB_CDC_PROTOCOL_Q921 0x51
#define USB_CDC_PROTOCOL_Q921TM 0x52
#define USB_CDC_PROTOCOL_V42BIS 0x90
#define USB_CDC_PROTOCOL_Q931 0x91
#define USB_CDC_PROTOCOL_V120 0x92
#define USB_CDC_PROTOCOL_CAPI20 0x93
#define USB_CDC_PROTOCOL_HOST 0xFD
#define USB_CDC_PROTOCOL_PUFD 0xFE
#define USB_CDC_PROTOCOL_VENDOR 0xFF
#define USB_CDC_PROTOCOL_EEM 0x07
#define USB_CDC_CS_INTERFACE 0x24
#define USB_CDC_CS_ENDPOINT 0x25
#define USB_CDC_SCS_HEADER 0x00
#define USB_CDC_SCS_CALL_MGMT 0x01
#define USB_CDC_SCS_ACM 0x02
#define USB_CDC_SCS_UNION 0x06
#define USB_CDC_SCS_ETH 0x0F
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
#define CDC_SET_COMM_FEATURE 0x02
#define CDC_GET_COMM_FEATURE 0x03
#define CDC_CLEAR_COMM_FEATURE 0x04
#define CDC_SET_AUX_LINE_STATE 0x10
#define CDC_SET_HOOK_STATE 0x11
#define CDC_PULSE_SETUP 0x12
#define CDC_SEND_PULSE 0x13
#define CDC_SET_PULSE_TIME 0x14
#define CDC_RING_AUX_JACK 0x15
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
#define CDC_SET_RINGER_PARMS 0x30
#define CDC_GET_RINGER_PARMS 0x31
#define CDC_SET_OPERATION_PARMS 0x32
#define CDC_GET_OPERATION_PARMS 0x33
#define CDC_SET_LINE_PARMS 0x34
#define CDC_GET_LINE_PARMS 0x35
#define CDC_DIAL_DIGITS 0x36
#define CDC_SET_UNIT_PARAMETER 0x37
#define CDC_GET_UNIT_PARAMETER 0x38
#define CDC_CLEAR_UNIT_PARAMETER 0x39
#define CDC_GET_PROFILE 0x3A
#define CDC_SET_ETH_MULTICAST_FILTERS 0x40
#define CDC_SET_ETH_POWER_MGMT_FILT 0x41
#define CDC_GET_ETH_POWER_MGMT_FILT 0x42
#define CDC_SET_ETH_PACKET_FILTER 0x43
#define CDC_GET_ETH_STATISTIC 0x44
#define CDC_SET_ATM_DATA_FORMAT 0x50
#define CDC_GET_ATM_DEVICE_STATISTICS 0x51
#define CDC_SET_ATM_DEFAULT_VC 0x52
#define CDC_GET_ATM_VC_STATISTICS 0x53
/* The baudrate can be defined as*/
#define BAUD_RATE_2400 2400
#define BAUD_RATE_4800 4800
#define BAUD_RATE_9600 9600
#define BAUD_RATE_19200 19200
#define BAUD_RATE_38400 38400
#define BAUD_RATE_57600 57600
#define BAUD_RATE_115200 115200
#define BAUD_RATE_230400 230400
#define BAUD_RATE_460800 460800
#define BAUD_RATE_921600 921600
#define BAUD_RATE_2000000 2000000
#define BAUD_RATE_3000000 3000000
/* Data bits can be defined as*/
#define DATA_BITS_5 5
#define DATA_BITS_6 6
#define DATA_BITS_7 7
#define DATA_BITS_8 8
#define DATA_BITS_9 9
/* Stop bits can be defined as */
#define STOP_BITS_1 0
#define STOP_BITS_2 1
#define STOP_BITS_3 2
#define STOP_BITS_4 3
/* Parity bits can be defined as */
#define PARITY_NONE 0
#define PARITY_ODD 1
#define PARITY_EVEN 2
/* Bit order can be defined as */
#define BIT_ORDER_LSB 0
#define BIT_ORDER_MSB 1
/* Mode canbe defined as */
#define NRZ_NORMAL 0 /* normal mode */
#define NRZ_INVERTED 1 /* inverted mode */
/* Default size of the receive data buffer */
#define RT_SERIAL_RB_BUFSZ 64
#pragma pack(1)
enum vcom_control_cmd
{
USBD_VCOM_CTRL_GET,
USBD_VCOM_CTRL_SET,
USBD_VCOM_CTRL_CONNECTED,
};
struct ucdc_header_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t subtype;
rt_uint16_t bcd;
};
typedef struct ucdc_header_descriptor* ucdc_hdr_desc_t;
struct ucdc_acm_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t subtype;
rt_uint8_t capabilties;
};
typedef struct ucdc_acm_descriptor* ucdc_acm_desc_t;
struct ucdc_call_mgmt_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t subtype;
rt_uint8_t capabilties;
rt_uint8_t data_interface;
};
typedef struct ucdc_call_mgmt_descriptor* ucdc_call_mgmt_desc_t;
struct ucdc_union_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t subtype;
rt_uint8_t master_interface;
rt_uint8_t slave_interface0;
};
typedef struct ucdc_union_descriptor* ucdc_union_desc_t;
struct ucdc_comm_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct ucdc_header_descriptor hdr_desc;
struct ucdc_call_mgmt_descriptor call_mgmt_desc;
struct ucdc_acm_descriptor acm_desc;
struct ucdc_union_descriptor union_desc;
struct uendpoint_descriptor ep_desc;
};
typedef struct ucdc_comm_descriptor* ucdc_comm_desc_t;
struct ucdc_enet_descriptor
{
rt_uint8_t bFunctionLength;
rt_uint8_t bDescriptorType;
rt_uint8_t bDescriptorSubtype;
rt_uint8_t iMACAddress;
rt_uint8_t bmEthernetStatistics[4];
rt_uint16_t wMaxSegmentSize;
rt_uint16_t wMCFilters;
rt_uint8_t bNumberPowerFilters;
};
struct ucdc_eth_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct ucdc_header_descriptor hdr_desc;
struct ucdc_union_descriptor union_desc;
struct ucdc_enet_descriptor enet_desc;
struct uendpoint_descriptor ep_desc;
};
typedef struct ucdc_eth_descriptor* ucdc_eth_desc_t;
struct ucdc_data_descriptor
{
struct uinterface_descriptor intf_desc;
struct uendpoint_descriptor ep_out_desc;
struct uendpoint_descriptor ep_in_desc;
};
typedef struct ucdc_data_descriptor* ucdc_data_desc_t;
struct ucdc_line_coding
{
rt_uint32_t dwDTERate;
rt_uint8_t bCharFormat;
rt_uint8_t bParityType;
rt_uint8_t bDataBits;
};
typedef struct ucdc_line_coding* ucdc_line_coding_t;
struct cdc_eps
{
uep_t ep_out;
uep_t ep_in;
uep_t ep_cmd;
};
typedef struct cdc_eps* cdc_eps_t;
struct ucdc_management_element_notifications
{
rt_uint8_t bmRequestType;
rt_uint8_t bNotificatinCode;
rt_uint16_t wValue;
rt_uint16_t wIndex;
rt_uint16_t wLength;
};
typedef struct ucdc_management_element_notifications * ucdc_mg_notifications_t;
struct ucdc_connection_speed_change_data
{
rt_uint32_t down_bit_rate;
rt_uint32_t up_bit_rate;
};
typedef struct connection_speed_change_data * connect_speed_data_t;
enum ucdc_notification_code
{
UCDC_NOTIFI_NETWORK_CONNECTION = 0x00,
UCDC_NOTIFI_RESPONSE_AVAILABLE = 0x01,
UCDC_NOTIFI_AUX_JACK_HOOK_STATE = 0x08,
UCDC_NOTIFI_RING_DETECT = 0x09,
UCDC_NOTIFI_SERIAL_STATE = 0x20,
UCDC_NOTIFI_CALL_STATE_CHANGE = 0x28,
UCDC_NOTIFI_LINE_STATE_CHANGE = 0x29,
UCDC_NOTIFI_CONNECTION_SPEED_CHANGE = 0x2A,
};
typedef enum ucdc_notification_code ucdc_notification_code_t;
/**
* Notify structure
*/
struct rt_device_notify
{
void (*notify)(rt_device_t dev);
struct rt_device *dev;
};
struct serial_configure
{
rt_uint32_t baud_rate;
rt_uint32_t data_bits :4;
rt_uint32_t stop_bits :2;
rt_uint32_t parity :2;
rt_uint32_t bit_order :1;
rt_uint32_t invert :1;
rt_uint32_t bufsz :16;
rt_uint32_t flowcontrol :1;
rt_uint32_t reserved :5;
};
struct rt_serial_device
{
struct rt_device parent;
const struct rt_uart_ops *ops;
struct serial_configure config;
void *serial_rx;
void *serial_tx;
struct rt_device_notify rx_notify;
struct ufunction *func;
};
/**
* uart operators
*/
struct rt_uart_ops
{
rt_err_t (*configure)(struct rt_serial_device *serial,
struct serial_configure *cfg);
rt_err_t (*control)(struct rt_serial_device *serial,
int cmd,
void *arg);
int (*putc)(struct rt_serial_device *serial, char c);
int (*getc)(struct rt_serial_device *serial);
rt_ssize_t (*transmit)(struct rt_serial_device *serial,
rt_uint8_t *buf,
rt_size_t size,
rt_uint32_t tx_flag);
};
#pragma pack()
#endif

View File

@@ -0,0 +1,682 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-11-19 ZYH first version
* 2019-06-10 ZYH fix hotplug
*/
#include <rtthread.h>
#ifdef RT_USB_DEVICE_ECM
#include "cdc.h"
//#define DBG_LEVEL DBG_WARNING
//#define DBG_SECTION_NAME "ECM"
//#include <rtdbg.h>
/* RT-Thread LWIP ethernet interface */
#include <netif/ethernetif.h>
#ifndef USB_ETH_MTU
#define USB_ETH_MTU 1514
#endif
#define MAX_ADDR_LEN 6
#define ECM_INTF_STR_INDEX 10
struct rt_ecm_eth
{
/* inherit from ethernet device */
struct eth_device parent;
struct ufunction * func;
struct cdc_eps eps;
/* interface address info */
rt_uint8_t host_addr[MAX_ADDR_LEN];
rt_uint8_t dev_addr[MAX_ADDR_LEN];
rt_align(4)
rt_uint8_t rx_pool[512];
rt_align(4)
rt_size_t rx_size;
rt_align(4)
rt_size_t rx_offset;
rt_align(4)
char rx_buffer[USB_ETH_MTU];
char tx_buffer[USB_ETH_MTU];
struct rt_semaphore tx_buffer_free;
};
typedef struct rt_ecm_eth * rt_ecm_eth_t;
rt_align(4)
static struct udevice_descriptor _dev_desc =
{
USB_DESC_LENGTH_DEVICE, /* bLength */
USB_DESC_TYPE_DEVICE, /* type */
USB_BCD_VERSION, /* bcdUSB */
USB_CLASS_CDC, /* bDeviceClass */
USB_CDC_SUBCLASS_ETH, /* bDeviceSubClass */
USB_CDC_PROTOCOL_NONE, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */
_VENDOR_ID, /* idVendor */
_PRODUCT_ID, /* idProduct */
USB_BCD_DEVICE, /* bcdDevice */
USB_STRING_MANU_INDEX, /* iManufacturer */
USB_STRING_PRODUCT_INDEX, /* iProduct */
USB_STRING_SERIAL_INDEX, /* iSerialNumber */
USB_DYNAMIC /* bNumConfigurations */
};
/* communcation interface descriptor */
rt_align(4)
const static struct ucdc_eth_descriptor _comm_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x02,
USB_CDC_CLASS_COMM,
USB_CDC_SUBCLASS_ETH,
USB_CDC_PROTOCOL_NONE,
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x01,
USB_CDC_CLASS_COMM,
USB_CDC_SUBCLASS_ETH,
USB_CDC_PROTOCOL_NONE,
#ifdef RT_USB_DEVICE_COMPOSITE
ECM_INTF_STR_INDEX,
#else
0x00,
#endif
},
/* Header Functional Descriptor */
{
sizeof(struct ucdc_header_descriptor),
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_HEADER,
0x0110,
},
/* Union Functional Descriptor */
{
sizeof(struct ucdc_union_descriptor),
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_UNION,
USB_DYNAMIC,
USB_DYNAMIC,
},
/* Abstract Control Management Functional Descriptor */
{
sizeof(struct ucdc_enet_descriptor),
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_ETH,
USB_STRING_SERIAL_INDEX,
{0,0,0,0},
USB_ETH_MTU,
0x00,
0x00,
},
/* Endpoint Descriptor */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DIR_IN | USB_DYNAMIC,
USB_EP_ATTR_INT,
0x08,
0xFF,
},
};
/* data interface descriptor */
rt_align(4)
const static struct ucdc_data_descriptor _data_desc =
{
/* interface descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x02,
USB_CDC_CLASS_DATA,
USB_CDC_SUBCLASS_ETH,
0x00,
0x00,
},
/* endpoint, bulk out */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DIR_OUT | USB_DYNAMIC,
USB_EP_ATTR_BULK,
USB_DYNAMIC,
0x00,
},
/* endpoint, bulk in */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
USB_EP_ATTR_BULK,
USB_DYNAMIC,
0x00,
},
};
rt_align(4)
const static char* _ustring[] =
{
"Language", /* LANGID */
"RT-Thread Team.", /* MANU */
"RT-Thread ECM device", /* PRODUCT */
"3497F694ECAB", /* SERIAL (MAC)*/
"Configuration", /* CONFIG */
"Interface", /* INTERFACE */
};
rt_align(4)
//FS and HS needed
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_CDC, //bDeviceClass
USB_CDC_SUBCLASS_ETH, //bDeviceSubClass
USB_CDC_PROTOCOL_NONE, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
static rt_err_t _cdc_send_notifi(ufunction_t func,ucdc_notification_code_t notifi,rt_uint16_t wValue,rt_uint16_t wLength)
{
static struct ucdc_management_element_notifications _notifi;
cdc_eps_t eps;
RT_ASSERT(func!=RT_NULL)
eps = &((rt_ecm_eth_t)func->user_data)->eps;
_notifi.bmRequestType = 0xA1;
_notifi.bNotificatinCode = notifi;
_notifi.wValue = wValue;
_notifi.wLength = wLength;
eps->ep_cmd->request.buffer = (void *)&_notifi;
eps->ep_cmd->request.size = 8;
eps->ep_cmd->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, eps->ep_cmd, &eps->ep_cmd->request);
return RT_EOK;
}
static rt_err_t _ecm_set_eth_packet_filter(ufunction_t func, ureq_t setup)
{
rt_ecm_eth_t _ecm_eth = (rt_ecm_eth_t)func->user_data;
dcd_ep0_send_status(func->device->dcd);
/* send link up. */
eth_device_linkchange(&_ecm_eth->parent, RT_TRUE);
_cdc_send_notifi(func, UCDC_NOTIFI_NETWORK_CONNECTION, 1, 0);
#ifdef LWIP_USING_DHCPD
extern void dhcpd_start(const char *netif_name);
dhcpd_start("u0");
#endif
return RT_EOK;
}
/**
* This function will handle rndis interface request.
*
* @param device the usb device object.
* @param setup the setup request.
*
* @return RT_EOK on successful.
*/
static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(setup != RT_NULL);
switch(setup->bRequest)
{
case CDC_SET_ETH_PACKET_FILTER:
LOG_D("CDC_SET_ETH_PACKET_FILTER");
_ecm_set_eth_packet_filter(func, setup);
break;
default:
LOG_E("Unknow setup->bRequest: 0x%02X", setup->bRequest);
break;
}
return RT_EOK;
}
/**
* This function will handle rndis bulk in endpoint request.
*
* @param device the usb device object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
{
rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
rt_sem_release(&ecm_device->tx_buffer_free);
return RT_EOK;
}
/**
* This function will handle RNDIS bulk out endpoint request.
*
* @param device the usb device object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
{
rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
rt_memcpy((void *)(ecm_device->rx_buffer + ecm_device->rx_offset),ecm_device->rx_pool,size);
ecm_device->rx_offset += size;
if(size < EP_MAXPACKET(ecm_device->eps.ep_out))
{
ecm_device->rx_size = ecm_device->rx_offset;
ecm_device->rx_offset = 0;
eth_device_ready(&ecm_device->parent);
}else
{
ecm_device->eps.ep_out->request.buffer = ecm_device->eps.ep_out->buffer;
ecm_device->eps.ep_out->request.size = EP_MAXPACKET(ecm_device->eps.ep_out);
ecm_device->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(ecm_device->func->device, ecm_device->eps.ep_out, &ecm_device->eps.ep_out->request);
}
return RT_EOK;
}
static rt_err_t rt_ecm_eth_init(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t rt_ecm_eth_open(rt_device_t dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t rt_ecm_eth_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_ssize_t rt_ecm_eth_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
{
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_ssize_t rt_ecm_eth_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
{
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_err_t rt_ecm_eth_control(rt_device_t dev, int cmd, void *args)
{
rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
switch(cmd)
{
case NIOCTL_GADDR:
/* get mac address */
if(args) rt_memcpy(args, ecm_eth_dev->dev_addr, MAX_ADDR_LEN);
else return -RT_ERROR;
break;
default :
break;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops ecm_device_ops =
{
rt_ecm_eth_init,
rt_ecm_eth_open,
rt_ecm_eth_close,
rt_ecm_eth_read,
rt_ecm_eth_write,
rt_ecm_eth_control
};
#endif
struct pbuf *rt_ecm_eth_rx(rt_device_t dev)
{
struct pbuf* p = RT_NULL;
rt_uint32_t offset = 0;
rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
if(ecm_eth_dev->rx_size != 0)
{
/* allocate buffer */
p = pbuf_alloc(PBUF_RAW, ecm_eth_dev->rx_size, PBUF_RAM);
if (p != RT_NULL)
{
struct pbuf* q;
for (q = p; q != RT_NULL; q= q->next)
{
/* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
rt_memcpy(q->payload,
(rt_uint8_t *)((ecm_eth_dev->rx_buffer) + offset),
q->len);
offset += q->len;
}
}
}
{
if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED)
{
ecm_eth_dev->rx_size = 0;
ecm_eth_dev->rx_offset = 0;
ecm_eth_dev->eps.ep_out->request.buffer = ecm_eth_dev->eps.ep_out->buffer;
ecm_eth_dev->eps.ep_out->request.size = EP_MAXPACKET(ecm_eth_dev->eps.ep_out);
ecm_eth_dev->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_out, &ecm_eth_dev->eps.ep_out->request);
}
}
return p;
}
rt_err_t rt_ecm_eth_tx(rt_device_t dev, struct pbuf* p)
{
struct pbuf* q;
char * pbuffer;
rt_err_t result = RT_EOK;
rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
if(!ecm_eth_dev->parent.link_status)
{
LOG_D("linkdown, drop pkg");
return RT_EOK;
}
if(p->tot_len > USB_ETH_MTU)
{
LOG_W("ECM MTU is:%d, but the send packet size is %d",
USB_ETH_MTU, p->tot_len);
p->tot_len = USB_ETH_MTU;
}
result = rt_sem_take(&ecm_eth_dev->tx_buffer_free, rt_tick_from_millisecond(1000));
if(result != RT_EOK)
{
LOG_W("wait for buffer free timeout");
/* if cost 1s to wait send done it said that connection is close . drop it */
rt_sem_release(&ecm_eth_dev->tx_buffer_free);
return result;
}
pbuffer = (char *)&ecm_eth_dev->tx_buffer;
for (q = p; q != NULL; q = q->next)
{
rt_memcpy(pbuffer, q->payload, q->len);
pbuffer += q->len;
}
{
if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED)
{
ecm_eth_dev->eps.ep_in->request.buffer = (void *)&ecm_eth_dev->tx_buffer;
ecm_eth_dev->eps.ep_in->request.size = p->tot_len;
ecm_eth_dev->eps.ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_in, &ecm_eth_dev->eps.ep_in->request);
}
}
return result;
}
/**
* This function will handle RNDIS interrupt in endpoint request.
*
* @param device the usb device object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size)
{
return RT_EOK;
}
/**
* This function will run cdc class, it will be called on handle set configuration request.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _function_enable(ufunction_t func)
{
cdc_eps_t eps;
rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
LOG_D("plugged in");
eps = (cdc_eps_t)&ecm_device->eps;
eps->ep_out->buffer = ecm_device->rx_pool;
/* reset eth rx tx */
ecm_device->rx_size = 0;
ecm_device->rx_offset = 0;
eps->ep_out->request.buffer = (void *)eps->ep_out->buffer;
eps->ep_out->request.size = EP_MAXPACKET(eps->ep_out);
eps->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(func->device, eps->ep_out, &eps->ep_out->request);
return RT_EOK;
}
/**
* This function will stop cdc class, it will be called on handle set configuration request.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _function_disable(ufunction_t func)
{
LOG_D("plugged out");
eth_device_linkchange(&((rt_ecm_eth_t)func->user_data)->parent, RT_FALSE);
/* reset eth rx tx */
((rt_ecm_eth_t)func->user_data)->rx_size = 0;
((rt_ecm_eth_t)func->user_data)->rx_offset = 0;
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure cdc descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr, rt_uint8_t device_is_hs)
{
comm->call_mgmt_desc.data_interface = dintf_nr;
comm->union_desc.master_interface = cintf_nr;
comm->union_desc.slave_interface0 = dintf_nr;
#ifdef RT_USB_DEVICE_COMPOSITE
comm->iad_desc.bFirstInterface = cintf_nr;
#endif
data->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
data->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
return RT_EOK;
}
/**
* This function will create a cdc ecm class instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
ufunction_t rt_usbd_function_ecm_create(udevice_t device)
{
ufunction_t cdc;
rt_ecm_eth_t _ecm_eth;
cdc_eps_t eps;
uintf_t intf_comm, intf_data;
ualtsetting_t comm_setting, data_setting;
ucdc_data_desc_t data_desc;
ucdc_eth_desc_t comm_desc;
/* parameter check */
RT_ASSERT(device != RT_NULL);
/* set usb device string description */
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, ECM_INTF_STR_INDEX, _ustring[2]);
#else
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a cdc class */
cdc = rt_usbd_function_new(device, &_dev_desc, &ops);
rt_usbd_device_set_qualifier(device, &dev_qualifier);
_ecm_eth= rt_malloc(sizeof(struct rt_ecm_eth));
RT_ASSERT(_ecm_eth != RT_NULL);
rt_memset(_ecm_eth, 0, sizeof(struct rt_ecm_eth));
cdc->user_data = _ecm_eth;
_ecm_eth->func = cdc;
/* create a cdc class endpoints collection */
eps = &_ecm_eth->eps;
/* create a cdc communication interface and a cdc data interface */
intf_comm = rt_usbd_interface_new(device, _interface_handler);
intf_data = rt_usbd_interface_new(device, _interface_handler);
/* create a communication alternate setting and a data alternate setting */
comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_eth_descriptor));
data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc,
(rt_off_t)&((ucdc_eth_desc_t)0)->intf_desc);
rt_usbd_altsetting_config_descriptor(data_setting, &_data_desc, 0);
/* configure the cdc interface descriptor */
_cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num, device->dcd->device_is_hs);
/* create a command endpoint */
comm_desc = (ucdc_eth_desc_t)comm_setting->desc;
eps->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler);
/* add the command endpoint to the cdc communication interface */
rt_usbd_altsetting_add_endpoint(comm_setting, eps->ep_cmd);
/* add the communication alternate setting to the communication interface,
then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_comm, comm_setting);
rt_usbd_set_altsetting(intf_comm, 0);
/* add the communication interface to the cdc class */
rt_usbd_function_add_interface(cdc, intf_comm);
/* create a bulk in and a bulk out endpoint */
data_desc = (ucdc_data_desc_t)data_setting->desc;
eps->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler);
eps->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler);
/* add the bulk out and bulk in endpoints to the data alternate setting */
rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_in);
rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_out);
/* add the data alternate setting to the data interface
then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_data, data_setting);
rt_usbd_set_altsetting(intf_data, 0);
/* add the cdc data interface to cdc class */
rt_usbd_function_add_interface(cdc, intf_data);
rt_sem_init(&_ecm_eth->tx_buffer_free, "ue_tx", 1, RT_IPC_FLAG_FIFO);
/* OUI 00-00-00, only for test. */
_ecm_eth->dev_addr[0] = 0x34;
_ecm_eth->dev_addr[1] = 0x97;
_ecm_eth->dev_addr[2] = 0xF6;
/* generate random MAC. */
_ecm_eth->dev_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
_ecm_eth->dev_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14);
_ecm_eth->dev_addr[5] = 0xAC;//(const rt_uint8_t *)(0x1fff7a18);
/* OUI 00-00-00, only for test. */
_ecm_eth->host_addr[0] = 0x34;
_ecm_eth->host_addr[1] = 0x97;
_ecm_eth->host_addr[2] = 0xF6;
/* generate random MAC. */
_ecm_eth->host_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
_ecm_eth->host_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14);
_ecm_eth->host_addr[5] = 0xAB;//*(const rt_uint8_t *)(0x1fff7a18);
#ifdef RT_USING_DEVICE_OPS
_ecm_eth->parent.parent.ops = &ecm_device_ops;
#else
_ecm_eth->parent.parent.init = rt_ecm_eth_init;
_ecm_eth->parent.parent.open = rt_ecm_eth_open;
_ecm_eth->parent.parent.close = rt_ecm_eth_close;
_ecm_eth->parent.parent.read = rt_ecm_eth_read;
_ecm_eth->parent.parent.write = rt_ecm_eth_write;
_ecm_eth->parent.parent.control = rt_ecm_eth_control;
#endif
_ecm_eth->parent.parent.user_data = device;
_ecm_eth->parent.eth_rx = rt_ecm_eth_rx;
_ecm_eth->parent.eth_tx = rt_ecm_eth_tx;
/* register eth device */
eth_device_init(&_ecm_eth->parent, "u0");
/* send link up. */
eth_device_linkchange(&_ecm_eth->parent, RT_FALSE);
return cdc;
}
struct udclass ecm_class =
{
.rt_usbd_function_create = rt_usbd_function_ecm_create
};
int rt_usbd_ecm_class_register(rt_uint32_t devid)
{
rt_usbd_class_register(&ecm_class, devid);
return 0;
}
INIT_PREV_EXPORT(rt_usbd_ecm_class_register);
#endif /* RT_USB_DEVICE_ECM */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-01 Yi Qiu first version
* 2012-12-12 heyuanjie87 add MASS endpoints collection
*/
#ifndef __MSTORAGE_H__
#define __MSTORAGE_H__
#include <rtthread.h>
#pragma pack(1)
struct umass_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct uendpoint_descriptor ep_out_desc;
struct uendpoint_descriptor ep_in_desc;
};
typedef struct umass_descriptor* umass_desc_t;
struct capacity_data
{
rt_uint8_t LastLogicalBlockAddress[4];
rt_uint8_t BlockLengthInBytes[4];
};
struct request_sense_data
{
rt_uint8_t ErrorCode:7;
rt_uint8_t Valid:1;
rt_uint8_t Reserved1;
rt_uint8_t SenseKey:4;
rt_uint8_t Reserved2:4;
rt_uint8_t Information[4];
rt_uint8_t AdditionalSenseLength;
rt_uint8_t Reserved3[4];
rt_uint8_t AdditionalSenseCode;
rt_uint8_t AdditionalSenseCodeQualifier;
rt_uint8_t Reserved4[4];
}request_sense_data_t;
#pragma pack()
#endif

View File

@@ -0,0 +1,237 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/*
* ndis.h
*
* Modified by Colin O'Flynn <coflynn@newae.com>
* ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
*
* Thanks to the cygwin development team,
* espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAIMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef __NDIS_H__
#define __NDIS_H__
#define NDIS_STATUS_MULTICAST_FULL 0xC0010009
#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A
#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B
/* from drivers/net/sk98lin/h/skgepnmi.h */
#define OID_PNP_CAPABILITIES 0xFD010100
#define OID_PNP_SET_POWER 0xFD010101
#define OID_PNP_QUERY_POWER 0xFD010102
#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103
#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104
#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
enum NDIS_DEVICE_POWER_STATE
{
NdisDeviceStateUnspecified = 0,
NdisDeviceStateD0,
NdisDeviceStateD1,
NdisDeviceStateD2,
NdisDeviceStateD3,
NdisDeviceStateMaximum
};
struct NDIS_PM_WAKE_UP_CAPABILITIES
{
enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp;
enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp;
enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp;
};
/* NDIS_PNP_CAPABILITIES.Flags constants */
#define NDIS_DEVICE_WAKE_UP_ENABLE 0x00000001
#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002
#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004
/* Required Object IDs (OIDs) */
#define OID_GEN_SUPPORTED_LIST 0x00010101
#define OID_GEN_HARDWARE_STATUS 0x00010102
#define OID_GEN_MEDIA_SUPPORTED 0x00010103
#define OID_GEN_MEDIA_IN_USE 0x00010104
#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
#define OID_GEN_LINK_SPEED 0x00010107
#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
#define OID_GEN_VENDOR_ID 0x0001010C
#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
#define OID_GEN_DRIVER_VERSION 0x00010110
#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
#define OID_GEN_MAC_OPTIONS 0x00010113
#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
#define OID_GEN_SUPPORTED_GUIDS 0x00010117
#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118
#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119
#define OID_GEN_MACHINE_NAME 0x0001021A
#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B
#define OID_GEN_VLAN_ID 0x0001021C
/* Optional OIDs */
#define OID_GEN_MEDIA_CAPABILITIES 0x00010201
#define OID_GEN_PHYSICAL_MEDIUM 0x00010202
/* Required statistics OIDs */
#define OID_GEN_XMIT_OK 0x00020101
#define OID_GEN_RCV_OK 0x00020102
#define OID_GEN_XMIT_ERROR 0x00020103
#define OID_GEN_RCV_ERROR 0x00020104
#define OID_GEN_RCV_NO_BUFFER 0x00020105
/* Optional statistics OIDs */
#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
#define OID_GEN_RCV_CRC_ERROR 0x0002020D
#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
#define OID_GEN_GET_TIME_CAPS 0x0002020F
#define OID_GEN_GET_NETCARD_TIME 0x00020210
#define OID_GEN_NETCARD_LOAD 0x00020211
#define OID_GEN_DEVICE_PROFILE 0x00020212
#define OID_GEN_INIT_TIME_MS 0x00020213
#define OID_GEN_RESET_COUNTS 0x00020214
#define OID_GEN_MEDIA_SENSE_COUNTS 0x00020215
#define OID_GEN_FRIENDLY_NAME 0x00020216
#define OID_GEN_MINIPORT_INFO 0x00020217
#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218
/* IEEE 802.3 (Ethernet) OIDs */
#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001
#define OID_802_3_PERMANENT_ADDRESS 0x01010101
#define OID_802_3_CURRENT_ADDRESS 0x01010102
#define OID_802_3_MULTICAST_LIST 0x01010103
#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104
#define OID_802_3_MAC_OPTIONS 0x01010105
#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101
#define OID_802_3_XMIT_ONE_COLLISION 0x01020102
#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103
#define OID_802_3_XMIT_DEFERRED 0x01020201
#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202
#define OID_802_3_RCV_OVERRUN 0x01020203
#define OID_802_3_XMIT_UNDERRUN 0x01020204
#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205
#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206
#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207
/* Wireless LAN OIDs */
#define OID_802_11_BSSID 0x0D010101 /* Q S */
#define OID_802_11_SSID 0x0D010102 /* Q S */
#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 /* Q S */
#define OID_802_11_RSSI 0x0D010206 /* Q I */
#define OID_802_11_BSSID_LIST 0x0D010217 /* Q */
#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A /* S */
#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 /* Q S */
#define OID_802_11_SUPPORTED_RATES 0x0D01020E /* Q */
#define OID_802_11_CONFIGURATION 0x0D010211 /* Q S */
#define OID_802_11_ADD_WEP 0x0D010113 /* S */
#define OID_802_11_WEP_STATUS 0x0D01011B /* Q S */
#define OID_802_11_REMOVE_WEP 0x0D010114 /* S */
#define OID_802_11_DISASSOCIATE 0x0D010115 /* S */
#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 /* Q S */
#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C /* S */
/* OID_GEN_MINIPORT_INFO constants */
#define NDIS_MINIPORT_BUS_MASTER 0x00000001
#define NDIS_MINIPORT_WDM_DRIVER 0x00000002
#define NDIS_MINIPORT_SG_LIST 0x00000004
#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY 0x00000008
#define NDIS_MINIPORT_INDICATES_PACKETS 0x00000010
#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE 0x00000020
#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE 0x00000040
#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS 0x00000080
#define NDIS_MINIPORT_INTERMEDIATE_DRIVER 0x00000100
#define NDIS_MINIPORT_IS_NDIS_5 0x00000200
#define NDIS_MINIPORT_IS_CO 0x00000400
#define NDIS_MINIPORT_DESERIALIZE 0x00000800
#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING 0x00001000
#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE 0x00002000
#define NDIS_MINIPORT_NETBOOT_CARD 0x00004000
#define NDIS_MINIPORT_PM_SUPPORTED 0x00008000
#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000
#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS 0x00020000
#define NDIS_MINIPORT_HIDDEN 0x00040000
#define NDIS_MINIPORT_SWENUM 0x00080000
#define NDIS_MINIPORT_SURPRISE_REMOVE_OK 0x00100000
#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND 0x00200000
#define NDIS_MINIPORT_HARDWARE_DEVICE 0x00400000
#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS 0x00800000
#define NDIS_MINIPORT_64BITS_DMA 0x01000000
#define NDIS_MEDIUM_802_3 0x00000000
#define NDIS_MEDIUM_802_5 0x00000001
#define NDIS_MEDIUM_FDDI 0x00000002
#define NDIS_MEDIUM_WAN 0x00000003
#define NDIS_MEDIUM_LOCAL_TALK 0x00000004
#define NDIS_MEDIUM_DIX 0x00000005
#define NDIS_MEDIUM_ARCENT_RAW 0x00000006
#define NDIS_MEDIUM_ARCENT_878_2 0x00000007
#define NDIS_MEDIUM_ATM 0x00000008
#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009
#define NDIS_MEDIUM_IRDA 0x0000000A
#define NDIS_MEDIUM_BPC 0x0000000B
#define NDIS_MEDIUM_CO_WAN 0x0000000C
#define NDIS_MEDIUM_1394 0x0000000D
#define NDIS_PACKET_TYPE_DIRECTED 0x00000001
#define NDIS_PACKET_TYPE_MULTICAST 0x00000002
#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004
#define NDIS_PACKET_TYPE_BROADCAST 0x00000008
#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010
#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020
#define NDIS_PACKET_TYPE_SMT 0x00000040
#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080
#define NDIS_PACKET_TYPE_GROUP 0x00000100
#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200
#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
#define NDIS_MEDIA_STATE_CONNECTED 0x00000000
#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001
#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001
#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002
#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004
#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008
#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010
#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020
#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040
#define NDIS_MAC_OPTION_RESERVED 0x80000000
#endif /* __NDIS_H__ */

View File

@@ -0,0 +1,440 @@
/* $NetBSD: uaudioreg.h,v 1.15.38.1 2012/06/02 11:09:29 mrg Exp $ */
/*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
//#include <rtdef.h>
#include <rtthread.h>
#include <stdint.h>
typedef uint8_t uByte;
typedef uint16_t uWord;
#define UPACKED __attribute__ ((packed))
#define UAUDIO_VERSION 0x100
#define USB_SUBCLASS_AUDIOCONTROL 1
#define USB_SUBCLASS_AUDIOSTREAMING 2
#define USB_SUBCLASS_AUDIOMIDISTREAM 3
#define UDESC_CS_CONFIG 0x22
#define UDESC_CS_STRING 0x23
#define UDESC_CS_INTERFACE 0x24
#define UDESC_CS_ENDPOINT 0x25
#define UDESCSUB_AC_HEADER 1
#define UDESCSUB_AC_INPUT 2
#define UDESCSUB_AC_OUTPUT 3
#define UDESCSUB_AC_MIXER 4
#define UDESCSUB_AC_SELECTOR 5
#define UDESCSUB_AC_FEATURE 6
#define UDESCSUB_AC_PROCESSING 7
#define UDESCSUB_AC_EXTENSION 8
#ifndef AUFMT_MAX_FREQUENCIES
#define AUFMT_MAX_FREQUENCIES 1
#endif
/* The first fields are identical to usb_endpoint_descriptor_t */
typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bEndpointAddress;
uByte bmAttributes;
uWord wMaxPacketSize;
uByte bInterval;
/*
* The following two entries are only used by the Audio Class.
* And according to the specs the Audio Class is the only one
* allowed to extend the endpoint descriptor.
* Who knows what goes on in the minds of the people in the USB
* standardization? :-(
*/
uByte bRefresh;
uByte bSynchAddress;
} UPACKED usb_endpoint_descriptor_audio_t;
/* generic, for iteration */
typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
} UPACKED uaudio_cs_descriptor_t;
struct usb_audio_control_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uWord bcdADC;
uWord wTotalLength;
uByte bInCollection;
uByte baInterfaceNr[1];
} UPACKED;
struct usb_audio_streaming_interface_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bTerminalLink;
uByte bDelay;
uWord wFormatTag;
} UPACKED;
struct usb_audio_streaming_endpoint_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bmAttributes;
#define UA_SED_FREQ_CONTROL 0x01
#define UA_SED_PITCH_CONTROL 0x02
#define UA_SED_MAXPACKETSONLY 0x80
uByte bLockDelayUnits;
uWord wLockDelay;
} UPACKED;
struct usb_audio_streaming_type1_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bFormatType;
uByte bNrChannels;
uByte bSubFrameSize;
uByte bBitResolution;
uByte bSamFreqType;
#define UA_SAMP_CONTNUOUS 0
uByte tSamFreq[3*AUFMT_MAX_FREQUENCIES];
#define UA_GETSAMP(p, n) ((p)->tSamFreq[(n)*3+0] | ((p)->tSamFreq[(n)*3+1] << 8) | ((p)->tSamFreq[(n)*3+2] << 16))
#define UA_SAMP_LO(p) UA_GETSAMP(p, 0)
#define UA_SAMP_HI(p) UA_GETSAMP(p, 1)
} UPACKED;
struct usb_audio_cluster {
uByte bNrChannels;
uWord wChannelConfig;
#define UA_CHANNEL_LEFT 0x0001
#define UA_CHANNEL_RIGHT 0x0002
#define UA_CHANNEL_CENTER 0x0004
#define UA_CHANNEL_LFE 0x0008
#define UA_CHANNEL_L_SURROUND 0x0010
#define UA_CHANNEL_R_SURROUND 0x0020
#define UA_CHANNEL_L_CENTER 0x0040
#define UA_CHANNEL_R_CENTER 0x0080
#define UA_CHANNEL_SURROUND 0x0100
#define UA_CHANNEL_L_SIDE 0x0200
#define UA_CHANNEL_R_SIDE 0x0400
#define UA_CHANNEL_TOP 0x0800
uByte iChannelNames;
} UPACKED;
/* Shared by all units and terminals */
struct usb_audio_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
};
/* UDESCSUB_AC_INPUT */
struct usb_audio_input_terminal {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bTerminalId;
uWord wTerminalType;
uByte bAssocTerminal;
uByte bNrChannels;
uWord wChannelConfig;
uByte iChannelNames;
uByte iTerminal;
} UPACKED;
/* UDESCSUB_AC_OUTPUT */
struct usb_audio_output_terminal {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bTerminalId;
uWord wTerminalType;
uByte bAssocTerminal;
uByte bSourceId;
uByte iTerminal;
} UPACKED;
/* UDESCSUB_AC_MIXER */
struct usb_audio_mixer_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uByte bNrInPins;
uByte baSourceId[255]; /* [bNrInPins] */
/* struct usb_audio_mixer_unit_1 */
} UPACKED;
struct usb_audio_mixer_unit_1 {
uByte bNrChannels;
uWord wChannelConfig;
uByte iChannelNames;
uByte bmControls[255]; /* [bNrChannels] */
/*uByte iMixer;*/
} UPACKED;
/* UDESCSUB_AC_SELECTOR */
struct usb_audio_selector_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uByte bNrInPins;
uByte baSourceId[255]; /* [bNrInPins] */
/* uByte iSelector; */
} UPACKED;
/* UDESCSUB_AC_FEATURE */
struct usb_audio_feature_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uByte bSourceId;
uByte bControlSize;
uByte bmaControls[2]; /* size for more than enough */
/* uByte iFeature; */
} UPACKED;
/* UDESCSUB_AC_PROCESSING */
struct usb_audio_processing_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uWord wProcessType;
uByte bNrInPins;
uByte baSourceId[255]; /* [bNrInPins] */
/* struct usb_audio_processing_unit_1 */
} UPACKED;
struct usb_audio_processing_unit_1{
uByte bNrChannels;
uWord wChannelConfig;
uByte iChannelNames;
uByte bControlSize;
uByte bmControls[255]; /* [bControlSize] */
#define UA_PROC_ENABLE_MASK 1
} UPACKED;
struct usb_audio_processing_unit_updown {
uByte iProcessing;
uByte bNrModes;
uWord waModes[255]; /* [bNrModes] */
} UPACKED;
/* UDESCSUB_AC_EXTENSION */
struct usb_audio_extension_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uWord wExtensionCode;
uByte bNrInPins;
uByte baSourceId[255]; /* [bNrInPins] */
/* struct usb_audio_extension_unit_1 */
} UPACKED;
struct usb_audio_extension_unit_1 {
uByte bNrChannels;
uWord wChannelConfig;
uByte iChannelNames;
uByte bControlSize;
uByte bmControls[255]; /* [bControlSize] */
#define UA_EXT_ENABLE_MASK 1
#define UA_EXT_ENABLE 1
/*uByte iExtension;*/
} UPACKED;
/* USB terminal types */
#define UAT_UNDEFINED 0x0100
#define UAT_STREAM 0x0101
#define UAT_VENDOR 0x01ff
/* input terminal types */
#define UATI_UNDEFINED 0x0200
#define UATI_MICROPHONE 0x0201
#define UATI_DESKMICROPHONE 0x0202
#define UATI_PERSONALMICROPHONE 0x0203
#define UATI_OMNIMICROPHONE 0x0204
#define UATI_MICROPHONEARRAY 0x0205
#define UATI_PROCMICROPHONEARR 0x0206
/* output terminal types */
#define UATO_UNDEFINED 0x0300
#define UATO_SPEAKER 0x0301
#define UATO_HEADPHONES 0x0302
#define UATO_DISPLAYAUDIO 0x0303
#define UATO_DESKTOPSPEAKER 0x0304
#define UATO_ROOMSPEAKER 0x0305
#define UATO_COMMSPEAKER 0x0306
#define UATO_SUBWOOFER 0x0307
/* bidir terminal types */
#define UATB_UNDEFINED 0x0400
#define UATB_HANDSET 0x0401
#define UATB_HEADSET 0x0402
#define UATB_SPEAKERPHONE 0x0403
#define UATB_SPEAKERPHONEESUP 0x0404
#define UATB_SPEAKERPHONEECANC 0x0405
/* telephony terminal types */
#define UATT_UNDEFINED 0x0500
#define UATT_PHONELINE 0x0501
#define UATT_TELEPHONE 0x0502
#define UATT_DOWNLINEPHONE 0x0503
/* external terminal types */
#define UATE_UNDEFINED 0x0600
#define UATE_ANALOGCONN 0x0601
#define UATE_DIGITALAUIFC 0x0602
#define UATE_LINECONN 0x0603
#define UATE_LEGACYCONN 0x0604
#define UATE_SPDIF 0x0605
#define UATE_1394DA 0x0606
#define UATE_1394DV 0x0607
/* embedded function terminal types */
#define UATF_UNDEFINED 0x0700
#define UATF_CALIBNOISE 0x0701
#define UATF_EQUNOISE 0x0702
#define UATF_CDPLAYER 0x0703
#define UATF_DAT 0x0704
#define UATF_DCC 0x0705
#define UATF_MINIDISK 0x0706
#define UATF_ANALOGTAPE 0x0707
#define UATF_PHONOGRAPH 0x0708
#define UATF_VCRAUDIO 0x0709
#define UATF_VIDEODISCAUDIO 0x070a
#define UATF_DVDAUDIO 0x070b
#define UATF_TVTUNERAUDIO 0x070c
#define UATF_SATELLITE 0x070d
#define UATF_CABLETUNER 0x070e
#define UATF_DSS 0x070f
#define UATF_RADIORECV 0x0710
#define UATF_RADIOXMIT 0x0711
#define UATF_MULTITRACK 0x0712
#define UATF_SYNTHESIZER 0x0713
#define SET_CUR 0x01
#define GET_CUR 0x81
#define SET_MIN 0x02
#define GET_MIN 0x82
#define SET_MAX 0x03
#define GET_MAX 0x83
#define SET_RES 0x04
#define GET_RES 0x84
#define SET_MEM 0x05
#define GET_MEM 0x85
#define GET_STAT 0xff
#define MUTE_CONTROL 0x01
#define VOLUME_CONTROL 0x02
#define BASS_CONTROL 0x03
#define MID_CONTROL 0x04
#define TREBLE_CONTROL 0x05
#define GRAPHIC_EQUALIZER_CONTROL 0x06
#define AGC_CONTROL 0x07
#define DELAY_CONTROL 0x08
#define BASS_BOOST_CONTROL 0x09
#define LOUDNESS_CONTROL 0x0a
#define FU_MASK(u) (1 << ((u)-1))
#define MASTER_CHAN 0
#define AS_GENERAL 1
#define FORMAT_TYPE 2
#define FORMAT_SPECIFIC 3
#define UA_FMT_PCM 1
#define UA_FMT_PCM8 2
#define UA_FMT_IEEE_FLOAT 3
#define UA_FMT_ALAW 4
#define UA_FMT_MULAW 5
#define UA_FMT_MPEG 0x1001
#define UA_FMT_AC3 0x1002
#define SAMPLING_FREQ_CONTROL 0x01
#define PITCH_CONTROL 0x02
#define FORMAT_TYPE_UNDEFINED 0
#define FORMAT_TYPE_I 1
#define FORMAT_TYPE_II 2
#define FORMAT_TYPE_III 3
#define UA_PROC_MASK(n) (1<< ((n)-1))
#define PROCESS_UNDEFINED 0
#define XX_ENABLE_CONTROL 1
#define UPDOWNMIX_PROCESS 1
#define UD_ENABLE_CONTROL 1
#define UD_MODE_SELECT_CONTROL 2
#define DOLBY_PROLOGIC_PROCESS 2
#define DP_ENABLE_CONTROL 1
#define DP_MODE_SELECT_CONTROL 2
#define P3D_STEREO_EXTENDER_PROCESS 3
#define P3D_ENABLE_CONTROL 1
#define P3D_SPACIOUSNESS_CONTROL 2
#define REVERBATION_PROCESS 4
#define RV_ENABLE_CONTROL 1
#define RV_LEVEL_CONTROL 2
#define RV_TIME_CONTROL 3
#define RV_FEEDBACK_CONTROL 4
#define CHORUS_PROCESS 5
#define CH_ENABLE_CONTROL 1
#define CH_LEVEL_CONTROL 2
#define CH_RATE_CONTROL 3
#define CH_DEPTH_CONTROL 4
#define DYN_RANGE_COMP_PROCESS 6
#define DR_ENABLE_CONTROL 1
#define DR_COMPRESSION_RATE_CONTROL 2
#define DR_MAXAMPL_CONTROL 3
#define DR_THRESHOLD_CONTROL 4
#define DR_ATTACK_TIME_CONTROL 5
#define DR_RELEASE_TIME_CONTROL 6
struct rt_audio_configure
{
rt_uint32_t samplerate;
rt_uint16_t channels;
rt_uint16_t samplebits;
};
struct rt_audio_caps
{
int main_type;
int sub_type;
union
{
rt_uint32_t mask;
int value;
struct rt_audio_configure config;
} udata;
};

View File

@@ -0,0 +1,768 @@
/*
* File : hid.c
* COPYRIGHT (C) 2006 - 2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-03-13 Urey the first version
* 2017-11-16 ZYH Update to common hid
*/
//#include <rthw.h>
#include <rtthread.h>
#include "include/usb_common.h"
#include "include/rttusb_device.h"
#include "usbd_hid.h"
#ifdef RT_USB_DEVICE_HID
#define HID_INTF_STR_INDEX 7
typedef rt_ssize_t (*usbd_hid_write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
struct hid_s
{
struct rt_device parent;
usbd_hid_write write;
struct ufunction *func;
uep_t ep_in;
uep_t ep_out;
int status;
rt_uint8_t protocol;
rt_uint8_t report_buf[MAX_REPORT_SIZE] rt_align(4);
struct hid_report *report_write_data;
struct rt_messagequeue hid_mq;
struct rt_semaphore hid_write_sema;
};
static rt_uint8_t hid_mq_pool[(sizeof(struct hid_report)+sizeof(void*))*8];
static struct rt_thread hid_thread;
/* CustomHID_ConfigDescriptor */
rt_align(4)
rt_uint8_t _report_desc[]=
{
#ifdef RT_USB_DEVICE_HID_KEYBOARD
USAGE_PAGE(1), 0x01,
USAGE(1), 0x06,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_KEYBOARD1,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x05,
REPORT_SIZE(1), 0x01,
USAGE_PAGE(1), 0x08,
USAGE_MINIMUM(1), 0x01,
USAGE_MAXIMUM(1), 0x05,
OUTPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x03,
OUTPUT(1), 0x01,
REPORT_COUNT(1), 0x06,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00,
END_COLLECTION(0),
#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>1
/****keyboard2*****/
USAGE_PAGE(1), 0x01,
USAGE(1), 0x06,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_KEYBOARD2,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x06,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00,
END_COLLECTION(0),
#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>2
USAGE_PAGE(1), 0x01,
USAGE(1), 0x06,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_KEYBOARD3,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x06,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00,
END_COLLECTION(0),
#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>3
USAGE_PAGE(1), 0x01,
USAGE(1), 0x06,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_KEYBOARD4,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x06,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00,
END_COLLECTION(0),
#endif
#endif
#endif
#endif
// Media Control
#ifdef RT_USB_DEVICE_HID_MEDIA
USAGE_PAGE(1), 0x0C,
USAGE(1), 0x01,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_MEDIA,
USAGE_PAGE(1), 0x0C,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x07,
USAGE(1), 0xB5, // Next Track
USAGE(1), 0xB6, // Previous Track
USAGE(1), 0xB7, // Stop
USAGE(1), 0xCD, // Play / Pause
USAGE(1), 0xE2, // Mute
USAGE(1), 0xE9, // Volume Up
USAGE(1), 0xEA, // Volume Down
INPUT(1), 0x02, // Input (Data, Variable, Absolute)
REPORT_COUNT(1), 0x01,
INPUT(1), 0x01,
END_COLLECTION(0),
#endif
#ifdef RT_USB_DEVICE_HID_GENERAL
USAGE_PAGE(1), 0x8c,
USAGE(1), 0x01,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_GENERAL,
REPORT_COUNT(1), RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH,
USAGE(1), 0x03,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0xFF,
INPUT(1), 0x02,
REPORT_COUNT(1), RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH,
USAGE(1), 0x04,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0xFF,
OUTPUT(1), 0x02,
END_COLLECTION(0),
#endif
#ifdef RT_USB_DEVICE_HID_MOUSE
USAGE_PAGE(1), 0x01, // Generic Desktop
USAGE(1), 0x02, // Mouse
COLLECTION(1), 0x01, // Application
USAGE(1), 0x01, // Pointer
COLLECTION(1), 0x00, // Physical
REPORT_ID(1), HID_REPORT_ID_MOUSE,
REPORT_COUNT(1), 0x03,
REPORT_SIZE(1), 0x01,
USAGE_PAGE(1), 0x09, // Buttons
USAGE_MINIMUM(1), 0x1,
USAGE_MAXIMUM(1), 0x3,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x05,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x03,
REPORT_SIZE(1), 0x08,
USAGE_PAGE(1), 0x01,
USAGE(1), 0x30, // X
USAGE(1), 0x31, // Y
USAGE(1), 0x38, // scroll
LOGICAL_MINIMUM(1), 0x81,
LOGICAL_MAXIMUM(1), 0x7f,
INPUT(1), 0x06,
END_COLLECTION(0),
END_COLLECTION(0),
#endif
}; /* CustomHID_ReportDescriptor */
rt_align(4)
static struct udevice_descriptor _dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
0x0, //bDeviceClass;
0x00, //bDeviceSubClass;
0x00, //bDeviceProtocol;
64, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
0x0, //bDeviceClass
0x0, //bDeviceSubClass
0x50, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
/* hid interface descriptor */
rt_align(4)
const static struct uhid_comm_descriptor _hid_comm_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x01,
0x03, /* bInterfaceClass: HID */
#if defined(RT_USB_DEVICE_HID_KEYBOARD)||defined(RT_USB_DEVICE_HID_MOUSE)
USB_HID_SUBCLASS_BOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#else
USB_HID_SUBCLASS_NOBOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#endif
#if !defined(RT_USB_DEVICE_HID_KEYBOARD)&&!defined(RT_USB_DEVICE_HID_MOUSE)&&!defined(RT_USB_DEVICE_HID_MEDIA)
USB_HID_PROTOCOL_NONE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#elif !defined(RT_USB_DEVICE_HID_MOUSE)
USB_HID_PROTOCOL_KEYBOARD, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#else
USB_HID_PROTOCOL_MOUSE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#endif
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
#if defined(RT_USB_DEVICE_HID_KEYBOARD)||defined(RT_USB_DEVICE_HID_MOUSE)
USB_HID_SUBCLASS_BOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#else
USB_HID_SUBCLASS_NOBOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#endif
#if !defined(RT_USB_DEVICE_HID_KEYBOARD)&&!defined(RT_USB_DEVICE_HID_MOUSE)&&!defined(RT_USB_DEVICE_HID_MEDIA)
USB_HID_PROTOCOL_NONE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#elif !defined(RT_USB_DEVICE_HID_MOUSE)
USB_HID_PROTOCOL_KEYBOARD, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#else
USB_HID_PROTOCOL_MOUSE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#endif
#ifdef RT_USB_DEVICE_COMPOSITE
HID_INTF_STR_INDEX, /* iInterface: Index of string descriptor */
#else
0,
#endif
},
/* HID Descriptor */
{
HID_DESCRIPTOR_SIZE, /* bLength: HID Descriptor size */
HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID */
0x0110, /* bcdHID: HID Class Spec release number */
0x00, /* bCountryCode: Hardware target country */
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
{
{
0x22, /* bDescriptorType */
sizeof(_report_desc), /* wItemLength: Total length of Report descriptor */
},
},
},
/* Endpoint Descriptor IN */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
USB_EP_ATTR_INT,
0x40,
0x0A,
},
/* Endpoint Descriptor OUT */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_OUT,
USB_EP_ATTR_INT,
0x40,
0x01,
},
};
rt_align(4)
const static char* _ustring[] =
{
"Language",
"RT-Thread Team.",
"RTT HID-Device",
"32021919830108",
"Configuration",
"Interface",
};
static void dump_data(rt_uint8_t *data, rt_size_t size)
{
rt_size_t i;
for (i = 0; i < size; i++)
{
rt_kprintf("%02x ", *data++);
if ((i + 1) % 8 == 0)
{
rt_kprintf("\n");
}else if ((i + 1) % 4 == 0){
rt_kprintf(" ");
}
}
}
static void dump_report(struct hid_report * report)
{
rt_kprintf("\nHID Recived:");
rt_kprintf("\nReport ID %02x \n", report->report_id);
dump_data(report->report,report->size);
}
static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
{
struct hid_s *data;
struct hid_report report;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
data = (struct hid_s *) func->user_data;
if(size != 0)
{
rt_memcpy((void *)&report,(void*)data->ep_out->buffer,size);
report.size = size-1;
rt_mq_send(&data->hid_mq,(void *)&report,sizeof(report));
}
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
return RT_EOK;
}
static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
{
struct hid_s *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
data = (struct hid_s *) func->user_data;
rt_sem_release(&data->hid_write_sema);
return RT_EOK;
}
static rt_err_t _hid_set_report_callback(udevice_t device, rt_size_t size)
{
LOG_D("_hid_set_report_callback");
if(size != 0)
{
}
dcd_ep0_send_status(device->dcd);
return RT_EOK;
}
/**
* This function will handle hid interface bRequest.
*
* @param device the usb device object.
* @param setup the setup bRequest.
*
* @return RT_EOK on successful.
*/
static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
struct hid_s *data = (struct hid_s *) func->user_data;
switch (setup->bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
if((setup->wValue >> 8) == USB_DESC_TYPE_REPORT)
{
rt_usbd_ep0_write(func->device, (void *)(&_report_desc), sizeof(_report_desc));
}
else if((setup->wValue >> 8) == USB_DESC_TYPE_HID)
{
rt_usbd_ep0_write(func->device, (void *)(&_hid_comm_desc.hid_desc), sizeof(struct uhid_descriptor));
}
break;
case USB_HID_REQ_GET_REPORT:
if(setup->wLength == 0)
{
rt_usbd_ep0_set_stall(func->device);
break;
}
if((setup->wLength == 0) || (setup->wLength > MAX_REPORT_SIZE))
setup->wLength = MAX_REPORT_SIZE;
rt_usbd_ep0_write(func->device, data->report_buf,setup->wLength);
break;
case USB_HID_REQ_GET_IDLE:
dcd_ep0_send_status(func->device->dcd);
break;
case USB_HID_REQ_GET_PROTOCOL:
rt_usbd_ep0_write(func->device, &data->protocol,1);
break;
case USB_HID_REQ_SET_REPORT:
if((setup->wLength == 0) || (setup->wLength > MAX_REPORT_SIZE))
rt_usbd_ep0_set_stall(func->device);
rt_usbd_ep0_read(func->device, data->report_buf, setup->wLength, _hid_set_report_callback);
break;
case USB_HID_REQ_SET_IDLE:
dcd_ep0_send_status(func->device->dcd);
break;
case USB_HID_REQ_SET_PROTOCOL:
data->protocol = setup->wValue;
dcd_ep0_send_status(func->device->dcd);
break;
}
return RT_EOK;
}
/**
* This function will run cdc function, it will be called on handle set configuration bRequest.
*
* @param func the usb function object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _function_enable(ufunction_t func)
{
struct hid_s *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
data = (struct hid_s *) func->user_data;
LOG_D("hid function enable");
rt_sem_init(&data->hid_write_sema, "hid_write_sema", 1, RT_IPC_FLAG_FIFO);
if(data->ep_out->buffer == RT_NULL)
{
data->ep_out->buffer = rt_malloc(HID_RX_BUFSIZE);
}
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
return RT_EOK;
}
/**
* This function will stop cdc function, it will be called on handle set configuration bRequest.
*
* @param func the usb function object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _function_disable(ufunction_t func)
{
struct hid_s *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
data = (struct hid_s *) func->user_data;
LOG_D("hid function disable");
rt_sem_detach(&data->hid_write_sema);
if(data->ep_out->buffer != RT_NULL)
{
rt_free(data->ep_out->buffer);
data->ep_out->buffer = RT_NULL;
}
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure hid descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _hid_descriptor_config(uhid_comm_desc_t hid, rt_uint8_t cintf_nr)
{
#ifdef RT_USB_DEVICE_COMPOSITE
hid->iad_desc.bFirstInterface = cintf_nr;
#endif
return RT_EOK;
}
static rt_ssize_t _hid_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
struct hid_s *hiddev = (struct hid_s *)dev;
struct hid_report *report = hiddev->report_write_data;
if (hiddev->func->device->state == USB_STATE_CONFIGURED)
{
int ret = rt_sem_take(&hiddev->hid_write_sema, 1000);
if (ret != RT_EOK) {
rt_kprintf("%s %d write err!!!\n", __FUNCTION__, __LINE__);
return 0;
}
report->report_id = pos;
rt_memcpy((void *)report->report, (void *)buffer, size);
report->size = size;
hiddev->ep_in->request.buffer = (void *)report;
hiddev->ep_in->request.size = (size+1) > 64 ? 64 : size+1;
hiddev->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(hiddev->func->device, hiddev->ep_in, &hiddev->ep_in->request);
return size;
}
return 0;
}
rt_weak void HID_Report_Received(hid_report_t report)
{
dump_report(report);
}
static void hid_thread_entry(void* parameter)
{
struct hid_report report;
struct hid_s *hiddev;
hiddev = (struct hid_s *)parameter;
while(1)
{
if(rt_mq_recv(&hiddev->hid_mq, &report, sizeof(report),RT_WAITING_FOREVER) < 0)
continue;
HID_Report_Received(&report);
}
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops hid_device_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
_hid_write,
RT_NULL,
};
#endif
static void rt_usb_hid_init(struct ufunction *func)
{
struct hid_s *hiddev;
hiddev = (struct hid_s *)func->user_data;
rt_memset(&hiddev->parent, 0, sizeof(hiddev->parent));
#ifdef RT_USING_DEVICE_OPS
hiddev->parent.ops = &hid_device_ops;
#else
hiddev->write = _hid_write;
#endif
hiddev->func = func;
hiddev->report_write_data = (struct hid_report *)rt_malloc(sizeof(struct hid_report) + USB_RX_BUFF_RESERVE_SIZE);
rt_mq_init(&hiddev->hid_mq, "hiddmq", hid_mq_pool, sizeof(struct hid_report),
sizeof(hid_mq_pool), RT_IPC_FLAG_FIFO);
rt_thread_init(&hid_thread, "usbd_hid", hid_thread_entry, hiddev,
NULL, 512, RT_USBD_THREAD_PRIO, 20);
rt_thread_startup(&hid_thread);
}
/**
* This function will create a hid function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
ufunction_t rt_usbd_function_hid_create(udevice_t device)
{
ufunction_t func;
struct hid_s *data;
uintf_t hid_intf;
ualtsetting_t hid_setting;
uhid_comm_desc_t hid_desc;
/* parameter check */
RT_ASSERT(device != RT_NULL);
/* set usb device string description */
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, HID_INTF_STR_INDEX, _ustring[2]);
#else
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a cdc function */
func = rt_usbd_function_new(device, &_dev_desc, &ops);
/* For high speed mode supporting */
rt_usbd_device_set_qualifier(device, &dev_qualifier);
/* allocate memory for cdc vcom data */
data = (struct hid_s*)rt_malloc(sizeof(struct hid_s));
rt_memset(data, 0, sizeof(struct hid_s));
func->user_data = (void*)data;
/* create an interface object */
hid_intf = rt_usbd_interface_new(device, _interface_handler);
/* create an alternate setting object */
hid_setting = rt_usbd_altsetting_new(sizeof(struct uhid_comm_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(hid_setting, &_hid_comm_desc, (rt_off_t)&((uhid_comm_desc_t)0)->intf_desc);
/* configure the hid interface descriptor */
_hid_descriptor_config(hid_setting->desc, hid_intf->intf_num);
/* create endpoint */
hid_desc = (uhid_comm_desc_t)hid_setting->desc;
data->ep_out = rt_usbd_endpoint_new(&hid_desc->ep_out_desc, _ep_out_handler);
data->ep_in = rt_usbd_endpoint_new(&hid_desc->ep_in_desc, _ep_in_handler);
/* add the int out and int in endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(hid_setting, data->ep_out);
rt_usbd_altsetting_add_endpoint(hid_setting, data->ep_in);
/* add the alternate setting to the interface, then set default setting */
rt_usbd_interface_add_altsetting(hid_intf, hid_setting);
rt_usbd_set_altsetting(hid_intf, 0);
/* add the interface to the mass storage function */
rt_usbd_function_add_interface(func, hid_intf);
/* initilize hid */
rt_usb_hid_init(func);
return func;
}
struct udclass hid_class =
{
.rt_usbd_function_create = rt_usbd_function_hid_create
};
int rt_usbd_hid_class_register(rt_uint32_t dev_id)
{
rt_usbd_class_register(&hid_class, dev_id);
return 0;
}
#endif /* RT_USB_DEVICE_HID */

View File

@@ -0,0 +1,258 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-03-13 Urey the first version
* 2017-11-16 ZYH Update to common hid
*/
#ifndef _USBDEVICE_CLASS_HID_H_
#define _USBDEVICE_CLASS_HID_H_
#ifdef __cplusplus
extern "C" {
#endif
#define HID_DESCRIPTOR_TYPE 0x21
#define HID_DESCRIPTOR_SIZE 0x09
#define HID_OFF_HID_DESC 0x12
#define USB_HID_SUBCLASS_BOOT 0x01
#define USB_HID_SUBCLASS_NOBOOT 0x00
#define USB_HID_PROTOCOL_NONE 0x00
#define USB_HID_PROTOCOL_KEYBOARD 0x01
#define USB_HID_PROTOCOL_MOUSE 0x02
#define USB_HID_REQ_GET_REPORT 0x01
#define USB_HID_REQ_GET_IDLE 0x02
#define USB_HID_REQ_GET_PROTOCOL 0x03
#define USB_HID_REQ_SET_REPORT 0x09
#define USB_HID_REQ_SET_IDLE 0x0a
#define USB_HID_REQ_SET_PROTOCOL 0x0b
#define MAX_REPORT_SIZE 64
#define HID_RX_BUFSIZE 64
/* HID Report Types */
#define HID_REPORT_INPUT 0x01
#define HID_REPORT_OUTPUT 0x02
#define HID_REPORT_FEATURE 0x03
/* Usage Pages */
#define USAGEPAGE_UNDEFINED 0x00
#define USAGEPAGE_GENERIC 0x01
#define USAGEPAGE_SIMULATION 0x02
#define USAGEPAGE_VR 0x03
#define USAGEPAGE_SPORT 0x04
#define USAGEPAGE_GAME 0x05
#define USAGEPAGE_DEV_CONTROLS 0x06
#define USAGEPAGE_KEYBOARD 0x07
#define USAGEPAGE_LED 0x08
#define USAGEPAGE_BUTTON 0x09
#define USAGEPAGE_ORDINAL 0x0A
#define USAGEPAGE_TELEPHONY 0x0B
#define USAGEPAGE_CONSUMER 0x0C
#define USAGEPAGE_DIGITIZER 0x0D
#define USAGEPAGE_PIDPAGE 0x0F
#define USAGEPAGE_UNICODE 0x10
#define USAGEPAGE_ALPHANUMERIC 0x14
#define USAGEPAGE_BARCODESCANNER 0x8C
/* Generic Desktop Page (0x01) */
#define USAGE_GENERIC_POINTER 0x01
#define USAGE_GENERIC_MOUSE 0x02
#define USAGE_GENERIC_JOYSTICK 0x04
#define USAGE_GENERIC_GAMEPAD 0x05
#define USAGE_GENERIC_KEYBOARD 0x06
#define USAGE_GENERIC_KEYPAD 0x07
#define USAGE_GENERIC_X 0x30
#define USAGE_GENERIC_Y 0x31
#define USAGE_GENERIC_Z 0x32
#define USAGE_GENERIC_RX 0x33
#define USAGE_GENERIC_RY 0x34
#define USAGE_GENERIC_RZ 0x35
#define USAGE_GENERIC_SLIDER 0x36
#define USAGE_GENERIC_DIAL 0x37
#define USAGE_GENERIC_WHEEL 0x38
#define USAGE_GENERIC_HATSWITCH 0x39
#define USAGE_GENERIC_COUNTED_BUFFER 0x3A
#define USAGE_GENERIC_BYTE_COUNT 0x3B
#define USAGE_GENERIC_MOTION_WAKEUP 0x3C
#define USAGE_GENERIC_VX 0x40
#define USAGE_GENERIC_VY 0x41
#define USAGE_GENERIC_VZ 0x42
#define USAGE_GENERIC_VBRX 0x43
#define USAGE_GENERIC_VBRY 0x44
#define USAGE_GENERIC_VBRZ 0x45
#define USAGE_GENERIC_VNO 0x46
#define USAGE_GENERIC_SYSTEM_CTL 0x80
#define USAGE_GENERIC_SYSCTL_POWER 0x81
#define USAGE_GENERIC_SYSCTL_SLEEP 0x82
#define USAGE_GENERIC_SYSCTL_WAKE 0x83
#define USAGE_GENERIC_SYSCTL_CONTEXT_MENU 0x84
#define USAGE_GENERIC_SYSCTL_MAIN_MENU 0x85
#define USAGE_GENERIC_SYSCTL_APP_MENU 0x86
#define USAGE_GENERIC_SYSCTL_HELP_MENU 0x87
#define USAGE_GENERIC_SYSCTL_MENU_EXIT 0x88
#define USAGE_GENERIC_SYSCTL_MENU_SELECT 0x89
#define USAGE_GENERIC_SYSCTL_MENU_RIGHT 0x8A
#define USAGE_GENERIC_SYSCTL_MENU_LEFT 0x8B
#define USAGE_GENERIC_SYSCTL_MENU_UP 0x8C
#define USAGE_GENERIC_SYSCTL_MENU_DOWN 0x8D
/* Simulation Controls Page(0x02) */
#define USAGE_SIMCTRL_THROTTLE 0xBB
/* HID Report Items */
/* Main Items */
#define HID_Input(x) 0x81,x
#define HID_Output(x) 0x91,x
#define HID_Feature(x) 0xB1,x
#define HID_Collection(x) 0xA1,x
#define HID_EndCollection() 0xC0
/* Local Items */
#define HID_Usage(x) 0x09,x
#define HID_UsageMin(x) 0x19,x
#define HID_UsageMax(x) 0x29,x
/* Global Items */
#define HID_UsagePage(x) 0x05,x
#define HID_UsagePageVendor(x) 0x06,x,0xFF
#define HID_LogicalMin(x) 0x15,x
#define HID_LogicalMinS(x) 0x16,(x&0xFF),((x>>8)&0xFF)
#define HID_LogicalMinL(x) 0x17,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_LogicalMax(x) 0x25,x
#define HID_LogicalMaxS(x) 0x26,(x&0xFF),((x>>8)&0xFF)
#define HID_LogicalMaxL(x) 0x27,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_PhysicalMin(x) 0x35,x
#define HID_PhysicalMinS(x) 0x36,(x&0xFF),((x>>8)&0xFF)
#define HID_PhysicalMinL(x) 0x37,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_PhysicalMax(x) 0x45,x
#define HID_PhysicalMaxS(x) 0x46,(x&0xFF),((x>>8)&0xFF)
#define HID_PhysicalMaxL(x) 0x47,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_UnitExponent(x) 0x55,x
#define HID_Unit(x) 0x65,x
#define HID_UnitS(x) 0x66,(x&0xFF),((x>>8)&0xFF)
#define HID_UnitL(x) 0x67,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_ReportSize(x) 0x75,x
#define HID_ReportSizeS(x) 0x76,(x&0xFF),((x>>8)&0xFF))
#define HID_ReportSizeL(x) 0x77,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_ReportID(x) 0x85,x
#define HID_ReportCount(x) 0x95,x
#define HID_ReportCountS(x) 0x96,(x&0xFF),((x>>8)&0xFF)
#define HID_ReportCountL(x) 0x97,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_Push() 0xA4
#define HID_Pop() 0xB4
/* Input, Output, Feature Data */
#define HID_DATA (0<<0)
#define HID_CONST (1<<0)
#define HID_ARRAY (0<<1)
#define HID_VAR (1<<1)
#define HID_ABS (0<<2)
#define HID_REL (1<<2)
#define HID_NOWRAP (0<<3)
#define HID_WRAP (1<<3)
#define HID_LINEAR (0<<4)
#define HID_NONLINEAR (1<<4)
#define HID_PREFERREDSTATE (0<<5)
#define HID_NOPREFERRED (1<<5)
#define HID_NONULLPOSITION (0<<6)
#define HID_NULLSTATE (1<<6)
#define HID_NONVOLATILE (0<<7)
#define HID_VOLATILE (1<<7)
/* Collection Data */
#define HID_PHYSICAL 0x00
#define HID_APPLICATION 0x01
#define HID_LOGICAL 0x02
#define HID_REPORT 0x03
#define HID_NAMEDARRAY 0x04
#define HID_USAGESWITCH 0x05
#define HID_USAGEMODIFIER 0x06
//HID_MBED_DEFINE
#define HID_VERSION_1_11 (0x0111)
/* HID Class */
#define HID_CLASS (3)
#define HID_SUBCLASS_NONE (0)
#define HID_SUBCLASS_BOOT (1)
#define HID_PROTOCOL_NONE (0)
#define HID_PROTOCOL_KEYBOARD (1)
#define HID_PROTOCOL_MOUSE (2)
/* Descriptors */
#define HID_DESCRIPTOR (33)
#define HID_DESCRIPTOR_LENGTH (0x09)
#define REPORT_DESCRIPTOR (34)
/* Class requests */
#define GET_REPORT (0x1)
#define GET_IDLE (0x2)
#define SET_REPORT (0x9)
#define SET_IDLE (0xa)
/* HID Class Report Descriptor */
/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
/* of data as per HID Class standard */
/* Main items */
#define INPUT(size) (0x80 | size)
#define OUTPUT(size) (0x90 | size)
#define FEATURE(size) (0xb0 | size)
#define COLLECTION(size) (0xa0 | size)
#define END_COLLECTION(size) (0xc0 | size)
/* Global items */
#define USAGE_PAGE(size) (0x04 | size)
#define LOGICAL_MINIMUM(size) (0x14 | size)
#define LOGICAL_MAXIMUM(size) (0x24 | size)
#define PHYSICAL_MINIMUM(size) (0x34 | size)
#define PHYSICAL_MAXIMUM(size) (0x44 | size)
#define UNIT_EXPONENT(size) (0x54 | size)
#define UNIT(size) (0x64 | size)
#define REPORT_SIZE(size) (0x74 | size)
#define REPORT_ID(size) (0x84 | size)
#define REPORT_COUNT(size) (0x94 | size)
#define PUSH(size) (0xa4 | size)
#define POP(size) (0xb4 | size)
/* Local items */
#define USAGE(size) (0x08 | size)
#define USAGE_MINIMUM(size) (0x18 | size)
#define USAGE_MAXIMUM(size) (0x28 | size)
#define DESIGNATOR_INDEX(size) (0x38 | size)
#define DESIGNATOR_MINIMUM(size) (0x48 | size)
#define DESIGNATOR_MAXIMUM(size) (0x58 | size)
#define STRING_INDEX(size) (0x78 | size)
#define STRING_MINIMUM(size) (0x88 | size)
#define STRING_MAXIMUM(size) (0x98 | size)
#define DELIMITER(size) (0xa8 | size)
#define LSB(n) ((n)&0xff)
#define MSB(n) (((n)&0xff00)>>8)
struct uhid_comm_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct uhid_descriptor hid_desc;
struct uendpoint_descriptor ep_in_desc;
struct uendpoint_descriptor ep_out_desc;
};
typedef struct uhid_comm_descriptor* uhid_comm_desc_t;
#ifdef __cplusplus
}
#endif
#endif /* _USBDEVICE_CLASS_HID_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,227 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-12-24 heyuanjie87 first version
*/
#ifndef __USBD_RNDIS_H__
#define __USBD_RNDIS_H__
#include <rtthread.h>
#define USB_ETH_MTU 1500+14
#define RNDIS_MESSAGE_BUFFER_SIZE 128
#define RESPONSE_AVAILABLE 0x00000001
/* Remote NDIS version numbers */
#define RNDIS_MAJOR_VERSION 1
#define RNDIS_MINOR_VERSION 0
/* common status values */
#define RNDIS_STATUS_SUCCESS 0X00000000
#define RNDIS_STATUS_FAILURE 0XC0000001
#define RNDIS_STATUS_INVALID_DATA 0XC0010015
#define RNDIS_STATUS_NOT_SUPPORTED 0XC00000BB
#define RNDIS_STATUS_MEDIA_CONNECT 0X4001000B
#define RNDIS_STATUS_MEDIA_DISCONNECT 0X4001000C
/* Remote NDIS message types */
#define REMOTE_NDIS_PACKET_MSG 0x00000001
#define REMOTE_NDIS_INITIALIZE_MSG 0X00000002
#define REMOTE_NDIS_HALT_MSG 0X00000003
#define REMOTE_NDIS_QUERY_MSG 0X00000004
#define REMOTE_NDIS_SET_MSG 0X00000005
#define REMOTE_NDIS_RESET_MSG 0X00000006
#define REMOTE_NDIS_INDICATE_STATUS_MSG 0X00000007
#define REMOTE_NDIS_KEEPALIVE_MSG 0X00000008
#define REMOTE_NDIS_INITIALIZE_CMPLT 0X80000002
#define REMOTE_NDIS_QUERY_CMPLT 0X80000004
#define REMOTE_NDIS_SET_CMPLT 0X80000005
#define REMOTE_NDIS_RESET_CMPLT 0X80000006
#define REMOTE_NDIS_KEEPALIVE_CMPLT 0X80000008
/* device flags */
#define RNDIS_DF_CONNECTIONLESS 0x00000001
#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002
/* mediums */
#define RNDIS_MEDIUM_802_3 0x00000000
struct ucls_rndis
{
uep_t notify;
rt_uint32_t filter;
rt_bool_t header;
rt_uint8_t rndis_state;
rt_uint8_t media_state;
rt_uint8_t ethaddr[6];
};
/* Remote NDIS generic message type */
struct rndis_gen_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
};
typedef struct rndis_gen_msg* rndis_gen_msg_t;
struct rndis_packet_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t DataOffset;
rt_uint32_t DataLength;
rt_uint32_t OOBDataOffset;
rt_uint32_t OOBDataLength;
rt_uint32_t NumOOBDataElements;
rt_uint32_t PerPacketInfoOffset;
rt_uint32_t PerPacketInfoLength;
rt_uint32_t VcHandle;
rt_uint32_t Reserved;
};
typedef struct rndis_packet_msg* rndis_packet_msg_t;
/* Remote NDIS Initialize Message */
struct rndis_init_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t MajorVersion;
rt_uint32_t MinorVersion;
rt_uint32_t MaxTransferSize;
};
typedef struct rndis_init_msg* rndis_init_msg_t;
/* Response */
struct rndis_init_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Status;
rt_uint32_t MajorVersion;
rt_uint32_t MinorVersion;
rt_uint32_t DeviceFlags;
rt_uint32_t Medium;
rt_uint32_t MaxPacketsPerTransfer;
rt_uint32_t MaxTransferSize;
rt_uint32_t PacketAlignmentFactor;
rt_uint32_t AfListOffset;
rt_uint32_t AfListSize;
};
typedef struct rndis_init_cmplt* rndis_init_cmplt_t;
/* Remote NDIS Halt Message */
struct rndis_halt_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
};
/* Remote NDIS Query Message */
struct rndis_query_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Oid;
rt_uint32_t InformationBufferLength;
rt_uint32_t InformationBufferOffset;
rt_uint32_t DeviceVcHandle;
};
typedef struct rndis_query_msg* rndis_query_msg_t;
/* Response */
struct rndis_query_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Status;
rt_uint32_t InformationBufferLength;
rt_uint32_t InformationBufferOffset;
};
typedef struct rndis_query_cmplt* rndis_query_cmplt_t;
/* Remote NDIS Set Message */
struct rndis_set_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Oid;
rt_uint32_t InformationBufferLength;
rt_uint32_t InformationBufferOffset;
rt_uint32_t DeviceVcHandle;
};
typedef struct rndis_set_msg* rndis_set_msg_t;
/* Response */
struct rndis_set_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Status;
};
typedef struct rndis_set_cmplt* rndis_set_cmplt_t;
/* Remote NDIS Soft Reset Message */
struct rndis_reset_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t Reserved;
};
/* Remote NDIS Soft Reset Response */
struct rndis_reset_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t Status;
rt_uint32_t AddressingReset;
};
/* Remote NDIS Indicate Status Message */
struct rndis_indicate_status_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t Status;
rt_uint32_t StatusBufferLength;
rt_uint32_t StatusBufferOffset;
};
typedef struct rndis_indicate_status_msg* rndis_indicate_status_msg_t;
struct rndis_keepalive_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestID;
};
typedef struct rndis_keepalive_msg* rndis_keepalive_msg_t;
/* Response: */
struct rndis_keepalive_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Status;
};
typedef struct rndis_keepalive_cmplt* rndis_keepalive_cmplt_t;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBD_VIDEO_H
#define USBD_VIDEO_H
#include <rtthread.h>
#include "include/usb_video.h"
#include "lib/multimedia/msi.h"
#ifdef __cplusplus
extern "C" {
#endif
enum usbd_video_mode
{
USBD_VIDEO_CLOSE = 0,
USBD_VIDEO_OPEN,
};
struct video_entity_info {
rt_uint8_t bDescriptorSubtype;
rt_uint8_t bEntityId;
rt_uint16_t wTerminalType;
};
struct usbd_video_msg
{
rt_uint8_t * flush_info_addr;
rt_uint8_t * dma_buff;
rt_uint8_t copy_len;
rt_uint8_t control_selector;
};
struct usbd_video_process_unit_cur_info
{
rt_uint32_t wWhiteBalance_Component;
rt_uint16_t wBacklightCompensation;
rt_uint16_t wBrightness;
rt_uint16_t wContrast;
rt_uint16_t wHue;
rt_uint16_t wHue_Auto;
rt_uint16_t wSaturation;
rt_uint16_t wSharpness;
rt_uint16_t wGamma;
rt_uint16_t wGain;
rt_uint16_t wWhiteBalance_Temprature;
rt_uint16_t wWhiteBalance_Temprature_Auto;
rt_uint16_t wWhiteBalance_Component_Auto;
rt_uint16_t wDigital_Multiplier;
rt_uint8_t wDigital_Multiplier_Limit;
rt_uint8_t bPowerLineFrequency;
};
typedef void (*uvc_set_resolution)(uint32_t in_weight, uint32_t in_height, uint32_t out_weight, uint32_t out_height, uint32_t en);
struct usbd_video_ops
{
uvc_set_resolution mjpeg_set_resolution;
uvc_set_resolution h264_set_resolution;
};
struct usbd_video_priv {
struct video_probe_and_commit_controls probe __attribute__((aligned(4)));
struct video_probe_and_commit_controls commit __attribute__((aligned(4)));
struct usbd_video_process_unit_cur_info process_unit_info;
rt_uint8_t power_mode;
rt_uint8_t error_code;
struct video_entity_info info[3];
struct rt_messagequeue video_mq;
struct usbd_video_ops ops;
};
/*
* uvc class device type
*/
struct uvc_class_device
{
rt_device_t dev;
rt_event_t event;
rt_uint8_t open_count;
rt_uint8_t *buffer;
rt_uint32_t buffer_index;
uep_t ep;
rt_thread_t thread;
struct msi *recv_msi;
struct msi *cur_msi;
};
/* Init video interface driver */
static rt_bool_t usbd_uvc_init(struct ufunction *func);
static void usbd_video_init_intf(uint8_t busid, uint32_t dwFrameInterval, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize);
static rt_err_t usbd_video_open(uint8_t busid, ufunction_t func);
static rt_err_t usbd_video_close(uint8_t busid, ufunction_t func);
static uint32_t usbd_video_mjpeg_payload_fill(uint8_t busid, uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len);
#ifdef __cplusplus
}
#endif
#endif /* USBD_VIDEO_H */

View File

@@ -0,0 +1,526 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-11-16 ZYH first version
*/
//#include <rthw.h>
//#include <rtdevice.h>
#include <include/rttusb_device.h>
#include "winusb.h"
#include "hal/isp_tunning.h"
#include "dev/audio/ausys_debug.h"
#include "dev/audio/ausys.h"
#include "dev/audio/ausys_da.h"
#include "dev/audio/components/eq/aueq.h"
#include "hal/isp.h"
#ifdef RT_USB_DEVICE_WINUSB
#if ISP_TUNNING_EN
extern struct isp_tunnning_dev *isp_tunning;
#endif
struct winusb_device
{
struct rt_device parent;
udevice_t device;
void (*cmd_handler)(rt_uint8_t *buffer,rt_size_t size);
void (*rx_handler)(rt_uint8_t *buffer,rt_size_t size);
void (*tx_handler)(rt_uint8_t *buffer,rt_size_t size);
rt_uint8_t cmd_buff[256 + USB_RX_BUFF_RESERVE_SIZE] rt_align(4);
rt_uint8_t dat_buff[1024 + USB_RX_BUFF_RESERVE_SIZE] rt_align(4);
uep_t ep_out;
uep_t ep_in;
void *user_data;
};
#define WINUSB_INTF_STR_INDEX 13
typedef struct winusb_device * winusb_device_t;
rt_align(4)
static struct udevice_descriptor dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
0xFF, //bDeviceClass;
0xFF, //bDeviceSubClass;
0xFF, //bDeviceProtocol;
0x40, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
0xFF, //bDeviceClass
0x00, //bDeviceSubClass
0x00, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
rt_align(4)
struct winusb_descriptor _winusb_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x01,
0xFF,
0x00,
0x00,
0x00,
},
#endif
/*interface descriptor*/
{
USB_DESC_LENGTH_INTERFACE, //bLength;
USB_DESC_TYPE_INTERFACE, //type;
USB_DYNAMIC, //bInterfaceNumber;
0x00, //bAlternateSetting;
0x02, //bNumEndpoints
0xFF, //bInterfaceClass;
0xFF, //bInterfaceSubClass;
0xFF, //bInterfaceProtocol;
#ifdef RT_USB_DEVICE_COMPOSITE
WINUSB_INTF_STR_INDEX,
#else
0x00, //iInterface;
#endif
},
/*endpoint descriptor*/
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_OUT,
USB_EP_ATTR_BULK,
USB_DYNAMIC,
0x00,
},
/*endpoint descriptor*/
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
USB_EP_ATTR_BULK,
USB_DYNAMIC,
0x00,
},
};
rt_align(4)
const static char* _ustring[] =
{
"Language",
"RT-Thread Team.",
"RTT Win USB",
"32021919830108",
"Configuration",
"Interface",
USB_STRING_OS//must be
};
rt_align(4)
const char winusb_device_interface_guids[142] = {
///////////////////////////////////////
/// WCID property descriptor
///////////////////////////////////////
0x8e, 0x00, 0x00, 0x00, /* dwLength */
0x00, 0x01, /* bcdVersion */
0x05, 0x00, /* wIndex */
0x01, 0x00, /* wCount */
///////////////////////////////////////
/// registry propter descriptor
///////////////////////////////////////
0x84, 0x00, 0x00, 0x00, /* dwSize */
0x01, 0x00, 0x00, 0x00, /* dwPropertyDataType */
0x28, 0x00, /* wPropertyNameLength */
/* DeviceInterfaceGUID */
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, /* wcName_20 */
'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, /* wcName_20 */
't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, /* wcName_20 */
'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, /* wcName_20 */
'U', 0x00, 'I', 0x00, 'D', 0x00, 0x00, 0x00, /* wcName_20 */
0x4e, 0x00, 0x00, 0x00, /* dwPropertyDataLength */
/* {1D4B2365-4749-48EA-B38A-7C6FDDDD7E26} */
'{', 0x00, '1', 0x00, 'D', 0x00, '4', 0x00, /* wcData_39 */
'B', 0x00, '2', 0x00, '3', 0x00, '6', 0x00, /* wcData_39 */
'5', 0x00, '-', 0x00, '4', 0x00, '7', 0x00, /* wcData_39 */
'4', 0x00, '9', 0x00, '-', 0x00, '4', 0x00, /* wcData_39 */
'8', 0x00, 'E', 0x00, 'A', 0x00, '-', 0x00, /* wcData_39 */
'B', 0x00, '3', 0x00, '8', 0x00, 'A', 0x00, /* wcData_39 */
'-', 0x00, '7', 0x00, 'C', 0x00, '6', 0x00, /* wcData_39 */
'F', 0x00, 'D', 0x00, 'D', 0x00, 'D', 0x00, /* wcData_39 */
'D', 0x00, '7', 0x00, 'E', 0x00, '2', 0x00, /* wcData_39 */
'6', 0x00, '}', 0x00, 0x00, 0x00, /* wcData_39 */
};
rt_align(4)
struct usb_os_proerty winusb_proerty[] =
{
USB_OS_PROPERTY_DESC(USB_OS_PROPERTY_TYPE_REG_SZ,"DeviceInterfaceGUID",winusb_device_interface_guids),
};
rt_align(4)
struct usb_os_function_comp_id_descriptor winusb_func_comp_id_desc =
{
.bFirstInterfaceNumber = USB_DYNAMIC,
.reserved1 = 0x01,
.compatibleID = {'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00},
.subCompatibleID = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.reserved2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
{
winusb_device_t winusb_device = (winusb_device_t)func->user_data;
LOG_D("%s %x %d\r\n", __FUNCTION__, winusb_device->ep_out->buffer, size);
/* example write back recieve data */
rt_ssize_t win_usb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
win_usb_write(&winusb_device->parent, 0, winusb_device->ep_out->buffer, size);
#ifdef HG_EQ_APP_CMD_PARSE
#define AUSYS_DA_CMD_EQ (0x01)
#define AUSYS_DA_CMD_SAMPLE_RATE (0x02)
#define AUSYS_DA_CMD_VOLUME (0x03)
#define AUSYS_DA_CMD_TEST_OPEN (0x04)
#define AUSYS_DA_CMD_TEST_CLOSE (0x05)
#define AUSYS_DA_CMD_TEST_SINE (0x06)
uint32 cmd = *(uint32 *)&winusb_device->ep_out->buffer[0];
uint32 len = *(uint32 *)&winusb_device->ep_out->buffer[4];
uint8 *p_content = &winusb_device->ep_out->buffer[4+4];
struct aueq_device *p_dev = (struct aueq_device*)dev_get(HG_AUEQ_DEVID);
uint32 sample_rate = *(uint32 *)p_content;
uint32 percent_0to100 = *(uint32 *)p_content;
uint32 cur_volume_0to100 = 0;
switch (cmd) {
case (AUSYS_DA_CMD_EQ):
if (p_dev) {
aueq_run(p_dev, (void *)p_content, len);
} else {
os_printf("eq dev is NULL\r\n");
}
break;
case (AUSYS_DA_CMD_SAMPLE_RATE):
ausys_da_change_sample_rate(sample_rate);
break;
case (AUSYS_DA_CMD_VOLUME):
ausys_da_get_cur_volume((uint32 *)&cur_volume_0to100);
os_printf("cur vol:%d\r\n", cur_volume_0to100);
ausys_da_change_volume(percent_0to100);
break;
case (AUSYS_DA_CMD_TEST_OPEN):
ausys_da_test_mode(AUSYS_DA_TEST_OPEN, 0, 0, 0);
break;
case (AUSYS_DA_CMD_TEST_CLOSE):
ausys_da_test_mode(AUSYS_DA_TEST_CLOSE, 0, 0, 0);
break;
case (AUSYS_DA_CMD_TEST_SINE):
ausys_da_test_mode(AUSYS_DA_TEST_PLAY_SINE, 0, 0, 0);
break;
}
#endif
rt_ssize_t win_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
win_usb_read(&winusb_device->parent, 0, winusb_device->ep_out->buffer, 512);
if(winusb_device->rx_handler != RT_NULL)
{
winusb_device->rx_handler(winusb_device->ep_out->buffer, size);
}
#if ISP_TUNNING_EN
rt_ssize_t win_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
uint16 head = *(uint16 *)&winusb_device->ep_out->buffer[0];
if (head == isp_tunning->tunning_head)
{
isp_tunning->cmd_head = head;
isp_tunning->cmd_num = *(uint16 *)&winusb_device->ep_out->buffer[2];
isp_tunning->cmd_channel = *(uint16 *)&winusb_device->ep_out->buffer[4];
isp_tunning->p_data = (uint16 *)&winusb_device->ep_out->buffer[8];
isp_tunning->p_winusb = (rt_device_t)&winusb_device->parent;
os_sema_up(&isp_tunning->usb_cmd_sema);
}
win_usb_read(&winusb_device->parent, 0, winusb_device->ep_out->buffer, 512);
#endif
return RT_EOK;
}
static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
{
winusb_device_t winusb_device = (winusb_device_t)func->user_data;
LOG_D("%s %x %d\r\n", __FUNCTION__, winusb_device->ep_in->buffer, size);
if(winusb_device->tx_handler != RT_NULL)
{
winusb_device->tx_handler( winusb_device->ep_in->buffer, size);
}
#if ISP_TUNNING_EN
os_sema_up(&isp_tunning->usb_write_sema);
#endif
return RT_EOK;
}
static ufunction_t cmd_func = RT_NULL;
static rt_err_t _ep0_cmd_handler(udevice_t device, rt_size_t size)
{
winusb_device_t winusb_device;
if(cmd_func != RT_NULL)
{
winusb_device = (winusb_device_t)cmd_func->user_data;
cmd_func = RT_NULL;
if(winusb_device->cmd_handler != RT_NULL)
{
winusb_device->cmd_handler(winusb_device->cmd_buff,size);
}
}
dcd_ep0_send_status(device->dcd);
return RT_EOK;
}
static rt_err_t _ep0_cmd_read(ufunction_t func, ureq_t setup)
{
winusb_device_t winusb_device = (winusb_device_t)func->user_data;
cmd_func = func;
rt_usbd_ep0_read(func->device,winusb_device->cmd_buff,setup->wLength,_ep0_cmd_handler);
return RT_EOK;
}
static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
switch(setup->bRequest)
{
os_printf("winusb bRequest:%x wIndex:%x \r\n",setup->bRequest,setup->wIndex);
case 'A':
switch(setup->wIndex)
{
case 0x05:
usbd_os_proerty_descriptor_send(func,setup,winusb_proerty,sizeof(winusb_proerty)/sizeof(winusb_proerty[0]));
break;
}
break;
case 0x0A://customer
_ep0_cmd_read(func, setup);
break;
}
return RT_EOK;
}
static rt_err_t _function_enable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
winusb_device_t winusb_device = (winusb_device_t)func->user_data;
LOG_D("%s\r\n", __FUNCTION__);
/* trig recieve data when function enable */
rt_ssize_t win_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
win_usb_read(&winusb_device->parent, 0, winusb_device->dat_buff, 512);
return RT_EOK;
}
static rt_err_t _function_disable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
static rt_err_t _winusb_descriptor_config(winusb_desc_t winusb, rt_uint8_t cintf_nr, rt_uint8_t device_is_hs)
{
#ifdef RT_USB_DEVICE_COMPOSITE
winusb->iad_desc.bFirstInterface = cintf_nr;
#endif
winusb->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
winusb->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
winusb_func_comp_id_desc.bFirstInterfaceNumber = cintf_nr;
return RT_EOK;
}
rt_ssize_t win_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
/* read & write by class, actually, all class use the same udcd */
winusb_device_t winusb_device = (winusb_device_t)dev;
udevice_t device = winusb_device->device;
//if(device->state != USB_STATE_CONFIGURED)
if(device == NULL)
{
return 0;
}
winusb_device->ep_out->buffer = buffer;
winusb_device->ep_out->request.buffer = buffer;
winusb_device->ep_out->request.size = size;
winusb_device->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(device,winusb_device->ep_out,&winusb_device->ep_out->request);
return size;
}
rt_ssize_t win_usb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
winusb_device_t winusb_device = (winusb_device_t)dev;
udevice_t device = winusb_device->device;
if (device->state != USB_STATE_CONFIGURED)
{
return 0;
}
winusb_device->ep_in->buffer = (void *)buffer;
winusb_device->ep_in->request.buffer = winusb_device->ep_in->buffer;
winusb_device->ep_in->request.size = size;
winusb_device->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(device,winusb_device->ep_in,&winusb_device->ep_in->request);
return size;
}
static rt_err_t win_usb_control(rt_device_t dev, int cmd, void *args)
{
//udcd_t udcd = (struct usb_device *)dev_get(HG_USB_DEV_CONTROLLER_DEVID);
winusb_device_t winusb_device = (winusb_device_t)dev;
//if(RT_DEVICE_CTRL_CONFIG == cmd)
{
winusb_device->cmd_handler = (void(*)(rt_uint8_t*,rt_size_t))args;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops winusb_device_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
win_usb_read,
win_usb_write,
win_usb_control,
};
#endif
static rt_err_t rt_usb_winusb_init(ufunction_t func)
{
// rt_err_t ret;
//winusb_device_t winusb_device = (winusb_device_t)func->user_data;
// struct usb_device *p_usb_d = (struct usb_device *)dev_get(HG_USB_DEV_CONTROLLER_DEVID);
// ret = dev_register(HG_USB_DEV_CONTROLLER_DEVID, (struct dev_obj *)p_usb_d);
return 0;
}
udevice_t g_winusb_device = NULL;
ufunction_t rt_usbd_function_winusb_create(udevice_t device)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
ufunction_t func;
winusb_device_t winusb_device;
uintf_t winusb_intf;
ualtsetting_t winusb_setting;
winusb_desc_t winusb_desc;
/* parameter check */
RT_ASSERT(device != RT_NULL);
g_winusb_device = device;
/* set usb device string description */
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, WINUSB_INTF_STR_INDEX, _ustring[2]);
rt_usbd_device_set_interface_string(device, USB_STRING_OS_INDEX, _ustring[6]);
#else
rt_usbd_device_set_string(device, _ustring);
rt_usbd_device_set_interface_string(device, USB_STRING_OS_INDEX, _ustring[6]);
#endif
/* create a cdc function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
rt_usbd_device_set_qualifier(device, &dev_qualifier);
/* allocate memory for cdc vcom data */
winusb_device = (winusb_device_t)rt_malloc(sizeof(struct winusb_device));
if (winusb_device == NULL)
return RT_NULL;
rt_memset((void *)winusb_device, 0, sizeof(struct winusb_device));
func->user_data = (void*)winusb_device;
winusb_device->user_data = (void *)func;
winusb_device->device = device;
/* create an interface object */
winusb_intf = rt_usbd_interface_new(device, _interface_handler);
/* create an alternate setting object */
winusb_setting = rt_usbd_altsetting_new(sizeof(struct winusb_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(winusb_setting, &_winusb_desc, (rt_off_t)&((winusb_desc_t)0)->intf_desc);
/* configure the hid interface descriptor */
_winusb_descriptor_config(winusb_setting->desc, winusb_intf->intf_num, device->dcd->device_is_hs);
/* create endpoint */
winusb_desc = (winusb_desc_t)winusb_setting->desc;
winusb_device->ep_out = rt_usbd_endpoint_new(&winusb_desc->ep_out_desc, _ep_out_handler);
winusb_device->ep_in = rt_usbd_endpoint_new(&winusb_desc->ep_in_desc, _ep_in_handler);
/* add the int out and int in endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(winusb_setting, winusb_device->ep_out);
rt_usbd_altsetting_add_endpoint(winusb_setting, winusb_device->ep_in);
/* add the alternate setting to the interface, then set default setting */
rt_usbd_interface_add_altsetting(winusb_intf, winusb_setting);
rt_usbd_set_altsetting(winusb_intf, 0);
/* add the interface to the mass storage function */
rt_usbd_function_add_interface(func, winusb_intf);
rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(device->os_comp_id_desc, &winusb_func_comp_id_desc);
/* initilize winusb */
rt_usb_winusb_init(func);
return func;
}
struct udclass winusb_class =
{
.rt_usbd_function_create = rt_usbd_function_winusb_create
};
int rt_usbd_winusb_class_register(rt_uint32_t dev_id)
{
rt_usbd_class_register(&winusb_class, dev_id);
return 0;
}
INIT_PREV_EXPORT(rt_usbd_winusb_class_register);
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-11-16 ZYH first version
*/
#ifndef __WINUSB_H__
#define __WINUSB_H__
#include <rtthread.h>
struct winusb_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct uendpoint_descriptor ep_out_desc;
struct uendpoint_descriptor ep_in_desc;
};
typedef struct winusb_descriptor* winusb_desc_t;
#endif

View File

@@ -0,0 +1,334 @@
/*
* File : hid.c
* COPYRIGHT (C) 2006 - 2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-02 Yi Qiu first version
*/
#include <rtthread.h>
//#include <rtdevice.h>
#include <rtservice.h>
#include "include/rttusb_device.h"
#ifdef RT_USING_USB_DEVICE
#define USB_DEVICE_CONTROLLER_NAME "usbd"
#define HG_USB_DEVICE_NUM 2
typedef struct {
rt_list_t class_list;
rt_uint32_t dev_id;
}class_list_device;
static class_list_device usbd_class_list[HG_USB_DEVICE_NUM] =
{
{
.dev_id = HG_USB_DEV_CONTROLLER_DEVID,
},
{
.dev_id = HG_USB11_DEV_CONTROLLER_DEVID,
}
};
#ifdef RT_USB_DEVICE_COMPOSITE
const static char* ustring[] =
{
"Language",
"RT-Thread Team.",
"RTT Composite Device",
"320219198301",
"Configuration",
"Interface",
USB_STRING_OS
};
static struct udevice_descriptor compsit_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
USB_CLASS_MISC, //bDeviceClass;
0x02, //bDeviceSubClass;
0x01, //bDeviceProtocol;
0x40, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_MISC, //bDeviceClass
0x02, //bDeviceSubClass
0x01, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
#endif
struct usb_os_comp_id_descriptor usb_comp_id_desc =
{
//head section
{
USB_DYNAMIC,
0x0100,
0x04,
USB_DYNAMIC,
{0x00,0x00,0x00,0x00,0x00,0x00,0x00},
},
};
static rt_list_t *rt_usbd_find_class_list(rt_uint32_t devid)
{
rt_list_t *class_list = RT_NULL;
rt_uint32_t i = 0;
for(i = 0; i < HG_USB_DEVICE_NUM; i++)
{
if(usbd_class_list[i].dev_id == devid)
{
class_list = &usbd_class_list[i].class_list;
}
}
return class_list;
}
int rt_usbd_class_list_init(rt_uint32_t devid)
{
rt_list_t *class_list = rt_usbd_find_class_list(devid);
if (class_list) {
rt_list_init(class_list);
}
return 0;
}
int rt_usbd_class_list_deinit(rt_uint32_t devid)
{
rt_list_t *class_list = rt_usbd_find_class_list(devid);
if (class_list) {
if(!rt_list_isempty(class_list)){
rt_list_del(class_list);
}
}
return 0;
}
rt_err_t rt_usbd_class_register(udclass_t udclass, rt_uint32_t devid)
{
rt_list_t *class_list = rt_usbd_find_class_list(devid);
if (class_list == RT_NULL) {
return RT_ERROR;
}
#ifndef RT_USB_DEVICE_COMPOSITE
if(!rt_list_isempty(class_list))
{
rt_kprintf("[D/USBD] If you want to use usb composite device please define RT_USB_DEVICE_COMPOSITE\n");
return -RT_ERROR;
}
#endif
if(rt_usbd_class_driver_find(udclass, devid) == RT_NULL)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
rt_list_insert_before(class_list,&udclass->list);
}
return RT_EOK;
}
rt_err_t rt_usbd_class_driver_unregister(udclass_t udclass, rt_uint32_t devid)
{
if(udclass == RT_NULL)
{
return -RT_ERROR;
}
if(rt_usbd_class_driver_find(udclass, devid) != RT_NULL)
{
os_printf("%s %d\n",__FUNCTION__,__LINE__);
rt_list_remove(&udclass->list);
}
return RT_EOK;
}
udclass_t rt_usbd_class_driver_find(udclass_t udclass, rt_uint32_t devid)
{
rt_list_t *class_list = rt_usbd_find_class_list(devid);
if (class_list == RT_NULL) {
return RT_NULL;
}
struct rt_list_node *node;
for (node = class_list->next; node != class_list; node = node->next)
{
udclass_t udc = (udclass_t)rt_list_entry(node, struct udclass, list);
if(udc == udclass)
{
return udc;
}
}
return RT_NULL;
}
rt_err_t rt_usb_device_init(rt_uint32_t devid, const char *dev)
{
rt_device_t udc;
udcd_t udc_t;
udevice_t udevice;
uconfig_t cfg;
ufunction_t func = RT_NULL;
rt_list_t *i;
udclass_t udclass;
rt_list_t *class_list = rt_usbd_find_class_list(devid);
if (class_list == RT_NULL) {
return -RT_ERROR;
}
if(rt_list_isempty(class_list))
{
rt_kprintf("[D/USBD] No class register on usb device\n");
return -RT_ERROR;
}
udc = dev_get(devid);
if(udc == RT_NULL)
{
rt_kprintf("can't find usb device controller %s\n", dev);
return -RT_ERROR;
}
udc_t = (udcd_t)udc;
udc_t->usb_thread = RT_NULL;
/* create and startup usb device thread */
rt_usbd_core_init(dev, (void **)&udc_t->usb_thread, (void *)&udc_t->usb_mq);
os_printf("[D/USBD] usb device thread created : %x\n",udc_t->usb_thread);
/* create a device object */
udevice = rt_usbd_device_new();
os_printf("%s %d\n",__FUNCTION__,__LINE__);
udc_t->p_udevice = udevice;
//os_printf("udevice:%x udc_t->p_udevice:%x\n",udevice,udc_t->p_udevice);
/* set usb controller driver to the device */
rt_usbd_device_set_controller(udevice, (udcd_t)udc);
/* create a configuration object */
cfg = rt_usbd_config_new();
udc_t->cfg = cfg;
rt_usbd_device_set_os_comp_id_desc(udevice, &usb_comp_id_desc);
for(i = class_list->next; i!= class_list; i = i->next)
{
/* get a class creater */
udclass = rt_list_entry(i, struct udclass, list);
/* create a function object */
func = udclass->rt_usbd_function_create(udevice);
/* add the function to the configuration */
rt_usbd_config_add_function(cfg, func);
}
/* set device descriptor to the device */
#ifdef RT_USB_DEVICE_COMPOSITE
if(udevice->dcd->device_is_hs)
{
compsit_desc.bcdUSB = 0x0200;
rt_usbd_device_set_qualifier(udevice, &dev_qualifier);
}
else
{
compsit_desc.bcdUSB = 0x0110;
}
rt_usbd_device_set_descriptor(udevice, &compsit_desc);
rt_usbd_device_set_string(udevice, ustring);
#else
if(udevice->dcd->device_is_hs)
{
func->dev_desc->bcdUSB = 0x0200;
}
else
{
func->dev_desc->bcdUSB = 0x0110;
}
rt_usbd_device_set_descriptor(udevice, func->dev_desc);
#endif
/* add the configuration to the device */
rt_usbd_device_add_config(udevice, cfg);
/* initialize usb device controller */
rt_device_init(udc);
/* set default configuration to 1 */
rt_usbd_set_config(udevice, 1);
return RT_EOK;
}
rt_err_t rt_usb_device_deinit(rt_uint32_t devid)
{
udcd_t udc;
rt_list_t *i;
udclass_t udclass;
udc = (udcd_t)dev_get(devid);
if(udc == RT_NULL)
{
rt_kprintf("can't find usb device controller %s\n", USB_DEVICE_CONTROLLER_NAME);
return -RT_ERROR;
}
rt_usbd_core_deinit((void **)&udc->usb_thread, (void *)&udc->usb_mq);
rt_list_t *class_list = rt_usbd_find_class_list(devid);
if (class_list == RT_NULL) {
return -RT_ERROR;
}
if(rt_list_isempty(class_list))
{
rt_kprintf("[D/USBD] No class register on usb device\n");
}
else
{
for(i = class_list->next; i!= class_list; i = i->next)
{
/* get a class creater */
udclass = rt_list_entry(i, struct udclass, list);
/* create a function object */
udclass->rt_usbd_function_delete();
}
}
rt_usbd_ep_unassign(udc->p_udevice, RT_NULL);
if(udc->cfg != RT_NULL)
{
rt_free(udc->cfg);
udc->cfg = RT_NULL;
}
if(udc->p_udevice != RT_NULL)
{
rt_free(udc->p_udevice);
udc->p_udevice = RT_NULL;
}
return RT_EOK;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,426 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "adk.h"
#ifdef RT_USBH_ADK
//#define DBG_TAG "usbhost.adk"
//#define DBG_LVL DBG_INFO
//#include <rtdbg.h>
static struct uclass_driver adk_driver;
static const char* _adk_manufacturer = RT_NULL;
static const char* _adk_model = RT_NULL;
static const char* _adk_description = RT_NULL;
static const char* _adk_version = RT_NULL;
static const char* _adk_uri = RT_NULL;
static const char* _adk_serial = RT_NULL;
rt_err_t rt_usbh_adk_set_string(const char* manufacturer, const char* model,
const char* description, const char* _version, const char* uri,
const char* serial)
{
_adk_manufacturer = manufacturer;
_adk_model = model;
_adk_description = description;
_adk_version = _version;
_adk_uri = uri;
_adk_serial = serial;
return RT_EOK;
}
#ifdef RT_USING_MODULE
#include <rtm.h>
RTM_EXPORT(rt_usbh_adk_set_string);
#endif
/**
* This function will do USB_REQ_GET_PROTOCOL request to set idle period to the usb adk device
*
* @param intf the interface instance.
* @duration the idle period of requesting data.
* @report_id the report id
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_get_protocol(struct uintf* intf, rt_uint16_t *protocol)
{
struct urequest setup;
uinst_t device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_VENDOR |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_GET_PROTOCOL;
setup.index = 0;
setup.length = 2;
setup.value = 0;
if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)protocol, 2,
timeout) == 0) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will do USB_REQ_SEND_STRING request to set idle period to the usb adk device
*
* @param intf the interface instance.
* @duration the idle period of requesting data.
* @report_id the report id
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_send_string(struct uintf* intf, rt_uint16_t index,
const char* str)
{
struct urequest setup;
uinst_t device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_SEND_STRING;
setup.index = index;
setup.length = rt_strlen(str) + 1;
setup.value = 0;
if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)str,
rt_strlen(str) + 1, timeout) == 0) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will do USB_REQ_START request to set idle period to the usb adk device
*
* @param intf the interface instance.
* @duration the idle period of requesting data.
* @report_id the report id
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_start(struct uintf* intf)
{
struct urequest setup;
uinst_t device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_START;
setup.index = 0;
setup.length = 0;
setup.value = 0;
if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0,
timeout) == 0) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will read data from usb adk device
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_ssize_t rt_usbh_adk_read(rt_device_t device, rt_off_t pos, void* buffer,
rt_size_t size)
{
uadk_t adk;
rt_size_t length;
struct uintf* intf;
/* check parameter */
RT_ASSERT(device != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
intf = (struct uintf*)device->user_data;
adk = (uadk_t)intf->user_data;
length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_in,
buffer, size, 300);
return length;
}
/**
* This function will write data to usb adk device
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_ssize_t rt_usbh_adk_write (rt_device_t device, rt_off_t pos, const void* buffer,
rt_size_t size)
{
uadk_t adk;
rt_size_t length;
struct uintf* intf;
RT_ASSERT(buffer != RT_NULL);
intf = (struct uintf*)device->user_data;
adk = (uadk_t)intf->user_data;
length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_out,
(void*)buffer, size, 300);
return length;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops adk_device_ops =
{
RT_NULL;
RT_NULL;
RT_NULL;
rt_usbh_adk_read;
rt_usbh_adk_write;
RT_NULL;
};
#endif
/**
* This function will run adk class driver when usb device is detected and identified
* as a adk class device, it will continue the enumulate process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_enable(void* arg)
{
int i = 0;
uadk_t adk;
struct uintf* intf = (struct uintf*)arg;
udev_desc_t dev_desc;
rt_uint16_t protocol;
rt_err_t ret;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
LOG_D("rt_usbh_adk_run");
dev_desc = &intf->device->dev_desc;
if(dev_desc->idVendor == USB_ACCESSORY_VENDOR_ID &&
(dev_desc->idProduct == USB_ACCESSORY_PRODUCT_ID ||
dev_desc->idProduct == USB_ACCESSORY_ADB_PRODUCT_ID))
{
if(intf->intf_desc->bInterfaceSubClass != 0xFF) return -RT_ERROR;
LOG_D("found android accessory device");
}
else
{
LOG_D("switch device");
if((ret = rt_usbh_adk_get_protocol(intf, &protocol)) != RT_EOK)
{
rt_kprintf("rt_usbh_adk_get_protocol failed\n");
return ret;
}
if(protocol != 1)
{
rt_kprintf("read protocol failed\n");
return -RT_ERROR;
}
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_MANUFACTURER, _adk_manufacturer);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_MODEL, _adk_model);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_DESCRIPTION, _adk_description);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_VERSION, _adk_version);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_URI, _adk_uri);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_SERIAL, _adk_serial);
LOG_D("manufacturer %s", _adk_manufacturer);
LOG_D("model %s", _adk_model);
LOG_D("description %s", _adk_description);
LOG_D("version %s", _adk_version);
LOG_D("uri %s", _adk_uri);
LOG_D("serial %s", _adk_serial);
if((ret = rt_usbh_adk_start(intf)) != RT_EOK)
{
rt_kprintf("rt_usbh_adk_start failed\n");
return ret;
}
return RT_EOK;
}
adk = rt_malloc(sizeof(struct uadkinst));
RT_ASSERT(adk != RT_NULL);
/* initilize the data structure */
rt_memset(adk, 0, sizeof(struct uadkinst));
intf->user_data = (void*)adk;
for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
{
uep_desc_t ep_desc;
/* get endpoint descriptor from interface descriptor */
rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
/* the endpoint type of adk class should be BULK */
if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
/* allocate pipes according to the endpoint type */
if(ep_desc->bEndpointAddress & USB_DIR_IN)
{
/* allocate an in pipe for the adk instance */
ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_in,
intf, ep_desc, RT_NULL);
if(ret != RT_EOK) return ret;
}
else
{
/* allocate an output pipe for the adk instance */
ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_out,
intf, ep_desc, RT_NULL);
if(ret != RT_EOK) return ret;
}
}
/* check pipes infomation */
if(adk->pipe_in == RT_NULL || adk->pipe_out == RT_NULL)
{
rt_kprintf("pipe error, unsupported device\n");
return -RT_ERROR;
}
/* set configuration */
ret = rt_usbh_set_configure(intf->device, 1);
if(ret != RT_EOK) return ret;
/* register adk device */
adk->device.type = RT_Device_Class_Char;
#ifdef RT_USING_DEVICE_OPS
adk->device.ops = &adk_device_ops;
#else
adk->device.init = RT_NULL;
adk->device.open = RT_NULL;
adk->device.close = RT_NULL;
adk->device.read = rt_usbh_adk_read;
adk->device.write = rt_usbh_adk_write;
adk->device.control = RT_NULL;
#endif
adk->device.user_data = (void*)intf;
rt_device_register(&adk->device, "adkdev", RT_DEVICE_FLAG_RDWR);
return RT_EOK;
}
/**
* This function will be invoked when usb device plug out is detected and it would clean
* and release all hub class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_disable(void* arg)
{
uadk_t adk;
struct uintf* intf = (struct uintf*)arg;
RT_ASSERT(intf != RT_NULL);
LOG_D("rt_usbh_adk_stop");
adk = (uadk_t)intf->user_data;
if(adk == RT_NULL)
{
rt_free(intf);
return RT_EOK;
}
if(adk->pipe_in != RT_NULL)
rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_in);
if(adk->pipe_out != RT_NULL)
rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_out);
/* unregister adk device */
rt_device_unregister(&adk->device);
/* free adk instance */
if(adk != RT_NULL)
{
rt_free(adk);
}
/* free interface instance */
rt_free(intf);
return RT_EOK;
}
/**
* This function will register adk class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usbh_class_driver_adk(void)
{
adk_driver.class_code = USB_CLASS_ADK;
adk_driver.enable = rt_usbh_adk_enable;
adk_driver.disable = rt_usbh_adk_disable;
return &adk_driver;
}
#endif

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __ADK_H__
#define __ADK_H__
#include <rtthread.h>
struct uadkinst
{
upipe_t pipe_in;
upipe_t pipe_out;
struct rt_device device;
};
typedef struct uadkinst* uadk_t;
#define USB_ACCESSORY_VENDOR_ID 0x18D1
#define USB_ACCESSORY_PRODUCT_ID 0x2D00
#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
#define ACCESSORY_STRING_MANUFACTURER 0
#define ACCESSORY_STRING_MODEL 1
#define ACCESSORY_STRING_DESCRIPTION 2
#define ACCESSORY_STRING_VERSION 3
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
#define USB_REQ_GET_PROTOCOL 51
#define USB_REQ_SEND_STRING 52
#define USB_REQ_START 53
#define USB_CLASS_ADK 0xff
#endif

View File

@@ -0,0 +1,482 @@
#include "include/rttusb_host.h"
#include "cdc.h"
#ifdef RT_USBH_VENDOR_YUGE
#include "yuge.h"
#endif
#ifdef RT_USBH_VENDOR_ZXINFO
#include "zxinfo.h"
#endif
#ifdef RT_USBH_CDC
#ifdef RT_USBH_CDC_THREAD
#define EVENT_CDC_DATA_START (1 << 0)
#define EVENT_CDC_DATA_END (1 << 1)
static ucdc_data_t cdc_d;
static rt_event_t cdc_data_event;
uint8_t buff_out[64] __attribute__((aligned(4)));
uint8_t buff_in[64 + USB_RX_BUFF_RESERVE_SIZE] __attribute__((aligned(4)));
#endif
static struct uclass_driver cdc_driver;
rt_err_t rt_usbh_cdc_send_command(uinst_t device, void* buffer, int nbytes)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = SEND_ENCAPSULATED_COMMAND;
setup.wIndex = 0;
setup.wLength = nbytes;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, buffer, nbytes, timeout) == nbytes)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
return nbytes;
}
}
}
return RT_ERROR;
}
rt_err_t rt_usbh_cdc_get_response(uinst_t device, void* buffer, int nbytes)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
int ret_size;
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = GET_ENCAPSULATED_RESPONSE;
setup.wIndex = 0;
setup.wLength = nbytes;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
ret_size = rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout);
if(ret_size > 0)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return ret_size;
}
}
}
return RT_ERROR;
}
rt_err_t rt_usbh_cdc_get_line_coding(uinst_t device, int intf, void* buffer)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
int ret_size;
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = GET_LINE_CODING;
setup.wIndex = intf;
setup.wLength = 7;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
ret_size = rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, 7, timeout);
if(ret_size == 7)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return ret_size;
}
}
}
return RT_ERROR;
}
rt_err_t rt_usbh_cdc_set_line_coding(uinst_t device, int intf, void* buffer)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = SET_LINE_CODING;
setup.wIndex = intf; // interface
setup.wLength = 7;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, buffer, 7, timeout) == 7)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
return -RT_ERROR;
}
rt_err_t rt_usbh_cdc_set_control_line_state(uinst_t device, int intf, void * buffer, int len)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = SET_CONTROL_LINE_STATE;
setup.wIndex = intf; // interface
setup.wLength = len;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
return -RT_ERROR;
}
void analysis_cdc_line_coding(struct usb_cdc_line_coding * line_coding)
{
os_printf("=========line coding=========\n");
os_printf("dwDTERate:%d\n", line_coding->dwDTERate);
os_printf("bCharFormat:%d\n", line_coding->bCharFormat);
os_printf("bParityType:%d\n", line_coding->bParityType);
os_printf("bDataBits:%d\n", line_coding->bDataBits);
os_printf("=============================\n");
}
static rt_err_t rt_usbh_get_CDC_interface_descriptor(ucfg_desc_t cfg_desc, int num,
uintf_desc_t* intf_desc)
{
rt_uint32_t ptr, depth = 0;
udesc_t desc;
/* check parameter */
RT_ASSERT(cfg_desc != RT_NULL);
ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength;
while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength)
{
if(depth++ > 0x40)
{
*intf_desc = RT_NULL;
return -RT_EIO;
}
desc = (udesc_t)ptr;
if(desc->type == USB_DESC_TYPE_INTERFACE)
{
if(((uintf_desc_t)desc)->bNumEndpoints == 0)
{
ptr = (rt_uint32_t)desc + desc->bLength;
continue;
}
if(((uintf_desc_t)desc)->bInterfaceNumber == num)
{
*intf_desc = (uintf_desc_t)desc;
LOG_D("rt_usb_get_interface_descriptor: %d", num);
return RT_EOK;
}
}
ptr = (rt_uint32_t)desc + desc->bLength;
}
rt_kprintf("rt_usb_get_interface_descriptor %d failed\n", num);
return -RT_EIO;
}
#ifdef RT_USBH_CDC_THREAD
int32 demo_atcmd_cdc_trans_ctrl(const char *cmd, char *argv[], uint32 argc)
{
if(*argv[0] == '1') {
rt_usbh_cdc_trans_init();
} else if(*argv[0] == '2') {
rt_usbh_cdc_trans_deinit();
}
printf("OK/n");
return 0;
}
void rt_usbh_cdc_trans_init()
{
if (cdc_data_event != RT_NULL) {
rt_event_send(cdc_data_event, EVENT_CDC_DATA_START);
}
}
void rt_usbh_cdc_trans_deinit()
{
if (cdc_data_event != RT_NULL) {
rt_event_send(cdc_data_event, EVENT_CDC_DATA_END);
}
}
static void rt_usbh_cdc_communication_thread(void* arg)
{
int i;
struct uhintf **intf = arg;
// uhcd_t hcd = NULL;
// uintf_desc_t intf_desc;
int timeout = USB_TIMEOUT_BASIC;
rt_uint32_t e;
struct usb_cdc_line_coding *line_coding = (struct usb_cdc_line_coding *)rt_malloc(sizeof(struct usb_cdc_line_coding) + USB_RX_BUFF_RESERVE_SIZE);
if(line_coding == RT_NULL)
{
rt_kprintf("rt_usbh_cdc_communication_thread malloc line_coding failed\n");
goto __exit;
}
os_printf("rt_usbh_cdc_communication_thread arg:%x\n",arg);
cdc_d->thread_state = 1;
cdc_d->line_coding = line_coding;
while(1)
{
if (rt_event_recv(cdc_data_event, EVENT_CDC_DATA_START | EVENT_CDC_DATA_END,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK)
{
continue;
}
if (e & EVENT_CDC_DATA_START)
{
}else if(e & EVENT_CDC_DATA_END)
{
goto __exit;
}else
{
continue;
}
os_printf("cdc translate strat\n");
memset(line_coding, 0, sizeof(struct usb_cdc_line_coding));
rt_usbh_cdc_get_line_coding(intf[0]->device, intf[0]->intf_desc->bInterfaceNumber, line_coding);
analysis_cdc_line_coding(line_coding);
line_coding->dwDTERate = BAUD_RATE_2000000;
line_coding->bCharFormat = STOP_BITS_1;
line_coding->bParityType = PARITY_NONE;
line_coding->bDataBits = DATA_BITS_8;
rt_usbh_cdc_set_line_coding(intf[0]->device, intf[0]->intf_desc->bInterfaceNumber, line_coding);
analysis_cdc_line_coding(line_coding);
memset(line_coding, 0, sizeof(struct usb_cdc_line_coding));
rt_usbh_cdc_get_line_coding(intf[0]->device, intf[0]->intf_desc->bInterfaceNumber, line_coding);
rt_usbh_cdc_set_control_line_state(intf[0]->device, intf[0]->intf_desc->bInterfaceNumber, RT_NULL, 0);
analysis_cdc_line_coding(line_coding);
if(cdc_d->pipe_in == RT_NULL && cdc_d->pipe_out == RT_NULL)
{
for(i = 0; i < intf[1]->intf_desc->bNumEndpoints; i++)
{
uep_desc_t ep_desc;
upipe_t pipe;
rt_usbh_get_endpoint_descriptor(intf[1]->intf_desc, i, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return ;
}
analysis_usb_ep_desc(ep_desc); //获取端点描述符 打印端点描述符信息
/* the endpoint type of mass storage class should be BULK */
if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
if (rt_usb_hcd_alloc_pipe(intf[0]->device->hcd, &pipe, intf[0]->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return ;
}
rt_usb_instance_add_pipe(intf[0]->device, pipe);
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
cdc_d->pipe_in = pipe;
os_printf("cdc_d->pipe_in:%x pipe:%x\n",cdc_d->pipe_in,pipe);
} else {
cdc_d->pipe_out = pipe;
os_printf("cdc_d->pipe_out:%x pipe:%x\n",cdc_d->pipe_out,pipe);
}
}
}
if(cdc_d->pipe_in != RT_NULL && cdc_d->pipe_out != RT_NULL)
{
buff_out[0] = 0xAA;
buff_out[1] = 0x55;
buff_out[2] = 0xD1;
buff_out[3] = 0x00;
buff_out[4] = 0x00;
buff_out[5] = 0x00;
buff_out[6] = 0x00;
buff_out[7] = 0x00;
buff_out[8] = 0x00;
buff_out[9] = 0xD0;
memset(buff_in,0,10);
rt_usb_hcd_pipe_xfer(intf[0]->device->hcd, cdc_d->pipe_out, buff_out, 64, timeout);
rt_usb_hcd_pipe_xfer(intf[0]->device->hcd, cdc_d->pipe_in, buff_in, 64, timeout);
for(int i = 0; i < 10; i++)
{
printf("buff_in[%d]:%x\n",i,buff_in[i]);
}
}
}
__exit:
if (cdc_d->line_coding != RT_NULL)
{
rt_free(cdc_d->line_coding);
cdc_d->line_coding = RT_NULL;
}
rt_thread_suspend(cdc_d->thread);
cdc_d->thread_state = 0;
return ;
}
#endif
static rt_err_t rt_usbh_cdc_enable(void *arg)
{
struct uhintf **intf = arg;
uhcd_t hcd = NULL;
if (intf[0] == NULL) {
return -EIO;
}
hcd = intf[0]->device->hcd;
os_printf("subclass %d, protocal %d\r\n",
intf[0]->intf_desc->bInterfaceSubClass,
intf[0]->intf_desc->bInterfaceProtocol);
#ifdef RT_USBH_CDC_THREAD
cdc_d = rt_malloc(sizeof(struct ucdc_data));
if(cdc_d == RT_NULL)
{
rt_kprintf("allocate cdc_d memory failed\n");
return -RT_ENOMEM;
}
rt_memset(cdc_d, 0, sizeof(struct ucdc_data));
cdc_d->device = intf[0]->device;
os_printf("cdc_d:%x cdc_d->device:%x hcd:%x\n",cdc_d,cdc_d->device,cdc_d->device->hcd);
intf[0]->user_data = (void *)cdc_d;
os_printf("rt_usbh_cdc_enable arg:%x\n",arg);
cdc_data_event = rt_event_create("cdc_data_event", RT_IPC_FLAG_FIFO);
cdc_d->thread = rt_thread_create("cdc_comm_thread",rt_usbh_cdc_communication_thread,arg,1024,OS_TASK_PRIORITY_NORMAL,0);
if(cdc_d->thread != RT_NULL)
{
rt_thread_startup(cdc_d->thread);
}
#endif
#ifdef RT_USBH_VENDOR_YUGE
if (intf[0]->device->dev_desc.idVendor == USB_VENDOR_ID_YUGE) {
rt_usbh_yuge_at_run(intf);
}
#endif
#ifdef RT_USBH_VENDOR_ZXINFO
if (intf[0]->device->dev_desc.idVendor == USB_VENDOR_ID_ZXINFO) {
rt_usbh_zxinfo_at_run(intf);
}
#endif
return RET_OK;
}
static rt_err_t rt_usbh_cdc_disable(void *arg)
{
struct uhintf *intf = arg;
#ifdef RT_USBH_CDC_THREAD
rt_usbh_cdc_trans_deinit();
while(!cdc_d->thread_state)
{
rt_thread_delay(1);
}
if(cdc_d->thread != RT_NULL)
{
rt_thread_delete(cdc_d->thread);
cdc_d->thread = RT_NULL;
}
if(cdc_data_event != RT_NULL)
{
rt_event_delete(cdc_data_event);
cdc_data_event = RT_NULL;
}
if(cdc_d != RT_NULL)
{
rt_free(cdc_d);
cdc_d = RT_NULL;
}
#endif
#ifdef RT_USBH_VENDOR_YUGE
if (intf->device->dev_desc.idVendor == USB_VENDOR_ID_YUGE) {
rt_usbh_yuge_at_stop(intf);
}
#endif
#ifdef RT_USBH_VENDOR_ZXINFO
if (intf->device->dev_desc.idVendor == USB_VENDOR_ID_ZXINFO) {
rt_usbh_zxinfo_at_stop(intf);
}
#endif
return RET_OK;
}
ucd_t rt_usbh_class_driver_cdc(void)
{
cdc_driver.class_code = USB_CLASS_COMM;
cdc_driver.enable = rt_usbh_cdc_enable;
cdc_driver.disable = rt_usbh_cdc_disable;
return &cdc_driver;
}
#endif

View File

@@ -0,0 +1,95 @@
#ifndef __CLASS_CDC_H__
#define __CLASS_CDC_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtthread.h>
#define SEND_ENCAPSULATED_COMMAND 0x00
#define GET_ENCAPSULATED_RESPONSE 0x01
// CDC PSTN Subclass
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
#define CDC_RX_BUFSIZE 128
#define CDC_TX_BUFSIZE 1024
/* The baudrate can be defined as*/
#define BAUD_RATE_2400 2400
#define BAUD_RATE_4800 4800
#define BAUD_RATE_9600 9600
#define BAUD_RATE_19200 19200
#define BAUD_RATE_38400 38400
#define BAUD_RATE_57600 57600
#define BAUD_RATE_115200 115200
#define BAUD_RATE_230400 230400
#define BAUD_RATE_460800 460800
#define BAUD_RATE_921600 921600
#define BAUD_RATE_2000000 2000000
#define BAUD_RATE_3000000 3000000
/* Data bits can be defined as*/
#define DATA_BITS_5 5
#define DATA_BITS_6 6
#define DATA_BITS_7 7
#define DATA_BITS_8 8
#define DATA_BITS_9 9
/* Stop bits can be defined as */
#define STOP_BITS_1 0
#define STOP_BITS_2 1
#define STOP_BITS_3 2
#define STOP_BITS_4 3
/* Parity bits can be defined as */
#define PARITY_NONE 0
#define PARITY_ODD 1
#define PARITY_EVEN 2
/* Bit order can be defined as */
#define BIT_ORDER_LSB 0
#define BIT_ORDER_MSB 1
/* Mode canbe defined as */
#define NRZ_NORMAL 0 /* normal mode */
#define NRZ_INVERTED 1 /* inverted mode */
/* Default size of the receive data buffer */
#define RT_SERIAL_RB_BUFSZ 64
struct ucdc_data
{
struct uinstance* device;
upipe_t pipe_in;
upipe_t pipe_out;
struct usb_cdc_line_coding* line_coding;
rt_uint8_t rx_rbp[CDC_RX_BUFSIZE];
struct rt_ringbuffer rx_ringbuffer;
rt_uint8_t tx_rbp[CDC_TX_BUFSIZE];
struct rt_ringbuffer tx_ringbuffer;
rt_thread_t thread;
rt_uint32_t thread_state;
};
typedef struct ucdc_data* ucdc_data_t;
struct usb_cdc_line_coding {
rt_uint32_t dwDTERate;
rt_uint8_t bCharFormat;
rt_uint8_t bParityType;
rt_uint8_t bDataBits;
} __attribute__((packed));
rt_err_t rt_usbh_cdc_send_command(uinst_t device, void* buffer, int nbytes);
rt_err_t rt_usbh_cdc_get_response(uinst_t device, void* buffer, int nbytes);
rt_err_t rt_usbh_cdc_get_line_coding(uinst_t device, int intf, void* buffer);
rt_err_t rt_usbh_cdc_set_line_coding(uinst_t device, int intf, void* buffer);
rt_err_t rt_usbh_cdc_set_control_line_state(uinst_t device, int intf, void * buffer, int len);
void analysis_cdc_line_coding(struct usb_cdc_line_coding * line_coding);
void rt_usbh_cdc_trans_init();
void rt_usbh_cdc_trans_deinit();
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,361 @@
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "chinamobile.h"
#include "cdc.h"
#include "rndis.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
#include "lwip/tcpip.h"
#include "netif/ethernetif.h"
#include "lib/common/sysevt.h"
#ifdef RT_USBH_VENDOR_CHINAMOBILE
#define USB_VENDOR_ID_CHINAMOBILE 0x2ECC
#define USB_PRODUCT_ID_CHINAMOBILE 0x3012 // ML307R
#define CHINAMOBILE_ATCMD_BUFF_SIZE 128
static char recv_str[CHINAMOBILE_ATCMD_BUFF_SIZE];
static struct uclass_driver chinamobile_driver;
static rt_bool_t send_recv_atcmd_check(void *context, const char *send_str,
const char *check_str, char *ret_str)
{
struct usb_chinamobile_at *chinamobile_at = context;
uinst_t device = chinamobile_at->device;
int recv_size;
char *recv_str = NULL;
rt_bool_t pass = RT_FALSE;
os_sprintf((char *)chinamobile_at->at_cmd_buff, send_str);
rt_usb_hcd_pipe_xfer(device->hcd, chinamobile_at->pipe_out,
chinamobile_at->at_cmd_buff, os_strlen(send_str), 0);
os_sleep_ms(10); // 需要点延迟给LTE模组反应
do {
// 每次读取会清除缓存
os_memset(chinamobile_at->at_cmd_buff, 0, CHINAMOBILE_ATCMD_BUFF_SIZE);
recv_size = rt_usb_hcd_pipe_xfer(device->hcd, chinamobile_at->pipe_in,
chinamobile_at->at_cmd_buff, CHINAMOBILE_ATCMD_BUFF_SIZE, 10);
if (recv_size > 0) {
recv_str = os_strstr(chinamobile_at->at_cmd_buff, check_str);
if (recv_str != NULL) {
pass = RT_TRUE;
if (ret_str != NULL && recv_size > os_strlen(check_str)) {
// ret_str存在说明需要获取返回结果做额外判断复制到函数外面
os_memcpy(ret_str, recv_str + os_strlen(check_str),
recv_size - os_strlen(check_str));
ret_str[recv_size - os_strlen(check_str)] = '\0'; // 字符串结束符
}
}
}
} while (recv_size > 0);
return pass;
}
// 计算下行频点FDD不知道上行频点号猜测直接偏固定频率
static rt_uint16_t eutra_channel_freq_mapping(rt_uint8_t band, rt_uint16_t earfcn, rt_bool_t uplink)
{
rt_uint16_t freq = 0;
switch (band) {
// FDD上下行频点有偏差
case 3:
freq = 1805 + (earfcn - 1200) / 10;
if (uplink)
freq -= 95;
break;
case 5:
freq = 869 + (earfcn - 2400) / 10;
if (uplink)
freq -= 45;
break;
case 8:
freq = 925 + (earfcn - 3450) / 10;
if (uplink)
freq -= 45;
break;
// TDD上下行使用相同频点
case 34: freq = 2010 + (earfcn - 36200) / 10; break;
case 38: freq = 2570 + (earfcn - 37750) / 10; break;
case 39: freq = 1880 + (earfcn - 38250) / 10; break;
case 40: freq = 2300 + (earfcn - 38650) / 10; break;
case 41: freq = 2496 + (earfcn - 39650) / 10; break;
default: break;
}
return freq;
}
static void chinamobile_network_info(void *context, char *recv_str)
{
struct usb_chinamobile_at *chinamobile_at = context;
//char *argv[16];
char **argv = NULL;
int argc = 0;
rt_int16_t rsrp, rssi, sinr, rsrq;
rt_uint16_t num_dl;
rt_uint16_t freq_dl, freq_ul;
rt_uint8_t band = 0;
argv = os_malloc(16 * sizeof(char *));
if (argv == NULL) {
return;
}
// 获取运营商
if (send_recv_atcmd_check(chinamobile_at, "AT+COPS?\r\n", "+COPS:", recv_str) == RT_TRUE) {
argc = os_strtok(recv_str, ",", argv, 16);
if (argc >= 3) {
// 0,0,"CHINA MOBILE",7
_os_printf("%s\r\n", argv[2]);
}
}
// 获取网络信息
if (send_recv_atcmd_check(chinamobile_at, "AT+MUESTATS=\"sband\"\r\n", "+MUESTATS:", recv_str) == RT_TRUE) {
argc = os_strtok(recv_str, ",", argv, 16);
if (argc >= 2) {
// "sband",39
band = os_atoi(argv[1]);
_os_printf("BAND: %d\r\n", band);
}
}
if (send_recv_atcmd_check(chinamobile_at, "AT+MUESTATS=\"radio\"\r\n", "+MUESTATS:", recv_str) == RT_TRUE) {
argc = os_strtok(recv_str, ",", argv, 16);
if (argc >= 13) {
// "radio",4,-790,-560,-32768,0,0,0A513F03,255,200,38400,197,-30
rsrp = os_atoi(argv[2]); // 0.1dBm
rssi = os_atoi(argv[3]); // 0.1dBm
sinr = os_atoi(argv[9]); // 0.1dB
rsrq = os_atoi(argv[12]); // 0.1dB
num_dl = os_atoi(argv[10]);
freq_dl = eutra_channel_freq_mapping(band, num_dl, 0);
freq_ul = eutra_channel_freq_mapping(band, num_dl, 1);
_os_printf("RSRP: %d.%d dBm\r\n", rsrp/10, os_abs(rsrp%10));
_os_printf("RSSI: %d.%d dBm\r\n", rssi/10, os_abs(rssi%10));
_os_printf("SINR: %d.%d dB\r\n", sinr/10, os_abs(sinr%10));
_os_printf("RSRQ: %d.%d dB\r\n", rsrq/10, os_abs(rsrq%10));
_os_printf("F_dl: %d MHz, F_ul: %d MHz\r\n", freq_dl, freq_ul);
}
}
os_free(argv);
}
// 发送一条AT命令会有多条数据返回发送后多次读循环
static void chinamobile_at_recv(void *context)
{
struct usb_chinamobile_at *chinamobile_at = context;
while (1) {
if (chinamobile_at->retry > 3) {
chinamobile_at->retry = 0;
chinamobile_at->state = CHINAMOBILE_STATE_UNKNOW;
}
// os_printf("recv state:%d\r\n", chinamobile_at->state);
switch (chinamobile_at->state) {
case CHINAMOBILE_STATE_UNKNOW:
chinamobile_at->retry = 0;
chinamobile_at->state = CHINAMOBILE_STATE_CHECK_AT_STATUS;
break;
case CHINAMOBILE_STATE_CHECK_AT_STATUS:
// AT查询模块是否工作启动初始化流程
if (send_recv_atcmd_check(chinamobile_at, "AT\r\n", "OK", NULL) == RT_TRUE) {
chinamobile_at->retry = 0;
chinamobile_at->state = CHINAMOBILE_STATE_CHECK_SIM_STATUS;
os_printf("AT ready\r\n");
} else {
chinamobile_at->retry++;
os_sleep(1);
}
break;
case CHINAMOBILE_STATE_CHECK_SIM_STATUS:
// AT+CPIN查询SIM卡状态
if (send_recv_atcmd_check(chinamobile_at, "AT+CPIN?\r\n", "+CPIN: READY", NULL) == RT_TRUE) {
chinamobile_at->retry = 0;
chinamobile_at->state = CHINAMOBILE_STATE_CHECK_PS_STATUS;
os_printf("SIM ready\r\n");
} else {
chinamobile_at->retry++;
os_sleep(1);
}
break;
case CHINAMOBILE_STATE_CHECK_PS_STATUS:
// AT+CEREG查询EPS域网络注册状态
if (send_recv_atcmd_check(chinamobile_at, "AT+CEREG?\r\n", "+CEREG: 0,1", NULL) == RT_TRUE) {
chinamobile_at->retry = 0;
chinamobile_at->state = CHINAMOBILE_STATE_CHECK_PDP_CONTEXT;
os_printf("CS ready\r\n");
} else {
chinamobile_at->retry++;
os_sleep(1);
}
break;
case CHINAMOBILE_STATE_CHECK_PDP_CONTEXT:
// AT+CGDCONT查询PDP场景
if (send_recv_atcmd_check(chinamobile_at, "AT+CGDCONT?\r\n", "+CGDCONT: 1", NULL) == RT_TRUE) {
chinamobile_at->retry = 0;
chinamobile_at->state = CHINAMOBILE_STATE_CHECK_IP_STATUS;
os_printf("PDP ready\r\n");
} else {
chinamobile_at->retry++;
os_sleep(1);
}
break;
case CHINAMOBILE_STATE_CHECK_IP_STATUS:
// AT+MDIALUP拨号上网
if (send_recv_atcmd_check(chinamobile_at, "AT+MDIALUP=1,1\r\n", "+MDIALUP: 1,1,", recv_str) == RT_TRUE) {
chinamobile_at->retry = 0;
chinamobile_at->state = CHINAMOBILE_STATE_INITIALIZED;
os_printf("Get IP: %s", recv_str);
SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_CONNECTED, 0);
os_printf("dial up\r\n");
} else {
chinamobile_at->retry++;
os_sleep(1);
}
break;
case CHINAMOBILE_STATE_INITIALIZED:
// 查询网络信息
chinamobile_network_info(chinamobile_at, recv_str);
// 定时10s检查拨号上网状态
if (send_recv_atcmd_check(chinamobile_at, "AT+MDIALUP?\r\n", "+MDIALUP: 1,1,", NULL) == RT_TRUE) {
chinamobile_at->retry = 0;
os_printf("LTE status ok\r\n");
os_sleep(10);
} else {
chinamobile_at->retry++;
os_sleep(1);
}
break;
default:
break;
}
}
os_printf("at task end\r\n");
}
static rt_err_t rt_usbh_chinamobile_enable(void *arg)
{
rt_err_t ret = RET_OK;
struct uhintf *intf = arg;
uhcd_t hcd = NULL;
uep_desc_t ep_desc = NULL;
struct ustring_descriptor str_desc __attribute__((aligned(4)));
struct usb_chinamobile_at *chinamobile_at = NULL;
struct usb_cdc_line_coding line_coding;
upipe_t pipe;
rt_uint8_t ep_index, i;
if (intf == NULL) {
return -EIO;
}
hcd = intf->device->hcd;
if (intf->device->dev_desc.idProduct == USB_PRODUCT_ID_CHINAMOBILE) {
// 怎么有两个AT串口先直接用第2个接口判断好了
if (intf->intf_desc->bInterfaceNumber != 2) {
return RET_ERR;
}
// 通过字符描述符判断哪个是主调试串口
ret = rt_usbh_get_string_descriptor(intf->device, intf->intf_desc->iInterface,
&str_desc, sizeof(struct ustring_descriptor));
if (ret != RET_OK) {
return ret;
}
for (i = 0; i < str_desc.bLength; i += 2) { // 暂时没支持UNICODE的打印默认ASCII可以隔一个打印
_os_printf("%c", str_desc.String[i / 2]);
}
_os_printf("\r\n");
os_printf("chinamobile_at\r\n");
chinamobile_at = (struct usb_chinamobile_at *)os_zalloc(sizeof(struct usb_chinamobile_at));
if (chinamobile_at == NULL) {
os_printf("chinamobile at alloc fail\r\n");
return -ENOMEM;
}
// 按照命令预期回复长度对齐预留长度
chinamobile_at->at_cmd_buff = os_malloc(CHINAMOBILE_ATCMD_BUFF_SIZE);
if (chinamobile_at->at_cmd_buff == NULL) {
os_printf("at_cmd_buff alloc fail\r\n");
os_free(chinamobile_at);
return -ENOMEM;
}
chinamobile_at->device = intf->device;
intf->user_data = chinamobile_at;
// 顺便注册devid
dev_register(HG_USB_AT_DEVID, (struct dev_obj *)chinamobile_at);
for (ep_index = 0; ep_index < intf->intf_desc->bNumEndpoints; ++ep_index) {
rt_usbh_get_endpoint_descriptor(intf->intf_desc, ep_index, &ep_desc);
if (ep_desc == NULL) {
return RET_ERR;
}
if ((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
if (rt_usb_hcd_alloc_pipe(intf->device->hcd, &pipe, intf->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(intf->device, pipe);
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
chinamobile_at->pipe_in = pipe;
} else {
chinamobile_at->pipe_out = pipe;
}
}
// 获取串口参数
os_memset(&line_coding, 0, sizeof(line_coding));
rt_usbh_cdc_get_line_coding(intf->device, intf->intf_desc->bInterfaceNumber, &line_coding);
os_printf("Serial: %d %d %d %d\r\n",
line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
rt_thread_init(&chinamobile_at->recv_task, "at_recv", chinamobile_at_recv, chinamobile_at,
NULL, 512, OS_TASK_PRIORITY_BELOW_NORMAL, 20);
rt_thread_startup(&chinamobile_at->recv_task);
}
return ret;
}
static rt_err_t rt_usbh_chinamobile_disable(void *arg)
{
struct uhintf *intf = arg;
uhcd_t hcd = NULL;
struct usb_chinamobile_at *chinamobile_at = NULL;
if (intf == NULL) {
return -EIO;
}
chinamobile_at = intf->user_data;
if (chinamobile_at) {
hcd = intf->device->hcd;
dev_unregister((struct dev_obj *)chinamobile_at);
rt_thread_detach(&chinamobile_at->recv_task);
os_free(chinamobile_at->at_cmd_buff);
os_free(chinamobile_at);
}
return RET_OK;
}
ucd_t rt_usbh_class_driver_chinamobile(void)
{
chinamobile_driver.class_code = USB_CLASS_VEND_SPECIFIC;
chinamobile_driver.vendor_id = USB_VENDOR_ID_CHINAMOBILE;
chinamobile_driver.enable = rt_usbh_chinamobile_enable;
chinamobile_driver.disable = rt_usbh_chinamobile_disable;
return &chinamobile_driver;
}
#endif

View File

@@ -0,0 +1,36 @@
#ifndef __CLASS_CHINAMOBILE_H__
#define __CLASS_CHINAMOBILE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtthread.h>
enum chinamobile_state {
CHINAMOBILE_STATE_UNKNOW,
CHINAMOBILE_STATE_CHECK_AT_STATUS,
CHINAMOBILE_STATE_CHECK_SIM_STATUS,
CHINAMOBILE_STATE_CHECK_PS_STATUS,
CHINAMOBILE_STATE_CHECK_PDP_CONTEXT,
CHINAMOBILE_STATE_CHECK_IP_STATUS,
CHIANMOBILE_STATE_CHECK_BAND,
CHINAMOBILE_STATE_INITIALIZED,
};
struct usb_chinamobile_at {
struct dev_obj dev;
void *device;
struct rt_thread recv_task;
rt_uint8_t *at_cmd_buff;
rt_uint32_t state;
upipe_t pipe_in;
upipe_t pipe_out;
rt_uint8_t retry;
};
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,424 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
* 2021-02-23 Leslie Lee update with current usb api
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "hid.h"
#ifdef RT_USBH_HID
//#define DBG_TAG "usbhost.hid"
//#define DBG_LVL DBG_INFO
//#include <rtdbg.h>
static struct uclass_driver hid_driver;
static rt_list_t _protocal_list;
/**
* This function will do USB_REQ_SET_IDLE request to set idle period to the usb hid device
*
* @param intf the interface instance.
* @duration the idle period of requesting data.
* @report_id the report id
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_IDLE;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = (duration << 8 )| report_id;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
return -RT_FALSE;
}
/**
* This function will do USB_REQ_GET_REPORT request to get report from the usb hid device
*
* @param intf the interface instance.
* @buffer the data buffer to save usb report descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type,
rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_GET_REPORT;
setup.wIndex = intf->intf_desc->bInterfaceNumber;
setup.wLength = size;
setup.wValue = (type << 8 ) + id;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) == size)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
return -RT_FALSE;
}
/**
* This function will do USB_REQ_SET_REPORT request to set report to the usb hid device
*
* @param intf the interface instance.
* @buffer the data buffer to save usb report descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_REPORT;
setup.wIndex = intf->intf_desc->bInterfaceNumber;
setup.wLength = size;
setup.wValue = 0x02 << 8;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
return -RT_FALSE;
}
/**
* This function will do USB_REQ_SET_PROTOCOL request to set protocal to the usb hid device.
*
* @param intf the interface instance.
* @param protocol the protocol id.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_PROTOCOL;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = protocol;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
return -RT_FALSE;
}
/**
* This function will do USB_REQ_GET_DESCRIPTOR request for the device instance
* to set feature of the hub port.
*
* @param intf the interface instance.
* @buffer the data buffer to save usb report descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf,
rt_uint8_t *buffer, rt_size_t size)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD|
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_GET_DESCRIPTOR;
setup.wIndex = 0;
setup.wLength = size;
setup.wValue = USB_DESC_TYPE_REPORT << 8;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) == size)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
else
return -RT_FALSE;
return -RT_FALSE;
}
/**
* This function will register specified hid protocal to protocal list
*
* @param protocal the specified protocal.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal)
{
RT_ASSERT(protocal != RT_NULL);
if (protocal == RT_NULL) return -RT_ERROR;
/* insert class driver into driver list */
rt_list_insert_after(&_protocal_list, &(protocal->list));
return RT_EOK;
}
/**
* This function is the callback function of hid's int endpoint, it is invoked when data comes.
*
* @param context the context of the callback function.
*
* @return none.
*/
static void rt_usbh_hid_callback(void* context)
{
upipe_t pipe;
struct uhid* hid;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
RT_ASSERT(context != RT_NULL);
pipe = (upipe_t)context;
hid = (struct uhid*)((struct uhintf*)pipe->inst)->user_data;
/* invoke protocal callback function */
hid->protocal->callback((void*)hid);
/* parameter check */
RT_ASSERT(((struct uhintf*)pipe->inst)->device->hcd != RT_NULL);
rt_usb_hcd_pipe_xfer(((struct uhintf*)pipe->inst)->device->hcd, pipe,
hid->buffer, pipe->ep.wMaxPacketSize, timeout);
}
/**
* This function will find specified hid protocal from protocal list
*
* @param pro_id the protocal id.
*
* @return the found protocal or RT_NULL if there is no this protocal.
*/
static uprotocal_t rt_usbh_hid_protocal_find(int pro_id)
{
struct rt_list_node *node;
/* try to find protocal object */
for (node = _protocal_list.next; node != &_protocal_list; node = node->next)
{
uprotocal_t protocal =
(uprotocal_t)rt_list_entry(node, struct uprotocal, list);
if (protocal->pro_id == pro_id) return protocal;
}
/* not found */
return RT_NULL;
}
/**
* This function will run hid class driver when usb device is detected and identified
* as a hid class device, it will continue the enumulate process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hid_enable(void* arg)
{
int i = 0, pro_id;
uprotocal_t protocal;
struct uhid* hid;
struct uhintf* intf = (struct uhintf*)arg;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
pro_id = intf->intf_desc->bInterfaceProtocol;
os_printf("HID device enable, protocal id %d\n", pro_id);
protocal = rt_usbh_hid_protocal_find(pro_id);
if(protocal == RT_NULL)
{
rt_kprintf("can't find hid protocal %d\n", pro_id);
intf->user_data = RT_NULL;
return -RT_ERROR;
}
hid = rt_malloc(sizeof(struct uhid));
RT_ASSERT(hid != RT_NULL);
/* initilize the data structure */
rt_memset(hid, 0, sizeof(struct uhid));
intf->user_data = (void*)hid;
hid->protocal = protocal;
for(i = 0; i < intf->intf_desc->bNumEndpoints; i++)
{
rt_err_t ret;
uep_desc_t ep_desc;
/* get endpoint descriptor */
rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usbh_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
analysis_usb_ep_desc(ep_desc); //获取端点描述符 打印端点描述符信息
if(USB_EP_ATTR(ep_desc->bmAttributes) != USB_EP_ATTR_INT)
continue;
if(!(ep_desc->bEndpointAddress & USB_DIR_IN)) continue;
ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &hid->pipe_in,
intf->device, ep_desc);
if(ret != RT_EOK) return ret;
rt_usb_instance_add_pipe(intf->device, hid->pipe_in);
}
/* initialize hid protocal */
hid->protocal->init((void*)intf);
return RT_EOK;
}
/**
* This function will be invoked when usb device plug out is detected and it would clean
* and release all hub class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hid_disable(void* arg)
{
struct uhid* hid;
struct uhintf* intf = (struct uhintf*)arg;
RT_ASSERT(intf != RT_NULL);
LOG_D("rt_usbh_hid_disable");
hid = (struct uhid*)intf->user_data;
if(hid != RT_NULL)
{
if(hid->pipe_in != RT_NULL)
{
/* free the HID in pipe */
rt_usb_hcd_free_pipe(intf->device->hcd, hid->pipe_in);
}
/* free the hid instance */
rt_free(hid);
}
return RT_EOK;
}
/**
* This function will register hid class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usbh_class_driver_hid(void)
{
rt_list_init(&_protocal_list);
hid_driver.class_code = USB_CLASS_HID;
hid_driver.enable = rt_usbh_hid_enable;
hid_driver.disable = rt_usbh_hid_disable;
return &hid_driver;
}
#endif

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __HID_H__
#define __HID_H__
#include <rtthread.h>
struct uhid
{
upipe_t pipe_in;
rt_uint8_t buffer[8 + USB_RX_BUFF_RESERVE_SIZE];
uprotocal_t protocal;
};
typedef struct uhid uhid_t;
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_GET_IDLE 0x02
#define USB_REQ_GET_PROTOCOL 0x03
#define USB_REQ_SET_REPORT 0x09
#define USB_REQ_SET_IDLE 0x0a
#define USB_REQ_SET_PROTOCOL 0x0b
#define USB_HID_KEYBOARD 1
#define USB_HID_MOUSE 2
rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id);
rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type, rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size);
rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size);
rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol);
rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size);
rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal);
#endif

View File

@@ -0,0 +1,691 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include "rtthread.h"
#include "include/rttusb_host.h"
#include "mass.h"
#ifdef RT_USBH_MSTORAGE
//#define DBG_TAG "usbhost.mass"
//#define DBG_LVL DBG_INFO
//#include <rtdbg.h>
extern rt_err_t rt_udisk_run(struct uhintf* intf);
extern rt_err_t rt_udisk_stop(struct uhintf* intf);
static struct uclass_driver storage_driver;
/**
* This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
*
* @param intf the interface instance.
* @param max_lun the buffer to save max_lun.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t _pipe_check(struct uhintf* intf, upipe_t pipe)
{
struct uinstance* device;
ustor_t stor;
int size = 0;
struct ustorage_csw csw;
if(intf == RT_NULL || pipe == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
/* get usb device instance from the interface instance */
device = intf->device;
/* get storage instance from the interface instance */
stor = (ustor_t)intf->user_data;
#if 0
rt_err_t ret;
/* check pipe status */
if(pipe->status == UPIPE_STATUS_OK) return RT_EOK;
if(pipe->status == UPIPE_STATUS_ERROR)
{
rt_kprintf("pipe status error\n");
return -RT_EIO;
}
if(pipe->status == UPIPE_STATUS_STALL)
{
/* clear the pipe stall status */
ret = rt_usbh_clear_feature(device, pipe->ep.bEndpointAddress,
USB_FEATURE_ENDPOINT_HALT);
if(ret != RT_EOK) return ret;
}
#else
return RT_EOK;
#endif
rt_thread_delay(50);
rt_kprintf("pipes1 0x%x, 0x%x\n", stor->pipe_in, stor->pipe_out);
stor->pipe_in->status = UPIPE_STATUS_OK;
LOG_D("clean storage in pipe stall");
/* it should receive csw after clear the stall feature */
size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd,
stor->pipe_in, &csw, SIZEOF_CSW, 100);
if(size != SIZEOF_CSW)
{
rt_kprintf("receive the csw after stall failed\n");
return -RT_EIO;
}
return -RT_ERROR;
}
/**
* This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
*
* @param intf the interface instance.
* @param max_lun the buffer to save max_lun.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_uint8_t csw_buff[SIZEOF_CSW + USB_RX_BUFF_RESERVE_SIZE];
static rt_err_t rt_usb_bulk_only_xfer(struct uhintf* intf,
ustorage_cbw_t cmd, rt_uint8_t* buffer, int timeout)
{
rt_size_t size;
rt_err_t ret;
upipe_t pipe;
ustorage_csw_t csw = (ustorage_csw_t)csw_buff;
ustor_t stor;
RT_ASSERT(cmd != RT_NULL);
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
/* get storage instance from the interface instance */
stor = (ustor_t)intf->user_data;
if(stor == RT_NULL)
{
rt_kprintf("stor is not available\n");
return -RT_EIO;
}
stor->ref ++;
do
{
/* send the cbw */
size = rt_usb_hcd_pipe_xfer(stor->pipe_out->inst->hcd, stor->pipe_out,
cmd, SIZEOF_CBW, timeout);
if(size != SIZEOF_CBW)
{
rt_kprintf("CBW size error\n");
goto __exit_err;
}
if(cmd->xfer_len != 0)
{
pipe = (cmd->dflags == CBWFLAGS_DIR_IN) ? stor->pipe_in :
stor->pipe_out;
size = rt_usb_hcd_pipe_xfer(pipe->inst->hcd, pipe, (void*)buffer,
cmd->xfer_len, timeout);
if(size != cmd->xfer_len)
{
rt_kprintf("request size %d, transfer size %d\n",
cmd->xfer_len, size);
break;
}
}
/* receive the csw */
size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd, stor->pipe_in,
csw_buff, SIZEOF_CSW, timeout);
if(size != SIZEOF_CSW)
{
rt_kprintf("csw size error\n");
goto __exit_err;
}
}while(0);
/* check in pipes status */
ret = _pipe_check(intf, stor->pipe_in);
if(ret != RT_EOK)
{
rt_kprintf("in pipe error\n");
goto __exit_err;
}
/* check out pipes status */
ret = _pipe_check(intf, stor->pipe_out);
if(ret != RT_EOK)
{
rt_kprintf("out pipe error\n");
goto __exit_err;
}
/* check csw status */
if(csw->signature != CSW_SIGNATURE || csw->tag != CBW_TAG_VALUE)
{
rt_kprintf("csw signature error\n");
goto __exit_err;
}
if(csw->status != 0)
{
rt_kprintf("csw status error:%d\n",csw->status);
goto __exit_err;
}
stor->ref --;
return RT_EOK;
__exit_err:
stor->ref --;
return -RT_ERROR;
}
/**
* This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
*
* @param intf the interface instance.
* @param max_lun the buffer to save max_lun.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun)
{
struct uinstance* device;
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
/* parameter check */
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_get_max_lun");
/* get usb device instance from the interface instance */
device = intf->device;
/* construct the request */
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USBREQ_GET_MAX_LUN;
setup.wValue = intf->intf_desc->bInterfaceNumber;
setup.wIndex = 0;
setup.wLength = 1;
/* do control transfer request */
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_EIO;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, max_lun, 1, timeout) != 1)
{
return -RT_EIO;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) != 0)
{
return -RT_EIO;
}
return RT_EOK;
}
/**
* This function will do USBREQ_MASS_STORAGE_RESET request for the usb interface instance.
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_reset(struct uhintf* intf)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_reset");
/* get usb device instance from the interface instance */
device = intf->device;
/* construct the request */
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USBREQ_MASS_STORAGE_RESET;
setup.wIndex = intf->intf_desc->bInterfaceNumber;
setup.wLength = 0;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_EIO;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return -RT_EIO;
}
return RT_EOK;
}
/**
* This function will execute SCSI_READ_10 command to read data from the usb device.
*
* @param intf the interface instance.
* @param buffer the data buffer to save read data
* @param sector the start sector address to read.
* @param sector the sector count to read.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer,
rt_uint32_t sector, rt_size_t count, int timeout)
{
struct ustorage_cbw cmd;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_read10");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = SECTOR_SIZE * count;
cmd.dflags = CBWFLAGS_DIR_IN;
cmd.lun = 0;
cmd.cb_len = 10;
cmd.cb[0] = SCSI_READ_10;
cmd.cb[1] = 0;
cmd.cb[2] = (rt_uint8_t)(sector >> 24);
cmd.cb[3] = (rt_uint8_t)(sector >> 16);
cmd.cb[4] = (rt_uint8_t)(sector >> 8);
cmd.cb[5] = (rt_uint8_t)sector;
cmd.cb[6] = 0;
cmd.cb[7] = (count & 0xff00) >> 8;
cmd.cb[8] = (rt_uint8_t) count & 0xff;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will execute SCSI_WRITE_10 command to write data to the usb device.
*
* @param intf the interface instance.
* @param buffer the data buffer to save write data
* @param sector the start sector address to write.
* @param sector the sector count to write.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer,
rt_uint32_t sector, rt_size_t count, int timeout)
{
struct ustorage_cbw cmd;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_write10");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = SECTOR_SIZE * count;
cmd.dflags = CBWFLAGS_DIR_OUT;
cmd.lun = 0;
cmd.cb_len = 10;
cmd.cb[0] = SCSI_WRITE_10;
cmd.cb[1] = 0;
cmd.cb[2] = (rt_uint8_t)(sector >> 24);
cmd.cb[3] = (rt_uint8_t)(sector >> 16);
cmd.cb[4] = (rt_uint8_t)(sector >> 8);
cmd.cb[5] = (rt_uint8_t)sector;
cmd.cb[6] = 0;
cmd.cb[7] = (count & 0xff00) >> 8;
cmd.cb[8] = (rt_uint8_t) count & 0xff;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will execute SCSI_REQUEST_SENSE command to get sense data.
*
* @param intf the interface instance.
* @param buffer the data buffer to save sense data
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer)
{
struct ustorage_cbw cmd;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_request_sense");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = 18;
cmd.dflags = CBWFLAGS_DIR_IN;
cmd.lun = 0;
cmd.cb_len = 6;
cmd.cb[0] = SCSI_REQUEST_SENSE;
cmd.cb[4] = 18;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will execute SCSI_TEST_UNIT_READY command to get unit ready status.
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf)
{
struct ustorage_cbw cmd;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_test_unit_ready");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = 0;
cmd.dflags = CBWFLAGS_DIR_OUT;
cmd.lun = 0;
cmd.cb_len = 12;
cmd.cb[0] = SCSI_TEST_UNIT_READY;
return rt_usb_bulk_only_xfer(intf, &cmd, RT_NULL, timeout);
}
/**
* This function will execute SCSI_INQUIRY_CMD command to get inquiry data.
*
* @param intf the interface instance.
* @param buffer the data buffer to save inquiry data
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer)
{
struct ustorage_cbw cmd;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_inquiry");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = 36;
cmd.dflags = CBWFLAGS_DIR_IN;
cmd.lun = 0;
cmd.cb_len = 6;//12
cmd.cb[0] = SCSI_INQUIRY_CMD;
cmd.cb[4] = 36;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will execute SCSI_READ_CAPACITY command to get capacity data.
*
* @param intf the interface instance.
* @param buffer the data buffer to save capacity data
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer)
{
struct ustorage_cbw cmd;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_get_capacity");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = 8;
cmd.dflags = CBWFLAGS_DIR_IN;
cmd.lun = 0;
cmd.cb_len = 12;
cmd.cb[0] = SCSI_READ_CAPACITY;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will run mass storage class driver when usb device is detected
* and identified as a mass storage class device, it will continue to do the enumulate
* process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_storage_enable(void* arg)
{
int i = 0;
rt_err_t ret;
ustor_t stor;
upipe_t pipe;
struct uhintf* intf = (struct uhintf*)arg;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
LOG_D("subclass %d, protocal %d",
intf->intf_desc->bInterfaceSubClass,
intf->intf_desc->bInterfaceProtocol);
LOG_D("rt_usbh_storage_run");
/* only support SCSI subclass and bulk only protocal */
stor = rt_malloc(sizeof(struct ustor));
RT_ASSERT(stor != RT_NULL);
/* initilize the data structure */
rt_memset(stor, 0, sizeof(struct ustor));
intf->user_data = (void*)stor;
for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
{
uep_desc_t ep_desc;
/* get endpoint descriptor from interface descriptor */
rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
analysis_usb_ep_desc(ep_desc); //获取端点描述符 打印端点描述符信息
/* the endpoint type of mass storage class should be BULK */
if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
if (rt_usb_hcd_alloc_pipe(intf->device->hcd, &pipe, intf->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
/* allocate pipes according to the endpoint type */
if(ep_desc->bEndpointAddress & USB_DIR_IN)
{
/* alloc an in pipe for the storage instance */
rt_usb_instance_add_pipe(intf->device, pipe);
stor->pipe_in = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress);
}
else
{
/* alloc an output pipe for the storage instance */
rt_usb_instance_add_pipe(intf->device, pipe);
stor->pipe_out = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress);
}
}
/* check pipes infomation */
if(stor->pipe_in == RT_NULL || stor->pipe_out == RT_NULL)
{
rt_kprintf("pipe error, unsupported device\n");
return -RT_ERROR;
}
/* should implement as callback */
ret = rt_udisk_run(intf);
if(ret != RT_EOK) return ret;
return RT_EOK;
}
/**
* This function will be invoked when usb device plug out is detected and it would clean
* and release all mass storage class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_storage_disable(void* arg)
{
ustor_t stor;
struct uhintf* intf = (struct uhintf*)arg;
rt_uint32_t flags = 0;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->user_data != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_stop");
/* get storage instance from interface instance */
stor = (ustor_t)intf->user_data;
rt_udisk_stop(intf);
intf->user_data = NULL;
while(1)
{
if(stor->ref)
{
os_sleep_ms(1);
}
else
{
flags = disable_irq();
/* free storage instance */
if(stor != RT_NULL) rt_free(stor);
enable_irq(flags);
break;
}
}
return RT_EOK;
}
/**
* This function will register mass storage class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usbh_class_driver_storage(void)
{
storage_driver.class_code = 0x08; //USB_CLASS_MASS_STORAGE
storage_driver.enable = rt_usbh_storage_enable;
storage_driver.disable = rt_usbh_storage_disable;
return &storage_driver;
}
#endif

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __MASS_H__
#define __MASS_H__
#include <rtthread.h>
#include "dev.h"
#include "devid.h"
#include "diskio.h"
#include "ff.h"
#define MAX_PARTITION_COUNT 4
#define SECTOR_SIZE 512
struct ustor_data
{
struct uhintf* intf;
int udisk_id;
const char path;
};
struct ustor_device
{
rt_uint32_t type;
fatfs_disk_status status;
fatfs_disk_initialize init;
fatfs_disk_read read;
fatfs_disk_write write;
fatfs_disk_ioctl ioctl;
void *user_data;
};
struct ustor
{
upipe_t pipe_in;
upipe_t pipe_out;
rt_uint32_t capicity[2];
struct ustor_device dev[MAX_PARTITION_COUNT];
rt_uint8_t dev_cnt;
rt_uint32_t ref;
};
typedef struct ustor* ustor_t;
rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun);
rt_err_t rt_usbh_storage_reset(struct uhintf* intf);
rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer,
rt_uint32_t sector, rt_size_t count, int timeout);
rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer,
rt_uint32_t sector, rt_size_t count, int timeout);
rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer);
rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf);
rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer);
rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer);
#endif

View File

@@ -0,0 +1,349 @@
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "quectel.h"
#include "cdc.h"
#include "rndis.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
#include "lwip/tcpip.h"
#include "netif/ethernetif.h"
#include "lib/common/sysevt.h"
#ifdef RT_USBH_VENDOR_QUECTEL
#define USB_VENDOR_ID_QUECTEL 0x2C7C
#define USB_PRODUCT_ID_QUECTEL 0x0903 // EC801E-CN
#define QUECTEL_ATCMD_BUFF_SIZE 64
static char recv_str[QUECTEL_ATCMD_BUFF_SIZE];
static struct uclass_driver quectel_driver;
static rt_bool_t send_recv_atcmd_check(void *context, const char *send_str,
const char *check_str, char *ret_str)
{
struct usb_quectel_at *quectel_at = context;
uinst_t device = quectel_at->device;
int recv_size;
char *recv_str = NULL;
rt_bool_t pass = RT_FALSE;
os_sprintf((char *)quectel_at->at_cmd_buff, send_str);
rt_usb_hcd_pipe_xfer(device->hcd, quectel_at->pipe_out,
quectel_at->at_cmd_buff, os_strlen(send_str), 0);
os_sleep_ms(10); // 需要点延迟给LTE模组反应
do {
// 每次读取会清除缓存
os_memset(quectel_at->at_cmd_buff, 0, QUECTEL_ATCMD_BUFF_SIZE);
recv_size = rt_usb_hcd_pipe_xfer(device->hcd, quectel_at->pipe_in,
quectel_at->at_cmd_buff, QUECTEL_ATCMD_BUFF_SIZE, 10);
if (recv_size > 0) {
recv_str = os_strstr(quectel_at->at_cmd_buff, check_str);
if (recv_str != NULL) {
pass = RT_TRUE;
if (ret_str != NULL && recv_size > os_strlen(check_str)) {
// ret_str存在说明需要获取返回结果做额外判断复制到函数外面
os_memcpy(ret_str, recv_str + os_strlen(check_str),
recv_size - os_strlen(check_str));
ret_str[recv_size - os_strlen(check_str)] = '\0'; // 字符串结束符
}
}
}
} while (recv_size > 0);
return pass;
}
static void quectel_at_recv(void *context)
{
struct usb_quectel_at *quectel_at = context;
while (1) {
if (quectel_at->retry > 3) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_UNKNOW;
}
// os_printf("recv state:%d\r\n", quectel_at->state);
switch (quectel_at->state) {
case QUECTEL_STATE_UNKNOW:
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CHECK_AT_STATUS;
break;
case QUECTEL_STATE_CHECK_AT_STATUS:
// AT查询模块是否工作启动初始化流程
if (send_recv_atcmd_check(quectel_at, "AT\r\n", "OK", NULL) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CHECK_SIM_STATUS;
os_printf("AT ready\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_CHECK_SIM_STATUS:
if (send_recv_atcmd_check(quectel_at, "AT+CPIN?\r\n", "+CPIN: READY", NULL) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CHECK_CS_STATUS;
os_printf("SIM ready\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_CHECK_CS_STATUS:
// AT+CREG查询CS域网络注册状态
if (send_recv_atcmd_check(quectel_at, "AT+CREG?\r\n", "+CREG: 0,1", NULL) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CHECK_PS_STATUS;
os_printf("PS ready\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_CHECK_PS_STATUS:
// AT+CEREG查询EPS域网络注册状态
if (send_recv_atcmd_check(quectel_at, "AT+CEREG?\r\n", "+CEREG: 0,1", NULL) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CHECK_USBNET_STATUS;
os_printf("CS ready\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_CHECK_USBNET_STATUS:
// 查询usb网卡接口
if (send_recv_atcmd_check(quectel_at, "AT+QCFG=\"usbnet\"\r\n", "+QCFG: \"usbnet\",", recv_str) == RT_TRUE) {
if (os_atoi(recv_str) == 1) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CONFIG_USBNET_STATUS;
os_printf("USBNET is ECM\r\n");
} else {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CONFIG_PDP_CONTEXT;
os_printf("USBNET is RNDIS\r\n");
}
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_CONFIG_USBNET_STATUS:
// ecm网卡发送命令切换到rndis网卡
if (send_recv_atcmd_check(quectel_at, "AT+QCFG=\"usbnet\",3\r\n", "OK", NULL) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_POWERDOWN;
os_printf("switch to RNDIS\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_CONFIG_PDP_CONTEXT:
// AT+QICSGP设置场景参数
if (send_recv_atcmd_check(quectel_at, "AT+QICSGP=1,1,\"UNINET\",\"\",\"\",1\r\n", "OK", NULL) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_ACTIVE_PDP_CONTEXT;
os_printf("PDP config\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_ACTIVE_PDP_CONTEXT:
// AT+QIACT激活PDP场景
if (send_recv_atcmd_check(quectel_at, "AT+QIACT=1\r\n", "OK", NULL) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CHECK_IP_STATUS;
os_printf("PDP ready\r\n");
} else {
quectel_at->retry++;
if (quectel_at->retry > 3) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_DEACTIVE_PDP_CONTEXT;
}
os_sleep(1);
}
break;
case QUECTEL_STATE_CHECK_IP_STATUS:
// AT+QIACT查询激活PDP场景和IP
if (send_recv_atcmd_check(quectel_at, "AT+QIACT?\r\n", "+QIACT: 1,1,1,", recv_str) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CONNECT_USB_ADAPTER;
os_printf("Get IP: %s", recv_str);
os_printf("PDP actived\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_CONNECT_USB_ADAPTER:
// AT+QNETDEVCTL连接USB网卡
if (send_recv_atcmd_check(quectel_at, "AT+QNETDEVCTL=1,1,1\r\n", "OK", recv_str) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_INITIALIZED;
SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_CONNECTED, 0);
os_printf("network conneted\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_INITIALIZED:
// 定时10s不知道干什么好呢
os_sleep(10);
break;
case QUECTEL_STATE_DEACTIVE_PDP_CONTEXT:
// 失败后反激活模组
if (send_recv_atcmd_check(quectel_at, "AT+QIDEACT=1\r\n", "OK", NULL) == RT_TRUE) {
quectel_at->retry = 0;
quectel_at->state = QUECTEL_STATE_CHECK_SIM_STATUS;
os_printf("PDP deactived\r\n");
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
case QUECTEL_STATE_POWERDOWN:
if (send_recv_atcmd_check(quectel_at, "AT+QPOWD\r\n", "POWERED DOWN", NULL) == RT_TRUE) {
quectel_at->retry = 0;
os_printf("LTE power down\r\n");
os_sleep(2);
mcu_reset();
} else {
quectel_at->retry++;
os_sleep(1);
}
break;
default:
break;
}
}
os_printf("at task end\r\n");
}
static rt_err_t rt_usbh_quectel_enable(void *arg)
{
rt_err_t ret = RET_OK;
struct uhintf *intf = arg;
uhcd_t hcd = NULL;
uep_desc_t ep_desc = NULL;
struct ustring_descriptor str_desc __attribute__((aligned(4)));
struct usb_quectel_at *quectel_at = NULL;
struct usb_cdc_line_coding line_coding;
upipe_t pipe;
rt_uint8_t ep_index, i;
if (intf == NULL) {
return -EIO;
}
hcd = intf->device->hcd;
if (intf->device->dev_desc.idProduct == USB_PRODUCT_ID_QUECTEL) {
// 怎么有两个AT串口先直接用第3个接口判断好了
if (intf->intf_desc->bInterfaceNumber != 3) {
return RET_ERR;
}
// 通过字符描述符判断哪个是主调试串口
ret = rt_usbh_get_string_descriptor(intf->device, intf->intf_desc->iInterface,
&str_desc, sizeof(struct ustring_descriptor));
if (ret != RET_OK) {
return ret;
}
for (i = 0; i < str_desc.bLength; i += 2) { // 暂时没支持UNICODE的打印默认ASCII可以隔一个打印
_os_printf("%c", str_desc.String[i / 2]);
}
_os_printf("\r\n");
os_printf("quectel_at\r\n");
quectel_at = (struct usb_quectel_at *)os_zalloc(sizeof(struct usb_quectel_at));
if (quectel_at == NULL) {
os_printf("quectel at alloc fail\r\n");
return -ENOMEM;
}
// 按照命令预期回复长度对齐预留长度
quectel_at->at_cmd_buff = os_malloc(QUECTEL_ATCMD_BUFF_SIZE);
if (quectel_at->at_cmd_buff == NULL) {
os_printf("at_cmd_buff alloc fail\r\n");
os_free(quectel_at);
return -ENOMEM;
}
quectel_at->device = intf->device;
intf->user_data = quectel_at;
// 顺便注册devid
dev_register(HG_USB_AT_DEVID, (struct dev_obj *)quectel_at);
for (ep_index = 0; ep_index < intf->intf_desc->bNumEndpoints; ++ep_index) {
rt_usbh_get_endpoint_descriptor(intf->intf_desc, ep_index, &ep_desc);
if (ep_desc == NULL) {
return RET_ERR;
}
if ((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
if (rt_usb_hcd_alloc_pipe(intf->device->hcd, &pipe, intf->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(intf->device, pipe);
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
quectel_at->pipe_in = pipe;
} else {
quectel_at->pipe_out = pipe;
}
}
// 获取串口参数
os_memset(&line_coding, 0, sizeof(line_coding));
rt_usbh_cdc_get_line_coding(intf->device, intf->intf_desc->bInterfaceNumber, &line_coding);
os_printf("Serial: %d %d %d %d\r\n",
line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
rt_thread_init(&quectel_at->recv_task, "at_recv", quectel_at_recv, quectel_at,
NULL, 512, OS_TASK_PRIORITY_BELOW_NORMAL, 20);
rt_thread_startup(&quectel_at->recv_task);
}
return ret;
}
static rt_err_t rt_usbh_quectel_disable(void *arg)
{
struct uhintf *intf = arg;
uhcd_t hcd = NULL;
struct usb_quectel_at *quectel_at = NULL;
if (intf == NULL) {
return -EIO;
}
quectel_at = intf->user_data;
if (quectel_at) {
hcd = intf->device->hcd;
dev_unregister((struct dev_obj *)quectel_at);
rt_thread_detach(&quectel_at->recv_task);
os_free(quectel_at->at_cmd_buff);
os_free(quectel_at);
}
return RET_OK;
}
ucd_t rt_usbh_class_driver_quectel(void)
{
quectel_driver.class_code = USB_CLASS_VEND_SPECIFIC;
quectel_driver.vendor_id = USB_VENDOR_ID_QUECTEL;
quectel_driver.enable = rt_usbh_quectel_enable;
quectel_driver.disable = rt_usbh_quectel_disable;
return &quectel_driver;
}
#endif

View File

@@ -0,0 +1,42 @@
#ifndef __CLASS_QUECTEL_H__
#define __CLASS_QUECTEL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtthread.h>
enum quectel_state {
QUECTEL_STATE_UNKNOW,
QUECTEL_STATE_CHECK_AT_STATUS,
QUECTEL_STATE_CHECK_SIM_STATUS,
QUECTEL_STATE_CHECK_CS_STATUS,
QUECTEL_STATE_CHECK_PS_STATUS,
QUECTEL_STATE_CHECK_USBNET_STATUS,
QUECTEL_STATE_CONFIG_USBNET_STATUS,
QUECTEL_STATE_CONFIG_PDP_CONTEXT,
QUECTEL_STATE_ACTIVE_PDP_CONTEXT,
QUECTEL_STATE_CHECK_IP_STATUS,
QUECTEL_STATE_CONNECT_USB_ADAPTER,
QUECTEL_STATE_INITIALIZED,
QUECTEL_STATE_DEACTIVE_PDP_CONTEXT,
QUECTEL_STATE_POWERDOWN,
};
struct usb_quectel_at {
struct dev_obj dev;
void *device;
struct rt_thread recv_task;
rt_uint8_t *at_cmd_buff;
rt_uint32_t state;
upipe_t pipe_in;
upipe_t pipe_out;
rt_uint8_t retry;
};
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,439 @@
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "rndis.h"
#include "cdc.h"
#include "hal/usb_device.h"
#include "lib/usb/usb_device_rndis.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
#include "lwip/tcpip.h"
#include "netif/ethernetif.h"
#if defined(RT_USBH_WIRELESS) && defined(RT_USBH_WIRELESS_RNDIS)
static rt_err_t rt_rndis_msg_send_recv(struct usb_rndis *rndis, rt_uint8_t *send_buf, rt_uint32_t send_len,
rt_uint8_t *recv_buf, rt_uint32_t recv_size, rt_uint32_t *recv_len)
{
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)recv_buf;
uinst_t device = rndis->device;
int ret = 0;
rt_uint32_t rndis_avial[2 + (USB_RX_BUFF_RESERVE_SIZE / 4)] = {0}; // 防止越界
rt_uint32_t req_type = msg->Ctrl.MsgType;
ret = rt_usbh_cdc_send_command(device, send_buf, send_len);
if (ret == send_len) {
__retry:
/* waite for the interrupt ep */
ret = rt_usb_hcd_pipe_xfer(device->hcd, rndis->pipe_int, rndis_avial, 8, USB_TIMEOUT_BASIC);
if (ret == 8 && rndis_avial[0] == 1 && rndis_avial[1] == 0) {
ret = rt_usbh_cdc_get_response(device, recv_buf, recv_size);
if (ret > 0) {
*recv_len = ret;
if (msg->Resp.MsgType != (0x80000000UL | req_type) ||
msg->Resp.ReqId != rndis->req_id ||
msg->Resp.Status != CDC_RNDIS_STATUS_SUCCESS) {
//os_printf("retry,%d,%d,%d,%d,%d\r\n", msg->Resp.MsgType, req_type, msg->Resp.ReqId, rndis->req_id, msg->Resp.Status);
goto __retry;
}
return RET_OK;
}
}
ret = RET_ERR;
}
return ret;
}
static rt_err_t rt_rndis_msg_init(struct usb_rndis *rndis)
{
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)rndis->msg_buffer;
rt_uint32_t recv_len = 0;
int ret = 0;
// 清理buffer空间
os_memset(rndis->msg_buffer, 0, sizeof(USBD_CDC_RNDIS_InitMsgTypeDef));
msg->Init.MsgType = CDC_RNDIS_INITIALIZE_MSG_ID;
msg->Init.MsgLength = sizeof(USBD_CDC_RNDIS_InitMsgTypeDef);
msg->Init.ReqId = ++rndis->req_id;
msg->Init.MajorVersion = CDC_RNDIS_VERSION_MAJOR;
msg->Init.MinorVersion = CDC_RNDIS_VERSION_MINOR;
msg->Init.MaxTransferSize = 2048;
ret = rt_rndis_msg_send_recv(rndis, rndis->msg_buffer, msg->Init.MsgLength,
rndis->msg_buffer, 128, &recv_len);
return ret;
}
static rt_err_t rt_rndis_msg_keepalive(struct usb_rndis *rndis)
{
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)rndis->msg_buffer;
rt_uint32_t recv_len = 0;
int ret = 0;
os_memset(rndis->msg_buffer, 0, sizeof(USBD_CDC_RNDIS_KpAliveMsgTypeDef));
msg->KpAlive.MsgType = CDC_RNDIS_KEEPALIVE_MSG_ID;
msg->KpAlive.MsgLength = sizeof(USBD_CDC_RNDIS_KpAliveMsgTypeDef);
msg->KpAlive.ReqId = ++rndis->req_id;
ret = rt_rndis_msg_send_recv(rndis, rndis->msg_buffer, msg->KpAlive.MsgLength,
rndis->msg_buffer, 128, &recv_len);
return ret;
}
rt_err_t rt_rndis_msg_query(struct usb_rndis *rndis, rt_uint32_t oid, rt_uint8_t *buff, rt_uint32_t *len)
{
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)rndis->msg_buffer;
rt_uint32_t recv_len = 0;
int ret = 0;
os_memset(rndis->msg_buffer, 0, sizeof(USBD_CDC_RNDIS_QueryMsgTypeDef));
msg->Query.MsgType = CDC_RNDIS_QUERY_MSG_ID;
msg->Query.MsgLength = sizeof(USBD_CDC_RNDIS_QueryMsgTypeDef);
msg->Query.RequestId = ++rndis->req_id;
msg->Query.Oid = oid;
msg->Query.InfoBufLength = 0;
msg->Query.InfoBufOffset = 20;
msg->Query.DeviceVcHandle = 0;
ret = rt_rndis_msg_send_recv(rndis, rndis->msg_buffer, msg->Query.MsgLength,
rndis->msg_buffer, 128, &recv_len);
if (ret == RET_OK) {
os_memcpy(buff, msg->QueryCplt.InfoBuf, msg->QueryCplt.InfoBufLength);
*len = msg->QueryCplt.InfoBufLength;
return RET_OK;
}
return ret;
}
rt_err_t rt_rndis_msg_set(struct usb_rndis *rndis, rt_uint32_t oid, rt_uint8_t *buff, rt_uint32_t len)
{
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)rndis->msg_buffer;
uinst_t device = rndis->device;
rt_uint32_t recv_len = 0;
rt_uint32_t rndis_avial[2 + (USB_RX_BUFF_RESERVE_SIZE / 4)] = {0}; // 防止越界
int ret = 0;
os_memset(rndis->msg_buffer, 0, sizeof(USBD_CDC_RNDIS_SetMsgTypeDef));
msg->Set.MsgType = CDC_RNDIS_SET_MSG_ID;
msg->Set.MsgLength = sizeof(USBD_CDC_RNDIS_SetMsgTypeDef) + len;
msg->Set.ReqId = ++rndis->req_id;
msg->Set.Oid = oid;
msg->Set.InfoBufLength = 0;
msg->Set.InfoBufOffset = 20;
msg->Set.DeviceVcHandle = 0;
ret = rt_rndis_msg_send_recv(rndis, rndis->msg_buffer, msg->Set.MsgLength,
rndis->msg_buffer, 128, &recv_len);
return ret;
}
static void rt_usbh_rndis_keepalive_timer(void *args)
{
struct usb_rndis *rndis = args;
// os_printf("keep alive\r\n");
rt_rndis_msg_keepalive(rndis);
os_timer_start(&rndis->keepalive_timer, 5000);
}
static rt_err_t rt_usbh_rndis_open(struct netdev *ndev, netdev_input_cb input_cb, netdev_event_cb evt_cb, void *priv)
{
rt_uint32_t flags;
struct usb_rndis *rndis = container_of(ndev, struct usb_rndis, ndev);
flags = disable_irq();
rndis->input_cb = input_cb;
rndis->input_priv = priv;
enable_irq(flags);
return RET_OK;
}
static rt_err_t rt_usbh_rndis_ioctl(struct netdev *ndev, rt_uint32_t cmd, rt_uint32_t param1, rt_uint32_t param2)
{
struct usb_rndis *rndis = container_of(ndev, struct usb_rndis, ndev);
switch (cmd) {
case NETDEV_IOCTL_GET_ADDR:
os_memcpy((rt_uint8_t *)param1, rndis->mac, 6);
break;
default:
return -ENOTSUPP;
}
return RET_OK;
}
// 注意send_data直接将data指针前移获取预留的空间
// 必须确认调用方是skb申请有预留足够空间否则存在风险
// 由于USB DMA需要4字节对齐skb->data经过处理后IP包头不是4字节对齐不能前移处理
static rt_err_t rt_usbh_rndis_send_data(struct netdev *ndev, rt_uint8_t *p_data, rt_uint32_t size)
{
struct usb_rndis *rndis = container_of(ndev, struct usb_rndis, ndev);
uinst_t device = rndis->device;
USBD_CDC_RNDIS_PacketMsgTypeDef *packet = NULL;
if (p_data == NULL || size == 0) {
return -EINVAL;
}
if (!rndis->ready) {
// usb没准备好就不发包
os_printf("rndis send no ready\r\n");
return -EIO;
}
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)os_malloc(size + sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
if (packet == NULL) {
return -ENOMEM;
}
os_memset(packet, 0, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
packet->MsgType = CDC_RNDIS_PACKET_MSG_ID;
packet->MsgLength = size + 44;
packet->DataOffset = 36; // 明明是44但是抓包看全是36不知道为什么
packet->DataLength = size;
hw_memcpy(packet + 1, p_data, size);
rt_usb_hcd_pipe_xfer(device->hcd, rndis->pipe_out, packet, packet->MsgLength, 1000);
os_free(packet);
return RET_OK;
}
// 注意USB驱动大部分不支持scatter发送因此需要额外拷贝
// 调用方多数来自于LWIP数据量可能小一点
static rt_err_t rt_usbh_rndis_send_scatter_data(struct netdev *ndev, scatter_data *data, rt_uint32_t count)
{
struct usb_rndis *rndis = container_of(ndev, struct usb_rndis, ndev);
uinst_t device = rndis->device;
USBD_CDC_RNDIS_PacketMsgTypeDef *packet = NULL;
rt_uint8_t *p_data;
rt_uint32_t size = 0;
rt_uint32_t offset = 0;
rt_uint32_t i;
if (data == NULL || count == 0) {
return -EINVAL;
}
if (!rndis->ready) {
// usb没准备好就不发包
os_printf("rndis scatter send no ready\r\n");
return -EIO;
}
for (i = 0; i < count; ++i) size += data[i].size;
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)os_malloc(size + sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
if (packet == NULL) {
return -ENOMEM;
}
os_memset(packet, 0, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
packet->MsgType = CDC_RNDIS_PACKET_MSG_ID;
packet->MsgLength = size + 44;
packet->DataOffset = 36; // 明明是44但是抓包看全是36不知道为什么
packet->DataLength = size;
// 拷贝scatter中数据
p_data = (rt_uint8_t *)(packet + 1);
for (i = 0; i < count; ++i) {
hw_memcpy(p_data + offset, data[i].addr, data[i].size);
offset += data[i].size;
}
rt_usb_hcd_pipe_xfer(device->hcd, rndis->pipe_out, packet, packet->MsgLength, 1000);
os_free(packet);
return RET_OK;
}
void rt_usbh_rndis_network_init(struct usb_rndis *rndis)
{
struct netdev *ndev = &rndis->ndev;
rt_uint8_t mac[8]; // 有些设备返回mac会多些字节
rt_uint32_t recv_len = 0;
rt_uint32_t packet_filter = CDC_RNDIS_PACKET_DIRECTED | \
CDC_RNDIS_PACKET_ALL_MULTICAST | \
CDC_RNDIS_PACKET_BROADCAST | \
CDC_RNDIS_PACKET_PROMISCUOUS;
if (ndev) {
// tcpip_init(NULL, NULL); // 外面wifi应该初始化过了
rt_rndis_msg_query(rndis, OID_802_3_CURRENT_ADDRESS, mac, &recv_len);
os_memcpy(rndis->mac, mac, 6);
rt_rndis_msg_set(rndis, OID_GEN_CURRENT_PACKET_FILTER, (rt_uint8_t *)&packet_filter, 4);
lwip_netif_add(ndev, "l0", NULL, NULL, NULL);
// 利用事件驱动
os_printf("add l0 interface!\r\n");
}
}
static const struct netdev_hal_ops rndis_ops = {
.open = rt_usbh_rndis_open,
.close = NULL,
.ioctl = rt_usbh_rndis_ioctl,
.send_data = rt_usbh_rndis_send_data,
.send_scatter_data = rt_usbh_rndis_send_scatter_data,
};
rt_err_t rt_usbh_rndis_attach(struct usb_rndis *rndis)
{
if (rndis == NULL) {
return -EIO;
}
// 绑定处理函数
rndis->ndev.dev.ops = (const struct devobj_ops *)&rndis_ops;
// 顺便注册devid
return dev_register(HG_LTE_RNDIS_DEVID, (struct dev_obj *)rndis);
}
rt_err_t rt_usbh_rndis_attach2(void)
{
struct usb_rndis *rndis = (struct usb_rndis *)os_zalloc(sizeof(struct usb_rndis));
ASSERT(rndis);
rndis->ndev.dev.ops = (const struct devobj_ops *)&rndis_ops;
return dev_register(HG_LTE_RNDIS_DEVID, (struct dev_obj *)rndis);
}
void rndis_data_recv(void *context)
{
struct usb_rndis *rndis = context;
uinst_t device = rndis->device;
USBD_CDC_RNDIS_PacketMsgTypeDef *packet = NULL;
rt_uint32_t flags;
int recv_size;
int offset;
int shift;
netdev_input_cb input_cb;
void *input_priv;
rt_uint32_t target_copyLength = 0;
while (1) {
if (!rndis->ready) {
os_sleep_ms(10); // 需要有点延迟给线程,不然占住不释放
continue;
}
offset = 0;
recv_size = rt_usb_hcd_pipe_xfer(device->hcd, rndis->pipe_in, rndis->data_buffer, 2048, 0);
while (recv_size > 0) {
shift = offset % 4;
if (shift != 0) {
os_memmove(rndis->data_buffer + offset - shift , rndis->data_buffer + offset, recv_size);
offset -= shift;
}
/*上一个usb包余下的新rndis包数据*/
if (rndis->ts_saveLength) {
/*暂存的rndis包里有存储到该包的包头信息*/
if (rndis->ts_saveLength < sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef)) {
/*先拷贝rndis包头大小的长度确保能读取到该rndis包的长度信息*/
os_memcpy(rndis->ts_buffer + rndis->ts_saveLength,
rndis->data_buffer + offset,
MIN(recv_size, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef)));
rndis->ts_saveLength += MIN(recv_size, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
offset += MIN(recv_size, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
recv_size -= MIN(recv_size, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
}
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)(rndis->ts_buffer);
} else {
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)(rndis->data_buffer + offset);
/*没有余留的rndis包包类型也不对则丢掉该包可能丢掉一整个聚合的包正常不应该出现这种情况*/
if ((recv_size >= sizeof(uint32_t)) && (packet->MsgType != CDC_RNDIS_PACKET_MSG_ID)) {
os_printf("WRONG RNDIS ID!\r\n");
break;
}
/*包头对齐且长度大于一个完整包则不用拷贝到暂存buf直接传进lwip*/
if ((recv_size >= sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef)) && (recv_size >= packet->MsgLength)) {
flags = disable_irq();
input_cb = rndis->input_cb;
input_priv = rndis->input_priv;
enable_irq(flags);
if (input_cb) {
input_cb(&rndis->ndev,
(rt_uint8_t *)packet + packet->DataOffset + 8,
packet->DataLength,
input_priv);
}
offset += packet->MsgLength;
recv_size -= packet->MsgLength;
continue;
}
}
if (recv_size > (2 * sizeof(uint32_t))) {
target_copyLength = (packet->MsgLength - rndis->ts_saveLength);
} else {
target_copyLength = recv_size;
}
if (recv_size) {
os_memcpy(rndis->ts_buffer + rndis->ts_saveLength,
rndis->data_buffer + offset,
MIN(recv_size, target_copyLength));
}
offset += MIN(recv_size, target_copyLength);
rndis->ts_saveLength += MIN(recv_size, target_copyLength);
recv_size -= MIN(recv_size, target_copyLength);
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)(rndis->ts_buffer);
if ((packet->MsgType == CDC_RNDIS_PACKET_MSG_ID) && (rndis->ts_saveLength >= packet->MsgLength)) {
flags = disable_irq();
input_cb = rndis->input_cb;
input_priv = rndis->input_priv;
enable_irq(flags);
if (input_cb) {
input_cb(&rndis->ndev,
(rt_uint8_t *)packet + packet->DataOffset + 8,
packet->DataLength,
input_priv);
}
rndis->ts_saveLength -= packet->MsgLength;
}
}
if (recv_size < 0) {
// 返回负数大概是usb断线了不再循环读数准备释放线程了
rndis->ready = 0;
}
}
}
rt_err_t rt_usbh_rndis_run(struct usb_rndis *rndis)
{
if (rndis == NULL) {
return RET_ERR;
}
os_printf("rndis\r\n");
#ifndef STATIC_RNDIS_NETDEV
rt_usbh_rndis_attach(rndis);
rt_usbh_rndis_network_init(rndis);
#endif
rt_rndis_msg_init(rndis);
rndis->ready = 1;
os_timer_init(&rndis->keepalive_timer, rt_usbh_rndis_keepalive_timer,
OS_TIMER_MODE_ONCE, rndis);
os_timer_start(&rndis->keepalive_timer, 5000);
rt_thread_init(&rndis->recv_task, "rndis_recv", rndis_data_recv, rndis,
NULL, 512, OS_TASK_PRIORITY_HIGH-1, 20);
rt_thread_startup(&rndis->recv_task);
return RET_OK;
}
rt_err_t rt_usbh_rndis_stop(struct usb_rndis *rndis)
{
rt_uint32_t flags;
if (rndis == NULL) {
return RET_ERR;
}
rndis->ready = 0;
flags = disable_irq();
rndis->input_cb = NULL;
rndis->input_priv = NULL;
enable_irq(flags);
#ifndef STATIC_RNDIS_NETDEV
dev_unregister((struct dev_obj *)rndis);
lwip_netif_remove(&rndis->ndev);
#endif
os_timer_stop(&rndis->keepalive_timer);
os_timer_del(&rndis->keepalive_timer);
rt_thread_detach(&rndis->recv_task);
os_free(rndis->msg_buffer);
os_free(rndis->data_buffer);
os_free(rndis->ts_buffer);
#ifndef STATIC_RNDIS_NETDEV
os_free(rndis);
#endif
return RET_OK;
}
#endif

View File

@@ -0,0 +1,41 @@
#ifndef __CLASS_RNDIS_H__
#define __CLASS_RNDIS_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtthread.h>
#include "hal/netdev.h"
struct usb_rndis {
struct netdev ndev;
netdev_input_cb input_cb;
void *input_priv;
void *device;
struct rt_thread recv_task;
struct rt_timer keepalive_timer;
rt_uint8_t *msg_buffer;
rt_uint8_t *data_buffer;
//收到的下一个buf的内容先暂存在这个buf用于下次接收到后重组
rt_uint8_t *ts_buffer;
rt_uint32_t ts_saveLength;
rt_uint32_t req_id;
rt_uint8_t mac[6];
upipe_t pipe_in;
upipe_t pipe_out;
upipe_t pipe_int;
rt_uint8_t link_up: 1, ready: 1, resv: 6;
};
rt_err_t rt_usbh_rndis_run(struct usb_rndis *rndis);
rt_err_t rt_usbh_rndis_stop(struct usb_rndis *rndis);
rt_err_t rt_usbh_host_rndis_attach(struct usb_rndis *rndis);
void rndis_ctrl_recv(void *context);
void rndis_data_recv(void *context);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,552 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#ifdef RT_USBH_MSTORAGE
#include "mass.h"
#include "dev.h"
#include "devid.h"
#include "diskio.h"
#include "ff.h"
#include "osal_file.h"
#include "lib/ota/fw.h"
#include "tx_platform.h"
#include "dev/csi/hgdvp.h"
#define UDISK_MAX_COUNT 8
#define UDISK_CACHE_SIZE (512)
static rt_uint8_t _udisk_idset = 0;
static rt_uint8_t udisk_ota = 0;
struct udisk_device
{
rt_uint32_t count;
rt_uint32_t sector_size;
struct ustor_data* user_data;
struct uhintf* intf;
};
FATFS *udisk_fs = NULL;
static struct udisk_device usb_disk;
static int udisk_get_id(void)
{
int i;
for(i=0; i< UDISK_MAX_COUNT; i++)
{
if((_udisk_idset & (1 << i)) != 0) continue;
else break;
}
/* it should not happen */
if(i == UDISK_MAX_COUNT) RT_ASSERT(0);
_udisk_idset |= (1 << i);
return i;
}
static void udisk_free_id(int id)
{
RT_ASSERT(id < UDISK_MAX_COUNT);
_udisk_idset &= ~(1 << id);
}
static DSTATUS rt_udisk_status(void *dev)
{
struct udisk_device *disk = (struct udisk_device *)dev;
if((disk==NULL) || (disk->intf == NULL))
{
rt_kprintf("%s disk is null!!!\n",__FUNCTION__);
return RES_ERROR;
}
return RES_OK;
}
static DSTATUS rt_udisk_init(void *dev)
{
printf("%s %d\n",__FUNCTION__,__LINE__);
struct udisk_device *disk = (struct udisk_device *)dev;
if(!disk)
{
os_printf("disk is null!!!\n");
return RES_ERROR;
}
return RES_OK;
}
static DRESULT rt_udisk_read(void *dev, BYTE* buffer, DWORD sector,
UINT count)
{
rt_err_t ret;
struct uhintf* intf;
struct ustor_data* data;
int timeout = USB_TIMEOUT_LONG/5;
struct udisk_device *disk = (struct udisk_device *)dev;
/* check parameter */
if((disk==NULL) ||(buffer==NULL) || (disk->intf == NULL))
{
rt_kprintf("%s disk is null!!!\n",__FUNCTION__);
return RES_ERROR;
}
if(count > 4096) timeout *= 2;
data = (struct ustor_data*)disk->user_data;
intf = disk->intf;
//os_printf("%s sector:%d count:%d\n",__FUNCTION__,sector,count);
ret = rt_usbh_storage_read10(intf, (rt_uint8_t*)buffer, sector, count, timeout);
if (ret != RT_EOK)
{
rt_kprintf("usb mass_storage read failed\n");
return RES_ERROR;
}
return RES_OK;
}
static DRESULT rt_udisk_write (void *dev, BYTE* buffer, DWORD sector,
UINT count)
{
rt_err_t ret;
struct uhintf* intf;
struct ustor_data* data;
int timeout = USB_TIMEOUT_LONG/5;
struct udisk_device *disk = (struct udisk_device *)dev;
/* check parameter */
if((disk==NULL) ||(buffer==NULL) || (disk->intf == NULL)){
rt_kprintf("udisk write parameter error\n");
return RES_ERROR;
}
if(count * SECTOR_SIZE > 4096) timeout *= 2;
data = (struct ustor_data*)disk->user_data;
intf = disk->intf;
//os_printf("%s write sector:%d count:%d \n",__FUNCTION__,sector,count);
ret = rt_usbh_storage_write10(intf, (rt_uint8_t*)buffer, sector, count, timeout);
if (ret != RT_EOK)
{
rt_kprintf("usb mass_storage write %d sector failed\n", count);
return RES_ERROR;
}
return RES_OK;
}
static DRESULT rt_udisk_control(void *dev, BYTE cmd, void *buf)
{
printf("%s %d\n",__FUNCTION__,__LINE__);
struct udisk_device *udisk = (struct udisk_device *)dev;
rt_uint8_t ret = RES_OK;
//os_printf("cmd:%d\n",cmd);
switch(cmd)
{
case CTRL_SYNC:
break;
case GET_SECTOR_COUNT:
*(DWORD *)buf = udisk->count;
ret = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD *)buf = udisk->sector_size;
ret = RES_OK;
break;
case GET_BLOCK_SIZE:
*(DWORD *)buf = 1;
ret = RES_OK;
break;
default:
ret = RES_ERROR;
printf("rtos_sd_ioctl err\n");
break;
}
return ret;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops udisk_device_ops =
{
rt_udisk_init,
RT_NULL,
RT_NULL,
rt_udisk_read,
rt_udisk_write,
rt_udisk_control
};
#endif
static struct fatfs_diskio udisk_driver =
{
.status = rt_udisk_status,
.init = rt_udisk_init,
.read = rt_udisk_read,
.write = rt_udisk_write,
.ioctl = rt_udisk_control,
};
void rt_udisk_ota_thread(void)
{
#if DVP_EN
void *dvp = (void *)dev_get(HG_DVP_DEVID);
if(dvp)
{
dvp_close(dvp);
}
#endif
if(!udisk_ota){
rt_uint8_t *cache_buf = NULL;
void *fp = osal_fopen("USB:/UPDATE.BIN","r");
if(!fp)
{
os_printf("udisk ota file not open\n");
goto __udisk_ota_end;
}
rt_uint32_t filesize = osal_fsize(fp);
rt_uint32_t filesize_tmp = filesize;
rt_uint32_t readsize = UDISK_CACHE_SIZE;
rt_uint32_t ota_offset = 0;
cache_buf = (rt_uint8_t *)os_malloc(UDISK_CACHE_SIZE);
if(!cache_buf)
{
os_printf("cache_buf malloc failed\n");
goto __udisk_ota_end;
}
os_printf("filesize:%d cache_buf:%x\n",filesize,cache_buf);
while(filesize)
{
if(filesize < UDISK_CACHE_SIZE)
{
readsize = filesize;
}
osal_fread(cache_buf,readsize,1,fp);
libota_write_fw(filesize_tmp,ota_offset,cache_buf,readsize);
filesize -= readsize;
ota_offset += readsize;
}
udisk_ota = 1;
__udisk_ota_end:
if(fp)
{
osal_fclose(fp);
}
if(cache_buf)
{
os_free(cache_buf);
}
}
}
/**
* This function will run udisk driver when usb disk is detected.
*
* @param intf the usb interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_udisk_run(struct uhintf* intf)
{
int i = 0;
rt_err_t ret;
//char dname[8];
char sname[8];
rt_align(4) rt_uint8_t max_lun[1 + USB_RX_BUFF_RESERVE_SIZE];
rt_uint8_t *sector;
rt_align(4) rt_uint8_t sense[18 + USB_RX_BUFF_RESERVE_SIZE];
rt_align(4) rt_uint8_t inquiry[36 + USB_RX_BUFF_RESERVE_SIZE];
ustor_t stor;
/* check parameter */
RT_ASSERT(intf != RT_NULL);
printf("%s %d\n",__FUNCTION__,__LINE__);
/* set interface */
// ret = rt_usbh_set_interface(intf->device, intf->intf_desc->bInterfaceNumber);
// if(ret != RT_EOK)
// rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
/* reset mass storage class device */
ret = rt_usbh_storage_reset(intf);
if(ret != RT_EOK) return ret;
stor = (ustor_t)intf->user_data;
stor->dev_cnt = 1;
/* get max logic unit number */
ret = rt_usbh_storage_get_max_lun(intf, max_lun);
if(ret != RT_EOK)
rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
/* reset pipe in endpoint */
if(stor->pipe_in->status == UPIPE_STATUS_STALL)
{
ret = rt_usbh_clear_feature(intf->device,
stor->pipe_in->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
printf("%s %d\n",__FUNCTION__,__LINE__);
if(ret != RT_EOK) return ret;
}
/* reset pipe out endpoint */
if(stor->pipe_out->status == UPIPE_STATUS_STALL)
{
ret = rt_usbh_clear_feature(intf->device,
stor->pipe_out->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
printf("%s %d\n",__FUNCTION__,__LINE__);
if(ret != RT_EOK) return ret;
}
while((ret = rt_usbh_storage_inquiry(intf, inquiry)) != RT_EOK)
{
if(ret == -RT_EIO) return ret;
rt_thread_delay(5);
if(i++ < 10) continue;
rt_kprintf("rt_usbh_storage_inquiry error\n");
return -RT_ERROR;
}
i = 0;
/* wait device ready */
while((ret = rt_usbh_storage_test_unit_ready(intf)) != RT_EOK)
{
if(ret == -RT_EIO) return ret;
ret = rt_usbh_storage_request_sense(intf, sense);
if(ret == -RT_EIO) return ret;
rt_thread_delay(10);
if(i++ < 10) continue;
rt_kprintf("rt_usbh_storage_test_unit_ready error\n");
return -RT_ERROR;
}
i = 0;
rt_memset(stor->capicity, 0, sizeof(stor->capicity));
/* get storage capacity */
while((ret = rt_usbh_storage_get_capacity(intf,
(rt_uint8_t*)stor->capicity)) != RT_EOK)
{
if(ret == -RT_EIO) return ret;
rt_thread_delay(50);
if(i++ < 10) continue;
stor->capicity[0] = 2880;
stor->capicity[1] = 0x200;
rt_kprintf("rt_usbh_storage_get_capacity error\n");
break;
}
stor->capicity[0] = uswap_32(stor->capicity[0]);
stor->capicity[1] = uswap_32(stor->capicity[1]);
stor->capicity[0] += 1;
rt_kprintf("capicity %d, block size %d\n",
stor->capicity[0], stor->capicity[1]);
/* get the first sector to read partition table */
sector = (rt_uint8_t*) rt_malloc (SECTOR_SIZE + USB_RX_BUFF_RESERVE_SIZE);
if (sector == RT_NULL)
{
rt_kprintf("allocate partition sector buffer failed\n");
return -RT_ERROR;
}
rt_memset(sector, 0, SECTOR_SIZE);
rt_kprintf("read partition table\n");
/* get the partition table */
ret = rt_usbh_storage_read10(intf, sector, 0, 1, USB_TIMEOUT_LONG);
if(ret != RT_EOK)
{
rt_kprintf("read parition table error\n");
rt_free(sector);
return -RT_ERROR;
}
rt_kprintf("finished reading partition\n");
int res = 0;
struct ustor_data* data = rt_malloc(sizeof(struct ustor_data));
if (data == RT_NULL)
{
rt_kprintf("Allocate partition data buffer failed.");
}
rt_memset(data, 0, sizeof(struct ustor_data));
data->intf = intf;
// data->udisk_id = udisk_get_id();
// os_printf("udisk_id:%d\n",data->udisk_id);
// os_snprintf(dname, 6, "ud%d-%d", data->udisk_id, 0);
os_snprintf(sname, 8, "sem_ud%d", 0);
/* register sdcard device */
stor->dev[0].type = 0; //RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
stor->dev[0].ops = &udisk_device_ops;
#else
stor->dev[0].status = rt_udisk_status;
stor->dev[0].init = rt_udisk_init;
stor->dev[0].read = rt_udisk_read;
stor->dev[0].write = rt_udisk_write;
stor->dev[0].ioctl = rt_udisk_control;
#endif
stor->dev[0].user_data = (void*)data;
usb_disk.count = stor->capicity[0];
usb_disk.sector_size = stor->capicity[1];
usb_disk.user_data = data;
usb_disk.intf = intf;
fatfs_register_drive(DEV_USB, &udisk_driver, &usb_disk);
if(!udisk_fs)
{
udisk_fs = (FATFS *)os_malloc(sizeof(FATFS));
}
if(udisk_fs)
{
res = f_mount(udisk_fs, "USB:", 1);
if(res)
{
os_printf("%s mount fatfs err:%d\n",__FUNCTION__,res);
return RT_EOK;
}
}
DIR dir;
FILINFO f_info;
rt_uint8_t maxdir = 0;
FRESULT rets;
rets = f_opendir(&dir, "USB:/");
if (rets != FR_OK) {
printf("failed open\n");
return 1;
}
os_printf("===========USB DIR===========\n");
while (1) {
rets = f_readdir(&dir, &f_info);
if (rets != FR_OK) {
break;
}
if (f_info.fname[0] == 0) {
break;
} else {
if (f_info.fattrib) {
printf("%s \n", f_info.fname);
maxdir++;
}
}
}
os_printf("=============================\n");
os_printf("%s %d\n",__FUNCTION__,__LINE__);
#if 0
rt_thread_t thread;
thread = rt_thread_create("udisk_test",rt_udisk_ota_thread,NULL,4096,OS_TASK_PRIORITY_NORMAL,0);
if(thread != RT_NULL)
{
rt_thread_startup(thread);
}
#endif
rt_free(sector);
return RT_EOK;
}
/**
* This function will be invoked when usb disk plug out is detected and it would clean
* and release all udisk related resources.
*
* @param intf the usb interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_udisk_stop(struct uhintf* intf)
{
int i;
ustor_t stor;
struct ustor_data* data;
/* check parameter */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
stor = (ustor_t)intf->user_data;
RT_ASSERT(stor != RT_NULL);
for(i=0; i<stor->dev_cnt; i++)
{
struct ustor_device *dev = &stor->dev[i];
data = (struct ustor_data*)dev->user_data;
usb_disk.intf = NULL;
/* unmount filesystem */
f_umount("USB:");
if(udisk_fs)
{
os_free(udisk_fs);
udisk_fs = NULL;
}
// udisk_free_id(data->udisk_id);
rt_free(data);
}
return RT_EOK;
}
#endif

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-03 Yi Qiu first version
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "hid.h"
#if defined(RT_USBH_HID) && defined(RT_USBH_HID_KEYBOARD)
static struct uprotocal kbd_protocal;
static rt_err_t rt_usbh_hid_kbd_callback(void* arg)
{
rt_uint32_t int1, int2;
struct uhid* hid;
hid = (struct uhid*)arg;
rt_memcpy(&int1, hid->buffer, 4);
rt_memcpy(&int2, hid->buffer+4, 4);
if(int1 != 0 || int2 != 0)
{
os_printf("key down 0x%x, 0x%x", int1, int2);
}
return RT_EOK;
}
static rt_thread_t kbd_thread;
static void kbd_task(void* param)
{
struct uhintf* intf = (struct uhintf*)param;
while (1)
{
if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in,
((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize,
USB_TIMEOUT_BASIC) == 0)
{
break;
}
rt_usbh_hid_kbd_callback(intf->user_data);
}
}
static rt_err_t rt_usbh_hid_kbd_init(void* arg)
{
struct uhintf* intf = (struct uhintf*)arg;
RT_ASSERT(intf != RT_NULL);
rt_usbh_hid_set_protocal(intf, 0);
rt_usbh_hid_set_idle(intf, 10, 0);
os_printf("start usb keyboard");
kbd_thread = rt_thread_create("kbd0", kbd_task, intf, 1024, 8, 100);
rt_thread_startup(kbd_thread);
return RT_EOK;
}
/**
* This function will define the hid keyboard protocal, it will be register to the protocal list.
*
* @return the keyboard protocal structure.
*/
uprotocal_t rt_usbh_hid_protocal_kbd(void)
{
kbd_protocal.pro_id = USB_HID_KEYBOARD;
kbd_protocal.init = rt_usbh_hid_kbd_init;
kbd_protocal.callback = rt_usbh_hid_kbd_callback;
return &kbd_protocal;
}
#endif

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-03 Yi Qiu first version
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "hid.h"
#if defined(RT_USBH_HID) && defined(RT_USBH_HID_MOUSE)
static struct uprotocal mouse_protocal;
static rt_err_t rt_usbh_hid_mouse_callback(void* arg)
{
rt_uint32_t int1, int2;
struct uhid* hid;
hid = (struct uhid*)arg;
rt_memcpy(&int1, hid->buffer, 4);
rt_memcpy(&int2, hid->buffer+4, 4);
if(int1 != 0 || int2 != 0)
{
os_printf("key down 0x%x, 0x%x", int1, int2);
}
return RT_EOK;
}
static rt_thread_t mouse_thread;
static void mouse_task(void* param)
{
struct uhintf* intf = (struct uhintf*)param;
while (1)
{
if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in,
((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize,
USB_TIMEOUT_BASIC) == 0)
{
break;
}
rt_usbh_hid_mouse_callback(intf->user_data);
}
}
static rt_err_t rt_usbh_hid_mouse_init(void* arg)
{
struct uhintf* intf = (struct uhintf*)arg;
RT_ASSERT(intf != RT_NULL);
rt_usbh_hid_set_protocal(intf, 0);
rt_usbh_hid_set_idle(intf, 0, 0);
mouse_thread = rt_thread_create("mouse0", mouse_task, intf, 1024, 8, 100);
rt_thread_startup(mouse_thread);
os_printf("start usb mouse");
return RT_EOK;
}
/**
* This function will define the hid mouse protocal, it will be register to the protocal list.
*
* @return the keyboard protocal structure.
*/
uprotocal_t rt_usbh_hid_protocal_mouse(void)
{
mouse_protocal.pro_id = USB_HID_MOUSE;
mouse_protocal.init = rt_usbh_hid_mouse_init;
mouse_protocal.callback = rt_usbh_hid_mouse_callback;
return &mouse_protocal;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_AUDIO_H
#define USBH_AUDIO_H
#include "rtthread.h"
#include "include/rttusb_host.h"
#include "uaudioreg.h"
#include "dev/usb/hgusb20_v1_dev_api.h"
#include "dev/usb/usb11_v0/hgusb11_v0_host_api.h"
#include "lib/audio/uac/uac_host.h"
#include "audio_usbh_msi.h"
#ifndef CONFIG_USBHOST_MAX_AUDIO_CLASS
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
#endif
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
#define CONFIG_USBHOST_DEV_NAMELEN 16
struct usbh_audio_format_type {
rt_uint8_t channels;
rt_uint8_t format_type;
rt_uint8_t bitresolution;
rt_uint8_t sampfreq_num;
rt_uint32_t sampfreq[3];
};
/**
* bSourceID in feature_unit = input_terminal_id
* bSourceID in output_terminal = feature_unit_id
* terminal_link_id = input_terminal_id or output_terminal_id (if input_terminal_type or output_terminal_type is 0x0101)
*
*
*/
struct usbh_audio_module {
const char *name;
rt_uint8_t data_intf;
rt_uint8_t input_terminal_id;
rt_uint16_t input_terminal_type;
rt_uint16_t input_channel_config;
rt_uint8_t output_terminal_id;
rt_uint16_t output_terminal_type;
rt_uint8_t feature_unit_id;
rt_uint8_t feature_unit_controlsize;
rt_uint8_t feature_unit_controls[8];
rt_uint8_t terminal_link_id;
struct usbh_audio_format_type altsetting[CONFIG_USBHOST_MAX_INTF_ALTSETTINGS];
};
struct usbh_audio {
//struct usbh_hubport *hport;
struct uinstance* device;
char devname[CONFIG_USBHOST_DEV_NAMELEN];
struct uendpoint_descriptor isoin; /* ISO IN endpoint */
struct uendpoint_descriptor isoout; /* ISO OUT endpoint */
upipe_t pipe_in;
upipe_t pipe_out;
rt_uint8_t ctrl_intf; /* interface number */
rt_uint8_t minor;
rt_uint16_t isoin_mps;
rt_uint16_t isoout_mps;
bool is_opened;
rt_uint16_t bcdADC;
rt_uint8_t bInCollection;
rt_uint8_t num_of_intf_altsettings;
struct usbh_audio_module module[2];
rt_uint8_t module_num;
rt_uint8_t *rx_buff;
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_audio_open(struct usbh_audio *audio_class, const char *name, rt_uint32_t samp_freq);
int usbh_audio_close(struct usbh_audio *audio_class, const char *name);
int usbh_audio_get_min_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *min_volume);
int usbh_audio_get_max_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *max_volume);
int usbh_audio_get_cur_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *cur_volume);
int usbh_audio_get_res_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *res_volume);
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t volume_hex);
int usbh_audio_set_volume_db(struct usbh_audio *audio_class, const char *name, int volume_db, int min_volume_db, int max_volume_db);
int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, bool mute);
void rtt_usbh_audio_irq(void * dev, rt_uint32_t irq, rt_uint8_t ep);
rt_uint32_t rtt_usbh_audio_dev_pipe_mange(rt_uint8_t dev_num, const char *name, rt_uint8_t alloc_or_free);
rt_uint32_t rtt_usbh_audio_user_open();
rt_uint32_t rtt_usbh_audio_user_close();
rt_uint32_t rtt_usbh_audio_user_stop();
rt_uint32_t rtt_usbh_audio_user_start();
void usbh_audio_run(struct usbh_audio *audio_class);
void usbh_audio_stop(struct usbh_audio *audio_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_AUDIO_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_VIDEO_H
#define USBH_VIDEO_H
#include "rtthread.h"
#include "include/rttusb_host.h"
#include "include/usb_video.h"
#include "dev/usb/hgusb20_v1_dev_api.h"
#define USBH_VIDEO_PPB 1 //usbh video 软件双缓存区使能
#define USBH_VIDEO_FORMAT_UNCOMPRESSED 0
#define USBH_VIDEO_FORMAT_MJPEG 1
#define USBH_VIDEO_FORMAT_BASED 2
#define CONFIG_USBHOST_DEV_NAMELEN 16
#define CONFIG_ALTERSETTING_MAXLEN 10
#define USBH_VIDEO_MAX_FORMAT_NUM 5
#define USBH_VIDEO_MAX_FRAME_NUM 15
struct usbh_video_resolution {
rt_uint16_t wWidth;
rt_uint16_t wHeight;
rt_uint32_t dwDefaultFrameInterval;
};
struct usbh_video_format {
struct usbh_video_resolution frame[USBH_VIDEO_MAX_FRAME_NUM];
rt_uint8_t format_type;
rt_uint8_t num_of_frames;
};
struct usbh_videoframe {
rt_uint8_t *frame_buf;
rt_uint32_t frame_bufsize;
rt_uint32_t frame_format;
rt_uint32_t frame_size;
};
struct usbh_videostreaming {
struct usbh_videoframe *frame;
rt_uint32_t frame_format;
rt_uint32_t bufoffset;
rt_uint16_t width;
rt_uint16_t height;
};
struct intf_altersetting_cfg {
uep_desc_t ep_desc_t;
rt_uint32_t altersetting_num;
rt_uint32_t check_use;
};
struct usbh_video {
//struct usbh_hubport *hport;
struct uinstance* device;
char devname[CONFIG_USBHOST_DEV_NAMELEN];
struct uendpoint_descriptor isoin; /* ISO IN endpoint */
struct uendpoint_descriptor isoout; /* ISO OUT endpoint */
upipe_t pipe_in;
upipe_t pipe_out;
rt_uint8_t ctrl_intf; /* interface number */
rt_uint8_t data_intf; /* interface number */
rt_uint8_t minor;
struct video_probe_and_commit_controls probe;
struct video_probe_and_commit_controls commit;
rt_uint16_t isoin_mps;
rt_uint16_t isoout_mps;
bool is_opened;
rt_uint8_t current_format;
rt_uint16_t bcdVDC;
rt_uint8_t num_of_intf_altsettings;
rt_uint8_t num_of_formats;
struct usbh_video_format format[USBH_VIDEO_MAX_FORMAT_NUM];
rt_uint8_t *rx_buff;
#if USBH_VIDEO_PPB
volatile rt_uint8_t usbh_pingpang_flag;
rt_uint8_t *rx_double_buff;
#endif
struct intf_altersetting_cfg intf_altersetting[CONFIG_ALTERSETTING_MAXLEN];
rt_uint32_t cur_set_altersetting_num;
rt_uint32_t video_rx_size;
rt_uint32_t uvc_head;
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_video_get(struct usbh_video *video_class, rt_uint8_t request, rt_uint8_t intf, rt_uint8_t entity_id, rt_uint8_t cs, rt_uint8_t *buf, rt_uint16_t len);
int usbh_video_set(struct usbh_video *video_class, rt_uint8_t request, rt_uint8_t intf, rt_uint8_t entity_id, rt_uint8_t cs, rt_uint8_t *buf, rt_uint16_t len);
int usbh_video_open(struct usbh_video *video_class,
rt_uint8_t format_type,
rt_uint16_t wWidth,
rt_uint16_t wHeight,
rt_uint8_t altsetting);
int usbh_video_close(uinst_t device, struct usbh_video *video_class);
void usbh_video_list_info(struct usbh_video *video_class);
void rtt_usbh_video_irq(void * dev, rt_uint8_t ep, uhcd_t hcd);
void rtt_usb11h_video_irq(void * dev, rt_uint8_t ep , uhcd_t hcd);
rt_uint32_t rtt_usbh_video_dev_pipe_manage(rt_uint8_t dev_num, rt_uint8_t alloc_or_free);
rt_uint32_t rtt_usbh_video_user_open(rt_uint8_t dev_num);
rt_uint32_t rtt_usbh_video_user_close(rt_uint8_t dev_num);
void usbh_video_run(struct usbh_video *video_class);
void usbh_video_stop(struct usbh_video *video_class);
ucd_t rt_usbh_class_driver_video(void);
extern void usb_host_enum_finish_init_mjpeg(uint32_t uvc_format);
extern void usb_host_enum_finish_init_h264(uint32_t uvc_format);
#ifdef __cplusplus
}
#endif
#endif /* USBH_VIDEO_H */

View File

@@ -0,0 +1,138 @@
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "rndis.h"
#ifdef RT_USBH_WIRELESS
static struct uclass_driver wireless_driver;
static rt_err_t rt_usbh_wireless_enable(void *arg)
{
struct uhintf **intf = arg;
uhcd_t hcd = NULL;
uep_desc_t ep_desc = NULL;
struct usb_rndis *rndis = NULL;
upipe_t pipe;
rt_uint8_t ep_index;
if (intf[0] == NULL) {
return -EIO;
}
hcd = intf[0]->device->hcd;
os_printf("subclass %d, protocal %d\r\n",
intf[0]->intf_desc->bInterfaceSubClass,
intf[0]->intf_desc->bInterfaceProtocol);
// 中云信安cat1模组在iad描述符和接口描述符中不一致兼容多了一种判断
if ((intf[0]->intf_desc->bInterfaceSubClass == 1 && intf[0]->intf_desc->bInterfaceProtocol == 3) || \
(intf[0]->intf_desc->bInterfaceSubClass == 2 && intf[0]->intf_desc->bInterfaceProtocol == 255)) {
#ifdef STATIC_RNDIS_NETDEV
rndis = (struct usb_rndis *)dev_get(HG_LTE_RNDIS_DEVID);
#else
rndis = (struct usb_rndis *)os_zalloc(sizeof(struct usb_rndis));
#endif
if (rndis == NULL) {
os_printf("rndis alloc fail\r\n");
return -ENOMEM;
}
rndis->msg_buffer = (rt_uint8_t *)os_malloc(128 + USB_RX_BUFF_RESERVE_SIZE);
if (rndis->msg_buffer == NULL) {
os_printf("rndis msg buffer alloc fail\r\n");
os_free(rndis);
return -ENOMEM;
}
rndis->data_buffer = (rt_uint8_t *)os_malloc(2048 + USB_RX_BUFF_RESERVE_SIZE);
if (rndis->data_buffer == NULL) {
os_printf("rndis data buffer alloc fail\r\n");
os_free(rndis->msg_buffer);
os_free(rndis);
return -ENOMEM;
}
rndis->ts_buffer = (rt_uint8_t *)os_zalloc(2048 + USB_RX_BUFF_RESERVE_SIZE);
if(rndis->ts_buffer == NULL) {
os_printf("rndis ts_buf alloc fail\r\n");
os_free(rndis->msg_buffer);
os_free(rndis->data_buffer);
os_free(rndis);
return -ENOMEM;
}
rndis->ts_saveLength = 0;
rndis->device = intf[0]->device;
rndis->req_id = 1;
intf[0]->user_data = rndis;
for (ep_index = 0; ep_index < intf[0]->intf_desc->bNumEndpoints; ++ep_index) {
rt_usbh_get_endpoint_descriptor(intf[0]->intf_desc, ep_index, &ep_desc);
if (ep_desc == NULL) {
return RET_ERR;
}
if ((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_INT)
continue;
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
if (rt_usb_hcd_alloc_pipe(intf[0]->device->hcd, &pipe, intf[0]->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(intf[0]->device, pipe);
rndis->pipe_int = pipe;
}
}
for (ep_index = 0; ep_index < intf[1]->intf_desc->bNumEndpoints; ++ep_index) {
rt_usbh_get_endpoint_descriptor(intf[1]->intf_desc, ep_index, &ep_desc);
if (ep_desc == NULL) {
return RET_ERR;
}
if ((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
if (rt_usb_hcd_alloc_pipe(intf[0]->device->hcd, &pipe, intf[0]->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(intf[0]->device, pipe);
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
rndis->pipe_in = pipe;
} else {
rndis->pipe_out = pipe;
}
}
rt_usbh_rndis_run(rndis);
}
return RET_OK;
}
static rt_err_t rt_usbh_wireless_disable(void *arg)
{
struct uhintf *intf = arg;
struct usb_rndis *rndis = NULL;
if (intf == NULL) {
return -EIO;
}
rndis = intf->user_data;
if (rndis) {
rt_usbh_rndis_stop(rndis);
}
return RET_OK;
}
ucd_t rt_usbh_class_driver_wireless(void)
{
wireless_driver.class_code = USB_CLASS_WIRELESS;
wireless_driver.enable = rt_usbh_wireless_enable;
wireless_driver.disable = rt_usbh_wireless_disable;
return &wireless_driver;
}
#endif

View File

@@ -0,0 +1,472 @@
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "yuge.h"
#include "cdc.h"
#include "rndis.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
#include "lwip/tcpip.h"
#include "netif/ethernetif.h"
#include "lib/common/sysevt.h"
#ifdef RT_USBH_VENDOR_YUGE
// #define USB_VENDOR_ID_YUGE 0x19D1
// #define USB_PRODUCT_ID_YUGE 0x1003 // YM310 X09
#define YUGE_ATCMD_BUFF_SIZE 128
static char recv_str[YUGE_ATCMD_BUFF_SIZE];
static struct uclass_driver yuge_driver;
__weak void mifi_led_control(rt_int16_t rsrq, rt_int16_t rssi){};
static rt_bool_t send_recv_atcmd_check(void *context, const char *send_str,
const char *check_str, char *ret_str)
{
struct usb_yuge_at *yuge_at = context;
uinst_t device = yuge_at->device;
int recv_size;
char *recv_str = NULL;
rt_bool_t pass = RT_FALSE;
os_sprintf((char *)yuge_at->at_cmd_buff, send_str);
rt_usb_hcd_pipe_xfer(device->hcd, yuge_at->pipe_out,
yuge_at->at_cmd_buff, os_strlen(send_str), 0);
os_sleep_ms(10); // 需要点延迟给LTE模组反应
do {
// 每次读取会清除缓存
os_memset(yuge_at->at_cmd_buff, 0, YUGE_ATCMD_BUFF_SIZE);
recv_size = rt_usb_hcd_pipe_xfer(device->hcd, yuge_at->pipe_in,
yuge_at->at_cmd_buff, YUGE_ATCMD_BUFF_SIZE, 10);
if (recv_size > 0) {
recv_str = os_strstr(yuge_at->at_cmd_buff, check_str);
if (recv_str != NULL) {
pass = RT_TRUE;
if (ret_str != NULL && recv_size > os_strlen(check_str)) {
// ret_str存在说明需要获取返回结果做额外判断复制到函数外面
os_memcpy(ret_str, recv_str + os_strlen(check_str),
recv_size - os_strlen(check_str));
ret_str[recv_size - os_strlen(check_str)] = '\0'; // 字符串结束符
}
}
}
} while (recv_size > 0);
return pass;
}
// 计算下行频点FDD不知道上行频点号猜测直接偏固定频率
static rt_uint16_t eutra_channel_freq_mapping(rt_uint8_t band, rt_uint16_t earfcn, rt_bool_t uplink)
{
rt_uint16_t freq = 0;
switch (band) {
// FDD上下行频点有偏差
case 3:
freq = 1805 + (earfcn - 1200) / 10;
if (uplink)
freq -= 95;
break;
case 5:
freq = 869 + (earfcn - 2400) / 10;
if (uplink)
freq -= 45;
break;
case 8:
freq = 925 + (earfcn - 3450) / 10;
if (uplink)
freq -= 45;
break;
// TDD上下行使用相同频点
case 34: freq = 2010 + (earfcn - 36200) / 10; break;
case 38: freq = 2570 + (earfcn - 37750) / 10; break;
case 39: freq = 1880 + (earfcn - 38250) / 10; break;
case 40: freq = 2300 + (earfcn - 38650) / 10; break;
case 41: freq = 2496 + (earfcn - 39650) / 10; break;
default: break;
}
return freq;
}
static void yuge_network_info(void *context, char *recv_str)
{
struct usb_yuge_at *yuge_at = context;
//char *argv[4];
char **argv = NULL;
int argc = 0;
rt_int16_t rssi, ber;
rt_uint16_t num_dl;
rt_uint16_t freq_dl, freq_ul;
rt_uint16_t freq_wifi = 0;
rt_uint8_t band = 0, rxqual = 0;
argv = os_malloc(4 * sizeof(char *));
if (argv == NULL) {
return;
}
// 获取运营商
if (send_recv_atcmd_check(yuge_at, "AT+COPS?\r\n", "+COPS:", recv_str) == RT_TRUE) {
argc = os_strtok(recv_str, ",", argv, 4);
if (argc >= 3) {
// 0,0,"CHINA MOBILE",7
_os_printf("%s\r\n", argv[2]);
}
}
// 获取网络信息
if (send_recv_atcmd_check(yuge_at, "AT+CCED=0,1\r\n", "+CCED:", recv_str) == RT_TRUE) {
// argc = os_strtok(recv_str, ",", argv, 4);
// if (argc >= 4) {
// // "FDD LTE",46001,"LTE BAND 3",1650
// band = os_atoi(argv[2] + 10);
// num_dl = os_atoi(argv[3]);
// freq_dl = eutra_channel_freq_mapping(band, num_dl, 0);
// freq_ul = eutra_channel_freq_mapping(band, num_dl, 1);
// _os_printf("BAND: %d\r\n", band);
// _os_printf("F_dl: %d MHz, F_ul: %d MHz\r\n", freq_dl, freq_ul);
// // 检查有无和wifi频点冲突
// freq_wifi = sys_status.channel * 5 + 2407;
// // TDD同频ul和dl一致
// if (band == 40) {
// if ((freq_wifi - freq_dl < 90) && sys_status.channel != 13) {
// os_printf("!!!!!!! OVERLAP at %d and %d !!!!!!!\r\n", freq_wifi, freq_dl);
// SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_OVERLAP_WIFI, 13); // 切去高信道
// }
// } else if (band == 41) {
// if ((freq_dl - freq_wifi < 90) && sys_status.channel != 1) {
// os_printf("!!!!!!! OVERLAP at %d and %d !!!!!!!\r\n", freq_wifi, freq_dl);
// SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_OVERLAP_WIFI, 1); // 切去低信道
// }
// }
// }
}
if (send_recv_atcmd_check(yuge_at, "AT+CSQ\r\n", "+CSQ:", recv_str) == RT_TRUE) {
argc = os_strtok(recv_str, ",", argv, 4);
if (argc >= 2) {
// 28,99
rssi = os_atoi(argv[0]); // dBm
rxqual = os_atoi(argv[1]);
mifi_led_control(0, -113 + rssi * 2);
if (rssi == 99) {
_os_printf("RSSI: unknow\r\n");
} else if (rssi <= 0) {
_os_printf("RSSI: <= -113 dBm\r\n");
} else if (rssi >= 31) {
_os_printf("RSSI: >= -51 dBm\r\n");
} else {
_os_printf("RSSI: %d dBm\r\n", -113 + rssi * 2);
}
// RXQUAL_0 BER < 0,2 % Assumed value = 0,14 %
// RXQUAL_1 0,2 % < BER < 0,4 % Assumed value = 0,28 %
// RXQUAL_2 0,4 % < BER < 0,8 % Assumed value = 0,57 %
// RXQUAL_3 0,8 % < BER < 1,6 % Assumed value = 1,13 %
// RXQUAL_4 1,6 % < BER < 3,2 % Assumed value = 2,26 %
// RXQUAL_5 3,2 % < BER < 6,4 % Assumed value = 4,53 %
// RXQUAL_6 6,4 % < BER < 12,8 % Assumed value = 9,05 %
// RXQUAL_7 12,8 % < BER Assumed value = 18,10 %
ber = 1 << (rxqual + 1);
if (rxqual == 99) {
_os_printf("BER: unknow\r\n");
} else if (rxqual <= 0) {
_os_printf("BER: < 0.2 %%\r\n");
} else if (rxqual >= 7) {
_os_printf("BER: > 12.8 %%\r\n");
} else {
_os_printf("BER: %d.%d %% ~ %d.%d %%\r\n", (ber/2)/10, (ber/2)%10, ber/10, ber%10);
}
}
}
os_free(argv);
}
static void yuge_at_recv(void *context)
{
struct usb_yuge_at *yuge_at = context;
while (1) {
if (yuge_at->retry > 10) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_UNKNOW;
}
// os_printf("recv state:%d\r\n", yuge_at->state);
switch (yuge_at->state) {
case YUGE_STATE_UNKNOW:
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_CHECK_AT_STATUS;
break;
case YUGE_STATE_CHECK_AT_STATUS:
// AT查询模块是否工作启动初始化流程
if (send_recv_atcmd_check(yuge_at, "AT\r\n", "OK", NULL) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_CHECK_SIM_STATUS;
os_printf("AT ready\r\n");
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
case YUGE_STATE_CHECK_SIM_STATUS:
if (send_recv_atcmd_check(yuge_at, "AT+CPIN?\r\n", "+CPIN: READY", NULL) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_CHECK_CS_STATUS;
os_printf("SIM ready\r\n");
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
case YUGE_STATE_CHECK_CS_STATUS:
// AT+CREG查询CS域网络注册状态
if (send_recv_atcmd_check(yuge_at, "AT+CREG?\r\n", "+CREG: 0,1", NULL) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_CHECK_PS_STATUS;
os_printf("PS ready\r\n");
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
case YUGE_STATE_CHECK_PS_STATUS:
// AT+CEREG查询EPS域网络注册状态
if (send_recv_atcmd_check(yuge_at, "AT+CEREG?\r\n", "+CEREG: 0,1", NULL) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_INITIALIZED;
SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_CONNECTED, 0);
os_printf("CS ready\r\n");
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
case YUGE_STATE_CONFIG_PDP_CONTEXT:
// 设置band优先级排除band 40/41
send_recv_atcmd_check(yuge_at, "AT+QCFG=\"band\",0x0,0x6200000095\r\n", "+QCFG: \"band\",", NULL);
// AT+QICSGP设置场景参数
if (send_recv_atcmd_check(yuge_at, "AT+QICSGP=1,1,\"UNINET\",\"\",\"\",1\r\n", "OK", NULL) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_ACTIVE_PDP_CONTEXT;
os_printf("PDP config\r\n");
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
case YUGE_STATE_ACTIVE_PDP_CONTEXT:
// AT+QIACT激活PDP场景
if (send_recv_atcmd_check(yuge_at, "AT+QIACT=1\r\n", "OK", NULL) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_CHECK_IP_STATUS;
os_printf("PDP ready\r\n");
} else {
yuge_at->retry++;
if (yuge_at->retry > 3) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_DEACTIVE_PDP_CONTEXT;
}
os_sleep(1);
}
break;
case YUGE_STATE_CHECK_IP_STATUS:
// AT+QIACT查询激活PDP场景和IP
if (send_recv_atcmd_check(yuge_at, "AT+QIACT?\r\n", "+QIACT: 1,1,1,", recv_str) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_CONNECT_USB_ADAPTER;
os_printf("Get IP: %s", recv_str);
os_printf("PDP actived\r\n");
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
case YUGE_STATE_CONNECT_USB_ADAPTER:
// AT+QNETDEVCTL连接USB网卡
if (send_recv_atcmd_check(yuge_at, "AT+QNETDEVCTL=1,1,1\r\n", "OK", recv_str) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_INITIALIZED;
SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_CONNECTED, 0);
os_printf("network conneted\r\n");
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
case YUGE_STATE_INITIALIZED:
// 定时10s不知道干什么好呢
yuge_network_info(yuge_at, recv_str);
os_sleep(10);
break;
case YUGE_STATE_DEACTIVE_PDP_CONTEXT:
// 失败后反激活模组
if (send_recv_atcmd_check(yuge_at, "AT+QIDEACT=1\r\n", "OK", NULL) == RT_TRUE) {
yuge_at->retry = 0;
yuge_at->state = YUGE_STATE_CHECK_SIM_STATUS;
os_printf("PDP deactived\r\n");
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
case YUGE_STATE_POWERDOWN:
if (send_recv_atcmd_check(yuge_at, "AT+QPOWD\r\n", "POWERED DOWN", NULL) == RT_TRUE) {
yuge_at->retry = 0;
os_printf("LTE power down\r\n");
os_sleep(2);
mcu_reset();
} else {
yuge_at->retry++;
os_sleep(1);
}
break;
default:
break;
}
}
os_printf("at task end\r\n");
}
static rt_err_t rt_usbh_yuge_enable(void *arg)
{
rt_err_t ret = RET_OK;
struct uhintf **intf = arg;
uhcd_t hcd = NULL;
uep_desc_t ep_desc = NULL;
struct ustring_descriptor str_desc __attribute__((aligned(4)));
struct usb_yuge_at *yuge_at = NULL;
struct usb_cdc_line_coding line_coding;
upipe_t pipe;
rt_uint8_t ep_index, i;
if (intf[0] == NULL) {
return -EIO;
}
hcd = intf[0]->device->hcd;
os_printf("subclass %d, protocal %d\r\n",
intf[0]->intf_desc->bInterfaceSubClass,
intf[0]->intf_desc->bInterfaceProtocol);
if (intf[0]->intf_desc->bInterfaceSubClass == 2 && intf[0]->intf_desc->bInterfaceProtocol == 1) {
// 域格的AT口也是走复合设备描述符的
if (intf[0]->device->dev_desc.idProduct != USB_PRODUCT_ID_YUGE) {
return RET_ERR;
}
// 域格有多个复合设备第二个复合设备是AT串口算起来接口号是3但索引是用复合设备前面的那个所以是2
if (intf[0]->intf_desc->bInterfaceNumber != 2) {
return RET_ERR;
}
// 通过字符描述符判断哪个是主调试串口
ret = rt_usbh_get_string_descriptor(intf[0]->device, intf[0]->intf_desc->iInterface,
&str_desc, sizeof(struct ustring_descriptor));
if (ret != RET_OK) {
os_printf("no string\r\n");
return ret;
}
for (i = 0; i < str_desc.bLength; i += 2) { // 暂时没支持UNICODE的打印默认ASCII可以隔一个打印
_os_printf("%c", str_desc.String[i / 2]);
}
_os_printf("\r\n");
os_printf("yuge_at\r\n");
yuge_at = (struct usb_yuge_at *)os_zalloc(sizeof(struct usb_yuge_at));
if (yuge_at == NULL) {
os_printf("yuge at alloc fail\r\n");
return -ENOMEM;
}
// 按照命令预期回复长度对齐预留长度
yuge_at->at_cmd_buff = os_malloc(YUGE_ATCMD_BUFF_SIZE);
if (yuge_at->at_cmd_buff == NULL) {
os_printf("at_cmd_buff alloc fail\r\n");
os_free(yuge_at);
return -ENOMEM;
}
yuge_at->device = intf[0]->device;
intf[0]->user_data = yuge_at;
// 顺便注册devid
dev_register(HG_USB_AT_DEVID, (struct dev_obj *)yuge_at);
for (ep_index = 0; ep_index < intf[1]->intf_desc->bNumEndpoints; ++ep_index) {
rt_usbh_get_endpoint_descriptor(intf[1]->intf_desc, ep_index, &ep_desc);
if (ep_desc == NULL) {
os_printf("no ep_desc\r\n");
return RET_ERR;
}
if ((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
if (rt_usb_hcd_alloc_pipe(intf[0]->device->hcd, &pipe, intf[0]->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(intf[0]->device, pipe);
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
yuge_at->pipe_in = pipe;
} else {
yuge_at->pipe_out = pipe;
}
}
// 获取串口参数
os_memset(&line_coding, 0, sizeof(line_coding));
rt_usbh_cdc_get_line_coding(intf[0]->device, intf[0]->intf_desc->bInterfaceNumber, &line_coding);
os_printf("Serial: %d %d %d %d\r\n",
line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
rt_thread_init(&yuge_at->recv_task, "at_recv", yuge_at_recv, yuge_at,
NULL, 512, OS_TASK_PRIORITY_BELOW_NORMAL, 20);
rt_thread_startup(&yuge_at->recv_task);
}
return ret;
}
static rt_err_t rt_usbh_yuge_disable(void *arg)
{
struct uhintf *intf = arg;
uhcd_t hcd = NULL;
struct usb_yuge_at *yuge_at = NULL;
if (intf == NULL) {
return -EIO;
}
yuge_at = intf->user_data;
if (yuge_at) {
hcd = intf->device->hcd;
dev_unregister((struct dev_obj *)yuge_at);
rt_thread_detach(&yuge_at->recv_task);
os_free(yuge_at->at_cmd_buff);
os_free(yuge_at);
}
return RET_OK;
}
void rt_usbh_yuge_at_run(void *arg)
{
rt_usbh_yuge_enable(arg);
}
void rt_usbh_yuge_at_stop(void *arg)
{
rt_usbh_yuge_disable(arg);
}
// 中云信安使用CDC类型接口不用注册VENDOR了从cdc.c中调用enable处理
ucd_t rt_usbh_class_driver_yuge(void)
{
yuge_driver.class_code = USB_CLASS_CDC;
yuge_driver.enable = rt_usbh_yuge_enable;
yuge_driver.disable = rt_usbh_yuge_disable;
return &yuge_driver;
}
#endif

View File

@@ -0,0 +1,48 @@
#ifndef __CLASS_YUGE_H__
#define __CLASS_YUGE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtthread.h>
#define USB_VENDOR_ID_YUGE 0x19D1
#define USB_PRODUCT_ID_YUGE 0x1003 // YM310 X09
enum quectel_state {
YUGE_STATE_UNKNOW,
YUGE_STATE_CHECK_AT_STATUS,
YUGE_STATE_CHECK_SIM_STATUS,
YUGE_STATE_CHECK_CS_STATUS,
YUGE_STATE_CHECK_PS_STATUS,
YUGE_STATE_CHECK_USBNET_STATUS,
YUGE_STATE_CONFIG_USBNET_STATUS,
YUGE_STATE_CONFIG_PDP_CONTEXT,
YUGE_STATE_ACTIVE_PDP_CONTEXT,
YUGE_STATE_CHECK_IP_STATUS,
YUGE_STATE_CONNECT_USB_ADAPTER,
YUGE_STATE_INITIALIZED,
YUGE_STATE_DEACTIVE_PDP_CONTEXT,
YUGE_STATE_POWERDOWN,
};
struct usb_yuge_at {
struct dev_obj dev;
void *device;
struct rt_thread recv_task;
rt_uint8_t *at_cmd_buff;
rt_uint32_t state;
upipe_t pipe_in;
upipe_t pipe_out;
rt_uint8_t retry;
};
void rt_usbh_yuge_at_run(void *arg);
void rt_usbh_yuge_at_stop(void *arg);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,473 @@
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "zxinfo.h"
#include "cdc.h"
#include "rndis.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
#include "lwip/tcpip.h"
#include "netif/ethernetif.h"
#include "lib/common/sysevt.h"
#include "syscfg.h"
#ifdef RT_USBH_VENDOR_ZXINFO
// #define USB_VENDOR_ID_ZXINFO 0x3361
// #define USB_PRODUCT_ID_ZXINFO 0x7B6E // ZX800
#define ZXINFO_ATCMD_BUFF_SIZE 128
static char recv_str[ZXINFO_ATCMD_BUFF_SIZE];
static struct uclass_driver zxinfo_driver;
__weak void mifi_led_control(rt_int16_t rsrq, rt_int16_t rssi){};
static rt_bool_t send_recv_atcmd_check(void *context, const char *send_str,
const char *check_str, char *ret_str)
{
struct usb_zxinfo_at *zxinfo_at = context;
uinst_t device = zxinfo_at->device;
int recv_size;
char *recv_str = NULL;
rt_bool_t pass = RT_FALSE;
os_sprintf((char *)zxinfo_at->at_cmd_buff, send_str);
rt_usb_hcd_pipe_xfer(device->hcd, zxinfo_at->pipe_out,
zxinfo_at->at_cmd_buff, os_strlen(send_str), 0);
os_sleep_ms(10); // 需要点延迟给LTE模组反应
do {
// 每次读取会清除缓存
os_memset(zxinfo_at->at_cmd_buff, 0, ZXINFO_ATCMD_BUFF_SIZE);
recv_size = rt_usb_hcd_pipe_xfer(device->hcd, zxinfo_at->pipe_in,
zxinfo_at->at_cmd_buff, ZXINFO_ATCMD_BUFF_SIZE, 10);
if (recv_size > 0) {
recv_str = os_strstr(zxinfo_at->at_cmd_buff, check_str);
if (recv_str != NULL) {
pass = RT_TRUE;
if (ret_str != NULL && recv_size > os_strlen(check_str)) {
// ret_str存在说明需要获取返回结果做额外判断复制到函数外面
os_memcpy(ret_str, recv_str + os_strlen(check_str),
recv_size - os_strlen(check_str));
ret_str[recv_size - os_strlen(check_str)] = '\0'; // 字符串结束符
}
}
}
} while (recv_size > 0);
return pass;
}
// 计算下行频点FDD不知道上行频点号猜测直接偏固定频率
static rt_uint16_t eutra_channel_freq_mapping(rt_uint8_t band, rt_uint16_t earfcn, rt_bool_t uplink)
{
rt_uint16_t freq = 0;
switch (band) {
// FDD上下行频点有偏差
case 3:
freq = 1805 + (earfcn - 1200) / 10;
if (uplink)
freq -= 95;
break;
case 5:
freq = 869 + (earfcn - 2400) / 10;
if (uplink)
freq -= 45;
break;
case 8:
freq = 925 + (earfcn - 3450) / 10;
if (uplink)
freq -= 45;
break;
// TDD上下行使用相同频点
case 34: freq = 2010 + (earfcn - 36200) / 10; break;
case 38: freq = 2570 + (earfcn - 37750) / 10; break;
case 39: freq = 1880 + (earfcn - 38250) / 10; break;
case 40: freq = 2300 + (earfcn - 38650) / 10; break;
case 41: freq = 2496 + (earfcn - 39650) / 10; break;
default: break;
}
return freq;
}
static void zxinfo_network_info(void *context, char *recv_str)
{
struct usb_zxinfo_at *zxinfo_at = context;
//char *argv[4];
char **argv = NULL;
int argc = 0;
rt_int16_t rssi, ber;
rt_uint16_t num_dl;
rt_uint16_t freq_dl, freq_ul;
rt_uint16_t freq_wifi = 0;
rt_uint8_t band = 0, rxqual = 0;
argv = os_malloc(4 * sizeof(char *));
if (argv == NULL) {
return;
}
// 获取运营商
if (send_recv_atcmd_check(zxinfo_at, "AT+COPS?\r\n", "+COPS:", recv_str) == RT_TRUE) {
argc = os_strtok(recv_str, ",", argv, 4);
if (argc >= 3) {
// 0,0,"CHINA MOBILE",7
_os_printf("%s\r\n", argv[2]);
}
}
// 获取网络信息
if (send_recv_atcmd_check(zxinfo_at, "AT+QNWINFO\r\n", "+QNWINFO:", recv_str) == RT_TRUE) {
argc = os_strtok(recv_str, ",", argv, 4);
if (argc >= 4) {
// "FDD LTE",46001,"LTE BAND 3",1650
band = os_atoi(argv[2] + 10);
num_dl = os_atoi(argv[3]);
freq_dl = eutra_channel_freq_mapping(band, num_dl, 0);
freq_ul = eutra_channel_freq_mapping(band, num_dl, 1);
_os_printf("BAND: %d\r\n", band);
_os_printf("F_dl: %d MHz, F_ul: %d MHz\r\n", freq_dl, freq_ul);
// 检查有无和wifi频点冲突
freq_wifi = sys_status.channel * 5 + 2407;
// TDD同频ul和dl一致
if (band == 40) {
if ((freq_wifi - freq_dl < 90) && sys_status.channel != 13) {
os_printf("!!!!!!! OVERLAP at %d and %d !!!!!!!\r\n", freq_wifi, freq_dl);
SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_OVERLAP_WIFI, 13); // 切去高信道
}
} else if (band == 41) {
if ((freq_dl - freq_wifi < 90) && sys_status.channel != 1) {
os_printf("!!!!!!! OVERLAP at %d and %d !!!!!!!\r\n", freq_wifi, freq_dl);
SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_OVERLAP_WIFI, 1); // 切去低信道
}
}
}
}
if (send_recv_atcmd_check(zxinfo_at, "AT+CSQ\r\n", "+CSQ:", recv_str) == RT_TRUE) {
argc = os_strtok(recv_str, ",", argv, 4);
if (argc >= 2) {
// 28,99
rssi = os_atoi(argv[0]); // dBm
rxqual = os_atoi(argv[1]);
mifi_led_control(0, -113 + rssi * 2);
if (rssi == 99) {
_os_printf("RSSI: unknow\r\n");
} else if (rssi <= 0) {
_os_printf("RSSI: <= -113 dBm\r\n");
} else if (rssi >= 31) {
_os_printf("RSSI: >= -51 dBm\r\n");
} else {
_os_printf("RSSI: %d dBm\r\n", -113 + rssi * 2);
}
// RXQUAL_0 BER < 0,2 % Assumed value = 0,14 %
// RXQUAL_1 0,2 % < BER < 0,4 % Assumed value = 0,28 %
// RXQUAL_2 0,4 % < BER < 0,8 % Assumed value = 0,57 %
// RXQUAL_3 0,8 % < BER < 1,6 % Assumed value = 1,13 %
// RXQUAL_4 1,6 % < BER < 3,2 % Assumed value = 2,26 %
// RXQUAL_5 3,2 % < BER < 6,4 % Assumed value = 4,53 %
// RXQUAL_6 6,4 % < BER < 12,8 % Assumed value = 9,05 %
// RXQUAL_7 12,8 % < BER Assumed value = 18,10 %
ber = 1 << (rxqual + 1);
if (rxqual == 99) {
_os_printf("BER: unknow\r\n");
} else if (rxqual <= 0) {
_os_printf("BER: < 0.2 %%\r\n");
} else if (rxqual >= 7) {
_os_printf("BER: > 12.8 %%\r\n");
} else {
_os_printf("BER: %d.%d %% ~ %d.%d %%\r\n", (ber/2)/10, (ber/2)%10, ber/10, ber%10);
}
}
}
os_free(argv);
}
static void zxinfo_at_recv(void *context)
{
struct usb_zxinfo_at *zxinfo_at = context;
while (1) {
if (zxinfo_at->retry > 10) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_UNKNOW;
}
// os_printf("recv state:%d\r\n", zxinfo_at->state);
switch (zxinfo_at->state) {
case ZXINFO_STATE_UNKNOW:
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_CHECK_AT_STATUS;
break;
case ZXINFO_STATE_CHECK_AT_STATUS:
// AT查询模块是否工作启动初始化流程
if (send_recv_atcmd_check(zxinfo_at, "AT\r\n", "OK", NULL) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_CHECK_SIM_STATUS;
os_printf("AT ready\r\n");
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
case ZXINFO_STATE_CHECK_SIM_STATUS:
if (send_recv_atcmd_check(zxinfo_at, "AT+CPIN?\r\n", "+CPIN: READY", NULL) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_CHECK_CS_STATUS;
os_printf("SIM ready\r\n");
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
case ZXINFO_STATE_CHECK_CS_STATUS:
// AT+CREG查询CS域网络注册状态
if (send_recv_atcmd_check(zxinfo_at, "AT+CREG?\r\n", "+CREG: 0,1", NULL) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_CHECK_PS_STATUS;
os_printf("PS ready\r\n");
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
case ZXINFO_STATE_CHECK_PS_STATUS:
// AT+CEREG查询EPS域网络注册状态
if (send_recv_atcmd_check(zxinfo_at, "AT+CEREG?\r\n", "+CEREG: 0,1", NULL) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_INITIALIZED;
SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_CONNECTED, 0);
os_printf("CS ready\r\n");
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
case ZXINFO_STATE_CONFIG_PDP_CONTEXT:
// 设置band优先级排除band 40/41
send_recv_atcmd_check(zxinfo_at, "AT+QCFG=\"band\",0x0,0x6200000095\r\n", "+QCFG: \"band\",", NULL);
// AT+QICSGP设置场景参数
if (send_recv_atcmd_check(zxinfo_at, "AT+QICSGP=1,1,\"UNINET\",\"\",\"\",1\r\n", "OK", NULL) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_ACTIVE_PDP_CONTEXT;
os_printf("PDP config\r\n");
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
case ZXINFO_STATE_ACTIVE_PDP_CONTEXT:
// AT+QIACT激活PDP场景
if (send_recv_atcmd_check(zxinfo_at, "AT+QIACT=1\r\n", "OK", NULL) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_CHECK_IP_STATUS;
os_printf("PDP ready\r\n");
} else {
zxinfo_at->retry++;
if (zxinfo_at->retry > 3) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_DEACTIVE_PDP_CONTEXT;
}
os_sleep(1);
}
break;
case ZXINFO_STATE_CHECK_IP_STATUS:
// AT+QIACT查询激活PDP场景和IP
if (send_recv_atcmd_check(zxinfo_at, "AT+QIACT?\r\n", "+QIACT: 1,1,1,", recv_str) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_CONNECT_USB_ADAPTER;
os_printf("Get IP: %s", recv_str);
os_printf("PDP actived\r\n");
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
case ZXINFO_STATE_CONNECT_USB_ADAPTER:
// AT+QNETDEVCTL连接USB网卡
if (send_recv_atcmd_check(zxinfo_at, "AT+QNETDEVCTL=1,1,1\r\n", "OK", recv_str) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_INITIALIZED;
SYSEVT_NEW_LTE_EVT(SYSEVT_LTE_CONNECTED, 0);
os_printf("network conneted\r\n");
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
case ZXINFO_STATE_INITIALIZED:
// 定时10s不知道干什么好呢
zxinfo_network_info(zxinfo_at, recv_str);
os_sleep(10);
break;
case ZXINFO_STATE_DEACTIVE_PDP_CONTEXT:
// 失败后反激活模组
if (send_recv_atcmd_check(zxinfo_at, "AT+QIDEACT=1\r\n", "OK", NULL) == RT_TRUE) {
zxinfo_at->retry = 0;
zxinfo_at->state = ZXINFO_STATE_CHECK_SIM_STATUS;
os_printf("PDP deactived\r\n");
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
case ZXINFO_STATE_POWERDOWN:
if (send_recv_atcmd_check(zxinfo_at, "AT+QPOWD\r\n", "POWERED DOWN", NULL) == RT_TRUE) {
zxinfo_at->retry = 0;
os_printf("LTE power down\r\n");
os_sleep(2);
mcu_reset();
} else {
zxinfo_at->retry++;
os_sleep(1);
}
break;
default:
break;
}
}
os_printf("at task end\r\n");
}
static rt_err_t rt_usbh_zxinfo_enable(void *arg)
{
rt_err_t ret = RET_OK;
struct uhintf **intf = arg;
uhcd_t hcd = NULL;
uep_desc_t ep_desc = NULL;
struct ustring_descriptor str_desc __attribute__((aligned(4)));
struct usb_zxinfo_at *zxinfo_at = NULL;
struct usb_cdc_line_coding line_coding;
upipe_t pipe;
rt_uint8_t ep_index, i;
if (intf[0] == NULL) {
return -EIO;
}
hcd = intf[0]->device->hcd;
os_printf("subclass %d, protocal %d\r\n",
intf[0]->intf_desc->bInterfaceSubClass,
intf[0]->intf_desc->bInterfaceProtocol);
if (intf[0]->intf_desc->bInterfaceSubClass == 2 && intf[0]->intf_desc->bInterfaceProtocol == 1) {
// 中云信安的AT口也是走复合设备描述符的
if (intf[0]->device->dev_desc.idProduct != USB_PRODUCT_ID_ZXINFO) {
return RET_ERR;
}
// 中云信安有多个复合设备第二个复合设备是AT串口算起来接口号是5但索引是用复合设备前面的那个所以是4
if (intf[0]->intf_desc->bInterfaceNumber != 4) {
return RET_ERR;
}
// 通过字符描述符判断哪个是主调试串口
ret = rt_usbh_get_string_descriptor(intf[0]->device, intf[0]->intf_desc->iInterface,
&str_desc, sizeof(struct ustring_descriptor));
if (ret != RET_OK) {
os_printf("no string\r\n");
return ret;
}
for (i = 0; i < str_desc.bLength; i += 2) { // 暂时没支持UNICODE的打印默认ASCII可以隔一个打印
_os_printf("%c", str_desc.String[i / 2]);
}
_os_printf("\r\n");
os_printf("zxinfo_at\r\n");
zxinfo_at = (struct usb_zxinfo_at *)os_zalloc(sizeof(struct usb_zxinfo_at));
if (zxinfo_at == NULL) {
os_printf("zxinfo at alloc fail\r\n");
return -ENOMEM;
}
// 按照命令预期回复长度对齐预留长度
zxinfo_at->at_cmd_buff = os_malloc(ZXINFO_ATCMD_BUFF_SIZE);
if (zxinfo_at->at_cmd_buff == NULL) {
os_printf("at_cmd_buff alloc fail\r\n");
os_free(zxinfo_at);
return -ENOMEM;
}
zxinfo_at->device = intf[0]->device;
intf[0]->user_data = zxinfo_at;
// 顺便注册devid
dev_register(HG_USB_AT_DEVID, (struct dev_obj *)zxinfo_at);
for (ep_index = 0; ep_index < intf[1]->intf_desc->bNumEndpoints; ++ep_index) {
rt_usbh_get_endpoint_descriptor(intf[1]->intf_desc, ep_index, &ep_desc);
if (ep_desc == NULL) {
os_printf("no ep_desc\r\n");
return RET_ERR;
}
if ((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
if (rt_usb_hcd_alloc_pipe(intf[0]->device->hcd, &pipe, intf[0]->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(intf[0]->device, pipe);
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) {
zxinfo_at->pipe_in = pipe;
} else {
zxinfo_at->pipe_out = pipe;
}
}
// 获取串口参数
os_memset(&line_coding, 0, sizeof(line_coding));
rt_usbh_cdc_get_line_coding(intf[0]->device, intf[0]->intf_desc->bInterfaceNumber, &line_coding);
os_printf("Serial: %d %d %d %d\r\n",
line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
rt_thread_init(&zxinfo_at->recv_task, "at_recv", zxinfo_at_recv, zxinfo_at,
NULL, 512, OS_TASK_PRIORITY_BELOW_NORMAL, 20);
rt_thread_startup(&zxinfo_at->recv_task);
}
return ret;
}
static rt_err_t rt_usbh_zxinfo_disable(void *arg)
{
struct uhintf *intf = arg;
uhcd_t hcd = NULL;
struct usb_zxinfo_at *zxinfo_at = NULL;
if (intf == NULL) {
return -EIO;
}
zxinfo_at = intf->user_data;
if (zxinfo_at) {
hcd = intf->device->hcd;
dev_unregister((struct dev_obj *)zxinfo_at);
rt_thread_detach(&zxinfo_at->recv_task);
os_free(zxinfo_at->at_cmd_buff);
os_free(zxinfo_at);
}
return RET_OK;
}
void rt_usbh_zxinfo_at_run(void *arg)
{
rt_usbh_zxinfo_enable(arg);
}
void rt_usbh_zxinfo_at_stop(void *arg)
{
rt_usbh_zxinfo_disable(arg);
}
// 中云信安使用CDC类型接口不用注册VENDOR了从cdc.c中调用enable处理
ucd_t rt_usbh_class_driver_zxinfo(void)
{
zxinfo_driver.class_code = USB_CLASS_CDC;
zxinfo_driver.enable = rt_usbh_zxinfo_enable;
zxinfo_driver.disable = rt_usbh_zxinfo_disable;
return &zxinfo_driver;
}
#endif

View File

@@ -0,0 +1,48 @@
#ifndef __CLASS_ZXINFO_H__
#define __CLASS_ZXINFO_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <rtthread.h>
#define USB_VENDOR_ID_ZXINFO 0x3361
#define USB_PRODUCT_ID_ZXINFO 0x7B6E // ZX800
enum zxinfo_state {
ZXINFO_STATE_UNKNOW,
ZXINFO_STATE_CHECK_AT_STATUS,
ZXINFO_STATE_CHECK_SIM_STATUS,
ZXINFO_STATE_CHECK_CS_STATUS,
ZXINFO_STATE_CHECK_PS_STATUS,
ZXINFO_STATE_CHECK_USBNET_STATUS,
ZXINFO_STATE_CONFIG_USBNET_STATUS,
ZXINFO_STATE_CONFIG_PDP_CONTEXT,
ZXINFO_STATE_ACTIVE_PDP_CONTEXT,
ZXINFO_STATE_CHECK_IP_STATUS,
ZXINFO_STATE_CONNECT_USB_ADAPTER,
ZXINFO_STATE_INITIALIZED,
ZXINFO_STATE_DEACTIVE_PDP_CONTEXT,
ZXINFO_STATE_POWERDOWN,
};
struct usb_zxinfo_at {
struct dev_obj dev;
void *device;
struct rt_thread recv_task;
rt_uint8_t *at_cmd_buff;
rt_uint32_t state;
upipe_t pipe_in;
upipe_t pipe_out;
rt_uint8_t retry;
};
void rt_usbh_zxinfo_at_run(void *arg);
void rt_usbh_zxinfo_at_stop(void *arg);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,155 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-03-12 Yi Qiu first version
* 2021-02-23 Leslie Lee provide possibility for multi usb host
*/
#include <rtthread.h>
#include <rtservice.h>
#include <include/rttusb_host.h>
static rt_list_t _driver_list;
static rt_bool_t _driver_list_created = RT_FALSE;
/**
* This function will initilize the usb class driver related data structure,
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_init(void)
{
if (_driver_list_created == RT_FALSE)
{
rt_list_init(&_driver_list);
_driver_list_created = RT_TRUE;
}
return RT_EOK;
}
/**
* This function will register an usb class driver to the class driver manager.
*
* @param drv the pointer of the usb class driver.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_register(ucd_t drv)
{
if (drv == RT_NULL) return -RT_ERROR;
if (rt_usbh_class_driver_find(drv->class_code, drv->subclass_code, drv->vendor_id) == RT_NULL)
{
/* insert class driver into driver list */
rt_list_insert_after(&_driver_list, &(drv->list));
}
return RT_EOK;
}
/**
* This function will removes a previously registed usb class driver.
*
* @param drv the pointer of the usb class driver structure.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_unregister(ucd_t drv)
{
RT_ASSERT(drv != RT_NULL);
/* remove class driver from driver list */
rt_list_remove(&(drv->list));
return RT_EOK;
}
/**
* This function will run an usb class driver.
*
* @param drv the pointer of usb class driver.
* @param args the parameter of run function.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args)
{
RT_ASSERT(drv != RT_NULL);
if(drv->enable != RT_NULL)
drv->enable(args);
return RT_EOK;
}
/**
* This function will stop a usb class driver.
*
* @param drv the pointer of usb class driver structure.
* @param args the argument of the stop function.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args)
{
RT_ASSERT(drv != RT_NULL);
if(drv->disable != RT_NULL)
drv->disable(args);
return RT_EOK;
}
/**
* This function finds a usb class driver by specified class code and subclass code.
*
* @param class_code the usb class driver's class code.
* @param subclass_code the usb class driver's sub class code.
*
* @return the registered usb class driver on successful, or RT_NULL on failure.
*/
ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code, int vendor_id)
{
struct rt_list_node *node;
/* enter critical */
if (rt_thread_self() != RT_NULL)
rt_enter_critical();
/* try to find driver object */
for (node = _driver_list.next; node != &_driver_list; node = node->next)
{
ucd_t drv =
(ucd_t)rt_list_entry(node, struct uclass_driver, list);
if (drv->class_code == class_code)
{
if (drv->class_code == USB_CLASS_VEND_SPECIFIC)
{
/* need check vendor id */
if (drv->vendor_id != vendor_id)
{
continue;
}
}
/* leave critical */
if (rt_thread_self() != RT_NULL)
rt_exit_critical();
return drv;
}
}
/* leave critical */
if (rt_thread_self() != RT_NULL)
rt_exit_critical();
/* not found */
return RT_NULL;
}

View File

@@ -0,0 +1,952 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
* 2021-02-23 Leslie Lee provide possibility for multi usb host
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#include "dev/usb/hgusb20_v1_dev_api.h"
#define USB_THREAD_STACK_SIZE 2048
//#define DBG_TAG "usb.host.hub"
//#define DBG_LVL DBG_INFO
//#include <rtdbg.h>
// static struct rt_messagequeue *usb_mq;
static struct uclass_driver hub_driver;
static rt_sem_t hub_sem = RT_NULL;
static rt_thread_t usbh_hub_thread = RT_NULL;
// static struct uhub root_hub;
static rt_err_t root_hub_ctrl(struct uhcd *hcd, rt_uint16_t port, rt_uint8_t cmd, void *args)
{
switch(cmd)
{
case RH_GET_PORT_STATUS:
(*(rt_uint32_t *)args) = hcd->roothub->port_status[port-1];
break;
case RH_SET_PORT_STATUS:
hcd->roothub->port_status[port-1] = (*(rt_uint32_t *)args);
break;
case RH_CLEAR_PORT_FEATURE:
switch(((rt_uint32_t)args))
{
case PORT_FEAT_C_CONNECTION:
hcd->roothub->port_status[port-1] &= ~PORT_CCSC;
break;
case PORT_FEAT_C_ENABLE:
hcd->roothub->port_status[port-1] &= ~PORT_PESC;
break;
case PORT_FEAT_C_SUSPEND:
hcd->roothub->port_status[port-1] &= ~PORT_PSSC;
break;
case PORT_FEAT_C_OVER_CURRENT:
hcd->roothub->port_status[port-1] &= ~PORT_POCIC;
break;
case PORT_FEAT_C_RESET:
hcd->roothub->port_status[port-1] &= ~PORT_PRSC;
break;
}
break;
case RH_SET_PORT_FEATURE:
switch((rt_uint32_t)args)
{
case PORT_FEAT_CONNECTION:
hcd->roothub->port_status[port-1] |= PORT_CCSC;
break;
case PORT_FEAT_ENABLE:
hcd->roothub->port_status[port-1] |= PORT_PESC;
break;
case PORT_FEAT_SUSPEND:
hcd->roothub->port_status[port-1] |= PORT_PSSC;
break;
case PORT_FEAT_OVER_CURRENT:
hcd->roothub->port_status[port-1] |= PORT_POCIC;
break;
case PORT_FEAT_RESET:
hcd->ops->reset_port(port);
break;
case PORT_FEAT_POWER:
break;
case PORT_FEAT_LOWSPEED:
break;
case PORT_FEAT_HIGHSPEED:
break;
}
break;
default:
return -RT_ERROR;
}
return RT_EOK;
}
void rt_usbh_root_hub_connect_handler(struct uhcd *hcd, rt_uint8_t port, rt_bool_t isHS)
{
struct uhost_msg msg;
if(hcd == NULL || hcd->roothub == NULL)
{
rt_kprintf("[%s]:hcd or hcd->roothub is NULL!!!\r\n",__FUNCTION__);
return;
}
msg.type = USB_MSG_CONNECT_IRQ;
msg.content.hub = hcd->roothub;
rt_usbh_event_signal(hcd, &msg);
}
void rt_usbh_root_hub_disconnect_handler(struct uhcd *hcd, rt_uint8_t port)
{
struct uhost_msg msg;
if(hcd == NULL || hcd->roothub == NULL)
{
rt_kprintf("[%s]:hcd or hcd->roothub is NULL!!!\r\n",__FUNCTION__);
return;
}
msg.type = USB_MSG_DISCONNECT_IRQ;
msg.content.hub = hcd->roothub;
rt_usbh_event_signal(hcd, &msg);
}
/**
* This function will do USB_REQ_GET_DESCRIPTOR bRequest for the device instance
* to get usb hub descriptor.
*
* @param intf the interface instance.
* @buffer the data buffer to save usb hub descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer, rt_size_t nbytes)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(device != RT_NULL);
LOG_D("%s %d\n",__FUNCTION__,__LINE__);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_GET_DESCRIPTOR;
setup.wIndex = 0;
setup.wLength = nbytes;
setup.wValue = USB_DESC_TYPE_HUB << 8;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
return -RT_ERROR;
}
/**
* This function will do USB_REQ_GET_STATUS bRequest for the device instance
* to get usb hub status.
*
* @param intf the interface instance.
* @buffer the data buffer to save usb hub status.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint32_t* buffer)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(device != RT_NULL);
LOG_D("%s %d\n",__FUNCTION__,__LINE__);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_GET_STATUS;
setup.wIndex = 0;
setup.wLength = 4;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, 4, timeout) == 4)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
return -RT_ERROR;
}
/**
* This function will do USB_REQ_GET_STATUS bRequest for the device instance
* to get hub port status.
*
* @param intf the interface instance.
* @port the hub port to get status.
* @buffer the data buffer to save usb hub status.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_get_port_status(uhub_t hub, rt_uint16_t port, rt_uint32_t* buffer)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
//LOG_D("%s %d\n",__FUNCTION__,__LINE__);
/* get roothub port status */
if(hub->is_roothub)
{
root_hub_ctrl(hub->hcd, port, RH_GET_PORT_STATUS,
(void*)buffer);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_OTHER;
setup.bRequest = USB_REQ_GET_STATUS;
setup.wIndex = port;
setup.wLength = 4;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(hub->hcd, hub->self->pipe_ep0_in, buffer, 4, timeout) == 4)
{
if(rt_usb_hcd_pipe_xfer(hub->hcd, hub->self->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
return -RT_ERROR;
}
/**
* This function will do USB_REQ_CLEAR_FEATURE bRequest for the device instance
* to clear feature of the hub port.
*
* @param intf the interface instance.
* @port the hub port.
* @feature feature to be cleared.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_clear_port_feature(uhub_t hub, rt_uint16_t port, rt_uint16_t feature)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
LOG_D("%s %d\n",__FUNCTION__,__LINE__);
/* clear roothub feature */
if(hub->is_roothub)
{
root_hub_ctrl(hub->hcd, port, RH_CLEAR_PORT_FEATURE,
(void*)(rt_uint32_t)feature);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_OTHER;
setup.bRequest = USB_REQ_CLEAR_FEATURE;
setup.wIndex = port;
setup.wLength = 0;
setup.wValue = feature;
if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(hub->hcd, hub->self->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
return -RT_ERROR;
}
/**
* This function will do USB_REQ_SET_FEATURE bRequest for the device instance
* to set feature of the hub port.
*
* @param intf the interface instance.
* @port the hub port.
* @feature feature to be set.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_set_port_feature(uhub_t hub, rt_uint16_t port,
rt_uint16_t feature)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
LOG_D("%s %d\n",__FUNCTION__,__LINE__);
/* clear roothub feature */
if(hub->is_roothub)
{
root_hub_ctrl(hub->hcd, port, RH_SET_PORT_FEATURE,
(void*)(rt_uint32_t)feature);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_OTHER;
setup.bRequest = USB_REQ_SET_FEATURE;
setup.wIndex = port;
setup.wLength = 0;
setup.wValue = feature;
if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(hub->hcd, hub->self->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
return -RT_ERROR;
}
/**
* This function will rest hub port, it is invoked when sub device attached to the hub port.
*
* @param intf the interface instance.
* @param port the hub port.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_reset_port(uhub_t hub, rt_uint16_t port)
{
rt_err_t ret;
rt_uint32_t pstatus;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
LOG_D("%s %d\n",__FUNCTION__,__LINE__);
// rt_thread_delay(50);
/* reset hub port */
ret = rt_usbh_hub_set_port_feature(hub, port, PORT_FEAT_RESET);
if(ret != RT_EOK) return ret;
while(1)
{
ret = rt_usbh_hub_get_port_status(hub, port, &pstatus);
if(!(pstatus & PORT_PRS)) break;
}
/* clear port reset feature */
ret = rt_usbh_hub_clear_port_feature(hub, port, PORT_FEAT_C_RESET);
if(ret != RT_EOK) return ret;
// rt_thread_delay(50);
return RT_EOK;
}
/**
* This function will do debouce, it is invoked when sub device attached to the hub port.
*
* @param device the usb instance.
* @param port the hub port.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_port_debounce(uhub_t hub, rt_uint16_t port)
{
rt_err_t ret;
int i = 0, times = 20;
rt_uint32_t pstatus;
rt_bool_t connect = RT_TRUE;
int delayticks = USB_DEBOUNCE_TIME;
if (delayticks < 1)
delayticks = 1;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
LOG_D("%s %d\n",__FUNCTION__,__LINE__);
for(i=0; i<times; i++)
{
ret = rt_usbh_hub_get_port_status(hub, port, &pstatus);
if(ret != RT_EOK) return ret;
if(!(pstatus & PORT_CCS))
{
connect = RT_FALSE;
break;
}
if((pstatus & PORT_CCS))
{
break;
}
rt_thread_delay(delayticks);
}
LOG_D("%s %d pstatus:%X\n",__FUNCTION__,__LINE__,pstatus);
if(connect) return RT_EOK;
else return -RT_ERROR;
}
/**
* This function will poll all the hub ports to detect port status, especially connect and
* disconnect events.
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hub_port_change(uhub_t hub)
{
int i;
rt_bool_t reconnect;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
LOG_D("%s %d\n",__FUNCTION__,__LINE__);
if(!hub->is_roothub){
rt_usbh_hub_alloc_ep0_pipe(hub);
}
/* get usb device instance */
for (i = 0; i < hub->num_ports; i++)
{
rt_err_t ret;
struct uinstance* device;
rt_uint32_t pstatus = 0;
reconnect = RT_FALSE;
/* get hub port status */
ret = rt_usbh_hub_get_port_status(hub, i + 1, &pstatus);
if(ret != RT_EOK) continue;
LOG_D("port %d status 0x%x", i + 1, pstatus);
/* check port status change */
if (pstatus & PORT_CCSC)
{
/* clear port status change feature */
rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_CONNECTION);
rt_usbh_hub_get_port_status(hub, i + 1, &pstatus);
reconnect = RT_TRUE;
}
if(pstatus & PORT_PESC)
{
rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_ENABLE);
reconnect = RT_TRUE;
}
if(reconnect)
{
if(hub->child[i] != RT_NULL && hub->child[i]->status != DEV_STATUS_IDLE)
{
rt_usbh_detach_instance(hub->child[i]);
/* Child device have been detach. Set hub->child[i] to NULL. */
hub->child[i] = RT_NULL;
}
ret = rt_usbh_hub_port_debounce(hub, i + 1);
if(ret != RT_EOK) continue;
/* allocate an usb instance for new connected device */
device = rt_usbh_alloc_instance(hub->hcd);
if(device == RT_NULL) break;
/* reset usb roothub port */
rt_usbh_hub_reset_port(hub, i + 1);
ret = rt_usbh_hub_get_port_status(hub, i + 1, &pstatus);
if(ret != RT_EOK) continue;
ret = rt_usbh_hub_get_port_status(hub, i + 1, &pstatus);
if(ret != RT_EOK) continue;
os_printf("pstatus:%x\n",pstatus);
/* set usb device speed */
if (pstatus & PORT_HSDA) {
device->speed = RTTUSB_DEV_HighSpeed;
} else if (pstatus & PORT_LSDA) {
device->speed = RTTUSB_DEV_LowSpeed;
} else {
device->speed = RTTUSB_DEV_FullSpeed;
}
device->parent_hub = hub;
device->hcd = hub->hcd;
device->port = i + 1;
hub->child[i] = device;
os_printf("hub device speed:%x device port:%x\n",device->speed,device->port);
if (!hub->is_roothub)
{
struct uhub_param hub_param;
hub_param.hub_addr = 1;
hub_param.hub_mtt_en = 0;
hub_param.dev_addr = 0;
hub_param.dev_port = device->port;
hub_param.dev_speed = device->speed;
rt_usb_hcd_hub_port_set(hub->hcd, &hub_param);
}
/* attatch the usb instance to the hcd */
rt_usbh_attatch_instance(device);
}
}
os_printf("%s %d return!\n",__FUNCTION__,__LINE__);
return RT_EOK;
}
//hub下行端点暂不支持热插拔
void usbh_hub_thread_entry(void *arg)
{
upipe_t pipe;
uhub_t hub;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(arg != RT_NULL);
pipe = (upipe_t)arg;
hub = (uhub_t)pipe->user_data;
while(1)
{
rt_sem_take(hub_sem, RT_WAITING_FOREVER);
LOG_D("hub int xfer...");
/* parameter check */
RT_ASSERT(pipe->inst->hcd != RT_NULL);
rt_usb_hcd_pipe_xfer(hub->self->hcd, pipe, hub->buffer, pipe->ep.wMaxPacketSize, timeout);
}
}
/**
* This function is the callback function of hub's int endpoint, it is invoked when data comes.
*
* @param context the context of the callback function.
*
* @return none.
*/
static void rt_usbh_hub_irq(void* context)
{
upipe_t pipe;
uhub_t hub;
struct uhost_msg msg;
RT_ASSERT(context != RT_NULL);
pipe = (upipe_t)context;
hub = (uhub_t)pipe->user_data;
if(pipe->status != UPIPE_STATUS_OK)
{
LOG_D("hub irq error");
rt_sem_release(hub_sem);
return;
}
os_printf("%s %d\n",__FUNCTION__,__LINE__);
msg.type = USB_MSG_CONNECT_CHANGE;
msg.content.hub = hub;
rt_usbh_event_signal(pipe->inst->hcd, &msg);
}
/**
* This function will run usb hub class driver when usb hub is detected and identified
* as a hub class device, it will continue to do the enumulate process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hub_enable(void *arg)
{
int i = 0;
rt_err_t ret = RT_EOK;
uep_desc_t ep_desc = RT_NULL;
uhub_t hub;
upipe_t pipe;
struct uinstance* device;
struct uhintf* intf = (struct uhintf*)arg;
upipe_t pipe_in = RT_NULL;
int timeout = USB_TIMEOUT_BASIC;
/* paremeter check */
RT_ASSERT(intf != RT_NULL);
/* get usb device instance */
device = intf->device;
LOG_D("=======%s %d=======\n",__FUNCTION__,__LINE__);
/* create a hub instance */
hub = rt_malloc(sizeof(struct uhub));
RT_ASSERT(hub != RT_NULL);
rt_memset(hub, 0, sizeof(struct uhub));
/* make interface instance's user data point to hub instance */
intf->user_data = (void*)hub;
/* get hub descriptor head */
ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, 8);
if(ret != RT_EOK)
{
rt_kprintf("get hub descriptor failed\n");
return -RT_ERROR;
}
/* get full hub descriptor */
ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc,
hub->hub_desc.length);
if(ret != RT_EOK)
{
rt_kprintf("get hub descriptor again failed\n");
return -RT_ERROR;
}
/* get hub ports number */
/* If hub device supported ports over USB_HUB_PORT_NUM(Ex: 8 port hub). Set hub->num_ports to USB_HUB_PORT_NUM */
if(hub->hub_desc.num_ports > USB_HUB_PORT_NUM)
hub->num_ports = USB_HUB_PORT_NUM;
else
hub->num_ports = hub->hub_desc.num_ports;
hub->hcd = device->hcd;
hub->self = device;
/* reset all hub ports */
for (i = 0; i < hub->num_ports; i++)
{
rt_usbh_hub_set_port_feature(hub, i + 1, PORT_FEAT_POWER);
rt_thread_delay(hub->hub_desc.pwron_to_good
* 2 * RT_TICK_PER_SECOND / 1000 );
}
if(intf->intf_desc->bNumEndpoints != 1)
return -RT_ERROR;
/* get endpoint descriptor from interface descriptor */
rt_usbh_get_endpoint_descriptor(intf->intf_desc, 0, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
/* the endpoint type of hub class should be interrupt */
if( USB_EP_ATTR(ep_desc->bmAttributes) == USB_EP_ATTR_INT)
{
/* the endpoint direction of hub class should be in */
if(ep_desc->bEndpointAddress & USB_DIR_IN)
{
analysis_usb_ep_desc(ep_desc);
if (rt_usb_hcd_alloc_pipe(device->hcd, &pipe, device, ep_desc) != RT_EOK) {
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(device, pipe);
/* allocate a pipe according to the endpoint type */
pipe_in = rt_usb_instance_find_pipe(device,ep_desc->bEndpointAddress);
if(pipe_in == RT_NULL)
{
return -RT_ERROR;
}
rt_usb_pipe_add_callback(pipe_in,rt_usbh_hub_irq);
}
else return -RT_ERROR;
}
/* parameter check */
RT_ASSERT(device->hcd != RT_NULL);
pipe_in->user_data = hub;
hub_sem = rt_sem_create("hub_sem", 0, RT_IPC_FLAG_FIFO);
if (hub_sem == RT_NULL) {
os_printf("hub sem create err!!!\n");
return -RT_ERROR;
}
usbh_hub_thread = rt_thread_create("usbh_hub_thread",
usbh_hub_thread_entry,
pipe_in,
1024,
OS_TASK_PRIORITY_BELOW_NORMAL,
20);
if(usbh_hub_thread != RT_NULL)
rt_thread_startup(usbh_hub_thread);
rt_usb_hcd_pipe_xfer(hub->hcd, pipe_in, hub->buffer,
pipe_in->ep.wMaxPacketSize, timeout);
return RT_EOK;
}
/**
* This function will be invoked when usb hub plug out is detected and it would clean
* and release all hub class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hub_disable(void* arg)
{
int i;
uhub_t hub;
struct uhintf* intf = (struct uhintf*)arg;
/* paremeter check */
RT_ASSERT(intf != RT_NULL);
LOG_D("rt_usbh_hub_stop");
hub = (uhub_t)intf->user_data;
for(i=0; i<hub->num_ports; i++)
{
if(hub->child[i] != RT_NULL)
rt_usbh_detach_instance(hub->child[i]);
}
rt_thread_delete(usbh_hub_thread);
usbh_hub_thread = RT_NULL;
rt_sem_delete(hub_sem);
hub_sem = RT_NULL;
if(hub != RT_NULL) rt_free(hub);
return RT_EOK;
}
/**
* This function will register hub class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usbh_class_driver_hub(void)
{
hub_driver.class_code = USB_CLASS_HUB;
hub_driver.enable = rt_usbh_hub_enable;
hub_driver.disable = rt_usbh_hub_disable;
return &hub_driver;
}
/**
* This function is the main entry of usb hub thread, it is in charge of
* processing all messages received from the usb message buffer.
*
* @param parameter the parameter of the usb host thread.
*
* @return none.
*/
static void rt_usbh_hub_thread_entry(void* parameter)
{
uhcd_t hcd = (uhcd_t)parameter;
while(1)
{
struct uhost_msg msg;
/* receive message */
if (rt_mq_recv(hcd->usb_mq, &msg, sizeof(struct uhost_msg), RT_WAITING_FOREVER) < 0)
continue;
//USB CONNECT 同步状态设置
if (msg.type == USB_MSG_CONNECT_IRQ) {
uhub_t hub = msg.content.hub;
rt_bool_t isHS = RT_TRUE;
rt_uint8_t port = 1;
hub->port_status[port - 1] |= PORT_CCS | PORT_CCSC;
if(isHS)
{
hub->port_status[port - 1] &= ~PORT_LSDA;
}
else
{
hub->port_status[port - 1] |= PORT_LSDA;
}
}
//USB DISCONNECT 同步状态设置
if (msg.type == USB_MSG_DISCONNECT_IRQ) {
uhub_t hub = msg.content.hub;
rt_uint8_t port = 1;
hub->port_status[port - 1] |= PORT_CCSC;
hub->port_status[port - 1] &= ~PORT_CCS;
}
switch (msg.type)
{
case USB_MSG_CONNECT_IRQ:
case USB_MSG_DISCONNECT_IRQ:
case USB_MSG_CONNECT_CHANGE:
rt_usbh_hub_port_change(msg.content.hub);
if(!msg.content.hub->is_roothub)
{
rt_sem_release(hub_sem);
}
break;
case USB_MSG_CALLBACK:
/* invoke callback */
msg.content.cb.function(msg.content.cb.context);
break;
case USB_MSG_DELETE_THREAD:
goto __exit_end;
break;
default:
break;
}
}
__exit_end:
hcd->thread_status = 0;
/* 挂起线程等待删除 */
rt_thread_suspend(hcd->thread);
}
/**
* This function will post an message to the usb message queue,
*
* @param msg the message to be posted
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_event_signal(uhcd_t hcd, struct uhost_msg* msg)
{
RT_ASSERT(msg != RT_NULL);
/* send message to usb message queue */
rt_mq_send(hcd->usb_mq, (void*)msg, sizeof(struct uhost_msg));
return RT_EOK;
}
/**
* This function will initialize usb hub thread.
*
* @return none.
*
*/
void rt_usbh_hub_init(uhcd_t hcd, const char* dev)
{
rt_thread_t thread;
/* create root hub for hcd */
hcd->roothub = rt_malloc(sizeof(struct uhub));
if(hcd->roothub == RT_NULL)
{
LOG_E("hcd->roothub: allocate buffer failed.");
return;
}
rt_memset(hcd->roothub, 0, sizeof(struct uhub));
hcd->roothub->is_roothub = RT_TRUE;
hcd->roothub->hcd = hcd;
hcd->roothub->num_ports = hcd->num_ports;
/* create usb message queue */
if(hcd->usb_mq == RT_NULL)
{
hcd->usb_mq = rt_mq_create(NULL, 32, 16, RT_IPC_FLAG_FIFO);
}
if(hcd->thread == RT_NULL)
{
/* create usb hub thread */
thread = rt_thread_create((const char *)dev, rt_usbh_hub_thread_entry, hcd,
USB_THREAD_STACK_SIZE, OS_TASK_PRIORITY_ABOVE_NORMAL, 20); //OS_TASK_PRIORITY_BELOW_NORMAL
if(thread != RT_NULL)
{
/* startup usb host thread */
rt_thread_startup(thread);
}else{
os_printf("hub thread start fail\n");
}
hcd->thread = thread;
hcd->thread_status = 1;
}
}
void rt_usbh_hub_deinit(uhcd_t hcd)
{
struct uhost_msg msg;
rt_uint32_t timeout = 100;
if(hcd->thread != RT_NULL)
{
msg.type = USB_MSG_DELETE_THREAD;
msg.content.hub = hcd->roothub;
rt_usbh_event_signal(hcd, &msg);
do {
os_sleep_ms(10);
timeout--;
if (timeout == 0) {
os_printf("usbh wait hcd thread timeout!!!\n");
break;
}
} while (hcd->thread_status);
rt_thread_delete(hcd->thread);
if(hcd->usb_mq)
{
rt_mq_delete(hcd->usb_mq);
hcd->usb_mq = NULL;
}
if(hcd->roothub)
{
rt_free(hcd->roothub);
hcd->roothub = NULL;
}
hcd->thread = NULL;
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
* 2021-02-23 Leslie Lee provide possibility for multi usb host
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
#define USB_HOST_CONTROLLER_NAME "usbh"
#if defined(RT_USBH_HID_KEYBOARD) || defined(RT_USBH_HID_MOUSE)
#include <hid.h>
#endif
/**
* This function will initialize the usb host stack, all the usb class driver and
* host controller driver are also be initialized here.
*
* @return none.
*/
rt_err_t rt_usb_host_init(uint32 devid, const char *dev)
{
ucd_t drv;
uhcd_t uhc;
uhc = (uhcd_t)dev_get(devid);
if(uhc == RT_NULL)
{
rt_kprintf("can't find usb host controller\n");
return -RT_ERROR;
}
/* initialize usb hub */
uhc->devid = devid;
rt_usbh_hub_init((uhcd_t)uhc, dev);
/* initialize class driver */
rt_usbh_class_driver_init();
#ifdef RT_USBH_MSTORAGE
/* register mass storage class driver */
drv = rt_usbh_class_driver_storage();
rt_usbh_class_driver_register(drv);
#endif
#ifdef RT_USBH_HID
extern ucd_t rt_usbh_class_driver_hid(void);
/* register mass storage class driver */
drv = rt_usbh_class_driver_hid();
rt_usbh_class_driver_register(drv);
#ifdef RT_USBH_HID_MOUSE
{
extern uprotocal_t rt_usbh_hid_protocal_mouse(void);
rt_usbh_hid_protocal_register(rt_usbh_hid_protocal_mouse());
}
#endif
#ifdef RT_USBH_HID_KEYBOARD
{
extern uprotocal_t rt_usbh_hid_protocal_kbd(void);
rt_usbh_hid_protocal_register(rt_usbh_hid_protocal_kbd());
}
#endif
#endif
#ifdef RT_USBH_CDC
extern ucd_t rt_usbh_class_driver_cdc(void);
drv = rt_usbh_class_driver_cdc();
rt_usbh_class_driver_register(drv);
#endif
#ifdef RT_USBH_UVC
extern ucd_t rt_usbh_class_driver_video(void);
drv = rt_usbh_class_driver_video();
rt_usbh_class_driver_register(drv);
#endif
#ifdef RT_USBH_UAC
extern ucd_t rt_usbh_class_driver_audio(void);
drv = rt_usbh_class_driver_audio();
rt_usbh_class_driver_register(drv);
#endif
#ifdef RT_USBH_WIRELESS
extern ucd_t rt_usbh_class_driver_wireless(void);
drv = rt_usbh_class_driver_wireless();
rt_usbh_class_driver_register(drv);
#endif
#ifdef RT_USBH_VENDOR_QUECTEL
extern ucd_t rt_usbh_class_driver_quectel(void);
drv = rt_usbh_class_driver_quectel();
rt_usbh_class_driver_register(drv);
#endif
#ifdef RT_USBH_VENDOR_CHINAMOBILE
extern ucd_t rt_usbh_class_driver_chinamobile(void);
drv = rt_usbh_class_driver_chinamobile();
rt_usbh_class_driver_register(drv);
#endif
/* register hub class driver */
drv = rt_usbh_class_driver_hub();
rt_usbh_class_driver_register(drv);
/* initialize usb host controller */
rt_device_init(uhc);
return RT_EOK;
}
rt_err_t rt_usb_host_deinit(uint32 devid)
{
uhcd_t uhc;
uhc = (uhcd_t)dev_get(devid);
if(uhc == RT_NULL)
{
rt_kprintf("can't find usb host controller\n");
return -RT_ERROR;
}
rt_usbh_hub_deinit((uhcd_t)uhc);
return RT_EOK;
}

View File

@@ -0,0 +1,878 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <include/rttusb_host.h>
//#define DBG_TAG "usbhost.core"
//#define DBG_LVL DBG_INFO
//#include <rtdbg.h>
static struct uinstance dev[USB_MAX_DEVICE];
/**
* This function will allocate an usb device instance from system.
*
* @param parent the hub instance to which the new allocated device attached.
* @param port the hub port.
*
* @return the allocate instance on successful, or RT_NULL on failure.
*/
uinst_t rt_usbh_alloc_instance(uhcd_t uhcd)
{
int i;
/* lock scheduler */
rt_enter_critical();
for(i=0; i<USB_MAX_DEVICE; i++)
{
/* to find an idle instance handle */
if(dev[i].status != DEV_STATUS_IDLE) continue;
/* initialize the usb device instance */
rt_memset(&dev[i], 0, sizeof(struct uinstance));
dev[i].status = DEV_STATUS_BUSY;
dev[i].index = i + 1;
dev[i].address = 0;
dev[i].max_packet_size = 0x8;
rt_list_init(&dev[i].pipe);
dev[i].hcd = uhcd;
/* unlock scheduler */
rt_exit_critical();
return &dev[i];
}
/* unlock scheduler */
rt_exit_critical();
return RT_NULL;
}
/**
* This function will attatch an usb device instance to a host controller,
* and do device enumunation process.
*
* @param hcd the host controller driver.
* @param device the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
static struct uendpoint_descriptor ep0_out_desc =
{
/*endpoint descriptor*/
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
0x00 | USB_DIR_OUT,
USB_EP_ATTR_CONTROL,
0x00,
0x00,
};
static struct uendpoint_descriptor ep0_in_desc =
{
/*endpoint descriptor*/
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
0x00 | USB_DIR_IN,
USB_EP_ATTR_CONTROL,
0x00,
0x00,
};
void analysis_usb_dev_desc(udev_desc_t desc, uint32 desclen)
{
udev_desc_t dev_desc = (udev_desc_t)desc;
os_printf("=================device desc=================\r\n");
printf("bLength:%#x\n",dev_desc->bLength);
printf("type:%#x\n",dev_desc->type);
printf("bcdUSB:%#x\n",dev_desc->bcdUSB);
printf("bDeviceClass:%#x\n",dev_desc->bDeviceClass);
printf("bDeviceSubClass:%#x\n",dev_desc->bDeviceSubClass);
printf("bDeviceProtocol:%#x\n",dev_desc->bDeviceProtocol);
printf("bMaxPacketSize0:%#x\n",dev_desc->bMaxPacketSize0);
printf("idVendor:%#x\n",dev_desc->idVendor);
printf("idProduct:%#x\n",dev_desc->idProduct);
printf("bcdDevice:%#x\n",dev_desc->bcdDevice);
printf("iManufacturer:%#x\n",dev_desc->iManufacturer);
printf("iProduct:%#x\n",dev_desc->iProduct);
printf("iSerialNumber:%#x\n",dev_desc->iSerialNumber);
printf("bNumConfigurations:%#x\n",dev_desc->bNumConfigurations);
}
void analysis_usb_cfg_desc(ucfg_desc_t desc, uint32 desclen)
{
ucfg_desc_t cfg_desc = (ucfg_desc_t)desc;
os_printf("=================config desc=================\r\n");
printf("bLength:%#x\n",cfg_desc->bLength);
printf("bDescriptorType:%#x\n",cfg_desc->type);
printf("wTotalLength:%#x\n",cfg_desc->wTotalLength);
printf("bNumInterfaces:%#x\n",cfg_desc->bNumInterfaces);
printf("bConfigurationValue:%#x\n",cfg_desc->bConfigurationValue);
printf("iConfiguration:%#x\n",cfg_desc->iConfiguration);
printf("bmAttributes:%#x\n",cfg_desc->bmAttributes);
printf("bMaxPower:%#x\n",cfg_desc->MaxPower);
}
void analysis_usb_intf_desc(uintf_desc_t desc, uint32 desclen)
{
uintf_desc_t intf_desc = (uintf_desc_t)desc;
os_printf("=================intf desc=================\r\n");
printf("bLength:%#x\n",intf_desc->bLength);
printf("bDescriptorType:%#x\n",intf_desc->type);
printf("bInterfaceNumber:%#x\n",intf_desc->bInterfaceNumber);
printf("bAlternateSetting:%d\n",intf_desc->bAlternateSetting);
printf("bNumEndpoints:%d\n",intf_desc->bNumEndpoints);
printf("bInterfaceClass:%#x\n",intf_desc->bInterfaceClass);
printf("bInterfaceSubClass:%#x\n",intf_desc->bInterfaceSubClass);
printf("bInterfaceProtocol:%d\n",intf_desc->bInterfaceProtocol);
printf("iInterface:%#x\n",intf_desc->iInterface);
}
void analysis_usb_ep_desc(uep_desc_t ep_desc)
{
os_printf("=================ep desc=================\r\n");
printf("bLength:%#x\n",ep_desc->bLength);
printf("type:%#x\n",ep_desc->type);
printf("bEndpointAddress:%#x\n",ep_desc->bEndpointAddress);
printf("bmAttributes:%#x\n",ep_desc->bmAttributes);
printf("wMaxPacketSize:%#x\n",ep_desc->wMaxPacketSize);
printf("bInterval:%#x\n",ep_desc->bInterval);
}
void analysis_usb_iad_desc(uiad_desc_t iad_desc)
{
os_printf("=================iad desc=================\r\n");
printf("bLength:%#x\n",iad_desc->bLength);
printf("bDescriptorType:%#x\n",iad_desc->bDescriptorType);
printf("bFirstInterface:%#x\n",iad_desc->bFirstInterface);
printf("bInterfaceCount:%#x\n",iad_desc->bInterfaceCount);
printf("bFunctionClass:%#x\n",iad_desc->bFunctionClass);
printf("bFunctionSubClass:%#x\n",iad_desc->bFunctionSubClass);
printf("bFunctionProtocol:%#x\n",iad_desc->bFunctionProtocol);
printf("iFunction:%#x\n",iad_desc->iFunction);
}
rt_err_t rt_usbh_hub_alloc_ep0_pipe(uhub_t hub)
{
if (!hub->is_roothub) {
struct uinstance* device = hub->self;
rt_usb_hub_ep0_open_pipe(device->hcd, &ep0_out_desc);
rt_usb_hub_ep0_open_pipe(device->hcd, &ep0_in_desc);
}
return RT_EOK;
}
rt_err_t rt_usbh_attatch_instance(uinst_t device)
{
int i = 0;
rt_err_t ret = RT_EOK;
rt_uint8_t cfg_desc_buff[18];
udev_desc_t dev_desc;
uintf_desc_t intf_desc = RT_NULL;
uiad_desc_t iad_desc;
ucfg_desc_t cfg_desc;
// uep_desc_t ep_desc;
// rt_uint8_t ep_index;
rt_uint8_t iad_index;
// upipe_t pipe;
ucd_t drv;
RT_ASSERT(device != RT_NULL);
rt_memset(cfg_desc_buff, 0, sizeof(cfg_desc_buff));
cfg_desc = (ucfg_desc_t)cfg_desc_buff;
dev_desc = &device->dev_desc;
device->cfg_desc = RT_NULL;
/* alloc address 0 ep0 pipe*/
ep0_out_desc.wMaxPacketSize = 8;
ep0_in_desc.wMaxPacketSize = 8;
rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc);
rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc);
LOG_D("start enumnation");
/* get device descriptor head */
ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8);
if(ret != RT_EOK)
{
rt_kprintf("get device descriptor head failed\n");
return ret;
}
analysis_usb_dev_desc(dev_desc, 8);//第一次获取设备描述符 打印设备描述符信息
/* reset bus */
rt_usbh_hub_reset_port(device->parent_hub, device->port);
rt_thread_delay(2);
rt_usbh_hub_clear_port_feature(device->parent_hub, device->port, PORT_FEAT_C_CONNECTION);
/* set device address */
ret = rt_usbh_set_address(device);
if(ret != RT_EOK)
{
rt_kprintf("set device address failed\n");
return ret;
}
/* free address 0 ep0 pipe*/
rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out);
rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in);
/* set device max packet size */
ep0_out_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0;
ep0_in_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0;
/* alloc true address ep0 pipe*/
rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc);
rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc);
LOG_D("get device descriptor length %d",
dev_desc->bLength);
/* get full device descriptor again */
ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength);
if(ret != RT_EOK)
{
rt_kprintf("get full device descriptor failed\n");
return ret;
}
analysis_usb_dev_desc(dev_desc, dev_desc->bLength); //第二次获取设备描述符 打印设备描述符信息
LOG_D("Vendor ID 0x%x", dev_desc->idVendor);
LOG_D("Product ID 0x%x", dev_desc->idProduct);
/* get configuration descriptor head */
ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, cfg_desc, 18);
if(ret != RT_EOK)
{
rt_kprintf("get configuration descriptor head failed\n");
return ret;
}
analysis_usb_cfg_desc(cfg_desc, 18); //第一次获取配置描述符 打印配置描述符信息
/* alloc memory for configuration descriptor */
device->cfg_desc = (ucfg_desc_t)rt_zalloc(cfg_desc->wTotalLength);
if(device->cfg_desc == RT_NULL)
{
return -RT_ENOMEM;
}
rt_memset(device->cfg_desc, 0, cfg_desc->wTotalLength);
/* get full configuration descriptor */
ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION,
device->cfg_desc, cfg_desc->wTotalLength);
if(ret != RT_EOK)
{
rt_kprintf("get full configuration descriptor failed\n");
return ret;
}
analysis_usb_cfg_desc(device->cfg_desc, device->cfg_desc->wTotalLength); //第二次获取配置描述符 打印配置描述符信息
/* set configuration */
ret = rt_usbh_set_configure(device, 1);
if(ret != RT_EOK)
{
return ret;
}
for(i=0; i<device->cfg_desc->bNumInterfaces; i++)
{
/* check IAD */
rt_usbh_get_interface_associtaion_descriptor(device->cfg_desc, i, &iad_desc);
if (iad_desc != RT_NULL)
{
analysis_usb_iad_desc(iad_desc);
for (iad_index = iad_desc->bFirstInterface;
iad_index < iad_desc->bFirstInterface + iad_desc->bInterfaceCount;
++iad_index)
{
rt_usbh_get_interface_descriptor(device->cfg_desc, iad_index, &intf_desc);
if (intf_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_interface_descriptor error\n");
return -RT_ERROR;
}
analysis_usb_intf_desc(intf_desc, 0);//获取接口描述符,打印接口描述符信息
LOG_D("interface class 0x%x, subclass 0x%x",
intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass);
#if 0 // 因为我们的USB端口不够用不能每个EP都分配改到driver里面分配
/* alloc pipe*/
for (ep_index = 0; ep_index < intf_desc->bNumEndpoints; ++ep_index)
{
rt_usbh_get_endpoint_descriptor(intf_desc, ep_index, &ep_desc);
if(ep_desc != RT_NULL)
{
if(rt_usb_hcd_alloc_pipe(device->hcd, &pipe, device, ep_desc) != RT_EOK)
{
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(device,pipe);
}
else
{
rt_kprintf("get endpoint desc failed\n");
return -RT_ERROR;
}
}
#endif
device->intf[iad_index] = (struct uhintf *)rt_malloc(sizeof(struct uhintf));
LOG_D("rt malloc intf[%d]\n",iad_index);
if(device->intf[iad_index] == RT_NULL)
{
return -RT_ENOMEM;
}
device->intf[iad_index]->drv = RT_NULL;
device->intf[iad_index]->device = device;
device->intf[iad_index]->intf_desc = intf_desc;
device->intf[iad_index]->user_data = RT_NULL;
}
i += iad_desc->bInterfaceCount - 1; // 前面for循环还会+1补回去
// 通过接口关联class查找对应驱动
drv = rt_usbh_class_driver_find(iad_desc->bFunctionClass,
iad_desc->bFunctionSubClass, dev_desc->idVendor);
if (drv != RT_NULL)
{
// 给接口关联的第一个接口添加驱动,后续就能通过怎么样找到?
device->intf[iad_desc->bFirstInterface]->drv = drv;
// 复合设备传递参数是指针的指针
ret = rt_usbh_class_driver_enable(drv, (void *)&device->intf[iad_desc->bFirstInterface]);
if(ret != RT_EOK)
{
rt_kprintf("interface %d run class driver error\n", i);
}
}
else
{
rt_kprintf("find usb device driver failed\n");
continue;
}
}
else
{
/* get interface descriptor through configuration descriptor */
ret = rt_usbh_get_interface_descriptor(device->cfg_desc, i, &intf_desc);
if(ret != RT_EOK)
{
rt_kprintf("rt_usb_get_interface_descriptor error\n");
return -RT_ERROR;
}
analysis_usb_intf_desc(intf_desc, 0);//获取接口描述符,打印接口描述符信息
LOG_D("interface class 0x%x, subclass 0x%x",
intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass);
#if 0 // 因为我们的USB端口不够用不能每个EP都分配改到driver里面分配
/* alloc pipe*/
for(ep_index = 0; ep_index < intf_desc->bNumEndpoints; ep_index++)
{
rt_usbh_get_endpoint_descriptor(intf_desc, ep_index, &ep_desc);
if(ep_desc != RT_NULL)
{
if(rt_usb_hcd_alloc_pipe(device->hcd, &pipe, device, ep_desc) != RT_EOK)
{
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(device,pipe);
}
else
{
rt_kprintf("get endpoint desc failed\n");
return -RT_ERROR;
}
}
#endif
/* find driver by class code found in interface descriptor */
drv = rt_usbh_class_driver_find(intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass, dev_desc->idVendor);
if(drv != RT_NULL)
{
/* allocate memory for interface device */
device->intf[i] = (struct uhintf*)rt_malloc(sizeof(struct uhintf));
if(device->intf[i] == RT_NULL)
{
return -RT_ENOMEM;
}
device->intf[i]->drv = drv;
device->intf[i]->device = device;
device->intf[i]->intf_desc = intf_desc;
device->intf[i]->user_data = RT_NULL;
/* open usb class driver */
// 非复合设备传递参数是指针
ret = rt_usbh_class_driver_enable(drv, (void*)device->intf[i]);
if(ret != RT_EOK)
{
rt_kprintf("interface %d run class driver error\n", i);
}
}
else
{
rt_kprintf("find usb device driver failed\n");
continue;
}
}
}
return RT_EOK;
}
/**
* This function will detach an usb device instance from its host controller,
* and release all resource.
*
* @param device the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_detach_instance(uinst_t device)
{
int i = 0;
rt_list_t * l;
if(device == RT_NULL)
{
rt_kprintf("no usb instance to detach\n");
return -RT_ERROR;
}
/* free configration descriptor */
if (device->cfg_desc) {
for (i = 0; i < device->cfg_desc->bNumInterfaces; i++)
{
if (device->intf[i] == RT_NULL) continue;
if (device->intf[i]->drv == RT_NULL)
{
LOG_D("rt free intf[%d]\n",i);
rt_free(device->intf[i]);
continue;
}
RT_ASSERT(device->intf[i]->device == device);
LOG_D("free interface instance %d", i);
rt_usbh_class_driver_disable(device->intf[i]->drv, (void*)device->intf[i]);
rt_free(device->intf[i]);
LOG_D("rt free intf[%d]\n",i);
}
rt_free(device->cfg_desc);
}
rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out);
rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in);
while(device->pipe.next!= &device->pipe)
{
l = device->pipe.next;
rt_list_remove(l);
rt_usb_hcd_free_pipe(device->hcd,rt_list_entry(l,struct upipe,list));
}
rt_memset(device, 0, sizeof(struct uinstance));
return RT_EOK;
}
/**
* This function will do USB_REQ_GET_DESCRIPTO' bRequest for the usb device instance,
*
* @param device the usb device instance.
* @param type the type of descriptor bRequest.
* @param buffer the data buffer to save requested data
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_get_descriptor(uinst_t device, rt_uint8_t type, void* buffer,
int nbytes)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_GET_DESCRIPTOR;
setup.wIndex = 0;
setup.wLength = nbytes;
setup.wValue = type << 8;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
return -RT_ERROR;
}
/**
* This function will do USB_REQ_GET_DESCRIPTO' bRequest for the usb device instance,
*
* @param device the usb device instance.
* @param intf the interface number.
* @param buffer the data buffer to save requested data
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_get_string_descriptor(uinst_t device, int intf, void* buffer,
int nbytes)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_GET_DESCRIPTOR;
setup.wIndex = 0;
setup.wLength = nbytes;
setup.wValue = (USB_DESC_TYPE_STRING << 8) | intf;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) > 0)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
return -RT_ERROR;
}
/**
* This function will set an address to the usb device.
*
* @param device the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_set_address(uinst_t device)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(device != RT_NULL);
LOG_D("rt_usb_set_address");
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_SET_ADDRESS;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = device->index;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
device->address = device->index;
}
return RT_EOK;
}
/**
* This function will set a configuration to the usb device.
*
* @param device the usb device instance.
* @param config the configuration number.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_set_configure(uinst_t device, int config)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* check parameter */
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_SET_CONFIGURATION;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = config;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function will set an interface to the usb device.
*
* @param device the usb device instance.
* @param intf the interface number.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_set_interface(uinst_t device, int intf)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* check parameter */
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_INTERFACE;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = intf;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function will clear feature for the endpoint of the usb device.
*
* @param device the usb device instance.
* @param endpoint the endpoint number of the usb device.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_clear_feature(uinst_t device, int endpoint, int feature)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* check parameter */
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_ENDPOINT;
setup.bRequest = USB_REQ_CLEAR_FEATURE;
setup.wIndex = endpoint;
setup.wLength = 0;
setup.wValue = feature;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function will get an interface descriptor from the configuration descriptor.
*
* @param cfg_desc the point of configuration descriptor structure.
* @param num the number of interface descriptor.
* @intf_desc the point of interface descriptor point.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num,
uintf_desc_t* intf_desc)
{
rt_uint32_t ptr, depth = 0;
udesc_t desc;
/* check parameter */
RT_ASSERT(cfg_desc != RT_NULL);
ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength;
while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength)
{
if(depth++ > 0x40)
{
*intf_desc = RT_NULL;
return -RT_EIO;
}
desc = (udesc_t)ptr;
if(desc->type == USB_DESC_TYPE_INTERFACE)
{
if(((uintf_desc_t)desc)->bInterfaceNumber == num)
{
*intf_desc = (uintf_desc_t)desc;
LOG_D("rt_usb_get_interface_descriptor: %d", num);
return RT_EOK;
}
}
ptr = (rt_uint32_t)desc + desc->bLength;
}
rt_kprintf("rt_usb_get_interface_descriptor %d failed\n", num);
return -RT_EIO;
}
/**
* This function will get an interface associtaion descriptor from the configuration descriptor.
*
* @param cfg_desc the point of configuration descriptor structure.
* @param num the number of interface descriptor.
* @iad_desc the point of interface associtaion descriptor point.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_get_interface_associtaion_descriptor(ucfg_desc_t cfg_desc, int num,
uiad_desc_t* iad_desc)
{
rt_uint32_t ptr, depth = 0;
udesc_t desc;
rt_uint16_t last_len = 0;
/* check parameter */
RT_ASSERT(cfg_desc != RT_NULL);
ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength;
while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength)
{
if(depth++ > 0x40)
{
*iad_desc = RT_NULL;
return -RT_EIO;
}
desc = (udesc_t)ptr;
// 寻找接口描述符
if (desc->type == USB_DESC_TYPE_INTERFACE)
{
if (((uintf_desc_t)desc)->bInterfaceNumber == num)
{
// 找到目标接口描述后,检查上一个描述符是不是接口关联描述符
ptr -= last_len;
desc = (udesc_t)ptr;
if (desc->type == USB_DESC_TYPE_IAD)
{
*iad_desc = (uiad_desc_t)desc;
return RT_EOK;
}
else
{
*iad_desc = NULL;
return -RT_EIO;
}
}
}
// 解析下一个描述符
ptr = (rt_uint32_t)desc + desc->bLength;
last_len = desc->bLength;
}
// 无法解析
*iad_desc = NULL;
return -RT_EIO;
}
/**
* This function will get an endpoint descriptor from the interface descriptor.
*
* @param intf_desc the point of interface descriptor structure.
* @param num the number of endpoint descriptor.
* @param ep_desc the point of endpoint descriptor point.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num,
uep_desc_t* ep_desc)
{
int count = 0, depth = 0;
rt_uint32_t ptr;
udesc_t desc;
/* check parameter */
RT_ASSERT(intf_desc != RT_NULL);
RT_ASSERT(num < intf_desc->bNumEndpoints);
*ep_desc = RT_NULL;
ptr = (rt_uint32_t)intf_desc + intf_desc->bLength;
while(count < intf_desc->bNumEndpoints)
{
if(depth++ > 0x20)
{
*ep_desc = RT_NULL;
return -RT_EIO;
}
desc = (udesc_t)ptr;
if(desc->type == USB_DESC_TYPE_ENDPOINT)
{
if(num == count)
{
*ep_desc = (uep_desc_t)desc;
LOG_D("rt_usb_get_endpoint_descriptor: %d", num);
return RT_EOK;
}
else count++;
}
ptr = (rt_uint32_t)desc + desc->bLength;
}
rt_kprintf("rt_usb_get_endpoint_descriptor %d failed\n", num);
return -RT_EIO;
}
int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout)
{
int ret_size;
rt_uint8_t * pbuffer = (rt_uint8_t *)buffer;
LOG_D("pipe transform remain size: %d", nbytes);
ret_size = hcd->ops->pipe_xfer(pipe, USBH_PID_DATA, pbuffer, nbytes, timeout);
if(ret_size <= nbytes)
{
return ret_size;
}
else
{
return 0;
}
return nbytes;
}
int rt_usb_hcd_hub_port_set(uhcd_t hcd, uhub_param_t param)
{
int ret = RT_ERROR;
if (hcd->ops->hub_port_set) {
ret = hcd->ops->hub_port_set(param);
}
return ret;
}