现在的位置: 首页 > 综合 > 正文

闲聊linux中的input设备(7) 爱情的结晶

2013年01月25日 ⁄ 综合 ⁄ 共 4447字 ⁄ 字号 评论关闭

Handler兄果然是handler兄,很给力,这不,刚和人家好上,就有了爱情的种子。有位仁兄要问了:“他是怎么做到的呢?说出来让我学习学习一下,哥这么多年了,还是一直和自己的左手生活着”,好吧,我们就来看看事情是怎样发生的:

  没有错,就在第六节的error = handler->connect(handler, dev, id);这行代码中,发生了那么点事儿,也就是那么点事儿,让他们最终走到了一起了,有时候你不得不佩服那句话的力量“生米煮成熟饭”,不过在当今社会,貌似这话也不再那么给力了……可以看到,此行代码调用了我们这位evdev handler兄的connect函数。好了,见证奇迹的时刻到了:

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,

                      const struct input_device_id *id)

{

       1 struct evdev *evdev;

       2 int minor;

       3 int error;

 

       4 for (minor = 0; minor < EVDEV_MINORS; minor++)

       5     if (!evdev_table[minor])

       6            break;

 

       7 if (minor == EVDEV_MINORS) {

       8     printk(KERN_ERR "evdev: no more free evdev devices/n");

       9     return -ENFILE;

       10 }

 

       11 evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);

       12 if (!evdev)

       13    return -ENOMEM;

 

       14 INIT_LIST_HEAD(&evdev->client_list);

       15 spin_lock_init(&evdev->client_lock);

       16 mutex_init(&evdev->mutex);

       17 init_waitqueue_head(&evdev->wait);

       18 snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);

       19 evdev->exist = 1;

       20 evdev->minor = minor;

 

       21 evdev->handle.dev = input_get_device(dev);

       22 evdev->handle.name = evdev->name;

       23 evdev->handle.handler = handler;

       24 evdev->handle.private = evdev;

 

       25 dev_set_name(&evdev->dev, evdev->name);

       26 evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);

       27 evdev->dev.class = &input_class;

       28 evdev->dev.parent = &dev->dev;

       29 evdev->dev.release = evdev_free;

       30 device_initialize(&evdev->dev);

 

       31 error = input_register_handle(&evdev->handle);

       32 if (error)

       33    goto err_free_evdev;

 

       34 error = evdev_install_chrdev(evdev);

       35 if (error)

       36    goto err_unregister_handle;

 

       37 error = device_add(&evdev->dev);

       38 if (error)

       39 goto err_cleanup_evdev;

 

       40 return 0;

 

 41 err_cleanup_evdev:

       42 evdev_cleanup(evdev);

    43 err_unregister_handle:

       44 input_unregister_handle(&evdev->handle);

    45 err_free_evdev:

       46 put_device(&evdev->dev);

       47 return error;

48 }

估计兄弟你看到这么长的一个函数(其实不算很长,48行代码的函数在内核中算很短的了,当然中间省略了好多的空行),马上会拖动鼠标的滑轮一直往下走,如果你真的这么干了,说明兄弟你很有远见,因为我接下来会一行行的和你来谈论这个事件的经过。如果你没有这样,说明你是一个自由探索精神很强的哥们,好好保持,linux内核开发就需要你这样的人才。闲话不多说,我们来慢慢欣赏这小两口的那点事儿。

1-3行,定义一些基本变量,以后我们会用到的,注意这里来了一新的面孔,struct evdev *evdev,他是谁呢?这儿等会我们再讨论,先来看看这个家伙长什么样:

 

struct evdev {

       int exist;

       int open;

       int minor;

       char name[16];

       struct input_handle handle;

       wait_queue_head_t wait;

       struct evdev_client *grab;

       struct list_head client_list;

       spinlock_t client_lock; /* protects client_list */

       struct mutex mutex;

       struct device dev;

};

现在我们不需要搞清楚里面每一个成员的含义,到了后面你自然就明白了。就是这样,有些东西你在某一个时侯怎么想也想不明白,只要一旦到了某个阶段,再一想想,其实就那么回事。怪自己当时想的多了,考虑的太复杂了,完全没必要。所以人啊,还是要活在当下,好好做好的当前的每一件事情,未来不可遇见,也不知会有什么即将发生在你身上,比如说2012。

