从今年四月多开始,就开始接触android 底层,从制作刷机包,到友善之臂开发板-> 杨梅派A20 开发板-> 杨梅派Rk3006.差不多一年了,有成就,也有未完成的,也尝试过很多失败,但也收获很多。就里就把触屏解决方案整理一下。
刚开始接触开发速度很慢,kernel部分不会调试,sdk层,就通过打log来一步一步跟踪,因为插上触屏设备后,点击设备,只有中间会出现一个点,其他为反应,所以确定底层是可以上报数据的; 一开始是通过打log,后来通过google官网发现是有调试命令的。 这里查看
adb shell
getevent #打印出的以下第一组数据
getevent -lt #以下第二组数据
我们就分析部分数据
1.这是后来补上去的鼠标的event,当初singletouch的还要改回去麻烦。大概原理是这样的
/dev/input/event4: 0002 0001 fffffffe
/dev/input/event4: 0000 0000 00000000
/dev/input/event4: 0002 0000 0000000a
/dev/input/event4: 0002 0001 fffffffd
2.
EV_ABS ABS_X 000000bd
前面怎样获取数据的我就不提了,可以看一下这里
关于配置文件,原来android 4.0 以后,设备是要有配置文件的,文件名字为设备名字.idc,是触屏和鼠标设备的,在/system/usr/idc,当然设备名字是需要翻译的 通过getevent -p 获取设备名字,空格用_代替,我没有去改这个,而是在读取设备的地方,直接读取一个死文件。后来发现这样很不灵活,4.0的设备还好,当杨梅派盒子升级到了4.2 触屏和鼠标就冲突了, 鼠标也读取该配置,导致不正常运作,每次切换鼠标的时候都得手动去删除一下那个配置文件,但是因为卖出去的设备都是内嵌到显示屏里面的,就不需要鼠标,所以就这样先改着了!关于设备配置文件,进入idc文件, 拷贝一个,然后改名就可以了,至少我至今为止没发现什么不同。
打开 $ANDROIDSOURCE/frameworks/base/services/input/InputReader.cpp
设备在底层上报的时候就知道自己的类型了,通过classes 去和INPUT_DEVICE_... 做于运算,来new 一个inputmapper,这里我们走的是 device->addMapper(new SingleTouchInputMapper(device));
InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
const InputDeviceIdentifier& identifier, uint32_t classes) {
InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
identifier, classes);
// External devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
device->setExternal(true);
}
......
// Touchscreens and touchpad devices.
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
device->addMapper(new SingleTouchInputMapper(device));
}
虽然是一个singletouch设备,但上报的数据type所匹配的是BTN_MOUSE,在这里获取的type 为0110,通过查看input.h 查看到宏定义为0110的是BTN_MOUSE,而下面没有这个设备,所以自己加上了。要加的地方分有
void TouchButtonAccumulator::process(const RawEvent* rawEvent) {
if (rawEvent->type == EV_KEY) {
switch (rawEvent->code) {
//以下两句是自己加的
case BTN_MOUSE:
mBtnMouse=rawEvent->value;
void TouchButtonAccumulator::reset(InputDevice* device) {
mBtnMouse=device->isKeyPressed(BTN_MOUSE);
void TouchButtonAccumulator::clearButtons() {
mBtnMouse=0;
bool TouchButtonAccumulator::isToolActive() const {
return mBtnMouse||mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber
5.在inputreader.h 中加入定义
private:
bool mHaveBtnTouch;
bool mHaveStylus;
bool mBtnMouse;
走完了touch process方法筛选,其实那个方法就是确定你的设备是否isactive(以上方法4,怎么用以下再提)
void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent){
switch (rawEvent->code) {
case ABS_X:
mAbsX = rawEvent->value;
break;
没错,这里就是你看到的通过getevent获得的触点数据,既然x,y,都有了,而且坐标也正常,为什么还不正常呢。
在数据类型,以及数据捕获后,会调用sycn进行处理,然后就是回调上层的事件函数了。
void TouchInputMapper::sync(nsecs_t when) {
...
syncTouch(when, &havePointerIds);//调用自有的处理逻辑
...
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
if (mTouchButtonAccumulator.isToolActive()) {
......
bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
&& (mTouchButtonAccumulator.isHovering()
|| (mRawPointerAxes.pressure.valid
&& mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
.....
//mCurrentRawPointerData.markIdBit(0, isHovering);
mCurrentRawPointerData.markIdBit(0,false); //这里是我的修改
}
在这里你也许就明白了,第一步加设备的BTN_MOUSE的用意,因为没有设备,所以isToolActive不会调用里面的处理。是处理了后,设备点还是不对, 这里就出现了一个概念,就是hovering 悬空,我们想一下,因为是当鼠标处理的,当你没有按下鼠标左键,只是在屏幕上有个鼠标在移动而已,只有左键按下后,才能左右拖动屏幕。 于是我就把isHovering,强制让它不悬空,这样usbtouch设备在不修改内核的情况下,就能实现单点触控了。也许会遇到很多问题,但是因为是定制的,盒子也是镶嵌在内部的,所以很多其他设备问题就 不用担心了。就我测试过很多触屏,和很多开发板,居然都可以如此解决。
我原先就看过关于内核触屏驱动的很多资料,自己写驱动,感觉比较庞大的工程,因为没有写过,而且不知道怎么调试,光通过dmesg,也不是很会用。想通过修改驱动,以上能上报数据,说明是内核是有驱动的,只要将上报点类型修改一下。但是一直 苦于找不到,对应的驱动,一直以为驱动会在kernel/drivers/input/touchscreen下,那么多驱动文件怎么找啊。后来狗血的发现驱动居然在 kernel/drivers/hid/下面
连接好设备
adb shell
cat /proc/bus/input/devices
#出现以下信息
I: Bus=0003 Vendor=03fc Product=0588 Version=0100 //这个信息很重要,就是以后要说的vid,pid
N: Name="Touch__KiT Touch Computer INC." //设备名称
P: Phys=usb-usb20_host-1.1/input1
S: Sysfs=/devices/platform/usb20_host/usb2/2-1/2-1.1/2-1.1:1.1/input/input5 //设备在sys目录下的位置
U: Uniq=
H: Handlers=event3
B: PROP=0
B: EV=100003
B: KEY=0
cd /sys/devices/platform/usb20_host/usb2/2-1/2-1.1/2-1.1:1.1/input/input5
ll
#出现以下信息
drwxr-xr-x root root 2000-01-01 09:44 capabilities
lrwxrwxrwx root root 2000-01-01 09:44 device -> ../../../2-1.1:1.0 #设备链接的位置
drwxr-xr-x root root 2000-01-01 09:44 event2
drwxr-xr-x root root 2000-01-01 09:44 id
-r--r--r-- root root 4096 2000-01-01 09:44 modalias
drwxr-xr-x root root 2000-01-01 09:44 mouse0
cd ../../../2-1.1:1.0
ll
#出现以下信息
drwxr-xr-x root root 2000-01-01 09:48 0003:03FC:0588.0004
-r--r--r-- root root 4096 2000-01-01 09:48 bAlternateSetting
-r--r--r-- root root 4096 2000-01-01 09:48 bInterfaceClass
-r--r--r-- root root 4096 2000-01-01 09:48 bInterfaceNumber
-r--r--r-- root root 4096 2000-01-01 09:48 bInterfaceProtocol
-r--r--r-- root root 4096 2000-01-01 09:48 bInterfaceSubClass
-r--r--r-- root root 4096 2000-01-01 09:48 bNumEndpoints
lrwxrwxrwx root root 2000-01-01 09:48 driver -> ../../../../../../../bus/usb/drivers/usbhid #内核divers目录
cd ../../../../../../../bus/usb/drivers/usbhid
ll
#出现以下信息
lrwxrwxrwx root root 2000-01-01 09:51 2-1.1:1.0 -> ../../../../devices/platform/usb20_host/usb2/2-1/2-1.1/2-1.1:1.0
lrwxrwxrwx root root 2000-01-01 09:51 2-1.1:1.1 -> ../../../../devices/platform/usb20_host/usb2/2-1/2-1.1/2-1.1:1.1
lrwxrwxrwx root root 2000-01-01 09:51 2-1.1:1.2 -> ../../../../devices/platform/usb20_host/usb2/2-1/2-1.1/2-1.1:1.2
lrwxrwxrwx root root 2000-01-01 09:51 2-1.3:1.0 -> ../../../../devices/platform/usb20_host/usb2/2-1/2-1.3/2-1.3:1.0
--w------- root root 4096 2000-01-01 09:51 bind
lrwxrwxrwx root root 2000-01-01 09:51 module -> ../../../../module/usbhid
--w------- root root 4096 2000-01-01 09:51 new_id
--w------- root root 4096 2000-01-01 09:51 remove_id
--w------- root root 4096 2000-01-01 09:51 uevent
--w------- root root 4096 2000-01-01 09:51 unbind
进入android源代码,进入kernel目录
cd drivers
find . -name usbhid*
#出现以下信息
./hid/usbhid
./hid/usbhid/usbhid.o
./hid/usbhid/usbhid.h
我们知道kernel设备是需要注册的,hid目录下有一个hid-ids.h在里面通过vid和pid加入我们自己的设备
vi ./hid/hid-ids.h
#ifndef HID_IDS_H_FILE
#define HID_IDS_H_FILE
//加在所有设备的上面 =.=
#define USB_VENROR_ID_KIT 0x03fc //名字自己定义,id为第一步中的vid
#define USB_PRO_ID_KIT 0x0588 //名字自己定义,id为第一步中的pid
下面我们看一下怎样使用这些id,全局搜索一下系统自带的id如何使用的。
find ./hid/ -name '*' -exec grep 'USB_VENDOR_ID_3M' '{}' \; -print
# 出现以下信息
grep: ./hid/: 是一个目录
HID_USB_DEVICE(USB_VENDOR_ID_3M,
HID_USB_DEVICE(USB_VENDOR_ID_3M,
HID_USB_DEVICE(USB_VENDOR_ID_3M,
./hid/hid-multitouch.c
#define USB_VENDOR_ID_3M 0x0596
./hid/hid-ids.h
grep: ./hid/usbhid: 是一个目录
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
./hid/hid-core.c
按照以上出现的地方,hid-multitouch.c,hid-core.c 中去加自己的设备
vi ./hid/hid-multitouch.c
static const struct hid_device_id mt_devices[] = {
/* 仿照其他的将自己的设备vid pid写上 */
{ .driver_data = MT_CLS_KIT,
HID_USB_DEVICE(USB_VENROR_ID_KIT,
USB_PRO_ID_KIT) },
修改hid-core
vi ./hid/hid-core.c
static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENROR_ID_KIT, USB_PRO_ID_KIT) },
我博客中有讲,不细说
sudo make ARCH=arm menuconfig
#需要配置的地方
1. Device Drivers -->
HID Devices -->//这里面的全选
HID Multitouch panels //在这个选项上按y
2.Device Drivers -->
Input device support -->
[*] Provide legacy /dev/psaux device
(1024) Horizontal screen resolution
(768) Vertical screen resolution
然后编译内核和android 这里就不说了!
getevent 查看
#出现以下信息,如果出现ABS_MT恭喜你 你成功了
[ 8698.525097] /dev/input/event2: EV_SYN SYN_REPORT 00000000
[ 8698.542045] /dev/input/event2: EV_ABS ABS_MT_POSITION_X 00000095
[ 8698.542052] /dev/input/event2: EV_ABS ABS_MT_POSITION_Y 0000048b
[ 8698.542084] /dev/input/event2: EV_ABS ABS_X 00000095
[ 8698.542089] /dev/input/event2: EV_ABS ABS_Y 0000048b
[ 8698.542101] /dev/input/event2: EV_SYN SYN_REPORT 00000000
[ 8698.559043] /dev/input/event2: EV_ABS ABS_MT_POSITION_X 0000009e
[ 8698.559051] /dev/input/event2: EV_ABS ABS_MT_POSITION_Y 00000484