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