编写简单的触摸屏驱动程序——基于QEMU

参考资料

  • Documentation/input/input-programming.txt
  • Documentation/input/event-codes.txt

一、准备QEMU

启动虚拟设备:./qemu-imx6ull-gui.sh
ubuntu-18.04_imx6ul_qemu_system/imx6ull-system-image目录下修改设备树和内核

二、QEMU触摸屏操作方法

2.1 原理:

  1. 鼠标在屏幕上按下、松开:
    1. QEMU改变GPIO电平、产生中断
    2. 在touch_pressure_register中记录压力值
  2. 鼠标在屏幕上滑动
    1. 在touch_x_register、touch_y_register中记录坐标

2.2 寄存器说明

地址寄存器说明
0x021B4000touch_pressure_register记录触摸屏压力值,只有0、1两个取值。1表示按下,0表示松开
0x021B4004touch_x_register记录触摸屏X坐标
0x021B4008touch_y_register记录触摸屏Y坐标
0x021B400Ctouch_clean_register写入任意值,就会清零上述3个寄存器(仅用于测试)

鼠标在屏幕上按下、松开:

  • QEMU改变GPIO电平、产生中断
  • 在touch_pressure_register中记录压力值
    鼠标在屏幕上滑动
  • 在touch_x_register、touch_y_register中记录坐标
    仅能模拟单点触摸,不能模拟多点触摸

三、编写驱动程序

#include <linux/module.h>
#include <linux/init.h>
#include <linux/irqreturn.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>

#define TOUCHSCREEN_POLL_TIME_MS 10

struct qemu_ts_con {
	volatile unsigned int pressure;
	volatile unsigned int x;
	volatile unsigned int y;
	volatile unsigned int clean;
};

static struct input_dev *g_input_dev;
static int g_irq;
static struct qemu_ts_con *ts_con;
struct timer_list ts_timer;

static void ts_irq_timer(unsigned long _data)
{
	if(ts_con->pressure) {
		input_event(g_input_dev, EV_ABS, ABS_X, ts_con->x);
		input_event(g_input_dev, EV_ABS, ABS_Y, ts_con->y);
		input_sync(g_input_dev);

		mod_timer(&ts_timer, jiffies + msecs_to_jiffies(TOUCHSCREEN_POLL_TIME_MS));
	}
}

static irqreturn_t input_dev_demo_irq(int irq, void *dev_id)
{
	/* read data */

	/* report data */
	//input_event(g_input_dev, EV_KEY, XX, 0);
	//input_sync(g_input_dev);
	//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	if(ts_con->pressure) {
		input_event(g_input_dev, EV_ABS, ABS_X, ts_con->x);
		input_event(g_input_dev, EV_ABS, ABS_Y, ts_con->y);
		input_event(g_input_dev, EV_KEY, BTN_TOUCH, 1);
		input_sync(g_input_dev);

		mod_timer(&ts_timer, 
				jiffies + msecs_to_jiffies(TOUCHSCREEN_POLL_TIME_MS));			//更新中断时间
		
	} else {
		input_event(g_input_dev, EV_KEY, BTN_TOUCH, 0);
		input_sync(g_input_dev);
	}

	return IRQ_HANDLED;
}

