历史上的今天
返回首页

历史上的今天

今天是:2024年11月19日(星期二)

正在发生

2019年11月19日 | ARM Linux内核Input输入子系统浅解

2019-11-19 来源:51hei

--以触摸屏驱动为例

第一章、了解linux input子系统

 

Linux输入设备总类繁杂,常见的包括有按键、键盘、触摸屏、鼠标、摇杆等等,他们本身就是字符设备,而linux内核将这些设备的共同性抽象出来,简化驱动开发建立了一个input子系统。子系统共分为三层,如图1所示。

图1  input输入子系统

 

驱动层和硬件相关,直接捕捉和获取硬件设备的数据信息等(包括触摸屏被按下、按下位置、鼠标移动、键盘按下等等),然后将数据信息报告到核心层。核心层负责连接驱动层和事件处理层,设备驱动(device driver)和处理程序(handler)的注册需要通过核心层来完成,核心层接收来自驱动层的数据信息,并将数据信息选择对应的handler去处理,最终handler将数据复制到用户空间。


先了解三个定义在/linux/input.h下重要的结构体input_dev、input_handler、input_handle。

struct input_dev {

      void *private;

 

      const char *name;

      const char *phys;

      const char *uniq;

      struct input_id id;      //与input_handler匹配用的id

 

      unsigned long evbit[NBITS(EV_MAX)];            //设备支持的事件类型

      unsigned long keybit[NBITS(KEY_MAX)];      //按键事件支持的子事件类型

      unsigned long relbit[NBITS(REL_MAX)];

      unsigned long absbit[NBITS(ABS_MAX)];      //绝对坐标事件支持的子事件类型

      unsigned long mscbit[NBITS(MSC_MAX)];

      unsigned long ledbit[NBITS(LED_MAX)];

      unsigned long sndbit[NBITS(SND_MAX)];

      unsigned long ffbit[NBITS(FF_MAX)];

      unsigned long swbit[NBITS(SW_MAX)];

      int ff_effects_max;

 

      unsigned int keycodemax;

      unsigned int keycodesize;

      void *keycode;

 

      unsigned int repeat_key;

      struct timer_list timer;

 

      struct pt_regs *regs;

      int state;

      int sync;

 

      int abs[ABS_MAX + 1];

      int rep[REP_MAX + 1];

 

      unsigned long key[NBITS(KEY_MAX)];

      unsigned long led[NBITS(LED_MAX)];

      unsigned long snd[NBITS(SND_MAX)];

      unsigned long sw[NBITS(SW_MAX)];

 

      int absmax[ABS_MAX + 1];      //绝对坐标事件的最大键值

      int absmin[ABS_MAX + 1];      //绝对坐标事件的最小键值

      int absfuzz[ABS_MAX + 1];

      int absflat[ABS_MAX + 1];

 

      int (*open)(struct input_dev *dev);

      void (*close)(struct input_dev *dev);

      int (*accept)(struct input_dev *dev, struct file *file);

      int (*flush)(struct input_dev *dev, struct file *file);

      int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

      int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);

      int (*erase_effect)(struct input_dev *dev, int effect_id);

 

      struct input_handle *grab;      //当前占有该设备的handle

 

      struct mutex mutex;      /* serializes open and close operations */

      unsigned int users;            //打开该设备的用户量

 

      struct class_device cdev;

      struct device *dev;      /* will be removed soon */

 

      int dynalloc;      /* temporarily */

 

      struct list_head      h_list;      //该链表头用于链接该设备所关联的input_handle

      struct list_head      node;      //该链表头用于将设备链接到input_dev_list

};


Input_dev是一个很强大的结构体,它把所有的input设备(触摸屏、键盘、鼠标等)的信息都考虑到了,对于触摸屏来说只用到它里面的一部分而已,尤其是加粗的部分,注意该结构体中最后两行定义的两个list_head结构体,list_head在/linux/list.h中有定义,深入跟踪

struct list_head {

      struct list_head *next, *prev;

};

该结构体内部并没有定义数据而只定义了两个指向本身结构体的指针,预先说明一下,所有的input device在注册后会加入一个input_dev_list(输入设备链表),所有的eventhandler在注册后会加入一个input_handler_list(输入处理程序链表),这里的list_head主要的作用是作为input_dev_list和input_handler_list的一个节点来保存地址。Input_dev_list和input_handler_list之间的对应关系由input_handle结构体桥接,具体后面说明。

 

struct input_handler {

 

      void *private;

 

      void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

      struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);

      void (*disconnect)(struct input_handle *handle);

 

      const struct file_operations *fops;      //提供给用户对设备操作的函数指针

      int minor;

      char *name;

 

      struct input_device_id *id_table;      //与input_dev匹配用的id

      struct input_device_id *blacklist;      //标记的黑名单

 

      struct list_head      h_list;            //用于链接和该handler相关的handle

      struct list_head      node;            //用于将该handler链入input_handler_list

};

input_handler顾名思义,它是用来处理input_dev的一个结构体,相关的处理函数在结构里内部都有定义,最后两行定义的list_head结构体作用同input_dev所定义的一样,这里不再说明。

注:input_device_id结构体在/linux/mod_devicetable.h中有定义

 

struct input_handle {

 

      void *private;

 

      int open;      //记录设备打开次数

      char *name;

 

      struct input_dev *dev;      //指向所属的input_dev

      struct input_handler *handler;      //指向所属的input_handler

 

      struct list_head      d_node;            //用于链入所指向的input_dev的handle链表

      struct list_head      h_node;            //用于链入所指向的input_handler的handle链表

};

可以看到input_handle中拥有指向input_dev和input_handler的指针,即input_handle是用来关联input_dev和input_handler。为什么用input_handle来关联input_dev和input_handler而不将input_dev和input_handler直接对应呢?因为一个device可以对应多个handler,而一个handler也可处理多个device。就如一个触摸屏设备可以对应event handler也可以对应tseve handler。

input_dev、input_handler、input_handle的关系如下图2所示。

图2  input_dev,input_handler,input_handle关系图

 

第二章、input device的注册

Input device的注册实际上仅仅只有几行代码,因为在input.c中已经将大量的代码封装好了,主需要调用几个关键的函数就能完成对input device的注册。


在xxx_ts.c中预先定义全局变量struct input_dev  tsdev;然后进入到初始化函数

static int __init xxx_probe(struct platform_device *pdev)

{

      …

 

      if (!(tsdev = input_allocate_device()))

      {

            printk(KERN_ERR "tsdev: not enough memoryn");

            err = -ENOMEM;

            goto fail;

      }

 

      …

 

      tsdev->name = "xxx TouchScreen";            //xxx为芯片型号

      tsdev ->phys = "xxx/event0";

      tsdev ->id.bustype = BUS_HOST;            //设备id,用于匹配handler的id

      tsdev ->id.vendor  = 0x0005;

      tsdev ->id.product = 0x0001;

      tsdev ->id.version = 0x0100;

 

      tsdev ->open    = xxx_open;

      tsdev ->close   =xxx_close;

 

      tsdev ->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_SYN);            //设置支持的事件类型

tsdev ->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);           

      input_set_abs_params(tsdev, ABS_X, 0, 0x400, 0, 0);            //限定绝对坐标X的取值范围

      input_set_abs_params(tsdev, ABS_Y, 0, 0x400, 0, 0);            //同上

      input_set_abs_params(tsdev, ABS_PRESSURE, 0, 1000, 0, 0);      //触摸屏压力值范围

推荐阅读

史海拾趣

Frequency Sources公司的发展小趣事

随着技术的不断成熟和市场的日益扩大,Frequency Sources公司开始积极拓展国内外市场。公司通过参加国际电子展会、建立海外销售网络、与跨国企业建立合作关系等方式,不断提升品牌知名度和市场份额。同时,公司还针对不同地区的市场需求,定制化开发符合当地标准的产品和服务,进一步增强了市场竞争力。在国际化战略的推动下,公司的业务遍布全球多个国家和地区,实现了跨越式发展。

风华(FH)公司的发展小趣事

近年来,全球半导体行业面临严重的缺芯问题,给包括福斯特半导体在内的众多企业带来了巨大挑战。为了应对这一挑战,福斯特半导体积极调整策略,加强内部管理和优化生产结构。公司更新了一套全新的内部管理系统,对多个业务领域和管理板块进行配套和升级,提升了团队研发效率和质量。同时,公司还加强了移动化办公模式的更新升级,满足了灵活管理的需要。通过这些措施,福斯特半导体在保持高效运营的同时,也增强了自身的抗风险能力,为未来的发展奠定了坚实基础。

Facon公司的发展小趣事

在竞争激烈的电子行业中,品牌形象对于企业的成功至关重要。Facon深知这一点,因此他们始终注重品牌塑造和形象维护。通过举办技术研讨会、参加行业展会等方式,Facon不断向外界展示自己的技术实力和产品优势。同时,他们还积极参与公益活动和社会责任项目,提升企业的社会形象。这些努力让Facon在消费者和合作伙伴中树立了良好的品牌形象。

