浅析usb鼠标input_register_device注册input_dev设备全过程
hid_probe
==> usb_hid_configure
==*> hid->hidinput_input_event = usb_hidinput_input_event;
==*> hid->hid_open = usbhid_open;
==*> hid->hid_close = usbhid_close;
==> hidinput_connect
==*> input_dev = input_allocate_device();
==*> input_dev->event = hid->hidinput_input_event; // usb_hidinput_input_event
==*> input_dev->open = hidinput_open;
==*> input_dev->close = hidinput_close;
==*> input_dev->setkeycode = hidinput_setkeycode;
==*> input_dev->getkeycode = hidinput_getkeycode;
==*> hidinput->input = input_dev;
==*> list_add_tail(&hidinput->list, &hid->inputs); // 添加到hid->inputs链表上,以便hid_irq_in收到hid硬件设备数据后遍历分发数据[luther.gliethttp]
==*> input_register_device(hidinput->input)
int input_register_device(struct input_dev *dev)
{
list_add_tail(&dev->node, &input_dev_list); // 添加到input_dev_list输入设备链表上,以便input_register_handler注册新handler时遍历.
list_for_each_entry(handler, &input_handler_list, node) // 遍历驱动链表,尝试给我们的hid设备变身成的普通input设备匹配一个驱动
input_attach_handler(dev, handler); // attach一个驱动给我们变身为普通input设备的hid设备[luther.gliethttp]
}
drivers/input/evdev.c|995| return input_register_handler(&evdev_handler);
drivers/input/mousedev.c|1072| error = input_register_handler(&mousedev_handler);
drivers/char/keyboard.c|1416| error = input_register_handler(&kbd_handler);
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error;
if (handler->blacklist && input_match_device(handler->blacklist, dev))
return -ENODEV;
id = input_match_device(handler->id_table, dev); // mousedev_handler
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id); // mousedev_connect为该dev建立一个连接到mousedev_handler的handle
if (error && error != -ENODEV) // 每个input_dev可以对应n多个handle,他们都挂接在input_dev的h_list链表上
printk(KERN_ERR // 每个handle唯一对应一个handler,用来处理由input_dev设备发送过来的数据[luther.gliethttp]
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
static int mousedev_connect(struct input_handler *handler,
struct input_dev *dev,
const struct input_device_id *id)
{
struct mousedev *mousedev;
int minor;
int error;
for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
if (!mousedev_table[minor]) // 从mousedev_handler驱动管理的最多32个设备槽中申请一个空槽[luther.gliethttp]
break;
if (minor == MOUSEDEV_MINORS) { // 没有空槽了
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
return -ENFILE;
}
mousedev = mousedev_create(dev, handler, minor); // 创建包装了dev的mousedev设备,同时uevent出去,创建/dev/input/mousex节点
if (IS_ERR(mousedev))
return PTR_ERR(mousedev);
error = mixdev_add_device(mousedev); // 见后将mousedev添加到mousedev_mix_list管理链表
if (error) {
mousedev_destroy(mousedev);
return error;
}
return 0;
}
static struct mousedev *mousedev_create(struct input_dev *dev,
struct input_handler *handler,
int minor)
{
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
if (minor == MOUSEDEV_MIX)
strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); // minor等于MOUSEDEV_MIX那么创建/dev/input/mice节点
else
snprintf(mousedev->name, sizeof(mousedev->name),
"mouse%d", minor); // 创建/dev/input/mousex节点,节点函数操作集fops为
// input_init==>register_chrdev(INPUT_MAJOR, "input", &input_fops);
// 创建的input_fops,当应用程序调用open时,执行input_open_file
// input_open_file
// ==> struct input_handler *handler = input_table[iminor(inode) >> 5];
// 每32个minor对应一个handler,
// ==> new_fops = fops_get(handler->fops))
// ==> file->f_op = new_fops;即mousedev_fops
// ==> new_fops->open(inode, file);即mousedev_open
// mousedev_init
// ==> #define MOUSEDEV_MINOR_BASE 32
// ==> static struct input_handler mousedev_handler = {
// .event = mousedev_event,
// .connect = mousedev_connect,
// .disconnect = mousedev_disconnect,
// .fops = &mousedev_fops,
// .minor = MOUSEDEV_MINOR_BASE,
// .name = "mousedev",
// .id_table = mousedev_ids,
// };
// ==> input_register_handler(&mousedev_handler);
// ==*> input_table[handler->minor >> 5] = handler;即mousedev_handler
mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = mousedev->name;
mousedev->handle.handler = handler; // mousedev_handler
mousedev->handle.private = mousedev;
strlcpy(mousedev->dev.bus_id, mousedev->name,
sizeof(mousedev->dev.bus_id));
mousedev->dev.class = &input_class;
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); // 见下,将handle添加的input_dev的h_list链表上,以便硬件设备数据到达之后遍历handle,
if (error) // 将硬件传上来的数据分发给每个handle对应的handler分别处理.[luther.gliethttp]
goto err_free_mousedev;
}
error = mousedev_install_chrdev(mousedev); // 记录登记到32个设备表中mousedev_table[mousedev->minor] = mousedev;
if (error) // 这个mousedev由mousedev_handler驱动使用唯一对应硬件设备,设备节点为/dev/input/mouse_[minor-32]
goto err_unregister_handle;
error = device_add(&mousedev->dev); // uevent然后作为daemon的应用程序生成/dev/input/mousex节点,函数操作集为input_fops
}
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
int error;
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
error = mutex_lock_interruptible(&dev->mutex);
if (error)
return error;
list_add_tail_rcu(&handle->d_node, &dev->h_list);// 将handle注册登记到input_dev设备的h_list链表上,这样当dev设备产生数据之后,
mutex_unlock(&dev->mutex); // 才能通过遍历h_list链表,一一向handle发送产生的物理数据[luther.gliethttp]
synchronize_rcu(); // 比如
// input_event
// ==>input_handle_event
// ==>input_pass_event
// ==>list_for_each_entry_rcu(handle, &dev->h_list, d_node)
// if (handle->open) 如果应用程序打开了/dev/input/mice或mousex节点,那么
// handle->handler->event(handle,type, code, value);
// mousedev_event
/*
* Since we are supposed to be called from ->connect()
* which is mutually exclusive with ->disconnect()
* we can't be racing with input_unregister_handle()
* and so separate lock is not needed here.
*/
list_add_tail(&handle->h_node, &handler->h_list);// 将handle添加到mousedev_handler的h_list链表上,在input_unregister_handler
// 函数中将遍历handler->h_list上的所有handle,然后一一断开它们[luther.gliethttp]
// input_unregister_handler
// list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
// handler->disconnect(handle);
if (handler->start)
handler->start(handle); // mousedev_handler没有start函数
return 0;
}
static int mixdev_add_device(struct mousedev *mousedev)
{
int retval;
retval = mutex_lock_interruptible(&mousedev_mix->mutex);
if (retval)
return retval;
if (mousedev_mix->open) { // 如果/dev/input/mice节点已经有应用程序打开了
retval = mousedev_open_device(mousedev); // 那么尝试打开mousedev,增加mousedev->open++引用[luther.gliethttp]
if (retval) // 如果mousedev->open等于0,那么说明没有应用程序打开/dev/input/mousex节点
goto out; // 所以将直接执行input_open_device(&mousedev->handle);操作.
mousedev->mixdev_open = 1; // 标识mousedev_mix驱动也在引用该mousedev设备,
// 当然该mousedev设备也可能已经由其他应用程序调用/dev/input/mousex打开
}
get_device(&mousedev->dev);
list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); // 添加到mousedev_mix_list管理链表
out:
mutex_unlock(&mousedev_mix->mutex);
return retval;
}
static int mousedev_open_device(struct mousedev *mousedev)
{
int retval;
retval = mutex_lock_interruptible(&mousedev->mutex);
if (retval)
return retval;
if (mousedev->minor == MOUSEDEV_MIX)
mixdev_open_devices(); // 打开mousedev_mix_list链表上的所有mousedev设备[luther.gliethttp]
else if (!mousedev->exist)
retval = -ENODEV;
else if (!mousedev->open++) { // mousedev->open还等于0,那么执行下面打开操作[luther.gliethttp]
retval = input_open_device(&mousedev->handle);
if (retval)
mousedev->open--;
}
mutex_unlock(&mousedev->mutex);
return retval;
}
static void mixdev_open_devices(void)
{
struct mousedev *mousedev;
if (mousedev_mix->open++)
return;
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
if (!mousedev->mixdev_open) {
if (mousedev_open_device(mousedev))
continue;
mousedev->mixdev_open = 1;
}
}
}
int input_open_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
int retval;
retval = mutex_lock_interruptible(&dev->mutex);
if (retval)
return retval;
if (dev->going_away) {
retval = -ENODEV;
goto out;
}
handle->open++; // 引用计数加1.
if (!dev->users++ && dev->open) // dev->users为0,说明我们是第一个引用dev的用户,所以需要执行dev->open函数
retval = dev->open(dev); // hidinput_connect==> input_dev->open = hidinput_open;
// hidinput_open ==> hid->hid_open(hid);
// usb_hid_configure
// hid->hid_open = usbhid_open;
// 所以最后调用usbhid_open
// usb_submit_urb(usbhid->urbin, GFP_ATOMIC); 提交一个in读取urb.[luther.gliethttp]
if (retval) {
dev->users--;
if (!--handle->open) {
/*
* Make sure we are not delivering any more events
* through this handle
*/
synchronize_rcu();
}
}
out:
mutex_unlock(&dev->mutex);
return retval;
}
阅读(3829) | 评论(0) | 转发(0) |