linux看鼠标设备描述符,浅析linux下usb鼠标和usb键盘usbhid驱动hid_parse_report报告描述符...

浅析linux下usb鼠标和usb键盘usbhid驱动hid_parse_report报告描述符解析

hid_probe

==>usb_hid_configure

==*>hid = hid_parse_report(rdesc, n)

/*

* Parse a report description into a hid_device structure. Reports are

* enumerated, fields are attached to these reports.

*/

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;

if (!(device->collection = kzalloc(sizeof(struct hid_collection) *

HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {

// #define HID_DEFAULT_NUM_COLLECTIONS    16

// 默认申请16个项内存

kfree(device);

return NULL;

}

device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; // 默认16项

for (i = 0; i < HID_REPORT_TYPES; i++)

INIT_LIST_HEAD(&device->report_enum[i].report_list);

// 报告描述符不会很大,所以kmalloc申请(kmalloc申请上限为2M)

if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) {

kfree(device->collection);

kfree(device);

return NULL;

}

memcpy(device->rdesc, start, size); // 将从设备读取上来报告描述符永久拷贝到device->rdesc中[luther.gliethttp]

device->rsize = size; // 记录报告描述符实际大小.

// struct hid_parser该结构体可是一个耗费内存大户,只能使用vmalloc申请只需虚拟地址连续的内核内存[luther.gliethttp]

// 当parser完报告描述符之后,会vfree释放掉,所以也只是生命期较短暂的占用一会内存[luther.gliehttp]

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; // 该parser需要对该device的报告描述符作解析

end = start + size;

// 从设备报告描述符中读取一个item项

while ((start = fetch_item(start, end, &item)) != NULL) {

if (item.format != HID_ITEM_FORMAT_SHORT) {

// 现在Long item项还没有使用,所以这里不支持

dbg_hid("unexpected long global item\n");

hid_free_device(device);

vfree(parser);

return NULL;

}

// 是我们所能支持的Short Item项,数据有0字节,1字节,2字节或者4字节等4中情况[luther.gliethttp]

// 比如0x05, 0x01, // USAGE_PAGE (Generic Desktop)

// 从fetch_item中我们知道,item.type = (0x05 >> 2) & 0x03 = 1;[luther.gliehttp]

// 所以将调用hid_parser_global处理函数.

// hid_parser_global    0x05, 0x01, // USAGE_PAGE (Generic Desktop)

// hid_parser_local     0x09, 0x02, // USAGE (Mouse)

// hid_parser_main      0xa1, 0x01, // COLLECTION (Application)

// hid_parser_local     0x09, 0x01, //   USAGE (Pointer)

// hid_parser_main      0xa1, 0x00, //   COLLECTION (Physical)

// hid_parser_global    0x05, 0x09, //     USAGE_PAGE (Button)

// hid_parser_local     0x19, 0x01, //     USAGE_MINIMUM (Button 1)

// ......

if (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) {

// 入栈操作多于出栈操作,比如

// COLLECTION (Application)就是入栈

// END_COLLECTION对应出栈

// 目前定义堆栈大小为4个

// #define HID_COLLECTION_STACK_SIZE 4

// 所以报告描述符脚本书写有误,返回NULL,失败[luther.gliethttp]

dbg_hid("unbalanced collection at end of report description\n");

hid_free_device(device);

vfree(parser);

return NULL;

}

if (parser->local.delimiter_depth) {

// 该变量也是通过入栈,出栈收集的,所以也必须配对[luther.giehtttp]

dbg_hid("unbalanced delimiter at end of report description\n");

hid_free_device(device);

vfree(parser);

return NULL;

}

vfree(parser); // 正常解析,释放vmalloc到的parser解释器结构体内存.

return device;

}

}

// 报告描述脚本有误[luther.gliehttp]

dbg_hid("item fetching failed at offset %d\n", (int)(end - start));

hid_free_device(device);

vfree(parser);

return NULL;

}

/*

* Fetch a report description item from the data stream. We support long

* items, though they are not used yet.

*/

static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)

{

u8 b;

if ((end - start) <= 0)

return NULL;

b = *start++; // 取出第1个开始字节,比如0x05, 0x01, --- USAGE_PAGE (Generic Desktop)

item->type = (b >> 2) & 3; // 取出类型[luther.gliethttp]

item->tag  = (b >> 4) & 15;// 取出tag信息

if (item->tag == HID_ITEM_TAG_LONG) {

// Long items: 3 – 258 bytes in length; used for items that require larger data

//             structures for parts.

item->format = HID_ITEM_FORMAT_LONG;

if ((end - start) < 2) // 空间不足,b算1个字节,所以至少保证还要2字节,才能到3个字节以上[luther.gliethttp]

// 0字节 -- b

// 1字节 -- 该Long itme的大小

// 2字节 -- tag信息[luther.gliethttp]

// 3字节 -- 有效数据开始

return NULL;

item->size = *start++;

item->tag  = *start++;

if ((end - start) < item->size) // 保证该Long item拥有所需的足够数据[luther.gliehttp]

return NULL;

item->data.longdata = start; // 从第4个字节开始就是数据区

start += item->size;    // start指向下一个item开始处[luther.gliethttp]

return start;

}

// Short items: 1 – 5 bytes total length; used for the most commonly occurring

//              items. A short item typically contains 1 or 0 bytes of optional data.

item->format = HID_ITEM_FORMAT_SHORT;

item->size = b & 3; // b算一个字节+0-3字节

switch (item->size) {

case 0:

return start; // 没有数据区,start指向下一个item开始处

case 1:

if ((end - start) < 1)

return NULL;

item->data.u8 = *start++; // 取出1字节数据

return start;

case 2:

if ((end - start) <

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值