diff --git a/Makefile.common b/Makefile.common index 727d1ea7ad..24de83fe49 100644 --- a/Makefile.common +++ b/Makefile.common @@ -201,6 +201,8 @@ OBJ += frontend/frontend.o \ audio/audio_driver.o \ $(LIBRETRO_COMM_DIR)/audio/audio_mixer.o \ input/input_driver.o \ + led/led_driver.o \ + led/null_led_driver.o \ gfx/video_coord_array.o \ gfx/video_display_server.o \ gfx/video_driver.o \ @@ -1657,3 +1659,7 @@ OBJ += libretro-common/audio/dsp_filters/echo.o \ libretro-common/audio/dsp_filters/reverb.o \ libretro-common/audio/dsp_filters/wahwah.o endif + +ifeq ($(HAVE_RPILED), 1) + OBJ += led/rpi_led_driver.o +endif diff --git a/configuration.c b/configuration.c index 6138b56aab..a0c7005568 100644 --- a/configuration.c +++ b/configuration.c @@ -41,6 +41,7 @@ #include "config.features.h" #include "input/input_keymaps.h" #include "input/input_remapping.h" +#include "led/led_defines.h" #include "defaults.h" #include "core.h" #include "dirs.h" @@ -885,6 +886,18 @@ const char *config_get_default_wifi(void) return "null"; } +/** + * config_get_default_led: + * + * Gets default led driver. + * + * Returns: Default led driver. + **/ +const char *config_get_default_led(void) +{ + return "null"; +} + /** * config_get_default_location: * @@ -982,7 +995,7 @@ static struct config_array_setting *populate_settings_array(settings_t *settings SETTING_ARRAY("bundle_assets_src_path", settings->arrays.bundle_assets_src, false, NULL, true); SETTING_ARRAY("bundle_assets_dst_path", settings->arrays.bundle_assets_dst, false, NULL, true); SETTING_ARRAY("bundle_assets_dst_path_subdir", settings->arrays.bundle_assets_dst_subdir, false, NULL, true); - + SETTING_ARRAY("led_driver", settings->arrays.led_driver, false, NULL, true); *size = count; return tmp; @@ -1429,7 +1442,7 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, SETTING_UINT("video_msg_bgcolor_red", &settings->uints.video_msg_bgcolor_red, true, message_bgcolor_red, false); SETTING_UINT("video_msg_bgcolor_green", &settings->uints.video_msg_bgcolor_green, true, message_bgcolor_green, false); SETTING_UINT("video_msg_bgcolor_blue", &settings->uints.video_msg_bgcolor_blue, true, message_bgcolor_blue, false); - + *size = count; return tmp; @@ -1479,6 +1492,7 @@ static void config_set_defaults(void) #endif const char *def_camera = config_get_default_camera(); const char *def_wifi = config_get_default_wifi(); + const char *def_led = config_get_default_led(); const char *def_location = config_get_default_location(); const char *def_record = config_get_default_record(); struct config_float_setting *float_settings = populate_settings_float (settings, &float_settings_size); @@ -1536,6 +1550,9 @@ static void config_set_defaults(void) if (def_wifi) strlcpy(settings->arrays.wifi_driver, def_wifi, sizeof(settings->arrays.wifi_driver)); + if (def_led) + strlcpy(settings->arrays.led_driver, + def_led, sizeof(settings->arrays.led_driver)); if (def_location) strlcpy(settings->arrays.location_driver, def_location, sizeof(settings->arrays.location_driver)); @@ -2455,6 +2472,18 @@ static bool config_load_file(const char *path, bool set_defaults, CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[i], buf); } } + + /* LED map for use by the led driver */ + for (i = 0; i < MAX_LEDS; i++) + { + char buf[64]; + + buf[0] = '\0'; + + snprintf(buf, sizeof(buf), "led%u_map", i + 1); + CONFIG_GET_INT_BASE(conf, settings, uints.led_map[i], buf); + } + { /* ugly hack around C89 not allowing mixing declarations and code */ int buffer_size = 0; diff --git a/configuration.h b/configuration.h index 881e94afee..eb73bb1819 100644 --- a/configuration.h +++ b/configuration.h @@ -27,6 +27,7 @@ #include "gfx/video_driver.h" #include "input/input_defines.h" +#include "led/led_defines.h" #define configuration_set_float(settings, var, newvar) \ { \ @@ -368,6 +369,8 @@ typedef struct settings unsigned input_keymapper_ids[RARCH_CUSTOM_BIND_LIST_END]; unsigned input_remap_ids[MAX_USERS][RARCH_CUSTOM_BIND_LIST_END]; + + unsigned led_map[MAX_LEDS]; } uints; struct @@ -378,6 +381,7 @@ typedef struct settings char record_driver[32]; char camera_driver[32]; char wifi_driver[32]; + char led_driver[32]; char location_driver[32]; char menu_driver[32]; char cheevos_username[32]; diff --git a/driver.c b/driver.c index 7cadd24508..67b6dfbb2e 100644 --- a/driver.c +++ b/driver.c @@ -37,6 +37,7 @@ #include "record/record_driver.h" #include "location/location_driver.h" #include "wifi/wifi_driver.h" +#include "led/led_driver.h" #include "configuration.h" #include "core.h" #include "core_info.h" @@ -316,6 +317,7 @@ static bool driver_update_system_av_info(const struct retro_system_av_info *info void drivers_init(int flags) { bool video_is_threaded = false; + if (flags & DRIVER_VIDEO_MASK) video_driver_unset_own_driver(); if (flags & DRIVER_AUDIO_MASK) @@ -383,6 +385,11 @@ void drivers_init(int flags) if (input_driver_is_nonblock_state()) driver_set_nonblock_state(); } + + if (flags & DRIVER_LED_MASK) + { + led_driver_init(); + } } @@ -429,6 +436,9 @@ void driver_uninit(int flags) if ((flags & DRIVER_WIFI_MASK) && !wifi_driver_ctl(RARCH_WIFI_CTL_OWNS_DRIVER, NULL)) wifi_driver_ctl(RARCH_WIFI_CTL_DEINIT, NULL); + if (flags & DRIVER_LED) + led_driver_free(); + if (flags & DRIVERS_VIDEO_INPUT) video_driver_free(); @@ -440,7 +450,7 @@ void driver_uninit(int flags) if ((flags & DRIVER_INPUT_MASK) && !input_driver_owns_driver()) input_driver_destroy_data(); - + if ((flags & DRIVER_AUDIO_MASK) && !audio_driver_owns_driver()) audio_driver_destroy_data(); } diff --git a/driver.h b/driver.h index 49d61bbf07..dbc56eb599 100644 --- a/driver.h +++ b/driver.h @@ -34,7 +34,8 @@ RETRO_BEGIN_DECLS | DRIVER_LOCATION_MASK \ | DRIVER_MENU_MASK \ | DRIVERS_VIDEO_INPUT_MASK \ - | DRIVER_WIFI_MASK ) + | DRIVER_WIFI_MASK \ + | DRIVER_LED_MASK ) #define DRIVERS_CMD_ALL_BUT_MENU \ ( DRIVER_AUDIO_MASK \ @@ -43,7 +44,8 @@ RETRO_BEGIN_DECLS | DRIVER_CAMERA_MASK \ | DRIVER_LOCATION_MASK \ | DRIVERS_VIDEO_INPUT_MASK \ - | DRIVER_WIFI_MASK ) + | DRIVER_WIFI_MASK \ + | DRIVER_LED_MASK ) enum { @@ -54,7 +56,8 @@ enum DRIVER_LOCATION, DRIVER_MENU, DRIVERS_VIDEO_INPUT, - DRIVER_WIFI + DRIVER_WIFI, + DRIVER_LED }; enum @@ -66,7 +69,8 @@ enum DRIVER_LOCATION_MASK = 1 << DRIVER_LOCATION, DRIVER_MENU_MASK = 1 << DRIVER_MENU, DRIVERS_VIDEO_INPUT_MASK = 1 << DRIVERS_VIDEO_INPUT, - DRIVER_WIFI_MASK = 1 << DRIVER_WIFI + DRIVER_WIFI_MASK = 1 << DRIVER_WIFI, + DRIVER_LED_MASK = 1 << DRIVER_LED }; enum driver_ctl_state diff --git a/dynamic.c b/dynamic.c index 2fdc566eb2..3a75ac0141 100644 --- a/dynamic.c +++ b/dynamic.c @@ -54,6 +54,7 @@ #include "driver.h" #include "performance_counters.h" #include "gfx/video_driver.h" +#include "led/led_driver.h" #include "cores/internal_cores.h" #include "frontend/frontend_driver.h" @@ -1680,6 +1681,13 @@ bool rarch_environment_cb(unsigned cmd, void *data) break; } + case RETRO_ENVIRONMENT_GET_LED_INTERFACE: + { + struct retro_led_interface *ledintf = + (struct retro_led_interface *)data; + ledintf->set_led_state = led_driver_set_led; + } + default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); return false; diff --git a/led/led_defines.h b/led/led_defines.h new file mode 100644 index 0000000000..720a887838 --- /dev/null +++ b/led/led_defines.h @@ -0,0 +1,6 @@ +#ifndef __OUTPUT_DEFINES__H +#define __OUTPUT_DEFINES__H + +#define MAX_LEDS 32 + +#endif diff --git a/led/led_driver.c b/led/led_driver.c new file mode 100644 index 0000000000..522218cc03 --- /dev/null +++ b/led/led_driver.c @@ -0,0 +1,56 @@ +#include +#include "led_driver.h" +#include "configuration.h" +#include "verbosity.h" + +extern led_driver_t *null_led_driver; +#if HAVE_RPILED +extern led_driver_t *rpi_led_driver; +#endif +led_driver_t *current_led_driver = NULL; + +bool led_driver_init(void) +{ + char *drivername = NULL; + settings_t *settings = config_get_ptr(); + drivername = settings->arrays.led_driver; + + if(drivername == NULL) + drivername = "null"; + +#if HAVE_RPILED + if(!strcmp("rpi",drivername)) + { + current_led_driver = rpi_led_driver; + } + else +#endif + { + current_led_driver = null_led_driver; + } + + RARCH_LOG("[LED]: LED driver = '%s' %p\n",drivername,current_led_driver); + + if(current_led_driver != NULL) + { + (*current_led_driver->init)(); + } + + return true; +} + +void led_driver_free(void) +{ + if(current_led_driver != NULL) + { + (*current_led_driver->free)(); + } +} + +void led_driver_set_led(int led,int value) +{ + if(current_led_driver != NULL) + { + (*current_led_driver->set_led)(led,value); + } +} diff --git a/led/led_driver.h b/led/led_driver.h new file mode 100644 index 0000000000..ba79f5b3a0 --- /dev/null +++ b/led/led_driver.h @@ -0,0 +1,35 @@ +#ifndef __LED_DRIVER__H +#define __LED_DRIVER__H + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "../msg_hash.h" + +RETRO_BEGIN_DECLS + +typedef struct led_driver +{ + void (*init)(void); + void (*free)(void); + void (*set_led)(int led,int value); +} led_driver_t; + +bool led_driver_init(void); + +void led_driver_free(void); + +void led_driver_set_led(int led,int value); + +#endif diff --git a/led/null_led_driver.c b/led/null_led_driver.c new file mode 100644 index 0000000000..0efbe34a95 --- /dev/null +++ b/led/null_led_driver.c @@ -0,0 +1,12 @@ +#include "led_driver.h" +#include "verbosity.h" + +static void null_init(void) +{ + RARCH_LOG("[LED]: using null LED driver\n"); +} +static void null_free(void) {} +static void null_set(int led,int state) {} + +static led_driver_t null_led_driver_ins = { null_init, null_free, null_set }; +led_driver_t *null_led_driver = &null_led_driver_ins; diff --git a/led/rpi_led_driver.c b/led/rpi_led_driver.c new file mode 100644 index 0000000000..9f59b5bb8e --- /dev/null +++ b/led/rpi_led_driver.c @@ -0,0 +1,107 @@ +#include +#include "led_driver.h" +#include "led_defines.h" + +#include "configuration.h" +#include "verbosity.h" + +typedef struct +{ + int setup[MAX_LEDS]; + int map[MAX_LEDS]; +} rpiled_t; + +static rpiled_t curins; +static rpiled_t *cur = &curins; + +static void rpi_init(void) +{ + int i; + settings_t *settings = config_get_ptr(); + RARCH_LOG("[LED]: rpi LED driver init\n"); + for(i=0;isetup[i] = 0; + cur->map[i] = settings->uints.led_map[i]; + RARCH_LOG("[LED]: rpi map[%d]=%d\n",i,cur->map[i]); + } +} +static void rpi_free(void) +{ + RARCH_LOG("[LED]: rpi LED driver free\n"); +} + +static int set_gpio(int gpio,int value) +{ + FILE *fp; + char buf[256]; + sprintf(buf,"/sys/class/gpio/%d/value",gpio); + fp = fopen(buf,"w"); + if(fp == NULL) + { + RARCH_WARN("[LED]: failed to set GPIO %d\n",gpio); + return -1; + } + fprintf(fp,"%d\n",value?1:0); + fclose(fp); + return 1; +} + + +static int setup_gpio(int gpio) { + FILE *fp; + char buf[256]; + sprintf(buf,"/sys/class/gpio/%d/direction",gpio); + fp = fopen(buf,"w"); + if(fp == NULL) { + sprintf(buf,"/sys/class/gpio/export"); + fp = fopen(buf,"w"); + if(fp == NULL) + { + RARCH_WARN("[LED]: failed to export GPIO %d\n",gpio); + return -1; + } + fprintf(fp,"%d\n",gpio); + fclose(fp); + + sprintf(buf,"/sys/class/gpio/%d/direction",gpio); + fp = fopen(buf,"w"); + } + if(fp == NULL) + { + RARCH_WARN("[LED]: failed to set direction GPIO %d\n",gpio); + return -1; + } + fprintf(fp,"out\n"); + fclose(fp); + return 1; + +} +static void rpi_set(int led,int state) +{ + int gpio = 0; + if((led < 0) || (led >= MAX_LEDS)) + { + RARCH_WARN("[LED]: invalid led %d\n",led); + return; + } + gpio = cur->map[led]; + if(gpio <= 0) return; + + if(cur->setup[led]==0) + { + RARCH_LOG("[LED]: rpi setup led %d gpio %d\n",led,gpio,state); + cur->setup[led] = setup_gpio(gpio); + if(cur->setup[led] <= 0) + { + RARCH_WARN("[LED]: failed to setup led %d gpio %d\n",led,gpio); + } + } + if(cur->setup[led] > 0) + { + RARCH_LOG("[LED]: rpi LED driver set led %d gpio %d = %d\n",led,gpio,state); + set_gpio(gpio,state); + } +} + +static led_driver_t rpi_led_driver_ins = { rpi_init, rpi_free, rpi_set }; +led_driver_t *rpi_led_driver = &rpi_led_driver_ins; diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 315123c913..02e3cc483c 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -1094,6 +1094,21 @@ struct retro_hw_render_interface enum retro_hw_render_interface_type interface_type; unsigned interface_version; }; + + +#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_led_interface * -- + * Gets an interface which is used by a libretro core to set + * state of LEDs. + */ + +typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state); +struct retro_led_interface +{ + retro_set_led_state_t set_led_state; +}; + + #define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* const struct retro_hw_render_interface ** -- * Returns an API specific rendering interface for accessing API specific data. diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 615c36853c..45eef59c3a 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -232,6 +232,7 @@ check_lib '' OSS_LIB -lossaudio if [ "$OS" = 'Linux' ]; then HAVE_TINYALSA=yes + HAVE_RPILED=yes fi if [ "$OS" = 'Darwin' ]; then