您的位置:首页 > 其它

mmap内核空间映射结合kfifo,poll机制的实现例子

2016-12-20 17:52 531 查看
平台:
	全志A20
	Android4.2.2 Linux3.4
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/kfifo.h>
#include <linux/wait.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <asm/io.h>//定义virt_to_phys接口
#include <linux/mm.h>//remap_pfn_range

#define FIFO_SIZE  128
static int DEV_MAJOR = 1222;
static int DEV_MINOR = 0;

static struct class *cdrv_class;
static struct device *cdrv_class_dev;
static struct cdev *c_cdev;
static char *buff;
#if 0
typedef STRUCT_KFIFO_REC_1(FIFO_SIZE) c_fifo;
static c_fifo cdrv_fifo;
#else
struct kfifo_rec_ptr_1 cdrv_fifo;
#endif

static const char *expected_buff1[] = {
"aaaaaaaaaa",
"bbbbbbbbbb",
"cccccccccc",
"dddddddddd",
"eeeeeeeeee",
"ffffffffff",
"gggggggggg",
"hhhhhhhhhh",
};
static const char *expected_buff2[] = {
"iiiiiiiiii",
"jjjjjjjjjj",
"kkkkkkkkkk",
"llllllllll",
"mmmmmmmmmm",
"nnnnnnnnnn",
"oooooooooo",
"pppppppppp",
};
static const char *expected_buff3 = "abcdefghijk";
static const char *expected_buff4 = "lmnopqrstuvwxyz";
#define pagesSIZE 4096
static wait_queue_head_t creadq;
static int flag = 0;
static int wakeMe = 0;
static struct task_struct *tsk;

static int c_open(struct inode *inode,struct file *filp){

//filp->private_data = buff;
buff = (char *)kmalloc(pagesSIZE,GFP_KERNEL);
if(!buff){
printk("kmalloc err \n");
return -1;
}
memset(buff,'\0',pagesSIZE);
return 0;
}

static int c_release(struct inode *inode,struct file *filp){

if(buff){
kfree(buff);
}
return 0;
}

static ssize_t c_read(struct file *filp,char *buf,size_t len,loff_t *off){
#if 0
if(copy_to_user(buf,filp->private_data,strlen(filp->private_data))){
return -EFAULT;
}
#else
int ret;
unsigned int copied;
ret = kfifo_to_user(&cdrv_fifo,buf,len,&copied);

return sizeof(filp->private_data);
#endif
return ret?ret:copied;
}

static ssize_t c_write(struct file *filp,const char *buf,size_t len,loff_t *off){
#if 0
memset(filp->private_data,0,strlen(filp->private_data));
if(copy_from_user(filp->private_data,buf,strlen(buf))){
return -EFAULT;
}

return sizeof(buf);
#else
int ret;
unsigned int copied;

ret = kfifo_from_user(&cdrv_fifo,buf,len,&copied);
return ret?ret:copied;
#endif
}
#if 0
static int fifo_handler(void){
int i;

for(i=0;i<ARRAY_SIZE(expected_buff);i++){
kfifo_in(&cdrv_fifo,expected_buff[i],1);
}
printk("fifo_handler success  \n");
return 0;
}
#endif
static int c_mmap(struct file *filp, struct vm_area_struct *vma){

vma->vm_flags |= VM_IO;
vma->vm_flags |= VM_RESERVED;
if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里
vma->vm_start,//虚拟空间的起始地址
virt_to_phys(buff)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位
vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍
vma->vm_page_prot))//保护属性,
{
return -EAGAIN;
}
//memcpy((void *)buff,"dddddd8",8);
return 0;
}
static int isReadyToWakeup(void *data){
int i,ret;
printk("kthread is in \n");
for(i=0;i<ARRAY_SIZE(expected_buff1);i++){
kfifo_in(&cdrv_fifo,expected_buff1[i],strlen(expected_buff1[i]));
}

//kfifo_in(&cdrv_fifo,expected_buff3,12);
while(!kthread_should_stop()){
if(!kfifo_is_empty(&cdrv_fifo)){
//队列非空
printk("kfifo is not empty \n");
if(wakeMe == 1){
memset(buff,'\0',sizeof(buff));
ret = kfifo_out(&cdrv_fifo,buff,strlen(expected_buff1[1]));
flag = 1;
wake_up_interruptible(&creadq);
wakeMe = 0;
}
}else{
//队列为空
flag = 0;
printk("kffio is empty#################################### \n");
schedule_timeout_uninterruptible(1500);
for(i=0;i<ARRAY_SIZE(expected_buff2);i++){
kfifo_in(&cdrv_fifo,expected_buff2[i],strlen(expected_buff2[i]));
}
//kfifo_in(&cdrv_fifo,expected_buff4,17);
}
schedule_timeout_uninterruptible(300);
}
printk("isReadyToWakeup return with unknew err \n");
return -1;
}
static unsigned int c_poll(struct file *filp,poll_table *wait){
unsigned int mask = 0;
wakeMe = 1;
poll_wait(filp,&creadq,wait);

if(0 != flag){
mask |= POLLIN | POLLRDNORM;
}
printk("release poll.. \n");
return mask;
}

struct file_operations c_fops = {
.owner = THIS_MODULE,
.open = c_open,
.release = c_release,
.read = c_read,
.write = c_write,
.mmap = c_mmap,
.poll = c_poll,
};

static int __init c_init(void){

int ret=0,err=0;
dev_t devno;

if(DEV_MAJOR){
devno = MKDEV(DEV_MAJOR,DEV_MINOR);
ret = register_chrdev_region(devno,1,"cdrv");
}else{
ret = alloc_chrdev_region(&devno,DEV_MINOR,1,"cdrv");
DEV_MAJOR = MAJOR(devno);
}

if(ret<0){
printk("devno request err  \n");
return ret;
}

c_cdev = cdev_alloc();
if(!c_cdev){
printk("cdev_alloc err  \n");
goto cdev_alloc_err;
}
c_cdev->ops = &c_fops;
c_cdev->owner = THIS_MODULE;

err = cdev_add(c_cdev,devno,1);
if(err<0){
printk("cdev_add err \n");
goto cdev_add_err;
}

cdrv_class = class_create(THIS_MODULE,"c_drv");
cdrv_class_dev = device_create(cdrv_class,NULL,MKDEV(DEV_MAJOR,DEV_MINOR),NULL,"cdrv-%d",0);
if(!cdrv_class_dev){
printk("device create err  \n");
goto device_create_err;
}
init_waitqueue_head(&creadq);
#if 0
INIT_KFIFO(cdrv_fifo);
#else
err = kfifo_alloc(&cdrv_fifo, FIFO_SIZE, GFP_KERNEL);
if (ret) {
printk(KERN_ERR "error kfifo_alloc\n");
goto kfifo_alloc_err;
}
#endif

#if 0
err = fifo_handler();
if(err){
printk("fifo_handler err  \n");
return err;
}
#endif
tsk = kthread_run(isReadyToWakeup,NULL,"thread_isReadyToWakeup");
if(NULL == tsk){
printk("kthread created failed  \n");
goto kthread_run_err;
}
printk("init is ok \n\n");
return 0;

kthread_run_err:
kfifo_free(&cdrv_fifo);
kfifo_alloc_err:
device_unregister(cdrv_class_dev);
device_create_err:
class_destroy(cdrv_class);
cdev_del(c_cdev);
cdev_add_err:
kfree(c_cdev);
cdev_alloc_err:
unregister_chrdev_region(devno,1);
return err;
}

static void __exit c_exit(void){
dev_t devno = MKDEV(DEV_MAJOR,DEV_MINOR);
if(tsk){
kthread_stop(tsk);
}
kfifo_free(&cdrv_fifo);
device_unregister(cdrv_class_dev);
class_destroy(cdrv_class);
cdev_del(c_cdev);
kfree(c_cdev);
unregister_chrdev_region(devno,1);
}

module_init(c_init);
module_exit(c_exit);
MODULE_LICENSE("GPL");
用户测设程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/select.h>
#define MBUFF_SIZE 20
int main()
{
char *mbuff;
        int fd,i;
fd_set rfds;
struct timeval tv;

        fd=open("/dev/cdrv-0",O_RDWR,S_IRUSR | S_IWUSR);
        if(fd == -1){
perror("open");
return -1;
}

mbuff = mmap(NULL,MBUFF_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(mbuff != NULL){
printf("mbuff:  %p \n",mbuff);
//puts(mbuff);
}
else{
puts("mbuff: err");
return -1;
}

while(1){
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
select(fd+1,&rfds,NULL,NULL,&tv);//最后一个参数设为NULL,将会永远等待,即阻塞!
if(FD_ISSET(fd,&rfds)){ 
puts("The new data is:");
puts(mbuff);
//	memset(mbuff,'\0',MBUFF_SIZE);
}else{
printf("No data within 5s,please wait.. \n",&tv.tv_sec);
}
sleep(3);
}

munmap(mbuff,MBUFF_SIZE);
        close(fd);
        return 0;

}
测试截图:

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mmap poll select kfifo kthread