Skip to content
Snippets Groups Projects
Select Git revision
  • 9f240f733b4017428417612090c7cd937fad6943
  • master default
  • 2015ss
  • 2014ss
4 results

chardev-1write.c

  • Forked from Peter Gerwinski / bs
    Source project has a limited visibility.
    chardev-1write.c 5.62 KiB
    /*  Modified by:      Christian Löpke <christian.loepke@hs-bochum.de>
     *  chardev-1write.c: Creates a char device that says Mr. Anderson or a 
     *                    written name how many times he read from the dev
     *                    file.
     */
    
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h>	/* for put_user */
    
    /*  
     *  Prototypes - this would normally go in a .h file
     */
    int init_module(void);
    void cleanup_module(void);
    static int device_open(struct inode *, struct file *);
    static int device_release(struct inode *, struct file *);
    static ssize_t device_read(struct file *, char *, size_t, loff_t *);
    static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
    
    #define SUCCESS 0
    #define DEVICE_NAME "chardev"	/* Dev name as it appears in /proc/devices   */
    #define BUF_LEN 80		/* Max length of the message from the device */
    #define USERBUF_LEN 20		/* Max length for user definable name */
    /* 
     * Global variables are declared as static, so are global within the file. 
     */
    
    static int Major;	    /* Major number assigned to our device driver */
    static int Device_Open = 0; /* Is device open?  
    			     * Used to prevent multiple access to device */
    static char msg[BUF_LEN];   /* The msg the device will give when asked */
    static char *msg_Ptr;	    /* The current char from msg we are writing */
    
    static char msg_username[USERBUF_LEN]; /* User definable name */
    static int told_you_counter = 0; /* Counts the outputs I've made */
    
    static struct file_operations fops = {
    	.read = device_read,
    	.write = device_write,
    	.open = device_open,
    	.release = device_release
    };
    
    /*
     * This function is called when the module is loaded
     */
    int init_module(void)
    {
            Major = register_chrdev(0, DEVICE_NAME, &fops);
    
    	if (Major < 0) {
    	  printk(	KERN_ALERT 
    			"%s: Registering char device failed with %d\n", 
    			DEVICE_NAME,			
    			Major);
    	  return Major;
    	}
    
    	printk(	KERN_INFO "%s: I was assigned major number %d. To talk to\n",
    		DEVICE_NAME,		
    		Major);
    	printk(	KERN_INFO 
    		"%s: the driver, create a dev file with\n", DEVICE_NAME);
    	printk(	KERN_INFO "%s: 'mknod /dev/%s c %d 0'.\n",
    		DEVICE_NAME,
    		DEVICE_NAME,
    		Major);
    	printk(	KERN_INFO 
    		"%s: Try various minor numbers. Try to cat and echo to\n",
    		DEVICE_NAME);
    	printk(	KERN_INFO "%s: the device file.\n", DEVICE_NAME);
    	printk(	KERN_INFO 
    		"%s: Remove the device file and module when done.\n", 
    		DEVICE_NAME);
    
    	sprintf(msg_username, "Mr. Anderson"); //Setup initial username.
    	return SUCCESS;
    }
    
    /*
     * This function is called when the module is unloaded
     */
    void cleanup_module(void)
    {
    	/* 
    	 * Unregister the device 
    	 */
    	unregister_chrdev(Major, DEVICE_NAME);
    }
    
    /*
     * Methods
     */
    
    /* 
     * Called when a process tries to open the device file, like
     * "cat /dev/mycharfile"
     */
    static int device_open(struct inode *inode, struct file *file)
    {
    	if (Device_Open)
    		return -EBUSY;
    
    	Device_Open++;
    	sprintf(msg,
    		"I already told you %d times Hello world!, %s.\n",
    		told_you_counter++,
    		msg_username);
    	msg_Ptr = msg;
    	try_module_get(THIS_MODULE);
    
    	return SUCCESS; /* Device successfully opened */
    }
    
    /* 
     * Called when a process closes the device file.
     */
    static int device_release(struct inode *inode, struct file *file)
    {
    	Device_Open--;		/* We're now ready for our next caller */
    
    	/* 
    	 * Decrement the usage count, or else once you opened the file, you'll
    	 * never get get rid of the module. 
    	 */
    	module_put(THIS_MODULE);
    
    	return 0; /* Device sucessfully closed */
    }
    
    /* 
     * Called when a process, which already opened the dev file, attempts to
     * read from it.
     */
    static ssize_t device_read(struct file *filp,	/* see include/linux/fs.h   */
    			   char *buffer,	/* buffer to fill with data */
    			   size_t length,	/* length of the buffer     */
    			   loff_t * offset)
    {
    	/*
    	 * Number of bytes actually written to the buffer 
    	 */
    	int bytes_read = 0;
    
    	/*
    	 * If we're at the end of the message, 
    	 * return 0 signifying end of file 
    	 */
    	if (*msg_Ptr == 0)
    		return 0;
    
    	/* 
    	 * Actually put the data into the buffer 
    	 */
    	while (length && *msg_Ptr) {
    
    		/* 
    		 * The buffer is in the user data segment, not the kernel 
    		 * segment so "*" assignment won't work.  We have to use 
    		 * put_user which copies data from the kernel data segment to
    		 * the user data segment. 
    		 */
    		put_user(*(msg_Ptr++), buffer++);
    
    		length--;
    		bytes_read++;
    	}
    
    	/* 
    	 * Most read functions return the number of bytes put into the buffer
    	 */
    	return bytes_read;
    }
    
    /*  
     * Called when a process writes to dev file: echo "hi" > /dev/hello 
     */
    static ssize_t
    device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
    {
    	/* Since nobody wants to read I have to correct the already told you
    	   counter! */
    	told_you_counter--;
    	if(len >= USERBUF_LEN) {
    		printk(	KERN_WARNING 
    			"%s: Sorry, your input is too long. Max %d allowed!\n",
    			DEVICE_NAME,
    			USERBUF_LEN);	  
    		return -ENOMEM; //Return not enaugh memory
    	}
    	else {
    		int i;
    		for(i = 0; i < len; i++) {//Save the given string
    			if(get_user(msg_username[i], buff + i) < 0) { //If returning error code
    				printk(KERN_WARNING 
    					   "%s: This memory does not belong to you!\n",
    						DEVICE_NAME);
    				return -EFAULT; //Stop reading from userspace.
    			}			
    			//msg_username[i] = buff[i]; //Heres was the CRASH
    			//printk(KERN_INFO "Got %c at %d from %d bytes.\n", buff[i], i, len);
    		}
    		for(i = len; i < USERBUF_LEN; i++) //Zeroing the rest of mem
    			msg_username[i] = 0;
    		printk(KERN_INFO "%s: Successfully got %d bytes!\n",
    		       DEVICE_NAME, (int)len);
    		if(msg_username[len-1] == '\n') //Got new line terminator ?
    		  msg_username[len-1] = 0; //Then terminate it!
    		return len; //Emit successfully stored len bytes
    	}	
    }