Linux下输入子系统上报触摸屏坐标

1.输入子系统简介

  在 Linux 中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。

  • 设备驱动层

      设备驱动层实现对硬件设备的各个寄存的访问,将底层硬件对用户层的响应数据转换为标准输入事件,再通过核心层提交给事件处理层。
  • 核心层

      核心层是设备驱动层和事件处理层的连接桥梁,为设备驱动层和事件处理层提供编程接口。
  • 事件处理层

      事件处理层则为用户空间提供统一访问接口,处理驱动层提交的数据,所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,只需要关心对各硬件寄存器的操作和提交的输入事件。

2.输入子系统好处

  1. 统一了物理形态各异的相似的输入设备的处理功能。例如,各种鼠标,不论 PS/2、 USB、还是蓝牙,都被同样处理。输入子系统常见事件类型为:按键事件(如键盘)、相对坐标事件(如鼠标)、绝对坐标事件(如触摸屏)。
  2. 提供了用于分发输入报告给用户应用程序的简单的事件( event)接口。你的驱动不必创建、管理/dev节点以及相关的访问方法。因此它能够很方便的调用输入 API 以发送鼠标移动、键盘按键,或触摸事件给用户空间。
  3. 抽取出了输入驱动的通用部分,简化了驱动,并提供了一致性。例如,输入子系统提供了一个底层驱动(成为 serio)的集合,支持对串口和键盘控制器等硬件输入的访问。

3.输入子系统相关接口函数

  • struct input_dev 结构体
      结构体 input_dev 表示底层硬件设备,是所有输入设备的抽象。驱动层需要实现对input_dev 结构体的填充。
struct input_dev {const char *name; //设备名字--比如:键盘的名字const char *phys; //设备在系统中的路径。比如:input/key0const char *uniq; //唯一ID号struct input_id id; //用于匹配事件处理层 handlerunsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //记录支持的事件unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按键事件unsigned long relbit[BITS_TO_LONGS(REL_CNT)];//相对坐标unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//绝对坐标unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];unsigned long swbit[BITS_TO_LONGS(SW_CNT)];unsigned int hint_events_per_packet;unsigned int keycodemax;unsigned int keycodesize;void *keycode;int (*setkeycode)(struct input_dev *dev,const struct input_keymap_entry *ke,unsigned int *old_keycode);int (*getkeycode)(struct input_dev *dev,struct input_keymap_entry *ke);struct ff_device *ff;unsigned int repeat_key;struct timer_list timer;int rep[REP_CNT];struct input_mt_slot *mt;int mtsize;int slot;int trkid;struct input_absinfo *absinfo;unsigned long key[BITS_TO_LONGS(KEY_CNT)];unsigned long led[BITS_TO_LONGS(LED_CNT)];unsigned long snd[BITS_TO_LONGS(SND_CNT)];unsigned long sw[BITS_TO_LONGS(SW_CNT)];//文件操作函数 ,可以自行实现int (*open)(struct input_dev *dev);void (*close)(struct input_dev *dev);int (*flush)(struct input_dev *dev, struct file *file);int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);struct input_handle __rcu *grab;spinlock_t event_lock;struct mutex mutex;unsigned int users;bool going_away;bool sync;//最后一次同步后没有新的事件置 1struct device dev;struct list_head h_list;struct list_head node;
};
  • struct input_event 结构体
      该结构体一般在应用层调用,用户接收事件层上报的数据内容。
struct input_event {struct timeval time; //时间戳__u16 type;//事件类型EV_KEY、EV_REL、EV_ABS__u16 code;//事件数据值,若按键事件,则保证按键键值;若坐标信息,则表明为x,y__s32 value;//标志值,若按键,则表示按下还是松开;若坐标,则表示位具体的坐标值
};
  • 动态分配和释放inptu_dev结构体函数

//动态分配input_dev结构体
struct input_dev *input_allocate_device(void)
//释放input_dev结构体
void input_free_device(struct input_dev *dev)

  • 注册和注销输入子系统

//注册输入子系统
int input_register_device(struct input_dev *dev)
//注销输入子系统
void input_free_device(struct input_dev *dev)
形参: input_dev --输入设备结构体
返回值: 注册成功返回0,失败返回其它值

  • 设置上报的数据内容input_set_capability

      input_set_capability函数用于填充input_dev结构体,设置要报的数据类型和数据信息。

void input_set_capability(struct input_dev *dev, unsigned int type,unsigned int code)
形参: dev --input_dev结构体
   type --事件类型EV_KEY、EV_REL、EV_ABS
   code --要上报的具体值
例:input_set_capability(dev,EV_KEY,KEY_A);//上报按键事件,上报的键值为’A’

  • 设置上报的数据内容__set_bit

  通过设置位的函数实现inptu_dev结构体填充,input_set_capability函数的内部就是通过调用__set_bit函数来实现的。

inline void __set_bit(int nr, volatile unsigned long *addr)
形参: nr–要上报的具体值
   addr --设置的地址
上报按键事件例:
  __set_bit(EV_KEY,dev->evbit);//设置事件属性为按键事件
  __set_bit(KEY_A,dev->keybit);//设置上报的键值
设置重复上报例:__set_bit(EV_REP,dev->evbit);

  • 设置上报的值的范围input_set_abs_params

      input_set_abs_params函数用于设置上报的数值的取值范围。

void input_set_abs_params(struct input_dev *dev, unsigned int axis, int min, int max, int fuzz, int flat)
形参: dev --input_dev结构体
   axis --上报的数值
   min --最小值
   max --最大值
    fuzz --数据偏差值
    flat --平滑位置
设置触摸屏x坐标范围:
 input_set_abs_params(touch_dev,ABS_X,0,800,0,0);//设置x坐标范围
设置触摸屏x坐标范围:
 input_set_abs_params(touch_dev,ABS_PRESSURE,0,1,0,0);//设置压力值范围

  • 上报数据到事件处理层

//上报按键事件键值,如键盘
inline void input_report_key(struct input_dev *dev, unsigned int code, int value);
//上报相对事件坐标值,如鼠标
inline void input_report_rel(struct input_dev *dev, unsigned int code, int value);
//上报绝对事件坐标值,如触摸屏
inline void input_report_abs(struct input_dev *dev, unsigned int code, int value);
形参: dev --input_dev结构体
    code --事件数据值,若按键事件,则保证按键键值;若坐标信息,则表明为x,y
    value --标志值,若按键,则表示按下还是松开;若坐标,则表示位具体的坐标值

  这几个函数完成数据上报内部靠input_event函数实现。

  • 事件同步input_mt_sync

void input_mt_sync(struct input_dev *dev)
形参: dev --input_dev结构体

  在完成数据上报后一定要调用事件同步函数。

4.输入子系统上报触摸屏坐标示例

硬件平台:tiny4412
开发平台:ubuntu18.04
交叉编译器:arm-linux-gcc
内核:linux3.5
触摸屏驱动IC:ft5X06

