Implemented open/release with multiple devices.
authorThadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
Tue, 8 Dec 2009 12:49:25 +0000 (10:49 -0200)
committerThadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
Tue, 8 Dec 2009 12:49:25 +0000 (10:49 -0200)
helloc.c

index 0db07e3..8c085f3 100644 (file)
--- a/helloc.c
+++ b/helloc.c
@@ -5,6 +5,7 @@
 #include <linux/cdev.h>
 /* Needed for copying to/from user space */
 #include <asm/uaccess.h>
+#include <linux/slab.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>");
@@ -12,22 +13,53 @@ MODULE_DESCRIPTION("A hello world char device");
 MODULE_VERSION("1.0.0");
 
 /* Message buffer we send to upstream */
-static char helloc_message[] = "hello, world\n";
+static char hello_message[] = "hello, world\n";
+static char goodbye_message[] = "goodbye, world\n";
+
+struct message {
+       char *text;
+       size_t len;
+};
+
+static int helloc_open(struct inode *ino, struct file *filp)
+{
+       struct message *msg;
+       printk(KERN_INFO "Opened file with minor %d\n", iminor(ino));
+       msg = kmalloc(sizeof(struct message), GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+       if (iminor(ino) == 0) {
+               msg->text = hello_message;
+               msg->len = sizeof(hello_message);
+       } else {
+               msg->text = goodbye_message;
+               msg->len = sizeof(goodbye_message);
+       }
+       filp->private_data = msg;
+       return 0;
+}
+
+static int helloc_release(struct inode *ino, struct file *filp)
+{
+       kfree(filp->private_data);
+       return 0;
+}
 
 /* our read function writes our message to the user buffer */
 static ssize_t helloc_read(struct file *filp, 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 >= sizeof(helloc_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 > sizeof(helloc_message) - *pos)
-               len = sizeof(helloc_message) - *pos;
+       if (len > msg->len - *pos)
+               len = msg->len - *pos;
        /* copy message to user space and return error if it fails */
-       r = copy_to_user(buf, helloc_message + *pos, len);
+       r = copy_to_user(buf, msg->text + *pos, len);
        if (r)
                return -EFAULT;
        /* update the file position */
@@ -38,6 +70,8 @@ static ssize_t helloc_read(struct file *filp, char __user *buf, size_t len,
 /* we only implement read */
 static struct file_operations helloc_fops = {
        .owner = THIS_MODULE,
+       .open = helloc_open,
+       .release = helloc_release,
        .read = helloc_read,
 };
 
@@ -49,7 +83,7 @@ static int __init helloc_init(void)
 {
        int r;
        /* allocate any major number with only one minor */
-       r = alloc_chrdev_region(&dev, 0, 1, "helloc");
+       r = alloc_chrdev_region(&dev, 0, 2, "helloc");
        if (r)
                goto out_region;
        r = -ENOMEM;
@@ -63,7 +97,7 @@ static int __init helloc_init(void)
        cdev->owner = THIS_MODULE;
        cdev->ops = &helloc_fops;
        /* register the chardev to the system */
-       r = cdev_add(cdev, dev, 1);
+       r = cdev_add(cdev, dev, 2);
        if (r)
                goto out_add;
        return 0;
@@ -72,7 +106,7 @@ out_add:
        kfree(cdev);
 out_alloc:
        /* release the device number allocated */
-       unregister_chrdev_region(dev, 1);
+       unregister_chrdev_region(dev, 2);
 out_region:
        return r;
 }
@@ -82,7 +116,7 @@ static void __exit helloc_exit(void)
        /* remove the chardev from the system */
        cdev_del(cdev);
        /* release the device number allocated */
-       unregister_chrdev_region(dev, 1);
+       unregister_chrdev_region(dev, 2);
 }
 
 module_init(helloc_init);