static int input_dev_demo_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	int error = 0;
	//struct resource *irq;
	struct resource *io;
	int gpio;

	/* get hardware info from device tree */
	gpio = of_get_gpio(pdev->dev.of_node, 0);
	if(!gpio) {
		printk(KERN_ERR"of_get_gpio error\n");
		return -1;
	}

	/* alloc/set/register input_dev */
	g_input_dev = devm_input_allocate_device(dev);
	if(!g_input_dev) {
		printk(KERN_ERR"devm_input_allocate_device error\n");
		return -1;
	}

	g_input_dev->name = "input_dev_demo";
	g_input_dev->phys = "input_dev_demo";
	g_input_dev->dev.parent = dev;

	g_input_dev->id.bustype = BUS_HOST;
	g_input_dev->id.vendor  = 0x0001;
	g_input_dev->id.product = 0x0001;
	g_input_dev->id.version = 0x0001;


	/* set 1: which type event ? */
	__set_bit(EV_KEY, g_input_dev->evbit);
	__set_bit(EV_ABS, g_input_dev->evbit);
	__set_bit(INPUT_PROP_DIRECT, g_input_dev->propbit);				//设备触摸设备标志位,可以让tslib识别到

	/* set 2: which event? */
	__set_bit(BTN_TOUCH, g_input_dev->keybit);
	__set_bit(ABS_X, g_input_dev->absbit);
	__set_bit(ABS_Y, g_input_dev->absbit);

	/* set 3: event params ? */
	input_set_abs_params(g_input_dev, ABS_X, 0, 0xffff, 0, 0);			//设置X和Y的范围,起始值
	input_set_abs_params(g_input_dev, ABS_Y, 0, 0xffff, 0, 0);

	error = input_register_device(g_input_dev);

	/* hardware operation  */
	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);		//获取IO资源
	ts_con = ioremap(io->start, io->end - io->start);

	g_irq = gpio_to_irq(gpio);			//获取中断号
	error = request_irq(g_irq, input_dev_demo_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "input_dev_demo_irq", NULL);

	setup_timer(&ts_timer, ts_irq_timer, (unsigned long)NULL);	//初始化定时器
	return 0;
}

static int input_dev_demo_remove(struct platform_device *pdev)
{
	del_timer_sync(&ts_timer);			//删除定时器
	iounmap(ts_con);				//释放io资源
	free_irq(g_irq, NULL);
	input_unregister_device(g_input_dev);
	return 0;
}

static struct of_device_id input_dev_demo_of_match[] = {
	{ .compatible = "100ask,input_dev_demo" },
	{ },
};

static struct platform_driver input_dev_demo_driver = {
	.probe = input_dev_demo_probe,
	.remove = input_dev_demo_remove,
	.driver = {
		.name = "input_dev_demo",
		.of_match_table = input_dev_demo_of_match,
	}
};

static int __init input_dev_demo_init(void)
{
	return platform_driver_register(&input_dev_demo_driver);
}

static void __exit input_dev_demo_exit(void)
{
	platform_driver_unregister(&input_dev_demo_driver);
}

module_init(input_dev_demo_init);
module_exit(input_dev_demo_exit);
MODULE_LICENSE("GPL");

四、上机实验

[root@qemu_imx6ul:/mnt/home/picture/input]# hexdump /dev/input/event3
0000000 051f 0000 c466 0008 0003 0000 23f5 0000
0000010 051f 0000 c466 0008 0003 0001 3698 0000
0000020 051f 0000 c466 0008 0001 014a 0001 0000
0000030 051f 0000 c466 0008 0000 0000 0000 0000
0000040 0520 0000 dc31 0009 0001 014a 0000 0000
0000050 0520 0000 dc31 0009 0000 0000 0000 0000
0000060 0528 0000 acf5 0008 0003 0000 2289 0000

五、使用tslib支持触摸

在Ubuntu上执行下列命令。

  • 编译
tar xJf tslib-1.21.tar.xz
cd tslib-1.21
./configure --host=arm-linux-gnueabihf  --prefix=/
make
make install DESTDIR=$PWD/tmp
  • 复制头文件/库到工具链(非必须, 编译其他APP时需要)
cd tslib-1.21/tmp/

cp include/* /home/book/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/6.2.1/../../../../arm-linux-gnueabihf/include

cp -d lib/*so*  /home/book/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/../arm-linux-gnueabihf/libc/usr/lib/

  • 复制库、APP到开发板

    假设在Ubuntu的/home/book/nfs_rootfs目录下有tslib-1.21。
    在开发板上执行:

mount -t nfs -o nolock,vers=3 10.0.2.2:/home/book/nfs_rootfs /mnt
cp  /mnt/tslib-1.21/tmp/lib/*  -drf     /lib
cp  /mnt/tslib-1.21/tmp/bin/*            /bin
cp  /mnt/tslib-1.21/tmp/etc/ts.conf  -d  /etc
  • 使用tslib
export TSLIB_TSDEVICE=/dev/input/event3
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0

ts_calibrate

ts_test
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

习惯就好zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值