USB鼠标实现——HID 报告的返回

Posted tyustli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了USB鼠标实现——HID 报告的返回相关的知识,希望对你有一定的参考价值。

文章目录

HID 报告的返回

仓库地址

仓库地址

USB 鼠标阅读顺序

报告返回

根据 HID 报告描述符 中设置的报告,返回 5 字节数据

typedef struct __attribute__ ((packed))

    uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
    int8_t  x;       /**< Current delta x movement of the mouse. */
    int8_t  y;       /**< Current delta y movement on the mouse. */
    int8_t  wheel;   /**< Current delta wheel movement on the mouse. */
    int8_t  pan;     // using AC Pan
 hid_mouse_report_t;

USB 端点数据分析

0x0 0x5 0x5 0x0 0x0
  • buttons:0x00
    • 鼠标左键是否按下 0 表示没有按下
  • x:0x05
    • x 轴移动量
  • y:0x05
    • y 轴移动量
  • whell:0x00
    • 滚轮移动量
  • pan:0x00
    • AC pan

配置描述符集合 中设置的端点地址为 0x81 ,bit7 位表示数据方向,输入端点 D7 为 1。所以输入端点 1 的地址为 0x81。

将上述报告通过端点返回即可。

浅析usbhid驱动如何源源不断的获取usb鼠标

参考技术A 浅析usbhid驱动如何源源不断的获取usb鼠标数据

hid_probe
==>usb_hid_configure
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize, // 首先申请interrupt urb内存,并填充下面的有效数据
// 后面的hid_start_in()函数会usb_submit_urb提交该urb,到
// usb host控制器,进而发送interrupt in事物到hid设备[鼠标或键盘]
hid_irq_in, hid, interval); // hid_irq_in为interrupt中断管道数据处理回调函数
// urb->complete = hid_irq_in;
// interval为usbhid driver需要每隔interval毫秒
// 产生一次in读取动作,这只是一个理论上的东西[luther.gliethttp]
// 实际上该interval数值,仅仅用来usb host管理interrupt类型总线带宽
// 时,作为调整系数之一而已,[luther.gliethttp]
// 真正通信是这样的,对该urb执行一次usb_submit_urb()操作,
// 那么usb host将等待interrupt数据返回,如果hid物理设备没有
// 向它的interrupt端点填入指定大小的数据,那么
// usb host将一直等待,直到hid物理设备将指定个数的数据填入
// 它的interrupt端点为止,于是usb host将触发中断,
// 通知usb_submit_urb提交的interrupt类型的urb有数据回来了,
// 同时该urb生命终结,如果不再执行usb_submit_urb提交动作,再次等待
// 下一次interrupt数据到来的话,那么usbhid.ko将只得到
// 一次数据,[luther.gliethttp]
// 于是hid_irq_in函数将被执行,幸运的是,
// hid_irq_in函数中确实又调用了usb_submit_urb,再次将
// 该urb添加usb host事件中,等待下一次hid设备产生数据上传,然后再次调用到这里hid_irq_in处理数据,
// 如果强行将hid_irq_in函数中的usb_submit_urb屏蔽掉,
// 我们可以通过kernel klog看到,鼠标数据只会产生一个[luther.gliethttp]
static void hid_irq_in(struct urb *urb)

struct hid_device *hid = urb->context;
struct usbhid_device *usbhid = hid->driver_data;
int status;

switch (urb->status)
case 0: /* success */
usbhid->retry_delay = 0;
hid_input_report(urb->context, HID_INPUT_REPORT, // 提交到更高一级的驱动层处理urb->transfer_buffer数据
urb->transfer_buffer, // 下面是截获的urb->transfer_buffer数据内容,对于我的mouse,每次都是4个字节:
urb->actual_length, 1); // [13602.612302] 00 fe 00 00
break; // [13602.868282] 01 00 00 00
case -EPIPE: /* stall */ // [13602.964277] 00 00 00 00
clear_bit(HID_IN_RUNNING, &usbhid->iofl); // [13603.860290] 04 00 00 00
set_bit(HID_CLEAR_HALT, &usbhid->iofl); // [13604.052288] 00 00 00 00
schedule_work(&usbhid->reset_work); // [13605.332295] 02 00 00 00
return; // [13605.460297] 00 00 00 00
case -ECONNRESET: /* unlink */ // [13605.812292] 00 f9 01 00
case -ENOENT: // [13605.876280] 00 ff 00 00
case -ESHUTDOWN: /* unplug */
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
return;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
case -ETIME: /* protocol error or unplug */
case -ETIMEDOUT: /* Should never happen, but... */
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
hid_io_error(hid);
return;
default: /* error */
warn("input irq status %d received", urb->status);