ft5x06驱动示例参考:Linux下IIC子系统和触摸屏驱动

  • 输入子系统注册上报数据示例
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/input.h>#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
static struct work_struct touch_work;
static struct i2c_client *touch_client;
static struct input_dev *touch_dev=NULL;
/*工作处理函数*/
static void touch_work_func(struct work_struct *work)
{u8 touch_buff[7];int x,y;int num;i2c_smbus_read_i2c_block_data(touch_client,0, 7,touch_buff);num=touch_buff[2]&0xf;//触控点个数x=((touch_buff[3]&0xf)<<8)|touch_buff[4];y=((touch_buff[5]&0xf)<<8)|touch_buff[6];//printk("(x,y)=%d,%d\tnum=%d\n",x,y,num);if(num){input_report_abs(touch_dev,ABS_X,x);//上报x坐标input_report_abs(touch_dev,ABS_Y,y);//上报x坐标input_report_abs(touch_dev,ABS_PRESSURE,1);//压力值,1表示按下input_report_key(touch_dev,BTN_TOUCH,1);//按下}else{input_report_abs(touch_dev,ABS_PRESSURE,0);//压力值,0表示松开input_report_key(touch_dev,BTN_TOUCH,0);//释放}input_sync(touch_dev);//同步
}
/*中断处理函数*/
static irqreturn_t touch_irq_work(int irq, void *dev)
{schedule_work(&touch_work);//调度工作return IRQ_HANDLED;
}static int ft5x06_probe(struct i2c_client *client, const struct i2c_device_id *id)//资源匹配函数
{int ret; printk("资源匹配成功\n");printk("name=%s\taddr=%#x\tirq=%d\n",client->name,client->addr,client->irq);touch_client=client;/*动态分配input_dev结构体*/touch_dev=input_allocate_device();if(!touch_dev)return -1;//动态分配失败/*设置要上报的数据内容*/input_set_capability(touch_dev,EV_ABS,ABS_X);//上报x坐标input_set_capability(touch_dev,EV_ABS,ABS_Y);//上报x坐标input_set_capability(touch_dev,EV_ABS,ABS_PRESSURE);//压力值input_set_capability(touch_dev,EV_KEY,BTN_TOUCH);//触摸屏点击事件/*设置xy取值范围*/input_set_abs_params(touch_dev,ABS_X,0,800,0,0);//设置x坐标范围input_set_abs_params(touch_dev,ABS_Y,0,480,0,0);//设置y坐标范围input_set_abs_params(touch_dev,ABS_PRESSURE,0,1,0,0);//设置压力值/*注册输入子系统*/ret=input_register_device(touch_dev);if(ret)return ret;//注册输入子系统设备失败/*1.初始化工作*/INIT_WORK(&touch_work, touch_work_func);/*注册中断*/ret=request_irq(client->irq,touch_irq_work,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,"ft5x06",NULL);if(ret){printk("中断注册失败\n");return -1;}return 0;
}
static int ft5x06_remove(struct i2c_client *client)//资源释放函数
{printk("IIC驱动程资源释放成功\n");free_irq(client->irq,NULL);//注销中断/*注销输入子系统设备*/input_unregister_device(touch_dev);/*释放input_dev结构体*/input_free_device(touch_dev);return 0;
}
//资源匹配结构体
static struct i2c_device_id id_table[]=
{{"touch_ft5x06",0},{},
};
static struct i2c_driver ft5x06_drv=
{.probe=ft5x06_probe,.remove=ft5x06_remove,.driver={.name="touch_drv",},.id_table=id_table,//资源匹配结构体
};static int __init wbyq_ft5x06_drv_init(void)
{i2c_add_driver(&ft5x06_drv); return 0;}
/*驱动释放*/
static void __exit wbyq_ft5x06_drv_cleanup(void)
{i2c_del_driver(&ft5x06_drv);printk("IIC驱动层注销成功\n");
}
module_init(wbyq_ft5x06_drv_init);//驱动入口函数
module_exit(wbyq_ft5x06_drv_cleanup);//驱动出口函数MODULE_LICENSE("GPL");//驱动注册协议
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 ft5x06_drv Driver");
  • 应用层读取触摸屏坐标示例
