zoukankan      html  css  js  c++  java
  • 输入子系统模型解析和原理分析

    一、输入子系统模型解
    1.为什么需要输入子系统
    按写按键驱动时:需要注册1个字符启动;open,read与用户程序交互;硬件设置。
    这些数据都是要输入的,所以可以全部整合成输入子系统。

    2.输入子系统的模型

    输入子系统由设备驱动层(input device driver),核心层(input core)和事件驱动层(event driver)三部份组成。
    任何一次输入事件,如鼠标移动,按
    键按下,都需要通过InputDeviceDriver->InputCore->EventDrive才能到达用户空间的应用程序。
    设备驱动层
    将底层的硬件输入转化为统一事件型式,向输入核心(InputCore)汇报。
    输入核心层
    为设备驱动层提供输入设备注册与操作接口,如:nput_register_device;通知事件处理层对事件进行处理;
    事件驱动层
    主要作用是和用户空间交互,如提供read,open等设备方法,创建设备文件等。

    3.编写代码
    key.c
    1. #include <linux/module.h>
    2. #include <linux/init.h>
    3. #include <linux/miscdevice.h>
    4. #include <linux/fs.h>
    5. #include <asm/uaccess.h>
    6. #include <linux/io.h>
    7. #include <linux/irqreturn.h>
    8. #include <linux/interrupt.h>
    9. #include <linux/uaccess.h>
    10. #include <linux/input.h> /*上报的按键编号*/

    11. #define GPFCON (volatile unsigned long*) 0x56000050
    12. #define GPFDAT (volatile unsigned long*) 0x56000054

    13. unsigned int *gpio_data;

    14. struct work_struct *work1;

    15. struct timer_list key_timer;

    16. wait_queue_head_t key_q;

    17. unsigned int key_num = 0;

    18. struct input_dev *button_dev;                             //创建input_dev结构

    19. void key_timer_func(unsigned long data)
    20. {
    21.     unsigned int key_val;
    22.     key_val = readw(gpio_data);
    23.     if((key_val & 0x01) == 0)
    24.     {
    25.         key_num = 4;
    26.         input_report_key(button_dev, KEY_4, 1);                                   //上报事件,button_dev结构发送了KEY_4事件,按下了                           
    27.     }
    28.     else if((key_val& 0x02) == 0)
    29.     {
    30.         key_num = 1;
    31.         input_report_key(button_dev, KEY_1, 1);                                   //上报事件
    32.     }
    33.     else if((key_val & 0x04) == 0)
    34.     {
    35.         key_num = 3;
    36.         input_report_key(button_dev, KEY_3, 1);                                   //上报事件                                      
    37.     }
    38.     else if((key_val & 0x10) == 0)
    39.     {
    40.         key_num = 2;
    41.         input_report_key(button_dev, KEY_2, 1);                                   //上报事件
    42.     }

    43.     input_sync(button_dev);                                                       //上报结束
    44. }

    45. void work1_func(struct work_struct *work)
    46. {
    47.     mod_timer(&key_timer, jiffies + HZ/10);
    48. }

    49. irqreturn_t key_int(int irq, void *dev_id)
    50. {
    51.     //1.检测是否发生了按键中断
    52.     
    53.     //2.清除已经发生的按键中断
    54.    
    55.     //3.提交下半部
    56.     schedule_work(work1);

    57.     return IRQ_HANDLED;
    58. }

    59. void key_hw_init()
    60. {
    61.     unsigned int *gpio_config;
    62.     unsigned short data;
    63.     
    64.     gpio_config = ioremap(GPFCON, 4);
    65.     gpio_data = ioremap(GPFDAT, 4);
    66.     data = readw(gpio_config);
    67.     data &= ~0x33f;
    68.     data |= 0x22a;
    69.     writew(data, gpio_config);
    70. }

    71. static int button_init()
    72. {
    73.     int ret;
    74.     //分配输入型设备结构
    75.     button_dev = input_allocate_device();                              //分配input_dev结构
    76.     
    77.     //申明所支持的事件类型
    78.     set_bit(EV_KEY, button_dev->evbit);                                //申明驱动可能上报的事件类型

    79.     /*上报可能的键编号*/
    80.     set_bit(KEY_1,button_dev->keybit);                                 //申明可能上报的
    81.     set_bit(KEY_2,button_dev->keybit);
    82.     set_bit(KEY_3,button_dev->keybit);
    83.     set_bit(KEY_4,button_dev->keybit);

    84.     /*注册输入型设备*/
    85.     input_register_device(button_dev);                                  //注册input_dev结构

    86.     //按键初始化
    87.     key_hw_init();

    88.     //注册中断处理程序
    89.     ret = request_irq(IRQ_EINT0, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
    90.     ret = request_irq(IRQ_EINT1, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
    91.     ret = request_irq(IRQ_EINT2, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
    92.     ret = request_irq(IRQ_EINT4, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);

    93.     //创建工作
    94.     work1 = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
    95.     INIT_WORK(work1, work1_func);

    96.     //初始化定时器
    97.     init_timer(&key_timer);
    98.     key_timer.function = key_timer_func;

    99.     //注册定时器
    100.     add_timer(&key_timer);

    101.     //初始化等待队列
    102.     init_waitqueue_head(&key_q);
    103.     return 0;
    104. }

    105. static void button_exit()
    106. {
    107.     input_unregister_device(button_dev);                                        //注销input_dev结构
    108. }

    109. module_init(button_init);
    110. module_exit(button_exit);
    key_app.c:
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <unistd.h>
    4. #include <sys/ioctl.h>
    5. #include <sys/types.h>
    6. #include <sys/stat.h>
    7. #include <fcntl.h>
    8. #include <sys/select.h>
    9. #include <sys/time.h>
    10. #include <errno.h>
    11. #include <linux/input.h>
    12. int main(void)
    13. {
    14.     int buttons_fd;
    15.     int key_value,i=0,count;

    16.     struct input_event ev_key;
    17.     buttons_fd = open("/dev/event1", O_RDWR);                                              //这里的设备名为/dev/evnet1
    18.     if (buttons_fd < 0) {
    19.         perror("open device buttons");
    20.         exit(1);
    21.     }

    22.     for (;;) {
    23.         count = read(buttons_fd,&ev_key,sizeof(struct input_event));                       //从设备中读取input_event事件
    24.     //    printf("count=%d ",count);
    25.         for(i=0; i<(int)count/sizeof(struct input_event); i++)
    26.             if(EV_KEY==ev_key.type)
    27.                 printf("type:%d,code:%d,value:%d ", ev_key.type,ev_key.code-1,ev_key.value);
    28.             if(EV_SYN==ev_key.type)
    29.                 printf("syn event ");

    30.     }

    31.     close(buttons_fd);
    32.     return 0;
    33. }
    二、输入子系统原理分析
    1.子系统核心架构

    2.输入子系统设备注册
    2.1设备注册
    input_register_device:
    1. int input_register_device(struct input_dev *dev)
    2. {
    3.     static atomic_t input_no = ATOMIC_INIT(0);
    4.     struct input_handler *handler;
    5.     const char *path;
    6.     int error;

    7.     __set_bit(EV_SYN, dev->evbit);

    8.     /*
    9.      * If delay and period are pre-set by the driver, then autorepeating
    10.      * is handled by the driver itself and we don't do it in input.c.
    11.      */

    12.     init_timer(&dev->timer);
    13.     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
    14.         dev->timer.data = (long) dev;
    15.         dev->timer.function = input_repeat_key;
    16.         dev->rep[REP_DELAY] = 250;
    17.         dev->rep[REP_PERIOD] = 33;
    18.     }

    19.     if (!dev->getkeycode)
    20.         dev->getkeycode = input_default_getkeycode;

    21.     if (!dev->setkeycode)
    22.         dev->setkeycode = input_default_setkeycode;

    23.     dev_set_name(&dev->dev, "input%ld",
    24.          (unsigned long) atomic_inc_return(&input_no) - 1);

    25.     error = device_add(&dev->dev);
    26.     if (error)
    27.         return error;

    28.     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
    29.     printk(KERN_INFO "input: %s as %s ",
    30.         dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
    31.     kfree(path);

    32.     error = mutex_lock_interruptible(&input_mutex);
    33.     if (error) {
    34.         device_del(&dev->dev);
    35.         return error;
    36.     }

    37.     list_add_tail(&dev->node, &input_dev_list);

    38.     list_for_each_entry(handler, &input_handler_list, node)                                       //从input_handler_list遍历找到能处理input_dev的handler
    39.         input_attach_handler(dev, handler);                                                       //将dev设备和handler处理事件匹配

    40.     input_wakeup_procfs_readers();

    41.     mutex_unlock(&input_mutex);

    42.     return 0;
    43. }
    input_attach_handler:
    1. static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
    2. {
    3.     const struct input_device_id *id;
    4.     int error;

    5.     if (handler->blacklist && input_match_device(handler->blacklist, dev))
    6.         return -ENODEV;

    7.     id = input_match_device(handler->id_table, dev);                                  //handler中有id_table(ID表)和dev
    8.     if (!id)
    9.         return -ENODEV;

    10.     error = handler->connect(handler, dev, id);                                       //找到对应的id后进行匹配,handler和dev之间
    11.     if (error && error != -ENODEV)
    12.         printk(KERN_ERR
    13.             "input: failed to attach handler %s to device %s, "
    14.             "error: %d ",
    15.             handler->name, kobject_name(&dev->dev.kobj), error);

    16.     return error;
    17. }
    evdev.c>>evdev_handler(事件层):
    1. static struct input_handler evdev_handler = {
    2.     .event        = evdev_event,                                                //event事件,下面会用到(事件处理)
    3.     .connect    = evdev_connect,                                                //连接函数
    4.     .disconnect    = evdev_disconnect,
    5.     .fops        = &evdev_fops,                                                 //操作函数集,在下面事件上报时,open中使用
    6.     .minor        = EVDEV_MINOR_BASE,
    7.     .name        = "evdev",
    8.     .id_table    = evdev_ids,                                                  //事件驱动id表
    9. };
    evdev_connect:
    1. static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
    2.              const struct input_device_id *id)
    3. {
    4.     struct evdev *evdev;
    5.     int minor;
    6.     int error;

    7.     for (minor = 0; minor < EVDEV_MINORS; minor++)                                      //检查minor是否在evdev_table中
    8.         if (!evdev_table[minor])
    9.             break;

    10.     if (minor == EVDEV_MINORS) {                                                        //检查minor是否有空闲
    11.         printk(KERN_ERR "evdev: no more free evdev devices ");
    12.         return -ENFILE;
    13.     }

    14.     evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);                                   //分配evdev空间
    15.     if (!evdev)
    16.         return -ENOMEM;

    17.     INIT_LIST_HEAD(&evdev->client_list);                                                 //加入链表
    18.     spin_lock_init(&evdev->client_lock);                                                 //初始化自旋锁
    19.     mutex_init(&evdev->mutex);                                                           //初始化mutex
    20.     init_waitqueue_head(&evdev->wait);

    21.     snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
    22.     evdev->exist = 1;                                                                    //evdev初始化
    23.     evdev->minor = minor;

    24.     evdev->handle.dev = input_get_device(dev);
    25.     evdev->handle.name = evdev->name;
    26.     evdev->handle.handler = handler;
    27.     evdev->handle.private = evdev;

    28.     dev_set_name(&evdev->dev, evdev->name);
    29.     evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
    30.     evdev->dev.class = &input_class;                                                     //指定input_class
    31.     evdev->dev.parent = &dev->dev;
    32.     evdev->dev.release = evdev_free;
    33.     device_initialize(&evdev->dev);

    34.     error = input_register_handle(&evdev->handle);
    35.     if (error)
    36.         goto err_free_evdev;

    37.     error = evdev_install_chrdev(evdev);                                               
    38.     if (error)
    39.         goto err_unregister_handle;

    40.     error = device_add(&evdev->dev);                                                      //自动创建设备文件设备
    41.     if (error)
    42.         goto err_cleanup_evdev;

    43.     return 0;

    44.  err_cleanup_evdev:
    45.     evdev_cleanup(evdev);
    46.  err_unregister_handle:
    47.     input_unregister_handle(&evdev->handle);
    48.  err_free_evdev:
    49.     put_device(&evdev->dev);
    50.     return error;
    51. }
    但是这里没有注册硬件驱动,实在input_init中注册了硬件驱动:
    1. static int __init input_init(void)
    2. {
    3.     int err;

    4.     input_init_abs_bypass();

    5.     err = class_register(&input_class);
    6.     if (err) {
    7.         printk(KERN_ERR "input: unable to register input_dev class ");
    8.         return err;
    9.     }

    10.     err = input_proc_init();
    11.     if (err)
    12.         goto fail1;

    13.     err = register_chrdev(INPUT_MAJOR, "input", &input_fops);                                  //这里注册驱动的函数(老版本的),input_fops是操作函数集
    14.     if (err) {
    15.         printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
    16.         goto fail2;
    17.     }

    18.     return 0;

    19.  fail2:    input_proc_exit();
    20.  fail1:    class_unregister(&input_class);
    21.     return err;
    22. }

    2.2 事件上报
    input_report_key:
    1. static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
    2. {
    3.     input_event(dev, EV_KEY, code, !!value);                                        //调用input_event函数
    4. }
    input_event:
    1. void input_event(struct input_dev *dev,
    2.          unsigned int type, unsigned int code, int value)
    3. {
    4.     unsigned long flags;

    5.     if (is_event_supported(type, dev->evbit, EV_MAX)) {                                      //判断上报的事件,是不是之前注册过的

    6.         spin_lock_irqsave(&dev->event_lock, flags);
    7.         add_input_randomness(type, code, value);
    8.         input_handle_event(dev, type, code, value);
    9.         spin_unlock_irqrestore(&dev->event_lock, flags);
    10.     }
    11. }
    input_handle_event:
    1. static void input_handle_event(struct input_dev *dev,
    2.              unsigned int type, unsigned int code, int value)
    3. {
    4.     int disposition = INPUT_IGNORE_EVENT;

    5.     ..........  

    6.     if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
    7.         dev->sync = 0;

    8.     if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
    9.         dev->event(dev, type, code, value);

    10.     if (disposition & INPUT_PASS_TO_HANDLERS)
    11.         input_pass_event(dev, type, code, value);                                          //此处调用input_pass_event,看名字就是传递事件
    12. }
    input_pass_event:
    1. static void input_pass_event(struct input_dev *dev,
    2.              unsigned int type, unsigned int code, int value)
    3. {
    4.     struct input_handle *handle;

    5.     rcu_read_lock();

    6.     handle = rcu_dereference(dev->grab);
    7.     if (handle)
    8.         handle->handler->event(handle, type, code, value);                                           //这里handle和handler,在注册时建立联系了。事件来了,就用event来处理
    9.     else
    10.         list_for_each_entry_rcu(handle, &dev->h_list, d_node)
    11.             if (handle->open)
    12.                 handle->handler->event(handle,
    13.                             type, code, value);
    14.     rcu_read_unlock();
    15. }
    evdev_event:
    1. static void evdev_event(struct input_handle *handle,
    2.             unsigned int type, unsigned int code, int value)
    3. {
    4.     struct evdev *evdev = handle->private;                                   
    5.     struct evdev_client *client;
    6.     struct input_event event;

    7.     do_gettimeofday(&event.time);                                              //写入事件的type,code,value
    8.     event.type = type;
    9.     event.code = code;
    10.     event.value = value;

    11.     rcu_read_lock();

    12.     client = rcu_dereference(evdev->grab);
    13.     if (client)
    14.         evdev_pass_event(client, &event);                                       //调用保存event
    15.     else
    16.         list_for_each_entry_rcu(client, &evdev->client_list, node)
    17.             evdev_pass_event(client, &event);

    18.     rcu_read_unlock();

    19.     wake_up_interruptible(&evdev->wait);
    20. }
    evdev_pass_event:
    1. static void evdev_pass_event(struct evdev_client *client,
    2.              struct input_event *event)
    3. {
    4.     /*
    5.      * Interrupts are disabled, just acquire the lock
    6.      */
    7.     spin_lock(&client->buffer_lock);
    8.     client->buffer[client->head++] = *event;                                                           //将事件保存到buff中
    9.     client->head &= EVDEV_BUFFER_SIZE - 1;
    10.     spin_unlock(&client->buffer_lock);

    11.     kill_fasync(&client->fasync, SIGIO, POLL_IN);
    12. }

    2.3 应用程序如何关联驱动
    input_fops:
    1. static const struct file_operations input_fops = {
    2.     .owner = THIS_MODULE,
    3.     .open = input_open_file,                                     //打开设备
    4. };
    input_open_file:
    1. static int input_open_file(struct inode *inode, struct file *file)
    2. {
    3.     struct input_handler *handler;
    4.     const struct file_operations *old_fops, *new_fops = NULL;
    5.     int err;

    6.     lock_kernel();
    7.     /* No load-on-demand here? */
    8.     handler = input_table[iminor(inode) >> 5];
    9.     if (!handler || !(new_fops = fops_get(handler->fops))) {                                //将handler->fops赋值给new_fops,handler是evdev_handler(也有file_operations)
    10.         err = -ENODEV;
    11.         goto out;
    12.     }

    13.     /*
    14.      * That's _really_ odd. Usually NULL ->open means "nothing special",
    15.      * not "no device". Oh, well...
    16.      */
    17.     if (!new_fops->open) {
    18.         fops_put(new_fops);                                                 
    19.         err = -ENODEV;
    20.         goto out;
    21.     }
    22.     old_fops = file->f_op;                                  
    23.     file->f_op = new_fops;                                                                   //这里将替换的new_fops替换了,打开时的fops。下一次读的时候就会调用evdev_handler中的操作集了。如读

    24.     err = new_fops->open(inode, file);

    25.     if (err) {
    26.         fops_put(file->f_op);
    27.         file->f_op = fops_get(old_fops);
    28.     }
    29.     fops_put(old_fops);
    30. out:
    31.     unlock_kernel();
    32.     return err;
    33. }
    evdev_fops(handler->fops):
    1. static const struct file_operations evdev_fops = {                                  //各种操作集在这里,事件中的只有open
    2.     .owner        = THIS_MODULE,
    3.     .read        = evdev_read,
    4.     .write        = evdev_write,
    5.     .poll        = evdev_poll,
    6.     .open        = evdev_open,
    7.     .release    = evdev_release,
    8.     .unlocked_ioctl    = evdev_ioctl,
    9. #ifdef CONFIG_COMPAT
    10.     .compat_ioctl    = evdev_ioctl_compat,
    11. #endif
    12.     .fasync        = evdev_fasync,
    13.     .flush        = evdev_flush
    14. };
    其中evdev_read:
    1. static ssize_t evdev_read(struct file *file, char __user *buffer,
    2.              size_t count, loff_t *ppos)
    3. {
    4.     struct evdev_client *client = file->private_data;
    5.     struct evdev *evdev = client->evdev;
    6.     struct input_event event;
    7.     int retval;

    8.     if (count < input_event_size())
    9.         return -EINVAL;

    10.     if (client->head == client->tail && evdev->exist &&
    11.      (file->f_flags & O_NONBLOCK))
    12.         return -EAGAIN;

    13.     retval = wait_event_interruptible(evdev->wait,
    14.         client->head != client->tail || !evdev->exist);
    15.     if (retval)
    16.         return retval;

    17.     if (!evdev->exist)
    18.         return -ENODEV;

    19.     while (retval + input_event_size() <= count &&
    20.      evdev_fetch_next_event(client, &event)) {

    21.         if (input_event_to_user(buffer + retval, &event))                               //将信息传递给用户层
    22.             return -EFAULT;

    23.         retval += input_event_size();
    24.     }

    25.     return retval;
    26. }
    evdev_fetch_next_event:
    1. static int evdev_fetch_next_event(struct evdev_client *client,
    2.                  struct input_event *event)
    3. {
    4.     int have_event;

    5.     spin_lock_irq(&client->buffer_lock);

    6.     have_event = client->head != client->tail;
    7.     if (have_event) {
    8.         *event = client->buffer[client->tail++];                                                //在Buffer中取出事件
    9.         client->tail &= EVDEV_BUFFER_SIZE - 1;
    10.     }

    11.     spin_unlock_irq(&client->buffer_lock);

    12.     return have_event;
    13. }


    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    剑指offer——关于排序算法的应用(一):归并排序
    剑指offer——关于排序算法的应用:选择排序和冒泡排序
    剑指offer:将矩阵选择、螺旋输出矩阵——Python之光
    剑指offer:链表——常见的多指针协同操作:
    剑指Offer:编程习惯篇:代码鲁棒性,代码可扩展性——防御性的编程习惯,解决问题时方法分模块考虑
    剑指offer:数字二进制含1个数,快速幂运算:二进制位运算的运用
    剑指offer:斐波那契数列,跳台阶,变态跳台阶——斐波那契数列类题目:
    回溯法实现各种组合的检索:
    剑指offer:二维数组中查找
    jdk生成https证书的方法
  • 原文地址:https://www.cnblogs.com/ch122633/p/7363300.html
Copyright © 2011-2022 走看看