曾经做过tslib触摸屏实验,虽然在硬件驱动下触摸屏确有反应,但是针对xserver,tslib提供上来的坐标数据不知如何处理再向上层传递,由于后来接触到触摸屏厂商,从官方网站touchkit上下载了一个针对本操作系统的驱动,包括xserver-input驱动。所以改变策略,从这个专用驱动开始入手。首先下载下来的驱动不符合我的内核和xserver,幸亏有源码。但是直接make不行,因为这些源码和make都是针对老xf86开发的,自从xf86-1.3版本以后不开放源码,xorg在xf86基础上自己改写了xserver,开始有了X11R6。这些改动对我一个初试牛刀的新手可谓困难重重。
首先重新编译发现依懒很多xf86工程,所以进行不下去,于是我针对每个目录各自编译试试,我的内核是debian的,该死的玩意以前就发现安装好后没有内核源码,现在又发现不带XServer头文件,疯了。还是采取老策略在红旗6下进行,先找出规律再说。发现在红旗6下部分源码编译通过,分别得到tkusb.ko,usbpnpd,tpaneld。这里先对他们的作用进行简单介绍。tkusb是最底层的硬件驱动,由他与触摸屏控制器通讯。而后usbpnpd做些初试工作后第一次启动tpaneld为第二次启动tpanld扫清障碍。tpaneld采用异步通知和信号的方式向上层传递数据,这些数据已经经过tpaneld校准。tpaneld采用的校准数据时由那些4点,25点校准程序先行运行得来的,官方还提供了drawtest程序进行了测试。只不过这些程序在我的机器上都需要经过改动,这样也好,逼着我对源码一点一点分析。问题说道这大家发现还有一个为解决的问题,那就是上层谁来接受数据呢。这就关系到上面提到的xserver。
因为从上面的一系列程序得到坐标位置已不是难事,问题是如何让正确传递给上层,或者针对实际情况就是如何让他转化为类似于鼠标事件。鼠标是相对位移,触摸是绝对位移。经过一系列实验,观察,总结对xserver有了一定的了解。xorg里有许多.so文件,linux里叫库文件,但是它们不同于图形库那些文件,在这里我个人把它们理解为xserver的驱动,也就是把底层驱动带来的数据通过xserver的驱动向x窗口系统报告事件(如单击等)。所以在下载的驱动中包括了一个叫xf86touchkit.so或者老版本的touchkit_drv.so。xserver就是通过这些驱动和底层驱动打交道,xserver对底层驱动是透明的。最大的问题也就出现在这。因为xserver跟内核一样,不同的版本对它自己的驱动程序有格式上的要求,不正确的话在日志文件xorg.0.log中会显示不认识的模组。也正因为这样我发现提供的都是xf86的驱动,在xserver不能用。这个让我伤透了脑筋。
继续摸索,我想到可以找到xorg里其他驱动(库文件)的源码,通过理解这些源码是如何编写的来试着改动触摸屏的驱动。既然有了思路我继续努力,下载了synapitcs和mtouch的xserver-input驱动源码。仿造他们的格式改写了touchkit的x驱动。在这里我用了一点小聪明,因为如果用源文件的makefile根本通不过编译,于是我把改写的驱动改名为synapitcs.c,替代synapitcs.c,借用synapitcs的Makefile和一些依懒成功编译了驱动,再把编译好的驱动名改回来放进xorg里,在红旗6好像成功了。因为我的触摸屏和显示器不一样大,所以只能观察到方向正确,点击的位置差不多。,还不能说完全成功。
到这里我也曾经和你们一样认为没问题,小乐了一下,可是接着发生的事情让我痛苦不已。因为我说了我是在红旗6上做的实验,还要回到debian上。我首先想到把依懒的头文件从红旗6上拷过来。成功编译后发现不行,xorg报错不认识的模组,我已经猜到版本不一样。于是查看两者的版本,发现红旗6是1.3,debian是1.4.我只能又去下载xorg-1.4,把需要的头文件拷到相应的目录,编译成功装入也成功。可是点击触摸屏发现明显不对,方向不对,只在一个小区域里活动,也看不出什么规律。这可让我伤透了脑筋。
于是跟踪程序的执行过程,发现1.3和1.4不同,1.4以后的版本(包括1.5,1.6)差不多。首先发现的不同是
typedef struct _LocalDeviceRec {
struct _LocalDeviceRec *next;
char * name;
int flags;
Bool (*device_control)(DeviceIntPtr device, int what);
void (*read_input)(struct _LocalDeviceRec *local);
int (*control_proc)(struct _LocalDeviceRec *local,
xDeviceCtl *control);
void (*close_proc)(struct _LocalDeviceRec *local);
int (*switch_mode)(ClientPtr client, DeviceIntPtr dev,
int mode);
Bool (*conversion_proc)(struct _LocalDeviceRec *local,
int first, int num, int v0,
int v1, int v2, int v3, int v4,
int v5, int *x, int *y);
Bool (*reverse_conversion_proc)(
struct _LocalDeviceRec *local,
int x, int y, int *valuators);
int (*set_device_valuators)
(struct _LocalDeviceRec *local,
int *valuators, int first_valuator,
int num_valuators);
int fd;
Atom atom;
DeviceIntPtr dev;
pointer private;
int private_flags;
unsigned int first;
unsigned int last;
int old_x;
int old_y;
char * type_name;
IntegerFeedbackPtr always_core_feedback;
IDevPtr conf_idev;
InputDriverPtr drv;
pointer module;
pointer options;
unsigned int history_size;
} LocalDeviceRec, *LocalDevicePtr, InputInfoRec, *InputInfoPtr;
这是一个xorg驱动结构,每一个驱动程序都会想xserver登记这个结构,里面包含了一些回调的函数指针,就像硬件驱动登记read,write一样。这里面主要的是*conversion_proc函数指针,他的回调是在某些情况下可以由用户特殊处理一下数据。关于触摸屏在1.3上就是将x,y进行一下特殊缩放转换成正确的屏幕坐标。但是在1.4上我发现这个函数已经不调用了。于是我第一想到在*read_input回调函数里直接缩放,可是还是不行,我做过很多次试验就是发现conversion_proc的处理放在哪都不行,不处理任由之也不行,可是以我的经验和道理,肯定是要把一个合适数据在回调的时候传进去就好了,可是如何找到这个其中的平衡点。我又继续看资料,认真对比1.3和1.4源码的不同,发现input_read里有一个函数xf86PostMotionEvent在两个版本中处理的不一样,并且conversion_proc也是在这里调用的,而且它似乎就是控制鼠标移动轨迹的。我曾经试图重载它直接放在我的驱动里,可是有些全局变量是活跃的,这种做法被否认了。我一直试图在寻找我的驱动和xserver之间的平衡点。沿着xf86PostMotionEvent不停追综下去,发现了一个小的细节那就是在xserver中有这么几行代码
if (pDev->coreEvents) {
int min = pDev->valuator->axes[0].min_value;
int max = pDev->valuator->axes[0].max_value;
if(min < max)
x = (int)((float)(x-min)*scr->width/(max-min+1));
cp->valuator->lastx = x;
min = pDev->valuator->axes[1].min_value;
max = pDev->valuator->axes[1].max_value;
if(min < max)
y = (int)((float)(y-min)*scr->height/(max-min+1));
cp->valuator->lasty = y;
}
那么我猜测是不是经过这里数据改变了,我猜测我传过去的应该是红色x,y,而xserver试图经过处理得到绿色x,y。又发现蓝色的数据也是我的驱动中传过去的,最小0,最大9600。根据计算公式那么我猜想一个不大的数经过9600倍的缩小就微乎其微了,所以我的鼠标只在小范围内乱动。一切的猜测似乎有些道理,但是还要根据实验得出正确的结论。于是我逆向思维将一个正确的坐标数据首先按照公式逆向处理一下再传进来,然后由上面的公式正向再计算一边那就不还原成正确的坐标了。这些都是大胆的猜想,还需要证实。我试着在input_read里这么干了,不出所料鼠标的方向和位置已经接近,和红旗6的一样了。那么我敢确定自己的思路应该是正确的了。当然还需要在产品的平台
上继续测试方能通过。这些都是后话。
到此,基本又可以告一段落。这几周触摸屏整的我有点痛苦,当然中途也做了一些紧急的事,呵呵。因为我是一个不能留下问题的人,对什么都希望弄得一清二楚。经过一段时间摸索,我总结出windows系统的确用起来很方便,不管什么程序傻瓜式安装就行,能装上就不会有大大的问题,而且版本之间追求一种兼容,都属于一个公司嘛。可是linux不同,版本之间细节差异很多,让修改源码的人理不清头绪。每个开源都是由不同的团队,不同的人开发出来的,不免有些出入,造成新手们措手不及。尤其象我们这种没有前辈指导,光靠摸索,的确很辛苦。不过反过来也提高了我们的综合素质,不停地分析源码,找出关联程序之间的关系,自己的知识和经验在不断地积累和形成,这对我们来说是好事。所以,还是得坚持,没有不能攀登的山,没有趟不过的河,努力一点,仔细一点,刻苦一点,总有办法能解决的。