Browse Source

First commit of project

tdVincentB 5 years ago
commit
4c3f0eca57
14 changed files with 2207 additions and 0 deletions
  1. 21 0
      Makefile
  2. 79 0
      driver_pcal6416a.c
  3. 39 0
      driver_pcal6416a.h
  4. 78 0
      funkey_gpio_management.c
  5. 55 0
      funkey_gpio_mapping.conf
  6. 241 0
      gpio-utils.c
  7. 17 0
      gpio-utils.h
  8. 353 0
      gpio_mapping.c
  9. 25 0
      gpio_mapping.h
  10. 576 0
      keydefs.c
  11. 382 0
      read_conf_file.c
  12. 74 0
      read_conf_file.h
  13. 230 0
      uinput.c
  14. 37 0
      uinput.h

+ 21 - 0
Makefile

@@ -0,0 +1,21 @@
+TOOLS_CFLAGS	:= -Wstrict-prototypes -Wshadow -Wpointer-arith -Wcast-qual \
+		   -Wcast-align -Wwrite-strings -Wnested-externs -Winline \
+		   -W -Wundef -Wmissing-prototypes
+#
+# Programs
+#
+all:	funkey_gpio_management 
+
+funkey_gpio_management:  funkey_gpio_management.o gpio-utils.o uinput.o gpio_mapping.o read_conf_file.o keydefs.o driver_pcal6416a.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
+
+#
+# Objects
+#
+
+%.o: %.c
+	$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+
+clean:
+	rm *.o funkey_gpio_management 

+ 79 - 0
driver_pcal6416a.c

@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <linux/input.h>
+#include "read_conf_file.h"
+#include <assert.h>
+#include <linux/i2c-dev.h>
+#include "driver_pcal6416a.h"
+
+/****************************************************************
+ * Defines
+ ****************************************************************/
+#define DEBUG_PCAL6416A_PRINTF 			(0)
+
+#if (DEBUG_PCAL6416A_PRINTF)
+	#define DEBUG_PRINTF(...) printf(__VA_ARGS__);
+#else
+	#define DEBUG_PRINTF(...)
+#endif
+
+/****************************************************************
+ * Static variables
+ ****************************************************************/
+int fd_i2c_expander;
+char i2c0_sysfs_filename[] = "/dev/i2c-0";
+
+/****************************************************************
+ * Static functions
+ ****************************************************************/
+
+/****************************************************************
+ * Public functions
+ ****************************************************************/
+bool pcal6416a_init(void) {
+    if ((fd_i2c_expander = open(i2c0_sysfs_filename,O_RDWR)) < 0) {
+        printf("Failed to open the I2C bus %s", i2c0_sysfs_filename);
+        // ERROR HANDLING; you can check errno to see what went wrong 
+        return false;
+    }
+
+    if (ioctl(fd_i2c_expander,I2C_SLAVE,PCAL6416A_I2C_ADDR) < 0) {
+        printf("Failed to acquire bus access and/or talk to slave.\n");
+        // ERROR HANDLING; you can check errno to see what went wrong 
+        return false;
+    }
+
+    uint16_t val_enable_pullups = 0xffff;
+ 	i2c_smbus_write_word_data ( fd_i2c_expander , PCAL6416A_EN_PULLUPDOWN , val_enable_pullups );
+
+    uint16_t val_enable_interrupts = 0x0000;
+ 	i2c_smbus_write_word_data ( fd_i2c_expander , PCAL6416A_INT_MASK , val_enable_interrupts );
+
+ 	return true;
+}
+
+bool pcal6416a_deinit(void) {
+    // Close I2C open interface
+	close(fd_i2c_expander);
+ 	return true;
+}
+
+uint16_t pcal6416a_read_mask_interrupts(void){
+	uint16_t val = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INT_STATUS );
+ 	DEBUG_PRINTF("READ PCAL6416A_INT_STATUS :  0x%04X\n",val);
+ 	return val;
+}
+
+uint16_t pcal6416a_read_mask_active_GPIOs(void){
+	uint16_t val = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INPUT );
+	val = 0xFFFF-val;
+ 	DEBUG_PRINTF("READ PCAL6416A_INPUT (active GPIOs) :  0x%04X\n",val);
+ 	return val;
+}

+ 39 - 0
driver_pcal6416a.h

@@ -0,0 +1,39 @@
+#ifndef _DRIVER_PCAL6416A_H_
+#define _DRIVER_PCAL6416A_H_
+
+
+ /****************************************************************
+ * Includes
+ ****************************************************************/
+#include <stdbool.h>
+
+ /****************************************************************
+ * Defines
+ ****************************************************************/
+// Chip physical address
+#define PCAL6416A_I2C_ADDR			0x20
+
+// Chip registers adresses
+#define PCAL6416A_INPUT			0x00 /* Input port [RO] */
+#define PCAL6416A_DAT_OUT      		0x02 /* GPIO DATA OUT [R/W] */
+#define PCAL6416A_POLARITY     		0x04 /* Polarity Inversion port [R/W] */
+#define PCAL6416A_CONFIG       		0x06 /* Configuration port [R/W] */
+#define PCAL6416A_DRIVE0		0x40 /* Output drive strength Port0 [R/W] */
+#define PCAL6416A_DRIVE1		0x42 /* Output drive strength Port1 [R/W] */
+#define PCAL6416A_INPUT_LATCH		0x44 /* Port0 Input latch [R/W] */
+#define PCAL6416A_EN_PULLUPDOWN		0x46 /* Port0 Pull-up/Pull-down enbl [R/W] */
+#define PCAL6416A_SEL_PULLUPDOWN	0x48 /* Port0 Pull-up/Pull-down slct [R/W] */
+#define PCAL6416A_INT_MASK		0x4A /* Interrupt mask [R/W] */ 
+#define PCAL6416A_INT_STATUS		0x4C /* Interrupt status [RO] */ 
+#define PCAL6416A_OUTPUT_CONFIG 	0x4F /* Output port config [R/W] */ 
+
+/****************************************************************
+ * Public functions
+ ****************************************************************/
+bool pcal6416a_init(void);
+bool pcal6416a_deinit(void);
+uint16_t pcal6416a_read_mask_interrupts(void);
+uint16_t pcal6416a_read_mask_active_GPIOs(void);
+
+
+#endif	//_DRIVER_PCAL6416A_H_

+ 78 - 0
funkey_gpio_management.c

@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>	// Defines signal-handling functions (i.e. trap Ctrl-C)
+#include <sys/select.h>
+#include "gpio-utils.h"
+#include <assert.h>
+#include "uinput.h"
+#include "gpio_mapping.h"
+#include "read_conf_file.h"
+
+ /****************************************************************
+ * Defines
+ ****************************************************************/
+ 
+/****************************************************************
+ * Global variables
+ ****************************************************************/
+int keepgoing = 1;	// Set to 0 when ctrl-c is pressed
+
+/****************************************************************
+ * signal_handler
+ ****************************************************************/
+void signal_handler(int sig);
+// Callback called when SIGINT is sent to the process (Ctrl-C)
+void signal_handler(int sig)
+{
+	printf( "Ctrl-C pressed, cleaning up and exiting..\n" );
+	keepgoing = 0;
+}
+
+/****************************************************************
+ * Local functions
+ ****************************************************************/
+
+
+/****************************************************************
+ * Main
+ ****************************************************************/
+int main(int argc, char **argv, char **envp)
+{
+	// Variables
+	STRUCT_MAPPED_GPIO * chained_list_mapping = NULL;
+	int nb_valid_gpios = 0;
+	int * gpio_pins = NULL;
+
+	// Set the signal callback for Ctrl-C
+	signal(SIGINT, signal_handler);
+	
+	// Init uinput device
+	init_uinput();
+
+	// Read Conf File: Get GPIO pins to declare and all valid pin mappings
+	get_mapping_from_conf_file(&chained_list_mapping, &nb_valid_gpios, &gpio_pins);
+
+	// Init GPIOs 
+	init_mapping_gpios(gpio_pins, nb_valid_gpios, chained_list_mapping);
+	
+	// Main Loop
+	while (keepgoing) {
+		listen_gpios_interrupts();
+	}
+
+	// De-Init GPIOs 
+	deinit_mapping_gpios();
+	
+	/*
+    * Give userspace some time to read the events before we destroy the
+    * device with UI_DEV_DESTOY.
+    */
+	close_uinput();
+    
+	return 0;
+}
+

+ 55 - 0
funkey_gpio_mapping.conf

@@ -0,0 +1,55 @@
+##################################
+# Funkey GPIO keymap config file #
+##################################
+# Format:
+#
+# 	- First all GPIO Pin numbers must be declared (integers separated by commas)
+#	  Example: 0,1,2,3,4,6,7,11,12,13,14,15
+#
+#	- Then the mapping can be done as follows (one line per mapping):
+#	  Pin_number[+Pin_number...], type_mapping, value, str_help_name_pin, str_help_fct_pin
+#	
+#	  args: * Pin_number is the pin number concerned by the maping, 
+#				add +Pin_number for multiple touch mapping (not limited in nb of pins)
+#			* type_mapping can be KEYBOARD or SHELL_COMMAND
+#			* value is :
+#					if type_mapping==KEYBOARD: the keycode from /usr/include/linux/input.h]
+#					if type_mapping==SHELL_COMMAND: the shell command to exec
+#			* str_help_name_pin is a sweet name for the pin (ex: PB5)
+#			* str_help_fct_pin is an help str to indicate the function of this mapping 
+
+
+
+###################################
+#	Pins declaration:
+0,1,2,3,4,6,7,11,12,13,14,15
+
+
+###################################
+#	Mapping:
+6, KEYBOARD, KEY_S, KEY_S, Start
+7, KEYBOARD, KEY_F, KEY_F, Fn
+3, KEYBOARD, KEY_U, KEY_U, Up
+4, KEYBOARD, KEY_L, KEY_L, Left
+1, KEYBOARD, KEY_D, KEY_D, Down
+0, KEYBOARD, KEY_R, KEY_R, Right
+15, KEYBOARD, KEY_N, KEY_N, R1
+2, KEYBOARD, KEY_M, KEY_M, L1
+12, KEYBOARD, KEY_B, KEY_B, B
+14, KEYBOARD, KEY_A, KEY_A, A
+13, KEYBOARD, KEY_X, KEY_X, X
+11, KEYBOARD, KEY_Y, KEY_Y, Y
+7+7, KEYBOARD, KEY_K, KEY_K, Select
+7+15, KEYBOARD, KEY_V, KEY_V, L2
+7+2, KEYBOARD, KEY_O, KEY_O, R2
+#7+3, SHELL_COMMAND, echo "Volume up", 6+3, Volume up
+#7+1, SHELL_COMMAND, echo "Volume down", 6+1, Volume down
+#7+0, SHELL_COMMAND, echo "Brightness up", 6+0, Brightness up
+#7+4, SHELL_COMMAND, echo "Brightness down", 6+4, Brightness down
+7+3, SHELL_COMMAND, /root/shell_cmds/start_gpsp.sh, 6+3, start gpsp
+7+1, SHELL_COMMAND, /root/shell_cmds/start_pcsx.sh, 6+1, start pcsx
+7+0, SHELL_COMMAND, /root/shell_cmds/start_psnes.sh, 6+0, start psnes
+7+4, SHELL_COMMAND, /root/shell_cmds/start_mednafen.sh, 6+4, start mednafen GBC
+7+11, SHELL_COMMAND, /root/shell_cmds/stop_all_emulators.sh, 6+4, stop all emulators
+
+

