Chinaunix首页 | 论坛 | 博客
  • 博客访问: 483483
  • 博文数量: 285
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 629
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-14 17:53
个人简介

相信自己,快乐每一天

文章分类

全部博文(285)

分类: LINUX

2013-10-23 11:39:27

input子系统

转载 请注明 来自 http://www.cnblogs.com/sdphome/
Input初始化分析
static int __init input_init(void)
{
int err;

input_init_abs_bypass();

err = class_register(&input_class); //注册一个input的类,所有的input设备都是这个类
if (err) {
printk(KERN_ERR "input: unable to register input_dev class\n");
return err;
}

err = input_proc_init();
if (err)
goto fail1;

err = register_chrdev(INPUT_MAJOR, "input", &input_fops); 注册字符设备,
input设备主设备号为13
if (err) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
goto fail2;
}

return 0;

fail2: input_proc_exit();
fail1: class_unregister(&input_class);
return err;
}

static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};

int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler;
const char *path;
int error;

/* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit); //设置支持的事件

/* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->keybit);

/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);

/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*/
init_timer(&dev->timer); //初始化定时器
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}

if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode;

if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;

dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);

error = device_add(&dev->dev); //添加设备进总线
if (error)
return error;

path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); //创建sys目录
printk(KERN_INFO "input: %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);
return error;
}

list_add_tail(&dev->node, &input_dev_list); //将该设备加入到input设备链表中

list_for_each_entry(handler, &input_handler_list, node) 
input_attach_handler(dev, handler);
对每一个挂在input_handler_list的handler调用input_attach_handler
input_wakeup_procfs_readers();
input_handler_list链表是在input_register_handler中填充,input_dev_list是在input_register_device中填充添加。

mutex_unlock(&input_mutex);

return 0;
}

static void input_repeat_key(unsigned long data)
{
struct input_dev *dev = (void *) data;
unsigned long flags;

spin_lock_irqsave(&dev->event_lock, flags);

if (test_bit(dev->repeat_key, dev->key) &&
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {

input_pass_event(dev, EV_KEY, dev->repeat_key, 2);

if (dev->sync) { //如果更新标志位设置了,上报更新
/*
* Only send SYN_REPORT if we are not in a middle
* of driver parsing a new hardware packet.
* Otherwise assume that the driver will send
* SYN_REPORT once it's done.
*/
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}

if (dev->rep[REP_PERIOD])
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}

spin_unlock_irqrestore(&dev->event_lock, flags);
}

int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
int retval;

retval = mutex_lock_interruptible(&input_mutex);
if (retval)
return retval;

INIT_LIST_HEAD(&handler->h_list);

if (handler->fops != NULL) {
if (input_table[handler->minor >> 5]) {
retval = -EBUSY;
goto out;
}
input_table[handler->minor >> 5] = handler; //除以32,每32个次设备号对应一个handler,evdev为64~64-1
}

list_add_tail(&handler->node, &input_handler_list); //添加handler到input_handler_list链表中

list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
对每一个挂在input_dev_list链表中的dev调用input_attach_handler.
input_wakeup_procfs_readers();

out:
mutex_unlock(&input_mutex);
return retval;
}

在evbug.c,evdev.c,joydev.c,mousedev.c中分别调用了一次
input_register_handler,注册对应属性的handler

joydev.c ------Joystick device driver---- 游戏手柄/操纵杆支持
mousedev.c -------ExplorerPS/2 device driver------鼠标支持
evdev.c------Event char devices, giving access to raw input device events.---原始输入设备支持

在这里只分析evdev.c,因为一般都是evdev设备

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error;

id = input_match_device(handler, dev); //主要调用了handler的match函数
if (!id)
return -ENODEV;

error = handler->connect(handler, dev, id); //handler的connect函数
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);

return error;
}
从上面程序中可以知道,attach的过程就是调用handler的match函数,match通过,进行connect

static const struct input_device_id *input_match_device(struct input_handler *handler,
struct input_dev *dev)
{
const struct input_device_id *id;
int i;

for (id = handler->id_table; id->flags || id->driver_info; id++) {

if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->bustype != dev->id.bustype)
continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->vendor != dev->id.vendor)
continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->product != dev->id.product)
continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->version != dev->id.version)
continue;

MATCH_BIT(evbit, EV_MAX);
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, FF_MAX);
MATCH_BIT(swbit, SW_MAX);

if (!handler->match || handler->match(handler, dev)) 
//调用handler的match,如果未定义match则直接返回id
return id;
}

return NULL;
}



evdev分析
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}

static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct evdev *evdev;
int minor;
int error;

