當使用者程序open裝置檔案時, 核心會根據開啟的裝置檔案的裝置號找到對應的cdev物件,
檢查cdev.ops->open, 如果不為空,則呼叫驅動裡的open函式,如為空,核心直接返回fd.
//注意使用者程序開啟裝置檔案得到檔案描述符不是由裝置驅動裡指定的,裝置驅動裡的open函式僅僅是告訴核心是否已正常開啟.
使用者程序:
kernel --->
cdev.ops
->
open(..)
read --->
kernel --->
cdev.ops
->
read(..)
ioctl --->
kernel --->
cdev.ops
->
unlocked_ioctl(..)
裝置驅動實現好功能後,基本上由使用者程序通過系統呼叫後進來呼叫的.
如需要迴圈操作硬體,則應是在使用者程序裡迴圈。
// 使用者程序操作裝置驅動,網路通訊等與普通的文字檔案操作的程式設計介面基本一樣(open, read, write, ioctl…).
這套介面就是所謂的vfs(虛擬檔案系統)。
//在linux核心,用乙個inode節點物件描述乙個要操作的檔案/裝置檔案, 包括許可權,裝置號等資訊. 就是描述乙個要操作的檔案的屬性. 乙個檔案可以開啟很多次, 但都是共用乙個inode物件來描述屬性的. 檔案描述符屬於乙個程序的資源,不同程序裡有可能相同的檔案描述符.
struct inode ;
//在使用者程序裡用乙個int型別來表示檔案描述符.但檔案描述符裡有還存有對檔案位置的偏移,開啟標誌等資訊, 用乙個int數無法記錄下來的,所在每個檔案描述符的資訊都是由核心裡用file物件描述檔案描述符, 在檔案開啟時建立, 關閉時銷毀
struct file ;
如果開啟裝置檔案,那麼得到的file物件:
file物件裡的成員f_path.dentry->d_inode->i_rdev可以獲取到裝置檔案的裝置號
file物件裡的成員f_path.dentry->d_inode可以獲取到裝置檔案的inode物件的位址
注意: 乙個檔案只有乙個inode節點物件, 但是可以開啟多次,得到不同的檔案描述符物件(也就是多個struct file物件)
////struct file_operations 裡函式引數
//inode表示應用程式開啟的檔案的節點物件, file表示開啟檔案獲取到的檔案描述符
int (*open) (struct inode *, struct file *);
//返回值0表示成功開啟,負數表示開啟失敗。核心根據open函式的返回值來確定是否給呼叫的使用者程序分配檔案描述符。
//在驅動可以不實現此函式, 如不實現。則表示每次開啟都是成功的.
//buf指向使用者程序裡的緩衝區, len表示buf的大小(由使用者呼叫read時傳進來的)
//off表示fl檔案描述符的操作偏移, 返回值為實際給使用者的資料位元組數.
ssize_t (*read) (struct file *fl, char __user *buf, size_t len, loff_t *off);
//注意,必須通過off指標來改變檔案描述符的偏移(*off += 操作位元組數). 不可以直接通過"fl->f_pos"來設定
//使用者程序把資料給驅動, 也就是讓驅動存放使用者程序傳進來的資料.
// 參考read函式
ssize_t (*write) (struct file *, const
char __user *buf, size_t len, loff_t *off);
// cmd表示使用者程序呼叫ioctl時的第二個引數, arg表示第三個引數(可選)
long (*unlocked_ioctl) (struct file *fl, unsigned
int cmd, unsigned
long arg);
// 返回值為0表示ioctl成功, 返回負數表示失敗.
loff_t (*llseek) (struct file *fl, loff_t offset, int whence);
//在驅動裡操作使用者資料緩衝區的函式:
#include
//to指使用者程序的緩衝區, from指驅動裡裝資料的緩衝區, n要複製多少位元組。
extern
inline
long copy_to_user(void __user *to, const
void *from, long n)
//返回值為還有多少位元組沒有複製成功. 正常情況下返回0.
//to指驅動的... from使用者... n多少位元組, ....
extern
inline
long copy_from_user(void *to, const
void __user *from, long n)
//返回值為還有多少位元組沒有複製成功. 正常情況下返回0.
//如果與使用者程序互動的資料是1,2,4,8位元組的話, 可用
put_user(x,p) //x為值, p為位址
//如果從使用者程序獲取1,2,4位元組的話, 可用
get_user(x,p)
/驅動裡動態申請緩衝區的函式:
#include
///動態申請記憶體, 並清零. size為申請多大(不要超過128k),
//flags為標誌(常為gfp_kernel). 成功返回位址, 失敗返回null
// gfp_atomic, 使用系統的記憶體緊急池
void *kmalloc(size_t size, gfp_t flags);//申請後要記憶體要清零
void *kzalloc(size_t size, gfp_t flags); //申請出來的記憶體已清零
void kfree(const
void *objp); //**kmalloc/kzalloc的記憶體
void *vmalloc(unsigned
long size); //申請大記憶體空間
void vfree(const
void *addr); //**vmalloc的記憶體
// kmalloc申請出來的記憶體是實體地址連續的, vmalloc不一定是連續的
驅動 linux裝置驅動 字元裝置驅動開發
preface 前面對linux裝置驅動的相應知識點進行了總結,現在進入實踐階段!linux 裝置驅動入門篇 linux 裝置驅動掃盲篇 fedora下的字元裝置驅動開發 開發乙個基本的字元裝置驅動 在linux核心驅動中,字元裝置是最基本的裝置驅動。字元裝置包括了裝置最基本的操作,如開啟裝置 關閉...
Linux裝置驅動之《字元裝置驅動》
linux裝置中最大的特點就是裝置操作猶如檔案操作一般,在應用層看來,硬體裝置只是乙個裝置檔案。應用程式可以像操作檔案一樣對硬體裝置進行操作,如open close read write 等。下面是乙個字元裝置驅動程式的簡單實現test.c 模組分析 1.初始化裝置驅動的結構體 struct fil...
Linux裝置驅動之字元裝置驅動
一 linux裝置的分類 linux系統將裝置分成三種基本型別,每個模組通常實現為其中某一類 字元模組 塊模組或網路模組。這三種型別有 字元裝置 字元裝置是個能夠像位元組流 類似檔案 一樣被訪問的裝置,由字元裝置驅動程式來實現這種特性。字元裝置可以通過檔案系統節點來訪問,比如 dev tty1等。這...