|
在實(shí)際應(yīng)用過(guò)程中,為了更加高效率的讓用戶層與底層進(jìn)行大量數(shù)據(jù)交換,可以采用內(nèi)存映射的方式,將物理內(nèi)存映射到進(jìn)程空間內(nèi),應(yīng)用程序可以直接對(duì)那塊內(nèi)存進(jìn)行操作從而提高效率。
貼出經(jīng)過(guò)驗(yàn)證的代碼,共后續(xù)分析原理使用。
驅(qū)動(dòng)程序:
- /*
- * Copyright (c) 2016, Lovemengx
- * All rights reserved.
- *
- * 文件名稱: zhc_led.c
- * 摘 要: mmap 學(xué)習(xí)驅(qū)動(dòng)
- *
- * 當(dāng)前版本: 1.0
- * 作 者: Love 夢(mèng)想
- * 完成日期:
- *
- * 取代版本:
- * 原作者 :
- * 完成日期:
- */
- #define __ISDEBUG__ // 開(kāi)啟打印信息
- #include <mach/zhc_public.h>
- #include <linux/miscdevice.h>
- #include <linux/delay.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/mm.h>
- #include <linux/fs.h>
- #include <linux/types.h>
- #include <linux/delay.h>
- #include <linux/moduleparam.h>
- #include <linux/slab.h>
- #include <linux/errno.h>
- #include <linux/ioctl.h>
- #include <linux/cdev.h>
- #include <linux/string.h>
- #include <linux/list.h>
- #include <linux/pci.h>
- #include <linux/vmalloc.h>
- #define DEVICE_NAME "mymap"
- #define MALLOC_SIZE (8192 * 100)
- #define USE_KMALLOC 1
- static unsigned char array[10]= {0,1,2,3,4,5,6,7,8,9};
- unsigned char *g_mmap_buff = NULL;
- int g_mmap_buff_size = MALLOC_SIZE;
- // 分配內(nèi)存
- int mmap_alloc(unsigned char **mmap_buff, int require_buf_size)
- {
- struct page *page;
- unsigned char *mmap_buf_t;
- int mmap_size;
- int i;
-
- mmap_size = PAGE_ALIGN(require_buf_size);
-
- #if USE_KMALLOC //for kmalloc
-
- mmap_buf_t = kzalloc(mmap_size, GFP_KERNEL);
- if (!mmap_buf_t)
- {
- return -1;
- }
- for (page = virt_to_page(mmap_buf_t ); page < virt_to_page(mmap_buf_t + mmap_size); page++)
- {
- SetPageReserved(page);
- }
-
- #else //for vmalloc
-
- mmap_buf_t = vmalloc(mmap_size);
- if (!mmap_buf_t )
- {
- return -1;
- }
- for (i = 0; i < mmap_size; i += PAGE_SIZE)
- {
- SetPageReserved(vmalloc_to_page((void *)(((unsigned long)mmap_buf_t) + i)));
- }
-
- #endif
-
- *mmap_buff = mmap_buf_t;
- return mmap_size;
- }
- void mmap_free(unsigned char *mmap_buf, int mmap_size)
- {
-
- #if USE_KMALLOC
-
- struct page *page;
- for (page = virt_to_page(mmap_buf); page < virt_to_page(mmap_buf + mmap_size); page++)
- {
- ClearPageReserved(page);
- }
- kfree(mmap_buf);
-
- #else
-
- int i;
- for (i = 0; i < mmap_size; i += PAGE_SIZE)
- {
- ClearPageReserved(vmalloc_to_page((void *)(((unsigned long)mmap_buf) + i)));
- }
- vfree(mmap_buf);
-
- #endif
-
- mmap_buf = NULL;
- }
- static int my_open(struct inode *inode, struct file *file)
- {
- dprintk();
- return 0;
- }
- static int my_map(struct file *filp, struct vm_area_struct *vma)
- {
- int ret;
- unsigned long pfn;
- unsigned long start = vma->vm_start;
- unsigned long size = PAGE_ALIGN(vma->vm_end - vma->vm_start);
- int i;
- unsigned char *mmap_buff = g_mmap_buff;
-
- if (size > g_mmap_buff_size || !g_mmap_buff)
- {
- return -EINVAL;
- }
-
- dprintk("g_mmap_buff = 0x%x", g_mmap_buff);
- //往該內(nèi)存寫10字節(jié)數(shù)據(jù)
- for(i=0; i<10; i++)
- {
- mmap_buff[i] = array[i];
- }
-
- #if USE_KMALLOC
-
- return remap_pfn_range(vma, start, (virt_to_phys(g_mmap_buff) >> PAGE_SHIFT), size, PAGE_SHARED);
-
- #else
- /* loop over all pages, map it page individually */
- while (size > 0)
- {
- pfn = vmalloc_to_pfn(mmap_buff);
- if ((ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) < 0)
- {
- return ret;
- }
- start += PAGE_SIZE;
- mmap_buff += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- #endif
- return 0;
- }
- static struct file_operations dev_fops =
- {
- .owner = THIS_MODULE,
- .open = my_open,
- .mmap = my_map,
- };
- static struct miscdevice misc =
- {
- .minor = MISC_DYNAMIC_MINOR,
- .name = DEVICE_NAME,
- .fops = &dev_fops,
- };
- static ssize_t hwrng_attr_current_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- int i;
- for(i = 0; i < 10 ; i++)
- {
- printk("%d\n",g_mmap_buff[i]);
- }
- return 0;
- }
- static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
- hwrng_attr_current_show,
- NULL);
-
- static int __init dev_init(void)
- {
- int ret;
-
- dprintk();
- //注冊(cè)混雜設(shè)備
- ret = misc_register(&misc);
-
- //內(nèi)存分配
- ret = mmap_alloc(&g_mmap_buff, g_mmap_buff_size);
- dprintk("ret = %d\n", ret);
-
- if(NULL == g_mmap_buff)
- {
- eprintk("g_mmap_buff => NULL");
- return 0;
- }
- ret = device_create_file(misc.this_device,&dev_attr_rng_current);
- return ret;
- }
- static void __exit dev_exit(void)
- {
- dprintk();
- //注銷設(shè)備
- misc_deregister(&misc);
-
- mmap_free(g_mmap_buff, g_mmap_buff_size);
- }
- module_init(dev_init);
- module_exit(dev_exit);
- MODULE_LICENSE("GPL");
- 應(yīng)用:
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
- #include <linux/fb.h>
- #include <sys/mman.h>
- #include <sys/ioctl.h>
- #define PAGE_SIZE 4096 * 2
-
- int main(int argc , char *argv[])
- {
- int fd;
- int i;
- unsigned char *p_map;
- //打開(kāi)設(shè)備
- fd = open("/dev/mymap",O_RDWR);
- if(fd < 0)
- {
- printf("open fail\n");
- exit(1);
- }
- //內(nèi)存映射
- p_map = (unsigned char *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
- if(p_map == MAP_FAILED)
- {
- printf("mmap fail\n");
- goto here;
- }
-
- //打印映射后的內(nèi)存中的前10個(gè)字節(jié)內(nèi)容
- for(i=0; i<10; i++)
- {
- printf("%d\n",p_map[i]);
- p_map[i] = i + 1;
- }
-
- strcpy(p_map, "adcdefghij");
-
- here:
- munmap(p_map, PAGE_SIZE);
-
- return 0;
- }
復(fù)制代碼
|
|