summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--sad_mod.c (renamed from mod_add.c)63
2 files changed, 44 insertions, 25 deletions
diff --git a/Makefile b/Makefile
index 6537a22..74f5f69 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,12 @@
-obj-m += mod_add.o
+obj-m += sad_mod.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
ins:
- sudo insmod mod_add.ko
+ sudo insmod sad_mod.ko
rm:
- sudo rmmod mod_add
+ sudo rmmod sad_mod
sudo rm -f dev
nod: all ins
diff --git a/mod_add.c b/sad_mod.c
index 096baaf..2950b35 100644
--- a/mod_add.c
+++ b/sad_mod.c
@@ -20,8 +20,10 @@ static dev_t dev;
static struct cdev *cdev;
static int device_open_count = 0;
+#define LL_MAX_LEN 20
+
struct sad_buf {
- char *buf;
+ char buf[LL_MAX_LEN + 1];
size_t size;
struct semaphore lock;
} *buf;
@@ -34,6 +36,41 @@ static struct file_operations sad_fops = {
.release = sad_release
};
+static ssize_t sad_parse(const char __user *user_buf, size_t len) {
+ char *in_buf;
+ unsigned long uncopied;
+ long long lhs, rhs, res;
+ char op;
+ int ret;
+
+ in_buf = kmalloc(len, GFP_KERNEL);
+ if (!in_buf)
+ return -ENOMEM;
+
+ uncopied = copy_from_user(in_buf, user_buf, len);
+ if (uncopied > 0) {
+ kfree(in_buf);
+ return -EFAULT;
+ }
+
+ sscanf(in_buf, "%lld%c%lld", &lhs, &op, &rhs);
+
+ switch (op) {
+ case '+': res = lhs + rhs; break;
+ case '-': res = lhs - rhs; break;
+ case '*': res = lhs * rhs; break;
+ case '/': res = lhs / rhs; break;
+ case '%': res = lhs & rhs; break;
+ default:
+ kfree(in_buf);
+ return -EPROTO;
+ }
+
+ ret = snprintf(buf->buf, LL_MAX_LEN + 1, "%lld", res);
+ buf->size = ret;
+
+ return len; /* need to indicate, that all data was processed */
+}
static ssize_t sad_read(struct file *flip, char __user *user_buf, size_t len, loff_t *offset) {
size_t bytes_left, read_size, uncopied;
@@ -53,34 +90,18 @@ static ssize_t sad_read(struct file *flip, char __user *user_buf, size_t len, lo
*offset += read_size - uncopied;
up(&buf->lock);
-
return read_size - uncopied;
}
static ssize_t sad_write(struct file *flip, const char __user *user_buf, size_t len, loff_t *offset) {
- size_t uncopied;
+ ssize_t ret;
if (down_interruptible(&buf->lock))
return -ERESTARTSYS;
- if (buf->buf)
- kfree(buf->buf);
-
- buf->buf = kmalloc(len, GFP_KERNEL);
- if (!buf->buf) {
- up(&buf->lock);
- return -ENOMEM;
- }
-
- buf->size = len;
-
- *offset = 0;
-
- uncopied = copy_from_user(buf->buf, user_buf, len);
-
+ ret = sad_parse(user_buf, len);
up(&buf->lock);
-
- return len - uncopied;
+ return ret;
}
static int sad_open(struct inode *inode, struct file *file) {
@@ -130,8 +151,6 @@ static int __init sad_init(void) {
}
static void __exit sad_exit(void) {
cdev_del(cdev);
- if (buf->buf)
- kfree(buf->buf);
kfree(buf);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "okay, bye\n");