UInput driver分析
http://blog.sina.com.cn/s/blog_602f87700100llew.html
标签:
it |
分类: linux_kernel |
作者:Sam (甄峰) sam_code@hotmail.com
Sam在开发中需要在用户态程序中模拟系统Keyboard,Mouse event. 开始想用之前在2.4 Kernel中开发的一个Virtual Input Driver,在改写为2.6Kernel模式后,连续尝试了2个嵌入式平台,发现竟然都缺乏必要的内核符号。突然想起之前在哪看到过Input User level driver这样的东西。赶快问了问Google老师。发现它就是UInput。(发现TCC8900所使用的IR Remote Controller Driver与Sam很多年前在S3C2440A上开发的IR Remote Controller Driver做法几乎完全一致,嘿嘿)
赶快以Module形式编译uinput.
先察看drivers/input/misc/Kconfig,看到INPUT_UINPUT(User level driver support)前提为INPUT_MISC。
于是在make menuconfig中
Device Drivers --->
Input device support --->
[*] Miscellaneous devices --->
<M> User level driver support
呵呵,现在才理解misc是各种其它非标准设备的意思。
#make
将其编译为uinput.ko
读uinput.c之前,最好先读 driver/char/misc.c
解析 misc.c
1. init函数
subsys_initcall(misc_init);
insmod misc时,会调用misc_init()
misc_init()使用比较老的方式创建字符设备driver:
register_chrdev(MISC_MAJOR,"misc",&misc_fops)
主设备号为:MISC_JAJOR=10
driver名字为 misc, 在/proc/device中出现。
driver处理程序为misc_fops.
2. driver处理程序:
static const struct file_operations misc_fops = {
.owner =
THIS_MODULE,
.open =
misc_open,
};
也就是说:它只赋值了open--misc_open()
换句话说,当用户在使用系统调用open主设备号为10的device时,kernel会最终调用misc_open().
misc_open():
它首先察看全局链表misc_list 成员中是否有次设备号与open()参数inode的次设备号相同。
如果有,则将链表中c->fops取出,并用它取代参数2 file中的fops.
并调用c->fops->open(inode, file)
注意:这里非常关键,因为misc是一系列driver的组合。各个driver所做工作完全不同,他们之间使用次设备号区分。
但Kernel只关心主设备号,也就是说,它只会把主设备号对应的file给对应出来。所以在open()时,需要使用次设备号作标记,替换对应driver的file(open()的参数2)的fops.
3.int misc_register(struct miscdevice * misc)
查全局链表misc_list内容。如果需要注册的参数misc的子设备号在链表misc_list中已经存在。则返回busy.
如果注册的参数misc的子设备号为MISC_DYNAMIC_MINOR(255,动态子设备号)。则从misc全局子设备号(misc_minors)中取出一个未用的来使用。并将misc_minors中对应子设备号标记为已用。
建立dev_t (主,次设备号)
并经参数misc加入到misc_list中去。
这样,就很清楚misc的处理了。先使用misc_register()注册一个次设备号对应driver.并将其放入misc_list链表。当用户使用系统调用open主设备号为10的device时,则在misc_list寻找device(也就是node)对应的次设备号fops对应file的对应fops.
解析 uinput.c
1. init函数
module_init(uinput_init);
insmod uinput时,会调用uinput_init()
它调用misc_register(&uinput_misc);
请注意参数uinput_misc。
static struct miscdevice uinput_misc = {
.fops =
&uinput_fops,
.minor =
UINPUT_MINOR, (223)
.name =
UINPUT_NAME, (uinput)
};
注册后,当用户使用系统调用open主设备号为10,次设备号为223的node时,则使用uinput_fops取代file->fops.
且同时调用fops->open()
2. open函数:
创建结构体uinput_device 实体,并将file->private_data 指向该实体。
struct uinput_device {
struct input_dev *dev;
struct
mutex mutex;
enum uinput_state state;
wait_queue_head_t waitq;
unsigned
char ready;
unsigned
char head;
unsigned
char tail;
struct
input_event buff[UINPUT_BUFFER_SIZE];
struct
uinput_request *requests[UINPUT_NUM_REQUESTS];
wait_queue_head_t requests_waitq;
spinlock_t requests_lock;
};

浙公网安备 33010602011771号