Revive io_osx.mm revision history and reapply the changes in r6693.

Avoid sending the Wii OS bluetooth packets with uninitialized data
past the nominal length of the report.

XXX IOWin.cpp still always returns MAX_PAYLOAD because I don't have
a Windows environment to test with.


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6708 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Soren Jorvang 2011-01-01 14:57:19 +00:00
parent 2f7da5d5d1
commit 28ef121a93
8 changed files with 347 additions and 68 deletions

View File

@ -138,7 +138,7 @@ if(WIN32)
set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Win32.cpp Src/stdafx.cpp
Src/HW/WiimoteReal/IOWin.cpp)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Apple.cpp Src/HW/WiimoteReal/IOOsx.mm)
set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Apple.cpp Src/HW/WiimoteReal/IOdarwin.mm)
elseif(UNIX)
set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Unix.cpp)
if((${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND BLUEZ_FOUND)

View File

@ -695,7 +695,8 @@ void Wiimote::Update()
g_refresh_critsec.Enter();
if (g_wiimotes[m_index])
{
u8* const real_data = g_wiimotes[m_index]->ProcessReadQueue();
Report rpt = g_wiimotes[m_index]->ProcessReadQueue();
const u8 *real_data = rpt.first;
if (real_data)
{
switch (real_data[1])
@ -757,11 +758,12 @@ void Wiimote::Update()
// copy over report from real-wiimote
if (-1 == rptf_size)
{
memcpy(data, real_data, MAX_PAYLOAD);
rptf_size = MAX_PAYLOAD;
memcpy(data, real_data, rpt.second);
rptf_size = rpt.second;
}
if (real_data != g_wiimotes[m_index]->m_last_data_report)
if (real_data != g_wiimotes[m_index]->\
m_last_data_report.first)
delete[] real_data;
}
}

View File

@ -196,14 +196,14 @@ void Wiimote::RealDisconnect()
in_sock = -1;
}
unsigned char *Wiimote::IORead()
int Wiimote::IORead(unsigned char *buf)
{
struct timeval tv;
fd_set fds;
int r;
if (!IsConnected())
return NULL;
return 0;
// Block select for 1/2000th of a second
tv.tv_sec = 0;
@ -215,15 +215,14 @@ unsigned char *Wiimote::IORead()
if (select(in_sock + 1, &fds, NULL, NULL, &tv) == -1)
{
ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", index + 1);
return NULL;
return 0;
}
if (!FD_ISSET(in_sock, &fds))
return NULL;
return 0;
// Read the pending message into the buffer
unsigned char *buffer = new unsigned char[MAX_PAYLOAD];
r = read(in_sock, buffer, sizeof(unsigned char) * MAX_PAYLOAD);
r = read(in_sock, buf, MAX_PAYLOAD);
if (r == -1)
{
// Error reading data
@ -237,17 +236,15 @@ unsigned char *Wiimote::IORead()
RealDisconnect();
}
delete[] buffer;
return NULL;
return 0;
}
if (!r)
{
// Disconnect
RealDisconnect();
delete[] buffer;
return NULL;
return 0;
}
return buffer;
return r;
}
int Wiimote::IOWrite(unsigned char* buf, int len)

View File

@ -255,18 +255,17 @@ void Wiimote::RealDisconnect()
ResetEvent(&hid_overlap);
}
unsigned char *Wiimote::IORead()
int Wiimote::IORead(unsigned char* buf)
{
DWORD b, r;
init_lib();
if (!IsConnected())
return NULL;
return 0;
unsigned char *buffer = new unsigned char[MAX_PAYLOAD];
*buffer = 0;
if (!ReadFile(dev_handle, buffer, sizeof(unsigned char) * MAX_PAYLOAD, &b, &hid_overlap))
*buf = 0;
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD, &b, &hid_overlap))
{
// Partial read
b = GetLastError();
@ -275,8 +274,7 @@ unsigned char *Wiimote::IORead()
{
// Remote disconnect
RealDisconnect();
delete[] buffer;
return NULL;
return 0;
}
r = WaitForSingleObject(hid_overlap.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
@ -284,36 +282,33 @@ unsigned char *Wiimote::IORead()
{
// Timeout - cancel and continue
if (*buffer)
if (*buf)
WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).",
WIIMOTE_DEFAULT_TIMEOUT);
CancelIo(dev_handle);
ResetEvent(hid_overlap.hEvent);
delete[] buffer;
return NULL;
return 0;
}
else if (r == WAIT_FAILED)
{
WARN_LOG(WIIMOTE, "A wait error occured on reading from wiimote %i.", index + 1);
delete[] buffer;
return NULL;
return 0;
}
if (!GetOverlappedResult(dev_handle, &hid_overlap, &b, 0))
{
delete[] buffer;
return NULL;
return 0;
}
}
// This needs to be done even if ReadFile fails, essential during init
// Move the data over one, so we can add back in data report indicator byte (here, 0xa1)
memmove(buffer + 1, buffer, sizeof(unsigned char) * MAX_PAYLOAD - 1);
buffer[0] = 0xa1;
memmove(buf + 1, buf, MAX_PAYLOAD - 1);
buf[0] = 0xa1;
ResetEvent(hid_overlap.hEvent);
return buffer;
return MAX_PAYLOAD; // XXX
}
int Wiimote::IOWrite(unsigned char* buf, int len)
@ -324,7 +319,7 @@ int Wiimote::IOWrite(unsigned char* buf, int len)
init_lib();
if (!IsConnected())
return NULL;
return 0;
switch (stack)
{

View File

@ -0,0 +1,282 @@
#import <CoreServices/CoreServices.h>
extern "C" OSErr UpdateSystemActivity(UInt8 activity);
#define BLUETOOTH_VERSION_USE_CURRENT
#import <IOBluetooth/IOBluetooth.h>
#include "Common.h"
#include "WiimoteReal.h"
@interface SearchBT: NSObject {
@public
unsigned int maxDevices;
}
@end
@implementation SearchBT
- (void) deviceInquiryComplete: (IOBluetoothDeviceInquiry *) sender
error: (IOReturn) error
aborted: (BOOL) aborted
{
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void) deviceInquiryDeviceFound: (IOBluetoothDeviceInquiry *) sender
device: (IOBluetoothDevice *) device
{
NOTICE_LOG(WIIMOTE, "Discovered bluetooth device at %s: %s",
[[device getAddressString] UTF8String],
[[device getName] UTF8String]);
if ([[sender foundDevices] count] == maxDevices)
[sender stop];
}
@end
@interface ConnectBT: NSObject {}
@end
@implementation ConnectBT
- (void) l2capChannelData: (IOBluetoothL2CAPChannel *) l2capChannel
data: (unsigned char *) data
length: (NSUInteger) length
{
IOBluetoothDevice *device = [l2capChannel getDevice];
WiimoteReal::Wiimote *wm = NULL;
for (int i = 0; i < MAX_WIIMOTES; i++) {
if (WiimoteReal::g_wiimotes[i] == NULL)
continue;
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
wm = WiimoteReal::g_wiimotes[i];
}
if (wm == NULL) {
WARN_LOG(WIIMOTE, "Received packet for unknown wiimote");
return;
}
if (length > MAX_PAYLOAD) {
WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, too large",
wm->index + 1);
return;
}
if (wm->queue[wm->writer].len != 0) {
WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, queue full",
wm->index + 1);
return;
}
memcpy(wm->queue[wm->writer].data, data, length);
wm->queue[wm->writer].len = length;
wm->writer++;
wm->outstanding++;
if (wm->writer == QUEUE_SIZE)
wm->writer = 0;
if (wm->outstanding > wm->watermark) {
wm->watermark = wm->outstanding;
WARN_LOG(WIIMOTE, "New queue watermark %i for wiimote %i",
wm->watermark, wm->index + 1);
}
CFRunLoopStop(CFRunLoopGetCurrent());
(void)UpdateSystemActivity(1);
}
- (void) l2capChannelClosed: (IOBluetoothL2CAPChannel *) l2capChannel
{
IOBluetoothDevice *device = [l2capChannel getDevice];
WiimoteReal::Wiimote *wm = NULL;
for (int i = 0; i < MAX_WIIMOTES; i++) {
if (WiimoteReal::g_wiimotes[i] == NULL)
continue;
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
wm = WiimoteReal::g_wiimotes[i];
}
if (wm == NULL) {
WARN_LOG(WIIMOTE, "Received packet for unknown wiimote");
return;
}
WARN_LOG(WIIMOTE, "L2CAP channel was closed for wiimote %i",
wm->index + 1);
if (l2capChannel == wm->cchan)
wm->cchan = nil;
if (l2capChannel == wm->ichan)
wm->ichan = nil;
}
@end
namespace WiimoteReal
{
// Find wiimotes.
// wm is an array of max_wiimotes wiimotes
// Returns the total number of found wiimotes.
int FindWiimotes(Wiimote **wm, int max_wiimotes)
{
IOBluetoothHostController *bth;
IOBluetoothDeviceInquiry *bti;
SearchBT *sbt;
NSEnumerator *en;
int found_devices = 0, found_wiimotes = 0;
// Count the number of already found wiimotes
for (int i = 0; i < MAX_WIIMOTES; ++i)
if (wm[i])
found_wiimotes++;
bth = [[IOBluetoothHostController alloc] init];
if ([bth addressAsString] == nil) {
WARN_LOG(WIIMOTE, "No bluetooth host controller");
[bth release];
return found_wiimotes;
}
sbt = [[SearchBT alloc] init];
sbt->maxDevices = max_wiimotes;
bti = [[IOBluetoothDeviceInquiry alloc] init];
[bti setDelegate: sbt];
[bti setInquiryLength: 5];
[bti setSearchCriteria: kBluetoothServiceClassMajorAny
majorDeviceClass: kBluetoothDeviceClassMajorPeripheral
minorDeviceClass: kBluetoothDeviceClassMinorPeripheral2Joystick
];
[bti setUpdateNewDeviceNames: FALSE];
if ([bti start] == kIOReturnSuccess)
[bti retain];
else
ERROR_LOG(WIIMOTE, "Unable to do bluetooth discovery");
CFRunLoopRun();
[bti stop];
found_devices = [[bti foundDevices] count];
NOTICE_LOG(WIIMOTE, "Found %i bluetooth device%c", found_devices,
found_devices == 1 ? '\0' : 's');
en = [[bti foundDevices] objectEnumerator];
for (int i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); i++) {
IOBluetoothDevice *tmp_btd = [en nextObject];
bool new_wiimote = true;
// Determine if this wiimote has already been found.
for (int j = 0; j < MAX_WIIMOTES && new_wiimote; ++j) {
if (wm[j] && [tmp_btd isEqual: wm[j]->btd] == TRUE)
new_wiimote = false;
}
if (new_wiimote) {
// Find an unused slot
unsigned int k = 0;
for ( ; k < MAX_WIIMOTES &&
!(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k)
{};
wm[k] = new Wiimote(k);
wm[k]->btd = tmp_btd;
found_wiimotes++;
}
}
[bth release];
[bti release];
[sbt release];
return found_wiimotes;
}
// Connect to a wiimote with a known address.
bool Wiimote::Connect()
{
ConnectBT *cbt = [[ConnectBT alloc] init];
if (IsConnected()) return false;
[btd openL2CAPChannelSync: &cchan
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
[btd openL2CAPChannelSync: &ichan
withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt];
if (ichan == NULL || cchan == NULL) {
ERROR_LOG(WIIMOTE, "Unable to open L2CAP channels "
"for wiimote %i", index + 1);
RealDisconnect();
return false;
}
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i at %s",
index + 1, [[btd getAddressString] UTF8String]);
m_connected = true;
Handshake();
SetLEDs(WIIMOTE_LED_1 << index);
[cbt release];
return true;
}
// Disconnect a wiimote.
void Wiimote::RealDisconnect()
{
if (!IsConnected())
return;
NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i", index + 1);
m_connected = false;
[cchan closeChannel];
[ichan closeChannel];
[btd closeConnection];
}
int Wiimote::IORead(unsigned char *buf)
{
int bytes;
if (!IsConnected())
return 0;
if (outstanding == 0)
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, true);
if (queue[reader].len == 0)
return 0;
bytes = queue[reader].len;
memcpy(buf, queue[reader].data, bytes);
queue[reader].len = 0;
reader++;
outstanding--;
if (reader == QUEUE_SIZE)
reader = 0;
if (buf[0] == '\0')
bytes = 0;
return bytes;
}
int Wiimote::IOWrite(unsigned char *buf, int len)
{
IOReturn ret;
ret = [cchan writeAsync: buf length: len refcon: nil];
if (ret == kIOReturnSuccess)
return len;
else
return 0;
}
};

