diff --git a/input/common/hid/device_ds3.c b/input/common/hid/device_ds3.c index 3c1a805d60..7ff4ae307b 100644 --- a/input/common/hid/device_ds3.c +++ b/input/common/hid/device_ds3.c @@ -22,33 +22,158 @@ typedef struct ds3_instance { void *handle; joypad_connection_t *pad; + int slot; + bool led_set; + uint32_t buttons; + uint16_t motors[2]; + uint8_t data[64]; } ds3_instance_t; static uint8_t activation_packet[] = { +#if defined(IOS) + 0x53, 0xF4, +#elif defined(HAVE_WIIUSB_HID) + 0x02, +#endif 0x42, 0x0c, 0x00, 0x00 }; +#if defined(WIIU) +#define PACKET_OFFSET 2 +#elif defined(HAVE_WIIUSB_HID) +#define PACKET_OFFSET 1 +#else +#define PACKET_OFFSET 0 +#endif + +#define LED_OFFSET 11 +#define MOTOR1_OFFSET 4 +#define MOTOR2_OFFSET 6 + +static uint8_t control_packet[] = { + 0x52, 0x01, + 0x00, 0xff, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; + +static int control_packet_size = sizeof(control_packet); + extern pad_connection_interface_t ds3_pad_connection; +static void print_error(const char *fmt, int32_t errcode) +{ + int16_t err1, err2; + + err1 = errcode & 0x0000ffff; + err2 = ((errcode & 0xffff0000) >> 16); + + RARCH_ERR(fmt, err1, err2); +} + +static uint32_t send_activation_packet(ds3_instance_t *instance) +{ + uint32_t result; +#if defined(WIIU) + result = HID_SET_REPORT(instance->handle, + HID_REPORT_FEATURE, + DS3_ACTIVATION_REPORT_ID, + activation_packet, + sizeof(activation_packet)); +#else + HID_SEND_CONTROL(instance->handle, + activation_packet, sizeof(activation_packet)); +#endif + if(result) + print_error("[ds3]: activation packet failed (%d:%d)\n", result); + return result; +} + +static uint32_t set_protocol(ds3_instance_t *instance, int protocol) +{ + uint32_t result = 0; +#if defined(WIIU) + result = HID_SET_PROTOCOL(1); + if(result) + print_error("[ds3]: set protocol failed (%d:%d)\n", result); + +#endif + return result; +} + +static uint32_t send_control_packet(ds3_instance_t *instance) +{ + uint8_t packet_buffer[control_packet_size]; + uint32_t result = 0; + memcpy(packet_buffer, control_packet, control_packet_size); + + packet_buffer[LED_OFFSET] = 0; + if(instance->pad) { + packet_buffer[LED_OFFSET] = 1 << ((instance->slot % 4) + 1); + } + packet_buffer[MOTOR1_OFFSET] = instance->motors[1] >> 8; + packet_buffer[MOTOR2_OFFSET] = instance->motors[0] >> 8; + +#if defined(HAVE_WIIUSB_HID) + packet_buffer[1] = 0x03; +#endif + +#if defined(WIIU) + result = HID_SET_REPORT(instance->handle, + HID_REPORT_OUTPUT, + DS3_RUMBLE_REPORT_ID, + packet_buffer+PACKET_OFFSET, + control_packet_size-PACKET_OFFSET); + if(result) + print_error("[ds3]: send control packet failed: (%d:%d)\n", result); +#else + HID_SEND_CONTROL(instance->handle, + packet_buffer+PACKET_OFFSET, + control_packet_size-PACKET_OFFSET); +#endif /* WIIU */ + return result; +} + static void *ds3_init(void *handle) { ds3_instance_t *instance; - + int errors = 0; + RARCH_LOG("[ds3]: init\n"); instance = (ds3_instance_t *)calloc(1, sizeof(ds3_instance_t)); if(!instance) goto error; instance->handle = handle; -/* TODO: do whatever is needed so that the read loop doesn't bomb out */ + RARCH_LOG("[ds3]: sending activation packet\n"); + if(send_activation_packet(instance)) + errors++; + RARCH_LOG("[ds3]: setting protocol\n"); + if(set_protocol(instance, 1)) + errors++; + RARCH_LOG("[ds3]: sending control packet\n"); + if(send_control_packet(instance)) + errors++; + + if(errors) + goto error; instance->pad = hid_pad_register(instance, &ds3_pad_connection); if(!instance->pad) goto error; + RARCH_LOG("[ds3]: init complete.\n"); return instance; error: + RARCH_ERR("[ds3]: init failed.\n"); if(instance) free(instance); return NULL; @@ -62,9 +187,14 @@ static void ds3_free(void *data) free(instance); } -static void ds3_handle_packet(void *data, uint8_t *buffer, size_t size) +static void ds3_handle_packet(void *data, uint8_t *packet, size_t size) { ds3_instance_t *instance = (ds3_instance_t *)data; + + if(!instance || !instance->pad) + return; + + instance->pad->iface->packet_handler(data, packet, size); } static bool ds3_detect(uint16_t vendor_id, uint16_t product_id) @@ -86,6 +216,9 @@ hid_device_t ds3_hid_device = { static void *ds3_pad_init(void *data, uint32_t slot, hid_driver_t *driver) { + ds3_instance_t *pad = (ds3_instance_t *)data; + pad->slot = slot; + return data; } @@ -97,11 +230,38 @@ static void ds3_pad_deinit(void *data) static void ds3_get_buttons(void *data, retro_bits_t *state) { ds3_instance_t *pad = (ds3_instance_t *)data; + + if(pad) + { + BITS_COPY16_PTR(state, pad->buttons); + + if(pad->buttons & 0x10000) + BIT256_SET_PTR(state, RARCH_MENU_TOGGLE); + } else { + BIT256_CLEAR_ALL_PTR(state); + } } static void ds3_packet_handler(void *data, uint8_t *packet, uint16_t size) { - ds3_instance_t *pad = (ds3_instance_t *)data; + ds3_instance_t *instance = (ds3_instance_t *)data; + RARCH_LOG_BUFFER(packet, size); + + if(!instance->led_set) + { + send_activation_packet(instance); + instance->led_set = true; + } + + if(size > control_packet_size) + { + RARCH_ERR("[ds3]: Expecting packet to be %d but was %d\n", + control_packet_size, size); + return; + } + + memcpy(instance->data, packet, size); + instance->buttons = 0; } static void ds3_set_rumble(void *data, enum retro_rumble_effect effect, uint16_t strength) diff --git a/input/common/hid/hid_device_driver.c b/input/common/hid/hid_device_driver.c index ee0ef38a58..37bc4feaa8 100644 --- a/input/common/hid/hid_device_driver.c +++ b/input/common/hid/hid_device_driver.c @@ -46,7 +46,10 @@ joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface slot = pad_connection_find_vacant_pad(hid_instance.pad_list); if(slot < 0) + { + RARCH_ERR("[hid]: failed to find a vacant pad.\n"); return NULL; + } result = &(hid_instance.pad_list[slot]); result->iface = iface; diff --git a/input/include/hid_driver.h b/input/include/hid_driver.h index 654c3849ea..577dbb093a 100644 --- a/input/include/hid_driver.h +++ b/input/include/hid_driver.h @@ -60,6 +60,12 @@ struct hid_driver hid_instance.os_driver_data, pad, axis) #define HID_PAD_NAME(pad) \ hid_instance.os_driver->name(hid_instance.os_driver_data, pad) +#define HID_SET_PROTOCOL(protocol) \ + hid_instance.os_driver->set_protocol(hid_instance.os_driver_data, protocol) +#define HID_SET_REPORT(pad, rpttype, rptid, data, len) \ + hid_instance.os_driver->set_report(pad, rpttype, rptid, data, len) +#define HID_SEND_CONTROL(pad, data, len) \ + hid_instance.os_driver->send_control(pad, data, len) #define HID_POLL() hid_instance.os_driver->poll( \ hid_instance.os_driver_data) #define HID_MAX_SLOT() hid_instance.max_slot diff --git a/input/input_autodetect_builtin.c b/input/input_autodetect_builtin.c index 2a237e8831..77a09e0487 100644 --- a/input/input_autodetect_builtin.c +++ b/input/input_autodetect_builtin.c @@ -635,6 +635,7 @@ const char* const input_builtin_autoconfs[] = DECL_AUTOCONF_DEVICE(PAD_NAME_CLASSIC, "wiiu", WIIUINPUT_CLASSIC_CONTROLLER_DEFAULT_BINDS), DECL_AUTOCONF_DEVICE(PAD_NAME_HID, "wiiu", WIIUINPUT_GAMEPAD_DEFAULT_BINDS), DECL_AUTOCONF_DEVICE("GameCube Controller", "wiiu", WIIUINPUT_GAMECUBE_DEFAULT_BINDS), + DECL_AUTOCONF_DEVICE("Sony DualShock 3", "wiiu", PS3INPUT_DEFAULT_BINDS), #endif #ifdef __CELLOS_LV2__ DECL_AUTOCONF_DEVICE("SixAxis Controller", "ps3", PS3INPUT_DEFAULT_BINDS), diff --git a/wiiu/input/wiiu_hid.c b/wiiu/input/wiiu_hid.c index b289f648f4..eaa9210e68 100644 --- a/wiiu/input/wiiu_hid.c +++ b/wiiu/input/wiiu_hid.c @@ -458,7 +458,6 @@ static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event) adapter->state = ADAPTER_STATE_NEW; synchronized_add_to_adapters_list(adapter); - wiiu_start_read_loop(adapter); return; @@ -580,6 +579,21 @@ static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list) } } +static void wiiu_handle_ready_adapters(wiiu_hid_t *hid) +{ + wiiu_adapter_t *it; + OSFastMutex_Lock(&(adapters.lock)); + + for(it = adapters.list; it != NULL; it = it->next) + { + if(it->state == ADAPTER_STATE_READY) + wiiu_start_read_loop(it); + } + + OSFastMutex_Unlock(&(adapters.lock)); + +} + static int wiiu_hid_polling_thread(int argc, const char **argv) { wiiu_hid_t *hid = (wiiu_hid_t *)argv; @@ -590,6 +604,7 @@ static int wiiu_hid_polling_thread(int argc, const char **argv) while(!hid->polling_thread_quit) { wiiu_handle_attach_events(hid, synchronized_get_events_list()); + wiiu_handle_ready_adapters(hid); usleep(10000); i += 10000; if(i >= (1000 * 1000 * 3))