0db07e3c6ff31cf7a2fd4674c6dee1650635b1a6
[cascardo/kernel/samples/02.char/.git] / helloc.c
1 #include <linux/module.h>
2 /* Needed for struct file_operations and others */
3 #include <linux/fs.h>
4 /* Needed for struct cdev */
5 #include <linux/cdev.h>
6 /* Needed for copying to/from user space */
7 #include <asm/uaccess.h>
8
9 MODULE_LICENSE("GPL");
10 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>");
11 MODULE_DESCRIPTION("A hello world char device");
12 MODULE_VERSION("1.0.0");
13
14 /* Message buffer we send to upstream */
15 static char helloc_message[] = "hello, world\n";
16
17 /* our read function writes our message to the user buffer */
18 static ssize_t helloc_read(struct file *filp, char __user *buf, size_t len,
19                            loff_t *pos)
20 {
21         int r;
22         /* do not read pass through the size of the message */
23         if (*pos >= sizeof(helloc_message))
24         /* return end of file */
25                 return 0;
26         /* if len is bigger than the rest of the message, clamp it */
27         if (len > sizeof(helloc_message) - *pos)
28                 len = sizeof(helloc_message) - *pos;
29         /* copy message to user space and return error if it fails */
30         r = copy_to_user(buf, helloc_message + *pos, len);
31         if (r)
32                 return -EFAULT;
33         /* update the file position */
34         *pos += len;
35         return len;
36 }
37
38 /* we only implement read */
39 static struct file_operations helloc_fops = {
40         .owner = THIS_MODULE,
41         .read = helloc_read,
42 };
43
44 /* the device number and the char device struct */
45 static dev_t dev;
46 static struct cdev *cdev;
47
48 static int __init helloc_init(void)
49 {
50         int r;
51         /* allocate any major number with only one minor */
52         r = alloc_chrdev_region(&dev, 0, 1, "helloc");
53         if (r)
54                 goto out_region;
55         r = -ENOMEM;
56         /* print the major number allocated so we can create our device node */
57         printk(KERN_INFO "Allocated major number %d\n", MAJOR(dev));
58         /* allocate the character device struct */
59         cdev = cdev_alloc();
60         if (!cdev)
61                 goto out_alloc;
62         /* set the module owner and the file operations of our chardev */
63         cdev->owner = THIS_MODULE;
64         cdev->ops = &helloc_fops;
65         /* register the chardev to the system */
66         r = cdev_add(cdev, dev, 1);
67         if (r)
68                 goto out_add;
69         return 0;
70 out_add:
71         /* release memory allocated to the cdev device */
72         kfree(cdev);
73 out_alloc:
74         /* release the device number allocated */
75         unregister_chrdev_region(dev, 1);
76 out_region:
77         return r;
78 }
79
80 static void __exit helloc_exit(void)
81 {
82         /* remove the chardev from the system */
83         cdev_del(cdev);
84         /* release the device number allocated */
85         unregister_chrdev_region(dev, 1);
86 }
87
88 module_init(helloc_init);
89 module_exit(helloc_exit);