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 /*  -*- C -*-
  2  * mmap.c -- memory mapping for the scullv char module
  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: _mmap.c.in,v 1.13 2004/10/18 18:07:36 corbet Exp $
 16  */
 17 
 18 /* #include <linux/config.h> */
 19 #include <linux/module.h>
 20 
 21 #include <linux/mm.h>           /* everything */
 22 #include <linux/errno.h>        /* error codes */
 23 #include <linux/fs.h>
 24 #include <asm/pgtable.h>
 25 
 26 #include "scullv.h"             /* local definitions */
 27 
 28 
 29 /*
 30  * open and close: just keep track of how many times the device is
 31  * mapped, to avoid releasing it.
 32  */
 33 
 34 void scullv_vma_open(struct vm_area_struct *vma)
 35 {
 36         struct scullv_dev *dev = vma->vm_private_data;
 37 
 38         dev->vmas++;
 39 }
 40 
 41 void scullv_vma_close(struct vm_area_struct *vma)
 42 {
 43         struct scullv_dev *dev = vma->vm_private_data;
 44 
 45         dev->vmas--;
 46 }
 47 
 48 /*
 49  * The nopage method: the core of the file. It retrieves the
 50  * page required from the scullv device and returns it to the
 51  * user. The count for the page must be incremented, because
 52  * it is automatically decremented at page unmap.
 53  *
 54  * For this reason, "order" must be zero. Otherwise, only the first
 55  * page has its count incremented, and the allocating module must
 56  * release it as a whole block. Therefore, it isn't possible to map
 57  * pages from a multipage block: when they are unmapped, their count
 58  * is individually decreased, and would drop to 0.
 59  */
 60 
 61 struct page *scullv_vma_nopage(struct vm_area_struct *vma,
 62                                 unsigned long address, int *type)
 63 {
 64         unsigned long offset;
 65         struct scullv_dev *ptr, *dev = vma->vm_private_data;
 66         struct page *page = NOPAGE_SIGBUS;
 67         void *pageptr = NULL; /* default to "missing" */
 68 
 69         down(&dev->sem);
 70         offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
 71         if (offset >= dev->size) goto out; /* out of range */
 72 
 73         /*
 74          * Now retrieve the scullv device from the list,then the page.
 75          * If the device has holes, the process receives a SIGBUS when
 76          * accessing the hole.
 77          */
 78         offset >>= PAGE_SHIFT; /* offset is a number of pages */
 79         for (ptr = dev; ptr && offset >= dev->qset;) {
 80                 ptr = ptr->next;
 81                 offset -= dev->qset;
 82         }
 83         if (ptr && ptr->data) pageptr = ptr->data[offset];
 84         if (!pageptr) goto out; /* hole or end-of-file */
 85 
 86         /*
 87          * After scullv lookup, "page" is now the address of the page
 88          * needed by the current process. Since it's a vmalloc address,
 89          * turn it into a struct page.
 90          */
 91         page = vmalloc_to_page(pageptr);
 92 
 93         /* got it, now increment the count */
 94         get_page(page);
 95         if (type)
 96                 *type = VM_FAULT_MINOR;
 97   out:
 98         up(&dev->sem);
 99         return page;
100 }
101 
102 
103 
104 struct vm_operations_struct scullv_vm_ops = {
105         .open =     scullv_vma_open,
106         .close =    scullv_vma_close,
107         .nopage =   scullv_vma_nopage,
108 };
109 
110 
111 int scullv_mmap(struct file *filp, struct vm_area_struct *vma)
112 {
113 
114         /* don't do anything here: "nopage" will set up page table entries */
115         vma->vm_ops = &scullv_vm_ops;
116         vma->vm_flags |= VM_RESERVED;
117         vma->vm_private_data = filp->private_data;
118         scullv_vma_open(vma);
119         return 0;
120 }
121 
122 
  This page was automatically generated by the LXR engine.