裝置驅動程式是作業系統核心和機器硬體之間的介面,它為應用程式遮蔽硬體的細節,一般來說, linux的設
備驅動程式需要完成如下功能:
.裝置初始化、釋放;
.提供各類裝置服務;
.負責核心和裝置之間的資料交換;
.檢測和處理裝置工作過程中出現的錯誤。
linux下的裝置驅動程式被組織為一組完成不同任務的函式的集合,通過這些函式使得 linux的裝置操作猶如
檔案一般。在應用程式看來,硬體裝置只是乙個裝置檔案,應用程式可以象操作普通檔案一樣對硬體裝置進行
操作,如 open ()、close ()、read ()、write () 等。
linux主要將裝置分為二類:字元裝置和塊裝置。字元裝置是指裝置傳送和接收資料以字元的形式進行;而塊
裝置則以整個資料緩衝區的形式進行。在對字元裝置發出讀 /寫請求時,實際的硬體 i/o一般就緊接著發生了;
而塊裝置則不然,它利用一塊系統記憶體作緩衝區,當使用者程序對裝置請求能滿足使用者的要求,就返回請求的數
據,如果不能,就呼叫請求函式來進行實際的 i/o操作。塊裝置主要針對磁碟等慢速裝置。
1.記憶體分配
由於linux驅動程式在核心中執行,因此在裝置驅動程式需要申請 /釋放記憶體時,不能使用使用者級的 malloc/free
函式,而需由核心級的函式 kmalloc/kfree ()來實現,kmalloc()函式的原型為:
void kmalloc (size_t size ,int priority);
引數 size為申請分配記憶體的位元組數, kmalloc最多只能開闢 128k的記憶體;引數 priority說明若 kmalloc()
不能馬上分配記憶體時使用者程序要採用的動作: gfp_kernel 表示等待,即等 kmalloc()函式將一些記憶體安排
到交換區來滿足你的記憶體需要, gfp_atomic 表示不等待,如不能立即分配到記憶體則返回 0 值;函式的返回
值指向已分配記憶體的起始位址,出錯時,返回 0。
kmalloc ()分配的記憶體需用 kfree()函式來釋放, kfree ()被定義為:
# define kfree (n) kfree_s( (n) ,0)
其中 kfree_s ()函式原型為:
void kfree_s (void * ptr ,int size);
引數 ptr為 kmalloc()返回的已分配記憶體的指標, size是要釋放記憶體的位元組數,若為 0 時,由核心自動確定內
存的大小。
2.中斷
許多裝置涉及到中斷操作,因此,在這樣的裝置的驅動程式中需要對硬體產生的中斷請求提供中斷服務程式。
用 request_irq()函式來實現請求:
120
int request_irq (unsigned int irq ,void( * handler) int ,unsigned long type ,char * name);
引數 irq為要中斷請求號,引數 handler為指向中斷服務程式的指標,引數 type 用來確定是正常中斷還是快
速中斷(正常中斷指中斷服務子程式返回後,核心可以執行排程程式來確定將執行哪乙個程序;而快速中斷是
指中斷服務子程式返回後,立即執行被中斷程式,正常中斷 type取值為 0 ,快速中斷 type 取值為
sa_interrupt),引數 name是裝置驅動程式的名稱。
3.字元裝置驅動
我們必須為字元裝置提供乙個初始化函式,該函式用來完成對所控裝置的初始化工作,並呼叫
register_chrdev() 函式註冊字元裝置。假設有一字元裝置 「exampledev」,則其 init函式為:
void exampledev_init(void)
其中, register_chrdev函式中的引數 major_num為主裝置號 ,「exampledev」為裝置名,
exampledev_fops為包含基本函式入口點的結構體,型別為 file_operations。當執行 exampledev_init時,
它將呼叫核心函式 register_chrdev,把驅動程式的基本入口點指標存放在核心的字元裝置位址表中,在使用者
程序對該裝置執行系統呼叫時提供入口位址。
隨著核心功能的加強, file_operations結構體也變得更加龐大。但是大多數的驅動程式只是利用了其中的一部
分,對於驅動程式中無需提供的功能,只需要把相應位置的值設為 null。對於字元裝置來說,要提供的主要
入口有:open ()、release ()、read ()、write ()、ioctl ()等。
open()函式對裝置特殊檔案進行 open()系統呼叫時,將呼叫驅動程式的 open ()函式:
int (*open)(struct inode * inode,struct file *filp);
其中引數 inode為裝置特殊檔案的 inode (索引結點 ) 結構的指標,引數 filp是指向這一裝置的檔案結構的指
針。open()的主要任務是確定硬體處在就緒狀態、驗證次裝置號的合法性 (次裝置號可以用 minor(inode->
i_rdev)取得)、控制使用裝置的程序數、根據執**況返回狀態碼 (0表示成功,負數表示存在錯誤 ) 等;
release()函式當最後乙個開啟裝置的使用者程序執行 close ()系統呼叫時,核心將呼叫驅動程式的 release ()
函式:
void (*release) (struct inode * inode,struct file *filp) ;
release 函式的主要任務是清理未結束的輸入 /輸出操作、釋放資源、使用者自定義排他標誌的復位等。
read()函式當對裝置特殊檔案進行 read()系統呼叫時,將呼叫驅動程式 read() 函式:
ssize_t (*read) (struct file * filp, char * buf, size_t count, loff_t * offp);
引數 buf是指向使用者空間緩衝區的指標,由使用者程序給出, count 為使用者程序要求讀取的位元組數,也由使用者給
出。 read()函式的功能就是從硬裝置或核心記憶體中讀取或複製 count個位元組到 buf 指定的緩衝區中。在複製資料
時要注意,驅動程式執行在核心中,而 buf指定的緩衝區在使用者記憶體區中,是不能直接在核心中訪問使用的,
因此,必須使用特殊的複製函式來完成複製工作,這些函式在 include/asm/uaccess.h中被宣告:
unsigned long copy_to_user (void * to, void * from, unsigned long len);
此外,put_user()函式用於核心空間和使用者空間的單值互動(如 char、int、long)。
write( ) 函式當裝置特殊檔案進行 write () 系統呼叫時,將呼叫驅動程式的 write () 函式:
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
write ()的功能是將引數 buf 指定的緩衝區中的 count 個位元組內容複製到硬體或核心記憶體中,和read()一樣,
複製工作也需要由特殊函式來完成:
unsigned long copy_from_user(void *to, const void *from, unsigned long n);
此外,get_user()函式用於核心空間和使用者空間的單值互動(如 char、int、long)。
ioctl() 函式該函式是特殊的控制函式,可以通過它向裝置傳遞控制資訊或從裝置取得狀態資訊,函式原型
為:
int (*ioctl) (struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg);
引數 cmd為裝置驅動程式要執行的命令的**,由使用者自定義,引數 arg 為相應的命令提供引數,型別可以
是整型、指標等。
同樣,在驅動程式中,這些函式的定義也必須符合命名規則,按照本文約定,裝置 「exampledev」的驅動程式
的這些函式應分別命名為 exampledev_open、 exampledev_ release、 exampledev_read、
exampledev_write、 exampledev_ioctl,因此裝置 「exampledev」的基本入口點結構變數
exampledev_fops 賦值如下(對較早版本的核心):
ARM的嵌入式Linux移植體驗之應用例項
linux的檔案操作api涉及到建立 開啟 讀寫和關閉檔案。建立int creat const char filename,mode t mode 引數mode指定新建檔案的訪問許可權,它同umask一起決定檔案的最終許可權 mode umask 其中umask代表了檔案在建立時需要去掉的一些訪問許...
libcurl移植到嵌入式ARM
curl 庫的主要功能是用不同的協議連線不同的伺服器,也就是相當封裝了的 socket 的協議庫,libcurl 當前支援 等常用協議,libcurl 也支援https 證書授權,是網路程式開發的一把利器。unzip curl curl 7 50 0.zip 也可以把目錄名字修改為libcurl m...
向linux嵌入式ARM板移植dropbear
最近出於專案需要,不再使用telnet協議來遠端操控嵌入式linux開發機,而需要使用有一定安全要求的ssh協議,做記錄以備將來回顧。2016 8 16 linux系統中常用的ssh軟體是openssh,由於openssh略顯龐大,後選擇輕量級的dropbear替換openssh。dropbear實...