linu串口觸摸屏設計總結_第1頁
linu串口觸摸屏設計總結_第2頁
linu串口觸摸屏設計總結_第3頁
已閱讀5頁,還剩2頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、Linux serial touch 設計總結概述:最近在做嵌入式linux下串口觸摸屏設計,遇到一些問題,經過查找資料和請教同事, 總算把問題解決了,事后有把linux相關的內核代碼仔細看了一遍,為了有點成果,特別寫了個總結。,轉載請標明出處。系統資源:Linux: 2636Ul: QT+TSLIB硬件資源不關心設計方法:有兩種實現途徑。1、是將要使用的串口單獨拿出來,作為一個platform總線設備實現,在嵌入式平臺mach文件里面,加上串口中斷號和寄存器首地址,然后將這個串口注冊成 一個platform總線設備。在驅動 probe函數里面需要得到這個串口中斷號以及 寄存器映射地址,通過寄

2、存器映射地址設置串口波特率,數據位,停止位等,通過中斷號注冊中斷等,然后調用in put_register_device注冊一個in put設備。在中斷里面得到外面觸摸屏的數據,然后根據in put touch協議上報觸摸數據。這種方法實現簡單明了,不需要和linux的tty,serio等打交道。但是要求知道串口硬件spec,比如寄存器等,而且這個串口就只能給觸摸屏使用了,不能作 為tty使用。因為是嵌入式開發,因此很容易知道硬件spec,而且嵌入式平臺一旦確定,那么這個串口肯定就是給觸摸屏使用了。因此在嵌入式平臺上,推 薦使用這個方法。2、是將串口作為一個 serio總線設備,利用linux

3、內核提供serio總線驅動,通過設置對應的串口,調用 serport提供的函數將串口當做serio總線設備,在驅動里面需要按照serio總線設備驅動的框架來實現,這方面的例子linux里面有很多,比如touchright.c,在模塊in it函數里面調用 serio_register_driver注冊serio總線 設備驅動,如果 serio總線上對應的serio設備存在,就調用 connect函數,在 這個函數里面調用in put_register_device注冊一個in put設備。具體驅動不再分 析了,很簡單,相信各位都能看的懂。至此,兩種方法都實現了串口觸摸屏的驅動,講到這里是不是就

4、完了,非也,本文的重點還在后面,請看下面分析:第一種方法只要驅動模塊被加載,就會在/dev/input下面創建一個eventx節點,tslib就能訪問這個節點,獲得觸摸坐標,然后送給qt。第二種方法驅動模塊加載后,并沒有創建eventx節點,也就是說connect函數沒有被調用,按照linux驅動模型來看,就是 serio總線上還沒有對應的serio設備,因此驅動加載時沒有對應的設備,就不會調用connect函數,這時的串口還是作為一個linux tty設備存在。我遇到的問題就是 serio驅動加載了,但是沒有創建eventx節點,查找資料也只有一個說是要把tty設置成N_MOUSE,然后讀,

5、說的不清楚,也不知道怎么實現,經過自己 摸索,終于把問題解決了。Lin ux啟動后串口形式:Linux 啟動是將串口作為tty來設置的。看下的調用:start_kernelinit/main.c大家對這個函數不陌生吧,linux啟動過程中重要的一個函數con sole_ in it();drivers/tty/tty_io.ctty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); drivers/tty/tty_idisc.c給串口注冊一個tty鏈路層處理函數ops。Source hl«s involved in serial managem

6、ent how they are connected and how flows.00000/L o o o o /停serio 總現在我們需要寫一個上層的使用程序,對這個tty進行設置,需要設置波特率,數據位,止位等,最重要的是要將這個tty設備設置成一個serio總線設備,然后把它注冊在線上,請看下面的代碼:fd = ope n( device, O_RDWR | O_NOCTTY | O_NONBLOCK);if (fd < 0) fprintf(stderr, "inputattach: '%s' - %sn", device, strerro

7、r(errno);return 1;setline(fd, type_>flags, type->speed);ldisc = N_MOUSE;if (ioctl(fd, TIOCSETD, &ldisc) fprintf(stderr, "inputattach: can't set line disciplinen”); return EXIT_FAILURE;devt = type->type | (id << 8) | (extra << 16);if (ioctl(fd, SPIOCSTYPE, & devt

8、) fprin tf(stderr, "in putattach: can't set device typen"); return EXIT_FAILURE;read(fd, NULL, 0);里面的device就是對應要使用的那個串口,linux里面一般是/dev/ttySO,首先是打開串口ope n( device, O_RDWR | O_NOCTTY | O_NONBLOCK)接著設置波特率等setline(fd, CS8, B9600);static void setl in e(i nt fd, int flags, int speed)struct t

9、ermios t;tcgetattr(fd, &t);t.c_cflag = flags | CREAD | HUPCL | CLOCAL;t.c_iflag = IGNBRK | IGNPAR;t.c_oflag = 0;t.c_lflag = 0;t.c_ccVMIN = 1;t.c_ccVTIME = 0; cfsetispeed( &t, speed);cfsetospeed(&t, speed); tcsetattr(fd, TCSANOW, &t);接下來就是重點了ldisc = N_MOUSE;if (ioctl(fd, TIOCSETD, &am

10、p;ldisc)跟蹤代碼到內核層ioctl:long tty_ioctl(struct file *file, un sig ned int cmd, un sig ned long arg) drivers/tty/tty_io.ccase TIOCSETD:return tiocsetd(tty, p); drivers/tty/tty_io.c tty_set_ldisc(tty, ldisc); drivers/tty/tty_idisc.c , ldisc 等于 N_MOUSE n ew_ldisc = tty_ldisc_get(ldisc);ldops = get_ldops(d

11、isc);這段代碼需要得到N_MOUSE的鏈路層,先在tty_ldiscs里面查找是否有 N_MOUSE鏈路層的處理函數ops,如果沒有,就需要加載serport模塊,看看這個模塊init函數retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);注冊一個N_MOUSE鏈路層的處理函數ops創建一個新的 N_MOUSE鏈路層new_ldisc,接著調用tty_ldisc_assign(tty, new_ldisc);把新的鏈路層放在 tty 里面retval = tty_ldisc_ope n( tty, n ew_ldisc); 打開

12、這個新的鏈路層ret = ld->ops->open(tty)ld->ops 就是 serport 注冊的 serport_ldiscstatic int serport_ldisc_ope n( struct tty_struct *tty) drivers/i nput/serio/serport.c這個函數里面會創建一個serport結構體,并初始化至此,已經給串口增加了一個N_MOUSE的鏈路層,并且把鏈路層的處理函數也注冊進去了。這個串口當前的鏈路層就是N_MOUSE。目前為止串口還只是個 tty設備,并沒有注冊到serio總線上。繼續看我們的使用程序:devt =

13、 type->type | (id << 8) | (extra << 16);if (ioctl(fd, SPIOCSTYPE, & devt) fprin tf(stderr, "in putattach: can't set device typen");return EXIT_FAILURE;調用long tty_ioctl(struct file *file, un sig ned int cmd, un sig ned long arg) drivers/tty/tty_io.cretval = ld->ops

14、->ioctl(tty, file, cmd, arg);static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, un sig ned int cmd, un sig ned long arg)設置serport->to = type & OxOOOOOOff;serport->id.id = (type & OxOOOOffOO) >> 8; serport->id.extra = (type & OxOOffOOOO) &g

15、t;> 16;這里三個值一定要和 serio總線驅動里面對應的值一致,serio總線就是靠它們來給設備和驅動建立聯系的。調用read(fd, NULL, 0);跟蹤代碼到內核層 tty_read :static ssize_t tty_read(struct file *file, char _user *buf, size_t count,loff_t *ppos)(ld->ops->read)(tty, file, buf, count) 這個ld就是tty當前的鏈路層結構,上面我們已 經設置N_MOUSE為tty的當前鏈路層,因此 ld->ops就是serport

16、注冊的serport_ldiscstatic ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, un sig ned char _user* buf, size_t nr)serio_register_port(serport->serio);serio_ ini t_port(serio); serio_queue_eve nt(serio, owner, SERIO_REGISTER_PORT);注冊一個serio總線設備,關于serio總線,網絡有很多資料介紹,這里就不說了。 至此,我們的

17、串口設備已經當做serio總線設備注冊在serio總線上了,如果相應的驅動也在serio總線上,就會進行設備和驅動的匹配,然后調用驅動里面的connect函數,在這個函數里面就會創建in put節點。我們的驅動和設備已經運行起來了,現在看看數據是如何傳遞的 先看具體串口中斷函數:我們以altera_uart.c為例:altera_uart_i nterruptaltera_uart_rx_chars(pp) tty_flip_buffer_push(port->state->port.tty);flush_to_ldisc(&tty->buf.work);disc-&

18、gt;ops->receive_buf(tty, char_buf,flag_buf, count); disc->ops 就是 serport 注冊的 serport_ldisc static void serport_ldisc_receive(struct tty_struct *tty, const un sig ned char*cp, char *fp, int count)serio_i nterrupt(serport->serio, cpi, ch_flags); ret = serio->drv ->in terrupt(serio, data, dfl);drv->interrupt就是我們驅動函數提供一個函數,它每次接受一個字符,在這個函數里面,接受到足夠信息后,就能得到觸摸屏坐標信息,然后通過input_report上報上去。看看數據處理流程圖:Data flow and function

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論