1 #include <linux/module.h>
2 /* Needed for struct file_operations and others */
4 /* Needed for struct cdev */
5 #include <linux/cdev.h>
6 /* Needed for copying to/from user space */
7 #include <asm/uaccess.h>
8 #include <linux/slab.h>
10 MODULE_LICENSE("GPL");
11 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>");
12 MODULE_DESCRIPTION("A hello world char device");
13 MODULE_VERSION("1.0.0");
15 #define BUFFER_SIZE 4096
16 #define DEVICE_NUMBER 2
23 /* Message buffer we send to upstream */
24 static struct message *hello_message[DEVICE_NUMBER];
26 static int helloc_open(struct inode *ino, struct file *filp)
29 printk(KERN_INFO "Opened file with minor %d\n", iminor(ino));
30 if (iminor(ino) >= DEVICE_NUMBER)
32 msg = hello_message[iminor(ino)];
33 filp->private_data = msg;
37 static int helloc_release(struct inode *ino, struct file *filp)
42 /* our read function writes our message to the user buffer */
43 static ssize_t helloc_read(struct file *filp, char __user *buf, size_t len,
47 struct message *msg = filp->private_data;
48 /* do not read pass through the size of the message */
50 /* return end of file */
52 /* if len is bigger than the rest of the message, clamp it */
53 if (len > msg->len - *pos)
54 len = msg->len - *pos;
55 /* copy message to user space and return error if it fails */
56 r = copy_to_user(buf, msg->text + *pos, len);
59 /* update the file position */
64 static ssize_t helloc_write(struct file *filp, const char __user *buf,
65 size_t len, loff_t *pos)
68 struct message *msg = filp->private_data;
69 /* do not read pass through the size of the message */
71 /* return end of file */
73 /* if len is bigger than the rest of the message, clamp it */
74 if (len > msg->len - *pos)
75 len = msg->len - *pos;
76 /* copy message to user space and return error if it fails */
77 r = copy_from_user(msg->text + *pos, buf, len);
80 /* update the file position */
85 /* we only implement read */
86 static struct file_operations helloc_fops = {
89 .release = helloc_release,
91 .write = helloc_write,
94 /* the device number and the char device struct */
96 static struct cdev *cdev;
98 static void helloc_free(void)
101 for (i = 0; i < DEVICE_NUMBER; i++) {
102 if (hello_message[i])
103 kfree(hello_message[i]->text);
104 kfree(hello_message[i]);
108 static int __init helloc_alloc(void)
111 for (i = 0; i < DEVICE_NUMBER; i++) {
112 hello_message[i] = kzalloc(sizeof(struct message), GFP_KERNEL);
113 if (!hello_message[i])
115 hello_message[i]->text = kzalloc(BUFFER_SIZE, GFP_KERNEL);
116 if (!hello_message[i]->text)
121 for (; i >= 0; i--) {
122 if (hello_message[i])
123 kfree(hello_message[i]->text);
124 kfree(hello_message[i]);
129 static int __init helloc_init(void)
135 /* allocate any major number with only one minor */
136 r = alloc_chrdev_region(&dev, 0, DEVICE_NUMBER, "helloc");
140 /* print the major number allocated so we can create our device node */
141 printk(KERN_INFO "Allocated major number %d\n", MAJOR(dev));
142 /* allocate the character device struct */
146 /* set the module owner and the file operations of our chardev */
147 cdev->owner = THIS_MODULE;
148 cdev->ops = &helloc_fops;
149 /* register the chardev to the system */
150 r = cdev_add(cdev, dev, DEVICE_NUMBER);
155 /* release memory allocated to the cdev device */
158 /* release the device number allocated */
159 unregister_chrdev_region(dev, DEVICE_NUMBER);
165 static void __exit helloc_exit(void)
167 /* remove the chardev from the system */
169 /* release the device number allocated */
170 unregister_chrdev_region(dev, DEVICE_NUMBER);
174 module_init(helloc_init);
175 module_exit(helloc_exit);