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  * pipe.c -- fifo driver for scull
  3  *
  4  * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
  5  * Copyright (C) 2001 O'Reilly & Associates
  6  * Modified for warning-free compilation under Linux 2.6.31 by baker@cs.fsu.edu.
  7  *
  8  * The source code in this file can be freely used, adapted,
  9  * and redistributed in source or binary form, so long as an
 10  * acknowledgment appears in derived source files.  The citation
 11  * should list that the code comes from the book "Linux Device
 12  * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 13  * by O'Reilly & Associates.   No warranty is attached;
 14  * we cannot take responsibility for errors or fitness for use.
 15  *
 16  */
 17  
 18 #include <linux/module.h>
 19 #include <linux/moduleparam.h>
 20 #include <linux/sched.h>        /* TASK_INTERRUPTIBLE */ //tpb
 21 /* Dependence on sched.h indicates the code probably is obsolescent.
 22    Should not be directly manipulating task state. */
 23 #include <linux/kernel.h>       /* printk(), min() */
 24 #include <linux/slab.h>         /* kmalloc() */
 25 #include <linux/fs.h>           /* everything... */
 26 #include <linux/proc_fs.h>
 27 #include <linux/errno.h>        /* error codes */
 28 #include <linux/types.h>        /* size_t */
 29 #include <linux/fcntl.h>
 30 #include <linux/poll.h>
 31 #include <linux/cdev.h>
 32 #include <asm/uaccess.h>
 33 
 34 #include "scull.h"              /* local definitions */
 35 
 36 struct scull_pipe {
 37         wait_queue_head_t inq, outq;       /* read and write queues */
 38         char *buffer, *end;                /* begin of buf, end of buf */
 39         int buffersize;                    /* used in pointer arithmetic */
 40         char *rp, *wp;                     /* where to read, where to write */
 41         int nreaders, nwriters;            /* number of openings for r/w */
 42         struct fasync_struct *async_queue; /* asynchronous readers */
 43         struct semaphore sem;              /* mutual exclusion semaphore */
 44         struct cdev cdev;                  /* Char device structure */
 45 };
 46 
 47 /* parameters */
 48 static int scull_p_nr_devs = SCULL_P_NR_DEVS;   /* number of pipe devices */
 49 int scull_p_buffer =  SCULL_P_BUFFER;   /* buffer size */
 50 dev_t scull_p_devno;                    /* Our first device number */
 51 
 52 module_param(scull_p_nr_devs, int, 0);  /* FIXME check perms */
 53 module_param(scull_p_buffer, int, 0);
 54 
 55 static struct scull_pipe *scull_p_devices;
 56 
 57 static int scull_p_fasync(int fd, struct file *filp, int mode);
 58 static int spacefree(struct scull_pipe *dev);
 59 /*
 60  * Open and close
 61  */
 62 
 63 
 64 static int scull_p_open(struct inode *inode, struct file *filp)
 65 {
 66         struct scull_pipe *dev;
 67 
 68         dev = container_of(inode->i_cdev, struct scull_pipe, cdev);
 69         filp->private_data = dev;
 70 
 71         if (down_interruptible(&dev->sem))
 72                 return -ERESTARTSYS;
 73         if (!dev->buffer) {
 74                 /* allocate the buffer */
 75                 dev->buffer = kmalloc(scull_p_buffer, GFP_KERNEL);
 76                 if (!dev->buffer) {
 77                         up(&dev->sem);
 78                         return -ENOMEM;
 79                 }
 80         }
 81         dev->buffersize = scull_p_buffer;
 82         dev->end = dev->buffer + dev->buffersize;
 83         dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */
 84 
 85         /* use f_mode,not  f_flags: it's cleaner (fs/open.c tells why) */
 86         if (filp->f_mode & FMODE_READ)
 87                 dev->nreaders++;
 88         if (filp->f_mode & FMODE_WRITE)
 89                 dev->nwriters++;
 90         up(&dev->sem);
 91 
 92         return nonseekable_open(inode, filp);
 93 }
 94 
 95 
 96 
 97 static int scull_p_release(struct inode *inode, struct file *filp)
 98 {
 99         struct scull_pipe *dev = filp->private_data;
100 
101         /* remove this filp from the asynchronously notified filp's */
102         scull_p_fasync(-1, filp, 0);
103         down(&dev->sem);
104         if (filp->f_mode & FMODE_READ)
105                 dev->nreaders--;
106         if (filp->f_mode & FMODE_WRITE)
107                 dev->nwriters--;
108         if (dev->nreaders + dev->nwriters == 0) {
109                 kfree(dev->buffer);
110                 dev->buffer = NULL; /* the other fields are not checked on open */
111         }
112         up(&dev->sem);
113         return 0;
114 }
115 
116 
117 /*
118  * Data management: read and write
119  */
120 
121 static ssize_t scull_p_read (struct file *filp, char __user *buf, size_t count,
122                 loff_t *f_pos)
123 {
124         struct scull_pipe *dev = filp->private_data;
125 
126         if (down_interruptible(&dev->sem))
127                 return -ERESTARTSYS;
128 
129         while (dev->rp == dev->wp) { /* nothing to read */
130                 up(&dev->sem); /* release the lock */
131                 if (filp->f_flags & O_NONBLOCK)
132                         return -EAGAIN;
133                 PDEBUG("\"%s\" reading: going to sleep\n", current->comm);
134                 if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))
135                         return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
136                 /* otherwise loop, but first reacquire the lock */
137                 if (down_interruptible(&dev->sem))
138                         return -ERESTARTSYS;
139         }
140         /* ok, data is there, return something */
141         if (dev->wp > dev->rp)
142                 count = min(count, (size_t)(dev->wp - dev->rp));
143         else /* the write pointer has wrapped, return data up to dev->end */
144                 count = min(count, (size_t)(dev->end - dev->rp));
145         if (copy_to_user(buf, dev->rp, count)) {
146                 up (&dev->sem);
147                 return -EFAULT;
148         }
149         dev->rp += count;
150         if (dev->rp == dev->end)
151                 dev->rp = dev->buffer; /* wrapped */
152         up (&dev->sem);
153 
154         /* finally, awake any writers and return */
155         wake_up_interruptible(&dev->outq);
156         PDEBUG("\"%s\" did read %li bytes\n",current->comm, (long)count);
157         return count;
158 }
159 
160 /* Wait for space for writing; caller must hold device semaphore.  On
161  * error the semaphore will be released before returning. */
162 static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
163 {
164         while (spacefree(dev) == 0) { /* full */
165                 DEFINE_WAIT(wait);
166                 
167                 up(&dev->sem);
168                 if (filp->f_flags & O_NONBLOCK)
169                         return -EAGAIN;
170                 PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
171                 prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
172                 if (spacefree(dev) == 0)
173                         schedule();
174                 finish_wait(&dev->outq, &wait);
175                 if (signal_pending(current))
176                         return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
177                 if (down_interruptible(&dev->sem))
178                         return -ERESTARTSYS;
179         }
180         return 0;
181 }       
182 
183 /* How much space is free? */
184 static int spacefree(struct scull_pipe *dev)
185 {
186         if (dev->rp == dev->wp)
187                 return dev->buffersize - 1;
188         return ((dev->rp + dev->buffersize - dev->wp) % dev->buffersize) - 1;
189 }
190 
191 static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count,
192                 loff_t *f_pos)
193 {
194         struct scull_pipe *dev = filp->private_data;
195         int result;
196 
197         if (down_interruptible(&dev->sem))
198                 return -ERESTARTSYS;
199 
200         /* Make sure there's space to write */
201         result = scull_getwritespace(dev, filp);
202         if (result)
203                 return result; /* scull_getwritespace called up(&dev->sem) */
204 
205         /* ok, space is there, accept something */
206         count = min(count, (size_t)spacefree(dev));
207         if (dev->wp >= dev->rp)
208                 count = min(count, (size_t)(dev->end - dev->wp)); /* to end-of-buf */
209         else /* the write pointer has wrapped, fill up to rp-1 */
210                 count = min(count, (size_t)(dev->rp - dev->wp - 1));
211         PDEBUG("Going to accept %li bytes to %p from %p\n", (long)count, dev->wp, buf);
212         if (copy_from_user(dev->wp, buf, count)) {
213                 up (&dev->sem);
214                 return -EFAULT;
215         }
216         dev->wp += count;
217         if (dev->wp == dev->end)
218                 dev->wp = dev->buffer; /* wrapped */
219         up(&dev->sem);
220 
221         /* finally, awake any reader */
222         wake_up_interruptible(&dev->inq);  /* blocked in read() and select() */
223 
224         /* and signal asynchronous readers, explained late in chapter 5 */
225         if (dev->async_queue)
226                 kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
227         PDEBUG("\"%s\" did write %li bytes\n",current->comm, (long)count);
228         return count;
229 }
230 
231 static unsigned int scull_p_poll(struct file *filp, poll_table *wait)
232 {
233         struct scull_pipe *dev = filp->private_data;
234         unsigned int mask = 0;
235 
236         /*
237          * The buffer is circular; it is considered full
238          * if "wp" is right behind "rp" and empty if the
239          * two are equal.
240          */
241         down(&dev->sem);
242         poll_wait(filp, &dev->inq,  wait);
243         poll_wait(filp, &dev->outq, wait);
244         if (dev->rp != dev->wp)
245                 mask |= POLLIN | POLLRDNORM;    /* readable */
246         if (spacefree(dev))
247                 mask |= POLLOUT | POLLWRNORM;   /* writable */
248         up(&dev->sem);
249         return mask;
250 }
251 
252 
253 
254 
255 
256 static int scull_p_fasync(int fd, struct file *filp, int mode)
257 {
258         struct scull_pipe *dev = filp->private_data;
259 
260         return fasync_helper(fd, filp, mode, &dev->async_queue);
261 }
262 
263 
264 
265 /* FIXME this should use seq_file */
266 #ifdef SCULL_DEBUG
267 static void scullp_proc_offset(char *buf, char **start, off_t *offset, int *len)
268 {
269         if (*offset == 0)
270                 return;
271         if (*offset >= *len) {  /* Not there yet */
272                 *offset -= *len;
273                 *len = 0;
274         }
275         else {                  /* We're into the interesting stuff now */
276                 *start = buf + *offset;
277                 *offset = 0;
278         }
279 }
280 
281 
282 static int scull_read_p_mem(char *buf, char **start, off_t offset, int count,
283                 int *eof, void *data)
284 {
285         int i, len;
286         struct scull_pipe *p;
287 
288 #define LIMIT (PAGE_SIZE-200)   /* don't print any more after this size */
289         *start = buf;
290         len = sprintf(buf, "Default buffersize is %i\n", scull_p_buffer);
291         for(i = 0; i<scull_p_nr_devs && len <= LIMIT; i++) {
292                 p = &scull_p_devices[i];
293                 if (down_interruptible(&p->sem))
294                         return -ERESTARTSYS;
295                 len += sprintf(buf+len, "\nDevice %i: %p\n", i, p);
296 /*              len += sprintf(buf+len, "   Queues: %p %p\n", p->inq, p->outq);*/
297                 len += sprintf(buf+len, "   Buffer: %p to %p (%i bytes)\n", p->buffer, p->end, p->buffersize);
298                 len += sprintf(buf+len, "   rp %p   wp %p\n", p->rp, p->wp);
299                 len += sprintf(buf+len, "   readers %i   writers %i\n", p->nreaders, p->nwriters);
300                 up(&p->sem);
301                 scullp_proc_offset(buf, start, &offset, &len);
302         }
303         *eof = (len <= LIMIT);
304         return len;
305 }
306 
307 
308 #endif
309 
310 
311 
312 /*
313  * The file operations for the pipe device
314  * (some are overlayed with bare scull)
315  */
316 struct file_operations scull_pipe_fops = {
317         .owner =        THIS_MODULE,
318         .llseek =       no_llseek,
319         .read =         scull_p_read,
320         .write =        scull_p_write,
321         .poll =         scull_p_poll,
322         .ioctl =        scull_ioctl,
323         .open =         scull_p_open,
324         .release =      scull_p_release,
325         .fasync =       scull_p_fasync,
326 };
327 
328 
329 /*
330  * Set up a cdev entry.
331  */
332 static void scull_p_setup_cdev(struct scull_pipe *dev, int index)
333 {
334         int err, devno = scull_p_devno + index;
335     
336         cdev_init(&dev->cdev, &scull_pipe_fops);
337         dev->cdev.owner = THIS_MODULE;
338         err = cdev_add (&dev->cdev, devno, 1);
339         /* Fail gracefully if need be */
340         if (err)
341                 printk(KERN_NOTICE "Error %d adding scullpipe%d", err, index);
342 }
343 
344  
345 
346 /*
347  * Initialize the pipe devs; return how many we did.
348  */
349 int scull_p_init(dev_t firstdev)
350 {
351         int i, result;
352 
353         result = register_chrdev_region(firstdev, scull_p_nr_devs, "scullp");
354         if (result < 0) {
355                 printk(KERN_NOTICE "Unable to get scullp region, error %d\n", result);
356                 return 0;
357         }
358         scull_p_devno = firstdev;
359         scull_p_devices = kmalloc(scull_p_nr_devs * sizeof(struct scull_pipe), GFP_KERNEL);
360         if (scull_p_devices == NULL) {
361                 unregister_chrdev_region(firstdev, scull_p_nr_devs);
362                 return 0;
363         }
364         memset(scull_p_devices, 0, scull_p_nr_devs * sizeof(struct scull_pipe));
365         for (i = 0; i < scull_p_nr_devs; i++) {
366                 init_waitqueue_head(&(scull_p_devices[i].inq));
367                 init_waitqueue_head(&(scull_p_devices[i].outq));
368                 init_MUTEX(&scull_p_devices[i].sem);
369                 scull_p_setup_cdev(scull_p_devices + i, i);
370         }
371 #ifdef SCULL_DEBUG
372         create_proc_read_entry("scullpipe", 0, NULL, scull_read_p_mem, NULL);
373 #endif
374         return scull_p_nr_devs;
375 }
376 
377 /*
378  * This is called by cleanup_module or on failure.
379  * It is required to never fail, even if nothing was initialized first
380  */
381 void scull_p_cleanup(void)
382 {
383         int i;
384 
385 #ifdef SCULL_DEBUG
386         remove_proc_entry("scullpipe", NULL);
387 #endif
388 
389         if (!scull_p_devices)
390                 return; /* nothing else to release */
391 
392         for (i = 0; i < scull_p_nr_devs; i++) {
393                 cdev_del(&scull_p_devices[i].cdev);
394                 kfree(scull_p_devices[i].buffer);
395         }
396         kfree(scull_p_devices);
397         unregister_chrdev_region(scull_p_devno, scull_p_nr_devs);
398         scull_p_devices = NULL; /* pedantic */
399 }
400 
  This page was automatically generated by the LXR engine.