现在又要把local中的内容清零了
好~ 到下一组0x95, 0x01
这里为全局项目,用途为修改项的数目
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;
}
return 0;
下一组为0x75, 0x05
这是一个全局项目,用于修改项的大小为5bit
case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
//检测是否超过32个bit,也就是4个字节
if ((parser->global.report_size = item_udata(item)) > 32) {
dbg_hid("invalid report_size %d\n", parser->global.report_size);
return -1;
}
return 0;
接着下一组为0x81, 0x03
这是一个主项目, 用于将设置好的项目信息添加到域中
case HID_MAIN_ITEM_TAG_INPUT:
ret = hid_add_field(parser, HID_INPUT_REPORT, data);
break;
添加完成后的数据结构图如下
咋看之下和之前的没什么不同,但是请注意report中的size,这里就变成8了~
也就是说我们所需要的占位效果出来了,之后的域数会从第9位开始读取
local继续被清0~
好` 下一组0x05, 0x01
这是一个全局项目,用于设置全局用途
case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
parser->global.usage_page = item_udata(item);
return 0;
接着下一组0x09, 0x30
这是一个局域项目,用于设置用途
case HID_LOCAL_ITEM_TAG_USAGE:
if (parser->local.delimiter_branch > 1) {
dbg_hid("alternative usage ignored\n");
return 0;
}
//检测数据的大小是否小于或者等于2字节
if (item->size = 2)
//加上作用标记
data = (parser->global.usage_page 16) + data;
return hid_add_usage(parser, data);
下一组0x09, 0x31
这是一个局域项目,用于设置用途
case HID_LOCAL_ITEM_TAG_USAGE:
if (parser->local.delimiter_branch > 1) {
dbg_hid("alternative usage ignored\n");
return 0;
}
//检测数据的大小是否小于或者等于2字节
if (item->size = 2)
//加上作用标记
data = (parser->global.usage_page 16) + data;
return hid_add_usage(parser, data);
下一组0x09, 0x38
这是一个局域项目,用于设置用途
case HID_LOCAL_ITEM_TAG_USAGE:
if (parser->local.delimiter_branch > 1) {
dbg_hid("alternative usage ignored\n");
return 0;
}
//检测数据的大小是否小于或者等于2字节
if (item->size = 2)
//加上作用标记
data = (parser->global.usage_page 16) + data;
return hid_add_usage(parser, data);
下一组0x15, 0x81
这是一个全局项目,用于设置逻辑最小值
case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
parser->global.logical_minimum = item_sdata(item);
return 0;
下一组0x25, 0x7f
这是一个全局项目,用于设置逻辑最大值
case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
//检测是否需要符号来表示负数
if (parser->global.logical_minimum 0)
parser->global.logical_maximum = item_sdata(item);
else
parser->global.logical_maximum = item_udata(item);
return 0;
下一组0x75, 0x08
这是一个全局项目,用于设置单个项的所需要的bit数目
case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
//检测是否超过32个bit,也就是4个字节
if ((parser->global.report_size = item_udata(item)) > 32) {
dbg_hid("invalid report_size %d\n", parser->global.report_size);
return -1;
}
return 0;
下一组0x95, 0x03
这是一个全局项目,用于设置项的数目
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;
}
return 0;
下一组0x81, 0x06
这是一个主项目, 用于将设置好的项目信息添加到域中
case HID_MAIN_ITEM_TAG_INPUT:
ret = hid_add_field(parser, HID_INPUT_REPORT, data);
break;
添加好后的数据结构如下图
下一组0xc0
这是一个主项目,用于结束物理收集
case HID_MAIN_ITEM_TAG_END_COLLECTION:
ret = close_collection(parser);
break;
下一组0xc0
这是一个主项目,用于结束物理收集
case HID_MAIN_ITEM_TAG_END_COLLECTION:
ret = close_collection(parser);
break;
到这里报告描述符就分析完了,然后过河拆桥,卸磨杀驴,把parser结构给释放掉
回到usb_hid_configure中,之后根据端点描述符申请相应的in类型urb或者out类型urb,最后是控制类型的urb,配置完成的数据结构图如下
连向usb设备的结构和urb我就不画出来了
usb_hid_configure完成后来到usbhid_init_reports
但是usbhid_init_reports对于鼠标是没有作用的
因为他所调用的usbhid_submit_report函数中会判断怪癖是否有HID_QUIRK_NOGET
而所有的鼠标都会有HID_QUIRK_NOGET这个设置,所以直接返回
现在来到梦寐以求的hidinput_connect
hidinput_connect负责input子系统和hid设备的连接
hidinput_connect在/drivers/hid/hid-input.c中
int hidinput_connect(struct hid_device *hid)
{
struct hid_report *report;
struct hid_input *hidinput = NULL;
struct input_dev *input_dev;
int i, j, k;
int max_report_type = HID_OUTPUT_REPORT;
if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
return -1;
INIT_LIST_HEAD(&hid->inputs);
//寻找应用收集
for (i = 0; i hid->maxcollection; i++)
if (hid->collection.type == HID_COLLECTION_APPLICATION ||
hid->collection.type == HID_COLLECTION_PHYSICAL)
if (IS_INPUT_APPLICATION(hid->collection.usage))
break;
if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDINPUT) == 0)
return -1;
if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
max_report_type = HID_INPUT_REPORT;
//历遍应用收集对应的报告
for (k = HID_INPUT_REPORT; k = max_report_type; k++)
list_for_each_entry(report, &hid->report_enum[k].report_list, list)
{
if (!report->maxfield)
continue;
//检测是否已经分配
if (!hidinput)
{
//分配hid_input结构所需要的空间
hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
//分配一个input_dev结构
input_dev = input_allocate_device();
if (!hidinput || !input_dev)
{
kfree(hidinput);
input_free_device(input_dev);
err_hid("Out of memory during hid input probe");
goto out_unwind;
}
input_set_drvdata(input_dev, hid);
input_dev->event = hid->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
input_dev->getkeycode = hidinput_getkeycode;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
input_dev->uniq = hid->uniq;
input_dev->id.bustype = hid->bus;
input_dev->id.vendor = hid->vendor;
input_dev->id.product = hid->product;
input_dev->id.version = hid->version;
input_dev->dev.parent = hid->dev;
hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs);
}
//分析协议
for (i = 0; i report->maxfield; i++)
for (j = 0; j report->field->maxusage; j++)
hidinput_configure_usage(hidinput, report->field,
report->field->usage + j);
if (hid->quirks & HID_QUIRK_MULTI_INPUT)
{
/* This will leave hidinput NULL, so that it
* allocates another one if we have more inputs on
* the same interface. Some devices (e.g. Happ's
* UGCI) cram a lot of unrelated inputs into the
* same interface. */
hidinput->report = report;
if (input_register_device(hidinput->input))
goto out_cleanup;
hidinput = NULL;
}
}
//匹配input驱动
if (hidinput && input_register_device(hidinput->input))
goto out_cleanup;
return 0;
out_cleanup:
input_free_device(hidinput->input);
kfree(hidinput);
out_unwind:
/* unwind the ones we already registered */
hidinput_disconnect(hid);
return -1;
}
首先申请了一个input_dev结构并对其进行初始化,然后分析hid协议
分析工作由hidinput_configure_usage完成
hidinput_configure_usage在drivers/hid/hid-input.c中
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
{
struct input_dev *input = hidinput->input;
struct hid_device *device = input_get_drvdata(input);
int max = 0, code, ret;
unsigned long *bit = NULL;
field->hidinput = hidinput;
dbg_hid("Mapping: ");
hid_resolv_usage(usage->hid);
dbg_hid_line(" ---> ");
if (field->flags & HID_MAIN_ITEM_CONSTANT)
goto ignore;
/* only LED usages are supported in output fields */
if (field->report_type == HID_OUTPUT_REPORT &&
(usage->hid & HID_USAGE_PAGE) != HID_UP_LED)
{
dbg_hid_line(" [non-LED output field] ");
goto ignore;
}
/* handle input mappings for quirky devices */
ret = hidinput_mapping_quirks(usage, input, &bit, &max);
if (ret)
goto mapped;
//检测用途
switch (usage->hid & HID_USAGE_PAGE)
{
case HID_UP_BUTTON:
code = ((usage->hid - 1) & 0xf);
switch (field->application)
{
case HID_GD_MOUSE:
case HID_GD_POINTER: code += 0x110; break;
case HID_GD_JOYSTICK: code += 0x120; break;
case HID_GD_GAMEPAD: code += 0x130; break;
default:
switch (field->physical)
{
case HID_GD_MOUSE:
case HID_GD_POINTER: code += 0x110; break;
case HID_GD_JOYSTICK: code += 0x120; break;
case HID_GD_GAMEPAD: code += 0x130; break;
default: code += 0x100;
}
}
/* Special handling for Logitech Cordless Desktop */
if (field->application != HID_GD_MOUSE)
{
if (device->quirks & HID_QUIRK_LOGITECH_EXPANDED_KEYMAP)
{
int hid = usage->hid & HID_USAGE;
if (hid LOGITECH_EXPANDED_KEYMAP_SIZE && logitech_expanded_keymap[hid] != 0)
code = logitech_expanded_keymap[hid];
}
}
else
{
if (device->quirks & HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL)
{
int hid = usage->hid & HID_USAGE;
if (hid == 7 || hid == 8)
goto ignore;
}
}
map_key(code);
break;
case HID_UP_GENDESK:
if ((usage->hid & 0xf0) == 0x80)
{ /* SystemControl */
switch (usage->hid & 0xf)
{
case 0x1: map_key_clear(KEY_POWER); break;
case 0x2: map_key_clear(KEY_SLEEP); break;
case 0x3: map_key_clear(KEY_WAKEUP); break;
default: goto unknown;
}
break;
}
if ((usage->hid & 0xf0) == 0x90)
{ /* D-pad */
switch (usage->hid)
{
case HID_GD_UP: usage->hat_dir = 1; break;
case HID_GD_DOWN: usage->hat_dir = 5; break;
case HID_GD_RIGHT: usage->hat_dir = 3; break;
case HID_GD_LEFT: usage->hat_dir = 7; break;
default: goto unknown;
}
if (field->dpad)
{
map_abs(field->dpad);
goto ignore;
}
map_abs(ABS_HAT0X);
break;
}
switch (usage->hid)
{
/* These usage IDs map directly to the usage codes. */
case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
if (field->flags & HID_MAIN_ITEM_RELATIVE)
map_rel(usage->hid & 0xf);
else
map_abs(usage->hid & 0xf);
break;
case HID_GD_HATSWITCH:
usage->hat_min = field->logical_minimum;
usage->hat_max = field->logical_maximum;
map_abs(ABS_HAT0X);
break;
case HID_GD_START: map_key_clear(BTN_START); break;
case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
default: goto unknown;
}
break;
default:
unknown:
if (field->report_size == 1)
{
if (field->report->type == HID_OUTPUT_REPORT)
{
map_led(LED_MISC);
break;
}
map_key(BTN_MISC);
break;
}
if (field->flags & HID_MAIN_ITEM_RELATIVE)
{
map_rel(REL_MISC);
break;
}
map_abs(ABS_MISC);
break;
}
mapped:
if (device->quirks & HID_QUIRK_MIGHTYMOUSE)
{
if (usage->hid == HID_GD_Z)
map_rel(REL_HWHEEL);
else if (usage->code == BTN_1)
map_key(BTN_2);
else if (usage->code == BTN_2)
map_key(BTN_1);
}
if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 |
HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) &&
(usage->code == REL_WHEEL))
set_bit(REL_HWHEEL, bit);
if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
|| ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
goto ignore;
if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) &&
usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
field->flags &= ~HID_MAIN_ITEM_RELATIVE;
set_bit(usage->type, input->evbit);
if (device->quirks & HID_QUIRK_DUPLICATE_USAGES &&
(usage->type == EV_KEY ||
usage->type == EV_REL ||
usage->type == EV_ABS))
clear_bit(usage->code, bit);
//检测是否大于最大值
//检测位图中的位是否已经占用,无占用则置这个位为1
while (usage->code = max && test_and_set_bit(usage->code, bit))
//已占用则寻找下一个为空的位
usage->code = find_next_zero_bit(bit, max + 1, usage->code);
if (usage->code > max)
goto ignore;
if (usage->type == EV_ABS)
{
int a = field->logical_minimum;
int b = field->logical_maximum;
if ((device->quirks & HID_QUIRK_BADPAD) &&
(usage->code == ABS_X || usage->code == ABS_Y))
{
a = field->logical_minimum = 0;
b = field->logical_maximum = 255;
}
if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
else
input_set_abs_params(input, usage->code, a, b, 0, 0);
}
if (usage->type == EV_ABS &&
(usage->hat_min usage->hat_max || usage->hat_dir))
{
int i;
for (i = usage->code; i usage->code + 2 && i = max; i++)
{
input_set_abs_params(input, i, -1, 1, 0, 0);
set_bit(i, input->absbit);
}
if (usage->hat_dir && !field->dpad)
field->dpad = usage->code;
}
/* for those devices which produce Consumer volume usage as relative,
* we emulate pressing volumeup/volumedown appropriate number of times
* in hidinput_hid_event()
*/
if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
(usage->code == ABS_VOLUME))
{
set_bit(KEY_VOLUMEUP, input->keybit);
set_bit(KEY_VOLUMEDOWN, input->keybit);
}
if (usage->type == EV_KEY)
{
set_bit(EV_MSC, input->evbit);
set_bit(MSC_SCAN, input->mscbit);
}
hid_resolv_event(usage->type, usage->code);
dbg_hid_line("\n");
return;
ignore:
dbg_hid_line("IGNORED\n");
return;
}
我们以第一个域中的第一个项为例进行分析
首先判断其用途,这里usage->hid为0x90001,呢么就会到case HID_UP_BUTTON 中
然后hid-1,取其最低4位,90001-1为90000,最低4位为0,呢么code就是0了
然后检测域中 的application属性,这里为0x10002,呢么就是case HID_GD_MOUSE,
code += 0x110,呢么现在code现在为0x110,然后检测是否为罗技的产品,我们显然不是,然后到map_key(code),map_key是一个宏
#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
这就是他的宏定义
我们这里需要注意的是bit = input->keybit和max = KEY_MAX这两个
然后到set_bit(usage->type, input->evbit),这里就要注意了,先看看evbit是什么
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
EV_CNT为0x20,0x20转换成10进制就是32,也就是说需要32个位,1个位表示1种事件
呢么这里unsigned long的类型根据x86来说就是32位,呢么这个数组其实只有1个成员,来看一下keybit
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
KEY_CNT为0x200,10进制就是512,也就说需要512个位, unsigned long是32位,呢么就是512/32 = 16,需要16个unsigned long来描述,而使用的时候会把这个数组初始化成一个bit序列来看,所以像test_and_set_bit(usage->code, bit),如果code等于0x110,转换为10进制就是273,也就是置512中的第273位为1,并返回第273位原本的数值
回到set_bit(usage->type, input->evbit),这里也就是置evbit中的第usage->type为1,usage->type为0x01,也就是置第一位为1
最后到
if (usage->type == EV_KEY)
{
set_bit(EV_MSC, input->evbit);
set_bit(MSC_SCAN, input->mscbit);
}
不用多说了吧,设置evbit的第EV_MSC位为1,设置mscbit的第MSC_SCAN位为1
这样一个项就分析完成了
全部分析完后的数据结构如下图
分析完协议之后就开始匹配input子系统中的处理模块了
这个入口在input_register_device
input_register_device在/drivers/input/input.c
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler;
const char *path;
int error;
__set_bit(EV_SYN, dev->evbit);
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*/
//初始化定时器结构
init_timer(&dev->timer);
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}
if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode;
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
//建立一个对应input设备
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
error = device_add(&dev->dev);
if (error)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
if (error) {
device_del(&dev->dev);
return error;
}
//将设备挂载到设备链表下
list_add_tail(&dev->node, &input_dev_list);
//历遍处理模块
list_for_each_entry(handler, &input_handler_list, node)
//进行匹配
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return 0;
}
一路来到input_attach_handler
input_attach_handler在drivers/input/input.c中
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int eror;
//检测处理模块是否有黑名单并进行黑名单的匹配
if (handler->blacklist && input_match_device(handler->blacklist, dev))
return -ENODEV;
//匹配模块特性
id = input_match_device(handler->id_table, dev);
if (!id)
return -ENODEV;
//匹配成功则连接设备与模块
error = handler->connect(handler, dev, id);
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
到这里就要开始看看input系统下mouse模块的挂载了
mousedev_init完成mouse模块的挂载
mousedev_init在/drivers/input/mousedev.c中
static int __init mousedev_init(void)
{
int error;
//注册一个misc的空设备
mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX);
if (IS_ERR(mousedev_mix))
return PTR_ERR(mousedev_mix);
//挂载到input模块下
error = input_register_handler(&mousedev_handler);
if (error) {
mousedev_destroy(mousedev_mix);
return error;
}
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
error = misc_register(&psaux_mouse);
if (error)
printk(KERN_WARNING "mice: could not register psaux device, "
"error: %d\n", error);
else
psaux_registered = 1;
#endif
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
return 0;
}
首先是mice的注册
mousedev_create在/drivers/input/mousedev.c中
static struct mousedev *mousedev_create(struct input_dev *dev,
struct input_handler *handler,
int minor)
{
struct mousedev *mousedev;
int error;
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
if (!mousedev) {
error = -ENOMEM;
goto err_out;
}
INIT_LIST_HEAD(&mousedev->client_list);
INIT_LIST_HEAD(&mousedev->mixdev_node);
spin_lock_init(&mousedev->client_lock);
mutex_init(&mousedev->mutex);
lockdep_set_subclass(&mousedev->mutex,
minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
init_waitqueue_head(&mousedev->wait);
//判断是否为mice设备
if (minor == MOUSEDEV_MIX)
strlcpy(mousedev->name, "mice", sizeof(mousedev->name));
else
snprintf(mousedev->name, sizeof(mousedev->name),
"mouse%d", minor);
mousedev->minor = minor;
mousedev->exist = 1;
mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = mousedev->name;
mousedev->handle.handler = handler;
mousedev->handle.private = mousedev;
strlcpy(mousedev->dev.bus_id, mousedev->name,
sizeof(mousedev->dev.bus_id));
mousedev->dev.class = &input_class;
if (dev)
mousedev->dev.parent = &dev->dev;
mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor);
mousedev->dev.release = mousedev_free;
device_initialize(&mousedev->dev);
if (minor != MOUSEDEV_MIX) {
//注册一个连接器
error = input_register_handle(&mousedev->handle);
if (error)
goto err_free_mousedev;
}
//注册进mouse设备组中
error = mousedev_install_chrdev(mousedev);
if (error)
goto err_unregister_handle;
error = device_add(&mousedev->dev);
if (error)
goto err_cleanup_mousedev;
return mousedev;
err_cleanup_mousedev:
mousedev_cleanup(mousedev);
err_unregister_handle:
if (minor != MOUSEDEV_MIX)
input_unregister_handle(&mousedev->handle);
err_free_mousedev:
put_device(&mousedev->dev);
err_out:
return ERR_PTR(error);
}
由于这里minor为MOUSEDEV_MIX,所以是不会进行连接器的注册的
然后到mousedev_install_chrdev
mousedev_install_chrdev在/drivers/input/mousedev.c中
static int mousedev_install_chrdev(struct mousedev *mousedev)
{
mousedev_table[mousedev->minor] = mousedev;
return 0;
}
很简单,就是根据minor在mousedev_table设备数组中占一个位置
这样mice就注册好了,如下图