status = usb_submit_urb(urb, GFP_ATOMIC); // 再次将该urb提交到usb host上,
if (status) // 这样才能继续读取下一次鼠标数据[luther.gliethttp]
clear_bit(HID_IN_RUNNING, &usbhid->iofl); // 如果将status = usb_submit_urb(urb, GFP_ATOMIC);注释掉
if (status != -EPERM) // 那么表示urb生命就真的终结在这次了,不会再读到mouse数据了.
err_hid("can't resubmit intr, %s-%s/input%d, status %d", // 因为没有任何urb让usb host做读取mouse的interrupt管道[luther.gliethttp].
hid_to_usb_dev(hid)->bus->bus_name,
hid_to_usb_dev(hid)->devpath,
usbhid->ifnum, status);
hid_io_error(hid);




那hid_irq_in什么时候被调用呢,来看看,对hid_irq_in的调用直接来自物理irq中断[luther.gliethttp]

drivers/usb/host/ohci-s3c2410.c|455| .urb_enqueue = ohci_urb_enqueue,
drivers/usb/host/ohci-ep93xx.c|132| .urb_enqueue = ohci_urb_enqueue
drivers/usb/host/ohci-at91.c|250| .urb_enqueue = ohci_urb_enqueue,
static const struct hc_driver ohci_at91_hc_driver =
.description = hcd_name,
.product_desc = "AT91 OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),

/*
* generic hardware linkage
*/
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,

/*
* basic lifecycle operations
*/
.start = ohci_at91_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,

/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,

/*
* scheduling support
*/
.get_frame_number = ohci_get_frame,

/*
* root hub support
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
.start_port_reset = ohci_start_port_reset,
;

static struct platform_driver ohci_hcd_at91_driver =
.probe = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_hcd_at91_drv_suspend,
.resume = ohci_hcd_at91_drv_resume,
.driver =
.name = "at91_ohci",
.owner = THIS_MODULE,
,
;
ohci_hcd_at91_drv_probe
==> usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
==*> usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED); // pdev->resource[1].start等于irqnum中断号[luther.gliethttp]
==**> request_irq(irqnum, &usb_hcd_irq, irqflags, hcd->irq_descr, hcd) // 注册物理中断处理函数usb_hcd_irq

所以当usb host有数据或者异常时就会产生物理irq中断,随后kernel调用到usb_hcd_irq中断处理函数
usb_hcd_irq
==> hcd->driver->irq (hcd);即ohci_irq
==> ohci_irq
==*> dl_done_list (ohci);
==**> takeback_td(ohci, td);
==***> finish_urb(ohci, urb, status); // 如果ed->td_list.next链表上没有任何控制管道,bulk等数据发送时,调用该函数[luther.gliethtt]
==****> usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
==*****> urb->complete (urb);即hid_irq_in // 调用回调函数, hid_irq_in会调用usb_submit_urb(urb, GFP_ATOMIC);
// 再次让usb host等待hid硬件设备的interrupt数据到来.[luther.gliethttp]
参考技术B 当然是不断的读取了。

以上是关于USB鼠标实现——HID 报告的返回的主要内容,如果未能解决你的问题,请参考以下文章

USB HID描述符

浅析USB HID ReportDesc (HID报告描述符)

求救!!usb hid设备(模拟键盘)遇到的问题

USB HID多点触控串行报告

HID 报告请求

浅析usbhid驱动如何源源不断的获取usb鼠标