//input 输入子系统分析//刘术河2016.08.22
linux-2.6.39-at91-2016.08.11-lsh\drivers\input\Input.c该文件下有input_register_device 和 input_register_handler 函数接口0.先分析input.c的核心层架构
input_init(void) class_register(&input_class); //注册一个类 register_chrdev(INPUT_MAJOR, "input", &input_fops); //注册一个字符设备,注册一个fops结构体0.1 fops结构体
static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, .llseek = noop_llseek, };0.2可见fops只提供一个open函数input_open_file//该open函数,是在应用程序open设备节点的时候,才会调用到这个input_open_file
input_open_file struct input_handler *handler; handler = input_table[iminor(inode) >> 5]; new_fops = fops_get(handler->fops); new_fops->open(inode, file); //这里调用open函数//注:new_fops是从input_table列表里查找出来的,搜索它是在哪里被赋值的//发现是在input_register_handler里
input_table[handler->minor >> 5] = handler;1.分析input_register_handler有9个驱动程序调用
Apm-power.c (drivers\input): return input_register_handler(&apmpower_handler); Evbug.c (drivers\input): return input_register_handler(&evbug_handler); Evdev.c (drivers\input): return input_register_handler(&evdev_handler); Joydev.c (drivers\input): return input_register_handler(&joydev_handler); Keyboard.c (drivers\tty\vt): error = input_register_handler(&kbd_handler); Kgdboc.c (drivers\tty\serial): if (input_register_handler(&kgdboc_reset_handler) == 0) Mac_hid.c (drivers\macintosh): err = input_register_handler(&mac_hid_emumouse_handler); Mousedev.c (drivers\input): error = input_register_handler(&mousedev_handler); Sysrq.c (drivers\tty): error = input_register_handler(&sysrq_handler);1.1这里只分析Evdev.c,他相对简单,Keyboard.c涉及到tty太复杂不去分析//这是handler的fops结构体
static const struct file_operations evdev_fops = { .owner = THIS_MODULE, .read = evdev_read, .write = evdev_write, .poll = evdev_poll, .open = evdev_open, .release = evdev_release, .unlocked_ioctl = evdev_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = evdev_ioctl_compat, #endif .fasync = evdev_fasync, .flush = evdev_flush, .llseek = no_llseek, };//handler结构体
static struct input_handler evdev_handler = { .event = evdev_event, .connect = evdev_connect, .disconnect = evdev_disconnect, .fops = &evdev_fops, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, }; static const struct input_device_id evdev_ids[] = { { .driver_info = 1 }, /* Matches all devices */ { }, /* Terminating zero entry */ };//Evdev.c初始化函数
module_init(evdev_init); evdev_init input_register_handler(&evdev_handler); input_table[handler->minor >> 5] = handler; //假设minor是64则64>>5=64/32=2,表示input_table[2]=&evdev_handler list_add_tail(&handler->node, &input_handler_list); //将evdev_handler加入input_handler_list列表,注意这个handler->node是添加到列表尾部,所以handler->node的next、prev会自动的被赋值故可以不初始化它 __list_add(new, head->prev, head); __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)__list_add实现 ,new=handler->node,prev=链表头的前驱,next=链表头
next->prev = new; //next->prev:指向尾节点,即将链表头前驱指向新的节点 new->next = next; //新节点的后驱指向链表头 new->prev = prev; //新节点的前驱,指向之前的尾节点 prev->next = new; //之前尾节点的后驱,指向新添加的节点//这就形成一个新的双向循环链表
list_for_each_entry(dev, &input_dev_list, node) //从input_dev_list开始,循环遍历dev中的node子项,返回一个dev的指针 input_attach_handler(dev, handler); //如果在设备链表input_dev_list找到对应的dev设备,就调用input_attach_handler(dev, handler); const struct input_device_id *id; input_match_device(handler, dev); //这里是看dev和handler能否匹配 if (!handler->match || handler->match(handler, dev)) return id;//这里如果handler->match不存在,或者handler->match(handler, dev)返回值非0,就返回ID//必须能匹配,否则这里不会执行
handler->connect(handler, dev, id); //这里相当于 .connect = evdev_connect, evdev_connect struct evdev *evdev; evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); init_waitqueue_head(&evdev->wait); //初始化,一个等待队列 dev_set_name(&evdev->dev, "event%d", minor); //设置输入事件名字 evdev->handle.dev = input_get_device(dev); //获取input_dev结构体 evdev->handle.handler = handler; //这里evdev->handle.handler=evdev_handler evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); //分配设备号//重点
input_register_handle(&evdev->handle); struct input_handler *handler = handle->handler; struct input_dev *dev = handle->dev; list_add_tail_rcu(&handle->d_node, &dev->h_list); //将handle里的d_node设备放进input_dev的设备链表尾部 list_add_tail_rcu(&handle->h_node, &handler->h_list); //将handle里的h_node:handler处理者,放进handler的设备链表尾部 evdev_install_chrdev(evdev); evdev_table[evdev->minor] = evdev; //将evdev放在evdev_table数组里 device_add(&evdev->dev);//注:这里又涉及到另一条总线 bus---device---driver//先不深入分析这条总线
bus_add_device(dev); //将设备添加到总线 bus_probe_device(dev); //在总线上探测设备2.分析到这里,input_register_handler基本就分析完了,一路跟踪到最后,发现就是在connect里初始化一个时间等待队列
handler->connect(handler, dev, id); 里初始化一个init_waitqueue_head(&evdev->wait); 事件等待队列那么设备和驱动如何调用起来的?
2.1应该是硬件会唤醒这个事件等待队列 evdev->wait 2.2分析 evdev->wait 被调用过程搜索evdev->wait,发现
在 evdev_event、evdev_hangup 里有wake_up_interruptible(&evdev->wait); 在 evdev_read、有wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist); 在 evdev_poll、有poll_wait(file, &evdev->wait, wait); 在evdev.c的 static struct input_handler evdev_handler = {.event = evdev_event,};有evdev_event这个函数,所以应该是在 evdev_event wake_up_interruptible(&evdev->wait); //唤醒等待那么在哪里发生休眠的?
分析在static const struct file_operations evdev_fops = {.read = evdev_read, .poll = evdev_poll,} 应该在evdev_read->wait_event_interruptible(evdev->waitclient->head != client->tail || !evdev->exist); 或者在evdev_poll->poll_wait(file, &evdev->wait, wait);这两个情况发生的休眠3.分析到这里,基本弄清楚 input_register_handler 干的工作,
3.1 填充 input_table[handler->minor >> 5] = handler; 3.2 注册handler到input_handler_list链表,并且遍历input_dev_list链表,遍历input_dev_list链表会调用input_attach_handler函数, 这个函数就是看handler和dev是否能匹配,能匹配做4件事 3.2.1. init_waitqueue_head(&evdev->wait); //初始化一个等待队列 3.2.2. input_register_handle(&evdev->handle); //注册一个handle结构,注意不是handler 3.2.3. evdev_install_chrdev(evdev); //填充evdev_table[] 3.2.4. device_add(&evdev->dev); //真正把输入设备注册进系统的bus上4.分析input_register_handler填充的 input_table 用途4.1 搜索发现在 input_open_file里用到input_table,而input_open_file在input_init()初始化里
static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, .llseek = noop_llseek, };input_initclass_register(&input_class);register_chrdev(INPUT_MAJOR, "input", &input_fops);//当有设备打开此设备会调用到input_open_file函数
input_open_file(struct inode *inode, struct file *file) struct input_handler *handler; struct file_operations *new_fops = NULL; handler = input_table[iminor(inode) >> 5];//这里发现是将次设备号inode>>5=inode/32 = 2,即从input_table[2]取出一个handler 这不就是input_register_handler注册时,填充的吗?注意看
nput_table[handler->minor >> 5] = handler; 太秒了!!! new_fops = fops_get(handler->fops); //从handler得到handler的fops结构体即evdev_fops new_fops->open(inode, file); //调用fops的open函数,即evdev_fops.open evdev_open // struct evdev *evdev; struct evdev_client *client; evdev = evdev_table[i]; //这个evdev_table[]就是在evdev_install_chrdev函数里填充的 //evdev_table[evdev->minor] = evdev;这里面有handle.handler client->evdev = evdev; //注意:这个evdev.handle.handler=evdev_handler,巧妙 evdev_attach_client(evdev, client); //将client->node添加到evdev->client_list链表尾部 evdev_open_device(evdev); { if (!evdev->exist) retval = -ENODEV; else if (!evdev->open++) { //evdev_connect初始化的时候没有设置evdev.open所以这里evdev.open=0 retval = input_open_device(&evdev->handle); //就调用evdev->handle if (retval) evdev->open--; } }//这里接着分析input_open_device(&evdev->handle);
input_open_device(&evdev->handle); struct input_dev *dev = handle->dev; //这里handle->dev = 就是evdev->handle.dev = input_get_device(dev); { if (!dev->users++ && dev->open) //这就是具体设备的硬件open函数,这里是判断 input_register_device注册 //的设备有没有open成员,有就调用 //所以就要分析具体的设备,这里举个例子Lpc32xx_ts.c //发现在lpc32xx_ts_probe有这2句话,具体分析等我写input_register_device //input = input_allocate_device(); //input->open = lpc32xx_ts_open; retval = dev->open(dev); //所以这里调用lpc32xx_ts_open lpc32xx_ts_open lpc32xx_setup_tsc(tsc); //都是这种寄存器 }5.分析input_register_device调用Lpc32xx_ts.c 就分析这个按键驱动程序5.1 这个按键涉及到2个框架 平台设备、输入子系统5.2 从入口函数进去
module_init(lpc32xx_ts_init); platform_driver_register(&lpc32xx_ts_driver);//这里就是注册一个平台设备,平台设备的分析我已经做过了,这里不深入进去分析//主要分析输入子系统,该platform_driver_register会调用lpc32xx_ts_driver.probe探测函数
static struct platform_driver lpc32xx_ts_driver = { .probe = lpc32xx_ts_probe, .remove = __devexit_p(lpc32xx_ts_remove), .driver = { .name = MOD_NAME, .owner = THIS_MODULE, .pm = LPC32XX_TS_PM_OPS, }, };5.2 直接分析 lpc32xx_ts_driver.probe = lpc32xx_ts_probe,
lpc32xx_ts_probe struct input_dev *input;//分配一个input结构体
lpc32xx_ts_probe struct input_dev *input;//设置能产生的事件类型
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);//设置能产生的事件
input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);//初始化input_dev结构体
input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,LPC32XX_TSC_MAX_XY_VAL, 0, 0); input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,LPC32XX_TSC_MAX_XY_VAL, 0, 0); input_set_drvdata(input, tsc);//注册触摸屏中断
request_irq(tsc->irq, lpc32xx_ts_interrupt,IRQF_DISABLED, pdev->name, tsc);//注册输入设备
input_register_device(input); struct input_handler *handler; __set_bit(EV_SYN, dev->evbit); __clear_bit(KEY_RESERVED, dev->keybit); init_timer(&dev->timer); dev->timer.function = input_repeat_key; device_add(&dev->dev); list_add_tail(&dev->node, &input_dev_list); list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler); input_match_device(handler, dev); handler->connect(handler, dev, id);6.分析触摸屏中断函数
lpc32xx_ts_interrupt struct input_dev *input = tsc->dev; input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2); input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2); input_report_key(input, BTN_TOUCH, 1);//只分析一个上报事件,其他类似
input_report_key(input, BTN_TOUCH, 0); input_event(dev, EV_KEY, code, !!value); input_handle_event(dev, type, code, value); input_pass_event(dev, type, code, value); struct input_handler *handler; struct input_handle *handle; handler = handle->handler; handler->event(handle, type, code, value); //其实就是evdev.c里的evdev_handler.event = evdev_event input_sync(input);6.1 分析evdev_event函数
evdev_event struct evdev_client *client; client = rcu_dereference(evdev->grab); list_for_each_entry_rcu(client, &evdev->client_list, node) evdev_pass_event(client, &event); wake_up_interruptible(&evdev->wait); //注意这个等待队列,就是在注册input_register_handler初始化的 //init_waitqueue_head(&evdev->wait); //初始化一个等待队列6.2 分析evdev->wait)是在哪里休眠的?应该是应用程序读数据,没有数据时休眠的,直接分析evdev.c的 evdev_handler.evdev_fops.read = evdev_read
evdev_read wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist) //里面就有这句休眠语句6.3 到这里基本input输入子系统流程大致分析明白
转载于:https://www.cnblogs.com/liushuhe1990/p/9608999.html
