Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493745
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-11-29 18:52:23

一、输入子系统模型解
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\n",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\n", ev_key.type,ev_key.code-1,ev_key.value);
  28.             if(EV_SYN==ev_key.type)
  29.                 printf("syn event\n\n");

  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\n",
  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\n",
  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\n");
  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\n");
  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. }


阅读(651) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~