Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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.12 2005/01/31 16:15:31 rubini Exp $
 16  */
 17 
 18 #include <linux/module.h>
 19 #include <linux/moduleparam.h>
 20 #include <linux/init.h>
 21 
 22 #include <linux/kernel.h>   /* printk() */
 23 #include <linux/slab.h>   /* kmalloc() */
 24 #include <linux/fs.h>       /* everything... */
 25 #include <linux/errno.h>    /* error codes */
 26 #include <linux/types.h>    /* size_t */
 27 #include <linux/mm.h>
 28 #include <linux/kdev_t.h>
 29 #include <asm/page.h>
 30 #include <linux/cdev.h>
 31 
 32 #include <linux/device.h>
 33 
 34 static int simple_major = 0;
 35 module_param(simple_major, int, 0);
 36 MODULE_AUTHOR("Jonathan Corbet");
 37 MODULE_LICENSE("Dual BSD/GPL");
 38 
 39 /*
 40  * Open the device; in fact, there's nothing to do here.
 41  */
 42 static int simple_open (struct inode *inode, struct file *filp)
 43 {
 44         return 0;
 45 }
 46 
 47 
 48 /*
 49  * Closing is just as simpler.
 50  */
 51 static int simple_release(struct inode *inode, struct file *filp)
 52 {
 53         return 0;
 54 }
 55 
 56 
 57 
 58 /*
 59  * Common VMA ops.
 60  */
 61 
 62 void simple_vma_open(struct vm_area_struct *vma)
 63 {
 64         printk(KERN_NOTICE "Simple VMA open, virt %lx, phys %lx\n",
 65                         vma->vm_start, vma->vm_pgoff << PAGE_SHIFT);
 66 }
 67 
 68 void simple_vma_close(struct vm_area_struct *vma)
 69 {
 70         printk(KERN_NOTICE "Simple VMA close.\n");
 71 }
 72 
 73 
 74 /*
 75  * The remap_pfn_range version of mmap.  This one is heavily borrowed
 76  * from drivers/char/mem.c.
 77  */
 78 
 79 static struct vm_operations_struct simple_remap_vm_ops = {
 80         .open =  simple_vma_open,
 81         .close = simple_vma_close,
 82 };
 83 
 84 static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma)
 85 {
 86         if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
 87                             vma->vm_end - vma->vm_start,
 88                             vma->vm_page_prot))
 89                 return -EAGAIN;
 90 
 91         vma->vm_ops = &simple_remap_vm_ops;
 92         simple_vma_open(vma);
 93         return 0;
 94 }
 95 
 96 
 97 
 98 /*
 99  * The nopage version.
100  */
101 struct page *simple_vma_nopage(struct vm_area_struct *vma,
102                 unsigned long address, int *type)
103 {
104         struct page *pageptr;
105         unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
106         unsigned long physaddr = address - vma->vm_start + offset;
107         unsigned long pageframe = physaddr >> PAGE_SHIFT;
108 
109 // Eventually remove these printks
110         printk (KERN_NOTICE "---- Nopage, off %lx phys %lx\n", offset, physaddr);
111         printk (KERN_NOTICE "VA is %p\n", __va (physaddr));
112         printk (KERN_NOTICE "Page at %p\n", virt_to_page (__va (physaddr)));
113         if (!pfn_valid(pageframe))
114                 return NOPAGE_SIGBUS;
115         pageptr = pfn_to_page(pageframe);
116         printk (KERN_NOTICE "page->index = %ld mapping %p\n", pageptr->index, pageptr->mapping);
117         printk (KERN_NOTICE "Page frame %ld\n", pageframe);
118         get_page(pageptr);
119         if (type)
120                 *type = VM_FAULT_MINOR;
121         return pageptr;
122 }
123 
124 static struct vm_operations_struct simple_nopage_vm_ops = {
125         .open =   simple_vma_open,
126         .close =  simple_vma_close,
127         .nopage = simple_vma_nopage,
128 };
129 
130 static int simple_nopage_mmap(struct file *filp, struct vm_area_struct *vma)
131 {
132         unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
133 
134         if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))
135                 vma->vm_flags |= VM_IO;
136         vma->vm_flags |= VM_RESERVED;
137 
138         vma->vm_ops = &simple_nopage_vm_ops;
139         simple_vma_open(vma);
140         return 0;
141 }
142 
143 
144 /*
145  * Set up the cdev structure for a device.
146  */
147 static void simple_setup_cdev(struct cdev *dev, int minor,
148                 struct file_operations *fops)
149 {
150         int err, devno = MKDEV(simple_major, minor);
151     
152         cdev_init(dev, fops);
153         dev->owner = THIS_MODULE;
154         dev->ops = fops;
155         err = cdev_add (dev, devno, 1);
156         /* Fail gracefully if need be */
157         if (err)
158                 printk (KERN_NOTICE "Error %d adding simple%d", err, minor);
159 }
160 
161 
162 /*
163  * Our various sub-devices.
164  */
165 /* Device 0 uses remap_pfn_range */
166 static struct file_operations simple_remap_ops = {
167         .owner   = THIS_MODULE,
168         .open    = simple_open,
169         .release = simple_release,
170         .mmap    = simple_remap_mmap,
171 };
172 
173 /* Device 1 uses nopage */
174 static struct file_operations simple_nopage_ops = {
175         .owner   = THIS_MODULE,
176         .open    = simple_open,
177         .release = simple_release,
178         .mmap    = simple_nopage_mmap,
179 };
180 
181 #define MAX_SIMPLE_DEV 2
182 
183 #if 0
184 static struct file_operations *simple_fops[MAX_SIMPLE_DEV] = {
185         &simple_remap_ops,
186         &simple_nopage_ops,
187 };
188 #endif
189 
190 /*
191  * We export two simple devices.  There's no need for us to maintain any
192  * special housekeeping info, so we just deal with raw cdevs.
193  */
194 static struct cdev SimpleDevs[MAX_SIMPLE_DEV];
195 
196 /*
197  * Module housekeeping.
198  */
199 static int simple_init(void)
200 {
201         int result;
202         dev_t dev = MKDEV(simple_major, 0);
203 
204         /* Figure out our device number. */
205         if (simple_major)
206                 result = register_chrdev_region(dev, 2, "simple");
207         else {
208                 result = alloc_chrdev_region(&dev, 0, 2, "simple");
209                 simple_major = MAJOR(dev);
210         }
211         if (result < 0) {
212                 printk(KERN_WARNING "simple: unable to get major %d\n", simple_major);
213                 return result;
214         }
215         if (simple_major == 0)
216                 simple_major = result;
217 
218         /* Now set up two cdevs. */
219         simple_setup_cdev(SimpleDevs, 0, &simple_remap_ops);
220         simple_setup_cdev(SimpleDevs + 1, 1, &simple_nopage_ops);
221         return 0;
222 }
223 
224 
225 static void simple_cleanup(void)
226 {
227         cdev_del(SimpleDevs);
228         cdev_del(SimpleDevs + 1);
229         unregister_chrdev_region(MKDEV(simple_major, 0), 2);
230 }
231 
232 
233 module_init(simple_init);
234 module_exit(simple_cleanup);
235 
  This page was automatically generated by the LXR engine.