mini2440觸控螢幕驅動—-非input子系統實現方法

來源:互聯網
上載者:User

觸控螢幕的驅動程式在不是使用input子系統的實現過程中,其實和普通的字元裝置驅動沒有太大的差別,只要按照觸控螢幕那幾個步驟正常進行就可以。

①s3c2410_ts_init函數,這是整個程式的入口處。實現了各類初始化的作用。


/*裝置初始化函數*/static int __init s3c2410_ts_init(void){int ret;tsEvent = tsEvent_dummy;/* 註冊字元裝置第一個參數為0表示自動分配*/ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);//普通的註冊失敗判斷。if (ret < 0) {  printk(DEVICE_NAME " can't get major number\n");  return ret;}//tsMajor是一個全域變數,這裡被賦裝置註冊的傳回值tsMajor = ret;/* set gpio to XP, YM, YP and  YM *///操作相應的GPIO寄存器,這些函數是核心留下來的介面。set_gpio_ctrl(GPIO_YPON); set_gpio_ctrl(GPIO_YMON);set_gpio_ctrl(GPIO_XPON);set_gpio_ctrl(GPIO_XMON);/*註冊中斷分別註冊ADC和TC中斷。DEVICE_NAME在開始處有宏定義。*/ret = request_irq(IRQ_ADC_DONE, s3c2410_isr_adc, SA_INTERRUPT,   DEVICE_NAME, s3c2410_isr_adc);if (ret) goto adc_failed;ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT,   DEVICE_NAME, s3c2410_isr_tc);if (ret) goto tc_failed;/*等待觸控螢幕被按下的中斷這個函數的實現是使用宏來實現的。這就是一個等待函數,讓我想起了當年的祥哥。*/wait_down_int();//建立裝置檔案。#ifdef CONFIG_DEVFS_FSdevfs_ts_dir = devfs_mk_dir(NULL, "touchscreen", NULL);devfs_tsraw = devfs_register(devfs_ts_dir, "0raw", DEVFS_FL_DEFAULT,tsMajor, TSRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR,&s3c2410_fops, NULL);#endifADCDLY = 0xFFFF;printk(DEVICE_NAME " initialized\n");return 0;//兩個中斷註冊失敗的跳轉點。 tc_failed:free_irq(IRQ_ADC_DONE, s3c2410_isr_adc); adc_failed:return ret;}

在這個函數中出現了以前沒有的條件編譯,所以自己注意一下,不過這個條件編譯的主要作用就是建立裝置檔案。同時還有兩個中斷註冊失敗的goto。為了自己看以後的程式不糊塗,先記下這句話://tsMajor是一個全域變數,這裡被賦裝置註冊的傳回值tsMajor = ret;

 

②s3c2410_ts_exit,這個函數是整個程式的退出函數,主要實現了裝置的登出和中斷的釋放。

