重庆开发网站,2016网站建设总结,做一个网站app需要多少钱,品牌网站建设美丽文章目录 1、声明2、HID协议2.1、描述符2.2、鼠标数据格式 3、应用程序4、编译应用程序5、测试6、其它 1、声明
本文是在学习韦东山《驱动大全》USB子系统时#xff0c;为梳理知识点和自己回看而记录#xff0c;全部内容高度复制粘贴。
韦老师的《驱动大全》#xff1a;商… 文章目录 1、声明2、HID协议2.1、描述符2.2、鼠标数据格式 3、应用程序4、编译应用程序5、测试6、其它 1、声明
本文是在学习韦东山《驱动大全》USB子系统时为梳理知识点和自己回看而记录全部内容高度复制粘贴。
韦老师的《驱动大全》商品详情
其对应的讲义资料https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
libusb apihttps://libusb.sourceforge.io/api-1.0/libusb_api.html
2、HID协议
HIDHuman Interface Devices, 人类用来跟计算机交互的设备。就是鼠标、键盘、游戏手柄等设备。对于USB接口的HID设备有一套协议。
2.1、描述符
HID设备有如下描述符 HID设备的设备描述符并无实际意义没有使用设备描述符来表示自己是HID设备。HID设备只有一个配置所以只有一个配置描述符。接口描述符 bInterfaceClass为3表示它是HID设备。bInterfaceSubClass是0或11表示它支持Boot Interface(表示PC的BIOS能识别、使用它)0表示必须等操作系统启动后通过驱动程序来使用它。bInterfaceProtocol0-None, 1-键盘, 2-鼠标。 端点描述符HID设备有一个控制端点、一个中断端点。 对于鼠标HOST可以通过中断端点读到数据。
2.2、鼠标数据格式
通过中断传输可以读到鼠标数据它是8字节的数据格式如下
偏移大小描述01字节11字节按键状态22字节X位移42字节Y位移61字节或2字节滚轮
按键状态里每一位对应鼠标的一个按键等1时表示对应按键被点击了格式如下
位长度描述01鼠标的左键11鼠标的右键21鼠标的中间键35保留设备自己定义bit3: 鼠标的侧边按键bit4:
X位移、Y位移都是8位的有符号数。对于X位移负数表示鼠标向左移动正数表示鼠标向右移动移动的幅度就使用这个8位数据表示。对于Y位移负数表示鼠标向上移动正数表示鼠标向下移动移动的幅度就使用这个8位数据表示。
3、应用程序
本次应用程序使用的是同步接口读取鼠标数据。
#include errno.h
#include signal.h
#include stdio.h
#include stdlib.h
#include string.h#include libusb-1.0/libusb.hint main(int argc, char **argv)
{int err;libusb_device *dev, **devs;int num_devices;int endpoint;int interface_num;int transferred;int count 0;unsigned char buffer[8];struct libusb_config_descriptor *config_desc;struct libusb_device_handle *dev_handle NULL;int found 0;/* libusb init */err libusb_init(NULL);if (err 0) {fprintf(stderr, failed to initialise libusb %d - %s\n, err, libusb_strerror(err));exit(1);}/* get device list */if ((num_devices libusb_get_device_list(NULL, devs)) 0) // 获取设备描述符列表函数返回设备描述符数量{fprintf(stderr, libusb_get_device_list() failed\n);libusb_exit(NULL);exit(1);} fprintf(stdout, libusb_get_device_list() ok\n);/* for each device, get config descriptor */for (int i 0; i num_devices; i){dev devs[i];err libusb_get_config_descriptor(dev, 0, config_desc); // 获取配置描述符if (err) {fprintf(stderr, could not get configuration descriptor\n);continue;}fprintf(stdout, libusb_get_config_descriptor() ok\n);/* parse interface descriptor, find usb mouse */for (int interface 0; interface config_desc-bNumInterfaces; interface) // 枚举所有接口描述符{const struct libusb_interface_descriptor *intf_desc config_desc-interface[interface].altsetting[0]; // 获取配置描述符里的第一个接口描述符interface_num intf_desc-bInterfaceNumber; // 记录该接口描述符的编号编号是从0开始if (intf_desc-bInterfaceClass ! 3 || intf_desc-bInterfaceProtocol ! 2) // 判断是否是HID设备和是否是鼠标协议continue;/* 找到了USB鼠标 */fprintf(stdout, find usb mouse ok\n);for (int ep 0; ep intf_desc-bNumEndpoints; ep) // 枚举所有端点描述符{// 判断是否是中断传输是否是输入端点输入输出都是以USB Host来讨论所以该端点是USB Device输出到USB Hostif ((intf_desc-endpoint[ep].bmAttributes 3) LIBUSB_TRANSFER_TYPE_INTERRUPT || (intf_desc-endpoint[ep].bEndpointAddress 0x80) LIBUSB_ENDPOINT_IN){/* 找到了输入的中断端点 */fprintf(stdout, find in int endpoint\n);endpoint intf_desc-endpoint[ep].bEndpointAddress;found 1;break;}}if (found)break;}libusb_free_config_descriptor(config_desc);if (found)break; }if (!found){/* free device list */libusb_free_device_list(devs, 1);libusb_exit(NULL);exit(1);}/* libusb open */if (found){err libusb_open(dev, dev_handle);if (err){fprintf(stderr, failed to open usb mouse\n);exit(1);}fprintf(stdout, libusb_open ok\n);}/* free device list */libusb_free_device_list(devs, 1);/* claim interface */libusb_set_auto_detach_kernel_driver(dev_handle, 1); err libusb_claim_interface(dev_handle, interface_num);if (err){fprintf(stderr, failed to libusb_claim_interface\n);exit(1);}fprintf(stdout, libusb_claim_interface ok\n);/* libusb interrupt transfer */while (1){err libusb_interrupt_transfer(dev_handle, endpoint, buffer, 8, transferred, 5000); // 发起中断传输阻塞等待5s超时时间if (!err) {/* parser data */printf(%04d datas: , count);printf(recv datas len %d\n, transferred);for (int i 0; i transferred; i){printf(%02x , buffer[i]);}printf(\n);} else if (err LIBUSB_ERROR_TIMEOUT){fprintf(stderr, libusb_interrupt_transfer timout\n);} else {const char *errname libusb_error_name(err);fprintf(stderr, libusb_interrupt_transfer err : %d, %s\n, err, errname);//exit(1);}}/* libusb close */libusb_release_interface(dev_handle, interface_num);libusb_close(dev_handle);libusb_exit(NULL);
}4、编译应用程序
假设你的开发板是ubuntu系统
# 安装libusb库
$ sudo apt install libusb-1.0-0-dev# 编译程序
$ gcc -o readmouse readmouse.c -lusb-1.05、测试
将usb鼠标插入开发板 执行程序
$ sudo ./readmouse移动鼠标 滚轮滑动 按键状态 另外每个鼠标的数据格式是不一样的。以上测试结果只是我使用的鼠标。
6、其它
以下是使用异步接口读取鼠标数据的测试程序。
#include errno.h
#include signal.h
#include stdio.h
#include stdlib.h
#include string.h#include libusb-1.0/libusb.hstruct usb_mouse {struct libusb_device_handle *handle;int interface;int endpoint;unsigned char buf[16];int transferred;struct libusb_transfer *transfer;struct usb_mouse *next;
};static struct usb_mouse *usb_mouse_list;void free_usb_mouses(struct usb_mouse *usb_mouse_list)
{struct usb_mouse *pnext;while (usb_mouse_list){pnext usb_mouse_list-next;free(usb_mouse_list);usb_mouse_list pnext;}
}int get_usb_mouse(libusb_device **devs, int num_devices, struct usb_mouse **usb_mouse_list)
{int err;libusb_device *dev;int endpoint;int interface_num;struct libusb_config_descriptor *config_desc;struct libusb_device_handle *dev_handle NULL;struct usb_mouse *pmouse;struct usb_mouse *list NULL;int mouse_cnt 0;/* for each device, get config descriptor */for (int i 0; i num_devices; i) {dev devs[i];/* parse interface descriptor, find usb mouse */ err libusb_get_config_descriptor(dev, 0, config_desc); // 获取配置描述符if (err) {fprintf(stderr, could not get configuration descriptor\n);continue;}fprintf(stdout, libusb_get_config_descriptor() ok\n);for (int interface 0; interface config_desc-bNumInterfaces; interface) { // 枚举所有接口描述符const struct libusb_interface_descriptor *intf_desc config_desc-interface[interface].altsetting[0];interface_num intf_desc-bInterfaceNumber; // 记录该接口描述符的编号编号是从0开始if (intf_desc-bInterfaceClass ! 3 || intf_desc-bInterfaceProtocol ! 2) // 判断是否是HID设备和是否是鼠标协议 continue;else{/* 找到了USB鼠标 */fprintf(stdout, find usb mouse ok\n);for (int ep 0; ep intf_desc-bNumEndpoints; ep) // 枚举所有端点描述符{// 判断是否是中断传输是否是输入端点输入输出都是以USB Host来讨论所以该端点是USB Device输出到USB Hostif ((intf_desc-endpoint[ep].bmAttributes 3) LIBUSB_TRANSFER_TYPE_INTERRUPT ||(intf_desc-endpoint[ep].bEndpointAddress 0x80) LIBUSB_ENDPOINT_IN) {/* 找到了输入的中断端点 */fprintf(stdout, find in int endpoint\n);endpoint intf_desc-endpoint[ep].bEndpointAddress;/* libusb_open */err libusb_open(dev, dev_handle);if (err){fprintf(stderr, failed to open usb mouse\n);return -1;}fprintf(stdout, libusb_open ok\n);/* 记录下来: 放入链表 */pmouse malloc(sizeof(struct usb_mouse));if (!pmouse){fprintf(stderr, can not malloc\n);return -1;}pmouse-endpoint endpoint;pmouse-interface interface_num;pmouse-handle dev_handle;pmouse-next NULL;if (!list)list pmouse;else{pmouse-next list;list pmouse;}mouse_cnt;break;}}}}libusb_free_config_descriptor(config_desc);}*usb_mouse_list list;return mouse_cnt;
}static void mouse_irq(struct libusb_transfer *transfer)
{static int count 0;if (transfer-status LIBUSB_TRANSFER_COMPLETED){/* parser data */printf(%04d datas: , count);for (int i 0; i transfer-actual_length; i){printf(%02x , transfer-buffer[i]);}printf(\n);}if (libusb_submit_transfer(transfer) 0){fprintf(stderr, libusb_submit_transfer err\n);}
}int main(int argc, char **argv)
{int err;libusb_device **devs;int num_devices, num_mouse;struct usb_mouse *pmouse;/* libusb init */err libusb_init(NULL);if (err 0) {fprintf(stderr, failed to initialise libusb %d - %s\n, err, libusb_strerror(err));exit(1);}/* get device list */if ((num_devices libusb_get_device_list(NULL, devs)) 0) // 获取设备描述符列表函数返回设备描述符数量{fprintf(stderr, libusb_get_device_list() failed\n);libusb_exit(NULL);exit(1);} fprintf(stdout, libusb_get_device_list() ok\n);/* get usb mouse */num_mouse get_usb_mouse(devs, num_devices, usb_mouse_list);if (num_mouse 0){/* free device list */libusb_free_device_list(devs, 1);libusb_exit(NULL);exit(1);}fprintf(stdout, get %d mouses\n, num_mouse);/* free device list */libusb_free_device_list(devs, 1);/* claim interface */pmouse usb_mouse_list;while (pmouse){libusb_set_auto_detach_kernel_driver(pmouse-handle, 1); err libusb_claim_interface(pmouse-handle, pmouse-interface);if (err){fprintf(stderr, failed to libusb_claim_interface\n);exit(1);}pmouse pmouse-next;}fprintf(stdout, libusb_claim_interface ok\n);/* for each mouse, alloc transfer, fill transfer, submit transfer */pmouse usb_mouse_list;while (pmouse){/* alloc transfer */pmouse-transfer libusb_alloc_transfer(0);/* fill transfer */libusb_fill_interrupt_transfer(pmouse-transfer, pmouse-handle, pmouse-endpoint, pmouse-buf,sizeof(pmouse-buf), mouse_irq, pmouse, 0);/* submit transfer */libusb_submit_transfer(pmouse-transfer);pmouse pmouse-next;}/* handle events */while (1) {struct timeval tv { 5, 0 };int r;r libusb_handle_events_timeout(NULL, tv);if (r 0) {fprintf(stderr, libusb_handle_events_timeout err\n);break;}}/* libusb_close */pmouse usb_mouse_list;while (pmouse){libusb_release_interface(pmouse-handle, pmouse-interface);libusb_close(pmouse-handle); pmouse pmouse-next;}free_usb_mouses(usb_mouse_list);libusb_exit(NULL);}运行程序前先把多个鼠标插入开发板然后运行测试程序移动鼠标查看打印结果。