/[pcsx2_0.9.7]/trunk/pcsx2/Sio.cpp
ViewVC logotype

Annotation of /trunk/pcsx2/Sio.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (10 years, 4 months ago) by william
File size: 21272 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 william 31 /* PCSX2 - PS2 Emulator for PCs
2     * Copyright (C) 2002-2010 PCSX2 Dev Team
3     *
4     * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5     * of the GNU Lesser General Public License as published by the Free Software Found-
6     * ation, either version 3 of the License, or (at your option) any later version.
7     *
8     * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10     * PURPOSE. See the GNU General Public License for more details.
11     *
12     * You should have received a copy of the GNU General Public License along with PCSX2.
13     * If not, see <http://www.gnu.org/licenses/>.
14     */
15    
16     #include "PrecompiledHeader.h"
17     #include "IopCommon.h"
18    
19     #include "Sio.h"
20     #include "sio_internal.h"
21    
22     _sio sio;
23    
24     static const u8 cardh[4] = { 0xFF, 0xFF, 0x5a, 0x5d };
25    
26     // Memory Card Specs for standard Sony 8mb carts:
27     // Flags (magic sio '+' thingie!), Sector size, eraseBlockSize (in pages), card size (in pages), xor checksum (superblock?), terminator (unused?).
28     static const mc_command_0x26_tag mc_sizeinfo_8mb= {'+', 512, 16, 0x4000, 0x52, 0x5A};
29    
30     // Ejection timeout management belongs in the MemoryCardFile plugin, except the plugin
31     // interface is not yet complete.
32     static int m_ForceEjectionTimeout[2];
33    
34     // SIO Inline'd IRQs : Calls the SIO interrupt handlers directly instead of
35     // feeding them through the IOP's branch test. (see SIO.H for details)
36    
37     #ifdef SIO_INLINE_IRQS
38     #define SIO_INT() sioInterrupt()
39 william 62 #define SIO_FORCEINLINE __fi
40 william 31 #else
41 william 62 __fi void SIO_INT()
42 william 31 {
43     if( !(psxRegs.interrupt & (1<<IopEvt_SIO)) )
44     PSX_INT(IopEvt_SIO, 64 ); // PSXCLK/250000);
45     }
46 william 62 #define SIO_FORCEINLINE __fi
47 william 31 #endif
48    
49     // Currently only check if pad wants mtap to be active.
50     // Could lets PCSX2 have its own options, if anyone ever
51     // wants to add support for using the extra memcard slots.
52     static bool IsMtapPresent( uint port )
53     {
54     return EmuConfig.MultitapEnabled( port );
55     //return (0 != PADqueryMtap(port+1));
56     }
57    
58     static void _ReadMcd(u8 *data, u32 adr, int size)
59     {
60     SysPlugins.McdRead(
61     sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
62     data, adr, size
63     );
64     }
65    
66     static void _SaveMcd(const u8 *data, u32 adr, int size)
67     {
68     SysPlugins.McdSave(
69     sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
70     data, adr, size
71     );
72     }
73    
74     static void _EraseMCDBlock(u32 adr)
75     {
76     SysPlugins.McdEraseBlock( sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()], adr );
77     }
78    
79     static u8 sio_xor( const u8 *buf, uint length )
80     {
81     u8 i, x;
82     for (x=0, i=0; i<length; i++) x ^= buf[i];
83     return x;
84     }
85    
86     template< typename T >
87     static void apply_xor( u8& dest, const T& src )
88     {
89     u8* buf = (u8*)&src;
90     for (uint x=0; x<sizeof(src); x++) dest ^= buf[x];
91     }
92    
93     void sioInit()
94     {
95     memzero(sio);
96     memzero(m_ForceEjectionTimeout);
97    
98     // Transfer(?) Ready and the Buffer is Empty
99     sio.StatReg = TX_RDY | TX_EMPTY;
100     sio.packetsize = 0;
101     sio.terminator = 0x55; // Command terminator 'U'
102     }
103    
104     u8 sioRead8() {
105     u8 ret = 0xFF;
106    
107     if (sio.StatReg & RX_RDY) {
108     ret = sio.buf[sio.parp];
109     if (sio.parp == sio.bufcount) {
110     sio.StatReg &= ~RX_RDY; // Receive is not Ready now?
111     sio.StatReg |= TX_EMPTY; // Buffer is Empty
112    
113     if (sio.padst == 2) sio.padst = 0;
114     /*if (sio.mcdst == 1) {
115     sio.mcdst = 99;
116     sio.StatReg&= ~TX_EMPTY;
117     sio.StatReg|= RX_RDY;
118     }*/
119     }
120     }
121     //PAD_LOG("sio read8 ;ret = %x", ret);
122     return ret;
123     }
124    
125     void SIO_CommandWrite(u8 value,int way) {
126     PAD_LOG("sio write8 %x", value);
127    
128     // PAD COMMANDS
129     switch (sio.padst) {
130     case 1: SIO_INT();
131     if ((value&0x40) == 0x40) {
132     sio.padst = 2; sio.parp = 1;
133     switch (sio.CtrlReg&0x2002) {
134     case 0x0002:
135     sio.packetsize ++; // Total packet size sent
136     sio.buf[sio.parp] = PADpoll(value);
137     break;
138     case 0x2002:
139     sio.packetsize ++; // Total packet size sent
140     sio.buf[sio.parp] = PADpoll(value);
141     break;
142     }
143     if (!(sio.buf[sio.parp] & 0x0f)) {
144     sio.bufcount = 2 + 32;
145     } else {
146     sio.bufcount = 2 + (sio.buf[sio.parp] & 0x0f) * 2;
147     }
148     }
149     else sio.padst = 0;
150     return;
151     case 2:
152     sio.parp++;
153     switch (sio.CtrlReg&0x2002) {
154     case 0x0002: sio.packetsize ++; sio.buf[sio.parp] = PADpoll(value); break;
155     case 0x2002: sio.packetsize ++; sio.buf[sio.parp] = PADpoll(value); break;
156     }
157     if (sio.parp == sio.bufcount) { sio.padst = 0; return; }
158     SIO_INT();
159     return;
160     case 3:
161     // No pad connected.
162     sio.parp++;
163     if (sio.parp == sio.bufcount) { sio.padst = 0; return; }
164     SIO_INT();
165     return;
166     }
167    
168     // MEMORY CARD COMMANDS
169     switch (sio.mcdst) {
170     case 1:
171 william 62 {
172 william 31 sio.packetsize++;
173     SIO_INT();
174     if (sio.rdwr) { sio.parp++; return; }
175     sio.parp = 1;
176 william 62
177     const char* log_cmdname = "";
178    
179 william 31 switch (value) {
180     case 0x11: // RESET
181 william 62 log_cmdname = "Reset1";
182 william 31
183     sio.bufcount = 8;
184     memset8<0xff>(sio.buf);
185     sio.buf[3] = sio.terminator;
186     sio.buf[2] = '+';
187     sio.mcdst = 99;
188     sio2.packet.recvVal3 = 0x8c;
189     break;
190 william 62
191     // FIXME : Why are there two identical cases for resetting the
192     // memorycard(s)? there doesn't appear to be anything dealing with
193     // card slots here. --air
194 william 31 case 0x12: // RESET
195 william 62 log_cmdname = "Reset2";
196 william 31 sio.bufcount = 8;
197     memset8<0xff>(sio.buf);
198     sio.buf[3] = sio.terminator;
199     sio.buf[2] = '+';
200     sio.mcdst = 99;
201     sio2.packet.recvVal3 = 0x8c;
202     break;
203 william 62
204 william 31 case 0x81: // COMMIT
205 william 62 log_cmdname = "Commit";
206 william 31 sio.bufcount = 8;
207     memset8<0xff>(sio.buf);
208     sio.mcdst = 99;
209     sio.buf[3] = sio.terminator;
210     sio.buf[2] = '+';
211     sio2.packet.recvVal3 = 0x8c;
212     if(value == 0x81) {
213     if(sio.mc_command==0x42)
214     sio2.packet.recvVal1 = 0x1600; // Writing
215     else if(sio.mc_command==0x43) sio2.packet.recvVal1 = 0x1700; // Reading
216     }
217     break;
218     case 0x21:
219     case 0x22:
220     case 0x23: // SECTOR SET
221 william 62 log_cmdname = "SetSector";
222 william 31 sio.bufcount = 8; sio.mcdst = 99; sio.sector=0; sio.k=0;
223     memset8<0xff>(sio.buf);
224     sio2.packet.recvVal3 = 0x8c;
225     sio.buf[8]=sio.terminator;
226     sio.buf[7]='+';
227     break;
228    
229 william 62 case 0x24: break;
230     case 0x25: break;
231    
232 william 31 case 0x26:
233     {
234 william 62 log_cmdname = "GetInfo";
235    
236 william 31 const uint port = sio.GetMemcardIndex();
237     const uint slot = sio.activeMemcardSlot[port];
238    
239     mc_command_0x26_tag cmd = mc_sizeinfo_8mb;
240     PS2E_McdSizeInfo info;
241    
242     info.SectorSize = cmd.sectorSize;
243     info.EraseBlockSizeInSectors = cmd.eraseBlocks;
244     info.McdSizeInSectors = cmd.mcdSizeInSectors;
245    
246     SysPlugins.McdGetSizeInfo( port, slot, info );
247     pxAssumeDev( cmd.mcdSizeInSectors >= mc_sizeinfo_8mb.mcdSizeInSectors,
248     "Mcd plugin returned an invalid memorycard size: Cards smaller than 8MB are not supported." );
249    
250     cmd.sectorSize = info.SectorSize;
251     cmd.eraseBlocks = info.EraseBlockSizeInSectors;
252     cmd.mcdSizeInSectors = info.McdSizeInSectors;
253    
254     // Recalculate the xor summation
255     // This uses a trick of removing the known xor values for a default 8mb memorycard (for which the XOR
256     // was calculated), and replacing it with our new values.
257    
258     apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.sectorSize );
259     apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.eraseBlocks );
260     apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.mcdSizeInSectors );
261    
262     apply_xor( cmd.mc_xor, cmd.sectorSize );
263     apply_xor( cmd.mc_xor, cmd.eraseBlocks );
264     apply_xor( cmd.mc_xor, cmd.mcdSizeInSectors );
265    
266     sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83;
267     memset8<0xff>(sio.buf);
268     memcpy_fast(&sio.buf[2], &cmd, sizeof(cmd));
269     sio.buf[12]=sio.terminator;
270     }
271     break;
272    
273     case 0x27:
274     case 0x28:
275     case 0xBF:
276 william 62 log_cmdname = "NotSure"; // FIXME !!
277 william 31 sio.bufcount = 4; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8b;
278     memset8<0xff>(sio.buf);
279     sio.buf[4]=sio.terminator;
280     sio.buf[3]='+';
281     break;
282 william 62
283     // FIXME ?
284     // sio.lastsector and sio.mode are unused.
285    
286 william 31 case 0x42: // WRITE
287 william 62 log_cmdname = "Write";
288     //sio.mode = 0;
289     goto __doReadWrite;
290    
291 william 31 case 0x43: // READ
292 william 62 log_cmdname = "Read";
293     //sio.lastsector = sio.sector; // Reading
294     goto __doReadWrite;
295    
296 william 31 case 0x82:
297 william 62 log_cmdname = "Read(?)"; // FIXME !!
298     //if(sio.lastsector==sio.sector) sio.mode = 2;
299 william 31
300 william 62 __doReadWrite:
301 william 31 sio.bufcount =133; sio.mcdst = 99;
302     memset8<0xff>(sio.buf);
303     sio.buf[133]=sio.terminator;
304     sio.buf[132]='+';
305 william 62 break;
306    
307    
308 william 31 case 0xf0:
309     case 0xf1:
310     case 0xf2:
311 william 62 log_cmdname = "NoClue"; // FIXME !!
312 william 31 sio.mcdst = 99;
313     break;
314 william 62
315 william 31 case 0xf3:
316     case 0xf7:
317 william 62 log_cmdname = "NoClueHereEither"; // FIXME !!
318 william 31 sio.bufcount = 4; sio.mcdst = 99;
319     memset8<0xff>(sio.buf);
320     sio.buf[4]=sio.terminator;
321     sio.buf[3]='+';
322     break;
323 william 62
324 william 31 case 0x52:
325 william 62 log_cmdname = "FixMe"; // FIXME !!
326 william 31 sio.rdwr = 1; memset8<0xff>(sio.buf);
327     sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
328     break;
329     case 0x57:
330 william 62 log_cmdname = "FixMe"; // FIXME !!
331 william 31 sio.rdwr = 2; memset8<0xff>(sio.buf);
332     sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
333     break;
334     default:
335 william 62 log_cmdname = "Unknown";
336 william 31 sio.mcdst = 0;
337     memset8<0xff>(sio.buf);
338     sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
339     }
340 william 62 MEMCARDS_LOG("MC(%d) command 0x%02X [%s]", sio.GetMemcardIndex()+1, value, log_cmdname);
341     sio.mc_command = value;
342     }
343     return; // END CASE 1.
344    
345 william 31 // FURTHER PROCESSING OF THE MEMORY CARD COMMANDS
346     case 99:
347 william 62 {
348 william 31 sio.packetsize++;
349     sio.parp++;
350     switch(sio.mc_command)
351     {
352     // SET_ERASE_PAGE; the next erase commands will *clear* data starting with the page set here
353     case 0x21:
354     // SET_WRITE_PAGE; the next write commands will commit data starting with the page set here
355     case 0x22:
356     // SET_READ_PAGE; the next read commands will return data starting with the page set here
357     case 0x23:
358     if (sio.parp==2)sio.sector|=(value & 0xFF)<< 0;
359     if (sio.parp==3)sio.sector|=(value & 0xFF)<< 8;
360     if (sio.parp==4)sio.sector|=(value & 0xFF)<<16;
361     if (sio.parp==5)sio.sector|=(value & 0xFF)<<24;
362     if (sio.parp==6)
363     {
364     if (sio_xor((u8 *)&sio.sector, 4) == value)
365     MEMCARDS_LOG("MC(%d) SET PAGE sio.sector, sector=0x%04X", sio.GetMemcardIndex()+1, sio.sector);
366     else
367     MEMCARDS_LOG("MC(%d) SET PAGE XOR value ERROR 0x%02X != ^0x%02X",
368     sio.GetMemcardIndex()+1, value, sio_xor((u8 *)&sio.sector, 4));
369     }
370     break;
371    
372     // SET_TERMINATOR; reads the new terminator code
373     case 0x27:
374     if(sio.parp==2) {
375     sio.terminator = value;
376     sio.buf[4] = value;
377     MEMCARDS_LOG("MC(%d) SET TERMINATOR command, value=0x%02X", sio.GetMemcardIndex()+1, value);
378    
379     }
380     break;
381    
382     // GET_TERMINATOR; puts in position 3 the current terminator code and in 4 the default one
383     // depending on the param
384     case 0x28:
385     if(sio.parp == 2) {
386     sio.buf[2] = '+';
387     sio.buf[3] = sio.terminator;
388    
389     //if(value == 0) sio.buf[4] = 0xFF;
390     sio.buf[4] = 0x55;
391     MEMCARDS_LOG("MC(%d) GET TERMINATOR command, value=0x%02X", sio.GetMemcardIndex()+1, value);
392     }
393     break;
394     // WRITE DATA
395     case 0x42:
396     if (sio.parp==2) {
397     sio.bufcount=5+value;
398     memset8<0xff>(sio.buf);
399     sio.buf[sio.bufcount-1]='+';
400     sio.buf[sio.bufcount]=sio.terminator;
401     MEMCARDS_LOG("MC(%d) WRITE command, size=0x%02X", sio.GetMemcardIndex()+1, value);
402     }
403     else
404     if ((sio.parp>2) && (sio.parp<sio.bufcount-2)) {
405     sio.buf[sio.parp]=value;
406     //MEMCARDS_LOG("MC(%d) WRITING 0x%02X", sio.GetMemcardIndex()+1, value);
407     } else
408     if (sio.parp==sio.bufcount-2) {
409     if (sio_xor(&sio.buf[3], sio.bufcount-5)==value) {
410     _SaveMcd(&sio.buf[3], (512+16)*sio.sector+sio.k, sio.bufcount-5);
411     sio.buf[sio.bufcount-1]=value;
412     sio.k+=sio.bufcount-5;
413     } else {
414     MEMCARDS_LOG("MC(%d) write XOR value error 0x%02X != ^0x%02X",
415     sio.GetMemcardIndex()+1, value, sio_xor(&sio.buf[3], sio.bufcount-5));
416     }
417     }
418     break;
419     // READ DATA
420     case 0x43:
421     if (sio.parp==2)
422     {
423     //int i;
424     sio.bufcount=value+5;
425     sio.buf[3]='+';
426     MEMCARDS_LOG("MC(%d) READ command, size=0x%02X", sio.GetMemcardIndex()+1, value);
427     _ReadMcd(&sio.buf[4], (512+16)*sio.sector+sio.k, value);
428    
429     /*if(sio.mode==2)
430     {
431     int j;
432     for(j=0; j < value; j++)
433     sio.buf[4+j] = ~sio.buf[4+j];
434     }*/
435    
436     sio.k+=value;
437     sio.buf[sio.bufcount-1]=sio_xor(&sio.buf[4], value);
438     sio.buf[sio.bufcount]=sio.terminator;
439     }
440     break;
441     // INTERNAL ERASE
442     case 0x82:
443     if(sio.parp==2)
444     {
445     sio.buf[2]='+';
446     sio.buf[3]=sio.terminator;
447     //if (sio.k != 0 || (sio.sector & 0xf) != 0)
448     // Console.Warning("saving : odd position for erase.");
449    
450     _EraseMCDBlock((512+16)*(sio.sector&~0xf));
451    
452     /* memset(sio.buf, -1, 256);
453     _SaveMcd(sio.buf, (512+16)*sio.sector, 256);
454     _SaveMcd(sio.buf, (512+16)*sio.sector+256, 256);
455     _SaveMcd(sio.buf, (512+16)*sio.sector+512, 16);
456     sio.buf[2]='+';
457     sio.buf[3]=sio.terminator;*/
458     //sio.buf[sio.bufcount] = sio.terminator;
459     MEMCARDS_LOG("MC(%d) INTERNAL ERASE command 0x%02X", sio.GetMemcardIndex()+1, value);
460     }
461     break;
462     // CARD AUTHENTICATION CHECKS
463     case 0xF0:
464     if (sio.parp==2)
465     {
466     MEMCARDS_LOG("MC(%d) CARD AUTH :0x%02X", sio.GetMemcardIndex()+1, value);
467     switch(value){
468     case 1:
469     case 2:
470     case 4:
471     case 15:
472     case 17:
473     case 19:
474     sio.bufcount=13;
475     memset8<0xff>(sio.buf);
476     sio.buf[12] = 0; // Xor value of data from index 4 to 11
477     sio.buf[3]='+';
478     sio.buf[13] = sio.terminator;
479     break;
480     case 6:
481     case 7:
482     case 11:
483     sio.bufcount=13;
484     memset8<0xff>(sio.buf);
485     sio.buf[12]='+';
486     sio.buf[13] = sio.terminator;
487     break;
488     default:
489     sio.bufcount=4;
490     memset8<0xff>(sio.buf);
491     sio.buf[3]='+';
492     sio.buf[4] = sio.terminator;
493     }
494     }
495     break;
496     }
497     if (sio.bufcount<=sio.parp) sio.mcdst = 0;
498 william 62 }
499     return; // END CASE 99.
500 william 31 }
501    
502     switch (sio.mtapst)
503     {
504     case 0x1:
505     sio.packetsize++;
506     sio.parp = 1;
507     SIO_INT();
508     switch(value) {
509     case 0x12:
510     // Query number of pads supported.
511     sio.buf[3] = 4;
512     sio.mtapst = 2;
513     sio.bufcount = 5;
514     break;
515     case 0x13:
516     // Query number of memcards supported.
517     sio.buf[3] = 4;
518     sio.mtapst = 2;
519     sio.bufcount = 5;
520     break;
521     case 0x21:
522     // Set pad slot.
523     sio.mtapst = value;
524     sio.bufcount = 6; // No idea why this is 6, saved from old code.
525     break;
526     case 0x22:
527     // Set memcard slot.
528     sio.mtapst = value;
529     sio.bufcount = 6; // No idea why this is 6, saved from old code.
530     break;
531     }
532     // Commented out values are from original code. They break multitap in bios.
533     sio.buf[sio.bufcount-1]=0;//'+';
534     sio.buf[sio.bufcount]=0;//'Z';
535     return;
536     case 0x2:
537     sio.packetsize++;
538     sio.parp++;
539     if (sio.bufcount<=sio.parp) sio.mcdst = 0;
540     SIO_INT();
541     return;
542     case 0x21:
543     // Set pad slot.
544     sio.packetsize++;
545     sio.parp++;
546     sio.mtapst = 2;
547     if (sio.CtrlReg & 2)
548     {
549     int port = sio.GetMultitapPort();
550     if (IsMtapPresent(port))
551     sio.activePadSlot[port] = value;
552     }
553     SIO_INT();
554     return;
555     case 0x22:
556     // Set memcard slot.
557     sio.packetsize++;
558     sio.parp++;
559     sio.mtapst = 2;
560     if (sio.CtrlReg & 2)
561     {
562     int port = sio.GetMultitapPort();
563     if (IsMtapPresent(port))
564     sio.activeMemcardSlot[port] = value;
565     }
566     SIO_INT();
567     return;
568     }
569    
570     if(sio.count == 1 || way == 0) InitializeSIO(value);
571     }
572    
573     void InitializeSIO(u8 value)
574     {
575     switch (value) {
576     case 0x01: // start pad
577     sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
578     sio.StatReg |= RX_RDY; // Transfer is Ready
579    
580     sio.bufcount = 4; // Default size, when no pad connected.
581     sio.parp = 0;
582     sio.padst = 1;
583     sio.packetsize = 1;
584     sio.count = 0;
585     sio2.packet.recvVal1 = 0x1100; // Pad is present
586    
587     if( (sio.CtrlReg & 2) == 2 )
588     {
589     int padslot = (sio.CtrlReg>>12) & 2; // move 0x2000 bitmask into leftmost bits
590     if( padslot != 1 )
591     {
592     padslot >>= 1; // transform 0/2 to be 0/1 values
593    
594     if (!PADsetSlot(padslot+1, 1+sio.activePadSlot[padslot]) && sio.activePadSlot[padslot])
595     {
596     // Pad is not present. Don't send poll, just return a bunch of 0's.
597     sio2.packet.recvVal1 = 0x1D100;
598     sio.padst = 3;
599     }
600     else {
601     sio.buf[0] = PADstartPoll(padslot+1);
602     }
603     }
604     }
605    
606     SIO_INT();
607     return;
608    
609     case 0x21: // start mtap
610     sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
611     sio.StatReg |= RX_RDY; // Transfer is Ready
612     sio.parp = 0;
613     sio.packetsize = 1;
614     sio.mtapst = 1;
615     sio.count = 0;
616     sio2.packet.recvVal1 = 0x1D100; // Mtap is not connected :(
617     if (sio.CtrlReg & 2) // No idea if this test is needed. Pads use it, memcards don't.
618     {
619     int port = sio.GetMultitapPort();
620     if (!IsMtapPresent(port))
621     {
622     // If "unplug" multitap mid game, set active slots to 0.
623     sio.activePadSlot[port] = 0;
624     sio.activeMemcardSlot[port] = 0;
625     }
626     else
627     {
628     sio.bufcount = 3;
629     sio.buf[0] = 0xFF;
630     sio.buf[1] = 0x80; // Have no idea if this is correct. From PSX mtap.
631     sio.buf[2] = 0x5A;
632     sio2.packet.recvVal1 = 0x1100; // Mtap is connected :)
633     }
634     }
635     SIO_INT();
636     return;
637    
638     case 0x61: // start remote control sensor
639     sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
640     sio.StatReg |= RX_RDY; // Transfer is Ready
641     sio.parp = 0;
642     sio.packetsize = 1;
643     sio.count = 0;
644     sio2.packet.recvVal1 = 0x1100; // Pad is present
645     SIO_INT();
646     return;
647    
648     case 0x81: // start memcard
649     {
650     sio.StatReg &= ~TX_EMPTY;
651     sio.StatReg |= RX_RDY;
652     memcpy(sio.buf, cardh, 4);
653     sio.parp = 0;
654     sio.bufcount = 8;
655     sio.mcdst = 1;
656     sio.packetsize = 1;
657     sio.rdwr = 0;
658     sio.count = 0;
659    
660     // Memcard presence reporting!
661     // Note:
662     // 0x01100 means Memcard is present
663     // 0x1D100 means Memcard is missing.
664    
665     const uint port = sio.GetMemcardIndex();
666     const uint slot = sio.activeMemcardSlot[port];
667    
668     // forced ejection logic. Technically belongs in the McdIsPresent handler for
669     // the plugin, once the memorycard plugin system is completed.
670     // (ejection is only supported for the default non-multitap cards at this time)
671    
672     bool forceEject = false;
673     if( slot == 0 && m_ForceEjectionTimeout[port] )
674     {
675     --m_ForceEjectionTimeout[port];
676     forceEject = true;
677     }
678    
679     if( !forceEject && SysPlugins.McdIsPresent( port, slot ) )
680     {
681     sio2.packet.recvVal1 = 0x1100;
682     PAD_LOG("START MEMCARD [port:%d, slot:%d] - Present", port, slot );
683     }
684     else
685     {
686     sio2.packet.recvVal1 = 0x1D100;
687     PAD_LOG("START MEMCARD [port:%d, slot:%d] - Missing", port, slot );
688     }
689    
690     SIO_INT();
691     }
692     return;
693     }
694     }
695    
696     void sioWrite8(u8 value)
697     {
698     SIO_CommandWrite(value,0);
699     }
700    
701     void SIODMAWrite(u8 value)
702     {
703     SIO_CommandWrite(value,1);
704     }
705    
706     void sioWriteCtrl16(u16 value) {
707     sio.CtrlReg = value & ~RESET_ERR;
708     if (value & RESET_ERR) sio.StatReg &= ~IRQ;
709     if ((sio.CtrlReg & SIO_RESET) || (!sio.CtrlReg))
710     {
711     sio.mtapst = 0; sio.padst = 0; sio.mcdst = 0; sio.parp = 0;
712     sio.StatReg = TX_RDY | TX_EMPTY;
713     psxRegs.interrupt &= ~(1<<IopEvt_SIO);
714     }
715     }
716    
717     void SIO_FORCEINLINE sioInterrupt() {
718     PAD_LOG("Sio Interrupt");
719     sio.StatReg|= IRQ;
720     psxHu32(0x1070)|=0x80;
721     }
722    
723     void SaveStateBase::sioFreeze()
724     {
725     // CRCs for memory cards.
726     u64 m_mcdCRCs[2][8];
727    
728     FreezeTag( "sio" );
729     Freeze( sio );
730    
731     // TODO : This stuff should all be moved to the memorycard plugin eventually,
732     // but that requires adding memorycard plugin to the savestate, and I'm not in
733     // the mood to do that (let's plan it for 0.9.8) --air
734    
735     // Note: The Ejection system only works for the default non-multitap MemoryCards
736     // only. This is because it could become very (very!) slow to do a full CRC check
737     // on multiple 32 or 64 meg carts. I have chosen to save
738    
739     if( IsSaving() )
740     {
741     for( uint port=0; port<2; ++port )
742     //for( uint slot=0; slot<4; ++slot )
743     {
744     const uint slot = 0; // see above comment about multitap slowness
745     m_mcdCRCs[port][slot] = SysPlugins.McdGetCRC( port, slot );
746     }
747     }
748    
749     Freeze( m_mcdCRCs );
750    
751     if( IsLoading() && EmuConfig.McdEnableEjection )
752     {
753     // Notes on the ForceEjectionTimeout:
754     // * TOTA works with values as low as 20 here.
755     // It "times out" with values around 1800 (forces user to check the memcard
756     // twice to find it). Other games could be different. :|
757     //
758     // * At 64: Disgaea 1 and 2, and Grandia 2 end up displaying a quick "no memcard!"
759     // notice before finding the memorycard and re-enumerating it. A very minor
760     // annoyance, but no breakages.
761    
762     // * GuitarHero will break completely with almost any value here, by design, because
763     // it has a "rule" that the memcard should never be ejected during a song. So by
764     // ejecting it, the game freezes (which is actually good emulation, but annoying!)
765    
766     for( uint port=0; port<2; ++port )
767     //for( int slot=0; slot<4; ++slot )
768     {
769     const uint slot = 0; // see above comment about multitap slowness
770     u64 newCRC = SysPlugins.McdGetCRC( port, slot );
771     if( newCRC != m_mcdCRCs[port][slot] )
772     {
773     //m_mcdCRCs[port][slot] = newCRC;
774     m_ForceEjectionTimeout[port] = 128;
775     }
776     }
777     }
778     }
779    

  ViewVC Help
Powered by ViewVC 1.1.22