概述
http://blog.csdn.net/myarrow/article/details/7098504
网上的例子很多,如上。
数据结构
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 %sn",
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=%pn",&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=%pn",&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: %dn", 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=%sn",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=%sn", 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=%pn",__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,一次事件传输完。
最后
以上就是狂野灰狼为你收集整理的input输入子系统框架的全部内容,希望文章能够帮你解决input输入子系统框架所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复