⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 map_driver.c

📁 mmap driver 是linux环境下的驱动程序
💻 C
字号:
#define _VERSION__#include <linux/kernel.h>#include <linux/module.h>#if CONFIG_MODVERSIOINS==1#define MODVERSIONS#include <linux/modversions.h>#endif#include<linux/fs.h>#include<linux/string.h>#include<linux/errno.h>#include<linux/mm.h>#include<linux/vmalloc.h>#include<linux/wrapper.h>#include<linux/slab.h>#include<asm/io.h>#include<linux/mman.h>#define MAPLEN (4096*10)/* device open */int mapdrv_open(struct inode *inode,struct file *file);/* device close */int mapdrv_release(struct inode *inode,struct file *file);/*device mmap */int mapdrv_mmap(struct file *file,struct vm_area_struct *vma);/* vm area open */void map_vopen(struct vm_area_struct *vma);/* vm area close */void map_vclose(struct vm_area_struct *vma);/* vm area nopage */struct page *map_nopage(struct vm_area_struct *vma,unsigned long address,int write_access);static struct file_operations mapdrv_fops={	owner  : THIS_MODULE,	mmap   : mapdrv_mmap,	open   : mapdrv_open,	release:mapdrv_release,};static struct vm_operations_struct map_vm_ops={	open  : map_vopen,	close : map_vclose,	nopage: map_nopage,};      static int *vmalloc_area = NULL;             static int major; // major number of device      volatile void *vaddr_to_kaddr(volatile void *address){  pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte;  unsigned long va, ret = 0UL;  va=VMALLOC_VMADDR((unsigned long)address);  /* get the page directory. Use the kernel memory map. */  pgd = pgd_offset_k(va);  /* check whether we found an entry */  if (!pgd_none(*pgd))  {   /* get the page middle directory */   pmd = pmd_offset(pgd, va);   /* check whether we found an entry */   if (!pmd_none(*pmd))   {    /* get a pointer to the page table entry */    ptep = pte_offset(pmd, va);    pte = *ptep;    /* check for a valid page */    if (pte_present(pte))      {       /* get the address the page is refering to */       ret = (unsigned long)page_address(pte_page(pte));       /* add the offset within the page to the page address */                        ret |= (va & (PAGE_SIZE -1));      }   }  }   return((volatile void *)ret);}static int  __init mapdrv_init(void){    unsigned long virt_addr;  if ((major=register_chrdev(0, "mapdrv", &mapdrv_fops))<0)   {  printk("mapdrv: unable to register character device\n");  return (-EIO);  }   /* get a memory area that is only virtual contigous. */    vmalloc_area=vmalloc(MAPLEN/*+2*PAGE_SIZE*/);    for (virt_addr=(unsigned long)vmalloc_area;virt_addr<(unsigned long)(&(vmalloc_area[MAPLEN/sizeof(int)]));virt_addr+=PAGE_SIZE)     {     	         mem_map_reserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));     }    /* set a hello message to kernel space for read by user */     strcpy((char*)vmalloc_area,"hello world from kernel space !");             printk("vmalloc_area at 0x%p (phys 0x%lx)\n", vmalloc_area,     virt_to_phys((void *)vaddr_to_kaddr(vmalloc_area)));        return(0);}static void __exit mapdrv_exit(void){  unsigned long virt_addr;  /* unreserve all pages */ for (virt_addr=(unsigned long)vmalloc_area;virt_addr<(unsigned long)(&(vmalloc_area[MAPLEN/sizeof(int)]));virt_addr+=PAGE_SIZE)  {   mem_map_unreserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr)));  }  /* and free the two areas */  if (vmalloc_area)    vfree(vmalloc_area); /* unregister the device */  unregister_chrdev(major, "mapdrv");  return;}/* device open method */int mapdrv_open(struct inode *inode, struct file *file){    MOD_INC_USE_COUNT;    return(0);}/* device close method */int mapdrv_release(struct inode *inode, struct file *file){    MOD_DEC_USE_COUNT;    return(0);}int mapdrv_mmap(struct file *file, struct vm_area_struct *vma){   unsigned long offset = vma->vm_pgoff<<PAGE_SHIFT;   unsigned long size = vma->vm_end - vma->vm_start;   if (offset & ~PAGE_MASK)   {    printk("offset not aligned: %ld\n", offset);    return -ENXIO;   }   if (size>MAPLEN)   {    printk("size too big\n");    return(-ENXIO);   }  /*  only support shared mappings.*/   if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))   {    printk("writeable mappings must be shared, rejecting\n");    return(-EINVAL);   }  /* do not want to have this area swapped out, lock it */    vma->vm_flags |= VM_LOCKED;   if (offset == 0)   {    vma->vm_ops = &map_vm_ops;   /* call the open routine to increment the usage count */    map_vopen(vma);   }else   {     printk("offset out of range\n");     return -ENXIO;   }   return(0);}															       /* open handler for vm area */void map_vopen(struct vm_area_struct *vma){  /* needed to prevent the unloading of the module while  somebody still has memory mapped */     MOD_INC_USE_COUNT;}/* close handler form vm area */void map_vclose(struct vm_area_struct *vma){     MOD_DEC_USE_COUNT;}/* page fault handler */struct page *map_nopage(struct vm_area_struct *vma, unsigned long address, int write_access){  unsigned long offset;  unsigned long virt_addr;  /* determine the offset within the vmalloc'd area  */  offset = address - vma->vm_start + (vma->vm_pgoff<<PAGE_SHIFT);  /* translate the vmalloc address to kmalloc address  */  virt_addr = (unsigned long)vaddr_to_kaddr(&vmalloc_area[offset/sizeof(int)]);  if (virt_addr == 0UL)     {     return((struct page *)0UL);     }  /* increment the usage count of the page */  atomic_inc(&(virt_to_page(virt_addr)->count));  printk("map_drv: page fault for offset 0x%lx (kseg x%lx)\n",offset, virt_addr);   return(virt_to_page(virt_addr));	  }  	module_init(mapdrv_init);module_exit(mapdrv_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -