summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c149
1 files changed, 128 insertions, 21 deletions
diff --git a/main.c b/main.c
index b6975a4..d791d62 100644
--- a/main.c
+++ b/main.c
@@ -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);