diff --git a/griffin/griffin.c b/griffin/griffin.c index f4e25c3b76..1ca0b3a192 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -342,6 +342,7 @@ INPUT #include "../input/connect/connect_wii.c" #ifdef HAVE_HID +#include "../input/drivers_hid/apple_hid.c" #include "../input/drivers_joypad/apple_joypad_hid.c" #endif diff --git a/input/drivers_hid/apple_hid.c b/input/drivers_hid/apple_hid.c new file mode 100644 index 0000000000..dc0164ae8b --- /dev/null +++ b/input/drivers_hid/apple_hid.c @@ -0,0 +1,271 @@ +/* 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. + * + * 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 + +static IOHIDManagerRef g_hid_manager; + +struct pad_connection +{ + int v_id; + int p_id; + uint32_t slot; + IOHIDDeviceRef device_handle; + uint8_t data[2048]; +}; + +static void hid_pad_connection_send_control(void *data, uint8_t* data_buf, size_t size) +{ + struct pad_connection* connection = (struct pad_connection*)data; + + if (connection) + IOHIDDeviceSetReport(connection->device_handle, + kIOHIDReportTypeOutput, 0x01, data_buf + 1, size - 1); +} + +/* NOTE: I pieced this together through trial and error, + * any corrections are welcome. */ + +static void hid_device_input_callback(void* context, IOReturn result, + void* sender, IOHIDValueRef value) +{ + driver_t *driver = driver_get_ptr(); + apple_input_data_t *apple = (apple_input_data_t*)driver->input_data; + struct pad_connection* connection = (struct pad_connection*)context; + IOHIDElementRef element = IOHIDValueGetElement(value); + uint32_t type = IOHIDElementGetType(element); + uint32_t page = IOHIDElementGetUsagePage(element); + uint32_t use = IOHIDElementGetUsage(element); + + if (type != kIOHIDElementTypeInput_Misc) + if (type != kIOHIDElementTypeInput_Button) + if (type != kIOHIDElementTypeInput_Axis) + return; + + /* Joystick handler. + * TODO: Can GamePad work the same? */ + + switch (page) + { + case kHIDPage_GenericDesktop: + switch (type) + { + case kIOHIDElementTypeInput_Misc: + switch (use) + { + case kHIDUsage_GD_Hatswitch: + break; + default: + { + int i; + static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 }; + + for (i = 0; i < 4; i ++) + { + CFIndex min = IOHIDElementGetPhysicalMin(element); + CFIndex max = IOHIDElementGetPhysicalMax(element) - min; + CFIndex state = IOHIDValueGetIntegerValue(value) - min; + float val = (float)state / (float)max; + + if (use != axis_use_ids[i]) + continue; + + apple->axes[connection->slot][i] = + ((val * 2.0f) - 1.0f) * 32767.0f; + } + } + break; + } + break; + } + break; + case kHIDPage_Button: + switch (type) + { + case kIOHIDElementTypeInput_Button: + { + CFIndex state = IOHIDValueGetIntegerValue(value); + unsigned id = use - 1; + + if (state) + BIT64_SET(apple->buttons[connection->slot], id); + else + BIT64_CLEAR(apple->buttons[connection->slot], id); + } + break; + } + break; + } +} + +static void remove_device(void* context, IOReturn result, void* sender) +{ + driver_t *driver = driver_get_ptr(); + apple_input_data_t *apple = (apple_input_data_t*)driver->input_data; + struct pad_connection* connection = (struct pad_connection*)context; + + if (connection && (connection->slot < MAX_USERS)) + { + char msg[PATH_MAX_LENGTH]; + + snprintf(msg, sizeof(msg), "Joypad #%u (%s) disconnected.", + connection->slot, "N/A"); + rarch_main_msg_queue_push(msg, 0, 60, false); + RARCH_LOG("[apple_input]: %s\n", msg); + + apple->buttons[connection->slot] = 0; + memset(apple->axes[connection->slot], 0, sizeof(apple->axes)); + + pad_connection_pad_deinit(&slots[connection->slot], connection->slot); + free(connection); + } +} + +static void hid_device_report(void* context, IOReturn result, void *sender, + IOHIDReportType type, uint32_t reportID, uint8_t *report, + CFIndex reportLength) +{ + struct pad_connection* connection = (struct pad_connection*)context; + + if (!connection) + return; + + pad_connection_packet(&slots[connection->slot], connection->slot, + connection->data, reportLength + 1); +} + +static void add_device(void* context, IOReturn result, + void* sender, IOHIDDeviceRef device) +{ + char device_name[PATH_MAX_LENGTH]; + CFStringRef device_name_ref; + CFNumberRef vendorID, productID; + autoconfig_params_t params = {{0}}; + settings_t *settings = config_get_ptr(); + struct pad_connection* connection = (struct pad_connection*) + calloc(1, sizeof(*connection)); + + connection->device_handle = device; + connection->slot = MAX_USERS; + + IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); + + /* Move the device's run loop to this thread. */ + IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), + kCFRunLoopCommonModes); + IOHIDDeviceRegisterRemovalCallback(device, remove_device, connection); + +#ifndef IOS + device_name_ref = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); + CFStringGetCString(device_name_ref, device_name, + sizeof(device_name), kCFStringEncodingUTF8); +#endif + + vendorID = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)); + CFNumberGetValue(vendorID, kCFNumberIntType, &connection->v_id); + + productID = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)); + CFNumberGetValue(productID, kCFNumberIntType, &connection->p_id); + + connection->slot = pad_connection_pad_init(slots, device_name, + connection, &hid_pad_connection_send_control); + + if (pad_connection_has_interface(slots, connection->slot)) + IOHIDDeviceRegisterInputReportCallback(device, + connection->data + 1, sizeof(connection->data) - 1, + hid_device_report, connection); + else + IOHIDDeviceRegisterInputValueCallback(device, + hid_device_input_callback, connection); + + if (device_name[0] == '\0') + return; + + strlcpy(settings->input.device_names[connection->slot], + device_name, sizeof(settings->input.device_names)); + + params.idx = connection->slot; + strlcpy(params.name, device_name, sizeof(params.name)); + params.vid = connection->v_id; + params.pid = connection->p_id; + strlcpy(params.driver, apple_hid_joypad.ident, sizeof(params.driver)); + + input_config_autoconfigure_joypad(¶ms); + RARCH_LOG("Port %d: %s.\n", connection->slot, device_name); +} + +static void append_matching_dictionary(CFMutableArrayRef array, + uint32_t page, uint32_t use) +{ + CFNumberRef usen, pagen; + CFMutableDictionaryRef matcher = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + pagen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); + CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsagePageKey), pagen); + CFRelease(pagen); + + usen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &use); + CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsageKey), usen); + CFRelease(usen); + + CFArrayAppendValue(array, matcher); + CFRelease(matcher); +} + +static bool apple_hid_init(void) +{ + CFMutableArrayRef matcher; + + if (!(g_hid_manager = IOHIDManagerCreate( + kCFAllocatorDefault, kIOHIDOptionsTypeNone))) + return false; + + matcher = CFArrayCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeArrayCallBacks); + + append_matching_dictionary(matcher, kHIDPage_GenericDesktop, + kHIDUsage_GD_Joystick); + append_matching_dictionary(matcher, kHIDPage_GenericDesktop, + kHIDUsage_GD_GamePad); + + IOHIDManagerSetDeviceMatchingMultiple(g_hid_manager, matcher); + CFRelease(matcher); + + IOHIDManagerRegisterDeviceMatchingCallback(g_hid_manager, + add_device, 0); + IOHIDManagerScheduleWithRunLoop(g_hid_manager, CFRunLoopGetCurrent(), + kCFRunLoopDefaultMode); + + IOHIDManagerOpen(g_hid_manager, kIOHIDOptionsTypeNone); + + return true; +} + +static void apple_hid_free(void) +{ + if (!g_hid_manager) + return; + + IOHIDManagerClose(g_hid_manager, kIOHIDOptionsTypeNone); + IOHIDManagerUnscheduleFromRunLoop(g_hid_manager, + CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + + CFRelease(g_hid_manager); + + g_hid_manager = NULL; +} diff --git a/input/drivers_joypad/apple_joypad_hid.c b/input/drivers_joypad/apple_joypad_hid.c index bb0d169fdc..63b73c8cc8 100644 --- a/input/drivers_joypad/apple_joypad_hid.c +++ b/input/drivers_joypad/apple_joypad_hid.c @@ -14,267 +14,13 @@ * If not, see . */ -#include -#include #include "../drivers/apple_input.h" #include "../input_autodetect.h" #include "../input_common.h" #include "../../general.h" #include "../../runloop.h" -struct pad_connection -{ - int v_id; - int p_id; - uint32_t slot; - IOHIDDeviceRef device_handle; - uint8_t data[2048]; -}; - static joypad_connection_t *slots; -static IOHIDManagerRef g_hid_manager; - -static void hid_pad_connection_send_control(void *data, uint8_t* data_buf, size_t size) -{ - struct pad_connection* connection = (struct pad_connection*)data; - - if (connection) - IOHIDDeviceSetReport(connection->device_handle, - kIOHIDReportTypeOutput, 0x01, data_buf + 1, size - 1); -} - -/* NOTE: I pieced this together through trial and error, - * any corrections are welcome. */ - -static void hid_device_input_callback(void* context, IOReturn result, - void* sender, IOHIDValueRef value) -{ - driver_t *driver = driver_get_ptr(); - apple_input_data_t *apple = (apple_input_data_t*)driver->input_data; - struct pad_connection* connection = (struct pad_connection*)context; - IOHIDElementRef element = IOHIDValueGetElement(value); - uint32_t type = IOHIDElementGetType(element); - uint32_t page = IOHIDElementGetUsagePage(element); - uint32_t use = IOHIDElementGetUsage(element); - - if (type != kIOHIDElementTypeInput_Misc) - if (type != kIOHIDElementTypeInput_Button) - if (type != kIOHIDElementTypeInput_Axis) - return; - - /* Joystick handler. - * TODO: Can GamePad work the same? */ - - switch (page) - { - case kHIDPage_GenericDesktop: - switch (type) - { - case kIOHIDElementTypeInput_Misc: - switch (use) - { - case kHIDUsage_GD_Hatswitch: - break; - default: - { - int i; - static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 }; - - for (i = 0; i < 4; i ++) - { - CFIndex min = IOHIDElementGetPhysicalMin(element); - CFIndex max = IOHIDElementGetPhysicalMax(element) - min; - CFIndex state = IOHIDValueGetIntegerValue(value) - min; - float val = (float)state / (float)max; - - if (use != axis_use_ids[i]) - continue; - - apple->axes[connection->slot][i] = - ((val * 2.0f) - 1.0f) * 32767.0f; - } - } - break; - } - break; - } - break; - case kHIDPage_Button: - switch (type) - { - case kIOHIDElementTypeInput_Button: - { - CFIndex state = IOHIDValueGetIntegerValue(value); - unsigned id = use - 1; - - if (state) - BIT64_SET(apple->buttons[connection->slot], id); - else - BIT64_CLEAR(apple->buttons[connection->slot], id); - } - break; - } - break; - } -} - -static void remove_device(void* context, IOReturn result, void* sender) -{ - driver_t *driver = driver_get_ptr(); - apple_input_data_t *apple = (apple_input_data_t*)driver->input_data; - struct pad_connection* connection = (struct pad_connection*)context; - - if (connection && (connection->slot < MAX_USERS)) - { - char msg[PATH_MAX_LENGTH]; - - snprintf(msg, sizeof(msg), "Joypad #%u (%s) disconnected.", - connection->slot, "N/A"); - rarch_main_msg_queue_push(msg, 0, 60, false); - RARCH_LOG("[apple_input]: %s\n", msg); - - apple->buttons[connection->slot] = 0; - memset(apple->axes[connection->slot], 0, sizeof(apple->axes)); - - pad_connection_pad_deinit(&slots[connection->slot], connection->slot); - free(connection); - } -} - -static void hid_device_report(void* context, IOReturn result, void *sender, - IOHIDReportType type, uint32_t reportID, uint8_t *report, - CFIndex reportLength) -{ - struct pad_connection* connection = (struct pad_connection*)context; - - if (!connection) - return; - - pad_connection_packet(&slots[connection->slot], connection->slot, - connection->data, reportLength + 1); -} - -static void add_device(void* context, IOReturn result, - void* sender, IOHIDDeviceRef device) -{ - char device_name[PATH_MAX_LENGTH]; - CFStringRef device_name_ref; - CFNumberRef vendorID, productID; - autoconfig_params_t params = {{0}}; - settings_t *settings = config_get_ptr(); - struct pad_connection* connection = (struct pad_connection*) - calloc(1, sizeof(*connection)); - - connection->device_handle = device; - connection->slot = MAX_USERS; - - IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); - - /* Move the device's run loop to this thread. */ - IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), - kCFRunLoopCommonModes); - IOHIDDeviceRegisterRemovalCallback(device, remove_device, connection); - -#ifndef IOS - device_name_ref = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); - CFStringGetCString(device_name_ref, device_name, - sizeof(device_name), kCFStringEncodingUTF8); -#endif - - vendorID = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)); - CFNumberGetValue(vendorID, kCFNumberIntType, &connection->v_id); - - productID = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)); - CFNumberGetValue(productID, kCFNumberIntType, &connection->p_id); - - connection->slot = pad_connection_pad_init(slots, device_name, - connection, &hid_pad_connection_send_control); - - if (pad_connection_has_interface(slots, connection->slot)) - IOHIDDeviceRegisterInputReportCallback(device, - connection->data + 1, sizeof(connection->data) - 1, - hid_device_report, connection); - else - IOHIDDeviceRegisterInputValueCallback(device, - hid_device_input_callback, connection); - - if (device_name[0] == '\0') - return; - - strlcpy(settings->input.device_names[connection->slot], - device_name, sizeof(settings->input.device_names)); - - params.idx = connection->slot; - strlcpy(params.name, device_name, sizeof(params.name)); - params.vid = connection->v_id; - params.pid = connection->p_id; - strlcpy(params.driver, apple_hid_joypad.ident, sizeof(params.driver)); - - input_config_autoconfigure_joypad(¶ms); - RARCH_LOG("Port %d: %s.\n", connection->slot, device_name); -} - -static void append_matching_dictionary(CFMutableArrayRef array, - uint32_t page, uint32_t use) -{ - CFNumberRef usen, pagen; - CFMutableDictionaryRef matcher = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - pagen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); - CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsagePageKey), pagen); - CFRelease(pagen); - - usen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &use); - CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsageKey), usen); - CFRelease(usen); - - CFArrayAppendValue(array, matcher); - CFRelease(matcher); -} - -static bool apple_hid_init(void) -{ - CFMutableArrayRef matcher; - - if (!(g_hid_manager = IOHIDManagerCreate( - kCFAllocatorDefault, kIOHIDOptionsTypeNone))) - return false; - - matcher = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks); - - append_matching_dictionary(matcher, kHIDPage_GenericDesktop, - kHIDUsage_GD_Joystick); - append_matching_dictionary(matcher, kHIDPage_GenericDesktop, - kHIDUsage_GD_GamePad); - - IOHIDManagerSetDeviceMatchingMultiple(g_hid_manager, matcher); - CFRelease(matcher); - - IOHIDManagerRegisterDeviceMatchingCallback(g_hid_manager, - add_device, 0); - IOHIDManagerScheduleWithRunLoop(g_hid_manager, CFRunLoopGetCurrent(), - kCFRunLoopDefaultMode); - - IOHIDManagerOpen(g_hid_manager, kIOHIDOptionsTypeNone); - - return true; -} - -static void apple_hid_free(void) -{ - if (!g_hid_manager) - return; - - IOHIDManagerClose(g_hid_manager, kIOHIDOptionsTypeNone); - IOHIDManagerUnscheduleFromRunLoop(g_hid_manager, - CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - - CFRelease(g_hid_manager); - - g_hid_manager = NULL; -} static bool apple_joypad_init(void) {