+ 241 - 0
gpio-utils.c

@@ -0,0 +1,241 @@
+/* Copyright (c) 2011, RidgeRun
+ * All rights reserved.
+ *
+From https://www.ridgerun.com/developer/wiki/index.php/Gpio-int-test.c
+
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the RidgeRun.
+ * 4. Neither the name of the RidgeRun nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gpio-utils.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+/****************************************************************
+ * gpio_export
+ ****************************************************************/
+int gpio_export(unsigned int gpio)
+{
+	int fd, len;
+	char buf[MAX_BUF];
+ 
+	fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/export");
+		return fd;
+	}
+ 
+	len = snprintf(buf, sizeof(buf), "%d", gpio);
+	write(fd, buf, len);
+	close(fd);
+ 
+	return 0;
+}
+
+/****************************************************************
+ * gpio_unexport
+ ****************************************************************/
+int gpio_unexport(unsigned int gpio)
+{
+	int fd, len;
+	char buf[MAX_BUF];
+ 
+	fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/export");
+		return fd;
+	}
+ 
+	len = snprintf(buf, sizeof(buf), "%d", gpio);
+	write(fd, buf, len);
+	close(fd);
+	return 0;
+}
+
+/****************************************************************
+ * gpio_set_dir
+ ****************************************************************/
+int gpio_set_dir(unsigned int gpio, const char* dir)
+{
+	int fd, len;
+	char buf[MAX_BUF];
+ 
+	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR  "/gpio%d/direction", gpio);
+ 
+	fd = open(buf, O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/direction");
+		return fd;
+	}
+
+	write(fd, dir, sizeof(dir)+1);
+
+	close(fd);
+	return 0;
+}
+
+/****************************************************************
+ * gpio_set_value
+ ****************************************************************/
+int gpio_set_value(unsigned int gpio, unsigned int value)
+{
+	int fd, len;
+	char buf[MAX_BUF];
+ 
+	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+ 
+	fd = open(buf, O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/set-value");
+		return fd;
+	}
+ 
+	if (value)
+		write(fd, "1", 2);
+	else
+		write(fd, "0", 2);
+ 
+	close(fd);
+	return 0;
+}
+
+/****************************************************************
+ * gpio_get_value
+ ****************************************************************/
+int gpio_get_value(unsigned int gpio, unsigned int *value)
+{
+	int fd, len;
+	char buf[MAX_BUF];
+	char ch;
+
+	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+ 
+	fd = open(buf, O_RDONLY);
+	if (fd < 0) {
+		perror("gpio/get-value");
+		return fd;
+	}
+ 
+	read(fd, &ch, 1);
+
+	if (ch != '0') {
+		*value = 1;
+	} else {
+		*value = 0;
+	}
+ 
+	close(fd);
+	return 0;
+}
+
+
+/****************************************************************
+ * gpio_set_edge
+ ****************************************************************/
+
+int gpio_set_edge(unsigned int gpio, const char *edge)
+{
+	int fd, len;
+	char buf[MAX_BUF];
+
+	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
+ 
+	fd = open(buf, O_WRONLY);
+	if (fd < 0) {
+		perror("gpio/set-edge");
+		return fd;
+	}
+ 
+	write(fd, edge, strlen(edge) + 1); 
+	close(fd);
+	return 0;
+}
+
+/****************************************************************
+ * gpio_fd_open
+ ****************************************************************/
+
+int gpio_fd_open(unsigned int gpio, unsigned int dir)
+{
+	int fd, len;
+	char buf[MAX_BUF];
+
+	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+ 
+	fd = open(buf, dir | O_NONBLOCK );
+	if (fd < 0) {
+		perror("gpio/fd_open");
+	}
+	return fd;
+}
+
+/****************************************************************
+ * gpio_fd_close
+ ****************************************************************/
+
+int gpio_fd_close(int fd)
+{
+	return close(fd);
+}
+
+/****************************************************************
+ * ain_get_value (from Mike McDonald)
+ * https://groups.google.com/forum/#!topic/beagleboard-ece497/SLJ5nQQ_GoU
+ ****************************************************************/
+int ain_get_value(unsigned int ain, unsigned int *value)
+{
+    int fd, len, bytesRead;
+    char buf[MAX_BUF];
+    char adc_in[ADC_BUF];
+
+    len = snprintf(buf, sizeof(buf), SYSFS_AIN_DIR "/AIN%d", ain);
+ 
+    fd = open(buf, O_RDONLY);
+    if (fd < 0) {
+        perror(buf);
+        return fd;
+    }
+    
+    // Read from the 
+    bytesRead = read(fd, adc_in, ADC_BUF);
+
+    // Turn the buffer value (a string) into an integer
+    if (bytesRead != -1) {
+        *value = atoi(adc_in);
+        adc_in[bytesRead] = (int)NULL;
+        lseek(fd, 0, SEEK_SET);
+    }
+
+    // Sleep for a little to ensure that we get good ADC values
+    usleep(1000);
+ 
+    close(fd);
+    return bytesRead;
+}
+

+ 17 - 0
gpio-utils.h

@@ -0,0 +1,17 @@
+
+#define SYSFS_GPIO_DIR "/sys/class/gpio"
+#define MAX_BUF 64
+
+int gpio_export(unsigned int gpio);
+int gpio_unexport(unsigned int gpio);
+int gpio_set_dir(unsigned int gpio, const char* dir);
+int gpio_set_value(unsigned int gpio, unsigned int value);
+int gpio_get_value(unsigned int gpio, unsigned int *value);
+int gpio_set_edge(unsigned int gpio, const char *edge);
+int gpio_fd_open(unsigned int gpio, unsigned int dir);
+int gpio_fd_close(int fd);
+
+// Analog in
+#define ADC_BUF 1024
+#define SYSFS_AIN_DIR "/sys/devices/ocp.2/helper.11"
+int ain_get_value(unsigned int ain, unsigned int *value);

+ 353 - 0
gpio_mapping.c

