#include #include #include #include #include #include /* used for kmalloc */ #include #include #include /* copy_*_user */ #include #include /* major and minor numbers for character device under /dev/ */ int hello_major = HELLO_MAJOR; int hello_minor = 0; 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 ret = 0; dev_t devnum = 0; char *hellomsg_copy = NULL; 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 */ 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; } /* 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(MKDEV(hello_major, hello_minor), 1); hello_debugfs_destroy(debugfs_dir, debugfs_file); printk(KERN_INFO "[hello] module removed\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");