static void iohidmanager_hid_device_add(void *data, IOReturn result, void* sender, IOHIDDeviceRef device) { IOReturn ret; uint16_t dev_vid, dev_pid; settings_t *settings = config_get_ptr(); iohidmanager_hid_t *hid = (iohidmanager_hid_t*)hid_driver_get_data(); struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*) calloc(1, sizeof(*adapter)); if (!adapter || !hid) return; adapter->handle = device; ret = IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); if (ret != kIOReturnSuccess) { free(adapter); return; } /* Move the device's run loop to this thread. */ IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); IOHIDDeviceRegisterRemovalCallback(device, iohidmanager_hid_device_remove, adapter); #ifndef IOS iohidmanager_hid_device_get_product_string(device, adapter->name, sizeof(adapter->name)); #endif dev_vid = iohidmanager_hid_device_get_vendor_id (device); dev_pid = iohidmanager_hid_device_get_product_id (device); adapter->slot = pad_connection_pad_init(hid->slots, adapter->name, dev_vid, dev_pid, adapter, &iohidmanager_hid_device_send_control); if (adapter->slot == -1) return; if (pad_connection_has_interface(hid->slots, adapter->slot)) IOHIDDeviceRegisterInputReportCallback(device, adapter->data + 1, sizeof(adapter->data) - 1, iohidmanager_hid_device_report, adapter); else IOHIDDeviceRegisterInputValueCallback(device, iohidmanager_hid_device_input_callback, adapter); if (adapter->name[0] == '\0') return; strlcpy(settings->input.device_names[adapter->slot], adapter->name, sizeof(settings->input.device_names[adapter->slot])); iohidmanager_hid_device_add_autodetect(adapter->slot, adapter->name, iohidmanager_hid.ident, dev_vid, dev_pid); }
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; 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(g_settings.input.device_names[connection->slot], device_name, sizeof(g_settings.input.device_names)); input_config_autoconfigure_joypad(connection->slot, device_name, connection->v_id, connection->p_id, apple_hid_joypad.ident); RARCH_LOG("Port %d: %s.\n", connection->slot, device_name); }
static int add_adapter(void *data, struct libusb_device *dev) { int rc; struct libusb_device_descriptor desc; const char *device_name = NULL; struct libusb_adapter *old_head = NULL; struct libusb_hid *hid = (struct libusb_hid*)data; struct libusb_adapter *adapter = (struct libusb_adapter*) calloc(1, sizeof(struct libusb_adapter)); if (!adapter) return -1; if (!hid) { free(adapter); RARCH_ERR("Allocation of adapter failed.\n"); return -1; } rc = libusb_get_device_descriptor(dev, &desc); if (rc != LIBUSB_SUCCESS) { RARCH_ERR("Error getting device descriptor.\n"); goto error; } adapter->device = dev; libusb_get_description(adapter->device, adapter); if (adapter->endpoint_in == 0) { RARCH_ERR("Could not find HID config for device.\n"); goto error; } rc = libusb_open (adapter->device, &adapter->handle); if (rc != LIBUSB_SUCCESS) { RARCH_ERR("Error opening device 0x%p (VID/PID: %04x:%04x).\n", (void*)adapter->device, desc.idVendor, desc.idProduct); goto error; } if (desc.iManufacturer) { libusb_get_string_descriptor_ascii(adapter->handle, desc.iManufacturer, adapter->manufacturer_name, sizeof(adapter->manufacturer_name)); #if 0 RARCH_ERR(" Adapter Manufacturer name: %s\n", adapter->manufacturer_name); #endif } if (desc.iProduct) { libusb_get_string_descriptor_ascii(adapter->handle, desc.iProduct, adapter->name, sizeof(adapter->name)); #if 0 RARCH_ERR(" Adapter name: %s\n", adapter->name); #endif } device_name = (const char*)adapter->name; if (string_is_empty((const char*)adapter->name)) 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, &libusb_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); if (libusb_kernel_driver_active(adapter->handle, 0) == 1 && libusb_detach_kernel_driver(adapter->handle, 0)) { RARCH_ERR("Error detaching handle 0x%p from kernel.\n", adapter->handle); goto error; } rc = libusb_claim_interface(adapter->handle, adapter->interface_number); if (rc != LIBUSB_SUCCESS) { RARCH_ERR("Error claiming interface %d .\n", adapter->interface_number); goto error; } RARCH_LOG("Device 0x%p attached (VID/PID: %04x:%04x).\n", adapter->device, desc.idVendor, desc.idProduct); libusb_hid_device_add_autodetect(adapter->slot, device_name, libusb_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; } old_head = adapters.next; adapters.next = adapter; adapter->next = old_head; 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); return -1; }
static void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { unsigned i; bd_addr_t event_addr; struct btpad_queue_command* cmd = &commands[insert_position]; switch (packet_type) { case L2CAP_DATA_PACKET: for (i = 0; i < MAX_USERS; i ++) { struct btstack_hid_adapter *connection = &g_connections[i]; if (!connection || connection->state != BTPAD_CONNECTED) continue; if ( connection->channels[0] == channel || connection->channels[1] == channel) pad_connection_packet(&slots[connection->slot], connection->slot, packet, size); } break; case HCI_EVENT_PACKET: switch (packet[0]) { case BTSTACK_EVENT_STATE: RARCH_LOG("[BTstack]: HCI State %d.\n", packet[2]); switch (packet[2]) { case HCI_STATE_WORKING: btpad_queue_reset(); btpad_queue_hci_read_bd_addr(cmd); /* TODO: Where did I get 672 for MTU? */ bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_CONTROL, 672); bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_INTERRUPT, 672); btpad_queue_hci_inquiry(cmd, HCI_INQUIRY_LAP, 3, 1); btpad_queue_run(1); break; case HCI_STATE_HALTING: btpad_close_all_connections(); break; } break; case HCI_EVENT_COMMAND_STATUS: btpad_queue_run(packet[3]); break; case HCI_EVENT_COMMAND_COMPLETE: btpad_queue_run(packet[2]); if (COMMAND_COMPLETE_EVENT(packet, (*hci_read_bd_addr_ptr))) { bt_flip_addr_ptr(event_addr, &packet[6]); if (!packet[5]) RARCH_LOG("[BTpad]: Local address is %s.\n", bd_addr_to_str_ptr(event_addr)); else RARCH_LOG("[BTpad]: Failed to get local address (Status: %02X).\n", packet[5]); } break; case HCI_EVENT_INQUIRY_RESULT: if (packet[2]) { struct btstack_hid_adapter* connection = NULL; bt_flip_addr_ptr(event_addr, &packet[3]); connection = btpad_find_empty_connection(); if (!connection) return; RARCH_LOG("[BTpad]: Inquiry found device\n"); memset(connection, 0, sizeof(struct btstack_hid_adapter)); memcpy(connection->address, event_addr, sizeof(bd_addr_t)); connection->has_address = true; connection->state = BTPAD_CONNECTING; bt_send_cmd_ptr(l2cap_create_channel_ptr, connection->address, PSM_HID_CONTROL); bt_send_cmd_ptr(l2cap_create_channel_ptr, connection->address, PSM_HID_INTERRUPT); } break; case HCI_EVENT_INQUIRY_COMPLETE: /* This must be turned off during gameplay * as it causes a ton of lag. */ inquiry_running = !inquiry_off; if (inquiry_running) btpad_queue_hci_inquiry(cmd, HCI_INQUIRY_LAP, 3, 1); break; case L2CAP_EVENT_CHANNEL_OPENED: { uint16_t handle, psm, channel_id; struct btstack_hid_adapter *connection = NULL; bt_flip_addr_ptr(event_addr, &packet[3]); handle = READ_BT_16(packet, 9); psm = READ_BT_16(packet, 11); channel_id = READ_BT_16(packet, 13); connection = btpad_find_connection_for(handle, event_addr); if (!packet[2]) { if (!connection) { RARCH_LOG("[BTpad]: Got L2CAP 'Channel Opened' event for unrecognized device.\n"); break; } RARCH_LOG("[BTpad]: L2CAP channel opened: (PSM: %02X)\n", psm); connection->handle = handle; switch (psm) { case PSM_HID_CONTROL: connection->channels[0] = channel_id; break; case PSM_HID_INTERRUPT: connection->channels[1] = channel_id; break; default: RARCH_LOG("[BTpad]: Got unknown L2CAP PSM, ignoring (PSM: %02X).\n", psm); break; } if (connection->channels[0] && connection->channels[1]) { RARCH_LOG("[BTpad]: Got both L2CAP channels, requesting name.\n"); btpad_queue_hci_remote_name_request(cmd, connection->address, 0, 0, 0); } } else RARCH_LOG("[BTpad]: Got failed L2CAP 'Channel Opened' event (PSM: %02X, Status: %02X).\n", psm, packet[2]); } break; case L2CAP_EVENT_INCOMING_CONNECTION: { uint16_t handle, psm, channel_id; struct btstack_hid_adapter* connection = NULL; bt_flip_addr_ptr(event_addr, &packet[2]); handle = READ_BT_16(packet, 8); psm = READ_BT_16(packet, 10); channel_id = READ_BT_16(packet, 12); connection = btpad_find_connection_for(handle, event_addr); if (!connection) { connection = btpad_find_empty_connection(); if (!connection) break; RARCH_LOG("[BTpad]: Got new incoming connection\n"); memset(connection, 0, sizeof(struct btstack_hid_adapter)); memcpy(connection->address, event_addr, sizeof(bd_addr_t)); connection->has_address = true; connection->handle = handle; connection->state = BTPAD_CONNECTING; } RARCH_LOG("[BTpad]: Incoming L2CAP connection (PSM: %02X).\n", psm); bt_send_cmd_ptr(l2cap_accept_connection_ptr, channel_id); } break; case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: { struct btstack_hid_adapter *connection = NULL; bt_flip_addr_ptr(event_addr, &packet[3]); connection = btpad_find_connection_for(0, event_addr); if (!connection) { RARCH_LOG("[BTpad]: Got unexpected remote name, ignoring.\n"); break; } RARCH_LOG("[BTpad]: Got %.200s.\n", (char*)&packet[9]); connection->slot = pad_connection_pad_init(&slots[connection->slot], (char*)packet + 9, 0, 0, connection, &btpad_connection_send_control); connection->state = BTPAD_CONNECTED; } break; case HCI_EVENT_PIN_CODE_REQUEST: RARCH_LOG("[BTpad]: Sending Wiimote PIN.\n"); bt_flip_addr_ptr(event_addr, &packet[2]); btpad_queue_hci_pin_code_request_reply(cmd, event_addr, &packet[2]); break; case HCI_EVENT_DISCONNECTION_COMPLETE: { const uint32_t handle = READ_BT_16(packet, 3); if (!packet[2]) { struct btstack_hid_adapter* connection = btpad_find_connection_for(handle, 0); if (connection) { connection->handle = 0; pad_connection_pad_deinit(&slots[connection->slot], connection->slot); btpad_close_connection(connection); } } else RARCH_LOG("[BTpad]: Got failed 'Disconnection Complete' event (Status: %02X).\n", packet[2]); } break; case L2CAP_EVENT_SERVICE_REGISTERED: if (packet[2]) RARCH_LOG("[BTpad]: Got failed 'Service Registered' event (PSM: %02X, Status: %02X).\n", READ_BT_16(packet, 3), packet[2]); break; } break; } }
static int wiiusb_hid_add_adapter(void *data, usb_device_entry *dev) { usb_devdesc desc; const char *device_name = NULL; wiiusb_hid_t *hid = (wiiusb_hid_t*)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", dev->device_id, dev->vid, dev->pid); free(adapter); return -1; } adapter->device_id = dev->device_id; USB_GetDescriptors(adapter->handle, &desc); wiiusb_get_description(dev, adapter, &desc); if (adapter->endpoint_in == 0) { RARCH_ERR("Could not find HID config for device.\n"); goto error; } /* Allocate mem for the send control buffer, 32bit aligned */ adapter->send_control_type = WIIUSB_SC_NONE; adapter->send_control_buffer = memalign(32, 128); if (!adapter->send_control_buffer) { RARCH_ERR("Error creating send control buffer.\n"); goto error; } /* Sent the pad name as dummy, we don't know the * control name until we get its interface */ adapter->slot = pad_connection_pad_init(hid->connections, "hid", desc.idVendor, desc.idProduct, adapter, &wiiusb_hid); if (adapter->slot == -1) goto error; if (!pad_connection_has_interface(hid->connections, adapter->slot)) { RARCH_ERR(" Interface not found.\n"); goto error; } adapter->data = memalign(32, 128); adapter->hid = hid; adapter->next = hid->adapters_head; hid->adapters_head = adapter; /* Get the name from the interface */ device_name = wiiusb_hid_joypad_name(hid, adapter->slot); RARCH_LOG("Interface found: [%s].\n", device_name); RARCH_LOG("Device 0x%p attached (VID/PID: %04x:%04x).\n", adapter->device_id, desc.idVendor, desc.idProduct); wiiusb_hid_device_add_autodetect(adapter->slot, device_name, wiiusb_hid.ident, desc.idVendor, desc.idProduct); USB_FreeDescriptors(&desc); USB_DeviceRemovalNotifyAsync(adapter->handle, wiiusb_hid_removal_cb, adapter); return 0; error: if (adapter->send_control_buffer) free(adapter->send_control_buffer); if (adapter) free(adapter); USB_FreeDescriptors(&desc); USB_CloseDevice(&adapter->handle); return -1; }
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)); (void)rc; 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; 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 void iohidmanager_hid_device_add(void *data, IOReturn result, void* sender, IOHIDDeviceRef device) { int i; IOReturn ret; uint16_t dev_vid, dev_pid; CFArrayRef elements_raw; int count; CFMutableArrayRef elements; CFRange range; bool found_axis[6] = { false, false, false, false, false, false }; apple_input_rec_t *tmp = NULL; apple_input_rec_t *tmpButtons = NULL; apple_input_rec_t *tmpAxes = NULL; iohidmanager_hid_t *hid = (iohidmanager_hid_t*) hid_driver_get_data(); struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*) calloc(1, sizeof(*adapter)); if (!adapter) return; if (!hid) goto error; adapter->handle = device; ret = IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); if (ret != kIOReturnSuccess) goto error; /* Move the device's run loop to this thread. */ IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); IOHIDDeviceRegisterRemovalCallback(device, iohidmanager_hid_device_remove, adapter); #ifndef IOS iohidmanager_hid_device_get_product_string(device, adapter->name, sizeof(adapter->name)); #endif dev_vid = iohidmanager_hid_device_get_vendor_id (device); dev_pid = iohidmanager_hid_device_get_product_id (device); adapter->slot = pad_connection_pad_init(hid->slots, adapter->name, dev_vid, dev_pid, adapter, &iohidmanager_hid); if (adapter->slot == -1) goto error; if (pad_connection_has_interface(hid->slots, adapter->slot)) IOHIDDeviceRegisterInputReportCallback(device, adapter->data + 1, sizeof(adapter->data) - 1, iohidmanager_hid_device_report, adapter); else IOHIDDeviceRegisterInputValueCallback(device, iohidmanager_hid_device_input_callback, adapter); if (string_is_empty(adapter->name)) goto error; /* scan for buttons, axis, hats */ elements_raw = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); count = (int)CFArrayGetCount(elements_raw); elements = CFArrayCreateMutableCopy( kCFAllocatorDefault,(CFIndex)count,elements_raw); range = CFRangeMake(0,count); CFArraySortValues(elements, range, iohidmanager_sort_elements, NULL); for (i = 0; i < count; i++) { IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i); if (!element) continue; IOHIDElementType type = IOHIDElementGetType(element); uint32_t page = (uint32_t)IOHIDElementGetUsagePage(element); uint32_t use = (uint32_t)IOHIDElementGetUsage(element); uint32_t cookie = (uint32_t)IOHIDElementGetCookie(element); int detected_button = 0; switch (page) { case kHIDPage_GenericDesktop: switch (type) { case kIOHIDElementTypeCollection: case kIOHIDElementTypeInput_ScanCodes: case kIOHIDElementTypeFeature: case kIOHIDElementTypeInput_Button: case kIOHIDElementTypeOutput: case kIOHIDElementTypeInput_Axis: /* TODO/FIXME */ break; case kIOHIDElementTypeInput_Misc: switch (use) { case kHIDUsage_GD_Hatswitch: { /* as far as I can tell, OSX only reports one Hat */ apple_input_rec_t *hat = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t)); hat->id = 0; hat->cookie = (IOHIDElementCookie)cookie; hat->next = NULL; adapter->hats = hat; } break; default: { uint32_t i = 0; static const uint32_t axis_use_ids[6] = { 48, 49, 51, 52, 50, 53 }; while (i < 6 && axis_use_ids[i] != use) i++; if (i < 6) { apple_input_rec_t *axis = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t)); axis->id = i; axis->cookie = (IOHIDElementCookie)cookie; axis->next = NULL; if(iohidmanager_check_for_id(adapter->axes,i)) { /* axis ID already exists, save to tmp for appending later */ if(tmpAxes) iohidmanager_append_record(tmpAxes, axis); else tmpAxes = axis; } else { found_axis[axis->id] = true; if(adapter->axes) iohidmanager_append_record(adapter->axes, axis); else adapter->axes = axis; } } else detected_button = 1; } break; } break; } break; case kHIDPage_Consumer: case kHIDPage_Button: switch (type) { case kIOHIDElementTypeCollection: case kIOHIDElementTypeFeature: case kIOHIDElementTypeInput_ScanCodes: case kIOHIDElementTypeInput_Axis: case kIOHIDElementTypeOutput: /* TODO/FIXME */ break; case kIOHIDElementTypeInput_Misc: case kIOHIDElementTypeInput_Button: detected_button = 1; break; } break; } if (detected_button) { apple_input_rec_t *btn = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t)); btn->id = (uint32_t)use; btn->cookie = (IOHIDElementCookie)cookie; btn->next = NULL; if(iohidmanager_check_for_id(adapter->buttons,btn->id)) { if(tmpButtons) iohidmanager_append_record_ordered(&tmpButtons, btn); else tmpButtons = btn; } else { if(adapter->buttons) iohidmanager_append_record_ordered(&adapter->buttons, btn); else adapter->buttons = btn; } } } /* take care of buttons/axes with duplicate 'use' values */ for (i = 0; i < 6; i++) { if(found_axis[i] == false && tmpAxes) { apple_input_rec_t *next = tmpAxes->next; tmpAxes->id = i; tmpAxes->next = NULL; iohidmanager_append_record(adapter->axes, tmpAxes); tmpAxes = next; } } tmp = adapter->buttons; if (tmp) { while(tmp->next) tmp = tmp->next; } while(tmpButtons) { apple_input_rec_t *next = tmpButtons->next; tmpButtons->id = tmp->id; tmpButtons->next = NULL; tmp->next = tmpButtons; tmp = tmp->next; tmpButtons = next; } iohidmanager_hid_device_add_autodetect(adapter->slot, adapter->name, iohidmanager_hid.ident, dev_vid, dev_pid); return; error: { apple_input_rec_t *tmp = NULL; while(adapter->hats != NULL) { tmp = adapter->hats; adapter->hats = adapter->hats->next; free(tmp); } while(adapter->axes != NULL) { tmp = adapter->axes; adapter->axes = adapter->axes->next; free(tmp); } while(adapter->buttons != NULL) { tmp = adapter->buttons; adapter->buttons = adapter->buttons->next; free(tmp); } while(tmpAxes != NULL) { tmp = tmpAxes; tmpAxes = tmpAxes->next; free(tmp); } while(tmpButtons != NULL) { tmp = tmpButtons; tmpButtons = tmpButtons->next; free(tmp); } free(adapter); } }