for (minor = 0; minor < EVDEV_MINORS; minor++)
if (!evdev_table[minor])
break;

if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: 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 = 1;
evdev->minor = minor;

evdev->handle.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;
evdev->handle.private = evdev;
这个结构封装了一个handle结构,这个结构与handler不同,handle可以看成是handler和input device的结合。
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
在这段代码里主要完成evdev封装的device的初始化.注意在这里,使它所属的类指向input_class.这样在/sysfs中创建的设备目录就会在/sys/class/input/下面显示.

error = input_register_handle(&evdev->handle);
if (error)
goto err_free_evdev;

error = evdev_install_chrdev(evdev);
if (error)
goto err_unregister_handle;

error = device_add(&evdev->dev); //将evdev->device注册到sysfs
if (error)
goto err_cleanup_evdev;

return 0;

err_cleanup_evdev:
evdev_cleanup(evdev);
err_unregister_handle:
input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
return error;
}

int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
int error;

/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
error = mutex_lock_interruptible(&dev->mutex);
if (error)
return error;

//将handle挂载到h_list结构体
if (handler->filter)
list_add_rcu(&handle->d_node, &dev->h_list);
else
list_add_tail_rcu(&handle->d_node, &dev->h_list);

mutex_unlock(&dev->mutex);

//还将handle挂载在handler的h_list结构体
list_add_tail_rcu(&handle->h_node, &handler->h_list);
//如果handler定义了start,则调用start,这里没有定义
if (handler->start)
handler->start(handle);

return 0;
}

static int evdev_install_chrdev(struct evdev *evdev)
{
evdev_table[evdev->minor] = evdev; //evdev_table的minor项指向evdev.
return 0;
}

event层分析
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
}

static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}

static inline void input_mt_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
}
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
unsigned long flags;

if (is_event_supported(type, dev->evbit, EV_MAX)) {

spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);
input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}

#define INPUT_IGNORE_EVENT 0
#define INPUT_PASS_TO_HANDLERS 1
#define INPUT_PASS_TO_DEVICE 2
#define INPUT_PASS_TO_ALL
(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)

static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT;

switch (type) {

case EV_SYN:
switch (code) {
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;

case SYN_REPORT:
if (!dev->sync) {
dev->sync = 1; //更新
disposition = INPUT_PASS_TO_HANDLERS; //控制权交给handler
}
break;
case SYN_MT_REPORT:
dev->sync = 0; //等待更新
disposition = INPUT_PASS_TO_HANDLERS; //控制权交给handler
break;
}
break;

case EV_KEY:
if (is_event_supported(code, dev->keybit, KEY_MAX) && //判断事件是否有效
!!test_bit(code, dev->key) != value) {

if (value != 2) {
__change_bit(code, dev->key);
if (value)
input_start_autorepeat(dev, code); //如果有按键按下,则循环
else
input_stop_autorepeat(dev);
}

disposition = INPUT_PASS_TO_HANDLERS;
}
break;

case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {

__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;

case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX)) {

if (test_bit(code, input_abs_bypass)) {
disposition = INPUT_PASS_TO_HANDLERS;
break;
}

value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]); //处理坐标,什么原理啊??

if (dev->abs[code] != value) {
dev->abs[code] = value; //保存value到dev->abs[code]
disposition = INPUT_PASS_TO_HANDLERS;
}
}
break;

case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;
break;

case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;
break;

case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {

__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {

if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_REP:
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_FF:
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;

case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
break;
}

if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = 0;

if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) //调用device的event函数,如果定义了dev->event的话
dev->event(dev, type, code, value);

if (disposition & INPUT_PASS_TO_HANDLERS) //调用handler的event函数
input_pass_event(dev, type, code, value);
}

static int input_defuzz_abs_event(int value, int old_val, int fuzz)
{ 什么原理啊???
if (fuzz) {
if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
return old_val;

if (value > old_val - fuzz && value < old_val + fuzz)
return (old_val * 3 + value) / 4;

if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
return (old_val + value) / 2;
}

return value;
}

static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
struct input_handle *handle;

rcu_read_lock();

handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value); //evdev的event函数
else {
bool filtered = false;

list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
if (!handle->open)
continue;

handler = handle->handler; //找到handle
if (!handler->filter) {
if (filtered)
break;

handler->event(handle, type, code, value);

} else if (handler->filter(handle, type, code, value))
filtered = true;
}
}

rcu_read_unlock();
}

evdev中还有一个比较重要的函数是evdev_event
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event; //input_event结构体,即为上层上报的事件
struct input_event {
struct timeval time; //事件上报事件
__u16 type; //事件类型码,如EV_ABS/EV_KEY/EV_REL/EV_SYN
__u16 code; //按键时为扫描码,触摸屏时为数据类型
__s32 value; //属性值,按键时代表按下弹起,触摸屏为数据
};
struct timespec ts;

ktime_get_ts(&ts);
event.time.tv_sec = ts.tv_sec; //填充时间,秒
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC; //纳秒

event.type = type; //填充类型码
event.code = code; //填充按键扫描码或touch数据类型
event.value = value; //填充数据类型值

rcu_read_lock();

client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event);

rcu_read_unlock();

wake_up_interruptible(&evdev->wait); //唤醒睡眠在evdev->wait等待队列等待输入信息的进程,通知evdev_read读取。
}

static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock);
client->buffer[client->head++] = *event; //加入client的信息缓冲
client->head &= EVDEV_BUFFER_SIZE - 1; //环形缓存区处理
spin_unlock(&client->buffer_lock);

if (event->type == EV_SYN)
kill_fasync(&client->fasync, SIGIO, POLL_IN); //发送SIGIO信号,告知事件
}
//将event保存到client->buf中,client->head是当前数据的位置。注意这里是一个环形缓存区.写数据是从client->head写.而读数据则是从client->tail中读.

信息读取
//设备的open函数
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler;
const struct file_operations *old_fops, *new_fops = NULL;
int err;

err = mutex_lock_interruptible(&input_mutex);
if (err)
return err;

/* No load-on-demand here? */
handler = input_table[iminor(inode) >> 5]; //根据次设备号来得到handler,次设备号右移5位,这个就是input子系统次设备号的分配了,evdev的次设备号是64~64+32-1,对应着同一个handler
if (handler)
new_fops = fops_get(handler->fops); //得到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;
goto out;
}

old_fops = file->f_op; //保存老的fops
file->f_op = new_fops; //然后将handler中的fops替换掉当前的fops.这样只要设备open以后,调用其它的函数时(如read,write,poll,ioctl就可以调用)

err = new_fops->open(inode, file); //调用handler的fops中的open
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
out:
return err;
}
//event层中的read函数
static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
int retval;

if (count < input_event_size())
return -EINVAL;

if (client->head == client->tail && evdev->exist && //缓存中没有数据,且设备存在
(file->f_flags & O_NONBLOCK))
return -EAGAIN;

retval = wait_event_interruptible(evdev->wait,
client->head != client->tail || !evdev->exist); //等待evdev_event函数去唤醒
if (retval)
return 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)) //将event结构copy_to_user,给用户层
return -EFAULT;

retval += input_event_size();
}

return retval;
}

static int evdev_fetch_next_event(struct evdev_client *client,
struct input_event *event)
{
int have_event;

spin_lock_irq(&client->buffer_lock);

have_event = client->head != client->tail;
if (have_event) {
*event = client->buffer[client->tail++];
client->tail &= EVDEV_BUFFER_SIZE - 1;
}

spin_unlock_irq(&client->buffer_lock);

return have_event;
}

int input_event_to_user(char __user *buffer,
const struct input_event *event)
{
if (copy_to_user(buffer, event, sizeof(struct input_event)))
return -EFAULT;

return 0;
}







input子系统总结
1.input.c中 input_init
注册input类,初始化proc,注册设备register_chrdev(INPUT_MAJOR, "input", &input_fops)
2.evdev.c中 evdev_init
input_register_handler(&evdev_handler)注册handler : 将evdev_handler加入到input_handler_list链表中,然后遍历每一个挂在Input_dev_list上的设备调用input_attach_handler
3.inp[ut.c中 input_register_device
device_Add(&dev->dev) →
Kobject_get_path 创建sys接口→
list_add_tail(&dev->node.&input_dev_list)将设备加入全局链表中→
然后遍历input_handler_list中的每一个handler,调用input_attach_handler进行attach
4.input.c中 input_attach_handler
调用input_match_device检测id匹配情况,然后调用handler中的connect函数 : 
在connect中封装了handle和evdev->dev结构体
input_register_handle注册handle,handle可看作handler和device的结合
最终调用device_Add(&evdev->dev)
5.input_event
Input_event -->input_handler_event :对type进行switch查找,对不同事件执行不同处理。对于按键和触摸屏,交由handler->event处理。-->
Input_pass_event →
handler->event-->即evdev_event函数
在evdev_event中封装了input_event,并将该结构体保存在client->buffer[client->head++]数组中。client中的buffer会处理成环形缓冲区,
处理方式: client->head &= EVDEV_BUFFER_SIZE-1
6.evdev.c中 evdev_read
将client中的input_event结构体提取出来,然后将该结构体copy_to_user到应用层。

阅读(325) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~