




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第11章 設(shè)備管理第11章 設(shè)備管理1
Linux和其他操作系統(tǒng)一樣,支持眾多的、各式各樣的外接設(shè)備。 但是,面對(duì)層出不窮的新硬件產(chǎn)品,必須有人不斷編寫(xiě)新的驅(qū)動(dòng)程序,以便讓這些設(shè)備能夠在Linux下正常工作,從這個(gè)意義上講,講述驅(qū)動(dòng)程序的編寫(xiě)就是一件非常有意義的工作。 本章也涉及到Linux下設(shè)備管理的原則和方法。 Linux和其他操作系統(tǒng)一樣,支持眾多的、各式各樣的2 舉例來(lái)說(shuō),Linux下的驅(qū)動(dòng)程序僅僅是為相應(yīng)的設(shè)備編寫(xiě)幾個(gè)基本函數(shù),并向VFS注冊(cè)就可以安裝成功了。 當(dāng)應(yīng)用程序需要設(shè)備時(shí),可以訪問(wèn)該設(shè)備對(duì)應(yīng)的文件節(jié)點(diǎn),利用VFS調(diào)用該設(shè)備的相關(guān)處理函數(shù)。 舉例來(lái)說(shuō),Linux下的驅(qū)動(dòng)程序僅僅是為相應(yīng)的設(shè)備編3 本章主要介紹了設(shè)備管理方面的有關(guān)知識(shí): ◆系統(tǒng)管理設(shè)備的方式。 ◆驅(qū)動(dòng)程序運(yùn)作過(guò)程。 ◆驅(qū)動(dòng)程序的具體實(shí)例。 本章主要介紹了設(shè)備管理方面的有關(guān)知識(shí):411.1設(shè)備管理結(jié)構(gòu)11.1設(shè)備管理結(jié)構(gòu)511.1.1概述
設(shè)備管理即輸入輸出子系統(tǒng),可分為上下兩部分:一部分是上層的,與設(shè)備無(wú)關(guān)的,這部分根據(jù)輸入輸出請(qǐng)求,通過(guò)特定的設(shè)備驅(qū)動(dòng)程序接口,來(lái)與設(shè)備進(jìn)行通信。 另一部分是下層的,與設(shè)備有關(guān)的,常稱為設(shè)備驅(qū)動(dòng)程序,它直接與相應(yīng)設(shè)備打交道,并且向上層提供一組訪問(wèn)接口。11.1.1概述 設(shè)備管理即輸入輸出子系統(tǒng),6 設(shè)備管理的目標(biāo)是對(duì)所有的外接設(shè)備進(jìn)行良好的讀、寫(xiě)、控制等操作。 首先要解決的問(wèn)題就是怎樣將任意的一個(gè)設(shè)備的所有操作進(jìn)行歸納,設(shè)計(jì)出統(tǒng)一的接口。 內(nèi)核常常使用設(shè)備類型、主設(shè)備號(hào)和次設(shè)備號(hào)來(lái)標(biāo)識(shí)一個(gè)具體的設(shè)備。 設(shè)備管理的目標(biāo)是對(duì)所有的外接設(shè)備進(jìn)行良好的讀、寫(xiě)、控7 但用戶希望能用同樣的應(yīng)用程序和命令來(lái)訪問(wèn)設(shè)備和普通文件。 為此,Linux中的設(shè)備管理應(yīng)用了設(shè)備文件這個(gè)概念來(lái)統(tǒng)一設(shè)備的訪問(wèn)接口。 簡(jiǎn)單的說(shuō),系統(tǒng)試圖使它對(duì)所有各類設(shè)備的輸入、輸出看起來(lái)就好像對(duì)普通文件的輸入、輸出一樣。 但用戶希望能用同樣的應(yīng)用程序和命令來(lái)訪問(wèn)設(shè)備和普通文8
如圖11-1所示,應(yīng)用程序通過(guò)Linux的系統(tǒng)調(diào)用與內(nèi)核通信。 如圖11-1所示,應(yīng)用程序通過(guò)Linux的系統(tǒng)調(diào)用與9圖11-1Linux內(nèi)核體系結(jié)構(gòu)圖11-1Linux內(nèi)核體系結(jié)構(gòu)10 由于Linux中將設(shè)備當(dāng)作文件來(lái)處理,所以對(duì)設(shè)備進(jìn)行操作的系統(tǒng)調(diào)用和對(duì)文件操作的類似,主要包括open()、read()、write()、ioctl()、close()等。 應(yīng)用程序發(fā)出系統(tǒng)調(diào)用指令以后,會(huì)從用戶態(tài)轉(zhuǎn)換到內(nèi)核態(tài),通過(guò)內(nèi)核將open()這樣的系統(tǒng)調(diào)用轉(zhuǎn)換成對(duì)物理設(shè)備的操作。 由于Linux中將設(shè)備當(dāng)作文件來(lái)處理,所以對(duì)設(shè)備進(jìn)行1111.1.2字符設(shè)備與塊設(shè)備
字符設(shè)備以字節(jié)為單位進(jìn)行數(shù)據(jù)處理。字符設(shè)備通常只允許按順序訪問(wèn),一般不使用緩存技術(shù)。如鼠標(biāo),聲卡等。
塊設(shè)備以塊為單位進(jìn)行處理,塊的大小通常為0.5KB到32KB等。11.1.2字符設(shè)備與塊設(shè)備 字符設(shè)備以字節(jié)12 大多數(shù)塊設(shè)備允許隨機(jī)訪問(wèn),而且常常采用緩存技術(shù)。 塊設(shè)備有硬盤(pán)、光盤(pán)驅(qū)動(dòng)器等??梢圆榭次募?proc/devices獲得。 我們這里主要討論字符設(shè)備,有興趣的讀者可參考其它書(shū)籍中有關(guān)塊設(shè)備的內(nèi)容。 大多數(shù)塊設(shè)備允許隨機(jī)訪問(wèn),而且常常采用緩存技術(shù)。1311.1.3主設(shè)備號(hào)和次設(shè)備號(hào) 設(shè)備管理中,除了設(shè)備類型(字符設(shè)備或塊設(shè)備)以外,內(nèi)核還需要一對(duì)稱做主、次設(shè)備號(hào)的參數(shù),才能唯一表示設(shè)備。11.1.3主設(shè)備號(hào)和次設(shè)備號(hào) 設(shè)備管理中14 主設(shè)備號(hào)(majornumber)相同的設(shè)備使用相同的驅(qū)動(dòng)程序,而次設(shè)備號(hào)(minornumber)用來(lái)區(qū)分具體設(shè)備的實(shí)例。 例如,第一IDE接口上的所有磁盤(pán)及其分區(qū)共用同一主設(shè)備號(hào)3,而次設(shè)備號(hào)則為0,1,2,3…。 主設(shè)備號(hào)(majornumber)相同的設(shè)備使用相1511.1.4Linux設(shè)備命名習(xí)慣: Linux習(xí)慣上將設(shè)備文件放在目錄/dev或其子目錄之下。
設(shè)備文件命名(通常由兩部分組成)規(guī)則為:第一部分通常較短,可能只有2或3個(gè)字母組成,用來(lái)表示設(shè)備大類。11.1.4Linux設(shè)備命名習(xí)慣: Li16 例如,普通硬盤(pán)如IDE接口的為“hd”,軟盤(pán)為“fd”。第二部分通常為數(shù)字或字母用來(lái)區(qū)別設(shè)備實(shí)例。 例如,/dev/hda、/dev/hdb、/dev/hdc表示第一、二、三塊硬盤(pán);而dev/hda1、/dev/hda2、/dev/hda3則表示第一硬盤(pán)的第一、二、三分區(qū)。 例如,普通硬盤(pán)如IDE接口的為“hd”,軟盤(pán)為“fd1711.2驅(qū)動(dòng)程序11.2驅(qū)動(dòng)程序1811.2.1驅(qū)動(dòng)程序基本功能 在Linux操作系統(tǒng)中驅(qū)動(dòng)程序是操作系統(tǒng)內(nèi)核與硬件設(shè)備之間的橋梁,它屏蔽了硬件的細(xì)節(jié)(如總線協(xié)議、DMA操作等),在應(yīng)用程序看來(lái)硬件設(shè)備只是一個(gè)特殊的文件。
11.2.1驅(qū)動(dòng)程序基本功能 在Linux19 驅(qū)動(dòng)程序的基本功能為:
1.對(duì)設(shè)備初始化和釋放。如對(duì)音頻設(shè)備而言包括向內(nèi)核注冊(cè)設(shè)備,設(shè)置音頻的輸入輸出參數(shù)(如采樣頻率、采樣寬度等)、分配音頻設(shè)備使用的內(nèi)核內(nèi)存等工作。
2.對(duì)設(shè)備進(jìn)行管理。包括實(shí)時(shí)參數(shù)設(shè)置以及提供對(duì)設(shè)備的操作接口。 驅(qū)動(dòng)程序的基本功能為:20
3.讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)并回送應(yīng)用程序請(qǐng)求的數(shù)據(jù)。這需要在用戶空間、內(nèi)核空間、總線及外設(shè)之間傳輸數(shù)據(jù)。
4.檢測(cè)和處理設(shè)備出現(xiàn)的錯(cuò)誤。 3.讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)并回送應(yīng)用程序請(qǐng)求的2111.2.2驅(qū)動(dòng)程序的運(yùn)作過(guò)程 為了便于讀者理解,在此結(jié)合大家比較熟悉的鍵盤(pán)來(lái)了解其運(yùn)作過(guò)程。
如圖11-2所示.11.2.2驅(qū)動(dòng)程序的運(yùn)作過(guò)程 為了便于讀者22圖11-2驅(qū)動(dòng)程序的實(shí)現(xiàn)過(guò)程圖11-2驅(qū)動(dòng)程序的實(shí)現(xiàn)過(guò)程23 當(dāng)一個(gè)程序讀/dev/tty文件(此為鍵盤(pán))時(shí),就會(huì)執(zhí)行系統(tǒng)調(diào)用sys_read()(在fs/read_write.c中),該系統(tǒng)調(diào)用在判別出所讀文件是一個(gè)字符設(shè)備文件時(shí),即會(huì)調(diào)用rw_char()函數(shù)(在fs/char_dev.c中), 該函數(shù)則會(huì)根據(jù)所讀設(shè)備的設(shè)備類型,主、次設(shè)備號(hào)等參數(shù),由字符設(shè)備讀寫(xiě)函數(shù)表(設(shè)備開(kāi)關(guān)表)調(diào)用rw_tty(),最終調(diào)用到這里的終端讀操作函數(shù)tty_read() 當(dāng)一個(gè)程序讀/dev/tty文件(此為鍵盤(pán))時(shí),就會(huì)24 當(dāng)用戶在鍵盤(pán)上鍵入了一個(gè)字符時(shí),會(huì)引起鍵盤(pán)中斷響應(yīng),此時(shí)鍵盤(pán)中斷處理程序就會(huì)從鍵盤(pán)控制器讀入對(duì)應(yīng)的鍵盤(pán)掃描碼,然后根據(jù)使用的鍵盤(pán)掃描碼映射表譯成相應(yīng)字符,放入tty讀隊(duì)列read_q中。 當(dāng)用戶在鍵盤(pán)上鍵入了一個(gè)字符時(shí),會(huì)引起鍵盤(pán)中斷響應(yīng),25 然后調(diào)用中斷處理程序的do_tty_interrupt()函數(shù),它又直接調(diào)用行規(guī)則函數(shù)copy_to_cooked()對(duì)該字符進(jìn)行過(guò)濾處理,并放入tty輔助隊(duì)列secondary中,供上述tty_read()讀取。 然后調(diào)用中斷處理程序的do_tty_interrup26 同時(shí)把該字符放入tty寫(xiě)隊(duì)列write_q中,并調(diào)用寫(xiě)控制臺(tái)函數(shù)con_write()。 此時(shí)如果該終端的回顯(echo)屬性是設(shè)置的,則該字符會(huì)顯示到屏幕上(注:do_tty_interrupt()和copy_to_cooked()函數(shù)在tty_io.c中實(shí)現(xiàn))。 同時(shí)把該字符放入tty寫(xiě)隊(duì)列write_q中,并調(diào)用2711.2.2常用接口介紹
open():打開(kāi)設(shè)備,并初始化設(shè)備準(zhǔn)備進(jìn)行操作??梢詾镹ULL,這樣每次打開(kāi)設(shè)備總會(huì)成功,而且不通知設(shè)備驅(qū)動(dòng)程序。
read():從設(shè)備中讀數(shù)據(jù),需要提供字符串指針。
write():向字符設(shè)備寫(xiě)數(shù)據(jù),需要提供所寫(xiě)內(nèi)容指針。
ioctl():控制設(shè)備,例如控制光盤(pán)的彈出等。需要提供符合設(shè)備預(yù)先定義的命令字。11.2.2常用接口介紹 open():28
llseek():重新定位讀、寫(xiě)位置,需要提供偏移量參數(shù)。
flush():清除內(nèi)容。
release():關(guān)閉設(shè)備,并釋放資源等。
mmap():將設(shè)備內(nèi)存映射到進(jìn)程地址空間。通常只有塊設(shè)備驅(qū)動(dòng)程序使用。 llseek():重新定位讀、寫(xiě)位置,需要提供偏移量2911.2.3常用函數(shù)原型
1.設(shè)備操作函數(shù)原形 structfile_operations { structmodule*owner; loff_t(*llseek)(structfile*,loff_t,int); ssize_t(*read)(structfile*,char*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar *,size_t,loff_t*); int(*readdir)(structfile*,void*,filldir_t);11.2.3常用函數(shù)原型 1.設(shè)備操作函數(shù)原形30 unsignedint(*poll)(structfile*,struct poll_table_struct*); int(*ioctl)(structinode*,structfile*,unsigned int,unsignedlong); int(mmap)(structfile*,structvm_area_struct*); int(*open)(structinode*,structfile*); int(*flush)(structfile*); int(*release)(structinode*,structfile*); unsignedint(*poll)(structf31 int(*fsync)(structfile,structdentry*,int datasync); int(*fasync)(int,structfile*,int); int(*lock)(structfile*,intstructfile_lock*); ssize_t(*readv)(structfile*,conststructiovec *,unsignedlong,loff_t*); ssize_t(*writev)(structfile*,conststructiovec *,unsignedlong,loff_t*); } int(*fsync)(structfile,s32 2.向系統(tǒng)注冊(cè)的函數(shù)原形 int
register_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops) { if(major==0) { write_lock(&chrdevs_lock); 2.向系統(tǒng)注冊(cè)的函數(shù)原形33 for(major=MAX_CHRDEV-1;major>0;major--) { if(chrdevs[major].fops==NULL) { chrdevs[major].name=name; chrdevs[major].fops=fops; write_unlock(&chrdevs_lock); returnmajor; } } for(major=MAX_CHRDEV-1;major>34 write_unlock(&chrdevs_lock); return-EBUSY; } if(major>MAX_CHRDEV) return-EINVAL; write_lock(&chrdevs_lock); write_unlock(&chrdevs_lock);35 if(chrdevs[major].fops&&chrdevs[major].fops!=fops) { write_unlock(&chrdevs_lock); return-EBUSY; } chrdevs[major].name=name; chrdevs[major].fops=fops; write_unlock(&chrdevs_lock); return0; } if(chrdevs[major].fops&&chr3611.3驅(qū)動(dòng)程序編寫(xiě)實(shí)例 為了更清楚地講述Linux中設(shè)備驅(qū)動(dòng)程序的編寫(xiě),加深讀者對(duì)啟動(dòng)程序的了解。下面介紹一個(gè)簡(jiǎn)單的設(shè)備驅(qū)動(dòng)的實(shí)現(xiàn)過(guò)程。 由于基于特殊的硬件設(shè)備實(shí)現(xiàn)的驅(qū)動(dòng)程序難度較大,而且不方便驗(yàn)證,下面舉一個(gè)虛擬設(shè)備驅(qū)動(dòng)程序的例子。11.3驅(qū)動(dòng)程序編寫(xiě)實(shí)例 為了更清楚地講述3711.3.1設(shè)備功能介紹 實(shí)現(xiàn)虛擬設(shè)備的寫(xiě)入、讀出等操作。這個(gè)驅(qū)動(dòng)程序并不是基于特定硬件設(shè)備的,實(shí)際上僅僅是對(duì)內(nèi)存進(jìn)行讀、寫(xiě)操作。11.3.1設(shè)備功能介紹 實(shí)現(xiàn)虛擬設(shè)備的寫(xiě)入38 當(dāng)執(zhí)行寫(xiě)入操作時(shí),將會(huì)對(duì)特定的存儲(chǔ)空間進(jìn)行寫(xiě)入;當(dāng)執(zhí)行讀出操作時(shí),將會(huì)對(duì)該存儲(chǔ)空間進(jìn)行數(shù)據(jù)的讀??;同時(shí)還可以利用ioctl進(jìn)行清除該存儲(chǔ)空間的操作。 這個(gè)mydrv設(shè)備的實(shí)現(xiàn)文件是mydrv.c,其中的文件接口flle_operations{}提供了mydrv_open、mydrv_release、mydrv_read、mydrv_write、mydrv_ioctl等函數(shù)。 當(dāng)執(zhí)行寫(xiě)入操作時(shí),將會(huì)對(duì)特定的存儲(chǔ)空間進(jìn)行寫(xiě)入;當(dāng)執(zhí)39 1.函數(shù)mydrv_read()的功能是從mybuf[110]中讀取字符串,并傳遞給調(diào)用的進(jìn)程。 2.函數(shù)mydrv_write()的功能是將調(diào)用的進(jìn)程傳入的字符串賦值給mybuf,如果字符串的長(zhǎng)度超過(guò)110,則只取前110個(gè)字符。 3.函數(shù)mydrv_ioctl()中僅僅實(shí)現(xiàn)了一個(gè)控制功能:清除mybuf存儲(chǔ)區(qū)。 1.函數(shù)mydrv_read()的功能是從mybuf[14011.3.2具體實(shí)現(xiàn) 首先,要根據(jù)設(shè)備功能的需要,編寫(xiě)file_operations結(jié)構(gòu)中的操作函數(shù)。 其次,要向系統(tǒng)注冊(cè)該設(shè)備,包括字符設(shè)備的注冊(cè),devfs節(jié)點(diǎn)的注冊(cè)與中斷響應(yīng)函數(shù)的注冊(cè)。然后就可以利用對(duì)應(yīng)的文件進(jìn)行設(shè)備操控了。具體如下:11.3.2具體實(shí)現(xiàn) 首先,要根據(jù)設(shè)備功能的41 1.源程序 #include<linux/module.h> #include<linux/kernel.h> #include<linux/fs.h> #include<linux/types.h> #include<linux/malloc.h> #include<asm/uaccess.h> #include<asm/page.h> #include<linux/ermo.h> #include<linux/config.h> 1.源程序42 #defineMYDRV_CLS_IO('c',0x01)
//定義清存儲(chǔ)區(qū)命令字 charmybuf[110];
//存儲(chǔ)區(qū)域 intmydrv_major=99;
//主設(shè)備號(hào) devfs_handle_tdev_handle;
//保存設(shè)備文件系統(tǒng)的注冊(cè)句柄 //第一步:編寫(xiě)file_operations函數(shù) #defineMYDRV_CLS_IO('c',043 ssize_tmydrv_read(structfile*filp,char*buf,size_tcount,loff_t*f_pos);//函數(shù)聲明 staticssize_tmydrv_write(structfile*filp,constchar*buf,size_tcount,loff_t*ppos); staticintmydrv_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg); intmydrv_open(structinode*inode,structfile*filp); intmydrv_release(structinode*inode,structfile*filp);//函數(shù)聲明 ssize_tmydrv_read(structfil44 structfile_operationsmydrv_ops={
//設(shè)備函數(shù)接口 open:mydrv_open,
//實(shí)現(xiàn)對(duì)設(shè)備的操作 read:mydrv_read, write:mydrv_write, ioctl:mydrv_ioctl, release:mydrv_release; };
//mydrv_read()將內(nèi)核空間的mybuf中的字符串賦給用戶空間的buf區(qū) structfile_operationsmydrv_45 ssize_tmydrv_read(structfile*filp,char*bur,size_tcount,loff_t*f_pos)
//filp:指向設(shè)備文件的指針;f_pos:偏移量 intlength=strlen(mybuf); if(count>99)count=99;
//忽略大于110部分 count=length-*f_pos;
//計(jì)算字符個(gè)數(shù)的技巧 ssize_tmydrv_read(structfil46 if(copy_to_user(buf,mybuf,count)){
//重內(nèi)核區(qū)復(fù)制到用戶區(qū) printk("errorreading,copy_to_user\n”); retum-EFAULT; } *f_pos+=count;//下一個(gè) retumcount; }
//mydtv_write()將用戶空間的buf字符串賦給內(nèi)核空間的mybuf[]數(shù)組中 if(copy_to_user(buf,mybuf,c47 staticssize_tmydrv_write(structfile*filp,constchar*buf,size_tcount,loff_t*ppos){ intnum; num=count<110?count:110; if(copy_from_user(mybuf,buf,num))//mybufbuf return-EFAULT; printk("mydrv_writesucceed!\n”); returnnum; } staticssize_tmydrv_write(st48 staticintmydrv_ioctl(structinode*inode,structfile*file,//如果傳人的命令字是 unsignedintcmd,unsignedlongarg){//MYDRV-CLS則清除mybuf數(shù)組內(nèi)容 switch(cmd){ caseMYDRV_CLS: mybuf[0]=0x0; return0; default: return-EINVAL; } }
//打開(kāi)mydrv設(shè)備時(shí)調(diào)用 staticintmydrv_ioctl(struc49 #defineMAX_MYDRV_DEV2 intmydrv_open(structinode*inode,structfile*filp){//inede:設(shè)備文件節(jié)點(diǎn) unsignedintdev=MINOR(inode->i_rdev); if(mydrv_num) return-1; #defineMAX_MYDRV_DEV250 if(dev>=MAX_MYDRV_DEV) return-ENODEV; filp->f_ap=&mydrv_ops;//指向操作函數(shù) printk(“opensuccess\n”); MOD_INC_USE_COUNT;//只是簡(jiǎn)單地加1 return0; }
//關(guān)閉mydrv設(shè)備,這里只是將引用次數(shù)減1 intmydrv_release(structinode*inode,structfile*filp){ MOD_DEC_USE_COUNT; return0; } if(dev>=MAX_MYDRV_DEV)51
//第二步:向系統(tǒng)注冊(cè)該設(shè)備 //module的安裝,采用兩種方式進(jìn)行了設(shè)備的注冊(cè) intinit_module(void) { intresult; printk(“initing...\n”); result=devfs_register_chrdev(mydrv_major,“mydrv”,&mydrv_ops); //第二步:向系統(tǒng)注冊(cè)該設(shè)備52 if(result<0){ printk(KERN_WARNING“mydrv:unabletogetmajor%d\n”,mydrv_major); returnresult; } dev_handle=devfs_register(NULL,“mydrv",DEVFS_FL_DEFAULT,99,0, S_IFCHR,&mydrv_ops,NULL);
//devfs_register(devfs_handle_tdir,constchar*name,unsignedintflags, //unsignedintmajor,unsignedintminor,umode_tmode,void*ops,void*info) if(result<0){53 if(mydrv_major:==0) mydrv_major=result; strcpy(mybuf,"Hello,pleasewriteanything(length<110)tomydrv.”); printk(“succeedingettingbuffer\n"); printk("%s\n",mybuf); retum0; }
//module的卸載,進(jìn)行設(shè)備的注銷(xiāo) if(mydrv_major:==0)54 voidcleanup_module(void) { devfs_unregister_chrdev(mydrv_major,“mydrv”); devfs_unregister(dev_handle); printk("exiting...\n"); } voidcleanup_module(void)55 2.設(shè)備驅(qū)動(dòng)程序編譯和安裝 采用下面的命令可以對(duì)mydrv.c進(jìn)行編譯: [root@Linuxroot]#gcc-cmydrv.c–D__KERNEL__-DMODULE-O2-g-Wall-o 如果沒(méi)有出錯(cuò)的話,將會(huì)在本目錄下生成一個(gè)mydrv.o文件。 2.設(shè)備驅(qū)動(dòng)程序編譯和安裝56 下面的操作必須是以root身份進(jìn)行的(用命令su轉(zhuǎn)換成root身份): 先執(zhí)行模塊的插入操作, [root@Unuxroot]#/sbin/insmodmydrv.o 下面的操作必須是以root身份進(jìn)行的(用命令su轉(zhuǎn)換57 如果設(shè)備文件系統(tǒng)已經(jīng)應(yīng)用起來(lái)的話,此時(shí)在設(shè)備文件系統(tǒng)掛接的目錄(通常是/dev)下,就可以找到mydrv文件節(jié)點(diǎn)了。如果沒(méi)有應(yīng)用設(shè)備文件系統(tǒng),則需要手工為設(shè)備添加文件節(jié)點(diǎn): [root@Linux/dev]#mknodmydrvc990 此時(shí)就可以對(duì)設(shè)備進(jìn)行讀、寫(xiě)、ioctl等操作了。 如果設(shè)備文件系統(tǒng)已經(jīng)應(yīng)用起來(lái)的話,此時(shí)在設(shè)備文件系統(tǒng)58 當(dāng)不再需要對(duì)設(shè)備進(jìn)行操作時(shí),可以采用下面的命令卸載模塊: [root@Linux/dev]#/sbin/rmmodmydrv 當(dāng)不再需要對(duì)設(shè)備進(jìn)行操作時(shí),可以采用下面的命令卸載模59 3.設(shè)備的使用 下面的小程序可以對(duì)任何文件進(jìn)行先寫(xiě)后讀的操作: #include<stdio.h> intmain() { FILE*fp; charbuf[l00]; printf("Pleaseinputfilename:"); scanf("%s",buf); 3.設(shè)備的使用60 if((fp=fopen(buf,"wb"))==NULL)
//buf:文件名;wb:模式(只寫(xiě)、二進(jìn)制) { printf("Couldnotopened!\n"); return-1; } elseprintf("Fileopenok!\n"); printf("Pleaseinput(<110):"); scanf("%s",buf); if((fp=fopen(buf,"wb"))=61 if(fputs(buf,fp)==EOF){ printf("Errorwritingfile!"); return-2; } fgets(but,110,fp);//由文件讀取一字符串 printf("theFilecontentis:%s\n",buf); fclose(fp); return0; } if(fputs(buf,fp)==EOF){62 直接用gcc編譯生成可執(zhí)行文件之后,就可以用該程序?qū)ydrv設(shè)備的文件節(jié)點(diǎn)進(jìn)行操作。 當(dāng)然,也可以采用cat命令得到mydrv設(shè)備的輸出內(nèi)容。 直接用gcc編譯生成可執(zhí)行文件之后,就可以用該程序?qū)?311.4本章小結(jié) 本章主要介紹了設(shè)備管理方面的有關(guān)知識(shí). 首先介紹了系統(tǒng)是怎樣來(lái)管理設(shè)備的,即把設(shè)備看作一種的特殊的文件,從而實(shí)現(xiàn)了對(duì)設(shè)備的有關(guān)操作。 然后,說(shuō)明了驅(qū)動(dòng)程序運(yùn)作過(guò)程。 最后,結(jié)合一個(gè)具體實(shí)例,闡明了驅(qū)動(dòng)程序的具體的編寫(xiě)方法。11.4本章小結(jié) 本章主要介紹了設(shè)備管理方面64練習(xí)題 1.操作系統(tǒng)是怎么實(shí)現(xiàn)對(duì)設(shè)備進(jìn)行管理的? 2.舉出5個(gè)驅(qū)動(dòng)程序的常用接口函數(shù)。 3.編寫(xiě)驅(qū)動(dòng)程序一般有幾個(gè)步驟,具體各是什么?練習(xí)題 1.操作系統(tǒng)是怎么實(shí)現(xiàn)對(duì)設(shè)備進(jìn)行管理的?65第11章 設(shè)備管理第11章 設(shè)備管理66
Linux和其他操作系統(tǒng)一樣,支持眾多的、各式各樣的外接設(shè)備。 但是,面對(duì)層出不窮的新硬件產(chǎn)品,必須有人不斷編寫(xiě)新的驅(qū)動(dòng)程序,以便讓這些設(shè)備能夠在Linux下正常工作,從這個(gè)意義上講,講述驅(qū)動(dòng)程序的編寫(xiě)就是一件非常有意義的工作。 本章也涉及到Linux下設(shè)備管理的原則和方法。 Linux和其他操作系統(tǒng)一樣,支持眾多的、各式各樣的67 舉例來(lái)說(shuō),Linux下的驅(qū)動(dòng)程序僅僅是為相應(yīng)的設(shè)備編寫(xiě)幾個(gè)基本函數(shù),并向VFS注冊(cè)就可以安裝成功了。 當(dāng)應(yīng)用程序需要設(shè)備時(shí),可以訪問(wèn)該設(shè)備對(duì)應(yīng)的文件節(jié)點(diǎn),利用VFS調(diào)用該設(shè)備的相關(guān)處理函數(shù)。 舉例來(lái)說(shuō),Linux下的驅(qū)動(dòng)程序僅僅是為相應(yīng)的設(shè)備編68 本章主要介紹了設(shè)備管理方面的有關(guān)知識(shí): ◆系統(tǒng)管理設(shè)備的方式。 ◆驅(qū)動(dòng)程序運(yùn)作過(guò)程。 ◆驅(qū)動(dòng)程序的具體實(shí)例。 本章主要介紹了設(shè)備管理方面的有關(guān)知識(shí):6911.1設(shè)備管理結(jié)構(gòu)11.1設(shè)備管理結(jié)構(gòu)7011.1.1概述
設(shè)備管理即輸入輸出子系統(tǒng),可分為上下兩部分:一部分是上層的,與設(shè)備無(wú)關(guān)的,這部分根據(jù)輸入輸出請(qǐng)求,通過(guò)特定的設(shè)備驅(qū)動(dòng)程序接口,來(lái)與設(shè)備進(jìn)行通信。 另一部分是下層的,與設(shè)備有關(guān)的,常稱為設(shè)備驅(qū)動(dòng)程序,它直接與相應(yīng)設(shè)備打交道,并且向上層提供一組訪問(wèn)接口。11.1.1概述 設(shè)備管理即輸入輸出子系統(tǒng),71 設(shè)備管理的目標(biāo)是對(duì)所有的外接設(shè)備進(jìn)行良好的讀、寫(xiě)、控制等操作。 首先要解決的問(wèn)題就是怎樣將任意的一個(gè)設(shè)備的所有操作進(jìn)行歸納,設(shè)計(jì)出統(tǒng)一的接口。 內(nèi)核常常使用設(shè)備類型、主設(shè)備號(hào)和次設(shè)備號(hào)來(lái)標(biāo)識(shí)一個(gè)具體的設(shè)備。 設(shè)備管理的目標(biāo)是對(duì)所有的外接設(shè)備進(jìn)行良好的讀、寫(xiě)、控72 但用戶希望能用同樣的應(yīng)用程序和命令來(lái)訪問(wèn)設(shè)備和普通文件。 為此,Linux中的設(shè)備管理應(yīng)用了設(shè)備文件這個(gè)概念來(lái)統(tǒng)一設(shè)備的訪問(wèn)接口。 簡(jiǎn)單的說(shuō),系統(tǒng)試圖使它對(duì)所有各類設(shè)備的輸入、輸出看起來(lái)就好像對(duì)普通文件的輸入、輸出一樣。 但用戶希望能用同樣的應(yīng)用程序和命令來(lái)訪問(wèn)設(shè)備和普通文73
如圖11-1所示,應(yīng)用程序通過(guò)Linux的系統(tǒng)調(diào)用與內(nèi)核通信。 如圖11-1所示,應(yīng)用程序通過(guò)Linux的系統(tǒng)調(diào)用與74圖11-1Linux內(nèi)核體系結(jié)構(gòu)圖11-1Linux內(nèi)核體系結(jié)構(gòu)75 由于Linux中將設(shè)備當(dāng)作文件來(lái)處理,所以對(duì)設(shè)備進(jìn)行操作的系統(tǒng)調(diào)用和對(duì)文件操作的類似,主要包括open()、read()、write()、ioctl()、close()等。 應(yīng)用程序發(fā)出系統(tǒng)調(diào)用指令以后,會(huì)從用戶態(tài)轉(zhuǎn)換到內(nèi)核態(tài),通過(guò)內(nèi)核將open()這樣的系統(tǒng)調(diào)用轉(zhuǎn)換成對(duì)物理設(shè)備的操作。 由于Linux中將設(shè)備當(dāng)作文件來(lái)處理,所以對(duì)設(shè)備進(jìn)行7611.1.2字符設(shè)備與塊設(shè)備
字符設(shè)備以字節(jié)為單位進(jìn)行數(shù)據(jù)處理。字符設(shè)備通常只允許按順序訪問(wèn),一般不使用緩存技術(shù)。如鼠標(biāo),聲卡等。
塊設(shè)備以塊為單位進(jìn)行處理,塊的大小通常為0.5KB到32KB等。11.1.2字符設(shè)備與塊設(shè)備 字符設(shè)備以字節(jié)77 大多數(shù)塊設(shè)備允許隨機(jī)訪問(wèn),而且常常采用緩存技術(shù)。 塊設(shè)備有硬盤(pán)、光盤(pán)驅(qū)動(dòng)器等??梢圆榭次募?proc/devices獲得。 我們這里主要討論字符設(shè)備,有興趣的讀者可參考其它書(shū)籍中有關(guān)塊設(shè)備的內(nèi)容。 大多數(shù)塊設(shè)備允許隨機(jī)訪問(wèn),而且常常采用緩存技術(shù)。7811.1.3主設(shè)備號(hào)和次設(shè)備號(hào) 設(shè)備管理中,除了設(shè)備類型(字符設(shè)備或塊設(shè)備)以外,內(nèi)核還需要一對(duì)稱做主、次設(shè)備號(hào)的參數(shù),才能唯一表示設(shè)備。11.1.3主設(shè)備號(hào)和次設(shè)備號(hào) 設(shè)備管理中79 主設(shè)備號(hào)(majornumber)相同的設(shè)備使用相同的驅(qū)動(dòng)程序,而次設(shè)備號(hào)(minornumber)用來(lái)區(qū)分具體設(shè)備的實(shí)例。 例如,第一IDE接口上的所有磁盤(pán)及其分區(qū)共用同一主設(shè)備號(hào)3,而次設(shè)備號(hào)則為0,1,2,3…。 主設(shè)備號(hào)(majornumber)相同的設(shè)備使用相8011.1.4Linux設(shè)備命名習(xí)慣: Linux習(xí)慣上將設(shè)備文件放在目錄/dev或其子目錄之下。
設(shè)備文件命名(通常由兩部分組成)規(guī)則為:第一部分通常較短,可能只有2或3個(gè)字母組成,用來(lái)表示設(shè)備大類。11.1.4Linux設(shè)備命名習(xí)慣: Li81 例如,普通硬盤(pán)如IDE接口的為“hd”,軟盤(pán)為“fd”。第二部分通常為數(shù)字或字母用來(lái)區(qū)別設(shè)備實(shí)例。 例如,/dev/hda、/dev/hdb、/dev/hdc表示第一、二、三塊硬盤(pán);而dev/hda1、/dev/hda2、/dev/hda3則表示第一硬盤(pán)的第一、二、三分區(qū)。 例如,普通硬盤(pán)如IDE接口的為“hd”,軟盤(pán)為“fd8211.2驅(qū)動(dòng)程序11.2驅(qū)動(dòng)程序8311.2.1驅(qū)動(dòng)程序基本功能 在Linux操作系統(tǒng)中驅(qū)動(dòng)程序是操作系統(tǒng)內(nèi)核與硬件設(shè)備之間的橋梁,它屏蔽了硬件的細(xì)節(jié)(如總線協(xié)議、DMA操作等),在應(yīng)用程序看來(lái)硬件設(shè)備只是一個(gè)特殊的文件。
11.2.1驅(qū)動(dòng)程序基本功能 在Linux84 驅(qū)動(dòng)程序的基本功能為:
1.對(duì)設(shè)備初始化和釋放。如對(duì)音頻設(shè)備而言包括向內(nèi)核注冊(cè)設(shè)備,設(shè)置音頻的輸入輸出參數(shù)(如采樣頻率、采樣寬度等)、分配音頻設(shè)備使用的內(nèi)核內(nèi)存等工作。
2.對(duì)設(shè)備進(jìn)行管理。包括實(shí)時(shí)參數(shù)設(shè)置以及提供對(duì)設(shè)備的操作接口。 驅(qū)動(dòng)程序的基本功能為:85
3.讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)并回送應(yīng)用程序請(qǐng)求的數(shù)據(jù)。這需要在用戶空間、內(nèi)核空間、總線及外設(shè)之間傳輸數(shù)據(jù)。
4.檢測(cè)和處理設(shè)備出現(xiàn)的錯(cuò)誤。 3.讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)并回送應(yīng)用程序請(qǐng)求的8611.2.2驅(qū)動(dòng)程序的運(yùn)作過(guò)程 為了便于讀者理解,在此結(jié)合大家比較熟悉的鍵盤(pán)來(lái)了解其運(yùn)作過(guò)程。
如圖11-2所示.11.2.2驅(qū)動(dòng)程序的運(yùn)作過(guò)程 為了便于讀者87圖11-2驅(qū)動(dòng)程序的實(shí)現(xiàn)過(guò)程圖11-2驅(qū)動(dòng)程序的實(shí)現(xiàn)過(guò)程88 當(dāng)一個(gè)程序讀/dev/tty文件(此為鍵盤(pán))時(shí),就會(huì)執(zhí)行系統(tǒng)調(diào)用sys_read()(在fs/read_write.c中),該系統(tǒng)調(diào)用在判別出所讀文件是一個(gè)字符設(shè)備文件時(shí),即會(huì)調(diào)用rw_char()函數(shù)(在fs/char_dev.c中), 該函數(shù)則會(huì)根據(jù)所讀設(shè)備的設(shè)備類型,主、次設(shè)備號(hào)等參數(shù),由字符設(shè)備讀寫(xiě)函數(shù)表(設(shè)備開(kāi)關(guān)表)調(diào)用rw_tty(),最終調(diào)用到這里的終端讀操作函數(shù)tty_read() 當(dāng)一個(gè)程序讀/dev/tty文件(此為鍵盤(pán))時(shí),就會(huì)89 當(dāng)用戶在鍵盤(pán)上鍵入了一個(gè)字符時(shí),會(huì)引起鍵盤(pán)中斷響應(yīng),此時(shí)鍵盤(pán)中斷處理程序就會(huì)從鍵盤(pán)控制器讀入對(duì)應(yīng)的鍵盤(pán)掃描碼,然后根據(jù)使用的鍵盤(pán)掃描碼映射表譯成相應(yīng)字符,放入tty讀隊(duì)列read_q中。 當(dāng)用戶在鍵盤(pán)上鍵入了一個(gè)字符時(shí),會(huì)引起鍵盤(pán)中斷響應(yīng),90 然后調(diào)用中斷處理程序的do_tty_interrupt()函數(shù),它又直接調(diào)用行規(guī)則函數(shù)copy_to_cooked()對(duì)該字符進(jìn)行過(guò)濾處理,并放入tty輔助隊(duì)列secondary中,供上述tty_read()讀取。 然后調(diào)用中斷處理程序的do_tty_interrup91 同時(shí)把該字符放入tty寫(xiě)隊(duì)列write_q中,并調(diào)用寫(xiě)控制臺(tái)函數(shù)con_write()。 此時(shí)如果該終端的回顯(echo)屬性是設(shè)置的,則該字符會(huì)顯示到屏幕上(注:do_tty_interrupt()和copy_to_cooked()函數(shù)在tty_io.c中實(shí)現(xiàn))。 同時(shí)把該字符放入tty寫(xiě)隊(duì)列write_q中,并調(diào)用9211.2.2常用接口介紹
open():打開(kāi)設(shè)備,并初始化設(shè)備準(zhǔn)備進(jìn)行操作。可以為NULL,這樣每次打開(kāi)設(shè)備總會(huì)成功,而且不通知設(shè)備驅(qū)動(dòng)程序。
read():從設(shè)備中讀數(shù)據(jù),需要提供字符串指針。
write():向字符設(shè)備寫(xiě)數(shù)據(jù),需要提供所寫(xiě)內(nèi)容指針。
ioctl():控制設(shè)備,例如控制光盤(pán)的彈出等。需要提供符合設(shè)備預(yù)先定義的命令字。11.2.2常用接口介紹 open():93
llseek():重新定位讀、寫(xiě)位置,需要提供偏移量參數(shù)。
flush():清除內(nèi)容。
release():關(guān)閉設(shè)備,并釋放資源等。
mmap():將設(shè)備內(nèi)存映射到進(jìn)程地址空間。通常只有塊設(shè)備驅(qū)動(dòng)程序使用。 llseek():重新定位讀、寫(xiě)位置,需要提供偏移量9411.2.3常用函數(shù)原型
1.設(shè)備操作函數(shù)原形 structfile_operations { structmodule*owner; loff_t(*llseek)(structfile*,loff_t,int); ssize_t(*read)(structfile*,char*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar *,size_t,loff_t*); int(*readdir)(structfile*,void*,filldir_t);11.2.3常用函數(shù)原型 1.設(shè)備操作函數(shù)原形95 unsignedint(*poll)(structfile*,struct poll_table_struct*); int(*ioctl)(structinode*,structfile*,unsigned int,unsignedlong); int(mmap)(structfile*,structvm_area_struct*); int(*open)(structinode*,structfile*); int(*flush)(structfile*); int(*release)(structinode*,structfile*); unsignedint(*poll)(structf96 int(*fsync)(structfile,structdentry*,int datasync); int(*fasync)(int,structfile*,int); int(*lock)(structfile*,intstructfile_lock*); ssize_t(*readv)(structfile*,conststructiovec *,unsignedlong,loff_t*); ssize_t(*writev)(structfile*,conststructiovec *,unsignedlong,loff_t*); } int(*fsync)(structfile,s97 2.向系統(tǒng)注冊(cè)的函數(shù)原形 int
register_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops) { if(major==0) { write_lock(&chrdevs_lock); 2.向系統(tǒng)注冊(cè)的函數(shù)原形98 for(major=MAX_CHRDEV-1;major>0;major--) { if(chrdevs[major].fops==NULL) { chrdevs[major].name=name; chrdevs[major].fops=fops; write_unlock(&chrdevs_lock); returnmajor; } } for(major=MAX_CHRDEV-1;major>99 write_unlock(&chrdevs_lock); return-EBUSY; } if(major>MAX_CHRDEV) return-EINVAL; write_lock(&chrdevs_lock); write_unlock(&chrdevs_lock);100 if(chrdevs[major].fops&&chrdevs[major].fops!=fops) { write_unlock(&chrdevs_lock); return-EBUSY; } chrdevs[major].name=name; chrdevs[major].fops=fops; write_unlock(&chrdevs_lock); return0; } if(chrdevs[major].fops&&chr10111.3驅(qū)動(dòng)程序編寫(xiě)實(shí)例 為了更清楚地講述Linux中設(shè)備驅(qū)動(dòng)程序的編寫(xiě),加深讀者對(duì)啟動(dòng)程序的了解。下面介紹一個(gè)簡(jiǎn)單的設(shè)備驅(qū)動(dòng)的實(shí)現(xiàn)過(guò)程。 由于基于特殊的硬件設(shè)備實(shí)現(xiàn)的驅(qū)動(dòng)程序難度較大,而且不方便驗(yàn)證,下面舉一個(gè)虛擬設(shè)備驅(qū)動(dòng)程序的例子。11.3驅(qū)動(dòng)程序編寫(xiě)實(shí)例 為了更清楚地講述10211.3.1設(shè)備功能介紹 實(shí)現(xiàn)虛擬設(shè)備的寫(xiě)入、讀出等操作。這個(gè)驅(qū)動(dòng)程序并不是基于特定硬件設(shè)備的,實(shí)際上僅僅是對(duì)內(nèi)存進(jìn)行讀、寫(xiě)操作。11.3.1設(shè)備功能介紹 實(shí)現(xiàn)虛擬設(shè)備的寫(xiě)入103 當(dāng)執(zhí)行寫(xiě)入操作時(shí),將會(huì)對(duì)特定的存儲(chǔ)空間進(jìn)行寫(xiě)入;當(dāng)執(zhí)行讀出操作時(shí),將會(huì)對(duì)該存儲(chǔ)空間進(jìn)行數(shù)據(jù)的讀取;同時(shí)還可以利用ioctl進(jìn)行清除該存儲(chǔ)空間的操作。 這個(gè)mydrv設(shè)備的實(shí)現(xiàn)文件是mydrv.c,其中的文件接口flle_operations{}提供了mydrv_open、mydrv_release、mydrv_read、mydrv_write、mydrv_ioctl等函數(shù)。 當(dāng)執(zhí)行寫(xiě)入操作時(shí),將會(huì)對(duì)特定的存儲(chǔ)空間進(jìn)行寫(xiě)入;當(dāng)執(zhí)104 1.函數(shù)mydrv_read()的功能是從mybuf[110]中讀取字符串,并傳遞給調(diào)用的進(jìn)程。 2.函數(shù)mydrv_write()的功能是將調(diào)用的進(jìn)程傳入的字符串賦值給mybuf,如果字符串的長(zhǎng)度超過(guò)110,則只取前110個(gè)字符。 3.函數(shù)mydrv_ioctl()中僅僅實(shí)現(xiàn)了一個(gè)控制功能:清除mybuf存儲(chǔ)區(qū)。 1.函數(shù)mydrv_read()的功能是從mybuf[110511.3.2具體實(shí)現(xiàn) 首先,要根據(jù)設(shè)備功能的需要,編寫(xiě)file_operations結(jié)構(gòu)中的操作函數(shù)。 其次,要向系統(tǒng)注冊(cè)該設(shè)備,包括字符設(shè)備的注冊(cè),devfs節(jié)點(diǎn)的注冊(cè)與中斷響應(yīng)函數(shù)的注冊(cè)。然后就可以利用對(duì)應(yīng)的文件進(jìn)行設(shè)備操控了。具體如下:11.3.2具體實(shí)現(xiàn) 首先,要根據(jù)設(shè)備功能的106 1.源程序 #include<linux/module.h> #include<linux/kernel.h> #include<linux/fs.h> #include<linux/types.h> #include<linux/malloc.h> #include<asm/uaccess.h> #include<asm/page.h> #include<linux/ermo.h> #include<linux/config.h> 1.源程序107 #defineMYDRV_CLS_IO('c',0x01)
//定義清存儲(chǔ)區(qū)命令字 charmybuf[110];
//存儲(chǔ)區(qū)域 intmydrv_major=99;
//主設(shè)備號(hào) devfs_handle_tdev_handle;
//保存設(shè)備文件系統(tǒng)的注冊(cè)句柄 //第一步:編寫(xiě)file_operations函數(shù) #defineMYDRV_CLS_IO('c',0108 ssize_tmydrv_read(structfile*filp,char*buf,size_tcount,loff_t*f_pos);//函數(shù)聲明 staticssize_tmydrv_write(structfile*filp,constchar*buf,size_tcount,loff_t*ppos); staticintmydrv_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg); intmydrv_open(structinode*inode,structfile*filp); intmydrv_release(structinode*inode,structfile*filp);//函數(shù)聲明 ssize_tmydrv_read(structfil109 structfile_operationsmydrv_ops={
//設(shè)備函數(shù)接口 open:mydrv_open,
//實(shí)現(xiàn)對(duì)設(shè)備的操作 read:mydrv_read, write:mydrv_write, ioctl:mydrv_ioctl, release:mydrv_release; };
//mydrv_read()將內(nèi)核空間的mybuf中的字符串賦給用戶空間的buf區(qū) structfile_operationsmydrv_110 ssize_tmydrv_read(structfile*filp,char*bur,size_tcount,loff_t*f_pos)
//filp:指向設(shè)備文件的指針;f_pos:偏移量 intlength=strlen(mybuf); if(count>99)count=99;
//忽略大于110部分 count=length-*f_pos;
//計(jì)算字符個(gè)數(shù)的技巧 ssize_tmydrv_read(structfil111 if(copy_to_user(buf,mybuf,count)){
//重內(nèi)核區(qū)復(fù)制到用戶區(qū) printk("errorreading,copy_to_user\n”); retum-EFAULT; } *f_pos+=count;//下一個(gè) retumcount; }
//mydtv_write()將用戶空間的buf字符串賦給內(nèi)核空間的mybuf[]數(shù)組中 if(copy_to_user(buf,mybuf,c112 staticssize_tmydrv_write(structfile*filp,constchar*buf,size_tcount,loff_t*ppos){ intnum; num=count<110?count:110; if(copy_from_user(mybuf,buf,num))//mybufbuf return-EFAULT; printk("mydrv_writesucceed!\n”); returnnum; } staticssize_tmydrv_write(st113 staticintmydrv_ioctl(structinode*inode,structfile*file,//如果傳人的命令字是 unsignedintcmd,unsignedlongarg){//MYDRV-CLS則清除mybuf數(shù)組內(nèi)容 switch(cmd){ caseMYDRV_CLS: mybuf[0]=0x0; return0; default: return-EINVAL; } }
//打開(kāi)mydrv設(shè)備時(shí)調(diào)用 staticintmydrv_ioctl(struc114 #defineMAX_MYDRV_DEV2 intmydrv_open(structinode*inode,structfile*filp){//inede:設(shè)備文件節(jié)點(diǎn) unsignedintdev=MINOR(inode->i_rdev); if(mydrv_num) return-1; #defineMAX_MYDRV_DEV2115 if(dev>=MAX_MYDRV_DEV) return-ENODEV; filp->f_ap=&mydrv_ops;//指向操作函數(shù) printk(“opensuccess\n”); MOD_INC_USE_COUNT;//只是簡(jiǎn)單地加1 return0; }
//關(guān)閉mydrv設(shè)備,這里只是將引用次數(shù)減1 intmydrv_release(structinode*inode,structfile*filp){ MOD_DEC_USE_COUNT; return0; } if(dev>=MAX_MYDRV_DEV)116
//第二步:向系統(tǒng)注冊(cè)該設(shè)備 //module的安裝,采用兩種方式進(jìn)行了設(shè)備的注冊(cè) intinit_module(void) { intresult; printk(“initing...\n”); result=devfs_register_chrdev(mydrv_major,“mydrv”,&mydrv_ops); /
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 中級(jí)收入建筑合同范本
- 公司運(yùn)輸貨物合同范本
- 保過(guò)合同范本
- 出資入股協(xié)議合同范本
- 買(mǎi)賣(mài)合同非住宅類合同范本
- 中介買(mǎi)房糾紛合同范本
- 倉(cāng)房買(mǎi)賣(mài)合同范本
- 加工玉米采購(gòu)合同范本
- 別墅購(gòu)買(mǎi)合同范本
- 出租嬰兒服裝合同范本
- 2024年江蘇衛(wèi)生健康職業(yè)學(xué)院?jiǎn)握新殬I(yè)適應(yīng)性測(cè)試題庫(kù)及答案解析0
- 《中國(guó)陶瓷史》課件-3-陶與瓷
- 第一章創(chuàng)新意識(shí)課件
- 浙江省杭州市2022-2023學(xué)年七年級(jí)下學(xué)期語(yǔ)文期中質(zhì)量檢測(cè)試卷(含答案)
- 【真題】2023年南京市中考語(yǔ)文試卷(含答案解析)
- 數(shù)學(xué)教育的國(guó)際比較與交流
- 安徽安慶家鄉(xiāng)介紹
- 自動(dòng)測(cè)試系統(tǒng)第1章第1節(jié)測(cè)試系統(tǒng)發(fā)展綜述
- 2024年河南省水務(wù)規(guī)劃設(shè)計(jì)研究有限公司人才招聘筆試參考題庫(kù)附帶答案詳解
- 山地光伏設(shè)計(jì)方案
- 案卷評(píng)查培訓(xùn)課件模板
評(píng)論
0/150
提交評(píng)論