嵌入式 globalmem虚拟字符设备驱动雏形

来源:互联网 发布:重大网络教育学院 编辑:程序博客网 时间:2024/05/19 06:51

 

一、globalmem虚拟设备简介

globalmem意味着“全局内存”,在globalmem字符设备驱动中会分配一片大小GLOBALMEM_SIZE(4KB)的内存空间,并在驱动中提供了对这片内存的读写、控制和定位函数,用户空间的进程能通过Linux系统调用访问这片内存。该设备驱动仅仅是为了讲解问题的方便而凭空制造出来的设备。但他也有用处,由于globalmem可被两个或以上的进程同时访问,其中的全局内存可作为用户空间进程进行通信一种蹩脚的手段。

二、编写驱动代码

1.头文件globalmem.h

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <asm/dma.h>
#include <asm/delay.h>
#include <linux/delay.h>

 

#define GLOBALMEM_SIZE0x1000

#define MEM_CLEAR0x01

#define GLOBALMEM_MAJOR250

static intglobalmem_major = GLOBALMEM_MAJOR;

structglobalmem_dev{

struct cdev cdev;

unsigned char mem[GLOBALMEM_SIZE];

};

2.驱动代码globalmem.c

#include"globalmem.h"

struct globalmem_dev*globalmem_devp;

 

intglobalmem_open(struct inode *inode,struct file *filp)

{

dev_tdevno;

 

filp->private_data=globalmem_devp;

printk("inode->i_rdev=%dglobalmem->cdev->dev=%d\n",inode->i_ino,MAJOR(globalmem_devp->cdev.dev));

return0;

}

 

intglobalmem_release(struct inode *inode,struct file*filp)

{

return0;

}

 

static ssize_tglobalmem_read(struct file *filp,char __user *buf,size_tcount,loff_t *ppos)

{

unsignedlong p = *ppos;

intret = 0;

 

structglobalmem_dev *dev=filp->private_data;

 

if(p>= GLOBALMEM_SIZE - p)

return0;

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 %d\n",count,p);

}

 

returnret;

}

 

static ssize_tglobalmem_write(struct file*filp,const char __user *buf, size_tcount,loff_t *ppos)

{

unsignedlong p = *ppos;

intret = 0;

 

structglobalmem_dev*dev=filp->private_data;

 

if(p>= GLOBALMEM_SIZE)

return 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 %d\n",count,p);

}

returnret;

}

 

static loff_tglobalmem_llseek(struct file *filp,loff_t offset,intorig)

{

loff_tret;

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;

}

returnret;

}

 

static intglobalmem_ioctl(struct inode *inodep,struct file *filp,unsigned intcmd,unsigned long arg)

{

int ret;

struct globalmem_dev*dev=filp->private_data;

switch(cmd){

caseMEM_CLEAR:

memset(dev->mem,0,GLOBALMEM_SIZE);

filp->f_pos= 0;

printk(KERN_INFO"globalmem id set tozero\n");

break;

default:

return-EINVAL;

}

return0;

}

 

static const structfile_operations globalmem_fops = {

.owner= THIS_MODULE,

.llseek= globalmem_llseek,

.read= globalmem_read,

.write= globalmem_write,

.ioctl= globalmem_ioctl,

.open=globalmem_open,

.release=globalmem_release

};

 

static voidglobalmem_setup_cdev(struct globalmem_dev *dev,intindex)

{

interr,devno =MKDEV(globalmem_major,index);

cdev_init(&dev->cdev,&globalmem_fops);

dev->cdev.owner= THIS_MODULE;

err=cdev_add(&dev->cdev,devno,1);

if(err)

printk(KERN_NOTICE"Error %d addingglobalmem",err);

}

 

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;

 

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);

return0;

fail_malloc:

unregister_chrdev_region(devno,1);

returnresult;

}

 

voidglobalmem_exit(void)

{

cdev_del(&globalmem_devp->cdev);

kfree(globalmem_devp);

unregister_chrdev_region(MKDEV(globalmem_major,0),1);

}

 

MODULE_LICENSE("DualBSD/GPL");

module_param(globalmem_major,int,S_IRUGO);

 

module_init(globalmem_init);

module_exit(globalmem_exit);

MODULE_AUTHOR("Mac");

3.测试应用程序代码test.c

#include

#include

#include

#include

#include

#include

#include"test_cmd.h"

#include

int main()

{

intfd;

charbuf[20]="Welcome toChina",receve[20]={'\0'};

structioctl_data test_data={

.size=10,

.buf="123456789"

};

fd= open("/dev/Mac",O_WRONLY);

if(fd< 0)

{

printf("open/dev/Mac error\n");

return0;

}

write(fd,buf,20);

close(fd);

fd =open("/dev/Mac",O_RDONLY);

if(fd< 0)

{

printf("open/dev/Mac error\n");

return0;

}

 

read(fd,receve,20);

printf("buf:%s\n",receve);

ioctl(fd,MEM_CLEAR);

read(fd,receve,20);

printf("buf:%s\n",receve);

close(fd);

return0;

}

3.编写Makefile文件

ifneq($(KERNELRELEASE),)

 

obj-m:=mac_test.o

 

else

 

KDIR:=/lib/modules/2.6.28/build

all:

make -C $(KDIR) M=`pwd`modules

clean:

-rm -f *.markers *.order*.ko *.o *.mod.o *.mod.c *.symvers

#make -C $(KDIR) M=`pwd` modulesclean

endif

 

三、测试操作

1.在/dev目录下创建Mac设备文件:#mknod/dev/Mac c 250 0

2.make产生模块文件并加载上。使用gcc编译应用测试程序。

3.执行应用程序即可看到效果。

嵌入式 <wbr>globalmem虚拟字符设备驱动雏形