當前位置:首頁 » 操作系統 » linux驅動程序設計

linux驅動程序設計

發布時間: 2022-04-12 12:14:20

Ⅰ 深入理解linux驅動程序設計怎麼樣

《LINUX設備驅動程序(第3版)》詳細介紹了Linux。
如果您希望在Linux操作系統上支持計算機外部設備,或者在Linux上運行新的硬體,或者只是希望一般性地了解Linux內核的編程,就一定要閱讀本書。
本書描述了如何針對各種設備編寫驅動程序,而在過去,這些內容僅僅以口頭形式交流,或者零星出現在神秘的代碼注釋中。

Ⅱ 怎樣入門Linux驅動程序開發,如:網卡驅動。

網卡驅動不涉及網路編程,所謂驅動就是硬體和OS通信的橋梁。想學linux驅動,自己網上買塊開發板,買本linux設備驅動程序的書,然後從最簡單的key驅動開始,然後觸屏驅動,由淺入深。

Ⅲ 如何進行linux驅動程序設計

Linux是Unix操作系統的一種變種,在Linux下編寫驅動程序的原理和思想完全類似於其他的Unix系統,但它dos或window環境下的驅動程序有很大的區別。在Linux環境下設計驅動程序,思想簡潔,操作方便,功能也很強大,但是支持函數少

Ⅳ 嵌入式Linux驅動程序開發學習路線

關於這個方向,我認為大概分3個階段:
1、嵌入式linux上層應用,包括QT的GUI開發
2、嵌入式linux系統開發
3、嵌入式linux驅動開發

嵌入式目前主要面向的幾個操作系統是,LINUX,WINCE、VxWorks等等
Linux是開源免費的,而且其源代碼是開放的,更加適合我們學習嵌入式。

所以你可以嘗試以下路線:
(1) C語言是所有編程語言中的強者,單片機、DSP、類似ARM的種種晶元的編程都可以用C語言搞定),因此必須非常熟練的掌握。
推薦書籍:《The C Programming Language》 這本經典的教材是老外寫的,也有中譯版本。
(2) 操作系統原理,是必需的,如果你是計算機專業畢業那也就無所謂了,如果是非計算機專業的就必須找一本比較淺顯的計算機原理書籍看一看,把啥叫「進程」「線程」「系統調度」等等基本問題搞清楚。
(3)Linux操作系統就是用C語言編寫的,所以你也應該先學習下Linux方面的編程,只有你會應用了,才能近一步去了解其內核的精髓。
推薦書籍:《UNIX環境高級編程》(第2版)
(4) 了解ARM的架構,原理,以及其匯編指令,我們在嵌入式開發中,一般很少去寫匯編,但是最起碼的要求是能夠看懂arm匯編。
(5) 系統移植的時候,就需要你從最下層的bootloader開始,然後內核移植,文件系統移植等。而移植這部分對硬體的依賴是非常大的,其配置步驟也相對復雜,也沒有太多詳細資料。
(6) 驅動開發
linux驅動程序設計既是個極富有挑戰性的領域,又是一個博大精深的內容。
linux驅動程序設計本質是屬於linux內核編程范疇的,因而是對linux內核和內核編程是有要求的。在學習前你要想了解linux內核的組成,因為每一部分要詳細研究的話足夠可以擴展成一本厚書。

以上只不過是大概的框架,在實際的開發中還會涉及很多東西,比如:交叉編譯、makefile、shell腳本等等,所以說學習嵌入式的周期較長,門檻較高,自學的話更是需要較強的學習能力和專業功底。只要能堅持下來一定會取得成功!
…………………………………………
嵌入式非常難,看書的話比較晦澀難懂,不容易入門,我個人比較偏向於看視頻教程,因為有老師帶著比較容易入門。給看看一篇文章是關於一位專科生怎麼自學嵌入式的。

做個自我介紹,我07年考上一所很爛專科民辦的學校,學的是生物專業,具體的學校名稱我就不說出來獻丑了。09年我就輟學了,我在那樣的學校,一年學費要1萬多,但是根本沒有人學習,我實在看不到希望,我就退學了。
退學後我也迷茫,大專都沒有畢業,我真的不知道我能幹什麼,我在糾結著我能做什麼。所以輟學後我一段時間,我想去找工作,因為我比較沉默寡言,不是很會說話,我不適合去應聘做業務。我想應聘做技術的,可是處處碰壁。
一次偶然的機會,我才聽到嵌入式這個行業。那天我去新華書店,在計算機分類那邊想找本書學習。後來有個女孩子走過來,問我是不是讀計算機的,有沒有興趣學習嵌入式,然後給我介紹了一下嵌入式現在的火熱情況,告訴我學嵌入式多麼的有前景,給我了一份傳單,嵌入式培訓的廣告。聽了她的介紹,我心裡癢癢的,確實我很想去學會一門自己的技術,靠自己的雙手吃飯。
回家後,我就上網查了下嵌入式,確實是當今比較熱門的行業,也是比較好找工作的,工資也是相對比較高。我就下決心想學嵌入式了。於是我去找嵌入式培訓的相關信息,說真的,我也很迷茫,我不知道培訓是否真的能像他們宣傳的那樣好,所以我就想了解一段時間再做打算。
後來,我在網路知道看到一篇讓我很鼓舞的文章,是一個嵌入式高手介紹沒有基礎的朋友怎麼自學入門學嵌入式,文章寫的很好,包含了如何學習,該怎麼學習。他提到一個方法就是看視頻,因為看書實在太枯燥和費解的,很多我們也看不懂。這點我真的很認同,我自己看書往往看不了幾頁。
我在想,為什麼別人都能自學成才,我也可以的!我要相信自己,所以我就想自學,如果實在學不會我再去培訓。
主意一定,我就去搜索嵌入式的視頻,雖然零星找到一些嵌入式的視頻,但是都不系統,我是想找一個能夠告訴我該怎麼學的視頻,一套從入門到精通的視頻,一個比較完整的資料,最好能有老師教,不懂可以請教的。
後來我又找到一份很好的視頻,是在IT學習聯盟網站推出的一份視頻《零基礎嵌入式就業班》(喜歡《零基礎嵌入式就業班》的可以復制 sina.lt/qKh 粘貼瀏覽器按回車鍵即打開)。裡面的教程還不錯,很完整,可以讓我從基礎的開始學起。視頻比較便宜。
下面介紹下我的學習流程,希望對和我一樣完全沒有基礎的朋友有所幫助。
收到他們寄過來的光碟後,我就開始學習了,由於我沒有什麼基礎,我就從最簡單的C語言視頻教程學起,話說簡單,其實我還是很多不懂的,我只好請教他們,他們還是很熱心的,都幫我解決了。C語言我差不多學了一個禮拜,接下來我就學了linux的基本命令,我在他們提供linux虛擬機上都有做練習,敲linux的基本命令,寫簡單的C語言代碼,差不多也就三個禮拜。我每天都在不停的寫一些簡單的代碼,這樣一月後我基本掌握了C和linux的基本操作。
接下來我就去學習了人家的視頻的培訓教程,是整套的,和去參加培訓沒有多大的區別,這一看就是兩個月,學習了ARM的基本原理,學習嵌入式系統的概念,也掌握了嵌入式的環境的一些搭建,對linux也有更深層次的理解了,明白了嵌入式應用到底是怎麼做的,但是驅動我只是有一點點的了解,這個相對難一點,我想以後再慢慢啃。
這兩個月,除了吃飯睡覺,我幾乎都在學習。因為我知道幾乎沒有基礎,比別人差勁,我只能堅持努力著,我不能放棄,我必要要靠自己來養活自己,必須學好這門技術,然後我就把不懂的問題總結記下來,這樣慢慢積累了一段時間,我發現自己真的有點入門了。
最後的一個月,我就去看關於實踐部分的內容,了解嵌入式項目具體的開發流程,需要什麼樣的知識,我就開始准備這方面的知識,也就是學習這方面的視頻,同時他們建議我去找了找一些嵌入式面試的題目,為自己以後找工作做准備。我就到網上找了很多嵌入式的題目,把他們理解的記下來,這樣差不多准備了20天左右
我覺得自己差不多入門了,會做一些簡單的東西了。我就想去找工作看看,於是我就到51job瘋狂的投簡歷,因為我學歷的問題,專科沒有畢業,說真的,大公司沒有人會要我,所以我投的都是民營的小公司,我希望自己的努力有所回報。沒有想過幾天過後,就有面試了,但是第一次面試我失敗了,雖然我自認為筆試很好,因為我之前做了准備,但是他們的要求比較嚴格,需要有一年的項目經驗,所以我沒有被選中。
後來陸續面試了幾家公司,終於功夫不負有心人。我終於面試上的,是在閔行的一家民營的企業,公司規模比較小,我的職務是嵌入式linux應用開發,做安防產品的應用的。我想我也比較幸運,經理很看重我的努力,就決定錄用我,開的工資是3500一個月,雖然我知道在上海3500隻能過溫飽的生活,但是我想我足夠了。我至少不用每天都要靠父母養,我自己也能養活自己的。我想只要我繼續努力,我工資一定會翻倍的。
把本文寫出來,希望能讓和我一樣的沒有基礎的朋友有信心,其實我們沒有必要自卑,我們不比別人笨,只要我們肯努力,我們一樣會成功。

