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 scullp 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 "scullp.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 scullp_vma_open(struct vm_area_struct *vma)
 34 {
 35         struct scullp_dev *dev = vma->vm_private_data;
 36 
 37         dev->vmas++;
 38 }
 39 
 40 void scullp_vma_close(struct vm_area_struct *vma)
 41 {
 42         struct scullp_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 scullp 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 *scullp_vma_nopage(struct vm_area_struct *vma,
 61                                 unsigned long address, int *type)
 62 {
 63         unsigned long offset;
 64         struct scullp_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 scullp 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         page = virt_to_page(pageptr);
 85 
 86         /* got it, now increment the count */
 87         get_page(page);
 88         if (type)
 89                 *type = VM_FAULT_MINOR;
 90   out:
 91         up(&dev->sem);
 92         return page;
 93 }
 94 
 95 
 96 
 97 struct vm_operations_struct scullp_vm_ops = {
 98         .open =     scullp_vma_open,
 99         .close =    scullp_vma_close,
100         .nopage =   scullp_vma_nopage,
101 };
102 
103 
104 int scullp_mmap(struct file *filp, struct vm_area_struct *vma)
105 {
106         struct inode *inode = filp->f_dentry->d_inode;
107 
108         /* refuse to map if order is not 0 */
109         if (scullp_devices[iminor(inode)].order)
110                 return -ENODEV;
111 
112         /* don't do anything here: "nopage" will set up page table entries */
113         vma->vm_ops = &scullp_vm_ops;
114         vma->vm_flags |= VM_RESERVED;
115         vma->vm_private_data = filp->private_data;
116         scullp_vma_open(vma);
117         return 0;
118 }
119 
120 
  This page was automatically generated by the LXR engine.