Take care of a few more compiler warnings.
[dolphin.git] / Source / Plugins / Plugin_WiimoteNew / Src / WiimoteEmu / EmuSubroutines.cpp
blob4e2737fded43b2a92a39f506e546341f44a9897d
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()
22 0x10 - 0x14: General
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() */
32 #include <vector>
33 #include <string>
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];
52 namespace WiimoteEmu
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.");
73 // Validation check
74 switch (dr->mode)
76 case WM_REPORT_CORE :
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 :
81 break;
82 default:
83 PanicAlert("Wiimote: Unsupported reporting mode 0x%x", dr->mode);
84 break;
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.
93 The call browser:
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);
105 switch (sr->wm)
107 case WM_RUMBLE : // 0x10
108 m_rumble->controls[0]->control_ref->State( sr->data[0] > 0 );
109 return; // no ack
110 break;
112 case WM_LEDS : // 0x11
113 //INFO_LOG(WIIMOTE, "Set LEDs: 0x%02x", sr->data[0]);
114 m_status.leds = sr->data[0] >> 4;
115 break;
117 case WM_REPORT_MODE : // 0x12
118 ReportMode(_channelID, (wm_report_mode*)sr->data);
119 break;
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;
124 break;
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;
129 break;
131 case WM_REQUEST_STATUS : // 0x15
132 RequestStatus(_channelID, (wm_request_status*)sr->data);
133 return; // sends its own ack
134 break;
136 case WM_WRITE_DATA : // 0x16
137 WriteData(_channelID, (wm_write_data*)sr->data);
138 break;
140 case WM_READ_DATA : // 0x17
141 ReadData(_channelID, (wm_read_data*)sr->data);
142 return; // sends its own ack
143 break;
145 case WM_WRITE_SPEAKER_DATA : // 0x18
146 // TODO: Does this need an ack?
147 return; // no ack
148 break;
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;
153 break;
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;
161 break;
163 default:
164 PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr->wm);
165 return; // no ack
166 break;
169 // send ack
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)
180 u8 data[6];
182 data[0] = 0xA1;
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;
189 ack->errorID = 0;
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
197 report. */
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;
207 else
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;
218 // set up report
219 u8 data[8];
220 data[0] = 0xA1;
221 data[1] = WM_STATUS_REPORT;
223 // status values
224 *(wm_status_report*)(data + 2) = m_status;
226 // send report
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);
237 if (wd->size > 16)
239 PanicAlert("WriteData: size is > 16 bytes");
240 return;
243 switch (wd->space)
245 case WM_SPACE_EEPROM :
247 static bool first = true;
248 if (first)
250 PanicAlert("WriteData: first write to EEPROM");
251 first = false;
253 // 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!");
258 return;
260 memcpy(m_eeprom + address, wd->data, wd->size);
262 break;
263 case WM_SPACE_REGS1 :
264 case WM_SPACE_REGS2 :
266 // Write to Control Register
268 // ignore the 0x010000 bit
269 address &= 0xFEFFFF;
271 // ignore second byte for extension area
272 if (0xA4 == (address >> 16))
273 address &= 0xFF00FF;
275 // write to the register
276 m_register.Write(address, wd->data, wd->size);
278 switch (address >> 16)
280 // extension register
281 case 0xa4 :
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 );
293 break;
297 break;
298 default:
299 PanicAlert("WriteData: unimplemented parameters!");
300 break;
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);
310 switch (rd->space)
312 case WM_SPACE_EEPROM :
314 //PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size);
315 // Read from EEPROM
316 if (address + size > WIIMOTE_EEPROM_FREE_SIZE)
318 if (address + size > WIIMOTE_EEPROM_SIZE)
320 PanicAlert("ReadData: address + size out of bounds");
321 return;
323 // generate a read error
324 size = 0;
326 SendReadDataReply(_channelID, m_eeprom + address, address, size);
328 break;
329 case WM_SPACE_REGS1 :
330 case WM_SPACE_REGS2 :
332 // Read from Control Register
334 // ignore the 0x010000 bit
335 address &= 0xFEFFFF;
337 // ignore second byte for extension area
338 if (0xA4 == (address >> 16))
339 address &= 0xFF00FF;
341 u8* const block = new u8[ size ];
342 m_register.Read( address, block, size );
344 switch (address >> 16)
346 case 0xa4 :
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);
356 break;
357 case 0xa6 :
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;
365 break;
368 // Let this function process the message and send it to the Wii
369 SendReadDataReply(_channelID, block, address, (int)size);
371 delete[] block;
373 break;
374 default :
375 PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x)!", size, rd->space);
376 break;
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)
393 u8 data[23];
394 data[0] = 0xA1;
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;
398 reply->error = 0;
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.
405 if (0 == _Size)
407 reply->size = 0x0f;
408 reply->error = 0x08;
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));
415 while (_Size)
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));
428 // copy piece of mem
429 memcpy(reply->data, _Base, amt);
431 // Send a piece
432 m_wiimote_init->pWiimoteInput(m_index, _channelID, data, sizeof(data));
434 // advance pointers
435 _Size -= amt;
436 _Base = (u8*)_Base + amt;
437 _Address += amt;