该小节我们开始讲解多点触摸屏的驱动层。我们的驱动只需要上报多个触点的位置就可以了。
应用程序一般会使用open,read,write,ioctl等访问驱动程序,最简单的方法就是我们在驱动程序中也实现对应的函数,在linux中存在一个输入子系统,以上的函数,在驱动层,其已经帮我们实现了,我们只需要实现硬件相关的那比部分即可。
比如有数据时,上报数据(上报给输入子系统)。前面提到驱动程序需要提供open,read,write,ioctl等函数,那么在输入子系统中,谁来提供该函数呢?其核心在SDK/kernel/input.c与SDK/kernel/evedv.c(内核源码)文件中。
在evedv.c文件中:
static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
.flush = evdev_flush,
.llseek = no_llseek,
};
我们可以找到以上文件描述符,那么这个文件描述符是在哪里注册的呢?在文中查找evdev_fops,可以找到:
/*当有输入设备接入的时候,调用该函数*/
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
/*获取一个新的次设备号*/
minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
/*绑定文件描述符*/
cdev_init(&evdev->cdev, &evdev_fops);
/*生成设备节点*/
error = device_add(&evdev->dev);
这样就完成了input驱动设备的注册。那么evdev_fops中的函数,他怎么获得数据呢?这些就是和硬件相关的操作了,也就是我们需要去编写的驱动程序
一般来说步骤如下:
1.构造input_device
2.设置input_device
3.注册input_device
4.有数据时,调用input_event函数上报数据,该函数会把数据放到evdev_fops->read的buffer中。
假设应用程序调用open函数,打开了某个输入设备节点,然后其read函数被调用,在没有数据的时候,其会处于阻塞状态。当我们按下,或者点击触摸屏的时候,会产生某个中断,在中断中,从硬件获取数据,调用input_event上报,input_event会把数据放在read的buffer中,同时唤醒休眠的应用程序。
下面我们来对比一下单点触摸(电阻屏),和多点触摸(电容屏)的区别。
单点触摸(电阻屏):
按下上报:BTN_TOOCH,1
滑动:循环上报ABS_X(X坐标),ABS_Y(Y坐标),ASB_PRESSORE(压力值),BTN_TOOCH为1。
松开上报:BTN_TOOCH,1
多点触摸:
在一个时刻有几个点,就上报几个点(即在循环上报所有触点位置)。一般来说,有两中上报方式:
a:直接上报触电
b.上报触电,以及触点之间的关系(如是否为同一划痕)
下面是设置多点触摸上报事件类型设定,以及上报数据的例子:
类型设定:
input_set_abs_params(input_device,ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
input_set_abs_params(input_device,ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
input_set_abs_params(input_device,ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
input_set_abs_params(input_device, ABS_MT_PRESSURE, 0, 255, 0, 0);
上报数据:
input_report_abs(ts->input, ABS_MT_PRESSURE, id);//id可以理解为是否为同一划痕
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 1);
input_report_abs(ts->input, ABS_MT_POSITION_X, x);
input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
input_mt_sync(ts->input);
光说不练是没有作用的,下小节我们开始进入实战,编写电容屏驱动程序的框架。