linux设备模型之input子系统

来源:互联网 发布:深圳 原画 培训 知乎 编辑:程序博客网 时间:2024/04/27 18:11

==================================
本文系本站原创,欢迎转载!

转载请注明出处:http://blog.csdn.net/gdt_A20

==================================


摘要:

input子系统是kernel中比较简单的一个子系统,主要用来管理输入设备(触摸屏,键盘等等),个人感
觉可以作为driver的起点,输入设备不明思议,要提供输入信息,input子系统将这些信息当作事件,进行区分,实
时的上传!input中不是那么规矩,并没有抽象出来总线的概念(硬件上不存在),而是用一个结构struct input_handle充当了总线

的结构,struct input_handle挂接了操作结构以及设备,input设备用struct input_dev结构来表示,操作函数用struct input_handler

来表示,注意这里input_handle和input_handler很相似,存在全局的input设备链表input_dev_list,用于连接所有input devices,

存在全局的input操作链表input_handler_list,用于挂接所有handler.


主要涉及目录:drivers/input

struct input_dev


一、相关数据结构

1.input device

   

[cpp] view plaincopy
  1. struct input_dev {  
  2.     const char *name;               //名字  
  3.     const char *phys;               //物理地址  
  4.     const char *uniq;               //设备特殊标识码  
  5.     struct input_id id;             //设备id  
  6.   
  7.     unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];  //设备属性相关位图  
  8.   
  9.     unsigned long evbit[BITS_TO_LONGS(EV_CNT)];            //支持的事件  
  10.     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];          //key,button位图  
  11.     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];          //相对坐标  
  12.     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];          //绝对坐标  
  13.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];          //杂项事件支持  
  14.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];          //led相关  
  15.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];          //音响效果相关  
  16.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];  
  17.     unsigned long swbit[BITS_TO_LONGS(SW_CNT)];  
  18.   
  19.     unsigned int hint_events_per_packet;  
  20.   
  21.     unsigned int keycodemax;                              //键码表大小  
  22.     unsigned int keycodesize;                               
  23.     void *keycode;                                        //按键扫描码  
  24.   
  25.     int (*setkeycode)(struct input_dev *dev,              //老式扫描方法  
  26.               const struct input_keymap_entry *ke,  
  27.               unsigned int *old_keycode);  
  28.     int (*getkeycode)(struct input_dev *dev,  
  29.               struct input_keymap_entry *ke);  
  30.   
  31.     struct ff_device *ff;  
  32.   
  33.     unsigned int repeat_key;  
  34.     struct timer_list timer;                             //定时器  
  35.   
  36.     int rep[REP_CNT];  
  37.   
  38.     struct input_mt_slot *mt;  
  39.     int mtsize;  
  40.     int slot;  
  41.     int trkid;  
  42.   
  43.     struct input_absinfo *absinfo;  
  44.   
  45.     unsigned long key[BITS_TO_LONGS(KEY_CNT)];  
  46.     unsigned long led[BITS_TO_LONGS(LED_CNT)];  
  47.     unsigned long snd[BITS_TO_LONGS(SND_CNT)];  
  48.     unsigned long sw[BITS_TO_LONGS(SW_CNT)];  
  49.   
  50.     int (*open)(struct input_dev *dev);                 //open回调函数  
  51.     void (*close)(struct input_dev *dev);  
  52.     int (*flush)(struct input_dev *dev, struct file *file);  
  53.     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);  
  54.   
  55.     struct input_handle __rcu *grab;  
  56.   
  57.     spinlock_t event_lock;  
  58.     struct mutex mutex;  
  59.   
  60.     unsigned int users;  
  61.     bool going_away;  
  62.   
  63.     bool sync;  
  64.   
  65.     struct device dev;                                  //devices 模型  
  66.   
  67.     struct list_head    h_list;                    //连接相应的handle  
  68.     struct list_head    node;                      //挂接到全局input_dev_list  
  69. };  
2.操作函数结构input_handler

[cpp] view plaincopy
  1. struct input_handler {  
  2.   
  3.     void *private;                            //私有属性结构  
  4.   
  5.     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);  
  6.     bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);  
  7.     bool (*match)(struct input_handler *handler, struct input_dev *dev);  
  8.     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);  
  9.     void (*disconnect)(struct input_handle *handle);  
  10.     void (*start)(struct input_handle *handle);  
  11.   
  12.     const struct file_operations *fops;  
  13.     int minor;  
  14.     const char *name;                          //名字  
  15.   
  16.     const struct input_device_id *id_table;    //支持的devices,id表  
  17.   
  18.     struct list_head    h_list;   //用于连接到对应的handle的  
  19.     struct list_head    node;     //用于连接到全局的input_handler_list链表  
  20. };  
3.bus的充当者总体管理结构

