mmap.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:4k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * mmap.c -- memory mapping for the scull-page char module
  3.  *
  4.  * Can't run with 1.2 or Sparc (unless you tweak it)
  5.  * Tested with 2.0 on the x86
  6.  */
  7. #ifndef __KERNEL__
  8. #  define __KERNEL__
  9. #endif
  10. #ifndef MODULE
  11. #  define MODULE
  12. #endif
  13. #define __NO_VERSION__ /* don't define kernel_verion in module.h */
  14. #include <linux/module.h>
  15. #include <linux/version.h>
  16. #include <linux/mm.h>     /* everything */
  17. #include <linux/errno.h>  /* error codes */
  18. #include <asm/pgtable.h>
  19. #include "scullp.h"        /* local definitions */
  20. /*
  21.  * Don't try to compile mmap on the Sparc: symbols are not exported
  22.  * Nor with old kernels, as the structures were different
  23.  */
  24. #if !defined(__sparc__) && (LINUX_VERSION_CODE >= VERSION_CODE(2,0,0))
  25. /*
  26.  * open and close: just keep track of how many times the device is
  27.  * mapped, to avoid releasing it.
  28.  */
  29. void scullp_vma_open(struct vm_area_struct *vma)
  30. {
  31.     ScullP_Dev *dev = scullp_devices + MINOR(vma->vm_inode->i_rdev);
  32.     dev->vmas++;
  33.     MOD_INC_USE_COUNT;
  34. }
  35. void scullp_vma_release(struct vm_area_struct *vma)
  36. {
  37.     ScullP_Dev *dev = scullp_devices + MINOR(vma->vm_inode->i_rdev);
  38.     dev->vmas--;
  39.     MOD_DEC_USE_COUNT;
  40. }
  41. /*
  42.  * The nopage method: the core of the file. It retrieves the
  43.  * page required from the scullp device and returns it to the
  44.  * user. The count for the page must be incremented, because
  45.  * it is automatically decremented at page unmap.
  46.  *
  47.  * For this reason, "order" must be zero. Otherwise, only the first
  48.  * page has its count incremented, and the allocating module must
  49.  * release it as a whole block. Therefore, it isn't possible to map
  50.  * pages from a multipage block: when they are unmapped, their count
  51.  * is individually decreased, and would drop to 0.
  52.  */
  53. unsigned long scullp_vma_nopage(struct vm_area_struct *vma,
  54.                                 unsigned long address, int write)
  55. {
  56.     unsigned long offset = address - vma->vm_start + vma->vm_offset;
  57.     ScullP_Dev *ptr, *dev = scullp_devices + MINOR(vma->vm_inode->i_rdev);
  58.     void *pageptr = NULL; /* default to "missing" */
  59.     if (offset >= dev->size) return 0; /* out of range: send SIGBUS */
  60.     /*
  61.      * Now retrieve the scullp device from the list,then the page.
  62.      * Don't want to allocate: I'm too lazy. If the device has holes,
  63.      * the process receives a SIGBUS when accessing the hole.
  64.      */
  65.     offset >>= PAGE_SHIFT; /* offset is a number of pages */
  66.     for (ptr = dev; ptr && offset >= dev->qset;) {
  67.         ptr = ptr->next;
  68.         offset -= dev->qset;
  69.     }
  70.     if (ptr && ptr->data) pageptr = ptr->data[offset];
  71.     if (!pageptr) return 0; /* hole or end-of-file: SIGBUS */
  72.     /* got it, now increment the count */
  73.     atomic_inc(&mem_map[MAP_NR(pageptr)].count);
  74.     return (unsigned long)pageptr;
  75. }
  76. struct vm_operations_struct scullp_vm_ops = {
  77.     scullp_vma_open,
  78.     scullp_vma_release,
  79.     NULL,            /* unmap */
  80.     NULL,            /* protect */
  81.     NULL,            /* sync */
  82.     NULL,            /* advise */
  83.     scullp_vma_nopage,
  84. };
  85. int scullp_mmap(struct inode *inode, struct file *filp,
  86.                 struct vm_area_struct *vma)
  87. {
  88.     /* refuse to map if order is not 0 */
  89.     if (scullp_devices[MINOR(inode->i_rdev)].order)
  90.         return -ENODEV;
  91.     if (vma->vm_offset & (PAGE_SIZE-1))
  92.         return -ENXIO; /* need aligned offsets */
  93.     /* don't do anything here: "nopage" will fill the holes */
  94.     vma->vm_ops = &scullp_vm_ops;
  95.     vma->vm_inode = inode;
  96.     inode->i_count++;
  97.     scullp_vma_open(vma);
  98.     return 0;
  99. }
  100. #else /* old or __sparc__ */
  101. int scullp_mmap(struct inode *inode, struct file *filp,
  102.                 struct vm_area_struct *vma)
  103. {
  104.     return -ENODEV; /* like the kernel proper */
  105. }
  106. #endif /* old or __sparc__ */