#include <linux/module.h>
+/* Needed for struct file_operations and others */
#include <linux/fs.h>
+/* Needed for struct cdev */
#include <linux/cdev.h>
+/* Needed for copying to/from user space */
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A hello world char device");
MODULE_VERSION("1.0.0");
+/* Message buffer we send to upstream */
static char helloc_message[] = "hello, world\n";
+/* our read function writes our message to the user buffer */
static ssize_t helloc_read(struct file *filp, char __user *buf, size_t len,
loff_t *pos)
{
int r;
+ /* do not read pass through the size of the message */
if (*pos >= sizeof(helloc_message))
+ /* return end of file */
return 0;
+ /* if len is bigger than the rest of the message, clamp it */
if (len > sizeof(helloc_message) - *pos)
len = sizeof(helloc_message) - *pos;
+ /* copy message to user space and return error if it fails */
r = copy_to_user(buf, helloc_message + *pos, len);
if (r)
return -EFAULT;
+ /* update the file position */
*pos += len;
return len;
}
+/* we only implement read */
static struct file_operations helloc_fops = {
.owner = THIS_MODULE,
.read = helloc_read,
};
+/* the device number and the char device struct */
static dev_t dev;
static struct cdev *cdev;
static int __init helloc_init(void)
{
int r;
+ /* allocate any major number with only one minor */
r = alloc_chrdev_region(&dev, 0, 1, "helloc");
if (r)
goto out_region;
r = -ENOMEM;
+ /* print the major number allocated so we can create our device node */
printk(KERN_INFO "Allocated major number %d\n", MAJOR(dev));
+ /* allocate the character device struct */
cdev = cdev_alloc();
if (!cdev)
goto out_alloc;
+ /* set the module owner and the file operations of our chardev */
cdev->owner = THIS_MODULE;
cdev->ops = &helloc_fops;
+ /* register the chardev to the system */
r = cdev_add(cdev, dev, 1);
if (r)
goto out_add;
return 0;
out_add:
- kobject_put(&cdev->kobj);
+ /* release memory allocated to the cdev device */
+ kfree(cdev);
out_alloc:
+ /* release the device number allocated */
unregister_chrdev_region(dev, 1);
out_region:
return r;
static void __exit helloc_exit(void)
{
+ /* remove the chardev from the system */
cdev_del(cdev);
+ /* release the device number allocated */
unregister_chrdev_region(dev, 1);
}