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; }
测试截图:
相关文章推荐
- 内核和用户空间共享内存的实现例程-proc和mmap
- 内核和用户空间共享内存的实现例程-proc和mmap
- 内核和用户空间共享内存的实现例程-proc和mmap
- 内核和用户空间共享内存的实现例程-proc和mmap
- poll系统调用的内核态实现机制分析
- poll机制之内核实现简要分析
- select,poll,epoll实现分析—结合内核源代码
- 利用mmap实现用户空间与内核空间的共享内存通信
- 虚拟字符驱动,申请n页内存,使用mmap映射到应用程序空间,用户就可以直接访问不需要任何同步机制
- select,poll,epoll实现分析—结合内核源代码
- select,poll,epoll实现分析—结合内核源代码
- linux内存布局的内核实现--用户空间的映射方式
- 内核和用户空间共享内存的实现例程-proc和mmap(zt)
- 《Linux 系统内核空间与用户空间通信的实现与分析》 Netlink 机制实现
- 唯快不破:结合内核实现源码分析 select poll epoll区别
- select,poll,epoll实现分析—结合内核源代码 http://blog.csdn.net/vividonly/article/details/7539342
- [Linux内存管理] linux内存布局的内核实现--用户空间的映射方式
- 利用mmap实现用户空间与内核空间的共享内存通信
- 使用netlink机制实现内核空间和用户空间的双向消息通讯
- 内核和用户空间共享内存的实现例程-proc和mmap