Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
USB_HID
USB主机_host
解决usbhost 无法使用hid设备的问题,
发布于 2020-11-28 11:48:10 浏览:2457
订阅该版
[tocm] 由于我自己需要用到USBhost接口访问HID设备,所以掉进HID坑里了,官网的hid.c文件估 计有快10年没更新了,与现有代码存在不兼容和错误,然后把这些坑填了填,希望能帮助使 用HID时遇到问题的同学,能将host的hid用起来. HID设备使用标准的HID协议,用户需要关心的主要是下面这两个接口: ```c rt_err_t rt_usbh_hid_set_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_get_report(struct uhintf* intf, rt_uint8_t type, rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size); ``` rt_usbh_hid_set_report()接口用于向HID设备发送一条命令, rt_usbh_hid_get_report()接口用于从HID设备读取返回数据, 所以在应用中这两个函数应该配合使用,如果没有返回数据,则只需set_report接口. 发送指令的格式为: 1) 先发送控制字协议包;对应rt_usb_hcd_setup_xfer()接口; 2) 接着发送用户命令包;对应rt_usb_hcd_pipe_xfer()接口; 3) rt_usb_hcd_pipe_xfer()接口如果传入的是pipe_ep0_out,就是向设备写数据; rt_usb_hcd_pipe_xfer()接口如果传入的是pipe_ep0_in,就是从设备读数据; 总体来说rtthread的usb驱动架构,使用了线程异步处理,用户应用中数据流就类似于线性的,处理数据很方便;作为对比原子的usb驱动接口使用的状态机模式,在操作系统下,处理usb数据就很麻烦,反而非RTOS下处理起来更容易. 下面贴出hid源码,我们可以一起完善它 hid.c ```c /* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2011-12-12 Yi Qiu first version */ #include
#include
#include "hid.h" #ifdef RT_USBH_HID 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) == 0) return RT_EOK; else return -RT_ERROR; } /** * 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; //0xA1 setup.bRequest = USB_REQ_GET_REPORT; //0x01 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) { return -RT_ERROR; } if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) != size) { return -RT_ERROR; } return RT_EOK; } /** * 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 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_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; //0x21 setup.bRequest = USB_REQ_SET_REPORT; //0x09 setup.wValue = type << 8 || id; setup.wIndex = intf->intf_desc->bInterfaceNumber; setup.wLength = size; 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_out, buffer, size, timeout) != size) { return -RT_ERROR; } return RT_EOK; } /** * 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) == 0) return RT_EOK; else return -RT_ERROR; } /** * 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) == size) return RT_EOK; else return -RT_ERROR; } /** * 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*)pipe->user_data; rt_kprintf("%s()\n", __func__); /* This function is not used in HID protocal?! */ /* invoke protocal callback function */ hid->protocal->callback((void*)hid); /* parameter check */ RT_ASSERT(pipe->inst->hcd != RT_NULL); rt_usb_hcd_pipe_xfer(pipe->inst->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); rt_kprintf("protocal->pro_id=%d\n", protocal->pro_id); 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; int timeout = USB_TIMEOUT_BASIC; upipe_t pipe; /* parameter check */ if(intf == RT_NULL) { rt_kprintf("the interface is not available\n"); return -RT_EIO; } pro_id = intf->intf_desc->bInterfaceProtocol; RT_DEBUG_LOG(RT_DEBUG_USB, ("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_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; } 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; } /* initialize hid protocal */ hid->protocal->init((void*)intf); #if 0 pipe = hid->pipe_in; /* parameter check */ RT_ASSERT(pipe->inst->hcd != RT_NULL); rt_usb_hcd_pipe_xfer(pipe->inst->hcd, pipe, hid->buffer, pipe->ep.wMaxPacketSize, timeout); /* 这里直接读取一个报告?按照HID规范,读报告都要先设定报告指令,再读取,因为 一般HID设备都有多个报告, 所以这里直接读取的行为不合适.只有mouse类HID设备 才可能使用这种方式,驱动应该是适应多数设备的,所以这里屏蔽掉! */ #endif 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); RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_hid_disable\n")); 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); } /* free the instance */ rt_free(intf); 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 ``` ## hid.h ```c /* * Copyright (c) 2006-2018, 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
struct uhid { upipe_t pipe_in; rt_uint8_t buffer[8]; 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_TOUCH 0 #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 type, rt_uint8_t id, 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); ucd_t rt_usbh_class_driver_hid(void); #endif ``` 举例应用方法,我这里以读取USB触摸屏info为例: ```c static rt_uint8_t outbuf[64]; void ilitek_read_tp_info(struct uhintf* intf) { rt_uint8_t buf[64] = {0x03, 0xA3, 1, 5, 0x61}; //0x61 /* parameter2&3 varies from device to device!! */ if (rt_usbh_hid_set_report(intf, 0x02, 0x03, buf, 5) == RT_EOK) { rt_kprintf("set report 0x61 OK\n"); if (rt_usbh_hid_get_report(intf, 0x02, 0x03, outbuf, 9) == RT_EOK) { rt_kprintf("get report 0x61 OK\n"); /* In outbuf is the returned data from HID device */ /* 03 A3 61 05 11 25 0D 00 01 */ /* my touch chip is ili2511 */ } } } ``` 参考umouse.c实现touch的接口函数, ```c static rt_err_t rt_usbh_hid_touch_init(void* arg) { struct uhintf* intf = (struct uhintf*)arg; RT_ASSERT(intf != RT_NULL); rt_usbh_hid_set_protocal(intf, 0); /* 指定HID设备的协议, 协议号从接口描述符中获取 */ rt_usbh_hid_set_idle(intf, 10, 0); #ifdef RT_USING_RTGUI //EVENT_MOUSE_BUTTON_INIT(&etouch); /* etouch是我的触摸屏的数据接口,因设备而异 */ #endif ilitek_read_tp_info(intf); return RT_EOK; } /** * This function will define the hid touch protocal, it will be register to the protocal list. * * @return the touch protocal structure. */ uprotocal_t rt_usbh_hid_protocal_touch(void) { touch_protocal.pro_id = USB_HID_TOUCH; touch_protocal.init = rt_usbh_hid_touch_init; touch_protocal.callback = rt_usbh_hid_touch_callback; return &touch_protocal; } ``` 在usbhost.c中的rt_usb_host_init()接口中加入HID相关初始化 ```c rt_err_t rt_usb_host_init(void) { ucd_t drv; rt_device_t uhc; uprotocal_t protocal; uhc = rt_device_find(USB_HOST_CONTROLLER_NAME); if(uhc == RT_NULL) { rt_kprintf("can't find usb host controller %s\n", USB_HOST_CONTROLLER_NAME); return -RT_ERROR; } /* initialize usb hub */ rt_usbh_hub_init((uhcd_t)uhc); /* 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 /* register hub class driver */ drv = rt_usbh_class_driver_hub(); rt_usbh_class_driver_register(drv); drv = rt_usbh_class_driver_hid(); rt_usbh_class_driver_register(drv); #ifdef RT_USBH_HID_MOUSE protocal = rt_usbh_hid_protocal_mouse(); rt_usbh_hid_protocal_register(protocal); #endif #ifdef RT_USBH_HID_TOUCH protocal = rt_usbh_hid_protocal_touch(); rt_usbh_hid_protocal_register(protocal); #endif /* initialize usb host controller */ rt_device_init(uhc); return RT_EOK; } ```
查看更多
aozima
2020-11-28
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
感谢楼主分享
4
个回答
默认排序
按发布时间排序
iamyhw
2020-11-28
这家伙很懒,什么也没写!
有个接口函数 ```c /** * 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); ``` 没有搞懂应该在哪里调用它,我的理解是,在用户处理数据的线程中调用这样的一个接口,看注释该接口的设定是由中断调用的,但是中断处理部分已经由drv_usbh.c的drv_pipe_xfer()接口处理好了.所以这里很迷惑!
じ★ve萫彯彯
2020-12-28
这家伙很懒,什么也没写!
```c rt_err_t rt_usbh_hid_set_report(struct uintf* intf, rt_uint8_t *buffer, rt_size_t size) ``` 请问,为什么我这边的驱动是这个样子的,然后这边找不到uintf结构体
好的名字
2021-03-09
这家伙很懒,什么也没写!
想问一下楼主,初始化完成之后是怎么操作的,怎么进行连接设备,接收数据等操作。
撰写答案
登录
注册新账号
关注者
2
被浏览
2.5k
关于作者
iamyhw
这家伙很懒,什么也没写!
提问
6
回答
128
被采纳
6
关注TA
发私信
相关问题
1
RT thread HID 如何收发数据
2
rtthread winusb 修改 vid 与 pid 设备就不识别
3
rtthread USB HOST怎么与HID设备连接通讯
4
usb设备端HID问题
5
USB Host 鼠标键盘枚举无法获取HID设备描述符
6
USB作为HID设备怎么与PC交互?
7
USB Device HID 如何使用?
8
usb hid device超时接口
9
shell如何移植到HID接口?
10
USB HOST HID 里面用到的struct uintf在哪里定义的?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
进行i2c驱动移植的经验总结
2
在VSCode中使用clang-format
3
我该如何使用这个微雪的WIFI400 WIFI-LPB-100在rtt里或者我该怎样为它开发驱动
4
在GD32F470Z的RTC适配笔记
5
RT Thread 源码笔记 :内存池
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
289
次被采纳
张世争
808
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
catcatbing
3
篇文章
4
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部