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>
11 #include <linux/miscdevice.h>
13 MODULE_LICENSE("GPL");
14 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>");
15 MODULE_DESCRIPTION("A hello world char device");
16 MODULE_VERSION("1.0.0");
18 #define BUFFER_SIZE 4096
25 /* Message buffer we send to upstream */
26 static struct message *hello_message;
28 static int helloc_open(struct inode *ino, struct file *filp)
31 printk(KERN_INFO "Opened file with minor %d\n", iminor(ino));
33 filp->private_data = msg;
34 if (filp->f_flags & O_TRUNC) {
35 memset(msg->text, 0, msg->len);
37 printk(KERN_INFO "File opened with truncate flags\n");
39 if (filp->f_flags & O_APPEND) {
40 filp->f_pos = msg->len;
45 static int helloc_release(struct inode *ino, struct file *filp)
50 /* our read function writes our message to the user buffer */
51 static ssize_t helloc_read(struct file *filp, char __user *buf, size_t len,
55 struct message *msg = filp->private_data;
56 /* do not read pass through the size of the message */
58 /* return end of file */
60 /* if len is bigger than the rest of the message, clamp it */
61 if (len > msg->len - *pos)
62 len = msg->len - *pos;
63 /* copy message to user space and return error if it fails */
64 r = copy_to_user(buf, msg->text + *pos, len);
67 /* update the file position */
72 static ssize_t helloc_write(struct file *filp, const char __user *buf,
73 size_t len, loff_t *pos)
76 struct message *msg = filp->private_data;
77 /* do not read pass through the size of the message */
78 if (*pos >= BUFFER_SIZE)
79 /* return end of file */
81 /* if len is bigger than the rest of the message, clamp it */
82 if (len > BUFFER_SIZE - *pos)
83 len = BUFFER_SIZE - *pos;
85 /* copy message to user space and return error if it fails */
86 r = copy_from_user(msg->text + *pos, buf, len);
88 if (*pos + len > msg->len)
89 memset(msg->text + msg->len, 0, *pos + len - msg->len);
92 /* update the file position */
94 if (msg->len < *pos) {
95 printk(KERN_DEBUG "Updating size from %d to %lld\n", msg->len, *pos);
102 /* we only implement read */
103 static struct file_operations helloc_fops = {
104 .owner = THIS_MODULE,
106 .release = helloc_release,
108 .write = helloc_write,
111 static int hello_len_show(struct seq_file *seq, void *data)
113 struct message *msg = seq->private;
114 seq_printf(seq, "%d\n", msg->len);
118 static int hello_proc_open(struct inode *ino, struct file *filp)
120 return single_open(filp, hello_len_show, hello_message);
123 static struct file_operations hello_proc_fops = {
124 .owner = THIS_MODULE,
125 .open = hello_proc_open,
128 .release = seq_release,
131 static void helloc_free(void)
134 kfree(hello_message->text);
135 kfree(hello_message);
138 static int __init helloc_alloc(void)
140 hello_message = kzalloc(sizeof(struct message), GFP_KERNEL);
143 hello_message->text = kzalloc(BUFFER_SIZE, GFP_KERNEL);
144 if (!hello_message->text)
148 kfree(hello_message);
152 static struct miscdevice hello_misc = {
154 .fops = &helloc_fops,
155 .minor = MISC_DYNAMIC_MINOR,
158 static int __init helloc_init(void)
160 struct proc_dir_entry *hello_pde;
165 r = misc_register(&hello_misc);
168 hello_pde = proc_create("hello_len", 0666, NULL, &hello_proc_fops);
173 misc_deregister(&hello_misc);
179 static void __exit helloc_exit(void)
181 remove_proc_entry("hello_len", NULL);
182 misc_deregister(&hello_misc);
186 module_init(helloc_init);
187 module_exit(helloc_exit);