/*
关于内核模块读写函数中的最后一个参数loff_t *f_pos的说明:
这个参数的默认值为0,该变量一但修改后,再使用读 或 写函数时,这个参数的值就是修改后的值。
可以用这个值来修改copy_to_user copy_from_user 的指针的偏移。
另外对于file->f_pos 这个值默认也是0,如果没有手动修改它,它会一值为0。
使用这个变量也可以修改上述两个函数的指针的偏移量。
copy_to_user与copy_from_user 这两个函数作为内核内存与用户内存之间的相互复制,返回值为
成功时:返回0 失败时,返回没有复制的数据字节数。
设备注册函数register_chrdev(major,*name,&fops)
这个字符注册函数只能注册一个主设备号,在使用时要注意;反函数为:unregister_chrdev(major,*name)
对于使用不同的主设备号与次设备号的设备驱动注册与卸载过程如下:
驱动加载的过程:
当使用MKDEV(250,0)时,可以使用register_chrdev_region(设备号MKDEV(250,0),设备数量,驱动程序名*name)
cdev_init(struct cdev型的变量,&fops)
cdev_add(&cdev上面初始化好的cdev变量的地址,设备号,设备数量)--
驱动卸载的过程:
cdev_del(&cdev上面初始化好的cdev变量的地址)
在以上的三个函数中都使用的struct cdev类型的变量,这个变量必须是一个cdev型的实例,不能是一个空指针
在下面代码的编写测试时,使用了一个cdev型的空指针,结果导致,死机!
反函数为:unregister_chrdev_region(设备号,设备数量);
*/
#include
#include
#include
#include
//file_operations 位于上面的头文件中
#include
//使用的copy_to_user copy_from_user位于上面的头文件中
#include
//memset()位于上面的头文件中
#include
#include
#include"ioctl_test.h"
#define MEM_DEV_NO MKDEV(251,0)
#define MEM_NAME "mem_dev"
struct mem_dev_struct
{
struct cdev memory_device;
unsigned char buf[1024];
};
static struct mem_dev_struct* mem_dev;
int mem_dev_open(struct inode *inode,struct file *filp)
{
printk("mem_dev_open call\n");
filp->private_data=mem_dev;
return 0;
}
int mem_dev_release(struct inode *inode,struct file *filp)
{
printk("mem_dev_release call\n");
kfree(mem_dev);
return 0;
}
ssize_t mem_dev_read(struct file *filp,char *buf,size_t count,loff_t *f_pos)
{
int ret;
// printk("mem_dev_read call f_pos is %p\n",*f_pos);
// printk("mem dev read filp->f_pos is %p", filp->f_pos);
ret=copy_to_user(buf,mem_dev->buf,count); //数据复制成功返回0,否则返回没有复制成功的字节数
ret = count-ret;
// printk("mem_dev_read call f_pos is %p\n",*f_pos);
return ret;
}
ssize_t mem_dev_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos)
{
int ret;
struct mem_dev_struct *dev = filp->private_data;
// printk("mem_dev_write call f_pos is %p\n",*f_pos);
// printk("mem dev read filp->f_pos is %p", filp->f_pos);
ret=copy_from_user(dev->buf+(*f_pos),buf,count);
ret = count-ret;
*f_pos += count;
// printk("mem_dev_write call f_pos is %p\n",*f_pos);
return ret;
}
int mem_dev_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
int size,err;
int tmp_i;
struct mem_dev_struct *tmp_dev;
tmp_dev=(struct mem_dev_struct *)(filp->private_data);
if(_IOC_TYPE(cmd)!=IOCTL_MAGIC)
return -EINVAL;
if(_IOC_NR(cmd)>=IOCTL_MAX_NR)
return -EINVAL;
size = _IOC_SIZE(cmd);
if(size)
{
err=0;
}
switch(cmd)
{
case IOCTL_SET:
memset(tmp_dev,1,sizeof(struct mem_dev_struct));
break;
case IOCTL_CLEAR:
memset(tmp_dev,0,sizeof(struct mem_dev_struct));
break;
case IOCTL_GETSTATE:
if( tmp_dev->buf[1023]==0 )
return 0;
else
return 1;
break;
case IOCTL_READ:
if(!copy_to_user((void*)arg,tmp_dev->buf,size) )//读取的字节数由 命令的变量类型所占字节 决定
return -1;
break;
case IOCTL_WRITE:
if(!copy_from_user(tmp_dev->buf,(void*)arg,size) )
break;
case IOCTL_WRITE_READ:
if(copy_from_user(tmp_dev->buf,(void*)arg,size) )
return -1;
for(tmp_i=0;tmp_i tmp_dev->buf[tmp_i] +=1; if(copy_to_user((void*)arg,tmp_dev->buf,size) ) return -1; break; } return 0; } struct file_operations mem_fops={ .owner = THIS_MODULE, .open = mem_dev_open, .release= mem_dev_release, .write = mem_dev_write, .read = mem_dev_read, .ioctl = mem_dev_ioctl, }; static int __init mem_init(void) { int result; result=register_chrdev_region(MEM_DEV_NO,1,MEM_NAME); mem_dev=kmalloc(sizeof(struct mem_dev_struct),GFP_KERNEL); if(mem_dev==NULL) { kfree(mem_dev); return -1; } memset(mem_dev,0,sizeof(struct mem_dev_struct)); cdev_init(&mem_dev->memory_device,&mem_fops); cdev_add(&mem_dev->memory_device,MEM_DEV_NO,1); if(result<0) return result; // printk("init hello world\n"); return 0; } static void __exit mem_exit(void) { cdev_del(&mem_dev->memory_device); unregister_chrdev_region(MEM_DEV_NO,1); printk("exit hello world\n"); } module_init(mem_init); module_exit(mem_exit);