共享内存驱动模拟

#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<asm/uaccess.h>
#include<linux/slab.h>
#include<linux/sched.h>

#define GLOBALMEM_SIZE 50 /*全局fifo最大20字节*/

struct globalmem_dev{
struct cdev cdev; /*cdev结构体*/
unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/
unsigned long globalmem_len; /*globalmem有效数据长度*/
struct class *globalmem_class;
struct device *globalmem_dev;
};

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

static unsigned int globalmem_major=0;

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

return 0;
}

static int globalmem_close(struct inode *inode, struct file *file)
{
return 0;
}

static ssize_t globalmem_read(struct file *file, char __user *buf, size_t size, loff_t *opps)
{
int ret =0;
unsigned long p=*opps;
unsigned count =size;

/* 获得设备结构体指针 */
struct globalmem_dev *dev =file->private_data;

printk("%s():%d %ld\n",__func__,__LINE__,p);

//判断是否为空
if(globalmem_devp->globalmem_len==0)
return 0;

if(count>globalmem_devp->globalmem_len)
count=globalmem_devp->globalmem_len;

/* 内核空间到用户空间 */
if(copy_to_user(buf,(void *)(dev->mem+p),count)){
ret= -EFAULT;
}
else{
*opps +=count;
globalmem_devp->globalmem_len -=count;
ret =count;
}
printk(KERN_INFO "read %d bytes from %ld\n",count,p);

return ret;
}

static ssize_t globalmem_write(struct file *file, const char __user *buf, size_t size, loff_t *opps)
{
unsigned int ret;
unsigned long p =*opps;
unsigned int count =size;

/* 获得设备结构体指针 */
struct globalmem_dev *dev =file->private_data;
printk(KERN_INFO "write :%d", size);
printk("%s():%d %ld\n",__func__,__LINE__,p);

//判断是否满了
if(GLOBALMEM_SIZE-globalmem_devp->globalmem_len==0)
return 0;

//要写入的字节数大于剩余的空间了
if(count>GLOBALMEM_SIZE-globalmem_devp->globalmem_len)
count =GLOBALMEM_SIZE-globalmem_devp->globalmem_len;

/* 用户空间拷贝到内核空间 */
if(copy_from_user((void *)(dev->mem+p),buf,count)){
ret =-EFAULT;
}
else{
*opps +=count;
globalmem_devp->globalmem_len +=count;
ret =count;
}
printk(KERN_INFO "written %d bytes from %ld\n",count,p);

return ret;
}

static loff_t globalmem_llseek(struct file *file, loff_t offset, int orig)
{
loff_t ret =0;
switch(orig){
case 0: /* 相当于文件开始位置偏移 */
if(offset<0){
ret =-EFAULT;
break;
}

if((unsigned int )offset>GLOBALMEM_SIZE){
ret =-EINVAL;
break;
}

file->f_pos =(unsigned int )offset;

ret =file->f_pos;
break;

case 1:/* 相当于从文件当前位置偏移 */
if((file->f_pos + offset)>GLOBALMEM_SIZE){
ret =-EINVAL;
break;
}
if((file->f_pos + offset)<0){
ret =-EINVAL;
break;
}
file->f_pos +=offset;
ret =file->f_pos;
break;
case 2: /*相当于从文件结尾处偏移*/
if((unsigned int )offset>GLOBALMEM_SIZE){
ret =-EINVAL;
break;
}
file->f_pos =globalmem_devp->globalmem_len+(unsigned int )offset;
ret =file->f_pos;
default:
ret =-EINVAL;
break;
}
return ret;
}

static struct file_operations globalmem_fops={
.owner =THIS_MODULE,
.open =globalmem_open,
.release =globalmem_close,
.write =globalmem_write,
.read =globalmem_read,
.llseek =globalmem_llseek,
};

static void globalmem_setup_cdev(void)
{
int err;
cdev_init(&globalmem_devp->cdev,&globalmem_fops);
globalmem_devp->cdev.owner =THIS_MODULE;
err =cdev_add(&globalmem_devp->cdev,MKDEV(globalmem_major,0),1);
if (err){
printk(KERN_ERR "dvb-core: unable register character device\n");
goto error;
}
return;
error:
kobject_put(&globalmem_devp->cdev.kobj);
}

