0

Hello I am trying to write to a fake char device driver using:

echo > /dev/

and reading it using:

cat /dev/

My problem is that I am getting continuously the first character written printed on the terminal when I do a read with the above mentioned "cat" read method after writing using the echo method above.

My aim is to get the entire set of characters written to the driver back...

I am using dynamic memory allocation for this purpose but not getting the final result after trying many ways of rewriting the code of read() and write() in the driver. Please help..

my Makefile is correct... (I am using ubuntu with a kernel version of 2.6.33...)

My code is as below:

#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

static dev_t first;
static struct cdev c_dev;
static struct class *cl;
static char* k_buf = NULL;

static int my_open(struct inode *i,struct file *f)
{
    printk(KERN_INFO "In driver open()\n");
    return 0;
}

static int my_close(struct inode *i,struct file *f)
{
    printk(KERN_INFO "In driver close()\n");
    return 0;
}

static ssize_t my_read(struct file *f,char __user *buf,size_t len,loff_t *off)
{
    printk(KERN_INFO "In driver read()\n");

    if(k_buf == NULL)
    {
        printk(KERN_INFO "You cannot read before writing!\n");
        return -1;
    }

    while(*k_buf != 'EOF')
    {
        if(copy_to_user(buf,k_buf,1))
            return -EFAULT;
        off++;
        return 1;
    }

    return 0;
}

static ssize_t my_write(struct file *f,const char __user *buf,size_t len,loff_t *off)
{
    printk(KERN_INFO "In driver write()\n");
    k_buf = (char*) kmalloc(sizeof(len),GFP_KERNEL);

    if(copy_from_user(k_buf,buf,len))
        return -EFAULT;

    off += len;

    return (len);
}

static struct file_operations fops =
{
    .owner = THIS_MODULE,
    .open = my_open,
    .release = my_close,
    .read = my_read,
    .write = my_write
};

static int __init rw_init(void) /*Constructor*/
{
    printk(KERN_INFO "hello: rw_ch_driver registered\n");

    if(alloc_chrdev_region(&first,0,1,"krishna") < 0)
    {
        return -1;
    }

    if ((cl = class_create(THIS_MODULE,"chardev")) == NULL)
    {
        unregister_chrdev_region(first,1);
        return -1;
    }

    if (device_create(cl,NULL,first,NULL,"rw_char_driver") == NULL)
    {
        class_destroy(cl);
        unregister_chrdev_region(first,1);
        return -1;
    }

    cdev_init(&c_dev,&fops);

    if(cdev_add(&c_dev,first,1) == -1)
    {
        device_destroy(cl,first);
        class_destroy(cl);
        unregister_chrdev_region(first,1);
        return -1;
    }

return 0;
}

static void __exit rw_exit(void)/*destructor*/
{
    cdev_del(&c_dev);
    device_destroy(cl,first);
    class_destroy(cl);
    unregister_chrdev_region(first,1);
    printk(KERN_INFO "bye rw_chardriver unregistered");
}

module_init(rw_init);
module_exit(rw_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("krishna");
MODULE_DESCRIPTION("read write character driver");
skrrgwasme
  • 9,358
  • 11
  • 54
  • 84

1 Answers1

0

Take a careful look at your while loop in my_read().

Most important note first: you don't need this loop. You've put a return statement in it, so it is never going to execute more than once, because the whole function is going to exit when the return is reached. It looks like you're trying to make the function return a single byte at a time repeatedly, but you should just call copy_to_user once, and pass it the number of bytes you want to give back to the user instead. If you only send one character at a time that's fine. It will be up to the user to make the read call again to get the next character.

The nice thing about copy_to_user, is that its return code will tell you if it failed because of bad array bounds, so there's no need to check for EOF on every character. In fact, you are not going to get 'EOF' as a character when you are reading from your buffer because it doesn't exist. Your buffer will store characters and usually a null terminator, '\0', but there is no 'EOF' character in C. EOF is a state you need to identify yourself and report to whoever called open. For the "cat" command, this is done by returning 0 from read. That being said, you should still check your array bounds so we don't end up with another Heartbleed. This SO answer has a good suggestion for how to do bounds checking to make sure you don't send more bytes than your buffer has.

Also, give [this post(https://meta.stackexchange.com/questions/981/syntax-highlighting-language-hints) a read. If you don't have your language in your question tags, it is helpful to other readers to tag your. I've edited your question to clean it up, so you can click "edit" now to see how I did it.

Community
  • 1
  • 1
skrrgwasme
  • 9,358
  • 11
  • 54
  • 84