日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

關注“技術簡說”,帶你一步一步學習linux內核驅動。

在linux操作系統中,一切皆是文件:文件是文件,目錄是文件,設備是文件,socket套接字是文件,管道也是文件。

linux操作系統用文件抽象出了這一切,文件成為了以上這些實體的編程接口。正由于此,基于linux的編程變成了面向文件的編程,對于linux應用程序開發者而言,簡直是爽的不要不要的。

但是,對于內核開發者而言,卻是未必。雖然應用層可以用open, write,read操縱一切,但是在內核里面,卻需要不同的部分(或者說驅動)來真正實現這一切。

本文接著linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動,來講述linux應用程序中的write()函數如何調用到hello驅動里的write()函數,并順道回答上一講最后的幾個遺留問題。

先上一張圖簡單說明下調用流程:

linux驅動開發第2講:應用程序里的write如何調到驅動里的write?

 

任何一個可以正常使用的函數,如果你的應用程序里沒有定義,那么肯定定義在c庫里。而c庫怎么做會視情況而定。像一些字符處理函數,c庫里會實現它們;但是像write函數,c庫只會做一些檢查,然后就陷入write的系統調用,系統調用會通過軟中斷的方式陷入到內核空間里去執行。

應用空間和內核空間是彼此隔離的,互相看不到對方,也無法訪問對方的數據,這是為了安全。所以就write函數而言,當從用戶空間通過系統調用進入到內核空間以后,內核需要通過copy_from_user函數才能把應用程序傳給write的數據拷貝到內核空間,之后內核空間才能對此數據進行處理。

整個流程,上圖表現的已經非常明顯,但是問題也是有的,操作系統中的系統調用最終是如何知道應該調用哪個驅動里的write函數呢?在linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動里,我們確實看到當執行測試程序的時候,當調用測試程序里的open, write和read函數的時候,分別調用到了hello驅動里的hello_open, hello_write和hello_read函數,難道這是一個巧合嗎?

當然不是!

我們先從邏輯上說明這個問題。

如果我們沒有記錯,在hello驅動里,有定義主次設備號:

int reg_major  =  232;    
int reg_minor =   0;
int hello_init(void)
{   
    devNum = MKDEV(reg_major, reg_minor);
		gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
    gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
    ...
    cdev_init(gDev, gFile);
    cdev_add(gDev, devNum, 3);
}

在hello_init里,我們把主設備號232和此設備號0組合成了devNum。

cdev_init(gDev, gFile); 建立了gDev和gFile的邏輯關系;

cdev_add(gDev, devNum, 3); 建立了gDev和devNum的邏輯關系;

其實你翻開代碼看細節會發現,以上兩句代碼其實建立了gFile和devNum的對應關系,也就是file_operations和devNum的對應關系,也就是建立了file_operation和主次設備號(232,0)的對應關系。

注意:在linux里,在應用層用文件句柄也就是fd表示一個打開的文件,但是在內核里用struct file 表示一個打開的文件,用struct file_operations表示對該文件的操作。fd和struct file是一一對應的,而struct file和struct file_operations也是一一對應的。這是struct file_operations的結構體定義:

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*fasync) (int, struct file *, int);
  ...
};

在上一講的例子里,我們打開的文件名字是/dev/hello,這是一個設備文件,對應的主次設備號分別為232和0。所以,當你打開/dev/hello之后,就已經建立了這個文件和hello驅動里的 struct file 的對應關系,也就建立了這個文件和hello驅動里的struct file_operations的對應關系。

好,了解以上的背景之后,我們來看看代碼。

我們從內核里write系統調用的實現部分開始閱讀:

相關的代碼在:fs/read_write.c

linux驅動開發第2講:應用程序里的write如何調到驅動里的write?

 

備注:SYSCALL_開頭表示是系統調用。

關鍵代碼在vfs_write。所以,我們繼續跟進入:

linux驅動開發第2講:應用程序里的write如何調到驅動里的write?

 

繼續跟入__vfs_write:

ssize_t __vfs_write(struct file *file, const char __user *p, size_t count,
		    loff_t *pos)
{
	if (file->f_op->write)
		return file->f_op->write(file, p, count, pos);
	else if (file->f_op->write_iter)
		return new_sync_write(file, p, count, pos);
	else
		return -EINVAL;

關鍵代碼在這里:

if (file->f_op->write)
		return file->f_op->write(file, p, count, pos);

上面提到建立了/dev/hello和file_operations的關系。所以這里其實就是判斷hello驅動里有沒有定義write函數,如果有,那就調用hello驅動里的write函數。

所以,按照如上的路徑,應用程序里的write就順利的調用到了hello驅動里的write函數。因為我們驅動里的hello_write和hello_read里都返回了0。所以,應用程序里的write和read也返回了0。

ssize_t hello_write(struct file *f, const char __user *u, size_t s, loff_t *l)
{
    printk(KERN_EMERG"hello_writern");
    return 0;
}
ssize_t hello_read(struct file *f, char __user *u, size_t s, loff_t *l)
{
    printk(KERN_EMERG"hello_readrn");      
    return 0;
}

如果你想讓測試程序里的write和read返回非零值,只要把驅動里的return 0,改為任意值就好了,大家可以自己測試一下。

關注“技術簡說”,帶你一步一步學習linux內核驅動。

分享到:
標簽:驅動 開發 linux
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定