summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle K <kylek389@gmail.com>2012-12-24 12:53:20 -0600
committerKyle Kaminski <kyle@kkaminsk.com>2012-12-24 12:53:20 -0600
commit0d9aff9bd305d18625c322a1a891aba278049862 (patch)
tree274aa52bf311107232488fb3f924cef316cfcb28
parentf0531d88e958b5fa77f8dc9bb34e697e872aeba9 (diff)
downloadkernelhello-0d9aff9bd305d18625c322a1a891aba278049862.tar.gz
kernelhello-0d9aff9bd305d18625c322a1a891aba278049862.tar.bz2
kernelhello-0d9aff9bd305d18625c322a1a891aba278049862.zip
spawn char device at /dev/, implement read
-rw-r--r--Makefile11
-rw-r--r--debug.c22
-rw-r--r--debug.h8
-rwxr-xr-xhello_load.sh (renamed from load.sh)2
-rw-r--r--main.c149
-rw-r--r--main.h28
6 files changed, 181 insertions, 39 deletions
diff --git a/Makefile b/Makefile
index 4104b64..4b897db 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,7 @@
-#ccflags-y += -g
+# causes weird file size, smaller than stripped?
+ifeq ($(DEBUG),)
+ ccflags-y += -g
+endif
# Makfile assignments:
# := value at right is expanded and assigned at declaration time
@@ -13,11 +16,13 @@ hello-y += main.o debug.o
# .ko module to be created
obj-m := hello.o
+KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+
# '-C' changes the dir
# '-M' causes the the kernel's toplevel Makefile to move back into this dir
# before trying to build 'modules' target
all:
- make -C /lib/modules/$(shell uname -r)/build KCPPFLAGS="-I$(CURDIR)" M=$(PWD) modules
+ make -C $(KERNELDIR) KCPPFLAGS="-I$(CURDIR)" M=$(PWD) modules
clean:
- make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
+ make -C $(KERNELDIR) M=$(PWD) clean
diff --git a/debug.c b/debug.c
index 40ee10c..5c746d1 100644
--- a/debug.c
+++ b/debug.c
@@ -10,6 +10,8 @@
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/uaccess.h>
+
#include <debug.h>
#include <main.h>
@@ -24,7 +26,7 @@ char kernel_buff[BUFF_LEN] = {'f','o','o','b','a','r','\0'};
int fileprv = 1; /* hmm */
/* struct file, an abstract open file, not on disk, which would be a an inode */
-static ssize_t debugfs_read(struct file *fp, char __user /* userspace */ *ubuff, size_t c, loff_t *pos)
+static ssize_t hello_hello_debugfs_read(struct file *fp, char __user /* userspace */ *ubuff, size_t c, loff_t *pos)
{
/**
* simple_read_from_buffer - copy data from the buffer to user space
@@ -43,7 +45,7 @@ static ssize_t debugfs_read(struct file *fp, char __user /* userspace */ *ubuff,
return simple_read_from_buffer(ubuff, c, pos, kernel_buff, BUFF_LEN);
}
-static ssize_t debugfs_write(struct file *fp, const char __user *ubuff, size_t c, loff_t *pos)
+static ssize_t hello_debugfs_write(struct file *fp, const char __user *ubuff, size_t c, loff_t *pos)
{
/**
* simple_write_to_buffer - copy data from user space to the buffer
@@ -64,14 +66,20 @@ static ssize_t debugfs_write(struct file *fp, const char __user *ubuff, size_t c
return (-EINVAL);
return simple_write_to_buffer(kernel_buff, BUFF_LEN, pos, ubuff, c);
+
+#if 0
+ printk(KERN_INFO "count %lu, offset %u", c, *pos);
+ copy_from_user(kernel_buff + *pos, ubuff, c);
+ return c;
+#endif
}
-int debug_init(struct dentry **dir, struct dentry **file)
+int hello_debugfs_init(struct dentry **dir, struct dentry **file)
{
/* func ptrs that perform various operations on the device, in this case char device, well not even */
struct file_operations fops = {
- .read = debugfs_read,
- .write = debugfs_write
+ .read = hello_hello_debugfs_read,
+ .write = hello_debugfs_write
};
/* omitted fields are initialized to NULL */
@@ -82,12 +90,12 @@ int debug_init(struct dentry **dir, struct dentry **file)
/* regular file, read by user/group/other, write by user */
*file = debugfs_create_file("magic", S_IFREG | S_IRUGO | S_IWUSR, *dir, &fileprv, &fops);
if (!*file)
- printk("debugfs: error creating file\n");
+ printk(KERN_WARNING "[hello] debugfs: error creating file\n");
return 0;
}
-int debug_destroy(struct dentry *dir, struct dentry *file)
+int hello_debugfs_destroy(struct dentry *dir, struct dentry *file)
{
if (file)
debugfs_remove(file);
diff --git a/debug.h b/debug.h
index 1b973bf..b82662a 100644
--- a/debug.h
+++ b/debug.h
@@ -1,10 +1,10 @@
-#ifndef _DEBUG_H_
-#define _DEBUG_H_
+#ifndef _HELLODEBUG_H_
+#define _HELLODEBUG_H_
struct dentry;
-int debug_init(struct dentry **, struct dentry **);
-int debug_destroy(struct dentry *, struct dentry *);
+int hello_debugfs_init(struct dentry **, struct dentry **);
+int hello_debugfs_destroy(struct dentry *, struct dentry *);
#endif
diff --git a/load.sh b/hello_load.sh
index 41266bc..fc54ab6 100755
--- a/load.sh
+++ b/hello_load.sh
@@ -1,7 +1,7 @@
#!/bin/bash
MODULE=hello
-DEVICE=skull
+DEVICE=helloc
MODE=664
# invoke insmod with all arguments and use a pathname
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);
diff --git a/main.h b/main.h
index 229e387..e437853 100644
--- a/main.h
+++ b/main.h
@@ -1,7 +1,29 @@
-#ifndef _MAIN_H_
-#define _MAIN_H_
+#ifndef _HELLOMAIN_H_
+#define _HELLOMAIN_H_
-extern char *debugmsg;
+#include <linux/cdev.h>
+
+#ifndef HELLO_MAJOR
+#define HELLO_MAJOR 0 /* let kernel choose, unless user really defined it */
+#endif
+
+#define HELLO_KERNEL_BUFF_LEN 1024
+
+extern int hello_major;
+extern int hello_minor;
+
+extern char *magicstr;
+
+struct hello_dev {
+ dev_t devnum;
+ struct cdev cdev; /* char device */
+ /* for r/w operations */
+ char hello_buffer[HELLO_KERNEL_BUFF_LEN];
+ size_t buff_index;
+};
+
+/* function prototypes */
+int hello_debugfs(void);
#endif