Linux下HID 设备
python读取usb hid数据例程 -回复
python读取usb hid数据例程-回复如何使用Python读取USB HID数据USB HID(Human Interface Device)是一种USB设备类别,它允许计算机与各种输入设备进行通信,例如键盘、鼠标、游戏控制器等。
在本文中,我们将讨论如何使用Python读取USB HID设备的数据。
首先,让我们来了解一下Python中用于读取HID设备数据的库。
有几个库可用于这个任务,但我们这里将重点介绍`pyUSB`库。
`pyUSB`是一个Python库,用于与USB设备进行通信。
它提供了一组丰富的功能,包括设备枚举、控制传输和数据传输等。
在开始使用`pyUSB`之前,我们需要安装它。
打开终端(Mac和Linux)或命令提示符(Windows),运行以下命令来安装`pyUSB`:pip install pyusb安装完成后,我们可以开始编写代码来读取USB HID设备的数据。
首先,让我们导入必要的模块:pythonimport usb.coreimport usb.util接下来,我们需要找到我们想要读取数据的HID设备。
我们可以使用`usb.core.find()`方法来查找设备。
这个方法接受一个字典作为参数,用于指定要查找的设备的属性。
通常,我们会指定设备的供应商ID和产品ID 来查找设备。
例如,假设我们要查找供应商ID为0x1234,产品ID为0x5678的设备,我们可以这样做:pythondev = usb.core.find(idVendor=0x1234, idProduct=0x5678)如果设备被找到,`dev`将是一个`usb.core.Device`对象,否则将为`None`。
在这之后,我们需要将设备设置为活动状态,并为我们的读取操作获取一个接口。
pythonif dev is None:raise ValueError("Device not found")# 设置设备活动状态dev.set_configuration()# 获取接口intf = dev.get_active_configuration().interfaces()[0]ep = intf.endpoints()[0]现在,我们已经准备好读取HID设备的数据了。
USBHID协议中文版__USB接口HID设备
USBHID协议中文版__USB接口HID设备##USBHID协议
USBHID协议(Universal Serial Bus Human Interface Device)是
USB设备的一种常用协议,它主要用于连接和控制人与计算机的交互设备,如键盘、鼠标、游戏手柄、虚拟摇杆、扫描仪和图形表格等设备。
它主要
用于USB设备的连接和控制,以及电脑上支持的操作系统,如Windows、Mac OS、Linux。
USBHID协议使用HID类设备来提高人机交互的效率,有效地减少计
算机程序的数据处理时间。
使用HID类设备的程序可以实时地进行输入,
计算机也可以实时地反馈反应。
通过使用HID类设备,可以有效地提高用
户体验。
USBHID协议具有许多优点,如:支持所有兼容USB的操作系统,不
需要额外的驱动程序,可以支持各种类型的HID设备,延长设备的稳定性,减少传输延迟,减少接口占用,支持许多不同的传输速率,可以支持许多
不同的设备和设备类型,支持多种接口,支持大量的数据通信,以及减少
计算机程序数据处理时间等优点。
另外,USBHID协议也给使用这些设备带来了极大的便利,如:可以
将设备连接到计算机,让设备能够立即响应输入;可以使用设备时装载更
多的功能;可以在多个设备之间进行快速传输;可以有意识地管理电源;
可以支持多种设备,如跳线选择器。
Linux设备驱动之HID驱动---非常全面而且深刻
Linux设备驱动之HID驱动---⾮常全⾯⽽且深刻本⽂系本站原创,欢迎转载!转载请注明出处:/------------------------------------------⼀:前⾔继前⾯分析过UHCI和HUB驱动之后,接下来以HID设备驱动为例来做⼀个具体的USB设备驱动分析的例⼦.HID是Human Interface Devices的缩写.翻译成中⽂即为⼈机交互设备.这⾥的⼈机交互设备是⼀个宏观上⾯的概念,任何设备,只要符合HID spec,都⼆:HID驱动⼊⼝分析USB HID设备驱动⼊⼝位于linux-2.6.25/drivers/hid/usbhid/hid-core.c中.该module的⼊⼝为hid_init().代码如下:static int __init hid_init(void){int retval;retval = usbhid_quirks_init(quirks_param);if (retval)goto usbhid_quirks_init_fail;retval = hiddev_init();if (retval)goto hiddev_init_fail;retval = usb_register(&hid_driver);if (retval)goto usb_register_fail;info(DRIVER_VERSION ":" DRIVER_DESC);return0;usb_register_fail:hiddev_exit();hiddev_init_fail:usbhid_quirks_exit();usbhid_quirks_init_fail:return retval;}⾸先来看usbhid_quirks_init()函数.quirks我们在分析UHCI和HUB的时候也接触过,表⽰需要做某种修正的设备.该函数调⽤的参数是quirks_param.定义如下:static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };module_param_array_named(quirks, quirks_param, charp, NULL, 0444);从此可以看出, quirks_param是MAX_USBHID_BOOT_QUIRKS元素的字符串数组.并且在加载module的时候,可以动态的指定这些值.分析到这⾥.有⼈可以反应过来了,usbhid_quirks_init()是⼀种动态进⾏HID设备修正的⽅式.具体要修正哪些设备,要修正设备的那些⽅⾯,都可以由加载模块是所带参数来决定.usbhid_quirks_init()的代码如下:int usbhid_quirks_init(char **quirks_param){u16 idVendor, idProduct;u32 quirks;int n = 0, m;for (; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) {m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",&idVendor, &idProduct, &quirks);if (m != 3 ||usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {printk(KERN_WARNING"Could not parse HID quirk module param %s\n",quirks_param[n]);}}return0;}由此可以看出, quirks_param数组中的每⼀项可以分为三个部份,分别是要修正设备的VendorID,ProductID和要修正的功能.⽐如0x1000 0x0001 0x0004就表⽰:要忽略掉VendorID为0x1000,ProductID为0x0004的设备.(在代码中,有#define HID_QUIRK_跟进usbhid_modify_dquirk()函数,代码如下:int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,const u32 quirks){struct quirks_list_struct *q_new, *q;int list_edited = 0;if (!idVendor) {dbg_hid("Cannot add a quirk with idVendor = 0\n");return -EINVAL;}q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL);if (!q_new) {dbg_hid("Could not allocate quirks_list_struct\n");return -ENOMEM;}q_new->hid_bl_item.idVendor = idVendor;q_new->hid_bl_item.idProduct = idProduct;q_new->hid_bl_item.quirks = quirks;down_write(&dquirks_rwsem);list_for_each_entry(q, &dquirks_list, node) {if (q->hid_bl_item.idVendor == idVendor &&q->hid_bl_item.idProduct == idProduct) {list_replace(&q->node, &q_new->node);kfree(q);list_edited = 1;break;}}if (!list_edited)list_add_tail(&q_new->node, &dquirks_list);up_write(&dquirks_rwsem);return0;}这个函数⽐较简单,就把quirks_param数组项中的三个部份存⼊⼀个封装结构.然后将其结构挂载到dquirks_list表.如果dquirks_list有重复的VendorId和ProductID就更新其quirks信息.经过usbhid_quirks_init()之后,所有要修正的设备的相关操作都会存放在dquirks_list中.返回到hid_init(),继续往下⾯分析.hiddev_init()是⼀个⽆关的操作,不会影响到后⾯的操作.忽略后⾯就是我们今天要分析的重点了,如下:retval = usb_register(&hid_driver);通过前⾯对HUB的驱动分析,相信对usb_redister()应该很熟悉了.hid_driver定义如下:static struct usb_driver hid_driver = {.name = "usbhid",.probe = hid_probe,.disconnect = hid_disconnect,.suspend = hid_suspend,.resume = hid_resume,.reset_resume = hid_post_reset,.pre_reset = hid_pre_reset,.post_reset = hid_post_reset,.id_table = hid_usb_ids,.supports_autosuspend = 1,};其中,id_table的结构为hid_usb_ids.定义如下:static struct usb_device_id hid_usb_ids [] = {{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,.bInterfaceClass = USB_INTERFACE_CLASS_HID },{ } /* Terminating entry */};也就是说,该驱动会匹配interface的ClassID,所有ClassID为USB_INTERFACE_CLASS_HID的设备都会被这个驱动所匹配.所以,所有USB HID设备都会由这个module来驱动.三:HID驱动的probe过程从上⾯的分析可看到,probe接⼝为hid_probe().定义如下:static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id){struct hid_device *hid;char path[64];int i;char *c;dbg_hid("HID probe called for ifnum %d\n",intf->altsetting->desc.bInterfaceNumber);//config the hid deviceif (!(hid = usb_hid_configure(intf)))return -ENODEV;usbhid_init_reports(hid);hid_dump_device(hid);if (hid->quirks & HID_QUIRK_RESET_LEDS)usbhid_set_leds(hid);if (!hidinput_connect(hid))hid->claimed |= HID_CLAIMED_INPUT;if (!hiddev_connect(hid))hid->claimed |= HID_CLAIMED_HIDDEV;if (!hidraw_connect(hid))hid->claimed |= HID_CLAIMED_HIDRAW;usb_set_intfdata(intf, hid);if (!hid->claimed) {printk ("HID device claimed by neither input, hiddev nor hidraw\n");hid_disconnect(intf);return -ENODEV;}if ((hid->claimed & HID_CLAIMED_INPUT))hid_ff_init(hid);if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),intf->cur_altsetting->desc.bInterfaceNumber);printk(KERN_INFO);if (hid->claimed & HID_CLAIMED_INPUT)printk("input");if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||hid->claimed & HID_CLAIMED_HIDRAW))printk(",");if (hid->claimed & HID_CLAIMED_HIDDEV)printk("hiddev%d", hid->minor);if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&(hid->claimed & HID_CLAIMED_HIDRAW))printk(",");if (hid->claimed & HID_CLAIMED_HIDRAW)printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);c = "Device";for (i = 0; i < hid->maxcollection; i++) {if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&(hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&(hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {c = hid_types[hid->collection[i].usage & 0xffff];break;}}usb_make_path(interface_to_usbdev(intf), path, 63);printk(": USB HID v%x.%02x %s [%s] on %s\n",hid->version >> 8, hid->version & 0xff, c, hid->name, path);return0;}这个函数看起来是不是让⼈⼼慌慌?其实这个函数的最后⼀部份就是打印出⼀个Debug信息,我们根本就不需要去看. hiddev_connect()和hidraw_connect()是⼀个选择编译的操作,也不可以不要去理会.然后,剩下的就没多少了.3.1:usb_hid_configure()函数分析先来看usb_hid_configure().顾名思义,该接⼝⽤来配置hid设备.怎么配置呢?还是深⼊到代码来分析,该函数有⼀点长,分段分析如下:static struct hid_device *usb_hid_configure(struct usb_interface *intf){struct usb_host_interface *interface = intf->cur_altsetting;struct usb_device *dev = interface_to_usbdev (intf);struct hid_descriptor *hdesc;struct hid_device *hid;u32 quirks = 0;unsigned rsize = 0;char *rdesc;int n, len, insize = 0;struct usbhid_device *usbhid;quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),le16_to_cpu(dev->descriptor.idProduct));/* Many keyboards and mice don't like to be polled for reports,* so we will always set the HID_QUIRK_NOGET flag for them. *///如果是boot设备,跳出.不由此驱动处理if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)quirks |= HID_QUIRK_NOGET;}//如果是要忽略的if (quirks & HID_QUIRK_IGNORE)return NULL;if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&(interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))return NULL;⾸先找到该接⼝需要修正的操作,也就是上⾯代码中的quirks值,如果没有修正操作,则quirks为0.另外,根据usb hid spec中的定义,subclass如果为1,则说明该设备是⼀个boot阶段使⽤的hid设备,然后Protocol Code为1和2时分别代表Keyboard和Mouse. 如//get hid descriptorsif (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&(!interface->desc.bNumEndpoints ||usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {dbg_hid("class descriptor not present\n");return NULL;}//bNumDescriptors:⽀持的附属描述符数⽬for (n = 0; n < hdesc->bNumDescriptors; n++)if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);//如果Report_Descriptors长度不合法if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {dbg_hid("weird size of report descriptor (%u)\n", rsize);return NULL;}if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {dbg_hid("couldn't allocate rdesc memory\n");return NULL;}//Set idle_time = 0hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);//Get Report_Descriptorsif ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {dbg_hid("reading report descriptor failed\n");kfree(rdesc);return NULL;}//是否属于fixup?usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),le16_to_cpu(dev->descriptor.idProduct), rdesc,rsize, rdesc_quirks_param);dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);for (n = 0; n < rsize; n++)dbg_hid_line(" %02x", (unsigned char) rdesc[n]);dbg_hid_line("\n");对于HID设备来说,在interface description之后会附加⼀个hid description, hid description中的最后部份包含有Report description或者Physical Descriptors的长度.在上⾯的代码中,⾸先取得附加在interface description之后的hid description,然后,再从hid description中取得report description的长度.最后,取得report description的详细信息.在这⾥,还会将idle时间设备为0,表⽰⽆限时,即,从上⼀次报表传输后,只有在报表发⽣改变时,才会传送此报表内容,否则,传送NAK.这段代码的最后⼀部份是相关的fixup操作,不做详细分析.//pasrse the report_descriptorif (!(hid = hid_parse_report(rdesc, n))) {dbg_hid("parsing report descriptor failed\n");kfree(rdesc);return NULL;}kfree(rdesc);hid->quirks = quirks;if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))goto fail_no_usbhid;hid->driver_data = usbhid;usbhid->hid = hid;解析获得的report description,解析之后的信息,存放在hid_device->collection和hid_device->report_enum[ ]中,这个解析过程之后会做详细分析.然后,初始化⼀个usbhid_device结构,使usbhid_device->hid指向刚解析report description获得的hid_device.同 usbhid->bufsize = HID_MIN_BUFFER_SIZE;//计算各传输⽅向的最⼤bufferhid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)usbhid->bufsize = HID_MAX_BUFFER_SIZE;//in⽅向的传输最⼤值hid_find_max_report(hid, HID_INPUT_REPORT, &insize);if (insize > HID_MAX_BUFFER_SIZE)insize = HID_MAX_BUFFER_SIZE;if (hid_alloc_buffers(dev, hid)) {hid_free_buffers(dev, hid);goto fail;}计算传输数据的最⼤缓存区,并以这个⼤⼩为了hid设备的urb传输分配空间.另外,这⾥有⼀个最⼩值限制即代码中所看到的HID_MIN_BUFFER_SIZE,为64, 即⼀个⾼速设备的⼀个端点⼀次传输的数据量.在这⾥定义最⼩值为64是为了照顾低速然后,调⽤hid_alloc_buffers()为hid的urb传输初始化传输缓冲区.另外,需要注意的是,insize为INPUT⽅向的最⼤数据传输量.// 初始化usbhid->urbin和usbhid->usboutfor (n = 0; n < interface->desc.bNumEndpoints; n++) {struct usb_endpoint_descriptor *endpoint;int pipe;int interval;endpoint = &interface->endpoint[n].desc;//不是中断传输退出if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */continue;interval = endpoint->bInterval;/* Change the polling interval of mice. *///修正⿏标的双击时间if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)interval = hid_mousepoll_interval;if (usb_endpoint_dir_in(endpoint)) {if (usbhid->urbin)continue;if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))goto fail;pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,hid_irq_in, hid, interval);usbhid->urbin->transfer_dma = usbhid->inbuf_dma;usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;} else {if (usbhid->urbout)continue;if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))goto fail;pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,hid_irq_out, hid, interval);usbhid->urbout->transfer_dma = usbhid->outbuf_dma;usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;}}if (!usbhid->urbin) {err_hid("couldn't find an input interrupt endpoint");goto fail;}遍历接⼝中的所有endpoint,并初始化in中断传输⽅向和out中断⽅向的urb.如果⼀个hid设备没有in⽅向的中断传输,⾮法.另外,在这⾥要值得注意的是, 在为OUT⽅向urb初始化的时候,它的传输缓存区⼤⼩被设为了0.IN⽅向的中断传输缓存区⼤⼩被设为了insize,传输缓存区⼤⼩在submit的时候会修正的. init_waitqueue_head(&hid->wait);INIT_WORK(&usbhid->reset_work, hid_reset);setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);spin_lock_init(&usbhid->inlock);spin_lock_init(&usbhid->outlock);spin_lock_init(&usbhid->ctrllock);hid->version = le16_to_cpu(hdesc->bcdHID);hid->country = hdesc->bCountryCode;hid->dev = &intf->dev;usbhid->intf = intf;usbhid->ifnum = interface->desc.bInterfaceNumber;hid->name[0] = 0;if (dev->manufacturer)strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));if (dev->product) {if (dev->manufacturer)strlcat(hid->name, "", sizeof(hid->name));strlcat(hid->name, dev->product, sizeof(hid->name));}if (!strlen(hid->name))snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",le16_to_cpu(dev->descriptor.idVendor),le16_to_cpu(dev->descriptor.idProduct));hid->bus = BUS_USB;hid->vendor = le16_to_cpu(dev->descriptor.idVendor);hid->product = le16_to_cpu(dev->descriptor.idProduct);usb_make_path(dev, hid->phys, sizeof(hid->phys));strlcat(hid->phys, "/input", sizeof(hid->phys));len = strlen(hid->phys);if (len < sizeof(hid->phys) - 1)snprintf(hid->phys + len, sizeof(hid->phys) - len,"%d", intf->altsetting[0].desc.bInterfaceNumber);if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)hid->uniq[0] = 0;初始化hid的相关信息.//初始化hid 的ctrl传输usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);if (!usbhid->urbctrl)goto fail;usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,usbhid->ctrlbuf, 1, hid_ctrl, hid);usbhid->urbctrl->setup_dma = usbhid->cr_dma;usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);hid->hidinput_input_event = usb_hidinput_input_event;hid->hid_open = usbhid_open;hid->hid_close = usbhid_close;#ifdef CONFIG_USB_HIDDEVhid->hiddev_hid_event = hiddev_hid_event;hid->hiddev_report_event = hiddev_report_event;#endifhid->hid_output_raw_report = usbhid_output_raw_report;return hid;初始化usbhid的控制传输urb,之后⼜初始化了usbhid的⼏个操作函数.这个操作有什么⽤途,等⽤到的时候再来进⾏分析.fail:usb_free_urb(usbhid->urbin);usb_free_urb(usbhid->urbout);usb_free_urb(usbhid->urbctrl);hid_free_buffers(dev, hid);kfree(usbhid);fail_no_usbhid:hid_free_device(hid);return NULL;}经过上⾯的分析之后,我们对这个函数的⼤概操作有了⼀定的了解.现在分析⾥⾯调⽤的⼀些重要的⼦调函数.等这些⼦函数全部分析完了之后,不妨回过头看下这个函数.3.1.1:hid_parse_report()分析第⼀个要分析的函数是hid_parse_report().该函数⽤来解析report description.解析report description是⼀个繁杂的过程,对这个描述符不太清楚的,仔细看⼀下spec.在这⾥我们只会做代码上的分析.代码如下:struct hid_device *hid_parse_report(__u8 *start, unsigned size){struct hid_device *device;struct hid_parser *parser;struct hid_item item;__u8 *end;unsigned i;static int (*dispatch_type[])(struct hid_parser *parser,struct hid_item *item) = {hid_parser_main,hid_parser_global,hid_parser_local,hid_parser_reserved};if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))return NULL;//默认HID_DEFAULT_NUM_COLLECTIONS 项if (!(device->collection = kzalloc(sizeof(struct hid_collection) *HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {kfree(device);return NULL;}//hid_device->collection_size: collection的项数device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;for (i = 0; i < HID_REPORT_TYPES; i++)INIT_LIST_HEAD(&device->report_enum[i].report_list);if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) {kfree(device->collection);kfree(device);return NULL;}//hid_device->rdesc存放report_descriptor,hid_device->size存放这个描述符的⼤⼩memcpy(device->rdesc, start, size);device->rsize = size;if (!(parser = vmalloc(sizeof(struct hid_parser)))) {kfree(device->rdesc);kfree(device->collection);kfree(device);return NULL;}memset(parser, 0, sizeof(struct hid_parser));parser->device = device;end = start + size;while ((start = fetch_item(start, end, &item)) != NULL) {//long item在这⾥暂不做parseif (item.format != HID_ITEM_FORMAT_SHORT) {dbg_hid("unexpected long global item\n");hid_free_device(device);vfree(parser);return NULL;}//parse the short itemif (dispatch_type[item.type](parser, &item)) {dbg_hid("item %u %u %u %u parsing failed\n",item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);hid_free_device(device);vfree(parser);return NULL;}//如果全部解析完了if (start == end) {if (parser->collection_stack_ptr) {dbg_hid("unbalanced collection at end of report description\n");hid_free_device(device);vfree(parser);return NULL;}if (parser->local.delimiter_depth) {dbg_hid("unbalanced delimiter at end of report description\n");hid_free_device(device);vfree(parser);return NULL;}vfree(parser);return device;}}dbg_hid("item fetching failed at offset %d\n", (int)(end - start));hid_free_device(device);vfree(parser);return NULL;}进⼊到这个函数,我们⾸先看到的是Main,Globa,Local标签的解析函数.然后,分配并初始化了hid_device结构和hid_ parser.在代码中我们看到,hid_ parser-> device指向了hid_device.后hid_device没有任何域指向hid_parser. 实际上hid_parser只是⼀个辅另外,hid_device-> rdesc保存了⼀份report description副本.然后,就开始对report description的解析.函数fetch_item()⽤来取出report description的⼀项数据.代码如下:static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item){u8 b;//合法性检测if ((end - start) <= 0)return NULL;//取前⾯⼀个字节.对于短项.它的⾸个字节定义了bsize,bType,bTag.⽽对于长项,它的值为0xFEb = *start++;item->type = (b >> 2) & 3;item->tag = (b >> 4) & 15;//如果为长项.它的Type和Tag在其后的⼆个字节中.item->data.longdata指向数据的起始位置if (item->tag == HID_ITEM_TAG_LONG) {item->format = HID_ITEM_FORMAT_LONG;if ((end - start) < 2)return NULL;item->size = *start++;item->tag = *start++;if ((end - start) < item->size)return NULL;item->data.longdata = start;start += item->size;return start;}//对于短项的情况.取得size值.并根据size值取得它的data域item->format = HID_ITEM_FORMAT_SHORT;item->size = b & 3;switch (item->size) {case0:return start;case1:if ((end - start) < 1)return NULL;item->data.u8 = *start++;return start;case2:if ((end - start) < 2)return NULL;item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));start = (__u8 *)((__le16 *)start + 1);return start;case3:item->size++;if ((end - start) < 4)return NULL;item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));start = (__u8 *)((__le32 *)start + 1);return start;}return NULL;}对照代码中的注释,应该很容易看懂这个函数,不再详细分析.返回到hid_parse_report()中,取得相应项之后,如果是长项,这⾥不会做处理.对于短项.为不同的type调⽤不同的解析函数.3.1.1.1:Global项解析Global的解析⼊⼝是hid_parser_global().代码如下:static int hid_parser_global(struct hid_parser *parser, struct hid_item *item){switch (item->tag) {//PUSH项case HID_GLOBAL_ITEM_TAG_PUSH:if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {dbg_hid("global enviroment stack overflow\n");return -1;}memcpy(parser->global_stack + parser->global_stack_ptr++,&parser->global, sizeof(struct hid_global));return0;//POP项case HID_GLOBAL_ITEM_TAG_POP:if (!parser->global_stack_ptr) {dbg_hid("global enviroment stack underflow\n");return -1;}memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,sizeof(struct hid_global));return0;case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:parser->age_page = item_udata(item);return0;case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:parser->global.logical_minimum = item_sdata(item);return0;case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:if (parser->global.logical_minimum < 0)parser->global.logical_maximum = item_sdata(item);elseparser->global.logical_maximum = item_udata(item);return0;case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:parser->global.physical_minimum = item_sdata(item);return0;case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:if (parser->global.physical_minimum < 0)parser->global.physical_maximum = item_sdata(item);elseparser->global.physical_maximum = item_udata(item);return0;case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:parser->global.unit_exponent = item_sdata(item);return0;case HID_GLOBAL_ITEM_TAG_UNIT:parser->global.unit = item_udata(item);return0;case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:if ((parser->global.report_size = item_udata(item)) > 32) {dbg_hid("invalid report_size %d\n", parser->global.report_size);return -1;}return0;case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {dbg_hid("invalid report_count %d\n", parser->global.report_count);return -1;}return0;case HID_GLOBAL_ITEM_TAG_REPORT_ID:if ((parser->global.report_id = item_udata(item)) == 0) {dbg_hid("report_id 0 is invalid\n");return -1;}return0;default:dbg_hid("unknown global tag 0x%x\n", item->tag);return -1;}}这个函数虽然长,但是逻辑很简单,对于global信息,存放在hid_parse->global中.如果遇到了PUSH项,将当前的global项⼊栈,栈即为hid_parse-> global_stack[ ].当前的栈顶位置由hid_parse-> global_stack_ptr指定.如果遇到了POP项,就将栈中的global信息出栈.3.1.1.2:Local项解析Local项解析的相应接⼝为hid_parser_local().代码如下:static int hid_parser_local(struct hid_parser *parser, struct hid_item *item){__u32 data;unsigned n;if (item->size == 0) {dbg_hid("item data expected for local item\n");return -1;}data = item_udata(item);switch (item->tag) {//DELIMITER项,定义⼀个Local项的开始case HID_LOCAL_ITEM_TAG_DELIMITER://data>1:⼀个local项开始,0:⼀个local项结束//parse->local.delimiter_branch:表⽰local项计数.//进⼊⼀个local项时,local.delimiter_depth为1,退出⼀个local项时local.delimiter_depth为0// TODO: Local项不能嵌套if (data) {/** We treat items before the first delimiter* as global to all usage sets (branch 0).* In the moment we process only these global* items and the first delimiter set.*/if (parser->local.delimiter_depth != 0) {dbg_hid("nested delimiters\n");return -1;}parser->local.delimiter_depth++;parser->local.delimiter_branch++;} else {if (parser->local.delimiter_depth < 1) {dbg_hid("bogus close delimiter\n");return -1;}parser->local.delimiter_depth--;}return1;//以下各项不能出现在有DELIMITER标签的地⽅case HID_LOCAL_ITEM_TAG_USAGE:if (parser->local.delimiter_branch > 1) {dbg_hid("alternative usage ignored\n");return0;}//local的usage项有扩展⽤法,它的⾼16可以定义usage_page.如果⾼16为空,它的//usage_page则定义在global中的usage_page if (item->size <= 2)data = (parser->age_page << 16) + data;//然后添加到parse->local的usage列表return hid_add_usage(parser, data);//对于有usage_min和usage_max的情况,将usage_min和usage_max之间的usage添加到//parse=>local的usage列表case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:if (parser->local.delimiter_branch > 1) {dbg_hid("alternative usage ignored\n");return0;}if (item->size <= 2)data = (parser->age_page << 16) + data;parser->age_minimum = data;return0;case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:if (parser->local.delimiter_branch > 1) {dbg_hid("alternative usage ignored\n");return0;}if (item->size <= 2)data = (parser->age_page << 16) + data;for (n = parser->age_minimum; n <= data; n++)if (hid_add_usage(parser, n)) {dbg_hid("hid_add_usage failed\n");return -1;}return0;default:dbg_hid("unknown local item tag 0x%x\n", item->tag);return0;}return0;}详细分析⼀下hid_add_usage().代码如下:static int hid_add_usage(struct hid_parser *parser, unsigned usage){if (parser->age_index >= HID_MAX_USAGES) {dbg_hid("usage index exceeded\n");return -1;}parser->age[parser->age_index] = usage;parser->local.collection_index[parser->age_index] =parser->collection_stack_ptr ?parser->collection_stack[parser->collection_stack_ptr - 1] : 0;parser->age_index++;return0;}如果usage项超过了HID_MAX_USAGES,为⾮法.最⼤为8192项.Parse->age_index表⽰local的项数,当然也表⽰了parse->age[ ]数组中的下⼀个可⽤项.parser->local.collection_index表⽰该usage所在的collection项序号.具体的collection信息存放在hid_deivce->collection[ ]中.关于collection我们在分析Main项解析的时候会详细分析.3.1.1.3:Main项解析Main项解析的⼊⼝为hid_parser_main().代码如下:static int hid_parser_main(struct hid_parser *parser, struct hid_item *item){__u32 data;int ret;//data域data = item_udata(item);switch (item->tag) {//Collectioncase HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:ret = open_collection(parser, data & 0xff);break;//End Collectioncase HID_MAIN_ITEM_TAG_END_COLLECTION:ret = close_collection(parser);break;//Inputcase HID_MAIN_ITEM_TAG_INPUT:ret = hid_add_field(parser, HID_INPUT_REPORT, data);break;//Outpputcase HID_MAIN_ITEM_TAG_OUTPUT:ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);break;//Featurecase HID_MAIN_ITEM_TAG_FEATURE:ret = hid_add_field(parser, HID_FEATURE_REPORT, data);break;default:dbg_hid("unknown main item tag 0x%x\n", item->tag);ret = 0;}memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */return ret;}对Main项的解析要稍微复杂⼀点,Main项主要有两个部份,⼀个是Collection,⼀个是Input/Output/Feature项.先来看Collection项的解析.所有的collection信息都存放在hid_device->collection[ ]中.⽽Collection项⼜有嵌套的情况,每遇到⼀个Collection项就将collection的序号⼊栈,栈为parser_device->collection_stack[ ].栈顶指针为parser_device->collection_stack_ptr .遇到了⼀个end coll 熟悉这个⼤概的情况之后,就可以跟进open_collection()了.代码如下://所有的collection都存放在hid_dev->collection 中, ⽽hid_dev->maxcollection 表⽰collection[]中的下⼀个空闲位置//paser->collection_stack[ ]存放的是当前解析的collection在hid_dev->collection[ ]中的序号static int open_collection(struct hid_parser *parser, unsigned type){struct hid_collection *collection;unsigned usage;usage = parser->age[0];//colletcion嵌套过多if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {dbg_hid("collection stack overflow\n");return -1;}//device->maxcollection:存放的collection个数//device->collection[ ]太⼩,必须扩⼤存放空间if (parser->device->maxcollection == parser->device->collection_size) {collection = kmalloc(sizeof(struct hid_collection) *parser->device->collection_size * 2, GFP_KERNEL);if (collection == NULL) {dbg_hid("failed to reallocate collection array\n");return -1;}memcpy(collection, parser->device->collection,sizeof(struct hid_collection) *parser->device->collection_size);memset(collection + parser->device->collection_size, 0,sizeof(struct hid_collection) *parser->device->collection_size);kfree(parser->device->collection);parser->device->collection = collection;parser->device->collection_size *= 2;}//将collection序号⼊栈parser->collection_stack[parser->collection_stack_ptr++] =parser->device->maxcollection;//存⼊hid_device->collection[]collection = parser->device->collection +parser->device->maxcollection++;collection->type = type;collection->usage = usage;//collection的深度collection->level = parser->collection_stack_ptr - 1;if (type == HID_COLLECTION_APPLICATION)parser->device->maxapplication++;return0;}对照上⾯的分析和函数中的注释,理解这个函数应该很简单,不做详细分析.对于Input/Output/Feature项的解析:先来看⼀下hid_device结构的定义⽚段:struct hid_device{…………struct hid_report_enum report_enum[HID_REPORT_TYPES];……}对于INPUT/OUTPUT/FEATURE,每种类型都对应report_enum[ ]中的⼀项.Struct hid_report_enum定义如下:struct hid_report_enum {unsigned numbered;struct list_head report_list;struct hid_report *report_id_hash[256];};对于每⼀个report_id,对应report_id_hash[ ]中的⼀项,同时,将所对应的hid_report添加到report_list链表中.如果有多个report_id 的情况,numbered被赋为1.Struct hid_report定义如下:struct hid_report {struct list_head list;unsigned id; /* id of this report */unsigned type; /* report type */struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */unsigned maxfield; /* maximum valid field index */unsigned size; /* size of the report (bits) */struct hid_device *device; /* associated device */}List:⽤来形成链表Id:表⽰report_idType: INPUT/OUTPUT/FEATUREField[ ]:成员列表,对应⼀个report_id有多个INPUT(OUTPUT/FEATURE)项Maxfield: field[ ]中的有效项数Size: 该report的⼤⼩Device:所属的hid_device了解了这些之后,就可以来看⼀下代码了:如下:static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags){struct hid_report *report;struct hid_field *field;int usages;unsigned offset;int i;//找到类型和对应report_id所在的report.如果不存在,则新建之if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {dbg_hid("hid_register_report failed\n");return -1;}//对当前global数据的有效性判断。
hid协议
HID协议HID(Human Interface Device)协议是一种用于计算机与人机交互设备之间通信的协议。
它定义了计算机如何与键盘、鼠标、游戏手柄等输入设备进行通信,以及如何接收和处理来自这些设备的输入信息。
HID协议被广泛应用于各种操作系统和硬件平台中,为用户提供了良好的输入设备兼容性和可靠性。
HID协议的基本原理HID协议使用了一种称为报告(Report)的数据结构进行通信。
报告是一种特定格式的数据包,用于携带输入设备发送的信息。
在HID协议中,输入设备被称为HID设备,输出设备被称为HID主机。
HID主机通过发送请求来从HID设备获取报告,而HID设备则通过发送报告来向HID主机发送输入信息。
HID协议中定义了两种类型的报告:输入报告和输出报告。
输入报告用于向HID主机发送输入数据,比如按键信息、鼠标移动等。
而输出报告用于向HID设备发送控制命令,比如控制LED灯的亮度、设置鼠标灵敏度等。
HID协议的具体实现HID协议的具体实现方式因不同的操作系统和硬件平台而异。
以下以Windows 操作系统为例,介绍HID协议的具体实现过程。
在Windows操作系统中,HID协议的实现主要涉及到以下几个方面:1.设备识别:当插入一个HID设备时,Windows会自动识别设备并加载相应的驱动程序。
驱动程序是用来将HID设备的输入信息转换为操作系统能够理解的格式。
2.报告描述:HID设备需要提供一个报告描述符,用于描述设备支持的报告类型和报告格式。
报告描述符通常以二进制格式存储在设备的固件中,并在设备插入时由操作系统读取。
3.报告传输:HID设备和HID主机之间的报告传输通常使用USB接口进行。
HID设备通过USB接口将报告发送给HID主机,而HID主机则通过USB接口向HID设备发送请求并接收报告。
4.数据处理:HID主机接收到报告后,需要对报告进行解析和处理,以获取其中的输入数据。
操作系统提供了HID API供开发者使用,开发者可以使用这些API来访问和处理HID设备的输入信息。
hidd_getinputreport过程 -回复
hidd_getinputreport过程-回复hid_getinputreport是一种用于从HID设备读取输入报告的过程。
HID 是Human Interface Device的缩写,指的是各种输入设备,如键盘、鼠标和游戏手柄等。
hid_getinputreport函数允许应用程序从HID设备中获取输入报告的数据,并根据需要进行分析和处理。
本文将详细介绍hid_getinputreport过程的实现原理和步骤,并探讨其在实际开发中的应用。
第一步:了解HID设备和报告格式在深入研究hid_getinputreport过程之前,我们首先需要了解HID设备和报告格式。
HID设备是指通过USB或蓝牙等接口与计算机通信,用于输入人机交互数据的设备。
每个HID设备都有一个或多个报告描述符,用于定义数据的格式和意义。
报告格式可以是固定的,也可以是可变的,取决于设备的特性和功能。
因此,在编写hid_getinputreport函数之前,我们需要了解目标HID设备的报告描述符,以正确解析输入报告。
第二步:打开HID设备在开始读取输入报告之前,我们需要使用相关的API函数打开目标HID 设备。
具体的API函数根据操作系统和编程语言的不同而有所差异。
一般而言,我们需要使用设备的唯一标识符来打开HID设备。
在成功打开设备之后,我们就可以通过设备句柄访问设备的属性和数据。
第三步:确定输入报告IDHID设备可以通过多个输入报告传输数据。
每个输入报告都有一个唯一的ID,用于标识不同的报告类型。
我们需要确定需要读取的输入报告ID,并在之后的读取过程中使用该ID。
一般情况下,设备的报告描述符会提供相关信息,以帮助我们确定所需的报告ID。
第四步:设置读取缓冲区在读取输入报告之前,我们需要准备用于接收数据的缓冲区。
根据报告描述符中的定义,输入报告可以具有不同的长度和数据类型。
我们需要根据实际的报告格式设置合适的缓冲区大小。
在设置缓冲区之后,我们可以通过hid_getinputreport函数将数据读取到缓冲区中。
linuxHID设备读写
linuxHID设备读写linux下hid设备读写的问题#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <linux/hid.h>#include <linux/hiddev.h>int main(int argc,char **argv){int fd;int rtn,ret=0;int i,j=0;struct hiddev_report_info rinfo;struct hiddev_usage_ref uref;struct hiddev_field_info finfo;struct hiddev_usage_ref_multi urefs;struct hiddev_devinfo dinfo;struct hiddev_collection_info cinfo;unsigned char bufw[21]={0x02,0x08,0xce,0,0,0,0,0,0,0}; unsigned char recv[21]={0};//printf("argc = %d\n",argc);//打开设备文件fd=open("/dev/usb/hiddev0",O_RDWR);if(fd > 0){printf("open hid success!,fd = %d\n",fd);}//rinfo.report_type=HID_REPORT_TYPE_OUTPUT; rinfo.report_id=HID_REPORT_ID_FIRST;ret=ioctl(fd,HIDIOCGREPORTINFO,&rinfo);if(ret != 0){printf("ioctl one failed!\n");close(fd);return -1;}for(i=0;i<rinfo.num_fields;i++){finfo.report_type=rinfo.report_type;finfo.report_id=rinfo.report_id;finfo.field_index=i;ret = ioctl(fd,HIDIOCGFIELDINFO,&finfo); printf("finfo.maxusage %d\n",finfo.maxusage); if(ret != 0){printf("ioctl two failed\n");close(fd);return -1;}//for(j=0;j<finfo.maxusage;j++)//{uref.report_type=finfo.report_type;uref.report_id=finfo.report_id;uref.field_index=i;age_index=j;//ioctl(fd,HIDIOCGUCODE,&uref);ret = ioctl(fd,HIDIOCGUSAGE,&uref);if(ret != 0){printf("ioctl three faile!\n");close(fd);return -1;}ret = ioctl(fd,HIDIOCGUCODE,&uref);printf("usage.value:%x\n",uref.value);printf("usage report_type %d report_id %d field_index %d usage_index %d usage_code %d\n",uref.report_type, uref.report_id, uref.field_index, age_index, age_code);if(ret != 0){printf("ioctl four failed\n");close(fd);return -1;}printf("\n");//}urefs.uref.report_type=HID_REPORT_TYPE_OUTPUT;urefs.uref.report_id=finfo.report_id;urefs.num_values=8;urefs.uref.field_index=i;age_index=0;for(j=0;j<21;j++){age_code+=4;urefs.values[j]=bufw[j];printf("usagereport_type:%d,report_id:%d,field_index:%d,usage_index:%d,usa ge_code:%d\n",urefs.uref.report_id,urefs.uref.report_id,urefs.uref.field_index,uref age_index, age_code);}ret=ioctl(fd,HIDIOCSUSAGES,&urefs);//写入数据1if(ret !=0){printf("failed !\n");close(fd);return -1;}}rinfo.report_type=HID_REPORT_TYPE_INPUT;rinfo.report_id=HID_REPORT_ID_FIRST;for(i=0;i<rinfo.num_fields;i++){printf("num_field=%d\n",rinfo.num_fields);finfo.report_type=rinfo.report_type;finfo.report_id=rinfo.report_id;finfo.field_index=i;printf("finfo.report_id:%d\n",finfo.report_id);ret =ioctl(fd,HIDIOCGFIELDINFO,&finfo);if(ret !=0){printf("ioctl five faile!\n");close(fd);return -1;}else{printf("finfo.report_id:%d\n",finfo.report_id);}}for(i=0;i<21;i++)//打印结构体中是否有值。
hid 协议
hid 协议HID 协议。
HID(Human Interface Device)是一种用于描述计算机与人体交互设备通信协议的标准。
它定义了计算机如何与键盘、鼠标、游戏手柄等设备进行通信,使得这些设备可以被计算机正确识别和使用。
HID 协议的设计旨在让不同厂家生产的设备可以在不同的操作系统上无缝运行,为用户提供更好的使用体验。
HID 协议的核心是报告(Report)机制,它规定了设备与计算机之间的数据交换格式。
在 HID 协议中,设备会定期向计算机发送报告,告诉计算机当前设备的状态,比如按下了哪个键,鼠标移动了多少距离等。
而计算机也可以向设备发送报告,告诉设备需要执行的操作,比如让设备发出蜂鸣声,或者让设备的指示灯闪烁。
除了报告机制,HID 协议还规定了设备的描述信息应该如何组织。
这些描述信息包括设备的厂商 ID、产品 ID、设备类型、支持的报告类型等。
这些信息可以让计算机正确识别设备,并加载对应的驱动程序,从而实现设备的正常工作。
HID 协议的设计考虑了设备的通用性和可扩展性。
它并不限定设备的具体实现方式,只规定了设备与计算机之间的通信格式,这使得不同厂家生产的设备可以共用同一套驱动程序,从而降低了开发和维护的成本。
同时,HID 协议还支持设备的热插拔,这意味着用户可以在不重启计算机的情况下插拔设备,而计算机会自动识别新插入的设备,并加载对应的驱动程序。
总的来说,HID 协议是一种非常重要的标准,它为计算机与人体交互设备之间的通信提供了统一的规范。
在日常生活中,我们使用的键盘、鼠标、游戏手柄等设备都是基于 HID 协议设计的,它们之所以能够在不同的计算机和操作系统上正常工作,得益于 HID 协议的统一规范。
同时,HID 协议也为设备厂商和软件开发者提供了便利,他们可以基于 HID 协议开发符合标准的设备和驱动程序,从而为用户带来更好的使用体验。
在未来,随着人体交互设备的不断发展,HID 协议也将不断完善和扩展,以适应新的设备和应用场景。
如何编写应用程序与USBHID设备通讯
如何编写应用程序与USBHID设备通讯编写应用程序与USBHID设备通讯的过程可以分为以下几个步骤:设备初始化、数据读取与写入以及释放资源。
下面将详细介绍如何完成每个步骤。
1.设备初始化:首先,需要获取系统中的所有HID设备信息,并找到目标设备的相关信息,如厂商ID、产品ID等。
可以使用操作系统提供的API函数来实现这一步骤,例如,Windows系统可以使用SetupAPI、DeviceIoControl等函数来获取设备信息。
2.打开设备:找到目标设备后,需要使用操作系统提供的API函数打开设备。
在Windows系统下,使用CreateFile函数打开设备句柄。
在Linux系统下,可以通过打开特定的文件来获取设备句柄。
3.读取数据:打开设备后,可以使用ReadFile函数从设备中读取数据。
需要设置好读取的缓冲区大小和读取的超时时间等相关参数。
读取的数据通常以报文形式传输,需要根据设备的通信协议进行解析和处理。
4.写入数据:使用WriteFile函数将数据写入设备。
写入的数据也通常以报文形式进行传输,需要按照设备的通信协议来填充报文的内容。
5.释放资源:通信完成后,需要关闭设备句柄并释放相关资源。
在Windows系统下,使用CloseHandle函数关闭设备句柄;在Linux系统下,使用close函数关闭设备文件描述符。
总结起来,编写应用程序与USBHID设备通讯的过程包括设备初始化、打开设备、读取数据、写入数据以及释放资源等步骤。
具体实现过程需要根据操作系统和编程语言的不同而有所调整,但总体思路相似。
通过调用操作系统提供的API函数来完成和USBHID设备的通信,可以实现读取和写入数据的功能。
linux hid使用手册
linux hid使用手册在Linux系统中,HID(Human Interface Device)是一种用于连接人机界面设备的通信协议。
这些设备包括键盘、鼠标、游戏手柄等常见的输入设备。
本手册将为您介绍Linux系统中HID的使用方法。
1. HID驱动程序的加载在Linux系统中,HID驱动程序被编译成内核模块的形式,需要使用modprobe命令加载。
示例如下:$ modprobe hid如果需要加载特定的HID驱动程序,可以使用modprobe命令指定驱动程序的名称,例如:$ modprobe usbhid2. 检测和识别HID设备在Linux系统中,可以使用lsusb命令来检测和识别连接到系统的USB设备。
示例如下:$ lsusb该命令会列出所有连接到系统的USB设备,包括HID设备。
可以根据设备的厂商ID和产品ID来确定具体是哪种HID设备。
例如,如果HID设备的厂商ID是045e,产品ID是076c,可以通过以下命令查看设备的详细信息:$ lsusb -d 045e:076c3. HID设备的读取和控制在Linux系统中,可以使用udev规则来对HID设备进行读取和控制。
udev是一个用于管理设备节点的工具,可以根据设备的属性和特征来为其分配唯一的节点。
通过udev规则,可以将HID设备映射为/dev/hidrawX文件,然后可以使用该文件进行读取和控制。
示例udev规则如下:```# /etc/udev/rules.d/99-hid.rules# HID devicesKERNEL=="hidraw*", ATTRS{idVendor}=="045e",ATTRS{idProduct}=="076c", MODE="0666"```以上规则将匹配到厂商ID为045e,产品ID为076c的HID设备,并将其节点权限设置为0666,即所有用户都可以读取和控制该设备。
linux hid gadget 的工作原理
linux hid gadget 的工作原理一、概述HID(Human Interface Device)是一种设备接口规范,用于将设备与计算机进行通信。
Linux HID Gadget提供了一种在Linux内核中实现低级HID设备驱动的方法,它允许开发人员为各种不同类型的HID 设备创建自定义驱动程序。
本文将详细介绍Linux HID Gadget的工作原理,包括其基本概念、体系结构、设备分类、驱动程序开发以及与用户空间的交互。
二、基本概念1. HID设备:HID设备是与人类直接交互的设备,如键盘、鼠标、触摸板、手柄等。
每个HID设备都有一个特定的设备接口规范,用于定义设备的行为和数据传输方式。
2. HID规范:HID规范定义了设备如何与计算机进行通信,包括数据格式、传输速率、报告速率等。
不同的HID设备有不同的规范。
3. Linux内核:Linux内核是操作系统的核心部分,负责管理硬件资源、设备驱动程序和系统调用。
4. Linux HID Gadget驱动程序:Linux HID Gadget驱动程序是一种低级设备驱动程序,用于与特定的HID设备通信。
它提供了对设备的访问接口,允许应用程序与设备进行交互。
三、体系结构Linux HID Gadget提供了一种分层体系结构,包括内核空间和用户空间两部分。
内核空间包含HID Gadget驱动程序,负责与硬件通信和执行低级任务;用户空间包含应用程序,通过用户接口与HID设备进行交互。
四、设备分类Linux HID Gadget支持多种类型的HID设备,如键盘、鼠标、触摸板、手柄等。
每个类型的HID设备都有其特定的设备接口规范,驱动程序根据这些规范进行开发。
五、驱动程序开发开发Linux HID Gadget驱动程序需要一定的专业知识,包括C语言编程、Linux内核开发、HID设备规范等。
开发过程通常包括以下步骤:1. 识别设备:通过读取系统中已安装设备的列表,找到要开发的HID设备。
linux hid使用手册
Linux HID使用手册一、介绍HID是Human Interface Devices的缩写,翻译成中文即为人机交互设备。
在Linux系统中,HID设备是一种常见的输入设备,如鼠标、键盘、游戏手柄等。
这些设备通过USB或蓝牙等接口与计算机连接,并通过HID协议与计算机进行通信。
二、HID设备的识别与连接在Linux系统中,当HID设备连接到计算机时,系统会自动识别并加载相应的驱动程序。
用户可以通过以下命令查看已连接的HID设备:插入HID设备并打开终端。
输入命令“lsusb”查看USB设备列表,找到HID设备的厂商ID和产品ID。
输入命令“dmesg | grep <厂商ID>:<产品ID>”查看HID设备的连接信息。
三、HID设备的配置与使用鼠标和键盘:Linux系统会自动识别并配置鼠标和键盘。
用户可以在系统设置中调整鼠标和键盘的灵敏度、按键映射等参数。
游戏手柄:对于游戏手柄,用户需要使用专门的工具进行配置。
常用的工具有“jstest-gtk”和“qjoypad”。
这些工具可以帮助用户映射手柄按键、设置摇杆灵敏度等。
自定义HID设备:如果用户需要使用自定义的HID设备,可以通过编写udev规则来实现。
udev规则可以帮助系统识别并加载自定义的HID设备驱动程序。
具体方法请参考相关文档。
四、HID设备的调试与排错查看设备状态:使用命令“lsusb -v <厂商ID>:<产品ID>”查看HID设备的详细信息,包括设备的状态、接口描述符等。
调试工具:使用hidraw工具可以对HID设备进行调试。
该工具可以读取和写入HID设备的报告,帮助用户分析设备的工作状态。
日志分析:当HID设备出现问题时,可以查看系统日志以获取更多信息。
使用命令“dmesg | grep hid”可以查看与HID设备相关的日志信息。
驱动更新:如果HID设备出现问题,可能是由于驱动程序不兼容或过时导致的。
hid协议
hid协议HID(Human Interface Device)协议是一种用于定义人机交互设备的通信规范。
它被广泛应用于各种输入设备,如键盘、鼠标、游戏手柄等。
HID协议使得这些设备能够与主机进行数据交换,实现输入操作。
HID协议定义了设备与主机之间的通信格式。
它规定了设备应该如何将按键、鼠标移动等操作转化为数据包,并通过USB 等接口发送给主机。
同时,它也规定了主机应该如何解析这些数据包,并将其映射为对应的操作。
HID协议的通信格式一般包含四个部分:报头、报体、报尾和错误检查。
报头用于标识数据包的类型和长度等信息,报体包含了具体的操作数据,报尾用于标识数据包的结束。
错误检查部分用于校验数据包的完整性。
在HID协议中,每个设备都被分配了一个唯一的设备ID。
主机通过查询设备ID来确定连接的设备类型,并根据设备类型的不同,采取不同的数据解析方式。
例如,对于键盘设备,主机会解析键盘扫描码,并将其转化为对应的字符。
而对于鼠标设备,主机会解析鼠标移动的相对坐标,并相应地改变光标的位置。
HID协议还支持多种数据输入方式。
除了常见的按键和鼠标移动外,它还支持滚轮、摇杆、触摸屏等。
这些设备可以通过HID协议将对应的操作数据发送给主机,主机再根据数据解释为相应的操作。
HID协议在人机交互设备中的应用非常广泛。
它不仅支持传统的键盘、鼠标等设备,也能够支持新兴的触控设备、虚拟现实设备等。
无论是在个人电脑还是移动设备上,HID协议都扮演着至关重要的角色。
但是,由于HID协议的复杂性,实现一个兼容HID协议的设备并不容易。
在开发过程中,需要按照HID协议的规定编写相应的代码,并完成对应的硬件设计。
此外,由于不同厂商实现HID协议的方式可能会有所不同,所以在使用HID设备时,可能会遇到不兼容的问题。
总之,HID协议是一种非常重要的人机交互设备通信规范。
它定义了设备与主机之间的数据交换方式,使得各种输入设备能够与主机进行通信。
Linux下USB驱动详解(HOST)
Linux下USB驱动详解(HOST)USB驱动分为两块,一块是USB的bus驱动,这个东西,Linux内核已经做好了,我们可以不管,我们只需要了解它的功能。
形象的说,USB的bus驱动相当于铺出一条路来,让所有的信息都可以通过这条USB通道到达该到的地方,这部分工作由usb_core(drivers/usb/usb.c)来完成。
当USB设备接到USB控制器接口时,usb_core就检测该设备的一些信息,如生产厂商的ID(VID)和产品的ID(PID),或者是设备所属的class、subclass跟protocol,以便确定应该调用哪一个驱动处理该设备。
里面复杂细节我们不用管,我们要做的是另一块工作——usb的设备驱动。
也就是说,我们就等着usb_core告诉我们要工作了,我们才工作。
OHCI(Open Host Controller Interface)是支持USB1.1的标准,但它不仅仅是针对USB,还支持其他的一些接口,比如它还支持Apple的火线(Firewire,IEEE 1394)接口。
与UHCI 相比,OHCI的硬件复杂,硬件做的事情更多,所以实现对应的软件驱动的任务,就相对较简单。
主要用于非x86的USB,如扩展卡、嵌入式开发板的USB主控。
本文也是基于OHCI来介绍usb设备驱动的。
USB从设备的分类可以从USB设备接口描述符(Standard Interface Descriptor)对应的的bInterfaceClass这一个byte得到。
bInterfaceClass的典型代码为1,2,3,6,7,8,9,10,11,255。
分别代表的意思为1-audio:表示一个音频设备。
2-communication device:通讯设备,如电话,moden等等。
3-HID:人机交互设备,如键盘,鼠标等。
6-image图象设备,如扫描仪,摄像头等,有时数码相机也可归到这一类。
7-打印机类。
Linux下HID 设备
Linux下HID 设备,如果非标准的输入设备(Keypad/MOUSE/JoyStick/input event device). 将会把信息转入hid device的设备结点。
这一点可以参见内核的关于hiddev的文档/source/Documentation/usb/hiddev.txt?v=2.6.30它在Documentation/usb/hiddev.txt 目录下,大致有这样一个流程,usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event]||--> hiddev.c ----> POWER / MONITOR CONTROL关于操作非标准的HID设备,可以参见如下文档./hiddev/在设备文件系统中,会产生的/dev/hiddev0这样的结点,这类设备主设备号为180,从设备号最低为96Cat /proc/device | grep hiddevmknod /dev/hiddev0 c 180 96mknod /dev/hiddev1 c 180 97mknod /dev/hiddev2 c 180 98mknod /dev/hiddev3 c 180 99...mknod /dev/hiddev15 c 180 111对此设备结点的处理有两种接口,一种是read(),另一种是ioctl();∙read(): This is the event interface. When the HID device performs an interrupt transfer, indicating a change of state, data will be made available at the associated hiddev device with the content of a struct hiddev_event:struct hiddev_event { unsigned hid;signed int value; };containing the HID usage identifier for the status that changed, and the value that it was changed to.∙ioctl(): This is the control interface. There are a number ofcontrols:HIDIOCGVERSIONint (read) Gets the version code out of the hiddev driver. HIDIOCAPPLICATION (none)This ioctl call returns the HID application usageassociated with the hid device. The thirdargument to ioctl() specifies which applicationindex to get. This is useful when the device hasmore than one application collection. If the indexis invalid (greater or equal to the number ofapplication collections this device has) the ioctlreturns -1. You can find out beforehand howmany application collections the device has fromthe num_applications field from thehiddev_devinfo structure.HIDIOCGD EVINFO struct hiddev_devinfo(read)Gets a hiddev_devinfo structure which describesthe device.HIDIOCGS TRING struct structhiddev_string_descriptor(read/write)Gets a string descriptor from the device. Thecaller must fill in the "index" field to indicatewhich descriptor should be returned.HIDIOCINIT REPORT Instructs the kernel to retrieve all input and feature report values from the device. At this point, all the usage structures will containcurrent values for the device, and will maintain itas the device changes.HIDIOCGNAMEstring (variable length) Gets the device nameHIDIOCGR EPORT struct hiddev_report_info(write)Instructs the kernel to get a feature or inputreport from the device, in order to selectivelyupdate the usage structures (in contrast toINITREPORT).HIDIOCSR EPORT struct hiddev_report_info(write)Instructs the kernel to send a report to thedevice. This report can be filled in by the userthroughHIDIOCSUSAGE calls (below) to fill inindividual usage values in the report beforesending the report in full to the device.HIDIOCGREPORTINF O struct hiddev_report_info(read/write)Fills in a hiddev_report_info structure for theuser. The report is looked up by type (input,output or feature) and id, so these fields must befilled in by the user. The ID can be absolute --the actual report id as reported by the device --or relative -- HID_REPORT_ID_FIRST for thefirst report, and (HID_REPORT_ID_NEXT |report_id) for the next report after report_id.Without a-priori information about report ids, theright way to use this ioctl is to use the relative IDs above to enumerate the valid IDs. The ioctl returns non-zero when there is no more next ID. The real report ID is filled into the returned hiddev_report_info structure.HIDIOCGFI ELDINFO struct hiddev_field_info(read/write)Returns the field information associated with areport in a hiddev_field_info structure. The usermust fill in report_id and report_type in thisstructure, as above. The field_index should alsobe filled in, which should be a number from 0and maxfield-1, as returned from a previousHIDIOCGREPORTINFO call.HIDIOCGU CODE struct hiddev_usage_ref(read/write)Returns the usage_code in a hiddev_usage_refstructure, given that given its report type, reportid, field index, and index within the field havealready been filled into the structure.HIDIOCGU SAGE struct hiddev_usage_ref(read/write)Returns the value of a usage in ahiddev_usage_ref structure. The usage to beretrieved can be specified as above, or the usercan choose to fill in the report_type field andspecify the report_idasHID_REPORT_ID_UNKNOWN. In this case,the hiddev_usage_ref will be filled in with the report and field infomation associated with this usage if it is found.HIDIOCSU SAGE struct hiddev_usage_ref(write)Sets the value of a usage in an output report.1测试代码/*2Author : Andrew Huang <bluedrum@>3<<Care and feeding of your Human Interface Devices>>4/source/Documentation/usb/hiddev.txt?v=2.6.30 5/hiddev/6*/7#include <stdio.h>8#include <stdlib.h>9#include <string.h>10#include <sys/types.h>11#include <sys/stat.h>12#include <fcntl.h>13#include <time.h>14#include <sys/ioctl.h>15#include <linux/hiddev.h>1617static void showReports(int fd, unsigned report_type);18static void show_all_report(int fd);19static int read_event(int fd);2021int main()22{23char dev_name[64]="/dev/hiddev0";24int fd =-1;25int version;26char name[100];27struct hiddev_devinfo dinfo;282930fd = open(dev_name,O_RDWR);31if(fd ==-1)32{33fprintf(stderr,"open %s failure\n",dev_name); 34return -1;35}363738printf("%s infor\n",dev_name);3940if(ioctl(fd, HIDIOCGVERSION,&version)< 0)41perror("HIDIOCGVERSION");42else43{44printf("HIDIOCGVERSION: %d.%d\n",(version>>16)&0xFFFF, version & 0xFFFF);45if(version != HID_VERSION)46printf("WARNING: version does not match compile-time version\n");47}4849if(ioctl(fd, HIDIOCGDEVINFO,&dinfo)< 0)50perror("HIDIOCGDEVINFO");51else52{53printf("HIDIOCGDEVINFO: bustype=%d busnum=%d devnum=%d ifnum=%d\n"54"\tvendor=0x%04hx product=0x%04hx version=0x%04hx\n" 55"\tnum_applications=%d\n",56dinfo.bustype, dinfo.busnum, dinfo.devnum, dinfo.ifnum,57dinfo.vendor,dinfo.product,dinfo.version, dinfo.num_applications);5960if(ioctl(fd, HIDIOCGNAME(99), name)< 0)61perror("HIDIOCGNAME");62else63{64name[99]= 0;65printf("HIDIOCGNAME: %s\n", name);66}6768#if 069printf("\n*** INPUT:\n"); showReports(fd, HID_REPORT_TYPE_INPUT); 70printf("\n*** OUTPUT:\n");showReports(fd, HID_REPORT_TYPE_OUTPUT);71printf("\n*** FEATURE:\n");showReports(fd, HID_REPORT_TYPE_FEATURE);72#endif73show_all_report(fd);7475read_event(fd);7677close(fd);798081}8283848586static void showReports(int fd, unsigned report_type)87{88struct hiddev_report_info rinfo;89struct hiddev_field_info finfo;90struct hiddev_usage_ref uref;91int i, j, ret;9293rinfo.report_type = report_type;94rinfo.report_id = HID_REPORT_ID_FIRST;95ret = ioctl(fd, HIDIOCGREPORTINFO,&rinfo);96while(ret >= 0)97{98printf("HIDIOCGREPORTINFO: report_id=0x%X (%u fields)\n", 99rinfo.report_id, rinfo.num_fields);100for(i = 0; i < rinfo.num_fields; i++)101{102finfo.report_type = rinfo.report_type;103finfo.report_id = rinfo.report_id;104finfo.field_index = i;105ioctl(fd, HIDIOCGFIELDINFO,&finfo);106107printf("HIDIOCGFIELDINFO: field_index=%u maxusage=%u flags=0x%X\n"108"\tphysical=0x%X logical=0x%X application=0x%X\n"109"\tlogical_minimum=%d,maximum=%dphysical_minimum=%d,maximum=%d\n",110finfo.field_index, finfo.maxusage, finfo.flags,111finfo.physical, finfo.logical, finfo.application,112finfo.logical_minimum, finfo.logical_maximum,113finfo.physical_minimum, finfo.physical_maximum);114115for(j = 0; j < finfo.maxusage; j++)116{117uref.report_type = finfo.report_type;118uref.report_id = finfo.report_id;119uref.field_index = i;age_index = j;121ioctl(fd, HIDIOCGUCODE,&uref);122ioctl(fd, HIDIOCGUSAGE,&uref);123124printf(" >> usage_index=%u usage_code=0x%X () value=%d\n", age_index,age_code,127//controlName(age_code),128uref.value);129130}131}132printf("\n");133134rinfo.report_id |= HID_REPORT_ID_NEXT;135ret = ioctl(fd, HIDIOCGREPORTINFO,&rinfo);136}137}138139140void show_all_report(int fd)141{142143struct hiddev_report_info rinfo;144struct hiddev_field_info finfo;145struct hiddev_usage_ref uref;146int rtype, i, j;147char *rtype_str;148149for(rtype = HID_REPORT_TYPE_MIN; rtype <= HID_REPORT_TYPE_MAX; 150rtype++){151switch (rtype){152case HID_REPORT_TYPE_INPUT: rtype_str ="Input"; break;153case HID_REPORT_TYPE_OUTPUT: rtype_str ="Output"; break;154case HID_REPORT_TYPE_FEATURE: rtype_str ="Feature"; break; 155default: rtype_str ="Unknown"; break;156}157fprintf(stdout,"Reports of type %s (%d):\n", rtype_str, rtype);158rinfo.report_type = rtype;159rinfo.report_id = HID_REPORT_ID_FIRST;160while(ioctl(fd, HIDIOCGREPORTINFO,&rinfo)>= 0){161fprintf(stdout," Report id: %d (%d fields)\n",162rinfo.report_id, rinfo.num_fields);163for(i = 0; i < rinfo.num_fields; i++){164memset(&finfo, 0, sizeof(finfo));165finfo.report_type = rinfo.report_type;166finfo.report_id = rinfo.report_id;167finfo.field_index = i;168ioctl(fd, HIDIOCGFIELDINFO,&finfo);169fprintf(stdout," Field: %d: app: %04x phys %04x " 170"flags %x (%d usages) unit %x exp %d\n", 171i, finfo.application, finfo.physical, finfo.flags, 172finfo.maxusage, finfo.unit, finfo.unit_exponent); 173memset(&uref, 0, sizeof(uref));174for(j = 0; j < finfo.maxusage; j++){175uref.report_type = finfo.report_type;176uref.report_id = finfo.report_id;177uref.field_index = i;age_index = j;179ioctl(fd, HIDIOCGUCODE,&uref);180ioctl(fd, HIDIOCGUSAGE,&uref);181fprintf(stdout," Usage: %04x val %d\n",age_code, uref.value);183}184}185rinfo.report_id |= HID_REPORT_ID_NEXT;187}188//if(!run_as_daemon)189fprintf(stdout,"Waiting for events ... (interrupt to exit)\n"); 190191}192193int read_event(int fd)194{195struct hiddev_event ev[64];196int i,rd;197time_t curr_time;198char name[100];199200while(1)201{202rd = read(fd, ev, sizeof(ev));203if(rd <(int) sizeof(ev[0])){204if(rd < 0)205perror("\nevtest: error reading");206207return -1;209210for(i = 0; i < rd / sizeof(ev[0]); i++){211//int idx = info_idx(ev[i].hid);212int idx = ev[i].hid;213curr_time =time(NULL);214strftime(name, sizeof(name),"%b %d %T",215localtime(&curr_time));216fprintf(stdout,"%s: Event: usage %x ( ), value %d\n", 217name, ev[i].hid,218/*(idx >= 0)? ups_info[idx].label :"Unknown",*/ 219ev[i].value);220}221222}223224return 0;225226}。
Linux如何使用libudev获取USB设备VID及PID
Linux如何使⽤libudev获取USB设备VID及PID在本⽂将使⽤libudev库来访问hidraw的设备。
通过libudev库,我们可以查询设备的⼚家ID(Vendor ID, VID),产品ID(Product ID, PID),序列号和设备字符串等⽽不需要打开设备。
进⼀步,libudev可以告诉我们在/dev⽬录下设备节点的具体位置路径,为应⽤程序提供⼀种具有⾜够鲁棒性⽽⼜和系统⼚家独⽴的访问设备的⽅式。
使⽤libudev库,需要包含libudev.h头⽂件,并且在编译时加上-ludev告诉编译器去链接udev库。
将列出当前连接在系统中的所有hidraw设备,并且输出它们的设备节点路径、⽣产商、序列号等信息。
为了获取这些信息,需要创建⼀个udev_enumerate对象,其中“hidraw”字符串作为过滤条件,libudev将返回所有匹配这个过滤字符串的udev_device对象。
这个列⼦的步骤如下:1、初始化库,获取⼀个struct udev句柄2、枚举设备3、对找到的匹配设备输出它的节点名称,找到实际USB设备的起始节点,打印出USB设备的IDs和序列号等,最后解引⽤设备对象4、解引⽤枚举对象5、解引⽤udev对象具体代码如下:#include <libudev.h>#include <stdio.h>#include <stdlib.h>#include <locale.h>#include <unistd.h>int main (void){struct udev *udev;struct udev_enumerate *enumerate;struct udev_list_entry *devices, *dev_list_entry;struct udev_device *dev;/* Create the udev object */udev = udev_new();if (!udev) {printf("Can't create udev\n");exit(1);}/* Create a list of the devices in the 'hidraw' subsystem. */enumerate = udev_enumerate_new(udev);udev_enumerate_add_match_subsystem(enumerate, "hidraw");udev_enumerate_scan_devices(enumerate);devices = udev_enumerate_get_list_entry(enumerate);/* For each item enumerated, print out its information.udev_list_entry_foreach is a macro which expands toa loop. The loop will be executed for each member indevices, setting dev_list_entry to a list entrywhich contains the device's path in /sys. */udev_list_entry_foreach(dev_list_entry, devices) {const char *path;/* Get the filename of the /sys entry for the deviceand create a udev_device object (dev) representing it */path = udev_list_entry_get_name(dev_list_entry);dev = udev_device_new_from_syspath(udev, path);/* usb_device_get_devnode() returns the path to the device nodeitself in /dev. */printf("Device Node Path: %s\n", udev_device_get_devnode(dev));/* The device pointed to by dev contains information aboutthe hidraw device. In order to get information about theUSB device, get the parent device with thesubsystem/devtype pair of "usb"/"usb_device". This willbe several levels up the tree, but the function will findit.*/dev = udev_device_get_parent_with_subsystem_devtype(dev,"usb","usb_device");if (!dev) {printf("Unable to find parent usb device.");exit(1);}/* From here, we can call get_sysattr_value() for each filein the device's /sys entry. The strings passed into thesefunctions (idProduct, idVendor, serial, etc.) corresponddirectly to the files in the directory which representsthe USB device. Note that USB strings are Unicode, UCS2encoded, but the strings returned fromudev_device_get_sysattr_value() are UTF-8 encoded. */printf(" VID/PID: %s %s\n",udev_device_get_sysattr_value(dev,"idVendor"),udev_device_get_sysattr_value(dev, "idProduct"));printf(" %s\n %s\n",udev_device_get_sysattr_value(dev,"manufacturer"),udev_device_get_sysattr_value(dev,"product"));printf(" serial: %s\n",udev_device_get_sysattr_value(dev, "serial"));udev_device_unref(dev);}/* Free the enumerator object */udev_enumerate_unref(enumerate);udev_unref(udev);return 0;}编译程序:gcc -Wall -g -o udev_example udev_example.c -ludev以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
符合hid标准的用户控制设备
符合hid标准的用户控制设备符合HID标准的用户控制设备。
随着科技的不断发展,人们对于用户控制设备的需求也日益增加。
而符合HID标准的用户控制设备,正是能够满足人们需求的一种先进技术。
HID,即Human Interface Device,是一种能够让人与电脑进行交互的设备,如键盘、鼠标、游戏手柄等。
那么,符合HID标准的用户控制设备具有怎样的特点呢?首先,符合HID标准的用户控制设备具有良好的兼容性。
无论是在Windows、Mac还是Linux系统下,这些设备都能够完美地进行兼容,不需要安装额外的驱动程序,即插即用。
这为用户带来了极大的便利,不再需要为了设备的兼容性而烦恼。
其次,这些设备具有高度的稳定性和可靠性。
符合HID标准的用户控制设备经过严格的测试和认证,确保在长时间的使用中不会出现故障或者不稳定的情况。
用户可以放心地使用这些设备,不必担心出现意外情况导致工作中断。
另外,这些设备在性能上也有很大的提升。
符合HID标准的用户控制设备采用了先进的传感技术和信号处理技术,能够实现更加精准的操作和更加流畅的体验。
无论是在办公、游戏还是其他领域,都能够得到更好的用户体验。
除此之外,符合HID标准的用户控制设备还具有良好的人体工程学设计。
这些设备在外形设计、按键布局等方面都经过了精心的设计,能够更好地适应人体的使用习惯,减少用户的疲劳感,提高工作效率。
总的来说,符合HID标准的用户控制设备在兼容性、稳定性、性能和人体工程学设计等方面都具有明显的优势,能够为用户带来更好的使用体验。
随着科技的不断进步,相信这些设备在未来会有更加广阔的应用前景。
Linux-HID
Table of Contents
I. How Linux handles USB HID devices..........................................................................7 1. Introduction ..............................................................................................................7 The Universal Serial Bus....................................................................................7 Host Controllers..................................................................................................7 USB Devices and Transfer Characteristics ......................................................7 USB Device Drivers ............................................................................................9 2. Configuring Linux HID support..........................................................................11 USB subsystem..................................................................................................11 Input subsystem................................................................................................11 3. The HID device interface ......................................................................................13 What is the hiddev interface ...........................................................................13 How HID devices relate to the hiddev interface..........................................13 Getting the version of the hiddev interface ..................................................13 Getting information about the HID device...................................................14 Determining which Applications a device uses...........................................15 Reading from the HID device interface.........................................................16 4. The event interface .................................................................................................17 How HID relates to the event interface .........................................................17 Getting the version of the evdev interface ....................................................17 Getting information about the HID device identity ....................................18 Determining the device capabilities and features........................................19 Getting user input from the device ................................................................24 Sending information to the device .................................................................25 Modifying key repeat settings ........................................................................25 5. Other approaches to Linux HID support............................................................27 The keyboard interface ....................................................................................27 The mouse interface .........................................................................................27 The joystick interface........................................................................................27 A new kernel interface .....................................................................................27
hid标准键盘
hid标准键盘
HID标准键盘。
HID标准键盘是一种基于HID(Human Interface Device)协议
的键盘设备,它在计算机及其他电子设备中具有广泛的应用。
HID
标准键盘采用了一系列标准化的协议和规范,使得它可以与各种操
作系统和设备进行兼容,并且具有良好的稳定性和可靠性。
首先,HID标准键盘具有良好的通用性。
由于其采用了HID协议,因此它可以在不同的操作系统中进行使用,包括Windows、Mac OS、Linux等。
无论是在个人电脑、笔记本电脑还是其他智能设备上,HID标准键盘都可以轻松地进行连接和使用,为用户带来便利。
其次,HID标准键盘具有良好的稳定性和可靠性。
在设计和制
造过程中,HID标准键盘采用了严格的质量控制标准,确保产品的
稳定性和可靠性。
无论是长时间的敲击操作,还是频繁的连接拔插,HID标准键盘都能够保持良好的性能,不会出现卡键、漏键等问题,保障用户的使用体验。
此外,HID标准键盘还具有良好的响应速度和舒适的手感。
在
键盘的设计中,HID标准键盘充分考虑了按键的触感和反馈,使得用户在使用过程中能够得到良好的按键体验。
无论是办公工作还是游戏娱乐,HID标准键盘都能够满足用户对于按键手感和响应速度的需求,提高工作效率和游戏体验。
总的来说,HID标准键盘作为一种基于HID协议的键盘设备,具有良好的通用性、稳定性和可靠性,同时还具有良好的响应速度和舒适的手感。
无论是在办公还是娱乐中,HID标准键盘都能够为用户带来良好的使用体验。
随着科技的不断发展,相信HID标准键盘在未来会有更广阔的应用前景,为用户带来更多的便利和乐趣。
hid 协议
hid 协议HID(Human Interface Device)是一种用于计算机和外部设备之间进行通信的协议,它允许人们通过各种输入设备例如键盘、鼠标、游戏控制器等来与计算机进行交互。
HID协议是一种通用的协议,广泛应用于各种消费电子产品和工业自动化设备中。
HID协议定义了一系列标准化的命令和数据格式,使得各种设备可以通过共同的协议来进行通信。
通过HID协议,外部设备可以向计算机发送各种输入数据,例如按键信息、鼠标移动信息、传感器数据等。
计算机通过解析这些数据来理解用户的操作意图,从而进行相应的响应。
HID协议具有以下特点:1. 简单易用:HID协议定义了一系列简单明了的命令和数据格式,使得设备开发者可以轻松地将各种输入设备与计算机进行连接。
设备驱动程序和操作系统也提供了相应的支持,使得设备的安装和使用变得十分方便。
2. 多设备并行:HID协议允许多个设备同时连接到计算机,而不需要为每个设备分配独立的端口。
这意味着用户可以同时使用多个输入设备,提高了操作的便利性和效率。
3. 可扩展性:HID协议可以根据具体的应用需求进行扩展,以满足不同设备的特殊需求。
例如,游戏控制器可以使用HID协议的标准命令和数据格式来进行基本的交互,同时还可以定义一些专用命令和数据格式,以实现更高级的功能。
4. 兼容性:HID协议的标准化使得设备可以在不同的平台和操作系统上进行通用的使用。
无论是Windows、Mac还是Linux 系统,都提供了相应的支持,使得用户可以随意选择不同的操作系统来满足自己的需求。
总之,HID协议是一种简单易用、多设备并行、可扩展、兼容性强的协议,广泛应用于各种消费电子产品和工业自动化设备中。
它的出现使得人们可以更加方便、高效地与计算机进行交互,极大地提升了用户体验和工作效率。
未来,随着物联网技术的发展和智能设备的普及,HID协议将扮演更加重要的角色。
人们可以通过各种智能设备来与计算机和其他设备进行交互,从而实现更为智能化和便捷化的生活。
hid标准键盘什么意思
hid标准键盘什么意思HID标准键盘是指采用HID(Human Interface Device)协议的标准键盘。
HID 是一种通用的设备通信协议,它允许计算机与外部设备(如键盘、鼠标、游戏手柄等)进行通信和交互。
因此,HID标准键盘是指符合HID协议的键盘,它可以通过USB接口连接到计算机,并且可以直接被操作系统识别,无需安装额外的驱动程序。
HID标准键盘通常具有以下特点:1. 插即用,HID标准键盘可以实现即插即用的功能,即插入计算机的USB接口后,操作系统会自动识别并安装相应的驱动程序,无需用户手动安装。
2. 兼容性好,由于HID是一个通用的设备通信协议,因此符合HID协议的键盘可以在不同的操作系统上使用,如Windows、Mac OS、Linux等,而且不同的厂商生产的HID标准键盘也可以实现通用性。
3. 简化开发,对于设备厂商来说,采用HID协议可以简化设备的开发流程,因为不需要开发特定的驱动程序,而是直接利用操作系统提供的通用驱动程序进行通信。
4. 低成本,由于HID标准键盘无需额外的驱动程序和复杂的通信协议,因此可以降低设备的成本,使得HID标准键盘在市场上具有一定的竞争优势。
HID标准键盘在实际应用中具有广泛的用途,主要体现在以下几个方面:1. 个人电脑,作为最常见的外部输入设备,HID标准键盘广泛应用于个人电脑上,用户可以通过键盘进行文字输入、快捷键操作等。
2. 工作站,在一些专业的工作场景中,HID标准键盘也扮演着重要的角色,如金融交易员、程序员、设计师等,他们对键盘的输入效率和稳定性有较高的要求。
3. 游戏设备,许多游戏玩家对键盘的反应速度和手感有较高的要求,因此一些专为游戏设计的HID标准键盘也受到了玩家的青睐。
4. 工业控制,在工业自动化控制领域,HID标准键盘也被广泛应用,用于控制设备、输入指令等操作。
总的来说,HID标准键盘作为一种通用的输入设备,具有诸多优点,如插即用、兼容性好、简化开发、低成本等,因此在各个领域都有着广泛的应用前景。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
struct HIDIOCGREPORTINFO hiddev_report_info (read/write)
with a report in a hiddev_field_info structure. The user must struct hiddev_field_info fill in report_id and HIDIOCGFIELDINFO report_type in this (read/write) structure, as above. The field_index should also be filled in, which should be a number from 0 and maxfield-1, as returned from a previous HIDIOCGREPORTINFO call. Returns the usage_code in a hiddev_usage_ref structure, given that given its report type, struct hiddev_usage_ref HIDIOCGUCODE report id, field index, (read/write) and index within the field have already been filled into the structure. Returns the value of a usage in a hiddev_usage_ref structure. The usage to be retrieved can be specified as above, or the user can choose to fill in the report_type struct hiddev_usage_ref field and specify the HIDIOCGUSAGE (read/write) report_id asHID_REPORT_ID_UNKNOWN. In this case, the hiddev_usage_ref will be filled in with the report and field infomation associated with this usage if it is found.
ห้องสมุดไป่ตู้
HIDIOCSREPORT
struct hiddev_report_info (write)
throughHIDIOCSUSAGE calls (below) to fill in individual usage values in the report before sending the report in full to the device. Fills in a hiddev_report_info structure for the user. The report is looked up by type (input, output or feature) and id, so these fields must be filled in by the user. The ID can be absolute - the actual report id as reported by the device -- or relative -HID_REPORT_ID_FIRST for the first report, and (HID_REPORT_ID_NEXT | report_id) for the next report after report_id. Without a-priori information about report ids, the right way to use this ioctl is to use the relative IDs above to enumerate the valid IDs. The ioctl returns non-zero when there is no more next ID. The real report ID is filled into the returned hiddev_report_info structure. Returns the field information associated
HIDIOCGVERSION int (read) Gets the version code out of the hiddev driver. This ioctl call returns the HID application usage associated with the hid device. The third argument to ioctl() specifies which application index to get. This is useful when the device has more than one application collection. If the index is invalid (greater or equal to the number of application collections this device has) the ioctl returns -1. You
对此设备结点的处理有两种接口,一种是read(),另一种是ioctl();
read(): This is the event interface. When the HID device performs an interrupt transfer, indicating a change of state, data will be made available at the associated hiddev device with the content of a struct hiddev_event:struct hiddev_event { unsigned hid; signed int value; }; containing the HID usage identifier for the status that changed, and the value that it was changed to. ioctl(): This is the control interface. There are a number of controls:
HIDIOCAPPLICATION(none)
can find out beforehand how many application collections the device has from the num_applications field from the hiddev_devinfo structure. Gets a hiddev_devinfo struct hiddev_devinfo HIDIOCGDEVINFO structure which (read) describes the device. Gets a string descriptor from the device. The struct struct caller must fill in the HIDIOCGSTRING hiddev_string_descriptor "index" field to (read/write) indicate which descriptor should be returned. Instructs the kernel to retrieve all input and feature report values from the device. At this point, all the usage HIDIOCINITREPORT structures will contain current values for the device, and will maintain it as the device changes. HIDIOCGNAME string (variable length)Gets the device name Instructs the kernel to get a feature or input struct report from the device, HIDIOCGREPORT hiddev_report_info in order to selectively (write) update the usage structures (in contrast to INITREPORT). Instructs the kernel to send a report to the device. This report can be filled in by the user
HIDIOCSUSAGE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
struct hiddev_usage_ref Sets the value of a usage in an output (write) report.
Linux下HID 设备,如果非标准的输入设备 (Keypad/MOUSE/JoyStick/input event device). 将会把信息转入hid device的设备结点。 这一点可以参见内核的关于hiddev的文档 /source/Documentation/usb/hiddev.txt?v=2.6.30 它在 Documentation/usb/hiddev.txt 目录下,大致有这样一个流程, usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event] | | --> hiddev.c ----> POWER / MONITOR CONTROL 关于操作非标准的HID设备,可以参见如下文档. /hiddev/ 在设备文件系统中,会产生的/dev/hiddev0这样的结点,这类设备主设 备号为 180,从设备号最低为96 Cat /proc/device | grep hiddev mknod /dev/hiddev0 c 180 96 mknod /dev/hiddev1 c 180 97 mknod /dev/hiddev2 c 180 98 mknod /dev/hiddev3 c 180 99 ... mknod /dev/hiddev15 c 180 111