Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- ** This "device" reverses strings that are written to it
- */
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/cdev.h>
- #include <linux/mutex.h> //for mutexes
- #include <linux/types.h> // for dev_t typedef
- #include <linux/kdev_t.h> // for format_dev_t
- #include <linux/fs.h> // for alloc_chrdev_region()
- #include <asm/uaccess.h> // for copy_to_user, copy_from_user
- #define BUFSZ 6
- static dev_t mydev; // (major,minor) value
- static struct cdev my_cdev;
- static struct mutex write;
- static struct mutex read;
- static struct semaphore bufempty;
- static struct semaphore buffull;
- static int access_count = 0;
- static char internal_buffer[BUFSZ];
- /*********************************************************************
- ** The set of file operations that are implemented in this driver
- **********************************************************************/
- static ssize_t device_read(struct file *filp, char __user *buf,
- size_t len, loff_t *f_pos);
- static ssize_t device_write(struct file *filp, const char __user *buf,
- size_t len, loff_t *f_pos);
- static int device_open( struct inode *, struct file *);
- static int device_close( struct inode *, struct file *);
- static struct file_operations my_fops = {
- .owner = THIS_MODULE,
- .open = device_open,
- .read = device_read,
- .write = device_write,
- .release = device_close
- };
- /*********************************************************************
- ** Called when the device is opened (system call open)
- **********************************************************************/
- static int device_open(struct inode *inodep, struct file *filep)
- {
- //mutex_lock_interruptible(&reject); //rejecting mutex read
- access_count++;
- printk(KERN_ALERT "Reverse device opened %d time(s)\n", access_count);
- if ( filep->f_mode & FMODE_READ )
- printk(KERN_ALERT "Reverse device opened for read\n" );
- if ( filep->f_mode & FMODE_WRITE )
- printk(KERN_ALERT "Reverse device opened for write\n" );
- return 0;
- }
- /**********************************************************************
- ** Called when the device is read from
- **********************************************************************/
- static ssize_t device_read( struct file *filp, char __user *buf,
- size_t len, loff_t *f_pos )
- {
- // print some information
- mutex_lock_interruptible(&read);
- printk( KERN_INFO "In reverse read routine.\n" );
- printk( KERN_INFO "Length field is %lu.\n", (long unsigned int) len );
- printk( KERN_INFO "Offset is %lu.\n", (long unsigned int) *f_pos );
- if ( internal_buffer[*f_pos] == '\0' )
- {
- printk( KERN_INFO "End of string, returning zero.\n" );
- return 0;
- }
- if ( copy_to_user( buf, &internal_buffer[*f_pos], 1 ) != 0 )
- return -EFAULT;
- *f_pos += 1;
- mutex_unlock(&read);
- mutex_unlock(&write);
- return 1; // return a single character
- }
- /**********************************************************************
- ** Called when the device is written to
- **********************************************************************/
- static ssize_t device_write( struct file *filep, const char *buf,
- size_t len, loff_t *f_pos )
- {
- mutex_lock_interruptible(&write); //rejecting mutex write
- int i;
- int count = 0;
- i = 0; // start at the end to reverse
- // print some information
- printk( KERN_INFO "In reverse write routine.\n" );
- printk( KERN_INFO "Length field is %lu.\n", (long unsigned int) len );
- printk( KERN_INFO "Offset is %lu.\n", (long unsigned int) *f_pos );
- // clear the buffer
- memset( internal_buffer, 0, BUFSZ );
- *f_pos = 0;
- if(len>BUFSZ){ //checking if the input is bigger than the size of buffer
- int k=0;
- for(k=0; k<BUFSZ-1; k++){ //only BUFSZ-1
- if ( copy_from_user( &internal_buffer[count++], buf+i, 1 ) != 0 )
- return -EFAULT;
- i++;
- len--;
- }
- printk( KERN_INFO "FULL DEVICE.\n" );
- mutex_lock_interruptible(&write);
- //mutex_unlock(&read);
- }
- else{
- // copy the data from the user into the internal buffer
- while ( len > 0 )
- {
- if ( copy_from_user( &internal_buffer[count++], buf+i, 1 ) != 0 )
- return -EFAULT;
- i++;
- len--;
- }
- printk( KERN_INFO "DEVICE is not full.\n" );
- }
- mutex_unlock(&write);
- mutex_unlock(&read);
- return count;
- }
- /**********************************************************************
- ** Called when the device is closed
- **********************************************************************/
- static int device_close(struct inode *inodep, struct file *filep)
- {
- //mutex_unlock(&reject);
- printk(KERN_ALERT "reverse device closed !\n");
- //rejecting mutex unlock
- return 0;
- }
- /**********************************************************************
- ** Called when this driver module is loaded
- **********************************************************************/
- static int __init chardrv_in(void)
- {
- int result;
- printk(KERN_INFO "module reverse driver being loaded.\n");
- mutex_init(&write);
- mutex_init(&read);
- sema_init(&bufempty, BUFSZ);
- sema_init(&buffull, BUFSZ);
- result = alloc_chrdev_region(&mydev, 0, 1, "rday");
- if ( result < 0 )
- {
- printk(KERN_WARNING "Failed to allocate major/minor numbers");
- return result;
- }
- cdev_init(&my_cdev, &my_fops);
- my_cdev.owner = THIS_MODULE;
- result = cdev_add(&my_cdev, mydev, 1);
- if ( result < 0 )
- {
- printk(KERN_WARNING "Failed to register the cdev structure");
- return result;
- }
- return 0;
- }
- /*********************************************************************
- ** Called when this driver module is unloaded
- *********************************************************************/
- static void __exit chardrv_out(void)
- {
- printk(KERN_INFO "module chardrv being unloaded.\n");
- cdev_del(&my_cdev);
- unregister_chrdev_region(mydev, 1);
- }
- module_init(chardrv_in);
- module_exit(chardrv_out);
- MODULE_AUTHOR("Robert P. J. Day, http://crashcourse.ca");
- MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement