wiimote emulation improvements... wpad tries now to read out the HID attribs per SDP
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@902 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
469310dc14
commit
636dfdd177
|
@ -1344,6 +1344,14 @@
|
||||||
RelativePath=".\Src\VolumeHandler.h"
|
RelativePath=".\Src\VolumeHandler.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Src\IPC_HLE\WiiMote_HID_Attr.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Src\IPC_HLE\WiiMote_HID_Attr.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
||||||
</Globals>
|
</Globals>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -41,6 +41,22 @@ union UACLHeader
|
||||||
u32 Hex;
|
u32 Hex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SQueuedEvent
|
||||||
|
{
|
||||||
|
u8 m_buffer[1024];
|
||||||
|
size_t m_size;
|
||||||
|
SQueuedEvent(size_t size) :
|
||||||
|
m_size(size)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ACLFrame
|
||||||
|
{
|
||||||
|
u16 ConnectionHandle;
|
||||||
|
u8* data;
|
||||||
|
u32 size;
|
||||||
|
};
|
||||||
|
|
||||||
class CWII_IPC_HLE_Device_usb_oh1_57e_305 : public IWII_IPC_HLE_Device
|
class CWII_IPC_HLE_Device_usb_oh1_57e_305 : public IWII_IPC_HLE_Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -60,6 +76,15 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
typedef std::queue<SQueuedEvent> CEventQueue;
|
||||||
|
CEventQueue m_EventQueue;
|
||||||
|
|
||||||
|
void AddEventToQueue(const SQueuedEvent& _event)
|
||||||
|
{
|
||||||
|
m_EventQueue.push(_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
USB_IOCTL_HCI_COMMAND_MESSAGE = 0,
|
USB_IOCTL_HCI_COMMAND_MESSAGE = 0,
|
||||||
|
@ -95,10 +120,9 @@ private:
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
std::queue<SHCICommandMessage> m_HCICommandMessageQueue;
|
std::queue<SHCICommandMessage> m_HCICommandMessageQueue;
|
||||||
|
std::queue<ACLFrame> m_AclFrameQue;
|
||||||
|
|
||||||
bool m_ACLAnswer;
|
|
||||||
SIOCtlVBuffer* m_pACLBuffer;
|
SIOCtlVBuffer* m_pACLBuffer;
|
||||||
|
|
||||||
SIOCtlVBuffer* m_pHCIBuffer;
|
SIOCtlVBuffer* m_pHCIBuffer;
|
||||||
|
|
||||||
bool SendEventCommandStatus(u16 _Opcode);
|
bool SendEventCommandStatus(u16 _Opcode);
|
||||||
|
@ -107,12 +131,14 @@ private:
|
||||||
bool SendEventInquiryResponse();
|
bool SendEventInquiryResponse();
|
||||||
bool SendEventInquiryComplete();
|
bool SendEventInquiryComplete();
|
||||||
|
|
||||||
bool SendEventRemoteNameReq();
|
bool SendEventRemoteNameReq(bdaddr_t _bd);
|
||||||
bool SendEventRequestConnection();
|
bool SendEventRequestConnection();
|
||||||
bool SendEventConnectionComplete();
|
bool SendEventConnectionComplete(bdaddr_t _bd);
|
||||||
bool SendEventReadClockOffsetComplete();
|
bool SendEventReadClockOffsetComplete(u16 _connectionHandle);
|
||||||
bool SendEventReadRemoteVerInfo();
|
bool SendEventReadRemoteVerInfo(u16 _connectionHandle);
|
||||||
bool SendEventReadRemoteFeatures();
|
bool SendEventReadRemoteFeatures(u16 _connectionHandle);
|
||||||
|
bool SendEventRoleChange(bdaddr_t _bd);
|
||||||
|
bool SendEventNumberOfCompletedPackets(u16 _connectionHandle);
|
||||||
|
|
||||||
void ExecuteHCICommandMessage(const SHCICommandMessage& _rCtrlMessage);
|
void ExecuteHCICommandMessage(const SHCICommandMessage& _rCtrlMessage);
|
||||||
|
|
||||||
|
@ -147,45 +173,10 @@ private:
|
||||||
|
|
||||||
void SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size);
|
void SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size);
|
||||||
|
|
||||||
enum EState
|
|
||||||
{
|
|
||||||
STATE_NONE,
|
|
||||||
STATE_INQUIRY_RESPONSE,
|
|
||||||
STATE_INQUIRY_COMPLETE,
|
|
||||||
STATE_START_REMOTE_NAME_REQ,
|
|
||||||
STATE_REMOTE_NAME_REQ,
|
|
||||||
STATE_CONNECTION_COMPLETE_EVENT,
|
|
||||||
STATE_READ_CLOCK_OFFSET,
|
|
||||||
STATE_READ_REMOTE_VER_INFO,
|
|
||||||
STATE_READ_REMOTE_FEATURES,
|
|
||||||
STATE_CONNECT_WIIMOTE
|
|
||||||
};
|
|
||||||
|
|
||||||
EState m_State;
|
|
||||||
u32 m_UpdateWaitCount;
|
u32 m_UpdateWaitCount;
|
||||||
bdaddr_t m_StateTempBD;
|
|
||||||
u16 m_StateTempConnectionHandle;
|
|
||||||
|
|
||||||
struct ACLFrame {
|
|
||||||
u16 ConnectionHandle;
|
|
||||||
u8* data;
|
|
||||||
u32 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::queue<ACLFrame> m_AclFrameQue;
|
|
||||||
|
|
||||||
u8 scan_enable;
|
u8 scan_enable;
|
||||||
|
|
||||||
//TODO: get rid of these, integrate into EState.
|
|
||||||
enum EDelayedEvent
|
|
||||||
{
|
|
||||||
EVENT_NONE,
|
|
||||||
EVENT_REQUEST_CONNECTION,
|
|
||||||
EVENT_CONNECTION_COMPLETE
|
|
||||||
};
|
|
||||||
EDelayedEvent m_DelayedEvent;
|
|
||||||
void SetDelayedEvent(EDelayedEvent e);
|
|
||||||
|
|
||||||
bdaddr_t m_ControllerBD;
|
bdaddr_t m_ControllerBD;
|
||||||
u8 m_ClassOfDevice[HCI_CLASS_SIZE];
|
u8 m_ClassOfDevice[HCI_CLASS_SIZE];
|
||||||
char m_LocalName[HCI_UNIT_NAME_SIZE];
|
char m_LocalName[HCI_UNIT_NAME_SIZE];
|
||||||
|
@ -203,8 +194,6 @@ public: //hack for wiimote plugin
|
||||||
std::vector<CWII_IPC_HLE_WiiMote> m_WiiMotes;
|
std::vector<CWII_IPC_HLE_WiiMote> m_WiiMotes;
|
||||||
CWII_IPC_HLE_WiiMote* AccessWiiMote(const bdaddr_t& _rAddr);
|
CWII_IPC_HLE_WiiMote* AccessWiiMote(const bdaddr_t& _rAddr);
|
||||||
CWII_IPC_HLE_WiiMote* AccessWiiMote(u16 _ConnectionHandle);
|
CWII_IPC_HLE_WiiMote* AccessWiiMote(u16 _ConnectionHandle);
|
||||||
void ClearBD(bdaddr_t& _rAddr);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "WII_IPC_HLE_WiiMote.h"
|
#include "WII_IPC_HLE_WiiMote.h"
|
||||||
#include "l2cap.h"
|
#include "l2cap.h"
|
||||||
|
#include "WiiMote_HID_Attr.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
@ -29,10 +30,13 @@
|
||||||
#define HIDP_OUTPUT_CHANNEL 0x11
|
#define HIDP_OUTPUT_CHANNEL 0x11
|
||||||
#define HIDP_INPUT_CHANNEL 0x13
|
#define HIDP_INPUT_CHANNEL 0x13
|
||||||
|
|
||||||
#define HID_OUTPUT_SCID 0x1234
|
// #define HID_OUTPUT_SCID 0x1234
|
||||||
#define HID_INPUT_SCID 0x5678
|
// #define HID_INPUT_SCID 0x5678
|
||||||
|
|
||||||
|
|
||||||
|
#define HID_OUTPUT_SCID 0x0040
|
||||||
|
#define HID_INPUT_SCID 0x0040
|
||||||
|
|
||||||
struct SL2CAP_Header
|
struct SL2CAP_Header
|
||||||
{
|
{
|
||||||
u16 Length;
|
u16 Length;
|
||||||
|
@ -128,8 +132,8 @@ namespace Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number)
|
CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number)
|
||||||
: m_Name("Nintendo RVL-CNT-01")
|
: m_Name("Nintendo RVL-CNT-01")
|
||||||
, m_pHost(_pHost)
|
, m_pHost(_pHost)
|
||||||
{
|
{
|
||||||
s_Usb = _pHost;
|
s_Usb = _pHost;
|
||||||
LOG(WIIMOTE, "Wiimote %i constructed", _Number);
|
LOG(WIIMOTE, "Wiimote %i constructed", _Number);
|
||||||
|
@ -143,9 +147,9 @@ CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305*
|
||||||
|
|
||||||
m_ControllerConnectionHandle = 0x100 + _Number;
|
m_ControllerConnectionHandle = 0x100 + _Number;
|
||||||
|
|
||||||
uclass[0]= 0x04;
|
uclass[0]= 0x00;
|
||||||
uclass[1]= 0x25;
|
uclass[1]= 0x04;
|
||||||
uclass[2]= 0x00;
|
uclass[2]= 0x48;
|
||||||
|
|
||||||
features[0] = 0xBC;
|
features[0] = 0xBC;
|
||||||
features[1] = 0x02;
|
features[1] = 0x02;
|
||||||
|
@ -155,6 +159,9 @@ CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305*
|
||||||
features[5] = 0x00;
|
features[5] = 0x00;
|
||||||
features[6] = 0x00;
|
features[6] = 0x00;
|
||||||
features[7] = 0x00;
|
features[7] = 0x00;
|
||||||
|
|
||||||
|
lmp_version = 0x2;
|
||||||
|
lmp_subversion = 0x229;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWII_IPC_HLE_WiiMote::SendACLFrame(u8* _pData, u32 _Size)
|
void CWII_IPC_HLE_WiiMote::SendACLFrame(u8* _pData, u32 _Size)
|
||||||
|
@ -190,12 +197,32 @@ void CWII_IPC_HLE_WiiMote::SendACLFrame(u8* _pData, u32 _Size)
|
||||||
case 0x0001:
|
case 0x0001:
|
||||||
SignalChannel(pData, DataSize);
|
SignalChannel(pData, DataSize);
|
||||||
break;
|
break;
|
||||||
case HID_OUTPUT_SCID:
|
|
||||||
HidOutput(pData, DataSize);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlert("SendACLFrame to unknown channel");
|
{
|
||||||
|
CChannelMap::iterator itr= m_Channel.find(pHeader->CID);
|
||||||
|
if (itr != m_Channel.end())
|
||||||
|
{
|
||||||
|
SChannel& rChannel = itr->second;
|
||||||
|
switch(rChannel.PSM)
|
||||||
|
{
|
||||||
|
case 0x01: //SDP
|
||||||
|
{
|
||||||
|
HandleSDP(pHeader->CID, pData, DataSize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
PanicAlert("channel %i has unknow PSM %x", pHeader->CID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PanicAlert("SendACLFrame to unknown channel %i", pHeader->CID);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,16 +250,29 @@ void CWII_IPC_HLE_WiiMote::SendCommandToACL(u8 _Ident, u8 _Code, u8 _CommandLeng
|
||||||
// send ....
|
// send ....
|
||||||
m_pHost->SendACLFrame(GetConnectionHandle(), DataFrame, pHeader->Length + sizeof(SL2CAP_Header));
|
m_pHost->SendACLFrame(GetConnectionHandle(), DataFrame, pHeader->Length + sizeof(SL2CAP_Header));
|
||||||
|
|
||||||
// stupid self-test
|
|
||||||
// SendACLFrame(DataFrame, pHeader->Length + sizeof(SL2CAP_Header));
|
// dump raw data
|
||||||
|
{
|
||||||
|
LOG(WIIMOTE, "m_pHost->SendACLFrame: 0x%x", GetConnectionHandle());
|
||||||
|
std::string Temp;
|
||||||
|
for (u32 j=0; j<pHeader->Length + sizeof(SL2CAP_Header); j++)
|
||||||
|
{
|
||||||
|
char Buffer[128];
|
||||||
|
sprintf(Buffer, "%02x ", DataFrame[j]);
|
||||||
|
Temp.append(Buffer);
|
||||||
|
}
|
||||||
|
LOG(WIIMOTE, " Data: %s", Temp.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWII_IPC_HLE_WiiMote::Connect() {
|
void CWII_IPC_HLE_WiiMote::Connect()
|
||||||
|
{
|
||||||
SendConnectionRequest(HID_OUTPUT_SCID, HIDP_OUTPUT_CHANNEL);
|
SendConnectionRequest(HID_OUTPUT_SCID, HIDP_OUTPUT_CHANNEL);
|
||||||
SendConnectionRequest(HID_INPUT_SCID, HIDP_INPUT_CHANNEL);
|
SendConnectionRequest(HID_INPUT_SCID, HIDP_INPUT_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWII_IPC_HLE_WiiMote::SendConnectionRequest(u16 scid, u16 psm) {
|
void CWII_IPC_HLE_WiiMote::SendConnectionRequest(u16 scid, u16 psm)
|
||||||
|
{
|
||||||
// create the channel
|
// create the channel
|
||||||
SChannel& rChannel = m_Channel[scid];
|
SChannel& rChannel = m_Channel[scid];
|
||||||
rChannel.PSM = psm;
|
rChannel.PSM = psm;
|
||||||
|
@ -253,15 +293,33 @@ void CWII_IPC_HLE_WiiMote::SendConfigurationRequest(u16 scid) {
|
||||||
_dbg_assert_(WIIMOTE, DoesChannelExist(scid));
|
_dbg_assert_(WIIMOTE, DoesChannelExist(scid));
|
||||||
SChannel& rChannel = m_Channel[scid];
|
SChannel& rChannel = m_Channel[scid];
|
||||||
|
|
||||||
l2cap_conf_req cr;
|
u8 Buffer[1024];
|
||||||
cr.dcid = rChannel.DCID;
|
int Offset = 0;
|
||||||
cr.flags = 0; //what goes here? check libogc.
|
|
||||||
|
l2cap_conf_req* cr = (l2cap_conf_req*)Buffer;
|
||||||
|
cr->dcid = rChannel.DCID;
|
||||||
|
cr->flags = 0; //what goes here? check libogc.
|
||||||
|
|
||||||
|
Offset += 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
controller doesnt know this...
|
||||||
|
Buffer[Offset++] = 1;
|
||||||
|
Buffer[Offset++] = 2;
|
||||||
|
Buffer[Offset++] = 0;
|
||||||
|
Buffer[Offset++] = 1;*/
|
||||||
|
|
||||||
|
Buffer[Offset++] = 2;
|
||||||
|
Buffer[Offset++] = 2;
|
||||||
|
Buffer[Offset++] = 0xff;
|
||||||
|
Buffer[Offset++] = 0xff;
|
||||||
|
|
||||||
|
|
||||||
LOG(WIIMOTE, " SendConfigurationRequest()");
|
LOG(WIIMOTE, " SendConfigurationRequest()");
|
||||||
LOG(WIIMOTE, " Dcid: 0x%04x", cr.dcid);
|
LOG(WIIMOTE, " Dcid: 0x%04x", cr->dcid);
|
||||||
LOG(WIIMOTE, " Flags: 0x%04x", cr.flags);
|
LOG(WIIMOTE, " Flags: 0x%04x", cr->flags);
|
||||||
|
|
||||||
SendCommandToACL(L2CAP_CONF_REQ, L2CAP_CONF_REQ, sizeof(cr), (u8*)&cr);
|
SendCommandToACL(L2CAP_CONF_REQ, L2CAP_CONF_REQ, Offset, Buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -367,6 +425,46 @@ void CWII_IPC_HLE_WiiMote::CommandConnectionReq(u8 _Ident, u8* _pData, u32 _Size
|
||||||
SendCommandToACL(_Ident, L2CAP_CONN_RSP, sizeof(SL2CAP_ConnectionResponse), (u8*)&Rsp);
|
SendCommandToACL(_Ident, L2CAP_CONN_RSP, sizeof(SL2CAP_ConnectionResponse), (u8*)&Rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CConfigurationResponse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CConfigurationResponse(u8 identifier, u16 scid, u16 flags, u16 result)
|
||||||
|
{
|
||||||
|
buffer[0] = 0x05;
|
||||||
|
buffer[1] = identifier;
|
||||||
|
*(u16*)&buffer[4] = scid;
|
||||||
|
*(u16*)&buffer[6] = flags;
|
||||||
|
*(u16*)&buffer[8] = result;
|
||||||
|
|
||||||
|
length = 10;
|
||||||
|
|
||||||
|
UpdateLen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddConfig(u8 type, u8 len, void* data)
|
||||||
|
{
|
||||||
|
buffer[length++] = type;
|
||||||
|
buffer[length++] = len;
|
||||||
|
memcpy(&buffer[length], data, len);
|
||||||
|
length += len;
|
||||||
|
|
||||||
|
UpdateLen();
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 getLen() { return length; }
|
||||||
|
u8* getBuffer() { return buffer; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void UpdateLen()
|
||||||
|
{
|
||||||
|
*(u16*)&buffer[2] = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 buffer[1024];
|
||||||
|
u16 length;
|
||||||
|
};
|
||||||
|
|
||||||
void CWII_IPC_HLE_WiiMote::CommandCofigurationReq(u8 _Ident, u8* _pData, u32 _Size)
|
void CWII_IPC_HLE_WiiMote::CommandCofigurationReq(u8 _Ident, u8* _pData, u32 _Size)
|
||||||
{
|
{
|
||||||
u32 Offset = 0;
|
u32 Offset = 0;
|
||||||
|
@ -437,6 +535,9 @@ void CWII_IPC_HLE_WiiMote::CommandCofigurationReq(u8 _Ident, u8* _pData, u32 _Si
|
||||||
|
|
||||||
|
|
||||||
SendCommandToACL(_Ident, L2CAP_CONF_RSP, RespLen, TempBuffer);
|
SendCommandToACL(_Ident, L2CAP_CONF_RSP, RespLen, TempBuffer);
|
||||||
|
|
||||||
|
// ugly
|
||||||
|
SendConfigurationRequest(Rsp->scid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWII_IPC_HLE_WiiMote::CommandConnectionResponse(u8 _Ident, u8* _pData, u32 _Size)
|
void CWII_IPC_HLE_WiiMote::CommandConnectionResponse(u8 _Ident, u8* _pData, u32 _Size)
|
||||||
|
@ -475,3 +576,219 @@ void CWII_IPC_HLE_WiiMote::CommandCofigurationResponse(u8 _Ident, u8* _pData, u3
|
||||||
|
|
||||||
_dbg_assert_(WIIMOTE, rsp->result == 0);
|
_dbg_assert_(WIIMOTE, rsp->result == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define SDP_UINT8 0x08
|
||||||
|
#define SDP_UINT16 0x09
|
||||||
|
#define SDP_UINT32 0x0A
|
||||||
|
#define SDP_SEQ8 0x35
|
||||||
|
#define SDP_SEQ16 0x36
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CWII_IPC_HLE_WiiMote::SDPSendServiceSearchResponse(u16 cid, u16 TransactionID, u8* pServiceSearchPattern, u16 MaximumServiceRecordCount)
|
||||||
|
{
|
||||||
|
// verify block... we hanlde search pattern for HID service only
|
||||||
|
{
|
||||||
|
CBigEndianBuffer buffer(pServiceSearchPattern);
|
||||||
|
_dbg_assert_(WIIMOTE, buffer.Read8(0) == SDP_SEQ8); // data sequence
|
||||||
|
_dbg_assert_(WIIMOTE, buffer.Read8(1) == 0x03); // sequence size
|
||||||
|
|
||||||
|
// HIDClassID
|
||||||
|
_dbg_assert_(WIIMOTE, buffer.Read8(2) == 0x19);
|
||||||
|
_dbg_assert_(WIIMOTE, buffer.Read16(3) == 0x1124);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 DataFrame[1000];
|
||||||
|
CBigEndianBuffer buffer(DataFrame);
|
||||||
|
|
||||||
|
int Offset = 0;
|
||||||
|
SL2CAP_Header* pHeader = (SL2CAP_Header*)&DataFrame[Offset]; Offset += sizeof(SL2CAP_Header);
|
||||||
|
pHeader->CID = cid;
|
||||||
|
pHeader->Length = 0x14;
|
||||||
|
|
||||||
|
buffer.Write8 (Offset, 0x03); Offset++;
|
||||||
|
buffer.Write16(Offset, TransactionID); Offset += 2; // transaction ID
|
||||||
|
buffer.Write16(Offset, 0x0009); Offset += 2; // param length
|
||||||
|
buffer.Write16(Offset, 0x0001); Offset += 2; // TotalServiceRecordCount
|
||||||
|
buffer.Write16(Offset, 0x0001); Offset += 2; // CurrentServiceRecordCount
|
||||||
|
buffer.Write32(Offset, 0x1234ABCD); Offset += 4; // ServiceRecordHandleList[4]
|
||||||
|
buffer.Write8( Offset, 0x00); Offset++; // no continuation state;
|
||||||
|
|
||||||
|
pHeader->Length = Offset - sizeof(SL2CAP_Header);
|
||||||
|
|
||||||
|
m_pHost->SendACLFrame(GetConnectionHandle(), DataFrame, Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetStartAndEndID(u8* pAttribIDList, u16& _startID, u16& _endID)
|
||||||
|
{
|
||||||
|
u32 attribOffset = 0;
|
||||||
|
CBigEndianBuffer attribList(pAttribIDList);
|
||||||
|
|
||||||
|
u8 sequence = attribList.Read8(attribOffset); attribOffset++; _dbg_assert_(WIIMOTE, sequence == SDP_SEQ8);
|
||||||
|
u8 seqSize = attribList.Read8(attribOffset); attribOffset++;
|
||||||
|
u8 typeID = attribList.Read8(attribOffset); attribOffset++;
|
||||||
|
|
||||||
|
if (typeID == SDP_UINT32)
|
||||||
|
{
|
||||||
|
_startID = attribList.Read16(attribOffset); attribOffset += 2;
|
||||||
|
_endID = attribList.Read16(attribOffset); attribOffset += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_startID = attribList.Read8(attribOffset); attribOffset += 2;
|
||||||
|
_endID = _startID;
|
||||||
|
PanicAlert("Read just a single attrib - not tested");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CWII_IPC_HLE_WiiMote::SDPSendServiceAttributeResponse(u16 cid, u16 TransactionID, u32 ServiceHandle, u8* pAttribIDList, u16 AttribListIDSize)
|
||||||
|
{
|
||||||
|
u8 DataFrame[1000];
|
||||||
|
CBigEndianBuffer buffer(DataFrame);
|
||||||
|
|
||||||
|
int Offset = 0;
|
||||||
|
SL2CAP_Header* pHeader = (SL2CAP_Header*)&DataFrame[Offset]; Offset += sizeof(SL2CAP_Header);
|
||||||
|
pHeader->CID = cid;
|
||||||
|
|
||||||
|
buffer.Write8 (Offset, 0x05); Offset++;
|
||||||
|
buffer.Write16(Offset, TransactionID); Offset += 2; // transaction ID
|
||||||
|
|
||||||
|
{
|
||||||
|
u32 paraLenOffset = Offset; Offset += 2;
|
||||||
|
u32 AttributeListByteCountOffset = Offset; Offset += 2;
|
||||||
|
|
||||||
|
buffer.Write8(Offset, SDP_SEQ16); Offset ++; // write 16 bit sequencer
|
||||||
|
u32 sequenceSizeOffset = Offset; Offset += 2;
|
||||||
|
|
||||||
|
// get attrib range
|
||||||
|
u16 startAttrID;
|
||||||
|
u16 endAttrID;
|
||||||
|
GetStartAndEndID(pAttribIDList, startAttrID, endAttrID);
|
||||||
|
|
||||||
|
// walk through the table
|
||||||
|
const CAttribTable& rAttribTable = GetAttribTable();
|
||||||
|
CAttribTable::const_iterator itr = rAttribTable.begin();
|
||||||
|
|
||||||
|
u32 sequenceSize = 0;
|
||||||
|
while(itr != rAttribTable.end())
|
||||||
|
{
|
||||||
|
const SAttrib& rAttrib = *itr;
|
||||||
|
|
||||||
|
if ((rAttrib.ID >= startAttrID) && (rAttrib.ID <= endAttrID))
|
||||||
|
{
|
||||||
|
_dbg_assert_(WIIMOTE, rAttrib.size <= 230);
|
||||||
|
|
||||||
|
// ATTRIB TYPE ID
|
||||||
|
buffer.Write8(Offset, SDP_UINT16); Offset ++;
|
||||||
|
buffer.Write16(Offset, rAttrib.ID); Offset += 2;
|
||||||
|
sequenceSize += 3;
|
||||||
|
|
||||||
|
// RAW ATTRIB DATA SEQ HEADER
|
||||||
|
buffer.Write8(Offset, SDP_SEQ8); Offset ++;
|
||||||
|
buffer.Write8(Offset, rAttrib.size); Offset ++;
|
||||||
|
sequenceSize += 2;
|
||||||
|
|
||||||
|
// RAW ATTRIB DATA
|
||||||
|
memcpy(buffer.GetPointer(Offset), rAttrib.pData, rAttrib.size);
|
||||||
|
Offset += rAttrib.size;
|
||||||
|
|
||||||
|
sequenceSize += rAttrib.size;
|
||||||
|
}
|
||||||
|
itr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
buffer.Write16(sequenceSizeOffset, sequenceSize);
|
||||||
|
buffer.Write16(AttributeListByteCountOffset, sequenceSize + 4); // AttributeListByteCount
|
||||||
|
buffer.Write16(paraLenOffset, sequenceSize + 4 + 3); // param length
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Write8(Offset, 0x00); Offset++; // no continuation state;
|
||||||
|
|
||||||
|
pHeader->Length = Offset - sizeof(SL2CAP_Header);
|
||||||
|
|
||||||
|
|
||||||
|
// dump raw data
|
||||||
|
{
|
||||||
|
LOG(WIIMOTE, "test response: 0x%x", GetConnectionHandle());
|
||||||
|
std::string Temp;
|
||||||
|
for (u32 j=0; j<pHeader->Length + sizeof(SL2CAP_Header); j++)
|
||||||
|
{
|
||||||
|
char Buffer[128];
|
||||||
|
sprintf(Buffer, "%02x ", DataFrame[j]);
|
||||||
|
Temp.append(Buffer);
|
||||||
|
}
|
||||||
|
LOG(WIIMOTE, " Data: %s", Temp.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pHost->SendACLFrame(GetConnectionHandle(), DataFrame, pHeader->Length + sizeof(SL2CAP_Header));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWII_IPC_HLE_WiiMote::HandleSDP(u16 cid, u8* _pData, u32 _Size)
|
||||||
|
{
|
||||||
|
// dump raw data
|
||||||
|
{
|
||||||
|
LOG(WIIMOTE, "HandleSDP: 0x%x", GetConnectionHandle());
|
||||||
|
std::string Temp;
|
||||||
|
for (u32 j=0; j<_Size; j++)
|
||||||
|
{
|
||||||
|
char Buffer[128];
|
||||||
|
sprintf(Buffer, "%02x ", _pData[j]);
|
||||||
|
Temp.append(Buffer);
|
||||||
|
}
|
||||||
|
LOG(WIIMOTE, " Data: %s", Temp.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CBigEndianBuffer buffer(_pData);
|
||||||
|
|
||||||
|
switch(buffer.Read8(0))
|
||||||
|
{
|
||||||
|
// SDP_ServiceSearchRequest
|
||||||
|
case 0x02:
|
||||||
|
{
|
||||||
|
LOG(WIIMOTE, "!!! SDP_ServiceSearchRequest !!!");
|
||||||
|
|
||||||
|
_dbg_assert_(WIIMOTE, _Size == 13);
|
||||||
|
|
||||||
|
u16 TransactionID = buffer.Read16(1);
|
||||||
|
u16 ParameterLength = buffer.Read16(3);
|
||||||
|
u8* pServiceSearchPattern = buffer.GetPointer(5);
|
||||||
|
u16 MaximumServiceRecordCount = buffer.Read16(10);
|
||||||
|
u8 ContinuationState = buffer.Read8(12);
|
||||||
|
|
||||||
|
SDPSendServiceSearchResponse(cid, TransactionID, pServiceSearchPattern, MaximumServiceRecordCount);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// SDP_ServiceAttributeRequest
|
||||||
|
case 0x04:
|
||||||
|
{
|
||||||
|
LOG(WIIMOTE, "!!! SDP_ServiceAttributeRequest !!!");
|
||||||
|
|
||||||
|
u16 TransactionID = buffer.Read16(1);
|
||||||
|
u16 ParameterLength = buffer.Read16(3);
|
||||||
|
u32 ServiceHandle = buffer.Read32(5);
|
||||||
|
u16 MaximumAttributeByteCount = buffer.Read16(9); // MaximumAttributeByteCount
|
||||||
|
u8* pAttribIDList = buffer.GetPointer(11);
|
||||||
|
u8 ContinuationState = buffer.Read8(16);
|
||||||
|
|
||||||
|
u8 AttribListIDSize = ParameterLength - sizeof(ContinuationState) - sizeof(ServiceHandle) -sizeof(MaximumAttributeByteCount);
|
||||||
|
SDPSendServiceAttributeResponse(cid, TransactionID, ServiceHandle, pAttribIDList, AttribListIDSize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
PanicAlert("Unknown SDP command %x", _pData[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,56 @@
|
||||||
|
|
||||||
class CWII_IPC_HLE_Device_usb_oh1_57e_305;
|
class CWII_IPC_HLE_Device_usb_oh1_57e_305;
|
||||||
|
|
||||||
|
|
||||||
|
class CBigEndianBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBigEndianBuffer(u8* pBuffer)
|
||||||
|
: m_pBuffer(pBuffer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 Read8(u32 offset)
|
||||||
|
{
|
||||||
|
return m_pBuffer[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Read16(u32 offset)
|
||||||
|
{
|
||||||
|
return Common::swap16(*(u16*)&m_pBuffer[offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Read32(u32 offset)
|
||||||
|
{
|
||||||
|
return Common::swap32(*(u32*)&m_pBuffer[offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write8(u32 offset, u8 data)
|
||||||
|
{
|
||||||
|
m_pBuffer[offset] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write16(u32 offset, u16 data)
|
||||||
|
{
|
||||||
|
*(u16*)&m_pBuffer[offset] = Common::swap16(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write32(u32 offset, u32 data)
|
||||||
|
{
|
||||||
|
*(u32*)&m_pBuffer[offset] = Common::swap32(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* GetPointer(u32 offset)
|
||||||
|
{
|
||||||
|
return &m_pBuffer[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
u8* m_pBuffer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class CWII_IPC_HLE_WiiMote
|
class CWII_IPC_HLE_WiiMote
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -41,6 +91,12 @@ public:
|
||||||
|
|
||||||
const char* GetName() const { return m_Name.c_str(); }
|
const char* GetName() const { return m_Name.c_str(); }
|
||||||
|
|
||||||
|
u8 GetLMPVersion() const { return lmp_version; }
|
||||||
|
|
||||||
|
u16 GetLMPSubVersion() const { return lmp_subversion; }
|
||||||
|
|
||||||
|
u8 GetManufactorID() const { return 0xF; } // Broadcom Corporation
|
||||||
|
|
||||||
void SendACLFrame(u8* _pData, u32 _Size); //to wiimote
|
void SendACLFrame(u8* _pData, u32 _Size); //to wiimote
|
||||||
|
|
||||||
void Connect();
|
void Connect();
|
||||||
|
@ -58,6 +114,11 @@ private:
|
||||||
|
|
||||||
u8 features[HCI_FEATURES_SIZE];
|
u8 features[HCI_FEATURES_SIZE];
|
||||||
|
|
||||||
|
u8 lmp_version;
|
||||||
|
|
||||||
|
u16 lmp_subversion;
|
||||||
|
|
||||||
|
|
||||||
std::string m_Name;
|
std::string m_Name;
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_usb_oh1_57e_305* m_pHost;
|
CWII_IPC_HLE_Device_usb_oh1_57e_305* m_pHost;
|
||||||
|
@ -71,7 +132,9 @@ private:
|
||||||
u16 MTU;
|
u16 MTU;
|
||||||
u16 FlushTimeOut;
|
u16 FlushTimeOut;
|
||||||
};
|
};
|
||||||
std::map<u32, SChannel> m_Channel;
|
|
||||||
|
typedef std::map<u32, SChannel> CChannelMap;
|
||||||
|
CChannelMap m_Channel;
|
||||||
|
|
||||||
bool DoesChannelExist(u16 _SCID)
|
bool DoesChannelExist(u16 _SCID)
|
||||||
{
|
{
|
||||||
|
@ -91,5 +154,18 @@ private:
|
||||||
void CommandCofigurationReq(u8 _Ident, u8* _pData, u32 _Size);
|
void CommandCofigurationReq(u8 _Ident, u8* _pData, u32 _Size);
|
||||||
void CommandConnectionResponse(u8 _Ident, u8* _pData, u32 _Size);
|
void CommandConnectionResponse(u8 _Ident, u8* _pData, u32 _Size);
|
||||||
void CommandCofigurationResponse(u8 _Ident, u8* _pData, u32 _Size);
|
void CommandCofigurationResponse(u8 _Ident, u8* _pData, u32 _Size);
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////
|
||||||
|
// some new ugly stuff
|
||||||
|
//
|
||||||
|
// should be inside the plugin
|
||||||
|
//
|
||||||
|
void HandleSDP(u16 cid, u8* _pData, u32 _Size);
|
||||||
|
void SDPSendServiceSearchResponse(u16 cid, u16 TransactionID, u8* pServiceSearchPattern, u16 MaximumServiceRecordCount);
|
||||||
|
void SDPSendServiceAttributeResponse(u16 cid, u16 TransactionID, u32 ServiceHandle, u8* pAttribIDList, u16 AttribListIDSize);
|
||||||
|
|
||||||
|
u16 AddAttribToList(int attribID, u8* pBuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
|
// 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, version 2.0.
|
||||||
|
|
||||||
|
// 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 2.0 for more details.
|
||||||
|
|
||||||
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
|
// Official SVN repository and contact information can be found at
|
||||||
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include <vector>
|
||||||
|
#include "WiiMote_HID_Attr.h"
|
||||||
|
|
||||||
|
CAttribTable m_AttribTable;
|
||||||
|
|
||||||
|
|
||||||
|
// 0x00
|
||||||
|
u8 ServiceRecordHandle[] = { 0x0a, 0x00, 0x01, 0x00, 0x00 };
|
||||||
|
// 0x01
|
||||||
|
u8 SrvClassIDList[] = { 0x35, 0x03,
|
||||||
|
0x19, 0x11, 0x24 };
|
||||||
|
// 0x04
|
||||||
|
u8 ProtocolDescriptorList[] = { 0x35, 0x0D,
|
||||||
|
0x35, 0x06,
|
||||||
|
0x19, 0x01, 0x00, // Element 0
|
||||||
|
0x09, 0x00, 0x11, // Element 1
|
||||||
|
0x35, 0x03,
|
||||||
|
0x19, 0x00, 0x11}; // Element 0
|
||||||
|
// 0x5
|
||||||
|
u8 BrowseGroupList[] = { 0x35, 0x03, 0x09, 0x10, 0x02 };
|
||||||
|
// 0x6
|
||||||
|
u8 LanguageBaseAttributeIDList[] = { 0x35, 0x09,
|
||||||
|
0x09, 0x65, 0x6e,
|
||||||
|
0x09, 0x00, 0x6a,
|
||||||
|
0x09, 0x01, 0x00 };
|
||||||
|
// 0x09
|
||||||
|
u8 BluetoothProfileDescriptorList[] = { 0x35, 0x08,
|
||||||
|
0x35, 0x06,
|
||||||
|
0x19, 0x00, 0x11,
|
||||||
|
0x09, 0x01, 0x00 };
|
||||||
|
// 0x0D
|
||||||
|
u8 AdditionalProtocolDescriptorLists[] = { 0x35, 0x0a,
|
||||||
|
0x35, 0x03,
|
||||||
|
0x19, 0x01, 0x00,
|
||||||
|
0x09, 0x00, 0x13,
|
||||||
|
0x35, 0x03,
|
||||||
|
0x19, 0x00, 0x11 };
|
||||||
|
// 0x100
|
||||||
|
u8 ServiceName[] = { 0x25, 0x13, 'N','i','n','t','e','n','d','o',' ','R','V','L','-','C','N','T','-','0','1' };
|
||||||
|
// 0x101
|
||||||
|
u8 ServiceDescription[] = { 0x25, 0x13, 'N','i','n','t','e','n','d','o',' ','R','V','L','-','C','N','T','-','0','1' };
|
||||||
|
// 0x102
|
||||||
|
u8 ProviderName [] = { 0x25, 0x8, 'N','i','n','t','e','n','d','o'};
|
||||||
|
|
||||||
|
// 0x200
|
||||||
|
u8 HIDDeviceReleaseNumber[] = { 0x09, 0x01, 0x00 };
|
||||||
|
// 0x201
|
||||||
|
u8 HIDParserVersion[] = { 0x09, 0x01, 0x11 };
|
||||||
|
// 0x202
|
||||||
|
u8 HIDDeviceSubclass[] = { 0x09, 0x00, 0x04 };
|
||||||
|
// 0x203
|
||||||
|
u8 HIDCountryCode[] = { 0x09, 0x00, 0x33 };
|
||||||
|
// 0x204
|
||||||
|
u8 HIDVirtualCable[] = { 0x09, 0x00, 0x00 };
|
||||||
|
// 0x205
|
||||||
|
u8 HIDReconnectInitiate[] = { 0x09, 0x00, 0x01 };
|
||||||
|
|
||||||
|
// 0x206
|
||||||
|
u8 HIDDescriptorList[] = { 0x35, 0xDF,
|
||||||
|
0x35, 0xDD,
|
||||||
|
0x08, 0x22, // Element 0
|
||||||
|
0x25, 0xD9,
|
||||||
|
|
||||||
|
// 0xD9 Bytes - Element 1
|
||||||
|
0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
|
||||||
|
0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
|
||||||
|
0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
|
||||||
|
0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
|
||||||
|
0xc0 }; // end tag
|
||||||
|
|
||||||
|
|
||||||
|
// 0x207
|
||||||
|
u8 HIDLANGIDBaseList[] = { 0x35, 0x08,
|
||||||
|
0x35, 0x06,
|
||||||
|
0x09, 0x04, 0x09,
|
||||||
|
0x09, 0x01, 0x00 };
|
||||||
|
|
||||||
|
// 0x208
|
||||||
|
u8 HIDSDPDisable[] = { 0x28, 0x00 };
|
||||||
|
// 0x209
|
||||||
|
u8 HIDBatteryPower[] = { 0x28, 0x01 };
|
||||||
|
// 0x20a
|
||||||
|
u8 HIDRemoteWake[] = { 0x28, 0x01 };
|
||||||
|
// 0x20b
|
||||||
|
u8 HIDUnk_020B[] = { 0x09, 0x01, 0x00 };
|
||||||
|
// 0x20c
|
||||||
|
u8 HIDUnk_020C[] = { 0x09, 0x0c, 0x80 };
|
||||||
|
// 0x20d
|
||||||
|
u8 HIDUnk_020D[] = { 0x09, 0x00, 0x00 };
|
||||||
|
// 0x20e
|
||||||
|
u8 HIDBootDevice[] = { 0x28, 0x00 };
|
||||||
|
|
||||||
|
|
||||||
|
void InitAttribTable()
|
||||||
|
{
|
||||||
|
m_AttribTable.push_back(SAttrib(0x00, ServiceRecordHandle, sizeof(ServiceRecordHandle)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x01, SrvClassIDList, sizeof(SrvClassIDList)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x04, ProtocolDescriptorList, sizeof(ProtocolDescriptorList)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x05, BrowseGroupList, sizeof(BrowseGroupList)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x06, LanguageBaseAttributeIDList, sizeof(LanguageBaseAttributeIDList)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x09, BluetoothProfileDescriptorList, sizeof(BluetoothProfileDescriptorList)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x0D, AdditionalProtocolDescriptorLists, sizeof(AdditionalProtocolDescriptorLists)));
|
||||||
|
|
||||||
|
|
||||||
|
m_AttribTable.push_back(SAttrib(0x100, ServiceName, sizeof(ServiceName)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x101, ServiceDescription, sizeof(ServiceDescription)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x102, ProviderName, sizeof(ProviderName)));
|
||||||
|
|
||||||
|
m_AttribTable.push_back(SAttrib(0x200, HIDDeviceReleaseNumber, sizeof(HIDDeviceReleaseNumber)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x201, HIDParserVersion, sizeof(HIDParserVersion)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x202, HIDDeviceSubclass, sizeof(HIDDeviceSubclass)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x203, HIDCountryCode, sizeof(HIDCountryCode)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x204, HIDVirtualCable, sizeof(HIDVirtualCable)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x205, HIDReconnectInitiate, sizeof(HIDReconnectInitiate)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x206, HIDDescriptorList, sizeof(HIDDescriptorList)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x207, HIDLANGIDBaseList, sizeof(HIDLANGIDBaseList)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x208, HIDSDPDisable, sizeof(HIDSDPDisable)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x209, HIDBatteryPower, sizeof(HIDBatteryPower)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x20a, HIDRemoteWake, sizeof(HIDRemoteWake)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x20b, HIDUnk_020B, sizeof(HIDUnk_020B)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x20c, HIDUnk_020C, sizeof(HIDUnk_020C)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x20d, HIDUnk_020D, sizeof(HIDUnk_020D)));
|
||||||
|
m_AttribTable.push_back(SAttrib(0x20e, HIDBootDevice, sizeof(HIDBootDevice)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const CAttribTable& GetAttribTable()
|
||||||
|
{
|
||||||
|
if (m_AttribTable.empty())
|
||||||
|
{
|
||||||
|
InitAttribTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_AttribTable;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (C) 2003-2008 Dolphin Project.
|
||||||
|
|
||||||
|
// 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, version 2.0.
|
||||||
|
|
||||||
|
// 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 2.0 for more details.
|
||||||
|
|
||||||
|
// A copy of the GPL 2.0 should have been included with the program.
|
||||||
|
// If not, see http://www.gnu.org/licenses/
|
||||||
|
|
||||||
|
// Official SVN repository and contact information can be found at
|
||||||
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
#ifndef WIIMOTE_HID_ATTR_H_
|
||||||
|
#define WIIMOTE_HID_ATTR_H_
|
||||||
|
|
||||||
|
struct SAttrib
|
||||||
|
{
|
||||||
|
u16 ID;
|
||||||
|
u8* pData;
|
||||||
|
u16 size;
|
||||||
|
|
||||||
|
SAttrib(u16 _ID, u8* _Data, u16 _size)
|
||||||
|
: ID(_ID)
|
||||||
|
, pData(_Data)
|
||||||
|
, size(_size)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<SAttrib> CAttribTable;
|
||||||
|
|
||||||
|
const CAttribTable& GetAttribTable();
|
||||||
|
|
||||||
|
#endif
|
|
@ -2487,6 +2487,24 @@ struct SHCIEventConnectionComplete
|
||||||
u8 EncryptionEnabled;
|
u8 EncryptionEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SHCIEventRoleChange
|
||||||
|
{
|
||||||
|
u8 EventType;
|
||||||
|
u8 PayloadLength;
|
||||||
|
u8 Status;
|
||||||
|
bdaddr_t bdaddr;
|
||||||
|
u8 NewRole;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHCIEventNumberOfCompletedPackets
|
||||||
|
{
|
||||||
|
u8 EventType;
|
||||||
|
u8 PayloadLength;
|
||||||
|
u8 value;
|
||||||
|
u16 Connection_Handle;
|
||||||
|
u16 Number_Of_Completed_Packets;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,168 +0,0 @@
|
||||||
#ifndef WIIMOTE_HID_H
|
|
||||||
#define WIIMOTE_HID_H
|
|
||||||
|
|
||||||
#include <CommonTypes.h>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(disable:4200)
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//source: HID_010_SPC_PFL/1.0 (official HID specification)
|
|
||||||
|
|
||||||
struct hid_packet {
|
|
||||||
u8 param : 4;
|
|
||||||
u8 type : 4;
|
|
||||||
u8 data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HID_TYPE_SET_REPORT 5
|
|
||||||
#define HID_TYPE_DATA 0xA
|
|
||||||
|
|
||||||
#define HID_TYPE_HANDSHAKE 0
|
|
||||||
#define HID_HANDSHAKE_SUCCESS 0
|
|
||||||
#define HID_HANDSHAKE_WIIMOTE 8 //custom, reserved in HID specs.
|
|
||||||
|
|
||||||
#define HID_PARAM_INPUT 1
|
|
||||||
#define HID_PARAM_OUTPUT 2
|
|
||||||
|
|
||||||
//source: http://wiibrew.org/wiki/Wiimote
|
|
||||||
|
|
||||||
struct wm_report {
|
|
||||||
u8 channel;
|
|
||||||
u8 data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_LEDS 0x11
|
|
||||||
struct wm_leds {
|
|
||||||
u8 rumble : 1;
|
|
||||||
u8 : 3;
|
|
||||||
u8 leds : 4;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_DATA_REPORTING 0x12
|
|
||||||
struct wm_data_reporting {
|
|
||||||
u8 rumble : 1;
|
|
||||||
u8 continuous : 1;
|
|
||||||
u8 : 6;
|
|
||||||
u8 mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_IR_PIXEL_CLOCK 0x13
|
|
||||||
#define WM_IR_LOGIC 0x1A
|
|
||||||
|
|
||||||
#define WM_REQUEST_STATUS 0x15
|
|
||||||
struct wm_request_status {
|
|
||||||
u8 rumble : 1;
|
|
||||||
u8 : 7;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_STATUS_REPORT 0x20
|
|
||||||
struct wm_status_report {
|
|
||||||
u8 padding1[2];
|
|
||||||
u8 unknown : 1;
|
|
||||||
u8 extension : 1;
|
|
||||||
u8 speaker : 1;
|
|
||||||
u8 ir : 1;
|
|
||||||
u8 leds : 4;
|
|
||||||
u8 padding2[2];
|
|
||||||
u8 battery;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_WRITE_DATA 0x16
|
|
||||||
struct wm_write_data {
|
|
||||||
u8 rumble : 1;
|
|
||||||
u8 space : 2; //see WM_SPACE_*
|
|
||||||
u8 : 5;
|
|
||||||
u8 address[3];
|
|
||||||
u8 size;
|
|
||||||
u8 data[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_WRITE_DATA_REPLY 0x22 //empty, afaik
|
|
||||||
|
|
||||||
#define WM_READ_DATA 0x17
|
|
||||||
struct wm_read_data {
|
|
||||||
u8 rumble : 1;
|
|
||||||
u8 space : 2; //see WM_SPACE_*
|
|
||||||
u8 : 5;
|
|
||||||
u8 address[3];
|
|
||||||
u8 size[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_SPACE_EEPROM 0
|
|
||||||
#define WM_SPACE_REGS1 1
|
|
||||||
#define WM_SPACE_REGS2 2
|
|
||||||
#define WM_SPACE_INVALID 3
|
|
||||||
|
|
||||||
#define WM_READ_DATA_REPLY 0x21
|
|
||||||
struct wm_read_data_reply {
|
|
||||||
u16 buttons;
|
|
||||||
u8 error : 4; //see WM_RDERR_*
|
|
||||||
u8 size : 4;
|
|
||||||
u16 address;
|
|
||||||
u8 data[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_RDERR_WOREG 7
|
|
||||||
#define WM_RDERR_NOMEM 8
|
|
||||||
|
|
||||||
struct wm_core {
|
|
||||||
u8 left : 1;
|
|
||||||
u8 right : 1;
|
|
||||||
u8 down : 1;
|
|
||||||
u8 up : 1;
|
|
||||||
u8 plus : 1;
|
|
||||||
u8 : 3;
|
|
||||||
u8 two : 1;
|
|
||||||
u8 one : 1;
|
|
||||||
u8 b : 1;
|
|
||||||
u8 a : 1;
|
|
||||||
u8 minus : 1;
|
|
||||||
u8 : 2;
|
|
||||||
u8 home : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wm_accel {
|
|
||||||
u8 x, y, z;
|
|
||||||
};
|
|
||||||
|
|
||||||
//filled with 0xFF if empty
|
|
||||||
struct wm_ir_extended {
|
|
||||||
u8 x;
|
|
||||||
u8 y;
|
|
||||||
u8 size : 4;
|
|
||||||
u8 xHi : 2;
|
|
||||||
u8 yHi : 2;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_REPORT_CORE 0x30
|
|
||||||
|
|
||||||
#define WM_REPORT_CORE_ACCEL 0x31
|
|
||||||
struct wm_report_core_accel {
|
|
||||||
wm_core c;
|
|
||||||
wm_accel a;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_REPORT_CORE_EXT8 0x32
|
|
||||||
|
|
||||||
#define WM_REPORT_CORE_ACCEL_IR12 0x33
|
|
||||||
struct wm_report_core_accel_ir12 {
|
|
||||||
wm_core c;
|
|
||||||
wm_accel a;
|
|
||||||
wm_ir_extended ir[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WM_REPORT_CORE_EXT19 0x34
|
|
||||||
#define WM_REPORT_CORE_ACCEL_EXT16 0x35
|
|
||||||
#define WM_REPORT_CORE_IR10_EXT9 0x36
|
|
||||||
#define WM_REPORT_CORE_ACCEL_IR10_EXT6 0x37
|
|
||||||
#define WM_REPORT_EXT21 0x3d
|
|
||||||
#define WM_REPORT_INTERLEAVE1 0x3e
|
|
||||||
#define WM_REPORT_INTERLEAVE2 0x3f
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#pragma pack(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //WIIMOTE_HID_H
|
|
|
@ -190,13 +190,45 @@ extern "C" void Wiimote_Output(const void* _pData, u32 _Size) {
|
||||||
|
|
||||||
hid_packet* hidp = (hid_packet*) data;
|
hid_packet* hidp = (hid_packet*) data;
|
||||||
|
|
||||||
if(hidp->type == HID_TYPE_SET_REPORT &&
|
if ((hidp->param != HID_PARAM_INPUT) && (hidp->param != HID_PARAM_OUTPUT))
|
||||||
hidp->param == HID_PARAM_OUTPUT)
|
|
||||||
{
|
{
|
||||||
HidOutputReport((wm_report*)hidp->data);
|
PanicAlert("hidp->param has a wrong parameter!!!");
|
||||||
} else {
|
|
||||||
PanicAlert("HidOutput: Unknown type 0x%02x", data[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch(hidp->type)
|
||||||
|
{
|
||||||
|
case HID_TYPE_HANDSHAKE:
|
||||||
|
if (hidp->param == HID_PARAM_INPUT)
|
||||||
|
{
|
||||||
|
PanicAlert("HID_TYPE_HANDSHAKE - HID_PARAM_INPUT");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PanicAlert("HID_TYPE_HANDSHAKE - HID_PARAM_OUTPUT");
|
||||||
|
}
|
||||||
|
g_ReportingMode = 0x33;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HID_TYPE_SET_REPORT:
|
||||||
|
if (hidp->param == HID_PARAM_INPUT)
|
||||||
|
{
|
||||||
|
PanicAlert("HID_TYPE_SET_REPORT input");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HidOutputReport((wm_report*)hidp->data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HID_TYPE_DATA:
|
||||||
|
PanicAlert("HID_TYPE_DATA %s", hidp->type, hidp->param == HID_PARAM_INPUT ? "input" : "output");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
PanicAlert("HidOutput: Unknown type %x and param %x", hidp->type, hidp->param);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Wiimote_Update() {
|
extern "C" void Wiimote_Update() {
|
||||||
|
|
|
@ -16,10 +16,10 @@ struct hid_packet {
|
||||||
u8 data[0];
|
u8 data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define HID_TYPE_HANDSHAKE 0
|
||||||
#define HID_TYPE_SET_REPORT 5
|
#define HID_TYPE_SET_REPORT 5
|
||||||
#define HID_TYPE_DATA 0xA
|
#define HID_TYPE_DATA 0xA
|
||||||
|
|
||||||
#define HID_TYPE_HANDSHAKE 0
|
|
||||||
#define HID_HANDSHAKE_SUCCESS 0
|
#define HID_HANDSHAKE_SUCCESS 0
|
||||||
|
|
||||||
#define HID_PARAM_INPUT 1
|
#define HID_PARAM_INPUT 1
|
||||||
|
|
Loading…
Reference in New Issue