static void __exit s3c2410_ts_exit(void){#ifdef CONFIG_DEVFS_FSdevfs_unregister(devfs_tsraw);devfs_unregister(devfs_ts_dir);#endifunregister_chrdev(tsMajor, DEVICE_NAME);free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);free_irq(IRQ_TC, s3c2410_isr_tc);}

③一般分析字元裝置驅動程式的時候都是先看init函數,然後再去找file_operation。但是觸控螢幕的驅動程式的實現肯定有會有中斷,所以我們先來看一下中斷函數。

先看第一個中斷函數(在init函數中已經註冊完畢)

/* 當按鍵按下時首先產生的中斷 */static void s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg){//利用自旋鎖給中斷上鎖。spin_lock_irq(&(tsdev.lock));//這裡PEN_UP被宏定義為0,penStatus是一個結構體成員。if (tsdev.penStatus == PEN_UP) /*如果是按下中斷*/{  start_ts_adc(); /* 開始AD轉化 */} else {  tsdev.penStatus = PEN_UP; /* 如果是彈起中斷*/  DPRINTK("PEN UP: x: %08d, y: %08d\n", x, y);  wait_down_int(); /*等待按下中斷*/  tsEvent(); /* 調用後續處理函數 */}spin_unlock_irq(&(tsdev.lock));}

再說這個中斷函數之前,首先要說一下觸摸品主要的工作流程:

觸控螢幕的工作流程
①選擇X/Y的擷取模式。
②設定觸控螢幕等待中斷的狀態。
③如果中斷髮生啟動相應的數模轉換。
④當數模轉換之後,可以擷取X/Y座標值,返回到等待中斷的狀態(②之後③之前)。

同時還要說一下觸控螢幕的兩個中斷:

TC中斷:手按下拿起的時候
ADC中斷:發生在第四步。

上面的中斷處理函數其實就是TC中斷,從名字也可以看得出來,也就是觸控螢幕發生的第一個中斷。

當中斷髮生的時候首先是自旋鎖上鎖。然後給出判定並分配了兩種情況,假如確實是按下了,那麼就開始進行AD轉換,AD轉換的函數在另一個函數中實現,這裡只是調用。如果是彈起中斷,那麼就繼續等待,並調用後續函數(這裡的後續函數一定要仔細的看)。

上面的TC中斷函數中一共調用了兩個函數,分別是start_ts_adc和tsEvent函數。下面分別介紹這兩個函數。

start_ts_adc函數:

//通過響應的寄存器的設定來啟動AD轉換。//mode_x_axis,start_adc_x都是宏定義的函數。static inline void start_ts_adc(void){ adc_state = 0; mode_x_axis(); start_adc_x();}

這個函數主要是通過操作寄存器來實現的,具體的定義在整個程式開始的宏定義中有表現。

tsEvent函數:

static void tsEvent_raw(void){if (tsdev.penStatus == PEN_DOWN) { /* 儲存按下時的座標 */BUF_HEAD.x = x;BUF_HEAD.y = y;BUF_HEAD.pressure = PEN_DOWN;#ifdef HOOK_FOR_DRAG /*當筆在觸控螢幕上長期滑動的時候,如果不進行特殊處理不會產生點的軌跡。*/ts_timer.expires = jiffies + TS_TIMER_DELAY;add_timer(&ts_timer); /* 對長時間按下鍵的處理 這個函數的具體實現在本函數中實現。*/#endif} else {#ifdef HOOK_FOR_DRAG del_timer(&ts_timer);#endifBUF_HEAD.x = 0;BUF_HEAD.y = 0;BUF_HEAD.pressure = PEN_UP; /* 儲存彈起時的座標 */}tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);//這裡的喚醒進程和read函數中的sleep on對應。wake_up_interruptible(&(tsdev.wq)); /* 喚醒進程 */}

在等待按下中斷函數後再調用後續處理函數,這裡是一個迴圈的調用。在後續處理函數要注意:

#ifdef HOOK_FOR_DRAG
/*當筆在觸控螢幕上長期滑動的時候,如果不進行特殊處理不會產生點的軌跡。*/
  ts_timer.expires = jiffies + TS_TIMER_DELAY;
  add_timer(&ts_timer);

      /*
        對長時間按下鍵的處理
        這個函數的具體實現在本函數中實現。
       */
#endif

這個函數是針對長時間按鍵的情況,這裡ts_timer實現了檢測頻率的體現,同時,ts_timer中實現了如下函數:

static void ts_timer_handler(unsigned long data){spin_lock_irq(&(tsdev.lock));if (tsdev.penStatus == PEN_DOWN) {start_ts_adc();}//給這個程式解鎖。spin_unlock_irq(&(tsdev.lock));}

這樣長時間按鍵的情況就不是檢測連個中斷了,而且檢測的頻率還可以自己進行設定。

④當TC中斷函數執行完成以後自然而然的根據IRQ中斷號就要執行另一個中斷ADC中斷了。

static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg){spin_lock_irq(&(tsdev.lock));if (tsdev.penStatus == PEN_UP)  s3c2410_get_XY();#ifdef HOOK_FOR_DRAGelse  s3c2410_get_XY();#endifspin_unlock_irq(&(tsdev.lock));}

這一部分是ADC實現的代碼。其中這個函數主要調用了 s3c2410_get_XY這個函數,包括判定之後的執行也都是在s3c2410_get_XY這個函數再進行進一步判定之後進行的。

下面列出s3c2410_get_XY這個函數的主要代碼:

static inline void s3c2410_get_XY(void){//adc_state這個變數的作用是區分現在到底在擷取哪一個座標。if (adc_state == 0) { /* 轉換x */adc_state = 1;disable_ts_adc();y = (ADCDAT0 & 0x3ff); /* 擷取x座標 */mode_y_axis(); start_adc_y(); /*啟動y座標轉化*/} else if (adc_state == 1) {  /*轉換y*/adc_state = 0;disable_ts_adc();x = (ADCDAT1 & 0x3ff); /* 擷取y座標 */tsdev.penStatus = PEN_DOWN; /* 改變屏狀態 */DPRINTK("PEN DOWN: x: %08d, y: %08d\n", x, y);wait_up_int();   /* 等待彈起中斷 */tsEvent();}}

在上述的幾個中斷程式中涉及到了部分流程式控制制的迴圈調用,所以大家務必仔細閱讀。

⑤中斷講解完畢以後開始說一下file_operations。

多麼的親切!

static struct file_operations s3c2410_fops = {
 owner: THIS_MODULE,
 open: s3c2410_ts_open,
 read: s3c2410_ts_read, 
 release: s3c2410_ts_release,
 poll: s3c2410_ts_poll,
};

說到了file_operations了,那麼就把代碼分別粘貼出來了ha~

s3c2410_ts_open:

static int s3c2410_ts_open(struct inode *inode, struct file *filp){tsdev.head = tsdev.tail = 0;tsdev.penStatus = PEN_UP;#ifdef HOOK_FOR_DRAG init_timer(&ts_timer);ts_timer.function = ts_timer_handler;#endiftsEvent = tsEvent_raw;init_waitqueue_head(&(tsdev.wq));MOD_INC_USE_COUNT;return 0;}

說到這裡還有一個問題沒有弄懂,那就是tsdev.head = tsdev.tail = 0;不懂為什麼頭和尾都要置零。其他的部分也就不做過多的解釋了。
s3c2410_ts_read函數:

static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){TS_RET ts_ret;retry: if (tsdev.head != tsdev.tail) {int count;count = tsRead(&ts_ret);if (count) copy_to_user(buffer, (char *)&ts_ret, count);return count;} else {if (filp->f_flags & O_NONBLOCK)return -EAGAIN;interruptible_sleep_on(&(tsdev.wq));//這個判斷的作用是:判斷是否是訊號把它喚醒了if (signal_pending(current))return -ERESTARTSYS;goto retry;}return sizeof(TS_RET);}

注意一下這裡://這個判斷的作用是:判斷是否是訊號把它喚醒了if (signal_pending(current))。

release函數:

static int s3c2410_ts_release(struct inode *inode, struct file *filp){#ifdef HOOK_FOR_DRAGdel_timer(&ts_timer);#endifMOD_DEC_USE_COUNT;return 0;}

大體部分也就上面這些,我是在看過了input子系統實現了觸控螢幕驅動之後寫的這個,突然感覺還是input子系統實現起來比這個簡單了很多。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.