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.
|