First character device.
[cascardo/kernel/samples/02.char/.git] / helloc.c
1 #include <linux/module.h>
2 #include <linux/fs.h>
3 #include <linux/cdev.h>
4 #include <asm/uaccess.h>
5
6 MODULE_LICENSE("GPL");
7 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>");
8 MODULE_DESCRIPTION("A hello world char device");
9 MODULE_VERSION("1.0.0");
10
11 static char helloc_message[] = "hello, world\n";
12
13 static ssize_t helloc_read(struct file *filp, char __user *buf, size_t len,
14                            loff_t *pos)
15 {
16         int r;
17         if (*pos >= sizeof(helloc_message))
18                 return 0;
19         if (len > sizeof(helloc_message) - *pos)
20                 len = sizeof(helloc_message) - *pos;
21         r = copy_to_user(buf, helloc_message + *pos, len);
22         if (r)
23                 return -EFAULT;
24         *pos += len;
25         return len;
26 }
27
28 static struct file_operations helloc_fops = {
29         .owner = THIS_MODULE,
30         .read = helloc_read,
31 };
32
33 static dev_t dev;
34 static struct cdev *cdev;
35
36 static int __init helloc_init(void)
37 {
38         int r;
39         r = alloc_chrdev_region(&dev, 0, 1, "helloc");
40         if (r)
41                 goto out_region;
42         r = -ENOMEM;
43         printk(KERN_INFO "Allocated major number %d\n", MAJOR(dev));
44         cdev = cdev_alloc();
45         if (!cdev)
46                 goto out_alloc;
47         cdev->owner = THIS_MODULE;
48         cdev->ops = &helloc_fops;
49         r = cdev_add(cdev, dev, 1);
50         if (r)
51                 goto out_add;
52         return 0;
53 out_add:
54         kobject_put(&cdev->kobj);
55 out_alloc:
56         unregister_chrdev_region(dev, 1);
57 out_region:
58         return r;
59 }
60
61 static void __exit helloc_exit(void)
62 {
63         cdev_del(cdev);
64         unregister_chrdev_region(dev, 1);
65 }
66
67 module_init(helloc_init);
68 module_exit(helloc_exit);