嵌入式學習linux設備驅動程序_第1頁
嵌入式學習linux設備驅動程序_第2頁
嵌入式學習linux設備驅動程序_第3頁
嵌入式學習linux設備驅動程序_第4頁
嵌入式學習linux設備驅動程序_第5頁
已閱讀5頁,還剩24頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第六章Linux并能編寫簡單的字符設備(scullSimpleCharacterUtilityforLoadingLocalities)和塊設備(sbull,SimpleBlockUtilityforLoadingLocalities)LinuxLinux1?其它驅動程并口驅動程?其它驅動程并口驅動程串口驅動程鍵盤驅動程?其它驅動程光盤驅動程軟盤驅動程硬盤驅動程圖 Linux導致系統。I/O可設置:Linux操作系統設備驅動程序可以集成為內核的一部分,并可動態性:當系統啟動且各個設備驅動程序初始化后,驅動程序將其Lnux序相應的數據結構,以便定義一的接口并現驅動程序的可裝載性和動態性。驅動程序與操作系統內核的接口:這是通過數據結構

系統引 接

I/O塊,所以在內核內部用一個file結構來識別設備驅動程序,而且內核使用驅動程序的與注銷。◆設備的打開與釋放。◆設備的讀寫操作 ◆設備的中斷和輪詢處理第一部分了解字符設備的基本字符設備的基本點也可稱為子程序,它們被包含在驅動程序open()release(read(writeioctl()select()用。Linux系統通過調用register_chrdev()向系統字符型設備驅動程序。#include<linux/fs.h>#includelinux/errno.h>intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*ops);chrdevs表的相應位置。name是設備名,ops是對各個調用點的說明。配的主設備號。如果register_chrdev()操作成功,則設備名就會出現在字符設備以后,還必須在文件系統中為其創建一節點。該節點可以是在/dev中的一個節點,這種節點都是文件節點,且每個節點代表一個具體的設備文件下的一個節點,對于這種節點應根據主設備號給每一種設備都創建一個節點,在這個下才是代表具體設備的文件節點。編寫一個簡單的字符設備驅動程序。要求該字符設備包括scull_open()、structdevice_struct{constchar*name;structfile_operationsstaticstructdevice_structchrdevs[MAX_CHRDEV];typedefstructScull_Dev{voidint //thecurrentquantumintqset; //thecurrentarraysizeunsignedlongsize;unsignedintaccess_key;//usedbysculluidandscullprivunsignedintusage;//lockthedevicewhileusingitstructScull_Dev*next;//nextlistitem}名字和相關操作被添加到device_struct結構類型的chrdevs全局數組中,稱scull)****file_operationchr_fops****staticintscull_open(structinode*inode,structfile*filp);staticintscull_release(structinode*inode,structfile*filp);staticssize_tscull_write(structinode*inode,structfile*filp,constchar*buffer,intcount);staticssize_tscull_read(structinode*inode,structfile*filp,char*buffer,intcount);longintcmd,unsignedlongarg);structfile_operationchr_fops={ //seek //read //write //readdir //poll //ioctl //mmap //open //flushscull_release,//release //fsync // //checkmedia // //字符設備驅動程序字符設備驅動程序點主要包括初始化字符設備字符設備的I/O調用和中斷。在引導系統時,每個設備驅動程序通過其內部的初始化函數init()對其控制的設備及其自身初始化。字符設備初始化函數為chr_dev_init()/linux/drivers/char/mem.c中,它的主要功能之一是在內核中登記設備驅動程#include<linux/fs.h>#includeintregister_chrdev(unsignedintmajor,constchar*name,structfile_operation*fops);驅動程序動態地分配一個主設備號。name是設備名。fops是前面定義的file_operation結構的指針。在登記成功的情況下,如果指定了major,則I/Oopen()子程序或別的地方申請。在這些資源不用的I/Oopen()、release()、read()、write(ioctl()staticintscull_open(structinode*inode,structfile*filp){……return}staticintscull_release(structinode*inode,structfile*filp)……return}當設備文件執行read()調用時,將從設備中數據,實際上是從內核數據隊列中,并傳送給用戶空間。設備驅動程序的write()函數的使用和read()空間的緩沖區buf到硬件或內核的緩沖區中。longintcmd,unsignedlong本號(basenumber)及和基本號相關令范圍。具體的ioctl基本號可參見ation/ioctl-number。Linuxioctl()函數調用:_IO(base,command)//可以定義所需要令,沒有數據傳送的問題,返回正 ioctl ioctl //讀寫操作的ioctl1:“Thischrdevisinstructscull_dev是否scull.usage=0scull.new_msg=否是scull.usage=是scull.data=0否+scull.usage=scull.new_msg=是否是scull.usage非否是scull.data==NULL否strlen(scull.data)<count是否copy_to_user(buffer,scull.data,count+1scull.usage=scull.new_msg=count=strlen(scull.datascull.usage=SQNM還是SQML?是否否是—SRT:SQNM:SCULL_QUERY_NEW_MSGSRT:否I/O是否是open()1:MODDECUSECOUNT;將scull.h自定義頭文件和scull.c文件到包含字符設備驅動程序 drivers/char子 在chr_dev_init()函數的最后增加調用init_module()編輯drivers/char 義的后面,并將driver.c名稱放在SRCS定義的后面。 改變到Linux源程序 Linux在該字符設備驅動程序編譯加載后,再在/dev下創建字符設備文件chrdev,使用命令:#mknod/dev/chrdevcmajorminor,其中“c”表示“major譯加載后,可在/proc/devices文件中獲得主設備號,或者使用命令:/proc/devices|awk”\\$2”chrdev\”{print\\$1}”。open()否是write(寫入信息 o“Can'topentheread()讀取信息 o第二部分structblk_dev_struct//queue_prochastobeatomicrequest_queue_trequest_queue; *queue;void*datedataqueue所有塊設備的描述符都存放在blk_dev表中:structblk_dev_structblk_dev_struct

……

b了解塊設備的基本;③check_media_changerevalidate候也要進行。在初始化時通過register_blkdev()函數將相應的塊設備添加到blkdevsfs/block_dev.cstaticstructconstcharstructblock_device_operations}intregister_blkdev(unsignedintmajor,constchar*name,structblock_device_operations*bdops);0,否則返回負值。如果指定的主設備號為blockprintk(編寫一個簡單的塊設備驅動程序。要求該塊設備包括sbull_openstructdevice_struct{constcharstructfile_operationsstaticstructdevice_structblkdevs[MAX_BLKDEV];structsbull_dev{voidint //thecurrentquantumintqset; //thecurrentarraysizeunsignedlongsize;unsignedintaccess_key;//usedbysbulluidandsbullprivunsignedintusage;//lockthedevicewhileusingitunsignedintnew_msg;structsbull_dev*next;//nextexternstructsbull_dev*sbull;//device****file_operationsbull_fopsstructfile_operationblk_fops={ //seek // // // // // // // //sbull_check_media_change,//checkmediachange //revalidate //release()函數。塊設備驅動程序I/Oioctl()、open()、release()與字符設備類似。塊設備與字符設備最大的不同在于設備的讀寫操作。塊設備使用通用block_readblock_write()函數來進行數據讀寫。這兩個通用函數向請求表中ll_w_blockblk_dev_structrequest_fn(/blkdev.hstructblk_dev_structvoid(*request_fn)(void);structrequest*current_request;structrequestplug;structtq_structstructrequest……kdev_tint intunsignedlongsector;char*buffer;structrequest……request_fn都是由request()函數完成。所有的讀寫請求都在request結構的鏈表中。request()CURRENT#defineCURRENTvoidsbull_request(void){unsignedlongoffset,total;offset=CURRENT->sector*total=CURRENT->current_nr_sectors*//accessbeyondendoftheif(total+offset>sbull_size*1024)//errorinrequestgotoBegin;}if(CURRENT->cmd==READ)memcpy(CURRENT->buffer,sbull_storage+}elseif(CURRENT->cmd==WRITE)memcpy(sbull_storage+offset,CURRENT->}else}//successful//letINIT_REQUESTreturnwhenwearedonegotoBegin;}CURRENT=0,INIT_REQUESTrequest()函數返回,任務結束。當處理完請求后,request()end_request()函數。如果成功地完成了讀1end_request()函數;如果讀寫操作不成功,以參數0end_requestCURRENTinit()init(),blk_dev_init()函數中增加一行代碼:sbull_init()if(registr_blkde(sbull_AJOR“bull&sbll_fops)){filed\nsull_MAJR);return–EIO;request()函數的地址傳遞給內核:blk_dev[sbull_MAJOR].request_fnDEVICE_REQUEST;#definesbull_HARDS_SIZE#definesbull_BLOCK_SIZEstaticintsbull_hard=sbull_HARDS_SIZE;staticintsbull_soft=sbull_BLOCK_SIZE;hardsect_size[sbull_MAJOR]=&sbull_hard;blksize_size[sbull_MAJOR]=&sbull_soft;#defineMAJOR_NRsbull_MAJOR#defineDEVICE_NAME#defineDEVICE_REQUESTsbull_request#defineDEVICE_NR(device)(MINOR(device))#defineDEVICE_ON(device)#define否是否是否是是否structhd_geometry*geo=(structhd_geometry*)arg;structhd_geometry*geo=(structhd_geometry*)arg;是arg=否是suser()=否否err=是put_user()(—(long*)arg,sizeof(long);———調用fsync_dev()函數清除內核保存在不同高速緩存BFB:否是否是voidsleep_on(structwait_queuevoidinterruptible_sleep_on(structwait_queuevoidwake_up(structwait_queuevoidwake_up_interruptible(structwait_queuegetblk()用于分配緩沖區,breles()用于釋放緩沖區等:structbuffer_head*getblk(kdev_t,intblock,intsize);voidbreles(structbuffer_head*buf第一部分intscull_open(structinode*inode,structfile*filp){ 增加該模塊的用戶數目printk(“Thischrdevisinopen\n”);return}intscull_write(structinode*inode,structfile*filp,const*buffer,intcount)if(count<returnif(scull.usage||scull.new_msg)return–EBUSY;scull.usage=1;k(scull.data);data=kmalloc(sizeof(char)*(count+1),GFP_KERNEL);if(!scull.data){return}copy_from_user(scull.data,buffer,count+1);scull.usage=0;scull.new_msg=1;returncount;}intscull_read(structinode*inode,structfile*filp,char*buffer,intcount){intlength;if(count<returnreturn–EBUSY;scull.usage=1;if(scull.data==0)returnlength=strlen(scull.data);if(length<count)count=length;copy_to_user(buf,scull.data,count+1);scull.new_msg=0;scull.usage=0;return}#include<linux/ioctl.h>#defineSCULL_MAJOR0#defineSCULL_MAGIC#defineSCULL_RESET_IO(SCULL_MAGIC,0)//resetthe#defineSCULL_QUERY_NEW_MSG_IO(SCULL_MAGIC,1)//checkfornewmessage#defineSCULL_QUERY_MSG_LENGTH_IO(SCULL_MAGIC,2)//getmessagelength#defineIOC_NEW_MSG1staticintusage,new_msg;//controlstaticcharintscull_ioctl(structinode*inode,structfile*filp,unsignedlongintcmd,unsignedlongarg){intret=0;switch(cmd){case data=NULL;usage=0;new_msg=0;casereturnIOC_NEW_MSG;caseif(data==NULL){return0;}elsereturn}return}return}voidscull_release(structinode*inode,structfile*filp){ 1printk(“Thischrdevisinrelease\n”);return0;}

#ifdef在該字符設備驅動程序編譯加載后,再在/dev下創建字符設備文件chrdev,使用命令:#mknod/dev/chrdevcmajorminor,其中“c”表示“major譯加載后,可在/proc/devices文件中獲得主設備號,或者使用命令:/proc/devices|awk”\\$2”chrdev\”{print\\$1}”#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<sys/ioctl.h>#include<stdlib.h>#include<string.h>#include<fcntl.h>#include<unistd.h>#include<errno.h>#include voidwrite_proc(void);voidread_proc(void);main(intargc,char**argv){if(argc==1){puts(“syntax:testprog[write|read]\n”);}if(!strcmp(argv[1],“write”)){}if(!stcmp(arg[1]“ea”))}elseputs(“testprog:invalid}return}voidwrite_proc()intfd,len,quit=0;charbuf[100];fd=open(“/dev/chrdev”,O_WRONLY);if(fd<=0){printf(“Erroropeningdeviceforwriting!\n”);}while(!quit)printf(“\nPleasewriteinto:”);quit=1;len=write(fd,buf,strlen(buf));if(len<0){printf(“Errorwritingtodevice!\n”);}printf(“\nThereare%dbyteswrittentodevice!\n,len);}}voidread_proc()intfd,len,quit=0;char*buf=NULL;if(fd<0){printf(“Erroropeningdevicefor}while(!quit)printf(“\nPleasereadout:”);//getthemsglen=ioctl(fd,DYNCHAR_QUERY_MSG_LENGTH,NULL);if(len){if(buf!=buf=malloc(sizeof(char)*(len+1));len=read(fd,buf,len);if(len<0)printf(“Errorreadingfrom}elseif(!strcmp(buf“exit”){ //resetquit=1;}}}}

}chrdev.h#ifndef_DYNCHAR_DEVICE_H#define_DYNCHAR_DEVICE_H#include<linux/ioctl.h>#defineDYNCHAR_MAJOR42#defineDYNCHAR_MAGIC#defineDYNCHAR_RESET_IO(DYNCHAR_MAGIC,0)//resetthe#defineIOC_NEW_MSG1第二部分typedefstructSbull_Dev{void**data;int //thecurrentquantumint //thecurrentarrayunsignedlongsize;unsignedintnew_msg;unsignedintusage; //lockthedevicewhileusingitunsignedintaccess_key;//usedbysbulluidandsbullprivstructSbull_Dev*next;//nextlistitemexternstructsbull_dev //deviceintsbull_open(structinode*inode,structfile*filp){intnum=MINOR(inode->i_rdev);if(num>=sbull->size)return–ENODEV;sbull->size=sbul

溫馨提示

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

評論

0/150

提交評論