static int __init globalmem_init(void)
{
int ret;
dev_t devno;
/*1.申请主设备号*/
if(globalmem_major){
devno=MKDEV(globalmem_major,0);
ret=register_chrdev_region(devno,1,"globalmem");
}
else{
ret=alloc_chrdev_region(&devno,0,1,"globalmem");
globalmem_major =MAJOR(devno);
}

if(ret<0){
goto register_error;
}
printk("globalmem_major =%d\n",globalmem_major);

/* 2.GFP_KERNEL:如果分配不成功,则会休眠 */
globalmem_devp=kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL);
if(globalmem_devp==NULL){
ret =-ENOMEM;
goto malloc_error;
}

memset(globalmem_devp,0,sizeof(struct globalmem_dev));
globalmem_devp->globalmem_len =0; //有效数据长度

/*3.初始化cdev结构体*/
globalmem_setup_cdev(); //cdev_alloc cdev_init cdev_add

/*4.创建设备节点 */
globalmem_devp->globalmem_class =class_create(THIS_MODULE,"globalmem_class");
if (IS_ERR(globalmem_devp->globalmem_class)){
ret = PTR_ERR(globalmem_devp->globalmem_class);
goto class_create_error;
}

globalmem_devp->globalmem_dev=device_create(globalmem_devp->globalmem_class,NULL,devno,NULL,"globalmem");
if (unlikely(IS_ERR(globalmem_devp->globalmem_dev))){
ret = PTR_ERR(globalmem_devp->globalmem_dev);
goto device_create_error;
}

return 0;

device_create_error:
class_destroy(globalmem_devp->globalmem_class);

class_create_error:
cdev_del(&globalmem_devp->cdev);

malloc_error:
unregister_chrdev_region(devno,1);

register_error:
return ret;

}

static void __exit globalmem_exit(void)
{
dev_t devno =MKDEV(globalmem_major,0);
unregister_chrdev_region(devno,1);
cdev_del(&globalmem_devp->cdev);
device_destroy(globalmem_devp->globalmem_class,devno);
class_destroy(globalmem_devp->globalmem_class);
}

module_init(globalmem_init);
module_exit(globalmem_exit);
MODULE_LICENSE("GPL");

 

 

 

test:

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

/*write process
*./globalmem_test "xxx"
*/
int main(int argc,char argv)
{
int fd;
int nwrite;
int nread;
char rbuf[12]={0};
char *wbuf ="hello world!";

/*1.打开设备文件*/
fd =open("/dev/globalmem",O_RDWR);
if(fd<0){
printf("cannot open /dev/globalmem!\n");
return -1;
}

printf("nbytes =%d\n",strlen(wbuf));

 

 

/*2.往设备文件中写"hello world"字符串*/
nwrite = write(fd, wbuf, 20);
if(nwrite<0){
perror("write error");
exit(0);
}
else if(nwrite==0){
printf("no memory for write!\n");
}
else{
printf("write %d bytes to globalmem\n",nwrite);
}

/*3.将文件指针定位到文件头部*/
if(lseek(fd, 0, SEEK_SET)<0){
perror("lseek failed");
exit(1);
}

/*4.从设备中读取数据*/
nread =read(fd,rbuf,5);
if(nread<0){
perror("write error");
exit(0);
}
else if(nread==0){
printf("no data in globalmem!\n");
}
else{
printf("read %d bytes frome globalmem buf=%s\n",nread,rbuf);
}

close(fd);
return 0;
}

 Makefile:

ifeq ($(KERNELRELEASE),)
KERNELDIR =/home/farsight/Linux_source/linux-2.6.35.5
PWD =$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
arm-unknown-linux-gnueabi-gcc -o globalmem_write_test globalmem_write_test.c
cp globalmem_drv.ko globalmem_write_test /opt/rootfs/s5pc100_drv

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
rm -rf globalmem_write_test *.o *.ko .tmp_versions *.mod.c modules.order Module.symvers
else
obj-m :=globalmem_drv.o
endif

 

posted on 2013-12-26 21:57  weat  阅读(320)  评论(0编辑  收藏  举报