Ⅳ Linux驅動程序的工作原理

由於你的問題太長我只好轉載別人的手打的太累不好意思~~~
Linux是Unix***作系統的一種變種,在Linux下編寫驅動程序的原理和

思想完全類似於其他的Unix系統,但它dos或window環境下的驅動程序有很大的

區別.在Linux環境下設計驅動程序,思想簡潔,***作方便,功芤埠芮看?但是

支持函數少,只能依賴kernel中的函數,有些常用的***作要自己來編寫,而且調

試也不方便.本人這幾周來為實驗室自行研製的一塊多媒體卡編制了驅動程序,

獲得了一些經驗,願與Linux fans共享,有不當之處,請予指正.

以下的一些文字主要來源於khg,johnsonm的Write linux device driver,

Brennan's Guide to Inline Assembly,The Linux A-Z,還有清華BBS上的有關

device driver的一些資料. 這些資料有的已經過時,有的還有一些錯誤,我依

據自己的試驗結果進行了修正.

一. Linux device driver 的概念

系統調用是***作系統內核和應用程序之間的介面,設備驅動程序是***作系統

內核和機器硬體之間的介面.設備驅動程序為應用程序屏蔽了硬體的細節,這樣

在應用程序看來,硬體設備只是一個設備文件, 應用程序可以象***作普通文件

一樣對硬體設備進行***作.設備驅動程序是內核的一部分,它完成以下的功能:

1.對設備初始化和釋放.

2.把數據從內核傳送到硬體和從硬體讀取數據.

3.讀取應用程序傳送給設備文件的數據和回送應用程序請求的數據.

4.檢測和處理設備出現的錯誤.

在Linux***作系統下有兩類主要的設備文件類型,一種是字元設備,另一種是

塊設備.字元設備和塊設備的主要區別是:在對字元設備發出讀/寫請求時,實際

的硬體I/O一般就緊接著發生了,塊設備則不然,它利用一塊系統內存作緩沖區,

當用戶進程對設備請求能滿足用戶的要求,就返回請求的數據,如果不能,就調用請求函數來進行實際

的I/O***作.塊設備是主要針對磁碟等慢速設備設計的,以免耗費過多的CPU時間

來等待.

已經提到,用戶進程是通過設備文件來與實際的硬體打交道.每個設備文件都

都有其文件屬性(c/b),表示是字元設備還蔤強檣璞?另外每個文件都有兩個設

備號,第一個是主設備號,標識驅動程序,第二個是從設備號,標識使用同一個

設備驅動程序的不同的硬體設備,比如有兩個軟盤,就可以用從設備號來區分

他們.設備文件的的主設備號必須與設備驅動程序在登記時申請的主設備號

一致,否則用戶進程將無法訪問到驅動程序.

最後必須提到的是,在用戶進程調用驅動程序時,系統進入核心態,這時不再是

搶先式調度.也就是說,系統必須在你的驅動程序的子函數返回後才能進行其他

的工作.如果你的驅動程序陷入死循環,不幸的是你只有重新啟動機器了,然後就

是漫長的fsck.//hehe

(請看下節,實例剖析)

讀/寫時,它首先察看緩沖區的內容,如果緩沖區的數據

如何編寫Linux***作系統下的設備驅動程序

Roy G

二.實例剖析

我們來寫一個最簡單的字元設備驅動程序.雖然它什麼也不做,但是通過它

可以了解Linux的設備驅動程序的工作原理.把下面的C代碼輸入機器,你就會

獲得一個真正的設備驅動程序.不過我的kernel是2.0.34,在低版本的kernel

上可能會出現問題,我還沒測試過.//xixi

#define __NO_VERSION__

#include

#include

char kernel_version [] = UTS_RELEASE;

這一段定義了一些版本信息,雖然用處不是很大,但也必不可少.Johnsonm說所

有的驅動程序的開頭都要包含,但我看倒是未必.

由於用戶進程是通過設備文件同硬體打交道,對設備文件的***作方式不外乎就

是一些系統調用,如 open,read,write,close...., 注意,不是fopen, fread.,

但是如何把系統調用和驅動程序關聯起來呢?這需要了解一個非常關鍵的數據

結構:

struct file_operations {

int (*seek) (struct inode * ,struct file *, off_t ,int);

int (*read) (struct inode * ,struct file *, char ,int);

int (*write) (struct inode * ,struct file *, off_t ,int);

int (*readdir) (struct inode * ,struct file *, struct dirent * ,int);

int (*select) (struct inode * ,struct file *, int ,select_table *);

int (*ioctl) (struct inode * ,struct file *, unsined int ,unsigned long

int (*mmap) (struct inode * ,struct file *, struct vm_area_struct *);

int (*open) (struct inode * ,struct file *);

int (*release) (struct inode * ,struct file *);

int (*fsync) (struct inode * ,struct file *);

int (*fasync) (struct inode * ,struct file *,int);

int (*check_media_change) (struct inode * ,struct file *);

int (*revalidate) (dev_t dev);

}

這個結構的每一個成員的名字都對應著一個系統調用.用戶進程利用系統調用

在對設備文件進行諸如read/write***作時,系統調用通過設備文件的主設備號

找到相應的設備驅動程序,然後讀取這個數據結構相應的函數指針,接著把控制

權交給該函數.這是linux的設備驅動程序工作的基本原理.既然是這樣,則編寫

設備驅動程序的主要工作就是編寫子函數,並填充file_operations的各個域.

相當簡單,不是嗎?

下面就開始寫子程序.

#include

#include

#include

#include

#include

unsigned int test_major = 0;

static int read_test(struct inode *node,struct file *file,

char *buf,int count)

{

int left;

if (verify_area(VERIFY_WRITE,buf,count) == -EFAULT )

return -EFAULT;

for(left = count left > 0 left--)

{

__put_user(1,buf,1);

buf++;

}

return count;

}

這個函數是為read調用准備的.當調用read時,read_test()被調用,它把用戶的

緩沖區全部寫1.

buf 是read調用的一個參數.它是用戶進程空間的一個地址.但是在read_test

被調用時,系統進入核心態.所以不能使用buf這個地址,必須用__put_user(),

這是kernel提供的一個函數,用於向用戶傳送數據.另外還有很多類似功能的

函數.請參考.在向用戶空間拷貝數據之前,必須驗證buf是否可用.

這就用到函數verify_area.

static int write_tibet(struct inode *inode,struct file *file,

const char *buf,int count)

{

return count;

}

static int open_tibet(struct inode *inode,struct file *file )

{

MOD_INC_USE_COUNT;

return 0;

} static void release_tibet(struct inode *inode,struct file *file )

{

MOD_DEC_USE_COUNT;

}

這幾個函數都是空***作.實際調用發生時什麼也不做,他們僅僅為下面的結構

提供函數指針。

struct file_operations test_fops = {

NULL,

read_test,

write_test,

NULL, /* test_readdir */

NULL,

NULL, /* test_ioctl */

NULL, /* test_mmap */

open_test,

release_test, NULL, /* test_fsync */

NULL, /* test_fasync */

/* nothing more, fill with NULLs */

};

設備驅動程序的主體可以說是寫好了。現在要把驅動程序嵌入內核。驅動程序

可以按照兩種方式編譯。一種是編譯進kernel,另一種是編譯成模塊(moles),

如果編譯進內核的話,會增加內核的大小,還要改動內核的源文件,而且不能

動態的卸載,不利於調試,所以推薦使用模塊方式。

int init_mole(void)

{

int result;

result = register_chrdev(0, "test", &test_fops);

if (result < 0) {

printk(KERN_INFO "test: can't get major number ");

return result;

}

if (test_major == 0) test_major = result; /* dynamic */

return 0;

}

在用insmod命令將編譯好的模塊調入內存時,init_mole 函數被調用。在

這里,init_mole只做了一件事,就是向系統的字元設備表登記了一個字元

設備。register_chrdev需要三個參數,參數一是希望獲得的設備號,如果是

零的話,系統將選擇一個沒有被佔用的設備號返回。參數二是設備文件名,

參數三用來登記驅動程序實際執行***作的函數的指針。

如果登記成功,返回設備的主設備號,不成功,返回一個負值。

void cleanup_mole(void)

{

unregister_chrdev(test_major, "test");

}

在用rmmod卸載模塊時,cleanup_mole函數被調用,它釋放字元設備test

在系統字元設備表中佔有的表項。

一個極其簡單的字元設備可以說寫好了,文件名就叫test.c吧。

下面編譯

$ gcc -O2 -DMODULE -D__KERNEL__ -c test.c

得到文件test.o就是一個設備驅動程序。

如果設備驅動程序有多個文件,把每個文件按上面的命令行編譯,然後

ld -r file1.o file2.o -o molename.

驅動程序已經編譯好了,現在把它安裝到系統中去。

$ insmod -f test.o

如果安裝成功,在/proc/devices文件中就可以看到設備test,

並可以看到它的主設備號,。

要卸載的話,運行

$ rmmod test

下一步要創建設備文件。

mknod /dev/test c major minor

c 是指字元設備,major是主設備號,就是在/proc/devices里看到的。

用shell命令

$ cat /proc/devices | awk "\$2=="test" {print \$1}"

就可以獲得主設備號,可以把上面的命令行加入你的shell script中去。

minor是從設備號,設置成0就可以了。

我們現在可以通過設備文件來訪問我們的驅動程序。寫一個小小的測試程序。

#include

#include

#include

#include

main()

{

int testdev;

int i;

char buf[10];

testdev = open("/dev/test",O_RDWR);

if ( testdev == -1 )

{

printf("Cann't open file ");

exit(0);

}

read(testdev,buf,10);

for (i = 0; i < 10;i++)

printf("%d ",buf);

close(testdev);

}

編譯運行,看看是不是列印出全1 ?

以上只是一個簡單的演示。真正實用的驅動程序要復雜的多,要處理如中斷,

DMA,I/O port等問題。這些才是真正的難點。請看下節,實際情況的處理。

如何編寫Linux***作系統下的設備驅動程序

Roy G

三 設備驅動程序中的一些具體問題。

1. I/O Port.

和硬體打交道離不開I/O Port,老的ISA設備經常是佔用實際的I/O埠,

在linux下,***作系統沒有對I/O口屏蔽,也就是說,任何驅動程序都可以

對任意的I/O口***作,這樣就很容易引起混亂。每個驅動程序應該自己避免

誤用埠。

有兩個重要的kernel函數可以保證驅動程序做到這一點。

1)check_region(int io_port, int off_set)

這個函數察看系統的I/O表,看是否有別的驅動程序佔用某一段I/O口。

參數1:io埠的基地址,

參數2:io埠佔用的范圍。

返回值:0 沒有佔用, 非0,已經被佔用。

2)request_region(int io_port, int off_set,char *devname)

如果這段I/O埠沒有被佔用,在我們的驅動程序中就可以使用它。在使用

之前,必須向系統登記,以防止被其他程序佔用。登記後,在/proc/ioports

文件中可以看到你登記的io口。

參數1:io埠的基地址。

參數2:io埠佔用的范圍。

參數3:使用這段io地址的設備名。

在對I/O口登記後,就可以放心地用inb(), outb()之類的函來訪問了。

在一些pci設備中,I/O埠被映射到一段內存中去,要訪問這些埠就相當

於訪問一段內存。經常性的,我們要獲得一塊內存的物理地址。在dos環境下,

(之所以不說是dos***作系統是因為我認為DOS根本就不是一個***作系統,它實

在是太簡單,太不安全了)只要用段:偏移就可以了。在window95中,95ddk

提供了一個vmm 調用 _MapLinearToPhys,用以把線性地址轉化為物理地址。但

在Linux中是怎樣做的呢?

2 內存***作

在設備驅動程序中動態開辟內存,不是用malloc,而是kmalloc,或者用

get_free_pages直接申請頁。釋放內存用的是kfree,或free_pages. 請注意,

kmalloc等函數返回的是物理地址!而malloc等返回的是線性地址!關於

kmalloc返回的是物理地址這一點本人有點不太明白:既然從線性地址到物理

地址的轉換是由386cpu硬體完成的,那樣匯編指令的***作數應該是線性地址,

驅動程序同樣也不能直接使用物理地址而是線性地址。但是事實上kmalloc

返回的確實是物理地址,而且也可以直接通過它訪問實際的RAM,我想這樣可

以由兩種解釋,一種是在核心態禁止分頁,但是這好像不太現實;另一種是

linux的頁目錄和頁表項設計得正好使得物理地址等同於線性地址。我的想法

不知對不對,還請高手指教。

言歸正傳,要注意kmalloc最大隻能開辟128k-16,16個位元組是被頁描述符

結構佔用了。kmalloc用法參見khg.

內存映射的I/O口,寄存器或者是硬體設備的RAM(如顯存)一般佔用F0000000

以上的地址空間。在驅動程序中不能直接訪問,要通過kernel函數vremap獲得

重新映射以後的地址。

另外,很多硬體需要一塊比較大的連續內存用作DMA傳送。這塊內存需要一直

駐留在內存,不能被交換到文件中去。但是kmalloc最多隻能開辟128k的內存。

這可以通過犧牲一些系統內存的方法來解決。

具體做法是:比如說你的機器由32M的內存,在lilo.conf的啟動參數中加上

mem=30M,這樣linux就認為你的機器只有30M的內存,剩下的2M內存在vremap

之後就可以為DMA所用了。

請記住,用vremap映射後的內存,不用時應用unremap釋放,否則會浪費頁表。

3 中斷處理

同處理I/O埠一樣,要使用一個中斷,必須先向系統登記。

int request_irq(unsigned int irq ,

void(*handle)(int,void *,struct pt_regs *),

unsigned int long flags,

const char *device);

irq: 是要申請的中斷。

handle:中斷處理函數指針。

flags:SA_INTERRUPT 請求一個快速中斷,0 正常中斷。

device:設備名。

如果登記成功,返回0,這時在/proc/interrupts文件中可以看你請求的

中斷。

4一些常見的問題。

對硬體***作,有時時序很重要。但是如果用C語言寫一些低級的硬體***作

的話,gcc往往會對你的程序進行優化,這樣時序就錯掉了。如果用匯編寫呢,

gcc同樣會對匯編代碼進行優化,除非你用volatile關鍵字修飾。最保險的

辦法是禁止優化。這當然只能對一部分你自己編寫的代碼。如果對所有的代碼

都不優化,你會發現驅動程序根本無法裝載。這是因為在編譯驅動程序時要

用到gcc的一些擴展特性,而這些擴展特性必須在加了優化選項之後才能體現

出來。

關於kernel的調試工具,我現在還沒有發現有合適的。有誰知道請告訴我,

不勝感激。我一直都在printk列印調試信息,倒也還湊合。

關於設備驅動程序還有很多內容,如等待/喚醒機制,塊設備的編寫等。

