lol韩服语音包2017的xiaofengcanyue是谁

kernel(21)
首先从handler分析,我们看注册了的handler有那些,joydev.c(游戏杆事件),mousedev.c(鼠标事件),evdev.c(通用的触摸屏,按键,sensor等事件),keyboard.c(usb,ps2键盘事件),这里选一个我们最常用的evdev.c分析,在drivers/input/evdev.c中:
1002 static struct input_handler evdev_handler = {
= evdev_event,
= evdev_connect,
.disconnect = evdev_disconnect,
= &evdev_fops,
= EVDEV_MINOR_BASE,
= &evdev&,
= evdev_ids,
1012 static int __init evdev_init(void)
return input_register_handler(&evdev_handler);
1003行event就表示该handler处理事件的能力,所有注册到该handler的触摸屏,按键,sensor等上报事件时,都是经过它来处理并上报到用户空间的。先从1014行开始:
1936 int input_register_handler(struct input_handler *handler)
struct input_dev *
retval = mutex_lock_interruptible(&input_mutex);
if (retval)
INIT_LIST_HEAD(&handler-&h_list);
if (handler-&fops != NULL) {
if (input_table[handler-&minor && 5]) {
retval = -EBUSY;
input_table[handler-&minor && 5] =
list_add_tail(&handler-&node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
1947行不为NULL,所以将该input_handler放到input_table数组中,其中input_table的定义和handler-&minor的值为:
&& &static struct input_handler *input_table[8];
&& &#define EVDEV_MINOR_BASE&&& 64
从input_table数组的大小可以看出,linux子系统最多可以注册8个handler,那么每个handler可以处理多少个设备呢,难道和minor && 5有关,32个?接着往下看就知道了。接着1955行,将改handler加入input_handler_list链表中,input_handler_list链表维护着所有注册到输入子系统的handler。1957行,input_dev_list为所有注册了的input_dev链表(我们后面会看到这一点),list_for_each_entry遍历所有的input_dev,看看这些input_dev是否和该handler匹配,这里假设是input_handler先注册的,所有的input_dev都还没有注册,所以这里input_dev_list为空,这样input_register_handler注册就完成了。
接着看看input_dev的注册过程,就拿一个具体的按键事件分析,在drivers/input/keyboard/imapx800_gpio.c中:
struct input_dev *
input = input_allocate_device();
input-&name = &imap-gpio&;
input-&phys = &imap-gpio/input0&;
input-&dev.parent = &pdev-&
input-&id.bustype = BUS_HOST;
input-&id.vendor = 0x0001;
input-&id.product = 0x0001;
input-&id.version = 0x0100;
error = input_register_device(input);input_allocate_device():
1660 struct input_dev *input_allocate_device(void)
struct input_dev *
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
if (dev) {
dev-&dev.type = &input_dev_
dev-&dev.class = &input_
device_initialize(&dev-&dev);
mutex_init(&dev-&mutex);
spin_lock_init(&dev-&event_lock);
INIT_LIST_HEAD(&dev-&h_list);
INIT_LIST_HEAD(&dev-&node);
__module_get(THIS_MODULE);
527行,这里的dev.parent指向&pdev-&dev,pdev为platform_device,看354行的重点部分:
int input_register_device(struct input_dev *dev)
........................
dev_set_name(&dev-&dev, &input%ld&,
(unsigned long) atomic_inc_return(&input_no) - 1);
error = device_add(&dev-&dev);
if (error)
path = kobject_get_path(&dev-&dev.kobj, GFP_KERNEL);
pr_info(&%s as %s\n&,
dev-&name ? dev-&name : &Unspecified device&,
path ? path : &N/A&);
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
if (error) {
device_del(&dev-&dev);
list_add_tail(&dev-&node, &input_dev_list);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
....................
1885行,将该input_dev挂到input_dev_list链表中,该链表前面注册handler的时候就遇到过,所以我们可以发现,不管是先注册handler还是input_dev,他们都会遍历对方的链表,从而进行匹配。看重点的1887行,这里的input_handler_list挂的就是前面evdev.c中的handler,当然还可能有别的handler,如游戏杆等。进入input_attach_handler函数中:
908 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
const struct input_device_id *
id = input_match_device(handler, dev);
return -ENODEV;
error = handler-&connect(handler, dev, id);
if (error && error != -ENODEV)
pr_err(&failed to attach handler %s to device %s, error: %d\n&,
handler-&name, kobject_name(&dev-&dev.kobj), error);
913行的input_match_device匹配规则:
867 static const struct input_device_id *input_match_device(struct input_handler *handler,
struct input_dev *dev)
const struct input_device_id *
for (id = handler-&id_ id-&flags || id-&driver_ id++) {
if (id-&flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id-&bustype != dev-&id.bustype)
if (id-&flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id-&vendor != dev-&id.vendor)
if (id-&flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id-&product != dev-&id.product)
if (id-&flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id-&version != dev-&id.version)
MATCH_BIT(evbit,
MATCH_BIT(keybit, KEY_MAX);
MATCH_BIT(relbit, REL_MAX);
MATCH_BIT(absbit, ABS_MAX);
MATCH_BIT(mscbit, MSC_MAX);
MATCH_BIT(ledbit, LED_MAX);
MATCH_BIT(sndbit, SND_MAX);
MATCH_BIT(ffbit,
MATCH_BIT(swbit,
if (!handler-&match || handler-&match(handler, dev))
return NULL;
这里873行的handler-&id_table为evdev.c中input_handler结构体指向的:
995 static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 },
/* Matches all devices */
/* Terminating zero entry */
可以看到, id-&flags为0, id-&driver_info为1,所以前面的if条件都不成立了,到901行,这里handler-&match为空,所以返回了该id,即handler-&id_table。接着handler-&connect(handler, dev, id)调用了handler结构体中的connect指向的函数,这里在evdev.c中有定义,所以进入该函数:
922 static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
struct evdev *
for (minor = 0; minor & EVDEV_MINORS; minor++)
if (!evdev_table[minor])
if (minor == EVDEV_MINORS) {
pr_err(&no more free evdev devices\n&);
return -ENFILE;
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
if (!evdev)
return -ENOMEM;
INIT_LIST_HEAD(&evdev-&client_list);
spin_lock_init(&evdev-&client_lock);
mutex_init(&evdev-&mutex);
init_waitqueue_head(&evdev-&wait);
dev_set_name(&evdev-&dev, &event%d&, minor);
evdev-&exist =
evdev-&minor =
evdev-&handle.dev = input_get_device(dev);
evdev-&handle.name = dev_name(&evdev-&dev);
evdev-&handle.handler =
evdev-&handle.private =
evdev-&dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev-&dev.class = &input_
evdev-&dev.parent = &dev-&
evdev-&dev.release = evdev_
device_initialize(&evdev-&dev);
error = input_register_handle(&evdev-&handle);
if (error)
goto err_free_
error = evdev_install_chrdev(evdev);
if (error)
goto err_unregister_
error = device_add(&evdev-&dev);
if (error)
goto err_cleanup_
err_cleanup_evdev:
evdev_cleanup(evdev);
err_unregister_handle:
input_unregister_handle(&evdev-&handle);
err_free_evdev:
put_device(&evdev-&dev);
929行,这里的EVDEV_MINORS定义为:
&& &#define EVDEV_MINORS&&&&&&& 32&
这里就是把input_dev添加到evdev_table数组中,而且933行,我们发现,如果如果添加的input_dev大于32过的话,就不能继续添加了,说明该handler最都只能挂32个设备,也证实了前面的猜想是正确的。
938行创建evdev结构体,该结构体有一个成员input_handle,该handle用来连接handler和input_dev,我们可以从951和953行看到,他保存了handler和input_dev的位置以便后续查找
956行创建设备节点的主设备和从设备号,可以看到,挂在该输入子系统的主设备号是一样的,从设备号从0-255,所以输入子系统最多可以挂256个设备。
接着962行,就是把handle注册进input子系统。996行evdev_install_chrdev将evdev保存起来以便后面用到:
871 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] =
970经过device_add后,节点就出现在了dev/input目录下面,如event0,event1,event2,event3,编号是按照注册顺序在947行递增的。
接着来看数据的上报过程,首先在上层打开设备节点,如dev/input/event0,我们开看这个过程。用户空间open后,调用drivers/input/input.c的file_operations中的open:
2146 static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
.llseek = noop_llseek,
2150 };2148行input_open_file:
2106 static int input_open_file(struct inode *inode, struct file *file)
struct input_handler *
const struct file_operations *old_fops, *new_fops = NULL;
err = mutex_lock_interruptible(&input_mutex);
/* No load-on-demand here? */
handler = input_table[iminor(inode) && 5];
if (handler)
new_fops = fops_get(handler-&fops);
mutex_unlock(&input_mutex);
* That's _really_ odd. Usually NULL -&open means &nothing special&,
* not &no device&. Oh, well...
if (!new_fops || !new_fops-&open) {
fops_put(new_fops);
err = -ENODEV;
old_fops = file-&f_
file-&f_op = new_
err = new_fops-&open(inode, file);
if (err) {
fops_put(file-&f_op);
file-&f_op = fops_get(old_fops);
fops_put(old_fops);
2117行,iminor(inode)找到从设备号,由于evdev.c中的handler从设备号码是EVDEV_MINOR_BASE + minor,其中minor为0~31,EVDEV_MINOR_BASE为64,所以从设备号 && 5后就是1,这样就找到了前面evdev.c中注册的handler。
2119行,取得handler的file_operations结构体;2136行,将open指向了handler中file_operations的open。从这里可以看出,input.c中的open只是起了一个回调函数的作用,最后就是回调各自handler自己实现的file_operations中的open函数。所以进入evdev.c中:
855 static const struct file_operations evdev_fops = {
= THIS_MODULE,
= evdev_read,
= evdev_write,
= evdev_poll,
= evdev_open,
= evdev_release,
.unlocked_ioctl = evdev_ioctl,
863 #ifdef CONFIG_COMPAT
.compat_ioctl
= evdev_ioctl_compat,
865 #endif
= evdev_fasync,
= evdev_flush,
= no_llseek,
869 };860行evdev_open:
283 static int evdev_open(struct inode *inode, struct file *file)
struct evdev *
struct evdev_client *
int i = iminor(inode) - EVDEV_MINOR_BASE;
if (i &= EVDEV_MINORS)
return -ENODEV;
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
evdev = evdev_table[i];
if (evdev)
get_device(&evdev-&dev);
mutex_unlock(&evdev_table_mutex);
if (!evdev)
return -ENODEV;
bufsize = evdev_compute_buffer_size(evdev-&handle.dev);
client = kzalloc(sizeof(struct evdev_client) +
bufsize * sizeof(struct input_event),
GFP_KERNEL);
if (!client) {
error = -ENOMEM;
goto err_put_
client-&bufsize =
spin_lock_init(&client-&buffer_lock);
snprintf(client-&name, sizeof(client-&name), &%s-%d&,
dev_name(&evdev-&dev), task_tgid_vnr(current));
wake_lock_init(&client-&wake_lock, WAKE_LOCK_SUSPEND, client-&name);
client-&evdev =
evdev_attach_client(evdev, client);
error = evdev_open_device(evdev);
if (error)
goto err_free_
file-&private_data =
nonseekable_open(inode, file);
err_free_client:
evdev_detach_client(evdev, client);
wake_lock_destroy(&client-&wake_lock);
kfree(client);
err_put_evdev:
put_device(&evdev-&dev);
191 static void evdev_attach_client(struct evdev *evdev,
struct evdev_client *client)
spin_lock(&evdev-&client_lock);
list_add_tail_rcu(&client-&node, &evdev-&client_list);
spin_unlock(&evdev-&client_lock);
297行,evdev_table在前面connect函数中时候已经分析过,evdev_install_chrdev函数中保存的这里根据minor的值取出对应的evdev,这样我们就可以根据evdev的hanle找到对应的input_dev。307行创建保存上报数据的机构体,后续会分析,321行evdev_attach_client,就是将client添加到client_list链表中,323行,做一些open的处理工作,这样open操作就完成了。
接着用户空间会调用read,poll,ioctl等操作来过去事件,我们来看android最常用的poll + read方法,最终调用evdev.c的file_operations中poll:
433 static unsigned int evdev_poll(struct file *file, poll_table *wait)
struct evdev_client *client = file-&private_
struct evdev *evdev = client-&
poll_wait(file, &evdev-&wait, wait);
mask = evdev-&exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
if (client-&packet_head != client-&tail)
mask |= POLLIN | POLLRDNORM;
439行可以看到,poll操作会阻塞在这里,等待底层的上报事件唤醒。所以我们接着看看底层事件的上报,还是前面的drivers/input/keyboard/imapx800_gpio.c中:
&& &input_event(ptr-&input, EV_KEY, ptr-&code, 0);
&& &input_sync(ptr-&input);
其中的详细过层这里就不分析了,最终会调用handler的event方法:
95 static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
struct evdev *evdev = handle-&
struct evdev_client *
struct input_
ktime_get_ts(&ts);
event.time.tv_sec = ts.tv_
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
event.type =
event.code =
event.value =
rcu_read_lock();
client = rcu_dereference(evdev-&grab);
if (client)
evdev_pass_event(client, &event);
list_for_each_entry_rcu(client, &evdev-&client_list, node)
evdev_pass_event(client, &event);
rcu_read_unlock();
if (type == EV_SYN && code == SYN_REPORT)
wake_up_interruptible(&evdev-&wait);
104~108行对input_event结构体赋值,这就是最终要上报数据的结构体,114行,最终调用 kill_fasync(&client-&fasync, SIGIO, POLL_IN)唤醒异用户空间使用步等待读取事件的进程,这是主动唤醒用户空间的方法,122行,唤醒前面用户空间poll的阻塞,所以回到前面poll阻塞的地方,poll_wait已经被唤醒,用户空间知道有数据上报了,接着会调用read去读取数据,这样就调用了file_operations的evdev_read:
397 static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
struct evdev_client *client = file-&private_
struct evdev *evdev = client-&
struct input_
if (count & input_event_size())
return -EINVAL;
if (!(file-&f_flags & O_NONBLOCK)) {
retval = wait_event_interruptible(evdev-&wait,
client-&packet_head != client-&tail || !evdev-&exist);
if (retval)
if (!evdev-&exist)
return -ENODEV;
while (retval + input_event_size() &= count &&
evdev_fetch_next_event(client, &event)) {
if (input_event_to_user(buffer + retval, &event))
return -EFAULT;
retval += input_event_size();
if (retval == 0 && file-&f_flags & O_NONBLOCK)
retval = -EAGAIN;
430 }这里主要就是421行了,把数据拷贝到用户空间,这样整个上报过程就完成了。
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:182277次
积分:2488
积分:2488
排名:第13520名
原创:55篇
转载:48篇
评论:51条
(1)(1)(1)(1)(1)(2)(1)(2)(1)(1)(3)(1)(1)(1)(1)(2)(1)(2)(10)(5)(6)(3)(4)(10)(6)(2)(8)(13)(11)(1)}

我要回帖

更多关于 lol韩服语音包2017 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信