一.觸摸屏理論概述
對于觸摸屏驅(qū)動,我們主要需要掌握觸摸屏驅(qū)動代碼和應(yīng)用層測試代碼。下面講的是基于Mini2440的觸摸屏驅(qū)動,現(xiàn)在的驅(qū)動我們都將設(shè)備和驅(qū)動分離,掛在平臺設(shè)備總線上,讓設(shè)備和驅(qū)動去匹配。而我們在linu2.6.32.2內(nèi)核版本中的觸摸屏驅(qū)動仍然沒有將設(shè)備和驅(qū)動分離,這樣就不存在匹配問題,這種現(xiàn)象其實我們并不陌生,在我們學(xué)習(xí)驅(qū)動的前期,都會研究簡單字符驅(qū)動代表LED驅(qū)動,那個驅(qū)動就是把設(shè)備和驅(qū)動寫在了一起??偨Y(jié)下,驅(qū)動和設(shè)備可以分離也可以不分離,建議分離,而本觸摸屏驅(qū)動沒有分離設(shè)備和驅(qū)動,有興趣可以將設(shè)備和驅(qū)動進(jìn)行分離。
先說明下觸摸屏的工作原理,當(dāng)有人在觸摸屏上按下觸筆時,觸摸屏的四個引腳會產(chǎn)生不同的電壓值,這樣觸摸屏控制器就能檢測到這種變化,從而產(chǎn)生INT_TC中斷,表示觸筆按下。然后在得到CPU指示的情況下,觸摸屏控制器可以根據(jù)四個引腳上產(chǎn)生的不同電壓值進(jìn)行AD轉(zhuǎn)換,從而計算出X和Y坐標(biāo)的數(shù)值,并在將這兩個值保持到其內(nèi)部寄存器后,發(fā)出INT_ADC中斷,表示坐標(biāo)轉(zhuǎn)換已完成,從而軟件就可以讀取按下觸筆的位置。
二.觸摸屏驅(qū)動分析
本驅(qū)動分析很有特點,我對觸摸屏驅(qū)動的分析是按照整個觸摸事件的執(zhí)行順序進(jìn)行代碼分析的,有的函數(shù)由于每次被執(zhí)行完成的任務(wù)不同,所以需要多次分析。同時,我把整個觸摸事件的來龍去脈也都說的很清楚了。
驅(qū)動分析/driver/input/touchscreen/s3c2410_ts.c
static int __init s3c2410ts_init(void)
{
struct input_dev *input_dev;
adc_clock = clk_get(NULL, "adc");? //獲取時鐘
if (!adc_clock) {
printk(KERN_ERR "failed to get adc clock source ");
return -ENOENT;
}
clk_enable(adc_clock);?? //使能時鐘
base_addr=ioremap(S3C2410_PA_ADC,0x20);? //物理地址轉(zhuǎn)為虛擬地址
if (base_addr == NULL) {
printk(KERN_ERR "Failed to remap register block ");
return -ENOMEM;
}
s3c2410_ts_connect();? //觸摸屏端口配置
//使能預(yù)分頻,分頻系數(shù)為0xff
iowrite32(S3C2410_ADCCON_PRSCEN| S3C2410_ADCCON_PRSCVL(0xFF),base_addr+S3C2410_ADCCON);
iowrite32(0xffff,? base_addr+S3C2410_ADCDLY); //延時
//檢查光標(biāo)按下中斷信號,等待中斷
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
input_dev = input_allocate_device();? //分配input設(shè)備
if (!input_dev) {
printk(KERN_ERR "Unable to allocate the input device !! ");
return -ENOMEM;
}
dev = input_dev;
//支持按鍵事件、坐標(biāo)事件
dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);
//對于X軸范圍是0-ox3ff,數(shù)據(jù)誤差是0,中心平滑位置是0
input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);
dev->name = s3c2410ts_name;
dev->id.bustype = BUS_RS232;
dev->id.vendor = 0xDEAD;
dev->id.product = 0xBEEF;
dev->id.version = S3C2410TSVERSION;
//申請AD轉(zhuǎn)換中斷
if(request_irq(IRQ_ADC,stylus_action,IRQF_SHARED|IRQF_SAMPLE_RANDOM,"s3c2410_action", dev)) {
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC ! ");
iounmap(base_addr);
return -EIO;
}
//申請觸摸中斷
if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
"s3c2410_action", dev)) {
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC ! ");
iounmap(base_addr);
return -EIO;
}
printk(KERN_INFO "%s successfully loaded ", s3c2410ts_name);
input_register_device(dev);
return 0;
}
下面是這個模塊加載函數(shù)中調(diào)用的一個配置端口函數(shù)
static inline void s3c2410_ts_connect(void)
{
//將觸摸屏用到的四個端口配置成觸摸屏模式
s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);
s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);
s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);
s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
}
我們來分析兩種情況,第一種情況,如果沒有按下觸摸屏
驅(qū)動中定義了一個定時器
static struct timer_list touch_timer =
TIMER_INITIALIZER(touch_timer_fire, 0, 0);
因為這個定時器的期限時間設(shè)置為0,這表示當(dāng)驅(qū)動加載后就會執(zhí)行一次定時函數(shù)touch_timer_fire
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);? //讀取X坐標(biāo)
data1 = ioread32(base_addr+S3C2410_ADCDAT1);? //讀取Y坐標(biāo)
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN)); //觸摸屏是否被按下,如果按下updowm=1
if (updown) {
if (count != 0) {
long tmp;????????????????????????????????????????????????????????????????????????????????????????
tmp = xp;
xp = yp;
yp = tmp;????????????????????????????????????????????????????????????????????????????????????????
xp >>= 2;
yp >>= 2;
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp);
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
}
xp = 0;????
yp = 0;
count = 0;
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
} else { //沒有被按下
count = 0;??????? //初始化count為0,表示當(dāng)前AD轉(zhuǎn)換沒發(fā)生
input_report_key(dev, BTN_TOUCH, 0);? //向input子系統(tǒng)報告未按下
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC); //等待按鍵中斷
if (OwnADC) { //OwnADC是獲取一把鎖標(biāo)示,在此為0
OwnADC = 0;
up(&ADC_LOCK);
}
}
}
第二種情況,如果觸摸屏被按下,首先觸發(fā)觸摸中斷,執(zhí)行stylus_updown函數(shù)
static irqreturn_t stylus_updown(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
int updown;
if (down_trylock(&ADC_LOCK) == 0) {? //獲取一把鎖
OwnADC = 1;?????? //表示獲得鎖
data0 = ioread32(base_addr+S3C2410_ADCDAT0); //讀取X軸數(shù)據(jù)
data1 = ioread32(base_addr+S3C2410_ADCDAT1); //讀取Y軸數(shù)據(jù)
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN)); //觸摸屏是否被按下,按下updowm=1
if (updown) {
touch_timer_fire(0);? //?如果觸摸屏被按下,執(zhí)行touch_timer_fire
} else {? //去抖動操作,釋放鎖
OwnADC = 0;
up(&ADC_LOCK);
}
}
return IRQ_HANDLED;
}
下面我們第二次分析touch_timer_fire,而這次主要是因為觸摸中斷中調(diào)用了這個函數(shù),假設(shè)當(dāng)前觸摸屏被按下后,坐標(biāo)值還沒進(jìn)行AD轉(zhuǎn)換
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if (updown) {? //觸摸屏被按下
if (count != 0) { //count是全局變量,統(tǒng)計AD轉(zhuǎn)換次數(shù),目前未AD轉(zhuǎn)換
long tmp;????????????????????????????????????????????????????????????????????????????????????????
tmp = xp;
xp = yp;
yp = tmp;?????????????????????????????????????????????????????????????????????????? ??????????????
xp >>= 2;
yp >>= 2;
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp);
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
}
xp = 0;? ????//雖然觸摸屏被按下,但是未完成AD轉(zhuǎn)換
yp = 0;
count = 0;
//自動連續(xù)測量X和Y坐標(biāo)
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
//AD轉(zhuǎn)換開始且該位在開始后清零
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
} else {
count = 0;
input_report_key(dev, BTN_TOUCH, 0);
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
if (OwnADC) {
OwnADC = 0;
up(&ADC_LOCK);
}
}
}
現(xiàn)在我們知道,如果觸摸屏被按下,但是AD還沒轉(zhuǎn)換完畢,那么我們會開啟AD轉(zhuǎn)換,自動測量X和Y坐標(biāo),這樣就會觸發(fā)AD轉(zhuǎn)換中斷,執(zhí)行AD轉(zhuǎn)換的中斷處理程序。其實當(dāng)我們的觸摸屏被按下,當(dāng)X和Y軸獲取電壓值,然后就會進(jìn)行AD轉(zhuǎn)換,執(zhí)行AD轉(zhuǎn)換的中斷處理程序。好了,我們該看看AD轉(zhuǎn)換的中斷代碼了。
static irqreturn_t stylus_action(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
if (OwnADC) { //只有觸摸屏被按下,相應(yīng)了觸摸中斷該標(biāo)志才為1
data0 = ioread32(base_addr+S3C2410_ADCDAT0); //讀取X坐標(biāo)
data1 = ioread32(base_addr+S3C2410_ADCDAT1);? //讀取Y坐標(biāo)
xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;//疊加X坐標(biāo)
yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;//疊加Y坐標(biāo)
count++;? //統(tǒng)計AD轉(zhuǎn)換次數(shù)
if (count < (1<<2)) { //如果AD轉(zhuǎn)換次數(shù)不足4次
//自動連續(xù)測量X和Y坐標(biāo)
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
//AD轉(zhuǎn)換開始且該位在開始后清零
iowrite32(ioread32(base_addr+S3C2410_ADCCON) |S3C2410_ADCCON_ENABLE_START,base_addr+S3C2410_ADCCON);
} else {
mod_timer(&touch_timer, jiffies+1); //四次AD轉(zhuǎn)換后,修改定時時間
iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);//等待釋放
}
}
return IRQ_HANDLED;
}
在這個AD轉(zhuǎn)換的中斷程序中,有一個全局變量count令人費解,count是什么作用呢?我們做AD轉(zhuǎn)換時,其實是對一個點進(jìn)行了四次采樣,然后把四次采樣結(jié)果進(jìn)行疊加然后取平均。這樣提高AD轉(zhuǎn)換的精確度。在上面這個AD轉(zhuǎn)換的中斷處理程序中,我們知道,當(dāng)count不足4次時,會繼續(xù)進(jìn)行自動連續(xù)測量X和Y坐標(biāo)并開啟AD轉(zhuǎn)換,只有當(dāng)AD轉(zhuǎn)換次數(shù)達(dá)到四次后,就會修改定時器的時間,使得下一個節(jié)拍到來時執(zhí)行定時器處理程序,并且等待按鍵被釋放。當(dāng)AD轉(zhuǎn)換完畢,我們在下一個節(jié)拍到來后,會執(zhí)行一次定時器程序touch_timer_fire
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if (updown) {? //觸摸屏被按下
if (count != 0) { //count是全局變量,統(tǒng)計AD轉(zhuǎn)換次數(shù),目前已經(jīng)4次
long tmp;????????????????????????????????????????????????????????????????????????????????????????
tmp = xp;
xp = yp;
yp = tmp;? // X和Y軸數(shù)據(jù)交換?????????????????????????????????????????????????????????????????????? ????????????
xp >>= 2; //因為對同一個點采樣四次,這里對X軸取平均
yp >>= 2; //因為對同一個點采樣四次,這里對Y軸取平均
input_report_abs(dev, ABS_X, xp); //報告X坐標(biāo)
input_report_abs(dev, ABS_Y, yp); //報告Y坐標(biāo)
input_report_key(dev, BTN_TOUCH, 1); //報告觸摸事件
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev); //同步
}
xp = 0;???? //清零
yp = 0;
count = 0;
//自動連續(xù)測量X和Y坐標(biāo)
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
//AD轉(zhuǎn)換開始且該位在開始后清零
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
} else {
count = 0;
input_report_key(dev, BTN_TOUCH, 0);
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
if (OwnADC) {
OwnADC = 0;
up(&ADC_LOCK);
}
}
}
這里首先解釋下,為什么要對X和Y坐標(biāo)值交換,因為我們的X35LCD屏是240*320的,為了滿足用戶“X軸長Y軸短”的習(xí)慣,在此進(jìn)行X和Y坐標(biāo)值交換,當(dāng)然在此不交換,不會影響觸摸屏驅(qū)動的運(yùn)行。
我們這次分析這個定時器touch_timer_fire,最終發(fā)現(xiàn)我們不但向input子系統(tǒng)報告了我們的坐標(biāo)值,還對坐標(biāo)變量和統(tǒng)計AD轉(zhuǎn)換次數(shù)變量清零,最后還打開了AD轉(zhuǎn)換開關(guān),既然這次觸摸事件已經(jīng)結(jié)束,那么這里怎么還打開AD轉(zhuǎn)換開關(guān)呢?其實,如果你足夠細(xì)心,你會發(fā)現(xiàn),雖然AD開關(guān)打開了,然后會執(zhí)行AD轉(zhuǎn)換的中斷處理程序,一旦進(jìn)入AD轉(zhuǎn)換,肯定也是轉(zhuǎn)換四次,然后在下一個節(jié)拍到來時,執(zhí)行定時程序,最關(guān)鍵的是,此時我們的觸摸屏按鍵已經(jīng)釋放了,在這一的背景下,我們再次跟蹤定時函數(shù)touch_timer_fire
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);? //讀取X坐標(biāo)
data1 = ioread32(base_addr+S3C2410_ADCDAT1);? //讀取Y坐標(biāo)
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN)); //觸摸屏是否被按下,如果按下updowm=1
if (updown) {
if (count != 0) {
long tmp;????????????????????????????????????????????????????????????????????????????????????????
tmp = xp;
xp = yp;
yp = tmp;????????????????????????????????????????????????????????????????????????????????????????
xp >>= 2;
yp >>= 2;
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp);
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
}
xp = 0;????
yp = 0;
count = 0;
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
} else { //沒有被按下
count = 0;??????? //初始化count為0,表示當(dāng)前AD轉(zhuǎn)換沒發(fā)生
input_report_key(dev, BTN_TOUCH, 0);? //向input子系統(tǒng)報告未按下
input_report_abs(dev, ABS_PRESSURE, 0); //觸摸屏是抬起狀態(tài)
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC); //等待按鍵中斷
if (OwnADC) { //OwnADC是獲取一把鎖標(biāo)示,在此為1
OwnADC = 0;???????????? ?//該鎖標(biāo)志為0,表示釋放該鎖
up(&ADC_LOCK); //釋放鎖
}
}
}
好了,一旦釋放了鎖,那么我們觸摸屏事件的一個生命周期才真正算分析結(jié)束了,不過在此還有一個問題沒有解決,就是當(dāng)我們觸摸屏按鍵被釋放后,其實也會產(chǎn)生一個按鍵中斷,執(zhí)行觸摸中斷程序,不過在這個程序中起初是為了獲得一個信號量,由于信號量是等待鎖,所以,程序一直在試圖獲取這個信號量,當(dāng)我們的信號量在上面這個touch_timer_fire中被釋放后,我們就會再次獲取這個信號量,繼續(xù)跟蹤這個觸摸中斷函數(shù)stylus_updown
static irqreturn_t stylus_updown(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
int updown;
if (down_trylock(&ADC_LOCK) == 0) { //再次獲取鎖
OwnADC = 1;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if (updown) {?? //因為是釋放操作,所以updowm=0
touch_timer_fire(0);
} else {
OwnADC = 0;
up(&ADC_LOCK);?? //釋放鎖
}
}
return IRQ_HANDLED;
}
好了,這樣我們就真正結(jié)束了一次觸摸時間的周期。
總結(jié)下觸摸屏控制的整個運(yùn)行過程:
Step1:軟件開啟INT_ADC和INT_TS中斷,設(shè)置ADCCON以確定AD轉(zhuǎn)換需要的時鐘頻率,設(shè)置ADCDLY以確定從得到命令到開始轉(zhuǎn)換坐標(biāo)的延時時長,設(shè)置ADCTSC使得觸摸屏處于等待觸筆按下狀態(tài)
Step2:當(dāng)觸筆按下,產(chǎn)生INT_TC中斷,執(zhí)行stylus_updown,stylus_updown首先判斷中斷產(chǎn)生的原因是不是觸筆按下,是的話就調(diào)用定時函數(shù)touch_timer_fire,在touch_timer_fire中設(shè)置ADCTSC使得觸摸屏準(zhǔn)備進(jìn)行自動X/Y軸轉(zhuǎn)換狀態(tài),然后設(shè)置ADCCON啟動坐標(biāo)轉(zhuǎn)換,結(jié)束stylus_updown。
Step3:觸摸屏在延遲指定時間后開始轉(zhuǎn)換X/Y坐標(biāo),并將轉(zhuǎn)換的結(jié)果保存到ADCDAT0和ADADAT1中,完成后發(fā)出INT_ADC中斷,表示轉(zhuǎn)換完成。
Step4:進(jìn)入INT_ADC中斷處理程序stylus_action,獲取X/Y軸坐標(biāo),然后進(jìn)行四次坐標(biāo)轉(zhuǎn)換以求平均值,最后設(shè)置ADCTSC使得觸摸屏處于等待觸筆釋放狀態(tài),同時當(dāng)下一個節(jié)拍到來時,調(diào)用touch_timer_fire向input子系統(tǒng)報告坐標(biāo)。
Step5:當(dāng)觸筆釋放,還會產(chǎn)生INT_TC中斷,進(jìn)入其中斷處理程序,得到觸筆釋放的消息,最后設(shè)置ADCTSC使得觸摸屏處于下一次等待觸筆按下狀態(tài)。
三.觸摸屏驅(qū)動測試
由于mini2440的觸摸屏驅(qū)動是基于input子系統(tǒng)的,而input子系統(tǒng)給用戶層提供的是input_event結(jié)構(gòu)體,我們主要是在應(yīng)用層接收這個結(jié)構(gòu)體,然后對其類型進(jìn)行分類,取出我們需要的數(shù)值。
struct input_event { struct timeval time;
unsigned short type;? //支持的類型,如EV_ABS
unsigned short code;?? //支持的具體事件,如坐標(biāo)事件的ABS_X
unsigned int value; ?//值
};
測試觸摸屏驅(qū)動的應(yīng)用層代碼如下
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int fd = -1;
int num;
size_t rb;
int version;
char name[20];
struct input_event ev;
int i=0;
if ((fd = open("/dev/input/event0", O_RDONLY)) < 0)? //打開設(shè)備
{
perror("open error");
exit(1);
}
while(1)
{
rb = read(fd, &ev, sizeof(struct input_event));? //讀取設(shè)備
if (rb < (int)sizeof(struct input_event))? //讀取錯誤
{
perror("read error");
exit(1);
}
if (EV_ABS==ev.type)???????????????????? //讀取按鍵內(nèi)容
{
printf("event=%s,value=%d ",ev.code==ABS_X?"ABS_X":ev.code==ABS_Y?"ABS_Y":ev.code==ABS_PRESSURE?"ABS_PRESSURE":"UNKNOWEN",ev.value);?????
}else{
printf("not ev_abs ");????????
}
}????
close(fd);
return 0;
}
編譯測試程序test.c
超級終端:
./test
測試結(jié)果:(觸筆按下觸摸屏)
event=ABS_X, value=505
event=ABS_Y, value=334
event=ABS_PRESSURE, value=1
?
評論
查看更多