View File

@ -55,7 +55,7 @@ Wiimote::Wiimote(const unsigned int _index)
#elif defined(_WIN32)
, dev_handle(0), stack(MSBT_STACK_UNKNOWN)
#endif
, leds(0), m_last_data_report(NULL), m_channel(0), m_connected(false)
, leds(0), m_channel(0), m_connected(false)
{
#ifdef __APPLE__
memset(queue, 0, sizeof queue);
@ -67,6 +67,7 @@ Wiimote::Wiimote(const unsigned int _index)
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
#endif
ClearReadQueue();
DisableDataReporting();
}
@ -106,15 +107,16 @@ void Wiimote::DisableDataReporting()
void Wiimote::ClearReadQueue()
{
if (m_last_data_report)
Report rpt;
if (m_last_data_report.first)
{
delete[] m_last_data_report;
m_last_data_report = NULL;
delete[] m_last_data_report.first;
m_last_data_report.first = NULL;
}
u8 *rpt;
while (m_read_reports.Pop(rpt))
delete[] rpt;
delete[] rpt.first;
}
void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size)
@ -148,7 +150,7 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
m_channel = channel; // this right?
Wiimote::Report rpt;
Report rpt;
rpt.first = new u8[size];
rpt.second = (u8)size;
memcpy(rpt.first, (u8*)data, size);
@ -159,10 +161,10 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
//if (WM_REPORT_MODE == ((u8*)data)[1])
//{
// // also delete the last data report
// if (m_last_data_report)
// if (m_last_data_report.first)
// {
// delete[] m_last_data_report;
// m_last_data_report = NULL;
// delete[] m_last_data_report.first;
// m_last_data_report.first = NULL;
// }
// // nice var names :p, this seems to be this one
@ -175,18 +177,18 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
bool Wiimote::Read()
{
u8* rpt;
if ((rpt = IORead()))
{
if (m_channel)
{
// Add it to queue
m_read_reports.Push(rpt);
}
Report rpt;
rpt.first = new unsigned char[MAX_PAYLOAD];
rpt.second = IORead(rpt.first);
if (rpt.second > 0 && m_channel > 0) {
// Add it to queue
m_read_reports.Push(rpt);
return true;
}
delete rpt.first;
return false;
}
@ -205,13 +207,13 @@ bool Wiimote::Write()
}
// Returns the next report that should be sent
u8* Wiimote::ProcessReadQueue()
Report Wiimote::ProcessReadQueue()
{
// Pop through the queued reports
u8* rpt = m_last_data_report;
Report rpt = m_last_data_report;
while (m_read_reports.Pop(rpt))
{
if (rpt[1] >= WM_REPORT_CORE)
if (rpt.first[1] >= WM_REPORT_CORE)
// A data report
m_last_data_report = rpt;
else
@ -226,15 +228,16 @@ u8* Wiimote::ProcessReadQueue()
void Wiimote::Update()
{
// Pop through the queued reports
u8* const rpt = ProcessReadQueue();
Report const rpt = ProcessReadQueue();
// Send the report
if (rpt && m_channel)
Core::Callback_WiimoteInterruptChannel(index, m_channel, rpt, MAX_PAYLOAD);
if (rpt.first != NULL && m_channel > 0)
Core::Callback_WiimoteInterruptChannel(index, m_channel,
rpt.first, rpt.second);
// Delete the data if it isn't also the last data rpt
if (rpt != m_last_data_report)
delete[] rpt;
delete[] rpt.first;
}
void Wiimote::Disconnect()

View File

@ -37,6 +37,9 @@ enum
WIIMOTE_SRC_HYBRID = 3, // emu + real
};
// Pointer to data, and size of data
typedef std::pair<u8*,u8> Report;
namespace WiimoteReal
{
@ -51,7 +54,7 @@ public:
void InterruptChannel(const u16 channel, const void* const data, const u32 size);
void Update();
u8* ProcessReadQueue();
Report ProcessReadQueue();
bool Read();
bool Write();
@ -62,9 +65,6 @@ public:
void Rumble();
void SendPacket(const u8 rpt_id, const void* const data, const unsigned int size);
// Pointer to data, and size of data
typedef std::pair<u8*,u8> Report;
const unsigned int index;
#if defined(__APPLE__)
@ -95,7 +95,7 @@ public:
unsigned char leds; // Currently lit leds
protected:
u8 *m_last_data_report;
Report m_last_data_report;
u16 m_channel;
private:
@ -104,11 +104,11 @@ private:
bool SendRequest(unsigned char report_type, unsigned char* data, int length);
bool Handshake();
void SetLEDs(int leds);
unsigned char *IORead();
int IORead(unsigned char* buf);
int IOWrite(unsigned char* buf, int len);
bool m_connected;
Common::FifoQueue<u8*> m_read_reports;
bool m_connected;
Common::FifoQueue<Report> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
};

View File

@ -148,7 +148,7 @@ libs = [
if sys.platform == 'win32':
files += [ "HW/BBA-TAP/TAP_Win32.cpp", "stdafx.cpp", "HW/WiimoteReal/IOWin.cpp" ]
elif sys.platform == 'darwin':
files += [ "HW/BBA-TAP/TAP_Apple.cpp", "HW/WiimoteReal/IOOsx.mm" ]
files += [ "HW/BBA-TAP/TAP_Apple.cpp", "HW/WiimoteReal/IOdarwin.mm" ]
else:
files += [ "HW/BBA-TAP/TAP_Unix.cpp", "HW/WiimoteReal/IONix.cpp" ]