关闭

LINUX设备驱动之输入子系统(二)

438人阅读 评论(0) 收藏 举报

二.Input handler的注册

Input device的注册中存在下列疑问:

1,  匹配devhandler时,input_handler_list上的handler是什么时候挂上去的呢?

2,  匹配成功后会调用相应handlerconnect函数,此函数做了什么事?

带着这两个疑问,我们以键盘为例进行分析。

在系统启动初始化vtyvty_init函数,ttyvty部分内容将在以后分析)时会调用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 < MAX_NR_CONSOLES; i++) {

1409                     kbd_table[i].ledflagstate = KBD_DEFLEDS;

1410                     kbd_table[i].default_ledflagstate = KBD_DEFLEDS;

1411                            kbd_table[i].ledmode = LED_SHOW_FLAGS;

1412                     kbd_table[i].lockstate = KBD_DEFLOCK;

1413                     kbd_table[i].slockstate = 0;

1414                     kbd_table[i].modeflags = KBD_DEFMODE;

1415                     kbd_table[i].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_handlerkbd_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_KEYEV_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~1622handler去匹配input_dev_list上的input_devinput_attach_handler函数在上面已经分析过,再最后如果匹配成功会调用handlerconnect函数,对于这个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 < BTN_MISC; 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       }

16841693handle分别链接到dev->h_listhandler->h_list

1695~1696行,如果handlerstart函数存在,则调用它。对于这个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       }

增加handleopen计数,如果handle->dev->users不为0,则自增1,如果为0并且handle->devopen函数存在则会调用它,对于前面分析的atkbd,相应的handle->devopen函数不存在。

至此,input handlerinput handler的注册都分析完了,接着将分析事件处理部分内容。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:74019次
    • 积分:959
    • 等级:
    • 排名:千里之外
    • 原创:18篇
    • 转载:33篇
    • 译文:0篇
    • 评论:5条
    文章分类
    最新评论