@@ -0,0 +1,353 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/select.h>
+#include <linux/input.h>
+#include "gpio_mapping.h"
+#include "driver_pcal6416a.h"
+
+/****************************************************************
+ * Defines
+ ****************************************************************/
+#define die(str, args...) do { \
+        perror(str); \
+        return(EXIT_FAILURE); \
+    } while(0)
+
+#define DEBUG_GPIO_PRINTF 			(0)
+#define ERROR_GPIO_PRINTF 			(1)
+
+#if (DEBUG_GPIO_PRINTF)
+#define GPIO_PRINTF(...) printf(__VA_ARGS__);
+#else
+#define GPIO_PRINTF(...)
+#endif
+
+#if (ERROR_GPIO_PRINTF)
+#define GPIO_ERROR_PRINTF(...) printf(__VA_ARGS__);
+#else
+#define GPIO_ERROR_PRINTF(...)
+#endif
+
+
+/****************************************************************
+ * Static variables
+ ****************************************************************/
+static int nb_mapped_gpios;
+static int * gpio_pins;
+STRUCT_MAPPED_GPIO * chained_list_mapping;
+static int max_fd = 0;
+static int gpio_fd_interrupt_i2c;
+static fd_set fds;
+static bool * mask_gpio_value;
+
+
+/****************************************************************
+ * Static functions
+ ****************************************************************/
+ /*****  Add a fd to fd_set, and update max_fd_nb  ******/
+static int safe_fd_set(int fd, fd_set* list_fds, int* max_fd_nb) {
+    assert(max_fd_nb != NULL);
+
+    FD_SET(fd, list_fds);
+    if (fd > *max_fd_nb) {
+        *max_fd_nb = fd;
+    }
+    return 0;
+}
+
+/*****  Clear fd from fds, update max fd if needed  *****/
+static int safe_fd_clr(int fd, fd_set* list_fds, int* max_fd_nb) {
+    assert(max_fd_nb != NULL);
+
+    FD_CLR(fd, list_fds);
+    if (fd == *max_fd_nb) {
+        (*max_fd_nb)--;
+    }
+    return 0;
+}
+
+/*****  Apply mapping activation fuction  *****/
+static void apply_mapping_activation(STRUCT_MAPPED_GPIO * node_mapping){
+	node_mapping->activated = true;
+	if(node_mapping->type_mapping == TYPE_MAPPING_KEYBOARD){
+		GPIO_PRINTF("Apply mapping activation fct: Key event: %d\n", node_mapping->key_value);
+		sendKey(node_mapping->key_value, 1);
+		//sendKeyAndStopKey(node_mapping->key_value);
+	}
+	else if(node_mapping->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
+		GPIO_PRINTF("Apply mapping activation fct: shell command \"%s\"\n", node_mapping->shell_command);
+		system(node_mapping->shell_command);
+	}
+}
+
+/*****  Apply mapping desactivation function  *****/
+static void apply_mapping_desactivation(STRUCT_MAPPED_GPIO * node_mapping){
+	node_mapping->activated = false;
+	if(node_mapping->type_mapping == TYPE_MAPPING_KEYBOARD){
+		GPIO_PRINTF("Apply mapping desactivation fct: Key event: %d\n", node_mapping->key_value);
+		sendKey(node_mapping->key_value, 0);
+	}
+	else if(node_mapping->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
+		//GPIO_PRINTF("Apply mapping desactivation fct: shell command \"%s\"\n", node_mapping->shell_command);
+	}
+}
+
+
+static void find_and_call_mapping_function(int idx_gpio_interrupted,
+									STRUCT_MAPPED_GPIO * cl_mapping, 
+									bool* mask_gpio_current_interrupts,
+									bool * mask_gpio_values,
+									bool activation){
+	// Init variables
+	STRUCT_MAPPED_GPIO * current = cl_mapping;
+	bool mapping_found = false;
+	
+	// Search if there are mappings to deactivate
+	while (current != NULL) {
+		int i;
+		bool gpio_found_pin_in_mapping = false;
+		bool all_gpio_activated_in_mapping = true;
+
+
+		//GPIO_PRINTF("	Mapping searching for idx_gpio_interrupted: %d, and %s: \n", idx_gpio_interrupted, activation?"activation":"deactivation")
+		for (i=0; i < current->nb_simultaneous_pins; i++){
+			//GPIO_PRINTF("	Pin in mapping: %d, pin_idx=%d\n", gpio_pins[current->pins_idx[i]], current->pins_idx[i]);
+			// Find if current mapping contains interrupted pin
+			if (current->pins_idx[i] == idx_gpio_interrupted){
+				gpio_found_pin_in_mapping = true;
+			}
+
+			// Check if all other pins of current mapping were already activated in previous mask
+			if(!mask_gpio_values[current->pins_idx[i]]){
+				all_gpio_activated_in_mapping = false;
+			}
+		}
+
+
+		// If this mapping contains the interrupted pin and all other pins activated:
+		if(gpio_found_pin_in_mapping && all_gpio_activated_in_mapping){
+			// Treating activation cases
+			if(activation){
+				// if real mapping already found => need to deactivate previously activated ones
+				if(mapping_found && current->activated){
+					GPIO_PRINTF("	Mapping Deactivation because real one already found: GPIO %d found in following activated mapping: \n", 
+						gpio_pins[idx_gpio_interrupted]);
+					print_chained_list_node(current);
+					apply_mapping_desactivation(current);
+				}
+				else if(!mapping_found){ // If this is the real mapping 
+					if(current->activated){
+						GPIO_ERROR_PRINTF("WARNING in find_and_call_mapping_function - Activating already activated mapping %s\n", 
+							current->fct_help_str);
+					}
+					// Print information and activate mapping
+					GPIO_PRINTF("	Mapping Activation: GPIO %d found in following deactivated mapping: \n", 
+						gpio_pins[idx_gpio_interrupted]);
+					print_chained_list_node(current);
+					apply_mapping_activation(current);
+				}
+			}
+			else{ // Treating deactivation cases
+				if(current->activated){
+					GPIO_PRINTF("	Mapping Desactivation: GPIO %d found in following activated mapping: \n", 
+							gpio_pins[idx_gpio_interrupted]);
+					print_chained_list_node(current);
+					apply_mapping_desactivation(current);
+				}
+			}
+
+			// Set that mapping has been found
+			mapping_found = true;
+		}
+
+		// Next node in chained list
+		current = current->next_mapped_gpio;
+	}
+}
+
+/*****  Init GPIO Interrupt i2c expander fd  *****/
+static int init_gpio_interrupt(void)
+{
+  	// Variables
+  	int cur_pin_nb = GPIO_PIN_I2C_EXPANDER_INTERRUPT;
+  	GPIO_PRINTF("Initializing Interrupt i2c expander GPIO pin fd: %d\n", cur_pin_nb);
+	  
+	// Init fds fd_set 
+	FD_ZERO(&fds);
+	  
+	//Initializing I2C interrupt GPIO
+	gpio_export(cur_pin_nb); 
+	//gpio_set_edge(cur_pin_nb, "both");  // Can be rising, falling or both
+	gpio_set_edge(cur_pin_nb, "falling");  // Can be rising, falling or both
+	gpio_fd_interrupt_i2c = gpio_fd_open(cur_pin_nb, O_RDONLY);
+		
+	// add stdin and the sock fd to fds fd_set 
+	safe_fd_set(gpio_fd_interrupt_i2c, &fds, &max_fd);
+
+	return 0;
+}
+
+/*****  DeInit GPIO Interrupt i2c expander fd  *****/
+static int deinit_gpio_interrupt(void)
+{ 
+  	GPIO_PRINTF("DeInitializing Interrupt i2c expander GPIO pin fd\n");
+
+	// Remove stdin and  sock fd from fds fd_set 
+	safe_fd_clr(gpio_fd_interrupt_i2c, &fds, &max_fd);
+	
+	// Unexport GPIO
+	gpio_fd_close(gpio_fd_interrupt_i2c);
+
+	return 0;
+}
+
+
+/****************************************************************
+ * Public functions
+ ****************************************************************/
+/*****  Init I2C expander pin mappings *****/
+int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare, 
+	STRUCT_MAPPED_GPIO * chained_list_mapping_gpios)
+{
+  	// Variables
+  	int idx_gpio;
+  	unsigned int cur_pin_nb;
+
+	// Store arguments
+	nb_mapped_gpios = nb_gpios_to_declare;
+	gpio_pins = gpio_pins_to_declare;
+	chained_list_mapping = chained_list_mapping_gpios;
+  
+	// Init values
+	mask_gpio_value = malloc(nb_mapped_gpios*sizeof(bool));
+	memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
+	STRUCT_MAPPED_GPIO * current = chained_list_mapping;	
+	do{
+		//set mapping deactivated
+		current->activated = false;
+	
+		// Next node in chained list
+		current = current->next_mapped_gpio;
+	} while(current != NULL);
+
+	// Init GPIO interrupt from I2C expander
+	init_gpio_interrupt();
+
+	// Init I2C expander
+	pcal6416a_init();
+
+	return 0;
+}
+
+/*****  DeInit GPIO fds  *****/
+int deinit_mapping_gpios(void)
+{
+	// DeInit GPIO interrupt from I2C expander
+	deinit_gpio_interrupt();
+
+	// DeInit I2C expander
+	pcal6416a_deinit();
+	return 0;
+}
+
+
+/*****  Listen GPIOs interrupts *****/
+int listen_gpios_interrupts(void)
+{
+	// Variables
+	char buffer[2];
+	int idx_gpio, value;
+	bool previous_mask_gpio_value[nb_mapped_gpios];
+	bool mask_gpio_current_interrupts[nb_mapped_gpios];
+	uint16_t val_i2c_mask_interrupted, val_i2c_mask_active;
+	bool interrupt_found = false;
+
+	// Back up master 
+	fd_set dup = fds;
+
+	// Init masks
+	memcpy(previous_mask_gpio_value, mask_gpio_value, nb_mapped_gpios*sizeof(bool));
+	memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
+	memset(mask_gpio_current_interrupts, false, nb_mapped_gpios*sizeof(bool));
+
+	// Note the max_fd+1 
+	if (select(max_fd+1, NULL, NULL, &dup, NULL) < 0) {
+		perror("select");
+		return -1;
+	} 
+
+	// Check if interrupt from I2C expander
+	// Check which cur_fd is available for read 
+	for (int cur_fd = 0; cur_fd <= max_fd; cur_fd++) {
+		if (FD_ISSET(cur_fd, &dup)) {
+			// Revenir au debut du fichier (lectures successives).
+			lseek(cur_fd, 0, SEEK_SET);
+			
+			// Read current gpio value
+			if (read(cur_fd, & buffer, 2) != 2) {
+				perror("read");
+				break;
+			}
+
+			// Effacer le retour-chariot.
+			buffer[1] = '\0';
+			value = 1-atoi(buffer);
+
+			// Found interrupt
+			interrupt_found = true;
+		}
+	}
+
+	if(interrupt_found){
+		// Read I2C GPIO masks: 
+		val_i2c_mask_interrupted = pcal6416a_read_mask_interrupts();
+		val_i2c_mask_active = pcal6416a_read_mask_active_GPIOs();
+
+		// Find GPIO idx correspondance
+		for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){
+			uint16_t tmp_mask_gpio = (1 << gpio_pins[idx_gpio]);
+
+			// Found GPIO idx in active GPIOs
+			if(val_i2c_mask_active & tmp_mask_gpio){
+				mask_gpio_value[idx_gpio] = true;
+			}
+
+			// Found GPIO idx in interrupt mask
+			if(val_i2c_mask_interrupted & tmp_mask_gpio){
+				// Print information
+				GPIO_PRINTF("	--> Interrupt GPIO: %d, idx_pin: %d\n", gpio_pins[idx_gpio], idx_gpio);
+				mask_gpio_current_interrupts[idx_gpio] = true;
+			}
+		}
+
+
+		// Find and call mapping functions (after all active gpios have been assigned):
+		for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){
+			if(!mask_gpio_current_interrupts[idx_gpio]) continue;
+
+			if (mask_gpio_value[idx_gpio]){
+				find_and_call_mapping_function(idx_gpio,
+										chained_list_mapping, 
+										mask_gpio_current_interrupts,
+										mask_gpio_value,
+										true);
+			}
+			else{
+				find_and_call_mapping_function(idx_gpio,
+										chained_list_mapping, 
+										mask_gpio_current_interrupts,
+										previous_mask_gpio_value,
+										false);
+			}
+		}
+	}
+
+	return 0;
+}

+ 25 - 0
gpio_mapping.h

@@ -0,0 +1,25 @@
+#ifndef _GPIO_MAPPING_H_
+#define _GPIO_MAPPING_H_
+
+/****************************************************************
+* Includes
+****************************************************************/
+#include "gpio-utils.h"
+#include "uinput.h" 
+#include "read_conf_file.h"
+
+/****************************************************************
+* Defines
+****************************************************************/
+#define GPIO_PIN_I2C_EXPANDER_INTERRUPT	35			//PB3
+//#define GPIO_PIN_I2C_EXPANDER_INTERRUPT	38			//PB6
+
+/****************************************************************
+* Public functions
+****************************************************************/
+int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare, 
+	STRUCT_MAPPED_GPIO * chained_list_mapping_gpios);
+int deinit_mapping_gpios(void);
+int listen_gpios_interrupts(void);
+
+#endif	//_GPIO_MAPPING_H_

+ 576 - 0
keydefs.c

