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/)
浙公网安备 33010602011771号