ubantu14.04第三个使用文件私有数据的globalmem的设备驱动

1. 代码如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <asm/io.h>
//#include <asm/system.h>  //找不到这个文件
#include <linux/slab.h> // for kmalloc and kfree function
#include <asm/uaccess.h>

#define GLOBALMEM_SIZE 0X1000 /*全局内存最大4KB*/
#define MEM_CLEAR 0x1 /*清零全局内存*/
#define GLOBALMEM_MAJOR 354

static int globalmem_major = GLOBALMEM_MAJOR;/*预设的globalmem的主设备号*/

/*globalmem的设备结构体:包含了对应于globalmem字符设备的cdev 和 使用内存mem[GLOBALMEM_SIZE]*/
struct globalmem_dev
{
	struct cdev cdev;  //cdev结构体
	unsigned char mem[GLOBALMEM_SIZE];  //全局内存
};

struct globalmem_dev *globalmem_devp;  //设备结构体指针

/*文件打开函数*/
int globalmem_open(struct inode *inode,struct file *filp)
{
	filp->private_data = globalmem_devp; //将设备结构体指针赋值给文件私有数据指针
	return 0;
}

/*文件释放函数*/
int globalmem_release(struct inode *inode,struct file *filp)
{
	return 0;
}

/*设备控制函数:ioctl()函数接受的MEM_CLEAR命令,这个命令将全局内存的有效数据长度清零,对于设备不支持的命令,ioctl()函数应该返回-EINVAL*/
static long globalmem_ioctl( /*struct inode *inodep,*/struct file *filp,unsigned int cmd,unsigned long arg)
{
	 struct globalmem_dev *dev = filp->private_data; //获得设备结构体指针
	 switch(cmd)
	 {
	  case  MEM_CLEAR:
		memset(dev->mem,0,GLOBALMEM_SIZE);
		printk(KERN_INFO"globalmem is set to zero\n");
	   	break;
	  default:
	   	return -EINVAL;
 	}
 	return 0;
}

/*读函数:读写函数主要是让设备结构体的mem[]数组与用户空间交互数据,并随着访问字节数变更返回用户的文件读写偏移位置*/
static ssize_t globalmem_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos )
{
	 unsigned long p = *ppos;
	 unsigned int count = size;
	 int ret = 0;
	 struct globalmem_dev *dev = filp->private_data; //获得设备结构体指针
	 
	 if(p >= GLOBALMEM_SIZE)  //分析和获取有效的写长度
	 {
	  	return count ? -ENXIO:0;
	 }
	 if(count > GLOBALMEM_SIZE - p)
	 {
	  	count = GLOBALMEM_SIZE - p;
	 }
	 
	 if(copy_to_user(buf,(void *)(dev->mem+p),count))  //内核空间->用户空间
	 {
	  	ret = -EFAULT;
	 }
	 else
	 {
		  *ppos += count;
		  ret = count;
		  printk(KERN_INFO"read %d bytes(s) from %ld\n",count,p);
	 }
	 return ret;
}

/*写函数*/
static ssize_t globalmem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos)
{
	 unsigned long p = *ppos;
	 unsigned int count = size;
	 int ret = 0;
	 
	 struct globalmem_dev *dev = filp->private_data;
	 
	 if(p >= GLOBALMEM_SIZE)  //分析和获取有效的写长度
	 {
	  	return count? -ENXIO:0;
	 }
	 
	 if(count > GLOBALMEM_SIZE - p)
	 {
	  	count = GLOBALMEM_SIZE - p;
	 }
	 
	 if(copy_from_user(dev->mem + p,buf,count)) // 用户空间->内核空间
	 {
	  	ret = -EFAULT;
	 }
	 else
	 {
		  *ppos =+ count;
		  ret = count;
		  printk(KERN_INFO"written %d bytes(s) from %ld\n",count,p);
	 }
	 return ret;
}

/*seek文件定位函数:seek()函数对文件定位的起始地址可以是文件开头(SEEK_SET,0)、当前位置(SEEK_CUR,1)、文件尾(SEEK_END,2)*/
static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig)
{
 loff_t ret = 0;
 switch(orig)
 {
  case 0:   //相对文件开始位置偏移
   if(offset <0 )
   {
    ret = -EINVAL;
    break;
   }
   
   if((unsigned int )offset > GLOBALMEM_SIZE)
   {
    ret = - EINVAL;
    break;
   }
   filp->f_pos = (unsigned int)offset;
   ret = filp->f_pos;
   break;
   
  case 1:   //相对文件当前位置偏移
   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; 
 }
 return ret;
}

