diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 149 |
1 files changed, 128 insertions, 21 deletions
@@ -3,48 +3,155 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> -/* used for kmalloc */ -#include <linux/slab.h> +#include <linux/slab.h> /* used for kmalloc */ #include <linux/fs.h> +#include <linux/cdev.h> +#include <asm/uaccess.h> /* copy_*_user */ +#include <main.h> #include <debug.h> -char *debugmsg = "Tesla coil is a hi freq transformer"; -struct dentry *debug_dir = NULL; -struct dentry *debug_file = NULL; +/* major and minor numbers for character device under /dev/ */ +int hello_major = HELLO_MAJOR; +int hello_minor = 0; -dev_t devnum; +char *magicstr = "Tesla coil is a hi freq transformer"; +char *hellomsg = "photon is the energy carrier particle for EM waves within light spectrum"; +struct dentry *debugfs_dir = NULL; +struct dentry *debugfs_file = NULL; + +struct hello_dev *hello_device; + +static int hello_create_debugfs(void) +{ + int ret = 0; + + /* modifies passed in ptrs */ + ret = hello_debugfs_init(&debugfs_dir, &debugfs_file); + if (ret) + printk(KERN_WARNING "[hello] debugfs might not have been mounted\n"); + + return ret; +} + +static ssize_t hello_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos) +{ + struct hello_dev *dev = filp->private_data; + + if (*f_pos + count > HELLO_KERNEL_BUFF_LEN) + count = HELLO_KERNEL_BUFF_LEN - *f_pos; + + if (count > 0) + { + copy_to_user(buff, dev->hello_buffer + *f_pos, count); + *f_pos += count; /* yes we have to keep track */ + return count; + } + + return 0; /* end of file, also in case of out of bound */ +} + +static ssize_t hello_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos) +{ + struct hello_dev *dev = filp->private_data; + +#if 0 + /* we will truncate hello_buffer */ + copy_from_user(dev->hello_buffer + *f_pos, buff, count); + return count; +#endif + + return 0; +} + +/* there's a count in filp that gets incremented every time our char device gets opened, but note that + * this function does not get called multiple times, instead copies are made, think fork(), or just simple ptr? + */ +static int hello_open(struct inode *inode, struct file *filp) +{ + struct hello_dev *dev; + dev = container_of(inode->i_cdev, struct hello_dev, cdev); + filp->private_data = dev; /* our only chance to do that is here in open(), place to save our dev struct */ + + return 0; +} + +static int hello_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +struct file_operations hello_fops = { + .owner = THIS_MODULE, + .read = hello_read, + .write = hello_write, + .open = hello_open, + .release = hello_release +}; /* __init is a hint that the func is only used at initialization time, then module * loader drops the function after module is loaded making its memory available for other uses */ static int __init hello_init(void) { - int err = 0; - char *msg = (char *) kmalloc_array(128, sizeof(char), GFP_KERNEL /* kernel ram */); + int ret = 0; + dev_t devnum = 0; + char *hellomsg_copy = NULL; - printk("module named hello inserted\n"); - strcpy(msg, "photon is the energy carrier particle for EM waves within light spectrum"); - printk("%s\n", msg); - kfree(msg); + printk("[hello] module inserted\n"); /* little hello msg below */ + hellomsg_copy = (char *) kmalloc_array(128, sizeof(char), GFP_KERNEL /* kernel ram */); + strcpy(hellomsg_copy, hellomsg); + printk(KERN_INFO "%s\n", hellomsg_copy); + kfree(hellomsg_copy); /* device numbers, major will be picked for us */ - err = alloc_chrdev_region(&devnum, 0 /* first minor */, 1, "skull"); - printk("major: %d, minor: %d\n", MAJOR(devnum), MINOR(devnum)); + if (hello_major) { + devnum = MKDEV(hello_major, hello_minor); + ret = register_chrdev_region(devnum, 1, "helloc"); /* last param name will be reflected in /proc/devices */ + } else { + ret = alloc_chrdev_region(&devnum, 0 /* first minor */, 1, "helloc"); + hello_major = MAJOR(devnum); + hello_minor = MINOR(devnum); + printk(KERN_INFO "[hello] major: %d, minor: %d\n", hello_major, hello_minor); + } + if (ret < 0) { + printk(KERN_WARNING "[hello] can't get the major %d number\n", hello_major); + return ret; + } - /* modifies passed in ptrs */ - err = debug_init(&debug_dir, &debug_file); - if (err) - printk("debugfs might not have been mounted\n"); + /* allocate hello device and set it up */ + hello_device = kmalloc(sizeof(struct hello_dev), GFP_KERNEL); + if (!hello_device) { + ret = -ENOMEM; + goto fail; + } + memset(hello_device, 0, sizeof(struct hello_dev)); + hello_device->devnum = devnum; + strcpy(hello_device->hello_buffer, "write to me\n"); + + /* setup char_dev structure */ + cdev_init(&hello_device->cdev, &hello_fops); + hello_device->cdev.owner = THIS_MODULE; + if ((ret = cdev_add(&hello_device->cdev, devnum, 1)) < 0) + { + printk(KERN_WARNING "[hello] failed to add char device\n"); + goto fail; + } + + hello_create_debugfs(); return 0; + + fail: + unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1); + return ret; } static void __exit hello_exit(void) { - unregister_chrdev_region(devnum, 1); - debug_destroy(debug_dir, debug_file); - printk("module named hello removed\n"); + unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1); + hello_debugfs_destroy(debugfs_dir, debugfs_file); + printk(KERN_INFO "[hello] module removed\n"); } module_init(hello_init); |