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_t devno;
filp->private_data=globalmem_devp;
printk("inode->i_rdev=%dglobalmem->cdev->dev=%d\n",inode->i_ino,MAJOR(globalmem_devp->cdev.dev));
return 0;
}
intglobalmem_release(struct inode *inode,struct file*filp)
{
return 0;
}
static ssize_tglobalmem_read(struct file *filp,char __user *buf,size_tcount,loff_t *ppos)
{
unsigned long p = *ppos;
int ret = 0;
struct globalmem_dev *dev=filp->private_data;
if(p >= GLOBALMEM_SIZE - p)
return 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 %d\n",count,p);
}
return ret;
}
static ssize_tglobalmem_write(struct file *filp,const char __user *buf, size_tcount,loff_t *ppos)
{
unsigned long p = *ppos;
int ret = 0;
struct globalmem_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);
}
return ret;
}
static loff_tglobalmem_llseek(struct file *filp,loff_t offset,intorig)
{
loff_t ret;
switch (orig){
case 0:
if(offset < 0){
ret = -EINVAL;
break;
}
if((unsigned int)offset >GLOBALMEM_SIZE){
ret = -EINVAL;
break;
}
filp->f_pos= (unsignedint)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;
}
return ret;
}
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){
case MEM_CLEAR:
memset(dev->mem,0,GLOBALMEM_SIZE);
filp->f_pos= 0;
printk(KERN_INFO"globalmem id set tozero\n");
break;
default:
return -EINVAL;
}
return 0;
}
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)
{
int err,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)
{
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(structglobalmem_dev),GFP_KERNEL);
if(!globalmem_devp){
result=-ENOMEM;
goto fail_malloc;
}
memset(globalmem_devp,0,sizeof(structglobalmem_dev));
globalmem_setup_cdev(globalmem_devp,0);
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return result;
}
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()
{
int fd;
char buf[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");
return 0;
}
write(fd,buf,20);
close(fd);
fd =open("/dev/Mac",O_RDONLY);
if(fd < 0)
{
printf("open /dev/Mac error\n");
return 0;
}
read(fd,receve,20);
printf("buf:%s\n",receve);
ioctl(fd,MEM_CLEAR);
read(fd,receve,20);
printf("buf:%s\n",receve);
close(fd);
return 0;
}
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.执行应用程序即可看到效果。