Allow writing to a buffer for our devices.
[cascardo/kernel/samples/02.char/.git] / helloc.c
index 8c085f3..00ce97d 100644 (file)
--- a/helloc.c
+++ b/helloc.c
@@ -12,9 +12,11 @@ MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>");
 MODULE_DESCRIPTION("A hello world char device");
 MODULE_VERSION("1.0.0");
 
+#define BUFFER_SIZE 4096
+
 /* Message buffer we send to upstream */
-static char hello_message[] = "hello, world\n";
-static char goodbye_message[] = "goodbye, world\n";
+static char *hello_message;
+static char *goodbye_message;
 
 struct message {
        char *text;
@@ -30,10 +32,10 @@ static int helloc_open(struct inode *ino, struct file *filp)
                return -ENOMEM;
        if (iminor(ino) == 0) {
                msg->text = hello_message;
-               msg->len = sizeof(hello_message);
+               msg->len = BUFFER_SIZE;
        } else {
                msg->text = goodbye_message;
-               msg->len = sizeof(goodbye_message);
+               msg->len = BUFFER_SIZE;
        }
        filp->private_data = msg;
        return 0;
@@ -67,12 +69,34 @@ static ssize_t helloc_read(struct file *filp, char __user *buf, size_t len,
        return len;
 }
 
+static ssize_t helloc_write(struct file *filp, const char __user *buf,
+                           size_t len, loff_t *pos)
+{
+       int r;
+       struct message *msg = filp->private_data;
+       /* do not read pass through the size of the message */
+       if (*pos >= msg->len)
+       /* return end of file */
+               return 0;
+       /* if len is bigger than the rest of the message, clamp it */
+       if (len > msg->len - *pos)
+               len = msg->len - *pos;
+       /* copy message to user space and return error if it fails */
+       r = copy_from_user(msg->text + *pos, buf, len);
+       if (r)
+               return -EFAULT;
+       /* update the file position */
+       *pos += len;
+       return len;
+}
+
 /* we only implement read */
 static struct file_operations helloc_fops = {
        .owner = THIS_MODULE,
        .open = helloc_open,
        .release = helloc_release,
        .read = helloc_read,
+       .write = helloc_write,
 };
 
 /* the device number and the char device struct */
@@ -81,8 +105,14 @@ static struct cdev *cdev;
 
 static int __init helloc_init(void)
 {
-       int r;
+       int r = -ENOMEM;
        /* allocate any major number with only one minor */
+       hello_message = kzalloc(BUFFER_SIZE, GFP_KERNEL);
+       if (!hello_message)
+               goto out_hello;
+       goodbye_message = kzalloc(BUFFER_SIZE, GFP_KERNEL);
+       if (!goodbye_message)
+               goto out_goodbye;
        r = alloc_chrdev_region(&dev, 0, 2, "helloc");
        if (r)
                goto out_region;
@@ -108,6 +138,10 @@ out_alloc:
        /* release the device number allocated */
        unregister_chrdev_region(dev, 2);
 out_region:
+       kfree(goodbye_message);
+out_goodbye:
+       kfree(hello_message);
+out_hello:
        return r;
 }
 
@@ -117,6 +151,8 @@ static void __exit helloc_exit(void)
        cdev_del(cdev);
        /* release the device number allocated */
        unregister_chrdev_region(dev, 2);
+       kfree(goodbye_message);
+       kfree(hello_message);
 }
 
 module_init(helloc_init);