linux字元設備驅動
Ⅰ 在虛擬機linux操作系統上怎麼編寫一個簡單的字元設備驅動程序
下載 virtualbox 下載一個 linux iso
用virtualbox 建立虛擬系統 配置好 載入iso 啟動安裝
VMware安裝完畢後,利用它可以建立多個虛擬機,每新建一個虛擬機,就會要求你建立一個配置文件。這個配置文件實際上相當於新電腦的「硬體配置」,你可以在配置文件中決定虛擬機的硬碟如何配置,內存多大.准備運行哪種操作系統,是否有網路等。配置Linux虛擬機的步驟如下。
(1)選擇File菜單下的「New Virtual Machine」出現新虛擬機向導後單擊「下一步」,選擇「Typical」典型安裝。
(2)再單擊「下一步」,在選擇操作系統界面的「Guest Operation System」中選擇 「Linux」,然後單擊Version對應的下拉菜單選擇具體的Linux版本, 此處我們選擇「Red Hat LinuX」。
(3)單擊「下一步」進入安裝目錄選擇界面。該界面上面的文本框是系統的名字,保持默認值即可,下面的文本框需要選擇虛擬機操作系統的安裝位置。
(4)根據需要選擇好後,單擊「下一步」按鈕,出現設置虛擬機內存大小的界面。Linux9.O對內存的要求是:文本模式至少需要64MB;圖形化模式至少需要128MB,推薦使用192MB。此處我們選擇192MB:
(5)單擊「下一步」按鈕進入網路連接方式選擇界面。VMware有四種網路設置方式,一般來說,Bridged方式使虛擬機就像網路內一台獨立的計算機一樣,最為方便好用(四種連網方式的區別大家可參考VMware的有關資料)。在此、我們選擇Brided方式。
(6)單擊「下一步」按鈕進入虛擬磁碟的設置界面。 這里有三種方式(Create a new virtual disk、Use an existing virtual disk、Use a physical disk)可供選擇、建議初學者選擇「Create a new Virtual disk」,其含義是新建一個虛擬磁碟,該虛擬磁碟只是主機—卜的一個獨立文件。
(7)在「下一步」中設置磁碟大小。在此、我們採用默認的4GB。
(8)單擊「下一步」進入文件存放路徑選擇界面。
在此界面可單擊Browse按鈕進行設置。此處我們使用默認值,單擊「完成」按鈕。
至此,完成一個虛擬機的配置。
Ⅱ 請問Linux驅動程序中,字元設備驅動,塊設備驅動以及網路驅動的區別和比較,學的時候需要注意些什麼
可以講字元設備和塊設備歸為一類,它們都是可以順序/隨機地進行讀取和存儲的單元,二者驅動主要在於塊設備需要具體的burst實現,對訪問也有一定的邊界要求。其他的沒有什麼不同。
網路設備是特殊設備的驅動,它負責接收和發送幀數據,可能是物理幀,也可能是ip數據包,這些特性都有網路驅動決定。它並不存在於/dev下面,所以與一般的設備不同。網路設備是一個net_device結構,並通過register_netdev注冊到系統里,最後通過ifconfig -a的命令就能看到。
不論是什麼設備,設備級的數據傳輸都是基本類似的,內核里的數據表示只是一部分,更重要的是匯流排的訪問,例如串列spi,i2c,並行dma等。
Ⅲ 在Linux內核中,注冊字元設備驅動程序的函數是
字元設備驅動程序框架 1、寫出open、write函數 2、告訴內核 1)、定義一個struct file_operations結構並填充好 static struct file_operations first_drv_fops = { .owner = THIS_MODULE, /* 這是一個宏,推向編譯模塊時自動創建的__this_mole變數 */ .open = first_drv_open, .write = first_drv_write, }; 2)、把struct file_operations結構體告訴內核 major = register_chrdev(0, "first_drv", &first_drv_fops); // 注冊, 告訴內核相關參數:第一個,設備號,0自動分配主設備號,否則為主設備號0-255 第二個:設備名第二個:struct file_operations結構體 4)、register_chrdev由誰調用(入口函數調用) static int first_drv_init(void) 5)、入口函數須使用內核宏來修飾 mole_init(first_drv_init); mole_init會定義一個結構體,這個結構體裡面有一個函數指針指向first_drv_init這個函數,當我們載入或安裝一個驅動時,內核會自動找到這個結構體,然後調用裡面的函數指針,這個函數指針指向first_drv_init這個函數,first_drv_init這個函數就是把struct file_operations結構體告訴內核 6)、有入口函數就有出口函數 mole_exit(first_drv_exit); 最後加上協議 MODULE_LICENSE("GPL"); 3、mdev根據系統信息自動創建設備節點: 每次寫驅動都要手動創建設備文件過於麻煩,使用設備管理文件系統則方便很多。在2.6的內核以前一直使用的是devfs,但是它存在許多缺陷。它創建了大量的設備文件,其實這些設備更本不存在。而且設備與設備文件的映射具有不確定性,比如U盤即可能對應sda,又可能對應sdb。沒有足夠的主/輔設備號。2.6之後的內核引入了sysfs文件系統,它掛載在/sys上,配合udev使用,可以很好的完成devfs的功能,並彌補了那些缺點。(這里說一下,當今內核已經使用netlink了)。 udev是用戶空間的一個應用程序,在嵌入式中用的是mdev,mdev在busybox中。mdev是udev的精簡版。首先在busybox中添加支持mdev的選項: Linux System Utilities ---> [*] mdev [*] Support /etc/mdev.conf [*] Support subdirs/symlinks [*] Support regular expressions substitutions when renaming device [*] Support command execution at device addition/removal 然後修改/etc/init.d/rcS: echo /sbin/mdev > /proc/sys/kernel/hotplug /sbin/mdev -s 執行mdev -s :以『-s』為參數調用位於 /sbin目錄寫的mdev(其實是個鏈接,作用是傳遞參數給/bin目錄下的busybox程序並調用它),mdev掃描 /sys/class 和 /sys/block 中所有的類設備目錄,如果在目錄中含有名為「dev」的文件,且文件中包含的是設備號,則mdev就利用這些信息為這個設備在/dev 下創建設備節點文件。一般只在啟動時才執行一次 「mdev -s」。熱插拔事件:由於啟動時運行了命 令:echo /sbin/mdev > /proc/sys/kernel/hotplug ,那麼當有熱插拔事件產生時,內核就會調用位於 /sbin目錄的mdev。這時mdev通過環境變數中的 ACTION 和 DEVPATH,來確定此次熱插拔事件的動作以及影響了/sys中的那個目錄。接著會看看這個目錄中是否「dev」的屬性文件,如果有就利用這些信息為 這個設備在/dev 下創建設備節點文件重新打包文件系統,這樣/sys目錄,/dev目錄就有東西了下面是create_class的原型: #define class_create(owner, name) / ({ / static struct lock_class_key __key; / __class_create(owner, name, &__key); / }) extern struct class * __must_check __class_create(struct mole *owner, const char *name, struct lock_class_key *key); class_destroy的原型如下: extern void class_destroy(struct class *cls); device_create的原型如下: extern struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) __attribute__((format(printf, 5, 6))); device_destroy的原型如下: extern void device_destroy(struct class *cls, dev_t devt); 具體使用如下,可參考後面的實例: static struct class *firstdrv_class; static struct class_device *firstdrv_class_dev; firstdrv_class = class_create(THIS_MODULE, "firstdrv"); firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */ class_device_unregister(firstdrv_class_dev); class_destroy(firstdrv_class); 下面再來看一下應用程序如何找到這個結構體的在應用程序中我們使用open打開一個設備:如:open(/dev/xxx, O_RDWR); xxx有一個屬性,如字元設備為c,後面為讀寫許可權,還有主設備名、次設備名,我們注冊時 通過register_chrdev(0, "first_drv", &first_drv_fops)(有主設備號,設備名,struct file_operations結構體)將first_drv_fops結構體注冊到內核數組chrdev中去的,結構體中有open,write函數,那麼應用程序如何找到它的,事實上是根據打開的這個文件的屬性中的設備類型及主設備號在內核數組chrdev裡面找到我們注冊的first_drv_fops,實例代碼: #include #include #include #include #include #include #include #include #include #include static struct class *firstdrv_class; static struct class_device *firstdrv_class_dev; volatile unsigned long *gpfcon = NULL; volatile unsigned long *gpfdat = NULL; static int first_drv_open(struct inode *inode, struct file *file) { //printk("first_drv_open\n"); /* 配置GPF4,5,6為輸出 */ *gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2))); *gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2))); return 0; } static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { int val; //printk("first_drv_write\n"); _from_user(&val, buf, count); // _to_user(); if (val == 1) { // 點燈 *gpfdat &= ~((1<<4) | (1<<5) | (1<<6)); } else { // 滅燈 *gpfdat |= (1<<4) | (1<<5) | (1<<6); } return 0; } static struct file_operations first_drv_fops = { .owner = THIS_MODULE, /* 這是一個宏,推向編譯模塊時自動創建的__this_mole變數 */ .open = first_drv_open, .write = first_drv_write, }; int major; static int first_drv_init(void) { major = register_chrdev(0, "first_drv", &first_drv_fops); // 注冊, 告訴內核 firstdrv_class = class_create(THIS_MODULE, "firstdrv"); firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */ gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); gpfdat = gpfcon + 1; return 0; } static void first_drv_exit(void) { unregister_chrdev(major, "first_drv"); // 卸載 class_device_unregister(firstdrv_class_dev); class_destroy(firstdrv_class); iounmap(gpfcon); } mole_init(first_drv_init); mole_exit(first_drv_exit); MODULE_LICENSE("GPL"); 編譯用Makefile文件 KERN_DIR = /work/system/linux-2.6.22.6 all: make -C $(KERN_DIR) M=`pwd` moles clean: make -C $(KERN_DIR) M=`pwd` moles clean rm -rf moles.order obj-m += first_drv.o 測試程序: #include #include #include #include /* firstdrvtest on * firstdrvtest off */ int main(int argc, char **argv) { int fd; int val = 1; fd = open("/dev/xyz", O_RDWR); if (fd < 0) { printf("can't open!\n"); } if (argc != 2) { printf("Usage :\n"); printf("%s \n", argv[0]); return 0; } if (strcmp(argv[1], "on") == 0) { val = 1; } else { val = 0; } write(fd, &val, 4); return 0; }
Ⅳ linux的設備驅動一般分為幾類各有什麼特點
大致分為三類,字元驅動,塊設備驅動,網路設備驅動。
字元設備可以看成是用位元組流存取的文件
塊設備則可以看成是可以任意存取位元組數的字元設備,在應用上只是內核管理數據方式不同
網路設備可以是一個硬體設備,或者是軟體設備,他沒有相應的read write,它是面向流的一種特殊設備。
Ⅳ Linux輸入設備驅動
輸入設備(如按鍵、鍵盤、觸摸屏、滑鼠等)是典型的字元設備,其一般的工作機理是底層在按鍵、觸摸等動作發送時產生一個中斷(或驅動通過Timer定時查詢),然後CPU通過SPI、I-C或外部存儲器匯流排讀取鍵值、坐標等數據,並將它們放入一個緩沖區,字元設備驅動管理該緩沖區,而驅動的read ()介面讓用戶可以讀取鍵值、坐標等數據。顯然,在這些工作中,只是中斷、讀鍵值/坐標值是與設備相關的,而輸入事件的緩沖區管理以及字元設備驅動的file operations介面則對輸入設備是通用的。基於此,內核設計了輸入子系統,由核心層處理公共的工作。drivers/input/keyboardgpio_keys.c基於input架構實現了一個通用的GPIO按鍵驅動。該驅動是基於platform_driver架構的,名為「gpio-keys」。它將與硬體相關的信息(如使用的GPIO號,按下和抬起時的電平等)屏蔽在板文件platform_device的platform_data中,因此該驅動可應用於各個處理器,具有良好的跨平台性。GPIO按鍵驅動通過input_event () 、input_sync()這樣的函數來匯報按鍵事件以及同步事件。從底層的GPIO按鍵驅動可以看出,該驅動中沒有任何file_operations的動作,也沒有各種IO模型,注冊進入系統也用的是input_register_device ()這樣的與input相關的API。這是由於與Linux VFS介面的這一部分代碼全部都在drivers/input/evdev.c中實現了。
Ⅵ 如何編寫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、將驅動程序文件bcm5700src.rpm復制到一個臨時目錄中,並在此目錄中運行以下命令;
2、運行以下命令切換到驅動目錄中;
3、此目錄中會生成一個名字為bcm5700.spec的文件,運行以下命令對驅動程序進行編譯;
4、運行以下命令切換到RPM目錄中;
5、運行以下命令安裝驅動程序;
6、運行以下命令載入驅動模塊;
7、運行kudzu命令,系統會自動搜索到硬體,進行配置即可。
linux是文件型系統,在linux中,一切皆文件,所有硬體都會在對應的目錄(/dev)下面用相應的文件表示。 文件系統的linux下面,都有對於文件與這些設備關聯的,訪問這些文件就可以訪問實際硬體。 通過訪問文件去操作硬體設備,一切都會簡單很多,不需要再調用各種復雜的介面。 直接讀文件,寫文件就可以向設備發送、接收數據。 按照讀寫存儲數據方式,我們可以把設備分為以下幾種:字元設備(character device)、塊設備(Block device)和網路設備( network interface)。
字元設備(character device):指應用程序採用字元流方式訪問的設備。這些設備節點通常為傳真、虛擬終端和串口數據機、鍵盤之類設備提供流通信服務, 它通常只支持順序訪問。字元設備在實現時,大多不使用緩存器。系統直接從設備讀取/寫入每一個字元。
塊設備(Block device):通常支持隨機存取和定址,並使用緩存器,支持mount文件系統。典型的塊設備有硬碟、SD卡、快閃記憶體等,但此類設備一般不需要自己開發,linux對此提過了大部分的驅動。
網路設備(network interface):是一種特殊設備,它並不存在於/dev下面,主要用於網路數據的收發。網路驅動同塊驅動最大的不同在於網路驅動非同步接受外界數據,而塊驅動只對內核的請求作出響應。
上述設備中,字元設備驅動程序適合於大多數簡單的硬體設備,算是各類驅動程序中最簡單的一類,一般也是從這類驅動開始學習,然後再開始學習採用IIC、SPI等通訊介面的一些設備驅動。可以基於此類驅動調試LKT和LCS系列加密晶元。注意7位IIC地址是0x28。
Ⅷ 請教:linux 字元設備驅動IIC進不了中斷
如何編寫Linux設備驅動程序回想學習Linux操作系統已經有近一年的時間了,前前後後,零零碎碎的一路學習過來,也該試著寫的東西了。也算是給自己能留下一點記憶和回憶吧!由於完全是自學的,以下內容若有不當之處,還請大家多指教。Linux是Unix操作系統的一種變種,在Linux下編寫驅動程序的原理和思想完全類似於其他的Unix系統,但它dos或window環境下的驅動程序有很大的區別。在Linux環境下設計驅動程序,思想簡潔,操作方便,功能也很強大,但是支持函數少,只能依賴kernel中的函數,有些常用的操作要自己來編寫,而且調試也不方便。以下的一些文字主要來源於khg,johnsonm的Writelinuxdevicedriver,Brennan'sGuidetoInlineAssembly,TheLinuxA-Z,還有清華BBS上的有關devicedriver的一些資料。一、Linuxdevicedriver的概念系統調用是操作系統內核和應用程序之間的介面,設備驅動程序是操作系統內核和機器硬體之間的介面。設備驅動程序為應用程序屏蔽了硬體的細節,這樣在應用程序看來,硬體設備只是一個設備文件,應用程序可以象操作普通文件一樣對硬體設備進行操作。設備驅動程序是內核的一部分,它完成以下的功能:1、對設備初始化和釋放。2、把數據從內核傳送到硬體和從硬體讀取數據。3、讀取應用程序傳送給設備文件的數據和回送應用程序請求的數據。4、檢測和處理設備出現的錯誤。在Linux操作系統下有三類主要的設備文件類型,一是字元設備,二是塊設備,三是網路設備。字元設備和塊設備的主要區別是:在對字元設備發出讀/寫請求時,實際的硬體I/O一般就緊接著發生了,塊設備則不然,它利用一塊系統內存作緩沖區,當用戶進程對設備請求能滿足用戶的要求,就返回請求的數據,如果不能,就調用請求函數來進行實際的I/O操作。塊設備是主要針對磁碟等慢速設備設計的,以免耗費過多的CPU時間來等待。已經提到,用戶進程是通過設備文件來與實際的硬體打交道。每個設備文件都都有其文件屬性(c/b),表示是字元設備還是塊設備?另外每個文件都有兩個設備號,第一個是主設備號,標識驅動程序,第二個是從設備號,標識使用同一個設備驅動程序的不同的硬體設備,比如有兩個軟盤,就可以用從設備號來區分他們。設備文件的的主設備號必須與設備驅動程序在登記時申請的主設備號一致,否則用戶進程將無法訪問到驅動程序。最後必須提到的是,在用戶進程調用驅動程序時,系統進入核心態,這時不再是搶先式調度。也就是說,系統必須在你的驅動程序的子函數返回後才能進行其他的工作。如果你的驅動程序陷入死循環,不幸的是你只有重新啟動機器了,然後就是漫長的fsck。讀/寫時,它首先察看緩沖區的內容,如果緩沖區的數據未被處理,則先處理其中的內容。如何編寫Linux操作系統下的設備驅動程序二、實例剖析我們來寫一個最簡單的字元設備驅動程序。雖然它什麼也不做,但是通過它可以了解Linux的設備驅動程序的工作原理。把下面的C代碼輸入機器,你就會獲得一個真正的設備驅動程序。#define__NO_VERSION__#include#includecharkernel_version[]=UTS_RELEASE;這一段定義了一些版本信息,雖然用處不是很大,但也必不可少。Johnsonm說所有的驅動程序的開頭都要包含,一般來講最好使用。由於用戶進程是通過設備文件同硬體打交道,對設備文件的操作方式不外乎就是一些系統調用,如open,read,write,close…,注意,不是fopen,fread,但是如何把系統調用和驅動程序關聯起來呢?這需要了解一個非常關鍵的數據結構:structfile_operations{int(*seek)(structinode*,structfile*,off_t,int);int(*read)(structinode*,structfile*,char,int);int(*write)(structinode*,structfile*,off_t,int);int(*readdir)(structinode*,structfile*,structdirent*,int);int(*select)(structinode*,structfile*,int,select_table*);int(*ioctl)(structinode*,structfile*,unsinedint,unsignedlong);int(*mmap)(structinode*,structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structinode*,structfile*);int(*fasync)(structinode*,structfile*,int);int(*check_media_change)(structinode*,structfile*);int(*revalidate)(dev_tdev);}這個結構的每一個成員的名字都對應著一個系統調用。用戶進程利用系統調用在對設備文件進行諸如read/write操作時,系統調用通過設備文件的主設備號找到相應的設備驅動程序,然後讀取這個數據結構相應的函數指針,接著把控制權交給該函數。這是linux的設備驅動程序工作的基本原理。既然是這樣,則編寫設備驅動程序的主要工作就是編寫子函數,並填充file_operations的各個域。下面就開始寫子程序。#include#include#include#include#include#includeunsignedinttest_major=0;staticintread_test(structinode*node,structfile*file,char*buf,intcount){intleft;if(verify_area(VERIFY_WRITE,buf,count)==-EFAULT)return-EFAULT;for(left=count;left>0;left--){__put_user(1,buf,1);buf++;}returncount;}這個函數是為read調用准備的。當調用read時,read_test()被調用,它把用戶的緩沖區全部寫1。buf是read調用的一個參數。它是用戶進程空間的一個地址。但是在read_test被調用時,系統進入核心態。所以不能使用buf這個地址,必須用__put_user(),這是kernel提供的一個函數,用於向用戶傳送數據。另外還有很多類似功能的函數。請參考Robert著的《Linux內核設計與實現》(第二版)。然而,在向用戶空間拷貝數據之前,必須驗證buf是否可用。這就用到函數verify_area。staticintwrite_tibet(structinode*inode,structfile*file,constchar*buf,intcount){returncount;}staticintopen_tibet(structinode*inode,structfile*file){MOD_INC_USE_COUNT;return0;}staticvoidrelease_tibet(structinode*inode,structfile*file){MOD_DEC_USE_COUNT;}這幾個函數都是空操作。實際調用發生時什麼也不做,他們僅僅為下面的結構提供函數指針。structfile_operationstest_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*//*nothingmore,fillwithNULLs*/};這樣,設備驅動程序的主體可以說是寫好了。現在要把驅動程序嵌入內核。驅動程序可以按照兩種方式編譯。一種是編譯進kernel,另一種是編譯成模塊(moles),如果編譯進內核的話,會增加內核的大小,還要改動內核的源文件,而且不能動態的卸載,不利於調試,所以推薦使用模塊方式。intinit_mole(void){intresult;result=register_chrdev(0,"test",&test_fops);if(result#include#include#includemain(){inttestdev;inti;charbuf[10];testdev=open("/dev/test",O_RDWR);if(testdev==-1){printf("Cann'topenfile\n");exit(0);}read(testdev,buf,10);for(i=0;i<10;i++)printf("%d\n",buf[i]);close(testdev);}編譯運行,看看是不是列印出全1?以上只是一個簡單的演示。真正實用的驅動程序要復雜的多,要處理如中斷,DMA,I/Oport等問題。這些才是真正的難點。請看下節,實際情況的處理。如何編寫Linux操作系統下的設備驅動程序三、設備驅動程序中的一些具體問題1。I/OPort。和硬體打交道離不開I/OPort,老的ISA設備經常是佔用實際的I/O埠,在linux下,操作系統沒有對I/O口屏蔽,也就是說,任何驅動程序都可對任意的I/O口操作,這樣就很容易引起混亂。每個驅動程序應該自己避免誤用埠。有兩個重要的kernel函數可以保證驅動程序做到這一點。1)check_region(intio_port,intoff_set)這個函數察看系統的I/O表,看是否有別的驅動程序佔用某一段I/O口。參數1:I/O埠的基地址,參數2:I/O埠佔用的范圍。返回值:0沒有佔用,非0,已經被佔用。2)request_region(intio_port,intoff_set,char*devname)如果這段I/O埠沒有被佔用,在我們的驅動程序中就可以使用它。在使用之前,必須向系統登記,以防止被其他程序佔用。登記後,在/proc/ioports文件中可以看到你登記的I/O口。參數1:io埠的基地址。參數2:io埠佔用的范圍。參數3:使用這段io地址的設備名。在對I/O口登記後,就可以放心地用inb(),outb()之類的函來訪問了。在一些pci設備中,I/O埠被映射到一段內存中去,要訪問這些埠就相當於訪問一段內存。經常性的,我們要獲得一塊內存的物理地址。2。內存操作在設備驅動程序中動態開辟內存,不是用malloc,而是kmalloc,或者用get_free_pages直接申請頁。釋放內存用的是kfree,或free_pages。請注意,kmalloc等函數返回的是物理地址!注意,kmalloc最大隻能開辟128k-16,16個位元組是被頁描述符結構佔用了。內存映射的I/O口,寄存器或者是硬體設備的RAM(如顯存)一般佔用F0000000以上的地址空間。在驅動程序中不能直接訪問,要通過kernel函數vremap獲得重新映射以後的地址。另外,很多硬體需要一塊比較大的連續內存用作DMA傳送。這塊程序需要一直駐留在內存,不能被交換到文件中去。但是kmalloc最多隻能開辟128k的內存。這可以通過犧牲一些系統內存的方法來解決。3。中斷處理同處理I/O埠一樣,要使用一個中斷,必須先向系統登記。intrequest_irq(unsignedintirq,void(*handle)(int,void*,structpt_regs*),unsignedintlongflags,constchar*device);irq:是要申請的中斷。handle:中斷處理函數指針。flags:SA_INTERRUPT請求一個快速中斷,0正常中斷。device:設備名。如果登記成功,返回0,這時在/proc/interrupts文件中可以看你請求的中斷。4。一些常見的問題。對硬體操作,有時時序很重要(關於時序的具體問題就要參考具體的設備晶元手冊啦!比如網卡晶元RTL8139)。但是如果用C語言寫一些低級的硬體操作的話,gcc往往會對你的程序進行優化,這樣時序會發生錯誤。如果用匯編寫呢,gcc同樣會對匯編代碼進行優化,除非用volatile關鍵字修飾。最保險的法是禁止優化。這當然只能對一部分你自己編寫的代碼。如果對所有的代碼都不優化,你會發現驅動程序根本無法裝載。這是因為在編譯驅動程序時要用到gcc的一些擴展特性,而這些擴展特性必須在加了優化選項之後才能體現出來。寫在後面:學習Linux確實不是一件容易的事情,因為要付出很多精力,也必須具備很好的C語言基礎;但是,學習Linux也是一件非常有趣的事情,它裡麵包含了許多高手的智慧和「幽默」,這些都需要自己親自動手才能體會到,O(∩_∩)O~哈哈!