[cpp] view plaincopy
  1. struct input_handle {  
  2.   
  3.     void *private;                     //私有数据结构  
  4.   
  5.     int open;                          //open计数  
  6.     const char *name;                  //名字  
  7.   
  8.     struct input_dev *dev;             //连接设备  
  9.     struct input_handler *handler;     //连接driver的操作函数  
  10.   
  11.     struct list_head    d_node;    //设备挂接点  
  12.     struct list_head    h_node;    //handle挂接点  
  13. };  

二、相关的操作函数

1.关心一下核心文件input.c,input子系统的初始化:

[cpp] view plaincopy
  1. static int __init input_init(void)  
  2. {  
  3.     int err;  
  4.   
  5.     err = class_register(&input_class);                          //注册input类,出现在sys/class下         
  6.     if (err) {  
  7.         pr_err("unable to register input_dev class\n");  
  8.         return err;  
  9.     }  
  10.   
  11.     err = input_proc_init();                                    //在proc下添加相关信息(bus/input)  
  12.     if (err)  
  13.         goto fail1;  
  14.   
  15.     err = register_chrdev(INPUT_MAJOR, "input", &input_fops);  //注册成字符设备,设备号13  
  16.     if (err) {  
  17.         pr_err("unable to register char major %d", INPUT_MAJOR);  
  18.         goto fail2;  
  19.     }  
  20.   
  21.     return 0;  
  22.   
  23.  fail2: input_proc_exit();  
  24.  fail1: class_unregister(&input_class);  
  25.     return err;  
  26. }  
貌似戛然而止了,^.^!,
2.向input子系统添加设备的函数,

[cpp] view plaincopy
  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.   
  8.     /* Every input device generates EV_SYN/SYN_REPORT events. */  
  9.     __set_bit(EV_SYN, dev->evbit);  
  10.   
  11.     /* KEY_RESERVED is not supposed to be transmitted to userspace. */  
  12.     __clear_bit(KEY_RESERVED, dev->keybit);  
  13.   
  14.     /* Make sure that bitmasks not mentioned in dev->evbit are clean. */  
  15.     input_cleanse_bitmasks(dev);  
  16.   
  17.     if (!dev->hint_events_per_packet)  
  18.         dev->hint_events_per_packet =  
  19.                 input_estimate_events_per_packet(dev);  
  20.   
  21.     /* 
  22.      * If delay and period are pre-set by the driver, then autorepeating 
  23.      * is handled by the driver itself and we don't do it in input.c. 
  24.      */  
  25.     init_timer(&dev->timer);  
  26.     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {  
  27.         dev->timer.data = (long) dev;  
  28.         dev->timer.function = input_repeat_key;  
  29.         dev->rep[REP_DELAY] = 250;  
  30.         dev->rep[REP_PERIOD] = 33;  
  31.     }  
  32.   
  33.     if (!dev->getkeycode)  
  34.         dev->getkeycode = input_default_getkeycode;                //如果没有设置,设置成默认值  
  35.   
  36.     if (!dev->setkeycode)  
  37.         dev->setkeycode = input_default_setkeycode;  
  38.   
  39.     dev_set_name(&dev->dev, "input%ld",                               //name  
  40.              (unsigned long) atomic_inc_return(&input_no) - 1);  
  41.   
  42.     error = device_add(&dev->dev);                                   //标准设备的加入,这个,,加哪去了,没bus的野设备??  
[cpp] view plaincopy
  1.     if (error)                                                       //直接扔到系统全局总设备链表了  
  2.         return error;  
  3.   
  4.     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);  
  5.     pr_info("%s as %s\n",  
  6.         dev->name ? dev->name : "Unspecified device",  
  7.         path ? path : "N/A");  
  8.     kfree(path);  
  9.   
  10.     error = mutex_lock_interruptible(&input_mutex);  
  11.     if (error) {  
  12.         device_del(&dev->dev);  
  13.         return error;  
  14.     }  
  15.   
  16.     list_add_tail(&dev->node, &input_dev_list);                   //加入全局input device链表  
  17.   
  18.     list_for_each_entry(handler, &input_handler_list, node)       //遍历handler链表,匹配合适的handler  
  19.         input_attach_handler(dev, handler);  
  20.   
  21.     input_wakeup_procfs_readers();  
  22.   
  23.     mutex_unlock(&input_mutex);  
  24.   
  25.     return 0;  
  26. }  
继续跟一下input_attach_handler函数,

[cpp] view plaincopy
  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.   
  6.     id = input_match_device(handler, dev);                                  //具体的匹配函数  
  7.     if (!id)  
  8.         return -ENODEV;  
  9.   
  10.     error = handler->connect(handler, dev, id);                              //匹配后调用connect函数  
  11.     if (error && error != -ENODEV)  
  12.         pr_err("failed to attach handler %s to device %s, error: %d\n",  
  13.                handler->name, kobject_name(&dev->dev.kobj), error);  
  14.   
  15.     return error;  
  16. }  
