input输入子系统框架

来源:互联网 发布:微信软文软件 编辑:程序博客网 时间:2024/05/17 03:37

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_headh_list;struct list_headnode;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_headh_list;struct list_headnode;};


匹配,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_headd_node;struct list_headh_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);elselist_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);elselist_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,一次事件传输完。

原创粉丝点击