Allocate buffers for any number of devices.
[cascardo/kernel/samples/02.char/.git] / helloc.c
index 00ce97d..f43a767 100644 (file)
--- a/helloc.c
+++ b/helloc.c
@@ -13,37 +13,29 @@ 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;
-static char *goodbye_message;
+#define DEVICE_NUMBER 2
 
 struct message {
        char *text;
        size_t len;
 };
 
+/* Message buffer we send to upstream */
+static struct message *hello_message[DEVICE_NUMBER];
+
 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 = BUFFER_SIZE;
-       } else {
-               msg->text = goodbye_message;
-               msg->len = BUFFER_SIZE;
-       }
+       if (iminor(ino) >= DEVICE_NUMBER)
+               return -ENODEV;
+       msg = hello_message[iminor(ino)];
        filp->private_data = msg;
        return 0;
 }
 
 static int helloc_release(struct inode *ino, struct file *filp)
 {
-       kfree(filp->private_data);
        return 0;
 }
 
@@ -103,17 +95,45 @@ static struct file_operations helloc_fops = {
 static dev_t dev;
 static struct cdev *cdev;
 
+static void helloc_free(void)
+{
+       int i;
+       for (i = 0; i < DEVICE_NUMBER; i++) {
+               if (hello_message[i])
+                       kfree(hello_message[i]->text);
+               kfree(hello_message[i]);
+       }
+}
+
+static int __init helloc_alloc(void)
+{
+       int i;
+       for (i = 0; i < DEVICE_NUMBER; i++) {
+               hello_message[i] = kzalloc(sizeof(struct message), GFP_KERNEL);
+               if (!hello_message[i])
+                       goto out;
+               hello_message[i]->text = kzalloc(BUFFER_SIZE, GFP_KERNEL);
+               if (!hello_message[i]->text)
+                       goto out;
+       }
+       return 0;
+out:
+       for (; i >= 0; i--) {
+               if (hello_message[i])
+                       kfree(hello_message[i]->text);
+               kfree(hello_message[i]);
+       }
+       return -ENOMEM;
+}
+
 static int __init helloc_init(void)
 {
-       int r = -ENOMEM;
+       int r;
+       r = helloc_alloc();
+       if (r)
+               goto out_alloc2;
        /* 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");
+       r = alloc_chrdev_region(&dev, 0, DEVICE_NUMBER, "helloc");
        if (r)
                goto out_region;
        r = -ENOMEM;
@@ -127,7 +147,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, 2);
+       r = cdev_add(cdev, dev, DEVICE_NUMBER);
        if (r)
                goto out_add;
        return 0;
@@ -136,12 +156,9 @@ out_add:
        kfree(cdev);
 out_alloc:
        /* release the device number allocated */
-       unregister_chrdev_region(dev, 2);
+       unregister_chrdev_region(dev, DEVICE_NUMBER);
 out_region:
-       kfree(goodbye_message);
-out_goodbye:
-       kfree(hello_message);
-out_hello:
+out_alloc2:
        return r;
 }
 
@@ -150,9 +167,8 @@ static void __exit helloc_exit(void)
        /* remove the chardev from the system */
        cdev_del(cdev);
        /* release the device number allocated */
-       unregister_chrdev_region(dev, 2);
-       kfree(goodbye_message);
-       kfree(hello_message);
+       unregister_chrdev_region(dev, DEVICE_NUMBER);
+       helloc_free();
 }
 
 module_init(helloc_init);