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() */
35 #include "Common.h" // Common
36 #include "pluginspecs_wiimote.h"
38 #include "WiimoteEmu.h"
39 #include "Attachment/Attachment.h"
41 /* Bit shift conversions */
42 u32
convert24bit(const u8
* src
)
44 return (src
[0] << 16) | (src
[1] << 8) | src
[2];
47 u16
convert16bit(const u8
* src
)
49 return (src
[0] << 8) | src
[1];
55 void Wiimote::ReportMode(u16 _channelID
, wm_report_mode
* 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 // should I use the rumble var in here?
64 //m_rumble->controls[0]->control_ref->State( dr->rumble );
66 m_reporting_auto
= dr
->all_the_time
;
67 m_reporting_mode
= dr
->mode
;
68 m_reporting_channel
= _channelID
;
70 if (0 == dr
->all_the_time
)
71 PanicAlert("Wiimote: Reporting Always is set to OFF! Everything should be fine, but games never do this.");
77 case WM_REPORT_CORE_ACCEL
:
78 case WM_REPORT_CORE_ACCEL_IR12
:
79 case WM_REPORT_CORE_ACCEL_EXT16
:
80 case WM_REPORT_CORE_ACCEL_IR10_EXT6
:
83 PanicAlert("Wiimote: Unsupported reporting mode 0x%x", dr
->mode
);
88 /* Here we process the Output Reports that the Wii sends. Our response will be
89 an Input Report back to the Wii. Input and Output is from the Wii's
90 perspective, Output means data to the Wiimote (from the Wii), Input means
91 data from the Wiimote.
95 1. Wiimote_InterruptChannel > InterruptChannel > HidOutputReport
96 2. Wiimote_ControlChannel > ControlChannel > HidOutputReport
98 The IR enable/disable and speaker enable/disable and mute/unmute values are
99 bit2: 0 = Disable (0x02), 1 = Enable (0x06)
101 void Wiimote::HidOutputReport(u16 _channelID
, wm_report
* sr
)
103 INFO_LOG(WIIMOTE
, "HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index
, _channelID
, sr
->wm
);
107 case WM_RUMBLE
: // 0x10
108 m_rumble
->controls
[0]->control_ref
->State( sr
->data
[0] > 0 );
112 case WM_LEDS
: // 0x11
113 //INFO_LOG(WIIMOTE, "Set LEDs: 0x%02x", sr->data[0]);
114 m_status
.leds
= sr
->data
[0] >> 4;
117 case WM_REPORT_MODE
: // 0x12
118 ReportMode(_channelID
, (wm_report_mode
*)sr
->data
);
121 case WM_IR_PIXEL_CLOCK
: // 0x13
122 //INFO_LOG(WIIMOTE, "WM IR Clock: 0x%02x", sr->data[0]);
123 //m_ir_clock = (sr->data[0] & 0x04) ? 1 : 0;
126 case WM_SPEAKER_ENABLE
: // 0x14
127 //INFO_LOG(WIIMOTE, "WM Speaker Enable: 0x%02x", sr->data[0]);
128 m_status
.speaker
= (sr
->data
[0] & 0x04) ? 1 : 0;
131 case WM_REQUEST_STATUS
: // 0x15
132 RequestStatus(_channelID
, (wm_request_status
*)sr
->data
);
133 return; // sends its own ack
136 case WM_WRITE_DATA
: // 0x16
137 WriteData(_channelID
, (wm_write_data
*)sr
->data
);
140 case WM_READ_DATA
: // 0x17
141 ReadData(_channelID
, (wm_read_data
*)sr
->data
);
142 return; // sends its own ack
145 case WM_WRITE_SPEAKER_DATA
: // 0x18
146 // TODO: Does this need an ack?
150 case WM_SPEAKER_MUTE
: // 0x19
151 //INFO_LOG(WIIMOTE, "WM Speaker Mute: 0x%02x", sr->data[0]);
152 //m_speaker_mute = (sr->data[0] & 0x04) ? 1 : 0;
155 case WM_IR_LOGIC
: // 0x1a
156 // comment from old plugin:
157 // This enables or disables the IR lights, we update the global variable g_IR
158 // so that WmRequestStatus() knows about it
159 //INFO_LOG(WIIMOTE, "WM IR Enable: 0x%02x", sr->data[0]);
160 m_status
.ir
= (sr
->data
[0] & 0x04) ? 1 : 0;
164 PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr
->wm
);
170 SendAck(_channelID
, sr
->wm
);
173 /* This will generate the 0x22 acknowledgement for most Input reports.
174 It has the form of "a1 22 00 00 _reportID 00".
175 The first two bytes are the core buttons data,
176 00 00 means nothing is pressed.
177 The last byte is the success code 00. */
178 void Wiimote::SendAck(u16 _channelID
, u8 _reportID
)
183 data
[1] = WM_ACK_DATA
;
185 wm_acknowledge
* const ack
= (wm_acknowledge
*)(data
+ 2);
187 ack
->buttons
= m_status
.buttons
;
188 ack
->reportID
= _reportID
;
191 m_wiimote_init
->pWiimoteInput( m_index
, _channelID
, data
, sizeof(data
));
194 /* Here we produce a 0x20 status report to send to the Wii. We currently ignore
195 the status request rs and all its eventual instructions it may include (for
196 example turn off rumble or something else) and just send the status
198 void Wiimote::RequestStatus(u16 _channelID
, wm_request_status
* rs
, int _Extension
)
200 // handle switch extension
201 if ( m_extension
->active_extension
!= m_extension
->switch_extension
)
203 // if an extension is currently connected and we want to switch to a different extension
204 if ( (m_extension
->active_extension
> 0) && m_extension
->switch_extension
)
205 // detach extension first, wait til next Update() or RequestStatus() call to change to the new extension
206 m_extension
->active_extension
= 0;
208 // set the wanted extension
209 m_extension
->active_extension
= m_extension
->switch_extension
;
211 // update status struct
212 m_status
.extension
= m_extension
->active_extension
? 1 : 0;
214 // set register, I hate this line
215 m_register
[ 0xa40000 ] = ((WiimoteEmu::Attachment
*)m_extension
->attachments
[ m_extension
->active_extension
])->reg
;
221 data
[1] = WM_STATUS_REPORT
;
224 *(wm_status_report
*)(data
+ 2) = m_status
;
227 m_wiimote_init
->pWiimoteInput(m_index
, _channelID
, data
, sizeof(data
));
230 /* Write data to Wiimote and Extensions registers. */
231 void Wiimote::WriteData(u16 _channelID
, wm_write_data
* wd
)
233 u32 address
= convert24bit(wd
->address
);
234 // this is done in ReadDate, but not here in WriteData ?
235 //u16 size = convert16bit(rd->size);
239 PanicAlert("WriteData: size is > 16 bytes");
245 case WM_SPACE_EEPROM
:
247 static bool first
= true;
250 PanicAlert("WriteData: first write to EEPROM");
254 if (address
+ wd
->size
> WIIMOTE_EEPROM_SIZE
)
256 ERROR_LOG(WIIMOTE
, "WriteData: address + size out of bounds!");
257 PanicAlert("WriteData: address + size out of bounds!");
260 memcpy(m_eeprom
+ address
, wd
->data
, wd
->size
);
263 case WM_SPACE_REGS1
:
264 case WM_SPACE_REGS2
:
266 // Write to Control Register
268 // ignore the 0x010000 bit
271 // ignore second byte for extension area
272 if (0xA4 == (address
>> 16))
275 // write to the register
276 m_register
.Write(address
, wd
->data
, wd
->size
);
278 switch (address
>> 16)
280 // extension register
283 // Run the key generation on all writes in the key area, it doesn't matter
284 // that we send it parts of a key, only the last full key will have an effect
285 // I might have f'ed this up
286 if ( address
>= 0xa40040 && address
<= 0xa4004c )
288 u8 data
[WIIMOTE_REG_EXT_SIZE
];
289 m_register
.Read( 0xa40000, data
, WIIMOTE_REG_EXT_SIZE
);
290 wiimote_gen_key( &m_ext_key
, data
+ 0x40 );
299 PanicAlert("WriteData: unimplemented parameters!");
304 /* Read data from Wiimote and Extensions registers. */
305 void Wiimote::ReadData(u16 _channelID
, wm_read_data
* rd
)
307 u32 address
= convert24bit(rd
->address
);
308 u16 size
= convert16bit(rd
->size
);
312 case WM_SPACE_EEPROM
:
314 //PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size);
316 if (address
+ size
> WIIMOTE_EEPROM_FREE_SIZE
)
318 if (address
+ size
> WIIMOTE_EEPROM_SIZE
)
320 PanicAlert("ReadData: address + size out of bounds");
323 // generate a read error
326 SendReadDataReply(_channelID
, m_eeprom
+ address
, address
, size
);
329 case WM_SPACE_REGS1
:
330 case WM_SPACE_REGS2
:
332 // Read from Control Register
334 // ignore the 0x010000 bit
337 // ignore second byte for extension area
338 if (0xA4 == (address
>> 16))
341 u8
* const block
= new u8
[ size
];
342 m_register
.Read( address
, block
, size
);
344 switch (address
>> 16)
348 // Encrypt data read from extension register
349 // Check if encrypted reads is on
350 if ( m_reg_ext
[0xf0] == 0xaa )
352 // I probably totally f'ed this up
353 wiimote_encrypt(&m_ext_key
, block
, address
& 0xffff, (u8
)size
);
359 // motion plus crap copied from old wiimote plugin
360 //block[0xFC] = 0xA6;
361 //block[0xFD] = 0x20;
362 //block[0xFE] = 0x00;
363 //block[0xFF] = 0x05;
368 // Let this function process the message and send it to the Wii
369 SendReadDataReply(_channelID
, block
, address
, (int)size
);
375 PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x)!", size
, rd
->space
);
380 /* Here we produce the actual 0x21 Input report that we send to the Wii. The
381 message is divided into 16 bytes pieces and sent piece by piece. There will
382 be five formatting bytes at the begging of all reports. A common format is
383 00 00 f0 00 20, the 00 00 means that no buttons are pressed, the f means 16
384 bytes in the message, the 0 means no error, the 00 20 means that the message
385 is at the 00 20 offest in the registry that was read.
387 _Base: The data beginning at _Base[0]
388 _Address: The starting address inside the registry, this is used to check for out of bounds reading
389 _Size: The total size to send
391 void Wiimote::SendReadDataReply(u16 _channelID
, const void* _Base
, unsigned int _Address
, unsigned int _Size
)
395 data
[1] = WM_READ_DATA_REPLY
;
396 wm_read_data_reply
* const reply
= (wm_read_data_reply
*)(data
+ 2);
397 reply
->buttons
= m_status
.buttons
;
400 // Out of bounds. The real Wiimote generate an error for the first
401 // request to 0x1770 if we dont't replicate that the game will never
402 // read the calibration data at the beginning of Eeprom. I think this
403 // error is supposed to occur when we try to read above the freely
404 // usable space that ends at 0x16ff.
409 reply
->address
= Common::swap16(_Address
);
411 memset(reply
->data
, 0, sizeof(reply
->data
));
412 m_wiimote_init
->pWiimoteInput(m_index
, _channelID
, data
, sizeof(data
));
417 // Limit the amt to 16 bytes
418 // AyuanX: the MTU is 640B though... what a waste!
419 const int amt
= std::min( (unsigned int)16, _Size
);
421 // 0x1 means two bytes, 0xf means 16 bytes
422 reply
->size
= amt
- 1;
423 reply
->address
= Common::swap16(_Address
);
425 // Clear the mem first
426 memset(reply
->data
, 0, sizeof(reply
->data
));
429 memcpy(reply
->data
, _Base
, amt
);
432 m_wiimote_init
->pWiimoteInput(m_index
, _channelID
, data
, sizeof(data
));
436 _Base
= (u8
*)_Base
+ amt
;