Linux驅動開發概述


原文出處:http://www.cnblogs.com/jacklu/p/4722563.html

Linux設備分類

設備的驅動程序也要像裸機程序那樣進行一些硬件操作,不同的是驅動程序需要"融合進內核里",因此需要在驅動程序中加入操作系統規定的接口,這些接口都是獨立於設備的。雖然操作系統為驅動程序設計者帶來了"麻煩",卻為應用程序設計者帶來了"便利"。

Linux下設備分為三類:字符設備、塊設備、網絡設備

字符設備是指必須以串行順序訪問的設備,比如觸屏;塊設備是指可以以任意順序訪問的設備,即以塊為單位進行操作,比如鍵盤;

字符設備不經過Cache,塊設備數據經過Cache。兩者的驅動程序設計差異較大。除了網絡設備外,字符設備和塊設備的驅動程序都被映射到文件系統中,通過調用open、read、write、close就能訪問。需要說明一點,C語言的fopen、fread、fwrite、fclose實際上也是做相應的系統調用。下圖是一個Linux下不同驅動種類的結構關系圖:

驅動開發所需知識儲備

做好驅動程序開發,需要開發者有良好的硬件基礎C語言基礎Linux內核基礎以及多任務並發和控制的基礎。

Linux上瀏覽內核源碼,推薦使用的工具是vim+cscope或者vim+ctags

有無操作系統的驅動程序區別

下面以led驅動為例,來說明有無操作系統的區別。

一般處理器有GPIO有兩個寄存器,即控制寄存器和數據寄存器。

無操作系統時,一般需要的函數有三個,即

LightInit()//設置控制寄存器為輸出模式

LightOn()//打開Led

LightOff()//熄滅Led


Linux操作系統下,可以使用字符設備驅動程序框架來編寫,根據Linux下的編程習慣,可以重新將其命名為light_init(),light_on,light_off

代碼結構如下:

//定義設備結構體

struct light_dev{

    struct cdev cdev;//字符設備結構體

    unsigned char value;

}

struct light_dev *light_devp;

int light_major = LIGHT_MAJOR;

 

MODULE_AUTHOR(" ");

MODULE_LICENSE(" ");

 

int light_open(struct inode *inode, struct file *filp){}

int light_release(struct inode *inode, struct file *filp){}

//讀寫設備

ssize_t light_read(struct file *filp, char _user *buf, size_t count, loff_t *f_pos){}

ssize_t light_write(struct file *filp, const char _user *buf, size_t count, loff_t *f_pos){}

//ioctl

int light_ioctl(struct inode *inode, struct file *flip, unsigned int cmd, unsigned long arg){}

struct file_operations light_fops={

    .ower = THIS_MODULE;

    .read = light_read;

    .write = light_write;

    .open = light_open;

    .release = light_release;

    .ioctl = light_ioctl;

}

//設置字符設備cdev結構體

static void light_setup_cdev(struct light_dev *dev, int index){}

//模塊加載函數

int light_init(void)

//模塊卸載函數

int light_cleanup(void)

 

module_init(light_init)

module_exit(light_cleanup)


這只是一個程序的結構,可以看出,與裸機的驅動程序相比,Linux下的驅動程序代碼復雜很多。

Linux設備驅動開發的硬件基礎

RISC和CISC計算機的區別:RISC指令周期短,代碼量大;CISC指令復雜,指令周期長,代碼量小。

目前ROM基本上都使用Flash,NOR(或非)和NAND(與非)是兩種主流的Flash。

NOR Flash的特點是可在芯片內執行代碼,接口簡單,不需要再加額外的控制芯片;NAND Flash的特點是塊訪問,接口需要再加入控制芯片,不能在芯片內部執行代碼。NAND 的發生位反轉的幾率大於NOR,在使用時,應采用錯誤檢測、錯誤改正算法(EDC/ECC)。Flash都是只能將1寫為0,在燒寫前,需要將Flash全置位,所有字節都為0xff。

DRAM以電荷形式存儲在電容器中,需要定期刷新;SDRAM也是DRAM的范疇。CAM是以內容尋址的特殊RAM,輸入需要查詢的數據,輸出數據地址和匹配標識,在數據檢索中有很大優勢。

*開漏輸出、集電極開路輸出是指需要上拉電阻才能輸出高電平。

驅動工程師對硬件比IC工程師要更宏觀。驅動工程師一般不需要分析時序圖,但是許多企業的驅動工程師還需要承擔電路板的調試工作,因此還需要了解一些電路時序的分析。

真實的電路必須滿足芯片手冊上的建立時間和保持時間的最低要求。查看datasheet時,沒有必要通讀全屏,要學會查看主要的信息內容。

Linux內核代碼結構

  • arch:與不同CPU架構相關的代碼
  • block:塊設備驅動IO調度
  • crypto:相關算法,包括加密、散列、壓縮、CRC校驗等算法
  • Document:內核各部分的注釋與解釋
  • drivers:驅動,不同驅動有不同的子文件夾
  • fs:文件系統
  • include:頭文件
  • init:初始化相關代碼
  • ipc:進程通信
  • kernel:內核部分
  • lib:庫文件代碼
  • mm:內存管理代碼
  • net:網絡相關代碼,實現各種協議
  • scripts:配置內核腳本
  • security:安全相關
  • sound:音頻設備驅動
  • usr:用於打包壓縮的cpio

Linux內核主要由進程調度內存管理虛擬文件系統網絡接口進程通信組成。

內核空間和用戶空間

CPU內部往往都實現了不同的操作模式。

比如ARM的七種工作模式:

  • 用戶模式(usr)絕大多數應用程序運行在此模式
  • 快速中斷模式(fiq)用於高速數據傳輸
  • 外部中斷模式(irp)用於通用中斷處理
  • 管理模式(svc)
  • 數據訪問模式(abt)
  • 系統模式(sys)
  • 未定義指令終止模式(und)

ARM+Linux采用SWI,從usr模式進入svc模式;x86處理器包含4個不同的特權級(0-3)下,Linux的用戶代碼運行在特權級3,系統內核運行在特權級0

Linux只能通過系統調用或者硬件中斷完成從用戶空間到內核空間的控制轉換。

內核的編譯與加載

在linux內核中增加程序需要完成以下3項工作:

將代碼加入到linux的相應目錄;

在目錄的Kconfig中加入相應的編譯配置選項;

在目錄的Makefile中增加新項目的編譯條目。

Linux下的C編碼風格

Windows下,宏全部大寫,變量第一個單詞小寫,其后每一個單詞的首字母都大寫,函數名每個單詞的首字母都大寫。

例如:

#define MYLINUX

int myLinux;

int MyLinux(void);

 而Linux 下,采用如下的風格:

#define MYLINUX

int my_linux;

int my_linux(void);

Linux代碼縮進使用8個字符,對於結構體、if等{不另起一行,函數另起一行。

do{}while(0)主要用於宏定義中,其使用完全是為了保證宏定義無錯誤的編譯。

goto只用於出現錯誤解決錯誤時。

參考資料:

《Linux設備驅動開發詳解》 宋寶華


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM