当我们编撰完一个驱动后,我们要把它以模块方式编译或则直接编译进内核时,须要更改相关文件,其中最重要的便是kconfig,makefile。
主要是剖析一下二者之间的关系,之后就其句型简略的谈一下。
当我们在内核源码目录下执行make命令时,实际上是依据makefile来进行编译的。
在mini2440开发板上编撰了一个按钮控制led灯的驱动。文件名为buttons_leds.c属于字符驱动,把buttons_leds.c加入/driver/char/目录下,之后在/driver/char/目录下的makefile部份最后添加一行
obj-$(CONFIG_BUTTONS_LEDS)+=buttons_leds.o
如下:
obj-y+=mem.orandom.otty_io.on_tty.otty_ioctl.otty_ldisc.otty_buffer.otty_port.o
obj-$(CONFIG_BFIN_JTAG_COMM)+=bfin_jtag_comm.o
obj-$(CONFIG_CONSOLE_TRANSLATIONS)+=consolemap.oconsolemap_deftbl.o
obj-$(CONFIG_HW_CONSOLE)+=vt.odefkeymap.o
obj-$(CONFIG_AUDIT)+=tty_audit.o
obj-$(CONFIG_BUTTONS_LEDS)+=buttons_leds.o
其中第一行obj-y中的y表示编译进内核,而obj-$(CONFIG_BUTTONS_LEDS)中CONFIG_BUTTONS_LEDS则表示一个变量,类似于我们C语言中的变量linux rar,用$()来表示,它通常可以取三种值y,m,n。y表示编译进内核,而m则表示以模块的方法进行编译,n表示不编译进内核。obj-y+=等号旁边的.o后缀文件则是由该目录下的对应名称的.c文件编译而至。
里面CONFIG_BUTTONS_LEDS变量的取值则是通过.config文件来集中形参的。
.config部份内容如下
#Characterdevices
CONFIG_VT=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
#CONFIG_VT_HW_CONSOLE_BINDINGisnotset
#CONFIG_DEVKMEMisnotset
CONFIG_MINI2440_HELLO_MODULE=m
CONFIG_BUTTONS_LEDS=m
CONFIG_LEDS_MINI2440=m
CONFIG_MINI2440_BUTTONS=m
CONFIG_MINI2440_BUZZER=y
CONFIG_MINI2440_ADC=y
#CONFIG_SERIAL_NONSTANDARDisnotset
从前面几行我们可以看见,在makefile上面的变量都是在.config中形参的。当我们在源代码目录下输入make命令时,都是默认从.config中读入。
当我们在内核源码目录下输入makemenuconfig时,出现如下内容:
.config-LinuxKernelv2.6.32.2Configuration
──────────────────────────────────────────────
┌──────────LinuxKernelConfiguration────────────────────┐
│Arrowkeysnavigatethemenu.selectssubmenus--->.Highlightedlettersarehotkeys.Pressingincludes,excludes,modularizesfeatures.Presstoexit,forHelp,forSearch.Legend:[*]built-in[]excludedmodulemodulecapable
│┌───────────────────────────────────────────┐
││Generalsetup--->│
││[*]Enableloadablemodulesupport--->│
││-*-Enabletheblocklayer--->│
││SystemType--->│
││Bussupport--->│
││KernelFeatures--->│
││Bootoptions--->│
││CPUPowerManagement--->│
││Floatingpointemulation--->│
││Userspacebinaryformats--->│
││Powermanagementoptions--->│
││[*]Networkingsupport--->│
││DeviceDrivers--->│
││Filesystems--->│
│└─────────┴(+)───────────────────────────────│
├────────────────────────────────────────────┤
││
└────────────────────────────────────────────┘
它是通过读取在内核源码目录下的Kconfig文件来配置的。
在/drivers/char/下的目录kconfig部份内容如下:
configDEVKMEM
bool"/dev/kmemvirtualdevicesupport"
defaulty
help
SayYhereifyouwanttosupportthe/dev/kmemdevice.The
/dev/kmemdeviceisrarelyused,butcanbeusedforcertain
kindofkerneldebuggingoperations.
Whenindoubt,say"N".
configMINI2440_HELLO_MODULE
tristate"Mini2440modulesample"
dependsonMACH_MINI2440
defaultmifMACH_MINI2440
help
Mini2440modulesample.
configBUTTONS_LEDS
tristate"Mini2440buttonandledssample"(Mini2440buttonandledssample是显示在makemenuconfig对话框中)
dependsonMACH_MINI2440
defaultmifMACH_MINI2440
help
Mini2440buttonandledsmodulesample.
其具体句型格式说明如下:
config关键字是一个新的配置选项的入口,其后的选项BUTTONS_LEDS省略了CONFIG。完整的表示为CONFIG_BUTTONS_LEDS,也即是当我们将该选项设置成y时,它将手动的将.config的CONFIG_BUTTONS_LEDS=m改写成CONFIG_BUTTONS_LEDS=y。
紧接着的是菜单的属性最主要的有2种tristate,boolean。
tristate表示三态:编译进内核(y),编译成模块(m),不编译(n)。
boolean主要有两种y或n。
depend则表示依赖项。
default缺省的编译选项,m表示默认该文件表示以模块形式编译。
随着操作系统升级,编译选项达到几千个。对于通常人来说,要认清每一个选项是很困难的,通常很多选项都是默认的。
其中.config文件可以自动更改
总的来说,两者之间的关系如下:当我们在内核源码目录下输入makemenuconfig时(从kconfig文件上面读),在出现的菜单界面中选择一项时,它会手动更新.config相应项的值。假如我们没有选择,则会在.config问下插入一行注释。类似于#CONFIG_SERIAL_NONSTANDARDisnotset,当我们输入make时,按照makefile文件来编译,makefile文件中的变量值则由.config来进行形参操作。仅仅只在kconfig中添加选项,只会在菜单界面中显示,虽然此时选择y或m,也不会编译文件。还须要在makefile文件中根据规定添加相应行能够进行编译。简单图解如下:
(makemenuconfig)kconfig--->.config--->(make)makefile
2下边以动态为反例:
一个驱动分为应用层(这儿目的为测试)和底层。
底层:
第一步:
任意在系统上面构建一个文件夹(在用户目录下/home/litingting/)
指令:mkdir/tmp/led
第二步:
在早已构建的文件夹led上面编撰两个文档,一个是Makefile,一个是ledled.c。
指令:echo'obj-m:=ledled.o'>Makefile
解释:
Makefile作用就是定义ledled.c的编译规则。
Makefile编撰:obj-m:=led.o,表示C文件被编译成模块,为前面动态加载做打算ledled.c编撰:这是我们学习的最重要部份Linux驱动有自己的一套规则,一个驱动在linux中被当作一个文件,文件相关的函数主要是write,open之类的,至于程序的编撰系统基本给我们固定了了一个模型,我们编撰就是按这个模型完成上面的功能函数.
第三步:
编译ledled.c文件,把编译好生成的驱动加到开发板上运行,开发板的内核版本为3.0.8,所以我们编译这个函数肯定要在相同版本内核下编译,编译过程要用到相应版本的内头文件linux 驱动 makefile,编译完后会在led文件夹上面生成好多文件,我们要的就是那种ledled.ko文件。
指令:make-C/home/litingting/linux-3.0.8M=/tmp/led
(这一步之前可能要编译内核,先执行make之后执行
cpmini210_android_defconfig.config,这儿遇到时再说)
第四步:
用硬盘拷走ledled.ko文件插到开发板上,启动开发板。
第五步:
连好并口线,在笔记本终端输入sudominicom,步入开发板系统(硬盘会手动挂载到开发板系统的udisk文件下)linux 驱动 makefile,步入该文件夹就可以看见哪个.ko文件,然后输入insmodledled.ko(表示把驱动加入开发板内核)。
然后执行:ls-a/dev(可以查看到这个驱动)
ls-l/dev(可以查看到系统手动为这个驱动分配的主设备号和从设备号)
到此,正常的话驱动早已被烧入内核。
第六步:
构建设备文件(也叫设备节点),系统最终以打开文件的形式来调用驱动,所以肯定得为驱动构建一个与该驱动对应的设备文件,这儿取设备名为ledledo。
mknod/dev/ledledoc1042
c:代表该驱动为字符类型驱动(这些驱动最基础,也是我们主要研究的)
10:代表主设备号
42:从设备号(这两个设备号在第五步上面得到)
到此,底层部份早已完成。
应用层:
第七步:编撰应用层,起名为ledledapp.c(上面肯定有一条指令时打开驱动的指令),编好后用交叉编译器编译,生成可执行文件,之后用硬盘拷走,插到开发板上,打开开发板,打开udisk,才能看见可执行文件ledledapp,执行文件指令为./ledledapp
到此,一个完整的linux驱动反例完成
编译应用程序指令:arm-linux-gcc-static-ohellohello.c有时须要静态编译能够运行
我主要遇到的两个问题:
一个是交叉编译器的使用:
用arm-linux-gcc-static-ohellohello.或则
用arm-linux-gcchello.c-ohello来交叉编译c文件,生成的文件可在arm上运行。
另外一个是:
一定要把开发板一样的内核联通到linux系统的文件夹上面,我的在D盘上面,我如何编译都不能成功,后来我把这个内核文件夹移到linux本身系统上面,就可以了linux系统安装,问题就是D盘文件格式和linux系统上面的文件格式不一样。
文章评论