input输入子系统框架
来源:互联网 发布:微信软文软件 编辑:程序博客网 时间:2024/05/17 03:37
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_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,一次事件传输完。
- input输入子系统框架
- input输入子系统框架
- input输入子系统框架分析
- Linux的input输入子系统:总体框架
- Linux 输入子系统 input 子系统
- input输入子系统讲解
- [input] 输入子系统综述
- Linux input输入子系统
- input输入子系统
- input-dev输入子系统
- input 输入子系统
- Linux输入(input)子系统
- input输入子系统
- input输入子系统分析
- input输入子系统详解
- input-dev输入子系统
- input-dev输入子系统
- Linux input输入子系统
- Linux_ftp
- 获取的字段值是空值或者为null,而你自己的需求就是想要获取的字段为一个 * 默认的值
- office word 2016 在任意页面开始添加页码
- 【权限管理】基于shiro的权限管理开发实现
- Spring Security
- input输入子系统框架
- 光照模型
- Redis【主从复制】
- 防止sql注入的简单理解
- newCoder Wannafly挑战赛4:B-小AA的数列 (位运算)
- ConcurrentMap 、HashMap 、HashTable的比较
- 基础排序:归并排序
- SQL一维数据转二维
- 关于游戏交互界面设计的几点思考