4-6行 注意第5行中的evdev_table[minor]数组,她是一个专门用来装evdev的数组,可以把它想象成一个摇篮,只不过这个摇篮很大,一次可以装很多个孩子。注意到34行加粗部分evdev_install_chrdev(evdev)跟踪进去:

static int evdev_install_chrdev(struct evdev *evdev)

{

       /*

        * No need to do any locking here as calls to connect and

        * disconnect are serialized by the input core

        */

       evdev_table[evdev->minor] = evdev;

       return 0;

}

这个函数很简单,把一个孩子evdev放到我们的摇篮中去。现在可以来讨论evdev这个结构是个啥东东了,没有错,他正是evdev handler 和我们那个input 设备美眉两个人在那些激情燃烧的岁月里创造出来的爱情结晶。而evdev_table[minor]这个摇篮是给他们装孩子用的。注意了,前面提过,evdev handler兄比较有福气,女人多,所以linux内核给他准备了一个很大的摇篮,不过摇篮的不同位置有标号的。记住,这位仁兄和一个女人只有一个孩子(计划生意在内核里也有体现的),不过男人毕竟在社会上还是主力军,还得为社会贡献自己的价值,所以老婆不能太多,最多也只可以有EVDEV_MINORS个女人,所以给他分配的那个摇篮最多只能装EVDEV_MINORS个孩子。好了现在回过头来看第4-6行代码。遍历整个摇篮的所有位置。找到一个没有孩子的空位,等下好放孩子。

7-10行,对不起,姐姐,你来晚了,摇篮都满了,说明什么,对,说明handler兄已经有EVDEV_MINORS个老婆了,那么对不起,虽然你们两情同意和,但咱还得遵守婚姻法,走吧,姐姐,当二奶一般转正的可能性不大,何况这位handler兄女人如云。

11-13行,很幸运,姐姐你来的够早,这儿还有位子,所以你们两个可以结婚,还可以生孩子。所以这一行代码比较关键,孩子的生命体在这里诞生了。至于怎么诞生的?这还问我?相信每一个智商正常的哥们都明白如何让他诞生,不明白的话,到两性网上去好好学习一下相关知识。12-13行,很不幸,孩子这个生命体是诞生了,不够还没出娘肚,就夭折了。这是很不幸的。

14-20行,初始化evdev的一些内部成员。比如锁,互斥量,等待队列等等。这里要注意第20行:evdev->minor = minor;把前面内核给孩子分配的摇篮位置号给孩子挂上,等下好对号入座。

21-24行,前面的三大数据结构,好像一直还有一个没出现,对!就是input_handle。这里终于出现了。这三行就是来填充这个数据结构的。input_handle怎么理解呢?对,他就是把孩子和他们的爸爸妈妈绑在一起的一个户口信息本。孩子的爸爸是谁,孩子的妈妈是谁,孩子叫什么名字,从此整个孩子的信息就到我们的handle里面去了。

25-29行,每一个dev设备,最终都要在linux系统中的/dev或者它的递归子目录生成一个文件,以后我们就可以对它进行open,read….操作了,这里几行再加上37行就是专干这事的。

31-33行 提交户口信息本给相关政府单位,让我们可爱的政府知道你们两有孩子了。

后面都是一些错误处理函数,这里就不一一分析,有兴趣的哥们可以去研究一下。

好了,该讲的都讲了,不该讲的好像也讲了。整个故事貌似结束了。如意郎君找到了,婚姻也结了,孩子也生了,户口也注册了。可是当你当回到这个故事的开头,你发现好像什么都还没开始。我们现在确实创造了一个设备文件evdevX(X代表摇篮位置编号)。可是用它来干什么呢?曾哥要说话了:七月份的尾巴,我是狮子座……这还不简单!这里的evdev就是拿来给我们应用开发者操作的,她是她妈akm这个input 设备对应的设备文件实体。怎么用她?那么我们得先搞定她老爸,evdev
handler叔(毕竟有女儿的人了,不能再称兄了)。

抱歉!评论已关闭.