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

嵌入式Linux

开发平台:

C/C++

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