/*文件操作结构体*/
static const struct file_operations globalmem_fops=
{
 .owner = THIS_MODULE,
 .llseek = globalmem_llseek,
 .read = globalmem_read,
 .write = globalmem_write,
// .ioctl = globalmem_ioctl,
 .unlocked_ioctl = globalmem_ioctl,
 .open = globalmem_open,
 .release = globalmem_release,
};

/*初始化并注册cdev*/
static void globalmem_setup_cdev(struct globalmem_dev *dev,int index)
{
 int err,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 %d adding LED%d",err,index);
 }
 
}

/*设备驱动模块加载函数*/
static int __init globalmem_init(void)
{
 int result;
 dev_t devno = 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)
 {
  return result;
 }
 
 globalmem_devp = kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL); //申请设备结构体的内存
 if(!globalmem_devp)
 {
  result = -ENOMEM;
  goto fail_malloc;
 }
 
 memset(globalmem_devp,0,sizeof(struct globalmem_dev));
 globalmem_setup_cdev(globalmem_devp,0);
 return 0;
 
 fail_malloc:unregister_chrdev_region(devno,1);
 return result;
}

/*模块卸载函数*/
static void __exit globalmem_exit(void)
{
 cdev_del(&globalmem_devp->cdev); //注销cdev
 kfree(globalmem_devp);          //释放设备结构体内存
 unregister_chrdev_region(MKDEV(globalmem_major,0),1); //释放设备号
}

MODULE_AUTHOR("Song Baohua");
MODULE_LICENSE("Dual BSD/GPL");

module_param(globalmem_major,int,S_IRUGO);

module_init(globalmem_init);
module_exit(globalmem_exit);


2. Makefile:

</pre><p></p><pre name="code" class="plain">KERNELDIR := /lib/modules/$(shell uname -r)/build 

obj-m := globalmem.o

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
  
clean:
	make -C $(KERNELDIR) M=`pwd` modules clean  
	rm -rf modules.order
  

3. 执行:make ,然后sudo insmod globalmem.ko;


4.

 验证:lsmod 可以看到该模块,mknod /dev/globalmem c 354 0, echo 'good nihao' > /dev/globalmem, cat /dev/globalmem可以看到输出good nihao;

还出现了:cat: /dev/globalmem: 没有那个设备或地址,目前不知道是什么问题;

代码验证:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

void main(void)
{
	int fd;
	int i;
	char data[256];
	int retval;
	fd = open("/dev/globalmem",O_RDWR);
	if(fd==-1)
	{
		perror("erroropen\n");
		exit(-1);
	}
	printf("open/dev/globalmem successfully\n");
	//写数据
	retval = write(fd,"mem",3);
	if(retval==-1)
	{
		perror("writeerror\n");
		exit(-1);
	}

	printf("write successfully\n");
	close(fd);
      //若不重新打开,则globalmem.c中的write函数写入后,其写位置*ppos更新了,所以导致下面的读将从写入后的位置
        // 开始读,从而导致读不到数据,如写入后,*ppos位置为9,下次读时将从位置9开始读,导致读不到数据,当然可以设置为
       // 从文件开始位置读,如:copy_to_user(buf, dev->mem, count)
        fd = open("/dev/globalmem",O_RDWR); //  重新打开后,globalmem.c中的read和write函数中的读写位置都是为0
        if(fd==-1)  // <span style="color:#ff0000;">上面不关闭也行,使用lseek( fd, 0L, SEEK_SET );就可以了</span>
        {
                perror("erroropen\n");   
                exit(-1);
        }

	//读数据
	retval=read(fd,data,3 );
	if(retval==-1)
	{
		perror("readerror\n");
		exit(-1);
	}
	data[retval]=0;
	printf("read successfully:%s\n",data);
	//关闭设备
	close(fd);
}
输出如下:

open/dev/globalmem successfully
write successfully
read successfully:mem



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值