@@ -0,0 +1,576 @@
+/**** keydefs.c ****************************/
+/* M. Moller   2013-01-16                  */
+/*   Universal RPi GPIO keyboard daemon    */
+/*******************************************/
+
+/*
+   Copyright (C) 2013 Michael Moller.
+   This file is part of the Universal Raspberry Pi GPIO keyboard daemon.
+
+   This is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  
+*/
+
+#include <stdio.h>
+#include "gpio_mapping.h"
+
+const key_names_s key_names[] = {
+/*
+  a subset of
+  sed 's/^#define \([^ \t]\+\)[ \t]*\([^\ \t]\+\)/  { \"\1\",\t\2 },/' /usr/include/linux/input.h
+ */
+  { "KEY_RESERVED",	0 },
+  { "KEY_ESC",	1 },
+  { "KEY_1",	2 },
+  { "KEY_2",	3 },
+  { "KEY_3",	4 },
+  { "KEY_4",	5 },
+  { "KEY_5",	6 },
+  { "KEY_6",	7 },
+  { "KEY_7",	8 },
+  { "KEY_8",	9 },
+  { "KEY_9",	10 },
+  { "KEY_0",	11 },
+  { "KEY_MINUS",	12 },
+  { "KEY_EQUAL",	13 },
+  { "KEY_BACKSPACE",	14 },
+  { "KEY_TAB",	15 },
+  { "KEY_Q",	16 },
+  { "KEY_W",	17 },
+  { "KEY_E",	18 },
+  { "KEY_R",	19 },
+  { "KEY_T",	20 },
+  { "KEY_Y",	21 },
+  { "KEY_U",	22 },
+  { "KEY_I",	23 },
+  { "KEY_O",	24 },
+  { "KEY_P",	25 },
+  { "KEY_LEFTBRACE",	26 },
+  { "KEY_RIGHTBRACE",	27 },
+  { "KEY_ENTER",	28 },
+  { "KEY_LEFTCTRL",	29 },
+  { "KEY_A",	30 },
+  { "KEY_S",	31 },
+  { "KEY_D",	32 },
+  { "KEY_F",	33 },
+  { "KEY_G",	34 },
+  { "KEY_H",	35 },
+  { "KEY_J",	36 },
+  { "KEY_K",	37 },
+  { "KEY_L",	38 },
+  { "KEY_SEMICOLON",	39 },
+  { "KEY_APOSTROPHE",	40 },
+  { "KEY_GRAVE",	41 },
+  { "KEY_LEFTSHIFT",	42 },
+  { "KEY_BACKSLASH",	43 },
+  { "KEY_Z",	44 },
+  { "KEY_X",	45 },
+  { "KEY_C",	46 },
+  { "KEY_V",	47 },
+  { "KEY_B",	48 },
+  { "KEY_N",	49 },
+  { "KEY_M",	50 },
+  { "KEY_COMMA",	51 },
+  { "KEY_DOT",	52 },
+  { "KEY_SLASH",	53 },
+  { "KEY_RIGHTSHIFT",	54 },
+  { "KEY_KPASTERISK",	55 },
+  { "KEY_LEFTALT",	56 },
+  { "KEY_SPACE",	57 },
+  { "KEY_CAPSLOCK",	58 },
+  { "KEY_F1",	59 },
+  { "KEY_F2",	60 },
+  { "KEY_F3",	61 },
+  { "KEY_F4",	62 },
+  { "KEY_F5",	63 },
+  { "KEY_F6",	64 },
+  { "KEY_F7",	65 },
+  { "KEY_F8",	66 },
+  { "KEY_F9",	67 },
+  { "KEY_F10",	68 },
+  { "KEY_NUMLOCK",	69 },
+  { "KEY_SCROLLLOCK",	70 },
+  { "KEY_KP7",	71 },
+  { "KEY_KP8",	72 },
+  { "KEY_KP9",	73 },
+  { "KEY_KPMINUS",	74 },
+  { "KEY_KP4",	75 },
+  { "KEY_KP5",	76 },
+  { "KEY_KP6",	77 },
+  { "KEY_KPPLUS",	78 },
+  { "KEY_KP1",	79 },
+  { "KEY_KP2",	80 },
+  { "KEY_KP3",	81 },
+  { "KEY_KP0",	82 },
+  { "KEY_KPDOT",	83 },
+
+  { "KEY_ZENKAKUHANKAKU",	85 },
+  { "KEY_102ND",	86 },
+  { "KEY_F11",	87 },
+  { "KEY_F12",	88 },
+  { "KEY_RO",	89 },
+  { "KEY_KATAKANA",	90 },
+  { "KEY_HIRAGANA",	91 },
+  { "KEY_HENKAN",	92 },
+  { "KEY_KATAKANAHIRAGANA",	93 },
+  { "KEY_MUHENKAN",	94 },
+  { "KEY_KPJPCOMMA",	95 },
+  { "KEY_KPENTER",	96 },
+  { "KEY_RIGHTCTRL",	97 },
+  { "KEY_KPSLASH",	98 },
+  { "KEY_SYSRQ",	99 },
+  { "KEY_RIGHTALT",	100 },
+  { "KEY_LINEFEED",	101 },
+  { "KEY_HOME",	102 },
+  { "KEY_UP",	103 },
+  { "KEY_PAGEUP",	104 },
+  { "KEY_LEFT",	105 },
+  { "KEY_RIGHT",	106 },
+  { "KEY_END",	107 },
+  { "KEY_DOWN",	108 },
+  { "KEY_PAGEDOWN",	109 },
+  { "KEY_INSERT",	110 },
+  { "KEY_DELETE",	111 },
+  { "KEY_MACRO",	112 },
+  { "KEY_MUTE",	113 },
+  { "KEY_VOLUMEDOWN",	114 },
+  { "KEY_VOLUMEUP",	115 },
+  { "KEY_POWER",	116 },	/* SC System Power Down */
+  { "KEY_KPEQUAL",	117 },
+  { "KEY_KPPLUSMINUS",	118 },
+  { "KEY_PAUSE",	119 },
+  { "KEY_SCALE",	120 },	/* AL Compiz Scale (Expose) */
+
+  { "KEY_KPCOMMA",	121 },
+  { "KEY_HANGEUL",	122 },
+  { "KEY_HANGUEL",	122 /*KEY_HANGEUL*/ },
+  { "KEY_HANJA",	123 },
+  { "KEY_YEN",	124 },
+  { "KEY_LEFTMETA",	125 },
+  { "KEY_RIGHTMETA",	126 },
+  { "KEY_COMPOSE",	127 },
+
+  { "KEY_STOP",	128 },	/* AC Stop */
+  { "KEY_AGAIN",	129 },
+  { "KEY_PROPS",	130 },	/* AC Properties */
+  { "KEY_UNDO",	131 },	/* AC Undo */
+  { "KEY_FRONT",	132 },
+  { "KEY_COPY",	133 },	/* AC Copy */
+  { "KEY_OPEN",	134 },	/* AC Open */
+  { "KEY_PASTE",	135 },	/* AC Paste */
+  { "KEY_FIND",	136 },	/* AC Search */
+  { "KEY_CUT",	137 },	/* AC Cut */
+  { "KEY_HELP",	138 },	/* AL Integrated Help Center */
+  { "KEY_MENU",	139 },	/* Menu (show menu) */
+  { "KEY_CALC",	140 },	/* AL Calculator */
+  { "KEY_SETUP",	141 },
+  { "KEY_SLEEP",	142 },	/* SC System Sleep */
+  { "KEY_WAKEUP",	143 },	/* System Wake Up */
+  { "KEY_FILE",	144 },	/* AL Local Machine Browser */
+  { "KEY_SENDFILE",	145 },
+  { "KEY_DELETEFILE",	146 },
+  { "KEY_XFER",	147 },
+  { "KEY_PROG1",	148 },
+  { "KEY_PROG2",	149 },
+  { "KEY_WWW",	150 },	/* AL Internet Browser */
+  { "KEY_MSDOS",	151 },
+  { "KEY_COFFEE",	152 },	/* AL Terminal Lock/Screensaver */
+  { "KEY_SCREENLOCK",	152 /*KEY_COFFEE*/ },
+  { "KEY_DIRECTION",	153 },
+  { "KEY_CYCLEWINDOWS",	154 },
+  { "KEY_MAIL",	155 },
+  { "KEY_BOOKMARKS",	156 },	/* AC Bookmarks */
+  { "KEY_COMPUTER",	157 },
+  { "KEY_BACK",	158 },	/* AC Back */
+  { "KEY_FORWARD",	159 },	/* AC Forward */
+  { "KEY_CLOSECD",	160 },
+  { "KEY_EJECTCD",	161 },
+  { "KEY_EJECTCLOSECD",	162 },
+  { "KEY_NEXTSONG",	163 },
+  { "KEY_PLAYPAUSE",	164 },
+  { "KEY_PREVIOUSSONG",	165 },
+  { "KEY_STOPCD",	166 },
+  { "KEY_RECORD",	167 },
+  { "KEY_REWIND",	168 },
+  { "KEY_PHONE",	169 },	/* Media Select Telephone */
+  { "KEY_ISO",	170 },
+  { "KEY_CONFIG",	171 },	/* AL Consumer Control Configuration */
+  { "KEY_HOMEPAGE",	172 },	/* AC Home */
+  { "KEY_REFRESH",	173 },	/* AC Refresh */
+  { "KEY_EXIT",	174 },	/* AC Exit */
+  { "KEY_MOVE",	175 },
+  { "KEY_EDIT",	176 },
+  { "KEY_SCROLLUP",	177 },
+  { "KEY_SCROLLDOWN",	178 },
+  { "KEY_KPLEFTPAREN",	179 },
+  { "KEY_KPRIGHTPAREN",	180 },
+  { "KEY_NEW",	181 },	/* AC New */
+  { "KEY_REDO",	182 },	/* AC Redo/Repeat */
+
+  { "KEY_F13",	183 },
+  { "KEY_F14",	184 },
+  { "KEY_F15",	185 },
+  { "KEY_F16",	186 },
+  { "KEY_F17",	187 },
+  { "KEY_F18",	188 },
+  { "KEY_F19",	189 },
+  { "KEY_F20",	190 },
+  { "KEY_F21",	191 },
+  { "KEY_F22",	192 },
+  { "KEY_F23",	193 },
+  { "KEY_F24",	194 },
+
+  { "KEY_PLAYCD",	200 },
+  { "KEY_PAUSECD",	201 },
+  { "KEY_PROG3",	202 },
+  { "KEY_PROG4",	203 },
+  { "KEY_DASHBOARD",	204 },	/* AL Dashboard */
+  { "KEY_SUSPEND",	205 },
+  { "KEY_CLOSE",	206 },	/* AC Close */
+  { "KEY_PLAY",	207 },
+  { "KEY_FASTFORWARD",	208 },
+  { "KEY_BASSBOOST",	209 },
+  { "KEY_PRINT",	210 },	/* AC Print */
+  { "KEY_HP",	211 },
+  { "KEY_CAMERA",	212 },
+  { "KEY_SOUND",	213 },
+  { "KEY_QUESTION",	214 },
+  { "KEY_EMAIL",	215 },
+  { "KEY_CHAT",	216 },
+  { "KEY_SEARCH",	217 },
+  { "KEY_CONNECT",	218 },
+  { "KEY_FINANCE",	219 },	/* AL Checkbook/Finance */
+  { "KEY_SPORT",	220 },
+  { "KEY_SHOP",	221 },
+  { "KEY_ALTERASE",	222 },
+  { "KEY_CANCEL",	223 },	/* AC Cancel */
+  { "KEY_BRIGHTNESSDOWN",	224 },
+  { "KEY_BRIGHTNESSUP",	225 },
+  { "KEY_MEDIA",	226 },
+
+  { "KEY_SWITCHVIDEOMODE",	227 },	/* Cycle between available video
+					   outputs (Monitor/LCD/TV-out/etc) */
+  { "KEY_KBDILLUMTOGGLE",	228 },
+  { "KEY_KBDILLUMDOWN",	229 },
+  { "KEY_KBDILLUMUP",	230 },
+
+  { "KEY_SEND",	231 },	/* AC Send */
+  { "KEY_REPLY",	232 },	/* AC Reply */
+  { "KEY_FORWARDMAIL",	233 },	/* AC Forward Msg */
+  { "KEY_SAVE",	234 },	/* AC Save */
+  { "KEY_DOCUMENTS",	235 },
+
+  { "KEY_BATTERY",	236 },
+
+  { "KEY_BLUETOOTH",	237 },
+  { "KEY_WLAN",	238 },
+  { "KEY_UWB",	239 },
+
+  { "KEY_UNKNOWN",	240 },
+
+  { "KEY_VIDEO_NEXT",	241 },	/* drive next video source */
+  { "KEY_VIDEO_PREV",	242 },	/* drive previous video source */
+  { "KEY_BRIGHTNESS_CYCLE",	243 },	/* brightness up, after max is min */
+  { "KEY_BRIGHTNESS_ZERO",	244 },	/* brightness off, use ambient */
+  { "KEY_DISPLAY_OFF",	245 },	/* display device to off state */
+
+  { "KEY_WIMAX",	246 },
+  { "KEY_RFKILL",	247 },	/* Key that controls all radios */
+
+  { "KEY_MICMUTE",	248 },	/* Mute / unmute the microphone */
+
+/* Code 255 is reserved for special needs of AT keyboard driver */
+
+  { "BTN_MISC",	0x100 },
+  { "BTN_0",	0x100 },
+  { "BTN_1",	0x101 },
+  { "BTN_2",	0x102 },
+  { "BTN_3",	0x103 },
+  { "BTN_4",	0x104 },
+  { "BTN_5",	0x105 },
+  { "BTN_6",	0x106 },
+  { "BTN_7",	0x107 },
+  { "BTN_8",	0x108 },
+  { "BTN_9",	0x109 },
+
+  { "BTN_MOUSE",	0x110 },
+  { "BTN_LEFT",	0x110 },
+  { "BTN_RIGHT",	0x111 },
+  { "BTN_MIDDLE",	0x112 },
+  { "BTN_SIDE",	0x113 },
+  { "BTN_EXTRA",	0x114 },
+  { "BTN_FORWARD",	0x115 },
+  { "BTN_BACK",	0x116 },
+  { "BTN_TASK",	0x117 },
+
+  { "BTN_JOYSTICK",	0x120 },
+  { "BTN_TRIGGER",	0x120 },
+  { "BTN_THUMB",	0x121 },
+  { "BTN_THUMB2",	0x122 },
+  { "BTN_TOP",	0x123 },
+  { "BTN_TOP2",	0x124 },
+  { "BTN_PINKIE",	0x125 },
+  { "BTN_BASE",	0x126 },
+  { "BTN_BASE2",	0x127 },
+  { "BTN_BASE3",	0x128 },
+  { "BTN_BASE4",	0x129 },
+  { "BTN_BASE5",	0x12a },
+  { "BTN_BASE6",	0x12b },
+  { "BTN_DEAD",	0x12f },
+
+  { "BTN_GAMEPAD",	0x130 },
+  { "BTN_A",	0x130 },
+  { "BTN_B",	0x131 },
+  { "BTN_C",	0x132 },
+  { "BTN_X",	0x133 },
+  { "BTN_Y",	0x134 },
+  { "BTN_Z",	0x135 },
+  { "BTN_TL",	0x136 },
+  { "BTN_TR",	0x137 },
+  { "BTN_TL2",	0x138 },
+  { "BTN_TR2",	0x139 },
+  { "BTN_SELECT",	0x13a },
+  { "BTN_START",	0x13b },
+  { "BTN_MODE",	0x13c },
+  { "BTN_THUMBL",	0x13d },
+  { "BTN_THUMBR",	0x13e },
+
+#if 0
+
+  { "BTN_DIGI",	0x140 },
+  { "BTN_TOOL_PEN",	0x140 },
+  { "BTN_TOOL_RUBBER",	0x141 },
+  { "BTN_TOOL_BRUSH",	0x142 },
+  { "BTN_TOOL_PENCIL",	0x143 },
+  { "BTN_TOOL_AIRBRUSH",	0x144 },
+  { "BTN_TOOL_FINGER",	0x145 },
+  { "BTN_TOOL_MOUSE",	0x146 },
+  { "BTN_TOOL_LENS",	0x147 },
+  { "BTN_TOOL_QUINTTAP",	0x148 },	/* Five fingers on trackpad */
+  { "BTN_TOUCH",	0x14a },
+  { "BTN_STYLUS",	0x14b },
+  { "BTN_STYLUS2",	0x14c },
+  { "BTN_TOOL_DOUBLETAP",	0x14d },
+  { "BTN_TOOL_TRIPLETAP",	0x14e },
+  { "BTN_TOOL_QUADTAP",	0x14f },	/* Four fingers on trackpad */
+
+  { "BTN_WHEEL",	0x150 },
+  { "BTN_GEAR_DOWN",	0x150 },
+  { "BTN_GEAR_UP",	0x151 },
+
+  { "KEY_OK",	0x160 },
+  { "KEY_SELECT",	0x161 },
+  { "KEY_GOTO",	0x162 },
+  { "KEY_CLEAR",	0x163 },
+  { "KEY_POWER2",	0x164 },
+  { "KEY_OPTION",	0x165 },
+  { "KEY_INFO",	0x166 },	/* AL OEM Features/Tips/Tutorial */
+  { "KEY_TIME",	0x167 },
+  { "KEY_VENDOR",	0x168 },
+  { "KEY_ARCHIVE",	0x169 },
+  { "KEY_PROGRAM",	0x16a },	/* Media Select Program Guide */
+  { "KEY_CHANNEL",	0x16b },
+  { "KEY_FAVORITES",	0x16c },
+  { "KEY_EPG",	0x16d },
+  { "KEY_PVR",	0x16e },	/* Media Select Home */
+  { "KEY_MHP",	0x16f },
+  { "KEY_LANGUAGE",	0x170 },
+  { "KEY_TITLE",	0x171 },
+  { "KEY_SUBTITLE",	0x172 },
+  { "KEY_ANGLE",	0x173 },
+  { "KEY_ZOOM",	0x174 },
+  { "KEY_MODE",	0x175 },
+  { "KEY_KEYBOARD",	0x176 },
+  { "KEY_SCREEN",	0x177 },
+  { "KEY_PC",	0x178 },	/* Media Select Computer */
+  { "KEY_TV",	0x179 },	/* Media Select TV */
+  { "KEY_TV2",	0x17a },	/* Media Select Cable */
+  { "KEY_VCR",	0x17b },	/* Media Select VCR */
+  { "KEY_VCR2",	0x17c },	/* VCR Plus */
+  { "KEY_SAT",	0x17d },	/* Media Select Satellite */
+  { "KEY_SAT2",	0x17e },
+  { "KEY_CD",	0x17f },	/* Media Select CD */
+  { "KEY_TAPE",	0x180 },	/* Media Select Tape */
+  { "KEY_RADIO",	0x181 },
+  { "KEY_TUNER",	0x182 },	/* Media Select Tuner */
+  { "KEY_PLAYER",	0x183 },
+  { "KEY_TEXT",	0x184 },
+  { "KEY_DVD",	0x185 },	/* Media Select DVD */
+  { "KEY_AUX",	0x186 },
+  { "KEY_MP3",	0x187 },
+  { "KEY_AUDIO",	0x188 },	/* AL Audio Browser */
+  { "KEY_VIDEO",	0x189 },	/* AL Movie Browser */
+  { "KEY_DIRECTORY",	0x18a },
+  { "KEY_LIST",	0x18b },
+  { "KEY_MEMO",	0x18c },	/* Media Select Messages */
+  { "KEY_CALENDAR",	0x18d },
+  { "KEY_RED",	0x18e },
+  { "KEY_GREEN",	0x18f },
+  { "KEY_YELLOW",	0x190 },
+  { "KEY_BLUE",	0x191 },
+  { "KEY_CHANNELUP",	0x192 },	/* Channel Increment */
+  { "KEY_CHANNELDOWN",	0x193 },	/* Channel Decrement */
+  { "KEY_FIRST",	0x194 },
+  { "KEY_LAST",	0x195 },	/* Recall Last */
+  { "KEY_AB",	0x196 },
+  { "KEY_NEXT",	0x197 },
+  { "KEY_RESTART",	0x198 },
+  { "KEY_SLOW",	0x199 },
+  { "KEY_SHUFFLE",	0x19a },
+  { "KEY_BREAK",	0x19b },
+  { "KEY_PREVIOUS",	0x19c },
+  { "KEY_DIGITS",	0x19d },
+  { "KEY_TEEN",	0x19e },
+  { "KEY_TWEN",	0x19f },
+  { "KEY_VIDEOPHONE",	0x1a0 },	/* Media Select Video Phone */
+  { "KEY_GAMES",	0x1a1 },	/* Media Select Games */
+  { "KEY_ZOOMIN",	0x1a2 },	/* AC Zoom In */
+  { "KEY_ZOOMOUT",	0x1a3 },	/* AC Zoom Out */
+  { "KEY_ZOOMRESET",	0x1a4 },	/* AC Zoom */
+  { "KEY_WORDPROCESSOR",	0x1a5 },	/* AL Word Processor */
+  { "KEY_EDITOR",	0x1a6 },	/* AL Text Editor */
+  { "KEY_SPREADSHEET",	0x1a7 },	/* AL Spreadsheet */
+  { "KEY_GRAPHICSEDITOR",	0x1a8 },	/* AL Graphics Editor */
+  { "KEY_PRESENTATION",	0x1a9 },	/* AL Presentation App */
+  { "KEY_DATABASE",	0x1aa },	/* AL Database App */
+  { "KEY_NEWS",	0x1ab },	/* AL Newsreader */
+  { "KEY_VOICEMAIL",	0x1ac },	/* AL Voicemail */
+  { "KEY_ADDRESSBOOK",	0x1ad },	/* AL Contacts/Address Book */
+  { "KEY_MESSENGER",	0x1ae },	/* AL Instant Messaging */
+  { "KEY_DISPLAYTOGGLE",	0x1af },	/* Turn display (LCD) on and off */
+  { "KEY_SPELLCHECK",	0x1b0 },   /* AL Spell Check */
+  { "KEY_LOGOFF",	0x1b1 },   /* AL Logoff */
+
+  { "KEY_DOLLAR",	0x1b2 },
+  { "KEY_EURO",	0x1b3 },
+
+  { "KEY_FRAMEBACK",	0x1b4 },	/* Consumer - transport controls */
+  { "KEY_FRAMEFORWARD",	0x1b5 },
+  { "KEY_CONTEXT_MENU",	0x1b6 },	/* GenDesc - system context menu */
+  { "KEY_MEDIA_REPEAT",	0x1b7 },	/* Consumer - transport control */
+  { "KEY_10CHANNELSUP",	0x1b8 },	/* 10 channels up (10+) */
+  { "KEY_10CHANNELSDOWN",	0x1b9 },	/* 10 channels down (10-) */
+  { "KEY_IMAGES",	0x1ba },	/* AL Image Browser */
+
+  { "KEY_DEL_EOL",	0x1c0 },
+  { "KEY_DEL_EOS",	0x1c1 },
+  { "KEY_INS_LINE",	0x1c2 },
+  { "KEY_DEL_LINE",	0x1c3 },
+
+  { "KEY_FN",	0x1d0 },
+  { "KEY_FN_ESC",	0x1d1 },
+  { "KEY_FN_F1",	0x1d2 },
+  { "KEY_FN_F2",	0x1d3 },
+  { "KEY_FN_F3",	0x1d4 },
+  { "KEY_FN_F4",	0x1d5 },
+  { "KEY_FN_F5",	0x1d6 },
+  { "KEY_FN_F6",	0x1d7 },
+  { "KEY_FN_F7",	0x1d8 },
+  { "KEY_FN_F8",	0x1d9 },
+  { "KEY_FN_F9",	0x1da },
+  { "KEY_FN_F10",	0x1db },
+  { "KEY_FN_F11",	0x1dc },
+  { "KEY_FN_F12",	0x1dd },
+  { "KEY_FN_1",	0x1de },
+  { "KEY_FN_2",	0x1df },
+  { "KEY_FN_D",	0x1e0 },
+  { "KEY_FN_E",	0x1e1 },
+  { "KEY_FN_F",	0x1e2 },
+  { "KEY_FN_S",	0x1e3 },
+  { "KEY_FN_B",	0x1e4 },
+
+  { "KEY_BRL_DOT1",	0x1f1 },
+  { "KEY_BRL_DOT2",	0x1f2 },
+  { "KEY_BRL_DOT3",	0x1f3 },
+  { "KEY_BRL_DOT4",	0x1f4 },
+  { "KEY_BRL_DOT5",	0x1f5 },
+  { "KEY_BRL_DOT6",	0x1f6 },
+  { "KEY_BRL_DOT7",	0x1f7 },
+  { "KEY_BRL_DOT8",	0x1f8 },
+  { "KEY_BRL_DOT9",	0x1f9 },
+  { "KEY_BRL_DOT10",	0x1fa },
+
+  { "KEY_NUMERIC_0",	0x200 },	/* used by phones, remote controls, */
+  { "KEY_NUMERIC_1",	0x201 },	/* and other keypads */
+  { "KEY_NUMERIC_2",	0x202 },
+  { "KEY_NUMERIC_3",	0x203 },
+  { "KEY_NUMERIC_4",	0x204 },
+  { "KEY_NUMERIC_5",	0x205 },
+  { "KEY_NUMERIC_6",	0x206 },
+  { "KEY_NUMERIC_7",	0x207 },
+  { "KEY_NUMERIC_8",	0x208 },
+  { "KEY_NUMERIC_9",	0x209 },
+  { "KEY_NUMERIC_STAR",	0x20a },
+  { "KEY_NUMERIC_POUND",	0x20b },
+
+  { "KEY_CAMERA_FOCUS",	0x210 },
+  { "KEY_WPS_BUTTON",	0x211 },	/* WiFi Protected Setup key */
+
+  { "KEY_TOUCHPAD_TOGGLE",	0x212 },	/* Request switch touchpad on or off */
+  { "KEY_TOUCHPAD_ON",	0x213 },
+  { "KEY_TOUCHPAD_OFF",	0x214 },
+
+  { "KEY_CAMERA_ZOOMIN",	0x215 },
+  { "KEY_CAMERA_ZOOMOUT",	0x216 },
+  { "KEY_CAMERA_UP",	0x217 },
+  { "KEY_CAMERA_DOWN",	0x218 },
+  { "KEY_CAMERA_LEFT",	0x219 },
+  { "KEY_CAMERA_RIGHT",	0x21a },
+
+  { "BTN_TRIGGER_HAPPY",	0x2c0 },
+  { "BTN_TRIGGER_HAPPY1",	0x2c0 },
+  { "BTN_TRIGGER_HAPPY2",	0x2c1 },
+  { "BTN_TRIGGER_HAPPY3",	0x2c2 },
+  { "BTN_TRIGGER_HAPPY4",	0x2c3 },
+  { "BTN_TRIGGER_HAPPY5",	0x2c4 },
+  { "BTN_TRIGGER_HAPPY6",	0x2c5 },
+  { "BTN_TRIGGER_HAPPY7",	0x2c6 },
+  { "BTN_TRIGGER_HAPPY8",	0x2c7 },
+  { "BTN_TRIGGER_HAPPY9",	0x2c8 },
+  { "BTN_TRIGGER_HAPPY10",	0x2c9 },
+  { "BTN_TRIGGER_HAPPY11",	0x2ca },
+  { "BTN_TRIGGER_HAPPY12",	0x2cb },
+  { "BTN_TRIGGER_HAPPY13",	0x2cc },
+  { "BTN_TRIGGER_HAPPY14",	0x2cd },
+  { "BTN_TRIGGER_HAPPY15",	0x2ce },
+  { "BTN_TRIGGER_HAPPY16",	0x2cf },
+  { "BTN_TRIGGER_HAPPY17",	0x2d0 },
+  { "BTN_TRIGGER_HAPPY18",	0x2d1 },
+  { "BTN_TRIGGER_HAPPY19",	0x2d2 },
+  { "BTN_TRIGGER_HAPPY20",	0x2d3 },
+  { "BTN_TRIGGER_HAPPY21",	0x2d4 },
+  { "BTN_TRIGGER_HAPPY22",	0x2d5 },
+  { "BTN_TRIGGER_HAPPY23",	0x2d6 },
+  { "BTN_TRIGGER_HAPPY24",	0x2d7 },
+  { "BTN_TRIGGER_HAPPY25",	0x2d8 },
+  { "BTN_TRIGGER_HAPPY26",	0x2d9 },
+  { "BTN_TRIGGER_HAPPY27",	0x2da },
+  { "BTN_TRIGGER_HAPPY28",	0x2db },
+  { "BTN_TRIGGER_HAPPY29",	0x2dc },
+  { "BTN_TRIGGER_HAPPY30",	0x2dd },
+  { "BTN_TRIGGER_HAPPY31",	0x2de },
+  { "BTN_TRIGGER_HAPPY32",	0x2df },
+  { "BTN_TRIGGER_HAPPY33",	0x2e0 },
+  { "BTN_TRIGGER_HAPPY34",	0x2e1 },
+  { "BTN_TRIGGER_HAPPY35",	0x2e2 },
+  { "BTN_TRIGGER_HAPPY36",	0x2e3 },
+  { "BTN_TRIGGER_HAPPY37",	0x2e4 },
+  { "BTN_TRIGGER_HAPPY38",	0x2e5 },
+  { "BTN_TRIGGER_HAPPY39",	0x2e6 },
+  { "BTN_TRIGGER_HAPPY40",	0x2e7 },
+#endif
+
+  { "LAST", -1 },
+};

+ 382 - 0
read_conf_file.c

@@ -0,0 +1,382 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <linux/input.h>
+#include "read_conf_file.h"
+#include <assert.h>
+
+/****************************************************************
+ * Defines
+ ****************************************************************/
+#define die(str, args...) do { \
+        perror(str); \
+        return(EXIT_FAILURE); \
+    } while(0)
+
+#define DEBUG_READ_CONF_FILE_PRINTF 			(0)
+
+#if (DEBUG_READ_CONF_FILE_PRINTF)
+	#define READ_CONF_FILE_PRINTF(...) printf(__VA_ARGS__);
+#else
+	#define READ_CONF_FILE_PRINTF(...)
+#endif
+
+
+/****************************************************************
+ * Extern variables
+ ****************************************************************/
+extern key_names_s key_names[];
+
+
+/****************************************************************
+ * Static variables
+ ****************************************************************/
+static STRUCT_MAPPED_GPIO * head_chained_list_mapping_gpio = NULL;
+static int count_valid_gpios = 0;
+static int gpio_pins[MAX_NUM_GPIO];
+
+
+/****************************************************************
+ * Static functions
+ ****************************************************************/
+/* Return linux Key code from corresponding str*/
+static int find_key(const char *name)
+{
+	int i=0;
+	while(key_names[i].code >= 0){
+		if(!strncmp(key_names[i].name, name, 32))break;
+		i++;
+	}
+	if(key_names[i].code < 0){
+		i = 0;
+	}
+	return i;
+}
+
+/* Return pin idx in the array of instanciated pins  */
+static int get_idx_pin(int* ptr_list_gpio_pins, int size_list_gpio_pins, int pin_number_to_find){
+	int idx;
+
+	for (idx=0; idx<size_list_gpio_pins; idx++){
+		if(ptr_list_gpio_pins[idx] == pin_number_to_find){
+			return idx;
+		}
+	}
+
+	// if we get here, then we did not find the pin:
+	idx=-1;
+	return idx;
+}
+
+
+/* function to swap data of two nodes a and b in chained list */
+static void swap(STRUCT_MAPPED_GPIO *a, STRUCT_MAPPED_GPIO *b)
+{
+    STRUCT_MAPPED_GPIO temp;
+    memcpy(&temp, a, sizeof(STRUCT_MAPPED_GPIO));
+    memcpy(a, b, sizeof(STRUCT_MAPPED_GPIO));
+    memcpy(b, &temp, sizeof(STRUCT_MAPPED_GPIO));
+    b->next_mapped_gpio = a->next_mapped_gpio;
+    a->next_mapped_gpio = b;
+}
+
+
+/* Bubble sort the given linked list */
+static void bubbleSort(STRUCT_MAPPED_GPIO *head)
+{
+    int swapped, i;
+    STRUCT_MAPPED_GPIO *ptr1 = head;
+    STRUCT_MAPPED_GPIO *lptr = NULL;
+ 
+    /* Checking for empty list */
+    if (ptr1 == NULL)
+        return;
+ 
+    do
+    {
+        swapped = 0;
+        ptr1 = head;
+ 
+        while (ptr1->next_mapped_gpio != lptr)
+        {
+            if (ptr1->nb_simultaneous_pins < ptr1->next_mapped_gpio->nb_simultaneous_pins)
+            { 
+                swap(ptr1, ptr1->next_mapped_gpio);
+                swapped = 1;
+            }
+            ptr1 = ptr1->next_mapped_gpio;
+        }
+        lptr = ptr1;
+    }
+    while (swapped);
+}
+
+
+/* Push new node in chained list */
+static void push(STRUCT_MAPPED_GPIO ** head, STRUCT_MAPPED_GPIO * new_mapping) {
+	STRUCT_MAPPED_GPIO ** current = head;
+    while (*current != NULL) {
+        current = &(*current)->next_mapped_gpio;
+    }
+
+    /* now we can add a new variable */
+    *current = malloc(sizeof(STRUCT_MAPPED_GPIO));
+    memcpy(*current, new_mapping, sizeof(STRUCT_MAPPED_GPIO));
+    (*current)->next_mapped_gpio = NULL;
+}
+
+
+
+/****************************************************************
+ * Public functions
+ ****************************************************************/
+ void get_mapping_from_conf_file(STRUCT_MAPPED_GPIO ** chained_list_mapping, 
+ 	int* nb_valid_gpios, int ** valid_gpio_pins){
+ 	/* Variables */
+	READ_CONF_FILE_PRINTF("Reading the config file:\n");
+	FILE *fp;
+	char ln[MAX_LN_LENGTH];
+	int lnno = 0;
+	char conffile[80];
+	bool pins_declaration_line = true;
+
+  	/* search for the conf file in ~/.funkey_gpio_mapping.conf and /etc/funkey_gpio_mapping.conf */
+	sprintf(conffile, "%s/.funkey_gpio_mapping.conf", getenv("HOME"));
+	fp = fopen(conffile, "r");
+	if(!fp){
+		fp = fopen("/etc/funkey_gpio_mapping.conf", "r");
+		if(!fp){
+			fp = fopen("./funkey_gpio_mapping.conf", "r");
+			if(!fp){
+				perror(conffile);
+				perror("/etc/funkey_gpio_mapping.conf");
+				perror("./funkey_gpio_mapping.conf");
+			}
+			sprintf(conffile, "./funkey_gpio_mapping.conf");
+		}
+		else{
+			sprintf(conffile, "/etc/funkey_gpio_mapping.conf");
+		}
+	}
+	if(fp){
+		READ_CONF_FILE_PRINTF("Config file found at %s\n", conffile);
+	}
+
+	/* Main loop to read conf file (purposely exploded and not in multiple sub-functions) */
+	while(fp && !feof(fp)){
+		if(fgets(ln, MAX_LN_LENGTH, fp)){
+			lnno++;
+			if(strlen(ln) > 1){
+				if(ln[0]=='#')continue;
+				READ_CONF_FILE_PRINTF("\nCurrent line : %s\n", ln);
+
+				// ************ Pins declaration ************
+				if(pins_declaration_line){
+					char* token;
+					int token_int;
+					
+					//count nb valid GPIOs and store them
+					token = strtok(ln, ",");
+					while(token != NULL){
+						token_int = atoi(token);
+						if(token_int || !strcmp(token, "0")){
+							gpio_pins[count_valid_gpios] = token_int;
+							count_valid_gpios++;
+							READ_CONF_FILE_PRINTF("GPIO %d declared\n", token_int);
+						}
+						else{
+							READ_CONF_FILE_PRINTF("Could not declare GPIO: %s\n", token);
+						}
+						token = strtok(NULL, ",");
+					}
+					pins_declaration_line = false;
+				}
+
+				// ************ Pins mapping ************
+				else{
+					STRUCT_MAPPED_GPIO cur_gpio_mapping;
+					char* end_ln;
+					char* token_comma;
+					char * current_arg;
+					int cur_arg_idx = MAPPING_ARG_PINS;
+					int idx_pin = 0;
+					int cur_pin;
+					bool add_current_mapping = true;
+
+					token_comma = strtok_r(ln, ",", &end_ln);
+					while(token_comma != NULL && cur_arg_idx < NB_MAPPING_ARG_NAMES && add_current_mapping){
+						current_arg= token_comma;
+						//remove_initial_spaces: 
+						while(*current_arg==' ' && *current_arg!=0){current_arg++;}
+						READ_CONF_FILE_PRINTF("	Current arg: %s\n", current_arg);
+						//Handle current mapping arg
+						switch(cur_arg_idx){
+							case MAPPING_ARG_PINS:
+								//count nb valid GPIOs and store them
+								;char* end_arg;
+								char * token_plus = strtok_r(current_arg, "+", &end_arg);
+								while(token_plus != NULL){
+									cur_pin = atoi(token_plus);
+									if(cur_pin || !strcmp(token_plus, "0")){
+										int idx_cur_pin = get_idx_pin(gpio_pins, count_valid_gpios, cur_pin);
+										if(idx_cur_pin == -1){
+											READ_CONF_FILE_PRINTF("		Could not find GPIO: %s in previously instanciated GPIOs\n", token_plus);
+											add_current_mapping = false;
+											break;
+										}
+										cur_gpio_mapping.pins_idx[idx_pin] = idx_cur_pin;
+										idx_pin++;
+										READ_CONF_FILE_PRINTF("		GPIO %d in current mapping\n", cur_pin);
+									}
+									else{
+										READ_CONF_FILE_PRINTF("		Could not find GPIO: %s\n", token_plus);
+										add_current_mapping = false;
+										break;
+									}
+									token_plus = strtok_r(NULL, "+", &end_arg);//strtok_r(NULL, ",");
+								}
+								cur_gpio_mapping.nb_simultaneous_pins = idx_pin;
+								break;
+							case MAPPING_ARG_TYPE:
+								if(!strcmp(current_arg, "KEYBOARD")){
+									cur_gpio_mapping.type_mapping = TYPE_MAPPING_KEYBOARD;
+								}
+								else if(!strcmp(current_arg, "SHELL_COMMAND")){
+									cur_gpio_mapping.type_mapping = TYPE_MAPPING_SHELL_COMMAND;
+								}
+								else{
+									READ_CONF_FILE_PRINTF("		%s is not a valid mapping type\n", current_arg);
+									add_current_mapping = false;
+									break;
+								}
+								break;
+							case MAPPING_ARG_VALUE:
+								switch (cur_gpio_mapping.type_mapping){
+									case TYPE_MAPPING_KEYBOARD:
+										cur_gpio_mapping.key_value = find_key(current_arg);
+										if(!cur_gpio_mapping.key_value){
+											READ_CONF_FILE_PRINTF("		Could not find Key: %s\n", current_arg);
+											add_current_mapping = false;
+										}
+										break;
+									case TYPE_MAPPING_SHELL_COMMAND:
+										cur_gpio_mapping.shell_command = malloc(strlen(current_arg)*sizeof(char));
+										strcpy(cur_gpio_mapping.shell_command, current_arg);
+										break;
+									default:
+										READ_CONF_FILE_PRINTF("		%d is not a valid mapping type\n", cur_gpio_mapping.type_mapping);
+										add_current_mapping = false;
+										break;
+								}
+								break;
+							case MAPPING_ARG_STR_HELP_PIN_NAME:
+								if(!strlen(current_arg)) continue;
+								cur_gpio_mapping.pin_help_str = malloc(strlen(current_arg)*sizeof(char));
+								strcpy(cur_gpio_mapping.pin_help_str, current_arg);
+								break;
+							case MAPPING_ARG_STR_HELP_PIN_FCT:
+								if(!strlen(current_arg)) continue;
+								cur_gpio_mapping.fct_help_str = malloc(strlen(current_arg)*sizeof(char));
+								strcpy(cur_gpio_mapping.fct_help_str, current_arg);
+								break;
+							default:
+								break;
+						}
+
+
+						//next arg
+						token_comma = strtok_r(NULL, ",", &end_ln);
+						cur_arg_idx++;
+					}
+
+					if(add_current_mapping){
+						push(&head_chained_list_mapping_gpio, &cur_gpio_mapping);
+						READ_CONF_FILE_PRINTF("Current Mapping added successfully\n\n");
+					}
+					else{
+						READ_CONF_FILE_PRINTF("Current Mapping not added\n\n");
+					}
+				}
+			}
+		}
+	}
+
+	READ_CONF_FILE_PRINTF("Sorting Chained list...\n");
+	bubbleSort(head_chained_list_mapping_gpio);
+	print_all_chained_list(head_chained_list_mapping_gpio);
+	print_gpios(gpio_pins, count_valid_gpios);
+
+	if(fp){
+		fclose(fp);
+	}
+
+	/* Return parameters */ 
+	*chained_list_mapping = head_chained_list_mapping_gpio;
+	*nb_valid_gpios = count_valid_gpios;
+	*valid_gpio_pins = gpio_pins;
+ }
+
+
+/* Print all chained list content */
+void print_all_chained_list(STRUCT_MAPPED_GPIO * head){
+    STRUCT_MAPPED_GPIO * current = head;
+    int idx = 0;
+
+	READ_CONF_FILE_PRINTF("Printing Chained list:\n ");
+    while (current != NULL) {
+        READ_CONF_FILE_PRINTF("Chained list Mapping GPIOs, idx: %d\n", idx);
+        
+        print_chained_list_node(current);
+
+        idx++;
+        current = current->next_mapped_gpio;
+    }
+}
+
+
+/* Print one chained list node */
+void print_chained_list_node(STRUCT_MAPPED_GPIO * node){
+    // Print Pins:
+   	if(node->nb_simultaneous_pins > 1){
+	    READ_CONF_FILE_PRINTF("		%d Simultaneous pins at following idx: [", node->nb_simultaneous_pins);
+	    int i;
+	    for (i=0; i < node->nb_simultaneous_pins; i++){
+	       	READ_CONF_FILE_PRINTF("%d%s", node->pins_idx[i], (i==node->nb_simultaneous_pins-1)?"]\n":",");
+	    }
+    }
+    else{
+       	READ_CONF_FILE_PRINTF("		idx pin: %d\n", node->pins_idx[0]);
+    }
+
+    // Type mapping and Value
+    if (node->type_mapping == TYPE_MAPPING_KEYBOARD){
+        READ_CONF_FILE_PRINTF("		Type mapping: TYPE_MAPPING_KEYBOARD\n");
+        READ_CONF_FILE_PRINTF("		Key: %d\n", node->key_value);
+   }
+    else if (node->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
+        READ_CONF_FILE_PRINTF("		Type mapping: TYPE_MAPPING_SHELL_COMMAND\n");
+		READ_CONF_FILE_PRINTF("		Shell command: %s\n", node->shell_command);
+    }
+
+    // Pin help String
+    if(node->pin_help_str[0]){
+        READ_CONF_FILE_PRINTF("		Pins: %s\n", node->pin_help_str);
+   	}
+
+    // Function help String
+    if(node->fct_help_str[0]){
+        READ_CONF_FILE_PRINTF("		Function: %s\n", node->fct_help_str);
+    }
+}
+
+void print_gpios(int * valid_gpio_pins, int nb_valid_gpios){
+	READ_CONF_FILE_PRINTF("GPIO pins:\n[");
+	for(int i = 0; i< nb_valid_gpios; i++) {
+		READ_CONF_FILE_PRINTF("%d%s", valid_gpio_pins[i], (i==nb_valid_gpios-1)?"]\n":",");
+	}
+}

