input输入子系统框架

http://blog.csdn.net/myarrow/article/details/7098504

http://blog.csdn.net/sdvch/article/details/44619789

网上的例子很多,如上。

数据结构


static LIST_HEAD(input_dev_list);
static LIST_HEAD(input_handler_list);


struct input_dev {
	const char *name;
	const char *phys;
	const char *uniq;
	struct input_id id;

	........
	spinlock_t event_lock;
	struct mutex mutex;

	unsigned int users;
	bool going_away;

	struct device dev;

	struct list_head	h_list;
	struct list_head	node;

	unsigned int num_vals;
	unsigned int max_vals;
	struct input_value *vals;

	bool devres_managed;
};

struct input_handler {

	void *private;

	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
	void (*events)(struct input_handle *handle,
		       const struct input_value *vals, unsigned int count);
	bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
	bool (*match)(struct input_handler *handler, struct input_dev *dev);
	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
	void (*disconnect)(struct input_handle *handle);
	void (*start)(struct input_handle *handle);

	bool legacy_minors;
	int minor;
	const char *name;

	const struct input_device_id *id_table;

	struct list_head	h_list;
	struct list_head	node;
};


匹配,connect成功后,会把handler和input_dev放进来。并且把h_node和d_node分别放到handler和input_dev的h_list链表中。

struct input_handle {

	void *private;

	int open;
	const char *name;

	struct input_dev *dev;
	struct input_handler *handler;

	struct list_head	d_node;
	struct list_head	h_node;
};
evdev.c注册
static struct input_handler evdev_handler = {
	.event		= evdev_event,
	.events		= evdev_events,
	.connect	= evdev_connect,
	.disconnect	= evdev_disconnect,
	.legacy_minors	= true,
	.minor		= EVDEV_MINOR_BASE,
	.name		= "evdev",
	.id_table	= evdev_ids,
};



input.c是核心层,向设备驱动层和事件驱动层提供接口,我们需要实现的是设备驱动层,通常会调用input_event,input_sync之类的函数,事件驱动层就是evdev和kbd之类的。   

当系统启动时候,设备驱动程序会调用input_register_device,并执行list_add_tail(&dev->node, &input_dev_list);将此设备假如到链表中。并去input_handler_list中查找此dev对应的handler,比如dev对应acc_gyro,handler对应evdev,如果对应上了,就进行connect,在connect函数中将创建evdev,并将匹配上的handler和input_dev,分别填充到结构体中。并注册input_register_handle。此函数的作用是将已经创建的handle结构体中的d_node 和 h_node分别加入自己的成员变量input_dev->h_list和hander_dev->h_list中。这个有什么作用,搜索下d_node,在函数input_pass_values中,会遍历所有的dev->h_list,中的d_node,找到对应的handle,handle在找到对应的handler,handler在找到对应的client,client对应的eventX节点。这个也是数据传输的过程。基本是connect时候是绑定,发送数据时候找到对应的client。

handle对应的是eventX,handler对应的是kdb或者evdev,client对应的是event_number,input_dev对应得是acc_gyro.另外分层的设计一般都会设计到函数的注册和查询匹配。

这是发送数据的代码片段,遍历input_dev的链表,如果设备在上层已经打开就开始传输数据。

	list_for_each_entry_rcu(handle, &dev->h_list, d_node)
			if (handle->open){
				count = input_to_handler(handle, vals, count);
				}
	}


函数

设备驱动注册。

int input_register_device(struct input_dev *dev)
{
	struct input_devres *devres = NULL;
	struct input_handler *handler;
	unsigned int packet_size;
	const char *path;
	int error;

	if (dev->devres_managed) {
		devres = devres_alloc(devm_input_device_unregister,
				      sizeof(struct input_devres), GFP_KERNEL);
		if (!devres)
			return -ENOMEM;

		devres->input = dev;
	}

	/* 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);

	packet_size = input_estimate_events_per_packet(dev);
	if (dev->hint_events_per_packet < packet_size)
		dev->hint_events_per_packet = packet_size;

	dev->max_vals = dev->hint_events_per_packet + 2;
	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
	if (!dev->vals) {
		error = -ENOMEM;
		goto err_devres_free;
	}

	/*
	 * 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.
	 */
	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;

	error = device_add(&dev->dev);
	if (error)
		goto err_free_vals;

	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)
		goto err_device_del;

	list_add_tail(&dev->node, &input_dev_list);
	printk("========dev->node=%p\n",&dev->node);
	list_for_each_entry(handler, &input_handler_list, node)
		input_attach_handler(dev, handler);

	input_wakeup_procfs_readers();

	mutex_unlock(&input_mutex);

	if (dev->devres_managed) {
		dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
			__func__, dev_name(&dev->dev));
		devres_add(dev->dev.parent, devres);
	}
	return 0;

