驱动的MAKEFILE编写报告文档格式.docx
《驱动的MAKEFILE编写报告文档格式.docx》由会员分享,可在线阅读,更多相关《驱动的MAKEFILE编写报告文档格式.docx(17页珍藏版)》请在冰豆网上搜索。
![驱动的MAKEFILE编写报告文档格式.docx](https://file1.bdocx.com/fileroot1/2022-11/24/0a42ba20-0f92-4266-8150-1767dc87a568/0a42ba20-0f92-4266-8150-1767dc87a5681.gif)
2、IO驱动程序和测试程序的编写和下载
(1)、利用vi编辑器,编写一个用于编译xsb_seg.c驱动架构Makefile文件见附录IIMakefile1,运行make编译命令,用ls命令查看编译后的结果,在该目录中应生成xsb_seg.ko模块文件,利用file命令查看xsb_seg.ko文件的格式,应为ARM格式的ELF文件。
(2)、利用vi编辑器,编写一个用于编译IO_test.c驱动架构Makefile文件见附录二Makefile2,其中CC=/usr/local/arm/xscalev1/bin/arm-linux-gcc就是交叉编译工具xscalev1所在路径位置,INCLUDEDIR=/usr/local/arm/xscalev1/arm-linux/include为头文件所在的路径;
运行make命令对IO_test.c源代码进行编译,用ls命令查看编译后的结果,利用file命令查看IO_test文件的格式,应为ARM格式的ELF文件。
(3)、在Linux操作系统下输入minicom,配置串口参数,然后打开EELiod目标平台电源,平台启动后,按CTRL+A,然后按Z,启动串口命令界面,按S键,选择zmodem传输方式;
按回车;
选择PC平台中驱动模块文件xsb_seg.ko和驱动测试文件IO_test,并按回车键。
下载选中的文件,文件下载完毕后按ESC键,退出串口传输,返回目标平台界面。
在目标平台终端利用mknod命令建立设备文件节点;
并利用insmod命令动态加载驱动模块,同时利用lsmod命令查看驱动模块的加载情况。
(4)、在目标平台终端运行八段数码驱动测试程序IO_test,输入命令./IO_test,在平台终端将显示驱动测试程序菜单。
分别输入0、1、2、3、4、5、c、x观察实验箱4位数码管的现象,显然输入1,数码管显示0000-9999;
输入2,数码管显示0123-9012;
输入3,数码管显示8888;
输入4,数码管清0;
输入5,可以从键盘输入数据;
输入c,设备关闭;
输入x,退出。
三、【Makefile文件分析】
1、驱动程序xsb_seg.c的Makefile文件
#Makefileforthe8Segment_LedDriver.#
CFLAGS+=$(DEBFLAGS)–Wall//隐含规则中的变量
ifneq($(KERNELRELEASE),)//如果KERNELRELEASE宏被定义
obj-m:
=xsb_seg.o//生成目标文件
else//如果KERNELRELEASE没有被定义
KERNELDIR?
=/exam/linux-2.6.22.10//内核文件所在目录
PWD:
=$(shellpwd)//驱动程序xsb_seg.c所在目录
ALL:
//以KERNELDIR目录下的内核为基础,编译PWD目录下的驱动程序
$(MAKE)$(CFLAGS)-C$(KERNELDIR)M=$(PWD)modules
endif
clean:
//删除生成的中间文件
rm–fr*.o*.ko*~core.depend.*.cmd*.mod.c.tmp_versions
2、测试程序IO-test.c的Makefile文件
CC=/usr/local/arm/xscalev1/bin/arm-linux-gcc//交叉编译工具目录
INCLUDEDIR=/usr/local/arm/xscalev1/arm-linux/include//头文件目录
CFLAGS=-I..-I$(INCLUDEDIR)//隐含规则变量
TARGET_TEST=led_test
OBJ_TEST=$(TARGET_TEST)
SOURCE_TEST=$(TARGET_TEST).c
//执行OBJ_TEST目录下的SOURCE_TEST程序
$(CC)$(CFLAGS)-o$(OBJ_TEST)$(SOURCE_TEST)
rm-rf$(OBJ_TEST)
四、【驱动程序分析】
我们对驱动程序分几个模块进行分析:
1、模块初始化和驱动初始化:
模块初始化module_init(XSB_Seg_init)函数中的参数XSB_Seg_init实际上为数码管显示驱动模块的初始化函数staticint__initXSB_Seg_init(void),该函数主要完成将产生数码显示的片选控制信号的BA22~BA20通过void*ioremap(unsignedlongoffset,unsignedlongsize)函数为I/O内存区域分配虚拟地址,这样设备驱动程序就能访问I/O内存地址。
staticint__initXSB_Seg_init(void)
{
intret;
printk(KERN_EMERG"
TheModuleisInit,XSB_Seg_init\n"
);
CS1_Address=ioremap(SEG_CS1,4);
CS2_Address=ioremap(SEG_CS2,4);
ret=register_chrdev(61,DEVICE_NAME,&
Emdoor_fops);
if(ret<
0){
printk(DEVICE_NAME"
can'
tgetmajornumber\n"
returnret;
}
return0;
}
2、模块的卸载:
模块的卸载module_exit(XSB_Seg_exit)函数中参数XSB_Seg_exit实际上是模块的从内核卸载时所调用的staticvoid__exitXSB_Seg_exit(void);
设备在卸载时需要回收相应的资源,并利用unregister_chrdev()函数从内核中将设备注销。
staticvoid__exitXSB_Seg_exit(void)
TheModuleisExit,XSB_Seg_exit\n"
iounmap(CS1_Address);
iounmap(CS2_Address);
unregister_chrdev(61,DEVICE_NAME);
module_init(XSB_Seg_init);
module_exit(XSB_Seg_exit);
MODULE_AUTHOR("
Ben.li,ben.li@"
MODULE_DESCRIPTION("
Thisisa8SegmentLeddriverdemo"
3、同时更新所有七段数码光驱动管显示函数//参见附录I
staticvoidUpdateled(structseg*seg_7)
4、写具体某位七段数码光驱动管显示函数//参见附录I
voidvalue_seting(structseg*seg_7,charposition,charvalue)
5、实现七段数码光驱动写操作函数//参见附录I
staticssize_tXSB_Seg_write(structfile*file,constchar*buffer,size_tcount,loff_t*ppos)
6、实现七段数码管驱动IOCTL操作函数//参见附录I
staticintXSB_Seg_ioctl(structinode*ip,structfile*fp,unsignedintcmd,unsignedlongarg)
7、实现七段数码管驱动打开操作函数//参见附录I
staticintXSB_Seg_open(structinode*inode,structfile*filp)
8、实现七段数码管驱动释放函数//参见附录I
staticintXSB_Seg_release(structinode*inode,structfile*filp)
9、七段数码管驱动文件结构体定义//参见附录I
staticstructfile_operationsEmdoor_fops
五、总结
通过本次实验我了解了关于设备驱动的动态加载过程,设备驱动在加载时首先调用入口函数init_module(),该函数完成设备驱动的初始化工作,比如寄存器置位、结构体赋值等一系列工作,其中最重要的一个工作就是向内核注册该设备,对于字符设备调用register_chrdev()完成注册,对于块设备需要调用register_blkdev()完成注册。
注册成功后,该设备获得了系统分配的主设备号、自定义的次设备号,并建立起于文件系统的关联。
设备在卸载时需要回收相应的资源,令设备的响应寄存器复位并从系统中注销该设备,字符设备调用unregister_chrdev()、块设备调用unregister_blkdev()。
系统调用部分则是对设备的操作过程,比如open、read、write、ioctl等。
设备驱动程序负责将应用程序如读、写等操作正确无误的传递给相关的硬件,并使硬件能够做出正确反应的代码,因此在编写设备驱动程序时,必须要了解相应的硬件设备的寄存器、IO口及内存的配置参数。
此外,我还学会了编写驱动程序和测试程序的Makefile文件,并可以成功的下载到实验箱上,实现功能。
附录Ⅰ(驱动程序代码):
#include<
linux/module.h>
linux/kernel.h>
asm/io.h>
asm/uaccess.h>
linux/fs.h>
MODULE_LICENSE("
GPL"
charLED_MODULE=0;
#defineDEVICE_NAME"
xsb_seg"
#defineSEG_CS10x10300000
#defineSEG_CS20x10400000
staticcharLED[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7F,0x6F};
unsignedlong*CS1_Address,*CS2_Address;
structseg
charLED1_Val;
charLED2_Val;
charLED3_Val;
charLED4_Val;
charnegative;
};
staticvoidUpdateled(structseg*seg_7)
unsignedshortbuff=0x00;
buff=seg_7->
LED1_Val;
buff=buff|(seg_7->
LED2_Val<
<
8);
writew(buff,CS1_Address);
buff=0x00;
LED3_Val;
LED4_Val<
writew(buff,CS2_Address);
return;
voidvalue_seting(structseg*seg_7,charposition,charvalue)
{
if(seg_7->
negative==0)
value=~value&
~(0x1<
7);
else
value=(0x1<
7)|value;
if(position==1)
seg_7->
LED1_Val=value;
elseif(position==2)
LED2_Val=value;
elseif(position==3)
LED3_Val=value;
elseif(position==4)
LED4_Val=value;
inti;
structseg*seg_7=file->
private_data;
charled_forall[4];
TheModuleiswritten,XSB_Seg_write\n"
if(count!
=4)
{
printk(KERN_EMERG"
thecountofinputisnot4!
!
"
return0;
if(copy_from_user(led_forall,buffer,4))
for(i=1;
i<
=4;
i++)
{
value_seting(seg_7,i,LED[led_forall[i-1]]);
}
Updateled(seg_7);
charval=0x00;
structseg*seg_7=fp->
if(!
arg)
return-EINVAL;
if(copy_from_user(&
val,(int*)arg,sizeof(char)))
return-EFAULT;
switch(cmd){
case1:
value_seting(seg_7,1,val);
break;
case2:
value_seting(seg_7,2,val);
case3:
value_seting(seg_7,3,val);
case4:
value_seting(seg_7,4,val);
case0:
seg_7->
negative=LED_MODULE;
default:
printk(KERN_EMERG"
ioctlparameterinputerror,pleaseinputnumber0-4"
Updateled(seg_7);
structseg*seg_7;
TheModuleisopen,XSB_Seg_open\n"
seg_7=kmalloc(sizeof(structseg),GFP_KERNEL);
//在内核空间分配内存
seg_7->
negative=LED_MODULE;
filp->
private_data=seg_7;
TheModuleisrelease,XSB_Seg_release\n"
kfree(filp->
private_data);
staticstructfile_operationsEmdoor_fops={
open:
XSB_Seg_open,
write:
XSB_Seg_write,
release:
XSB_Seg_release,
ioctl:
XSB_Seg_ioctl,
owner:
THIS_MODULE,
staticvoid__exitXSB_Seg_exit(void)
附录Ⅱ(Makefile代码):
Makefile1
#Makefilefortheemdoor8segdriver.#
CFLAGS+=$(DEBFLAGS)-Wall
ifneq($(KERNELRELEASE),)
obj-m:
=xsb_seg.o
else
KERNELDIR?
=/exam/linux-2.6.22.10
PWD:
=$(shellpwd)
$(MAKE)$(CFLAGS)-C$(KERNELDIR)M=$(PWD)modules
rm-fr*.o*.ko*~core.depend.*.cmd*.mod.c.tmp_versions
Makefile2
CC=/usr/local/arm/xscalev1/bin/arm-linux-gcc
INCLUDEDIR=/usr/local/arm/xscalev1/arm-linux/include
CFLAGS=-I..-I$(INCLUDEDIR)
TARGET_TEST=IO_test
$(CC)$(CFLAGS)-o$(OBJ_TEST)$(SOURCE_TEST)
rm-rf$(OBJ_TEST)
附录Ⅲ(测试程序代码):
stdio.h>
fcntl.h>
unistd.h>
typedefunsignedcharu8;
#defineSEG_DEV"
/dev/xsb_seg"
charnumber[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7F,0x6F};
voidclear_led(intfd)
charval=0;
for(i=1;
ioctl(fd,i,&
val);
sleep
(1);
voiddisplay_led(intfd)
charval=0x7f;
voidappear_same(intfd)
chari,j,base=0;
for(j=0,base=0;
j<
=9;
j++,base++)
{
i<
i++)
ioctl(fd,i,number+base);
voidappear_roll(intfd)
chari,j,base=0;
for(j=0