LDD之input子系统--代码分析

原创 2012年03月29日 14:41:31
-----------------------------------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:http://blog.csdn.net/android_huber
交流邮箱:dp.shao@gmail.com
-----------------------------------------------------------------------



                                                   input子系统 ---  代码分析

                                                       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子系统的代码,可能看了这么多代码后大家的心里对input的整个框架并不了解,我将在稍后的一篇文章中,放入我刚画好的一张input子系统框架流程图,同时还有对input子系统的一些简单总结,到时大家可以参照一下,会对理解整个input子系统会有帮助。


 结合下一篇带流程图的文章一起看。

http://blog.csdn.net/android_huber/article/details/7407217

图比较大,看不全保存在本地方便放大看。



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

lib\kobject.c文件分析

本文件的函数列表:   char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) 获取指定kobject的完整路径名   vo...

LDD之input子系统 总结与流程图

----------------------------------------------------------------------- 本文系本站原创,欢迎转载! 转载请注明出处:http:/...

Kobject结构体分析

kobject是组成设备device、驱动driver、总线bus、class的基本结构。如果把前者看成基类,则后者均为它的派生产物。device、driver、bus、class构成了设备模型,而k...

代码分析:input子系统

一、input子系统概述 在linux下,按键、触摸屏、鼠标等都可以利用input接口函数来实现设备驱动。 1,linux输入子系统主要分三层: 驱动,输入CORE, 事件处理层。 驱动根据CORE提...

LDD3块设备代码分析

整个块设备抽象的数据结构struct sbull_dev {        int size;                       ...

输入子系统(2):代码分析

1:概述 上一篇文章对input子系统中的数据结构做了总结,本篇通过对代码的分析,总结输入子系统的整体架构;本文中所涉及的文件有:input.c和evdev.c文件; input.c:是输入子系统的核...

linux kernel的中断子系统:GIC代码分析

一、前言 GIC(Generic Interrupt Controller)是ARM公司提供的一个通用的中断控制器,其architecture specification目前有四个版本,V1~V...

输入服务子系统框架代码分析(韦东山的视频总结及针对linux-2.6.30.4)

自己的总结有错误请评论,我们共同进步。 static struct input_handler *input_table[8]; /*入口函数*/ static int __init inpu...

linux kernel的中断子系统之(七):GIC代码分析

linux kernel的中断子系统之(七):GIC代码分析 作者:linuxer 发布于:2014-9-4 19:59 分类:Linux内核分析 一、前言 GIC(Generic Inte...
  • M_O_Bz
  • M_O_Bz
  • 2014-10-29 03:08
  • 4446
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)