免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1495 | 回复: 0
打印 上一主题 下一主题

LINUX设备驱动之输入子系统(二) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-02-04 20:42 |只看该作者 |倒序浏览

Eric Fang  2010-02-03
--------------------------------------------------------------
本站分析linux内核源码,版本号为2.6.32.3
转载请注明出处:
http://ericfang.cublog.cn/
--------------------------------------------------------------

接上一篇文章继续分析。

二.Input handler的注册
在Input device的注册中存在下列疑问:
1,  匹配dev和handler时,input_handler_list上的handler是什么时候挂上去的呢?
2,  匹配成功后会调用相应handler的connect函数,此函数做了什么事?
带着这两个疑问,我们以键盘为例进行分析。
在系统启动初始化vty(vty_init函数,tty、vty部分内容将在以后分析)时会调用kbd_init()进行键盘初始化,kbd_init函数定义于drivers/char/keyboard.c:
1403       int __init kbd_init(void)
1404       {
1405              int i;
1406              int error;
1407      
1408               for (i = 0; i
1409                     kbd_table.ledflagstate = KBD_DEFLEDS;
1410                     kbd_table.default_ledflagstate = KBD_DEFLEDS;
1411                            kbd_table.ledmode = LED_SHOW_FLAGS;
1412                     kbd_table.lockstate = KBD_DEFLOCK;
1413                     kbd_table.slockstate = 0;
1414                     kbd_table.modeflags = KBD_DEFMODE;
1415                     kbd_table.kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
1416              }
1417      
1418              error = input_register_handler(&kbd_handler);
1419              if (error)
1420                     return error;
1421      
1422              tasklet_enable(&keyboard_tasklet);
1423              tasklet_schedule(&keyboard_tasklet);
1424      
1425              return 0;
1426       }
第1408~1416行初始化kbd_table数组,这部分与tty内容相关,以后再分析。
1418行,这里我们终于看到调用input_register_handler函数注册kbd_handler,kbd_handler定义如下:
1394       static struct input_handler kbd_handler = {
1395              .event             = kbd_event,
1396              .connect  = kbd_connect,
1397              .disconnect     = kbd_disconnect,
1398              .start              = kbd_start,
1399              .name             = "kbd",
1400              .id_table  = kbd_ids,
1401       };
我们看到id_table指向kbd_ids数组,kbd_ids定义如下:
1378       static const struct input_device_id kbd_ids[] = {
1379              {
1380                       .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
1381                       .evbit = { BIT_MASK(EV_KEY) },
1382               },
1383      
1384              {
1385                       .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
1386                       .evbit = { BIT_MASK(EV_SND) },
1387               },
1388      
1389              { },    /* Terminating entry */
1390       };
从这个id_table看到,只要input_dev设置了其evbit字段支持EV_KEY或EV_SND都会匹配到hnadler,回想一下在键盘驱动中创建input_dev后调用的atkbd_set_device_attrs设置input_dev的函数中有下列语句:
       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
              BIT_MASK(EV_MSC);
说明at键盘的input_dev会匹配到这个hnadler。
我们接着看input_register_handler函数:
1600       int input_register_handler(struct input_handler *handler)
1601       {
1602              struct input_dev *dev;
1603              int retval;
1604      
1605              retval = mutex_lock_interruptible(&input_mutex);
1606              if (retval)
1607                     return retval;
1608      
1609              INIT_LIST_HEAD(&handler->h_list);
1610      
1611                     if (handler->fops != NULL) {
1612                     if (input_table[handler->minor >> 5]) {
1613                            retval = -EBUSY;
1614                            goto out;
1615                     }
1616                     input_table[handler->minor >> 5] = handler;
1617              }
1618      
1619              list_add_tail(&handler->node, &input_handler_list);
1620      
1621              list_for_each_entry(dev, &input_dev_list, node)
1622                     input_attach_handler(dev, handler);
1623      
1624              input_wakeup_procfs_readers();
1625      
1626       out:
1627              mutex_unlock(&input_mutex);
1628              return retval;
1629       }
第1605行获得互斥信号量,1609行初始化handler 的h_list字段,这个h_list指向的链表用于存放input_handle。
第1611~1617行,我们的kbd_handler没有定义fops函数,所以这段代码不会执行,不过我们还是看一下,这里的input_table数组是一个struct input_handler结构数组,根据设备的次设备号除以32的值为下标的元素为input_handler为什么是32?输入子系统最多支持256个设备,而input_handler结构的数组最多处理8类事件,所以分给每一类的次设备号段分配32个。
第1619行把handler链接到input_handler_list尾部。
第1621~1622用handler去匹配input_dev_list上的input_dev,input_attach_handler函数在上面已经分析过,再最后如果匹配成功会调用handler的connect函数,对于这个kbd_handler相应的函数为kbd_connect,看一下这个函数:
1314       static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
1315                            const struct input_device_id *id)
1316       {
1317              struct input_handle *handle;
1318              int error;
1319              int i;
1320      
1321              for (i = KEY_RESERVED; i
1322                     if (test_bit(i, dev->keybit))
1323                            break;
1324      
1325              if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
1326                     return -ENODEV;
1327      
1328              handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
1329              if (!handle)
1330                     return -ENOMEM;
1331      
1332              handle->dev = dev;
1333              handle->handler = handler;
1334              handle->name = "kbd";
1335      
1336              error = input_register_handle(handle);
1337              if (error)
1338                     goto err_free_handle;
1339      
1340              error = input_open_device(handle);
1341              if (error)
1342                     goto err_unregister_handle;
1343      
1344              return 0;
1345      
1346       err_unregister_handle:
1347              input_unregister_handle(handle);
1348       err_free_handle:
1349              kfree(handle);
1350              return error;
1351       }
第1321~1326行判断dev->keybit,如果属于例外的情况,则不再往下走,返回-ENODEV。
第1328行,为handle分配内存空间,1332~1334行初始化handle的部分字段。
第1336行调用input_register_handle注册handle,看一下这个函数:
1671       int input_register_handle(struct input_handle *handle)
1672       {
1673              struct input_handler *handler = handle->handler;
1674              struct input_dev *dev = handle->dev;
1675              int error;
1676      
1677              /*
1678              * We take dev->mutex here to prevent race with
1679              * input_release_device().
1680              */
1681              error = mutex_lock_interruptible(&dev->mutex);
1682              if (error)
1683                     return error;
1684              list_add_tail_rcu(&handle->d_node, &dev->h_list);
1685              mutex_unlock(&dev->mutex);
1686      
1687              /*
1688              * Since we are supposed to be called from ->connect()
1689              * which is mutually exclusive with ->disconnect()
1690              * we can't be racing with input_unregister_handle()
1691              * and so separate lock is not needed here.
1692              */
1693              list_add_tail(&handle->h_node, &handler->h_list);
1694      
1695              if (handler->start)
1696                     handler->start(handle);
1697      
1698              return 0;
1699       }
第1684、1693将handle分别链接到dev->h_list和handler->h_list。
第1695~1696行,如果handler的start函数存在,则调用它。对于这个kbd_handler相应的函数为kbd_start,看一下这个函数:
1364       static void kbd_start(struct input_handle *handle)
1365       {
1366              unsigned char leds = ledstate;
1367      
1368              tasklet_disable(&keyboard_tasklet);
1369              if (leds != 0xff) {
1370                     input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
1371                     input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
1372                     input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
1373                     input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
1374              }
1375              tasklet_enable(&keyboard_tasklet);
1376       }
禁止keyboard_tasklet,初始化键盘的三个led灯及SYN_REPORT,然后启用keyboard_tasklet,这个keyboard_tasklet也是对led灯进行操作的,函数如下
1032              DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
1014       static void kbd_bh(unsigned long dummy)
1015       {
1016              struct list_head *node;
1017              unsigned char leds = getleds();
1018      
1019              if (leds != ledstate) {
1020                     list_for_each(node, &kbd_handler.h_list) {
1021                            struct input_handle *handle = to_handle_h(node);
1022                            input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
1023                            input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
1024                            input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
1025                            input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
1026                     }
1027              }
1028      
1029              ledstate = leds;
1030       }
input_register_handle函数返回后,第1340行调用input_open_device函数,这个函数执行后相应的handle就能接受设备上报的事件。函数如下:
0421       int input_open_device(struct input_handle *handle)
0422       {
0423              struct input_dev *dev = handle->dev;
0424              int retval;
0425      
0426              retval = mutex_lock_interruptible(&dev->mutex);
0427              if (retval)
0428                     return retval;
0429      
0430              if (dev->going_away) {
0431                     retval = -ENODEV;
0432                     goto out;
0433              }
0434      
0435              handle->open++;
0436      
0437              if (!dev->users++ && dev->open)
0438                     retval = dev->open(dev);
0439      
0440              if (retval) {
0441                     dev->users--;
0442                     if (!--handle->open) {
0443                            /*
0444                            * Make sure we are not delivering any more events
0445                            * through this handle
0446                            */
0447                            synchronize_rcu();
0448                     }
0449              }
0450      
0451       out:
0452              mutex_unlock(&dev->mutex);
0453              return retval;
0454       }
增加handle的open计数,如果handle->dev->users不为0,则自增1,如果为0并且handle->dev的open函数存在则会调用它,对于前面分析的atkbd,相应的handle->dev的open函数不存在。
至此,input handler和input handler的注册都分析完了,接着将分析事件处理部分内容。

接下一篇文章。





本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/92745/showart_2178052.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP