嵌入式系統(tǒng)原理與應(yīng)用-基于Cortex-A53微處理器 課件 第6章 設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)_第1頁(yè)
嵌入式系統(tǒng)原理與應(yīng)用-基于Cortex-A53微處理器 課件 第6章 設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)_第2頁(yè)
嵌入式系統(tǒng)原理與應(yīng)用-基于Cortex-A53微處理器 課件 第6章 設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)_第3頁(yè)
嵌入式系統(tǒng)原理與應(yīng)用-基于Cortex-A53微處理器 課件 第6章 設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)_第4頁(yè)
嵌入式系統(tǒng)原理與應(yīng)用-基于Cortex-A53微處理器 課件 第6章 設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)_第5頁(yè)
已閱讀5頁(yè),還剩40頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

電子與電氣工程學(xué)院設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)教師:程蔚正大氣象厚德載物MinnanUniversityofScienceandTechnology嵌入式系統(tǒng)原理與應(yīng)用目錄CONTENTS01.驅(qū)動(dòng)開發(fā)概述02.內(nèi)核模塊03.字符設(shè)備驅(qū)動(dòng)正大氣象厚德載物MinnanUniversityofScienceandTechnology01PARTONELinux驅(qū)動(dòng)概述正大氣象厚德載物MinnanUniversityofScienceandTechnology正大氣象厚德載物MinnanUniversityofScienceandTechnology設(shè)備驅(qū)動(dòng)程序(DeviceDriver),簡(jiǎn)稱驅(qū)動(dòng)程序(Driver)。它是一個(gè)允許計(jì)算機(jī)軟件與硬件交互的程序。這種程序建立了一個(gè)硬件與硬件,硬件與軟件形成連接,這樣的連接使得硬件設(shè)備之間的數(shù)據(jù)交換成為可能。設(shè)備驅(qū)動(dòng)程序是計(jì)算機(jī)硬件與應(yīng)用程序的接口,是軟件系統(tǒng)與硬件系統(tǒng)溝通的橋梁。字符設(shè)備塊設(shè)備網(wǎng)絡(luò)設(shè)備設(shè)備驅(qū)動(dòng)分類02PARTTWO內(nèi)核模塊正大氣象厚德載物MinnanUniversityofScienceandTechnology1、字符設(shè)備--c正大氣象厚德載物MinnanUniversityofScienceandTechnology一、Linux設(shè)備驅(qū)動(dòng)分類應(yīng)用程序和驅(qū)動(dòng)程序進(jìn)行數(shù)據(jù)讀寫時(shí),是以“字節(jié)”為單位,按照固定的順序傳輸;數(shù)據(jù)是實(shí)時(shí)傳輸,沒有緩存。字符設(shè)備是沒有文件系統(tǒng)的。絕大部分設(shè)備驅(qū)動(dòng)是字符設(shè)備:LED、BEEP、按鍵、鍵盤、觸摸屏、攝像頭、液晶屏、聲卡、IIC、SPI、...應(yīng)用程序:系統(tǒng)IO函數(shù)open("/dev/led_drv",O_RDWR)read()write()ioctl()mmap()close()2、塊設(shè)備--b正大氣象厚德載物MinnanUniversityofScienceandTechnology一、Linux設(shè)備驅(qū)動(dòng)分類應(yīng)用程序和驅(qū)動(dòng)程序之間進(jìn)行數(shù)據(jù)讀寫時(shí),數(shù)據(jù)是以“塊”為單位,1block=1024KB。塊設(shè)備是有緩存的,塊設(shè)備是有文件系統(tǒng)的。大容量的存儲(chǔ)設(shè)備一般都是塊設(shè)備:nandflash、eMMC、SD、U盤、硬盤、....#cat/proc/partitionsmajorminor#blocksnammcblk0179165536mmcblk0p1應(yīng)用程序訪問塊設(shè)備[root@GEC6818/]#ls/dev/sda*-lbrw-rw-rw-1rootroot8,0Jan100:11/dev/sda--->U盤1)掛載---塊設(shè)備是有文件系統(tǒng)的。2)像訪問普通文件一樣訪問塊設(shè)備的內(nèi)容。3、網(wǎng)絡(luò)設(shè)備正大氣象厚德載物MinnanUniversityofScienceandTechnology一、Linux設(shè)備驅(qū)動(dòng)分類網(wǎng)卡類的設(shè)備:有線網(wǎng)卡、無(wú)線網(wǎng)卡、...,網(wǎng)絡(luò)設(shè)備是沒有設(shè)備文件的。應(yīng)用程序:

socket套接字:IP+端口號(hào)正大氣象厚德載物MinnanUniversityofScienceandTechnology二、內(nèi)核模塊的定義1、linuxkernelmodule2、module編譯后會(huì)生成一個(gè)*.ko安裝驅(qū)動(dòng):#insmodled_drv.ko卸載驅(qū)動(dòng):#rmmodled_drv.ko查看系統(tǒng)中,已安裝的module:#lsmod驅(qū)動(dòng)程序在內(nèi)核中是獨(dú)立的模塊例如:beep驅(qū)動(dòng)和LED驅(qū)動(dòng),beep和led間沒有任何聯(lián)系,可以通過應(yīng)用

程序?qū)蓚€(gè)驅(qū)動(dòng)聯(lián)系在一起。beep驅(qū)動(dòng)和led驅(qū)動(dòng)各自是獨(dú)立的module。說(shuō)明:每個(gè)驅(qū)動(dòng)程序都是一個(gè)獨(dú)立模塊,每設(shè)計(jì)一個(gè)驅(qū)動(dòng)程序,首先設(shè)計(jì)一個(gè)module,驅(qū)動(dòng)程序是包含在module中。三、Sourceinsight創(chuàng)建工程1、SI設(shè)置Options--->DocumentOptions--->DocumentType:CSourceFile:*.c;*.h;*.S;*.s

X86AsmSourceFile:*.asm;*.inc;*.S;*.s2、創(chuàng)建一個(gè)工程project-->newproject-->工程文件放在源碼包中(I:\GEC6818物聯(lián)網(wǎng)綜合實(shí)驗(yàn)箱(多模塊版本)-201708\1、嵌入式6818網(wǎng)關(guān)平臺(tái)\源碼\kernel6818\kernel6818)addtree(稍微等一下)--->close3、文件的同步project--->synchronizeFiles(同步文件)4、內(nèi)核源碼在kernel中I:\GEC6818物聯(lián)網(wǎng)綜合實(shí)驗(yàn)箱(多模塊版本)-201708\1、嵌入式6818網(wǎng)關(guān)平臺(tái)\源碼\6818GEC\kernelMinnanUniversityofScienceandTechnology正大氣象厚德載物四、設(shè)計(jì)一個(gè)module并編譯注意:參考內(nèi)核源碼,首先使用sourceinsight創(chuàng)建一個(gè)內(nèi)核源碼的工程例子:/drivers/watchdog/mxp_wdt.c1、設(shè)計(jì)module正大氣象厚德載物MinnanUniversityofScienceandTechnology2、Makefile3、編譯1、指定安裝驅(qū)動(dòng)的入口函數(shù),用宏module_init(安裝驅(qū)動(dòng)的入口函數(shù)名)2、指定卸載驅(qū)動(dòng)的入口函數(shù),用宏module_exit(卸載驅(qū)動(dòng)的入口函數(shù)名)3、定義對(duì)應(yīng)入口函數(shù)4、驅(qū)動(dòng)的描述

MODULE_AUTHOR("bobeyfeng@163.com");//作者聯(lián)系方式MODULE_DESCRIPTION("LEDdriverforGEC6818");//驅(qū)動(dòng)描述MODULE_LICENSE(“GPL”);//GPL協(xié)議MODULE_VERSION("V1.0");#include<linux/module.h>#include<linux/kernel.h>#include<linux/init.h>//入口函數(shù)--->安裝驅(qū)動(dòng)staticint__initgec6818_led_init(void){ printk(“<4>”“gec6818leddriverinit\n”);//內(nèi)核程序打印printk,應(yīng)用程序printf return0;}//出口函數(shù)--->卸載驅(qū)動(dòng)staticvoid__exitgec6818_led_exit(void){ printk("gec6818leddriverexit\n");}

//驅(qū)動(dòng)程序的入口:#insmodled_drv.ko-->module_init()-->gec6818_led_init()module_init(gec6818_led_init);//驅(qū)動(dòng)程序的出口:#rmmodled_drv.ko--->module_exit()-->gec6818_led_exit()module_exit(gec6818_led_exit);

//module的描述。#modinfoled_drv.koMODULE_AUTHOR("bobeyfeng@163.com");//作者聯(lián)系方式MODULE_DESCRIPTION("LEDdriverforGEC6818");//驅(qū)動(dòng)描述MODULE_LICENSE(“GPL”);//GPL協(xié)議MODULE_VERSION("V1.0");1、設(shè)計(jì)module正大氣象厚德載物MinnanUniversityofScienceandTechnologyINSTALLDIR

=

/tftpboot

ifneq($(KERNELRELEASE),)obj-m:=hello.oelseKERNELDIR:=/home/cw/kernel/CROSS_COMPILE:=/home/cw/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-

PWD:=$(shellpwd)

default:

#mkdir-p$(INSTALLDIR)

$(MAKE)ARCH=armCROSS_COMPILE=$(CROSS_COMPILE)-C$(KERNELDIR)M=$(PWD)modules

#cp--target-dir=$(INSTALLDIR)hello.ko

clean:

rm-rf*.o*.ko*.order.*.cmd*.mod.c*.symversendif2、Makefile---版本1目標(biāo):依賴Tab命令3)交叉編譯工具2)內(nèi)核源碼的路徑1)將源程序的目標(biāo)文件led_drv.o,編譯成一個(gè)module(ko)4)當(dāng)前路徑5)向內(nèi)核源碼路徑下的Makefile文件傳遞兩個(gè)參數(shù),并調(diào)用內(nèi)核源碼下的Makefile文件,使用該Makfile中的工具,回到當(dāng)前路徑下,將源程序編譯成一個(gè)module正大氣象厚德載物MinnanUniversityofScienceandTechnology

ROOTFS_DIR=/opt/4412/rootfs

ifeq($(KERNELRELEASE),)

KERNEL_DIR=/home/cw/kernel

CUR_DIR=$(shellpwd)

all:

make-C

$(KERNEL_DIR)M=$(CUR_DIR)modulesclean:

make-C

$(KERNEL_DIR)M=$(CUR_DIR)cleaninstall:

cp-raf*.ko

$(ROOTFS_DIR)/drv_moduleelse

obj-m+=hello.oendif2、Makefile---版本2正大氣象厚德載物MinnanUniversityofScienceandTechnology3、編譯$make得到.ko下載到實(shí)驗(yàn)箱中(實(shí)驗(yàn)課)$fileled_drv.koled_drv.ko:ELF32-bitLSBrelocatable,ARM,EABI5version1(SYSV),BuildID[sha1]=04ff90444af056f8c1c04f119c7307950bfe16a5,notstripped$sizeled_drv.kotext data bss dec hex filename344 360 0 704 2c0 led_drv.ko$modinfoled_drv.kofilename:/mnt/hgfs/linux內(nèi)核驅(qū)動(dòng)/4module/demo/led_drv.koversion:V1.0license:GPLdescription:LEDdriverforGEC6818author:bobeyfeng@163.comsrcversion:5D5F2D6C66A08F289709359depends:vermagic:3.4.39-gecSMPpreemptmod_unloadARMv7p2v8vermagic--->versionmagic(魔數(shù)):驅(qū)動(dòng)可以安裝的linux版本:3.4.39-gec,其中:-gec--->localversion,配置內(nèi)核的時(shí)候ARMv7---->硬件的版本正大氣象厚德載物MinnanUniversityofScienceandTechnology3、編譯GEC6818平臺(tái):[root@GEC6818/]#uname-aLinuxGEC68183.4.39-gec#4SMPPREEMPTTueOct2421:09:31CST2017armv7lGNU/Linux[root@GEC6818/]#insmodled_drv.ko[292.145000]gec6818leddriverinit[root@GEC6818/]#lsmodled_drv7600-Live0xbf000000(O)

[root@GEC6818/]#rmmodled_drv.ko[364.399000]gec6818leddriverexit正大氣象厚德載物MinnanUniversityofScienceandTechnology1)簡(jiǎn)單方法[root@GEC6818/]#cat/proc/sys/kernel/printk

7717[root@GEC6818/]#echo7417>/proc/sys/kernel/printk

將echo7417>/proc/sys/kernel/printk寫入:/etc/profile2)printk加優(yōu)先級(jí)printk(KERN_WARNING"gec6818leddriverinit\n");printk("<4>""gec6818leddriverexit\n");3)配置linux內(nèi)核,修改優(yōu)先級(jí)--->一勞永逸(1)使用默認(rèn)的配置文件bobey@ubuntu:~/6818GEC/kernel$cparch/arm/configs/GEC6818_defconfig.config(2)makemenuconfig-->配置內(nèi)核sudoapt-getupdatesudoapt-getinstalllibncurses5-dev#makemenuconfigKernelhacking--->(4)Defaultmessageloglevel(1-7)(3)保存退出(4)復(fù)制配置文件cp.configarch/arm/configs/GEC6818_defconfig(5)編譯內(nèi)核./mk-k/home/bobey/6818GEC/out/release/boot.img--->燒寫到emmc正大氣象厚德載物MinnanUniversityofScienceandTechnology設(shè)置printk的優(yōu)先級(jí)驅(qū)動(dòng)程序有入口和出口,但是應(yīng)用程序只有入口--main()五、驅(qū)動(dòng)程序和應(yīng)用程序的區(qū)別編譯方法應(yīng)用程序:gcc驅(qū)動(dòng)程序:使用內(nèi)核源碼包提供的頭文件、使用內(nèi)核源碼的編譯工具:Makefile驅(qū)動(dòng)程序是一個(gè)個(gè)獨(dú)立的模塊。各個(gè)驅(qū)動(dòng)程序之間,一般是沒有關(guān)系設(shè)計(jì)驅(qū)動(dòng)程序時(shí),只能使用內(nèi)核源碼提供的頭文件,不能使用標(biāo)準(zhǔn)的C庫(kù):stdio.h,printf()正大氣象厚德載物MinnanUniversityofScienceandTechnology03PARTTHERE字符設(shè)備驅(qū)動(dòng)正大氣象厚德載物MinnanUniversityofScienceandTechnology正大氣象厚德載物MinnanUniversityofScienceandTechnology一、字符設(shè)備驅(qū)動(dòng)的設(shè)計(jì)流程-------定義并初始化一個(gè)字符設(shè)備---------1、定義一個(gè)字符設(shè)備--->structcdev2、定義并初始化字符設(shè)備的文件操作集--->structfile_operations3、給字符設(shè)備申請(qǐng)一個(gè)設(shè)備號(hào)--->設(shè)備號(hào)=主設(shè)備號(hào)<<20+次設(shè)備號(hào)4、初始化字符設(shè)備5、將字符設(shè)備加入內(nèi)核-------自動(dòng)生成設(shè)備文件---------6、創(chuàng)建class7、創(chuàng)建device,其中device是屬于class的-------得到物理地址對(duì)應(yīng)的虛擬地址-------8、申請(qǐng)物理內(nèi)存區(qū),申請(qǐng)SFR的地址區(qū)。SFR---SpecialFunctionRegister:GPIOEOUT9、內(nèi)存的動(dòng)態(tài)映射,得到物理地址對(duì)應(yīng)的虛擬地址10、訪問虛擬地址正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序1、描述字符設(shè)備的結(jié)構(gòu)體--cdev#include<linux/cdev.h>structcdev{ structkobjectkobj; --->內(nèi)核管理驅(qū)動(dòng)的時(shí)候,使用的一個(gè)object structmodule*owner; --->cdev是屬于哪個(gè)module,一般寫成THIS_MODULE conststructfile_operations*ops; --->cdev的文件操作集 structlist_headlist; --->內(nèi)核管理cdev的鏈表 dev_tdev; --->設(shè)備號(hào) unsignedintcount; --->次設(shè)備的數(shù)量};在linux內(nèi)核中,使用cdev來(lái)描述一個(gè)字符設(shè)備,每個(gè)字符設(shè)備都有一個(gè)自己的cdev。設(shè)計(jì)字符設(shè)備首先定義一個(gè)cdev。例:staticstructcdevgec6818_led_cdev;正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序2、定義并初始化一個(gè)文件操作集(1)文件操作集#include<linux/fs.h>structfile_operations{ structmodule*owner; ............................... ssize_t(*read)(structfile*,char__user*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*); int(*mmap)(structfile*,structvm_area_struct*); int(*open)(structinode*,structfile*); int(*release)(structinode*,structfile*); long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong); ..............................}正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序2、定義并初始化一個(gè)文件操作集(2)文件操作集的作用每個(gè)cdev都有一個(gè)文件操作集,文件操作集是驅(qū)動(dòng)程序給應(yīng)用程序提供的接口。應(yīng)用程序open()會(huì)找到驅(qū)動(dòng)程序的open(),驅(qū)動(dòng)程序的open()可以用來(lái)訪問硬件。(3)例intgec6818_led_open(structinode*inode,structfile*filp){ return0;}ssize_tgec6818_led_read(structfile*filp,char__user*user_buf,size_tsize,loff_t*off){}ssize_tgec6818_led_write(structfile*filp,constchar__user*user_buf,size_tsize,loff_t*off){

}正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序2、定義并初始化一個(gè)文件操作集intgec6818_led_release(structinode*inode,structfile*filp){

return0;}staticconststructfile_operationsgec6818_led_fops={ .owner=THIS_MODULE,//此處是逗號(hào) .open=gec6818_led_open, .read=gec6818_led_read, .write=gec6818_led_write, .release=gec6818_led_release,};正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序3、給字符設(shè)備申請(qǐng)一個(gè)設(shè)備號(hào)---dev_tdev(1)什么是設(shè)備號(hào)每個(gè)設(shè)備文件(字符設(shè)備or塊設(shè)備)都有一個(gè)設(shè)備號(hào),相當(dāng)于設(shè)備文件ID。設(shè)備號(hào)是一個(gè)32bits的無(wú)符號(hào)整型值,設(shè)備號(hào)有主設(shè)備號(hào)(高12位)和次設(shè)備號(hào)(低20位)組成的。 typedef__u32__kernel_dev_t; typedef__kernel_dev_t

dev_t;(2)設(shè)備號(hào)運(yùn)算的函數(shù) 1)由主設(shè)備號(hào)和次設(shè)備號(hào)生成設(shè)備號(hào) #defineMKDEV(ma,mi) (((ma)<<MINORBITS)|(mi))//MINORBITS=20 2)由設(shè)備號(hào)得到主設(shè)備號(hào)和次設(shè)備號(hào) #defineMAJOR(dev) ((unsignedint)((dev)>>MINORBITS)) #defineMINOR(dev) ((unsignedint)((dev)&MINORMASK))正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序3、給字符設(shè)備申請(qǐng)一個(gè)設(shè)備號(hào)---dev_tdev(3)主設(shè)備號(hào)和次設(shè)備號(hào)的作用

例:cd/dev---ls-l crw-rw----1rootroot204,64Jan11970ttySAC0串口0 crw-rw----1rootroot204,65Jan11970ttySAC1 crw-rw----1rootroot204,66Jan11970ttySAC2 crw-rw----1rootroot204,67Jan11970ttySAC3串口3主設(shè)備號(hào)描述一個(gè)硬件設(shè)備的類型:如uart、IIC、攝像頭、...次設(shè)備號(hào)描述這種硬件類型下的具體某個(gè)硬件/dev/sys/class/主設(shè)備號(hào)一樣,說(shuō)明使用同一個(gè)類。正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序3、給字符設(shè)備申請(qǐng)一個(gè)設(shè)備號(hào)---dev_tdev(4)如何申請(qǐng)?jiān)O(shè)備號(hào)

1)靜態(tài)注冊(cè)--->指定設(shè)備號(hào),注冊(cè)到內(nèi)核中。如果內(nèi)核已經(jīng)使用該設(shè)備號(hào),注冊(cè)就不成功。intregister_chrdev_region(dev_tfrom,unsignedcount,constchar*name)參數(shù)說(shuō)明: dev_tfrom--->注冊(cè)的設(shè)備號(hào);如果一次注冊(cè)多個(gè)設(shè)備號(hào),from就是注冊(cè)設(shè)備號(hào)的開始值 unsignedcount--->次設(shè)備的數(shù)量 constchar*name---->設(shè)備名稱,但不是設(shè)備文件的名字。#cat/proc/devices返回值:

成功返回0,失敗返回復(fù)數(shù)錯(cuò)誤碼。例:crw-rw----1rootroot204,64Jan11970ttySAC0串口0crw-rw----1rootroot204,65Jan11970ttySAC1crw-rw----1rootroot204,66Jan11970ttySAC2crw-rw----1rootroot204,67Jan11970ttySAC3串口3register_chrdev_region(MKDEV(204,64),4,"ttySAC")//ttySAC--->設(shè)備名稱

///dev/ttySAC0--->設(shè)備文件正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序3、給字符設(shè)備申請(qǐng)一個(gè)設(shè)備號(hào)---dev_tdev(4)如何申請(qǐng)?jiān)O(shè)備號(hào)

2)動(dòng)態(tài)分配--->內(nèi)核自動(dòng)分配空閑的設(shè)備號(hào)intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,

constchar*name)參數(shù)說(shuō)明: dev_t*dev --->分配后的設(shè)備號(hào) unsignedbaseminor --->次設(shè)備號(hào)的開始值 unsignedcount --->次設(shè)備的數(shù)量 constchar*name ---->設(shè)備名稱,但不是設(shè)備文件的名字。#cat/proc/devices返回值:

成功返回0,失敗返回復(fù)數(shù)錯(cuò)誤碼。

3)設(shè)備號(hào)的注銷voidunregister_chrdev_region(dev_tfrom,unsignedcount)參數(shù)說(shuō)明: dev_tfrom --->注冊(cè)的設(shè)備號(hào);如果一次注冊(cè)多個(gè)設(shè)備號(hào),from就是注冊(cè)設(shè)備號(hào)的開始值 unsignedcount --->次設(shè)備的數(shù)量正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序4、初始化字符設(shè)備voidcdev_init(structcdev*cdev,conststructfile_operations*fops)思考:staticstructcdevgec6818_led_cdev;//有內(nèi)存cdev_init(&gec6818_led_cdev,conststructfile_operations*fops);或:staticstructcdev*gec6818_led_cdev;//沒有內(nèi)存cdev_init(gec6818_led_cdev,conststructfile_operations*fops);//segmentfaultok:staticstructcdev*gec6818_led_cdev;gec6818_led_cdev=(structcdev*)kmalloc(sizeof(structcdev),GFP_KERNEL)if(gec6818_led_cdev==NULL){

}cdev_init(gec6818_led_cdev,conststructfile_operations*fops);//segmentfault正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序5、將字符設(shè)備加入內(nèi)核(1)字符設(shè)備加入到內(nèi)核intcdev_add(structcdev*p,dev_tdev,unsignedcount)參數(shù): structcdev*p--->定義初始化好的字符設(shè)備 dev_tdev--->設(shè)備號(hào) unsignedcount--->次設(shè)備的數(shù)量返回值:

錯(cuò)誤返回錯(cuò)誤碼(2)

從內(nèi)核中移除字符設(shè)備voidcdev_del(structcdev*p)正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序6、創(chuàng)建class

創(chuàng)建class和device的目的是在安裝的驅(qū)動(dòng)的時(shí)候,可以自動(dòng)生成設(shè)備文件,在卸載驅(qū)動(dòng)的時(shí)候,可以自動(dòng)的刪除設(shè)備文件。

如果不自動(dòng)生成設(shè)備文件:也可以手動(dòng)創(chuàng)建:#mkmodc/dev/led_drv主設(shè)備號(hào)

次設(shè)備號(hào)

創(chuàng)建的class生成在:/sys/class/#include<linux/device.h>(1)創(chuàng)建classstructclass*class_create(structmodule*owner,constchar*name)參數(shù)說(shuō)明: structmodule*owner--->創(chuàng)建的class屬于哪個(gè)module,一般為THIS_MODULE。 constchar*name--->自定義的class的名字返回值:

得到的class(2)class的刪除voidclass_destroy(structclass*cls);正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序7、創(chuàng)建devicedevice是輸于class的,當(dāng)驅(qū)動(dòng)程序有了class和device以后,內(nèi)核使用mdev這個(gè)工具,根據(jù)class和device創(chuàng)建該驅(qū)動(dòng)的設(shè)備文件。創(chuàng)建的device怎么查看:/sys/class/***/#include<linux/device.h>(1)創(chuàng)建devicestructdevice*device_create(structclass*class,structdevice*parent,dev_tdevt,void*drvdata,constchar*fmt,...)參數(shù)說(shuō)明: structclass*class --->device屬于哪個(gè)class structdevice*parent --->device的父設(shè)備,一般為NULL dev_tdevt --->設(shè)備號(hào) void*drvdata --->驅(qū)動(dòng)的data,一般為NULL constchar*fmt --->設(shè)備文件的名字返回值: structdevice* --->創(chuàng)建好的device(2)刪除devicevoiddevice_destroy(structclass*class,dev_tdevt)正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序8、申請(qǐng)物理內(nèi)存區(qū)回憶:裸機(jī)控制硬件的流程:

分析原理圖-->找到控制硬件的GPIO-->找GPIO的寄存器--->分析寄存器--->理解寄存器的控制順序--->通過寄存器的地址來(lái)訪問該寄存器注意:裸機(jī)使用的是物理地址,所以直接使用CPU手冊(cè)查到的地址可以編程。linux驅(qū)動(dòng)使用的虛擬地址,不能直接使用物理地址。想辦法,如果通過CPU手冊(cè)查到的物理地址找到其對(duì)應(yīng)虛擬地址???一般分成兩個(gè)過程:

申請(qǐng)物理地址區(qū)作為一個(gè)資源----->將物理內(nèi)存區(qū)做內(nèi)存的動(dòng)態(tài)映射,得到虛擬地址。注意:

資源---有限的,一旦一個(gè)物理內(nèi)存區(qū)已經(jīng)申請(qǐng)了,后面就不能再次申請(qǐng)。正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序8、申請(qǐng)物理內(nèi)存區(qū)(1)申請(qǐng)物理內(nèi)存區(qū)作為資源structresource*request_mem_region(resource_size_tstart,resource_size_tn, constchar*name)參數(shù)說(shuō)明: resource_size_tstart --->物理內(nèi)存區(qū)的開始地址 resource_size_tn --->物理內(nèi)存區(qū)的大小 constchar*name --->自定義的物理內(nèi)存區(qū)的名字返回值: structresource* --->物理內(nèi)存區(qū)作為了資源思考:LED驅(qū)動(dòng),申請(qǐng)哪個(gè)物理內(nèi)存區(qū)??? D8-->GPIOC17,D9-->GPIOC8,D10-->GPIOC7,D11-->GPIOC12 startaddress --->0xC001C000 addresssize --->結(jié)束地址:0xC001CFFF,大?。?x1000 name --->"GPIOC_MEM"(2)釋放申請(qǐng)的物理內(nèi)存區(qū)voidrelease_mem_region(resource_size_tstart,resource_size_tn)正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序9、io內(nèi)存動(dòng)態(tài)映射,得到虛擬地址#include<linux/io.h>(1)IO內(nèi)存動(dòng)態(tài)映射

將一段物理地址內(nèi)存區(qū)映射成一段虛擬地址內(nèi)存區(qū)void__iomem*ioremap(phys_addr_toffset,unsignedlongsize)參數(shù)說(shuō)明: phys_addr_toffset --->要映射的物理內(nèi)存區(qū)開始地址 unsignedlongsize --->物理內(nèi)存區(qū)的大小返回值: void__iomem* --->映射后,虛擬地址內(nèi)存區(qū)的首地址(2)解除IO內(nèi)存動(dòng)態(tài)映射voidiounmap(void__iomem*addr)正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序10、使用虛擬地址(1)得到虛擬地址 gpioc_base_va=ioremap(phys_addr_toffset,unsignedlongsize) if(gpioc_base_va==NULL){ printk("ioremaperror\n"); release_mem_region(0xC001C000,0x1000); device_destroy(leds_class,led_num); class_destroy(leds_class); cdev_del(&gec6818_led_cdev); unregister_chrdev_region(led_num,1); return-EBUSY; } //得到每個(gè)寄存器的虛擬地址 gpiocout_va=gpioc_base_va+0x00; gpiocoutenb_va=gpioc_base_va+0x04; gpiocaltfn0_va=gpioc_base_va+0x20; gpiocaltfn1_va=gpioc_base_va+0x24; gpiocpad_va=gpioc_base_va+0x18;正大氣象厚德載物MinnanUniversityofScienceandTechnology二、編寫LED驅(qū)動(dòng)程序10、使用虛擬地址(2)虛擬地址的類型:void__iomem*(3)訪問虛擬地址的方法:與訪問物理地址的方法一樣 //10.訪問虛擬地址 //10.1GPIOC7,8.12,17--->function1,作為普通的GPIO

*(unsignedint*)gpiocaltfn0_va&=~((3<<14)|(3<<16)|(3<<24)); *(unsignedint*)gpiocaltfn1_va&=~(3<<2); *(unsignedint*)gpiocaltfn0_va|=((1<<14)|(1<<16)|(1<<24)); *(unsignedint*)gpiocaltfn1_va|=(1<<2); //10.2GPIOC7,8.12,17--->設(shè)置為輸出

*(unsignedint*)gpiocoutenb_va|=((1<<7)|(1<<8)|(1<<12)|(1<<17)); //10.3GPIOC7,8.12,17--->設(shè)置為輸出高電平,D8~D11off

*(unsignedint*)gpiocout_va|=((1<<7)|(1<<8)|(1<<12)|(1<<17));(4)虛擬地址的訪問方法:使用內(nèi)核提供的函數(shù)u32readl(constvolatilevoid__iomem*addr)voidwritel(u32b,volatilevoid__iomem*addr)或者:void__raw_writel(u32b,volatilevoid__iomem*addr)u32__raw_readl(constvolatilevoid__iomem*addr)正大氣象厚德載物MinnanUniversityofScienceandTechnology三、常見錯(cuò)誤碼#include<linux/errno.h>#define EPERM 1 /*Operationnotpermitted*/#define ENOENT

2 /*Nosuchfileordirectory*/#define ESRCH 3 /*Nosuchprocess*/#define EINTR 4 /*Interruptedsystemcall*/#define EIO 5 /*I/Oerror*/#define ENXIO 6 /*Nosuchdeviceoraddress*/#define E2BIG 7 /*Argumentlisttoolong*/#define ENOEXEC 8 /*Execformaterror*/#define EBADF 9 /*Badfilenumber*/#define ECHILD 10 /*Nochildprocesses*/#define EAGAIN 11 /*Tryagain*/#define ENOMEM 12 /*Outofmemory*/#define EACCES 13 /*Permissiondenied*/#define EFAULT 14 /*Badaddress*/#define ENOTBLK 15 /*Blockdevicerequired*/#define EBUSY 16 /*Deviceorresourcebusy*/#define EEXIST 17 /*Fileexists*/正大氣象厚德載物MinnanUniversityofScienceandTechnology三、常見錯(cuò)誤碼#define EXDEV 18 /*Cross-devicelink*/#define ENODEV 19 /*Nosuchdevice*/#define ENOTDIR 20 /*Notadirectory*/#define EISDIR 21 /*Isadirectory*/#define EINVAL 22 /*Invalidargument*/#define ENFILE 23 /*Filetableoverflow*/#define EMFILE 24 /*Toomanyopenfiles*/#define ENOTTY 25 /*Notatypewriter*/#define ETXTBSY 26 /*Textfilebusy*/#define EFBIG 27 /*Filetoolarge*/#define ENOSPC 28 /*Nospaceleftondevice*/#define ESPIPE 29 /*Illegalseek*/#define EROFS 30 /*Read-onlyfilesystem*/#define EMLINK 31 /*Toomanylinks*/#define EPIPE 32 /*Brokenpipe*/#define EDOM 33 /*Mathargumentoutofdomainoffunc*/#define ERANGE 34 /*Mathresu

溫馨提示

  • 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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論