1 #include <cassert>
2 #include <cstring>
3 #include <vector>
4 #include "Iop_Sio2.h"
5 #include "../Log.h"
6 #include "../states/RegisterStateFile.h"
7 #include "../states/MemoryStateFile.h"
8 
9 #define LOG_NAME ("iop_sio2")
10 
11 #define STATE_REGS ("sio2/regs")
12 #define STATE_CTRL1 ("sio2/ctrl1")
13 #define STATE_CTRL2 ("sio2/ctrl2")
14 #define STATE_PAD ("sio2/pad")
15 #define STATE_INPUT ("sio2/input")
16 #define STATE_OUTPUT ("sio2/output")
17 
18 #define STATE_REGS_XML ("sio2/regs.xml")
19 #define STATE_REGS_CURRENTREGINDEX ("CurrentRegIndex")
20 
21 using namespace Iop;
22 
23 static const uint8 DUALSHOCK2_MODEL[6] =
24     {
25         0x03, //Model
26         0x02, //Mode Count
27         0x00, //Mode Current Offset
28         0x02, //Actuator Count
29         0x01, //Actuator Comb Count
30         0x00};
31 
32 static const uint8 DUALSHOCK2_ID[5][5] =
33     {
34         {0x00, 0x01, 0x02, 0x00, 0x0A}, //Actuator 0 info
35         {0x00, 0x01, 0x01, 0x01, 0x14}, //Actuator 1 info
36         {0x00, 0x02, 0x00, 0x01, 0x00}, //Actuator Comb 0 info
37         {0x00, 0x00, 0x04, 0x00, 0x00}, //Mode 0 info
38         {0x00, 0x00, 0x07, 0x00, 0x00}  //Mode 1 info
39 };
40 
41 #define ID_DIGITAL 0x41
42 #define ID_ANALOG 0x73
43 #define ID_ANALOGP 0x79
44 #define ID_CONFIG 0xF3
45 
CSio2(Iop::CIntc & intc)46 CSio2::CSio2(Iop::CIntc& intc)
47     : m_intc(intc)
48 {
49 	Reset();
50 }
51 
Reset()52 void CSio2::Reset()
53 {
54 	m_currentRegIndex = 0;
55 	m_outputBuffer.clear();
56 	m_inputBuffer.clear();
57 	memset(m_regs, 0, sizeof(m_regs));
58 	memset(m_ctrl1, 0, sizeof(m_ctrl1));
59 	memset(m_ctrl2, 0, sizeof(m_ctrl2));
60 	memset(&m_padState, 0, sizeof(m_padState));
61 	for(auto& padInfo : m_padState)
62 	{
63 		padInfo.buttonState = 0xFFFF;
64 		padInfo.mode = ID_ANALOG;
65 		padInfo.pollMask[0] = 0xFF;
66 		padInfo.pollMask[1] = 0xFF;
67 		padInfo.pollMask[2] = 0x03;
68 		memset(padInfo.analogStickState, 0x7F, sizeof(padInfo.analogStickState));
69 	}
70 }
71 
LoadState(Framework::CZipArchiveReader & archive)72 void CSio2::LoadState(Framework::CZipArchiveReader& archive)
73 {
74 	static const auto readBuffer =
75 	    [](ByteBufferType& outputBuffer, Framework::CStream& inputStream) {
76 		    outputBuffer.clear();
77 		    while(!inputStream.IsEOF())
78 		    {
79 			    uint8 buffer[256];
80 			    uint32 read = inputStream.Read(buffer, 256);
81 			    outputBuffer.insert(outputBuffer.end(), buffer, buffer + read);
82 		    }
83 	    };
84 
85 	{
86 		CRegisterStateFile registerFile(*archive.BeginReadFile(STATE_REGS_XML));
87 		m_currentRegIndex = registerFile.GetRegister32(STATE_REGS_CURRENTREGINDEX);
88 	}
89 
90 	archive.BeginReadFile(STATE_REGS)->Read(&m_regs, sizeof(m_regs));
91 	archive.BeginReadFile(STATE_CTRL1)->Read(&m_ctrl1, sizeof(m_ctrl1));
92 	archive.BeginReadFile(STATE_CTRL2)->Read(&m_ctrl2, sizeof(m_ctrl2));
93 	archive.BeginReadFile(STATE_PAD)->Read(&m_padState, sizeof(m_padState));
94 
95 	readBuffer(m_outputBuffer, *archive.BeginReadFile(STATE_OUTPUT));
96 	readBuffer(m_inputBuffer, *archive.BeginReadFile(STATE_INPUT));
97 }
98 
SaveState(Framework::CZipArchiveWriter & archive)99 void CSio2::SaveState(Framework::CZipArchiveWriter& archive)
100 {
101 	auto inputBuffer = std::vector<uint8>(m_inputBuffer.begin(), m_inputBuffer.end());
102 	auto outputBuffer = std::vector<uint8>(m_outputBuffer.begin(), m_outputBuffer.end());
103 
104 	{
105 		auto registerFile = new CRegisterStateFile(STATE_REGS_XML);
106 		registerFile->SetRegister32(STATE_REGS_CURRENTREGINDEX, m_currentRegIndex);
107 		archive.InsertFile(registerFile);
108 	}
109 
110 	archive.InsertFile(new CMemoryStateFile(STATE_REGS, &m_regs, sizeof(m_regs)));
111 	archive.InsertFile(new CMemoryStateFile(STATE_CTRL1, &m_ctrl1, sizeof(m_ctrl1)));
112 	archive.InsertFile(new CMemoryStateFile(STATE_CTRL2, &m_ctrl2, sizeof(m_ctrl2)));
113 	archive.InsertFile(new CMemoryStateFile(STATE_PAD, &m_padState, sizeof(m_padState)));
114 	archive.InsertFile(new CMemoryStateFile(STATE_INPUT, inputBuffer.data(), inputBuffer.size()));
115 	archive.InsertFile(new CMemoryStateFile(STATE_OUTPUT, outputBuffer.data(), outputBuffer.size()));
116 }
117 
SetButtonState(unsigned int padNumber,PS2::CControllerInfo::BUTTON button,bool pressed,uint8 * ram)118 void CSio2::SetButtonState(unsigned int padNumber, PS2::CControllerInfo::BUTTON button, bool pressed, uint8* ram)
119 {
120 	assert(padNumber < MAX_PADS);
121 	if(padNumber >= MAX_PADS) return;
122 
123 	auto& padState = m_padState[padNumber];
124 	auto buttonMask = static_cast<uint16>(GetButtonMask(button));
125 	padState.buttonState &= ~buttonMask;
126 	if(!pressed)
127 	{
128 		padState.buttonState |= buttonMask;
129 	}
130 }
131 
SetAxisState(unsigned int padNumber,PS2::CControllerInfo::BUTTON axis,uint8 axisValue,uint8 * ram)132 void CSio2::SetAxisState(unsigned int padNumber, PS2::CControllerInfo::BUTTON axis, uint8 axisValue, uint8* ram)
133 {
134 	assert(padNumber < MAX_PADS);
135 	if(padNumber >= MAX_PADS) return;
136 
137 	assert(axis < 4);
138 	if(axis >= 4) return;
139 
140 	static const unsigned int axisIndex[4] =
141 	    {
142 	        2,
143 	        3,
144 	        0,
145 	        1};
146 
147 	auto& padState = m_padState[padNumber];
148 	padState.analogStickState[axisIndex[axis]] = axisValue;
149 }
150 
ReadRegister(uint32 address)151 uint32 CSio2::ReadRegister(uint32 address)
152 {
153 	uint32 value = 0;
154 	switch(address)
155 	{
156 	case REG_DATA_IN:
157 		value = m_outputBuffer.front();
158 		m_outputBuffer.pop_front();
159 		break;
160 	}
161 #ifdef _DEBUG
162 	DisassembleRead(address, value);
163 #endif
164 	return value;
165 }
166 
WriteRegister(uint32 address,uint32 value)167 void CSio2::WriteRegister(uint32 address, uint32 value)
168 {
169 	if(address >= REG_BASE && address <= REG_BASE_END)
170 	{
171 		m_regs[(address - REG_BASE) / 4] = value;
172 	}
173 	else
174 	{
175 		switch(address)
176 		{
177 		case REG_PORT0_CTRL1:
178 		case REG_PORT1_CTRL1:
179 		case REG_PORT2_CTRL1:
180 		case REG_PORT3_CTRL1:
181 		{
182 			unsigned int portId = (address - REG_PORT0_CTRL1) / 8;
183 			m_ctrl1[portId] = value;
184 		}
185 		break;
186 		case REG_PORT0_CTRL2:
187 		case REG_PORT1_CTRL2:
188 		case REG_PORT2_CTRL2:
189 		case REG_PORT3_CTRL2:
190 		{
191 			unsigned int portId = (address - REG_PORT0_CTRL2) / 8;
192 			m_ctrl2[portId] = value;
193 		}
194 		break;
195 		case REG_CTRL:
196 			if(value == 0x0C)
197 			{
198 				m_currentRegIndex = 0;
199 			}
200 			if(value == 0x01)
201 			{
202 				//Ok, done transferring, generate interrupt.
203 				m_intc.AssertLine(CIntc::LINE_SIO2);
204 			}
205 			break;
206 		case REG_DATA_OUT:
207 			m_inputBuffer.push_back(static_cast<uint8>(value));
208 			ProcessCommand();
209 			break;
210 		}
211 	}
212 #ifdef _DEBUG
213 	DisassembleWrite(address, value);
214 #endif
215 }
216 
ReceiveDmaIn(uint8 * buffer,uint32 blockSize,uint32 blockAmount)217 uint32 CSio2::ReceiveDmaIn(uint8* buffer, uint32 blockSize, uint32 blockAmount)
218 {
219 	assert(m_currentRegIndex == 0);
220 	for(uint32 i = 0; i < blockAmount; i++)
221 	{
222 		m_inputBuffer.insert(std::end(m_inputBuffer), buffer, buffer + blockSize);
223 		buffer += blockSize;
224 		ProcessCommand();
225 	}
226 	assert(m_currentRegIndex == blockAmount);
227 	return blockAmount;
228 }
229 
ReceiveDmaOut(uint8 * buffer,uint32 blockSize,uint32 blockAmount)230 uint32 CSio2::ReceiveDmaOut(uint8* buffer, uint32 blockSize, uint32 blockAmount)
231 {
232 	assert(m_currentRegIndex == blockAmount);
233 	for(uint32 i = 0; i < blockAmount; i++)
234 	{
235 		uint32 currentReg = m_regs[i];
236 		uint32 dstSize = (currentReg >> 18) & 0x1FF;
237 		for(uint32 j = 0; j < dstSize; j++)
238 		{
239 			buffer[j] = m_outputBuffer.front();
240 			m_outputBuffer.pop_front();
241 		}
242 		buffer += blockSize;
243 	}
244 	return blockAmount;
245 }
246 
ProcessCommand()247 void CSio2::ProcessCommand()
248 {
249 	uint32 currentReg = m_regs[m_currentRegIndex];
250 	uint32 srcSize = (currentReg >> 8) & 0x1FF;
251 	uint32 dstSize = (currentReg >> 18) & 0x1FF;
252 	if(m_inputBuffer.size() >= srcSize)
253 	{
254 		unsigned int portId = currentReg & 0x03;
255 		uint32 deviceId = m_ctrl2[portId];
256 		size_t outputOffset = m_outputBuffer.size();
257 
258 		for(unsigned int i = 0; i < dstSize; i++)
259 		{
260 			m_outputBuffer.push_back(0xFF);
261 		}
262 
263 		if(deviceId == 0x00030064)
264 		{
265 			ProcessMultitap(portId, outputOffset, dstSize, srcSize);
266 		}
267 		else if(deviceId == 0x5FFFF)
268 		{
269 			ProcessMemoryCard(portId, outputOffset, dstSize, srcSize);
270 		}
271 		else
272 		{
273 			ProcessController(portId, outputOffset, dstSize, srcSize);
274 		}
275 
276 		assert((m_outputBuffer.size() - outputOffset) == dstSize);
277 
278 		m_inputBuffer.clear();
279 		m_currentRegIndex++;
280 	}
281 }
282 
ProcessController(unsigned int portId,size_t outputOffset,uint32 dstSize,uint32 srcSize)283 void CSio2::ProcessController(unsigned int portId, size_t outputOffset, uint32 dstSize, uint32 srcSize)
284 {
285 	if(portId < MAX_PADS)
286 	{
287 		assert(dstSize >= 3);
288 		assert(srcSize >= 3);
289 
290 		unsigned int padId = portId & 0x01;
291 		auto& padState = m_padState[padId];
292 
293 		//Write header
294 		m_outputBuffer[outputOffset + 0x00] = 0xFF;
295 		m_outputBuffer[outputOffset + 0x01] = padState.configMode ? ID_CONFIG : padState.mode;
296 		m_outputBuffer[outputOffset + 0x02] = 0x5A; //?
297 
298 		uint8 cmd = m_inputBuffer[1];
299 		switch(cmd)
300 		{
301 		case 0x40:
302 			assert(dstSize == 9);
303 			m_outputBuffer[outputOffset + 0x03] = 0x00;
304 			m_outputBuffer[outputOffset + 0x04] = 0x00;
305 			m_outputBuffer[outputOffset + 0x05] = 0x02;
306 			m_outputBuffer[outputOffset + 0x06] = 0x00;
307 			m_outputBuffer[outputOffset + 0x07] = 0x00;
308 			m_outputBuffer[outputOffset + 0x08] = 0x5A;
309 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: SetVrefParam();\r\n", padId);
310 			break;
311 		case 0x41:
312 			assert(dstSize == 9);
313 			if(padState.mode == ID_DIGITAL)
314 			{
315 				m_outputBuffer[outputOffset + 0x03] = 0x00;
316 				m_outputBuffer[outputOffset + 0x04] = 0x00;
317 				m_outputBuffer[outputOffset + 0x05] = 0x00;
318 				m_outputBuffer[outputOffset + 0x06] = 0x00;
319 				m_outputBuffer[outputOffset + 0x07] = 0x00;
320 				m_outputBuffer[outputOffset + 0x08] = 0x00;
321 			}
322 			else
323 			{
324 				m_outputBuffer[outputOffset + 0x03] = padState.pollMask[0];
325 				m_outputBuffer[outputOffset + 0x04] = padState.pollMask[1];
326 				m_outputBuffer[outputOffset + 0x05] = padState.pollMask[2];
327 				m_outputBuffer[outputOffset + 0x06] = 0x00;
328 				m_outputBuffer[outputOffset + 0x07] = 0x00;
329 				m_outputBuffer[outputOffset + 0x08] = 0x5A;
330 			}
331 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: QueryButtonMask();\r\n", padId);
332 			break;
333 		case 0x42: //Read Data
334 			assert(dstSize == 5 || dstSize == 9 || dstSize == 21);
335 			//Pad data goes here
336 			m_outputBuffer[outputOffset + 0x03] = static_cast<uint8>(padState.buttonState >> 8);
337 			m_outputBuffer[outputOffset + 0x04] = static_cast<uint8>(padState.buttonState & 0xFF);
338 			if(dstSize >= 9)
339 			{
340 				//Analog stuff
341 				m_outputBuffer[outputOffset + 0x05] = padState.analogStickState[0];
342 				m_outputBuffer[outputOffset + 0x06] = padState.analogStickState[1];
343 				m_outputBuffer[outputOffset + 0x07] = padState.analogStickState[2];
344 				m_outputBuffer[outputOffset + 0x08] = padState.analogStickState[3];
345 
346 				if(dstSize == 21)
347 				{
348 					//Pressure stuff
349 					m_outputBuffer[outputOffset + 0x09] = ((padState.buttonState & 0x2000) == 0) ? 0xFF : 0x00; //Left
350 					m_outputBuffer[outputOffset + 0x0A] = ((padState.buttonState & 0x8000) == 0) ? 0xFF : 0x00; //Right
351 					m_outputBuffer[outputOffset + 0x0B] = ((padState.buttonState & 0x1000) == 0) ? 0xFF : 0x00; //Up
352 					m_outputBuffer[outputOffset + 0x0C] = ((padState.buttonState & 0x4000) == 0) ? 0xFF : 0x00; //Down
353 
354 					m_outputBuffer[outputOffset + 0x0D] = ((padState.buttonState & 0x0010) == 0) ? 0xFF : 0x00; //Triangle
355 					m_outputBuffer[outputOffset + 0x0E] = ((padState.buttonState & 0x0020) == 0) ? 0xFF : 0x00; //Circle
356 					m_outputBuffer[outputOffset + 0x0F] = ((padState.buttonState & 0x0040) == 0) ? 0xFF : 0x00; //Cross
357 					m_outputBuffer[outputOffset + 0x10] = ((padState.buttonState & 0x0080) == 0) ? 0xFF : 0x00; //Square
358 
359 					m_outputBuffer[outputOffset + 0x11] = ((padState.buttonState & 0x0004) == 0) ? 0xFF : 0x00; //L1
360 					m_outputBuffer[outputOffset + 0x12] = ((padState.buttonState & 0x0008) == 0) ? 0xFF : 0x00; //R1
361 					m_outputBuffer[outputOffset + 0x13] = ((padState.buttonState & 0x0001) == 0) ? 0xFF : 0x00; //L2
362 					m_outputBuffer[outputOffset + 0x14] = ((padState.buttonState & 0x0002) == 0) ? 0xFF : 0x00; //R2
363 				}
364 			}
365 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: ReadData();\r\n", padId);
366 			break;
367 		case 0x43: //Enter Config Mode
368 			padState.configMode = (m_inputBuffer[3] == 0x01);
369 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: EnterConfigMode(config = %d);\r\n", padId, m_inputBuffer[3]);
370 			break;
371 		case 0x44: //Set Mode & Lock
372 		{
373 			assert(dstSize == 5 || dstSize == 9);
374 			uint8 mode = m_inputBuffer[3];
375 			uint8 lock = m_inputBuffer[4];
376 			//cmdBuffer[4] == 0x03 -> Mode Lock
377 			m_outputBuffer[outputOffset + 0x03] = 0x00;
378 			m_outputBuffer[outputOffset + 0x04] = 0x00;
379 			if(dstSize == 9)
380 			{
381 				m_outputBuffer[outputOffset + 0x05] = 0x00;
382 				m_outputBuffer[outputOffset + 0x06] = 0x00;
383 				m_outputBuffer[outputOffset + 0x07] = 0x00;
384 				m_outputBuffer[outputOffset + 0x08] = 0x00;
385 			}
386 			padState.mode = (mode == 0x01) ? ID_ANALOG : ID_DIGITAL;
387 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: SetModeAndLock(mode = %d, lock = %d);\r\n", padId, mode, lock);
388 		}
389 		break;
390 		case 0x45: //Query Model
391 			assert(dstSize == 9);
392 			assert(padState.configMode);
393 			std::copy(std::begin(DUALSHOCK2_MODEL), std::end(DUALSHOCK2_MODEL), m_outputBuffer.begin() + outputOffset + 0x03);
394 			m_outputBuffer[outputOffset + 5] = (padState.mode == ID_DIGITAL) ? 0x00 : 0x01; //0x01 if analog pad
395 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: QueryModel();\r\n", padId);
396 			break;
397 		case 0x46:
398 			assert(dstSize == 9);
399 			assert(padState.configMode);
400 			if(m_inputBuffer[3] == 0x00)
401 			{
402 				std::copy(std::begin(DUALSHOCK2_ID[0]), std::end(DUALSHOCK2_ID[0]), m_outputBuffer.begin() + outputOffset + 0x04);
403 			}
404 			else
405 			{
406 				std::copy(std::begin(DUALSHOCK2_ID[1]), std::end(DUALSHOCK2_ID[1]), m_outputBuffer.begin() + outputOffset + 0x04);
407 			}
408 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: QueryAct(mode = %d);\r\n", padId, m_inputBuffer[3]);
409 			break;
410 		case 0x47:
411 			assert(dstSize == 9);
412 			assert(padState.configMode);
413 			std::copy(std::begin(DUALSHOCK2_ID[2]), std::end(DUALSHOCK2_ID[2]), m_outputBuffer.begin() + outputOffset + 0x04);
414 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: QueryComb();\r\n", padId);
415 			break;
416 		case 0x4C:
417 			assert(dstSize == 9);
418 			assert(padState.configMode);
419 			if(m_inputBuffer[3] == 0x00)
420 			{
421 				std::copy(std::begin(DUALSHOCK2_ID[3]), std::end(DUALSHOCK2_ID[3]), m_outputBuffer.begin() + outputOffset + 0x04);
422 			}
423 			else
424 			{
425 				std::copy(std::begin(DUALSHOCK2_ID[4]), std::end(DUALSHOCK2_ID[4]), m_outputBuffer.begin() + outputOffset + 0x04);
426 			}
427 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: QueryMode(mode = %d);\r\n", padId, m_inputBuffer[3]);
428 			break;
429 		case 0x4D: //SetVibration
430 			assert(dstSize == 9);
431 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: SetVibration();\r\n", padId);
432 			break;
433 		case 0x4F: //SetPollMask
434 			assert(dstSize == 9);
435 			assert(padState.configMode);
436 			padState.mode = ID_ANALOGP;
437 			m_outputBuffer[outputOffset + 0x03] = 0x00;
438 			m_outputBuffer[outputOffset + 0x04] = 0x00;
439 			m_outputBuffer[outputOffset + 0x05] = 0x00;
440 			m_outputBuffer[outputOffset + 0x06] = 0x00;
441 			m_outputBuffer[outputOffset + 0x07] = 0x00;
442 			m_outputBuffer[outputOffset + 0x08] = 0x5A;
443 			padState.pollMask[0] = m_inputBuffer[3];
444 			padState.pollMask[1] = m_inputBuffer[4];
445 			padState.pollMask[2] = m_inputBuffer[5];
446 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: SetPollMask(mask = { 0x%02X, 0x%02X, 0x%02X });\r\n",
447 			                          padId, padState.pollMask[0], padState.pollMask[1], padState.pollMask[2]);
448 			break;
449 		default:
450 			CLog::GetInstance().Print(LOG_NAME, "Pad %d: Unknown command received (0x%02X).\r\n", padId, cmd);
451 			break;
452 		}
453 	}
454 	else
455 	{
456 		CLog::GetInstance().Print(LOG_NAME, "Sending command to unsupported pad (%d).\r\n", portId);
457 	}
458 }
459 
ProcessMultitap(unsigned int portId,size_t outputOffset,uint32 dstSize,uint32 srcSize)460 void CSio2::ProcessMultitap(unsigned int portId, size_t outputOffset, uint32 dstSize, uint32 srcSize)
461 {
462 	uint8 cmd = m_inputBuffer[1];
463 	switch(cmd)
464 	{
465 	case 0x12:
466 	case 0x13:
467 		//GetSlotNumber
468 		m_outputBuffer[outputOffset + 0x03] = 1;
469 		CLog::GetInstance().Print(LOG_NAME, "Multitap: GetSlotNumber();\r\n");
470 		break;
471 	case 0x21:
472 	case 0x22:
473 		//ChangeSlot
474 		m_outputBuffer[outputOffset + 0x05] = 0;
475 		CLog::GetInstance().Print(LOG_NAME, "Multitap: ChangeSlot();\r\n");
476 		break;
477 	}
478 }
479 
ComputeEDC(const std::deque<uint8> & bytes,uint32 offset,uint32 size)480 static uint8 ComputeEDC(const std::deque<uint8>& bytes, uint32 offset, uint32 size)
481 {
482 	uint8 checksum = 0;
483 	for(uint32 i = 0; i < size; i++)
484 	{
485 		checksum ^= bytes.at(offset + i);
486 	}
487 	return static_cast<uint8>(checksum);
488 }
489 
ProcessMemoryCard(unsigned int portId,size_t outputOffset,uint32 dstSize,uint32 srcSize)490 void CSio2::ProcessMemoryCard(unsigned int portId, size_t outputOffset, uint32 dstSize, uint32 srcSize)
491 {
492 	static uint8 g_terminationCode = 0x55;
493 	static uint32 g_currentPage = 0;
494 	static const uint16 pageSize = 0x200;
495 	static const uint16 rawPageSize = 0x210;
496 	uint8 cmd = m_inputBuffer[1];
497 	switch(cmd)
498 	{
499 	case 0x11:
500 		m_outputBuffer[outputOffset + 0x03] = g_terminationCode;
501 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: CardChanged();\r\n");
502 		break;
503 	case 0x12:
504 		//Erase page?
505 		m_outputBuffer[outputOffset + 0x03] = g_terminationCode;
506 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: Cmd_12();\r\n");
507 		break;
508 	case 0x21:
509 		//Erase page?
510 		m_outputBuffer[outputOffset + 0x08] = g_terminationCode;
511 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: Cmd_21();\r\n");
512 		break;
513 	case 0x22:
514 		//Write page?
515 		m_outputBuffer[outputOffset + 0x08] = g_terminationCode;
516 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: Cmd_22();\r\n");
517 		break;
518 	case 0x23:
519 	{
520 		uint32 page = (m_inputBuffer[3] << 8) | m_inputBuffer[2];
521 		g_currentPage = page;
522 	}
523 		m_outputBuffer[outputOffset + 0x08] = g_terminationCode;
524 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: SeekPage();\r\n");
525 		break;
526 	case 0x26:
527 		m_outputBuffer[outputOffset + 0x02] = 0;                                 //flags
528 		m_outputBuffer[outputOffset + 0x03] = static_cast<uint8>(pageSize);      //pageSizeLo
529 		m_outputBuffer[outputOffset + 0x04] = static_cast<uint8>(pageSize >> 8); //pageSizeHi (512 bytes)
530 		m_outputBuffer[outputOffset + 0x05] = 0;                                 //blockSizeLo
531 		m_outputBuffer[outputOffset + 0x06] = 0x20;                              //blockSizeHi
532 		m_outputBuffer[outputOffset + 0x07] = 0;                                 //cardSize0
533 		m_outputBuffer[outputOffset + 0x08] = 0;                                 //cardSize1
534 		m_outputBuffer[outputOffset + 0x09] = 0x80;                              //cardSize2
535 		m_outputBuffer[outputOffset + 0x0A] = 0;                                 //cardSize3
536 		m_outputBuffer[outputOffset + 0x0B] = ComputeEDC(m_outputBuffer, outputOffset + 3, 8);
537 		m_outputBuffer[outputOffset + 0x0C] = g_terminationCode;
538 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: GetCardSpec();\r\n");
539 		break;
540 	case 0x27:
541 		g_terminationCode = m_inputBuffer[2];
542 		m_outputBuffer[outputOffset + 0x04] = g_terminationCode;
543 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: Probe2();\r\n");
544 		break;
545 	case 0x28:
546 		m_outputBuffer[outputOffset + 0x04] = 0x66;
547 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: Probe1();\r\n");
548 		break;
549 	case 0x42:
550 	{
551 		uint8 writeCount = m_inputBuffer[2];
552 		m_outputBuffer[outputOffset + writeCount + 0x05] = g_terminationCode;
553 	}
554 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: WritePage();\r\n");
555 		break;
556 	case 0x43:
557 	{
558 		uint8 readCount = m_inputBuffer[2];
559 		for(uint32 i = 0; i < readCount; i++)
560 		{
561 			m_outputBuffer[outputOffset + 0x04 + i] = 0xCC;
562 		}
563 		g_currentPage += 1;
564 		m_outputBuffer[outputOffset + 0x04 + readCount + 0] = ComputeEDC(m_outputBuffer, outputOffset + 0x04, readCount);
565 		m_outputBuffer[outputOffset + 0x04 + readCount + 1] = g_terminationCode;
566 	}
567 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: ReadPage();\r\n");
568 		break;
569 	case 0x81:
570 		m_outputBuffer[outputOffset + 0x03] = g_terminationCode;
571 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: Cmd_81();\r\n");
572 		break;
573 	case 0x82:
574 		m_outputBuffer[outputOffset + 0x03] = g_terminationCode;
575 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: Cmd_82();\r\n");
576 		break;
577 	case 0xBF:
578 		m_outputBuffer[outputOffset + 0x04] = g_terminationCode;
579 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: Cmd_BF();\r\n");
580 		break;
581 	case 0xF3:
582 		m_outputBuffer[outputOffset + 0x03] = 0x2B;
583 		CLog::GetInstance().Print(LOG_NAME, "MemoryCard: ResetAuth();\r\n");
584 		break;
585 	default:
586 		assert(false);
587 		break;
588 	}
589 }
590 
DisassembleRead(uint32 address,uint32 value)591 void CSio2::DisassembleRead(uint32 address, uint32 value)
592 {
593 	switch(address)
594 	{
595 	case REG_DATA_IN:
596 		CLog::GetInstance().Print(LOG_NAME, "= DATA_IN = 0x%08X\r\n", value);
597 		break;
598 	case REG_CTRL:
599 		CLog::GetInstance().Print(LOG_NAME, "= REG_CTRL = 0x%08X\r\n", value);
600 		break;
601 	default:
602 		CLog::GetInstance().Print(LOG_NAME, "Read an unknown register 0x%08X.\r\n", address);
603 		break;
604 	}
605 }
606 
DisassembleWrite(uint32 address,uint32 value)607 void CSio2::DisassembleWrite(uint32 address, uint32 value)
608 {
609 	switch(address)
610 	{
611 	case REG_PORT0_CTRL1:
612 		CLog::GetInstance().Print(LOG_NAME, "REG_PORT0_CTRL1 = 0x%08X\r\n", value);
613 		break;
614 	case REG_PORT0_CTRL2:
615 		CLog::GetInstance().Print(LOG_NAME, "REG_PORT0_CTRL2 = 0x%08X\r\n", value);
616 		break;
617 	case REG_PORT1_CTRL1:
618 		CLog::GetInstance().Print(LOG_NAME, "REG_PORT1_CTRL1 = 0x%08X\r\n", value);
619 		break;
620 	case REG_PORT1_CTRL2:
621 		CLog::GetInstance().Print(LOG_NAME, "REG_PORT1_CTRL2 = 0x%08X\r\n", value);
622 		break;
623 	case REG_PORT2_CTRL1:
624 		CLog::GetInstance().Print(LOG_NAME, "REG_PORT2_CTRL1 = 0x%08X\r\n", value);
625 		break;
626 	case REG_PORT2_CTRL2:
627 		CLog::GetInstance().Print(LOG_NAME, "REG_PORT2_CTRL2 = 0x%08X\r\n", value);
628 		break;
629 	case REG_PORT3_CTRL1:
630 		CLog::GetInstance().Print(LOG_NAME, "REG_PORT3_CTRL1 = 0x%08X\r\n", value);
631 		break;
632 	case REG_PORT3_CTRL2:
633 		CLog::GetInstance().Print(LOG_NAME, "REG_PORT3_CTRL2 = 0x%08X\r\n", value);
634 		break;
635 	case REG_DATA_OUT:
636 		CLog::GetInstance().Print(LOG_NAME, "DATA_OUT = 0x%08X\r\n", value);
637 		break;
638 	case REG_CTRL:
639 		CLog::GetInstance().Print(LOG_NAME, "CTRL = 0x%08X\r\n", value);
640 		break;
641 	default:
642 		CLog::GetInstance().Print(LOG_NAME, "Write 0x%08X to an unknown register 0x%08X.\r\n", value, address);
643 		break;
644 	}
645 }
646