#include <stdio.h>
#include <linux/fb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>
#include <linux/input.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
static unsigned char *lcd_p=NULL;//屏幕缓存地址
static unsigned char *gbk_addr=NULL;//屏幕缓存地址
static struct fb_fix_screeninfo fb_fix;//固定参数结构体
static struct fb_var_screeninfo fb_var;//可变参数结构体
extern const unsigned char ascii_32_16[][32*16/8];//逐列式,高位在前/*LCD画点函数*/
static inline void LCD_DrawPoint(int x,int y,int c)
{//获取要绘制的点的地址unsigned int *p= (unsigned int *)(lcd_p+y*fb_fix.line_length+x*fb_var.bits_per_pixel/8);*p=c;//写入颜色值
}/*
显示汉字
x,y  --要显示的位置
size  --字体大小
font --要显示的汉字
c -- 颜色值
*/
static void LCD_DisplayFont(int x,int y,int size,char *font,int c)
{u8 *p=NULL;u8 H,L;u32 addr=0;//汉字偏移地址u16 font_size=size*size/8;//汉字点阵大小(宽度保证为8的倍数)H=*font;//汉字高字节L=*(font+1);//汉字的低字节if(L<0x7F)L-=0x40;else L-=0x41;H-=0x81;addr=(190*H+L)*font_size;//汉字所在点阵中的偏移地址p=malloc(font_size);if(p==NULL){printf("申请空间失败\r\n");return ;}memcpy(p,gbk_addr+addr,font_size);//读取点阵码数据   int i,j;int x0=x;unsigned char tmep;for(i=0;i<size*size/8;i++){tmep=p[i];//取出每个字节数据for(j=0;j<8;j++){if(tmep&0x80){LCD_DrawPoint(x0,y,c);}x0++;c+=60;//修改颜色值tmep<<=1;//继续下一个像素点}//换行if(x0-x>=size){x0=x;y++;}}
}
/*
显示字符
x,y  --要显示的位置
h,w -- 字符高和宽
cha --要显示的字符
c -- 颜色值
取模走向:逐列式,高位在前
*/
static void LCD_DisplayCha(int x,int y,int h,int w,char cha,int c)
{int i,j;int y0=y;u8 temp;for(i=0;i<w*h/8;i++){temp=ascii_32_16[cha-' '][i];for(j=0;j<8;j++){if(temp&0x80)LCD_DrawPoint(x,y0,c);y0++;c+=100;//修改颜色值temp<<=1;}if(y0-y==h)//换到下一列{y0=y;x++;}}
}
/*
显示字符串
x,y  --要显示的位置
size -- 字符高度
str --要显示的字符串
c -- 颜色值
*/
static void LCD_DisplayStr(int x,int y,int size,char *str,int c)
{int x0=x;while(*str){if(*str>=0x80)//汉字{LCD_DisplayFont(x0,y,size,str,c);str+=2;x0+=size;}else if(*str>=' ' && *str<='~')//字符显示{LCD_DisplayCha(x0,y,size,size/2,*str,c);str++;x0+=size/2;}else str++;}}
int main()
{/*1.打开设备*/int fd=open("/dev/fb0", 2);if(fd<0){printf("打开设备失败\n");}/*2.获取固定参数*/memset(&fb_fix,0, sizeof(fb_fix));ioctl(fd,FBIOGET_FSCREENINFO,&fb_fix);printf("屏幕缓存大小:%d\n",fb_fix.smem_len);printf("一行的字节数:%d\n",fb_fix.line_length);/*3.获取屏幕可变参数*/memset(&fb_var,0, sizeof(fb_var));ioctl(fd,FBIOGET_VSCREENINFO,&fb_var);printf("屏幕尺寸:%d*%d\n",fb_var.xres,fb_var.yres);printf("颜色位数:%d\n",fb_var.bits_per_pixel);/*4.将屏幕缓冲区映射到进程空间*/lcd_p=mmap(NULL,fb_fix.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);close(fd);if(lcd_p==(void *)-1){printf("内存映射失败\n");return 0;}/*打开字库文件*/int fontfd=open("GBK_32.DZK",2);if(fontfd<0){printf("字库文件打开失败\n");return 0;}struct stat statbuf;fstat(fontfd,&statbuf);if(statbuf.st_size<=0)goto AA;gbk_addr=mmap(NULL,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fontfd,0);close(fontfd);if(gbk_addr==(void *)-1)goto AA;memset(lcd_p,0xff,fb_fix.smem_len);//将屏幕清空为白色LCD_DisplayStr(300,50,32,"触摸屏驱动测试",0x45ff);/*打开触摸屏设备*/fd=open("/dev/input/event1",2);if(fd<0){printf("触摸屏驱动打开失败\n");return 0;}struct pollfd fds={.fd=fd,.events=POLLIN,};/*struct input_event {struct timeval time;__u16 type;__u16 code;__s32 value;};*/struct input_event touchxy;while(1){poll(&fds,1,-1);read(fd,&touchxy,sizeof(touchxy));switch(touchxy.type){case EV_KEY://按键值printf("key=%d\tstat=%d\n",touchxy.code,touchxy.value);break;case EV_ABS://绝对坐标if(touchxy.code == ABS_X)//x坐标{printf("x=%d\n",touchxy.value);}else if(touchxy.code == ABS_Y)//Y坐标{printf("y=%d\n",touchxy.value);}else if(touchxy.code == ABS_PRESSURE)//压力值{printf("press=%d\n",touchxy.value);}break;}}munmap(gbk_addr,statbuf.st_size);
AA: //取消映射munmap(lcd_p,fb_fix.smem_len);return 0;
}

Linux下输入子系统上报触摸屏坐标相关推荐

  1. Linux下IIC子系统和触摸屏驱动

    Linux下IIC子系统和触摸屏驱动 1.IIC简介   I2C( Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备. ...

  2. linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例

    1.1    本节阅读前提 本节的说明建立在前两节的基础之上,需要先阅读如下两篇章: linux input输入子系统分析<一>:初识input输入子系统 linux input输入子系统 ...

  3. linux input输入子系统分析《一》:初识input输入子系统

    主要讲述本人在学习Linux内核input子系统的全部过程,如有分析不当,多谢指正.以下交流方式,文章欢迎转载,保留联系信息,以便交流. 邮箱:eabi010@gmail.com 主页:www.iel ...

  4. 12.Linux之输入子系统分析(详解)

    在此节之前,我们学的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥/非阻塞.定时器去抖动. 其中驱动框架如下: 1)写file_op ...

  5. linux rapidio测试,Linux 下RapidIO 子系统的分析与实现.pdf

    Linux 下RapidIO 子系统的分析与实现.pdf 第36 卷 第9 期 计 算 机 工 程 2010 年5 月 V Computer Engineering May 2010 ol.36 No ...

  6. linux input输入子系统分析《四》:input子系统整体流程全面分析

    1      input输入子系统整体流程 本节分析input子系统在内核中的实现,包括输入子系统(Input Core),事件处理层(Event Handler)和设备驱动层.由于上节代码讲解了设备 ...

  7. linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析

    1      mini2440的ADC驱动实例 这节与输入子系统无关,出现在这里是因为后面的章节会讲到触摸屏输入子系统驱动,由于触摸屏也使用ADC,因此本节是为了说明ADC通过驱动代码是如何控制的. ...

  8. 浅析Linux下的子系统

    纸上得来终觉浅,绝知此事要躬行.--陆游<冬夜读书示子聿> 开始接触的驱动程序代码不长,而且结构体和重要函数基本在一个文件内,而后来遇见的内核自带的驱动程序就比较坑了,大部分结构体都分布在 ...

  9. linux env 变量,Linux下 输入 env 而得到的环境变量解读

    HOSTNAME=Master.Hadoop MAHOUT_HOME=/usr/hadoop/mahout-distribution-0.8 TERM=linux SHELL=/bin/bash HA ...

最新文章

  1. 全局声明宏定义_Rust语言:元编程,强大的宏系统,菜鸟到高手进阶的必经之路...
  2. Get Started with Field Service
  3. 第二次爬虫,更加熟练啦
  4. 2017 阿里技术-年度精选
  5. WPF初学——自定义样式
  6. 基于Domain Driven Design&Clean Architecture原则分层的新启动模板
  7. 理解C# 4 dynamic(2) – ExpandoObject的使用
  8. 震惊整个世界的新发现,科学界的大骗局
  9. macOS开启内建的TFTP服务器
  10. 微服务升级_SpringCloud Alibaba工作笔记0002---理解反应式编程中的背压(Backpressure)机_流的逆向压力
  11. android获取详细地址,Android获取当前子网掩码地址(亲测可用)
  12. 新浪微博php7升级实践,PHP7线上system time飙高问题
  13. 你们真的会追汉纸么?!
  14. 简书android 输入法设置,Android输入法弹出流程
  15. matlab实现矩形脉冲串,python中的矩形脉冲串
  16. win10下ctfmon.exe系统程序误删的解决方案
  17. Android平台Cocos2dx打包流程
  18. 计算机组装配置兼容,电脑组装时怎么选择配置主板
  19. Mac 系统下java端口占用
  20. defer、delay和postpone的区别?

热门文章

  1. 满二叉树和完全二叉树的区别
  2. L1-030 一帮一(分数 15)
  3. 【Android】之【WebView】
  4. CSS Display与Visibility区别和用法
  5. 2-44 JQuery
  6. 正则化,岭回归Shrinkage,lasso稀疏性推导和论文总结
  7. 网站丨这四个网站好像有点好玩
  8. 微软Ribbon界面
  9. /etc/passwd文件详解
  10. ERROR: Error in Log_event::read_log_event(): ‘Sanity check failed‘, data_len: 67, event_type: 35