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
->data
[0] & 0x01) != 0;
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;
111 case WM_REPORT_MODE
: // 0x12
112 ReportMode((wm_report_mode
*)sr
->data
);
115 case WM_IR_PIXEL_CLOCK
: // 0x13
116 //INFO_LOG(WIIMOTE, "WM IR Clock: 0x%02x", sr->data[0]);
117 //m_ir_clock = (sr->data[0] & 0x04) ? 1 : 0;
119 if (0 == (sr
->data
[0] & 0x02)) // only ack if 0x02 bit is set
123 case WM_SPEAKER_ENABLE
: // 0x14
124 //INFO_LOG(WIIMOTE, "WM Speaker Enable: 0x%02x", sr->data[0]);
125 //PanicAlert( "WM Speaker Enable: %d", sr->data[0] );
126 m_status
.speaker
= (sr
->data
[0] & 0x04) ? 1 : 0;
128 if (0 == (sr
->data
[0] & 0x02)) // only ack if 0x02 bit is set
132 case WM_REQUEST_STATUS
: // 0x15
133 RequestStatus((wm_request_status
*)sr
->data
);
134 return; // sends its own ack
137 case WM_WRITE_DATA
: // 0x16
138 WriteData((wm_write_data
*)sr
->data
);
141 case WM_READ_DATA
: // 0x17
142 ReadData((wm_read_data
*)sr
->data
);
143 return; // sends its own ack
146 case WM_WRITE_SPEAKER_DATA
: // 0x18
147 #ifdef USE_WIIMOTE_EMU_SPEAKER
148 SpeakerData((wm_speaker_data
*)sr
->data
);
150 // TODO: Does this need an ack?
154 case WM_SPEAKER_MUTE
: // 0x19
155 //INFO_LOG(WIIMOTE, "WM Speaker Mute: 0x%02x", sr->data[0]);
156 //PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 );
157 #ifdef USE_WIIMOTE_EMU_SPEAKER
159 if (sr
->data
[0] & 0x04)
160 memset(&m_channel_status
, 0, sizeof(m_channel_status
));
162 m_speaker_mute
= (sr
->data
[0] & 0x04) ? 1 : 0;
164 if (0 == (sr
->data
[0] & 0x02)) // only ack if 0x02 bit is set
168 case WM_IR_LOGIC
: // 0x1a
169 // comment from old plugin:
170 // This enables or disables the IR lights, we update the global variable g_IR
171 // so that WmRequestStatus() knows about it
172 //INFO_LOG(WIIMOTE, "WM IR Enable: 0x%02x", sr->data[0]);
173 m_status
.ir
= (sr
->data
[0] & 0x04) ? 1 : 0;
175 if (0 == (sr
->data
[0] & 0x02)) // only ack if 0x02 bit is set
180 PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr
->wm
);
190 /* This will generate the 0x22 acknowledgement for most Input reports.
191 It has the form of "a1 22 00 00 _reportID 00".
192 The first two bytes are the core buttons data,
193 00 00 means nothing is pressed.
194 The last byte is the success code 00. */
195 void Wiimote::SendAck(u8 _reportID
)
200 data
[1] = WM_ACK_DATA
;
202 wm_acknowledge
* const ack
= (wm_acknowledge
*)(data
+ 2);
204 ack
->buttons
= m_status
.buttons
;
205 ack
->reportID
= _reportID
;
208 g_WiimoteInitialize
.pWiimoteInterruptChannel( m_index
, m_reporting_channel
, data
, sizeof(data
));
211 void Wiimote::HandleExtensionSwap()
213 // handle switch extension
214 if (m_extension
->active_extension
!= m_extension
->switch_extension
)
216 // if an extension is currently connected and we want to switch to a different extension
217 if ((m_extension
->active_extension
> 0) && m_extension
->switch_extension
)
218 // detach extension first, wait til next Update() or RequestStatus() call to change to the new extension
219 m_extension
->active_extension
= 0;
221 // set the wanted extension
222 m_extension
->active_extension
= m_extension
->switch_extension
;
224 // update status struct
225 m_status
.extension
= m_extension
->active_extension
? 1 : 0;
227 // set register, I hate this line
228 m_register
[0xa40000] = ((WiimoteEmu::Attachment
*)m_extension
->attachments
[m_extension
->active_extension
])->reg
;
233 /* Here we produce a 0x20 status report to send to the Wii. We currently ignore
234 the status request rs and all its eventual instructions it may include (for
235 example turn off rumble or something else) and just send the status
237 void Wiimote::RequestStatus(const wm_request_status
* const rs
)
239 HandleExtensionSwap();
244 data
[1] = WM_STATUS_REPORT
;
247 *(wm_status_report
*)(data
+ 2) = m_status
;
249 // hybrid wiimote stuff
250 if (WIIMOTE_SRC_HYBRID
== g_wiimote_sources
[m_index
] && (m_extension
->switch_extension
<= 0))
252 using namespace WiimoteReal
;
254 g_refresh_critsec
.Enter();
255 if (g_wiimotes
[m_index
])
257 wm_request_status rpt
;
259 g_wiimotes
[m_index
]->SendPacket(WM_REQUEST_STATUS
, &rpt
, sizeof(rpt
));
261 g_refresh_critsec
.Leave();
267 g_WiimoteInitialize
.pWiimoteInterruptChannel(m_index
, m_reporting_channel
, data
, sizeof(data
));
270 /* Write data to Wiimote and Extensions registers. */
271 void Wiimote::WriteData(const wm_write_data
* const wd
)
273 u32 address
= swap24(wd
->address
);
275 // ignore the 0x010000 bit
280 PanicAlert("WriteData: size is > 16 bytes");
286 case WM_SPACE_EEPROM
:
290 if (address
+ wd
->size
> WIIMOTE_EEPROM_SIZE
)
292 ERROR_LOG(WIIMOTE
, "WriteData: address + size out of bounds!");
293 PanicAlert("WriteData: address + size out of bounds!");
296 memcpy(m_eeprom
+ address
, wd
->data
, wd
->size
);
298 // write mii data to file
299 // i need to improve this greatly
300 if (address
>= 0x0FCA && address
< 0x12C0)
302 // writing the whole mii block each write :/
304 file
.open( (std::string(File::GetUserPath(D_WIIUSER_IDX
)) + "mii.bin").c_str(), std::ios::binary
| std::ios::out
);
305 file
.write((char*)m_eeprom
+ 0x0FCA, 0x02f0);
310 case WM_SPACE_REGS1
:
311 case WM_SPACE_REGS2
:
313 // Write to Control Register
315 // ignore second byte for extension area
316 if (0xA4 == (address
>> 16))
319 // write to the register
320 m_register
.Write(address
, wd
->data
, wd
->size
);
322 switch (address
>> 16)
326 //PanicAlert("Write to speaker!!");
328 // extension register
331 // Run the key generation on all writes in the key area, it doesn't matter
332 // that we send it parts of a key, only the last full key will have an effect
333 // I might have f'ed this up
334 if ( address
>= 0xa40040 && address
<= 0xa4004c )
335 wiimote_gen_key(&m_ext_key
, m_reg_ext
->encryption_key
);
336 //else if ( address >= 0xa40020 && address < 0xa40040 )
337 // PanicAlert("Writing to extension calibration data! Extension may misbehave");
342 if (5 == m_reg_ir
->mode
)
343 PanicAlert("IR Full Mode is Unsupported!");
350 PanicAlert("WriteData: unimplemented parameters!");
355 /* Read data from Wiimote and Extensions registers. */
356 void Wiimote::ReadData(const wm_read_data
* const rd
)
358 u32 address
= swap24(rd
->address
);
359 u16 size
= Common::swap16(rd
->size
);
361 // ignore the 0x010000 bit
364 // hybrid wiimote stuff
365 // relay the read data request to real-wiimote
366 if (WIIMOTE_SRC_HYBRID
== g_wiimote_sources
[m_index
] && ((0xA4 != (address
>> 16)) || (m_extension
->switch_extension
<= 0)))
368 WiimoteReal::InterruptChannel(m_index
, m_reporting_channel
, ((u8
*)rd
) - 2, sizeof(wm_read_data
) + 2); // hacky
370 // don't want emu-wiimote to send reply
375 u8
* block
= new u8
[size
];
379 case WM_SPACE_EEPROM
:
381 //PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size);
383 if (address
+ size
>= WIIMOTE_EEPROM_FREE_SIZE
)
385 if (address
+ size
> WIIMOTE_EEPROM_SIZE
)
387 PanicAlert("ReadData: address + size out of bounds");
390 // generate a read error
394 // read mii data from file
395 // i need to improve this greatly
396 if (address
>= 0x0FCA && address
< 0x12C0)
398 // reading the whole mii block :/
400 file
.open( (std::string(File::GetUserPath(D_WIIUSER_IDX
)) + "mii.bin").c_str(), std::ios::binary
| std::ios::in
);
401 file
.read((char*)m_eeprom
+ 0x0FCA, 0x02f0);
405 // read mem to be sent to wii
406 memcpy( block
, m_eeprom
+ address
, size
);
409 case WM_SPACE_REGS1
:
410 case WM_SPACE_REGS2
:
412 // Read from Control Register
414 // ignore second byte for extension area
415 if (0xA4 == (address
>> 16))
418 // read block to send to wii
419 m_register
.Read( address
, block
, size
);
421 switch (address
>> 16)
425 //PanicAlert("read from speaker!!");
430 // Encrypt data read from extension register
431 // Check if encrypted reads is on
432 if (0xaa == m_reg_ext
->encryption
)
433 wiimote_encrypt(&m_ext_key
, block
, address
& 0xffff, (u8
)size
);
435 //if ( address >= 0xa40008 && address < 0xa40020 )
436 // PanicAlert("Reading extension data from register");
442 // motion plus crap copied from old wiimote plugin
443 //block[0xFC] = 0xA6;
444 //block[0xFD] = 0x20;
445 //block[0xFE] = 0x00;
446 //block[0xFF] = 0x05;
453 PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x)!", size
, rd
->space
);
457 // want the requested address, not the above modified one
458 rr
.address
= swap24(rd
->address
);
460 //rr.channel = _channelID;
464 // send up to 16 bytes
465 SendReadDataReply(rr
);
467 // if there is more data to be sent, add it to the queue
469 m_read_requests
.push( rr
);
475 /* Here we produce the actual 0x21 Input report that we send to the Wii. The
476 message is divided into 16 bytes pieces and sent piece by piece. There will
477 be five formatting bytes at the begging of all reports. A common format is
478 00 00 f0 00 20, the 00 00 means that no buttons are pressed, the f means 16
479 bytes in the message, the 0 means no error, the 00 20 means that the message
480 is at the 00 20 offest in the registry that was read.
482 void Wiimote::SendReadDataReply(ReadRequest
& _request
)
486 data
[1] = WM_READ_DATA_REPLY
;
488 wm_read_data_reply
* const reply
= (wm_read_data_reply
*)(data
+ 2);
489 reply
->buttons
= m_status
.buttons
;
490 reply
->address
= Common::swap16(_request
.address
);
492 // generate a read error
493 // Out of bounds. The real Wiimote generate an error for the first
494 // request to 0x1770 if we dont't replicate that the game will never
495 // read the calibration data at the beginning of Eeprom. I think this
496 // error is supposed to occur when we try to read above the freely
497 // usable space that ends at 0x16ff.
498 if (0 == _request
.size
)
503 memset(reply
->data
, 0, sizeof(reply
->data
));
507 // Limit the amt to 16 bytes
508 // AyuanX: the MTU is 640B though... what a waste!
509 const int amt
= std::min( (unsigned int)16, _request
.size
);
514 // 0x1 means two bytes, 0xf means 16 bytes
515 reply
->size
= amt
- 1;
517 // Clear the mem first
518 memset(reply
->data
, 0, sizeof(reply
->data
));
521 memcpy(reply
->data
, _request
.data
+ _request
.position
, amt
);
523 // update request struct
524 _request
.size
-= amt
;
525 _request
.position
+= amt
;
526 _request
.address
+= amt
;
530 g_WiimoteInitialize
.pWiimoteInterruptChannel(m_index
, m_reporting_channel
, data
, sizeof(data
));
533 void Wiimote::DoState(PointerWrap
& p
)
536 //if (p.MODE_READ == p.GetMode())
539 // Reset(); // should cause a status report to be sent, then wii should re-setup wiimote
541 //p.Do(m_reporting_channel);