+ 74 - 0
read_conf_file.h

@@ -0,0 +1,74 @@
+#ifndef _READ_CONF_FILE_H_
+#define _READ_CONF_FILE_H_
+
+
+/****************************************************************
+* Includes
+****************************************************************/
+#include <stdbool.h>
+
+/****************************************************************
+* Defines
+****************************************************************/
+#define MAX_NUM_GPIO 					32
+
+#define MAX_SIMULTANEOUS_GPIO			12
+
+#define MAX_LENGTH_STR_PINS				48
+#define MAX_LENGTH_STR_TYPE				16
+#define MAX_LENGTH_STR_VALUE			256
+#define MAX_LENGTH_STR_HELP_PIN_NAME	48
+#define MAX_LENGTH_STR_HELP_PIN_FCT		256
+#define MAX_LN_LENGTH 					(MAX_LENGTH_STR_PINS+\
+										MAX_LENGTH_STR_TYPE+\
+										MAX_LENGTH_STR_VALUE+\
+										MAX_LENGTH_STR_HELP_PIN_NAME+\
+										MAX_LENGTH_STR_HELP_PIN_FCT)
+
+typedef enum{
+	TYPE_MAPPING_KEYBOARD,
+	TYPE_MAPPING_SHELL_COMMAND,
+	NB_TYPE_MAPPING,
+} ENUM_TYPE_MAPPING;
+
+
+typedef enum{
+	MAPPING_ARG_PINS = 0,
+	MAPPING_ARG_TYPE,
+	MAPPING_ARG_VALUE,
+	MAPPING_ARG_STR_HELP_PIN_NAME,
+	MAPPING_ARG_STR_HELP_PIN_FCT,
+	NB_MAPPING_ARG_NAMES,
+} ENUM_MAPPING_ARGS_NAMES;
+
+
+typedef struct{
+	char name[32];
+	int code;
+}key_names_s;
+
+
+typedef struct gpio_mapping_s{
+	int pins_idx[MAX_SIMULTANEOUS_GPIO];
+	int nb_simultaneous_pins;
+	ENUM_TYPE_MAPPING type_mapping;
+	int key_value; 
+	char *shell_command;
+	char *pin_help_str;
+	char *fct_help_str;
+	struct gpio_mapping_s * next_mapped_gpio;
+	bool activated;
+}STRUCT_MAPPED_GPIO;
+
+
+
+/****************************************************************
+* Public functions
+****************************************************************/
+void get_mapping_from_conf_file(STRUCT_MAPPED_GPIO ** chained_list_mapping, 
+	int* nb_valid_gpios, int ** valid_gpio_pins);
+void print_all_chained_list(STRUCT_MAPPED_GPIO * head);
+void print_chained_list_node(STRUCT_MAPPED_GPIO * node);
+void print_gpios(int * valid_gpio_pins, int nb_valid_gpios);
+
+#endif	//_READ_CONF_FILE_H_

+ 230 - 0
uinput.c

@@ -0,0 +1,230 @@
+/**** uinput.c *****************************/
+/* M. Moller   2013-01-16                  */
+/*   Universal RPi GPIO keyboard daemon    */
+/*******************************************/
+
+/*
+   Copyright (C) 2013 Michael Moller.
+   This file is part of the Universal Raspberry Pi GPIO keyboard daemon.
+
+   This is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <linux/input.h>
+#include <linux/uinput.h>
+//#include "config.h"
+//include "daemon.h"
+#include "uinput.h"
+
+static int sendRel(int dx, int dy);
+static int sendSync(void);
+
+static struct input_event     uidev_ev;
+static int uidev_fd;
+/*static keyinfo_s lastkey;*/
+
+#define die(str, args...) do { \
+        perror(str); \
+        return(EXIT_FAILURE); \
+    } while(0)
+
+#define DEBUG_UINPUT_PRINTF (0)
+#if DEBUG_UINPUT_PRINTF
+  #define UINPUT_PRINTF(...) printf(__VA_ARGS__);
+#else
+  #define UINPUT_PRINTF(...)
+#endif
+
+int init_uinput(void)
+{
+  int fd;
+  struct uinput_user_dev uidev;
+  int i;
+
+  fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
+  if(fd < 0)
+    die("/dev/uinput");
+
+  if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
+    die("error: ioctl");
+  if(ioctl(fd, UI_SET_EVBIT, EV_REP) < 0)
+    die("error: ioctl");
+  if(ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0)
+    die("error: ioctl");
+
+  if(ioctl(fd, UI_SET_EVBIT, EV_REL) < 0)
+    die("error: ioctl");
+  if(ioctl(fd, UI_SET_RELBIT, REL_X) < 0)
+    die("error: ioctl");
+  if(ioctl(fd, UI_SET_RELBIT, REL_Y) < 0)
+    die("error: ioctl");
+
+  /* don't forget to add all the keys! */
+  for(i=0; i<256; i++){
+    if(ioctl(fd, UI_SET_KEYBIT, i) < 0)
+      die("error: ioctl");
+  }
+
+  memset(&uidev, 0, sizeof(uidev));
+  snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
+  uidev.id.bustype = BUS_USB;
+  uidev.id.vendor  = 0x1;
+  uidev.id.product = 0x1;
+  uidev.id.version = 1;
+
+  /*if(write(fd, &uidev, sizeof(uidev)) < 0)
+    die("error: write");*/
+  
+  if(ioctl(fd, UI_DEV_SETUP, &uidev) < 0)
+	die("error: ioctl");
+	
+  if(ioctl(fd, UI_DEV_CREATE) < 0)
+    die("error: ioctl");
+
+  uidev_fd = fd;
+  
+  sleep(1);
+
+  return 0;
+}
+
+int test_uinput(void)
+{
+  int                    dx, dy;
+  int                    i,k;
+
+  //srand(time(NULL));
+  int op = 1;
+
+  while(1) {
+    //switch(rand() % 4) {
+    switch(op) {
+    case 0:
+      dx = -10;
+      dy = -1;
+      break;
+    case 1:
+      dx = 10;
+      dy = 1;
+      break;
+    case 2:
+      dx = -1;
+      dy = 10;
+      break;
+    case 3:
+      dx = 1;
+      dy = -10;
+      break;
+    }
+
+    /*k = send_gpio_keys(21, 1);
+    sendKey(k, 0);*/
+    sendKey(KEY_D, 0);
+
+    for(i = 0; i < 20; i++) {
+      //sendKey(KEY_D, 1);
+      //sendKey(KEY_D, 0);
+      sendRel(dx, dy);
+
+      usleep(15000);
+    }
+
+    sleep(10);
+  }
+}
+
+int close_uinput(void)
+{
+  sleep(2);
+
+  if(ioctl(uidev_fd, UI_DEV_DESTROY) < 0)
+    die("error: ioctl");
+
+  close(uidev_fd);
+
+  return 0;
+}
+
+int sendKey(int key, int value)
+{
+  struct input_event ie;
+  //memset(&uidev_ev, 0, sizeof(struct input_event));
+  //gettimeofday(&uidev_ev.time, NULL);
+  ie.type = EV_KEY;
+  ie.code = key;
+  ie.value = value;
+  ie.time.tv_sec = 0;
+  ie.time.tv_usec = 0;
+  UINPUT_PRINTF("sendKey: %d = %d\n", key, value);
+  if(write(uidev_fd, &ie, sizeof(struct input_event)) < 0)
+    die("error: write");
+
+  sendSync();
+
+  return 0;
+}
+
+int sendKeyAndStopKey(int key)
+{
+  sendKey(key, 1);
+  sendKey(key, 0);
+
+  return 0;
+}
+
+static int sendRel(int dx, int dy)
+{
+  memset(&uidev_ev, 0, sizeof(struct input_event));
+  uidev_ev.type = EV_REL;
+  uidev_ev.code = REL_X;
+  uidev_ev.value = dx;
+  if(write(uidev_fd, &uidev_ev, sizeof(struct input_event)) < 0)
+    die("error: write");
+
+  memset(&uidev_ev, 0, sizeof(struct input_event));
+  uidev_ev.type = EV_REL;
+  uidev_ev.code = REL_Y;
+  uidev_ev.value = dy;
+  if(write(uidev_fd, &uidev_ev, sizeof(struct input_event)) < 0)
+    die("error: write");
+
+  sendSync();
+
+  return 0;
+}
+
+static int sendSync(void)
+{
+  UINPUT_PRINTF("sendSync\n");
+  //memset(&uidev_ev, 0, sizeof(struct input_event));
+  struct input_event ie;
+  ie.type = EV_SYN;
+  ie.code = SYN_REPORT;
+  ie.value = 0;
+  ie.time.tv_sec = 0;
+  ie.time.tv_usec = 0;
+  if(write(uidev_fd, &ie, sizeof(struct input_event)) < 0)
+    die("error: sendSync - write");
+
+  return 0;
+}
+

+ 37 - 0
uinput.h

@@ -0,0 +1,37 @@
+/**** uinput.h *****************************/
+/* M. Moller   2013-01-16                  */
+/*   Universal RPi GPIO keyboard daemon      */
+/*******************************************/
+
+/*
+   Copyright (C) 2013 Michael Moller.
+   This file is part of the Universal Raspberry Pi GPIO keyboard daemon.
+
+   This is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  
+*/
+
+#ifndef _UINPUT_H_
+#define _UINPUT_H_
+
+int init_uinput(void);
+int test_uinput(void);
+int close_uinput(void);
+int send_gpio_keys(int gpio, int value);
+int sendKey(int key, int value);
+int sendKeyAndStopKey(int key);
+//void get_last_key(keyinfo_s *kp);
+
+#endif   //_UINPUT_H_