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 +#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 #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 #include +#include #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