linux字符设备驱动课程设计报告.docx
- 文档编号:10022624
- 上传时间:2023-02-08
- 格式:DOCX
- 页数:22
- 大小:287.31KB
linux字符设备驱动课程设计报告.docx
《linux字符设备驱动课程设计报告.docx》由会员分享,可在线阅读,更多相关《linux字符设备驱动课程设计报告.docx(22页珍藏版)》请在冰豆网上搜索。
linux字符设备驱动课程设计报告
一、课程设计目的
Linux系统的开源性使其在嵌入式系统的开发中得到了越来越广泛的应用,但其本身并没有对种类繁多的硬件设备都提供现成的驱动程序,特别是由于工程应用中的灵活性,其驱动程序更是难以统一,这时就需开发一套适合于自己产品的设备驱动。
对用户而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说是把设备映射为一个特殊的设备文件,用户程序可以像对其它文件一样对此设备文件进行操作。
通过这次课程设计可以了解linux的模块机制,懂得如何加载模块和卸载模块,进一步熟悉模块的相关操作。
加深对驱动程序定义和设计的了解,了解linux驱动的编写过程,提高自己的动手能力。
二、课程设计内容与要求
字符设备驱动程序
1、设计目的:
掌握设备驱动程序的编写、编译和装载、卸载方法,了解设备文件的创建,并知道如何编写测试程序测试自己的驱动程序是否能够正常工作
2、设计要求:
1)编写一个简单的字符设备驱动程序,该字符设备包括打开、读、写、I\O控制与释放五个基本操作。
2)编写一个测试程序,测试字符设备驱动程序的正确性。
3)要求在实验报告中列出Linux内核的版本与内核模块加载过程。
三、系统分析与设计
1、系统分析
系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。
设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。
设备驱动程序是内核的一部分,它完成以下的功能:
1、对设备初始化和释放;
2、把数据从内核传送到硬件和从硬件读取数据;
3、读取应用程序传送给设备文件的数据和回送应用程序请求的数据;
4、检测和处理设备出现的错误。
字符设备提供给应用程序的是一个流控制接口,主要包括open、close(或release)、read、write、ioctl、poll和mmap等。
在系统中添加一个字符设备驱动程序,实际上就是给上述操作添加对应的代码。
对于字符设备和块设备,Linux内核对这些操作进行了统一的抽象,把它们定义在结构体file_operations中。
2、系统设计:
、模块设计:
数据结构说明
字符设备驱动主要应用了三种数据结构:
①file_operations结构,这是设备驱动程序所提供的一组用一个结构向系统进行说明的入口点;②file结构,主要用于与文件系统对应的设备驱动程序。
代表一个打开的文件,它由内核在open时创建,并传递给在该文件上进行操作的所有函数,直到碰到最后的close函数。
在文件的所有实例都被关闭之后,内核会释放这个数据结构;③inode结构,提供了关于特殊设备文件/dev/mydev的信息。
各个结构的定义如下:
(1)file_operations结构:
staticconststructfile_operationsmy_fops={
.owner=THIS_MODULE,
.llseek=my_llseek,
.read=my_read,
.write=my_write,
.open=my_open,
.release=my_release,
.unlocked_ioctl=ioctl,
};
(2)file结构:
1)读
staticssize_tmy_read(structfile*filp,char__user*buf,size_tsize,loff_t*ppos)
2)写
staticssize_tmy_write(structfile*filp,constchar__user*buf,size_tsize,loff_t*ppos)
3)seek文件定位
staticloff_tmy_llseek(structfile*filp,loff_toffset,intwhence)
4)I\O控制
staticintioctl(structfile*file,unsignedintcmd,unsignedlongarg)
(3)inode结构:
1)打开
intmy_open(structinode*inode,structfile*filp)
2)释放
intmy_release(structinode*inode,structfile*filp)
、算法流程图:
四、系统测试与调试分析
系统测试
启动超级管理员模式并输入密码
命令:
sudosu
对源程序进行编译
命令:
make
加载驱动程序并查看
命令:
insmod和lsmod
显示主设备号
命令:
cat/proc/devices
创建节点并查看
命令:
mknod/dev/lydev550和cd/dev
编译测试程序
命令:
gcc–ot
运行测试函数
命令:
./t
进行打开设备操作
命令:
1
进行写操作并输入hello
命令:
2
进行读操作
命令:
3
进行I/O控制
命令:
4
进行释放设备操作
命令:
5
进行退出操作
命令:
6
卸载驱动程序
命令:
rmmodlydev
查看日志
命令:
dmesg
删除节点并查看
命令:
rmlydev和ls
调试分析
最开始的时候没有启用sudo模式,导致很多命令不能执行,启用模式的时候需要输入密码,但是输入密码的时候是不显示东西的以为出错,查阅资料之后才知道是应有的现象。
程序测试一遍之后再次测试很多命令不能执行,原因是第一次测试之后产生的各种文件没有删除,再次测试会显示已存在。
有一次测试程序,不能卸载驱动,用lsmod查看有两个进程使用,后来强制关机才能正常使用,原因不明,以后要加强学习。
五、程序清单
1.主程序
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include""
#defineSCULL_IOC_MAGIC'k'
#defineSCULL_IOCRESET_IO(SCULL_IOC_MAGIC,0)
#defineSCULL_IOCSQUANTUM_IOW(SCULL_IOC_MAGIC,1,int)
#defineSCULL_IOCSQSET_IOW(SCULL_IOC_MAGIC,2,int)
#defineSCULL_IOCTQUANTUM_IO(SCULL_IOC_MAGIC,3)
#defineSCULL_IOCTQSET_IO(SCULL_IOC_MAGIC,4)
#defineSCULL_IOCGQUANTUM_IOR(SCULL_IOC_MAGIC,5,int)
#defineSCULL_IOCGQSET_IOR(SCULL_IOC_MAGIC,6,int)
#defineSCULL_IOCQQUANTUM_IO(SCULL_IOC_MAGIC,7)
#defineSCULL_IOCQQSET_IO(SCULL_IOC_MAGIC,8)
#defineSCULL_IOCXQUANTUM_IOWR(SCULL_IOC_MAGIC,9,int)
#defineSCULL_IOCXQSET_IOWR(SCULL_IOC_MAGIC,10,int)
#defineSCULL_IOCHQUANTUM_IO(SCULL_IOC_MAGIC,11)
#defineSCULL_IOCHQSET_IO(SCULL_IOC_MAGIC,12)
#defineSCULL_IOC_MAXNR14
staticintly_major=55;
module_param(ly_major,int,S_IRUGO);
structly_dev*ly_devp;/*设备结构体指针*/
structcdevcdev;
staticintioctl(structfile*file,unsignedintcmd,unsignedlongarg);
/*文件打开函数*/
intly_open(structinode*inode,structfile*filp)
{
structly_dev*dev;
/*获取次设备号*/
intnum=MINOR(inode->i_rdev);
if(num>=MYDEV_NR_DEVS)
return-ENODEV;
dev=&ly_devp[num];
/*将设备描述结构指针赋值给文件私有数据指针*/
filp->private_data=dev;
return0;
}
/*文件释放函数*/
intly_release(structinode*inode,structfile*filp)
{
return0;
}
/*读函数*/
staticssize_tly_read(structfile*filp,char__user*buf,size_tsize,loff_t*ppos)
{
unsignedlongp=*ppos;
unsignedintcount=size;
intret=0;
structly_dev*dev=filp->private_data;/*获得设备结构体指针*/
/*判断读位置是否有效*/
if(p>=MYDEV_SIZE)
return0;
if(count>MYDEV_SIZE-p)
count=MYDEV_SIZE-p;
/*读数据到用户空间*/
if(copy_to_user(buf,(void*)(dev->data+p),count))
{
ret=-EFAULT;
}
else
{
*ppos+=count;
ret=count;
printk(KERN_INFO"read%dbytes(s)from%lx\n",count,p);
}
returnret;
}
/*写函数*/
staticssize_tly_write(structfile*filp,constchar__user*buf,size_tsize,loff_t*ppos)
{
unsignedlongp=*ppos;
unsignedintcount=size;
intret=0;
structly_dev*dev=filp->private_data;/*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if(p>=MYDEV_SIZE)
return0;
if(count>MYDEV_SIZE-p)
count=MYDEV_SIZE-p;
/*从用户空间写入数据*/
if(copy_from_user(dev->data+p,buf,count))
ret=-EFAULT;
else
{
*ppos+=count;
ret=count;
printk(KERN_INFO"written%dbytes(s)from%lx\n",count,p);
}
returnret;
}
/*I\O控制函数*/
staticintioctl(structfile*file,unsignedintcmd,unsignedlongarg)
{
if(_IOC_TYPE(cmd)!
=SCULL_IOC_MAGIC)
{
return-EFAULT;
}
if(_IOC_NR(cmd)>SCULL_IOC_MAXNR)
{
return-EFAULT;
}
switch(cmd)
{
caseSCULL_IOCRESET:
printk("SCULL_IOCRESET+%lx",arg);
break;
caseSCULL_IOCSQUANTUM:
/*Set:
argpointstothevalue*/
printk("SCULL_IOCSQUANTUM+%lx",arg);
break;
caseSCULL_IOCTQUANTUM:
/*Tell:
argisthevalue*/
printk("SCULL_IOCTQUANTUM+%lx",arg);
break;
caseSCULL_IOCGQUANTUM:
/*Get:
argispointertoresult*/
printk("SCULL_IOCGQUANTUM+%lx",arg);
break;
caseSCULL_IOCQQUANTUM:
/*Query:
returnit(it'spositive)*/
printk("SCULL_IOCQQUANTUM+%lx",arg);
break;
caseSCULL_IOCXQUANTUM:
/*eXchange:
useargaspointer*/
printk("SCULL_IOCXQUANTUM+%lx",arg);
break;
caseSCULL_IOCHQUANTUM:
/*sHift:
likeTell+Query*/
printk("SCULL_IOCHQUANTUM+%lx",arg);
break;
}
return0;
}
/*seek文件定位函数*/
staticloff_tly_llseek(structfile*filp,loff_toffset,intwhence)
{
loff_tnewpos;
switch(whence){
case0:
/*SEEK_SET*/
newpos=offset;
break;
case1:
/*SEEK_CUR*/
newpos=filp->f_pos+offset;
break;
case2:
/*SEEK_END*/
newpos=MYDEV_SIZE-1+offset;
break;
default:
/*can'thappen*/
return-EINVAL;
}
if((newpos<0)||(newpos>MYDEV_SIZE))
return-EINVAL;
filp->f_pos=newpos;
returnnewpos;
}
/*文件操作结构体*/
staticconststructfile_operationsly_fops=
{
.owner=THIS_MODULE,
.llseek=ly_llseek,
.read=ly_read,
.write=ly_write,
.open=ly_open,
.release=ly_release,
.unlocked_ioctl=ioctl,
};
/*设备驱动模块加载函数*/
staticintlydev_init(void)
{
intresult;
inti;
dev_tdevno=MKDEV(ly_major,0);
/*静态申请设备号*/
if(ly_major)
result=register_chrdev_region(devno,2,"lydev");
else/*动态分配设备号*/
{
result=alloc_chrdev_region(&devno,0,2,"lydev");
ly_major=MAJOR(devno);
}
if(result<0)
returnresult;
/*初始化cdev结构*/
cdev_init(&cdev,&ly_fops);
=THIS_MODULE;
=&ly_fops;
/*注册字符设备*/
cdev_add(&cdev,MKDEV(ly_major,0),MYDEV_NR_DEVS);
/*为设备描述结构分配内存*/
ly_devp=kmalloc(MYDEV_NR_DEVS*sizeof(structly_dev),GFP_KERNEL);
if(!
ly_devp)/*申请失败*/
{
result=-ENOMEM;
gotofail_malloc;
}
memset(ly_devp,0,sizeof(structly_dev));
/*为设备分配内存*/
for(i=0;i { ly_devp[i].size=MYDEV_SIZE; ly_devp[i].data=kmalloc(MYDEV_SIZE,GFP_KERNEL); memset(ly_devp[i].data,0,MYDEV_SIZE); } printk("模块加载成功! \n"); return0; fail_malloc: unregister_chrdev_region(devno,1); returnresult; } /*模块卸载函数*/ staticvoidlydev_exit(void) { cdev_del(&cdev);/*注销设备*/ kfree(ly_devp);/*释放设备结构体内存*/unregister_chrdev_region(MKDEV(ly_major,0),2);/*释放设备号*/ printk("模块卸载成功! \n"); } MODULE_LICENSE("GPL"); module_init(lydev_init); module_exit(lydev_exit); 2.测试程序 #include<> #include #include<> #include<> #include #include #include<> #include<> #defineMAXBUF20 #defineSCULL_IOC_MAGIC'k' #defineSCULL_IOCRESET_IO(SCULL_IOC_MAGIC,0) #defineSCULL_IOCSQUANTUM_IOW(SCULL_IOC_MAGIC,1,int) #defineSCULL_IOCSQSET_IOW(SCULL_IOC_MAGIC,2,int) #defineSCULL_IOCTQUANTUM_IO(SCULL_IOC_MAGIC,3) #defineSCULL_IOCTQSET_IO(SCULL_IOC_MAGIC,4) #defineSCULL_IOCGQUANTUM_IOR(SCULL_IOC_MAGIC,5,int) #defineSCULL_IOCGQSET_IOR(SCULL_IOC_MAGIC,6,int) #defineSCULL_IOCQQUANTUM_IO(SCULL_IOC_MAGIC,7) #defineSCULL_IOCQQSET_IO(SCULL_IOC_MAGIC,8) #defineSCULL_IOCXQUANTUM_IOWR(SCULL_IOC_MAGIC,9,int) #defineSCULL_IOCXQSET_IOWR(SCULL_IOC_MAGIC,10,int) #defineSCULL_IOCHQUANTUM_IO(SCULL_IOC_MAGIC,11) #defineSCULL_IOCHQSET_IO(SCULL_IOC_MAGIC,12) #defineSCULL_IOC_MAXNR14 intmain() { inttestdev; inti,flag=1,t,len=-1; charsel; charbuf[MAXBUF],tmp[MAXBUF]; printf("1、打开设备\n2、写操作\n3、读操作\n4、I/O控制\n5、释放设备\n6、退出\n"); while (1){ printf("请输入要执行的操作: "); sel=getchar(); getchar(); switch(sel){ case'1': testdev=open("/dev/lydev",O_RDWR); if(testdev<0){ printf("设备打开失败\n"); break; } flag=0; printf("设备打开成功! \n" break; /*case'2': if(flag){ printf("请先打开设备! \n"); break; } printf("请输入写入的字符串: "); gets(tmp); len=strlen(tmp); printf("len=%d\n",len); t=write(testdev,tmp,len); if(t<0){ printf("写操作失败! \n"); break; } printf("%s字符串写入成功! \n",tmp); break; case'3': if(flag){ printf("请先打开设备! \n"); break; } if(len<0){ printf("请先进行写操作! \n"); break; } t=read(testdev,buf,len); if(t<0){ printf("读操作失败! \n"); break; } printf("读操作成功! 结果为: %s\n",buf); break;*/ case'2': if(flag){ printf("请先打开设备! \n"); continue; } printf("请
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 字符 设备 驱动 课程设计 报告