我還不是很明白,不敢亂說。

Ⅵ 解釋一下linux驅動程序結構框架及工作原理

一、Linux device driver 的概念

系統調用是操作系統內核和應用程序之間的介面,設備驅動程序是操作系統內核和機器硬體之間的介面。設備驅動程序為應用程序屏蔽了硬體的細節,這樣在應用程序看來,硬體設備只是一個設備文件,應用程序可以象操作普通文件一樣對硬體設備進行操作。設備驅動程序是內核的一部分,它完成以下的功能:

1、對設備初始化和釋放;

2、把數據從內核傳送到硬體和從硬體讀取數據;

3、讀取應用程序傳送給設備文件的數據和回送應用程序請求的數據;

4、檢測和處理設備出現的錯誤。

在Linux操作系統下有三類主要的設備文件類型,一是字元設備,二是塊設備,三是網路設備。字元設備和塊設備的主要區別是:在對字元設備發出讀/寫請求時,實際的硬體I/O一般就緊接著發生了,塊設備則不然,它利用一塊系統內存作緩沖區,當用戶進程對設備請求能滿足用戶的要求,就返回請求的數據,如果不能,就調用請求函數來進行實際的I/O操作。塊設備是主要針對磁碟等慢速設備設計的,以免耗費過多的CPU時間來等待。

已經提到,用戶進程是通過設備文件來與實際的硬體打交道。每個設備文件都都有其文件屬性(c/b),表示是字元設備還是塊設備?另外每個文件都有兩個設備號,第一個是主設備號,標識驅動程序,第二個是從設備號,標識使用同一個設備驅動程序的不同的硬體設備,比如有兩個軟盤,就可以用從設備號來區分他們。設備文件的的主設備號必須與設備驅動程序在登記時申請的主設備號一致,否則用戶進程將無法訪問到驅動程序。

最後必須提到的是,在用戶進程調用驅動程序時,系統進入核心態,這時不再是搶先式調度。也就是說,系統必須在你的驅動程序的子函數返回後才能進行其他的工作。如果你的驅動程序陷入死循環,不幸的是你只有重新啟動機器了,然後就是漫長的fsck。

二、實例剖析

我們來寫一個最簡單的字元設備驅動程序。雖然它什麼也不做,但是通過它可以了解Linux的設備驅動程序的工作原理。把下面的C代碼輸入機器,你就會獲得一個真正的設備驅動程序。

由於用戶進程是通過設備文件同硬體打交道,對設備文件的操作方式不外乎就是一些系統調用,如 open,read,write,close…, 注意,不是fopen, fread,但是如何把系統調用和驅動程序關聯起來呢?這需要了解一個非常關鍵的數據結構:

STruct file_operatiONs {

int (*seek) (struct inode * ,struct file *, off_t ,int);

int (*read) (struct inode * ,struct file *, char ,int);

int (*write) (struct inode * ,struct file *, off_t ,int);

int (*readdir) (struct inode * ,struct file *, struct dirent * ,int);

int (*select) (struct inode * ,struct file *, int ,select_table *);

int (*ioctl) (struct inode * ,struct file *, unsined int ,unsigned long);

int (*mmap) (struct inode * ,struct file *, struct vm_area_struct *);

int (*open) (struct inode * ,struct file *);

int (*release) (struct inode * ,struct file *);

int (*fsync) (struct inode * ,struct file *);

int (*fasync) (struct inode * ,struct file *,int);

int (*check_media_change) (struct inode * ,struct file *);

int (*revalidate) (dev_t dev);

}

這個結構的每一個成員的名字都對應著一個系統調用。用戶進程利用系統調用在對設備文件進行諸如read/write操作時,系統調用通過設備文件的主設備號找到相應的設備驅動程序,然後讀取這個數據結構相應的函數指針,接著把控制權交給該函數。這是linux的設備驅動程序工作的基本原理。既然是這樣,則編寫設備驅動程序的主要工作就是編寫子函數,並填充file_operations的各個域。

下面就開始寫子程序。

#include <linux/types.h> 基本的類型定義

#include <linux/fs.h> 文件系統使用相關的頭文件

#include <linux/mm.h>

#include <linux/errno.h>

#include <asm/segment.h>

unsigned int test_major = 0;

static int read_test(struct inode *inode,struct file *file,char *buf,int count)

{

int left; 用戶空間和內核空間

if (verify_area(VERIFY_WRITE,buf,count) == -EFAULT )

return -EFAULT;

for(left = count ; left > 0 ; left--)

{

__put_user(1,buf,1);

buf++;

}

return count;

}

這個函數是為read調用准備的。當調用read時,read_test()被調用,它把用戶的緩沖區全部寫1。buf 是read調用的一個參數。它是用戶進程空間的一個地址。但是在read_test被調用時,系統進入核心態。所以不能使用buf這個地址,必須用__put_user(),這是kernel提供的一個函數,用於向用戶傳送數據。另外還有很多類似功能的函數。請參考,在向用戶空間拷貝數據之前,必須驗證buf是否可用。這就用到函數verify_area。為了驗證BUF是否可以用。

static int write_test(struct inode *inode,struct file *file,const char *buf,int count)

{

return count;

}

static int open_test(struct inode *inode,struct file *file )

{

MOD_INC_USE_COUNT; 模塊計數加以,表示當前內核有個設備載入內核當中去

return 0;

}

static void release_test(struct inode *inode,struct file *file )

{

MOD_DEC_USE_COUNT;

}

這幾個函數都是空操作。實際調用發生時什麼也不做,他們僅僅為下面的結構提供函數指針。

struct file_operations test_fops = {?

read_test,

write_test,

open_test,

release_test,

};

設備驅動程序的主體可以說是寫好了。現在要把驅動程序嵌入內核。驅動程序可以按照兩種方式編譯。一種是編譯進kernel,另一種是編譯成模塊(moles),如果編譯進內核的話,會增加內核的大小,還要改動內核的源文件,而且不能動態的卸載,不利於調試,所以推薦使用模塊方式。

int init_mole(void)

{

int result;

result = register_chrdev(0, "test", &test_fops); 對設備操作的整個介面

if (result < 0) {

printk(KERN_INFO "test: can't get major number\n");

return result;

}

if (test_major == 0) test_major = result; /* dynamic */

return 0;

}

在用insmod命令將編譯好的模塊調入內存時,init_mole 函數被調用。在這里,init_mole只做了一件事,就是向系統的字元設備表登記了一個字元設備。register_chrdev需要三個參數,參數一是希望獲得的設備號,如果是零的話,系統將選擇一個沒有被佔用的設備號返回。參數二是設備文件名,參數三用來登記驅動程序實際執行操作的函數的指針。

如果登記成功,返回設備的主設備號,不成功,返回一個負值。

void cleanup_mole(void)

{

unregister_chrdev(test_major,"test");

}

在用rmmod卸載模塊時,cleanup_mole函數被調用,它釋放字元設備test在系統字元設備表中佔有的表項。

一個極其簡單的字元設備可以說寫好了,文件名就叫test.c吧。

下面編譯 :

$ gcc -O2 -DMODULE -D__KERNEL__ -c test.c –c表示輸出制定名,自動生成.o文件

得到文件test.o就是一個設備驅動程序。

如果設備驅動程序有多個文件,把每個文件按上面的命令行編譯,然後

ld ?-r ?file1.o ?file2.o ?-o ?molename。

驅動程序已經編譯好了,現在把它安裝到系統中去。

$ insmod ?–f ?test.o

如果安裝成功,在/proc/devices文件中就可以看到設備test,並可以看到它的主設備號。要卸載的話,運行 :

$ rmmod test

下一步要創建設備文件。

mknod /dev/test c major minor

c 是指字元設備,major是主設備號,就是在/proc/devices里看到的。

用shell命令

$ cat /proc/devices

就可以獲得主設備號,可以把上面的命令行加入你的shell script中去。

minor是從設備號,設置成0就可以了。

我們現在可以通過設備文件來訪問我們的驅動程序。寫一個小小的測試程序。

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

main()

{

int testdev;

int i;

char buf[10];

testdev = open("/dev/test",O_RDWR);

if ( testdev == -1 )

{

printf("Cann't open file \n");

exit(0);

}

read(testdev,buf,10);

for (i = 0; i < 10;i++)

printf("%d\n",buf[i]);

close(testdev);

}

編譯運行,看看是不是列印出全1

以上只是一個簡單的演示。真正實用的驅動程序要復雜的多,要處理如中斷,DMA,I/O port等問題。這些才是真正的難點。上述給出了一個簡單的字元設備驅動編寫的框架和原理,更為復雜的編寫需要去認真研究LINUX內核的運行機制和具體的設備運行的機制等等。希望大家好好掌握LINUX設備驅動程序編寫的方法。

Ⅶ 如何系統的學習Linux驅動開發

在學習之前一直對驅動開發非常的陌生,感覺有點神秘。不知道驅動開發和普通的程序開發究竟有什麼不同;它的基本框架又是什麼樣的;他的開發環境有什麼特殊的地方;以及怎麼寫編寫一個簡單的字元設備驅動前編譯載入,下面我就對這些問題一個一個的介紹。

一、驅動的基本框架

1.那麼究竟什麼是驅動程序,它有什麼用呢:

l驅動是硬體設備與應用程序之間的一個中間軟體層

l它使得某個特定硬體能夠響應一個定義良好的內部編程介面,同時完全隱蔽了設備的工作細節

l用戶通過一組與具體設備無關的標准化的調用來完成相應的操作

l驅動程序的任務就是把這些標准化的系統調用映射到具體設備對於實際硬體的特定操作上

l驅動程序是內核的一部分,可以使用中斷、DMA等操作

l驅動程序在用戶態和內核態之間傳遞數據

2.Linux驅動的基本框架

3.Linux下設備驅動程序的一般可以分為以下三類

1)字元設備

a)所有能夠象位元組流一樣訪問的設備都通過字元設備來實現

b)它們被映射為文件系統中的節點,通常在/dev/目錄下面

c)一般要包含open read write close等系統調用的實現

2)塊設備

d)通常是指諸如磁碟、內存、Flash等可以容納文件系統的存儲設備。

e)塊設備也是通過文件系統來訪問,與字元設備的區別是:內核管理數據的方式不同

f)它允許象字元設備一樣以位元組流的方式來訪問,也可一次傳遞任意多的位元組。

3)網路介面設備

g)通常它指的是硬體設備,但有時也可能是一個軟體設備(如回環介面loopback),它們由內核中網路子系統驅動,負責發送和接收數據包。

h)它們的數據傳送往往不是面向流的,因此很難將它們映射到一個文件系統的節點上。

二、怎麼搭建一個驅動的開發環境

因為驅動是要編譯進內核,在啟動內核時就會驅動此硬體設備;或者編譯生成一個.o文件,當應用程序需要時再動態載入進內核空間運行。因此編譯任何一個驅動程序都要鏈接到內核的源碼樹。所以搭建環境的第一步當然是建內核源碼樹

1.怎麼建內核源碼樹

a)首先看你的系統有沒有源碼樹,在你的/lib/ moles目錄下會有內核信息,比如我當前的系統里有兩個版本:

#ls /lib/ moles

2.6.15-rc72.6.21-1.3194.fc7

查看其源碼位置:

## ll /lib/moles/2.6.15-rc7/build

lrwxrwxrwx 1 root root 27 2008-04-28 19:19 /lib/moles/2.6.15-rc7/build -> /root/xkli/linux-2.6.15-rc7

發現build是一個鏈接文件,其所對應的目錄就是源碼樹的目錄。但現在這里目標目錄已經是無效的了。所以得自己重新下載

b)下載並編譯源碼樹

有很多網站上可以下載,但官方網址是:

http://www.kernel.org/pub/linux/kernel/v2.6/

下載完後當然就是解壓編譯了

# tar –xzvf linux-2.6.16.54.tar.gz

#cd linux-2.6.16.54

## make menuconfig (配置內核各選項,如果沒有配置就無法下一步編譯,這里可以不要改任何東西)

#make

如果編譯沒有出錯。那麼恭喜你。你的開發環境已經搭建好了

三、了解驅動的基本知識

1.設備號

1)什麼是設備號呢?我們進系統根據現有的設備來講解就清楚了:

#ls -l /dev/

crwxrwxrwx 1 root root1,3 2009-05-11 16:36 null

crw------- 1 root root4,0 2009-05-11 16:35 systty

crw-rw-rw- 1 root tty5,0 2009-05-11 16:36 tty

crw-rw---- 1 root tty4,0 2009-05-11 16:35 tty0

在日期前面的兩個數(如第一列就是1,3)就是表示的設備號,第一個是主設備號,第二個是從設備號

2)設備號有什麼用呢?

l傳統上,主編號標識設備相連的驅動.例如, /dev/null和/dev/zero都由驅動1來管理,而虛擬控制台和串口終端都由驅動4管理

l次編號被內核用來決定引用哪個設備.依據你的驅動是如何編寫的自己區別

3)設備號結構類型以及申請方式

l在內核中, dev_t類型(在中定義)用來持有設備編號,對於2.6.0內核, dev_t是32位的量, 12位用作主編號, 20位用作次編號.

l能獲得一個dev_t的主或者次編號方式:

MAJOR(dev_t dev); //主要

MINOR(dev_t dev);//次要

l但是如果你有主次編號,需要將其轉換為一個dev_t,使用: MKDEV(int major, int minor);

4)怎麼在程序中分配和釋放設備號

在建立一個字元驅動時需要做的第一件事是獲取一個或多個設備編號來使用.可以達到此功能的函數有兩個:

l一個是你自己事先知道設備號的

register_chrdev_region,在中聲明:

int register_chrdev_region(dev_t first, unsigned int count, char *name);

first是你要分配的起始設備編號. first的次編號部分常常是0,count是你請求的連續設備編號的總數. name是應當連接到這個編號范圍的設備的名子;它會出現在/proc/devices和sysfs中.

l第二個是動態動態分配設備編號

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);

使用這個函數, dev是一個只輸出的參數,它在函數成功完成時持有你的分配范圍的第一個數. fisetminor應當是請求的第一個要用的次編號;它常常是0. count和name參數如同給request_chrdev_region的一樣.

5)設備編號的釋放使用

不管你是採用哪些方式分配的設備號。使用之後肯定是要釋放的,其方式如下:

void unregister_chrdev_region(dev_t first, unsigned int count);

6)

2.驅動程序的二個最重要數據結構

1)file_operation

倒如字元設備scull的一般定義如下:
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};

file_operation也稱為設備驅動程序介面

定義在,是一個函數指針的集合.每個打開文件(內部用一個file結構來代表)與它自身的函數集合相關連(通過包含一個稱為f_op的成員,它指向一個file_operations結構).這些操作大部分負責實現系統調用,因此,命名為open, read,等等

2)File

定義位於include/fs.h

struct file結構與驅動相關的成員

lmode_t f_mode標識文件的讀寫許可權

lloff_t f_pos當前讀寫位置

lunsigned int_f_flag文件標志,主要進行阻塞/非阻塞型操作時檢查

lstruct file_operation * f_op文件操作的結構指針

lvoid * private_data驅動程序一般將它指向已經分配的數據

lstruct dentry* f_dentry文件對應的目錄項結構

3.字元設備注冊

1)內核在內部使用類型struct cdev的結構來代表字元設備.在內核調用你的設備操作前,必須編寫分配並注冊一個或幾個這些結構.有2種方法來分配和初始化一個這些結構.

l如果你想在運行時獲得一個獨立的cdev結構,可以這樣使用:

struct cdev *my_cdev = cdev_alloc();

my_cdev->ops = &my_fops;

l如果想將cdev結構嵌入一個你自己的設備特定的結構;你應當初始化你已經分配的結構,使用:

void cdev_init(struct cdev *cdev, struct file_operations *fops);

2)一旦cdev結構建立,最後的步驟是把它告訴內核,調用:

int cdev_add(struct cdev *dev, dev_t num, unsigned int count);

