Merge pull request #5815 from bparker06/blissbox

initial Bliss-Box support
This commit is contained in:
Twinaphex 2017-11-29 06:59:13 +01:00 committed by GitHub
commit 17d4793c3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 256 additions and 2 deletions

View File

@ -55,6 +55,7 @@ addons:
- libsdl-image1.2-dev
- libsdl-mixer1.2-dev
- libsdl-ttf2.0-dev
- libusb-1.0-0-dev
coverity_scan:
project:
name: "RetroArch"

100
input/include/blissbox.h Normal file
View File

@ -0,0 +1,100 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2016 - Daniel De Matteis
* Copyright (C) 2016-2017 - Brad Parker
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BLISSBOX_H
#define __BLISSBOX_H
#include <retro_common_api.h>
#define BLISSBOX_VID 0x16d0 /* requires firmware 2.0 */
#define BLISSBOX_PID 0x0d04 /* first of 4 controllers, each one increments PID by 1 */
#define BLISSBOX_UPDATE_MODE_PID 0x0a5f
#define BLISSBOX_OLD_PID 0x0a60
#define BLISSBOX_MAX_PADS 4
#define BLISSBOX_MAX_PAD_INDEX (BLISSBOX_MAX_PADS - 1)
#define BLISSBOX_USB_FEATURE_REPORT_ID 17
RETRO_BEGIN_DECLS
typedef struct {
const char *name;
int index;
} blissbox_pad_type_t;
const blissbox_pad_type_t blissbox_pad_types[] =
{
{"A5200", 6},
{"A5200_TB", 50},
{"A7800", 4},
{"ATARI_KEYPAD", 43},
{"ATMARK", 10},
{"BALLY", 42},
{"CD32", 24},
{"CDI", 33},
{"COL", 1},
{"DC_ASCI", 15},
{"DC_PAD", 16},
{"FC_ARKANOID", 53},
{"FC_NES", 52},
{"GC", 9},
{"GC_WHEEL", 18},
{"GEN_3", 20},
{"GEN_6", 21},
{"GRAVIS_EX", 38},
{"gx4000", 2},
{"HAMMERHEAD", 40},
{"HPD", 7},
{"INTELI", 14},
{"JAG", 11},
{"MSSW", 39},
{"N64", 19},
{"NEO", 49},
{"NES", 17},
{"PADDLES", 41},
{"PC_FX", 26},
{"PC_GAMEPAD", 46},
{"PSX_DIGITAL", 65},
{"PSX_DS", 115},
{"PSX_DS2", 121},
{"PSX_FS", 83},
{"PSX_NEGCON", 51},
{"PSX_WHEEL", 12},
{"SAC", 34},
{"SATURN_ANALOG", 8},
{"SATURN_DIGITAL", 3},
{"SMS", 22},
{"SPEEK", 45},
{"TG16", 23},
{"THREE_DO", 25},
{"THREE_DO_ANALOG", 37},
{"VEC", 5},
{"WII_NUNCHUK", 13},
{"ZXSINC", 44},
{"NES_ARKANOID", 30},
{"NES_GUN", 28},
{"NES_POWERPAD", 36},
{"SNES", 27},
{"V_BOY", 29},
{"WII_CLASSIC", 31},
{"WII_MPLUS", 32},
{NULL, 0}, /* used to mark unconnected ports, do not remove */
};
RETRO_END_DECLS
#endif

View File

@ -1,6 +1,7 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2017 - Daniel De Matteis
* Copyright (C) 2016-2017 - Brad Parker
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
@ -24,7 +25,16 @@
#include <file/config_file.h>
#include <string/stdstring.h>
#ifdef HAVE_LIBUSB
#ifdef __FreeBSD__
#include <libusb.h>
#else
#include <libusb-1.0/libusb.h>
#endif
#endif
#include "../input/input_driver.h"
#include "../input/include/blissbox.h"
#include "../configuration.h"
#include "../file_path_special.h"
@ -33,6 +43,19 @@
#include "tasks_internal.h"
/* HID Class-Specific Requests values. See section 7.2 of the HID specifications */
#define USB_HID_GET_REPORT 0x01
#define USB_CTRL_IN LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE
#define USB_PACKET_CTRL_LEN 64
#define USB_TIMEOUT 5000 /* timeout in ms */
/* only one blissbox per machine is currently supported */
static const blissbox_pad_type_t *blissbox_pads[BLISSBOX_MAX_PADS] = {NULL};
#ifdef HAVE_LIBUSB
static struct libusb_device_handle *autoconfig_libusb_handle = NULL;
#endif
typedef struct autoconfig_disconnect autoconfig_disconnect_t;
typedef struct autoconfig_params autoconfig_params_t;
@ -120,13 +143,16 @@ static int input_autoconfigure_joypad_try_from_conf(config_file_t *conf,
if (config_get_int (conf, "input_product_id", &tmp_int))
input_pid = tmp_int;
if (params->vid == BLISSBOX_VID)
input_pid = BLISSBOX_PID;
/* Check for VID/PID */
if ( (params->vid == input_vid)
&& (params->pid == input_pid)
&& (params->vid != 0)
&& (params->pid != 0)
&& (input_vid != 0)
&& (input_pid != 0))
&& (params->vid != BLISSBOX_VID)
&& (params->pid != BLISSBOX_PID))
score += 3;
/* Check for name match */
@ -333,6 +359,131 @@ static void input_autoconfigure_params_free(autoconfig_params_t *params)
params->autoconfig_directory = NULL;
}
static const blissbox_pad_type_t* input_autoconfigure_get_blissbox_pad_type(int vid, int pid)
{
#ifdef HAVE_LIBUSB
unsigned char answer[USB_PACKET_CTRL_LEN] = {0};
unsigned i;
int ret = libusb_init(NULL);
if (ret < 0)
{
RARCH_ERR("[Autoconf]: Could not initialize libusb.\n");
return NULL;
}
autoconfig_libusb_handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
if (!autoconfig_libusb_handle)
{
RARCH_ERR("[Autoconf]: Could not find or open libusb device %d:%d.\n", vid, pid);
goto error;
}
#ifdef __linux__
libusb_detach_kernel_driver(autoconfig_libusb_handle, 0);
#endif
ret = libusb_set_configuration(autoconfig_libusb_handle, 1);
if (ret < 0)
{
RARCH_ERR("[Autoconf]: Error during libusb_set_configuration.\n");
goto error;
}
ret = libusb_claim_interface(autoconfig_libusb_handle, 0);
if (ret < 0)
{
RARCH_ERR("[Autoconf]: Error during libusb_claim_interface.\n");
goto error;
}
ret = libusb_control_transfer(autoconfig_libusb_handle, USB_CTRL_IN, USB_HID_GET_REPORT, BLISSBOX_USB_FEATURE_REPORT_ID, 0, answer, USB_PACKET_CTRL_LEN, USB_TIMEOUT);
if (ret < 0)
RARCH_ERR("[Autoconf]: Error during libusb_control_transfer.\n");
libusb_release_interface(autoconfig_libusb_handle, 0);
#ifdef __linux__
libusb_attach_kernel_driver(autoconfig_libusb_handle, 0);
#endif
libusb_close(autoconfig_libusb_handle);
libusb_exit(NULL);
for (i = 0; i < sizeof(blissbox_pad_types) / sizeof(blissbox_pad_types[0]); i++)
{
const blissbox_pad_type_t *pad = &blissbox_pad_types[i];
if (!pad || string_is_empty(pad->name))
continue;
if (pad->index == answer[0])
return pad;
}
RARCH_LOG("[Autoconf]: Could not find connected pad in Bliss-Box port#%d.\n", pid - BLISSBOX_PID);
return NULL;
error:
libusb_close(autoconfig_libusb_handle);
libusb_exit(NULL);
return NULL;
#else
return NULL;
#endif
}
static void input_autoconfigure_override_handler(autoconfig_params_t *params)
{
if (params->vid == BLISSBOX_VID)
{
if (params->pid == BLISSBOX_UPDATE_MODE_PID)
RARCH_LOG("[Autoconf]: Bliss-Box in update mode detected. Ignoring.\n");
else if (params->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)
{
const blissbox_pad_type_t *pad;
char name[255] = {0};
int index = params->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);
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 ", sizeof(name));
strlcat(name, pad->name, sizeof(name));
params->name = strdup(name);
blissbox_pads[index] = pad;
}
else
{
int count = sizeof(blissbox_pad_types) / sizeof(blissbox_pad_types[0]);
/* use NULL entry to mark as an unconnected port */
blissbox_pads[index] = &blissbox_pad_types[count - 1];
}
}
}
}
static void input_autoconfigure_connect_handler(retro_task_t *task)
{
autoconfig_params_t *params = (autoconfig_params_t*)task->state;
@ -499,6 +650,8 @@ bool input_autoconfigure_connect(
state->max_users = *(
input_driver_get_uint(INPUT_ACTION_MAX_USERS));
input_autoconfigure_override_handler(state);
if (!string_is_empty(state->name))
input_config_set_device_name(state->idx, state->name);
input_config_set_pid(state->idx, state->pid);