From 060ffddcf15986572ef87d2ef618a8f2359b0d13 Mon Sep 17 00:00:00 2001
From: Lauchmelder <robert.altner11@gmail.com>
Date: Fri, 10 Jun 2022 22:02:28 +0200
Subject: [PATCH] added checks to pin configuration

---
 Makefile     |  2 +-
 src/checks.c | 37 +++++++++++++++++++++++++++++++++++++
 src/checks.h | 11 +++++++++++
 src/lcd.c    | 41 ++++++++++++++++++++++++++++++-----------
 src/lcd.h    |  4 +++-
 5 files changed, 82 insertions(+), 13 deletions(-)
 create mode 100644 src/checks.c
 create mode 100644 src/checks.h

diff --git a/Makefile b/Makefile
index 75e147e..fd7cc99 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 obj-m = lcd.o
-lcd-y = src/lcd.o src/io.o
+lcd-y = src/lcd.o src/io.o src/checks.o
 
 KVERSION = $(shell uname -r)
 
diff --git a/src/checks.c b/src/checks.c
new file mode 100644
index 0000000..3267c70
--- /dev/null
+++ b/src/checks.c
@@ -0,0 +1,37 @@
+#include "checks.h"
+
+#include <linux/module.h>
+#include "lcd.h"
+
+
+#define LCD_MIN_GPIO 2
+#define LCD_MAX_GPIO 27
+
+static int sub_pin = LCD_MIN_GPIO;
+
+int lcd_is_valid_gpio(int pin)
+{
+    return (LCD_MIN_GPIO <= pin && pin <= LCD_MAX_GPIO);
+}
+
+int lcd_assign_gpio(int pin)
+{
+    if(lcd_is_valid_gpio(pin))
+        return pin;
+
+
+    printk(KERN_WARNING "%s: GPIO pin %d is invalid. Using %d instead\n", THIS_MODULE->name, pin, sub_pin);
+    return sub_pin++;
+}
+
+int lcd_check_duplicates(const int* used_pins)
+{
+    int i, j;
+
+    for(i = 0; i < 7; i++)
+        for(j = i + 1; j < 8; j++)
+            if(used_pins[i] == used_pins[j])
+                return -EFAULT;
+
+    return 0;
+}
\ No newline at end of file
diff --git a/src/checks.h b/src/checks.h
new file mode 100644
index 0000000..7d06cfe
--- /dev/null
+++ b/src/checks.h
@@ -0,0 +1,11 @@
+#ifndef _LCD_CHECKS_H
+#define _LCD_CHECKS_H
+
+struct lcd_gpio_config;
+
+int lcd_is_valid_gpio(int pin);
+int lcd_assign_gpio(int pin);
+
+int lcd_check_duplicates(const int* config);
+
+#endif
\ No newline at end of file
diff --git a/src/lcd.c b/src/lcd.c
index 70a93c2..38ad89b 100644
--- a/src/lcd.c
+++ b/src/lcd.c
@@ -5,6 +5,7 @@
 #include <linux/gpio.h>
 
 #include "lcd.h"
+#include "checks.h" 
 
 MODULE_LICENSE("GPL");
 
@@ -85,7 +86,10 @@ static int __init lcd_init_module(void)
 
     result = lcd_init_gpio();
     if(result < 0)
+    {
+        printk(KERN_ERR "%s: Failed to configure GPIO pins\n", THIS_MODULE->name);
         return result;
+    }
 
     printk(KERN_INFO "%s: Module loaded!\n", THIS_MODULE->name);
     return result;
@@ -120,26 +124,41 @@ static int __init lcd_init_cdev(void)
 
 static int  __init lcd_init_gpio(void)
 {
-    lcd_validate_gpio();
+    int result, i;
+    
+    result = lcd_validate_gpio();
+    
+    if(result < 0)
+        return result;
+    
+    for(i = 0; i < 8; i++)
+        gpio_direction_output(lcddev.used_pins[i], 0);
 
-    // gpio_direction_output(lcddev.gpio, 0);
-    return 0;
+    return result;
 }
 
 static int __init lcd_validate_gpio(void)
 {
+    int result = 0;
     struct lcd_gpio_config* config = &lcddev.config;
+    lcddev.used_pins = (int*)config;
 
-    config->power  = pin_power;
-    config->rs     = pin_rs;
-    config->rw     = pin_rw;
-    config->enable = pin_enable;
+    config->power   = lcd_assign_gpio(pin_power);
+    config->rs      = lcd_assign_gpio(pin_rs);
+    config->rw      = lcd_assign_gpio(pin_rw);
+    config->enable  = lcd_assign_gpio(pin_enable);
 
-    memcpy(config->data, pin_data, 4 * sizeof(int));
+    config->data[0] = lcd_assign_gpio(pin_data[0]);
+    config->data[1] = lcd_assign_gpio(pin_data[1]);
+    config->data[2] = lcd_assign_gpio(pin_data[2]);
+    config->data[3] = lcd_assign_gpio(pin_data[3]);
 
-    // TODO: Check if pin configuration is valid
-    //  - no duplicate pins?
-    //  - all pin numbers in range?
+    result = lcd_check_duplicates(lcddev.used_pins);
+    if(result < 0)
+    {
+        printk(KERN_ERR "%s: Invalid pin configuration (duplicate pin usage)\n", THIS_MODULE->name);
+        return result;
+    }
 
     return 0;
 }
diff --git a/src/lcd.h b/src/lcd.h
index 5b5f58b..2467f1e 100644
--- a/src/lcd.h
+++ b/src/lcd.h
@@ -3,6 +3,7 @@
 
 #include <linux/module.h>
 #include <linux/cdev.h>
+#include <linux/semaphore.h>
 
 #define LCD_MAJOR 0
 #define LCD_MINOR 0
@@ -18,7 +19,7 @@ struct lcd_gpio_config
     int power;
     int rs, rw, enable;
     int data[4];
-};
+} __attribute__((packed));
 
 struct lcd_dev
 {
@@ -26,6 +27,7 @@ struct lcd_dev
     struct cdev dev;
     struct semaphore sem;
     struct lcd_gpio_config config;
+    int* used_pins;
 };
 
 #endif
\ No newline at end of file