xhawk整合过很多触控屏的驱动,这是最紧张的一次。
以前碰到的触控屏,无非就是将驱动代码放到linux kernel下面,加下i2c设备,
然后再看看屏幕是否旋转,大小是否对,三下五除二,效果就出来了。
这次的elan屏,有两种接口,usb口和i2c口的。
先说usb口触控屏,它是 “免驱” 的,插上windows直接可以使用。
我肋个去~~ android/linux素好源码,恶 “免驱”。
何不一试?也许运气不错!将屏幕连接到系统一看,有戏!
/dev/input下面成功的出现了新的event2和mouse2设备。
再到安卓界面上试试看,咦,没反应?
再 cat /dev/input/event2,发现触摸屏幕时,的确有数据输出的。
看来,情况很明显 -- 这个屏幕输出的数据,不被android所认可。
于是,结论也很明显 -- 要么屏的厂家能提供一份android驱动,要么我们自己写。
而厂家明确说,他们没有android/linux驱动。。。
现在,真的挑战来了。
离项目拿给客户做演示还有两天的时间,而我们要在没有数据手册的情况下,
为第三方产品开发一个驱动。。这都是苦命啊!
但是人还是要向前看,要充满英雄主义的自信感,事情总是会解决的。
每当这么悲催又必须自信的时候,我都不免想起大学挂科的经历。
挂科,然后补考。
补考出来,极为惆怅;同考的一个妹子,幽幽的跟俺说,同时天涯沦落人。。
我肋个去~~ 谁跟你沦落人,不就一辅修课吗,老子还有大好前程呢。这种鸟女人无需理会。
于是我大踏步走开,悲催又略显自信,任由妹子在风中。。
数年后,咱一贯的悲催又自信。岂止悲催,简直悲痛。用时下流行语,简直是喔草,屌丝,活该撸一被子。。。
扯远,言归正传。
xhawk不想写驱动,于是去试验用另一个i2c接口的屏幕,希望能取代此usb接口屏。
直接后果是,又浪费了一天。
此时,离截止时间还有半天。俗话说,压力之下必有激情,总之,咱找到办法了--
用uinput,用户层输入接口。写一个用户层应用程序即可,
这样程序修改调试是很快速的,不会把系统搞死,也无需重烧系统。
总之,比写kernel层的驱动经济有效的多。
现在,只要一个程序,从原usb的设备文件event2中读到数据,
将它用uinput包装成安卓可辨识的设备数据,就大功告成了。
事后证明,此法相当靠谱,写应用层驱动果然很方便,几个小时就完成了。
此次演示涉险过关。
贴上部分代码,很简单的。就是对原有hid数据转换一下而已。
#include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <linux/input.h> #include <android/log.h> #include <linux/uinput.h> #include <sys/select.h> #define SCREEN_W 4000 #define SCREEN_H 2250 #define SCREEN_RORATE int input_init(int fd) { int i; struct uinput_user_dev uidev; struct input_absinfo absX, absY; int ufd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if(ufd < 0) return ufd; memset(&uidev, 0, sizeof(uidev)); snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-convert"); uidev.absmax[ABS_X] = SCREEN_W; uidev.absmin[ABS_X] = 0; uidev.absmax[ABS_Y] = SCREEN_H; uidev.absmin[ABS_Y] = 0; ioctl(ufd, UI_SET_EVBIT, EV_SYN); ioctl(ufd, UI_SET_EVBIT, EV_KEY); ioctl(ufd, UI_SET_EVBIT, EV_ABS); //ioctl(ufd, UI_SET_EVBIT, EV_MSC); ioctl(ufd, UI_SET_ABSBIT, ABS_X); ioctl(ufd, UI_SET_ABSBIT, ABS_Y); ioctl(ufd, UI_SET_KEYBIT, BTN_TOUCH); write(ufd, &uidev, sizeof(uidev)); ioctl(ufd, UI_DEV_CREATE); return ufd; } void input_report(int ufd, struct input_event *ev) { write(ufd, ev, sizeof(*ev)); } void input_close(int ufd) { if(ufd < 0) return; ioctl(ufd, UI_DEV_DESTROY); close(ufd); } void convert_data(int ufd, int fd) { int i = 0; struct input_event ie; int last_key_down = 0; struct timeval tv_key0 = {0, 0}; struct timeval tv = {0, 0}; fd_set set; FD_ZERO(&set); while(1) { int j; int rt; ssize_t len; if(!FD_ISSET(fd, &set)) FD_SET(fd, &set); tv.tv_sec = 0; tv.tv_usec = 10000; rt = select(fd+1, &set, NULL, NULL, &tv); if(rt < 0) continue; if(rt == 0) { if(last_key_down) { last_key_down = 0; memset(&ie, 0, sizeof(ie)); ie.type = EV_KEY; ie.code = BTN_TOUCH; ie.value = 0; input_report(ufd, &ie); } continue; } if(!FD_ISSET(fd, &set)) continue; len = read(fd, &ie, sizeof(ie)); if(len < 0) break; switch(ie.type) { case EV_SYN: input_report(ufd, &ie); break; case EV_KEY: if(ie.code == BTN_TOUCH) { struct timeval interval; timersub(&ie.time, &tv_key0, &interval); tv_key0 = ie.time; if(interval.tv_sec == 0 && interval.tv_usec >= 0 && interval.tv_usec < 5000) ; //ignore else { last_key_down = ie.value; input_report(ufd, &ie); } } break; case EV_ABS: if(ie.code == 0x0) { #ifdef SCREEN_RORATE ie.value = (SCREEN_W > ie.value ? SCREEN_W - ie.value - 1 : 0); #endif input_report(ufd, &ie); } else if(ie.code == 0x2) { ie.code = ABS_Y; #ifdef SCREEN_RORATE ie.value = (SCREEN_H > ie.value ? SCREEN_H - ie.value - 1 : 0); #endif input_report(ufd, &ie); } break; default:; } } } int main(int argc, char **argv) { int fd; int ufd; if(argc != 2) { fprintf(stderr, "Usage: %s <touch_device_path>\n", argv[0]); return 1; } fd = open(argv[1], O_RDONLY); if(fd < 0) { fprintf(stderr, "Can not open device: %s\n", argv[1]); return 1; } ufd = input_init(fd); if(ufd < 0) { close(fd); fprintf(stderr, "Can not create uinput device\n"); return 1; } convert_data(ufd, fd); close(ufd); close(fd); return 0; }
(转载请标明:http://www.cnblogs.com/xhawk18/)