第二章字符設(shè)備驅(qū)動(dòng)程序_第1頁
第二章字符設(shè)備驅(qū)動(dòng)程序_第2頁
第二章字符設(shè)備驅(qū)動(dòng)程序_第3頁
第二章字符設(shè)備驅(qū)動(dòng)程序_第4頁
第二章字符設(shè)備驅(qū)動(dòng)程序_第5頁
已閱讀5頁,還剩39頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

上章回顧Linux設(shè)備驅(qū)動(dòng)的簡介,以及分類字符設(shè)備塊設(shè)備網(wǎng)絡(luò)接口模塊的應(yīng)用如何編寫模塊模塊相關(guān)的宏模塊和應(yīng)用程序的區(qū)別編譯和裝載內(nèi)核模塊字符設(shè)備驅(qū)動(dòng)程序第2章預(yù)習(xí)檢查本章目標(biāo)掌握字符設(shè)備驅(qū)動(dòng)程序的基本結(jié)構(gòu)和開發(fā)方法掌握用戶空間調(diào)用設(shè)備驅(qū)動(dòng)程序的方法本章結(jié)構(gòu)字符設(shè)備驅(qū)動(dòng)基本結(jié)構(gòu)

字符設(shè)備驅(qū)動(dòng)程序

用戶空間調(diào)用設(shè)備驅(qū)動(dòng)程序

添加驅(qū)動(dòng)程序到內(nèi)核

內(nèi)核配置和編譯方法添加驅(qū)動(dòng)程序到內(nèi)核中主要概念和結(jié)構(gòu)體實(shí)例字符驅(qū)動(dòng)的主要組成2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)字符設(shè)備開發(fā)的基本步驟確定主設(shè)備號和次設(shè)備號實(shí)現(xiàn)字符驅(qū)動(dòng)程序?qū)崿F(xiàn)file_operations結(jié)構(gòu)體實(shí)現(xiàn)初始化函數(shù),注冊字符設(shè)備實(shí)現(xiàn)銷毀函數(shù),釋放字符設(shè)備創(chuàng)建設(shè)備文件節(jié)點(diǎn)2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)什么是主設(shè)備號/次設(shè)備號主設(shè)備號是內(nèi)核識別一個(gè)設(shè)備的標(biāo)識。整數(shù)(占12bits),范圍從0到4095,通常使用1到255次設(shè)備號由內(nèi)核使用,用于正確確定設(shè)備文件所指的設(shè)備。整數(shù)(占20bits),范圍從0到1048575,一般使用0到2552-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)設(shè)備編號的內(nèi)部表達(dá)dev_t類型(32位):用來保存設(shè)備編號(包括主設(shè)備號(12位)和次設(shè)備號(20位))從dev_t獲得主設(shè)備號和次設(shè)備號:MAJOR(dev_t);MINOR(dev_t);將主設(shè)備號和次設(shè)備號轉(zhuǎn)換成dev_t類型:MKDEV(intmajor,intminor);

2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)分配主設(shè)備號手工分配主設(shè)備號:找一個(gè)內(nèi)核沒有使用的主設(shè)備號來使用。#include<linux/fs.h>int

register_chrdev_region(dev_tfirst,unsignedintcount,char*name);要分配的設(shè)備編號范圍的起始值,次設(shè)備號經(jīng)常為0所請求的連續(xù)設(shè)備編號的個(gè)數(shù)和該編號范圍關(guān)聯(lián)的設(shè)備名稱2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)動(dòng)態(tài)分配主設(shè)備號:#include<linux/fs.h>intalloc_chrdev_resion(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name);輸出的設(shè)備號要使用的被請求的第一個(gè)次設(shè)備號2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)釋放設(shè)備號void

unregister_chrdev_region(dev_tfirst,unsignedintcount);通常在模塊的清除函數(shù)中調(diào)用。2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)實(shí)現(xiàn)字符驅(qū)動(dòng)程序cdev結(jié)構(gòu)體structcdev{ structkobjectkobj;/*內(nèi)嵌的kobject對象*/ structmodule*owner;/*所屬模塊*/ structfile_operations*ops;/*文件操作結(jié)構(gòu)體*/ structlist_headlist; dev_tdev;/*設(shè)備號*/ unsignedintcount;};2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)操作cdev的函數(shù)voidcdev_init(structcdev*,structfile_operations*);structcdev*cdev_alloc(void);intcdev_add(structcdev*,dev_t,unsigned);voidcdev_del(structcdev*);用于初始化cdev的成員,并建立cdev和file_operations之間的連接分別向系統(tǒng)刪除一個(gè)cdev,完成字符設(shè)備的注銷,通常在模塊的卸載函數(shù)中調(diào)用分別向系統(tǒng)添加一個(gè)cdev,完成字符設(shè)備的注冊,通常在模塊加載函數(shù)中調(diào)用函數(shù)用于動(dòng)態(tài)申請一個(gè)cdev內(nèi)存2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)file_operations結(jié)構(gòu)體字符驅(qū)動(dòng)和內(nèi)核的接口:在include/linux/fs.h定義字符驅(qū)動(dòng)只要實(shí)現(xiàn)一個(gè)file_operations結(jié)構(gòu)體并注冊到內(nèi)核中,內(nèi)核就有了操作此設(shè)備的能力。2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)

file_operations的主要成員:structmodule*owner:

指向模塊自身open:打開設(shè)備release:關(guān)閉設(shè)備read:從設(shè)備上讀數(shù)據(jù)write:向設(shè)備上寫數(shù)據(jù)ioctl:I/O控制函數(shù)llseek:定位讀寫指針mmap:映射設(shè)備空間到進(jìn)程的地址空間2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)file結(jié)構(gòu)體

file結(jié)構(gòu):file_operations結(jié)構(gòu)相關(guān)的一個(gè)結(jié)構(gòu)體。描述一個(gè)正在打開的設(shè)備文件。成員:loff_tf_pos:

當(dāng)前讀/寫位置unsignedintf_flags標(biāo)識文件打開時(shí),是否可讀或可寫O_RDONLYO_NONBLOCKO_SYNCstructfile_operations*f_op文件相關(guān)的操作,指向所實(shí)現(xiàn)的structfile_operationsvoid*private_data:

私有數(shù)據(jù)指針。驅(qū)動(dòng)程序可以將這個(gè)字段用于任何目的或者忽略這個(gè)字段。2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)inode結(jié)構(gòu)體內(nèi)核用inode結(jié)構(gòu)在內(nèi)部表示文件Inode與file的區(qū)別file表示打開的文件描述符多個(gè)表示打開的文件描述符的file結(jié)構(gòu),可以指向單個(gè)inode結(jié)構(gòu)。2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)Inode結(jié)構(gòu)中的兩個(gè)主要字段:dev_ti_rdev;對表示設(shè)備文件的inode結(jié)構(gòu),該字段包含了真正的設(shè)備編號。structcdev*i_cdev;structcdev是表示字符設(shè)備的內(nèi)核的內(nèi)部結(jié)構(gòu)。當(dāng)inode指向一個(gè)字符設(shè)備文件時(shí),該字段包含了指向structcdev結(jié)構(gòu)的指針從一個(gè)inode中獲得主設(shè)備號和次設(shè)備號:unsignedintiminor(structinode*inode);unsignedintimajor(structinode*inode);2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)注冊設(shè)備

,在模塊或驅(qū)動(dòng)初始化時(shí)調(diào)用Linux-2.4及之前Linux-2.6intregister_chrdev(unsignedintmajor,constchar*name, structfile_operations*fops)如何操作字符設(shè)備的接口voidcdev_init(structcdev*,structfile_operations*);intcdev_add(structcdev*,dev_t,unsigned);2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)注銷設(shè)備:在模塊卸載時(shí)調(diào)用Linux-2.4及之前Linux-2.6intunregister_chrdev(unsignedintmajor, constchar*name);voidcdev_del(structcdev*);2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)//設(shè)備驅(qū)動(dòng)模塊加載函數(shù)staticint__initxxx_init(void){ ... cdev_init(&xxx_dev.cdev,&xxx_fops);//初始化cdev xxx_dev.cdev.owner=THIS_MODULE; //獲取字符設(shè)備號 if(xxx_major) { register_chrdev_region(xxx_dev_no,1,DEV_NAME); } else { alloc_chrdev_region(&xxx_dev_no,0,1,DEV_NAME); } ret=cdev_add(&xxx_dev.cdev,xxx_dev_no,1);//注冊設(shè)備 ...}2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)/*設(shè)備驅(qū)動(dòng)模塊卸載函數(shù)*/staticvoid__exitxxx_exit(void){ unregister_chrdev_region(xxx_dev_no,1);//釋放占用的設(shè)備號

cdev_del(&xxx_dev.cdev);//注銷設(shè)備 ...}2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)打開模塊使用計(jì)數(shù)加1識別次設(shè)備號硬件操作:檢查設(shè)備相關(guān)錯(cuò)誤(諸如設(shè)備未就緒或類似的硬件問題);如果設(shè)備是首次打開,則對其初始化;如果有中斷操作,申請中斷處理程序;intopen(structinode*inode,structfile*filp);2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)關(guān)閉模塊使用計(jì)數(shù)減1釋放由open分配的,保存在filp>private_data里的所有內(nèi)容。硬件操作:如果申請了中斷,則釋放中斷處理程序。在最后一次關(guān)閉操作時(shí)關(guān)閉設(shè)備。intrelease(structinode*inode,structfile*filp);2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)

read/writessize_tread(structfile*filp,char__user*buff,size_tcount,loff_t*offp);ssize_twrite(structfile*filp,constchar__user*buff,size_tcount,loff_t*offp);指向用戶空間的緩沖區(qū),這個(gè)緩沖區(qū)或者保存將寫入的數(shù)據(jù),或者是一個(gè)存放新讀入數(shù)據(jù)的空緩沖區(qū)。用戶在文件中存取操作的位置2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)

用戶空間和內(nèi)核空間之間的數(shù)據(jù)拷貝過程,不能簡單的用指針操作或者memcpy來進(jìn)行數(shù)據(jù)拷貝用戶空間的數(shù)據(jù)是可以被換出的,會(huì)產(chǎn)生一個(gè)頁面失效異常。用戶空間的地址無法在內(nèi)核空間中使用。用戶空間和內(nèi)核空間之間進(jìn)行數(shù)據(jù)拷貝的函數(shù):如果要復(fù)制的內(nèi)存是簡單類型,如char、int、long等,put_user()和get_user()unsignedlongcopy_from_user(void*to,constvoid__user*from,unsignedlongcount);unsignedlongcopy_to_user(void__user*to,constvoid*from,unsignedlongcount);2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)讀設(shè)備模板ssize_txxx_read(structfile*filp,char__user*buf, size_tcount,loff_t*f_pos){ ... copy_to_user(buf,...,...); ...}寫設(shè)備模板ssize_txxx_write(structfile*filp,constchar__user*buf, size_tcount,loff_t*f_pos){ ... copy_from_user(...,buf,...); ...}2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)

ioctl函數(shù)為設(shè)備驅(qū)動(dòng)程序執(zhí)行“命令”提供了一個(gè)特有的入口點(diǎn)用來設(shè)置或者讀取設(shè)備的屬性信息。intioctl(structinode*inode,structfile*filp, unsignedintcmd,unsignedlongarg);事先定義的IO控制命令

代碼arg為對應(yīng)于cmd命令的參數(shù)2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)cmd參數(shù)的定義不推薦用0x1,0x2,0x3之類的值Linux對ioctl()的cmd參數(shù)有特殊的定義構(gòu)造命令編號的宏:_IO(type,nr)用于構(gòu)造無參數(shù)的命令編號;_IOR(type,nr,datatype)用于構(gòu)造從驅(qū)動(dòng)程序中讀取數(shù)據(jù)的命令編號;_IOW(type,nr,datatype)用于寫入數(shù)據(jù)的命令;_IOWR(type,nr,datatype)用于雙向傳輸。type和number位字段通過參數(shù)傳入,而size位字段通過對datatype參數(shù)取sizeof獲得。

設(shè)備類型(type)

序列號(number)方向(direction)

數(shù)據(jù)尺寸(size)

8bit

8bit

2bit13/14bit2-1字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)Ioctl函數(shù)模板intxxx_ioctl(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg){ ... switch(cmd) { caseXXX_CMD1: ... break; caseXXX_CMD2: ... break; default:///*不能支持的命令*/ return-ENOTTY; } return0;}階段總結(jié)本節(jié)介紹了字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)2-2添加驅(qū)動(dòng)程序到內(nèi)核配置內(nèi)核編譯內(nèi)核添加驅(qū)動(dòng)程序到內(nèi)核中2-2添加驅(qū)動(dòng)程序到內(nèi)核配置內(nèi)核配置命令包括: makeconfig makemenuconfig makexconfig makegconfig

可通過“上”、“下”、“左”、“右”鍵移動(dòng)菜單,選擇某項(xiàng)按“Y”,取消選擇按“N”,如果選擇某項(xiàng)編譯為模塊按“M”,進(jìn)入子菜單按“Enter”,返回上一級菜單按“Esc”使用makeconfig、makemenuconfig等命令后,會(huì)生成一個(gè).config配置文件(是隱身文件,通過ls–a才能看到)

2-2添加驅(qū)動(dòng)程序到內(nèi)核編譯內(nèi)核可用如下命令編譯內(nèi)核:makeARC=armCROSS_COMPILE=arm-linux-zImage源代碼根目錄的Makefile中將ARCH和CROSS_COMPILE直接指定為arm和arm-linux-,如:

這樣就沒有必要每次編譯的時(shí)候都指定體系結(jié)構(gòu)和交叉編譯器了,只須使用下面命令就可以了:

makezImageARCH ?=armCROSS_COMPILE ?=arm-linux-2-2添加驅(qū)動(dòng)程序到內(nèi)核添加驅(qū)動(dòng)程序到內(nèi)核Linux2.6內(nèi)核的配置系統(tǒng)由以下3個(gè)部分組成。Makefile:分布在Linux內(nèi)核源代碼中的Makefite定義Linux內(nèi)核的編譯規(guī)則配置文件(Kconfig):給用戶提供配置選擇的功能。配置工具:包括配置命令解釋器(對配置腳本中使用的配置命令進(jìn)行解釋)配置用戶界面(提供字符界面和圖形界面)。這些配置工具都是使用腳本語言編寫的,如Tcl/TK、Perl等。在Linux內(nèi)核中增加程序需要完成以下3項(xiàng)工作。將編寫的源代碼復(fù)制到Linux內(nèi)核源代碼的相應(yīng)目錄。在目錄的Kconfig文件中增加新源代碼對應(yīng)項(xiàng)目的編譯配置選項(xiàng)。在目錄的Makefile文件中增加對新源代碼的編譯條目。2-2添加驅(qū)動(dòng)程序到內(nèi)核實(shí)例:在內(nèi)核源代碼drivers目錄下為ARM體系結(jié)構(gòu)新增testdrivertestdriver的樹形目錄:步驟:

1、拷貝test到drivers路徑下 2、為新增目錄創(chuàng)建Kconfig和Makefile 3、修改新增目錄父目錄的Kconfig和 Makefile,以便新增的Kconfig和 Makefile能夠被引用 4、在arch/arm/Kconfig里增加 source“drivers/test/Kconfig”2-2添加驅(qū)動(dòng)程序到內(nèi)核步驟:1、拷貝test到drivers路徑下cp–frtestlinux_kernel_path/drivers2、為新增目錄創(chuàng)建Kconfig和Makefile

2-2添加驅(qū)動(dòng)程序到內(nèi)核修改新增目錄的父目錄的Kconfig和Makefile在drivers/Kconig中加入:source"drivers/test/Kconfig“在drivers/Makefile中加入:obj-$(CONFIG_TEST)+=

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論