說明:dev是cdev結構, num是這個設備響應的第一個設備號, count是應當關聯到設備的設備號的數目.常常count是1,但是有多個設備號對應於一個特定的設備的情形.

3)為從系統去除一個字元設備,調用:

void cdev_del(struct cdev *dev);

4.open和release

Ⅷ 如何編寫Linux 驅動程序

以裝載和卸載模塊為例:

1、首先輸入代碼

#include <linux/init.h>

#include <linux/mole.h>

Ⅸ 如何編寫Linux操作系統的設備驅動程序

Linux是Unix操作系統的一種變種,在Linux下編寫驅動程序的原理和
思想完全類似於其他的Unix系統,但它dos或window環境下的驅動程序有很大的
區別.在Linux環境下設計驅動程序,思想簡潔,操作方便,功能也很強大,但是
支持函數少,只能依賴kernel中的函數,有些常用的操作要自己來編寫,而且調
試也不方便.本人這幾周來為實驗室自行研製的一塊多媒體卡編制了驅動程序,
獲得了一些經驗,願與Linux fans共享,有不當之處,請予指正.
以下的一些文字主要來源於khg,johnsonm的Write linux device driver,
Brennan's Guide to Inline Assembly,The Linux A-Z,還有清華BBS上的有關
device driver的一些資料. 這些資料有的已經過時,有的還有一些錯誤,我依
據自己的試驗結果進行了修正.
一. Linux device driver 的概念
系統調用是操作系統內核和應用程序之間的介面,設備驅動程序是操作系統
內核和機器硬體之間的介面.設備驅動程序為應用程序屏蔽了硬體的細節,這樣
在應用程序看來,硬體設備只是一個設備文件, 應用程序可以象操作普通文件
一樣對硬體設備進行操作.設備驅動程序是內核的一部分,它完成以下的功能:
1.對設備初始化和釋放.
2.把數據從內核傳送到硬體和從硬體讀取數據.
3.讀取應用程序傳送給設備文件的數據和回送應用程序請求的數據.
4.檢測和處理設備出現的錯誤.
在Linux操作系統下有兩類主要的設備文件類型,一種是字元設備,另一種是
塊設備.字元設備和塊設備的主要區別是:在對字元設備發出讀/寫請求時,實際
的硬體I/O一般就緊接著發生了,塊設備則不然,它利用一塊系統內存作緩沖區,
當用戶進程對設備請求讀/寫時,它首先察看緩沖區的內容,如果緩沖區的數據
能滿足用戶的要求,就返回請求的數據,如果不能,就調用請求函數來進行實際
的I/O操作.塊設備是主要針對磁碟等慢速設備設計的,以免耗費過多的CPU時間
來等待.
已經提到,用戶進程是通過設備文件來與實際的硬體打交道.每個設備文件都
都有其文件屬性(c/b),表示是字元設備還蔤強檣璞?另外每個文件都有兩個設
備號,第一個是主設備號,標識驅動程序,第二個是從設備號,標識使用同一個
設備驅動程序的不同的硬體設備,比如有兩個軟盤,就可以用從設備號來區分
他們.設備文件的的主設備號必須與設備驅動程序在登記時申請的主設備號
一致,否則用戶進程將無法訪問到驅動程序.
最後必須提到的是,在用戶進程調用驅動程序時,系統進入核心態,這時不再是
搶先式調度.也就是說,系統必須在你的驅動程序的子函數返回後才能進行其他
的工作.如果你的驅動程序陷入死循環,不幸的是你只有重新啟動機器了,然後就

Ⅹ Linux驅動開發入門與實戰的目錄