CUI Devices公司的发展小趣事

在压电警报器领域,CUI Devices凭借其卓越的技术和产品质量,赢得了全球市场的广泛认可。根据最新的行业报告,CUI Devices在全球压电警报器市场中位列第一梯队,与SATEP、Adafruit Industries LLC和Challenge Electronics等核心厂商共同占据了可观的市场份额。这一成绩的取得,离不开公司多年来的技术创新和市场拓展。

德艺隆(DEALON)公司的发展小趣事

随着环保意识的日益增强,德艺隆积极响应国家环保政策,将绿色环保理念融入产品设计和生产过程中。他们研发出了一系列绿色产品,如环保型连接器、节能型插座等,不仅满足了客户的需求,也为保护环境做出了贡献。同时,公司还加强了废弃物的管理和回收,减少了环境污染,树立了良好的环保形象。

ATO SOLUTION公司的发展小趣事

在电子行业的激烈竞争中,ATO SOLUTION公司通过一项创新性的技术突破,成功引领了市场的新潮流。该公司研发出了一款高效能的半导体芯片,极大地提升了电子设备的性能和能效比。这一技术的问世,迅速获得了行业内外的广泛关注和认可,为公司赢得了大量合作伙伴和客户,奠定了市场领先地位。

问答坊 | AI 解惑

模电应知应会20问

1、半导体材料制作电子器件与传统的真空电子器件相比有什么特点?答:频率特性好、体积小、功耗小,便于电路的集成化产品的袖珍化,此外在坚固抗震可靠等方面也特别突出;但是在失真度和稳定性等方面不及真空器件。 2、什么是本征半导体和杂质半导 ...…

查看全部问答>

红外半球摄像机让人欢喜让人忧

现在大陆市场中,由于监控发展较晚!红外半球摄像机红外灯被大陆的经销商和工程商吵的是如何如何的好,像什么白天一样!晚上没有任何光源,都能很清晰的分晰这个人是谁,这些话虽然让产品卖出去了,可是搞伤了我们技术人员和工程人员,验收那个难啊 ...…

查看全部问答>

基于AD9854的信号发生器的设计

基于AD9854的信号发生器的设计…

查看全部问答>

友善之臂X86-QTOPIA编译问题

编译源码时出现了附件中的错误,由以上可知,是缺少luuid,经查找是缺少e2fsprogs-1.39.tar.gz这个包,已经下载了这个文件,接下来该怎么做??? [ 本帖最后由 jxb01033016 于 2009-9-4 11:47 编辑 ]…

查看全部问答>

求梅兰日兰UPS中文使用说明书操作手册

求梅兰日兰UPS中文使用说明书 请问哪位师傅手里有梅兰日兰UPS中文使用说明书啊,帮忙给传一下,或者给个网址也行啊,UPS是4.2KW、6KVA,我先谢谢啦!…

查看全部问答>

有人改写过nboot吗?

nand flash里bootloader的结构如下: 0:nboot 1:tocblock1 file 2:eboot 有人这样安装吗? 有人改写过nboot吗? 我的板子是2410的,我从网上找到了2410 BSP里面关于nboot的代码 读了下nboot里面的代码,硬件主要是初始化串口,感觉这些是通用的, ...…

查看全部问答>

2440开发版不支持大容量SD卡 请教怎么修改

看了GOOOGLEMAN的文章 http://www.cnblogs.com/wogoyixikexie/archive/2009/05/06/1450503.html 在platform->setting->environment 中设置IMGSDBUS2 = 1 在common.bib中也修改过 根本内容我也修改了BSP.C:\\WINCE500\\PLATFORM\\smdk2440\\DRIV ...…

查看全部问答>

谁能救命--关于Mplayer中Demuxer处理流程

哪为江湖大虾有研究过播放器Mplayer的原代码啊,特别是它Demux是如何处理的,最好能讲讲Mplayer的主处理函数,和详细的Demux过程?小弟不胜感激!…

查看全部问答>

请教关于伺服电机精度的问题

小弟请问大家有关于伺服电机的问题.有一位做真空镀膜的客户问到我伺服电机的转矩精度和线性度的参数.请问各位高手转矩精度和线性度是什么意义?…

查看全部问答>

各种存储器的说明

看的电路越多就发现各种样的存储器,哪位说不同存储器类型的说明,像什么SRAM,闪存,ROM等等的学习资料 我邮箱ZJJONE1023@163.COM 在此谢谢过…

查看全部问答>