1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
19 /* HID reports access guide. */
21 /* 0x10 - 0x1a Output EmuMain.cpp: HidOutputReport()
23 0x15: Status report request from the Wii
24 0x16 and 0x17: Write and read memory or registers
25 0x19 and 0x1a: General
26 0x20 - 0x22 Input EmuMain.cpp: HidOutputReport() to the destination
27 0x15 leads to a 0x20 Input report
28 0x17 leads to a 0x21 Input report
29 0x10 - 0x1a leads to a 0x22 Input report
30 0x30 - 0x3f Input This file: Update() */
36 #include "Common.h" // Common
38 #include "pluginspecs_wiimote.h"
40 #include "WiimoteEmu.h"
41 #include "WiimoteHid.h"
42 #include "../WiimoteReal/WiimoteReal.h"
44 #include "Attachment/Attachment.h"
46 /* Bit shift conversions */
47 u32
swap24(const u8
* src
)
49 return (src
[0] << 16) | (src
[1] << 8) | src
[2];
55 void Wiimote::ReportMode(const wm_report_mode
* const dr
)
57 //INFO_LOG(WIIMOTE, "Set data report mode");
58 //DEBUG_LOG(WIIMOTE, " Rumble: %x", dr->rumble);
59 //DEBUG_LOG(WIIMOTE, " Continuous: %x", dr->continuous);
60 //DEBUG_LOG(WIIMOTE, " All The Time: %x", dr->all_the_time);
61 //DEBUG_LOG(WIIMOTE, " Mode: 0x%02x", dr->mode);
63 //m_reporting_auto = dr->all_the_time;
64 m_reporting_auto
= dr
->continuous
; // this right?
65 m_reporting_mode
= dr
->mode
;
66 //m_reporting_channel = _channelID; // this is set in every Interrupt/Control Channel now
69 //memset(m_reg_ir, 0, sizeof(*m_reg_ir)); //ugly hack
72 PanicAlert("Wiimote: Unsupported Reporting mode.");
73 else if (dr
->mode
< WM_REPORT_CORE
)
74 PanicAlert("Wiimote: Reporting mode < 0x30.");
77 /* Here we process the Output Reports that the Wii sends. Our response will be
78 an Input Report back to the Wii. Input and Output is from the Wii's
79 perspective, Output means data to the Wiimote (from the Wii), Input means
80 data from the Wiimote.
84 1. Wiimote_InterruptChannel > InterruptChannel > HidOutputReport
85 2. Wiimote_ControlChannel > ControlChannel > HidOutputReport
87 The IR enable/disable and speaker enable/disable and mute/unmute values are
88 bit2: 0 = Disable (0x02), 1 = Enable (0x06)
90 void Wiimote::HidOutputReport(const wm_report
* const sr
, const bool send_ack
)
92 INFO_LOG(WIIMOTE
, "HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index
, m_reporting_channel
, sr
->wm
);
95 // In every single Output Report, bit 0 (0x01) of the first byte controls the Rumble feature.
96 m_rumble_on
= sr
->rumble
;
100 case WM_RUMBLE
: // 0x10
101 // this is handled above
105 case WM_LEDS
: // 0x11
106 //INFO_LOG(WIIMOTE, "Set LEDs: 0x%02x", sr->data[0]);
107 m_status
.leds
= sr
->data
[0] >> 4;
110 case WM_REPORT_MODE
: // 0x12
111 ReportMode((wm_report_mode
*)sr
->data
);
114 case WM_IR_PIXEL_CLOCK
: // 0x13
115 //INFO_LOG(WIIMOTE, "WM IR Clock: 0x%02x", sr->data[0]);
116 //m_ir_clock = sr->enable;
117 if (false == sr
->ack
)
121 case WM_SPEAKER_ENABLE
: // 0x14
122 //INFO_LOG(WIIMOTE, "WM Speaker Enable: 0x%02x", sr->data[0]);
123 //PanicAlert( "WM Speaker Enable: %d", sr->data[0] );
124 m_status
.speaker
= sr
->enable
;
125 if (false == sr
->ack
)
129 case WM_REQUEST_STATUS
: // 0x15
130 RequestStatus((wm_request_status
*)sr
->data
);
131 return; // sends its own ack
134 case WM_WRITE_DATA
: // 0x16
135 WriteData((wm_write_data
*)sr
->data
);
138 case WM_READ_DATA
: // 0x17
139 ReadData((wm_read_data
*)sr
->data
);
140 return; // sends its own ack
143 case WM_WRITE_SPEAKER_DATA
: // 0x18
144 #ifdef USE_WIIMOTE_EMU_SPEAKER
145 SpeakerData((wm_speaker_data
*)sr
->data
);
147 // TODO: Does this need an ack?
151 case WM_SPEAKER_MUTE
: // 0x19
152 //INFO_LOG(WIIMOTE, "WM Speaker Mute: 0x%02x", sr->data[0]);
153 //PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 );
154 #ifdef USE_WIIMOTE_EMU_SPEAKER
156 if (sr
->data
[0] & 0x04)
157 memset(&m_channel_status
, 0, sizeof(m_channel_status
));
159 m_speaker_mute
= sr
->enable
;
160 if (false == sr
->ack
)
164 case WM_IR_LOGIC
: // 0x1a
165 // comment from old plugin:
166 // This enables or disables the IR lights, we update the global variable g_IR
167 // so that WmRequestStatus() knows about it
168 //INFO_LOG(WIIMOTE, "WM IR Enable: 0x%02x", sr->data[0]);
169 m_status
.ir
= sr
->enable
;
170 if (false == sr
->ack
)
175 PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr
->wm
);
185 /* This will generate the 0x22 acknowledgement for most Input reports.
186 It has the form of "a1 22 00 00 _reportID 00".
187 The first two bytes are the core buttons data,
188 00 00 means nothing is pressed.
189 The last byte is the success code 00. */
190 void Wiimote::SendAck(u8 _reportID
)
195 data
[1] = WM_ACK_DATA
;
197 wm_acknowledge
* const ack
= (wm_acknowledge
*)(data
+ 2);
199 ack
->buttons
= m_status
.buttons
;
200 ack
->reportID
= _reportID
;
203 g_WiimoteInitialize
.pWiimoteInterruptChannel( m_index
, m_reporting_channel
, data
, sizeof(data
));
206 void Wiimote::HandleExtensionSwap()
208 // handle switch extension
209 if (m_extension
->active_extension
!= m_extension
->switch_extension
)
211 // if an extension is currently connected and we want to switch to a different extension
212 if ((m_extension
->active_extension
> 0) && m_extension
->switch_extension
)
213 // detach extension first, wait til next Update() or RequestStatus() call to change to the new extension
214 m_extension
->active_extension
= 0;
216 // set the wanted extension
217 m_extension
->active_extension
= m_extension
->switch_extension
;
219 // update status struct
220 m_status
.extension
= m_extension
->active_extension
? 1 : 0;
222 // set register, I hate this line
223 m_register
[0xa40000] = ((WiimoteEmu::Attachment
*)m_extension
->attachments
[m_extension
->active_extension
])->reg
;
228 /* Here we produce a 0x20 status report to send to the Wii. We currently ignore
229 the status request rs and all its eventual instructions it may include (for
230 example turn off rumble or something else) and just send the status
232 void Wiimote::RequestStatus(const wm_request_status
* const rs
)
234 HandleExtensionSwap();
239 data
[1] = WM_STATUS_REPORT
;
242 *(wm_status_report
*)(data
+ 2) = m_status
;
244 // hybrid wiimote stuff
245 if (WIIMOTE_SRC_HYBRID
== g_wiimote_sources
[m_index
] && (m_extension
->switch_extension
<= 0))
247 using namespace WiimoteReal
;
249 g_refresh_critsec
.Enter();
250 if (g_wiimotes
[m_index
])
252 wm_request_status rpt
;
254 g_wiimotes
[m_index
]->SendPacket(WM_REQUEST_STATUS
, &rpt
, sizeof(rpt
));
256 g_refresh_critsec
.Leave();
262 g_WiimoteInitialize
.pWiimoteInterruptChannel(m_index
, m_reporting_channel
, data
, sizeof(data
));
265 /* Write data to Wiimote and Extensions registers. */
266 void Wiimote::WriteData(const wm_write_data
* const wd
)
268 u32 address
= swap24(wd
->address
);
270 // ignore the 0x010000 bit
275 PanicAlert("WriteData: size is > 16 bytes");
281 case WM_SPACE_EEPROM
:
285 if (address
+ wd
->size
> WIIMOTE_EEPROM_SIZE
)
287 ERROR_LOG(WIIMOTE
, "WriteData: address + size out of bounds!");
288 PanicAlert("WriteData: address + size out of bounds!");
291 memcpy(m_eeprom
+ address
, wd
->data
, wd
->size
);
293 // write mii data to file
294 // i need to improve this greatly
295 if (address
>= 0x0FCA && address
< 0x12C0)
297 // writing the whole mii block each write :/
299 file
.open( (std::string(File::GetUserPath(D_WIIUSER_IDX
)) + "mii.bin").c_str(), std::ios::binary
| std::ios::out
);
300 file
.write((char*)m_eeprom
+ 0x0FCA, 0x02f0);
305 case WM_SPACE_REGS1
:
306 case WM_SPACE_REGS2
:
308 // Write to Control Register
310 // ignore second byte for extension area
311 if (0xA4 == (address
>> 16))
314 // write to the register
315 m_register
.Write(address
, wd
->data
, wd
->size
);
317 switch (address
>> 16)
321 //PanicAlert("Write to speaker!!");
323 // extension register
326 // Run the key generation on all writes in the key area, it doesn't matter
327 // that we send it parts of a key, only the last full key will have an effect
328 // I might have f'ed this up
329 if ( address
>= 0xa40040 && address
<= 0xa4004c )
330 wiimote_gen_key(&m_ext_key
, m_reg_ext
->encryption_key
);
331 //else if ( address >= 0xa40020 && address < 0xa40040 )
332 // PanicAlert("Writing to extension calibration data! Extension may misbehave");
337 if (5 == m_reg_ir
->mode
)
338 PanicAlert("IR Full Mode is Unsupported!");
345 PanicAlert("WriteData: unimplemented parameters!");
350 /* Read data from Wiimote and Extensions registers. */
351 void Wiimote::ReadData(const wm_read_data
* const rd
)
353 u32 address
= swap24(rd
->address
);
354 u16 size
= Common::swap16(rd
->size
);
356 // ignore the 0x010000 bit
359 // hybrid wiimote stuff
360 // relay the read data request to real-wiimote
361 if (WIIMOTE_SRC_HYBRID
== g_wiimote_sources
[m_index
] && ((0xA4 != (address
>> 16)) || (m_extension
->switch_extension
<= 0)))
363 WiimoteReal::InterruptChannel(m_index
, m_reporting_channel
, ((u8
*)rd
) - 2, sizeof(wm_read_data
) + 2); // hacky
365 // don't want emu-wiimote to send reply
370 u8
* block
= new u8
[size
];
374 case WM_SPACE_EEPROM
:
376 //PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size);
378 if (address
+ size
>= WIIMOTE_EEPROM_FREE_SIZE
)
380 if (address
+ size
> WIIMOTE_EEPROM_SIZE
)
382 PanicAlert("ReadData: address + size out of bounds");
385 // generate a read error
389 // read mii data from file
390 // i need to improve this greatly
391 if (address
>= 0x0FCA && address
< 0x12C0)
393 // reading the whole mii block :/
395 file
.open( (std::string(File::GetUserPath(D_WIIUSER_IDX
)) + "mii.bin").c_str(), std::ios::binary
| std::ios::in
);
396 file
.read((char*)m_eeprom
+ 0x0FCA, 0x02f0);
400 // read mem to be sent to wii
401 memcpy( block
, m_eeprom
+ address
, size
);
404 case WM_SPACE_REGS1
:
405 case WM_SPACE_REGS2
:
407 // Read from Control Register
409 // ignore second byte for extension area
410 if (0xA4 == (address
>> 16))
413 // read block to send to wii
414 m_register
.Read( address
, block
, size
);
416 switch (address
>> 16)
420 //PanicAlert("read from speaker!!");
425 // Encrypt data read from extension register
426 // Check if encrypted reads is on
427 if (0xaa == m_reg_ext
->encryption
)
428 wiimote_encrypt(&m_ext_key
, block
, address
& 0xffff, (u8
)size
);
430 //if ( address >= 0xa40008 && address < 0xa40020 )
431 // PanicAlert("Reading extension data from register");
437 // motion plus crap copied from old wiimote plugin
438 //block[0xFC] = 0xA6;
439 //block[0xFD] = 0x20;
440 //block[0xFE] = 0x00;
441 //block[0xFF] = 0x05;
448 PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x)!", size
, rd
->space
);
452 // want the requested address, not the above modified one
453 rr
.address
= swap24(rd
->address
);
455 //rr.channel = _channelID;
459 // send up to 16 bytes
460 SendReadDataReply(rr
);
462 // if there is more data to be sent, add it to the queue
464 m_read_requests
.push( rr
);
470 /* Here we produce the actual 0x21 Input report that we send to the Wii. The
471 message is divided into 16 bytes pieces and sent piece by piece. There will
472 be five formatting bytes at the begging of all reports. A common format is
473 00 00 f0 00 20, the 00 00 means that no buttons are pressed, the f means 16
474 bytes in the message, the 0 means no error, the 00 20 means that the message
475 is at the 00 20 offest in the registry that was read.
477 void Wiimote::SendReadDataReply(ReadRequest
& _request
)
481 data
[1] = WM_READ_DATA_REPLY
;
483 wm_read_data_reply
* const reply
= (wm_read_data_reply
*)(data
+ 2);
484 reply
->buttons
= m_status
.buttons
;
485 reply
->address
= Common::swap16(_request
.address
);
487 // generate a read error
488 // Out of bounds. The real Wiimote generate an error for the first
489 // request to 0x1770 if we dont't replicate that the game will never
490 // read the calibration data at the beginning of Eeprom. I think this
491 // error is supposed to occur when we try to read above the freely
492 // usable space that ends at 0x16ff.
493 if (0 == _request
.size
)
498 memset(reply
->data
, 0, sizeof(reply
->data
));
502 // Limit the amt to 16 bytes
503 // AyuanX: the MTU is 640B though... what a waste!
504 const int amt
= std::min( (unsigned int)16, _request
.size
);
509 // 0x1 means two bytes, 0xf means 16 bytes
510 reply
->size
= amt
- 1;
512 // Clear the mem first
513 memset(reply
->data
, 0, sizeof(reply
->data
));
516 memcpy(reply
->data
, _request
.data
+ _request
.position
, amt
);
518 // update request struct
519 _request
.size
-= amt
;
520 _request
.position
+= amt
;
521 _request
.address
+= amt
;
525 g_WiimoteInitialize
.pWiimoteInterruptChannel(m_index
, m_reporting_channel
, data
, sizeof(data
));
528 void Wiimote::DoState(PointerWrap
& p
)
531 //if (p.MODE_READ == p.GetMode())
534 // Reset(); // should cause a status report to be sent, then wii should re-setup wiimote
536 //p.Do(m_reporting_channel);