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

Eric Fang2010-02-03

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

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

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

接上一篇文章继续分析。

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

1403int __init kbd_init(void)

1404{

1405int i;

1406int error;

1407

1408for (i = 0; i < MAX_NR_CONSOLES; i++) {

1409kbd_table[i].ledflagstate = KBD_DEFLEDS;

1410kbd_table[i].default_ledflagstate = KBD_DEFLEDS;

1411kbd_table[i].ledmode = LED_SHOW_FLAGS;

1412kbd_table[i].lockstate = KBD_DEFLOCK;

1413kbd_table[i].slockstate = 0;

1414kbd_table[i].modeflags = KBD_DEFMODE;

1415kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;

1416}

1417

1418error = input_register_handler(&kbd_handler);

1419if (error)

1420return error;

1421

1422tasklet_enable(&keyboard_tasklet);

1423tasklet_schedule(&keyboard_tasklet);

1424

1425return 0;

1426}

第1408~1416行初始化kbd_table数组,这部分与tty内容相关,以后再分析。

1418行,这里我们终于看到调用input_register_handler函数注册kbd_handler,kbd_handler定义如下:

1394static 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定义如下:

1378static 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函数:

1600int input_register_handler(struct input_handler *handler)

1601{

1602struct input_dev *dev;

1603int retval;

1604

1605retval = mutex_lock_interruptible(&input_mutex);

1606if (retval)

1607return retval;

1608

1609INIT_LIST_HEAD(&handler->h_list);

1610

1611if (handler->fops != NULL) {

1612if (input_table[handler->minor >> 5]) {

1613retval = -EBUSY;

1614goto out;

1615}

1616input_table[handler->minor >> 5] = handler;

1617}

1618

1619list_add_tail(&handler->node, &input_handler_list);

1620

1621list_for_each_entry(dev, &input_dev_list, node)

1622input_attach_handler(dev, handler);

1623

1624input_wakeup_procfs_readers();

1625

1626out:

1627mutex_unlock(&input_mutex);

1628return 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,看一下这个函数:

1314static int kbd_connect(struct input_handler *handler, struct input_dev *dev,

1315const struct input_device_id *id)

1316{

1317struct input_handle *handle;

1318int error;

1319int i;

1320

1321for (i = KEY_RESERVED; i < BTN_MISC; i++)

1322if (test_bit(i, dev->keybit))

1323break;

1324

1325if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))

1326return -ENODEV;

1327

1328handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);

1329if (!handle)

1330return -ENOMEM;

1331

1332handle->dev = dev;

1333handle->handler = handler;

1334handle->name = "kbd";

1335

1336error = input_register_handle(handle);

1337if (error)

1338goto err_free_handle;

1339

1340error = input_open_device(handle);

1341if (error)

1342goto err_unregister_handle;

1343

1344return 0;

1345

1346err_unregister_handle:

1347input_unregister_handle(handle);

1348err_free_handle:

1349kfree(handle);

1350return error;

1351}

第1321~1326行判断dev->keybit,如果属于例外的情况,则不再往下走,返回-ENODEV。

第1328行,为handle分配内存空间,1332~1334行初始化handle的部分字段。

第1336行调用input_register_handle注册handle,看一下这个函数:

1671int input_register_handle(struct input_handle *handle)

1672{

1673struct input_handler *handler = handle->handler;

1674struct input_dev *dev = handle->dev;

1675int error;

1676

1677/*

1678* We take dev->mutex here to prevent race with

1679* input_release_device().

1680*/

1681error = mutex_lock_interruptible(&dev->mutex);

1682if (error)

1683return error;

1684list_add_tail_rcu(&handle->d_node, &dev->h_list);

1685mutex_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*/

1693list_add_tail(&handle->h_node, &handler->h_list);

1694

1695if (handler->start)

1696handler->start(handle);

1697

1698return 0;

1699}

第1684、1693将handle分别链接到dev->h_list和handler->h_list。

第1695~1696行,如果handler的start函数存在,则调用它。对于这个kbd_handler相应的函数为kbd_start,看一下这个函数:

1364static void kbd_start(struct input_handle *handle)

1365{

1366unsigned char leds = ledstate;

1367

1368tasklet_disable(&keyboard_tasklet);

1369if (leds != 0xff) {

1370input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));

1371input_inject_event(handle, EV_LED, LED_NUML,!!(leds & 0x02));

1372input_inject_event(handle, EV_LED, LED_CAPSL,!!(leds & 0x04));

1373input_inject_event(handle, EV_SYN, SYN_REPORT, 0);

1374}

1375tasklet_enable(&keyboard_tasklet);

1376}

禁止keyboard_tasklet,初始化键盘的三个led灯及SYN_REPORT,然后启用keyboard_tasklet,这个keyboard_tasklet也是对led灯进行操作的,函数如下

1032DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);

1014static void kbd_bh(unsigned long dummy)

1015{

1016struct list_head *node;

1017unsigned char leds = getleds();

1018

1019if (leds != ledstate) {

1020list_for_each(node, &kbd_handler.h_list) {

1021struct input_handle *handle = to_handle_h(node);

1022input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));

1023input_inject_event(handle, EV_LED, LED_NUML,!!(leds & 0x02));

1024input_inject_event(handle, EV_LED, LED_CAPSL,!!(leds & 0x04));

1025input_inject_event(handle, EV_SYN, SYN_REPORT, 0);

1026}

1027}

1028

1029ledstate = leds;

1030}

input_register_handle函数返回后,第1340行调用input_open_device函数,这个函数执行后相应的handle就能接受设备上报的事件。函数如下:

0421int input_open_device(struct input_handle *handle)

0422{

0423struct input_dev *dev = handle->dev;

0424int retval;

0425

0426retval = mutex_lock_interruptible(&dev->mutex);

0427if (retval)

0428return retval;

0429

0430if (dev->going_away) {

0431retval = -ENODEV;

0432goto out;

0433}

0434

0435handle->open++;

0436

0437if (!dev->users++ && dev->open)

0438retval = dev->open(dev);

0439

0440if (retval) {

0441dev->users--;

0442if (!--handle->open) {

0443/*

0444* Make sure we are not delivering any more events

0445* through this handle

0446*/

0447synchronize_rcu();

0448}

0449}

0450

0451out:

0452mutex_unlock(&dev->mutex);

0453return retval;

0454}

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

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

接下一篇文章。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值