姓名:鄧皓軒? 學(xué)號:19020100151? 學(xué)院:電子工程學(xué)院
轉(zhuǎn)自:https://blog.csdn.net/qq_41035588/article/details/92002740?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162855377416780357290768%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162855377416780357290768&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-15-92002740.first_rank_v2_pc_rank_v29&utm_term=%E5%B5%8C%E5%85%A5%E5%BC%8Flinux&spm=1018.2226.3001.4187
【嵌牛導(dǎo)讀】基于ARM的嵌入式Linux開發(fā)總結(jié)
【嵌牛鼻子】介紹基于ARM的嵌入式Linux開發(fā)的重點
【嵌牛提問】基于ARM的嵌入式Linux開發(fā)總結(jié)有哪些要點
嵌入式知識點復(fù)習一
1恰响、 嵌入式系統(tǒng)的一般組成結(jié)構(gòu)
2呢袱、嵌入式硬件系統(tǒng)的結(jié)構(gòu)
(1)嵌入式處理器+外圍硬件
(2)常見的外圍硬件:電源溅呢、時鐘类嗤、內(nèi)存洗搂、I/O亮靴、通信宴树、調(diào)試藐握;
3护糖、嵌入式處理器
(1)ARM褥芒、S3C6410、STM32單片機嫡良、華為海思锰扶、高通驍龍等
(2)Intel /AMD 都不是嵌入式處理器
4、嵌入式操作系統(tǒng)
功能:
種類:嵌入式linux寝受;WinCE坷牛;Vxworks;μC/OS-II很澄;Android京闰;IOS。注意:linux不是嵌入式操作系統(tǒng)甩苛;MAC OS WINDOWS XP/7/8/10都不是
嵌入式知識點復(fù)習二 --體系結(jié)構(gòu)
1蹂楣、ARM:ADVANCED RISC MACHINES,是一款嵌入式微控制器,也是一家嵌入式處理器設(shè)計廠商讯蒲。設(shè)計高性能痊土、低功耗的嵌入式處理器。
2墨林、ARM微處理器工作狀態(tài):兩種指令對應(yīng)兩種狀態(tài)(通常情況)
(1)Thumb狀態(tài)赁酝、ARM狀態(tài);
(2)32位定長ARM指令旭等,16位定長Thumb指令酌呆。
(3)ARM1176支持ARM指令、Thumb指令辆雾、Jazelle指令肪笋,故有三種狀態(tài):ARM狀態(tài)、Thumb狀態(tài)、Jazelle狀態(tài)藤乙。
3猜揪、異常:
(1)處理器執(zhí)行某些區(qū)別于用戶指令的任務(wù),如中斷處理坛梁、復(fù)位而姐、調(diào)試等;為了區(qū)分用戶指令划咐,因此稱為異常拴念;
(2)異常的種類與類型(1176為例):7種,中斷(IRQ)褐缠、快中斷(FIQ)政鼠、未定義(Undef)、數(shù)據(jù)中止(DABT)队魏、預(yù)取指中止(PABT)公般、軟中斷、復(fù)位(reset)
4胡桨、工作模式:根據(jù)系統(tǒng)執(zhí)行正彻倭保或異常指令不同,分為8種工作模式:用戶模式昧谊、系統(tǒng)模式刽虹、中斷模式、快中斷模式呢诬、未定義模式涌哲、中止模式(對應(yīng)數(shù)據(jù)中止異常、預(yù)取指中止)馅巷、SVC管理模式(軟中斷膛虫、復(fù)位)、SM安全監(jiān)視器模式钓猬。
5稍刀、寄存器:
(1)ARM處理器均為32位寄存器;
(2)ARM1176寄存器數(shù)量:40個
(3)ARM1176寄存器包括:未分組寄存器敞曹、分組寄存器账月、CPSR、SPSR;
(4)未分組寄存器(所有模式通用):9個澳迫,R0~R7;R15(PC)
(5)分組寄存器(不同工作模式下專用,不同模式稍有不同):
① R8~R14;
② 6個不同模式下的SPSR寄存器:SPSR_irq,SPSR_fiq,SPSR_abt,
SPSR_und,SPSR_svc,SPSR_mon
(6)可復(fù)用寄存器:
① SP堆棧指針寄存器-R13局齿,用于保存子程序調(diào)用或異常處理的臨時數(shù)據(jù);
② LR連接寄存器-R14橄登,用于保存子程序調(diào)用或異常處理時抓歼,主程序調(diào)用指令/中斷跳轉(zhuǎn)指令的下一條指令的入口地址讥此,以便于恢復(fù)主程序;
③ PC程序計數(shù)器-P15谣妻,用于保存要執(zhí)行的指令的地址萄喳。
(7)PSR程序狀態(tài)寄存器:
① 包括CPSR當前程序狀態(tài)寄存器和SPSR備份的程序狀態(tài)寄存器;
② CPSP用于保存當前模式下處理器模式蹋半、狀態(tài)他巨、中斷使能、大小端模式及條件位等信息减江;
③ SPSR用于備份異常發(fā)生前的CPSR寄存器的值染突,以便異常處理結(jié)束時能返回用戶程序狀態(tài)。
6辈灼、ARM支持兩種中斷:IRQ和FIQ
7份企、ARM數(shù)據(jù)存儲格式:大端(big endian)和小端(little endian)
8、采用RISC架構(gòu)的ARM微處理器一般具有如下特點:
① 體積小茵休、低功耗薪棒、低成本、高性能榕莺;
② 支持Thumb(16位)/ARM(32位)雙指令集,能很好地兼容8位/16位器件棵介;
③ 大量使用寄存器钉鸯,指令執(zhí)行速度更快;
④ 大多數(shù)數(shù)據(jù)操作都在寄存器中完成邮辽;
⑤ 尋址方式靈活簡單唠雕,執(zhí)行效率高;
⑥ 指令長度固定吨述;
⑦ 指令支持按 條件執(zhí)行岩睁;
⑧ 內(nèi)存訪問采用load/store實現(xiàn)。
嵌入式知識點復(fù)習三 --ARM-LINUX嵌入式開發(fā)環(huán)境
一揣云、交叉開發(fā)模式
1捕儒、組成結(jié)構(gòu)
(1)宿主機:開發(fā)主機,一般由PC邓夕、發(fā)行版linux系統(tǒng)刘莹、開發(fā)工具(本地及交叉編譯)(代碼編輯器Vi,編譯器GCC、調(diào)試器GDB焚刚、工程管理器MAKE点弯、NFS等)組成;
(2)目標機:嵌入式系統(tǒng)矿咕,一般由ARM硬件抢肛、BOOTLOADER狼钮、內(nèi)核、根文件系統(tǒng)構(gòu)成捡絮;
(3)連接工具:串口線熬芜、網(wǎng)線、USB線等锦援。
2猛蔽、理解編譯工具鏈與交叉編譯工具鏈的異同
(1)相同點:
① 用于支持的語言的編譯、鏈接與調(diào)試灵寺,編譯器用法相同曼库;
② 通常都有編譯器、鏈接器略板、調(diào)試器毁枯、庫及其他二進制工具構(gòu)成。
(2)不同點:
① 編譯工具鏈一般用于本機編譯叮称、本機執(zhí)行的開發(fā)模式种玛;
② 交叉編譯工具鏈用于宿主機編譯,目標機運行的交叉開發(fā)模式瓤檐;
③ 編譯器一般Linux發(fā)行版都配備赂韵,直接調(diào)用gcc命令即可;
④ 交叉編譯器一般需根據(jù)宿主機軟硬件環(huán)境挠蛉,進行g(shù)cc祭示、相關(guān)庫、工具進行有針對性的定制谴古。
⑤ 實驗室使用的OK6410開發(fā)板定制的編譯器為32位的质涛,其交叉編譯工具鏈主要arm-linux-gcc,arm-linux-g++arm-linux-gdb等構(gòu)成。
二掰担、開發(fā)工具的用法
1汇陆、Vi的工作模式及其切換-掌握使用Vi完成源代碼編輯、保存及退出的常見按鍵操作带饱;
2毡代、GCC:GNU Compiler Collection,GUN編譯器套件纠炮,特點:
① 支持絕大多數(shù)高級語言的編譯月趟,既支持傳統(tǒng)的C/C++,Fortan,Objective-C ,也支持java,python,go等語言恢口;
② 支持匯編語言孝宗;
③ 支持絕大多數(shù)的主流處理器平臺;
④ 便于構(gòu)建交叉編譯工具鏈耕肩。
3因妇、gcc/arm-linux-gcc用法:
① 基本用法:gcc hello.c;arm-linux-gcc hello.c;輸出a.out
② 推薦用法:gcc hello.c -o hello/arm-linux-gcc hello.c -o hello ,可以指定輸出文件名稱问潭;
③ 主要的編譯參數(shù)
?-Wall 打印全部警告信息;
?-O{0-3,s} 支持代碼優(yōu)化婚被,0無優(yōu)化狡忙;
?-g 支持gdb調(diào)試;
?-lpthread 支持多線程址芯。
4灾茁、make及Makefile
(1)make:工程管理器,利用執(zhí)行Makefile文件實現(xiàn)工程管理(編譯谷炸、鏈接北专、生成工程鏡像、安裝旬陡、清理拓颓、卸載等);
(2)make用法:編寫Makefile描孟,在終端下執(zhí)行make命令即可驶睦。
(3)Makefile文件編寫示例:
一個工程,2個源文件testa.c ,testb.c,一個頭文件testb.h匿醒,編譯器為arm-linux-gcc场航,生成的可執(zhí)行文件為test,需支持代碼優(yōu)化、打印警告信息廉羔,支持gdb調(diào)試等編譯選項旗闽,其Makefile文件如下:
SRC=testa.testb b.c testb.h
EXEC=test
CC=arm-linux-gcc
CFLAGS=-Wall -O2 -g
( E X E C ) : (EXEC):(EXEC):(SRC)
$(CC) $(SRC) -o $(EXEC) $(CFLAGS)
嵌入式知識點復(fù)習四 --arm-linux文件編程
1、linux文件編程概述
(1)文件描述符:Linux中文件分為4種:普通文件蜜另、目錄文件、鏈接文件嫡意、設(shè)備文件要區(qū)分這些文件就要了解“文件描述符”举瑰;
文件描述符是一個非負的整數(shù),他是一個索引值蔬螟,并指向內(nèi)核中每個進程打開文件的記錄表此迅。當打開一個現(xiàn)存文件或創(chuàng)建一個新文件時,內(nèi)核就向進程返回一個文件描述符旧巾,當需要讀/寫文件時耸序,也需要把文件描述符作為參數(shù)傳遞給相應(yīng)的函數(shù)。
(2)基本I/O操作
Linux的輸入/輸出(I/O)操作鲁猩,通常為5個方面:打開坎怪,讀取,寫入廓握,和關(guān)閉
對應(yīng)的有5個系統(tǒng)調(diào)用:
open,read,write,close,lseek
所需要的頭文件:
#include <sys/types.h>
#include <unistd.h>
1.open函數(shù)
open函數(shù)的原型如下:
int open(const char *pathname, int flags, mode_t mode)
函數(shù)傳入?yún)?shù)含義如下:
pathname:為字符串搅窿,表示被打開的文件名稱嘁酿,可以包含路徑。
flags :為一個或多個標志男应,表示文件的打開方式闹司,常用標志如表所示:
O_RDONLY 只讀方式打開
O_WRONLY 只寫方式打開
O_RDWR 讀/寫方式打開
O_CREAT 如果文件不存在,就創(chuàng)建新的文件
O_EXCL 如果使用O_CREAT時文件存在沐飘,則可返回錯誤消息
O_TRUNC 如果文件已存在游桩,且以只讀或只寫成功打開,則先全部刪除文件中原有的數(shù)據(jù)
O_APPEND 以添加方式打開文件耐朴,在打開文件的同時借卧,文件指針指向文件的末尾、
注意:在open函數(shù)中隔箍,flags參數(shù)可以用過“|”組合而成谓娃,O_RDONLY,O_WRONLY,O_RDWR這三種方式是互斥的,不可同時使用蜒滩,因此這3個參數(shù)只能出現(xiàn)一個滨达。
mode 被打開文件的存取權(quán)限模式,可以使用八進制數(shù)來表示新文件的權(quán)限俯艰,也可以采用<sys/stat.h>中定義的符號常量捡遍,當打開已有文件時,將忽略這個參數(shù)竹握,函數(shù)返回值:成功則返回文件描述符画株,出錯返回-1。
文件模式符號常量:
S_IRWXU 00700 所屬用戶讀啦辐。寫和執(zhí)行權(quán)限
S_IRUSR 00400 所屬用戶讀權(quán)限
S_IWUSR 00200 所屬用戶寫權(quán)限
S_IXUSR 00100 所屬用戶執(zhí)行權(quán)限
S_IRWXG 00070 組用戶讀谓传,寫和執(zhí)行權(quán)限
S_IRGRP 00040 組用戶讀權(quán)限
S_IWGRP 00020 組用戶寫權(quán)限
S_IXGRP 00010 組用戶執(zhí)行權(quán)限
S_IRWXO 00007 其他用戶讀,寫和執(zhí)行權(quán)限
S_IROTH 00004 其他用戶讀權(quán)限
S_IWOTH 00002 其他用戶寫權(quán)限
S_IXOTH 00001 其他用戶執(zhí)行權(quán)限
2.read和write函數(shù)
函數(shù)原型如下:
ssize_t read(int fd, void *buf,size_t count)
ssize_t write(int fd,const void *buf, size_t count)
函數(shù)傳入?yún)?shù)含義如下:
fd 文件描述符
buf 指定存儲器獨處數(shù)據(jù)的緩沖區(qū)
count 指定讀出或?qū)懭氲淖止?jié)數(shù)
3.close函數(shù)
當使用完文件時可以使用close關(guān)閉文件芹关,close會讓緩沖區(qū)中的數(shù)據(jù)寫回磁盤续挟,并釋放文件所占的資源,close的原型如下:
int close(int fd)
函數(shù)傳入?yún)?shù):fd文件描述符
函數(shù)返回值:若文件順利關(guān)閉則返回0侥衬,發(fā)生錯誤則返回-1诗祸,并置errno,通常文件在關(guān)閉時出錯是不常見的,但也不是不可能的情況轴总,他別是在關(guān)閉通過網(wǎng)絡(luò)訪問的文件時就會出現(xiàn)這種情況直颅。
4.lseek函數(shù)
主要用于移動文件讀寫指針,主要用于獲取文件大小和拓展文件(先分配空間怀樟、然后再填充內(nèi)容)功偿,函數(shù)原型如下:
off_t lseek(int fd, off_t offset, int whence)
參數(shù) fd:文件描述符。
offset:偏移量漂佩,每一讀寫操作所需要移動的距離脖含,單位是字節(jié)的數(shù)量罪塔,可正可負(向前移,向后移)
whence
(當前位置基點): SEEK_SET:當前位置為文件的開頭养葵,新位置為偏移量的大小征堪。
SEEK_CUR:當前位置為文件指針的位置,新位置為當前位置加上偏移量关拒。
SEEK_END:當前位置為文件的結(jié)尾佃蚜,新位置為文件的大小加上偏移量的大小。
返回值 成功:文件的當前位移
-1:出錯
實例:(1)參考實驗2:linux文件編程着绊;
(2)網(wǎng)盤:/linux編程源代碼/IO(readwrite谐算、fcntl)下相關(guān)代碼
嵌入式知識點復(fù)習五 --arm-linux進程編程
一、Linux進程編程
進程(Process)是計算機中的程序關(guān)于某數(shù)據(jù)集合上的一次運行活動归露,是操作系統(tǒng)進行資源分配和調(diào)度的基本單位洲脂,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。
1 進程控制
?子進程創(chuàng)建:fork()函數(shù)
在Linux中創(chuàng)建一個新進程的唯一方法是使用fork()函數(shù)剧包。fork()函數(shù)是Linux中一個非常重要的函數(shù)恐锦,和以往遇到的函數(shù)有一些區(qū)別,因為fork()函數(shù)看起來執(zhí)行一次卻返回兩個值疆液。
1)fork()函數(shù)說明
fork()函數(shù)用于從已存在的進程中創(chuàng)建一個新進程一铅。新進程稱為子進程,而原進程稱為父進程堕油。
使用fork()函數(shù)得到的子進程是父進程的一個復(fù)制品潘飘,它從父進程處繼承了整個進程的地址空間,包括進程的上下文掉缺、代碼段卜录、進程堆棧、內(nèi)存信息眶明、打開的文件描述符暴凑、符號控制設(shè)定、進程優(yōu)先級赘来、進程組號、當前工作目錄凯傲、根目錄犬辰、資源限制和控制終端等,而子進程所獨有的只有它的進程號冰单、資源使用和計時器等幌缝。
因為子進程幾乎是父進程的完全復(fù)制,所以父子兩進程會運行同一個程序诫欠。這就需要用一種方式來區(qū)分它們涵卵,并使它們照此運行浴栽,否則,這兩個進程不可能做不同的事轿偎。
實際上是在父進程中執(zhí)行fork()函數(shù)時典鸡,父進程會復(fù)制一個子進程,而且父子進程的代碼從fork()函數(shù)的返回開始分別在兩個地址空間中同時運行坏晦,從而使兩個進程分別獲得所屬fork()函數(shù)的返回值萝玷,其中在父進程中的返回值是子進程的進程號,而在子進程中返回0昆婿。因此球碉,可以通過返回值來判斷該進程的父進程還是子進程。
2)fork()函數(shù)語法
?進程等待函數(shù)
1)wait()函數(shù)仓蛆,無條件等待睁冬,父進程阻塞直到子進程結(jié)束
2)waitpid()函數(shù),指定等待某個子進程結(jié)束以及等待的方式(阻塞或非阻塞)
所需頭文件 #include <sys/types.h>
#include <sys/wait.h>
函數(shù)原型 pid_t waitpid(pid_t pid, int *status, int options)
函數(shù)參數(shù) pid pid>0:只等待進程ID等于pid的子進程看疙,不管已經(jīng)有其他子進程運行結(jié)束退出了豆拨,只要指定的子進程還沒有結(jié)束,waitpid就會一直等下去狼荞。
pid=-1:等待任何一個子進程退出辽装,此時和wait作用一樣。
pid=0:等待其組ID等于調(diào)用進程的組ID的任一子進程相味。
pid<-1:等待其組ID等于pid的絕對值的任一子進程拾积。
status 同wait
options WNOHANG:若由pid指定的子進程并不立即可用,則waitpid不阻塞丰涉,此時返回值為0
WUNTRACED:若某實現(xiàn)支持作業(yè)控制拓巧,則由pid指定的任一子進程狀態(tài)已暫停,且其狀態(tài)自暫停以來還未報告過一死,則返回其狀態(tài)肛度。
0:同wait,阻塞父進程投慈,等待子進程退出承耿。
函數(shù)返回值 正常:結(jié)束的子進程的進程號
使用選項WNOHANG且沒有子進程結(jié)束時:0
調(diào)用出錯:-1
所需頭文件 #include <sys/types.h>
#include <sys/wait.h>
函數(shù)原型 pid_t waitpid(pid_t pid, int *status, int options)
函數(shù)參數(shù) pid pid>0:只等待進程ID等于pid的子進程,不管已經(jīng)有其他子進程運行結(jié)束退出了伪煤,只要指定的子進程還沒有結(jié)束加袋,waitpid就會一直等下去。
pid=-1:等待任何一個子進程退出抱既,此時和wait作用一樣职烧。
pid=0:等待其組ID等于調(diào)用進程的組ID的任一子進程。
pid<-1:等待其組ID等于pid的絕對值的任一子進程。
status 同wait
options WNOHANG:若由pid指定的子進程并不立即可用蚀之,則waitpid不阻塞蝗敢,此時返回值為0
WUNTRACED:若某實現(xiàn)支持作業(yè)控制,則由pid指定的任一子進程狀態(tài)已暫停足删,且其狀態(tài)自暫停以來還未報告過寿谴,則返回其狀態(tài)。
0:同wait壹堰,阻塞父進程拭卿,等待子進程退出。
函數(shù)返回值 正常:結(jié)束的子進程的進程號
使用選項WNOHANG且沒有子進程結(jié)束時:0
調(diào)用出錯:-1
?進程結(jié)束:exit()和_exit()
所需頭文件 exit:#include <stdlib.h>
_exit:#include <unistd.h>
函數(shù)原型 exit:void exit(int status);
_exit:void _exit(int status);
函數(shù)傳入值 status是一個整型的參數(shù),可以利用這個參數(shù)傳遞進程結(jié)束時的狀態(tài)。
通常0表示正常結(jié)束窜司;其他的數(shù)值表示出現(xiàn)了錯誤,進程非正常結(jié)束惠桃。
在實際編程時,可以用wait系統(tǒng)調(diào)用接收子進程的返回值辖试,進行相應(yīng)的
處理辜王。
所需頭文件 exit:#include <stdlib.h>
_exit:#include <unistd.h>
函數(shù)原型 exit:void exit(int status);
_exit:void _exit(int status);
函數(shù)傳入值 status是一個整型的參數(shù),可以利用這個參數(shù)傳遞進程結(jié)束時的狀態(tài)罐孝。
通常0表示正常結(jié)束呐馆;其他的數(shù)值表示出現(xiàn)了錯誤,進程非正常結(jié)束莲兢。
在實際編程時汹来,可以用wait系統(tǒng)調(diào)用接收子進程的返回值,進行相應(yīng)的
處理改艇。
兩者的區(qū)別:
(1)_exit()函數(shù)的作用最為簡單:直接使進程終止運行收班,清除其使用的內(nèi)存空間,并銷毀其在內(nèi)核中的各種數(shù)據(jù)結(jié)構(gòu)谒兄;
(2)exit()函數(shù)則在這些基礎(chǔ)上作了一些包裝摔桦,在執(zhí)行退出之前加了若干道工序。
(3)exit()函數(shù)在調(diào)用exit系統(tǒng)調(diào)用之前要檢查文件的打開情況承疲,把文件緩沖區(qū)中的內(nèi)容寫回文件邻耕,就是"清理I/O緩沖"。
?Linux下的進程間通信
進程間通信用于實現(xiàn)參數(shù)傳遞及通信功能燕鸽;Linux支持的常用的進程間通信方法:管道赊豌、消息隊列、共享內(nèi)存绵咱、信號量、套接口等等。
實例:(1)實驗三:Linux進程編程悲伶;
(2)網(wǎng)盤linux編程源代碼目錄下fork文件下相關(guān)實例(FIFO艾恼、msgque、shm)麸锉。
嵌入式知識點復(fù)習六 --arm-linux網(wǎng)絡(luò)編程
1钠绍、程序流程
(1)網(wǎng)絡(luò)通信程序架構(gòu)-客戶端/服務(wù)器架構(gòu)
(2)流程如下圖:
TCP通信
2、函數(shù)說明
?socket()
Sockfd=socket(AF_INET,SOCK_STREAM,0);
?Bind()
s_add.sin_family=AF_INET;IPV4協(xié)議
s_add.sin_addr.s_addr=inet_addr(“192.168.1.123”);IP地址192.168.1.123
s_add.sin_port=htons(0x8888);端口號是8888
if(-1 == bind(Sockfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
?listen()服務(wù)器端偵聽函數(shù)
listen(Sockfd,5)服務(wù)器偵聽來自客戶端的請求
?accept()服務(wù)器端接受客戶端連接請求
nfp = accept(Sockfd, (struct sockaddr *)(&c_add), sizeof(struct sockaddr);
?send()數(shù)據(jù)發(fā)送函數(shù)
send(nfp,“hello,welcome to my server”,32,0)
?recv()數(shù)據(jù)接收函數(shù)
recv(nfp,buffer,1024,0)
?關(guān)閉連接
Close(nfp)
?關(guān)閉服務(wù)器
Close(Sockfd)
實例:(1)實驗四:網(wǎng)絡(luò)聊天室設(shè)計
(2)網(wǎng)盤/linux編程源代碼/socket下相關(guān)代碼
嵌入式知識點復(fù)習七 --linux字符型設(shè)備驅(qū)動初步
一花沉、Linux字符設(shè)備驅(qū)動初步
1柳爽、Linux設(shè)備類型
(1)字符設(shè)備:只能一個字節(jié)一個字節(jié)的讀寫的設(shè)備,不能隨機讀取設(shè)備內(nèi)存中的某一數(shù)據(jù)碱屁,讀取數(shù)據(jù)需要按照先后順序進行磷脯。字符設(shè)備是面向流的設(shè)備,常見的字符設(shè)備如鼠標娩脾、鍵盤赵誓、串口、控制臺柿赊、LED等俩功。
(2)塊設(shè)備:是指可以從設(shè)備的任意位置讀取一定長度的數(shù)據(jù)設(shè)備。塊設(shè)備如硬盤碰声、磁盤诡蜓、U盤和SD卡等存儲設(shè)備。
(3)網(wǎng)絡(luò)設(shè)備:網(wǎng)絡(luò)設(shè)備比較特殊胰挑,不在是對文件進行操作蔓罚,而是由專門的網(wǎng)絡(luò)接口來實現(xiàn)。應(yīng)用程序不能直接訪問網(wǎng)絡(luò)設(shè)備驅(qū)動程序洽腺。在/dev目錄下也沒有文件來表示網(wǎng)絡(luò)設(shè)備脚粟。
2、開發(fā)流程
3蘸朋、關(guān)鍵函數(shù)講解(以2.6以下版本內(nèi)核為例)
(1)驅(qū)動模塊注冊register_chrdev()函數(shù)
原型:register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)核无;
major:主設(shè)備號,該值為 0 時藕坯,自動運行分配团南。而實際值不是 0 ;
name:設(shè)備名稱炼彪;
fops:操作函數(shù)吐根,實現(xiàn)驅(qū)動定義的open、read辐马、write拷橘、close等內(nèi)核函數(shù)與應(yīng)用程序調(diào)用的open、read、write冗疮、close間的映射萄唇;
返回值:
major 值為 0 ,正常注冊后术幔,返回分配的主設(shè)備號另萤。如果分配失敗,返回 EBUSY 的負值 ( -EBUSY ) 诅挑。major 值若大于 linux/major.h (2.4內(nèi)核)中聲明的最大值 (#define MAX_CHRDEV 255) 四敞,則返回EINVAL 的負值 (-EINVAL) 。指定 major 值后拔妥,若有注冊的設(shè)備忿危,返回 EBUSY 的負值 (-EBUSY)。若正常注冊毒嫡,則返回 0 值
(2)驅(qū)動注銷unregister_chrdev()函數(shù)
原型:
#include <linux.fs.h>
int unregister_chrdev (unsigned int major, const char *name)
變量:
?major 主設(shè)備號
?name 設(shè)備文件
返回值:
major 值若大于 linux/major.h (2.4 內(nèi)核)中聲明的最大值 (#define MAX_CHRDEV 255)癌蚁,返回 EINVAL的負值 (-EINVAL)。指定了 major的值后兜畸,若將要注銷的 major 值并不是注冊的設(shè)備驅(qū)動程序努释,返回 EINVAL的負值 ( -EINVAL )。正常注銷則返回 0值咬摇。
(3)File_operation結(jié)構(gòu)體
file_operations結(jié)構(gòu)是建立驅(qū)動程序和設(shè)備編號的連接伐蒂,內(nèi)部是一組函數(shù)指針,每個打開的文件肛鹏,也就是file結(jié)構(gòu)逸邦,和一組函數(shù)關(guān)聯(lián),這些操作主要用來實現(xiàn)系統(tǒng)調(diào)用的
struct file_operations {
struct module *owner;//擁有該結(jié)構(gòu)的模塊的指針在扰,一般為THIS_MODULES
loff_t (*llseek) (struct file *, loff_t, int);//用來修改文件當前的讀寫位置
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//從設(shè)備中同步讀取數(shù)據(jù)
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//向設(shè)備發(fā)送數(shù)據(jù)
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一個異步的讀取操作
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一個異步的寫入操作
int (*readdir) (struct file *, void *, filldir_t);//僅用于讀取目錄缕减,對于設(shè)備文件,該字段為NULL
unsigned int (*poll) (struct file *, struct poll_table_struct *); //輪詢函數(shù)芒珠,判斷目前是否可以進行非阻塞的讀寫或?qū)懭?/p>
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //執(zhí)行設(shè)備I/O控制命令
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系統(tǒng)桥狡,將使用此種函數(shù)指針代替ioctl
long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系統(tǒng)上,32位的ioctl調(diào)用將使用此函數(shù)指針代替
int (*mmap) (struct file *, struct vm_area_struct *); //用于請求將設(shè)備內(nèi)存映射到進程地址空間
int (*open) (struct inode *, struct file *); //打開
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *); //關(guān)閉
int (*fsync) (struct file *, struct dentry *, int datasync); //刷新待處理的數(shù)據(jù)
int (*aio_fsync) (struct kiocb *, int datasync); //異步刷新待處理的數(shù)據(jù)
int (*fasync) (int, struct file *, int); //通知設(shè)備FASYNC標志發(fā)生變化
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};