From 84a71ea13320b834e512d7d51a19bfc841b15a50 Mon Sep 17 00:00:00 2001
From: jdgleaver <james@leaver.myzen.co.uk>
Date: Tue, 14 Jul 2020 17:44:27 +0100
Subject: [PATCH] Rewrite 'task_autodetect.c': Ensure thread safety +
 clean-ups/rationalisation

---
 configuration.c                        |    5 +-
 input/drivers_joypad/linuxraw_joypad.c |    4 +-
 input/drivers_joypad/parport_joypad.c  |    4 +-
 input/drivers_joypad/udev_joypad.c     |    6 +-
 input/input_driver.h                   |   60 +-
 menu/cbs/menu_cbs_sublabel.c           |    6 +-
 menu/menu_displaylist.c                |    8 +-
 menu/menu_setting.c                    |    2 +-
 retroarch.c                            |  283 ++++--
 tasks/task_autodetect.c                | 1215 +++++++++++++++---------
 tasks/task_autodetect_blissbox.c       |   29 +-
 tasks/tasks_internal.h                 |   38 +-
 12 files changed, 1033 insertions(+), 627 deletions(-)

diff --git a/configuration.c b/configuration.c
index b3941b4657..073956aa2b 100644
--- a/configuration.c
+++ b/configuration.c
@@ -2270,7 +2270,6 @@ void config_set_defaults(void *data)
 #ifdef HAVE_CONFIGFILE
    input_remapping_set_defaults(true);
 #endif
-   input_autoconfigure_reset();
 
    /* Verify that binds are in proper order. */
    for (i = 0; i < MAX_USERS; i++)
@@ -3898,8 +3897,8 @@ bool config_save_autoconf_profile(const char *path, unsigned user)
    config_set_string(conf, "input_device",
          input_config_get_device_name(user));
 
-   pid_user = input_config_get_pid(user);
-   vid_user = input_config_get_vid(user);
+   pid_user = input_config_get_device_pid(user);
+   vid_user = input_config_get_device_vid(user);
 
    if (pid_user && vid_user)
    {
diff --git a/input/drivers_joypad/linuxraw_joypad.c b/input/drivers_joypad/linuxraw_joypad.c
index c43c50eae7..103a2cf8dd 100644
--- a/input/drivers_joypad/linuxraw_joypad.c
+++ b/input/drivers_joypad/linuxraw_joypad.c
@@ -99,7 +99,7 @@ static bool linuxraw_joypad_init_pad(const char *path,
       struct epoll_event event;
 
       ioctl(pad->fd,
-               JSIOCGNAME(sizeof(input_device_names[0])), pad->ident);
+               JSIOCGNAME(input_config_get_device_name_size(0)), pad->ident);
 
       event.events             = EPOLLIN;
       event.data.ptr           = pad;
@@ -234,7 +234,7 @@ static bool linuxraw_joypad_init(void *data)
       path[0]                     = '\0';
 
       pad->fd                     = -1;
-      pad->ident                  = input_device_names[i];
+      pad->ident                  = input_config_get_device_name_ptr(i);
 
       snprintf(path, sizeof(path), "/dev/input/js%u", i);
 
diff --git a/input/drivers_joypad/parport_joypad.c b/input/drivers_joypad/parport_joypad.c
index 44eeb6784b..ec37609c23 100644
--- a/input/drivers_joypad/parport_joypad.c
+++ b/input/drivers_joypad/parport_joypad.c
@@ -184,7 +184,7 @@ static bool parport_joypad_init_pad(
       if (!set_control)
          RARCH_WARN("[Joypad]: Failed to clear nStrobe and nIRQ bits on %s\n", path);
 
-      strlcpy(pad->ident, path, sizeof(input_device_names[0]));
+      strlcpy(pad->ident, path, input_config_get_device_name_size(0));
 
       for (i = 0; i < PARPORT_NUM_BUTTONS; i++)
          pad->button_enable[i] = true;
@@ -246,7 +246,7 @@ static bool parport_joypad_init(void *data)
       struct parport_joypad *pad = &parport_pads[i];
 
       pad->fd    = -1;
-      pad->ident = input_device_names[i];
+      pad->ident = input_config_get_device_name_ptr(i);
 
       snprintf(path, sizeof(path), "/dev/parport%u", i);
 
diff --git a/input/drivers_joypad/udev_joypad.c b/input/drivers_joypad/udev_joypad.c
index 31ba12101c..647ceb044e 100644
--- a/input/drivers_joypad/udev_joypad.c
+++ b/input/drivers_joypad/udev_joypad.c
@@ -161,8 +161,12 @@ static int udev_add_pad(struct udev_device *dev, unsigned p, int fd, const char
    unsigned long keybit[NBITS(KEY_MAX)] = {0};
    unsigned long absbit[NBITS(ABS_MAX)] = {0};
    unsigned long ffbit[NBITS(FF_MAX)]   = {0};
+   const char *device_name              = input_config_get_device_name(p);
 
-   strlcpy(pad->ident, input_device_names[p], sizeof(pad->ident));
+   if (string_is_empty(device_name))
+      pad->ident[0] = '\0';
+   else
+      strlcpy(pad->ident, device_name, sizeof(pad->ident));
 
    /* Failed to get pad name */
    if (ioctl(fd, EVIOCGNAME(sizeof(pad->ident)), pad->ident) < 0)
diff --git a/input/input_driver.h b/input/input_driver.h
index d79a2b8da7..975bc53adf 100644
--- a/input/input_driver.h
+++ b/input/input_driver.h
@@ -151,6 +151,18 @@ struct rarch_joypad_info
    float axis_threshold;
 };
 
+typedef struct
+{
+   char name[256];
+   char display_name[256];
+   char config_path[PATH_MAX_LENGTH];
+   char config_name[PATH_MAX_LENGTH];
+   uint16_t vid;
+   uint16_t pid;
+   bool autoconfigured;
+   unsigned name_index;
+} input_device_info_t;
+
 struct input_driver
 {
    /* Inits input driver.
@@ -390,7 +402,6 @@ void input_keyboard_event(bool down, unsigned code, uint32_t character,
 
 extern struct retro_keybind input_config_binds[MAX_USERS][RARCH_BIND_LIST_END];
 extern struct retro_keybind input_autoconf_binds[MAX_USERS][RARCH_BIND_LIST_END];
-extern char input_device_names[MAX_USERS][64];
 
 const char *input_config_bind_map_get_base(unsigned i);
 
@@ -428,23 +439,26 @@ unsigned input_config_translate_str_to_bind_id(const char *str);
 
 void config_read_keybinds_conf(void *data);
 
-void input_autoconfigure_joypad_conf(void *data, struct retro_keybind *binds);
+/* Note: 'data' is an object of type config_file_t
+ * > We assume it was done like this to avoid including
+ *   config_file.h... */
+void input_config_set_autoconfig_binds(unsigned port, void *data);
 
+/* Set input_device_info */
 void input_config_set_device_name(unsigned port, const char *name);
-
 void input_config_set_device_display_name(unsigned port, const char *name);
-
-void input_config_set_device_config_name(unsigned port, const char *name);
-
 void input_config_set_device_config_path(unsigned port, const char *path);
+void input_config_set_device_config_name(unsigned port, const char *name);
+void input_config_set_device_vid(unsigned port, uint16_t vid);
+void input_config_set_device_pid(unsigned port, uint16_t pid);
+void input_config_set_device_autoconfigured(unsigned port, bool autoconfigured);
+void input_config_set_device_name_index(unsigned port, unsigned name_index);
 
+/* Clear input_device_info */
 void input_config_clear_device_name(unsigned port);
-
 void input_config_clear_device_display_name(unsigned port);
-
-void input_config_clear_device_config_name(unsigned port);
-
 void input_config_clear_device_config_path(unsigned port);
+void input_config_clear_device_config_name(unsigned port);
 
 unsigned input_config_get_device_count(void);
 
@@ -454,32 +468,32 @@ unsigned input_config_get_device(unsigned port);
 
 void input_config_set_device(unsigned port, unsigned id);
 
+/* Get input_device_info */
 const char *input_config_get_device_name(unsigned port);
-
 const char *input_config_get_device_display_name(unsigned port);
-
-const char *input_config_get_device_config_name(unsigned port);
-
 const char *input_config_get_device_config_path(unsigned port);
+const char *input_config_get_device_config_name(unsigned port);
+uint16_t input_config_get_device_vid(unsigned port);
+uint16_t input_config_get_device_pid(unsigned port);
+bool input_config_get_device_autoconfigured(unsigned port);
+unsigned input_config_get_device_name_index(unsigned port);
 
-const char *input_config_get_device_config_port(unsigned port);
+/* TODO/FIXME: This is required by linuxraw_joypad.c
+ * and parport_joypad.c. These input drivers should
+ * be refactored such that this dubious low-level
+ * access is not required */
+char *input_config_get_device_name_ptr(unsigned port);
+size_t input_config_get_device_name_size(unsigned port);
 
 const struct retro_keybind *input_config_get_bind_auto(unsigned port, unsigned id);
 
-void input_config_set_pid(unsigned port, uint16_t pid);
-
-uint16_t input_config_get_pid(unsigned port);
-
-void input_config_set_vid(unsigned port, uint16_t vid);
-
-uint16_t input_config_get_vid(unsigned port);
-
 void input_config_save_keybinds_user(void *data, unsigned user);
 
 void input_config_save_keybind(void *data, const char *prefix,
       const char *base, const struct retro_keybind *bind,
       bool save_empty);
 
+void input_config_reset_autoconfig_binds(unsigned port);
 void input_config_reset(void);
 
 void set_connection_listener(pad_connection_listener_t *listener);
diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c
index 00b4c3439f..33fa33fbb9 100644
--- a/menu/cbs/menu_cbs_sublabel.c
+++ b/menu/cbs/menu_cbs_sublabel.c
@@ -866,13 +866,13 @@ static int action_bind_sublabel_systeminfo_controller_entry(
 
    for(controller = 0; controller < MAX_USERS; controller++)
    {
-      if (input_is_autoconfigured(controller))
+      if (input_config_get_device_autoconfigured(controller))
       {
             snprintf(tmp, sizeof(tmp), "%s #%d device name: %s (#%d)",
                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT),
                controller,
                input_config_get_device_name(controller),
-               input_autoconfigure_get_device_name_index(controller));
+               input_config_get_device_name_index(controller));
 
             if (string_is_equal(path, tmp))
                break;
@@ -881,7 +881,7 @@ static int action_bind_sublabel_systeminfo_controller_entry(
    snprintf(tmp, sizeof(tmp), "Device display name: %s\nDevice config name: %s\nDevice identifiers: %d/%d",
       input_config_get_device_display_name(controller) ? input_config_get_device_display_name(controller) : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
       input_config_get_device_display_name(controller) ? input_config_get_device_config_name(controller) : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
-      input_config_get_vid(controller), input_config_get_pid(controller));
+      input_config_get_device_vid(controller), input_config_get_device_pid(controller));
    strlcpy(s, tmp, len);
 
    return 0;
diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c
index b8a5d96418..324e21b4f2 100644
--- a/menu/menu_displaylist.c
+++ b/menu/menu_displaylist.c
@@ -1020,13 +1020,13 @@ static unsigned menu_displaylist_parse_system_info(file_list_t *list)
 
    for (controller = 0; controller < MAX_USERS; controller++)
    {
-      if (input_is_autoconfigured(controller))
+      if (input_config_get_device_autoconfigured(controller))
       {
          snprintf(tmp, sizeof(tmp), "%s #%d device name: %s (#%d)",
             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT),
             controller,
             input_config_get_device_name(controller),
-            input_autoconfigure_get_device_name_index(controller));
+            input_config_get_device_name_index(controller));
 
          if (menu_entries_append_enum(list, tmp, "",
             MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY,
@@ -1053,8 +1053,8 @@ static unsigned menu_displaylist_parse_system_info(file_list_t *list)
                MENU_SETTINGS_CORE_INFO_NONE, 0, 0))
                count++;
             snprintf(tmp, sizeof(tmp), " Device VID/PID: %d/%d",
-               input_config_get_vid(controller),
-               input_config_get_pid(controller));
+               input_config_get_device_vid(controller),
+               input_config_get_device_pid(controller));
             if (menu_entries_append_enum(list, tmp, "",
                MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY,
                MENU_SETTINGS_CORE_INFO_NONE, 0, 0))
diff --git a/menu/menu_setting.c b/menu/menu_setting.c
index ac940a6a69..480a08b995 100644
--- a/menu/menu_setting.c
+++ b/menu/menu_setting.c
@@ -6627,7 +6627,7 @@ static void get_string_representation_bind_device(rarch_setting_t *setting, char
 
       if (!string_is_empty(device_name))
       {
-         unsigned idx = input_autoconfigure_get_device_name_index(map);
+         unsigned idx = input_config_get_device_name_index(map);
 
          /*if idx is non-zero, it's part of a set*/
          if ( idx > 0)
diff --git a/retroarch.c b/retroarch.c
index c9c7e78749..eabc52322f 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -2137,9 +2137,6 @@ struct rarch_state
    uint8_t *midi_drv_input_buffer;
    uint8_t *midi_drv_output_buffer;
 
-   uint16_t input_config_vid[MAX_USERS];
-   uint16_t input_config_pid[MAX_USERS];
-
    size_t runloop_msg_queue_size;
    size_t recording_gpu_width;
    size_t recording_gpu_height;
@@ -2286,9 +2283,7 @@ struct rarch_state
    char current_savestate_dir[PATH_MAX_LENGTH];
    char dir_savestate[PATH_MAX_LENGTH];
 
-   char input_device_display_names[MAX_INPUT_DEVICES][64];
-   char input_device_config_names [MAX_INPUT_DEVICES][64];
-   char input_device_config_paths [MAX_INPUT_DEVICES][64];
+   input_device_info_t input_device_info[MAX_INPUT_DEVICES];
 
    char *osk_grid[45];
 #if defined(HAVE_RUNAHEAD)
@@ -2712,7 +2707,6 @@ bool discord_is_inited                                          = false;
 #endif
 uint64_t lifecycle_state                                        = 0;
 unsigned subsystem_current_count                                = 0;
-char        input_device_names        [MAX_INPUT_DEVICES][64];
 struct retro_keybind input_config_binds[MAX_USERS][RARCH_BIND_LIST_END];
 struct retro_keybind input_autoconf_binds[MAX_USERS][RARCH_BIND_LIST_END];
 struct retro_subsystem_info subsystem_data[SUBSYSTEM_MAX_SUBSYSTEMS];
@@ -24580,13 +24574,10 @@ static unsigned menu_event(
    bool menu_pointer_enable                        = settings->bools.menu_pointer_enable;
    bool swap_ok_cancel_btns                        = settings->bools.input_menu_swap_ok_cancel_buttons;
    bool menu_scroll_fast                           = settings->bools.menu_scroll_fast;
-   bool input_swap_override                        = input_autoconfigure_get_swap_override();
-   unsigned menu_ok_btn                            =
-         (!input_swap_override && swap_ok_cancel_btns) ?
-               RETRO_DEVICE_ID_JOYPAD_B : RETRO_DEVICE_ID_JOYPAD_A;
-   unsigned menu_cancel_btn                        =
-         (!input_swap_override && swap_ok_cancel_btns) ?
-               RETRO_DEVICE_ID_JOYPAD_A : RETRO_DEVICE_ID_JOYPAD_B;
+   unsigned menu_ok_btn                            = swap_ok_cancel_btns ?
+         RETRO_DEVICE_ID_JOYPAD_B : RETRO_DEVICE_ID_JOYPAD_A;
+   unsigned menu_cancel_btn                        = swap_ok_cancel_btns ?
+         RETRO_DEVICE_ID_JOYPAD_A : RETRO_DEVICE_ID_JOYPAD_B;
    unsigned ok_current                             = BIT256_GET_PTR(p_input, menu_ok_btn);
    unsigned ok_trigger                             = ok_current & ~ok_old;
 #ifdef HAVE_RGUI
@@ -27345,58 +27336,172 @@ void input_config_get_bind_string(char *buf,
       strlcat(buf, "---", size);
 }
 
+/* input_device_info wrappers START */
+
 unsigned input_config_get_device_count(void)
 {
+   struct rarch_state *p_rarch = &rarch_st;
    unsigned num_devices;
    for (num_devices = 0; num_devices < MAX_INPUT_DEVICES; ++num_devices)
    {
-      if (string_is_empty(input_device_names[num_devices]))
+      if (string_is_empty(p_rarch->input_device_info[num_devices].name))
          break;
    }
    return num_devices;
 }
 
+/* Adds an index to devices with the same name,
+ * so they can be uniquely identified in the
+ * frontend */
+static void input_config_reindex_device_names(void)
+{
+   unsigned i;
+   unsigned j;
+   unsigned name_index;
+
+   /* Reset device name indices */
+   for(i = 0; i < MAX_INPUT_DEVICES; i++)
+      input_config_set_device_name_index(i, 0);
+
+   /* Scan device names */
+   for(i = 0; i < MAX_INPUT_DEVICES; i++)
+   {
+      const char *device_name = input_config_get_device_name(i);
+
+      /* If current device name is empty, or a non-zero
+       * name index has already been assigned, continue
+       * to the next device */
+      if (string_is_empty(device_name) ||
+          (input_config_get_device_name_index(i) != 0))
+         continue;
+
+      /* > Uniquely named devices have a name index
+       *   of 0
+       * > Devices with the same name have a name
+       *   index starting from 1 */
+      name_index = 1;
+
+      /* Loop over all devices following the current
+       * selection */
+      for(j = i + 1; j < MAX_INPUT_DEVICES; j++)
+      {
+         const char *next_device_name = input_config_get_device_name(j);
+
+         if (string_is_empty(next_device_name))
+            continue;
+
+         /* Check if names match */
+         if (string_is_equal(device_name, next_device_name))
+         {
+            /* If this is the first match, set a starting
+             * index for the current device selection */
+            if (input_config_get_device_name_index(i) == 0)
+               input_config_set_device_name_index(i, name_index++);
+
+            /* Set name index for the next device
+             * (will keep incrementing as more matches
+             *  are found) */
+            input_config_set_device_name_index(j, name_index++);
+         }
+      }
+   }
+}
+
+/* > Get input_device_info */
+
 const char *input_config_get_device_name(unsigned port)
 {
-   if (string_is_empty(input_device_names[port]))
+   struct rarch_state *p_rarch = &rarch_st;
+   if (string_is_empty(p_rarch->input_device_info[port].name))
       return NULL;
-   return input_device_names[port];
+   return p_rarch->input_device_info[port].name;
 }
 
 const char *input_config_get_device_display_name(unsigned port)
 {
    struct rarch_state *p_rarch = &rarch_st;
-   if (string_is_empty(p_rarch->input_device_display_names[port]))
+   if (string_is_empty(p_rarch->input_device_info[port].display_name))
       return NULL;
-   return p_rarch->input_device_display_names[port];
+   return p_rarch->input_device_info[port].display_name;
 }
 
 const char *input_config_get_device_config_path(unsigned port)
 {
    struct rarch_state *p_rarch = &rarch_st;
-   if (string_is_empty(p_rarch->input_device_config_paths[port]))
+   if (string_is_empty(p_rarch->input_device_info[port].config_path))
       return NULL;
-   return p_rarch->input_device_config_paths[port];
+   return p_rarch->input_device_info[port].config_path;
 }
 
 const char *input_config_get_device_config_name(unsigned port)
 {
    struct rarch_state *p_rarch = &rarch_st;
-   if (string_is_empty(p_rarch->input_device_config_names[port]))
+   if (string_is_empty(p_rarch->input_device_info[port].config_name))
       return NULL;
-   return p_rarch->input_device_config_names[port];
+   return p_rarch->input_device_info[port].config_name;
 }
 
+uint16_t input_config_get_device_vid(unsigned port)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   return p_rarch->input_device_info[port].vid;
+}
+
+uint16_t input_config_get_device_pid(unsigned port)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   return p_rarch->input_device_info[port].pid;
+}
+
+bool input_config_get_device_autoconfigured(unsigned port)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   return p_rarch->input_device_info[port].autoconfigured;
+}
+
+unsigned input_config_get_device_name_index(unsigned port)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   return p_rarch->input_device_info[port].name_index;
+}
+
+/* TODO/FIXME: This is required by linuxraw_joypad.c
+ * and parport_joypad.c. These input drivers should
+ * be refactored such that this dubious low-level
+ * access is not required */
+char *input_config_get_device_name_ptr(unsigned port)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   return p_rarch->input_device_info[port].name;
+}
+
+size_t input_config_get_device_name_size(unsigned port)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   return sizeof(p_rarch->input_device_info[port].name);
+}
+
+/* > Set input_device_info */
+
 void input_config_set_device_name(unsigned port, const char *name)
 {
+   struct rarch_state *p_rarch = &rarch_st;
+
    if (string_is_empty(name))
       return;
 
-   strlcpy(input_device_names[port],
-         name,
-         sizeof(input_device_names[port]));
+   strlcpy(p_rarch->input_device_info[port].name, name,
+         sizeof(p_rarch->input_device_info[port].name));
 
-   input_autoconfigure_joypad_reindex_devices();
+   input_config_reindex_device_names();
+}
+
+void input_config_set_device_display_name(unsigned port, const char *name)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   if (!string_is_empty(name))
+      strlcpy(p_rarch->input_device_info[port].display_name, name,
+            sizeof(p_rarch->input_device_info[port].display_name));
 }
 
 void input_config_set_device_config_path(unsigned port, const char *path)
@@ -27410,9 +27515,9 @@ void input_config_set_device_config_path(unsigned port, const char *path)
 
       if (fill_pathname_parent_dir_name(parent_dir_name,
                path, sizeof(parent_dir_name)))
-         fill_pathname_join(p_rarch->input_device_config_paths[port],
+         fill_pathname_join(p_rarch->input_device_info[port].config_path,
                parent_dir_name, path_basename(path),
-               sizeof(p_rarch->input_device_config_paths[port]));
+               sizeof(p_rarch->input_device_info[port].config_path));
    }
 }
 
@@ -27420,44 +27525,63 @@ void input_config_set_device_config_name(unsigned port, const char *name)
 {
    struct rarch_state *p_rarch = &rarch_st;
    if (!string_is_empty(name))
-      strlcpy(p_rarch->input_device_config_names[port],
-            name,
-            sizeof(p_rarch->input_device_config_names[port]));
+      strlcpy(p_rarch->input_device_info[port].config_name, name,
+            sizeof(p_rarch->input_device_info[port].config_name));
 }
 
-void input_config_set_device_display_name(unsigned port, const char *name)
+void input_config_set_device_vid(unsigned port, uint16_t vid)
 {
    struct rarch_state *p_rarch = &rarch_st;
-   if (!string_is_empty(name))
-      strlcpy(p_rarch->input_device_display_names[port],
-            name,
-            sizeof(p_rarch->input_device_display_names[port]));
+   p_rarch->input_device_info[port].vid = vid;
 }
 
+void input_config_set_device_pid(unsigned port, uint16_t pid)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   p_rarch->input_device_info[port].pid = pid;
+}
+
+void input_config_set_device_autoconfigured(unsigned port, bool autoconfigured)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   p_rarch->input_device_info[port].autoconfigured = autoconfigured;
+}
+
+void input_config_set_device_name_index(unsigned port, unsigned name_index)
+{
+   struct rarch_state *p_rarch = &rarch_st;
+   p_rarch->input_device_info[port].name_index = name_index;
+}
+
+/* > Clear input_device_info */
+
 void input_config_clear_device_name(unsigned port)
 {
-   input_device_names[port][0] = '\0';
-   input_autoconfigure_joypad_reindex_devices();
+   struct rarch_state *p_rarch = &rarch_st;
+   p_rarch->input_device_info[port].name[0] = '\0';
+   input_config_reindex_device_names();
 }
 
 void input_config_clear_device_display_name(unsigned port)
 {
    struct rarch_state *p_rarch = &rarch_st;
-   p_rarch->input_device_display_names[port][0] = '\0';
+   p_rarch->input_device_info[port].display_name[0] = '\0';
 }
 
 void input_config_clear_device_config_path(unsigned port)
 {
    struct rarch_state *p_rarch = &rarch_st;
-   p_rarch->input_device_config_paths[port][0] = '\0';
+   p_rarch->input_device_info[port].config_path[0] = '\0';
 }
 
 void input_config_clear_device_config_name(unsigned port)
 {
    struct rarch_state *p_rarch = &rarch_st;
-   p_rarch->input_device_config_names[port][0] = '\0';
+   p_rarch->input_device_info[port].config_name[0] = '\0';
 }
 
+/* input_device_info wrappers END */
+
 unsigned *input_config_get_device_ptr(unsigned port)
 {
    struct rarch_state      *p_rarch = &rarch_st;
@@ -27482,7 +27606,6 @@ void input_config_set_device(unsigned port, unsigned id)
       settings->uints.input_libretro_device[port], id);
 }
 
-
 const struct retro_keybind *input_config_get_bind_auto(
       unsigned port, unsigned id)
 {
@@ -27495,33 +27618,35 @@ const struct retro_keybind *input_config_get_bind_auto(
    return NULL;
 }
 
-void input_config_set_pid(unsigned port, uint16_t pid)
+void input_config_reset_autoconfig_binds(unsigned port)
 {
-   struct rarch_state *p_rarch = &rarch_st;
-   p_rarch->input_config_pid[port] = pid;
-}
+   unsigned i;
 
-uint16_t input_config_get_pid(unsigned port)
-{
-   struct rarch_state *p_rarch = &rarch_st;
-   return p_rarch->input_config_pid[port];
-}
+   if (port >= MAX_USERS)
+      return;
 
-void input_config_set_vid(unsigned port, uint16_t vid)
-{
-   struct rarch_state *p_rarch = &rarch_st;
-   p_rarch->input_config_vid[port] = vid;
-}
+   for (i = 0; i < RARCH_BIND_LIST_END; i++)
+   {
+      input_autoconf_binds[port][i].joykey  = NO_BTN;
+      input_autoconf_binds[port][i].joyaxis = AXIS_NONE;
 
-uint16_t input_config_get_vid(unsigned port)
-{
-   struct rarch_state *p_rarch = &rarch_st;
-   return p_rarch->input_config_vid[port];
+      if (input_autoconf_binds[port][i].joykey_label)
+      {
+         free(input_autoconf_binds[port][i].joykey_label);
+         input_autoconf_binds[port][i].joykey_label = NULL;
+      }
+
+      if (input_autoconf_binds[port][i].joyaxis_label)
+      {
+         free(input_autoconf_binds[port][i].joyaxis_label);
+         input_autoconf_binds[port][i].joyaxis_label = NULL;
+      }
+   }
 }
 
 void input_config_reset(void)
 {
-   unsigned i, j;
+   unsigned i;
    struct rarch_state *p_rarch = &rarch_st;
 
    retro_assert(sizeof(input_config_binds[0]) >= sizeof(retro_keybinds_1));
@@ -27535,12 +27660,22 @@ void input_config_reset(void)
 
    for (i = 0; i < MAX_USERS; i++)
    {
-      p_rarch->input_config_vid[i]     = 0;
-      p_rarch->input_config_pid[i]     = 0;
-      p_rarch->libretro_input_binds[i] = input_config_binds[i];
+      /* Note: Don't use input_config_clear_device_name()
+       * here, since this will re-index devices each time
+       * (not required - we are setting all 'name indices'
+       * to zero manually) */
+      p_rarch->input_device_info[i].name[0] = '\0';
+      input_config_clear_device_display_name(i);
+      input_config_clear_device_config_path(i);
+      input_config_clear_device_config_name(i);
+      input_config_set_device_vid(i, 0);
+      input_config_set_device_pid(i, 0);
+      input_config_set_device_autoconfigured(i, false);
+      input_config_set_device_name_index(i, 0);
 
-      for (j = 0; j < 64; j++)
-         input_device_names[i][j]      = 0;
+      input_config_reset_autoconfig_binds(i);
+
+      p_rarch->libretro_input_binds[i] = input_config_binds[i];
    }
 }
 
@@ -27577,20 +27712,22 @@ void config_read_keybinds_conf(void *data)
    }
 }
 
-void input_autoconfigure_joypad_conf(void *data,
-      struct retro_keybind *binds)
+void input_config_set_autoconfig_binds(unsigned port, void *data)
 {
+   config_file_t *config       = (config_file_t*)data;
+   struct retro_keybind *binds = NULL;
    unsigned i;
-   config_file_t *conf = (config_file_t*)data;
 
-   if (!conf)
+   if ((port >= MAX_USERS) || !config)
       return;
 
+   binds = input_autoconf_binds[port];
+
    for (i = 0; i < RARCH_BIND_LIST_END; i++)
    {
-      input_config_parse_joy_button(conf, "input",
+      input_config_parse_joy_button(config, "input",
             input_config_bind_map_get_base(i), &binds[i]);
-      input_config_parse_joy_axis(conf, "input",
+      input_config_parse_joy_axis(config, "input",
             input_config_bind_map_get_base(i), &binds[i]);
    }
 }
diff --git a/tasks/task_autodetect.c b/tasks/task_autodetect.c
index 15dd3c2ef7..71b3d381f3 100644
--- a/tasks/task_autodetect.c
+++ b/tasks/task_autodetect.c
@@ -23,568 +23,847 @@
 #include <compat/strl.h>
 #include <file/file_path.h>
 #include <string/stdstring.h>
+#include <file/config_file.h>
 
 #include "../configuration.h"
 #include "../file_path_special.h"
 #include "../list_special.h"
 #include "../retroarch.h"
+#include "../input/input_driver.h"
 
 #include "tasks_internal.h"
 #ifdef HAVE_BLISSBOX
 #include "../input/include/blissbox.h"
 #endif
 
-typedef struct autoconfig_disconnect autoconfig_disconnect_t;
-
-struct autoconfig_disconnect
+typedef struct
 {
-   unsigned idx;
-   char *msg;
-};
+   unsigned port;
+   input_device_info_t device_info;
+   bool autoconfig_enabled;
+   bool suppress_notifcations;
+   char *dir_autoconfig;
+   char *dir_driver_autoconfig;
+   config_file_t *autoconfig_file;
+} autoconfig_handle_t;
 
-/* TODO/FIXME - global state - perhaps move outside this file */
-static bool input_autoconfigured[MAX_USERS];
-static unsigned input_device_name_index[MAX_INPUT_DEVICES];
-static bool input_autoconfigure_swap_override;
+/*********************/
+/* Utility functions */
+/*********************/
 
-/* TODO/FIXME - Not thread safe to access this
- * on main thread as well in its current state -
- * menu_input.c - menu_event calls this function
- * right now, while the underlying variable can
- * be modified by a task thread. */
-bool input_autoconfigure_get_swap_override(void)
+static void free_autoconfig_handle(autoconfig_handle_t *autoconfig_handle)
 {
-   return input_autoconfigure_swap_override;
+   if (!autoconfig_handle)
+      return;
+
+   if (autoconfig_handle->dir_autoconfig)
+   {
+      free(autoconfig_handle->dir_autoconfig);
+      autoconfig_handle->dir_autoconfig = NULL;
+   }
+
+   if (autoconfig_handle->dir_driver_autoconfig)
+   {
+      free(autoconfig_handle->dir_driver_autoconfig);
+      autoconfig_handle->dir_driver_autoconfig = NULL;
+   }
+
+   if (autoconfig_handle->autoconfig_file)
+   {
+      config_file_free(autoconfig_handle->autoconfig_file);
+      autoconfig_handle->autoconfig_file = NULL;
+   }
+
+   free(autoconfig_handle);
+   autoconfig_handle = NULL;
 }
 
-/* Adds an index for devices with the same name,
- * so they can be identified in the GUI. */
-void input_autoconfigure_joypad_reindex_devices(void)
+static void input_autoconfigure_free(retro_task_t *task)
 {
-   unsigned i, j, k;
+   autoconfig_handle_t *autoconfig_handle = NULL;
 
-   for(i = 0; i < MAX_INPUT_DEVICES; i++)
-      input_device_name_index[i] = 0;
+   if (!task)
+      return;
 
-   for(i = 0; i < MAX_INPUT_DEVICES; i++)
+   autoconfig_handle = (autoconfig_handle_t*)task->state;
+
+   free_autoconfig_handle(autoconfig_handle);
+}
+
+/******************************/
+/* Autoconfig 'File' Handling */
+/******************************/
+
+/* Returns a value corresponding to the
+ * 'affinity' between the connected input
+ * device and the specified config file
+ * > 0: No match
+ * > 2: Device name matches
+ * > 3: VID+PID match
+ * > 5: Both device name and VID+PID match */
+static unsigned input_autoconfigure_get_config_file_affinity(
+      autoconfig_handle_t *autoconfig_handle,
+      config_file_t *config)
+{
+   int tmp_int         = 0;
+   uint16_t config_vid = 0;
+   uint16_t config_pid = 0;
+   bool pid_match      = false;
+   unsigned affinity   = 0;
+   char config_device_name[256];
+
+   config_device_name[0] = '\0';
+
+   if (!autoconfig_handle || !config)
+      return 0;
+
+   /* Parse config file */
+   config_get_array(config, "input_device", config_device_name,
+         sizeof(config_device_name));
+
+   if (config_get_int(config, "input_vendor_id", &tmp_int))
+      config_vid = (uint16_t)tmp_int;
+
+   if (config_get_int(config, "input_product_id", &tmp_int))
+      config_pid = (uint16_t)tmp_int;
+
+   /* > Bliss-Box shenanigans... */
+#ifdef HAVE_BLISSBOX
+   if (autoconfig_handle->device_info.vid == BLISSBOX_VID)
+      config_pid = BLISSBOX_PID;
+#endif
+
+   /* Check for matching VID+PID */
+   pid_match = (autoconfig_handle->device_info.vid == config_vid) &&
+               (autoconfig_handle->device_info.pid == config_pid) &&
+               (autoconfig_handle->device_info.vid != 0) &&
+               (autoconfig_handle->device_info.pid != 0);
+
+   /* > More Bliss-Box shenanigans... */
+#ifdef HAVE_BLISSBOX
+   pid_match = pid_match &&
+               (autoconfig_handle->device_info.vid != BLISSBOX_VID) &&
+               (autoconfig_handle->device_info.pid != BLISSBOX_PID);
+#endif
+
+   if (pid_match)
+      affinity += 3;
+
+   /* Check for matching device name */
+   if (!string_is_empty(config_device_name) &&
+       string_is_equal(config_device_name,
+            autoconfig_handle->device_info.name))
+      affinity += 2;
+
+   return affinity;
+}
+
+/* 'Attaches' specified autoconfig file to autoconfig
+ * handle, parsing required device info metadata */
+static void input_autoconfigure_set_config_file(
+      autoconfig_handle_t *autoconfig_handle,
+      config_file_t *config)
+{
+   char device_display_name[256];
+
+   device_display_name[0] = '\0';
+
+   if (!autoconfig_handle || !config)
+      return;
+
+   /* Attach config file */
+   autoconfig_handle->autoconfig_file = config;
+
+   /* > Extract config file path + name */
+   if (!string_is_empty(config->path))
    {
-      const char *tmp = input_config_get_device_name(i);
-      if ( !tmp || input_device_name_index[i] )
+      const char *config_file_name = path_basename(config->path);
+
+      strlcpy(autoconfig_handle->device_info.config_path,
+            config->path,
+            sizeof(autoconfig_handle->device_info.config_path));
+
+      if (!string_is_empty(config_file_name))
+         strlcpy(autoconfig_handle->device_info.config_name,
+               config_file_name,
+               sizeof(autoconfig_handle->device_info.config_name));
+   }
+
+   /* Read device display name */
+   config_get_array(config, "input_device_display_name",
+         device_display_name, sizeof(device_display_name));
+
+   if (!string_is_empty(device_display_name))
+      strlcpy(autoconfig_handle->device_info.display_name,
+            device_display_name,
+            sizeof(autoconfig_handle->device_info.display_name));
+
+   /* Set auto-configured status to 'true' */
+   autoconfig_handle->device_info.autoconfigured = true;
+}
+
+/* Attempts to find an 'external' autoconfig file
+ * (in the autoconfig directory) matching the connected
+ * input device
+ * > Returns 'true' if successful */
+static bool input_autoconfigure_scan_config_files_external(
+      autoconfig_handle_t *autoconfig_handle)
+{
+   const char *dir_autoconfig           = autoconfig_handle->dir_autoconfig;
+   const char *dir_driver_autoconfig    = autoconfig_handle->dir_driver_autoconfig;
+   struct string_list *config_file_list = NULL;
+   config_file_t *best_config           = NULL;
+   unsigned max_affinity                = 0;
+   bool match_found                     = false;
+   size_t i;
+
+   /* Attempt to fetch file listing from driver-specific
+    * autoconfig directory */
+   if (!string_is_empty(dir_driver_autoconfig) &&
+       path_is_directory(dir_driver_autoconfig))
+      config_file_list = dir_list_new_special(
+            dir_driver_autoconfig, DIR_LIST_AUTOCONFIG,
+            "cfg", false);
+
+   if (!config_file_list || (config_file_list->size < 1))
+   {
+      /* No files found - attempt to fetch listing
+       * from autoconfig base directory */
+      if (config_file_list)
+      {
+         string_list_free(config_file_list);
+         config_file_list = NULL;
+      }
+
+      if (!string_is_empty(dir_autoconfig) &&
+          path_is_directory(dir_autoconfig))
+         config_file_list = dir_list_new_special(
+               dir_autoconfig, DIR_LIST_AUTOCONFIG,
+               "cfg", false);
+   }
+
+   if (!config_file_list || (config_file_list->size < 1))
+      goto end;
+
+   /* Loop through external config files */
+   for (i = 0; i < config_file_list->size; i++)
+   {
+      const char *config_file_path = config_file_list->elems[i].data;
+      config_file_t *config        = NULL;
+      unsigned affinity            = 0;
+
+      if (string_is_empty(config_file_path))
          continue;
 
-      k = 2; /*Additional devices start at two*/
+      /* Load autoconfig file */
+      config = config_file_new_from_path_to_string(config_file_path);
 
-      for(j = i+1; j < MAX_INPUT_DEVICES; j++)
+      if (!config)
+         continue;
+
+      /* Check for a match */
+      affinity = input_autoconfigure_get_config_file_affinity(
+            autoconfig_handle, config);
+
+      if (affinity > max_affinity)
       {
-         const char *other = input_config_get_device_name(j);
-
-         if (!other)
-            continue;
-
-         /*another device with the same name found, for the first time*/
-         if (string_is_equal(tmp, other) &&
-               input_device_name_index[j]==0 )
+         if (best_config)
          {
-            /*Mark the first device of the set*/
-            input_device_name_index[i] = 1;
-            /*count this additional device, from two up*/
-            input_device_name_index[j] = k++;
+            config_file_free(best_config);
+            best_config = NULL;
          }
+
+         /* 'Cache' config file for later processing */
+         best_config  = config;
+         config       = NULL;
+         max_affinity = affinity;
+
+         /* An affinity of 5 is a 'perfect' match,
+          * and means we can return immediately */
+         if (affinity == 5)
+            break;
       }
-   }
-}
-
-static int input_autoconfigure_joypad_try_from_conf(config_file_t *conf,
-      autoconfig_params_t *params)
-{
-   char ident[256];
-   char input_driver[32];
-   int tmp_int                = 0;
-   int              input_vid = 0;
-   int              input_pid = 0;
-   int                  score = 0;
-   bool check_pid             = false;
-
-   ident[0] = input_driver[0] = '\0';
-
-   config_get_array(conf, "input_device", ident, sizeof(ident));
-   config_get_array(conf, "input_driver", input_driver, sizeof(input_driver));
-
-   if (config_get_int  (conf, "input_vendor_id", &tmp_int))
-      input_vid = tmp_int;
-
-   if (config_get_int  (conf, "input_product_id", &tmp_int))
-      input_pid = tmp_int;
-
-#ifdef HAVE_BLISSBOX
-   if (params->vid == BLISSBOX_VID)
-      input_pid = BLISSBOX_PID;
-#endif
-
-   check_pid = 
-         (params->vid == input_vid)
-      && (params->pid == input_pid)
-      && (params->vid != 0)
-      && (params->pid != 0);
-
-#ifdef HAVE_BLISSBOX
-   check_pid = check_pid
-         && (params->vid != BLISSBOX_VID)
-         && (params->pid != BLISSBOX_PID);
-#endif
-
-   /* Check for VID/PID */
-   if (check_pid)
-      score += 3;
-
-   /* Check for name match */
-   if (
-            !string_is_empty(params->name)
-         && !string_is_empty(ident)
-         && string_is_equal(ident, params->name))
-      score += 2;
-
-   return score;
-}
-
-static void input_autoconfigure_joypad_add(config_file_t *conf,
-      autoconfig_params_t *params, retro_task_t *task)
-{
-   char msg[128], display_name[128], device_type[128];
-   /* This will be the case if input driver is reinitialized.
-    * No reason to spam autoconfigure messages every time. */
-   bool block_osd_spam                =
-#if defined(HAVE_LIBNX) && defined(HAVE_GFX_WIDGETS)
-      true;
-#else
-      input_autoconfigured[params->idx]
-      && !string_is_empty(params->name);
-#endif
-
-   msg[0] = display_name[0] = device_type[0] = '\0';
-
-   config_get_array(conf, "input_device_display_name",
-         display_name, sizeof(display_name));
-   config_get_array(conf, "input_device_type", device_type,
-         sizeof(device_type));
-
-   input_autoconfigured[params->idx] = true;
-
-   input_autoconfigure_joypad_conf(conf,
-         input_autoconf_binds[params->idx]);
-
-   if (string_is_equal(device_type, "remote"))
-   {
-      static bool remote_is_bound        = false;
-      const char *autoconfig_str         = (string_is_empty(display_name) &&
-            !string_is_empty(params->name)) ? params->name : (!string_is_empty(display_name) 
-            ? display_name 
-            : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
-      strlcpy(msg, autoconfig_str, sizeof(msg));
-      strlcat(msg, " configured.", sizeof(msg));
-
-      if (!remote_is_bound)
-      {
-         task_free_title(task);
-         task_set_title(task, strdup(msg));
-      }
-      remote_is_bound = true;
-      if (params->idx == 0)
-         input_autoconfigure_swap_override = true;
-   }
-   else
-   {
-      bool tmp                    = false;
-      const char *autoconfig_str  = (string_is_empty(display_name) &&
-            !string_is_empty(params->name))
-            ? params->name : (!string_is_empty(display_name) 
-                  ? display_name 
-                  : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
-
-      snprintf(msg, sizeof(msg), "%s %s #%u.",
-            autoconfig_str,
-            msg_hash_to_str(MSG_DEVICE_CONFIGURED_IN_PORT),
-            params->idx + 1);
-
-      /* allow overriding the swap menu controls for player 1*/
-      if (params->idx == 0)
-      {
-         if (config_get_bool(conf, "input_swap_override", &tmp))
-            input_autoconfigure_swap_override = tmp;
-         else
-            input_autoconfigure_swap_override = false;
-      }
-
-      if (!block_osd_spam)
-      {
-         task_free_title(task);
-         task_set_title(task, strdup(msg));
-      }
-   }
-   if (!string_is_empty(display_name))
-      input_config_set_device_display_name(params->idx, display_name);
-   else
-      input_config_set_device_display_name(params->idx, params->name);
-   if (!string_is_empty(conf->path))
-   {
-      input_config_set_device_config_name(params->idx, path_basename(conf->path));
-      input_config_set_device_config_path(params->idx, conf->path);
-   }
-   else
-   {
-      input_config_set_device_config_name(params->idx, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
-      input_config_set_device_config_path(params->idx, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
-   }
-
-   input_autoconfigure_joypad_reindex_devices();
-}
-
-static int input_autoconfigure_joypad_from_conf(
-      config_file_t *conf, autoconfig_params_t *params, retro_task_t *task)
-{
-   int ret = input_autoconfigure_joypad_try_from_conf(conf,
-         params);
-
-   if (ret)
-      input_autoconfigure_joypad_add(conf, params, task);
-
-   config_file_free(conf);
-
-   return ret;
-}
-
-static bool input_autoconfigure_joypad_from_conf_dir(
-      autoconfig_params_t *params, retro_task_t *task)
-{
-   size_t i;
-   char path[PATH_MAX_LENGTH];
-   char best_path[PATH_MAX_LENGTH];
-   bool found                  = false;
-   int index                   = -1;
-   int current_best            = 0;
-   config_file_t *best_conf    = NULL;
-   struct string_list *list    = NULL;
-
-   best_path[0]                = '\0';
-   path[0]                     = '\0';
-
-   fill_pathname_application_special(path, sizeof(path),
-         APPLICATION_SPECIAL_DIRECTORY_AUTOCONFIG);
-
-   list = dir_list_new_special(path, DIR_LIST_AUTOCONFIG, "cfg",
-         params->show_hidden_files);
-
-   if (!list || !list->size)
-   {
-      if (list)
-      {
-         string_list_free(list);
-         list = NULL;
-      }
-      if (!string_is_empty(params->autoconfig_directory))
-         list = dir_list_new_special(params->autoconfig_directory,
-               DIR_LIST_AUTOCONFIG, "cfg", params->show_hidden_files);
-   }
-
-   if (!list)
-      return false;
-
-   for (i = 0; i < list->size; i++)
-   {
-      int res;
-      config_file_t *conf = config_file_new_from_path_to_string(list->elems[i].data);
-      
-      if (!conf)
-         continue;
-
-      res  = input_autoconfigure_joypad_try_from_conf(conf, params);
-
-      if (res >= current_best)
-      {
-         index        = (int)i;
-         current_best = res;
-         if (best_conf)
-            config_file_free(best_conf);
-         strlcpy(best_path, list->elems[i].data, sizeof(best_path));
-         best_conf    = NULL;
-         best_conf    = conf;
-      }
+      /* No match - just clean up config file */
       else
-         config_file_free(conf);
+      {
+         config_file_free(config);
+         config = NULL;
+      }
    }
 
-   if (index >= 0 && current_best > 0 && best_conf)
+   /* If we reach this point and a config file has
+    * been cached, then we have a match */
+   if (best_config)
    {
-      input_autoconfigure_joypad_add(best_conf, params, task);
-      found = true;
+      input_autoconfigure_set_config_file(
+            autoconfig_handle, best_config);
+      match_found = true;
    }
 
-   if (best_conf)
-      config_file_free(best_conf);
+end:
+   if (config_file_list)
+   {
+      string_list_free(config_file_list);
+      config_file_list = NULL;
+   }
 
-   string_list_free(list);
-
-   return found;
+   return match_found;
 }
 
-static bool input_autoconfigure_joypad_from_conf_internal(
-      autoconfig_params_t *params, retro_task_t *task)
+/* Attempts to find an internal autoconfig definition
+ * matching the connected input device
+ * > Returns 'true' if successful */
+static bool input_autoconfigure_scan_config_files_internal(
+      autoconfig_handle_t *autoconfig_handle)
 {
    size_t i;
 
-   /* Load internal autoconfig files  */
+   /* Loop through internal autoconfig files
+    * > input_builtin_autoconfs is a static const,
+    *   and may be read safely in any thread  */
    for (i = 0; input_builtin_autoconfs[i]; i++)
    {
-      char *autoconf      = NULL;
-      config_file_t *conf = NULL;
+      char *autoconfig_str  = NULL;
+      config_file_t *config = NULL;
+      unsigned affinity     = 0;
 
       if (string_is_empty(input_builtin_autoconfs[i]))
          continue;
 
-      autoconf = strdup(input_builtin_autoconfs[i]);
-      conf     = config_file_new_from_string(autoconf, NULL);
-      free(autoconf);
+      /* Load autoconfig string */
+      autoconfig_str = strdup(input_builtin_autoconfs[i]);
+      config         = config_file_new_from_string(
+            autoconfig_str, NULL);
 
-      if (conf && input_autoconfigure_joypad_from_conf(conf, params, task))
-        return true;
+      /* > String no longer required - clean up */
+      free(autoconfig_str);
+      autoconfig_str = NULL;
+
+      /* Check for a match */
+      affinity = input_autoconfigure_get_config_file_affinity(
+            autoconfig_handle, config);
+
+      /* > In the case of internal autoconfigs, any kind
+       *   of match is considered to be a success */
+      if (affinity > 0)
+      {
+         input_autoconfigure_set_config_file(
+               autoconfig_handle, config);
+         return true;
+      }
+
+      /* No match - clean up */
+      if (config)
+      {
+         config_file_free(config);
+         config = NULL;
+      }
    }
 
-   return string_is_empty(params->autoconfig_directory);
+   return false;
 }
 
-static void input_autoconfigure_params_free(autoconfig_params_t *params)
+/*************************/
+/* Autoconfigure Connect */
+/*************************/
+
+static void cb_input_autoconfigure_connect(
+      retro_task_t *task, void *task_data,
+      void *user_data, const char *err)
 {
-   if (!params)
+   autoconfig_handle_t *autoconfig_handle = NULL;
+   unsigned port;
+
+   if (!task)
       return;
-   if (!string_is_empty(params->name))
-      free(params->name);
-   if (!string_is_empty(params->autoconfig_directory))
-      free(params->autoconfig_directory);
-   params->name                 = NULL;
-   params->autoconfig_directory = NULL;
+
+   autoconfig_handle = (autoconfig_handle_t*)task->state;
+
+   if (!autoconfig_handle)
+      return;
+
+   /* Use local copy of port index for brevity... */
+   port = autoconfig_handle->port;
+
+   /* We perform the actual 'connect' in this
+    * callback, to ensure it occurs on the main
+    * thread */
+
+   /* Copy task handle parameters into global
+    * state objects:
+    * > Name */
+   if (!string_is_empty(autoconfig_handle->device_info.name))
+      input_config_set_device_name(port,
+            autoconfig_handle->device_info.name);
+   else
+      input_config_clear_device_name(port);
+
+   /* > Display name */
+   if (!string_is_empty(autoconfig_handle->device_info.display_name))
+      input_config_set_device_display_name(port,
+            autoconfig_handle->device_info.display_name);
+   else if (!string_is_empty(autoconfig_handle->device_info.name))
+      input_config_set_device_display_name(port,
+            autoconfig_handle->device_info.name);
+   else
+      input_config_clear_device_display_name(port);
+
+   /* > VID/PID */
+   input_config_set_device_vid(port, autoconfig_handle->device_info.vid);
+   input_config_set_device_pid(port, autoconfig_handle->device_info.pid);
+
+   /* > Config file path/name */
+   if (!string_is_empty(autoconfig_handle->device_info.config_path))
+      input_config_set_device_config_path(port,
+            autoconfig_handle->device_info.config_path);
+   else
+      input_config_set_device_config_path(port,
+            msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
+
+   if (!string_is_empty(autoconfig_handle->device_info.config_name))
+      input_config_set_device_config_name(port,
+            autoconfig_handle->device_info.config_name);
+   else
+      input_config_set_device_config_name(port,
+            msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
+
+   /* > Auto-configured state */
+   input_config_set_device_autoconfigured(port,
+         autoconfig_handle->device_info.autoconfigured);
+
+   /* Reset any existing binds */
+   input_config_reset_autoconfig_binds(port);
+
+   /* If an autoconfig file is available, load its
+    * bind mappings */
+   if (autoconfig_handle->device_info.autoconfigured)
+      input_config_set_autoconfig_binds(port,
+            autoconfig_handle->autoconfig_file);
 }
 
 static void input_autoconfigure_connect_handler(retro_task_t *task)
 {
-   autoconfig_params_t *params = (autoconfig_params_t*)task->state;
+   autoconfig_handle_t *autoconfig_handle = NULL;
+   bool match_found                       = false;
+   const char *device_display_name        = NULL;
+   char task_title[PATH_MAX_LENGTH];
 
-   if (!params || string_is_empty(params->name))
-      goto end;
-
-   if (     !input_autoconfigure_joypad_from_conf_dir(params, task)
-         && !input_autoconfigure_joypad_from_conf_internal(params, task))
-   {
-      char msg[255];
-
-      msg[0] = '\0';
-#ifdef ANDROID
-      if (!string_is_empty(params->name))
-         free(params->name);
-      params->name = strdup("Android Gamepad");
-
-      if (input_autoconfigure_joypad_from_conf_internal(params, task))
-      {
-         snprintf(msg, sizeof(msg), "%s (%ld/%ld) %s.",
-               !string_is_empty(params->name) 
-               ? params->name 
-               : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
-               (long)params->vid, (long)params->pid,
-               msg_hash_to_str(MSG_DEVICE_NOT_CONFIGURED_FALLBACK));
-      }
-#else
-      snprintf(msg, sizeof(msg), "%s (%ld/%ld) %s.",
-            !string_is_empty(params->name) 
-            ? params->name 
-            : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
-            (long)params->vid, (long)params->pid,
-            msg_hash_to_str(MSG_DEVICE_NOT_CONFIGURED));
-#endif
-      task_free_title(task);
-      task_set_title(task, strdup(msg));
-   }
-
-end:
-   if (params)
-   {
-      input_autoconfigure_params_free(params);
-      free(params);
-   }
-   task_set_finished(task, true);
-}
-
-static void input_autoconfigure_disconnect_handler(retro_task_t *task)
-{
-   autoconfig_disconnect_t *params = (autoconfig_disconnect_t*)task->state;
-
-   task_set_title(task, strdup(params->msg));
-
-   task_set_finished(task, true);
-
-   if (!string_is_empty(params->msg))
-      free(params->msg);
-   free(params);
-}
-
-bool input_autoconfigure_disconnect(unsigned i, const char *ident)
-{
-   char msg[255];
-   autoconfig_disconnect_t 
-      *state     = NULL;
-   retro_task_t         
-      *task      = task_init();
+   task_title[0] = '\0';
 
    if (!task)
-      return false;
+      goto task_finished;
 
-   state         = (autoconfig_disconnect_t*)
-      malloc(sizeof(*state));
+   autoconfig_handle = (autoconfig_handle_t*)task->state;
 
-   if (!state)
+   if (!autoconfig_handle ||
+       string_is_empty(autoconfig_handle->device_info.name) ||
+       !autoconfig_handle->autoconfig_enabled)
+      goto task_finished;
+
+   /* Annoyingly, we have to scan all the autoconfig
+    * files (and in-built configs) in a single shot
+    * > Would prefer to scan one config per iteration
+    *   of the task, but this would render the gamepad
+    *   unusable for multiple frames after loading
+    *   content... */
+
+   /* Scan in order of preference:
+    * - External autoconfig files
+    * - Internal autoconfig definitions */
+   match_found = input_autoconfigure_scan_config_files_external(
+         autoconfig_handle);
+
+   if (!match_found)
+      match_found = input_autoconfigure_scan_config_files_internal(
+         autoconfig_handle);
+
+   /* If we reach this point on Android, attempt
+    * to search for the internal 'Android Gamepad'
+    * definition */
+#ifdef ANDROID
+   if (!match_found &&
+       !string_is_equal(autoconfig_handle->device_info.name,
+         "Android Gamepad"))
    {
-      free(task);
-      return false;
+      char *name_backup = strdup(autoconfig_handle->device_info.name);
+
+      strlcpy(autoconfig_handle->device_info.name,
+            "Android Gamepad",
+            sizeof(autoconfig_handle->device_info.name));
+
+      /* This is not a genuine match - leave
+       * match_found set to 'false' regardless
+       * of the outcome */
+      input_autoconfigure_scan_config_files_internal(
+            autoconfig_handle);
+
+      strlcpy(autoconfig_handle->device_info.name,
+            name_backup,
+            sizeof(autoconfig_handle->device_info.name));
+
+      free(name_backup);
+      name_backup = NULL;
    }
+#endif
 
-   state->idx    = i;
-   state->msg    = NULL;
-   msg[0]        = '\0';
+   /* Get display name for task status message */
+   device_display_name = autoconfig_handle->device_info.display_name;
+   if (string_is_empty(device_display_name))
+      device_display_name = autoconfig_handle->device_info.name;
+   if (string_is_empty(device_display_name))
+      device_display_name = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
 
-   snprintf(msg, sizeof(msg), "%s #%u (%s).",
-         msg_hash_to_str(MSG_DEVICE_DISCONNECTED_FROM_PORT),
-         i + 1, ident);
-
-   state->msg    = strdup(msg);
-
-   input_config_clear_device_name(state->idx);
-   input_config_clear_device_display_name(state->idx);
-   input_config_clear_device_config_name(state->idx);
-   input_config_clear_device_config_path(state->idx);
-
-   task->state   = state;
-   task->handler = input_autoconfigure_disconnect_handler;
-
-   task_queue_push(task);
-
-   return true;
-}
-
-void input_autoconfigure_reset(void)
-{
-   unsigned i, j;
-
-   for (i = 0; i < MAX_USERS; i++)
+   /* Generate task status message */
+   if (autoconfig_handle->device_info.autoconfigured)
    {
-      for (j = 0; j < RARCH_BIND_LIST_END; j++)
+      if (match_found)
       {
-         input_autoconf_binds[i][j].joykey  = NO_BTN;
-         input_autoconf_binds[i][j].joyaxis = AXIS_NONE;
+         /* A valid autoconfig was applied */
+         if (!autoconfig_handle->suppress_notifcations)
+            snprintf(task_title, sizeof(task_title), "%s %s #%u",
+                  device_display_name,
+                  msg_hash_to_str(MSG_DEVICE_CONFIGURED_IN_PORT),
+                  autoconfig_handle->port + 1);
       }
-      input_device_name_index[i] = 0;
-      input_autoconfigured[i]    = 0;
+      /* Device is autoconfigured, but a (most likely
+       * incorrect) fallback definition was used... */
+      else
+         snprintf(task_title, sizeof(task_title), "%s (%u/%u) %s",
+               device_display_name,
+               autoconfig_handle->device_info.vid,
+               autoconfig_handle->device_info.pid,
+               msg_hash_to_str(MSG_DEVICE_NOT_CONFIGURED_FALLBACK));
    }
+   /* Autoconfig failed */
+   else
+      snprintf(task_title, sizeof(task_title), "%s (%u/%u) %s",
+            device_display_name,
+            autoconfig_handle->device_info.vid,
+            autoconfig_handle->device_info.pid,
+            msg_hash_to_str(MSG_DEVICE_NOT_CONFIGURED));
 
-   input_autoconfigure_swap_override = false;
+   /* Update task title */
+   task_free_title(task);
+   if (!string_is_empty(task_title))
+      task_set_title(task, strdup(task_title));
+
+task_finished:
+
+   if (task)
+      task_set_finished(task, true);
 }
 
-bool input_is_autoconfigured(unsigned i)
+static bool autoconfigure_connect_finder(retro_task_t *task, void *user_data)
 {
-   return input_autoconfigured[i];
-}
+   autoconfig_handle_t *autoconfig_handle = NULL;
+   unsigned *port                         = NULL;
 
-unsigned input_autoconfigure_get_device_name_index(unsigned i)
-{
-   return input_device_name_index[i];
+   if (!task || !user_data)
+      return false;
+
+   if (task->handler != input_autoconfigure_connect_handler)
+      return false;
+
+   autoconfig_handle = (autoconfig_handle_t*)task->state;
+   if (!autoconfig_handle)
+      return false;
+
+   port = (unsigned*)user_data;
+   return (*port == autoconfig_handle->port);
 }
 
 void input_autoconfigure_connect(
       const char *name,
       const char *display_name,
       const char *driver,
-      unsigned idx,
+      unsigned port,
       unsigned vid,
       unsigned pid)
 {
-   unsigned i;
-   settings_t       *settings     = config_get_ptr();
-   const char *dir_autoconf       = 
-      settings ? settings->paths.directory_autoconfig : NULL;
-   bool autodetect_enable         = settings 
-      ? settings->bools.input_autodetect_enable : false;
-   autoconfig_params_t *state     = NULL;
-   retro_task_t         *task     = NULL;
+   retro_task_t *task                     = NULL;
+   autoconfig_handle_t *autoconfig_handle = NULL;
+   settings_t *settings                   = config_get_ptr();
+   bool autoconfig_enabled                = settings ?
+         settings->bools.input_autodetect_enable : false;
+   const char *dir_autoconfig             = settings ?
+         settings->paths.directory_autoconfig : NULL;
+   task_finder_data_t find_data;
+   char dir_driver_autoconfig[PATH_MAX_LENGTH];
 
-   if (!autodetect_enable)
+   dir_driver_autoconfig[0] = '\0';
+
+   if (port >= MAX_INPUT_DEVICES)
       goto error;
-   
-   task                           = task_init();
+
+   /* Cannot connect a device that is currently
+    * being connected */
+   find_data.func     = autoconfigure_connect_finder;
+   find_data.userdata = (void*)&port;
+
+   if (task_queue_find(&find_data))
+      goto error;
+
+   /* Configure handle */
+   autoconfig_handle = (autoconfig_handle_t*)malloc(sizeof(autoconfig_handle_t));
+
+   if (!autoconfig_handle)
+      goto error;
+
+   autoconfig_handle->port                        = port;
+   autoconfig_handle->device_info.vid             = vid;
+   autoconfig_handle->device_info.pid             = pid;
+   autoconfig_handle->device_info.name[0]         = '\0';
+   autoconfig_handle->device_info.display_name[0] = '\0';
+   autoconfig_handle->device_info.config_path[0]  = '\0';
+   autoconfig_handle->device_info.config_name[0]  = '\0';
+   autoconfig_handle->device_info.autoconfigured  = false;
+   autoconfig_handle->device_info.name_index      = 0;
+   autoconfig_handle->autoconfig_enabled          = autoconfig_enabled;
+   autoconfig_handle->suppress_notifcations       = false;
+   autoconfig_handle->dir_autoconfig              = NULL;
+   autoconfig_handle->dir_driver_autoconfig       = NULL;
+   autoconfig_handle->autoconfig_file             = NULL;
+
+   if (!string_is_empty(name))
+      strlcpy(autoconfig_handle->device_info.name, name,
+            sizeof(autoconfig_handle->device_info.name));
+
+   if (!string_is_empty(display_name))
+      strlcpy(autoconfig_handle->device_info.display_name, display_name,
+            sizeof(autoconfig_handle->device_info.display_name));
+
+   /* > Have to cache both the base autoconfig directory
+    *   and the driver-specific autoconfig directory
+    *   - Driver-specific directory is scanned by
+    *     default, if available
+    *   - If driver-specific directory is unavailable,
+    *     we scan the base autoconfig directory as
+    *     a fallback
+    * Note: fill_pathname_application_special() accesses
+    * the settings struct internally, so have to call it
+    * here and not in the task thread */
+   if (!string_is_empty(dir_autoconfig))
+      autoconfig_handle->dir_autoconfig = strdup(dir_autoconfig);
+
+   fill_pathname_application_special(dir_driver_autoconfig,
+         sizeof(dir_driver_autoconfig),
+         APPLICATION_SPECIAL_DIRECTORY_AUTOCONFIG);
+   if (!string_is_empty(dir_driver_autoconfig))
+      autoconfig_handle->dir_driver_autoconfig =
+            strdup(dir_driver_autoconfig);
+
+   /* Bliss-Box shenanigans... */
+#ifdef HAVE_BLISSBOX
+   if (autoconfig_handle->device_info.vid == BLISSBOX_VID)
+      input_autoconfigure_blissbox_override_handler(
+            (int)autoconfig_handle->device_info.vid,
+            (int)autoconfig_handle->device_info.pid,
+            autoconfig_handle->device_info.name,
+            sizeof(autoconfig_handle->device_info.name));
+#endif
+
+   /* If we are reconnecting a device that is already
+    * connect and autoconfigured, then there is no need
+    * to generate additional 'connection successful'
+    * task status messages */
+   if (!string_is_empty(autoconfig_handle->device_info.name))
+   {
+      const char *last_device_name = input_config_get_device_name(port);
+      uint16_t last_vid            = input_config_get_device_vid(port);
+      uint16_t last_pid            = input_config_get_device_pid(port);
+      bool last_autoconfigured     = input_config_get_device_autoconfigured(port);
+
+      if (!string_is_empty(last_device_name) &&
+          string_is_equal(autoconfig_handle->device_info.name,
+               last_device_name) &&
+          (autoconfig_handle->device_info.vid == last_vid) &&
+          (autoconfig_handle->device_info.pid == last_pid) &&
+          last_autoconfigured)
+         autoconfig_handle->suppress_notifcations = true;
+   }
+
+   /* Configure task */
+   task = task_init();
 
    if (!task)
       goto error;
-   
-   state                          = (autoconfig_params_t*)
-      malloc(sizeof(*state));
 
-   if (!state)
-   {
-      free(task);
-      goto error;
-   }
-
-   state->vid                     = 0;
-   state->pid                     = 0;
-   state->idx                     = 0;
-   state->max_users               = 0;
-   state->name                    = NULL;
-   state->autoconfig_directory    = NULL;
-   state->show_hidden_files       = false;
-
-   state->vid                     = vid;
-   state->pid                     = pid;
-   state->idx                     = idx;
-   state->max_users               = *(
-         input_driver_get_uint(INPUT_ACTION_MAX_USERS));
-
-   if (!string_is_empty(name))
-      state->name                 = strdup(name);
-
-   if (!string_is_empty(dir_autoconf))
-      state->autoconfig_directory = strdup(dir_autoconf);
-
-   state->show_hidden_files       = settings->bools.show_hidden_files;
-
-#ifdef HAVE_BLISSBOX
-   if (state->vid == BLISSBOX_VID)
-      input_autoconfigure_override_handler(state);
-#endif
-
-   if (!string_is_empty(state->name))
-      input_config_set_device_name(state->idx, state->name);
-   input_config_set_pid(state->idx, state->pid);
-   input_config_set_vid(state->idx, state->vid);
-
-   for (i = 0; i < RARCH_BIND_LIST_END; i++)
-   {
-      input_autoconf_binds[state->idx][i].joykey           = NO_BTN;
-      input_autoconf_binds[state->idx][i].joyaxis          = AXIS_NONE;
-      if (
-            !string_is_empty(input_autoconf_binds[state->idx][i].joykey_label))
-         free(input_autoconf_binds[state->idx][i].joykey_label);
-      if (
-            !string_is_empty(input_autoconf_binds[state->idx][i].joyaxis_label))
-         free(input_autoconf_binds[state->idx][i].joyaxis_label);
-      input_autoconf_binds[state->idx][i].joykey_label      = NULL;
-      input_autoconf_binds[state->idx][i].joyaxis_label     = NULL;
-   }
-
-   input_autoconfigured[state->idx] = false;
-
-   task->state                      = state;
-   task->handler                    = input_autoconfigure_connect_handler;
+   task->handler  = input_autoconfigure_connect_handler;
+   task->state    = autoconfig_handle;
+   task->mute     = false;
+   task->title    = NULL;
+   task->callback = cb_input_autoconfigure_connect;
+   task->cleanup  = input_autoconfigure_free;
 
    task_queue_push(task);
 
    return;
 
 error:
-   input_config_set_device_name(idx, name);
+
+   if (task)
+   {
+      free(task);
+      task = NULL;
+   }
+
+   free_autoconfig_handle(autoconfig_handle);
+   autoconfig_handle = NULL;
+
+   return;
+}
+
+/****************************/
+/* Autoconfigure Disconnect */
+/****************************/
+
+static void cb_input_autoconfigure_disconnect(
+      retro_task_t *task, void *task_data,
+      void *user_data, const char *err)
+{
+   autoconfig_handle_t *autoconfig_handle = NULL;
+   unsigned port;
+
+   if (!task)
+      return;
+
+   autoconfig_handle = (autoconfig_handle_t*)task->state;
+
+   if (!autoconfig_handle)
+      return;
+
+   /* Use local copy of port index for brevity... */
+   port = autoconfig_handle->port;
+
+   /* We perform the actual 'disconnect' in this
+    * callback, to ensure it occurs on the main thread */
+   input_config_clear_device_name(port);
+   input_config_clear_device_display_name(port);
+   input_config_clear_device_config_path(port);
+   input_config_clear_device_config_name(port);
+   input_config_set_device_vid(port, 0);
+   input_config_set_device_pid(port, 0);
+   input_config_set_device_autoconfigured(port, false);
+   input_config_reset_autoconfig_binds(port);
+}
+
+static void input_autoconfigure_disconnect_handler(retro_task_t *task)
+{
+   autoconfig_handle_t *autoconfig_handle = NULL;
+   char task_title[PATH_MAX_LENGTH];
+
+   task_title[0] = '\0';
+
+   if (!task)
+      goto task_finished;
+
+   autoconfig_handle = (autoconfig_handle_t*)task->state;
+
+   if (!autoconfig_handle)
+      goto task_finished;
+
+   /* Set task title */
+   if (!string_is_empty(autoconfig_handle->device_info.name))
+      snprintf(task_title, sizeof(task_title), "%s #%u (%s)",
+            msg_hash_to_str(MSG_DEVICE_DISCONNECTED_FROM_PORT),
+            autoconfig_handle->port + 1,
+            autoconfig_handle->device_info.name);
+   else
+      snprintf(task_title, sizeof(task_title), "%s #%u",
+            msg_hash_to_str(MSG_DEVICE_DISCONNECTED_FROM_PORT),
+            autoconfig_handle->port + 1);
+
+   task_free_title(task);
+   task_set_title(task, strdup(task_title));
+
+task_finished:
+
+   if (task)
+      task_set_finished(task, true);
+}
+
+static bool autoconfigure_disconnect_finder(retro_task_t *task, void *user_data)
+{
+   autoconfig_handle_t *autoconfig_handle = NULL;
+   unsigned *port                         = NULL;
+
+   if (!task || !user_data)
+      return false;
+
+   if (task->handler != input_autoconfigure_disconnect_handler)
+      return false;
+
+   autoconfig_handle = (autoconfig_handle_t*)task->state;
+   if (!autoconfig_handle)
+      return false;
+
+   port = (unsigned*)user_data;
+   return (*port == autoconfig_handle->port);
+}
+
+/* Note: There is no real need for autoconfigure
+ * 'disconnect' to be a task - we are merely setting
+ * a handful of variables. However:
+ * - Making it a task means we can call
+ *   input_autoconfigure_disconnect() on any thread
+ *   thread, and defer the global state changes until
+ *   the task queue is handled on the *main* thread
+ * - By using a task for both 'connect' and 'disconnect',
+ *   we ensure uniformity of OSD status messages */
+bool input_autoconfigure_disconnect(unsigned port, const char *name)
+{
+   retro_task_t *task                     = NULL;
+   autoconfig_handle_t *autoconfig_handle = NULL;
+   task_finder_data_t find_data;
+
+   if (port >= MAX_INPUT_DEVICES)
+      goto error;
+
+   /* Cannot disconnect a device that is currently
+    * being disconnected */
+   find_data.func     = autoconfigure_disconnect_finder;
+   find_data.userdata = (void*)&port;
+
+   if (task_queue_find(&find_data))
+      goto error;
+
+   /* Configure handle */
+   autoconfig_handle = (autoconfig_handle_t*)calloc(1, sizeof(autoconfig_handle_t));
+
+   if (!autoconfig_handle)
+      goto error;
+
+   autoconfig_handle->port = port;
+   if (!string_is_empty(name))
+      strlcpy(autoconfig_handle->device_info.name,
+            name, sizeof(autoconfig_handle->device_info.name));
+
+   /* Configure task */
+   task = task_init();
+
+   if (!task)
+      goto error;
+
+   task->handler  = input_autoconfigure_disconnect_handler;
+   task->state    = autoconfig_handle;
+   task->title    = NULL;
+   task->callback = cb_input_autoconfigure_disconnect;
+   task->cleanup  = input_autoconfigure_free;
+
+   task_queue_push(task);
+
+   return true;
+
+error:
+
+   if (task)
+   {
+      free(task);
+      task = NULL;
+   }
+
+   free_autoconfig_handle(autoconfig_handle);
+   autoconfig_handle = NULL;
+
+   return false;
 }
diff --git a/tasks/task_autodetect_blissbox.c b/tasks/task_autodetect_blissbox.c
index 61003a1ebc..66e63a12c6 100644
--- a/tasks/task_autodetect_blissbox.c
+++ b/tasks/task_autodetect_blissbox.c
@@ -504,39 +504,36 @@ static const blissbox_pad_type_t* input_autoconfigure_get_blissbox_pad_type(int
 #endif
 }
 
-void input_autoconfigure_override_handler(void *data)
+void input_autoconfigure_blissbox_override_handler(
+      int vid, int pid, char *device_name, size_t len)
 {
-   autoconfig_params_t *params = (autoconfig_params_t*)data;
-
-   if (params->pid == BLISSBOX_UPDATE_MODE_PID)
+   if (pid == BLISSBOX_UPDATE_MODE_PID)
       RARCH_LOG("[Autoconf]: Bliss-Box in update mode detected. Ignoring.\n");
-   else if (params->pid == BLISSBOX_OLD_PID)
+   else if (pid == BLISSBOX_OLD_PID)
       RARCH_LOG("[Autoconf]: Bliss-Box 1.0 firmware detected. Please update to 2.0 or later.\n");
-   else if (params->pid >= BLISSBOX_PID && params->pid <= BLISSBOX_PID + BLISSBOX_MAX_PAD_INDEX)
+   else if (pid >= BLISSBOX_PID && pid <= BLISSBOX_PID + BLISSBOX_MAX_PAD_INDEX)
    {
       const blissbox_pad_type_t *pad;
-      char name[255] = {0};
-      int index      = params->pid - BLISSBOX_PID;
+      int index      = pid - BLISSBOX_PID;
 
       RARCH_LOG("[Autoconf]: Bliss-Box detected. Getting pad type...\n");
 
       if (blissbox_pads[index])
          pad = blissbox_pads[index];
       else
-         pad = input_autoconfigure_get_blissbox_pad_type(params->vid, params->pid);
+         pad = input_autoconfigure_get_blissbox_pad_type(vid, pid);
 
       if (pad && !string_is_empty(pad->name))
       {
          RARCH_LOG("[Autoconf]: Found Bliss-Box pad type: %s (%d) in port#%d\n", pad->name, pad->index, index);
 
-         if (params->name)
-            free(params->name);
-
          /* override name given to autoconfig so it knows what kind of pad this is */
-         strlcat(name, "Bliss-Box 4-Play ", sizeof(name));
-         strlcat(name, pad->name, sizeof(name));
-
-         params->name = strdup(name);
+         if (len > 0)
+         {
+            device_name[0] = '\0';
+            strlcpy(device_name, "Bliss-Box 4-Play ", len);
+            strlcat(device_name, pad->name, len);
+         }
 
          blissbox_pads[index] = pad;
       }
diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h
index e7910cd0c9..6f257e8a5e 100644
--- a/tasks/tasks_internal.h
+++ b/tasks/tasks_internal.h
@@ -46,20 +46,6 @@ typedef struct nbio_buf
    char *path;
 } nbio_buf_t;
 
-typedef struct autoconfig_params     autoconfig_params_t;
-
-struct autoconfig_params
-{
-   int32_t vid;
-   int32_t pid;
-   unsigned idx;
-   uint32_t max_users;
-   char  *name;
-   char  *autoconfig_directory;
-   bool show_hidden_files;
-};
-
-
 #ifdef HAVE_NETWORKING
 typedef struct
 {
@@ -220,27 +206,19 @@ void *savefile_ptr_get(void);
 
 void path_init_savefile_new(void);
 
-bool input_is_autoconfigured(unsigned i);
-
-unsigned input_autoconfigure_get_device_name_index(unsigned i);
-
-void input_autoconfigure_reset(void);
-
-void input_autoconfigure_override_handler(void *data);
-
+/* Autoconfigure tasks */
+extern const char* const input_builtin_autoconfs[];
+void input_autoconfigure_blissbox_override_handler(
+      int vid, int pid, char *device_name, size_t len);
 void input_autoconfigure_connect(
       const char *name,
       const char *display_name,
       const char *driver,
-      unsigned idx,
+      unsigned port,
       unsigned vid,
       unsigned pid);
-
-bool input_autoconfigure_disconnect(unsigned i, const char *ident);
-
-bool input_autoconfigure_get_swap_override(void);
-
-void input_autoconfigure_joypad_reindex_devices(void);
+bool input_autoconfigure_disconnect(
+      unsigned port, const char *name);
 
 void set_save_state_in_background(bool state);
 
@@ -248,8 +226,6 @@ void set_save_state_in_background(bool state);
 void task_push_cdrom_dump(const char *drive);
 #endif
 
-extern const char* const input_builtin_autoconfs[];
-
 RETRO_END_DECLS
 
 #endif