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);  | 