还有个函数
[cpp] view plaincopy
  1. static const struct input_device_id *input_match_device(struct input_handler *handler,  
  2.                             struct input_dev *dev)  
  3. {  
  4.     const struct input_device_id *id;  
  5.     int i;  
  6.   
  7.     for (id = handler->id_table; id->flags || id->driver_info; id++) {  
  8.   
  9.         if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)  
  10.             if (id->bustype != dev->id.bustype)  
  11.                 continue;  
  12.   
  13.         if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)  
  14.             if (id->vendor != dev->id.vendor)  
  15.                 continue;  
  16.   
  17.         if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)  
  18.             if (id->product != dev->id.product)  
  19.                 continue;  
  20.   
  21.         if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)  
  22.             if (id->version != dev->id.version)  
  23.                 continue;  
  24.   
  25.         MATCH_BIT(evbit,  EV_MAX);  
  26.         MATCH_BIT(keybit, KEY_MAX);  
  27.         MATCH_BIT(relbit, REL_MAX);  
  28.         MATCH_BIT(absbit, ABS_MAX);  
  29.         MATCH_BIT(mscbit, MSC_MAX);  
  30.         MATCH_BIT(ledbit, LED_MAX);  
  31.         MATCH_BIT(sndbit, SND_MAX);  
  32.         MATCH_BIT(ffbit,  FF_MAX);  
  33.         MATCH_BIT(swbit,  SW_MAX);  
  34.   
  35.         if (!handler->match || handler->match(handler, dev))             //不光是调用match函数,上面的匹配也很严格,厂商  
  36.             return id;                                               //版本一个也不能少  
  37.     }  
  38.   
  39.     return NULL;  
  40. }  

3.handler的注册

同样handler也要有注册的

[cpp] view plaincopy
  1. int input_register_handler(struct input_handler *handler)  
  2. {  
  3.     struct input_dev *dev;  
  4.     int retval;  
  5.   
  6.     retval = mutex_lock_interruptible(&input_mutex);  
  7.     if (retval)  
  8.         return retval;  
  9.   
  10.     INIT_LIST_HEAD(&handler->h_list);  
  11.   
  12.     if (handler->fops != NULL) {  
  13.         if (input_table[handler->minor >> 5]) {  
  14.             retval = -EBUSY;  
  15.             goto out;  
  16.         }  
  17.         input_table[handler->minor >> 5] = handler;  
  18.     }  
  19.   
  20.     list_add_tail(&handler->node, &input_handler_list);         //加入全局handler链表  
  21.   
  22.     list_for_each_entry(dev, &input_dev_list, node)            //遍历devices链表,匹配  
  23.         input_attach_handler(dev, handler);  
  24.   
  25.     input_wakeup_procfs_readers();  
  26.   
  27.  out:  
  28.     mutex_unlock(&input_mutex);  
  29.     return retval;  
  30. }  

三、input deivce实例

这个东东还是找个例子看起来比较方便,

翻一翻touchscreen下s3c2410_ts.c,

直接进入主题看probe

