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

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * Simple - REALLY simple memory mapping demonstration.
  3.  * $Id: simple.c,v 1.6 2001/03/16 21:04:50 rubini Exp $
  4.  */
  5. #ifndef __KERNEL__
  6. #  define __KERNEL__
  7. #endif
  8. #ifndef MODULE
  9. #  define MODULE
  10. #endif
  11. #include <linux/config.h>
  12. #include <linux/module.h>
  13. #include <linux/kernel.h>   /* printk() */
  14. #include <linux/malloc.h>   /* kmalloc() */
  15. #include <linux/fs.h>       /* everything... */
  16. #include <linux/errno.h>    /* error codes */
  17. #include <linux/types.h>    /* size_t */
  18. #include <asm/page.h>
  19. #include "sysdep.h"
  20. #ifdef LINUX_20
  21. #  error "This module can't run with Linux-2.0"
  22. #endif
  23. static int simple_major = 0;
  24. MODULE_PARM(simple_major, "i");
  25. MODULE_AUTHOR("Jonathan Corbet");
  26. /*
  27.  * Forwards for our methods.
  28.  */
  29. int simple_open (struct inode *inode, struct file *filp);
  30. int simple_release(struct inode *inode, struct file *filp);
  31. int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma);
  32. int simple_nopage_mmap(struct file *filp, struct vm_area_struct *vma);
  33. /*
  34.  * Our various sub-devices.
  35.  */
  36. /* Device 0 uses remap_page_range */
  37. struct file_operations simple_remap_ops = {
  38.     open:    simple_open,
  39.     release: simple_release,
  40.     mmap:    simple_remap_mmap,
  41. };
  42. /* Device 1 uses nopage */
  43. struct file_operations simple_nopage_ops = {
  44.     open:    simple_open,
  45.     release: simple_release,
  46.     mmap:    simple_nopage_mmap,
  47. };
  48. #define MAX_SIMPLE_DEV 2
  49. struct file_operations *simple_fops[MAX_SIMPLE_DEV] = {
  50.     &simple_remap_ops,
  51.     &simple_nopage_ops,
  52. };
  53. /*
  54.  * Open the device; all we have to do here is to up the usage count and
  55.  * set the right fops.
  56.  */
  57. int simple_open (struct inode *inode, struct file *filp)
  58. {
  59.     unsigned int dev = MINOR(inode->i_rdev);
  60.     if (dev >= MAX_SIMPLE_DEV) 
  61.         return -ENODEV;
  62.     filp->f_op = simple_fops[dev];
  63.     MOD_INC_USE_COUNT;
  64.     return 0;
  65. }
  66. /*
  67.  * Closing is even simpler.
  68.  */
  69. int simple_release(struct inode *inode, struct file *filp)
  70. {
  71.     MOD_DEC_USE_COUNT;
  72.     return 0;
  73. }
  74. /*
  75.  * Common VMA ops.
  76.  */
  77. void simple_vma_open(struct vm_area_struct *vma)
  78. { MOD_INC_USE_COUNT; }
  79. void simple_vma_close(struct vm_area_struct *vma)
  80. { MOD_DEC_USE_COUNT; }
  81. /*
  82.  * The remap_page_range version of mmap.
  83.  */
  84. static struct vm_operations_struct simple_remap_vm_ops = {
  85.     open:  simple_vma_open,
  86.     close: simple_vma_close,
  87. };
  88. int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma)
  89. {
  90.     unsigned long offset = VMA_OFFSET(vma);
  91.     if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))
  92.         vma->vm_flags |= VM_IO;
  93.     vma->vm_flags |= VM_RESERVED;
  94.     if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
  95.                 vma->vm_page_prot))
  96.         return -EAGAIN;
  97.     vma->vm_ops = &simple_remap_vm_ops;
  98.     simple_vma_open(vma);
  99.     return 0;
  100. }
  101. /*
  102.  * The nopage version.
  103.  */
  104. struct page *simple_vma_nopage(struct vm_area_struct *vma,
  105.                 unsigned long address, int write_access)
  106. {
  107.     struct page *pageptr;
  108.     unsigned long physaddr = address - vma->vm_start + VMA_OFFSET(vma);
  109.     pageptr = virt_to_page(__va(physaddr));
  110.     get_page(pageptr);
  111.     return pageptr;
  112. }
  113. #ifdef LINUX_22 /* wrapper for 2.2, which had a different nopage retval */
  114. unsigned long simple_vma_nopage_22(struct vm_area_struct * area,
  115.                 unsigned long address, int write_access)
  116. {
  117.     return (unsigned long) simple_vma_nopage(area, address, write_access);
  118. }
  119. #define simple_vma_nopage simple_vma_nopage_22
  120. #endif  /* LINUX_22 */
  121.         
  122. static struct vm_operations_struct simple_nopage_vm_ops = {
  123.     open:    simple_vma_open,
  124.     close:   simple_vma_close,
  125.     nopage:  simple_vma_nopage,
  126. };
  127. int simple_nopage_mmap(struct file *filp, struct vm_area_struct *vma)
  128. {
  129.     unsigned long offset = VMA_OFFSET(vma);
  130.     if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))
  131.         vma->vm_flags |= VM_IO;
  132.     vma->vm_flags |= VM_RESERVED;
  133.     vma->vm_ops = &simple_nopage_vm_ops;
  134.     simple_vma_open(vma);
  135.     return 0;
  136. }
  137. /*
  138.  * Module housekeeping.
  139.  */
  140. static int simple_init(void)
  141. {
  142.     int result;
  143.     SET_MODULE_OWNER(&simple_remap_ops);
  144.     SET_MODULE_OWNER(&simple_nopage_ops);
  145.     result = register_chrdev(simple_major, "simple", &simple_remap_ops);
  146.     if (result < 0)
  147.     {
  148.         printk(KERN_WARNING "simple: unable to get major %dn", simple_major);
  149.         return result;
  150.     }
  151.     if (simple_major == 0)
  152.         simple_major = result;
  153.     return 0;
  154. }
  155. static void simple_cleanup(void)
  156. {
  157.     unregister_chrdev(simple_major, "simple");
  158. }
  159. module_init(simple_init);
  160. module_exit(simple_cleanup);