linux驅動read函數 copytouser,Linux驅動編程 step-by-step (五)主要的文件操作方法實現...

主要的文件操作方法實現

文件操作函數有很多的操作接口,驅動編程需要實現這些接口,在用戶編程時候系統調用時候會調用到這些操作

structfile_operations?{

...

loff_t?(*llseek)?(structfile?*,?loff_t,int);

ssize_t?(*read)?(structfile?*,char__user?*,size_t,?loff_t?*);

ssize_t?(*write)?(structfile?*,constchar__user?*,size_t,?loff_t?*);

int(*open)?(structinode?*,structfile?*);

int(*release)?(structinode?*,structfile?*);

...

};

以上只列出了主要的操作,下面會依次介紹:

本次的測試代碼上傳在:char_step2

結構體:

首先 我們會模擬寫一個不操作任何設備,而僅僅是存儲的一個驅動。

定義自己的一個結構體為:

structsimple_dev{

chardata[MAX_SIMPLE_LEN];

loff_t?count;

structsemaphore?semp;

};

data 保存數據, count表示文件的數據有效的位置, semp是一個信號量鎖,在以后的編程中使用,

之后的程序中結構體也會做相應的變化,以適應linux編寫驅動的習慣

open方法:

打開設備并進一步初始化工作,在沒有定義open方法時內核以一種默認的方式打開設備,保證每次都能正確打開。

open方法中有有struct inode參數,包含了設備號,程序中可以使用次設備號得到正操作的設備

在struct file中主要的操作是private_data指針,他可以傳遞任何自己創建的結構。

總得說來open方法的作用有3

1、獲得操作的設備(通過設備號)

2、進一步的初始化設備

3、初始化file結構體的private_data

staticintsimple_open(structinode?*inodp,structfile?*filp)

{

structsimple_dev?*temp_dev?=?NULL;

intminor?=?0;

#if?SIMPLE_DEBUG

printk(KERN_INFO?"In?%s?\n",?__func__);

#endif

minor?=?iminor(inodp);//獲得操作的設備的次設備號

if(minor?>?DEV_COUNT-1){

printk(KERN_ERR?"the?char?dev?in?invalid?\n");

return-ENODEV;

}

#if?SIMPLE_DEBUG

printk(KERN_INFO?"the?minor?is??%d?\n",?minor);

#endif

temp_dev?=?&char2_dev[minor];//獲得真正操作的設備

/*?進一步?初始化設備?因為是操作一個模擬的設備?故省去*/

filp->private_data?=?temp_dev;?//初始化?private_data

return0;

}

release方法:

主要是對open進一步初始化的操作的反操作

比如open時候分配了內存,在release時就需要釋放它等

例子中因為操作內存設備,故在release時無需做什么事

read方法:

read 是把設備中的數據傳遞給調用者

主要步驟

1、檢測偏移量有效(有些設備驅動不需要檢測)

2、檢測用戶空間地址有效

3、將數據傳給用戶(在此步驟中調用的函數可能會自己檢測步驟2)

4、調整偏移量

5、返回讀到的數據長度

(read write 用法相對靈活,不要依賴上邊的步驟,設備驅動程序要根據設備特性去設計此方法)

這里先介紹一個會檢測用戶空間地址是否有效的copy函數

用戶調用read讀設備,而在內核空間就是將數據傳給用戶,是一個to的操作

unsignedlong__must_check?copy_to_user(void__user?*to,constvoid*from,?unsignedlongn)

__must_check表述必須檢測其返回值,操作成功返回0,不成功返回負的錯誤碼

to是用戶空間指針 也就是read函數傳入的用戶空間的指針,

from指向設備要傳送的數據

n標識傳入長度

0818b9ca8b590ca3270a3433284dd417.png

上圖是 摘自LDD3上的經典視圖, 應該比較能說明read的方法

staticssize_t?simple_read(structfile?*filp,char__user?*userstr,size_tcount,?loff_t?*loff)

{

structsimple_dev?*dev?=?NULL;

intdata_remain?=?0;

interr;

#if?SIMPLE_DEBUG

printk(KERN_INFO?"In?%s?\n",?__func__);

#endif

dev?????????=?filp->private_data;

data_remain?=?dev->count?-?*loff;

if(MAX_SIMPLE_LEN?

{

printk(KERN_ERR?"the?offset?is?illegal?in?func?%s?\n",__func__?);

return-EINVAL;

}

elseif(data_remain?<=?0)

{

printk(KERN_WARNING?"there?was?not?much?data?in?the?device\n");

return0;

}

else

{

if(count?>?data_remain)

{

#if?SIMPLE_DEBUG

printk(KERN_INFO?"the?data?is?less?than?the?user?want?to?read\n");

#endif

count?=?data_remain;

}

else

{

}

}

err?=?copy_to_user(userstr,?(dev->data)+(*loff),?count);?//調用內核函數進行數據拷貝,它會檢測用戶地址是否有效

if(err?!=?0)

{

printk(KERN_ERR?"an?error?occured?when?copy?data?to?user\n");

returnerr;

}

else

{

#if?SIMPLE_DEBUG

printk(KERN_INFO?"data?copy?to?user?OK\n");

#endif

*loff?=?*loff?+?count;?//調整偏移量

returncount;//返回寫入的數據量

}

}

write方法:

與read類似 它是從用戶傳數據給設備驅動

從內核空間看就是一個從用戶空間取數據 是一個from操作

long__must_check?strncpy_from_user(char*dst,constchar__user?*src,longcount)

dst 驅動保存數據的地址

src 用戶空間傳入的數據

count 標識數據長度

staticssize_t?simple_write(structfile?*filp,constchar__user?*userstr,size_tcount,?loff_t?*loff)

{

structsimple_dev?*dev?=?NULL;

interr;

intremain_space?=?0;

#if?SIMPLE_DEBUG

printk(KERN_INFO?"In?%s\n",__func__);

#endif

dev??????????=?filp->private_data;

if(MAX_SIMPLE_LEN?<=?*loff)//檢測偏移量

{

printk(KERN_ERR?"the?offset?is?illegal?in?func?%s\n",?__func__);

return-EINVAL;

}

else

{

remain_space?=?MAX_SIMPLE_LEN?-?*loff;

if(count?>?remain_space)

{

#if?SIMPLE_DEBUG

printk(KERN_WARNING?"the?data?is?to?long?to?write?to?the?device\n");

#endif

count?=?remain_space;

}

else

{

}

}

err?=?copy_from_user((dev->data)+(*loff),userstr,count);//取得數據

if(err?!=?0)

{

printk(KERN_ERR?"an?error?occured?when?copy?data?from?user\n");

returnerr;

}

else

{

#if?SIMPLE_DEBUG

printk(KERN_INFO?"data?copy?from?user?OK\n");

#endif

*loff?=?*loff?+?count;?//跳著偏移

if(*loff?>?dev->count)

{

dev->count?=?*loff;

}

else

{

}

returncount;//返回寫入的數據量

}

}

lseek方法:

根據用戶傳入的參數調整文件偏移

mode

SEEK_SET

從文件起始處開始偏移

SEEK_CUR

從文件當前位置計算偏移

SEEK_END

從文件末尾計算偏移

file結構的f_pos保存了文件的偏移量

在調整文件偏移后需要 更新file中得f_pos成員

staticloff_t?simple_llseek(structfile?*filp,?loff_t?loff,intmode)

{

structsimple_dev?*dev?=?NULL;

loff_t?tmp_len;

#if?SIMPLE_DEBUG

printk(KERN_INFO?"In?%s\n",__func__);

#endif

dev??????????=?filp->private_data;

switch(?mode?)

{

caseSEEK_SET:

if(?loff?

{

printk(KERN_ERR?"can't?move?above?file?line?%d?\n",?__LINE__);

return-1;

}

elseif(loff?>?dev->count)

{

printk(KERN_ERR?"offset?is?too?long?line?%d\n",?__LINE__);

return-1;

}

else

{

filp->f_pos?=?loff;

}

break;

caseSEEK_CUR:

if((tmp_len?=?filp->f_pos+loff)?

{

printk(KERN_ERR?"can't?move?above?file?line?%d?\n",?__LINE__);

return-1;

}

elseif(tmp_len?>?dev->count)

{

printk(KERN_ERR?"offset?is?too?long?line?%d\n",?__LINE__);

return-1;

}

else

{

filp->f_pos?=?tmp_len;

}

break;

caseSEEK_END:

if((tmp_len?=?dev->count+loff?)?

{

printk(KERN_ERR?"can't?move?above?file?line?%d?\n",?__LINE__);

return-1;

}

elseif(tmp_len?>?dev->count)

{

printk(KERN_ERR?"offset?is?too?long?line?%d\n",?__LINE__);

return-1;

}

else

{

filp->f_pos?=?tmp_len;

}

break;

default:

printk(KERN_INFO?"illigal?lseek?mode!?\n");

return-1;

break;

}

returnfilp->f_pos;

}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/396834.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/396834.shtml
英文地址,請注明出處:http://en.pswp.cn/news/396834.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

web開發中的 emmet 效率提升工具

web開發中的 emmet 效率提升工具 可以用來快速生成html 代碼。 并且給各種IDE、編輯器提供了插件支持&#xff0c;sublime &#xff0c;webstorm等。 如在webstorm中安裝好emmet之后&#xff0c;輸入以下文本&#xff0c; #page>div.content[ng-model"user"]ul>…

python二維數組操作_Python二維數組應用與操作

課課家將會在這里為大家詳細的介紹一下Python二維數組的相關應用方法以及定義方式&#xff0c;相信朋友們可以從中學習到更多的知識。 Python數組的應用中在實際編程中是一個非常重要的應用技術&#xff0c;作為Python編程人員來說&#xff0c;必須要熟練的掌握這方面的所有應用…

基于光線追蹤的渲染中景深(Depth of field)效果的實現

圖形學離線渲染中常用的透視攝像機模型時根據小孔成像的原理建立的&#xff0c;其實現通常是從向成像平面上發射ray&#xff0c;并把trace這條ray的結果作為成像平面上對應交點的采樣結果。即&#xff1a; 圖片來自《Fundamentals of Computer Graphics》 現實中的鏡頭拍攝的圖…

ubuntu 安裝 pycharm

添加源&#xff1a;$ sudo add-apt-repository ppa:mystic-mirage/pycharm安裝收費的專業版&#xff1a;$ sudo apt update$ sudo apt install pycharm安裝免費的社區版&#xff1a;$ sudo apt update$ sudo apt install pycharm-community卸載&#xff1a;$ sudo apt remove p…

帶你制作百詞斬單詞表讀寫插件

上篇博文簡單的介紹了一下Chrome插件&#xff0c;今天就與大家分享一下我做的這款有實際意義的插件吧。 做這款插件主要是用百詞斬站點進行單詞學習時&#xff0c;遇到的一點點鬧心事兒。在單詞表中不能聽發音。也不能練習拼寫。所以才忍無可忍的做了這么一款插件。自我感覺還是…

Linux7改運行級別,Centos7.0修改系統運行級別

首先翻譯下ininttab里面的內容&#xff1a;#inittab不再使用時利用系統。#添加配置這會對你的系統沒有影響。#Ctrl-Alt-Delete由/usr/lib系統/系統/ctrl-alt-del.target處理#系統使用的目標而不是運行級別。默認情況下&#xff0c;有兩個主要目標&#xff1a;#multi-user.targe…

python測試字符串類型的函數_python-02 數據類型 字符串str

字符串str 一、字符串定義 概念&#xff1a;字符串是有序的 不可修改的&#xff0c;元素以引號包圍的序列 引號類型&#xff1a;單引號 “”雙引號 “ ””三引號 三單引號 print(python) print("python") print(python) print("""python""…

POJ2115 C Looooops(線性同余方程)

無符號k位數溢出就相當于mod 2k&#xff0c;然后設循環x次A等于B&#xff0c;就可以列出方程&#xff1a; $$ CxA \equiv B \pmod {2^k} $$ $$ Cx \equiv B-A \pmod {2^k} $$ 最后就用擴展歐幾里得算法求出這個線性同余方程的最小非負整數解。 1 #include<cstdio>2 #incl…

工作測試博客

工作測試博客轉載于:https://blog.51cto.com/12559670/1895000

iphone各機型參數對比_帶你了解新款iPhone 12系列四款機型

2020年10月14日凌晨1&#xff1a;00&#xff0c;蘋果召開新品發布會&#xff0c;發布了新款iPhone 12系列手機&#xff0c;“果粉”們期待已久的iPhone 12終于來了。iPhone 12系列手機共有四款機型&#xff0c;分別是iPhone 12 mini、iPhone 12、iPhone 12 Pro、iPhone 12 Pro …

設置開機自啟動服務

一、軟鏈接方法 利用ln -s 命令將/etc/rc.d/init.d/目錄下腳本&#xff08;注意執行權限&#xff09;軟連接到 rc3目錄下&#xff0c;/etc/rc.d/rc3.d 目錄也就是我們一般的系統運行級別。ln -s /etc/rc.d/init.d/** /etc/rc.d/rc3.d/S**這里的S代表的是開機自啟動服務&#x…

mysql benchmark基準測試

git項目地址&#xff1a; https://github.com/akopytov/sysbench 利用sysbench很容易對mysql做性能基準測試&#xff08;當然這個工具很強大&#xff0c;除了測試主流數據庫性能&#xff0c;還能測試其它方面&#xff0c;詳情自己看官網項目文檔&#xff09; mac上的用法&#…

高并發第一彈:準備階段 了解高并發

高并發第一彈:準備階段 了解高并發 首先需要知道什么并發, 什么是高并發. 并發: 關于并發的學習&#xff0c;可以從JDK提供的并發包為核心開始&#xff0c;許多其他的類和封裝都是對其進行擴展或者補充&#xff0c;我們來看一下Java并發包(java.util.concurrent包&#xff0c;簡…

matlab立體坐標定位_【半導光電】基于光電探測器的激光章動定位算法(二)

今日光電有人說&#xff0c;20世紀是電的世紀&#xff0c;21世紀是光的世紀&#xff1b;知光解電&#xff0c;再小的個體都可以被賦能。歡迎來到今日光電&#xff01;----與智者為伍 為創新賦能----1. 章動定位算法實驗前&#xff0c;首先需要對光路進行調節&#xff0c;保證經…

linux系統死機窗口移動不了怎么辦,Linux 操作系統死機故障處理方法總結

hai00882008-01-30 15:53我只備份一次,我的磁帶有400G, 備份第二次,磁帶就彈出來,我的tapelist里的內容 20080130151855 DailySet1-01 reuse是不是和我的anmanda.conf的chg-manua(更換磁帶的腳本)l這個腳本有關係,-sh-3.00$ amcheck DailySet1Amanda Tape Server Host Check---…

Android:支持多選的本地相冊

前段時間在做一個動態發布功能&#xff0c;需要用到圖片上傳。一開始直接調用的系統相冊和相機&#xff0c;由于系統相機不支持多選&#xff0c;就花點時間做了個本地相冊&#xff0c;在此開源下。 先上截圖&#xff0c;依次為選擇相冊界面、相冊詳情界面、查看圖片大圖界面 相…

心靈與大腦

2019獨角獸企業重金招聘Python工程師標準>>> http://blog.sina.com.cn/s/blog_6f034fc30102f2tg.html 轉載于:https://my.oschina.net/chirnson/blog/832011

python入門心得_記初學python的一些心得

人生苦短&#xff0c;我用python&#xff01; 其實我自學python也很長一段時間了&#xff0c;但總是去更換學習資料&#xff0c;搞的現在學的不是很好&#xff0c;因為沒更換次資料都要從頭開始學起&#xff0c;那么分享下我的學習戰況吧&#xff0c;不是很好&#xff0c;還將就…

羅技鍵盤linux,logiops,在 Linux下設置羅技鼠標的按鍵和手勢

眾所周知&#xff0c;幾乎所有的消費級電子產品都不會對 Linux 有太好的支持&#xff0c;羅技當然也不例外。Logitech Options 是羅技辦公鼠標的自定義功能驅動&#xff0c;很容易猜到&#xff0c;羅技只提供了Windows和Mac版本。但幸運的是&#xff0c;有人開發出了一個第三方…

16.U-boot的工作流程分析-2440

16.U-boot的工作流程分析-2440 分析的流程&#xff1a; 程序入口 第一階段程序分析 第二階段程序分析 2440開發板&#xff1a; 1.uboot的入口&#xff1a; 要看uboot工程的入口&#xff0c;首先打開頂層目錄的Makefile&#xff1a; Uboot所支持的開發板&#xff0c;在頂層的Ma…