一、linux裝置的分類
字元裝置、塊裝置、網路裝置,三種裝置之間的區別是資料的互動模式,分別為:
位元組流、資料塊、資料報。
二、vfs核心結構體
vfs核心結構體定義在」linux/fs.h」標頭檔案中。
1、struct inode結構體
記錄檔案的屬主、訪問時間等資訊。當第一次開啟檔案的時候由vfs建立並初始化。當檔案的所有引用都退出後,釋放inode; 如果使用者態有多個人同時開啟乙個檔案,則vfs只需要分配乙個inode。
2、struct file結構體
對應使用者態的open操作。如果多次開啟同乙個檔案,核心會生成多個file。file中記錄檔案的開啟方式,檔案內部指標等。當檔案徹底關閉時,釋放file。
3、struct file_operations結構體
該結構體包含若干函式指標,這些函式由驅動來實現,並集中到file_operations中,註冊到vfs。
驅動一般要實現的函式有:
open
release
read
write
unlocked_ioctl
驅動可能會實現的有:
poll
mmap
fasync
flush
llseek
三、字元裝置驅動開發流程
(1)確定硬體資訊
要確定硬體的數量,實體地址,中斷號等資訊;
(2)為要支援的裝置準備乙個私有結構體
核心並不要求必須有私有結構體,但如果驅動支援多個裝置,最好設計乙個。私有結構體完全由驅動人員自行設計,一般來說,會把和裝置相關的資訊寫入該結構體,比如裝置的位址等。
(3)為要支援的每個裝置分配對應的裝置號
裝置號由char驅動分配,要求唯一。一般來說,如果char驅動可支援多個類似的裝置,則應該為這些裝置選擇乙個主裝置號,然後為每個裝置選擇乙個特定的次裝置號。盡量挑選和其他驅動不一樣的主裝置號。可以看/proc/devices,檔案中記錄了其他驅動選擇的主裝置號;也可以向核心申請,由核心分配乙個主裝置號。
#define dev_major 50
...dev_id = mkdev(dev_major, 0);
(4)準備file_operations結構體
函式集中包括open/release/read/write/unlocked_ioctl等函式,如果驅動支援多個裝置,在函式中必須能區分自己訪問的是哪個裝置。
static struct file_operations mem_fops = ;
(5)註冊裝置
方法一:
利用cdev結構體,將裝置號和file_operations註冊到vfs。一般來說,將cdev結構體包含到私有結構體中。採用cdev註冊的裝置,不會自動建立裝置檔案。
cdev_init(&mem_cdev, &mem_fops);
cdev_add(&mem_cdev, dev_id, 1);
cdev_del(&mem_cdev); //登出cdev
方法二:
註冊miscdevice(用misc代替cdev註冊,可以自動建立裝置檔案)
這種情況下不需要定義主裝置號,即省去#define dev_major 50,同時需要用標頭檔案」linux/miscdevice.h」代替」linux/cdev.h」標頭檔案。
static struct miscdevice mem_miscdev = ;
ret = misc_register(&mem_miscdev); //註冊miscdevice
misc_deregister(&mem_miscdev); //登出miscdevice
cdev和miscdevice比較:
(1)cdev可以實現同乙個驅動對應多個裝置,而miscdevice只能實現乙個驅動對應乙個裝置;
(2)cdev不能實現裝置檔案的自動建立,而miscdevice可以實現裝置檔案的自動建立。
上述的過程比較適合較簡單的裝置,比如看門狗,led燈,各種感測器等。較複雜裝置的char驅動,常常要利用核心提供的驅動子系統**進行設計。
四、如何在linux驅動中訪問暫存器(sfr)
1、片內外設(pripheral)
(1)基於三匯流排訪問
(2)用暫存器控制
(3)暫存器有實體地址,可通過手冊查到,不可更改
2、片外外設
(1)很少通過三匯流排相連,一般是通過uart,can,i2c,usb,spi,mipi,i2s,ac97等匯流排相連。主晶元內部必須提供對應的控制器:內部的控制器 <–> 外部的外設
(2)片外外設基本都是智慧型裝置(不但有硬體,還有軟體)
(3)有些片外外設通過暫存器控制,有些則通過命令控制
(4)如果用暫存器控制,暫存器沒有實體地址,只有偏移。
(5)要控制片外外設,需要首先了解對應的匯流排
3、訪問暫存器的流程
由於linux使能了mmu,因此對於驅動來說,不能直接使用暫存器的實體地址,必須將其對映為虛擬位址才可以使用。
(1)定義暫存器物理基位址以及暫存器的偏移
#define gpio_base 0x11000000
#define gpio_size 0x1000 //0x8
#define gpm4con 0x2e0 //偏移位址
#define gpm4dat 0x2e4 //偏移位址
gpio_size為暫存器的範圍,可以按照使用的暫存器的總大小進行計算,比如用了兩個暫存器,範圍是0x8;但由於位址對映的最小單位是4k,因此小於4k的值都是可以的。
(2)將暫存器物理位址對映到虛擬位址,如果對映不成功,則無法訪問暫存器
static void __iomem *vir_base;
vir_base = ioremap(gpio_base, gpio_size);
if (!vir_base)
(3)訪問暫存器,一般採用基位址加偏移的模式,核心根據暫存器的大小,提供了一系列函式
8位暫存器的訪問
char value;
value = readb(vir_base + offset);
writeb(value, (vir_base + offset));
16位暫存器的訪問
short value;
value = readw(vir_base + offset);
writew(value, (vir_base + offset));
32位暫存器的訪問
int value;
value = readl(vir_base + offset);
writel(value, (vir_base + offset));
64位暫存器的訪問
u64 value;
value = readq(vir_base + offset);
writeq(value, (vir_base + offset));
(4)取消暫存器的對映
iounmap(vir_base);
嵌入式Linux裝置驅動開發筆記(二)
一 核心的時間 1 tick 滴答 核心採用了乙個新的時間單位來進行計時。該時間單位稱為tick 滴答 乙個tick對應硬體定時器兩次中斷之間的時間間隔。當前核心每秒鐘硬體定時器會發生hz次中斷。tick和秒的換算關係為 1 tick 1 hz秒。hz是在核心make menuconfig 核心的....
嵌入式Linux裝置驅動開發 1
使用者程序是通過裝置檔案來與實際的硬體打交道。每個裝置檔案都有其檔案屬性 c b 如表示是字元裝置還是塊裝置。另外每個檔案都有兩個裝置號,第乙個是主裝置號,用於標識驅動程式 第二個是從裝置號,用於標識使用同一裝置驅動的不同的硬體裝置。裝置檔案的主裝置號必須與裝置驅動程式在登記時申請的主裝置號一致,否...
嵌入式linux字元裝置驅動
arm linux 驅動 抵岸科技 1.我們需要先呼叫register chrdev region 或 alloc chrdev region 來向系統申請裝置號 int register chrdev region dev t first,unsigned int count,char name ...