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>
9 #include <linux/proc_fs.h>
10 #include <linux/seq_file.h>
12 MODULE_LICENSE("GPL");
13 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>");
14 MODULE_DESCRIPTION("A hello world char device");
15 MODULE_VERSION("1.0.0");
17 #define BUFFER_SIZE 4096
18 #define DEVICE_NUMBER 2
25 /* Message buffer we send to upstream */
26 static struct message *hello_message[DEVICE_NUMBER];
28 static int helloc_open(struct inode *ino, struct file *filp)
31 printk(KERN_INFO "Opened file with minor %d\n", iminor(ino));
32 if (iminor(ino) >= DEVICE_NUMBER)
34 msg = hello_message[iminor(ino)];
35 filp->private_data = msg;
36 if (filp->f_flags & O_TRUNC) {
37 memset(msg->text, 0, msg->len);
39 printk(KERN_INFO "File opened with truncate flags\n");
41 if (filp->f_flags & O_APPEND) {
42 filp->f_pos = msg->len;
47 static int helloc_release(struct inode *ino, struct file *filp)
52 /* our read function writes our message to the user buffer */
53 static ssize_t helloc_read(struct file *filp, char __user *buf, size_t len,
57 struct message *msg = filp->private_data;
58 /* do not read pass through the size of the message */
60 /* return end of file */
62 /* if len is bigger than the rest of the message, clamp it */
63 if (len > msg->len - *pos)
64 len = msg->len - *pos;
65 /* copy message to user space and return error if it fails */
66 r = copy_to_user(buf, msg->text + *pos, len);
69 /* update the file position */
74 static ssize_t helloc_write(struct file *filp, const char __user *buf,
75 size_t len, loff_t *pos)
78 struct message *msg = filp->private_data;
79 /* do not read pass through the size of the message */
80 if (*pos >= BUFFER_SIZE)
81 /* return end of file */
83 /* if len is bigger than the rest of the message, clamp it */
84 if (len > BUFFER_SIZE - *pos)
85 len = BUFFER_SIZE - *pos;
87 /* copy message to user space and return error if it fails */
88 r = copy_from_user(msg->text + *pos, buf, len);
90 if (*pos + len > msg->len)
91 memset(msg->text + msg->len, 0, *pos + len - msg->len);
94 /* update the file position */
96 if (msg->len < *pos) {
97 printk(KERN_DEBUG "Updating size from %d to %lld\n", msg->len, *pos);
104 /* we only implement read */
105 static struct file_operations helloc_fops = {
106 .owner = THIS_MODULE,
108 .release = helloc_release,
110 .write = helloc_write,
113 static int hello_len_show(struct seq_file *seq, void *data)
115 struct message *msg = seq->private;
116 seq_printf(seq, "%d\n", msg->len);
120 static int hello_proc_open(struct inode *ino, struct file *filp)
122 return single_open(filp, hello_len_show, hello_message[0]);
125 static struct file_operations hello_proc_fops = {
126 .owner = THIS_MODULE,
127 .open = hello_proc_open,
130 .release = seq_release,
134 /* the device number and the char device struct */
136 static struct cdev *cdev;
138 static void helloc_free(void)
141 for (i = 0; i < DEVICE_NUMBER; i++) {
142 if (hello_message[i])
143 kfree(hello_message[i]->text);
144 kfree(hello_message[i]);
148 static int __init helloc_alloc(void)
151 for (i = 0; i < DEVICE_NUMBER; i++) {
152 hello_message[i] = kzalloc(sizeof(struct message), GFP_KERNEL);
153 if (!hello_message[i])
155 hello_message[i]->text = kzalloc(BUFFER_SIZE, GFP_KERNEL);
156 if (!hello_message[i]->text)
161 for (; i >= 0; i--) {
162 if (hello_message[i])
163 kfree(hello_message[i]->text);
164 kfree(hello_message[i]);
169 static int __init helloc_init(void)
171 struct proc_dir_entry *hello_pde;
176 /* allocate any major number with only one minor */
177 r = alloc_chrdev_region(&dev, 0, DEVICE_NUMBER, "helloc");
181 /* print the major number allocated so we can create our device node */
182 printk(KERN_INFO "Allocated major number %d\n", MAJOR(dev));
183 /* allocate the character device struct */
187 /* set the module owner and the file operations of our chardev */
188 cdev->owner = THIS_MODULE;
189 cdev->ops = &helloc_fops;
190 /* register the chardev to the system */
191 r = cdev_add(cdev, dev, DEVICE_NUMBER);
194 hello_pde = proc_create("hello_len", 0666, NULL, &hello_proc_fops);
201 /* release memory allocated to the cdev device */
204 /* release the device number allocated */
205 unregister_chrdev_region(dev, DEVICE_NUMBER);
211 static void __exit helloc_exit(void)
213 remove_proc_entry("hello_len", NULL);
214 /* remove the chardev from the system */
216 /* release the device number allocated */
217 unregister_chrdev_region(dev, DEVICE_NUMBER);
221 module_init(helloc_init);
222 module_exit(helloc_exit);