//------------------------------------------------------------------- // stash.c // // This module implements a public clipboard (named 'stash'). // Anything written to this device by one process can then be // read back by any other process. (A ring-buffer is used by // this driver for its data storage.) // // NOTE: Written and tested with Linux kernel version 2.4.18. // // programmer: ALLAN CRUSE // date begun: 31 JAN 2003 // completion: 02 FEB 2003 // revised on: 13 JUN 2004 -- for Linux kernel version 2.4.23 // revised on: 25 OCT 2004 -- for Linux kernel version 2.4.26 //------------------------------------------------------------------- #include // for init_module() #include // for register_chrdev() #include // for interruptible_sleep_on() #include // for get_user(), put_user() #define RINGSIZE 512 static char modname[] = "stash"; static int my_major = 40; // driver's data-structures static wait_queue_head_t wq; static volatile int head, tail; static unsigned char ring[ RINGSIZE ]; static ssize_t my_write( struct file *file, const char *buf, size_t count, loff_t *pos ) { int prev; // sleep if necessary until the ringbuffer has room for new data prev = ( head - 1 ) % RINGSIZE; while ( prev == tail ) // the ringbuffer is aready full { interruptible_sleep_on( &wq ); if ( signal_pending( current ) ) return -ERESTARTSYS; } // insert a new byte of data into our ringbuffer if ( get_user( ring[ tail ], buf ) ) return -EFAULT; tail = ( 1 + tail ) % RINGSIZE; // and awaken any sleeping readers wake_up_interruptible( &wq ); return 1; } static ssize_t my_read( struct file *file, char *buf, size_t count, loff_t *pos ) { int next; // sleep if necessary until the ringbuffer has some data in it next = head; while ( next == tail ) // the ringbuffer is already empty { interruptible_sleep_on( &wq ); if ( signal_pending( current ) ) return -ERESTARTSYS; } // remove a byte of data from our ringbuffer if ( put_user( ring[ head ], buf ) ) return -EFAULT; head = ( 1 + head ) % RINGSIZE; // and awaken any sleeping writers wake_up_interruptible( &wq ); return 1; } static struct file_operations my_fops = { owner: THIS_MODULE, write: my_write, read: my_read, }; int init_module( void ) { printk( "<1>\nInstalling \'%s\' module ", modname ); printk( "(major=%d) \n", my_major ); // initialize our wait-queue structure init_waitqueue_head( &wq ); // register this device-driver with the kernel return register_chrdev( my_major, modname, &my_fops ); } void cleanup_module( void ) { printk( "<1>Removing \'%s\' module\n", modname ); // unregister this device-driver unregister_chrdev( my_major, modname ); } MODULE_LICENSE("GPL");