2009-07-28 21:32:10 +00:00
// Copyright (C) 2003 Dolphin Project.
2008-12-08 05:25:12 +00:00
// 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/
/* HID reports access guide. */
/* 0x10 - 0x1a Output EmuMain.cpp: HidOutputReport()
0x10 - 0x14 : General
0x15 : Status report request from the Wii
0x16 and 0x17 : Write and read memory or registers
0x19 and 0x1a : General
0x20 - 0x22 Input EmuMain . cpp : HidOutputReport ( ) to the destination
0x15 leads to a 0x20 Input report
0x17 leads to a 0x21 Input report
0x10 - 0x1a leads to a 0x22 Input report
0x30 - 0x3f Input This file : Update ( ) */
# include <vector>
# include <string>
2008-12-09 05:37:15 +00:00
# include "Common.h" // Common
# include "StringUtil.h"
2009-01-26 07:01:43 +00:00
# include "pluginspecs_wiimote.h"
2008-12-09 05:37:15 +00:00
2009-02-01 13:01:50 +00:00
# include "EmuMain.h" // Local
2008-12-08 05:25:12 +00:00
# include "EmuSubroutines.h"
# include "Config.h" // for g_Config
2009-01-07 02:59:19 +00:00
2008-12-08 05:25:12 +00:00
extern SWiimoteInitialize g_WiimoteInitialize ;
namespace WiiMoteEmu
{
2009-12-06 01:15:13 +00:00
extern void PAD_Rumble ( u8 _numPAD , unsigned int _uType ) ;
2009-07-05 05:59:03 +00:00
/* Here we process the Output Reports that the Wii sends. Our response will be
an Input Report back to the Wii . Input and Output is from the Wii ' s
perspective , Output means data to the Wiimote ( from the Wii ) , Input means
data from the Wiimote .
2009-01-07 02:59:19 +00:00
The call browser :
1. Wiimote_InterruptChannel > InterruptChannel > HidOutputReport
2. Wiimote_ControlChannel > ControlChannel > HidOutputReport
2009-12-05 20:01:48 +00:00
2010-01-05 17:39:06 +00:00
The IR enable / disable and speaker enable / disable and mute / unmute values are
bit2 : 0 = Disable ( 0x02 ) , 1 = Enable ( 0x06 )
2009-07-05 05:59:03 +00:00
*/
2009-11-24 05:03:47 +00:00
void HidOutputReport ( u16 _channelID , wm_report * sr )
{
2010-01-05 17:39:06 +00:00
INFO_LOG ( WIIMOTE , " HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x) " , g_ID , _channelID , sr - > wm ) ;
2009-01-07 02:59:19 +00:00
2009-11-24 05:03:47 +00:00
switch ( sr - > wm )
2009-01-07 02:59:19 +00:00
{
2009-12-05 20:01:48 +00:00
case WM_RUMBLE : // 0x10
2010-01-22 23:19:16 +00:00
PAD_Rumble ( g_ID , sr - > data [ 0 ] ) ;
2009-01-07 02:59:19 +00:00
break ;
2009-12-27 19:31:02 +00:00
2009-01-07 02:59:19 +00:00
case WM_LEDS : // 0x11
2010-01-05 17:39:06 +00:00
INFO_LOG ( WIIMOTE , " Set LEDs: 0x%02x " , sr - > data [ 0 ] ) ;
g_Leds [ g_ID ] = sr - > data [ 0 ] > > 4 ;
2009-01-07 02:59:19 +00:00
break ;
2009-11-24 05:03:47 +00:00
case WM_REPORT_MODE : // 0x12
WmReportMode ( _channelID , ( wm_report_mode * ) sr - > data ) ;
2009-01-07 02:59:19 +00:00
break ;
case WM_IR_PIXEL_CLOCK : // 0x13
2010-01-05 17:39:06 +00:00
INFO_LOG ( WIIMOTE , " WM IR Clock: 0x%02x " , sr - > data [ 0 ] ) ;
//g_IRClock[g_ID] = (sr->data[0] & 0x04) ? 1 : 0;
2009-01-07 02:59:19 +00:00
break ;
2009-11-24 05:03:47 +00:00
case WM_SPEAKER_ENABLE : // 0x14
INFO_LOG ( WIIMOTE , " WM Speaker Enable: 0x%02x " , sr - > data [ 0 ] ) ;
2010-01-05 17:39:06 +00:00
g_Speaker [ g_ID ] = ( sr - > data [ 0 ] & 0x04 ) ? 1 : 0 ;
2009-11-24 05:03:47 +00:00
break ;
case WM_REQUEST_STATUS : // 0x15
2009-12-08 19:58:19 +00:00
WmRequestStatus ( _channelID , ( wm_request_status * ) sr - > data ) ;
2009-11-24 05:03:47 +00:00
break ;
2009-01-07 02:59:19 +00:00
case WM_WRITE_DATA : // 0x16
2009-02-04 06:40:05 +00:00
WmWriteData ( _channelID , ( wm_write_data * ) sr - > data ) ;
2009-01-07 02:59:19 +00:00
break ;
2009-02-08 12:27:04 +00:00
2009-11-24 05:03:47 +00:00
case WM_READ_DATA : // 0x17
2009-12-08 19:58:19 +00:00
WmReadData ( _channelID , ( wm_read_data * ) sr - > data ) ;
2009-01-07 02:59:19 +00:00
break ;
2009-11-24 05:03:47 +00:00
case WM_WRITE_SPEAKER_DATA : // 0x18
2009-12-05 20:01:48 +00:00
// TODO: Does this need an ack?
2009-11-24 05:03:47 +00:00
break ;
2009-02-08 12:27:04 +00:00
case WM_SPEAKER_MUTE : // 0x19
2010-01-05 17:39:06 +00:00
INFO_LOG ( WIIMOTE , " WM Speaker Mute: 0x%02x " , sr - > data [ 0 ] ) ;
//g_SpeakerMute[g_ID] = (sr->data[0] & 0x04) ? 1 : 0;
break ;
case WM_IR_LOGIC : // 0x1a
// This enables or disables the IR lights, we update the global variable g_IR
// so that WmRequestStatus() knows about it
INFO_LOG ( WIIMOTE , " WM IR Enable: 0x%02x " , sr - > data [ 0 ] ) ;
g_IR [ g_ID ] = ( sr - > data [ 0 ] & 0x04 ) ? 1 : 0 ;
2009-01-07 02:59:19 +00:00
break ;
2009-02-08 12:27:04 +00:00
2009-01-07 02:59:19 +00:00
default :
2009-11-24 05:03:47 +00:00
PanicAlert ( " HidOutputReport: Unknown channel 0x%02x " , sr - > wm ) ;
2009-01-07 02:59:19 +00:00
return ;
}
2009-11-24 05:03:47 +00:00
// Send general feedback except the following types
// as these ones generate their own feedbacks
2009-12-06 18:26:20 +00:00
// or don't send feedbacks
if ( ( sr - > wm ! = WM_RUMBLE )
& & ( sr - > wm ! = WM_READ_DATA )
2009-11-24 05:03:47 +00:00
& & ( sr - > wm ! = WM_REQUEST_STATUS )
& & ( sr - > wm ! = WM_WRITE_SPEAKER_DATA )
)
{
WmSendAck ( _channelID , sr - > wm ) ;
}
2008-12-08 05:25:12 +00:00
}
2009-07-05 05:59:03 +00:00
/* Generate the right header for wm reports. The returned values is the length
of the header before the data begins . It ' s always two for all reports 0x20 -
0x22 , 0x30 - 0x37 */
2009-11-24 05:03:47 +00:00
int WriteWmReportHdr ( u8 * dst , u8 wm )
2009-02-01 13:01:50 +00:00
{
2009-02-04 06:40:05 +00:00
// Update the first byte to 0xa1
2009-01-07 02:59:19 +00:00
u32 Offset = 0 ;
2009-11-24 05:03:47 +00:00
hid_packet * pHidHeader = ( hid_packet * ) dst ;
2009-01-07 02:59:19 +00:00
Offset + = sizeof ( hid_packet ) ;
pHidHeader - > type = HID_TYPE_DATA ;
pHidHeader - > param = HID_PARAM_INPUT ;
2009-02-04 06:40:05 +00:00
// Update the second byte to the current report type 0x20 - 0x22, 0x30 - 0x37
2009-01-07 02:59:19 +00:00
wm_report * pReport = ( wm_report * ) ( dst + Offset ) ;
Offset + = sizeof ( wm_report ) ;
2009-11-24 05:03:47 +00:00
pReport - > wm = wm ;
2009-01-07 02:59:19 +00:00
return Offset ;
}
2008-12-08 05:25:12 +00:00
2009-11-24 05:03:47 +00:00
/* This will generate the 0x22 acknowledgement for most Input reports.
It has the form of " a1 22 00 00 _reportID 00 " .
The first two bytes are the core buttons data ,
00 00 means nothing is pressed .
The last byte is the success code 00. */
void WmSendAck ( u16 _channelID , u8 _reportID )
2008-12-08 05:25:12 +00:00
{
2009-01-07 02:59:19 +00:00
u8 DataFrame [ 1024 ] ;
2009-11-24 05:03:47 +00:00
// Write DataFrame header
u32 Offset = WriteWmReportHdr ( DataFrame , WM_ACK_DATA ) ;
2009-01-07 02:59:19 +00:00
wm_acknowledge * pData = ( wm_acknowledge * ) ( DataFrame + Offset ) ;
2009-12-23 07:56:55 +00:00
# if defined(HAVE_WX) && HAVE_WX
2009-12-05 20:01:48 +00:00
FillReportInfo ( pData - > buttons ) ;
2009-12-23 07:56:55 +00:00
# endif
2009-01-07 02:59:19 +00:00
pData - > reportID = _reportID ;
pData - > errorID = 0 ;
Offset + = sizeof ( wm_acknowledge ) ;
2009-11-24 05:03:47 +00:00
DEBUG_LOG ( WIIMOTE , " WMSendAck " ) ;
DEBUG_LOG ( WIIMOTE , " Report ID: %02x " , _reportID ) ;
2008-12-08 05:25:12 +00:00
2009-12-27 19:31:02 +00:00
g_WiimoteInitialize . pWiimoteInput ( g_ID , _channelID , DataFrame , Offset ) ;
2009-02-01 13:01:50 +00:00
// Debugging
2009-11-24 05:03:47 +00:00
//ReadDebugging(true, DataFrame, Offset);
2008-12-08 05:25:12 +00:00
}
2009-01-07 02:59:19 +00:00
/* Read data from Wiimote and Extensions registers. */
void WmReadData ( u16 _channelID , wm_read_data * rd )
2008-12-08 05:25:12 +00:00
{
2009-01-07 02:59:19 +00:00
u32 address = convert24bit ( rd - > address ) ;
u16 size = convert16bit ( rd - > size ) ;
2010-05-07 22:39:06 +00:00
u8 addressHI = ( address > > 16 ) & 0xFE ;
2009-11-24 05:03:47 +00:00
INFO_LOG ( WIIMOTE , " Read data " ) ;
DEBUG_LOG ( WIIMOTE , " Read data Space: %x " , rd - > space ) ;
DEBUG_LOG ( WIIMOTE , " Read data Address: 0x%06x " , address ) ;
DEBUG_LOG ( WIIMOTE , " Read data Size: 0x%04x " , size ) ;
2009-01-07 02:59:19 +00:00
2009-07-05 05:59:03 +00:00
/* Now we determine what address space we are reading from. Space 0 is
2009-11-24 05:03:47 +00:00
Eeprom and space 1 and 2 are the registers . */
2009-02-01 13:01:50 +00:00
if ( rd - > space = = WM_SPACE_EEPROM )
2009-01-07 02:59:19 +00:00
{
if ( address + size > WIIMOTE_EEPROM_SIZE )
{
2009-02-01 13:01:50 +00:00
PanicAlert ( " WmReadData: address + size out of bounds " ) ;
2009-01-07 02:59:19 +00:00
return ;
}
2010-05-07 22:39:06 +00:00
SendReadDataReply ( _channelID , g_Eeprom [ g_ID ] + address , address , addressHI , ( int ) size ) ;
2009-09-15 02:12:55 +00:00
/*DEBUG_LOG(WIIMOTE, "Read RegEeprom: Size: %i, Address: %08x, Offset: %08x",
2009-02-01 13:01:50 +00:00
size , address , ( address & 0xffff ) ) ; */
2009-01-07 02:59:19 +00:00
}
else if ( rd - > space = = WM_SPACE_REGS1 | | rd - > space = = WM_SPACE_REGS2 )
{
u8 * block ;
u32 blockSize ;
2010-05-07 22:39:06 +00:00
switch ( addressHI )
2009-01-07 02:59:19 +00:00
{
case 0xA2 :
2010-01-05 17:39:06 +00:00
block = g_RegSpeaker [ g_ID ] ;
2009-01-07 02:59:19 +00:00
blockSize = WIIMOTE_REG_SPEAKER_SIZE ;
2009-11-24 05:03:47 +00:00
DEBUG_LOG ( WIIMOTE , " Case 0xa2: g_RegSpeaker " ) ;
2009-01-07 02:59:19 +00:00
break ;
2010-01-05 17:39:06 +00:00
2009-01-07 02:59:19 +00:00
case 0xA4 :
2009-12-27 19:31:02 +00:00
block = g_RegExt [ g_ID ] ;
2009-01-07 02:59:19 +00:00
blockSize = WIIMOTE_REG_EXT_SIZE ;
2009-11-24 05:03:47 +00:00
DEBUG_LOG ( WIIMOTE , " Case 0xa4: ExtReg " ) ;
break ;
2009-11-26 05:01:24 +00:00
// MotionPlus is pretty much just a dummy atm :p
2009-11-24 05:03:47 +00:00
case 0xA6 :
2010-01-05 17:39:06 +00:00
block = g_RegMotionPlus [ g_ID ] ;
2009-11-24 05:03:47 +00:00
blockSize = WIIMOTE_REG_EXT_SIZE ;
DEBUG_LOG ( WIIMOTE , " Case 0xa6: MotionPlusReg [%x] " , address ) ;
2009-01-07 02:59:19 +00:00
break ;
2009-11-26 05:01:24 +00:00
2009-01-07 02:59:19 +00:00
case 0xB0 :
2010-01-05 17:39:06 +00:00
block = g_RegIr [ g_ID ] ;
2009-01-07 02:59:19 +00:00
blockSize = WIIMOTE_REG_IR_SIZE ;
2009-11-24 05:03:47 +00:00
DEBUG_LOG ( WIIMOTE , " Case 0xb0: g_RegIr " ) ;
2009-01-07 02:59:19 +00:00
break ;
2009-11-24 05:03:47 +00:00
2009-01-07 02:59:19 +00:00
default :
2009-09-15 02:12:55 +00:00
ERROR_LOG ( WIIMOTE , " WmReadData: bad register block! " ) ;
2010-01-05 17:39:06 +00:00
PanicAlert ( " WmReadData: bad register block! " ) ;
2009-01-07 02:59:19 +00:00
return ;
}
2008-12-08 05:25:12 +00:00
2009-01-07 02:59:19 +00:00
// Encrypt data that is read from the Wiimote Extension Register
2010-05-07 22:39:06 +00:00
if ( addressHI = = 0xa4 )
2009-01-07 02:59:19 +00:00
{
// Check if encrypted reads is on
2009-12-27 19:31:02 +00:00
if ( g_RegExt [ g_ID ] [ 0xf0 ] = = 0xaa )
2009-01-07 02:59:19 +00:00
{
/* Copy the registry to a temporary space. We don't want to change the unencrypted
data in the registry */
2009-12-27 19:31:02 +00:00
memcpy ( g_RegExtTmp , g_RegExt [ g_ID ] , sizeof ( g_RegExt [ 0 ] ) ) ;
2008-12-08 05:25:12 +00:00
2009-01-07 02:59:19 +00:00
// Encrypt g_RegExtTmp at that location
2010-01-02 05:15:36 +00:00
wiimote_encrypt ( & g_ExtKey [ g_ID ] , & g_RegExtTmp [ address & 0xffff ] , ( address & 0xffff ) , ( u8 ) size ) ;
2008-12-08 05:25:12 +00:00
2009-02-04 06:40:05 +00:00
// Update the block that SendReadDataReply will eventually send to the Wii
block = g_RegExtTmp ;
2009-01-07 02:59:19 +00:00
}
}
2008-12-08 05:25:12 +00:00
2009-01-07 02:59:19 +00:00
address & = 0xFFFF ;
2009-11-24 05:03:47 +00:00
if ( address + size > blockSize )
{
2009-09-15 02:12:55 +00:00
PanicAlert ( " WmReadData: address + size out of bounds! [%d %d %d] " , address , size , blockSize ) ;
2009-01-07 02:59:19 +00:00
return ;
}
2010-05-07 22:39:06 +00:00
//3x read error due activated(or not present device, which is not the case), WII will await a status report after init and attempting to read from write-only area @A600FE/FF
if ( ( g_MotionPlusReadError [ g_ID ] = = 2 ) & & ( g_RegExt [ g_ID ] [ 0xFF ] = = 0x05 ) ) { //if motionplus is active, its in the current ExtReg, 0xFF will be always 0x05
WmRequestStatus ( _channelID , ( wm_request_status * ) rd , 1 ) ;
}
2009-01-07 02:59:19 +00:00
// Let this function process the message and send it to the Wii
2010-05-07 22:39:06 +00:00
SendReadDataReply ( _channelID , block + address , address , addressHI , ( u8 ) size ) ;
2009-01-07 02:59:19 +00:00
}
else
{
2009-09-15 02:12:55 +00:00
PanicAlert ( " WmReadData: unimplemented parameters (size: %i, addr: 0x%x)! " , size , rd - > space ) ;
2009-01-07 02:59:19 +00:00
}
2008-12-08 05:25:12 +00:00
}
2009-06-15 21:10:11 +00:00
2009-07-05 05:59:03 +00:00
/* Here we produce the actual 0x21 Input report that we send to the Wii. The
message is divided into 16 bytes pieces and sent piece by piece . There will
be five formatting bytes at the begging of all reports . A common format is
00 00 f0 00 20 , the 00 00 means that no buttons are pressed , the f means 16
bytes in the message , the 0 means no error , the 00 20 means that the message
is at the 00 20 offest in the registry that was read .
2009-02-04 06:40:05 +00:00
2009-11-24 05:03:47 +00:00
_Base : The data beginning at _Base [ 0 ]
_Address : The starting address inside the registry , this is used to check for out of bounds reading
_Size : The total size to send
*/
2010-05-07 22:39:06 +00:00
void SendReadDataReply ( u16 _channelID , void * _Base , u16 _Address , u8 _AddressHI , int _Size )
2009-02-04 06:40:05 +00:00
{
int dataOffset = 0 ;
const u8 * data = ( const u8 * ) _Base ;
while ( _Size > 0 )
{
u8 DataFrame [ 1024 ] ;
// Write the first two bytes to DataFrame
2009-11-24 05:03:47 +00:00
u32 Offset = WriteWmReportHdr ( DataFrame , WM_READ_DATA_REPLY ) ;
2009-02-04 06:40:05 +00:00
// Limit the size to 16 bytes
2009-11-24 05:03:47 +00:00
int copySize = ( _Size > 16 ) ? 16 : _Size ;
// AyuanX: the MTU is 640B though... what a waste!
2009-02-04 06:40:05 +00:00
wm_read_data_reply * pReply = ( wm_read_data_reply * ) ( DataFrame + Offset ) ;
Offset + = sizeof ( wm_read_data_reply ) ;
2009-11-24 05:03:47 +00:00
2009-12-23 07:56:55 +00:00
# if defined(HAVE_WX) && HAVE_WX
2009-12-05 20:01:48 +00:00
FillReportInfo ( pReply - > buttons ) ;
2009-12-23 07:56:55 +00:00
# endif
2009-02-04 06:40:05 +00:00
pReply - > error = 0 ;
2009-02-07 03:16:41 +00:00
// 0x1 means two bytes, 0xf means 16 bytes
2009-11-24 05:03:47 +00:00
pReply - > size = copySize - 1 ;
2009-02-04 06:40:05 +00:00
pReply - > address = Common : : swap16 ( _Address + dataOffset ) ;
2009-11-24 05:03:47 +00:00
// Clear the mem first
memset ( pReply - > data , 0 , 16 ) ;
2009-02-04 06:40:05 +00:00
// Write a pice of _Base to DataFrame
memcpy ( pReply - > data , data + dataOffset , copySize ) ;
// Update DataOffset for the next loop
dataOffset + = copySize ;
2009-07-05 05:59:03 +00:00
/* Out of bounds. The real Wiimote generate an error for the first
request to 0x1770 if we dont ' t replicate that the game will never
read the capibration data at the beginning of Eeprom . I think this
error is supposed to occur when we try to read above the freely
usable space that ends at 0x16ff . */
2009-02-04 06:40:05 +00:00
if ( Common : : swap16 ( pReply - > address + pReply - > size ) > WIIMOTE_EEPROM_FREE_SIZE )
{
pReply - > size = 0x0f ;
pReply - > error = 0x08 ;
}
2010-05-07 22:39:06 +00:00
if ( WiiMapping [ g_ID ] . bMotionPlusConnected )
{
//MP+ will try to read from this Registeraddress, expecting an error if a previous WM+ activation has been succesful
//it also returns an error if there was no WM+ present at all
if ( ( ( _Address = = 0x00FE ) | | ( _Address = = 0x00FF ) ) & & ( _AddressHI = = 0xA6 ) )
{
//Check if MP+ is activated, resp. if its in the current RegExt.
if ( ( g_RegExt [ g_ID ] [ 0xFF ] = = 0x05 ) & & ( g_RegMotionPlus [ g_ID ] [ 0xFF ] ! = 0x05 ) )
{
pReply - > size = 0x0f ;
pReply - > error = 0x07 ; //error: write-only area when activated/or not present
// we use the read error at the same time as an indicator whether we need to send a faked 0x37 report or not
g_MotionPlusReadError [ g_ID ] + + ;
}
}
}
2008-12-08 05:25:12 +00:00
2009-02-04 06:40:05 +00:00
// Logging
2009-11-24 05:03:47 +00:00
DEBUG_LOG ( WIIMOTE , " SendReadDataReply " ) ;
DEBUG_LOG ( WIIMOTE , " Buttons: 0x%04x " , pReply - > buttons ) ;
DEBUG_LOG ( WIIMOTE , " Error: 0x%x " , pReply - > error ) ;
DEBUG_LOG ( WIIMOTE , " Size: 0x%x " , pReply - > size ) ;
DEBUG_LOG ( WIIMOTE , " Address: 0x%04x " , pReply - > address ) ;
# if defined(_DEBUG) || defined(DEBUGFAST)
std : : string Temp = ArrayToString ( DataFrame , Offset ) ;
2009-12-25 22:10:56 +00:00
DEBUG_LOG ( WIIMOTE , " Data: %s " , Temp . c_str ( ) ) ;
2009-11-24 05:03:47 +00:00
# endif
2009-02-04 06:40:05 +00:00
// Send a piece
2009-12-27 19:31:02 +00:00
g_WiimoteInitialize . pWiimoteInput ( g_ID , _channelID , DataFrame , Offset ) ;
2009-11-24 05:03:47 +00:00
2009-02-04 06:40:05 +00:00
// Update the size that is left
_Size - = copySize ;
// Debugging
2009-11-24 05:03:47 +00:00
//ReadDebugging(true, DataFrame, Offset);
2009-03-02 01:49:16 +00:00
}
2009-02-04 06:40:05 +00:00
}
2008-12-08 05:25:12 +00:00
2009-01-07 02:59:19 +00:00
/* Write data to Wiimote and Extensions registers. */
void WmWriteData ( u16 _channelID , wm_write_data * wd )
2008-12-08 05:25:12 +00:00
{
2009-11-24 05:03:47 +00:00
u32 address = convert24bit ( wd - > address ) ;
2010-05-07 22:39:06 +00:00
u8 addressHI = ( address > > 16 ) & 0xFE ;
2009-11-24 05:03:47 +00:00
INFO_LOG ( WIIMOTE , " Write data " ) ;
DEBUG_LOG ( WIIMOTE , " Space: %x " , wd - > space ) ;
DEBUG_LOG ( WIIMOTE , " Address: 0x%06x " , address ) ;
DEBUG_LOG ( WIIMOTE , " Size: 0x%02x " , wd - > size ) ;
2009-01-07 02:59:19 +00:00
// Write to EEPROM
if ( wd - > size < = 16 & & wd - > space = = WM_SPACE_EEPROM )
{
if ( address + wd - > size > WIIMOTE_EEPROM_SIZE ) {
2009-09-15 02:12:55 +00:00
ERROR_LOG ( WIIMOTE , " WmWriteData: address + size out of bounds! " ) ;
2009-01-07 02:59:19 +00:00
PanicAlert ( " WmWriteData: address + size out of bounds! " ) ;
return ;
}
2010-01-05 17:39:06 +00:00
memcpy ( g_Eeprom [ g_ID ] + address , wd - > data , wd - > size ) ;
2009-01-07 02:59:19 +00:00
}
// Write to registers
else if ( wd - > size < = 16 & & ( wd - > space = = WM_SPACE_REGS1 | | wd - > space = = WM_SPACE_REGS2 ) )
2008-12-08 05:25:12 +00:00
{
2009-01-07 02:59:19 +00:00
u8 * block ;
u32 blockSize ;
2010-05-07 22:39:06 +00:00
switch ( addressHI )
2008-12-08 05:25:12 +00:00
{
2009-01-07 02:59:19 +00:00
case 0xA2 :
2010-01-05 17:39:06 +00:00
block = g_RegSpeaker [ g_ID ] ;
2009-01-07 02:59:19 +00:00
blockSize = WIIMOTE_REG_SPEAKER_SIZE ;
2009-11-24 05:03:47 +00:00
DEBUG_LOG ( WIIMOTE , " Case 0xa2: RegSpeaker " ) ;
2008-12-08 05:25:12 +00:00
break ;
2010-01-05 17:39:06 +00:00
2009-01-07 02:59:19 +00:00
case 0xA4 :
2009-12-27 19:31:02 +00:00
block = g_RegExt [ g_ID ] ; // Extension Controller register
2009-01-07 02:59:19 +00:00
blockSize = WIIMOTE_REG_EXT_SIZE ;
2009-11-24 05:03:47 +00:00
DEBUG_LOG ( WIIMOTE , " Case 0xa4: ExtReg " ) ;
break ;
2009-11-26 05:01:24 +00:00
2009-11-24 05:03:47 +00:00
case 0xA6 :
2010-01-05 17:39:06 +00:00
block = g_RegMotionPlus [ g_ID ] ;
2009-11-24 05:03:47 +00:00
blockSize = WIIMOTE_REG_EXT_SIZE ;
DEBUG_LOG ( WIIMOTE , " Case 0xa6: MotionPlusReg [%x] " , address ) ;
2008-12-08 05:25:12 +00:00
break ;
2009-11-26 05:01:24 +00:00
2009-01-07 02:59:19 +00:00
case 0xB0 :
2010-01-05 17:39:06 +00:00
block = g_RegIr [ g_ID ] ;
2009-01-07 02:59:19 +00:00
blockSize = WIIMOTE_REG_IR_SIZE ;
2009-11-24 05:03:47 +00:00
INFO_LOG ( WIIMOTE , " Case 0xb0: RegIr " ) ;
2009-01-07 02:59:19 +00:00
break ;
2009-11-24 05:03:47 +00:00
2009-01-07 02:59:19 +00:00
default :
2009-09-15 02:12:55 +00:00
ERROR_LOG ( WIIMOTE , " WmWriteData: bad register block! " ) ;
2009-01-07 02:59:19 +00:00
PanicAlert ( " WmWriteData: bad register block! " ) ;
return ;
2008-12-08 05:25:12 +00:00
}
2010-01-05 18:07:23 +00:00
address & = 0xFFFF ;
2009-01-07 02:59:19 +00:00
// Check if the address is within bounds
2010-01-05 18:07:23 +00:00
if ( address + wd - > size > blockSize ) {
2009-01-07 02:59:19 +00:00
PanicAlert ( " WmWriteData: address + size out of bounds! " ) ;
return ;
}
2010-05-07 22:39:06 +00:00
2009-01-07 02:59:19 +00:00
// Finally write the registers to the right structure
2010-01-05 18:07:23 +00:00
memcpy ( block + address , wd - > data , wd - > size ) ;
2009-01-07 02:59:19 +00:00
// Generate key for the Wiimote Extension
2010-01-05 18:07:23 +00:00
if ( blockSize = = WIIMOTE_REG_EXT_SIZE )
2008-12-08 05:25:12 +00:00
{
2010-01-05 18:07:23 +00:00
// Run the key generation on all writes in the key area, it doesn't matter
// that we send it parts of a key, only the last full key will have an effect
2009-01-07 02:59:19 +00:00
if ( address > = 0x40 & & address < = 0x4c )
2010-01-02 05:15:36 +00:00
wiimote_gen_key ( & g_ExtKey [ g_ID ] , & g_RegExt [ g_ID ] [ 0x40 ] ) ;
2008-12-08 05:25:12 +00:00
}
2010-05-07 22:39:06 +00:00
if ( WiiMapping [ g_ID ] . bMotionPlusConnected ) {
HandlingMotionPlusWrites ( wd - > data , addressHI , address ) ;
}
2009-11-24 05:03:47 +00:00
}
else
{
2009-01-07 02:59:19 +00:00
PanicAlert ( " WmWriteData: unimplemented parameters! " ) ;
2008-12-08 05:25:12 +00:00
}
2009-01-07 02:59:19 +00:00
/* Just added for home brew... Isn't it enough that we call this from
2009-07-05 05:59:03 +00:00
InterruptChannel ( ) ? Or is there a separate route here that don ' t pass
though InterruptChannel ( ) ? */
2009-01-07 02:59:19 +00:00
}
2009-11-24 05:03:47 +00:00
2009-07-05 05:59:03 +00:00
/* Here we produce a 0x20 status report to send to the Wii. We currently ignore
the status request rs and all its eventual instructions it may include ( for
example turn off rumble or something else ) and just send the status
report . */
2009-02-07 03:16:41 +00:00
void WmRequestStatus ( u16 _channelID , wm_request_status * rs , int Extension )
2009-01-07 02:59:19 +00:00
{
u8 DataFrame [ 1024 ] ;
2009-11-24 05:03:47 +00:00
u32 Offset = WriteWmReportHdr ( DataFrame , WM_STATUS_REPORT ) ;
2009-01-07 02:59:19 +00:00
wm_status_report * pStatus = ( wm_status_report * ) ( DataFrame + Offset ) ;
Offset + = sizeof ( wm_status_report ) ;
2009-12-06 02:33:36 +00:00
memset ( pStatus , 0 , sizeof ( wm_status_report ) ) ; // fill the status report with zeros
2009-01-07 02:59:19 +00:00
// Status values
2009-12-23 07:56:55 +00:00
# if defined(HAVE_WX) && HAVE_WX
2009-12-05 20:01:48 +00:00
FillReportInfo ( pStatus - > buttons ) ;
2009-12-23 07:56:55 +00:00
# endif
2009-12-27 19:31:02 +00:00
pStatus - > leds = g_Leds [ g_ID ] ; // leds are 4 bit
pStatus - > ir = g_IR [ g_ID ] ; // 1 bit
2010-01-05 17:39:06 +00:00
pStatus - > speaker = g_Speaker [ g_ID ] ; // 1 bit
2009-11-24 05:03:47 +00:00
pStatus - > battery_low = 0 ; // battery is okay
pStatus - > battery = 0x5f ; // fully charged
2009-01-07 02:59:19 +00:00
/* Battery levels in voltage
0x00 - 0x32 : level 1
0x33 - 0x43 : level 2
0x33 - 0x54 : level 3
0x55 - 0xff : level 4 */
2009-02-07 03:16:41 +00:00
// Check if we have a specific order about the extension status
if ( Extension = = - 1 )
{
2009-11-24 05:03:47 +00:00
// Read config value for the first time
2010-05-07 22:39:06 +00:00
pStatus - > extension = ( ( g_MotionPlus [ g_ID ] ) | | ( WiiMapping [ g_ID ] . iExtensionConnected ! = EXT_NONE ) ) ? 1 : 0 ;
2009-02-07 03:16:41 +00:00
}
2009-01-07 02:59:19 +00:00
else
2009-02-07 03:16:41 +00:00
{
2009-12-27 19:31:02 +00:00
pStatus - > extension = ( Extension ) ? 1 : 0 ;
2009-02-07 03:16:41 +00:00
}
2009-01-07 02:59:19 +00:00
2009-11-24 05:03:47 +00:00
INFO_LOG ( WIIMOTE , " Request Status " ) ;
2009-12-06 02:33:36 +00:00
DEBUG_LOG ( WIIMOTE , " Buttons: 0x%04x " , pStatus - > buttons ) ;
2010-01-05 17:39:06 +00:00
DEBUG_LOG ( WIIMOTE , " Extension: %x " , pStatus - > extension ) ;
DEBUG_LOG ( WIIMOTE , " Speaker: %x " , pStatus - > speaker ) ;
DEBUG_LOG ( WIIMOTE , " IR: %x " , pStatus - > ir ) ;
DEBUG_LOG ( WIIMOTE , " LEDs: %x " , pStatus - > leds ) ;
2009-01-07 02:59:19 +00:00
2010-05-07 22:39:06 +00:00
2009-12-27 19:31:02 +00:00
g_WiimoteInitialize . pWiimoteInput ( g_ID , _channelID , DataFrame , Offset ) ;
2009-07-05 05:59:03 +00:00
2009-02-01 13:01:50 +00:00
// Debugging
2009-11-24 05:03:47 +00:00
//ReadDebugging(true, DataFrame, Offset);
2008-12-08 05:25:12 +00:00
}
2010-05-07 22:39:06 +00:00
void HandlingMotionPlusWrites ( u8 * data , u8 addressHI , u32 address ) {
switch ( addressHI )
{
case 0xA4 :
switch ( address )
{
case 0x00FE :
if ( data [ 0 ] = = 0x00 ) {
if ( ( g_RegExt [ g_ID ] [ 0xFF ] = = 0x05 ) & & ( g_RegMotionPlus [ g_ID ] [ 0xFF ] ! = 0x05 ) )
{
SwapExtRegisters ( ) ;
DEBUG_LOG ( WIIMOTE , " Writing [0x%02x] to [0x%02x:%04x]: Disabling WM+ and swapping registers back " , data [ 0 ] , addressHI , address ) ;
}
else {
DEBUG_LOG ( WIIMOTE , " Writing [0x%02x] to [0x%02x:%04x]: WM+ already inactive " , data [ 0 ] , addressHI , address ) ;
}
g_MotionPlus [ g_ID ] = 1 ;
}
break ;
case 0x00FB :
//1. Initializing the extension: writing 0x55 ->0xA400F0 and then 0x00 to 0xA400FB.
//2. Disables an active wiimote; ext disconnect.
if ( data [ 0 ] = = 0x00 ) {
//1. connecting extension
if ( ( g_RegExt [ g_ID ] [ 0xFF ] ! = 0x05 ) & & ( g_RegMotionPlus [ g_ID ] [ 0xFF ] = = 0x05 ) )
{
g_RegMotionPlus [ g_ID ] [ 0xFE ] = 0x04 ;
g_RegMotionPlus [ g_ID ] [ 0xF7 ] = 0x08 ; //control init byte, ingame check
SwapExtRegisters ( ) ;
DEBUG_LOG ( WIIMOTE , " Writing [0x%02x] to [0x%02x:%04x]: Enabling WM+ and swapping rgisters " , data [ 0 ] , addressHI , address ) ;
g_MotionPlus [ g_ID ] = 0 ;
} //2. disconnecting extension
else if ( ( g_RegExt [ g_ID ] [ 0xFF ] = = 0x05 ) & & ( g_RegMotionPlus [ g_ID ] [ 0xFF ] ! = 0x05 ) ) {
g_RegExt [ g_ID ] [ 0xFE ] = 0x04 ;
g_MotionPlus [ g_ID ] = 1 ;
DEBUG_LOG ( WIIMOTE , " Writing [0x%02x] to [0x%02x:%04x]: Disabling WM+ and swapping registers back " , data [ 0 ] , addressHI , address ) ;
}
}
break ;
}
break ;
case 0xA6 :
switch ( address )
{
case 0x00FE :
//Enabling WM+, swapping extension registers
if ( data [ 0 ] = = 0x05 ) {
if ( ( g_RegExt [ g_ID ] [ 0xFF ] ! = 0x05 ) & & ( g_RegMotionPlus [ g_ID ] [ 0xFF ] = = 0x05 ) ) {
//The WII will try to read from the readprotected A6 WM+ register now, we need to reply with an error each time,
//plus sent an statusreport 0x20(depending on if nunchuk inserted or not)
g_MotionPlusReadError [ g_ID ] = 0 ;
g_MotionPlus [ g_ID ] = 1 ;
SwapExtRegisters ( ) ;
DEBUG_LOG ( WIIMOTE , " Writing [0x%02x] to [0x%02x:%04x]: Enabling WM+ and swapping rgisters back " , data [ 0 ] , addressHI , address ) ;
}
else {
DEBUG_LOG ( WIIMOTE , " Writing [0x%02x] to [0x%02x:%04x]: WM already enabled no register swapping " , data [ 0 ] , addressHI , address ) ;
}
}
break ;
case 0x00F0 : //init() WM+, this will change some control bits in the WM+ register
if ( data [ 0 ] = = 0x55 ) { //enables passthroug, convert to 0405* A6 swap
if ( ( g_RegMotionPlus [ g_ID ] [ 0xFF ] = = 0x05 ) )
{
//control init byte, ingame check
g_RegMotionPlus [ g_ID ] [ 0xF7 ] = 0x08 ;
//motion plus id
g_RegMotionPlus [ g_ID ] [ 0xFE ] = 0x05 ;
//we will swap the register on write to 0x00FE
}
else if ( g_RegExt [ g_ID ] [ 0xFF ] = = 0x05 ) { //if the wiimote is already active, we will init() the WM+ directly in the ExtReg
g_RegExt [ g_ID ] [ 0xFE ] = 0x05 ;
g_RegExt [ g_ID ] [ 0xF7 ] = 0x08 ;
}
g_MotionPlus [ g_ID ] = 0 ;
}
break ;
default :
DEBUG_LOG ( WIIMOTE , " Writing [0x%02x] to [0x%02x:%04x]: unknown reason " , data [ 0 ] , addressHI , address ) ;
break ;
}
break ;
}
}
//Swapping Ext/WM+-registers
void SwapExtRegisters ( ) {
memset ( g_RegExtTmp , 0 , sizeof ( g_RegExtTmp ) ) ;
memcpy ( g_RegExtTmp , g_RegExt [ g_ID ] , sizeof ( g_RegExt [ 0 ] ) ) ;
memset ( g_RegExt [ 0 ] , 0 , sizeof ( g_RegExt [ 0 ] ) ) ;
memcpy ( g_RegExt [ g_ID ] , g_RegMotionPlus [ g_ID ] , sizeof ( g_RegMotionPlus [ 0 ] ) ) ;
memset ( g_RegMotionPlus [ 0 ] , 0 , sizeof ( g_RegMotionPlus [ 0 ] ) ) ;
memcpy ( g_RegMotionPlus [ g_ID ] , g_RegExtTmp , sizeof ( g_RegExtTmp ) ) ;
if ( g_RegMotionPlus [ g_ID ] [ 0xFC ] ) {
g_RegMotionPlus [ g_ID ] [ 0xFC ] = 0xa6 ;
}
if ( g_RegExt [ g_ID ] [ 0xFC ] ) {
g_RegExt [ g_ID ] [ 0xFC ] = 0xa4 ;
}
}
2009-01-07 02:59:19 +00:00
} // WiiMoteEmu