[cpp] view plaincopy
  1. <pre name="code" class="cpp">static int __devinit s3c2410ts_probe(struct platform_device *pdev)  
  2. {  
  3.     struct s3c2410_ts_mach_info *info;  
  4.     struct device *dev = &pdev->dev;  
  5.     struct input_dev *input_dev;  
  6.     struct resource *res;  
  7.     int ret = -EINVAL;  
  8.   
  9.     /* Initialise input stuff */  
  10.     memset(&ts, 0, sizeof(struct s3c2410ts));  
  11.   
  12.     ts.dev = dev;  
  13.   
  14.     info = pdev->dev.platform_data;  
  15.     if (!info) {  
  16.         dev_err(dev, "no platform data, cannot attach\n");  
  17.         return -EINVAL;  
  18.     }  
  19.   
  20.     dev_dbg(dev, "initialising touchscreen\n");  
  21.   
  22.     ts.clock = clk_get(dev, "adc");                                //申请clock  
  23.     if (IS_ERR(ts.clock)) {  
  24.         dev_err(dev, "cannot get adc clock source\n");  
  25.         return -ENOENT;  
  26.     }  
  27.   
  28.     clk_enable(ts.clock);                                         //使能clock  
  29.     dev_dbg(dev, "got and enabled clocks\n");  
  30.   
  31.     ts.irq_tc = ret = platform_get_irq(pdev, 0);                 //中断号  
  32.     if (ret < 0) {  
  33.         dev_err(dev, "no resource for interrupt\n");  
  34.         goto err_clk;  
  35.     }  
  36.   
  37.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);       //相关寄存器地址  
  38.     if (!res) {  
  39.         dev_err(dev, "no resource for registers\n");  
  40.         ret = -ENOENT;  
  41.         goto err_clk;  
  42.     }  
  43.   
  44.     ts.io = ioremap(res->start, resource_size(res));           //进行映射  
  45.     if (ts.io == NULL) {  
  46.         dev_err(dev, "cannot map registers\n");  
  47.         ret = -ENOMEM;  
  48.         goto err_clk;  
  49.     }  
  50.   
  51.     /* inititalise the gpio */  
  52.     if (info->cfg_gpio)  
  53.         info->cfg_gpio(to_platform_device(ts.dev));       //相关gpio配置  
  54.   
  55.     ts.client = s3c_adc_register(pdev, s3c24xx_ts_select,     //注意这里adc核心相关,select会启动timer上报adc事件  
  56.                      s3c24xx_ts_conversion, 1);  
  57.     if (IS_ERR(ts.client)) {  
  58.         dev_err(dev, "failed to register adc client\n");  
  59.         ret = PTR_ERR(ts.client);  
  60.         goto err_iomap;  
  61.     }  
  62.   
  63.     /* Initialise registers */  
  64.     if ((info->delay & 0xffff) > 0)  
  65.         writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);  
  66.   
  67.     writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);  
  68.   
  69.     input_dev = input_allocate_device();                    //这里重点,分配了一个input device设备  
  70.     if (!input_dev) {  
  71.         dev_err(dev, "Unable to allocate the input device !!\n");  
  72.         ret = -ENOMEM;  
  73.         goto err_iomap;  
  74.     }  
  75.   
  76.     ts.input = input_dev;  
  77.     ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  
  78.     ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);  
  79.     input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);  
  80.     input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);  
  81.   
  82.     ts.input->name = "S3C24XX TouchScreen";  
  83.     ts.input->id.bustype = BUS_HOST;  
  84.     ts.input->id.vendor = 0xDEAD;  
  85.     ts.input->id.product = 0xBEEF;  
  86.     ts.input->id.version = 0x0102;  
  87.   
  88.     ts.shift = info->oversampling_shift;  
  89.     ts.features = platform_get_device_id(pdev)->driver_data;  
  90.   
  91.     ret = request_irq(ts.irq_tc, stylus_irq, 0,          //申请中断,input设备大多都是使用中断的,pen down up事件  
  92.               "s3c2410_ts_pen", ts.input);  
  93.     if (ret) {  
  94.         dev_err(dev, "cannot get TC interrupt\n");  
  95.         goto err_inputdev;  
  96.     }  
  97.   
  98.     dev_info(dev, "driver attached, registering input device\n");  
  99.   
  100.     /* All went ok, so register to the input system */  
  101.     ret = input_register_device(ts.input);             //这里注册input device  
  102.     if (ret < 0) {  
  103.         dev_err(dev, "failed to register input device\n");  
  104.         ret = -EIO;  
  105.         goto err_tcirq;  
  106.     }  
  107.   
  108.     return 0;  
  109.   
  110.  err_tcirq:  
  111.     free_irq(ts.irq_tc, ts.input);  
  112.  err_inputdev:  
  113.     input_free_device(ts.input);  
  114.  err_iomap:  
  115.     iounmap(ts.io);  
  116.  err_clk:  
  117.     del_timer_sync(&touch_timer);  
  118.     clk_put(ts.clock);  
  119.     return ret;  
  120. }</pre><br>  
  121. <br>  
  122. <p></p>  
  123. <pre></pre>  
  124. 看一下 input_allocate_device函数,  
  125. <p></p>  
  126. <p></p><pre name="code" class="cpp">struct input_dev *input_allocate_device(void)  
  127. {  
  128.     struct input_dev *dev;  
  129.   
  130.     dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);  
  131.     if (dev) {  
  132.         dev->dev.type = &input_dev_type;        //初始化成input类型  
  133.         dev->dev.class = &input_class;   
  134.         device_initialize(&dev->dev);  
  135.         mutex_init(&dev->mutex);  
  136.         spin_lock_init(&dev->event_lock);  
  137.         INIT_LIST_HEAD(&dev->h_list);  
  138.         INIT_LIST_HEAD(&dev->node);  
  139.   
  140.         __module_get(THIS_MODULE);  
  141.     }  
  142.   
  143.     return dev;  
  144. }</pre>irq用于判断pen down up,启动adc上报坐标事件.<p></p>  
  145. <p><br>  
  146. </p>  
  147. <p>未完待续....</p>  
  148. <p><br>  
  149. </p>  
  150. <p>Thanks</p>  
  151. <p><br>  
  152. </p>  
  153. <p><br>  
  154. </p>  
  155. <p><br>  
  156. <br>  
  157. <br>  
  158. <br>  
  159. </p>  
0 0