diff --git a/input/connect/connect_wiiugca.c b/input/connect/connect_wiiugca.c index 92423481f4..9f4b0fbb7d 100644 --- a/input/connect/connect_wiiugca.c +++ b/input/connect/connect_wiiugca.c @@ -33,7 +33,11 @@ struct hidpad_wiiugca_data static void* hidpad_wiiugca_init(void *data, uint32_t slot, hid_driver_t *driver) { +#ifdef WIIU + static uint8_t magic_data[] = {0x13}; /* Special command to enable reading */ +#else static uint8_t magic_data[] = {0x01, 0x13}; /* Special command to enable reading */ +#endif struct pad_connection* connection = (struct pad_connection*)data; struct hidpad_wiiugca_data* device = (struct hidpad_wiiugca_data*) calloc(1, sizeof(struct hidpad_wiiugca_data)); diff --git a/input/drivers_hid/wiiu_hid.c b/input/drivers_hid/wiiu_hid.c index 6b53877d89..ca9d9970d5 100644 --- a/input/drivers_hid/wiiu_hid.c +++ b/input/drivers_hid/wiiu_hid.c @@ -19,10 +19,12 @@ #include #include #include +#include #include "wiiu_hid.h" static wiiu_event_list events; +static wiiu_adapter_list adapters; static bool wiiu_hid_joypad_query(void *data, unsigned pad) { @@ -87,7 +89,7 @@ static void *wiiu_hid_init(void) hid->connections = connections; - wiiu_hid_init_event_list(); + wiiu_hid_init_lists(); start_polling_thread(hid); if(!hid->polling_thread) goto error; @@ -133,15 +135,23 @@ static void wiiu_hid_poll(void *data) (void)data; } -static int32_t wiiu_hid_set_report(void *data, uint8_t report_type, report_id, - void *report_data, uint32_t report_length) +static void wiiu_hid_send_control(void *data, uint8_t *buf, size_t size) { - wiiu_hid_t *hid = (wiiu_hid_t)data; + wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; + if(!adapter) + return; - if(!hid) + HIDWrite(adapter->handle, buf, size, NULL, NULL); +} + +static int32_t wiiu_hid_set_report(void *data, uint8_t report_type, + uint8_t report_id, void *report_data, uint32_t report_length) +{ + wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; + if(!adapter) return -1; - return HIDSetReport(hid->handle, + return HIDSetReport(adapter->handle, report_type, report_id, report_data, @@ -151,24 +161,24 @@ static int32_t wiiu_hid_set_report(void *data, uint8_t report_type, report_id, static int32_t wiiu_hid_set_idle(void *data, uint8_t duration) { - wiiu_hid_t *hid = (wiiu_hid_t)data; - if(!hid) + wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; + if(!adapter) return -1; - return HIDSetIdle(hid->handle, - hid->interface_index, + return HIDSetIdle(adapter->handle, + adapter->interface_index, duration, NULL, NULL); } static int32_t wiiu_hid_set_protocol(void *data, uint8_t protocol) { - wiiu_hid_t *hid = (wiiu_hid_t)data; - if(!hid) + wiiu_adapter_t *adapter = (wiiu_adapter_t *)data; + if(!adapter) return -1; - return HIDSetProtocol(hid->handle, - hid->interface_index, + return HIDSetProtocol(adapter->handle, + adapter->interface_index, protocol, NULL, NULL); } @@ -200,6 +210,8 @@ static void start_polling_thread(wiiu_hid_t *hid) { goto error; } + OSSetThreadCleanupCallback(thread, wiiu_hid_polling_thread_cleanup); + hid->polling_thread = thread; hid->polling_thread_stack = stack; OSResumeThread(thread); @@ -246,6 +258,7 @@ static void log_device(HIDDevice *device) { RARCH_LOG(" max_packet_size_tx: %d\n", device->max_packet_size_tx); } + static void synchronized_add_event(wiiu_attach_event *event) { OSFastMutex_Lock(&(events.lock)); event->next = events.list; @@ -263,7 +276,11 @@ static wiiu_attach_event *synchronized_get_events_list(void) { return list; } -static void synchronized_add_to_adapters_list(struct wiiu_adapter *adapter) { +static void synchronized_add_to_adapters_list(wiiu_adapter_t *adapter) { + OSFastMutex_Lock(&(adapters.lock)); + adapter->next = adapters.list; + adapters.list = adapter; + OSFastMutex_Unlock(&(adapters.lock)); } static int32_t wiiu_attach_callback(HIDClient *client, HIDDevice *device, uint32_t attach) { @@ -295,7 +312,7 @@ static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event) { static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event) { - struct wiiu_adapter *adapter = new_adapter(); + wiiu_adapter_t *adapter = new_adapter(event); if(!adapter) { RARCH_ERR("[hid]: Failed to allocate adapter.\n"); @@ -303,9 +320,11 @@ static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event) { } adapter->hid = hid; - adapter->handle = event->handle; + + RARCH_LOG("[hid]: pad_connection_pad_init\n"); adapter->slot = pad_connection_pad_init(hid->connections, - "hid", event->vendor_id, event->product_id, adapter, +// "hid", event->vendor_id, event->product_id, adapter, + "hid", SWAP16(event->vendor_id), SWAP16(event->product_id), adapter, &wiiu_hid); if(adapter->slot < 0) { @@ -313,19 +332,72 @@ static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event) { goto error; } + RARCH_LOG("[hid]: got slot %d\n", adapter->slot); + if(!pad_connection_has_interface(hid->connections, adapter->slot)) { RARCH_ERR("[hid]: Interface not found for HID device with vid=0x%04x pid=0x%04x\n", event->vendor_id, event->product_id); goto error; } + RARCH_LOG("[hid]: adding to adapter list\n"); synchronized_add_to_adapters_list(adapter); + RARCH_LOG("[hid]: starting read loop\n"); + wiiu_start_read_loop(adapter); return; error: delete_adapter(adapter); } +void wiiu_start_read_loop(wiiu_adapter_t *adapter) +{ + adapter->state = ADAPTER_STATE_READING; + HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, wiiu_hid_read_loop_callback, adapter); +} + +static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, + uint8_t *buffer, uint32_t buffer_size, void *userdata) +{ + uint32_t coreId = OSGetCoreId(); + wiiu_adapter_t *adapter = (wiiu_adapter_t *)userdata; + if(!adapter) + { + RARCH_ERR("read_loop_callback: bad userdata\n"); + return; + } + + RARCH_LOG("read_loop_callback running on core %d\n", coreId); + usleep(5000); + if(!adapter->hid->polling_thread_quit) { + adapter->state = ADAPTER_STATE_READING; + HIDRead(adapter->handle, adapter->rx_buffer, adapter->rx_size, + wiiu_hid_read_loop_callback, adapter); + return; + } + + adapter->state = ADAPTER_STATE_DONE; +} + +/** + * Block until all the HIDRead() calls have returned. + */ +static void wiiu_hid_polling_thread_cleanup(OSThread *thread, void *stack) { + int not_done = 0; + wiiu_adapter_t *adapter; + do { + OSFastMutex_Lock(&(adapters.lock)); + not_done = 0; + for(adapter = adapters.list; adapter != NULL; adapter = adapter->next) { + if(adapter->state != ADAPTER_STATE_DONE) { + not_done++; + } + } + OSFastMutex_Unlock(&(adapters.lock)); + usleep(1000); + } while(not_done); +} + static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list) { wiiu_attach_event *event; if(!hid || !list) @@ -365,10 +437,13 @@ static OSThread *new_thread(void) { return t; } -static void wiiu_hid_init_event_list(void) { +static void wiiu_hid_init_lists(void) { RARCH_LOG("[hid]: Initializing events list\n"); memset(&events, 0, sizeof(events)); OSFastMutex_Init(&(events.lock), "attach_events"); + RARCH_LOG("[hid]: Initializing adapters list\n"); + memset(&adapters, 0, sizeof(adapters)); + OSFastMutex_Init(&(adapters.lock), "adapters"); } static wiiu_hid_t *new_hid(void) { @@ -393,15 +468,27 @@ static void delete_hidclient(HIDClient *client) { free(client); } -static struct wiiu_adapter *new_adapter(void) { +static wiiu_adapter_t *new_adapter(wiiu_attach_event *event) { RARCH_LOG("[hid]: new_adapter()\n"); - return alloc_zeroed(4, sizeof(struct wiiu_adapter)); + + wiiu_adapter_t *adapter = alloc_zeroed(64, sizeof(wiiu_adapter_t)); + adapter->handle = event->handle; + adapter->interface_index = event->interface_index; + adapter->rx_size = event->max_packet_size_rx; + adapter->rx_buffer = alloc_zeroed(64, adapter->rx_size); + + return adapter; } -static void delete_adapter(struct wiiu_adapter *adapter) { +static void delete_adapter(wiiu_adapter_t *adapter) { RARCH_LOG("[hid]: delete_adapter()\n"); - if(adapter) + if(adapter) { + if(adapter->rx_buffer) { + free(adapter->rx_buffer); + adapter->rx_buffer = NULL; + } free(adapter); + } } static wiiu_attach_event *new_attach_event(HIDDevice *device) { @@ -413,7 +500,7 @@ static wiiu_attach_event *new_attach_event(HIDDevice *device) { return NULL; event->handle = device->handle; event->vendor_id = device->vid; - event->product_id = device->vid; + event->product_id = device->pid; event->interface_index = device->interface_index; event->is_keyboard = (device->sub_class == 1 && device->protocol == 1); event->is_mouse = (device->sub_class == 1 && device->protocol == 2); @@ -450,8 +537,9 @@ hid_driver_t wiiu_hid = { wiiu_hid_joypad_rumble, wiiu_hid_joypad_name, "wiiu", - NULL, // send_control + wiiu_hid_send_control, wiiu_hid_set_report, wiiu_hid_set_idle, wiiu_hid_set_protocol }; + diff --git a/input/drivers_hid/wiiu_hid.h b/input/drivers_hid/wiiu_hid.h index d2f4bc0715..2609ff73b7 100644 --- a/input/drivers_hid/wiiu_hid.h +++ b/input/drivers_hid/wiiu_hid.h @@ -26,6 +26,10 @@ #define MAX_HID_PADS 5 +#define ADAPTER_STATE_NEW 0 +#define ADAPTER_STATE_READING 1 +#define ADAPTER_STATE_DONE 2 + typedef struct wiiu_hid { HIDClient *client; @@ -35,10 +39,17 @@ typedef struct wiiu_hid volatile bool polling_thread_quit; } wiiu_hid_t; +typedef struct wiiu_adapter wiiu_adapter_t; + struct wiiu_adapter { + wiiu_adapter_t *next; wiiu_hid_t *hid; + uint8_t state; + uint8_t *rx_buffer; + uint32_t rx_size; int32_t slot; uint32_t handle; + uint8_t interface_index; }; typedef struct wiiu_attach wiiu_attach_event; @@ -57,24 +68,30 @@ struct wiiu_attach { }; typedef struct _wiiu_event_list wiiu_event_list; +typedef struct _wiiu_adapter_list wiiu_adapter_list; struct _wiiu_event_list { OSFastMutex lock; wiiu_attach_event *list; }; +struct _wiiu_adapter_list { + OSFastMutex lock; + wiiu_adapter_t *list; +}; + static void *alloc_zeroed(size_t alignment, size_t size); static OSThread *new_thread(void); static wiiu_hid_t *new_hid(void); static void delete_hid(wiiu_hid_t *hid); static void delete_hidclient(HIDClient *client); static HIDClient *new_hidclient(void); -static struct wiiu_adapter *new_adapter(void); -static void delete_adapter(struct wiiu_adapter *adapter); +static wiiu_adapter_t *new_adapter(wiiu_attach_event *event); +static void delete_adapter(wiiu_adapter_t *adapter); static wiiu_attach_event *new_attach_event(HIDDevice *device); static void delete_attach_event(wiiu_attach_event *); -static void wiiu_hid_init_event_list(void); +static void wiiu_hid_init_lists(void); static void start_polling_thread(wiiu_hid_t *hid); static void stop_polling_thread(wiiu_hid_t *hid); static int wiiu_hid_polling_thread(int argc, const char **argv); @@ -83,7 +100,11 @@ static wiiu_attach_event *synchronized_get_events_list(void); static void wiiu_handle_attach_events(wiiu_hid_t *hid, wiiu_attach_event *list); static void wiiu_hid_attach(wiiu_hid_t *hid, wiiu_attach_event *event); static void wiiu_hid_detach(wiiu_hid_t *hid, wiiu_attach_event *event); -static void synchronized_add_to_adapters_list(struct wiiu_adapter *adapter); +static void synchronized_add_to_adapters_list(wiiu_adapter_t *adapter); static void synchronized_add_event(wiiu_attach_event *event); +static void wiiu_start_read_loop(wiiu_adapter_t *adapter); +static void wiiu_hid_read_loop_callback(uint32_t handle, int32_t error, + uint8_t *buffer, uint32_t buffer_size, void *userdata); +static void wiiu_hid_polling_thread_cleanup(OSThread *thread, void *stack); #endif // __WIIU_HID__H diff --git a/wiiu/system/imports.h b/wiiu/system/imports.h index 11dc810352..12acb41878 100644 --- a/wiiu/system/imports.h +++ b/wiiu/system/imports.h @@ -24,11 +24,14 @@ IMPORT(OSGetTitleID); IMPORT(OSIsThreadTerminated); IMPORT(OSSetThreadPriority); IMPORT(OSCreateThread); +IMPORT(OSSetThreadCleanupCallback); IMPORT(OSResumeThread); IMPORT(OSIsThreadSuspended); IMPORT(OSSuspendThread); IMPORT(OSJoinThread); IMPORT(OSYieldThread); +IMPORT(OSGetCoreId); +IMPORT(OSIsMainCore); IMPORT(OSGetSystemTime); IMPORT(OSGetSystemTick); IMPORT(OSGetSymbolName);