err_device_del:
	device_del(&dev->dev);
err_free_vals:
	kfree(dev->vals);
	dev->vals = NULL;
err_devres_free:
	devres_free(devres);
	return error;
}
EXPORT_SYMBOL(input_register_device);

/*
 * input_register_handler - register a new input handler
 * @handler: handler to be registered
 *
 * This function registers a new input handler (interface) for input
 * devices in the system and attaches it to all input devices that
 * are compatible with the handler.
 */
int input_register_handler(struct input_handler *handler)
{
	struct input_dev *dev;
	int error;

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

	INIT_LIST_HEAD(&handler->h_list);

	list_add_tail(&handler->node, &input_handler_list);
	printk("========handler->node=%p\n",&handler->node);

	list_for_each_entry(dev, &input_dev_list, node)
		input_attach_handler(dev, handler);

	input_wakeup_procfs_readers();

	mutex_unlock(&input_mutex);
	return 0;
}

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

	minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
	if (minor < 0) {
		error = minor;
		pr_err("failed to reserve new minor: %d\n", error);
		return error;
	}

	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
	if (!evdev) {
		error = -ENOMEM;
		goto err_free_minor;
	}

	INIT_LIST_HEAD(&evdev->client_list);
	spin_lock_init(&evdev->client_lock);
	mutex_init(&evdev->mutex);
	init_waitqueue_head(&evdev->wait);
	evdev->exist = true;

	dev_no = minor;
	/* Normalize device number if it falls into legacy range */
	if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
		dev_no -= EVDEV_MINOR_BASE;
	dev_set_name(&evdev->dev, "event%d", dev_no);

	evdev->handle.dev = input_get_device(dev);
	evdev->handle.name = dev_name(&evdev->dev);
	evdev->handle.handler = handler;
	evdev->handle.private = evdev;

	evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
	evdev->dev.class = &input_class;
	evdev->dev.parent = &dev->dev;
	evdev->dev.release = evdev_free;
	device_initialize(&evdev->dev);
	printk("========evdev->handle.handler=%s,evdev->handle.dev=%s\n",evdev->handle.handler->name,evdev->handle.dev->name);
	error = input_register_handle(&evdev->handle);
	if (error)
		goto err_free_evdev;

	cdev_init(&evdev->cdev, &evdev_fops);
	evdev->cdev.kobj.parent = &evdev->dev.kobj;
	error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
	if (error)
		goto err_unregister_handle;

	error = device_add(&evdev->dev);
	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);
 err_free_minor:
	input_free_minor(minor);
	return error;
}
connect之后把对应的handler和input_dev放在一起。
int input_register_handle(struct input_handle *handle)
{
	struct input_handler *handler = handle->handler;
	struct input_dev *dev = handle->dev;
	int error;
	printk("============input_register_handle=%s\n", handle->name);
	/*
	 * We take dev->mutex here to prevent race with
	 * input_release_device().
	 */
	error = mutex_lock_interruptible(&dev->mutex);
	if (error)
		return error;

	/*
	 * Filters go to the head of the list, normal handlers
	 * to the tail.
	 */
	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);

	/*
	 * Since we are supposed to be called from ->connect()
	 * which is mutually exclusive with ->disconnect()
	 * we can't be racing with input_unregister_handle()
	 * and so separate lock is not needed here.
	 */
	list_add_tail_rcu(&handle->h_node, &handler->h_list);

	if (handler->start)
		handler->start(handle);

	return 0;
}
evdev中传输数据的代码。
static void evdev_events(struct input_handle *handle,
			 const struct input_value *vals, unsigned int count)
{
	struct evdev *evdev = handle->private;
	struct evdev_client *client;
	ktime_t time_mono, time_real;

	time_mono = ktime_get();
	time_real = ktime_mono_to_real(time_mono);

	rcu_read_lock();

	client = rcu_dereference(evdev->grab);
	printk("=====%s client=%p\n",__func__,client);
	if (client)
		evdev_pass_values(client, vals, count, time_mono, time_real);
	else
		list_for_each_entry_rcu(client, &evdev->client_list, node)
			evdev_pass_values(client, vals, count,
					  time_mono, time_real);

	rcu_read_unlock();
}


系统在初始化的时候,会分别做匹配,evdev的初始化函数是module_init,此时调用input_register_handler,input.c的启动高于module_init,它是调用subsys_initcall(input_init);

并创建字符设备。设备驱动和evdev驱动都会注册,并且查找对应链表的匹配成功的项。比如key的input_dev对应kdb和event0,打开并读取 对应的event0,之后,上报到对应event0,而不是kdb。


对应Log

[    2.692105] ========handler->node=c0c3cb6c name=evdev
[    2.696292] msm_otg 78d9000.usb: phy_reset: success
[    2.701052] ========evdev->handle.handler=evdev,evdev->handle.dev=qpnp_pon
[    2.707886] ============input_register_handle=event0----------------------------》connect OK,注册成功。
[    2.712915] input: Try to attach handler evdev to device input0, error: 0
[    2.719607] ========evdev->handle.handler=evdev,evdev->handle.dev=i2c_key
[    2.726366] ============input_register_handle=event1
[    2.731381] input: Try to attach handler evdev to device input1, error: 0
[    2.738091] ========evdev->handle.handler=evdev,evdev->handle.dev=tpl5010
[    2.744855] ============input_register_handle=event2
[    2.749870] input: Try to attach handler evdev to device input2, error: 0
[    2.756581] ========evdev->handle.handler=evdev,evdev->handle.dev=hs_uart
[    2.763310] ============input_register_handle=event3
[    2.768403] input: Try to attach handler evdev to device input3, error: 0
[    2.775147] bmi160 4-0068: BMI160 i2c function probe entrance
[    2.781354] bmi160 4-0068: Regulator client_data->vdd enable success!
[    2.787736] (NULL device *): Bosch Sensortec Device detected, HW IC name: BMI160C3
[    2.795062] input: bmi160_accel as /devices/virtual/input/input4
[    2.800725] ========dev->node=ce5523a8 name = bmi160_accel
[    2.806368] ========evdev->handle.handler=evdev,evdev->handle.dev=bmi160_accel
[    2.813519] ============input_register_handle=event4
[    2.819260] input: Try to attach handler evdev to device input4, error: 0
[    2.825173] bmi160 4-0068: bmi160 input_accel register successfully!
[    2.831686] input: bmi160_gyro as /devices/virtual/input/input5
[    2.837399] ========dev->node=ce552ba8 name = bmi160_gyro
[    2.842748] ========evdev->handle.handler=evdev,evdev->handle.dev=bmi160_gyro
[    2.849892] ============input_register_handle=event5
[    2.854961] input: Try to attach handler evdev to device input5, error: 0
[    2.861578] bmi160 4-0068: bmi160 input register successfully, bmi160_gyro!
[    2.869323] dev->platform_data = NULL



这是sensor驱动中调用input_event和input_sync,打印出来的log。

  bmi_signification_motion_interrupt_handle
[ 5675.678310] ======1input_handle_event  disposition=3 dev->vals=ce549680, dev->num_vals=0
[ 5675.686366] ======2input_handle_event  disposition=3 dev->vals=ce549680, dev->num_vals=1
[ 5675.695120] ======1input_handle_event  disposition=9 dev->vals=ce549680, dev->num_vals=1
[ 5675.702511] ======2input_handle_event  disposition=9 dev->vals=ce549680, dev->num_vals=2
[ 5675.710586] enter input_pass_values count =2
[ 5675.714837] ========2 input_to_handler=2
[ 5675.718742] ========1 input_to_handler=2
[ 5675.722656] =====evdev_events client=  (null)
[ 5675.726984] ========evdev_pass_values
[ 5675.730638] ========evdev_pass_values val=ce549680 count=2
[ 5675.736105] ====__pass_event,head=1,tail=0,packet_head=0,event4-1552/n====__pass_event,head=2,tail=0,packet_head=0,event4-1552/nenter the SYN
[ 5675.748792] =====2 handle->name=event4
[ 5675.752504] ============= last  inputdev->name=bmi160_accel
[ 5675.758362] ======evdev_fetch_next_event
[ 5675.761977] =====!client->packet_head=2,client->tail=1,client->head=2
[ 5675.770859] ======evdev_fetch_next_event
[ 5675.773753] =====!client->packet_head=2,client->tail=2,client->head  //循环buffer,一次事件传输完。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值