0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-09-25 08:56 次阅读

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

1.输入子系统简介

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

pYYBAGMuvISABHEGAAUp7Zj3V_s861.png#pic_center

设备驱动层

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

核心层

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

事件处理层

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

2.输入子系统好处

统一了物理形态各异的相似的输入设备的处理功能。例如,各种鼠标,不论 PS/2、 USB、还是蓝牙,都被同样处理。输入子系统常见事件类型为:按键事件(如键盘)、相对坐标事件(如鼠标)、绝对坐标事件(如触摸屏)。

提供了用于分发输入报告给用户应用程序的简单的事件( event)接口。你的驱动不必创建、管理/dev节点以及相关的访问方法。因此它能够很方便的调用输入 API 以发送鼠标移动、键盘按键,或触摸事件给用户空间。

抽取出了输入驱动的通用部分,简化了驱动,并提供了一致性。例如,输入子系统提供了一个底层驱动(成为 serio)的集合,支持对串口和键盘控制器等硬件输入的访问。

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

struct input_dev 结构体
  结构体 input_dev 表示底层硬件设备,是所有输入设备的抽象。驱动层需要实现对input_dev 结构体的填充。

struct input_dev {
	const char *name; //设备名字--比如:键盘的名字
	const char *phys; //设备在系统中的路径。比如:input/key0
	const char *uniq; //唯一ID号
	struct input_id id; //用于匹配事件处理层 handler

	unsigned 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;//最后一次同步后没有新的事件置 1

	struct 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函数用于设置上报的数值的取值范围。

上报数据到事件处理层

//上报按键事件键值,如键盘
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
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,%dtnum=%dn",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=%staddr=%#xtirq=%dn",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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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("申请空间失败rn");
		return ;
	}
	memcpy(p,gbk_addr+addr,font_size);//读取点阵码数据	
	int i,j;
	int x0=x;
	unsigned char tmep;
	for(i=0;i=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*size>8;j++)"> 

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 触摸屏
    +关注

    关注

    42

    文章

    2304

    浏览量

    116173
  • Linux
    +关注

    关注

    87

    文章

    11302

    浏览量

    209434
  • 子系统
    +关注

    关注

    0

    文章

    109

    浏览量

    12398
收藏 人收藏

    评论

    相关推荐

    ARM触摸屏驱动系统设计

    介绍了基于飞思卡尔芯片i.MX27 和嵌入式linux 系统触摸屏硬件的连接设计和软件的驱动设计.
    发表于 05-02 10:56 2729次阅读

    STM32 SPI驱动触摸屏(XPT2046)(上)

    触摸屏又称触控面板,它是一种把触摸位置转化成坐标数据的输入设备触摸屏可以分为电阻式触摸屏和电容式
    发表于 07-22 15:01 5436次阅读
    STM32 SPI驱动<b class='flag-5'>触摸屏</b>(XPT2046)(上)

    基于触摸屏驱动的Linux内核输入子系统研究

    基于触摸屏驱动的 Linux 内核输入子系统研究华明, 徐造林( 东南大学 计算机科学与工程学院, 江苏 南京 210 096)摘要: Li nux 是目前最为优秀的开源
    发表于 03-20 16:04

    嵌入式Linux触摸屏在漆包线检测系统中的应用

    本文针对嵌入式Linux触摸屏在漆包线检测系统中的应用,介绍了本系统触摸屏的具体接口威廉希尔官方网站 ,嵌入式Lin
    发表于 07-27 15:47 29次下载

    基于MeeGo的电容式触摸屏驱动设计

    本文基于Nokia和Intel公司合作开发的开源操作系统MeeGo,采用基于内核对象的Linux输入子系统来设计触摸屏的驱动。该方案极大地方
    发表于 05-25 10:55 1379次阅读
    基于MeeGo的电容式<b class='flag-5'>触摸屏</b>驱动设计

    51单片机系统中的触摸屏坐标算法

    本文提出了一种在51单片机系统中的触摸屏坐标算法。
    发表于 03-24 15:49 1次下载

    Linux触摸屏驱动

    对于触摸屏驱动,我们主要需要掌握触摸屏驱动代码和应用层测试代码。下面讲的是基于Mini2440的触摸屏驱动,现在的驱动我们都将设备和驱动分离,挂在平台设备总线上,让设备和驱动去匹配。
    发表于 04-26 14:45 2520次阅读

    Android的触摸屏进行校准的方法详细说明

    知道通常驱动是把采集到的原始坐标(A/D值),直接通过input系统上报。对于12位的 A/D,触摸屏的范围是:0~0xFFF。在驱动中表示如下:
    发表于 08-12 17:33 1次下载
    Android的<b class='flag-5'>触摸屏</b>进行校准的方法详细说明

    英创信息技术EM9280 Linux触摸屏应用开发简介

    提供对于4线制电阻式触摸屏的支持,在定制的Linux内核中已完全实现了该触摸屏的驱动支持。 在EM9280中,触摸屏作为输入设备其设备文件为
    的头像 发表于 01-16 09:39 1919次阅读
    英创信息技术EM9280 <b class='flag-5'>Linux</b><b class='flag-5'>触摸屏</b>应用开发简介

    硬件开发技术之触摸屏的详细介绍

    触摸屏又称触控面板,它是一种把触摸位置转化成坐标数据的输入设备,根据触摸屏的检测原理,主要分为电阻式触摸
    发表于 01-08 11:33 2982次阅读
    硬件开发技术之<b class='flag-5'>触摸屏</b>的详细介绍

    AD7877输入触摸屏控制器Linux驱动

    AD7877输入触摸屏控制器Linux驱动
    发表于 04-20 14:25 2次下载
    AD7877<b class='flag-5'>输入</b><b class='flag-5'>触摸屏</b>控制器<b class='flag-5'>Linux</b>驱动

    AD7873输入触摸屏迪吉蒂泽Linux Driver

    AD7873输入触摸屏迪吉蒂泽Linux Driver
    发表于 04-21 19:34 5次下载
    AD7873<b class='flag-5'>输入</b><b class='flag-5'>触摸屏</b>迪吉蒂泽<b class='flag-5'>Linux</b> Driver

    stm32 USB HID多点触摸屏上报安卓触摸信号

    关于stm32USB HID触摸屏前面的内容大家可以参考我之前写的两个博客,是一步一步过渡过来的!使用stm32配置自定义的HID设备stm32 USB HID单点触摸屏上报安卓触摸
    发表于 12-28 19:53 17次下载
    stm32 USB HID多点<b class='flag-5'>触摸屏</b><b class='flag-5'>上报</b>安卓<b class='flag-5'>触摸</b>信号

    电容触摸屏原理 电容触摸屏和电阻触摸屏有什么区别

    电容触摸屏和电阻触摸屏是两种常见的触摸屏技术,它们在原理、结构和应用方面都有很大的区别。下面将详细介绍电容触摸屏的原理、结构和特点,并与电阻触摸屏
    的头像 发表于 01-22 16:13 4572次阅读

    广州大彩讲堂:安卓/linux触摸屏四路CVBS输入实现同时显示!

    广州大彩串口安卓/linux触摸屏四路CVBS输入实现同时显示!
    的头像 发表于 12-25 16:49 57次阅读
    广州大彩讲堂:安卓/<b class='flag-5'>linux</b><b class='flag-5'>触摸屏</b>四路CVBS<b class='flag-5'>输入</b>实现同时显示!