第1篇 linux驅動開發基礎
第1章 linux驅動開發概述 2
1.1 linux設備驅動的基本概念 2
1.1.1 設備驅動程序概述 2
1.1.2 設備驅動程序的作用 2
1.1.3 設備驅動的分類 3
1.2 linux操作系統與驅動的關系 4
1.3 linux驅動程序開發 4
1.3.1 用戶態和內核態 5
1.3.2 模塊機制 5
1.3.3 編寫設備驅動程序需要了解的知識 6
1.4 編寫設備驅動程序的注意事項 6
1.4.1 應用程序開發與驅動程序開發的差異 6
1.4.2 gun c開發驅動程序 7
1.4.3 不能使用c庫開發驅動程序 7
1.4.4 沒有內存保護機制 7
1.4.5 小內核棧 8
1.4.6 重視可移植性 8
1.5 linux驅動的發展趨勢 9
1.5.1 linux驅動的發展 9
.1.5.2 驅動的應用 9
1.5.3 相關學習資源 9
1.6 小結 10
第2章 嵌入式處理器和開發板簡介 11
2.1 處理器的選擇 11
2.1.1 處理器簡述 11
2.1.2 處理器的種類 11
2.2 arm處理器 13
2.2.1 arm處理器簡介 14
2.2.2 arm處理器系列 14
2.2.3 arm處理器的應用 16
2.2.4 arm處理器的選型 16
2.2.5 arm處理器選型舉例 19
2.3 s3c2440開發板 20
2.3.1 s3c2440開發板簡介 20
2.3.2 s3c2440開發板的特性 20
2.4 小結 22
第3章 構建嵌入式驅動程序開發環境 23
3.1 虛擬機和linux安裝 23
3.1.1 在windows上安裝虛擬機 23
3.1.2 在虛擬機上安裝linux 27
3.1.3 設置共享目錄 28
3.2 代碼閱讀工具source insight 29
3.2.1 source insight簡介 30
3.2.2 閱讀源代碼 30
3.3 小結 33
第4章 構建嵌入式linux操作系統 34
4.1 linux操作系統的介紹 34
4.1.1 linux操作系統 34
4.1.2 linux操作系統的優點 35
4.2 linux內核子系統 36
4.2.1 進程管理 36
4.2.2 內存管理 37
4.2.3 文件系統 37
4.2.4 設備管理 37
4.2.5 網路功能 38
4.3 linux源代碼結構分析 38
4.3.1 arch目錄 38
4.3.2 drivers目錄 39
4.3.3 fs目錄 39
4.3.4 其他目錄 40
4.4 內核配置選項 41
4.4.1 配置編譯過程 41
4.4.2 常規配置 42
4.4.3 模塊配置 44
4.4.4 塊設備層配置 44
4.4.5 cpu類型和特性配置 45
4.4.6 電源管理配置 47
4.4.7 匯流排配置 49
4.4.8 網路配置 50
4.4.9 設備驅動配置 53
4.4.10 文件系統配置 60
4.5 嵌入式文件系統基礎知識 62
4.5.1 嵌入式文件系統 62
4.5.2 嵌入式系統的存儲介質 63
4.5.3 jffs文件系統 64
4.5.4 yaffs文件系統 64
4.6 構建根文件系統 64
4.6.1 根文件系統概述 65
4.6.2 linux根文件系統目錄結構 65
4.6.3 busybox構建根文件系統 66
4.7 小結 71
第5章 構建第一個驅動程序 72
5.1 開發環境配置之內核升級 72
5.1.1 為什麼升級內核 72
5.1.2 內核升級 73
5.1.3 make menconfig的注意事項 75
5.2 hello world驅動程序 77
5.2.1 驅動模塊的組成 77
5.2.2 hello world模塊 78
5.2.3 編譯hello world模塊 79
5.2.4 模塊的操作 81
5.2.5 hello world模塊載入後文件系統的變化 82
5.3 模塊參數和模塊之間通信 83
5.3.1 模塊參數 83
5.3.2 模塊的文件格式elf 83
5.3.3 模塊之間的通信 84
5.3.4 模塊之間的通信實例 85
5.4 將模塊加入內核 88
5.4.1 向內核添加模塊 88
5.4.2 kconfig 88
5.4.3 kconfig的語法 89
5.4.4 應用實例:在內核中新增加add_sub模塊 92
5.4.5 對add_sub模塊進行配置 94
5.5 小結 95
第6章 簡單的字元設備驅動程序 96
6.1 字元設備驅動程序框架 96
6.1.1 字元設備和塊設備 96
6.1.2 主設備號和次設備號 97
6.1.3 申請和釋放設備號 98
6.2 初識cdev結構 99
6.2.1 cdev結構體 99
6.2.2 file_operations結構體 101
6.2.3 cdev和file_operations結構體的關系 102
6.2.4 inode結構體 103
6.3 字元設備驅動的組成 103
6.3.1 字元設備載入和卸載函數 103
6.3.2 file_operations結構體和其成員函數 104
6.3.3 驅動程序與應用程序的數據交換 105
6.3.4 字元設備驅動程序組成小結 106
6.4 virtualdisk字元設備驅動 106
6.4.1 virtualdisk的頭文件、宏和設備結構體 106
6.4.2 載入和卸載驅動程序 107
6.4.3 cdev的初始化和注冊 108
6.4.4 打開和釋放函數 109
6.4.5 讀寫函數 110
6.4.6 seek()函數 111
6.4.7 ioctl()函數 113
6.5 小結 113
第2篇 linux驅動開發核心技術
第7章 設備驅動中的並發控制 116
7.1 並發與競爭 116
7.2 原子變數操作 116
7.2.1 原子變數操作 116
7.2.2 原子整型操作 117
7.2.3 原子位操作 119
7.3 自旋鎖 120
7.3.1 自旋鎖概述 120
7.3.2 自旋鎖的使用 120
7.3.3 自旋鎖的使用注意事項 122
7.4 信號量 122
7.4.1 信號量概述 122
7.4.2 信號量的實現 123
7.4.3 信號量的使用 123
7.4.4 自旋鎖與信號量的對比 125
7.5 完成量 126
7.5.1 完成量概述 126
7.5.2 完成量的實現 126
7.5.3 完成量的使用 127
7.6 小結 128
第8章 設備驅動中的阻塞和同步機制 129
8.1 阻塞和非阻塞 129
8.2 等待隊列 130
8.2.1 等待隊列概述 130
8.2.3 等待隊列的實現 130
8.2.3 等待隊列的使用 131
8.3 同步機制實驗 132
8.3.1 同步機制設計 132
8.3.2 實驗驗證 136
8.4 小結 137
第9章 中斷與時鍾機制 138
9.1 中斷簡述 138
9.1.1 中斷的概念 138
9.1.2 中斷的宏觀分類 139
9.1.3 中斷產生的位置分類 140
9.1.4 同步和非同步中斷 140
9.1.5 中斷小結 140
9.2 中斷的實現過程 141
9.2.1 中斷信號線(irq) 141
9.2.2 中斷控制器 141
9.2.3 中斷處理過程 142
9.2.4 中斷的安裝與釋放 142
9.3 按鍵中斷實例 144
9.3.1 按鍵設備原理圖 144
9.3.2 有寄存器設備和無寄存器設備 144
9.3.3 按鍵設備相關埠寄存器 145
9.4 按鍵中斷實常式序分析 147
9.4.1 按鍵驅動程序組成 147
9.4.2 初始化函數s3c2440_buttons_init() 147
9.4.3 中斷處理函數isr_button() 148
9.4.4 退出函數s3c2440_buttons_exit() 149
9.5 時鍾機制 150
9.5.1 時間度量 150
9.5.2 時間延時 150
9.6 小結 151
第10章 內外存訪問 152
10.1 內存分配 152
10.1.1 kmalloc()函數 152
10.1.2 vmalloc()函數 153
10.1.3 後備高速緩存 155
10.2 頁面分配 156
10.2.1 內存分配 156
10.2.2 物理地址和虛擬地址之間的轉換 159
10.3 設備i/o埠的訪問 160
10.3.1 linux i/o埠讀寫函數 160
10.3.2 i/o內存讀寫 160
10.3.3 使用i/o埠 164
10.4 小結 166
第3篇 linux驅動開發實用實戰
第11章 設備驅動模型 168
11.1 設備驅動模型概述 168
11.1.1 設備驅動模型的功能 168
11.1.2 sysfs文件系統 169
11.1.3 sysfs文件系統的目錄結構 170
11.2 設備驅動模型的核心數據結構 171
11.2.1 kobject結構體 171
11.2.2 設備屬性kobj_type 175
11.3 注冊kobject到sysfs中的實例 179
11.3.1 設備驅動模型結構 179
11.3.2 kset集合 180
11.3.3 kset與kobject的關系 181
11.3.4 kset相關的操作函數 182
11.3.5 注冊kobject到sysfs中的實例 183
11.3.6 實例測試 187
11.4 設備驅動模型的三大組件 188
11.4.1 匯流排 188
11.4.2 匯流排屬性和匯流排方法 192
11.4.3 設備 194
11.4.4 驅動 196
11.5 小結 198
第12章 rtc實時時鍾驅動 199
12.1 rtc實時時鍾硬體原理 199
12.1.1 rtc實時時鍾 199
12.1.2 rtc實時時鍾的功能 199
12.1.2 rtc實時時鍾的工作原理 201
12.2 rtc實時時鍾架構 205
12.2.1 載入卸載函數 205
12.2.2 rtc實時時鍾的平台驅動 206
12.2.3 rtc驅動探測函數 207
12.2.4 rtc實時時鍾的使能函數s3c_rtc_enable() 210
12.2.5 rtc實時時鍾設置頻率函數s3c_rtc_setfreq() 211
12.2.6 rtc設備注冊函數 rtc_device_register() 212
12.3 rtc文件系統介面 214
12.3.1 文件系統介面rtc_class_ops 214
12.3.2 rtc實時時鍾打開函數s3c_rtc_open() 215
12.3.3 rtc實時時鍾關閉函數s3c_rtc_release() 216
12.3.4 rtc實時時鍾獲得時間函數s3c_rtc_gettime() 216
12.3.5 rtc實時時鍾設置時間函數s3c_rtc_settime() 218
12.3.6 rtc驅動探測函數s3c_rtc_getalarm() 219
12.3.7 rtc實時時鍾設置報警時間函數s3c_rtc_setalarm() 220
12.3.8 rtc設置脈沖中斷使能函數s3c_rtc_setpie() 222
12.3.9 rtc時鍾脈沖中斷判斷函數s3c_rtc_proc() 222
12.4 小結 223
第13章 看門狗驅動程序 224
13.1 看門狗硬體原理 224
13.1.1 看門狗 224
13.1.2 看門狗工作原理 224
13.2 平台設備模型 226
13.2.1 平台設備模型 226
13.2.2 平台設備 227
13.2.3 平台設備驅動 229
13.2.4 平台設備驅動的注冊和注銷 230
13.2.5 混雜設備 231
13.2.6 混雜設備的注冊和注銷 232
13.3 看門狗設備驅動程序分析 232
13.3.1 看門狗驅動程序的一些變數定義 232
13.3.2 看門狗模塊的載入和卸載函數 233
13.3.3 看門狗驅動程序探測函數 234
13.3.4 設置看門狗復位時間函數s3c2410wdt_set_heartbeat() 235
13.3.5 看門狗的開始函數s3c2410wdt_start()和停止函數
s3c2410wdt_ stop() 237
13.3.6 看門狗驅動程序移除函數s3c2410wdt_remove() 238
13.3.7 平台設備驅動s3c2410wdt_driver中的其他重要函數 238
13.3.8 混雜設備的file_operations中的函數 239
13.3.9 看門狗中斷處理函數s3c2410wdt_irq() 242
13.4 小結 243
第14章 iic設備驅動程序 244
14.1 iic設備的匯流排及其協議 244
14.1.1 iic匯流排的特點 244
14.1.2 iic匯流排的信號類型 245
14.1.3 iic匯流排的數據傳輸 245
14.2 iic設備的硬體原理 246
14.3 iic設備驅動程序的層次結構 247
14.3.1 iic設備驅動的概述 248
14.3.2 iic設備層 248
14.3.3 i2c_driver和i2c_client的關系 251
14.3.4 iic匯流排層 251
14.3.5 iic設備層和匯流排層的關系 253
14.3.6 寫iic設備驅動的步驟 253
14.4 iic子系統的初始化 254
14.4.1 iic子系統初始化函數i2c_init() 254
14.4.2 iic子系統退出函數i2c_exit () 254
14.5 適配器驅動程序 255
14.5.1 s3c2440對應的適配器結構體 255
14.5.2 iic適配器載入函數i2c_add_adapter() 257
14.5.3 idr機制 257
14.5.4 適配器卸載函數i2c_del_adapter() 260
14.5.5 iic匯流排通信方法s3c24xx_i2c_algorithm結構體 260
14.5.6 適配器的傳輸函數s3c24xx_i2c_doxfer() 262
14.5.7 適配器的中斷處理函數s3c24xx_i2c_irq() 265
14.5.8 位元組傳輸函數i2s_s3c_irq_nextbyte() 267
14.5.9 適配器傳輸停止函數s3c24xx_i2c_stop() 269
14.5.10 中斷處理函數的一些輔助函數 270
14.6 iic設備層驅動程序 270
14.6.1 iic設備驅動模塊載入和卸載 271
14.6.2 探測函數s3c24xx_i2c_probe() 272
14.6.3 移除函數s3c24xx_i2c_remove() 274
14.6.4 控制器初始化函數s3c24xx_i2c_init() 275
14.6.5 設置控制器數據發送頻率函數s3c24xx_i2c_clockrate() 276
14.7 小結 278
第15章 lcd設備驅動程序 279
15.1 framebuffer概述 279
15.1.1 framebuffer的概念 279
15.1.2 framebuffer與應用程序的交互 280
15.1.3 framebuffer顯示原理 280
15.1.4 lcd顯示原理 281
15.2 framebuffer的結構分析 281
15.2.1 framebuffer架構和其關系 281
15.2.2 framebuffer驅動程序的實現 282
15.2.3 framebuffer架構及其關系 283
15.3 lcd驅動程序分析 288
15.3.1 lcd模塊的載入和卸載函數 288
15.3.2 lcd驅動程序的平台數據 290
15.3.3 lcd模塊的探測函數 291
15.3.4 移除函數 295
15.4 小結 296
第16章 觸摸屏設備驅動程序 297
16.1 觸摸屏設備工作原理 297
16.1.1 觸摸屏設備概述 297
16.1.2 觸摸屏設備的類型 297
16.1.3 電阻式觸摸屏 298
16.2 觸摸屏設備硬體結構 298
16.2.1 s3c2440觸摸屏介面概述 298
16.2.2 s3c2440觸摸屏介面的工作模式 299
16.2.3 s3c2440觸摸屏設備寄存器 300
16.3 觸摸屏設備驅動程序分析 303
16.3.1 觸摸屏設備驅動程序組成 303
16.3.2 s3c2440觸摸屏驅動模塊的載入和卸載函數 304
16.3.3 s3c2440觸摸屏驅動模塊的探測函數 305
16.3.4 觸摸屏設備配置 308
16.3.5 觸摸屏設備中斷處理函數 309
16.3.6 s3c2440觸摸屏驅動模塊的remove()函數 314
16.4 測試觸摸屏驅動程序 314
16.5 小結 316
第17章 輸入子系統設計 317
17.1 input子系統入門 317
17.1.1 簡單的實例 317
17.1.2 注冊函數input_register_device() 319
17.1.3 向子系統報告事件 323
17.2 handler注冊分析 328
17.2.1 輸入子系統的組成 328
17.2.2 input_handler結構體 328
17.2.3 注冊input_handler 329
17.2.4 input_handle結構體 330
17.2.5 注冊input_handle 331
17.3 input子系統 332
17.3.1 子系統初始化函數input_init() 333
17.3.2 文件打開函數input_open_file() 333
17.4 evdev輸入事件驅動分析 335
17.4.1 evdev的初始化 335
17.4.2 evdev設備的打開 337
17.5 小結 340
第18章 塊設備驅動程序 341
18.1 塊設備簡介 341
18.1.1 塊設備總體概述 341
18.1.2 塊設備的結構 342
18.2 塊設備驅動程序的架構 344
18.2.1 塊設備載入過程 344
18.2.2 塊設備卸載過程 345
18.3 通用塊層 346
18.3.1 通用塊層 346
18.3.2 alloc_disk()函數對應的gendisk結構體 346
18.3.3 塊設備的注冊和注銷 349
18.3.4 請求隊列 349
18.3.5 設置gendisk屬性中的block_device_operations結構體 350
18.4 不使用請求隊列的塊設備驅動 351
18.4.1 不使用請求隊列的塊設備驅動程序的組成 352
18.4.2 宏定義和全局變數 352
18.4.3 載入函數 353
18.4.4 卸載函數 355
18.4.5 自定義請求處理函數 355
18.4.6 驅動的測試 356
18.5 i/o調度器 359
18.5.1 數據從內存到磁碟的過程 359
18.5.2 塊i/o請求(bio) 360
18.5.3 請求結構(request) 363
18.5.4 請求隊列(request_queue) 364
18.5.5 請求隊列、請求結構、bio等之間的關系 365
18.5.6 四種調度演算法 365
18.6 自定義i/o調度器 367
18.6.1 virtual_blkdev塊設備的缺陷 367
18.6.2 指定noop調度器 368
18.6.3 virtual_blkdev的改進實例 368
18.6.4 編譯和測試 369
18.7 脫離i/o調度器 370
18.7.1 請求隊列中的bio處理函數 370
18.7.2 通用塊層函數調用關系 371
18.7.3 對virtual_blkdev塊設備的改進 373
18.7.4 編譯和測試 376
18.8 塊設備的物理結構 377
18.8.1 為virtual_blkdev塊設備添加分區 377
18.8.2 對新的virtual_blkdev代碼的分析 378
18.8.3 編譯和測試 379
18.8.4 分區數的計算 381
18.8.5 設置virtual_blkdev的結構 382
18.8.6 編譯和測試 384
18.9 小結 387
第19章 usb設備驅動程序 389
19.1 usb概述 389
19.1.1 usb概念 389
19.1.2 usb的特點 390
19.1.3 usb匯流排拓撲結構 391
19.1.4 usb驅動總體架構 391
19.2 usb設備驅動模型 395
19.2.1 usb驅動初探 395
19.2.2 usb設備驅動模型 397
19.2.3 usb驅動結構usb_driver 399
19.3 usb設備驅動程序 404
19.3.1 usb設備驅動載入和卸載函數 404
19.3.2 探測函數probe()的參數usb_interface 405
19.3.3 usb協議中的設備 406
19.3.4 端點的傳輸方式 412
19.3.5 設置 413
19.3.6 探測函數storage_probe() 415
19.4 獲得usb設備信息 418
19.4.1 設備關聯函數associate_dev() 418
19.4.2 獲得設備信息函數get_device_info() 419
19.4.3 得到傳輸協議get_transport()函數 420
19.4.4 獲得協議信息函數get_protocol() 421
19.4.5 獲得管道信息函數get_pipes() 422
19.5 資源的初始化 425
19.5.1 storage_probe()函數調用過程 425
19.5.2 資源獲取函數usb_stor_acquire_resources() 426
19.5.3 usb請求塊(urb) 427
19.6 控制子線程 430
19.6.1 控制線程 431
19.6.2 掃描線程usb_stor_scan_thread() 433
19.6.3 獲得lun函數usb_stor_bulk_max_lun() 434
19.7 小結 441

熱點內容
安卓平板如何實現電腦雙擊 發布:2024-09-28 21:27:11 瀏覽:359
德育php 發布:2024-09-28 21:24:36 瀏覽:16
企業密信如何登錄伺服器ld 發布:2024-09-28 21:22:52 瀏覽:462
通過ip不能訪問網站 發布:2024-09-28 21:21:47 瀏覽:522
c語言取整數部分 發布:2024-09-28 21:17:59 瀏覽:65
進來學編程 發布:2024-09-28 21:01:17 瀏覽:965
ios微信記錄怎麼轉移到安卓手機 發布:2024-09-28 20:49:15 瀏覽:710
新建的access資料庫如何設置密碼 發布:2024-09-28 20:41:21 瀏覽:214
文件夾防刪除 發布:2024-09-28 20:16:13 瀏覽:687
安卓美團賬號怎麼退出 發布:2024-09-28 20:04:52 瀏覽:852