#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>");
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 */
/* we only implement read */
static struct file_operations helloc_fops = {
.owner = THIS_MODULE,
+ .open = helloc_open,
+ .release = helloc_release,
.read = helloc_read,
};
{
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;
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;
kfree(cdev);
out_alloc:
/* release the device number allocated */
- unregister_chrdev_region(dev, 1);
+ unregister_chrdev_region(dev, 2);
out_region:
return r;
}
/* 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);