summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle K <kylek389@gmail.com>2012-12-25 21:51:47 -0600
committerKyle Kaminski <kyle@kkaminsk.com>2012-12-25 21:51:47 -0600
commit3207df143a96c86e406c3c9dc1990a0642b9f98e (patch)
tree342c1d3db38db0ca4e23861439d35293543c2a28
parent80de1a348c74768af790d1821097e5a386af53a9 (diff)
downloadkernelhello-3207df143a96c86e406c3c9dc1990a0642b9f98e.tar.gz
kernelhello-3207df143a96c86e406c3c9dc1990a0642b9f98e.tar.bz2
kernelhello-3207df143a96c86e406c3c9dc1990a0642b9f98e.zip
implement write, use semaphores
-rw-r--r--Makefile5
-rw-r--r--debug.c3
-rw-r--r--main.c70
-rw-r--r--main.h2
4 files changed, 65 insertions, 15 deletions
diff --git a/Makefile b/Makefile
index 4b897db..eba35e6 100644
--- a/Makefile
+++ b/Makefile
@@ -24,5 +24,8 @@ KERNELDIR ?= /lib/modules/$(shell uname -r)/build
all:
make -C $(KERNELDIR) KCPPFLAGS="-I$(CURDIR)" M=$(PWD) modules
-clean:
+kclean:
make -C $(KERNELDIR) M=$(PWD) clean
+
+clean:
+ @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module.symvers modules.order
diff --git a/debug.c b/debug.c
index 5c746d1..ab0add8 100644
--- a/debug.c
+++ b/debug.c
@@ -1,5 +1,4 @@
-/*
- * debug.c
+/* debug.c
*
* utilize debufs
* FIXME: R/W from /sys/kernel/debug/hello/magic doesn't work
diff --git a/main.c b/main.c
index d791d62..fcd5732 100644
--- a/main.c
+++ b/main.c
@@ -1,3 +1,23 @@
+/* main.c
+ *
+ * r/w /dev/helloc0 character device
+ *
+ * to insert module and call mknod run:
+ * # ./hello_load.sh
+ *
+ * to remove module and cleanup run:
+ * # ./hello_unload.sh
+ *
+ * # cat /dev/helloc0
+ * # echo -n foobar > /dev/helloc0
+ *
+ * notes:
+ * - most notes are handwritten in my book, Device Drivers 3rd
+ * - ssize_t is an int, size_t is unsigned int, be careful
+ * - compile kernel with frame pointers to get better stack readout in case of an oops
+ *
+ */
+
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
@@ -37,31 +57,56 @@ static int hello_create_debugfs(void)
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;
+ ssize_t ret = 0; /* end of file, also in case of out of bound */
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ if (*f_pos >= HELLO_KERNEL_BUFF_LEN)
+ goto out; /* out of bound read */
if (*f_pos + count > HELLO_KERNEL_BUFF_LEN)
- count = HELLO_KERNEL_BUFF_LEN - *f_pos;
+ count = HELLO_KERNEL_BUFF_LEN - *f_pos; /* truncate the read */
- if (count > 0)
+ if (copy_to_user(buff, dev->hello_buffer + *f_pos, count)) /* write to userspace memory */
{
- copy_to_user(buff, dev->hello_buffer + *f_pos, count);
- *f_pos += count; /* yes we have to keep track */
- return count;
+ ret = -EFAULT;
+ goto out;
}
- return 0; /* end of file, also in case of out of bound */
+ *f_pos += count; /* yes we have to keep track */
+ dev->buff_index += count;
+ ret= count;
+
+ out:
+ up(&dev->sem);
+ return ret;
}
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;
+ ssize_t ret = 0;
-#if 0
- /* we will truncate hello_buffer */
- copy_from_user(dev->hello_buffer + *f_pos, buff, count);
- return count;
-#endif
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
- return 0;
+ if (count > HELLO_KERNEL_BUFF_LEN)
+ goto out;
+
+ if (*f_pos + count > HELLO_KERNEL_BUFF_LEN)
+ count = HELLO_KERNEL_BUFF_LEN - *f_pos;
+
+ if (copy_from_user(dev->hello_buffer + *f_pos, buff, count))
+ {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = count;
+
+ out:
+ up(&dev->sem);
+ return ret;
}
/* there's a count in filp that gets incremented every time our char device gets opened, but note that
@@ -127,6 +172,7 @@ static int __init hello_init(void)
}
memset(hello_device, 0, sizeof(struct hello_dev));
hello_device->devnum = devnum;
+ sema_init(&hello_device->sem, 1);
strcpy(hello_device->hello_buffer, "write to me\n");
/* setup char_dev structure */
diff --git a/main.h b/main.h
index e437853..db38aa8 100644
--- a/main.h
+++ b/main.h
@@ -16,7 +16,9 @@ extern char *magicstr;
struct hello_dev {
dev_t devnum;
+ struct semaphore sem;
struct cdev cdev; /* char device */
+
/* for r/w operations */
char hello_buffer[HELLO_KERNEL_BUFF_LEN];
size_t buff_index;