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

    技术2025-09-18  38

    Eric Fang  2010-02-03

    --------------------------------------------------------------

    本站分析linux内核源码,版本号为2.6.32.3

    转载请注明出处:http://ericfang.cublog.cn/

    --------------------------------------------------------------

     

    接上一篇文章继续分析。

     

    二.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)