版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
第11章嵌入式Linux設備驅(qū)動開發(fā)2023/6/9第11章嵌入式Linux設備驅(qū)動開發(fā)本章的主要內(nèi)容11.1設備驅(qū)動概述11.2字符設備驅(qū)動編程11.3GPIO驅(qū)動程序?qū)嵗?1.4塊設備驅(qū)動編程11.5中斷編程11.6按鍵驅(qū)動程序?qū)嵗?1.7實驗內(nèi)容——test驅(qū)動第11章嵌入式Linux設備驅(qū)動開發(fā)11.1設備驅(qū)動概述第11章嵌入式Linux設備驅(qū)動開發(fā)設備驅(qū)動簡介及驅(qū)動模塊操作系統(tǒng)是通過各種驅(qū)動程序來駕馭硬件設備的,它為用戶屏蔽了各種各樣的設備,驅(qū)動硬件是操作系統(tǒng)最基本的功能,并且提供統(tǒng)一的操作方式。設備驅(qū)動程序是內(nèi)核的一部分,硬件驅(qū)動程序是操作系統(tǒng)最基本的組成部分,在Linux內(nèi)核源程序中也占有60%以上。因此,熟悉驅(qū)動的編寫是很重要的。Linux內(nèi)核中采用可加載的模塊化設計(LKMs,LoadableKernelModules),一般情況下編譯的Linux內(nèi)核是支持可插入式模塊的,也就是將最基本的核心代碼編譯在內(nèi)核中,其他的代碼可以編譯到內(nèi)核中,或者編譯為內(nèi)核的模塊文件(在需要時動態(tài)加載)。第11章嵌入式Linux設備驅(qū)動開發(fā)內(nèi)核模塊的主要相關命令常見的驅(qū)動程序是作為內(nèi)核模塊動態(tài)加載的,比如聲卡驅(qū)動和網(wǎng)卡驅(qū)動等,而Linux最基礎的驅(qū)動,如CPU、PCI總線、TCP/IP協(xié)議、APM(高級電源管理)、VFS等驅(qū)動程序則直接編譯在內(nèi)核文件中。有時也把內(nèi)核模塊叫做驅(qū)動程序,只不過驅(qū)動的內(nèi)容不一定是硬件罷了,比如ext3文件系統(tǒng)的驅(qū)動。因此,加載驅(qū)動就是加載內(nèi)核模塊。lsmod列出當前系統(tǒng)中加載的模塊,其中左邊第一列是模塊名,第二列是該模塊大小,第三列則是使用該模塊的對象數(shù)目。rmmod是用于將當前模塊卸載。insmod和modprobe是用于加載當前模塊,但insmod不會自動解決依存關系,即如果要加載的模塊引用了當前內(nèi)核符號表中不存在的符號,則無法加載,也不會去查在其他尚未加載的模塊中是否定義了該符號;modprobe可以根據(jù)模塊間依存關系以及/etc/modules.conf文件中的內(nèi)容自動加載其他有依賴關系的模塊。第11章嵌入式Linux設備驅(qū)動開發(fā)設備分類(1)Linux系統(tǒng)的設備分為三類:字符設備、塊設備和網(wǎng)絡設備。 字符設備通常指像普通文件或字節(jié)流一樣,以字節(jié)為單位順序讀寫的設備,如并口設備、虛擬控制臺等。字符設備可以通過設備文件節(jié)點訪問,它與普通文件之間的區(qū)別在于普通文件可以被隨機訪問(可以前后移動訪問指針),而大多數(shù)字符設備只能提供順序訪問,因為對它們的訪問不會被系統(tǒng)所緩存。但也有例外,例如幀緩存(framebuffer)是一個可以被隨機訪問的字符設備。 塊設備通常指一些需要以塊為單位隨機讀寫的設備,如IDE硬盤、SCSI硬盤、光驅(qū)等。塊設備也是通過文件節(jié)點來訪問,它不僅可以提供隨機訪問,而且可以容納文件系統(tǒng)(例如硬盤、閃存等)。Linux可以使用戶態(tài)程序像訪問字符設備一樣每次進行任意字節(jié)的操作,只是在內(nèi)核態(tài)內(nèi)部中的管理方式和內(nèi)核提供的驅(qū)動接口上不同。第11章嵌入式Linux設備驅(qū)動開發(fā)設備分類(2)
網(wǎng)絡設備通常是指通過網(wǎng)絡能夠與其他主機進行數(shù)據(jù)通信的設備,如網(wǎng)卡等。內(nèi)核和網(wǎng)絡設備驅(qū)動程序之間的通信調(diào)用一套數(shù)據(jù)包處理函數(shù),它們完全不同于內(nèi)核和字符以及塊設備驅(qū)動程序之間的通信(read(),write()等函數(shù))。Linux網(wǎng)絡設備不是面向流的設備,因此不會將網(wǎng)絡設備的名字(例如eth0)映射到文件系統(tǒng)中去。$ls–l/devcrw-rw1rootuucp4,6408-3022:58ttyS0/*串口設備,c表示字符設備*/brw-r1rootfloppy2,008-3022:58fd0 /*軟盤設備,b表示塊設備*/第11章嵌入式Linux設備驅(qū)動開發(fā)設備號設備號是一個數(shù)字,它是設備的標志。就如前面所述,一個設備文件(也就是設備節(jié)點)可以通過mknod命令來創(chuàng)建,其中指定了主設備號和次設備號。主設備號表明設備的類型(例如串口設備、SCSI硬盤),與一個確定的驅(qū)動程序?qū)?;次設備號通常是用于標明不同的屬性,例如不同的使用方法,不同的位置,不同的操作等,它標志著某個具體的物理設備。高字節(jié)為主設備號,底字節(jié)為次設備號。 例如,在系統(tǒng)中的塊設備IDE硬盤的主設備號是3,而多個IDE硬盤及其各個分區(qū)分別賦予次設備號1、2、3……$ls–l/devcrw-rw1rootuucp4,6408-3022:58ttyS0/*主設備號4,此設備號64*/第11章嵌入式Linux設備驅(qū)動開發(fā)驅(qū)動層次結構第11章嵌入式Linux設備驅(qū)動開發(fā)設備驅(qū)動程序與外界的接口第11章嵌入式Linux設備驅(qū)動開發(fā)設備驅(qū)動程序的特點(1)(1)內(nèi)核代碼:設備驅(qū)動程序是內(nèi)核的一部分,如果驅(qū)動程序出錯,則可能導致系統(tǒng)崩潰。(2)內(nèi)核接口:設備驅(qū)動程序必須為內(nèi)核或者其子系統(tǒng)提供一個標準接口。比如,一個終端驅(qū)動程序必須為內(nèi)核提供一個文件I/O接口;一個SCSI設備驅(qū)動程序應該為SCSI子系統(tǒng)提供一個SCSI設備接口,同時SCSI子系統(tǒng)也必須為內(nèi)核提供文件的I/O接口及緩沖區(qū)。(3)內(nèi)核機制和服務:設備驅(qū)動程序使用一些標準的內(nèi)核服務,如內(nèi)存分配等。第11章嵌入式Linux設備驅(qū)動開發(fā)設備驅(qū)動程序的特點(2)(4)可裝載:大多數(shù)的Linux操作系統(tǒng)設備驅(qū)動程序都可以在需要時裝載進內(nèi)核,在不需要時從內(nèi)核中卸載。(5)可設置:Linux操作系統(tǒng)設備驅(qū)動程序可以集成為內(nèi)核的一部分,并可以根據(jù)需要把其中的某一部分集成到內(nèi)核中,這只需要在系統(tǒng)編譯時進行相應的設置即可。(6)動態(tài)性:在系統(tǒng)啟動且各個設備驅(qū)動程序初始化后,驅(qū)動程序?qū)⒕S護其控制的設備。如果該設備驅(qū)動程序控制的設備不存在也不影響系統(tǒng)的運行,那么此時的設備驅(qū)動程序只是多占用了一點系統(tǒng)內(nèi)存罷了。第11章嵌入式Linux設備驅(qū)動開發(fā)11.2字符設備驅(qū)動編程第11章嵌入式Linux設備驅(qū)動開發(fā)設備驅(qū)動程序工作原理模塊在調(diào)用insmod命令時被加載,此時的入口點是init_module()函數(shù),通常在該函數(shù)中完成設備的注冊。同樣,模塊在調(diào)用rmmod命令時被卸載,此時的入口點是cleanup_module()函數(shù),在該函數(shù)中完成設備的卸載。在設備完成注冊加載之后,用戶的應用程序就可以對該設備進行一定的操作,如open()、read()、write()等,而驅(qū)動程序就是用于實現(xiàn)這些操作,在用戶應用程序調(diào)用相應入口函數(shù)時執(zhí)行相關的操作。第11章嵌入式Linux設備驅(qū)動開發(fā)重要數(shù)據(jù)結構-file_operaions結構structfile_operations{loff_t(*llseek)(structfile*,loff_t,int);ssize_t(*read)(structfile*filp,char*buff,size_tcount,loff_t*offp);ssize_t(*write)(structfile*filp,constchar*buff,size_tcount,loff_t*offp);int(*readdir)(structfile*,void*,filldir_t);unsignedint(*poll)(structfile*,structpoll_table_struct*);int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);int(*mmap)(structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*flush)(structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structfile*,structdentry*);int(*fasync)(int,structfile*,int);int(*check_media_change)(kdev_tdev);int(*revalidate)(kdev_tdev);int(*lock)(structfile*,int,structfile_lock*);};第11章嵌入式Linux設備驅(qū)動開發(fā)重要數(shù)據(jù)結構-inode結構structfile{mode_tf_mode;/*標識文件是否可讀或可寫,F(xiàn)MODE_READ或FMODE_WRITE*/dev_tf_rdev;/*用于/dev/tty*/off_tf_pos;/*當前文件位移*/unsignedshortf_flags;/*文件標志,如O_RDONLY、O_NONBLOCK和O_SYNC*/unsignedshortf_count;/*打開的文件數(shù)目*/unsignedshortf_reada;structinode*f_inode;/*指向inode的結構指針*/structfile_operations*f_op;/*文件索引指針*/};第11章嵌入式Linux設備驅(qū)動開發(fā)早期版本的字符設備注冊(1)早期版本的設備注冊使用函數(shù)register_chrdev(),調(diào)用該函數(shù)后就可以向系統(tǒng)申請主設備號,如果register_chrdev()操作成功,設備名就會出現(xiàn)在/proc/devices文件里。在關閉設備時,通常需要解除原先的設備注冊,此時可使用函數(shù)unregister_chrdev(),此后該設備就會從/proc/devices里消失。其中主設備號和次設備號不能大于255。第11章嵌入式Linux設備驅(qū)動開發(fā)早期版本的字符設備注冊(2)第11章嵌入式Linux設備驅(qū)動開發(fā)設備號相關函數(shù)(1)在linux2.6的版本中,用dev_t類型來描述設備號(dev_t是32位數(shù)值類型,其中高12位表示主設備號,低20位表示次設備號)。用兩個宏MAJOR和MINOR分別獲得dev_t設備號的主設備號和次設備號,而且用MKDEV宏來實現(xiàn)逆過程,即組合主設備號和次設備號而獲得dev_t類型設備號。分配設備號有靜態(tài)和動態(tài)的兩種方法。靜態(tài)分配(register_chrdev_region()函數(shù))是指在事先知道設備主設備號的情況下,通過參數(shù)函數(shù)指定第一個設備號(它的次設備號通常為0)而向系統(tǒng)申請分配一定數(shù)目的設備號。動態(tài)分配(alloc_chrdev_region())是指通過參數(shù)僅設置第一個次設備號(通常為0,事先不會知道主設備號)和要分配的設備數(shù)目而系統(tǒng)動態(tài)分配所需的設備號。通過unregister_chrdev_region()函數(shù)釋放已分配的(無論是靜態(tài)的還是動態(tài)的)設備號。第11章嵌入式Linux設備驅(qū)動開發(fā)設備號相關函數(shù)(2)第11章嵌入式Linux設備驅(qū)動開發(fā)字符設備注冊(1)在Linux內(nèi)核中使用structcdev結構來描述字符設備,我們在驅(qū)動程序中必須將已分配到的設備號以及設備操作接口(即為structfile_operations結構)賦予structcdev結構變量。首先使用cdev_alloc()函數(shù)向系統(tǒng)申請分配structcdev結構,再用cdev_init()函數(shù)初始化已分配到的結構并與file_operations結構關聯(lián)起來。最后調(diào)用cdev_add()函數(shù)將設備號與structcdev結構進行關聯(lián)并向內(nèi)核正式報告新設備的注冊,這樣新設備可以被用起來了!。如果要從系統(tǒng)中刪除一個設備,則要調(diào)用cdev_del()函數(shù)。第11章嵌入式Linux設備驅(qū)動開發(fā)字符設備注冊(2)第11章嵌入式Linux設備驅(qū)動開發(fā)打開設備打開設備的函數(shù)接口是open,根據(jù)設備的不同,open函數(shù)接口完成的功能也有所不同,但通常情況下在open函數(shù)接口中要完成如下工作。遞增計數(shù)器,檢查錯誤。如果未初始化,則進行初始化。識別次設備號,如果必要,更新f_op指針。分配并填寫被置于filp->private_data的數(shù)據(jù)結構。其中遞增計數(shù)器是用于設備計數(shù)的。由于設備在使用時通常會打開多次,也可以由不同的進程所使用,所以若有一進程想要刪除該設備,則必須保證其他設備沒有使用該設備。因此使用計數(shù)器就可以很好地完成這項功能。第11章嵌入式Linux設備驅(qū)動開發(fā)釋放設備釋放設備的函數(shù)接口是release()。要注意釋放設備和關閉設備是完全不同的。當一個進程釋放設備時,其他進程還能繼續(xù)使用該設備,只是該進程暫時停止對該設備的使用;而當一個進程關閉設備時,其他進程必須重新打開此設備才能使用它。釋放設備時要完成的工作如下。遞減計數(shù)器MOD_DEC_USE_COUNT(最新版本已經(jīng)不再使用)。釋放打開設備時系統(tǒng)所分配的內(nèi)存空間(包括filp->private_data指向的內(nèi)存空間)。在最后一次釋放設備操作時關閉設備。第11章嵌入式Linux設備驅(qū)動開發(fā)讀寫設備讀寫設備的主要任務就是把內(nèi)核空間的數(shù)據(jù)復制到用戶空間,或者從用戶空間復制到內(nèi)核空間,也就是將內(nèi)核空間緩沖區(qū)里的數(shù)據(jù)復制到用戶空間的緩沖區(qū)中或者相反。第11章嵌入式Linux設備驅(qū)動開發(fā)內(nèi)核空間和用戶空間的數(shù)據(jù)交換內(nèi)核空間地址和用戶空間地址是有很大區(qū)別的,其中一個區(qū)別是用戶空間的內(nèi)存是可以被換出的,因此可能會出現(xiàn)頁面失效等情況。所以不能使用諸如memcpy()之類的函數(shù)來完成這樣的操作。在這里要使用copy_to_user()或copy_from_user()等函數(shù),它們是用來實現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)交換的。第11章嵌入式Linux設備驅(qū)動開發(fā)ioctl大部分設備除了讀寫操作,還需要硬件配置和控制(例如,設置串口設備的波特率)等很多其他操作。在字符設備驅(qū)動中ioctl函數(shù)接口給用戶提供對設備的非讀寫操作機制。第11章嵌入式Linux設備驅(qū)動開發(fā)獲取內(nèi)存(1)在應用程序中獲取內(nèi)存通常使用函數(shù)malloc(),但在設備驅(qū)動程序中動態(tài)開辟內(nèi)存可以以字節(jié)或頁面為單位。其中,以字節(jié)為單位分配內(nèi)存的函數(shù)有kmalloc(),注意的是,kmalloc()函數(shù)返回的是物理地址,而malloc()等返回的是線性虛擬地址,因此在驅(qū)動程序中不能使用malloc()函數(shù)。與malloc()不同,kmalloc()申請空間有大小限制。長度是2的整次方,并且不會對所獲取的內(nèi)存空間清零。以頁為單位分配內(nèi)存的函數(shù)如下所示:get_zeroed_page():獲得一個已清零頁面。get_free_page():獲得一個或幾個連續(xù)頁面。get_dma_pages():獲得用于DMA傳輸?shù)捻撁妗Ec之相對應的釋放內(nèi)存用也有kfree()或free_page函數(shù)族。第11章嵌入式Linux設備驅(qū)動開發(fā)獲取內(nèi)存(2)第11章嵌入式Linux設備驅(qū)動開發(fā)獲取內(nèi)存(3)第11章嵌入式Linux設備驅(qū)動開發(fā)獲取內(nèi)存(4)第11章嵌入式Linux設備驅(qū)動開發(fā)打印信息在內(nèi)核空間要用函數(shù)printk()而不能用平常的函數(shù)printf()。printk()還可以定義打印消息的優(yōu)先級。第11章嵌入式Linux設備驅(qū)動開發(fā)proc文件系統(tǒng)(1)/proc文件系統(tǒng)是一個偽文件系統(tǒng),它是一種內(nèi)核和內(nèi)核模塊用來向進程發(fā)送信息的機制。這個偽文件系統(tǒng)讓用戶可以和內(nèi)核內(nèi)部數(shù)據(jù)結構進行交互,獲取有關系統(tǒng)和進程的有用信息,在運行時通過改變內(nèi)核參數(shù)來改變設置。與其他文件系統(tǒng)不同,/proc存在于內(nèi)存之中而不是在硬盤上。讀者可以通過“l(fā)s”查看/proc文件系統(tǒng)的內(nèi)容。
第11章嵌入式Linux設備驅(qū)動開發(fā)proc文件系統(tǒng)(2)第11章嵌入式Linux設備驅(qū)動開發(fā)11.3GPIO驅(qū)動程序?qū)嵗?1章嵌入式Linux設備驅(qū)動開發(fā)GPIO工作原理FS2410開發(fā)板的S3C2410處理器具有117個多功能通用I/O(GPIO)端口管腳,包括GPIO8個端口組,分別為GPA(23個輸出端口)、GPB(11個輸入/輸出端口)、GPC(16個輸入/輸出端口)、GPD(16個輸入/輸出端口)、GPE(16個輸入/輸出端口)、GPF(8個輸入/輸出端口)、GPH(11個輸入/輸出端口)。根據(jù)各種系統(tǒng)設計的需求,通過軟件方法可以將這些端口配置成具有相應功能(例如:外部中斷或數(shù)據(jù)總線)的端口。為了控制這些端口,S3C2410處理器為每個端口組分別提供幾種相應的控制寄存器。其中最常用的有端口配置寄存器(GPACON~GPHCON)和端口數(shù)據(jù)寄存器(GPADAT~GPHDAT)。因為大部分I/O管腳可以提供多種功能,通過配置寄存器(PnCON)設定每個管腳用于何種目的。數(shù)據(jù)寄存器的每位將對應于某個管腳上的輸入或輸出。所以通過對數(shù)據(jù)寄存器(PnDAT)的位讀寫,可以進行對每個端口的輸入或輸出。第11章嵌入式Linux設備驅(qū)動開發(fā)LED和蜂鳴器驅(qū)動電路可知使用S3C2410處理器的通用I/O口GPF4、GPF5、GPF6和GPF7分別直接驅(qū)動LEDD12、D11、D10以及D9,而使用GPB0端口驅(qū)動蜂鳴器。4個LED分別在對應端口(GPF4~GPF7)為低電平時發(fā)亮,而蜂鳴器在GPB0為高電平時發(fā)聲。這5個端口的數(shù)據(jù)流方向均為輸出。第11章嵌入式Linux設備驅(qū)動開發(fā)主要控制寄存器(1)第11章嵌入式Linux設備驅(qū)動開發(fā)主要控制寄存器(2)為了驅(qū)動LED和蜂鳴器,首先通過端口配置寄存器將5個相應寄存器配置為輸出模式。然后通過對端口數(shù)據(jù)寄存器的寫操作,實現(xiàn)對每個GPIO設備的控制(發(fā)亮或發(fā)聲)。在下一個小節(jié)中介紹的驅(qū)動程序中,s3c2410_gpio_cfgpin()函數(shù)和s3c2410_gpio_pullup()函數(shù)將進行對某個端口的配置,而s3c2410_gpio_setpin()函數(shù)實現(xiàn)向數(shù)據(jù)寄存器的某個端口的輸出。第11章嵌入式Linux設備驅(qū)動開發(fā)GPIO驅(qū)動程序閱讀并運行11-3-2$makeclean;make/*驅(qū)動程序的編譯*/$insmodgpio_drv.ko/*加載gpio驅(qū)動*/$cat/proc/devices/*通過這個命令可以查到gpio設備的主設備號*/$mknod/dev/gpioc2520/*假設主設備號為252,創(chuàng)建設備文件節(jié)點*/$arm-linux-gcc–ogpio_testgpio_test.c$./gpio_test運行結果為4個LED輪流閃爍,同時蜂鳴器以一定周期發(fā)出聲響。第11章嵌入式Linux設備驅(qū)動開發(fā)11.4塊設備驅(qū)動編程第11章嵌入式Linux設備驅(qū)動開發(fā)塊設備驅(qū)動塊設備通常指一些需要以塊(如512字節(jié))的方式寫入的設備,如IDE硬盤、SCSI硬盤、光驅(qū)等。它的驅(qū)動程序的編寫過程與字符型設備驅(qū)動程序的編寫有很大的區(qū)別。塊設備驅(qū)動編程接口相對復雜,不如字符設備明晰易用。塊設備驅(qū)動程序?qū)φ麄€系統(tǒng)的性能影響較大,速度和效率是設計塊設備驅(qū)動程要重點考慮的問題。系統(tǒng)中使用緩沖區(qū)與訪問請求的優(yōu)化管理(合并與重新排序)來提高系統(tǒng)性能。
第11章嵌入式Linux設備驅(qū)動開發(fā)塊設備驅(qū)動工作流程塊設備驅(qū)動程序的編寫流程同字符設備驅(qū)動程序的編寫流程很類似,也包括了注冊和使用兩部分。但與字符驅(qū)動設備所不同的是,塊設備驅(qū)動程序包括一個request請求隊列。它是當內(nèi)核安排一次數(shù)據(jù)傳輸時在列表中的一個請求隊列,以最大化系統(tǒng)性能為原則進行排序。第11章嵌入式Linux設備驅(qū)動開發(fā)重要數(shù)據(jù)結構(1)每個塊設備物理實體由一個gendisk結構體來表示,每個gendisk可以支持多個分區(qū)。每個gendisk中包含了本物理實體的全部信息以及操作函數(shù)接口。整個塊設備的注冊過程是圍繞gendisk來展開的。structgendisk{intmajor;/*主設備號*/intfirst_minor;/*第一個次設備號*/intminors;/*次設備號個數(shù),一個塊設備至少需要使用一個次設備號,而且塊設備的每個分區(qū)都需要一個次設備號,因此這個成員等于1,則表明該塊設備是不可被分區(qū)的,否則可以包含minors–1個分區(qū)。*/chardisk_name[32];/*塊設備名稱,在/proc/partions中顯示*/structhd_struct**part;/*分區(qū)表*/structblock_device_operations*fops;/*塊設備操作接口,與字符設備的file_operations結構對應*/structrequest_queue*queue;/*I/O請求隊列*/void*private_data;/*指向驅(qū)動程序私有數(shù)據(jù)*/sector_tcapacity;/*塊設備可包含的扇區(qū)數(shù)*/……/*其他省略*/};第11章嵌入式Linux設備驅(qū)動開發(fā)重要數(shù)據(jù)結構(2)structblock_device_operations{int(*open)(structinode*,structfile*);int(*release)(structinode*,structfile*);int(*ioctl)(structinode*,structfile*,unsigned,unsignedlong);long(*unlocked_ioctl)(structfile*,unsigned,unsignedlong);long(*compat_ioctl)(structfile*,unsigned,unsignedlong);int(*direct_access)(structblock_device*,sector_t,unsignedlong*);int(*media_changed)(structgendisk*);int(*revalidate_disk)(structgendisk*);int(*getgeo)(structblock_device*,structhd_geometry*);structmodule*owner;};塊設備驅(qū)動程序也包含一個在<linux/fs.h>中定義的block_device_operations結構塊設備并不提供read()、write()等函數(shù)接口。對塊設備的讀寫請求都是以異步方式發(fā)送到設備相關的request隊列之中。
第11章嵌入式Linux設備驅(qū)動開發(fā)塊設備注冊和初始化(1)第11章嵌入式Linux設備驅(qū)動開發(fā)塊設備注冊和初始化(2)(1)向內(nèi)核注冊使用register_blkdev()函數(shù)對設備進行注冊。其中參數(shù)major為要注冊的塊設備的主設備號,如果其值等于0,則系統(tǒng)動態(tài)分配并返回主設備號。參數(shù)name為設備名,在/proc/devices中顯示。如果出錯,則該函數(shù)返回負值。與其對應的塊設備的注銷函數(shù)為unregister_blkdev()。其參數(shù)必須與注冊函數(shù)中的參數(shù)相同。如果出錯則返回負值。(2)申請并初始化請求隊列這一步要調(diào)用blk_init_queue()函數(shù)來申請并初始化請求隊列。其中參數(shù)rfn是請求隊列的處理函數(shù)指針,它負責執(zhí)行塊設備的讀、寫請求。參數(shù)lock為自旋鎖,用于控制對所分配的隊列的訪問。intregister_blkdev(unsignedintmajor,constchar*name);intunregister_blkdev(unsignedintmajor,constchar*name);structrequest_queue*blk_init_queue(request_fn_proc*rfn,spinlock_t*lock)第11章嵌入式Linux設備驅(qū)動開發(fā)塊設備注冊和初始化(3)(3)初始化并注冊gendisk結構首先使用alloc_disk()函數(shù)動態(tài)分配gendisk結構,接下來,對gendisk結構的主設備號(major)、次設備號相關成員(first_minor和minors)、塊設備操作函數(shù)(fops)、請求隊列(queue)、可包含的扇區(qū)數(shù)(capacity)以及設備名稱(disk_name)等成員進行初始化。在完成對gendisk的分配和初始化之后,調(diào)用add_disk()函數(shù)向系統(tǒng)注冊塊設備。在卸載gendisk結構的時候,要調(diào)用del_gendisk()函數(shù)。第11章嵌入式Linux設備驅(qū)動開發(fā)塊設備請求處理塊設備驅(qū)動中一般要實現(xiàn)一個請求隊列處理函數(shù)來處理隊列中的請求。從塊設備的運行流程,可知請求處理是塊設備的基本處理單位,也是最核心的部分。對塊設備的讀寫操作被封裝到了每一個請求中。
第11章嵌入式Linux設備驅(qū)動開發(fā)11.5中斷編程第11章嵌入式Linux設備驅(qū)動開發(fā)中斷編程接口(1)實際上,有很多Linux的驅(qū)動都是通過中斷的方式來進行內(nèi)核和硬件的交互。中斷機制提供了硬件和軟件之間異步傳遞信息的方式。硬件設備在發(fā)生某個事件時通過中斷通知軟件進行處理。中斷實現(xiàn)了硬件設備按需獲得處理器關注的機制,與查詢方式相比可以大大節(jié)省CPU資源的開銷。申請中斷使用request_irq()調(diào)用,釋放中斷使用free_irq()調(diào)用。intrequest_irq(unsignedintirq,void(*handler)(intirq,void*dev_id,structpt_regs*regs),unsignedlongirqflags,constchar*devname,oid*dev_id);voidfree_irq(unsignedintirq,void*dev_id);第11章嵌入式Linux設備驅(qū)動開發(fā)中斷編程接口(2)其中irq是要申請的硬件中斷號。在Intel平臺,范圍是0~15。參數(shù)handler為將要向系統(tǒng)注冊的中斷處理函數(shù)。這是一個回調(diào)函數(shù),中斷發(fā)生時,系統(tǒng)調(diào)用這個函數(shù),傳入的參數(shù)包括硬件中斷號、設備id以及寄存器值。設備id就是在調(diào)用request_irq()時傳遞給系統(tǒng)的參數(shù)dev_id。參數(shù)irqflags是中斷處理的一些屬性,其中比較重要的有SA_INTERRUPT。這個參數(shù)用于標明中斷處理程序是快速處理程序(設置SA_INTERRUPT)還是慢速處理程序(不設置SA_INTERRUPT)。快速處理程序被調(diào)用時屏蔽所有中斷。慢速處理程序只屏蔽正在處理的中斷。還有一個SA_SHIRQ屬性,設置了以后運行多個設備共享中斷,在中斷處理程序中根據(jù)dev_id區(qū)分不同設備產(chǎn)生的中斷。參數(shù)devname為設備名,會在/dev/interrupts中顯示。參數(shù)dev_id在中斷共享時會用到。一般設置為這個設備的device結構本身或者NULL。中斷處理程序可以用dev_id找到相應的控制這個中斷的設備,或者用irq2dev_map()找到中斷對應的設備。第11章嵌入式Linux設備驅(qū)動開發(fā)11.6按鍵驅(qū)動程序?qū)嵗?1章嵌入式Linux設備驅(qū)動開發(fā)按鍵工作原理(1)LED和蜂鳴器是最簡單的GPIO的應用,都不需要任何外部輸入或控制。按鍵同樣使用GPIO接口,但按鍵本身需要外部的輸入,即在驅(qū)動程序中要處理外部中斷。按鍵硬件驅(qū)動原理圖如圖11-7所示。在圖11-7的4X4矩陣按鍵(K1~K16)電路中,使用4個輸入/輸出端口(EINT0、EINT2、EINT11和EINT19)和4個輸出端口(KSCAN0~KSCAN3)。
第11章嵌入式Linux設備驅(qū)動開發(fā)按鍵工作原理(2)第11章嵌入式Linux設備驅(qū)動開發(fā)按鍵電路的主要端口第11章嵌入式Linux設備驅(qū)動開發(fā)按鍵驅(qū)動程序原理(1)因為通常中斷端口是比較珍貴且有限的資源,所以在本電路設計中,16個按鍵復用了4個中斷線。那怎么樣才能及時而準確地對矩陣按鍵進行掃描呢?某個中斷的產(chǎn)生表示,與它所對應的矩陣行的4個按鍵中,至少有一個按鍵被按住了。因此可以通過查看產(chǎn)生了哪個中斷,來確定在矩陣的哪一行中發(fā)生了按鍵操作(按住或釋放)。例如,如果產(chǎn)生了外部2號線中斷(EINT2變?yōu)榈碗娖剑瑒t表示K7、K8、K9和K15中至少有一個按鍵被按住了。這時候4個EINT端口應該通過GPIO配置寄存器被設置為外部中斷端口,而且4個KSCAN端口的輸出必須為低電平。第11章嵌入式Linux設備驅(qū)動開發(fā)按鍵驅(qū)動程序原理(2)在確定按鍵操作所在行的位置之后,我們還得查看按鍵操作所在列的位置。此時要使用KSCAN端口組,同時將4個EINT端口配置為通用輸入端口(而不是中斷端口)。在4個KSCAN端口中,輪流將其中某一個端口的輸出置為低電平,其他3個端口的輸出置為高電平。這樣逐列進行掃描,直到按鍵所在列的KSCAN端口輸出為低電平,此時按鍵操作所在行的EINT管腳的輸入端口的值會變成低電平。例如,在確認產(chǎn)生了外部2號中斷之后,進行逐列掃描。若發(fā)現(xiàn)在KSCAN1為低電平時(其他端口輸出均為高電平),GPF2(EINT2管腳的輸入端口)變?yōu)榈碗娖?,則可以斷定按鍵K8被按住了。實際的按鍵動作會在短時間(幾毫秒至幾十毫秒)內(nèi)產(chǎn)生信號抖動。例如,當按鍵被按下時,其動作就像彈簧的若干次往復運動,將產(chǎn)生幾個脈沖信號。一次按鍵操作將會產(chǎn)生若干次按鍵中斷,從而會產(chǎn)生抖動現(xiàn)象。因此驅(qū)動程序中必須要解決去除抖動所產(chǎn)生的毛刺信號的問題。第11章嵌入式Linux設備驅(qū)動開發(fā)按鍵驅(qū)動程序閱讀并運行示例11-6。$makeclean;make /*驅(qū)動程序的編譯*/$insmodbutt_dev.ko/*加載b
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年雞東縣幼兒園教師招教考試備考題庫附答案解析(奪冠)
- 2024年眉縣幼兒園教師招教考試備考題庫含答案解析(必刷)
- 2024年湘南幼兒師范高等??茖W校馬克思主義基本原理概論期末考試題及答案解析(必刷)
- 2025年景縣招教考試備考題庫含答案解析(必刷)
- 2025年鄭州亞歐交通職業(yè)學院馬克思主義基本原理概論期末考試模擬題及答案解析(奪冠)
- 2025年浙江音樂學院馬克思主義基本原理概論期末考試模擬題帶答案解析(必刷)
- 2024年貴陽人文科技學院馬克思主義基本原理概論期末考試題附答案解析
- 2025年新鄉(xiāng)縣幼兒園教師招教考試備考題庫含答案解析(奪冠)
- 2024年璧山縣招教考試備考題庫含答案解析(奪冠)
- 2026年軟件工程師編程技能進階測試題庫
- 2026山東聊城市新聊泰城市建設發(fā)展有限公司首批用人招聘10人備考題庫及答案詳解參考
- dbj41河南省城市軌道交通客 運服務標志設計標準
- 房地產(chǎn)公司開發(fā)全流程法律風險手冊(定稿)模版
- 2026國家國防科技工業(yè)局所屬事業(yè)單位第一批招聘62人備考題庫帶答案詳解
- 2026中國電信四川公用信息產(chǎn)業(yè)有限責任公司社會成熟人才招聘備考題庫及1套完整答案詳解
- 2025班組三級安全安全教育考試題庫(+答案解析)
- CRM培訓教學課件
- 安徽省亳州市2025屆高三上學期期末質(zhì)量檢測生物試卷(含答案)
- 電磁流量說明書
- XX少兒棋院加盟協(xié)議
- 五年級數(shù)學應用題專題訓練50題
評論
0/150
提交評論