diff --git a/input/connect/connect_ps4.c b/input/connect/connect_ps4.c index 68f91b33ef..f5f9d53976 100644 --- a/input/connect/connect_ps4.c +++ b/input/connect/connect_ps4.c @@ -1,7 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2013-2014 - Jason Fetters * Copyright (C) 2014-2015 - Daniel De Matteis - * + * * 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. diff --git a/input/connect/joypad_connection.c b/input/connect/joypad_connection.c index 9731d766b9..60e5723a2d 100644 --- a/input/connect/joypad_connection.c +++ b/input/connect/joypad_connection.c @@ -1,7 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2013-2014 - Jason Fetters * Copyright (C) 2011-2015 - Daniel De Matteis - * + * * 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. @@ -60,7 +60,7 @@ void *pad_connection_init(unsigned pads) } int32_t pad_connection_pad_init(joypad_connection_t *joyconn, - const char* name, uint16_t vid, uint16_t pid, + const char* name, uint16_t vid, uint16_t pid, void *data, send_control_t ptr) { int pad = pad_connection_find_vacant_pad(joyconn); @@ -76,7 +76,7 @@ int32_t pad_connection_pad_init(joypad_connection_t *joyconn, uint16_t vid; uint16_t pid; pad_connection_interface_t *iface; - } pad_map[] = + } pad_map[] = { { "Nintendo RVL-CNT-01", 1406, 816, &pad_connection_wii }, #if 0 @@ -105,14 +105,14 @@ int32_t pad_connection_pad_init(joypad_connection_t *joyconn, } } - return pad; + return -1; } void pad_connection_pad_deinit(joypad_connection_t *joyconn, uint32_t pad) { if (!joyconn || !joyconn->connected) return; - + if (joyconn->iface) { joyconn->iface->set_rumble(joyconn->data, RETRO_RUMBLE_STRONG, 0); @@ -152,7 +152,7 @@ int16_t pad_connection_get_axis(joypad_connection_t *joyconn, bool pad_connection_has_interface(joypad_connection_t *joyconn, unsigned pad) { - if (joyconn && joyconn->connected && joyconn->iface) + if (joyconn && pad >= 0 && pad < MAX_USERS && joyconn[pad].connected && joyconn[pad].iface) return true; return false; } diff --git a/input/drivers_hid/libusb_hid.c b/input/drivers_hid/libusb_hid.c index 309aed591f..f926588062 100644 --- a/input/drivers_hid/libusb_hid.c +++ b/input/drivers_hid/libusb_hid.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "../connect/joypad_connection.h" #include "../../driver.h" #include "../input_autodetect.h" @@ -45,6 +46,8 @@ struct libusb_adapter uint32_t slot; sthread_t *thread; + slock_t *send_control_lock; + fifo_buffer_t *send_control_buffer; struct libusb_adapter *next; }; @@ -53,20 +56,49 @@ static struct libusb_adapter adapters; static void adapter_thread(void *data) { struct libusb_adapter *adapter = (struct libusb_adapter*)data; + uint8_t send_command_buf[4096]; while (!adapter->quitting) { driver_t *driver = driver_get_ptr(); libusb_hid_t *hid = (libusb_hid_t*)driver->hid_data; int size = 0; - libusb_interrupt_transfer(adapter->handle, adapter->endpoint_in, &adapter->data[0], adapter->endpoint_in_max_size, &size, 0); + size_t send_command_size; + int tmp; + int report_number; + + 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); +#if 0 + report_number = send_command_buf[0]; + libusb_control_transfer(adapter->handle, + LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, + 0x09/*HID Set_Report*/, + (2/*HID output*/ << 8) | report_number, + adapter->interface_number, + send_command_buf, send_command_size, + 1000/*timeout millis*/); +#else + libusb_interrupt_transfer(adapter->handle, adapter->endpoint_out, send_command_buf, send_command_size, &tmp, 1000); +#endif + } + } + slock_unlock(adapter->send_control_lock); + + libusb_interrupt_transfer(adapter->handle, adapter->endpoint_in, &adapter->data[1], adapter->endpoint_in_max_size, &size, 1000); + #if 0 static unsigned count; fprintf(stderr, "[%s] Gets here, count: %d\n", adapter->name, count++); #endif - if (adapter && hid) + if (adapter && hid && hid->slots && size) pad_connection_packet(&hid->slots[adapter->slot], adapter->slot, - adapter->data, size); + adapter->data, size+1); } } @@ -74,21 +106,21 @@ static void libusb_hid_device_send_control(void *data, uint8_t* data_buf, size_t size) { struct libusb_adapter *adapter = (struct libusb_adapter*)data; - int report_number = data_buf[0]; - int tmp; if (adapter) - #if 0 - libusb_control_transfer(adapter->handle, - LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, - 0x09/*HID Set_Report*/, - (2/*HID output*/ << 8) | report_number, - adapter->interface_number, - data_buf, size, - 1000/*timeout millis*/); - #endif - // TODO: push this to the adapter thread - libusb_interrupt_transfer(adapter->handle, adapter->endpoint_out, data_buf, size, &tmp, 0); + { + 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 libusb_hid_device_add_autodetect(unsigned idx, @@ -121,7 +153,7 @@ static void libusb_get_description(struct libusb_device *device, { const struct libusb_interface *inter = &config->interface[i]; - fprintf(stderr, "Number of alternate settings: %d.\n", inter->num_altsetting); + fprintf(stderr, " Number of alternate settings: %d.\n", inter->num_altsetting); for(j = 0; j < inter->num_altsetting; j++) { @@ -131,8 +163,8 @@ static void libusb_get_description(struct libusb_device *device, { adapter->interface_number = (int)interdesc->bInterfaceNumber; - fprintf(stderr, "Interface Number: %d.\n", (int)interdesc->bInterfaceNumber); - fprintf(stderr, "Number of endpoints: %d.\n", (int)interdesc->bNumEndpoints); + fprintf(stderr, " Interface Number: %d.\n", (int)interdesc->bInterfaceNumber); + fprintf(stderr, " Number of endpoints: %d.\n", (int)interdesc->bNumEndpoints); for(k = 0; k < (int)interdesc->bNumEndpoints; k++) { @@ -153,8 +185,11 @@ static void libusb_get_description(struct libusb_device *device, adapter->endpoint_out_max_size = epdesc->wMaxPacketSize; } } - fprintf(stderr, "Descriptor Type: %d.\n", (int)epdesc->bDescriptorType); - fprintf(stderr, "EP Address: %d.\n", (int)epdesc->bEndpointAddress); + fprintf(stderr, " Descriptor Type: %d.\n", (int)epdesc->bDescriptorType); + fprintf(stderr, " EP Address: %d.\n", (int)epdesc->bEndpointAddress); + fprintf(stderr, " is_int: %d.\n", (int)is_int); + fprintf(stderr, " is_out: %d.\n", (int)is_out); + fprintf(stderr, " is_in: %d.\n\n", (int)is_in); } } goto ret; @@ -212,7 +247,7 @@ static int add_adapter(void *data, struct libusb_device *dev) libusb_get_string_descriptor_ascii(adapter->handle, desc.iManufacturer, adapter->manufacturer_name, sizeof(adapter->manufacturer_name)); - fprintf(stderr, "Adapter Manufacturer name: %s\n", + fprintf(stderr, " Adapter Manufacturer name: %s\n", adapter->manufacturer_name); } @@ -221,31 +256,48 @@ static int add_adapter(void *data, struct libusb_device *dev) libusb_get_string_descriptor_ascii(adapter->handle, desc.iProduct, adapter->name, sizeof(adapter->name)); - fprintf(stderr, "Adapter name: %s\n", adapter->name); - } - - if (libusb_kernel_driver_active(adapter->handle, 0) == 1 - && libusb_detach_kernel_driver(adapter->handle, 0)) - { - fprintf(stderr, "Error detaching handle 0x%p from kernel.\n", adapter->handle); - goto error; + fprintf(stderr, " Adapter name: %s\n", adapter->name); } device_name = (const char*)adapter->name; + if (adapter->name[0] == '\0') + goto error; + + adapter->send_control_lock = slock_new(); + adapter->send_control_buffer = fifo_new(4096); + + if (!adapter->send_control_lock || !adapter->send_control_buffer) + { + fprintf(stderr, "Error creating send control buffer.\n"); + goto error; + } + adapter->slot = pad_connection_pad_init(hid->slots, device_name, desc.idVendor, desc.idProduct, adapter, &libusb_hid_device_send_control); if (!pad_connection_has_interface(hid->slots, adapter->slot)) { - fprintf(stderr, "Interface not found (%s).\n", adapter->name); + fprintf(stderr, " Interface not found (%s).\n", adapter->name); goto error; } - if (adapter->name[0] == '\0') + if (libusb_kernel_driver_active(adapter->handle, 0) == 1 + && libusb_detach_kernel_driver(adapter->handle, 0)) + { + fprintf(stderr, " Error detaching handle 0x%p from kernel.\n", adapter->handle); goto error; + } - fprintf(stderr, "Device 0x%p attached (VID/PID: %04x:%04x).\n", + rc = libusb_claim_interface(adapter->handle, adapter->interface_number); + + if (rc != LIBUSB_SUCCESS) + { + fprintf(stderr, "Error claiming interface %d .\n", adapter->interface_number); + goto error; + } + + fprintf(stderr, " Device 0x%p attached (VID/PID: %04x:%04x).\n", adapter->device, desc.idVendor, desc.idProduct); libusb_hid_device_add_autodetect(adapter->slot, @@ -268,6 +320,10 @@ static int add_adapter(void *data, struct libusb_device *dev) 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); return -1; @@ -290,6 +346,10 @@ static int remove_adapter(void *data, struct libusb_device *dev) pad_connection_pad_deinit(&hid->slots[adapter->slot], adapter->slot); + slock_free(adapter->send_control_lock); + fifo_free(adapter->send_control_buffer); + + libusb_release_interface(adapter->next->handle, adapter->next->interface_number); libusb_close(adapter->next->handle); new_next = adapter->next->next;