pipe.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * pipe.c -- fifo driver for scull
  3.  *
  4.  * Tested with 1.2 on the x86
  5.  * Tested with 2.0 on the x86, Sparc
  6.  */
  7.  
  8. #ifndef __KERNEL__
  9. #  define __KERNEL__
  10. #endif
  11. #ifndef MODULE
  12. #  define MODULE
  13. #endif
  14. #define __NO_VERSION__
  15. #include <linux/module.h> /* get MOD_DEC_USE_COUNT, not the version string */
  16. #include <linux/version.h> /* need it for conditionals in scull.h */
  17. #include <linux/kernel.h> /* printk() */
  18. #include <linux/malloc.h> /* kmalloc() */
  19. #include <linux/fs.h>     /* everything... */
  20. #include <linux/proc_fs.h>
  21. #include <linux/errno.h>  /* error codes */
  22. #include <linux/types.h>  /* size_t */
  23. #include <linux/fcntl.h>
  24. #include <asm/segment.h>  /* memcpy to/from fs */
  25. #include "scull.h"        /* local definitions */
  26. typedef struct Scull_Pipe {
  27.     struct wait_queue *inq, *outq;  /* read and write queues */
  28.     char *buffer, *end;             /* begin of buf, end of buf */
  29.     int buffersize;                 /* used in pointer arithmetic */
  30.     char *rp, *wp;                  /* where to read, where to write */
  31.     int nreaders, nwriters;         /* number of openings for r/w */
  32.     struct fasync_struct *async_queue; /* asynchronous readers */
  33. } Scull_Pipe;
  34. /*
  35.  * I don't use static symbols here, because register_symtab is called
  36.  */
  37. int scull_p_nr_devs =    SCULL_P_NR_DEVS;  /* number of pipe devices */
  38. int scull_p_buffer =  SCULL_P_BUFFER; /* buffer size */
  39. Scull_Pipe *scull_p_devices;
  40. /*
  41.  * Open and close
  42.  */
  43. int scull_p_open (struct inode *inode, struct file *filp)
  44. {
  45.     Scull_Pipe *dev;
  46.     int num = NUM(inode->i_rdev);
  47.     if (num >= scull_p_nr_devs) return -ENODEV;
  48.     dev = &scull_p_devices[num];
  49.     if (!dev->buffer) { /* allocate the buffer */
  50.         dev->buffer = kmalloc(scull_p_buffer, GFP_KERNEL);
  51.         if (!dev->buffer)
  52.             return -ENOMEM;
  53.     }
  54.     dev->buffersize = scull_p_buffer;
  55.     dev->end = dev->buffer + dev->buffersize;
  56.     dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */
  57.     /* use f_mode,not  f_flags: it's cleaner (fs/open.c tells why) */
  58.     if (filp->f_mode & FMODE_READ)
  59.         dev->nreaders++;
  60.     if (filp->f_mode & FMODE_WRITE)
  61.         dev->nwriters++;
  62.     filp->private_data = dev;
  63.     MOD_INC_USE_COUNT;
  64.     return 0;
  65. }
  66. void scull_p_release (struct inode *inode, struct file *filp)
  67. {
  68.     Scull_Pipe *dev = filp->private_data;
  69.     int scull_p_fasync (struct inode *inode, struct file *filp, int mode);
  70.     /* remove this filp from the asynchronously notified filp's */
  71.     scull_p_fasync(inode, filp, 0);
  72.     if (filp->f_mode & FMODE_READ)
  73.         dev->nreaders--;
  74.     if (filp->f_mode & FMODE_WRITE)
  75.         dev->nwriters--;
  76.     if (dev->nreaders + dev->nwriters == 0) {
  77.         kfree(dev->buffer);
  78.         dev->buffer = NULL; /* the other fields are not checked on open */
  79.     }
  80.     MOD_DEC_USE_COUNT;
  81. }
  82. /*
  83.  * Data management: read and write
  84.  */
  85. read_write_t scull_p_read (struct inode *inode, struct file *filp,
  86.                 char *buf, count_t count)
  87. {
  88.     Scull_Pipe *dev = filp->private_data;
  89.     while (dev->rp == dev->wp) { /* nothing to read */
  90.         if (filp->f_flags & O_NONBLOCK)
  91.             return -EAGAIN;
  92.         PDEBUG(""%s" reading: going to sleepn",current->comm);
  93.         interruptible_sleep_on(&dev->inq);
  94.         if (current->signal & ~current->blocked) /* a signal arrived */
  95.           return -ERESTARTSYS; /* tell the fs layer to handle it */
  96.         /* otherwise loop */
  97.     }
  98.     /* ok, data is there, return something */
  99.     if (dev->wp > dev->rp)
  100.         count = min(count, dev->wp - dev->rp);
  101.     else /* the write pointer has wrapped, return data up to dev->end */
  102.         count = min(count, dev->end - dev->rp);
  103.     memcpy_tofs(buf, dev->rp, count);
  104.     dev->rp += count;
  105.     if (dev->rp == dev->end)
  106.         dev->rp = dev->buffer; /* wrapped */
  107.     /* finally, awake any writers and return */
  108.     wake_up_interruptible(&dev->outq);
  109.     PDEBUG(""%s" did read %li bytesn",current->comm, (long)count);
  110.     return count;
  111. }
  112. read_write_t scull_p_write (struct inode *inode, struct file *filp,
  113.                 const char *buf, count_t count)
  114. {
  115.     Scull_Pipe *dev = filp->private_data;
  116.     /* left is the free space in the buffer, but it must be positive */
  117.     int left = (dev->rp + dev->buffersize - dev->wp) % dev->buffersize;
  118.     PDEBUG("write: left is %in",left);
  119.     while (left==1) { /* empty */
  120.         if (filp->f_flags & O_NONBLOCK)
  121.             return -EAGAIN;
  122.         PDEBUG(""%s" writing: going to sleepn",current->comm);
  123.         interruptible_sleep_on(&dev->outq);
  124.         if (current->signal & ~current->blocked) /* a signal arrived */
  125.           return -ERESTARTSYS; /* tell the fs layer to handle it */
  126.         /* otherwise loop, but recalculate free space */
  127.         left = (dev->rp + dev->buffersize - dev->wp) % dev->buffersize;
  128.     }
  129.     /* ok, space is there, accept something */
  130.     if (dev->wp >= dev->rp) {
  131.         count = min(count, dev->end - dev->wp); /* up to end-of-buffer */
  132.         if (count == left) /* leave a hole, even if at e-o-b */
  133.             count--;
  134.     }
  135.     else /* the write pointer has wrapped, fill up to rp-1 */
  136.         count = min(count, dev->rp - dev->wp - 1);
  137.     PDEBUG("Going to accept %li bytes to %p from %pn",
  138.            (long)count, dev->wp, buf);
  139.     memcpy_fromfs(dev->wp, buf, count);
  140.     dev->wp += count;
  141.     if (dev->wp == dev->end)
  142.         dev ->wp = dev->buffer; /* wrapped */
  143.     /* finally, awake any reader */
  144.     wake_up_interruptible(&dev->inq);  /* blocked in read() and select() */
  145.     if (dev->async_queue)
  146.         kill_fasync (dev->async_queue, SIGIO); /* asynchronous readers */
  147.     PDEBUG(""%s" did write %li bytesn",current->comm, (long)count);
  148.     return count;
  149. }
  150. int scull_p_select (struct inode *inode, struct file *filp,
  151.                   int mode, select_table *table)
  152. {
  153.     Scull_Pipe *dev = filp->private_data;
  154.     if (mode == SEL_IN) {
  155.         if (dev->rp != dev->wp) return 1; /* readable */
  156.         PDEBUG("Waiting to readn");
  157.         select_wait(&dev->inq, table); /* wait for data */
  158.         return 0;
  159.     }
  160.     if (mode == SEL_OUT) {
  161.         /*
  162.          * the buffer is full if "wp" is right behind "rp",
  163.          * and the buffer is circular. "left" can't drop
  164.          * to 0, as this would be taken as empty buffer
  165.          */
  166.         int left = (dev->rp + dev->buffersize - dev->wp) % dev->buffersize;
  167.         if (left>1) return 1; /* writable */
  168.         PDEBUG("Waiting to writen");
  169.         select_wait(&dev->outq, table); /* wait for free space */
  170.         return 0;
  171.     }
  172.     return 0; /* never exception-able */
  173. }
  174. #if LINUX_VERSION_CODE > VERSION_CODE(1,3,50)
  175. int scull_p_fasync (struct inode *inode, struct file *filp, int mode)
  176. {
  177.     Scull_Pipe *dev = filp->private_data;
  178.     return fasync_helper(inode, filp, mode, &dev->async_queue);
  179. }
  180. #else /* not implemented */
  181. int scull_p_fasync (struct inode *inode, struct file *filp, int mode)
  182. {
  183.     return 0;
  184. }
  185. #endif
  186. int scull_p_lseek (struct inode *inode, struct file *filp,
  187.                  off_t off, int whence)
  188. {
  189.     return -ESPIPE; /* unseekable */
  190. }
  191. #ifdef SCULL_USE_PROC
  192. int scull_read_p_mem(char *buf, char **start, off_t offset,
  193.                    int len, int unused)
  194. {
  195.     int i;
  196.     Scull_Pipe *p;
  197.     #define LIMIT (PAGE_SIZE-200) /* don't print any more after this size */
  198.     len = sprintf(buf, "Default buffersize is %in", scull_p_buffer);
  199.     for(i = 0; i<scull_p_nr_devs; i++) {
  200.         if (len > LIMIT) break;
  201.         p = &scull_p_devices[i];
  202.         len += sprintf(buf+len, "nDevice %i: %pn", i, p);
  203.         len += sprintf(buf+len, "   Queues: %p %pn", p->inq, p->outq);
  204.         len += sprintf(buf+len, "   Buffer: %p to %p (%i bytes)n",
  205.                        p->buffer, p->end, p->buffersize);
  206.         len += sprintf(buf+len, "   rp %p   wp %pn", p->rp, p->wp);
  207.         len += sprintf(buf+len, "   readers %i   writers %in",
  208.                        p->nreaders, p->nwriters);
  209.     }
  210.     return len;
  211. }
  212. struct proc_dir_entry scull_proc_p_entry = {
  213.         0,                 /* low_ino: the inode -- dynamic */
  214.         9, "scullpipe",     /* len of name and name */
  215.         S_IFREG | S_IRUGO, /* mode */
  216.         1, 0, 0,           /* nlinks, owner, group */
  217.         0, NULL,           /* size - unused; operations -- use default */
  218.         &scull_read_p_mem,   /* function used to read data */
  219.         /* nothing more */
  220.     };
  221. #endif
  222. /*
  223.  * The file operations for the pipe device
  224.  * (some are overlayed with bare scull)
  225.  */
  226. struct file_operations scull_pipe_fops = {
  227.     scull_p_lseek,
  228.     scull_p_read,
  229.     scull_p_write,
  230.     NULL,          /* scull_p_readdir */
  231.     scull_p_select,
  232.     scull_ioctl,
  233.     NULL,          /* scull_p_mmap */
  234.     scull_p_open,
  235.     scull_p_release,
  236.     NULL,          /* scull_p_fsync */
  237.     scull_p_fasync,
  238.                    /* nothing more, fill with NULLs */
  239. };
  240. int scull_p_init(void)
  241. {
  242.     scull_p_devices = kmalloc(scull_p_nr_devs * sizeof(Scull_Pipe),
  243.                               GFP_KERNEL);
  244.     if (scull_p_devices == NULL)
  245.         return -ENOMEM;
  246.     memset(scull_p_devices, 0, scull_p_nr_devs * sizeof(Scull_Pipe));
  247. #ifdef SCULL_USE_PROC
  248.     proc_register_dynamic(&proc_root, &scull_proc_p_entry);
  249. #endif
  250.     return 0;
  251. }
  252. void scull_p_cleanup(void) /* called by cleanup_module */
  253. {
  254.     int i;
  255.     for (i=0; i < scull_p_nr_devs; i++) {
  256.         if (scull_p_devices[i].buffer)
  257.             kfree(scull_p_devices[i].buffer);
  258.     }
  259.     kfree(scull_p_devices);
  260. #ifdef SCULL_USE_PROC
  261.     proc_unregister(&proc_root, scull_proc_p_entry.low_ino);
  262. #endif
  263.     return;
  264. }