From 7fd5e0fffcf3f9e9a881b933114826a353a480c6 Mon Sep 17 00:00:00 2001 From: Lauchmelder Date: Tue, 7 Jun 2022 18:44:32 +0200 Subject: [PATCH] added write functionality --- src/io.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++----- src/lcd.c | 6 ++++- src/lcd.h | 4 ++-- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/io.c b/src/io.c index 4f2704b..8920288 100644 --- a/src/io.c +++ b/src/io.c @@ -5,6 +5,8 @@ #include #include "lcd.h" +static bool advance_ptr(const char* base, ssize_t size, char** ptr); + loff_t lcd_llseek(struct file* filp, loff_t where, int whence) { return 0; @@ -17,7 +19,54 @@ ssize_t lcd_read(struct file* filp, char __user* buf, size_t count, loff_t* off) ssize_t lcd_write(struct file* filp, const char __user* buf, size_t count, loff_t* off) { - return count; + struct lcd_dev* dev = (struct lcd_dev*)filp->private_data; + char* kern_buf = NULL; + char* cmd_start = NULL; + char* cmd_end = NULL; + ssize_t retval = 0; + + if(down_interruptible(&dev->sem)) + return retval; + + kern_buf = (char*)kmalloc(count, GFP_KERNEL); + if(kern_buf == NULL) + { + printk(KERN_ERR "%s: Failed to allocate buffer (%d bytes), aborting write.\n", THIS_MODULE->name, count); + retval = -ENOMEM; + goto out; + } + + if(copy_from_user(kern_buf, buf, count)) + { + printk(KERN_ERR "%s: Failed to copy data from user, aborting write.\n", THIS_MODULE->name); + retval = -EFAULT; + kfree(kern_buf); + goto out; + } + + cmd_start = kern_buf; + cmd_end = kern_buf; + + while(advance_ptr(kern_buf, count, &cmd_end)) + { + *cmd_end = '\0'; + + if(strcmp(cmd_start, "0") == 0) + gpio_set_value(dev->gpio, 0); + else if(strcmp(cmd_start, "1") == 0) + gpio_set_value(dev->gpio, 1); + else + printk(KERN_WARNING "%s: Unrecognized command \"%s\"\n", THIS_MODULE->name, cmd_start); + + cmd_start = cmd_end + 1; + } + + retval = count; + kfree(kern_buf); + +out: + up(&dev->sem); + return retval; } long lcd_ioctl(struct file* filp, unsigned int cmd, unsigned long arg) @@ -31,9 +80,7 @@ int lcd_open(struct inode* inode, struct file* filp) dev = container_of(inode->i_cdev, struct lcd_dev, dev); filp->private_data = (void*)dev; - gpio_set_value(dev->gpio, 1); - - printk(KERN_INFO "%s: Opened device\n", THIS_MODULE->name); + printk(KERN_DEBUG "%s: Opened device\n", THIS_MODULE->name); return 0; } @@ -41,9 +88,17 @@ int lcd_release(struct inode* inode, struct file* filp) { struct lcd_dev* dev; dev = (struct lcd_dev*)filp->private_data; - gpio_set_value(dev->gpio, 0); - printk(KERN_INFO "%s: Released device\n", THIS_MODULE->name); + + printk(KERN_DEBUG "%s: Released device\n", THIS_MODULE->name); return 0; } +static bool advance_ptr(const char* base, ssize_t size, char** ptr) +{ + while(*ptr - base < size && **ptr != '\n') + (*ptr)++; + + return *ptr - base < size; +} + #endif \ No newline at end of file diff --git a/src/lcd.c b/src/lcd.c index c60b48f..74fab78 100644 --- a/src/lcd.c +++ b/src/lcd.c @@ -10,9 +10,11 @@ MODULE_LICENSE("GPL"); int lcd_major = LCD_MAJOR; int lcd_minor = LCD_MINOR; +int lcd_gpio = LCD_GPIO; module_param(lcd_major, int, S_IRUGO); module_param(lcd_minor, int, S_IRUGO); +module_param(lcd_gpio, int, S_IRUGO); static struct lcd_dev lcddev = { 0 }; static int __init lcd_init_cdev(void); @@ -60,6 +62,8 @@ static int __init lcd_init_module(void) return result; } + sema_init(&lcddev.sem, 1); + result = lcd_init_cdev(); if(result < 0) return result; @@ -113,5 +117,5 @@ static int __init lcd_init_gpio(void) static void __exit lcd_exit_gpio(void) { - + } \ No newline at end of file diff --git a/src/lcd.h b/src/lcd.h index 4234690..f749317 100644 --- a/src/lcd.h +++ b/src/lcd.h @@ -7,13 +7,13 @@ #define LCD_MAJOR 0 #define LCD_MINOR 0 -extern int lcd_major; -extern int lcd_minor; +#define LCD_GPIO 18 struct lcd_dev { dev_t devno; struct cdev dev; + struct semaphore sem; int gpio; };