近期給客戶調試一塊數控板,今天客戶帶過來一個屏,並且有一個usb的觸控螢幕晶片接在屏上。屏很快就弄好正常顯示。
觸控螢幕在核心下找到usb 觸控螢幕驅動,核心啟動後這個usb轉的觸控螢幕也正常找到,註冊為event介面事件event0, cat /dev/event0,觸控螢幕幕有亂碼輸出,說明usb觸控螢幕驅動產生中斷並且將採集資料上報input子系統了。
然後用我移植的tslib中有幾個校準測試程式,運行,發現出現下面的錯誤:
selected device is not a touchscreen I understand
屏上出現校準介面,但是校準的5個點瞬間連了一遍程式就出錯結束了。
多次嘗試都是這個結果,我就插入一個usb的滑鼠,識別產生event1,我就講為tslib回合設定的環境變數中tslib的裝置設為event1,再運行校準程式,發現現象跟觸控螢幕的一樣。也就說tslib中應該是有容錯處理,會先根據一些條件來判斷這個環境變數指定的裝置是否是一個真正的觸控螢幕裝置。
想多無意,還是多看代碼,於是在tslib源碼中找到上面這句的出處如下:
static int check_fd(struct tslib_input *i)
{
struct tsdev *ts = i->module.dev;
int version;
u_int32_t bit;
u_int64_t absbit;
if (! ((ioctl(ts->fd, EVIOCGVERSION, &version) >= 0) &&
(version == EV_VERSION) &&
(ioctl(ts->fd, EVIOCGBIT(0, sizeof(bit) * 8), &bit) >= 0) &&
(bit & (1 << EV_ABS)) &&
(ioctl(ts->fd, EVIOCGBIT(EV_ABS, sizeof(absbit) * 8), &absbit) >= 0) &&
(absbit & (1 << ABS_X)) &&
(absbit & (1 << ABS_Y)) && (absbit & (1 << ABS_PRESSURE)))) {
fprintf(stderr, "selected device is not a touchscreen I understand\n");
return -1;
}
if (bit & (1 << EV_SYN))
i->using_syn = 1;
return 0;
}
這個check_fd中會根據這些條件來判斷是否列印如上錯誤。
第一個條件是ioctl擷取version,核心源碼下找到ioctl定義在driver/input/evdev.c中,對應命令EVIOCGVERSION定義值為0x10000 而編譯器中input.h中定義值也是0x10000,這個條件沒有問題。我看網上關於這個錯誤大部分問題都是處在這裡。可惜我的不是,繼續往下。
第二個條件是擷取input裝置的bit標誌,也就是看這個是被是否是一個觸控螢幕裝置。usb裝置我之前也沒有接觸過,但是根據cat /dev/event0,有反應,說明usb部分採集資料是沒有問題的,只是上報給input子系統出了問題,所以應該想到的是看一下usb觸控螢幕驅動註冊input裝置的部分代碼,在usb觸控螢幕驅動driver/usb/input/usbtouchscreen.c中的probe函數中代碼如下:
input_dev->name = usbtouch->name;
input_dev->phys = usbtouch->phys;
usb_to_input_id(udev, &input_dev->id);
input_dev->cdev.dev = &intf->dev;
input_dev->private = usbtouch;
input_dev->open = usbtouch_open;
input_dev->close = usbtouch_close;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
if (type->max_press)
input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
type->max_press, 0, 0);
可以看到evbit中設定了EV_ABS標誌位。這樣第二個條件也滿足了。
第三個條件是擷取專為觸控螢幕input裝置準備的absbit標誌中是否有觸控螢幕對應的標誌位,因為之前寫過一個觸控螢幕驅動,所以知道觸控螢幕標誌位為x y press,也就是座標以及按壓。
在input_set_abs_params實現中是為absbit置各種標誌位。並且設定對應標誌的範圍(min max),但是這個標誌比如x y press的範圍在後面沒有看到使用,我也實驗發現min max都寫0也沒有問題,這個是題外話了。
這裡就出現了問題了,usb觸控螢幕中枚舉出來的裝置中max_press和min_press都沒有設定,為0,所以最後這個設定press標誌位的函數就沒有調用。
所以我上面出現selected device is not a touchscreen I understand 是因為 absbit & (1 << ABS_PRESSURE)不滿足造成的。
我把if判斷注釋掉,然後重編核心啟動,運行tslib測試程式,發現不會出現上面的錯誤退出了,這個問題算是解決。後來我實驗發現input_set_abs_params中設定x y press的min max都沒有用到,即使這些都設定為0也沒有影響。
校準測試程式正常算是運行,但是我點擊螢幕,校準程式並沒有檢測到我的點擊行為,接著就遇到了這個問題。接著研究搞定。
運行tslib測試程式沒有檢測到點擊事件,但是cat /dev/event0時點擊螢幕是有東西傳給input子系統的,這說明觸控螢幕中斷是正常的。
之間編寫另外一個觸控螢幕驅動的時候點擊事件上報座標資料給input子系統是在觸控螢幕的中斷中做的,因此需要找到這段代碼來看一下有沒有問題,在usbtouchscreen.c中找到如下代碼:
static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
unsigned char *pkt, int len)
{
struct usbtouch_device_info *type = usbtouch->type;
if (!type->read_data(usbtouch, pkt))
return;
input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
if (swap_xy) {
input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
} else {
input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
}
if (type->max_press)
input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
input_sync(usbtouch->input);
}
這段代碼是中斷中上報資料給input子系統的部分,report key是標誌輸入事件是否按下和彈起,而對於觸控螢幕來說上報的資料包括x y press,這段代碼中可以看出由於max_press為0,所以中斷中一直沒有上報press,也就是說usb觸控螢幕一直上報的是座標,但是press值一直為0,所以上層程式就會認為沒有按壓下去。所以沒有反應。在中斷中加列印,發現從usb讀出來的資料press值為0,不管是按下還是彈起,但是touch在按下的時候是1,彈起的時候是0,可以用這個值來上報給input子系統當前的press,函數修改如下:
static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
unsigned char *pkt, int len)
{
struct usbtouch_device_info *type = usbtouch->type;
if (!type->read_data(usbtouch, pkt))
return;
input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
//zk modify for usb touchpad
input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->touch);
if (swap_xy) {
input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
} else {
input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
}
#if 0
if (type->max_press)
input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
#endif
input_sync(usbtouch->input);
}
重新編譯核心,啟動,運行tslib的校準測試程式,可以正常點擊,並且tslib程式可以檢測到觸控螢幕資料了。成功。。