




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例第 12 章Linux 字符驅動綜合實例本章將分析 5 個典型的字符所講解的內容。驅動,在這些驅動中,將靈活地運用到前面各章12.1 節講解按鍵的斷、定時器等相關12.2 節講解觸摸屏的些,但是很類似。驅動,加深讀者對字符。驅動架構、阻塞與非阻塞、中驅動,觸摸屏的驅動比按鍵的驅動稍微復雜一12.3 節講解 TI 的 DSP 提供給通用 CPU 的 HPI(主機并行接口)的件結構為 ARM+DSP,ARM 的總線連接 DSP 的 HPI 接口。驅動,硬12.4 節講解通用 NVRAM 的雜)。驅動,并會引入一個新的概念,即 misc
2、device(混12.5 節講解看門狗的驅動,它也被歸入 miscdevice,這一節還會引入兩個新的概念,即 platform_device(平臺)和 platform_driver(平臺驅動)。NVRAM 和看門狗的驅動與普通字符驅動有細微的差別。學院華清遠見旗下品牌:Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例12.1.1按鍵的硬件原理在系統中,按鍵的硬件原理比較簡單,通過一個上拉電阻將處理器的外部中斷(或 GPIO)引腳,電阻的另一端連接按鈕并接地即可實現。如圖 12.1 所示,當按鈕被按下時,EINT10、EIN13、EINT14、EINT15 上將產生低電平,這
3、個低電平將中斷 CPU(圖中的 CPU 為 S3C2410),CPU 可以依據中斷按鍵被按下。但是,僅僅依據中斷被產生就認定有一次按鍵行為是很確的,所有按鍵、觸摸屏等機械都一個固有的,那就是“抖動”,按鍵從最初接通到接通要經過數毫秒,其間可能發生多次“接通斷開”的過程。如果不消除“抖動”的影響,一次按鍵可能被理解為多次按鍵。消除按鍵抖動影響的是:在有鍵按下后,進行延時(如 20ms,在延時過程中要對應中斷),再鍵盤狀態,如果仍處于按鍵按下狀態,則可以斷定該按鍵被按入功能,則可以改為完全12.2(a)所示。如果按鍵對應的引身不具備中斷輸方式,流12.2(b)所示。圖 12.1 按鍵的硬件原理學院
4、華清遠見旗下品牌:按鍵的驅動Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例圖 12.2 確認按鍵的流程按鍵驅動中的數據結構12.1.2驅動中主要要設計的數據結構是結構體,按鍵的結構體中應包含一個緩沖區,因為多次按鍵可能無法被及時處理,可以用該緩沖區緩存按鍵。此外,在按鍵結構體中,還包含按鍵狀態標志和一個實現過程中要借助的等待隊列、cdev結構體。為了實現延時,定時器也是必要的,但可以不包含在結構體中。代碼12.1 給出了按鍵代碼結構體及定時器。12.1 按鍵驅動的結構體、定時器在按鍵值,如代碼驅動中,可用一個結構體每個按鍵所對應的中斷/GPIO 引腳及鍵12.2 所示。代碼1
5、2.2 按鍵硬件、鍵值信息結構體學院華清遠見旗下品牌:1 static struct key_info 2 3 int irq_no;/中斷號4 unsigned int gpio_port; /GPIO 端口5 int key_no;/鍵值6 key_info_tab4 = 7 8/*按鍵所使用的 CPU*/91 #define MAX_KEY_BUF 16 /按鍵緩沖區大小2 typedef unsigned char KEY_RET;3 /結構體:4 typedef struct 5 6 unsigned int keyStatusKEY_NUM; /4 個按鍵的按鍵狀態7 KEY_RE
6、T bufMAX_KEY_BUF; /按鍵緩沖區8 unsigned int head, tail; /按鍵緩沖區頭和尾9 wait_queue_head_t wq; /等待隊列10 struct cdev cdev;/cdev 結構體10 KEY_DEV;11 static struct timer_list key_timerKEY_NUM;/4 個按鍵去抖定時器Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例按鍵驅動的文件操作結構體如代碼12.3 所示,主要實現了打開、和讀函數,因為按鍵只是一個輸入,所以不寫函數。代碼12.3 按鍵驅動文件操作結構體1 static st
7、ruct file_operations s3c2410_key_fops = 2 3 owner: THIS_MODULE,4 open: s3c2410_key_open, /啟動5 release: s3c2410_key_release,6 read: s3c2410_key_read, / 7 ;/關閉 按鍵的鍵值12.1.3按鍵驅動的模塊加載和卸載函數按鍵作為一種字符,在其模塊加載和卸載函數中分別包含了號申請和、cdev 的添加和刪除行為,在模塊加載函數中,還需申請中斷、初始化定時器和等待隊列等,模塊卸載函數完成相反的行為,代碼12.4 和 12.5 分別給出了按鍵驅動的模塊加載和
8、卸載函數,代碼12.6 和 12.7 分別給出了模塊加載和卸載所調用的申請和4 個中斷的函數。代碼12.4 按鍵驅動的模塊加載函數static int init s3c2410_key_init(void)123456789101112131415./申請號,添加 cdevrequest_irqs(); /中斷函數keydev.head = keydev.tail = 0; /初始化結構體for (i = 0; i < KEY_NUM; i+)keydev.keyStatusi = KEYSTATUS_UP; init_waitqueue_head(&(keydev.wq); /
9、等待隊列/初始化定時器,實現的去抖動for (i = 0; i < KEY_NUM; i+) setup_timer(&key_timeri, key_timer_handler, i);/把按鍵的序號作為傳入定時器處理函數的參數代碼12.5 按鍵驅動的模塊卸載函數學院華清遠見旗下品牌:10IRQ_EINT10, GPIO_G2, 1 11 12 ,13 14IRQ_EINT13, GPIO_G5, 2 15 16 ,17 18IRQ_EINT14, GPIO_G6, 3 19 20 ,21 22IRQ_EINT15, GPIO_G7, 4 23 24 ,25 ;驅動開發詳解第
10、12 章、Linux 字符驅動綜合實例Linux代碼12.6按鍵驅動的中斷申請函數12.7代碼按鍵驅動的中斷函數12.1.4按鍵驅動中斷、定時器處理程序在鍵被按下后,將發生中斷,在中斷處理,應該關閉中斷進入模式,延遲 20ms 以實現去抖動,如代碼12.8 所示,這個中斷處理過程只包含頂半部,無底半部。代碼12.8 按鍵驅動的中斷處理程序在定時器處理,按鍵是否仍然被按下,如果是被按下的狀態,則將該學院華清遠見旗下品牌:1 static void s3c2410_eint_key(int irq, void *dev_id, struct pt_regs*reg)2 3 int key = de
11、v_id;4 disable_irq(key_info_tabkey.irq_no); /關中斷,轉入模式56 keydev.keyStatuskey = KEYSTATUS_DOWNX;/狀態為按下7 key_timerkey.expires = jiffies + KEY_TIMER_DELAY1;/延遲8 add_timer(&key_timerkey); /啟動定時器9 1 /*中斷*/2 static void free_irqs(void) 3 4 struct key_info *k;5 int i;6 for (i = 0; i < sizeof(key_info
12、_tab) / sizeof(key_info_tab1); i+) 78 k = key_info_tab + i;9 free_irq(k->irq_no, buttons_irq); /中斷10 11 1 /*申請系統中斷,中斷方式為下降沿觸發*/2 static int request_irqs(void) 3 4 struct key_info *k;5 int i;6 for (i = 0; i < sizeof(key_info_tab) / sizeof(key_info_tab1); i+) 78 k = key_info_tab + i;9 set_extern
13、al_irq(k->irq_no, EXT_LOWLEVEL, GPIO_PULLUP_DIS);10 /設置低電平觸發11 if (request_irq(k->irq_no, &buttons_irq, SA_INTERRUPT, DEVICE_NAME,12 i) /申請中斷,將按鍵序號作為參數傳入中斷服務程序1314return - 1;1516 17 return 0; 18 1 static void exit s3c2410_key_exit(void) 2 3 free_irqs(); /注銷中斷4 ./號,刪除 cdev5 Linux驅動開發詳解第 12
14、章、Linux 字符驅動綜合實例按鍵入緩沖區。同時啟動新的定時器延遲,延遲一個相對于去抖更長的時間(如100ms),每次定時器到期后,按鍵是否仍然處于按下狀態,如果是,則重新啟用新的 100ms 延遲;若到已經沒有按下,則認定鍵已抬起,這個時候應該開啟對應按鍵的中斷,等待新的按鍵。每次新的鍵值時,應喚醒等待隊列。定時器處理流12.3 所示,代碼代碼如 12.9 所示。12.9按鍵驅動的定時器處理函數學院華清遠見旗下品牌:1 static void key_timer_handler(unsigned long data) 2 3 int key = data;4 if (ISKEY_DOWN(
15、key) 56 if (keydev.keyStatuskey = KEYSTATUS_DOWNX)7 /從中斷進入89 keydev.keyStatuskey = KEYSTATUS_DOWN;10 key_timerkey.expires = jiffies + KEY_TIMER_DELAY; /延遲11 keyEvent(); /鍵值,喚醒等待隊列12 add_timer(&key_timerkey); 1314else1516 key_timerkey.expires = jiffies + KEY_TIMER_DELAY; /延遲17 add_timer(&key_
16、timerkey); 1819 20 else/鍵已抬起21 22 keydev.keyStatuskey = KEYSTATUS_UP;23 enable_irq(key_info_tabkey.irq_no); 24 25 Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例圖 12.3 定時器處理函數流程12.1.5按鍵驅動的打開、函數按鍵驅動的打開和函數比較簡單,主要是設置 keydev.head、keydev.tail和按鍵函數指針 keyEvent 的值,如代碼12.10 所示。代碼12.10 按鍵驅動的打開、函數12.1.6按鍵驅動讀函數代碼12.11 給出了按鍵驅動
17、的讀函數,按鍵驅動的讀函數主要提供對按鍵結構體中緩沖區的讀并到用戶空間。當 keydev.head ! = keydev.tail 時,意味著緩沖區有數據,使用 copy_to_user()拷貝到用戶空間,否則,根據用戶空間是阻塞讀還是非阻塞讀,分為如下兩種情況。l 若采用非阻塞讀,則因為沒有按鍵緩存,直接返回- EAGAIN;l 若采用阻塞讀,則在 keydev.wq 等待隊列上睡眠,直到有按鍵被區后被喚醒。入緩沖代碼12.11 按鍵驅動的讀函數1 static ssize_t s3c2410_key_read(struct file *filp, char *buf, ssize_t co
18、unt,loff_t*ppos)2345678910111213141516171819202122retry: if (keydev.head != keydev.tail)/當前循環隊列中有數據key_ret = keyRead(); /按鍵copy_to_user(.); /把數據從內核空間傳送到用戶空間elseif (filp->f_flags &O_NONBLOCK)/若用戶采用非阻塞方式return - EAGAIN;interruptible_sleep_on(&(keydev.wq);/用戶采用阻塞方式,調用該函數使進程睡眠goto retry;retur
19、n 0;學院華清遠見旗下品牌:1 static int s3c2410_key_open(struct inode *inode, struct file *filp) 2 3 keydev.head = keydev.tail = 0; /清空按鍵動作緩沖區4 keyEvent = keyEvent_raw; /函數指針指向按鍵處理函數 keyEvent_raw5 return 0;6 78 static int s3c2410_key_release(struct inode *inode, struct file*filp)9 10 keyEvent = keyEvent_dummy;
20、/函數指針指向空函數11 return 0; 12 Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例最后,解釋一下代碼12.9 第 11 行的 keyEvent()函數和代碼12.11 的keyRead()函數。在驅動的打開函數中,keyEvent 被賦值為 keyEvent_raw,這個函數完成鍵值,并使用 wait_up_interrupt(&(keydev.wq)語句喚醒 s3c2410_key_read()第 17 行所期待的等待隊列。而 keyRead()函數則直接從按鍵緩沖區中鍵值。12.2.1觸摸屏的硬件原理按照觸摸屏的工作原理和傳輸信息的介質,我們把觸摸
21、屏分為 4 種:電阻式、電容感應式、紅外線式以及表面聲波式。電阻式觸摸屏利用感應進行,包含上下疊合的兩個透明層,通常還要用一種彈性材料來將兩層隔開。在觸摸某點時,兩層會在此點接通。四線和八線觸摸屏由兩層具有相同表面電阻的透明阻性材料組成,五線和七線觸摸屏由一個阻性層和一個導電層組成。所有的電阻式觸摸屏都采用分壓器原理來產生代表 X 坐標和 Y 坐標的電壓。如圖12.4 所示,分壓器是通過將兩個電阻進行串聯來實現的。電阻R1 連接正參考電壓VREF,電阻 R2 接地。兩個電阻連接點處的電壓測量值與 R2 的阻值成正比。為了在電阻式觸摸屏上的特定方向測量一個坐標,需要對一個阻性層進行偏置:將它的一
22、邊接 VREF,另一邊接地。同時,將未偏置的連接到一個 ADC 的高阻抗輸入端。當觸摸屏上的足夠大,兩層之間發生接觸時,電阻性表面被分隔為兩個電阻。它們的阻值與觸摸點到偏置邊緣的距離成正比。觸摸點與接地邊之間的電阻相當于分壓器中下面的那個電阻。因此,在未偏置層上測得的電壓與觸摸點到接地邊之間的距離成正比。四線觸摸屏包含兩個阻性層。其中一層在屏幕的左右邊緣各有一條垂直總線,另一層在屏幕的底部和頂部各有一條水平總線,如圖 12.5 所示。為了在 X 軸方向進行測量,將左側總線偏置為 0V,右側總線偏置為 VREF。將頂部或底部總線連接到 ADC,當頂層和底層相接觸時即可作一次測量。為了在 Y 軸方
23、向進量,將頂部總線偏置為 VREF,底部總線偏置為 0V。將 ADC 輸入端接左側總線或右側總線,當頂層與底層相接觸時即可對電壓進量。學院華清遠見旗下品牌:觸摸屏的驅動驅動開發詳解第 12 章、Linux 字符驅動綜合實例Linux圖 12.4 電阻觸摸屏分壓圖 12.5 四線電阻式觸摸屏S3C2410 接 4 線電阻式觸摸屏的電路原理如圖 12.6 所示。S3C2410 提供了 nYMON、YMON、nXPON 和 XMON 直接作為觸摸屏的信號,它通過連接 FDC6321 場效應管觸摸屏驅動器觸摸屏。輸入信號在經過阻容式低通濾器濾除坐標信號噪聲后被接入 S3C2410 內集成的 ADC(模
24、數轉換器)的模擬信號輸入通道 AIN5、AIN7。學院華清遠見旗下品牌:Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例圖 12.6 S3C2410 連接 4 線電阻式觸摸屏S3C2410 內置了一個 8 信道的 10 位 ADC,該 ADC 能以 500KS/S 的采樣速率將外部的模擬信號轉換為 10 位分辨率的數字量。因此,ADC 能與觸摸屏作,完成對觸摸屏絕對地址的測量。S3C2410 的 ADC 和觸摸屏接口可工作于 5 種模式,分別如下。1普通轉換模式(Normal Converson Mode)普通轉換模式(AUTO_PST = 0,XY_PST = 0)用來進行一
25、般的 ADC 轉換,例如通過 ADC 測量電池電壓等。器協同工學院華清遠見旗下品牌:Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例2X/Y 位置轉換模式(Separate X/Y Position Conversion Mode)X/Y 軸坐標轉換模式其實包含了 X 軸模式和 Y 軸模式。為獲得 X、Y 坐標,需首先進行 X 軸的坐標轉換(AUTO_PST = 0,XY_PST = 1),X 軸的轉換資料會寫到ADCDAT0 寄存器的 XPDAT 中,等待轉換完成后,觸摸屏器會產生 INT_ADC 中斷。然后,進行 Y 軸的坐標轉換(AUTO_PST = 0,XY_PST =
26、 2),Y 軸的轉換資料會寫到 ADCDAT1 寄存器的 YPDAT 中,等待轉換完成后,觸摸屏INT_ADC 中斷。3自動(連續)X/Y 位置轉換模式(Auto X/Y Position Conversion Mode)自動(連續)X/Y 位置轉換模式(AUTO_PST = 1,XY_PST = 0)運行方式是觸摸器也會產生屏自動轉換 X 位置和 Y 位置。觸摸屏器在 ADCDAT0 的 XPDATA 位寫入 X測定數據,在 ADCDAT1 的 YPADATA 位寫入 Y 測定數據。自動(連續)位置轉換后, 觸摸屏器產生 INT_ADC 中斷。4等待中斷模式(Wait for Interru
27、pt Mode)當觸摸屏器等待中斷模式時,它等待觸摸屏觸點信號的到來。當觸點信號到來時,器產生 INT_TC 中斷信號。然后,X 位置和 Y 位置能被適當地轉換模式(獨立 X/Y 位置轉換模式或自動 X/Y 位置轉換模式)5待機模式(Standby Mode)當 ADCCON 寄存器的 STDBM 位置 1 時,待機模式被激活。在這種模式下,A/D到。轉換動作被換的數據。,ADCDAT0 的 XPDATA 位和 ADXDATA1 的 YPDAT 保留以前被轉12.2.2觸摸屏觸摸屏驅動中數據結構結構體的成員與按鍵結構體的成員類似,也包含一個緩沖區,同時自旋鎖、等待隊列和 fasync_stru
28、ct 指針,如代碼12.12 所示。代碼12.12 觸摸屏結構體觸摸屏結構體中包含的 TS_RET 值的類型定義如代碼12.13 所示,包含 X、Y坐標和狀態(PEN_DOWN、PEN_UP)等信息,這個信息會在用戶制到用戶空間。觸摸信息代碼12.13 TS_RET 結構體學院華清遠見旗下品牌:1 typedef struct1 typedef struct 2 3 unsigned int penStatus; /* PEN_UP, PEN_DOWN, PEN_SAMPLE */4 TS_RET bufMAX_TS_BUF; /* 緩沖區 */5 unsigned int head, tai
29、l; /* 緩沖區頭和尾 */6 wait_queue_head_t wq; /*等待隊列*/7 spinlock_t lock;8 #ifdef USE_ASYNC9 struct fasync_struct *aq;10 #endif11 struct cdev cdev;12 TS_DEV;Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例在觸摸屏驅動中,將實現 open()、release()、read()、fasync()和 poll()函數,因此,其文件操作結構體定義如代碼12.14 所示。代碼12.14 觸摸屏驅動文件操作結構體12.2.3觸摸屏驅動中的硬件代碼12
30、.15 中的一組宏用于觸摸屏和 ADC 進入不同的工作模式,如等待中斷、X/Y 位置轉換等。代碼12.15觸摸屏和 ADC 硬件學院華清遠見旗下品牌:1 #define wait_down_int() ADCTSC = DOWN_INT | XP_PULL_UP_EN |2 XP_AIN | XM_HIZ | YP_AIN | YM_GND | 3 XP_PST(WAIT_INT_MODE); 4 #define wait_up_int() ADCTSC = UP_INT | XP_PULL_UP_EN | XP_AIN|5 XM_HIZ |YP_AIN | YM_GND | XP_PST(W
31、AIT_INT_MODE); 6 #define mode_x_axis() ADCTSC = XP_EXTVLT | XM_GND | YP_AIN 7 | YM_HIZ |XP_PULL_UP_DIS | XP_PST(X_AXIS_MODE); 8 #define mode_x_axis_n() ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | 9 YM_HIZ |XP_PULL_UP_DIS | XP_PST(NOP_MODE); 10 #define mode_y_axis() ADCTSC = XP_AIN | XM_HIZ | YP_EXTVLT 11
32、 | YM_GND |XP_PULL_UP_DIS | XP_PST(Y_AXIS_MODE); 12 #define start_adc_x() ADCCON = PRESCALE_EN | PRSCVL(49) | 13 ADC_INPUT(ADC_IN5) | ADC_START_BY_RD_EN | 14 ADC_NORMAL_MODE; 15 ADCDAT0; 16 #define start_adc_y() ADCCON = PRESCALE_EN | PRSCVL(49) | 17 ADC_INPUT(ADC_IN7) | ADC_START_BY_RD_EN | 18 ADC_
33、NORMAL_MODE; 19 ADCDAT1; 20 #define disable_ts_adc() ADCCON &= (ADCCON_READ_START); 1 static struct file_operations s3c2410_fops = 2 3 owner: THIS_MODULE,4 open: s3c2410_ts_open, /打開5 read: s3c2410_ts_read, /讀坐標6 release:7 s3c2410_ts_release,8 #ifdef USE_ASYNC9 fasync: s3c2410_ts_fasync, / fasyn
34、c()函數10 #endif11 poll: s3c2410_ts_poll,/輪詢12 ;2 3 unsigned short pressure;/PEN_DOWN、PEN_UP4 unsigned short x;/x 坐標5 unsigned short y;/y 坐標6 unsigned short pad;7 TS_RET;Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例12.2.4在觸摸屏設置觸摸屏12.16 所示。觸摸屏驅動模塊加載和卸載函數驅動的模塊加載函數中,要完成申請號、添加 cdev、申請中斷、引腳(YPON、YMON、XPON、XMON)等多項工作,如代
35、碼代碼12.16觸摸屏驅動的模塊加載函數在觸摸屏等工作,如代碼驅動的模塊卸載函數中,要完成12.17 所示。號、刪除 cdev、中斷代碼12.17 觸摸屏驅動模塊卸載函數12.2.5觸摸屏驅動中斷、定時器處理程序由 12.2.1 小節對觸摸屏和 ADC 模式的分析,可知觸摸屏驅動中會產生兩類中斷, 一類是觸點中斷(INT-TC),一類是 X/Y 位置轉換中斷(INT-ADC)。在前一類中斷發生后,若之前處于 PEN_UP 狀態,則應該啟動 X/Y 位置轉換。另外,將抬起中斷也放學院華清遠見旗下品牌:1 static void exit s3c2410_ts_exit(void) 2 3 ./號
36、,刪除 cdev4 free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);5 free_irq(IRQ_TC, s3c2410_isr_tc); 6 1 static int init s3c2410_ts_init(void) 2 3 int ret;4 tsEvent = tsEvent_dummy;5 ./申請號,添加 cdev 67 /* 設置 XP、YM、YP 和YM 對應引腳 */8 set_gpio_ctrl(GPIO_YPON);9 set_gpio_ctrl(GPIO_YMON);10 set_gpio_ctrl(GPIO_XPON);11 set_
37、gpio_ctrl(GPIO_XMON); 1213 /* 使能觸摸屏中斷 */14 ret = request_irq(IRQ_ADC_DONE, s3c2410_isr_adc,15 SA_INTERRUPT, DEVICE_NAME,s3c2410_isr_adc);16 if (ret)17 goto adc_failed;18 ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT,19 DEVICE_NAME,s3c2410_isr_tc);20 if (ret)21 goto tc_failed; 2223 /*置于等待觸點中
38、斷模式*/24 wait_down_int(); 2526 printk(DEVICE_NAME " initializedn");2728 return 0;29 tc_failed:30 free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);31 adc_failed:32 return ret; 33 Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例在 INT-TC 處理12.18 所示。,它會調用 tsEvent()完成等待隊列和信號的,如代碼代碼12.18觸摸屏驅動的觸點/抬起中斷處理程序當 X/Y 位置轉換中斷發生后,應
39、12.19 所示。X、Y 的坐標值,填入緩沖區,如代碼代碼12.19 觸摸屏驅動 X/Y 位置轉換中斷處理程序上述調用的 s3c2410_get_XY()用于獲得 X、Y 坐標,它使用代碼12.15的硬件操作宏實現,如代碼12.20 所示。代碼12.20 觸摸屏驅動中獲得 X、Y 坐標學院華清遠見旗下品牌:1 static inline void s3c2410_get_XY(void) 2 1 static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs*reg)2 3 spin_lock_irq(&(tsdev.
40、lock);4 if (tsdev.penStatus = PEN_UP)5s3c2410_get_XY(); /坐標6 #ifdef HOOK_FOR_DRAG7 else8s3c2410_get_XY();9 #endif10 spin_unlock_irq(&(tsdev.lock); 11 1 static void s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs*reg)2 3 spin_lock_irq(&(tsdev.lock);4 if (tsdev.penStatus = PEN_UP) 56start
41、_ts_adc(); /開始 X/Y 位置轉換78else910 tsdev.penStatus = PEN_UP;11 DPRINTK("PEN UP: x: %08d, y: %08dn", x, y);12 wait_down_int();/置于等待觸點中斷模式13 tsEvent();14 15 spin_unlock_irq(&(tsdev.lock); 16 Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例代碼12.18、12.20 中調用的 tsEvent 最終為 tsEvent_raw(),這個函數很關鍵,當處于 PEN_DOWN 狀
42、態時調用該函數,它會完成緩沖區的填充、等待隊列的喚醒以;否則(處于 PEN_UP 狀態),將緩沖區頭清 0,也喚醒等待及異步通知信號的隊列并信號,如代碼12.21 所示。代碼12.21觸摸屏驅動的 tsEvent_raw()函數學院華清遠見旗下品牌:1 static void tsEvent_raw(void) 2 3if (tsdev.penStatus = PEN_DOWN)45 /*填充緩沖區*/6 BUF_HEAD.x = x;7 BUF_HEAD.y = y;8 BUF_HEAD.pressure = PEN_DOWN; 910 #ifdef HOOK_FOR_DRAG11 ts_t
43、imer.expires = jiffies + TS_TIMER_DELAY;12 add_timer(&ts_timer);/啟動定時器13 #endif14 15 else16 17 #ifdef HOOK_FOR_DRAG18 del_timer(&ts_timer);19 #endif 2021 /*填充緩沖區*/22 BUF_HEAD.x = 0;23 BUF_HEAD.y = 0;24 BUF_HEAD.pressure = PEN_UP; 25 2627 tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);28 wake_up
44、_interruptible(&(tsdev.wq); /喚醒等待隊列293if (adc_state = 0) 45 adc_state = 1;6 disable_ts_adc(); /INT-ADC7 y = (ADCDAT0 &0x3ff); /坐標值8 mode_y_axis();9 start_adc_y(); /開始 y 位置轉換10 11 else if (adc_state = 1) 12 13 adc_state = 0;14 disable_ts_adc(); /INT-ADC15 x = (ADCDAT1 &0x3ff); /坐標值16 tsde
45、v.penStatus = PEN_DOWN;17 DPRINTK("PEN DOWN: x: %08d, y: %08dn", x, y);18 wait_up_int(); /置于等待抬起中斷模式19 tsEvent();20 21 Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例在包含了對拖動軌跡支持的情況下,定時器會被啟用,周期為 10ms,在每次定時器處理函數被所示。時,調用 start_ts_adc()開始 X/Y 位置轉換過程,如代碼12.22學院華清遠見旗下品牌:30 #ifdef USE_ASYNC31 if (tsdev.aq)32 ki
46、ll_fasync(&(tsdev.aq), SIGIO, POLL_IN);/異步通知33 #endif34 Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例12.22 觸摸屏驅動的定時器處理函數代碼12.2.6在觸摸屏觸摸屏驅動的打開、函數驅動的打開函數中,應初始化緩沖區、penStatus 和定期器、等待隊列及 tsEvent 時間處理函數指針,如代碼12.23 所示。12.23 觸摸屏代碼驅動的打開函數觸摸屏可,如代碼驅動的函數非常簡單,刪除為用于拖動軌跡所使用的定時器即12.24 所示。12.24 觸摸屏代碼驅動的函數12.2.7觸摸屏時,直接觸摸屏驅動的讀函
47、數驅動的讀函數實現緩沖區中信息向用戶空間的,當緩沖區有內容;否則,如果用戶阻塞觸摸屏,則進程在等待隊列上睡眠,否則,立即返回-EAGAIN,如代碼12.25 所示。學院華清遠見旗下品牌:1 static int s3c2410_ts_release(struct inode *inode, struct file *filp) 2 3 #ifdef HOOK_FOR_DRAG4 del_timer(&ts_timer);/刪除定時器5 #endif6 return 0;7 1 static int s3c2410_ts_open(struct inode *inode, struct
48、file *filp) 2 3 tsdev.head = tsdev.tail = 0;4 tsdev.penStatus = PEN_UP;/初始化觸摸屏狀態為 PEN_UP5 #ifdef HOOK_FOR_DRAG /如果定義了拖動鉤子函數6 init_timer(&ts_timer);/初始化定時器7 ts_timer.function = ts_timer_handler;8 #endif9 tsEvent = tsEvent_raw;10 init_waitqueue_head(&(tsdev.wq);/初始化等待隊列1112 return 0;13 1 #ifde
49、f HOOK_FOR_DRAG2 static void ts_timer_handler(unsigned long data) 34 spin_lock_irq(&(tsdev.lock);5 if (tsdev.penStatus = PEN_DOWN) 67start_ts_adc(); /開始 X/Y 位置轉換89spin_unlock_irq(&(tsdev.lock); 10 11 #endifLinux驅動開發詳解第 12 章、Linux 字符驅動綜合實例12.25代碼觸摸屏驅動的讀函數12.2.8在觸摸屏觸摸屏驅動的輪詢與異步通知驅動中,通過 s3c2410_
50、ts_poll()函數實現了輪詢接口,這個函數的實現非常簡單。它將等待隊列添加到 poll_table,當緩沖區有數據時,返回可標志,否則返回 0,如代碼12.26 所示。代碼12.26 觸摸屏驅動的 poll()函數而為了實現觸摸屏驅動對應用程序的異步通知,驅動中要實現s3c2410_ts_fasync()函數,這個函數與第 9 章給出的模板完全一樣,如代碼所示。12.27代碼12.27 觸摸屏驅動的 fasync()函數學院華清遠見旗下品牌:1 #ifdef USE_ASYNC2 static int s3c2410_ts_fasync(int fd, struct file *filp,
51、 int mode)1 static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)2 3 poll_wait(filp, &(tsdev.wq), wait);/添加等待隊列到 poll_table4 return (tsdev.head = tsdev.tail) ? 0 : (POLLIN | POLLRDNORM); 5 1 static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t c
52、ount,2 loff_t *ppos) 3 4TS_RET ts_ret;56 retry:7 if (tsdev.head != tsdev.tail) /緩沖區有信息89 int count;10 count = tsRead(&ts_ret);11 if (count)12 copy_to_user(buffer, (char*) &ts_ret, count);/到用戶空間13 return count;14 15 else16 17 if (filp->f_flags &O_NONBLOCK)/非阻塞讀18 return - EAGAIN;19 interruptible_sleep_on(&(tsdev.wq); /在等待隊列上睡眠20 if (signal_pending(current)21 return - ERESTARTSYS;22 goto retry;23 2425 return sizeof(TS_RET); 26 Linux驅動開發詳解第 12 章、Linux 字符驅動綜合實例學院華清遠見旗下品牌:3 4return f
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 山西省晉源區第七小學2025屆三下數學期末學業質量監測試題含解析
- 重慶醫科大學《建筑師職業基礎(含務實與法規)》2023-2024學年第二學期期末試卷
- 山東省聊城莘縣聯考2025屆初三下學期中考試英語試題含答案
- 伊寧縣2025屆五下數學期末調研模擬試題含答案
- 上海市第八中學2025屆中考預測金卷:數學試題(浙江卷)含解析
- 西南科技大學《電視綜藝欄目編導》2023-2024學年第二學期期末試卷
- 接收發展對象大會流程
- 2025數據中心服務器采購與維護工程合同
- 《2025高速數據傳輸接入服務合同》
- 2025設備租賃合同「樣式」
- 氣管插管術培訓課件
- 國家開放大學畢業生登記表-
- 電腦故障診斷卡說明書
- 企業重組所得稅特殊性處理實務(深圳市稅務局)課件
- 2022年7月2日江蘇省事業單位招聘考試《綜合知識和能力素質》(管理崗客觀題)及答案
- 瓦斯超限事故專項應急預案
- 苗木質量保證措施
- 【公司利潤質量研究國內外文獻綜述3400字】
- 水利工程分部分項劃分表
- 學生班級衛生值日表模板下載
- 責任商業聯盟RBA(CSR)知識培訓
評論
0/150
提交評論