实验二:字符设备驱动实验.doc
- 文档编号:8952563
- 上传时间:2023-05-16
- 格式:DOC
- 页数:9
- 大小:54.50KB
实验二:字符设备驱动实验.doc
《实验二:字符设备驱动实验.doc》由会员分享,可在线阅读,更多相关《实验二:字符设备驱动实验.doc(9页珍藏版)》请在冰点文库上搜索。
实验二:
字符设备驱动实验
一、实验目的
通过本实验的学习,了解Linux操作系统中的字符设备驱动程序结构,并能编写简单的字符设备的驱动程序以及对所编写的设备驱动程序进行测试,最终了解Linux操作系统如何管理字符设备。
二、准备知识
字符设备驱动程序主要包括初始化字符设备、字符设备的I/O调用和中断服务程序。
在字符设备驱动程序的file_operations结构中,需要定义字符设备的基本入口点。
Øopen()函数;
Ørelease()函数
Øread()函数
Øwrite()函数
Øioctl()函数
Øselect()函数。
另外,注册字符设备驱动程序的函数为register_chrdev()。
register_chrdev()原型如下:
intregister_chrdev(unsignedintmajor,//主设备号
constchar*name,//设备名称
structfile_operations*ops);//指向设备操作函数指针
其中major是设备驱动程序向系统申请的主设备号。
如果major为0,则系统为该驱动程序动态分配一个空闲的主设备号。
name是设备名称,ops是指向设备操作函数的指针。
注销字符设备驱动程序的函数是unregister_chrdev(),原型如下:
intunregister_chrdev(unsignedintmajor,constchar*name);
字符设备注册后,必须在文件系统中为其创建一个设备文件。
该设备文件可以在/dev目录中创建,每个设备文件代表一个具体的设备。
使用mknod命令来创建设备文件。
创建设备文件时需要使用设备的主设备号和从设备号作为参数。
阅读教材相关章节知识,了解字符设备的驱动程序结构。
三、实验内容
根据教材提供的实例。
编写一个简单的字符设备驱动程序。
要求该字符设备包括open()、write()、read()、ioctl()和release()五个基本操作,并编写一个测试程序来测试所编写的字符设备驱动程序。
四、实验指导
1、驱动程序编写后,编写一个Makefile文件来编译此驱动程序。
Makefile格式如下:
obj-m:
=mydev.o
all:
make-C/lib/modules/$(shelluname-r)/buildM=$(shellpwd)modules
clean:
make-C/lib/modules/$(shelluname-r)/buildM=$(shellpwd)clean
2、使用#insmod***.ko来安装此驱动程序。
并通过#cat/proc/devices命令查看新加载设备的设备号。
3、接下来需要创建设备文件,使用命令#mknod/dev/***c2540
4、最后运行测试文件来测试驱动程序。
五、实验程序
1、驱动程序memdev.c如下:
staticmem_major=MEMDEV_MAJOR;
module_param(mem_major,int,S_IRUGO);
structmem_dev*mem_devp;/*设备结构体指针*/
structcdevcdev;
/*文件打开函数*/
intmem_open(structinode*inode,structfile*filp)
{
structmem_dev*dev;
/*获取次设备号*/
intnum=MINOR(inode->i_rdev);
if(num>=MEMDEV_NR_DEVS)
return-ENODEV;
dev=&mem_devp[num];
/*将设备描述结构指针赋值给文件私有数据指针*/
filp->private_data=dev;
return0;
}
/*文件释放函数*/
intmem_release(structinode*inode,structfile*filp)
{
return0;
}
/*读函数*/
staticssize_tmem_read(structfile*filp,char__user*buf,size_tsize,loff_t*ppos)
{
unsignedlongp=*ppos;/*记录文件指针偏移位置*/
unsignedintcount=size;/*记录需要读取的字节数*/
intret=0;/*返回值*/
structmem_dev*dev=filp->private_data;/*获得设备结构体指针*/
/*判断读位置是否有效*/
if(p>=MEMDEV_SIZE)/*要读取的偏移大于设备的内存空间*/
return0;
if(count>MEMDEV_SIZE-p)/*要读取的字节大于设备的内存空间*/
count=MEMDEV_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%d\n",count,p);
}
returnret;
}
/*写函数*/
staticssize_tmem_write(structfile*filp,constchar__user*buf,size_tsize,loff_t*ppos)
{
unsignedlongp=*ppos;
unsignedintcount=size;
intret=0;
structmem_dev*dev=filp->private_data;/*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if(p>=MEMDEV_SIZE)
return0;
if(count>MEMDEV_SIZE-p)/*要写入的字节大于设备的内存空间*/
count=MEMDEV_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%d\n",count,p);
}
returnret;
}
/*seek文件定位函数*/
staticloff_tmem_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=MEMDEV_SIZE-1+offset;
break;
default:
/*can'thappen*/
return-EINVAL;
}
if((newpos<0)||(newpos>MEMDEV_SIZE))
return-EINVAL;
filp->f_pos=newpos;
returnnewpos;
}
/*文件操作结构体*/
staticconststructfile_operationsmem_fops=
{
.owner=THIS_MODULE,
.llseek=mem_llseek,
.read=mem_read,
.write=mem_write,
.open=mem_open,
.release=mem_release,
};
/*设备驱动模块加载函数*/
staticintmemdev_init(void)
{
intresult;
inti;
dev_tdevno=MKDEV(mem_major,0);
/*申请设备号,当xxx_major不为0时,表示静态指定;当为0时,表示动态申请*/
/*静态申请设备号*/
if(mem_major)
result=register_chrdev_region(devno,2,"memdev");
else/*动态分配设备号*/
{
result=alloc_chrdev_region(&devno,0,2,"memdev");
mem_major=MAJOR(devno);/*获得申请的主设备号*/
}
if(result<0)
returnresult;
/*初始化cdev结构,并传递file_operations结构指针*/
cdev_init(&cdev,&mem_fops);
cdev.owner=THIS_MODULE;/*指定所属模块*/
cdev.ops=&mem_fops;
/*注册字符设备*/
cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);
/*为设备描述结构分配内存*/
mem_devp=kmalloc(MEMDEV_NR_DEVS*sizeof(structmem_dev),GFP_KERNEL);
if(!
mem_devp)/*申请失败*/
{
result=-ENOMEM;
gotofail_malloc;
}
memset(mem_devp,0,sizeof(structmem_dev));
/*为设备分配内存*/
for(i=0;i { mem_devp[i].size=MEMDEV_SIZE; mem_devp[i].data=kmalloc(MEMDEV_SIZE,GFP_KERNEL); memset(mem_devp[i].data,0,MEMDEV_SIZE); } return0; fail_malloc: unregister_chrdev_region(devno,1); returnresult; } /*模块卸载函数*/ staticvoidmemdev_exit(void) { cdev_del(&cdev);/*注销设备*/ kfree(mem_devp);/*释放设备结构体内存*/ unregister_chrdev_region(MKDEV(mem_major,0),2);/*释放设备号*/ } MODULE_AUTHOR("DavidXie"); MODULE_LICENSE("GPL"); module_init(memdev_init); module_exit(memdev_exit); 2、应用程序(测试文件)app-mem.c: #include intmain() { FILE*fp0=NULL; charBuf[4096]; /*初始化Buf*/ strcpy(Buf,"Memischardev! "); printf("BUF: %s\n",Buf); /*打开设备文件*/ fp0=fopen("/dev/memdev0","r+"); if(fp0==NULL) { printf("OpenMemdev0Error! \n"); return-1; } /*写入设备*/ fwrite(Buf,sizeof(Buf),1,fp0); /*重新定位文件位置(思考没有该指令,会有何后果)*/ fseek(fp0,0,SEEK_SET); /*清除Buf*/ strcpy(Buf,"BufisNULL! "); printf("BUF: %s\n",Buf); /*读出设备*/ fread(Buf,sizeof(Buf),1,fp0); /*检测结果*/ printf("BUF: %s\n",Buf); return0; } 3、测试步骤: a)cat/proc/devices看看有哪些编号已经被使用,我们选一个没有使用的XXX。 b)insmodmemdev.ko c)通过"mknod/dev/memdev0cXXX0"命令创建"/dev/memdev0"设备节点。 d)交叉编译app-mem.c文件,下载并执行: #./app-mem,显示: Memischardev!
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 字符 设备 驱动