您的位置:首页 > 运维架构 > Linux

Linux下的简单字符驱动--改自宋宝华《Linux驱动开发详解第2版》在kernel2.6.38通过

2013-02-26 15:59 127 查看
Linux下的简单字符驱动--改自宋宝华《Linux驱动开发详解第2版》在kernel2.6.38通过,实验过程:在fedora9虚拟机上完成交叉编译,生成mini6410_globalmem.ko,复制到tiny6410开发板上。可以用insmod及rmmod添加删除/*globalmemdriverasanexampleofchardevicedrivers
mini6410_globalmem.c
TheinitialdeveloperoftheoriginalcodeisBaohuaSong
<author@linuxdriver.cn>.AllRightsReserved.
======================================================================*/
#include<linux/module.h>
#include<linux/types.h>
#include<linux/fs.h>
#include<linux/errno.h>
#include<linux/mm.h>
#include<linux/sched.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<asm/io.h>
#include<asm/system.h>
#include<asm/uaccess.h>
#include<linux/device.h>
#include<linux/slab.h>
#defineGLOBALMEM_SIZE0x1000/*全局内存最大4K字节*/
#defineMEM_CLEAR0x1/*清0全局内存*/
#defineGLOBALMEM_MAJOR233/*预设的globalmem的主设备号*/
structclass*my_class;
staticglobalmem_major=GLOBALMEM_MAJOR;
/*globalmem设备结构体*/
structglobalmem_dev
{
structcdevcdev;/*cdev结构体*/
unsignedcharmem[GLOBALMEM_SIZE];/*全局内存*/
structsemaphoresem;
};
structglobalmem_dev*globalmem_devp;/*设备结构体指针*/
/*文件打开函数*/
intglobalmem_open(structinode*inode,structfile*filp)
{
/*将设备结构体指针赋值给文件私有数据指针*/
filp->private_data=globalmem_devp;
return0;
}
/*文件释放函数*/
intglobalmem_release(structinode*inode,structfile*filp)
{
return0;
}
/*ioctl设备控制函数afterkernel2.6.36removeioctl,addunlocked_ioctl*/
staticintglobalmem_unlocked_ioctl(structinode*inodep,structfile*filp,unsigned
intcmd,unsignedlongarg)
{
structglobalmem_dev*dev=filp->private_data;//获得设备结构体指针
switch(cmd)
{
caseMEM_CLEAR:
if(down_interruptible(&dev->sem))
return-ERESTARTSYS;
memset(dev->mem,0,GLOBALMEM_SIZE);
up(&dev->sem);
printk(KERN_INFO"globalmemissettozero\n");
break;
default:
return-EINVAL;
}
return0;
}
/*读函数*/
staticssize_tglobalmem_read(structfile*filp,char__user*buf,size_tsize,
loff_t*ppos)
{
unsignedlongp=*ppos;
unsignedintcount=size;
intret=0;
structglobalmem_dev*dev=filp->private_data;/*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if(p>=GLOBALMEM_SIZE)
returncount?-ENXIO:0;
if(count>GLOBALMEM_SIZE-p)
count=GLOBALMEM_SIZE-p;
if(down_interruptible(&dev->sem))
return-ERESTARTSYS;
/*内核空间->用户空间*/
if(copy_to_user(buf,(void*)(dev->mem+p),count))
{
ret=-EFAULT;
}
else
{
*ppos+=count;
ret=count;
printk(KERN_INFO"read%dbytes(s)from%d\n",count,p);
}
up(&dev->sem);
returnret;
}
/*写函数*/
staticssize_tglobalmem_write(structfile*filp,constchar__user*buf,
size_tsize,loff_t*ppos)
{
unsignedlongp=*ppos;
unsignedintcount=size;
intret=0;
structglobalmem_dev*dev=filp->private_data;/*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if(p>=GLOBALMEM_SIZE)
returncount?-ENXIO:0;
if(count>GLOBALMEM_SIZE-p)
count=GLOBALMEM_SIZE-p;
if(down_interruptible(&dev->sem))
return-ERESTARTSYS;
/*用户空间->内核空间*/
if(copy_from_user(dev->mem+p,buf,count))//p是偏移,也就是写入的起始地址
ret=-EFAULT;
else
{
*ppos+=count;
ret=count;
printk(KERN_INFO"written%dbytes(s)from%d\n",count,p);
}
up(&dev->sem);
returnret;
}
/*seek文件定位函数*/
staticloff_tglobalmem_llseek(structfile*filp,loff_toffset,intorig)
{
loff_tret=0;
switch(orig)
{
case0:/*相对文件开始位置偏移*/
if(offset<0)
{
ret=-EINVAL;
break;
}
if((unsignedint)offset>GLOBALMEM_SIZE)
{
ret=-EINVAL;
break;
}
filp->f_pos=(unsignedint)offset;
ret=filp->f_pos;
break;
case1:/*相对文件当前位置偏移*/
if((filp->f_pos+offset)>GLOBALMEM_SIZE)
{
ret=-EINVAL;
break;
}
if((filp->f_pos+offset)<0)
{
ret=-EINVAL;
break;
}
filp->f_pos+=offset;
ret=filp->f_pos;
break;
default:
ret=-EINVAL;
break;
}
returnret;
}
/*文件操作结构体*/
staticconststructfile_operationsglobalmem_fops=
{
.owner=THIS_MODULE,
.llseek=globalmem_llseek,
.read=globalmem_read,
.write=globalmem_write,
.unlocked_ioctl=globalmem_unlocked_ioctl,
.open=globalmem_open,
.release=globalmem_release,
};
/*初始化并注册cdev*/
staticvoidglobalmem_setup_cdev(structglobalmem_dev*dev,intindex)
{
interr,devno=MKDEV(globalmem_major,index);
cdev_init(&dev->cdev,&globalmem_fops);
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&globalmem_fops;
err=cdev_add(&dev->cdev,devno,1);
if(err)
printk(KERN_NOTICE"Error%daddingglobalmem%d",err,index);
}
/*设备驱动模块加载函数*/
intglobalmem_init(void)
{
intresult;
dev_tdevno=MKDEV(globalmem_major,0);
/*申请设备号*/
if(globalmem_major)
result=register_chrdev_region(devno,1,"globalmem");
else/*动态申请设备号*/
{
result=alloc_chrdev_region(&devno,0,1,"globalmem");
globalmem_major=MAJOR(devno);
}
if(result<0)
returnresult;
/*kmalloc*/
globalmem_devp=kmalloc(sizeof(structglobalmem_dev),GFP_KERNEL);
if(!globalmem_devp)/*申请失败*/
{
result=-ENOMEM;
gotofail_malloc;
}
memset(globalmem_devp,0,sizeof(structglobalmem_dev));
globalmem_setup_cdev(globalmem_devp,0);
sema_init(&globalmem_devp->sem,1);//init_MUTEX(&globalmem_devp->sem);
/*createyourownclassunder/sysfs*/
/*class_create-->class_register()*/
my_class=class_create(THIS_MODULE,"globalmem");
if(IS_ERR(my_class)){
printk("Err:failedincreatingclass.\n");
gotofail_malloc;
}
/*registeryourowndeviceinsysfs,andthiswillcauseudevtocreatecorrespondingdevicenode*/
device_create(my_class,NULL,MKDEV(globalmem_major,0),NULL,"globalmem");
printk(KERN_INFO"Registeredcharacterdriver\n");
return0;
fail_malloc:unregister_chrdev_region(devno,1);
returnresult;
}
/*模块卸载函数*/
voidglobalmem_exit(void)
{
cdev_del(&globalmem_devp->cdev);/*注销cdev*/
kfree(globalmem_devp);/*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(globalmem_major,0),1);/*释放设备号*/
}
MODULE_AUTHOR("SongBaohua");
MODULE_LICENSE("DualBSD/GPL");
module_param(globalmem_major,int,S_IRUGO);
module_init(globalmem_init);
module_exit(globalmem_exit);

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: