您的位置:首页 > 运维架构 > Linux

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

2011-08-24 16:03 351 查看
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 < 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_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 < 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 }

第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的注册都分析完了,接着将分析事件处理部分内容。

接下一篇文章。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: