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

嵌入式Linux

开发平台:

C/C++

  1. /*  -*- C -*-
  2.  * mmap.c -- memory mapping for the scullp char module
  3.  *
  4.  * $Id: _mmap.c.in,v 1.19 2001/07/11 08:46:28 rubini Exp $
  5.  */
  6. #ifndef __KERNEL__
  7. #  define __KERNEL__
  8. #endif
  9. #ifndef MODULE
  10. #  define MODULE
  11. #endif
  12. #include <linux/config.h>
  13. #define __NO_VERSION__
  14. #include <linux/module.h>
  15. #include <linux/mm.h>     /* everything */
  16. #include <linux/errno.h>  /* error codes */
  17. #include <asm/pgtable.h>
  18. #include "scullp.h"        /* local definitions */
  19. /*
  20.  * Given a VMA, get our device pointer from it.
  21.  */
  22. static inline ScullP_Dev *scullp_vma_to_dev (struct vm_area_struct *vma)
  23. {
  24. #if defined(LINUX_24)
  25.     return (ScullP_Dev *) vma->vm_private_data;
  26. #elif defined(LINUX_22)
  27.     struct inode *inode = INODE_FROM_F(vma->vm_file); 
  28.     return scullp_devices + MINOR(inode->i_rdev);
  29. #else /* LINUX_20 */
  30.     return scullp_devices + MINOR(vma->vm_inode->i_rdev);
  31. #endif
  32. }
  33. /*
  34.  * open and close: just keep track of how many times the device is
  35.  * mapped, to avoid releasing it.
  36.  */
  37. void scullp_vma_open(struct vm_area_struct *vma)
  38. {
  39.     ScullP_Dev *dev = scullp_vma_to_dev(vma);
  40.     dev->vmas++;
  41.     MOD_INC_USE_COUNT;
  42. }
  43. void scullp_vma_close(struct vm_area_struct *vma)
  44. {
  45.     ScullP_Dev *dev = scullp_vma_to_dev(vma);
  46.     dev->vmas--;
  47.     MOD_DEC_USE_COUNT;
  48. }
  49. /*
  50.  * The nopage method: the core of the file. It retrieves the
  51.  * page required from the scullp device and returns it to the
  52.  * user. The count for the page must be incremented, because
  53.  * it is automatically decremented at page unmap.
  54.  *
  55.  * For this reason, "order" must be zero. Otherwise, only the first
  56.  * page has its count incremented, and the allocating module must
  57.  * release it as a whole block. Therefore, it isn't possible to map
  58.  * pages from a multipage block: when they are unmapped, their count
  59.  * is individually decreased, and would drop to 0.
  60.  */
  61. struct page *scullp_vma_nopage(struct vm_area_struct *vma,
  62.                                 unsigned long address, int write)
  63. {
  64.     unsigned long offset;
  65.     ScullP_Dev *ptr, *dev = scullp_vma_to_dev(vma);
  66.     struct page *page = NOPAGE_SIGBUS;
  67.     void *pageptr = NULL; /* default to "missing" */
  68.     down(&dev->sem);
  69.     offset = (address - vma->vm_start) + VMA_OFFSET(vma);
  70.     if (offset >= dev->size) goto out; /* out of range */
  71.     /*
  72.      * Now retrieve the scullp device from the list,then the page.
  73.      * If the device has holes, the process receives a SIGBUS when
  74.      * accessing the hole.
  75.      */
  76.     offset >>= PAGE_SHIFT; /* offset is a number of pages */
  77.     for (ptr = dev; ptr && offset >= dev->qset;) {
  78.         ptr = ptr->next;
  79.         offset -= dev->qset;
  80.     }
  81.     if (ptr && ptr->data) pageptr = ptr->data[offset];
  82.     if (!pageptr) goto out; /* hole or end-of-file */
  83.     page = virt_to_page(pageptr);
  84.     
  85.     /* got it, now increment the count */
  86.     get_page(page);
  87. out:
  88.     up(&dev->sem);
  89.     return page;
  90. }
  91. #ifndef LINUX_24
  92. unsigned long scullp_vma_nopage_old(struct vm_area_struct *vma,
  93.                 unsigned long address, int write)
  94. {
  95.     struct page *page = scullp_vma_nopage(vma, address, write);
  96.     if (page)
  97. #ifdef LINUX_20
  98.         return (page->map_nr << PAGE_SHIFT);
  99. #else  /* 2.2 */
  100.         return (unsigned long) __va ((page - mem_map) << PAGE_SHIFT);
  101. #endif
  102.     return 0;
  103. }
  104. #define scullp_vma_nopage scullp_vma_nopage_old /* for the ops table */
  105. #endif /* not 2.4 */
  106. struct vm_operations_struct scullp_vm_ops = {
  107.     open:     scullp_vma_open,
  108.     close:  scullp_vma_close,
  109.     nopage:   scullp_vma_nopage,
  110. };
  111. #ifndef LINUX_20
  112. int scullp_mmap(struct file *filp, struct vm_area_struct *vma)
  113. {
  114.     struct inode *inode = INODE_FROM_F(filp);
  115.     /* refuse to map if order is not 0 */
  116.     if (scullp_devices[MINOR(inode->i_rdev)].order)
  117.         return -ENODEV;
  118.     if (VMA_OFFSET(vma) & (PAGE_SIZE-1))                
  119.         return -ENXIO; /* need aligned offsets */
  120.     /* don't do anything here: "nopage" will fill the holes */
  121.     vma->vm_ops = &scullp_vm_ops;
  122.     vma->vm_flags |= VM_RESERVED;
  123. #ifdef LINUX_24
  124.     vma->vm_private_data = scullp_devices + MINOR(inode->i_rdev);
  125. #else
  126.     vma->vm_file = filp;
  127. #endif
  128.     scullp_vma_open(vma);
  129.     return 0;
  130. }
  131. #else /* LINUX_20 */
  132. int scullp_mmap(struct inode *inode, struct file *filp,
  133.                 struct vm_area_struct *vma)
  134. {
  135.     /* refuse to map if order is not 0 */
  136.     if (scullp_devices[MINOR(inode->i_rdev)].order)
  137.         return -ENODEV;
  138.     if (VMA_OFFSET(vma) & (PAGE_SIZE-1))
  139.         return -ENXIO; /* need aligned offsets */
  140.     /* don't do anything here: "nopage" will fill the holes */
  141.     vma->vm_ops = &scullp_vm_ops;
  142.     vma->vm_inode = inode;
  143.     inode->i_count++;
  144.     scullp_vma_open(vma);
  145.     return 0;
  146. }
  147. #endif /* LINUX_20 */