diff --git a/Makefile.griffin b/Makefile.griffin
index ac5e473104..3cc1f53bc2 100644
--- a/Makefile.griffin
+++ b/Makefile.griffin
@@ -88,6 +88,8 @@ else ifeq ($(platform), ps3-cobra)
#TODO
MEDIA_SHADER_DIR := ps3/iso/PS3_GAME/USRDIR/cores/shaders
else ifeq ($(platform), wii)
+ HAVE_WIIUSB_HID := 1
+
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
LD = $(DEVKITPPC)/bin/powerpc-eabi-ld$(EXE_EXT)
@@ -161,6 +163,10 @@ ifeq ($(HAVE_LIBSICKSAXIS), 1)
CFLAGS += -DHAVE_LIBSICKSAXIS
endif
+ifeq ($(HAVE_WIIUSB_HID), 1)
+CFLAGS += -DHAVE_WIIUSB_HID -DHAVE_HID
+endif
+
ifeq ($(HAVE_LIBRETRODB), 1)
CFLAGS += -DHAVE_LIBRETRODB
endif
diff --git a/frontend/drivers/platform_gx.c b/frontend/drivers/platform_gx.c
index 936c3c4941..9fe0d9eadf 100644
--- a/frontend/drivers/platform_gx.c
+++ b/frontend/drivers/platform_gx.c
@@ -146,7 +146,7 @@ static void gx_devthread(void *a)
int gx_logger_net(struct _reent *r, int fd, const char *ptr, size_t len)
{
static char temp[4000];
- size_t l = len >= 4000 ? 3999 : len;
+ size_t l = len >= 4000 ? 3999 : len - 1;
memcpy(temp, ptr, l);
temp[l] = 0;
logger_send("%s", temp);
diff --git a/griffin/griffin.c b/griffin/griffin.c
index bbf9af772d..b98808fa23 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -379,6 +379,10 @@ INPUT (HID)
#include "../input/drivers_hid/iohidmanager_hid.c"
#endif
+#ifdef HAVE_WIIUSB_HID
+#include "../input/drivers_hid/wiiusb_hid.c"
+#endif
+
#ifdef HAVE_HID
#include "../input/connect/joypad_connection.c"
#include "../input/connect/connect_ps3.c"
diff --git a/input/connect/connect_ps4.c b/input/connect/connect_ps4.c
index 967e3209cf..a55a8fe472 100644
--- a/input/connect/connect_ps4.c
+++ b/input/connect/connect_ps4.c
@@ -36,6 +36,26 @@ enum connect_ps4_dpad_states
struct ps4buttons
{
+#ifdef MSB_FIRST
+ uint8_t triangle : 1;
+ uint8_t circle : 1;
+ uint8_t cross : 1;
+ uint8_t square : 1;
+ uint8_t dpad : 4;
+
+ uint8_t r3 : 1;
+ uint8_t l3 : 1;
+ uint8_t options : 1;
+ uint8_t share : 1;
+ uint8_t r2 : 1;
+ uint8_t l2 : 1;
+ uint8_t r1 : 1;
+ uint8_t l1 : 1;
+
+ uint8_t reportcounter : 6;
+ uint8_t touchpad : 1;
+ uint8_t ps : 1;
+#else
uint8_t dpad : 4;
uint8_t square : 1;
uint8_t cross : 1;
@@ -54,6 +74,7 @@ struct ps4buttons
uint8_t ps : 1;
uint8_t touchpad : 1;
uint8_t reportcounter : 6;
+#endif
}__attribute__((packed));
struct ps4
diff --git a/input/drivers_hid/wiiusb_hid.c b/input/drivers_hid/wiiusb_hid.c
new file mode 100644
index 0000000000..89bd6fdcbf
--- /dev/null
+++ b/input/drivers_hid/wiiusb_hid.c
@@ -0,0 +1,544 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2015 - Sergi Granell (xerpi)
+ *
+ * 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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include "../connect/joypad_connection.h"
+#include "../input_autodetect.h"
+#include "../input_hid_driver.h"
+
+typedef struct wiiusb_hid
+{
+ joypad_connection_t *slots;
+ int hp; /* wiiusb_hotplug_callback_handle is just int */
+ int quit;
+} wiiusb_hid_t;
+
+struct wiiusb_adapter
+{
+ wiiusb_hid_t *hid;
+ volatile bool quitting;
+ usb_device_entry device;
+ int handle;
+ int interface_number;
+ int endpoint_in;
+ int endpoint_out;
+ int endpoint_in_max_size;
+ int endpoint_out_max_size;
+
+ uint8_t manufacturer_name[255];
+ uint8_t name[255];
+ uint8_t *data;
+
+ int slot;
+
+ sthread_t *thread;
+ slock_t *send_control_lock;
+ fifo_buffer_t *send_control_buffer;
+ struct wiiusb_adapter *next;
+};
+
+static struct wiiusb_adapter adapters;
+
+static void adapter_thread(void *data)
+{
+ uint8_t __attribute__((aligned(32))) send_command_buf[4096];
+ struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)data;
+ wiiusb_hid_t *hid = adapter ? adapter->hid : NULL;
+
+ if (!adapter)
+ return;
+
+ while (!adapter->quitting)
+ {
+ size_t send_command_size;
+ int tmp;
+ int report_number;
+ int size = 0;
+
+ slock_lock(adapter->send_control_lock);
+ if (fifo_read_avail(adapter->send_control_buffer) >= sizeof(send_command_size))
+ {
+ fifo_read(adapter->send_control_buffer, &send_command_size, sizeof(send_command_size));
+ if (fifo_read_avail(adapter->send_control_buffer) >= sizeof(send_command_size))
+ {
+ fifo_read(adapter->send_control_buffer, send_command_buf, send_command_size);
+ USB_WriteIntrMsg(adapter->handle, adapter->endpoint_out, send_command_size, send_command_buf);
+ }
+ }
+ slock_unlock(adapter->send_control_lock);
+
+ size = USB_ReadIntrMsg(adapter->handle, adapter->endpoint_in, adapter->endpoint_in_max_size, &adapter->data[0]);
+ /* RARCH_LOG("%p USB_ReadIntrMsg(%i, %i, %i, %p): %i\n", &adapter->data[0],
+ adapter->handle, adapter->endpoint_in, adapter->endpoint_in_max_size, &adapter->data[0],
+ size); */
+
+ //RARCH_LOG("%03i %03i %03i %03i\n", adapter->data[0], adapter->data[1], adapter->data[2], adapter->data[3], adapter->data[4]);
+ //memmove(&adapter->data[1], &adapter->data[0], 2048);
+
+ if (adapter && hid && hid->slots && size)
+ pad_connection_packet(&hid->slots[adapter->slot], adapter->slot,
+ adapter->data - 1, size+1);
+ }
+}
+
+static void wiiusb_hid_device_send_control(void *data,
+ uint8_t* data_buf, size_t size)
+{
+ struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)data;
+
+ if (!adapter)
+ return;
+
+ slock_lock(adapter->send_control_lock);
+
+ if (fifo_write_avail(adapter->send_control_buffer) >= size + sizeof(size))
+ {
+ fifo_write(adapter->send_control_buffer, &size, sizeof(size));
+ fifo_write(adapter->send_control_buffer, data_buf, size);
+ }
+ else
+ {
+ RARCH_WARN("adapter write buffer is full, cannot write send control\n");
+ }
+ slock_unlock(adapter->send_control_lock);
+}
+
+static void wiiusb_hid_device_add_autodetect(unsigned idx,
+ const char *device_name, const char *driver_name,
+ uint16_t dev_vid, uint16_t dev_pid)
+{
+ autoconfig_params_t params = {{0}};
+
+ params.idx = idx;
+ params.vid = dev_vid;
+ params.pid = dev_pid;
+
+ strlcpy(params.name, device_name, sizeof(params.name));
+ strlcpy(params.driver, driver_name, sizeof(params.driver));
+
+ input_config_autoconfigure_joypad(¶ms);
+}
+
+static void wiiusb_get_description(usb_device_entry *device,
+ struct wiiusb_adapter *adapter, usb_devdesc *devdesc)
+{
+ unsigned char c;
+ unsigned i, k;
+
+ for (c = 0; c < devdesc->bNumConfigurations; c++)
+ {
+ const usb_configurationdesc *config = &devdesc->configurations[c];
+ for (i = 0; i < (int)config->bNumInterfaces; i++)
+ {
+ const usb_interfacedesc *inter = &config->interfaces[i];
+#if 0
+ if (inter->bInterfaceClass == USB_CLASS_HID)
+#endif
+ {
+ adapter->interface_number = (int)inter->bInterfaceNumber;
+
+ for(k = 0; k < (int)inter->bNumEndpoints; k++)
+ {
+ const usb_endpointdesc *epdesc = &inter->endpoints[k];
+ bool is_int = (epdesc->bmAttributes & 0x03) == USB_ENDPOINT_INTERRUPT;
+ bool is_out = (epdesc->bEndpointAddress & 0x80) == USB_ENDPOINT_OUT;
+ bool is_in = (epdesc->bEndpointAddress & 0x80) == USB_ENDPOINT_IN;
+ if (is_int)
+ {
+ if (is_in)
+ {
+ adapter->endpoint_in = epdesc->bEndpointAddress;
+ adapter->endpoint_in_max_size = epdesc->wMaxPacketSize;
+ }
+ if (is_out)
+ {
+ adapter->endpoint_out = epdesc->bEndpointAddress;
+ adapter->endpoint_out_max_size = epdesc->wMaxPacketSize;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+static int remove_adapter(void *data, usb_device_entry *dev)
+{
+ struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)&adapters;
+ struct wiiusb_hid *hid = (struct wiiusb_hid*)data;
+
+ while (adapter->next == NULL)
+ return -1;
+
+ if (&adapter->next->device == dev)
+ {
+ struct wiiusb_adapter *new_next = NULL;
+ const char *name = (const char*)adapter->next->name;
+
+ input_config_autoconfigure_disconnect(adapter->slot, name);
+
+ adapter->next->quitting = true;
+ sthread_join(adapter->next->thread);
+
+ pad_connection_pad_deinit(&hid->slots[adapter->slot], adapter->slot);
+
+ slock_free(adapter->send_control_lock);
+ fifo_free(adapter->send_control_buffer);
+
+ free(adapter->data);
+
+ USB_CloseDevice(&adapter->next->handle);
+
+ new_next = adapter->next->next;
+ free(adapter->next);
+ adapter->next = new_next;
+
+ return 0;
+ }
+
+ adapter = adapter->next;
+
+ return -1;
+}
+
+static int wiiusb_hid_removalnotify_cb(int result, void *usrdata)
+{
+ wiiusb_hid_t *hid = (wiiusb_hid_t*)usrdata;
+
+ if (!hid)
+ return -1;
+
+ remove_adapter(hid, &adapters.next->device);
+
+ return 0;
+}
+
+static int add_adapter(void *data, usb_device_entry *dev)
+{
+ int rc;
+ usb_devdesc desc;
+ const char *device_name = NULL;
+ struct wiiusb_adapter *old_head = NULL;
+ struct wiiusb_hid *hid = (struct wiiusb_hid*)data;
+ struct wiiusb_adapter *adapter = (struct wiiusb_adapter*)
+ calloc(1, sizeof(struct wiiusb_adapter));
+
+ if (!adapter)
+ return -1;
+
+ if (!hid)
+ {
+ free(adapter);
+ RARCH_ERR("Allocation of adapter failed.\n");
+ return -1;
+ }
+
+ if (USB_OpenDevice(dev->device_id, dev->vid, dev->pid, &adapter->handle) < 0)
+ {
+ RARCH_ERR("Error opening device 0x%p (VID/PID: %04x:%04x).\n",
+ (void*)&adapter->device, dev->vid, dev->pid);
+ free(adapter);
+ return -1;
+ }
+
+ adapter->device = *dev;
+
+ USB_GetDescriptors(adapter->handle, &desc);
+
+ wiiusb_get_description(&adapter->device, adapter, &desc);
+
+ if (adapter->endpoint_in == 0)
+ {
+ RARCH_ERR("Could not find HID config for device.\n");
+ goto error;
+ }
+
+ if (desc.iManufacturer)
+ {
+ USB_GetAsciiString(adapter->handle, desc.iManufacturer, 0,
+ sizeof(adapter->manufacturer_name), adapter->manufacturer_name);
+#if 0
+ RARCH_ERR(" Adapter Manufacturer name: %s\n", adapter->manufacturer_name);
+#endif
+ }
+
+ if (desc.iProduct)
+ {
+ USB_GetAsciiString(adapter->handle, desc.iProduct, 0,
+ sizeof(adapter->name), adapter->name);
+#if 0
+ RARCH_ERR(" Adapter name: %s\n", adapter->name);
+#endif
+ }
+
+ device_name = (const char *)adapter->name;
+
+ if (adapter->name[0] == '\0')
+ {
+ strcpy(adapter->name, "dummydev");
+ // goto error;
+ }
+
+ adapter->send_control_lock = slock_new();
+ adapter->send_control_buffer = fifo_new(4096);
+
+ if (!adapter->send_control_lock || !adapter->send_control_buffer)
+ {
+ RARCH_ERR("Error creating send control buffer.\n");
+ goto error;
+ }
+
+ adapter->slot = pad_connection_pad_init(hid->slots,
+ device_name, desc.idVendor, desc.idProduct,
+ adapter, &wiiusb_hid_device_send_control);
+
+ if (adapter->slot == -1)
+ goto error;
+
+ if (!pad_connection_has_interface(hid->slots, adapter->slot))
+ {
+ RARCH_ERR(" Interface not found (%s).\n", adapter->name);
+ goto error;
+ }
+
+ RARCH_LOG("Interface found: [%s].\n", adapter->name);
+
+ RARCH_LOG("Device 0x%p attached (VID/PID: %04x:%04x).\n",
+ adapter->device, desc.idVendor, desc.idProduct);
+
+ wiiusb_hid_device_add_autodetect(adapter->slot,
+ device_name, wiiusb_hid.ident, desc.idVendor, desc.idProduct);
+
+ adapter->hid = hid;
+ adapter->thread = sthread_create(adapter_thread, adapter);
+
+ if (!adapter->thread)
+ {
+ RARCH_ERR("Error initializing adapter thread.\n");
+ goto error;
+ }
+
+ adapter->data = memalign(32, 2048);
+
+ old_head = adapters.next;
+ adapters.next = adapter;
+ adapter->next = old_head;
+
+ USB_FreeDescriptors(&desc);
+
+ USB_DeviceRemovalNotifyAsync(adapter->handle, wiiusb_hid_removalnotify_cb, (void *)hid);
+
+ return 0;
+
+error:
+ if (adapter->thread)
+ sthread_join(adapter->thread);
+ if (adapter->send_control_lock)
+ slock_free(adapter->send_control_lock);
+ if (adapter->send_control_buffer)
+ fifo_free(adapter->send_control_buffer);
+ if (adapter)
+ free(adapter);
+ USB_FreeDescriptors(&desc);
+ USB_CloseDevice(&adapter->handle);
+ return -1;
+}
+
+static int wiiusb_hid_changenotify_cb(int result, void *usrdata)
+{
+ wiiusb_hid_t *hid = (wiiusb_hid_t*)usrdata;
+
+ if (!hid)
+ return -1;
+
+ /* usb_device_entry entries[8];
+ u8 cnt = 0;
+
+ USB_GetDeviceList(entries, 8, USB_CLASS_HID, &cnt);
+
+ add_adapter((void *)hid, &entries[0]); */
+
+ // RARCH_LOG("Wii USB hid change notify callback\n");
+
+ USB_DeviceChangeNotifyAsync(USB_CLASS_HID, wiiusb_hid_changenotify_cb, usrdata);
+
+ return 0;
+}
+
+static bool wiiusb_hid_joypad_query(void *data, unsigned pad)
+{
+ return pad < MAX_USERS;
+}
+
+static const char *wiiusb_hid_joypad_name(void *data, unsigned pad)
+{
+ /* TODO/FIXME - implement properly */
+ if (pad >= MAX_USERS)
+ return NULL;
+
+ return NULL;
+}
+
+static uint64_t wiiusb_hid_joypad_get_buttons(void *data, unsigned port)
+{
+ wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
+ if (hid)
+ return pad_connection_get_buttons(&hid->slots[port], port);
+ return 0;
+}
+
+static bool wiiusb_hid_joypad_button(void *data, unsigned port, uint16_t joykey)
+{
+ uint64_t buttons = wiiusb_hid_joypad_get_buttons(data, port);
+
+ if (joykey == NO_BTN)
+ return false;
+
+ /* Check hat. */
+ if (GET_HAT_DIR(joykey))
+ return false;
+
+ /* Check the button. */
+ if ((port < MAX_USERS) && (joykey < 32))
+ return ((buttons & (1 << joykey)) != 0);
+ return false;
+}
+
+static bool wiiusb_hid_joypad_rumble(void *data, unsigned pad,
+ enum retro_rumble_effect effect, uint16_t strength)
+{
+ wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
+ if (!hid)
+ return false;
+ return pad_connection_rumble(&hid->slots[pad], pad, effect, strength);
+}
+
+static int16_t wiiusb_hid_joypad_axis(void *data,
+ unsigned port, uint32_t joyaxis)
+{
+ wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
+ int16_t val = 0;
+
+ if (joyaxis == AXIS_NONE)
+ return 0;
+
+ if (AXIS_NEG_GET(joyaxis) < 4)
+ {
+ val = pad_connection_get_axis(&hid->slots[port],
+ port, AXIS_NEG_GET(joyaxis));
+
+ if (val >= 0)
+ val = 0;
+ }
+ else if(AXIS_POS_GET(joyaxis) < 4)
+ {
+ val = pad_connection_get_axis(&hid->slots[port],
+ port, AXIS_POS_GET(joyaxis));
+
+ if (val <= 0)
+ val = 0;
+ }
+
+ return val;
+}
+
+static void wiiusb_hid_free(void *data)
+{
+ wiiusb_hid_t *hid = (wiiusb_hid_t*)data;
+
+ while (adapters.next)
+ if (remove_adapter(hid, &adapters.next->device) == -1)
+ RARCH_ERR("could not remove device %p\n",
+ adapters.next->device);
+
+ pad_connection_destroy(hid->slots);
+
+ // wiiusb_hotplug_deregister_callback(hid->ctx, hid->hp);
+
+ USB_Deinitialize();
+
+ if (hid)
+ free(hid);
+}
+
+static void *wiiusb_hid_init(void)
+{
+ unsigned i;
+ u8 count;
+ int ret;
+ usb_device_entry *dev_entries;
+ wiiusb_hid_t *hid = (wiiusb_hid_t*)calloc(1, sizeof(*hid));
+
+ if (!hid)
+ goto error;
+
+ hid->slots = pad_connection_init(MAX_USERS);
+
+ if (!hid->slots)
+ goto error;
+
+ dev_entries = (usb_device_entry *)calloc(MAX_USERS, sizeof(*dev_entries));
+
+ if (!dev_entries)
+ goto error;
+
+ USB_Initialize();
+
+ if (USB_GetDeviceList(dev_entries, MAX_USERS, USB_CLASS_HID, &count) < 0)
+ {
+ free(dev_entries);
+ goto error;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (dev_entries[i].vid > 0 && dev_entries[i].pid > 0)
+ add_adapter(hid, &dev_entries[i]);
+ }
+
+ free(dev_entries);
+
+ USB_DeviceChangeNotifyAsync(USB_CLASS_HID, wiiusb_hid_changenotify_cb, (void *)hid);
+
+ return hid;
+
+error:
+ wiiusb_hid_free(hid);
+ return NULL;
+}
+
+
+static void wiiusb_hid_poll(void *data)
+{
+ (void)data;
+}
+
+hid_driver_t wiiusb_hid = {
+ wiiusb_hid_init,
+ wiiusb_hid_joypad_query,
+ wiiusb_hid_free,
+ wiiusb_hid_joypad_button,
+ wiiusb_hid_joypad_get_buttons,
+ wiiusb_hid_joypad_axis,
+ wiiusb_hid_poll,
+ wiiusb_hid_joypad_rumble,
+ wiiusb_hid_joypad_name,
+ "wiiusb",
+};
diff --git a/input/input_hid_driver.c b/input/input_hid_driver.c
index 02ec23ece2..018ff7e4bc 100644
--- a/input/input_hid_driver.c
+++ b/input/input_hid_driver.c
@@ -31,6 +31,9 @@ static hid_driver_t *hid_drivers[] = {
#endif
#ifdef HAVE_LIBUSB
&libusb_hid,
+#endif
+#ifdef GEKKO
+ &wiiusb_hid,
#endif
&null_hid,
NULL,
diff --git a/input/input_hid_driver.h b/input/input_hid_driver.h
index faa593579c..3bf0b24f19 100644
--- a/input/input_hid_driver.h
+++ b/input/input_hid_driver.h
@@ -46,6 +46,7 @@ struct hid_driver
extern hid_driver_t iohidmanager_hid;
extern hid_driver_t btstack_hid;
extern hid_driver_t libusb_hid;
+extern hid_driver_t wiiusb_hid;
extern hid_driver_t null_hid;
/**