//micros_mmap.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
//#include <linux/system.h>
#include <linux/uaccess.h>
//#include <asm/arch/irqs.h>
#include <linux/io.h>
#include <linux/version.h>
//#include <asm/hardware.h>
#include <linux/delay.h>
//#include <asm/arch/sep4020_hal.h>
#define DRIVE_MAJOR 165
#define DRIVE_NAME "Test drv"
typedef struct
{
dev_t dev_num ;
struct cdev cdev ;
}code_dev ;
static code_dev test_dev ;
unsigned char data_source;
unsigned char *testmap;
//unsigned char *kmalloc_area;
void *kmalloc_area;
unsigned long msize;
static int test_open(struct inode *inode , struct file *filp)
{
printk("<MICROS_MMAP> : I come in test_open function. \n");
return 0 ;
}
static int test_close(struct inode *inode , struct file *filp)
{
printk("<MICROS_MMAP> : I come in test_close function. \n");
return 0 ;
}
static ssize_t test_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)
{
printk("<MICROS_MMAP> : I come in test_write function. \n");
if(copy_from_user(&data_source,buf,sizeof(data_source)))
{
printk("write error!\n");
}
return(sizeof(data_source));
}
static ssize_t test_read(struct file *filp, char __user *buf,size_t count,loff_t *ppos)
{
printk("<MICROS_MMAP> : I come in test_read function. \n");
if(copy_to_user(buf,&data_source,sizeof(data_source)))
{
printk("read error!\n");
}
return(sizeof(data_source));
}
static int test_mmap(struct file *file,struct vm_area_struct *vma)
{
printk("<MICROS_MMAP> : I come in test_mmap function. \n");
int ret;
ret=remap_pfn_range(vma,vma->vm_start,virt_to_phys((void *)((unsigned long)kmalloc_area))>>PAGE_SHIFT,vma->vm_end-vma->vm_start,PAGE_SHARED);
if(ret!=0)
{
return -EAGAIN;
}
return ret;
}
//long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
static long test_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
printk("<MICROS_MMAP> : I come in test_ioctl function. \n");
int result;
int i;
switch(cmd)
{
case 0:
{
result=0;
}
break;
case 1:
{
result=1;
}
break ;
case 2:
{
for(i=0;i<20;i++)
{
printk("i=%d %c\n",i,*(testmap+i));
}
result=2;
}
break;
default:
return -ENOTTY;
}
return(result);
}
static struct file_operations test_fs = {
.owner = THIS_MODULE ,
.open = test_open ,
.release = test_close ,
.read = test_read ,
.write = test_write ,
.mmap = test_mmap,
//.ioctl = test_ioctl,
.unlocked_ioctl = test_ioctl
};
static int __init test_init(void)
{
printk("<MICROS_MMAP> : -----------------------init-------------. \n");
unsigned int ret ;
unsigned char *virt_addr;
memset(&test_dev , 0 ,sizeof(test_dev)) ;
test_dev.dev_num = MKDEV(DRIVE_MAJOR , 0) ;
ret = register_chrdev_region(test_dev.dev_num , 1 ,DRIVE_NAME) ;
if(ret < 0)
{
return(ret) ;
}
cdev_init(&test_dev.cdev , &test_fs) ;
test_dev.cdev.owner = THIS_MODULE ;
test_dev.cdev.ops = &test_fs ;
printk("\n<MICROS_MMAP> : Init drv \n") ;
ret = cdev_add(&test_dev.cdev , test_dev.dev_num , 1) ;
if(ret < 0)
{
printk("<MICROS_MMAP> : cdev add error !\n") ;
return(ret) ;
}
testmap=kmalloc(4096,GFP_KERNEL);
kmalloc_area=(int *)(((unsigned long)testmap +PAGE_SIZE-1)&PAGE_MASK);
if(testmap==NULL)
{
printk("<MICROS_MMAP> : Kernel mem get pages error\n");
}
for(virt_addr=(unsigned long)kmalloc_area;virt_addr<(unsigned long)kmalloc_area+4096;virt_addr+=PAGE_SIZE)
{
SetPageReserved(virt_to_page(virt_addr));
}
memset(testmap,'q',100);
printk("<MICROS_MMAP> : Test drv reg success !\n") ;
return 0 ;
}
static void __exit test_exit(void)
{
printk("<MICROS_MMAP> : Test drv exit\n") ;
cdev_del(&test_dev.cdev) ;
unregister_chrdev_region(test_dev.dev_num , 1) ;
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
//test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#define max_num 4096
int main(int argc,char *argv[])
{
int fd;
int ret;
unsigned char *rwc,*rrc;
unsigned int *map;
unsigned char ** newmap;
rwc=malloc(sizeof(unsigned char));
rrc=malloc(sizeof(unsigned char));
*rwc=50;
*rrc=30;
fd=open("/dev/drvio1",O_RDWR);
if(fd<0)
{
printf("open file error!\n");
return -1;
}
ret=write(fd,rwc,sizeof(rwc));
ret=read(fd,rrc,sizeof(rrc));
printf("rwc =%d\nrrc =%d\n",*rwc,*rrc);
*rwc=10;
ret=write(fd,rwc,sizeof(rwc));
ret=read(fd,rrc,sizeof(rrc));
printf("rwc =%d\nrrc =%d\n",*rwc,*rrc);
ioctl(fd,2,0);
if((map=(unsigned int *)mmap(NULL,max_num,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0))==MAP_FAILED)
{
printf("mmap error!\n");
}
memset(map,'c',max_num);
strcpy(map,"Welcome");
ioctl(fd,2,0);
munmap(map,4096);
map=NULL;
close(fd);
return 0;
}
MICROS_SOURCE = micros_mmap.c
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
obj-m +=micros_mmap.o
micros-objs := $(MICROS_SOURCE:.c=.o)
all:
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(PWD) modules
insmod:
sudo insmod micros_mmap.ko
rmmod:
sudo rmmod micros_mmap.ko
lsmod:
lsmod | grep micros_mmap
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
生成一个设备节点
mknod /dev/drvio1 c 165 0
验证流程:
0. 创建一个新的虚拟字符设备drvio1,sudo mknod /dev/drvio1 c 165 0
1. 编译模块,在模块目录下执行make,得到micros_mmap.ko
2. 将模块导入内核使之生效:insmod micros_mmap.ko
3. 查看模块是否在内核中运行:lsmod |grep micros_mmap
4. 在核外进行测试,编译test.c得到可执行文件test: gcc -o test test.c
5. 运行test,查看结果