mirror of
https://github.com/libretro/RetroArch
synced 2025-04-17 02:43:03 +00:00
333 lines
11 KiB
C
333 lines
11 KiB
C
/*
|
|
* This file is part of MAME4iOS.
|
|
*
|
|
* Copyright (C) 2012 David Valdeita (Seleuco)
|
|
*
|
|
* This program 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 Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* In addition, as a special exception, Seleuco
|
|
* gives permission to link the code of this program with
|
|
* the MAME library (or with modified versions of MAME that use the
|
|
* same license as MAME), and distribute linked combinations including
|
|
* the two. You must obey the GNU General Public License in all
|
|
* respects for all of the code used other than MAME. If you modify
|
|
* this file, you may extend this exception to your version of the
|
|
* file, but you are not obligated to do so. If you do not wish to
|
|
* do so, delete this exception statement from your version.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/sysctl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "btdynamic.h"
|
|
#include "btpad.h"
|
|
#include "wiimote.h"
|
|
|
|
static enum btpad_device_type_t device_type;
|
|
static bd_addr_t device_address;
|
|
static char device_name[256];
|
|
|
|
// Connection data
|
|
static uint32_t device_handle[2];
|
|
static uint32_t device_remote_cid[2];
|
|
static uint32_t device_local_cid[2];
|
|
|
|
// Inquiry data
|
|
static uint32_t device_page_scan_repetition_mode;
|
|
static uint32_t device_class;
|
|
static uint32_t device_clock_offset;
|
|
|
|
// Buffers
|
|
static struct wiimote_t wiimote_buffer;
|
|
static uint8_t psdata_buffer[512];
|
|
|
|
// MAIN THREAD ONLY
|
|
enum btpad_device_type_t btpad_get_connected_type()
|
|
{
|
|
return device_type;
|
|
}
|
|
|
|
uint32_t btpad_get_buttons()
|
|
{
|
|
switch (device_type)
|
|
{
|
|
case BTPAD_WIIMOTE:
|
|
return wiimote_buffer.btns | (wiimote_buffer.exp.classic.btns << 16);
|
|
case BTPAD_PS3:
|
|
return psdata_buffer[3] | (psdata_buffer[4] << 8);
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// BT THREAD ONLY
|
|
static void set_ps3_data(unsigned leds)
|
|
{
|
|
// TODO: LEDS
|
|
|
|
static uint8_t report_buffer[] = {
|
|
0x52, 0x01, 0x00, 0x00, 0x00, 0x00, 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
|
|
};
|
|
|
|
bt_send_l2cap_ptr(device_local_cid[0], report_buffer, sizeof(report_buffer));
|
|
}
|
|
|
|
void btstack_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
|
|
{
|
|
#if 1 // WiiMote
|
|
bd_addr_t event_addr;
|
|
|
|
switch (packet_type)
|
|
{
|
|
// Connection
|
|
case HCI_EVENT_PACKET:
|
|
{
|
|
switch (packet[0])
|
|
{
|
|
// Bluetooth is active, search for remote
|
|
case BTSTACK_EVENT_STATE:
|
|
{
|
|
if (packet[2] == HCI_STATE_WORKING)
|
|
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
|
|
break;
|
|
}
|
|
|
|
// Identifies devices found during inquiry, does not signal the end of the inquiry.
|
|
case HCI_EVENT_INQUIRY_RESULT:
|
|
{
|
|
for (int i = 0; i != packet[2]; i ++)
|
|
{
|
|
if (device_type == BTPAD_NONE)
|
|
{
|
|
bt_flip_addr_ptr(device_address, &packet[3 + i * 6]);
|
|
|
|
device_page_scan_repetition_mode = packet [3 + packet[2] * (6) + i*1];
|
|
device_class = READ_BT_24(packet, 3 + packet[2] * (6+1+1+1) + i*3);
|
|
device_clock_offset = READ_BT_16(packet, 3 + packet[2] * (6+1+1+1+3) + i*2) & 0x7fff;
|
|
|
|
device_type = BTPAD_PENDING;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// The inquiry has ended
|
|
case HCI_EVENT_INQUIRY_COMPLETE:
|
|
{
|
|
if (device_type == BTPAD_PENDING)
|
|
bt_send_cmd_ptr(hci_remote_name_request_ptr, device_address, device_page_scan_repetition_mode,
|
|
0, device_clock_offset | 0x8000);
|
|
else if(device_type == BTPAD_NONE)
|
|
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
// Received the name of a device
|
|
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
|
|
{
|
|
bt_flip_addr_ptr(event_addr, &packet[3]);
|
|
|
|
if (device_type == BTPAD_PENDING && BD_ADDR_CMP(event_addr, device_address) == 0)
|
|
{
|
|
strncpy(device_name, (const char*)&packet[9], 248);
|
|
device_name[248] = 0;
|
|
|
|
if (strncmp(device_name, "Nintendo RVL-CNT-01", 19) == 0)
|
|
{
|
|
device_type = BTPAD_WIIMOTE;
|
|
bt_send_cmd_ptr(l2cap_create_channel_ptr, device_address, PSM_HID_CONTROL);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Send PIN for pairing
|
|
case HCI_EVENT_PIN_CODE_REQUEST:
|
|
{
|
|
bt_flip_addr_ptr(event_addr, &packet[2]);
|
|
|
|
if (device_type == BTPAD_WIIMOTE && BD_ADDR_CMP(event_addr, device_address) == 0)
|
|
bt_send_cmd_ptr(hci_pin_code_request_reply_ptr, device_address, 6, &packet[2]);
|
|
break;
|
|
}
|
|
|
|
// WiiMote connections
|
|
case L2CAP_EVENT_CHANNEL_OPENED:
|
|
{
|
|
bt_flip_addr_ptr(event_addr, &packet[3]);
|
|
|
|
if (packet[2] == 0 && device_type > BTPAD_PENDING && BD_ADDR_CMP(event_addr, device_address) == 0)
|
|
{
|
|
const uint16_t psm = READ_BT_16(packet, 11);
|
|
const unsigned interrupt = (psm == PSM_HID_INTERRUPT) ? 1 : 0;
|
|
|
|
device_local_cid[interrupt] = READ_BT_16(packet, 13);
|
|
device_remote_cid[interrupt] = READ_BT_16(packet, 15);
|
|
device_handle[interrupt] = READ_BT_16(packet, 9);
|
|
|
|
if (device_type == BTPAD_WIIMOTE && psm == PSM_HID_CONTROL)
|
|
{
|
|
bt_send_cmd_ptr(l2cap_create_channel_ptr, device_address, PSM_HID_INTERRUPT);
|
|
|
|
memset(&wiimote_buffer, 0, sizeof(struct wiimote_t));
|
|
wiimote_buffer.unid = 0;
|
|
wiimote_buffer.c_source_cid = device_local_cid[0];
|
|
wiimote_buffer.exp.type = EXP_NONE;
|
|
wiimote_buffer.wiiMoteConHandle = device_handle[0];
|
|
memcpy(&wiimote_buffer.addr, &device_address, BD_ADDR_LEN);
|
|
}
|
|
else if (device_type == BTPAD_WIIMOTE && psm == PSM_HID_INTERRUPT)
|
|
{
|
|
wiimote_buffer.i_source_cid = device_local_cid[1];
|
|
wiimote_buffer.state = WIIMOTE_STATE_CONNECTED;
|
|
wiimote_handshake(&wiimote_buffer, -1, NULL, -1);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case L2CAP_EVENT_CHANNEL_CLOSED:
|
|
{
|
|
device_type = BTPAD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// WiiMote handling
|
|
case L2CAP_DATA_PACKET:
|
|
{
|
|
if (device_type == BTPAD_WIIMOTE)
|
|
{
|
|
byte* msg = packet + 2;
|
|
|
|
switch (packet[1])
|
|
{
|
|
case WM_RPT_BTN:
|
|
{
|
|
wiimote_pressed_buttons(&wiimote_buffer, msg);
|
|
break;
|
|
}
|
|
|
|
case WM_RPT_READ:
|
|
{
|
|
wiimote_pressed_buttons(&wiimote_buffer, msg);
|
|
|
|
byte len = ((msg[2] & 0xF0) >> 4) + 1;
|
|
byte *data = (msg + 5);
|
|
|
|
wiimote_handshake(&wiimote_buffer, WM_RPT_READ, data, len);
|
|
return;
|
|
}
|
|
|
|
case WM_RPT_CTRL_STATUS:
|
|
{
|
|
wiimote_pressed_buttons(&wiimote_buffer, msg);
|
|
wiimote_handshake(&wiimote_buffer,WM_RPT_CTRL_STATUS,msg,-1);
|
|
|
|
return;
|
|
}
|
|
|
|
case WM_RPT_BTN_EXP:
|
|
{
|
|
wiimote_pressed_buttons(&wiimote_buffer, msg);
|
|
wiimote_handle_expansion(&wiimote_buffer, msg+2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#else // SixAxis
|
|
switch (packet_type)
|
|
{
|
|
// Connection
|
|
case HCI_EVENT_PACKET:
|
|
{
|
|
switch (packet[0])
|
|
{
|
|
// Bluetooth is active, search for remote
|
|
case BTSTACK_EVENT_STATE:
|
|
{
|
|
if (packet[2] == HCI_STATE_WORKING)
|
|
bt_send_cmd_ptr(l2cap_register_service_ptr, 0x11, 672);
|
|
break;
|
|
}
|
|
|
|
case L2CAP_EVENT_SERVICE_REGISTERED:
|
|
{
|
|
if (READ_BT_16(packet, 3) == 0x11)
|
|
bt_send_cmd_ptr(l2cap_register_service_ptr, 0x13, 672);
|
|
break;
|
|
}
|
|
|
|
case L2CAP_EVENT_INCOMING_CONNECTION:
|
|
{
|
|
const uint32_t psm = READ_BT_16(packet, 10);
|
|
const bool second = (psm == 0x11) ? 0 : 1;
|
|
|
|
handle[second] = READ_BT_16(packet, 8);
|
|
local_cid[second] = READ_BT_16(packet, 12);
|
|
remote_cid[second] = READ_BT_16(packet, 14);
|
|
|
|
bt_flip_addr_ptr(address, &packet[2]);
|
|
bt_send_cmd_ptr(l2cap_accept_connection_ptr, local_cid[second]);
|
|
|
|
break;
|
|
}
|
|
|
|
case L2CAP_EVENT_CHANNEL_OPENED:
|
|
{
|
|
if (READ_BT_16(packet, 11) == PSM_HID_INTERRUPT)
|
|
{
|
|
uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
|
|
bt_send_l2cap_ptr(local_cid[0], data, 6);
|
|
set_ps3_data(0);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case L2CAP_DATA_PACKET:
|
|
{
|
|
if (packet[0] == 0xA1)
|
|
memcpy(psdata_buffer, packet, size);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|