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

Contents of /trunk/pcsx2/CDVD/CDVD.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 55824 byte(s)
re-commit (had local access denied errors when committing)
1 /* 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 #include "AppConfig.h"
19
20 #include <ctype.h>
21 #include <wx/datetime.h>
22
23 #include "CDVD.h"
24 #include "CDVD_internal.h"
25 #include "CDVDisoReader.h"
26
27 #include "GS.h" // for gsRegionMode
28 #include "Elfheader.h"
29 #include "ps2/BiosTools.h"
30 #include "GameDatabase.h"
31
32 // This typically reflects the Sony-assigned serial code for the Disc, if one exists.
33 // (examples: SLUS-2113, etc).
34 // If the disc is homebrew then it probably won't have a valid serial; in which case
35 // this string will be empty.
36 wxString DiscSerial;
37
38 static cdvdStruct cdvd;
39
40 static __fi void SetResultSize(u8 size)
41 {
42 cdvd.ResultC = size;
43 cdvd.ResultP = 0;
44 cdvd.sDataIn&=~0x40;
45 }
46
47 static void CDVDREAD_INT(int eCycle)
48 {
49 // Give it an arbitary FAST value. Good for ~5000kb/s in ULE when copying a file from CDVD to HDD
50 if (EmuConfig.Speedhacks.fastCDVD) eCycle = 3000;
51 PSX_INT(IopEvt_CdvdRead, eCycle);
52 }
53
54 static void CDVD_INT(int eCycle)
55 {
56 if( eCycle == 0 )
57 cdvdActionInterrupt();
58 else
59 PSX_INT(IopEvt_Cdvd, eCycle);
60 }
61
62 // Sets the cdvd IRQ and the reason for the IRQ, and signals the IOP for a branch
63 // test (which will cause the exception to be handled).
64 static void cdvdSetIrq( uint id = (1<<Irq_CommandComplete) )
65 {
66 cdvd.PwOff |= id;
67 iopIntcIrq( 2 );
68 hwIntcIrq(INTC_SBUS);
69 psxSetNextBranchDelta( 20 );
70 }
71
72 static int mg_BIToffset(u8 *buffer)
73 {
74 int i, ofs = 0x20;
75 for (i=0; i<*(u16*)&buffer[0x1A]; i++)
76 ofs+=0x10;
77
78 if (*(u16*)&buffer[0x18] & 1) ofs += buffer[ofs];
79 if ((*(u16*)&buffer[0x18] & 0xF000) == 0) ofs += 8;
80
81 return ofs + 0x20;
82 }
83
84 FILE *_cdvdOpenMechaVer()
85 {
86 // get the name of the bios file
87
88 wxFileName mecfile(EmuConfig.BiosFilename);
89 mecfile.SetExt( L"mec" );
90 const wxString fname( mecfile.GetFullPath() );
91
92 // if file doesnt exist, create empty one
93 FILE* fd = wxFopen(fname, L"r+b");
94 if (fd == NULL)
95 {
96 Console.Warning("MEC File Not Found, creating substitute...");
97 fd = wxFopen(fname, L"wb");
98 if (fd == NULL)
99 throw Exception::CannotCreateStream(fname);
100
101 fputc(0x03, fd);
102 fputc(0x06, fd);
103 fputc(0x02, fd);
104 fputc(0x00, fd);
105 }
106 return fd;
107 }
108
109 static void cdvdGetMechaVer(u8* ver)
110 {
111 FILE* fd = _cdvdOpenMechaVer();
112 fseek(fd, 0, SEEK_SET);
113 fread(ver, 1, 4, fd);
114 fclose(fd);
115 }
116
117 // Throws Exception::CannotCreateStream if the file cannot be opened for reading, or cannot
118 // be created for some reason.
119 FILE* _cdvdOpenNVM()
120 {
121 wxFileName nvmfile(EmuConfig.BiosFilename);
122 nvmfile.SetExt( L"nvm" );
123 const wxString fname( nvmfile.GetFullPath() );
124
125 // if file doesn't exist, create empty one
126 FILE* fd = wxFopen(fname, L"r+b");
127 if (fd == NULL)
128 {
129 Console.Warning("NVM File Not Found, Creating Blank File");
130 fd = wxFopen(fname, L"wb");
131 if (fd == NULL)
132 throw Exception::CannotCreateStream(fname);
133
134 for (int i=0; i<1024; i++) fputc(0, fd);
135 }
136 return fd;
137 }
138
139 //
140 // the following 'cdvd' functions all return 0 if successful
141 //
142
143 static void cdvdReadNVM(u8 *dst, int offset, int bytes) {
144 FILE* fd = _cdvdOpenNVM();
145
146 fseek(fd, offset, SEEK_SET);
147 fread(dst, 1, bytes, fd);
148 fclose(fd);
149 }
150
151 static void cdvdWriteNVM(const u8 *src, int offset, int bytes) {
152 FILE* fd = _cdvdOpenNVM();
153
154 fseek(fd, offset, SEEK_SET);
155 fwrite(src, 1, bytes, fd);
156 fclose(fd);
157 }
158
159 NVMLayout* getNvmLayout()
160 {
161 NVMLayout* nvmLayout = NULL;
162 s32 nvmIdx;
163
164 for(nvmIdx=0; nvmIdx<NVM_FORMAT_MAX; nvmIdx++)
165 {
166 if(nvmlayouts[nvmIdx].biosVer <= BiosVersion)
167 nvmLayout = &nvmlayouts[nvmIdx];
168 }
169 return nvmLayout;
170 }
171
172 void getNvmData(u8* buffer, s32 offset, s32 size, s32 fmtOffset)
173 {
174 // find the correct bios version
175 NVMLayout* nvmLayout = getNvmLayout();
176
177 // get data from eeprom
178 cdvdReadNVM(buffer, *(s32*)(((u8*)nvmLayout)+fmtOffset) + offset, size);
179 }
180
181 void setNvmData(const u8* buffer, s32 offset, s32 size, s32 fmtOffset)
182 {
183 // find the correct bios version
184 NVMLayout* nvmLayout = getNvmLayout();
185
186 // set data in eeprom
187 cdvdWriteNVM(buffer, *(s32*)(((u8*)nvmLayout)+fmtOffset) + offset, size);
188 }
189
190 static void cdvdReadConsoleID(u8* id)
191 {
192 getNvmData(id, 0, 8, offsetof(NVMLayout, consoleId));
193 }
194 static void cdvdWriteConsoleID(const u8* id)
195 {
196 setNvmData(id, 0, 8, offsetof(NVMLayout, consoleId));
197 }
198
199 static void cdvdReadILinkID(u8* id)
200 {
201 getNvmData(id, 0, 8, offsetof(NVMLayout, ilinkId));
202 }
203 static void cdvdWriteILinkID(const u8* id)
204 {
205 setNvmData(id, 0, 8, offsetof(NVMLayout, ilinkId));
206 }
207
208 static void cdvdReadModelNumber(u8* num, s32 part)
209 {
210 getNvmData(num, part, 8, offsetof(NVMLayout, modelNum));
211 }
212 static void cdvdWriteModelNumber(const u8* num, s32 part)
213 {
214 setNvmData(num, part, 8, offsetof(NVMLayout, modelNum));
215 }
216
217 static void cdvdReadRegionParams(u8* num)
218 {
219 getNvmData(num, 0, 8, offsetof(NVMLayout,regparams));
220 }
221 static void cdvdWriteRegionParams(const u8* num)
222 {
223 setNvmData(num, 0, 8, offsetof(NVMLayout,regparams));
224 }
225
226 static void cdvdReadMAC(u8* num)
227 {
228 getNvmData(num, 0, 8, offsetof(NVMLayout,mac));
229 }
230 static void cdvdWriteMAC(const u8* num)
231 {
232 setNvmData(num, 0, 8, offsetof(NVMLayout,mac));
233 }
234
235 s32 cdvdReadConfig(u8* config)
236 {
237 // make sure its in read mode
238 if(cdvd.CReadWrite != 0)
239 {
240 config[0] = 0x80;
241 memset(&config[1], 0x00, 15);
242 return 1;
243 }
244 // check if block index is in bounds
245 else if(cdvd.CBlockIndex >= cdvd.CNumBlocks)
246 return 1;
247 else if(
248 ((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))||
249 ((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))||
250 ((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7))
251 )
252 {
253 memzero_ptr<16>(config);
254 return 0;
255 }
256
257 // get config data
258 switch (cdvd.COffset)
259 {
260 case 0:
261 getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config0));
262 break;
263 case 2:
264 getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config2));
265 break;
266 default:
267 getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config1));
268 }
269 return 0;
270 }
271 s32 cdvdWriteConfig(const u8* config)
272 {
273 // make sure its in write mode && the block index is in bounds
274 if ((cdvd.CReadWrite != 1) || (cdvd.CBlockIndex >= cdvd.CNumBlocks))
275 return 1;
276 else if(
277 ((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))||
278 ((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))||
279 ((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7))
280 )
281 return 0;
282
283 // get config data
284 switch (cdvd.COffset)
285 {
286 case 0:
287 setNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config0));
288 break;
289 case 2:
290 setNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config2));
291 break;
292 default:
293 setNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config1));
294 }
295 return 0;
296 }
297
298 static MutexRecursive Mutex_NewDiskCB;
299
300 // Sets ElfCRC to the CRC of the game bound to the CDVD plugin.
301 static __fi ElfObject* loadElf( const wxString filename )
302 {
303 if (filename.StartsWith(L"host"))
304 return new ElfObject(filename.After(':'), Path::GetFileSize(filename.After(':')));
305
306 // Mimic PS2 behavior!
307 // Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
308 // the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
309 // filename *and* the ISOFS, when loading the game's ELF image. What this means is:
310 //
311 // 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
312 // 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
313 // or anything else. Its all ignored.
314 // 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
315 // or lower level filesystem APIs (fortunately that doesn't affect us).
316 //
317 // FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
318 // version information when doing file searches. I'll add this later. For now, assuming a ;1 should
319 // be sufficient (no known games have their ELF binary as anything but version ;1)
320
321 const wxString fixedname( wxStringTokenizer(filename, L';').GetNextToken() + L";1" );
322
323 if( fixedname != filename )
324 Console.WriteLn( Color_Blue, "(LoadELF) Non-conforming version suffix detected and replaced." );
325
326 IsoFSCDVD isofs;
327 IsoFile file(isofs, fixedname);
328 return new ElfObject(fixedname, file);
329 }
330
331 static __fi void _reloadElfInfo(wxString elfpath)
332 {
333 ScopedPtr<ElfObject> elfptr;
334
335 // Now's a good time to reload the ELF info...
336 ScopedLock locker( Mutex_NewDiskCB );
337
338 if (elfpath == LastELF) return;
339 LastELF = elfpath;
340
341 wxString fname = elfpath.AfterLast('\\');
342 if (!fname)
343 fname = elfpath.AfterLast('/');
344 if (!fname)
345 fname = elfpath.AfterLast(':');
346 if (fname.Matches(L"????_???.??*"))
347 DiscSerial = fname(0,4) + L"-" + fname(5,3) + fname(9,2);
348
349 elfptr = loadElf(elfpath);
350
351 ElfCRC = elfptr->getCRC();
352 ElfEntry = elfptr->header.e_entry;
353 Console.WriteLn(L"ELF (%s) CRC=0x%08X, EntryPoint=0x%08X", elfpath.c_str(), ElfCRC, ElfEntry);
354
355 // Note: Do not load game database info here. This code is generic and called from
356 // BIOS key encryption as well as eeloadReplaceOSDSYS. The first is actually still executing
357 // BIOS code, and patches and cheats should not be applied yet. (they are applied when
358 // eeGameStarting is invoked, which is when the VM starts executing the actual game ELF
359 // binary).
360 }
361
362 void cdvdReloadElfInfo(wxString elfoverride)
363 {
364 // called from context of executing VM code (recompilers), so we need to trap exceptions
365 // and route them through the VM's exception handler. (needed for non-SEH platforms, such
366 // as Linux/GCC)
367
368 try
369 {
370 if (!elfoverride.IsEmpty())
371 {
372 _reloadElfInfo(elfoverride);
373 return;
374 }
375
376 wxString elfpath;
377 u32 discType = GetPS2ElfName(elfpath);
378
379 if(discType==1)
380 {
381 // Is a PS1 disc.
382 if (!ENABLE_LOADING_PS1_GAMES)
383 Cpu->ThrowException( Exception::RuntimeError()
384 .SetDiagMsg(L"PSX game discs are not supported by PCSX2.")
385 .SetUserMsg(pxE( "!Notice:PsxDisc",
386 L"Playstation game discs are not supported by PCSX2. If you want to emulate PSX games "
387 L"then you'll have to download a PSX-specific emulator, such as ePSXe or PCSX.")
388 )
389 );
390 //Console.Error( "Playstation1 game discs are not supported by PCSX2." );
391 }
392
393 // Isn't a disc we recognize?
394 if(discType == 0) return;
395
396 // Recognized and PS2 (BOOT2). Good job, user.
397 _reloadElfInfo(elfpath);
398 }
399 catch (Exception::FileNotFound& e)
400 {
401 pxFail( "Not in my back yard!" );
402 Cpu->ThrowException(e);
403 }
404 }
405
406 static __fi s32 StrToS32(const wxString& str, int base = 10)
407 {
408 long l;
409 str.ToLong(&l, base);
410 return l;
411 }
412
413 void cdvdReadKey(u8, u16, u32 arg2, u8* key)
414 {
415 s32 numbers=0, letters=0;
416 u32 key_0_3;
417 u8 key_4, key_14;
418
419 cdvdReloadElfInfo();
420
421 // clear key values
422 memzero_ptr<16>(key);
423
424 if (!DiscSerial.IsEmpty())
425 {
426 // convert the number characters to a real 32 bit number
427 numbers = StrToS32(DiscSerial(5,5));
428
429 // combine the lower 7 bits of each char
430 // to make the 4 letters fit into a single u32
431 letters = (s32)((DiscSerial[3]&0x7F)<< 0) |
432 (s32)((DiscSerial[2]&0x7F)<< 7) |
433 (s32)((DiscSerial[1]&0x7F)<<14) |
434 (s32)((DiscSerial[0]&0x7F)<<21);
435 }
436
437 // calculate magic numbers
438 key_0_3 = ((numbers & 0x1FC00) >> 10) | ((0x01FFFFFF & letters) << 7); // numbers = 7F letters = FFFFFF80
439 key_4 = ((numbers & 0x0001F) << 3) | ((0x0E000000 & letters) >> 25); // numbers = F8 letters = 07
440 key_14 = ((numbers & 0x003E0) >> 2) | 0x04; // numbers = F8 extra = 04 unused = 03
441
442 // store key values
443 key[ 0] = (key_0_3&0x000000FF)>> 0;
444 key[ 1] = (key_0_3&0x0000FF00)>> 8;
445 key[ 2] = (key_0_3&0x00FF0000)>>16;
446 key[ 3] = (key_0_3&0xFF000000)>>24;
447 key[ 4] = key_4;
448
449 switch (arg2)
450 {
451 case 75:
452 key[14] = key_14;
453 key[15] = 0x05;
454 break;
455
456 // case 3075:
457 // key[15] = 0x01;
458 // break;
459
460 case 4246:
461 // 0x0001F2F707 = sector 0x0001F2F7 dec 0x07
462 key[ 0] = 0x07;
463 key[ 1] = 0xF7;
464 key[ 2] = 0xF2;
465 key[ 3] = 0x01;
466 key[ 4] = 0x00;
467 key[15] = 0x01;
468 break;
469
470 default:
471 key[15] = 0x01;
472 break;
473 }
474
475 DevCon.WriteLn( "CDVD.KEY = %02X,%02X,%02X,%02X,%02X,%02X,%02X",
476 cdvd.Key[0],cdvd.Key[1],cdvd.Key[2],cdvd.Key[3],cdvd.Key[4],cdvd.Key[14],cdvd.Key[15] );
477 }
478
479 s32 cdvdGetToc(void* toc)
480 {
481 s32 ret = CDVD->getTOC(toc);
482 if (ret == -1) ret = 0x80;
483 return ret;
484 }
485
486 s32 cdvdReadSubQ(s32 lsn, cdvdSubQ* subq)
487 {
488 s32 ret = CDVD->readSubQ(lsn, subq);
489 if (ret == -1) ret = 0x80;
490 return ret;
491 }
492
493 s32 cdvdCtrlTrayOpen()
494 {
495 Console.Warning("Open virtual disk tray");
496 DiscSwapTimerSeconds = cdvd.RTC.second; // remember the PS2 time when this happened
497 cdvd.Status = CDVD_STATUS_TRAY_OPEN;
498 cdvd.Ready = CDVD_NOTREADY;
499 trayState = 1;
500
501 return 0; // needs to be 0 for success according to homebrew test "CDVD"
502 }
503
504 s32 cdvdCtrlTrayClose()
505 {
506 Console.Warning("Close virtual disk tray");
507 cdvd.Status = CDVD_STATUS_PAUSE;
508 cdvd.Ready = CDVD_READY1;
509 trayState = 0;
510
511 return 0; // needs to be 0 for success according to homebrew test "CDVD"
512 }
513
514 // Some legacy function, not used anymore
515 s32 cdvdGetTrayStatus()
516 {
517 /*s32 ret = CDVD->getTrayStatus();
518
519 if (ret == -1)
520 return(CDVD_TRAY_CLOSE);
521 else
522 return(ret);*/
523 return -1;
524 }
525
526 // Note: Is tray status being kept as a var here somewhere?
527 // Yep, and sceCdTrayReq needs it to detect tray state changes (rama)
528
529 // cdvdNewDiskCB() can update it's status as well...
530
531 // Modified by (efp) - 16/01/2006
532 static __fi void cdvdGetDiskType()
533 {
534 cdvd.Type = DoCDVDdetectDiskType();
535 }
536
537 // check whether disc is single or dual layer
538 // if its dual layer, check what the disctype is and what sector number
539 // layer1 starts at
540 //
541 // args: gets value for dvd type (0=single layer, 1=ptp, 2=otp)
542 // gets value for start lsn of layer1
543 // returns: 1 if on dual layer disc
544 // 0 if not on dual layer disc
545 static s32 cdvdReadDvdDualInfo(s32* dualType, u32* layer1Start)
546 {
547 *dualType = 0;
548 *layer1Start = 0;
549
550 return CDVD->getDualInfo(dualType,layer1Start);
551 }
552
553 static uint cdvdBlockReadTime( CDVD_MODE_TYPE mode )
554 {
555 return (PSXCLK * cdvd.BlockSize) / (((mode==MODE_CDROM) ? PSX_CD_READSPEED : PSX_DVD_READSPEED) * cdvd.Speed);
556 }
557
558 void cdvdReset()
559 {
560 memzero(cdvd);
561
562 cdvd.Type = CDVD_TYPE_NODISC;
563 cdvd.Spinning = false;
564
565 cdvd.sDataIn = 0x40;
566 cdvd.Ready = CDVD_READY2;
567 cdvd.Speed = 4;
568 cdvd.BlockSize = 2064;
569 cdvd.Action = cdvdAction_None;
570 cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
571
572 // CDVD internally uses GMT+9. If you think the time's wrong, you're wrong.
573 // Set up your time zone and winter/summer in the BIOS. No PS2 BIOS I know of features automatic DST.
574 wxDateTime curtime( wxDateTime::GetTimeNow() );
575 cdvd.RTC.second = (u8)curtime.GetSecond();
576 cdvd.RTC.minute = (u8)curtime.GetMinute();
577 cdvd.RTC.hour = (u8)curtime.GetHour(wxDateTime::GMT9);
578 cdvd.RTC.day = (u8)curtime.GetDay(wxDateTime::GMT9);
579 cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0"
580 cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000);
581 }
582
583 struct Freeze_v10Compat
584 {
585 u8 Action;
586 u32 SeekToSector;
587 u32 ReadTime;
588 bool Spinning;
589 };
590
591 void SaveStateBase::cdvdFreeze()
592 {
593 FreezeTag( "cdvd" );
594 Freeze( cdvd );
595
596 if (IsLoading())
597 {
598 // Make sure the Cdvd plugin has the expected track loaded into the buffer.
599 // If cdvd.Readed is cleared it means we need to load the SeekToSector (ie, a
600 // seek is in progress!)
601
602 if( cdvd.Reading )
603 cdvd.RErr = DoCDVDreadTrack( cdvd.Readed ? cdvd.Sector : cdvd.SeekToSector, cdvd.ReadMode);
604 }
605 }
606
607 static void cdvdDetectDisk()
608 {
609 wxString str;
610 cdvd.Type = DoCDVDdetectDiskType();
611 cdvdReloadElfInfo();
612 }
613
614 void cdvdNewDiskCB()
615 {
616 ScopedTryLock lock( Mutex_NewDiskCB );
617 if( lock.Failed() ) return;
618
619 DoCDVDresetDiskTypeCache();
620 cdvdDetectDisk();
621 }
622
623 static void mechaDecryptBytes( u32 madr, int size )
624 {
625 int shiftAmount = (cdvd.decSet>>4) & 7;
626 int doXor = (cdvd.decSet) & 1;
627 int doShift = (cdvd.decSet) & 2;
628
629 u8* curval = iopPhysMem( madr );
630 for( int i=0; i<size; ++i, ++curval )
631 {
632 if( doXor ) *curval ^= cdvd.Key[4];
633 if( doShift ) *curval = (*curval >> shiftAmount) | (*curval << (8-shiftAmount) );
634 }
635 }
636
637 int cdvdReadSector() {
638 s32 bcr;
639
640 CDVD_LOG("SECTOR %d (BCR %x;%x)", cdvd.Sector, HW_DMA3_BCR_H16, HW_DMA3_BCR_L16);
641
642 bcr = (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4;
643 if (bcr < cdvd.BlockSize) {
644 CDVD_LOG( "READBLOCK: bcr < cdvd.BlockSize; %x < %x", bcr, cdvd.BlockSize );
645 if (HW_DMA3_CHCR & 0x01000000) {
646 HW_DMA3_CHCR &= ~0x01000000;
647 psxDmaInterrupt(3);
648 }
649 return -1;
650 }
651
652 // DMAs use physical addresses (air)
653 u8* mdest = iopPhysMem( HW_DMA3_MADR );
654
655 // if raw dvd sector 'fill in the blanks'
656 if (cdvd.BlockSize == 2064)
657 {
658 // get info on dvd type and layer1 start
659 u32 layer1Start;
660 s32 dualType;
661 s32 layerNum;
662 u32 lsn = cdvd.Sector;
663
664 cdvdReadDvdDualInfo(&dualType, &layer1Start);
665
666 if((dualType == 1) && (lsn >= layer1Start))
667 {
668 // dual layer ptp disc
669 layerNum = 1;
670 lsn = lsn - layer1Start + 0x30000;
671 }
672 else if((dualType == 2) && (lsn >= layer1Start))
673 {
674 // dual layer otp disc
675 layerNum = 1;
676 lsn = ~(layer1Start+0x30000 - 1);
677 }
678 else
679 {
680 // Assuming the other dualType is 0,
681 // single layer disc, or on first layer of dual layer disc.
682 layerNum = 0;
683 lsn += 0x30000;
684 }
685
686 mdest[0] = 0x20 | layerNum;
687 mdest[1] = (u8)(lsn >> 16);
688 mdest[2] = (u8)(lsn >> 8);
689 mdest[3] = (u8)(lsn );
690
691 // sector IED (not calculated at present)
692 mdest[4] = 0;
693 mdest[5] = 0;
694
695 // sector CPR_MAI (not calculated at present)
696 mdest[6] = 0;
697 mdest[7] = 0;
698 mdest[8] = 0;
699 mdest[9] = 0;
700 mdest[10] = 0;
701 mdest[11] = 0;
702
703 // normal 2048 bytes of sector data
704 memcpy_const(&mdest[12], cdr.Transfer, 2048);
705
706 // 4 bytes of edc (not calculated at present)
707 mdest[2060] = 0;
708 mdest[2061] = 0;
709 mdest[2062] = 0;
710 mdest[2063] = 0;
711 }
712 else
713 {
714 memcpy_fast( mdest, cdr.Transfer, cdvd.BlockSize);
715 }
716
717 // decrypt sector's bytes
718 if( cdvd.decSet ) mechaDecryptBytes( HW_DMA3_MADR, cdvd.BlockSize );
719
720 // Added a clear after memory write .. never seemed to be necessary before but *should*
721 // be more correct. (air)
722 psxCpu->Clear( HW_DMA3_MADR, cdvd.BlockSize/4 );
723
724 // Console.WriteLn("sector %x;%x;%x", PSXMu8(madr+0), PSXMu8(madr+1), PSXMu8(madr+2));
725
726 HW_DMA3_BCR_H16 -= (cdvd.BlockSize / (HW_DMA3_BCR_L16*4));
727 HW_DMA3_MADR += cdvd.BlockSize;
728
729 return 0;
730 }
731
732 // inlined due to being referenced in only one place.
733 __fi void cdvdActionInterrupt()
734 {
735 switch( cdvd.Action )
736 {
737 case cdvdAction_Seek:
738 cdvd.Spinning = true;
739 cdvd.Ready = CDVD_READY1; //check (rama)
740 cdvd.Sector = cdvd.SeekToSector;
741 cdvd.Status = CDVD_STATUS_PAUSE;
742 break;
743
744 case cdvdAction_Standby:
745 DevCon.Warning("CDVD Standby Call");
746 cdvd.Spinning = true; //check (rama)
747 cdvd.Ready = CDVD_READY1; //check (rama)
748 cdvd.Sector = cdvd.SeekToSector;
749 cdvd.Status = CDVD_STATUS_PAUSE;
750 break;
751
752 case cdvdAction_Stop:
753 cdvd.Spinning = false;
754 cdvd.Ready = CDVD_READY1;
755 cdvd.Sector = 0;
756 cdvd.Status = CDVD_STATUS_STOP;
757 break;
758
759 case cdvdAction_Break:
760 // Make sure the cdvd action state is pretty well cleared:
761 DevCon.Warning("CDVD Break Call");
762 cdvd.Reading = 0;
763 cdvd.Readed = 0;
764 cdvd.Ready = CDVD_READY2; // should be CDVD_READY1 or something else?
765 cdvd.Status = CDVD_STATUS_STOP;
766 cdvd.RErr = 0;
767 cdvd.nCommand = 0;
768 break;
769 }
770 cdvd.Action = cdvdAction_None;
771
772 cdvd.PwOff |= 1<<Irq_CommandComplete;
773 psxHu32(0x1070)|= 0x4;
774 hwIntcIrq(INTC_SBUS);
775 }
776
777 // inlined due to being referenced in only one place.
778 __fi void cdvdReadInterrupt()
779 {
780 //Console.WriteLn("cdvdReadInterrupt %x %x %x %x %x", cpuRegs.interrupt, cdvd.Readed, cdvd.Reading, cdvd.nSectors, (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4);
781
782 cdvd.Ready = CDVD_NOTREADY;
783 if (!cdvd.Readed)
784 {
785 // Seeking finished. Process the track we requested before, and
786 // then schedule another CDVD read int for when the block read finishes.
787
788 // NOTE: The first CD track was read when the seek was initiated, so no need
789 // to call CDVDReadTrack here.
790
791 cdvd.Spinning = true;
792 cdvd.RetryCntP = 0;
793 cdvd.Reading = 1;
794 cdvd.Readed = 1;
795 cdvd.Status = CDVD_STATUS_PAUSE; // check (rama)
796 cdvd.Sector = cdvd.SeekToSector;
797
798 CDVD_LOG( "Cdvd Seek Complete > Scheduling block read interrupt at iopcycle=%8.8x.",
799 psxRegs.cycle + cdvd.ReadTime );
800
801 CDVDREAD_INT(cdvd.ReadTime);
802 return;
803 }
804 else
805 {
806 if( cdvd.RErr == 0 )
807 {
808 while( (cdvd.RErr = DoCDVDgetBuffer(cdr.Transfer)), cdvd.RErr == -2 )
809 {
810 // not finished yet ... block on the read until it finishes.
811 Threading::Sleep( 0 );
812 Threading::SpinWait();
813 }
814 }
815
816 if (cdvd.RErr == -1)
817 {
818 cdvd.RetryCntP++;
819
820 if (cdvd.RetryCntP <= cdvd.RetryCnt)
821 {
822 CDVD_LOG( "CDVD read err, retrying... (attempt %d of %d)", cdvd.RetryCntP, cdvd.RetryCnt );
823 cdvd.RErr = DoCDVDreadTrack(cdvd.Sector, cdvd.ReadMode);
824 CDVDREAD_INT(cdvd.ReadTime);
825 }
826 else
827 Console.Error("CDVD READ ERROR, sector = 0x%08x", cdvd.Sector);
828
829 return;
830 }
831
832 cdvd.Reading = false;
833
834 // Any other value besides 0 should be considered invalid here (wtf is that wacky
835 // plugin trying to do?)
836 pxAssume( cdvd.RErr == 0 );
837 }
838
839 if (cdvdReadSector() == -1)
840 {
841 // This means that the BCR/DMA hasn't finished yet, and rather than fire off the
842 // sector-finished notice too early (which might overwrite game data) we delay a
843 // bit and try to read the sector again later.
844 // An arbitrary delay of some number of cycles probably makes more sense here,
845 // but for now it's based on the cdvd.ReadTime value. -- air
846
847 pxAssume((int)cdvd.ReadTime > 0 );
848 CDVDREAD_INT(cdvd.ReadTime/4);
849 return;
850 }
851
852 cdvd.Sector++;
853
854 if (--cdvd.nSectors <= 0)
855 {
856 cdvd.PwOff |= 1<<Irq_CommandComplete;
857 psxHu32(0x1070)|= 0x4;
858 hwIntcIrq(INTC_SBUS);
859
860 HW_DMA3_CHCR &= ~0x01000000;
861 psxDmaInterrupt(3);
862 cdvd.Ready = CDVD_READY2;
863
864 // All done! :D
865 return;
866 }
867
868 cdvd.RetryCntP = 0;
869 cdvd.Reading = 1;
870 cdvd.RErr = DoCDVDreadTrack(cdvd.Sector, cdvd.ReadMode);
871 CDVDREAD_INT(cdvd.ReadTime);
872
873 return;
874 }
875
876 // Returns the number of IOP cycles until the event completes.
877 static uint cdvdStartSeek( uint newsector, CDVD_MODE_TYPE mode )
878 {
879 cdvd.SeekToSector = newsector;
880
881 uint delta = abs( (s32)(cdvd.SeekToSector - cdvd.Sector) );
882 uint seektime;
883
884 cdvd.Ready = CDVD_NOTREADY;
885 cdvd.Reading = 0;
886 cdvd.Readed = 0;
887 cdvd.Status = CDVD_STATUS_STOP;
888
889 if( !cdvd.Spinning )
890 {
891 CDVD_LOG( "CdSpinUp > Simulating CdRom Spinup Time, and seek to sector %d", cdvd.SeekToSector );
892 seektime = PSXCLK / 3; // 333ms delay
893 cdvd.Spinning = true;
894 }
895 else if( (tbl_ContigiousSeekDelta[mode] == 0) || (delta >= tbl_ContigiousSeekDelta[mode]) )
896 {
897 // Select either Full or Fast seek depending on delta:
898
899 if( delta >= tbl_FastSeekDelta[mode] )
900 {
901 // Full Seek
902 CDVD_LOG( "CdSeek Begin > to sector %d, from %d - delta=%d [FULL]", cdvd.SeekToSector, cdvd.Sector, delta );
903 seektime = Cdvd_FullSeek_Cycles;
904 }
905 else
906 {
907 CDVD_LOG( "CdSeek Begin > to sector %d, from %d - delta=%d [FAST]", cdvd.SeekToSector, cdvd.Sector, delta );
908 seektime = Cdvd_FastSeek_Cycles;
909 }
910 }
911 else
912 {
913 CDVD_LOG( "CdSeek Begin > Contiguous block without seek - delta=%d sectors", delta );
914
915 // seektime is the time it takes to read to the destination block:
916 seektime = delta * cdvd.ReadTime;
917
918 if( delta == 0 )
919 {
920 cdvd.Status = CDVD_STATUS_PAUSE;
921 cdvd.Readed = 1; // Note: 1, not 0, as implied by the next comment. Need to look into this. --arcum42
922 cdvd.RetryCntP = 0;
923
924 // setting Readed to 0 skips the seek logic, which means the next call to
925 // cdvdReadInterrupt will load a block. So make sure it's properly scheduled
926 // based on sector read speeds:
927
928 seektime = cdvd.ReadTime;
929 }
930 }
931
932 return seektime;
933 }
934
935 u8 monthmap[13] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
936
937 void cdvdVsync() {
938 cdvd.RTCcount++;
939 if (cdvd.RTCcount < ((gsRegionMode == Region_NTSC) ? 60 : 50)) return;
940 cdvd.RTCcount = 0;
941
942 if ( cdvd.Status == CDVD_STATUS_TRAY_OPEN )
943 {
944 if ( cdvd.RTC.second != DiscSwapTimerSeconds)
945 {
946 cdvdCtrlTrayClose();
947 }
948 }
949
950 cdvd.RTC.second++;
951 if (cdvd.RTC.second < 60) return;
952 cdvd.RTC.second = 0;
953
954 cdvd.RTC.minute++;
955 if (cdvd.RTC.minute < 60) return;
956 cdvd.RTC.minute = 0;
957
958 cdvd.RTC.hour++;
959 if (cdvd.RTC.hour < 24) return;
960 cdvd.RTC.hour = 0;
961
962 cdvd.RTC.day++;
963 if (cdvd.RTC.day <= (cdvd.RTC.month == 2 && cdvd.RTC.year % 4 == 0 ? 29 : monthmap[cdvd.RTC.month-1])) return;
964 cdvd.RTC.day = 1;
965
966 cdvd.RTC.month++;
967 if (cdvd.RTC.month <= 12) return;
968 cdvd.RTC.month = 1;
969
970 cdvd.RTC.year++;
971 if (cdvd.RTC.year < 100) return;
972 cdvd.RTC.year = 0;
973 }
974
975 static __fi u8 cdvdRead18(void) // SDATAOUT
976 {
977 u8 ret = 0;
978
979 if (((cdvd.sDataIn & 0x40) == 0) && (cdvd.ResultP < cdvd.ResultC))
980 {
981 cdvd.ResultP++;
982 if (cdvd.ResultP >= cdvd.ResultC) cdvd.sDataIn|= 0x40;
983 ret = cdvd.Result[cdvd.ResultP-1];
984 }
985 CDVD_LOG("cdvdRead18(SDataOut) %x (ResultC=%d, ResultP=%d)", ret, cdvd.ResultC, cdvd.ResultP);
986
987 return ret;
988 }
989
990 u8 cdvdRead(u8 key)
991 {
992 switch (key)
993 {
994 case 0x04: // NCOMMAND
995 CDVD_LOG("cdvdRead04(NCMD) %x", cdvd.nCommand);
996 return cdvd.nCommand;
997 break;
998
999 case 0x05: // N-READY
1000 CDVD_LOG("cdvdRead05(NReady) %x", cdvd.Ready);
1001 return cdvd.Ready;
1002 break;
1003
1004 case 0x06: // ERROR
1005 CDVD_LOG("cdvdRead06(Error) %x", cdvd.Error);
1006 return cdvd.Error;
1007 break;
1008
1009 case 0x07: // BREAK
1010 CDVD_LOG("cdvdRead07(Break) %x", 0);
1011 return 0;
1012 break;
1013
1014 case 0x08: // STATUS
1015 CDVD_LOG("cdvdRead08(Status) %x", cdvd.Status);
1016 return cdvd.Status;
1017 break;
1018
1019 case 0x0A: // STATUS
1020 CDVD_LOG("cdvdRead0A(Status) %x", cdvd.Status);
1021 return cdvd.Status;
1022 break;
1023
1024 case 0x0B: // TRAY-STATE (if tray has been opened)
1025 {
1026 CDVD_LOG("cdvdRead0B(Tray) %x", trayState);
1027 return /*tray*/ trayState;
1028 break;
1029 }
1030 case 0x0C: // CRT MINUTE
1031 CDVD_LOG("cdvdRead0C(Min) %x", itob((u8)(cdvd.Sector/(60*75))));
1032 return itob((u8)(cdvd.Sector/(60*75)));
1033 break;
1034
1035 case 0x0D: // CRT SECOND
1036 CDVD_LOG("cdvdRead0D(Sec) %x", itob((u8)((cdvd.Sector/75)%60)+2));
1037 return itob((u8)((cdvd.Sector/75)%60)+2);
1038 break;
1039
1040 case 0x0E: // CRT FRAME
1041 CDVD_LOG("cdvdRead0E(Frame) %x", itob((u8)(cdvd.Sector%75)));
1042 return itob((u8)(cdvd.Sector%75));
1043 break;
1044
1045 case 0x0F: // TYPE
1046 CDVD_LOG("cdvdRead0F(Disc Type) %x", cdvd.Type);
1047 cdvdGetDiskType();
1048 return cdvd.Type;
1049 break;
1050
1051 case 0x13: // UNKNOWN
1052 CDVD_LOG("cdvdRead13(Unknown) %x", 4);
1053 return 4;
1054 break;
1055
1056 case 0x15: // RSV
1057 CDVD_LOG("cdvdRead15(RSV)");
1058 return 0x01; // | 0x80 for ATAPI mode
1059 break;
1060
1061 case 0x16: // SCOMMAND
1062 CDVD_LOG("cdvdRead16(SCMD) %x", cdvd.sCommand);
1063 return cdvd.sCommand;
1064 break;
1065
1066 case 0x17: // SREADY
1067 CDVD_LOG("cdvdRead17(SReady) %x", cdvd.sDataIn);
1068 return cdvd.sDataIn;
1069 break;
1070
1071 case 0x18:
1072 return cdvdRead18();
1073 break;
1074
1075 case 0x20:
1076 case 0x21:
1077 case 0x22:
1078 case 0x23:
1079 case 0x24:
1080 {
1081 int temp = key - 0x20;
1082
1083 CDVD_LOG("cdvdRead%d(Key%d) %x", key, temp, cdvd.Key[temp]);
1084 return cdvd.Key[temp];
1085 break;
1086 }
1087 case 0x28:
1088 case 0x29:
1089 case 0x2A:
1090 case 0x2B:
1091 case 0x2C:
1092 {
1093 int temp = key - 0x23;
1094
1095 CDVD_LOG("cdvdRead%d(Key%d) %x", key, temp, cdvd.Key[temp]);
1096 return cdvd.Key[temp];
1097 break;
1098 }
1099
1100 case 0x30:
1101 case 0x31:
1102 case 0x32:
1103 case 0x33:
1104 case 0x34:
1105 {
1106 int temp = key - 0x26;
1107
1108 CDVD_LOG("cdvdRead%d(Key%d) %x", key, temp, cdvd.Key[temp]);
1109 return cdvd.Key[temp];
1110 break;
1111 }
1112
1113 case 0x38: // valid parts of key data (first and last are valid)
1114 CDVD_LOG("cdvdRead38(KeysValid) %x", cdvd.Key[15]);
1115
1116 return cdvd.Key[15];
1117 break;
1118
1119 case 0x39: // KEY-XOR
1120 CDVD_LOG("cdvdRead39(KeyXor) %x", cdvd.KeyXor);
1121
1122 return cdvd.KeyXor;
1123 break;
1124
1125 case 0x3A: // DEC_SET
1126 CDVD_LOG("cdvdRead3A(DecSet) %x", cdvd.decSet);
1127
1128 Console.WriteLn("DecSet Read: %02X", cdvd.decSet);
1129 return cdvd.decSet;
1130 break;
1131
1132 default:
1133 // note: notify the console since this is a potentially serious emulation problem:
1134 PSXHW_LOG("*Unknown 8bit read at address 0x1f4020%x", key);
1135 Console.Error( "IOP Unknown 8bit read from addr 0x1f4020%x", key );
1136 return 0;
1137 break;
1138 }
1139 }
1140
1141 static void cdvdWrite04(u8 rt) { // NCOMMAND
1142 CDVD_LOG("cdvdWrite04: NCMD %s (%x) (ParamP = %x)", nCmdName[rt], rt, cdvd.ParamP);
1143
1144 cdvd.nCommand = rt;
1145 cdvd.Status = CDVD_STATUS_STOP; // check (rama)
1146 cdvd.PwOff = Irq_None; // good or bad?
1147
1148 switch (rt) {
1149 case N_CD_SYNC: // CdSync
1150 case N_CD_NOP: // CdNop_
1151 cdvdSetIrq();
1152 break;
1153
1154 case N_CD_STANDBY: // CdStandby
1155
1156 // Seek to sector zero. The cdvdStartSeek function will simulate
1157 // spinup times if needed.
1158
1159 DevCon.Warning( "CdStandby : %d", rt );
1160 cdvd.Action = cdvdAction_Standby;
1161 cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
1162 CDVD_INT( cdvdStartSeek( 0, MODE_DVDROM ) );
1163 break;
1164
1165 case N_CD_STOP: // CdStop
1166 DevCon.Warning( "CdStop : %d", rt );
1167 cdvd.Action = cdvdAction_Stop;
1168 CDVD_INT( PSXCLK / 6 ); // 166ms delay?
1169 break;
1170
1171 // from an emulation point of view there is not much need to do anything for this one
1172 case N_CD_PAUSE: // CdPause
1173 cdvdSetIrq();
1174 break;
1175
1176 case N_CD_SEEK: // CdSeek
1177 cdvd.Action = cdvdAction_Seek;
1178 cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
1179 CDVD_INT( cdvdStartSeek( *(uint*)(cdvd.Param+0), MODE_DVDROM ) );
1180 break;
1181
1182 case N_CD_READ: // CdRead
1183 // Assign the seek to sector based on cdvd.Param[0]-[3], and the number of sectors based on cdvd.Param[4]-[7].
1184 cdvd.SeekToSector = *(u32*) (cdvd.Param+0);
1185 cdvd.nSectors = *(u32*)(cdvd.Param+4);
1186 cdvd.RetryCnt = (cdvd.Param[8] == 0) ? 0x100 : cdvd.Param[8];
1187 cdvd.SpindlCtrl = cdvd.Param[9];
1188 cdvd.Speed = 24;
1189 switch (cdvd.Param[10]) {
1190 case 2: cdvd.ReadMode = CDVD_MODE_2340; cdvd.BlockSize = 2340; break;
1191 case 1: cdvd.ReadMode = CDVD_MODE_2328; cdvd.BlockSize = 2328; break;
1192 case 0:
1193 default: cdvd.ReadMode = CDVD_MODE_2048; cdvd.BlockSize = 2048; break;
1194 }
1195
1196 CDVD_LOG( "CdRead > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)",
1197 cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074));
1198
1199 if( EmuConfig.CdvdVerboseReads )
1200 Console.WriteLn("CdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
1201 cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed);
1202
1203 cdvd.ReadTime = cdvdBlockReadTime( MODE_CDROM );
1204 CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector,MODE_CDROM ) );
1205
1206 // Read-ahead by telling the plugin about the track now.
1207 // This helps improve performance on actual from-cd emulation
1208 // (ie, not using the hard drive)
1209 cdvd.RErr = DoCDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode );
1210
1211 // Set the reading block flag. If a seek is pending then Readed will
1212 // take priority in the handler anyway. If the read is contiguous then
1213 // this'll skip the seek delay.
1214 cdvd.Reading = 1;
1215 break;
1216
1217 case N_CD_READ_CDDA: // CdReadCDDA
1218 case N_CD_READ_XCDDA: // CdReadXCDDA
1219 // Assign the seek to sector based on cdvd.Param[0]-[3], and the number of sectors based on cdvd.Param[4]-[7].
1220 cdvd.SeekToSector = *(u32*) (cdvd.Param+0);
1221 cdvd.nSectors = *(u32*)(cdvd.Param+4);
1222
1223 if (cdvd.Param[8] == 0)
1224 cdvd.RetryCnt = 0x100;
1225 else
1226 cdvd.RetryCnt = cdvd.Param[8];
1227
1228 cdvd.SpindlCtrl = cdvd.Param[9];
1229
1230 switch (cdvd.Param[9]) {
1231 case 0x01: cdvd.Speed = 1; break;
1232 case 0x02: cdvd.Speed = 2; break;
1233 case 0x03: cdvd.Speed = 4; break;
1234 case 0x04: cdvd.Speed = 12; break;
1235 default: cdvd.Speed = 24; break;
1236 }
1237
1238 switch (cdvd.Param[10]) {
1239 case 1: cdvd.ReadMode = CDVD_MODE_2368; cdvd.BlockSize = 2368; break;
1240 case 2:
1241 case 0: cdvd.ReadMode = CDVD_MODE_2352; cdvd.BlockSize = 2352; break;
1242 }
1243
1244 CDVD_LOG( "CdReadCDDA > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%xx(%x), ReadMode=%x(%x) (1074=%x)",
1245 cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074));
1246
1247 if( EmuConfig.CdvdVerboseReads )
1248 Console.WriteLn("CdAudioRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
1249 cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed);
1250
1251 cdvd.ReadTime = cdvdBlockReadTime( MODE_CDROM );
1252 CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector, MODE_CDROM ) );
1253
1254 // Read-ahead by telling the plugin about the track now.
1255 // This helps improve performance on actual from-cd emulation
1256 // (ie, not using the hard drive)
1257 cdvd.RErr = DoCDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode );
1258
1259 // Set the reading block flag. If a seek is pending then Readed will
1260 // take priority in the handler anyway. If the read is contiguous then
1261 // this'll skip the seek delay.
1262 cdvd.Reading = 1;
1263 break;
1264
1265 case N_DVD_READ: // DvdRead
1266 // Assign the seek to sector based on cdvd.Param[0]-[3], and the number of sectors based on cdvd.Param[4]-[7].
1267 cdvd.SeekToSector = *(u32*) (cdvd.Param+0);
1268 cdvd.nSectors = *(u32*)(cdvd.Param+4);
1269
1270 if (cdvd.Param[8] == 0)
1271 cdvd.RetryCnt = 0x100;
1272 else
1273 cdvd.RetryCnt = cdvd.Param[8];
1274
1275 cdvd.SpindlCtrl = cdvd.Param[9];
1276 cdvd.Speed = 4;
1277 cdvd.ReadMode = CDVD_MODE_2048;
1278 cdvd.BlockSize = 2064; // Why oh why was it 2064
1279
1280 CDVD_LOG( "DvdRead > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)",
1281 cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074));
1282
1283 if( EmuConfig.CdvdVerboseReads )
1284 Console.WriteLn("DvdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
1285 cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed);
1286
1287 cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
1288 CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector, MODE_DVDROM ) );
1289
1290 // Read-ahead by telling the plugin about the track now.
1291 // This helps improve performance on actual from-cd emulation
1292 // (ie, not using the hard drive)
1293 cdvd.RErr = DoCDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode );
1294
1295 // Set the reading block flag. If a seek is pending then Readed will
1296 // take priority in the handler anyway. If the read is contiguous then
1297 // this'll skip the seek delay.
1298 cdvd.Reading = 1;
1299 break;
1300
1301 case N_CD_GET_TOC: // CdGetToc & cdvdman_call19
1302 //Param[0] is 0 for CdGetToc and any value for cdvdman_call19
1303 //the code below handles only CdGetToc!
1304 //if(cdvd.Param[0]==0x01)
1305 //{
1306 DevCon.WriteLn("CDGetToc Param[0]=%d, Param[1]=%d", cdvd.Param[0],cdvd.Param[1]);
1307 //}
1308 cdvdGetToc( iopPhysMem( HW_DMA3_MADR ) );
1309 cdvdSetIrq( (1<<Irq_CommandComplete) ); //| (1<<Irq_DataReady) );
1310 HW_DMA3_CHCR &= ~0x01000000;
1311 psxDmaInterrupt(3);
1312 break;
1313
1314 case N_CD_READ_KEY: // CdReadKey
1315 {
1316 u8 arg0 = cdvd.Param[0];
1317 u16 arg1 = cdvd.Param[1] | (cdvd.Param[2]<<8);
1318 u32 arg2 = cdvd.Param[3] | (cdvd.Param[4]<<8) | (cdvd.Param[5]<<16) | (cdvd.Param[6]<<24);
1319 DevCon.WriteLn("cdvdReadKey(%d, %d, %d)", arg0, arg1, arg2);
1320 cdvdReadKey(arg0, arg1, arg2, cdvd.Key);
1321 cdvd.KeyXor = 0x00;
1322 cdvdSetIrq();
1323 }
1324 break;
1325
1326 case N_CD_CHG_SPDL_CTRL: // CdChgSpdlCtrl
1327 Console.Warning("sceCdChgSpdlCtrl(%d)", cdvd.Param[0]);
1328 cdvdSetIrq();
1329 break;
1330
1331 default:
1332 Console.Warning("NCMD Unknown %x", rt);
1333 cdvdSetIrq();
1334 break;
1335 }
1336 cdvd.ParamP = 0;
1337 cdvd.ParamC = 0;
1338 }
1339
1340 static __fi void cdvdWrite05(u8 rt) { // NDATAIN
1341 CDVD_LOG("cdvdWrite05(NDataIn) %x", rt);
1342
1343 if (cdvd.ParamP < 32) {
1344 cdvd.Param[cdvd.ParamP++] = rt;
1345 cdvd.ParamC++;
1346 }
1347 }
1348
1349 static __fi void cdvdWrite06(u8 rt) { // HOWTO
1350 CDVD_LOG("cdvdWrite06(HowTo) %x", rt);
1351 cdvd.HowTo = rt;
1352 }
1353
1354 static __fi void cdvdWrite07(u8 rt) // BREAK
1355 {
1356 CDVD_LOG("cdvdWrite07(Break) %x", rt);
1357
1358 // If we're already in a Ready state or already Breaking, then do nothing:
1359 if ((cdvd.Ready != CDVD_NOTREADY) || (cdvd.Action == cdvdAction_Break)) return;
1360
1361 DbgCon.WriteLn("*PCSX2*: CDVD BREAK %x", rt);
1362
1363 // Aborts any one of several CD commands:
1364 // Pause, Seek, Read, Status, Standby, and Stop
1365
1366 psxRegs.interrupt &= ~( (1<<IopEvt_Cdvd) | (1<<IopEvt_CdvdRead) );
1367
1368 cdvd.Action = cdvdAction_Break;
1369 CDVD_INT( 64 );
1370
1371 // Clear the cdvd status:
1372 cdvd.Readed = 0;
1373 cdvd.Reading = 0;
1374 cdvd.Status = CDVD_STATUS_STOP;
1375 //cdvd.nCommand = 0;
1376 }
1377
1378 static __fi void cdvdWrite08(u8 rt) { // INTR_STAT
1379 CDVD_LOG("cdvdWrite08(IntrReason) = ACK(%x)", rt);
1380 cdvd.PwOff &= ~rt;
1381 }
1382
1383 static __fi void cdvdWrite0A(u8 rt) { // STATUS
1384 CDVD_LOG("cdvdWrite0A(Status) %x", rt);
1385 }
1386
1387 static __fi void cdvdWrite0F(u8 rt) { // TYPE
1388 CDVD_LOG("cdvdWrite0F(Type) %x", rt);
1389 DevCon.WriteLn("*PCSX2*: CDVD TYPE %x", rt);
1390 }
1391
1392 static __fi void cdvdWrite14(u8 rt) { // PS1 MODE??
1393 u32 cycle = psxRegs.cycle;
1394
1395 if (rt == 0xFE)
1396 Console.Warning("*PCSX2*: go PS1 mode DISC SPEED = FAST");
1397 else
1398 Console.Warning("*PCSX2*: go PS1 mode DISC SPEED = %dX", rt);
1399
1400 psxReset();
1401 psxHu32(0x1f801450) = 0x8;
1402 psxHu32(0x1f801078) = 1;
1403 psxRegs.cycle = cycle;
1404 }
1405
1406 static __fi void fail_pol_cal()
1407 {
1408 Console.Error("[MG] ERROR - Make sure the file is already decrypted!!!");
1409 cdvd.Result[0] = 0x80;
1410 }
1411
1412 static void cdvdWrite16(u8 rt) // SCOMMAND
1413 {
1414 // cdvdTN diskInfo;
1415 // cdvdTD trackInfo;
1416 // int i, lbn, type, min, sec, frm, address;
1417 static bool oldTrayState = 0;
1418 int address;
1419 u8 tmp;
1420
1421 CDVD_LOG("cdvdWrite16: SCMD %s (%x) (ParamP = %x)", sCmdName[rt], rt, cdvd.ParamP);
1422
1423 cdvd.sCommand = rt;
1424 cdvd.Result[0] = 0; // assume success -- failures will overwrite this with an error code.
1425
1426 switch (rt) {
1427 // case 0x01: // GetDiscType - from cdvdman (0:1)
1428 // SetResultSize(1);
1429 // cdvd.Result[0] = 0;
1430 // break;
1431
1432 case 0x02: // CdReadSubQ (0:11)
1433 SetResultSize(11);
1434 cdvd.Result[0] = cdvdReadSubQ(cdvd.Sector, (cdvdSubQ*)&cdvd.Result[1]);
1435 break;
1436
1437 case 0x03: // Mecacon-command
1438 switch (cdvd.Param[0])
1439 {
1440 case 0x00: // get mecha version (1:4)
1441 SetResultSize(4);
1442 cdvdGetMechaVer(&cdvd.Result[0]);
1443 break;
1444
1445 case 0x44: // write console ID (9:1)
1446 SetResultSize(1);
1447 cdvdWriteConsoleID(&cdvd.Param[1]);
1448 break;
1449
1450 case 0x45: // read console ID (1:9)
1451 SetResultSize(9);
1452 cdvdReadConsoleID(&cdvd.Result[1]);
1453 break;
1454
1455 case 0xFD: // _sceCdReadRenewalDate (1:6) BCD
1456 SetResultSize(6);
1457 cdvd.Result[0] = 0;
1458 cdvd.Result[1] = 0x04;//year
1459 cdvd.Result[2] = 0x12;//month
1460 cdvd.Result[3] = 0x10;//day
1461 cdvd.Result[4] = 0x01;//hour
1462 cdvd.Result[5] = 0x30;//min
1463 break;
1464
1465 default:
1466 SetResultSize(1);
1467 cdvd.Result[0] = 0x80;
1468 Console.WriteLn("*Unknown Mecacon Command param[0]=%02X", cdvd.Param[0]);
1469 break;
1470 }
1471 break;
1472
1473 case 0x05: // CdTrayReqState (0:1) - resets the tray open detection
1474
1475 //Console.Warning("CdTrayReqState. trayState = %d oldTrayState = %d",trayState, oldTrayState);
1476 SetResultSize(1);
1477 if (trayState != oldTrayState)
1478 cdvd.Result[0] = 1;
1479 else
1480 cdvd.Result[0] = 0; // old behaviour was always this
1481
1482 oldTrayState = trayState;
1483 break;
1484
1485 case 0x06: // CdTrayCtrl (1:1)
1486 SetResultSize(1);
1487 if(cdvd.Param[0] == 0)
1488 cdvd.Result[0] = cdvdCtrlTrayOpen();
1489 else
1490 cdvd.Result[0] = cdvdCtrlTrayClose();
1491 break;
1492
1493 case 0x08: // CdReadRTC (0:8)
1494 SetResultSize(8);
1495 cdvd.Result[0] = 0;
1496 cdvd.Result[1] = itob(cdvd.RTC.second); //Seconds
1497 cdvd.Result[2] = itob(cdvd.RTC.minute); //Minutes
1498 cdvd.Result[3] = itob(cdvd.RTC.hour); //Hours
1499 cdvd.Result[4] = 0; //Nothing
1500 cdvd.Result[5] = itob(cdvd.RTC.day); //Day
1501 cdvd.Result[6] = itob(cdvd.RTC.month); //Month
1502 cdvd.Result[7] = itob(cdvd.RTC.year); //Year
1503 /*Console.WriteLn("RTC Read Sec %x Min %x Hr %x Day %x Month %x Year %x", cdvd.Result[1], cdvd.Result[2],
1504 cdvd.Result[3], cdvd.Result[5], cdvd.Result[6], cdvd.Result[7]);
1505 Console.WriteLn("RTC Read Real Sec %d Min %d Hr %d Day %d Month %d Year %d", cdvd.RTC.second, cdvd.RTC.minute,
1506 cdvd.RTC.hour, cdvd.RTC.day, cdvd.RTC.month, cdvd.RTC.year);*/
1507 break;
1508
1509 case 0x09: // sceCdWriteRTC (7:1)
1510 SetResultSize(1);
1511 cdvd.Result[0] = 0;
1512 cdvd.RTC.pad = 0;
1513
1514 cdvd.RTC.second = btoi(cdvd.Param[cdvd.ParamP-7]);
1515 cdvd.RTC.minute = btoi(cdvd.Param[cdvd.ParamP-6]) % 60;
1516 cdvd.RTC.hour = btoi(cdvd.Param[cdvd.ParamP-5]) % 24;
1517 cdvd.RTC.day = btoi(cdvd.Param[cdvd.ParamP-3]);
1518 cdvd.RTC.month = btoi(cdvd.Param[cdvd.ParamP-2] & 0x7f);
1519 cdvd.RTC.year = btoi(cdvd.Param[cdvd.ParamP-1]);
1520 /*Console.WriteLn("RTC write incomming Sec %x Min %x Hr %x Day %x Month %x Year %x", cdvd.Param[cdvd.ParamP-7], cdvd.Param[cdvd.ParamP-6],
1521 cdvd.Param[cdvd.ParamP-5], cdvd.Param[cdvd.ParamP-3], cdvd.Param[cdvd.ParamP-2], cdvd.Param[cdvd.ParamP-1]);
1522 Console.WriteLn("RTC Write Sec %d Min %d Hr %d Day %d Month %d Year %d", cdvd.RTC.second, cdvd.RTC.minute,
1523 cdvd.RTC.hour, cdvd.RTC.day, cdvd.RTC.month, cdvd.RTC.year);*/
1524 //memcpy_fast((u8*)&cdvd.RTC, cdvd.Param, 7);
1525 break;
1526
1527 case 0x0A: // sceCdReadNVM (2:3)
1528 address = (cdvd.Param[0]<<8) | cdvd.Param[1];
1529
1530 if (address < 512)
1531 {
1532 SetResultSize(3);
1533 cdvdReadNVM(&cdvd.Result[1], address*2, 2);
1534 // swap bytes around
1535 tmp = cdvd.Result[1];
1536 cdvd.Result[1] = cdvd.Result[2];
1537 cdvd.Result[2] = tmp;
1538 }
1539 else
1540 {
1541 SetResultSize(1);
1542 cdvd.Result[0] = 0xff;
1543 }
1544 break;
1545
1546 case 0x0B: // sceCdWriteNVM (4:1)
1547 SetResultSize(1);
1548 address = (cdvd.Param[0]<<8) | cdvd.Param[1];
1549
1550 if (address < 512)
1551 {
1552 // swap bytes around
1553 tmp = cdvd.Param[2];
1554 cdvd.Param[2] = cdvd.Param[3];
1555 cdvd.Param[3] = tmp;
1556 cdvdWriteNVM(&cdvd.Param[2], address*2, 2);
1557 }
1558 else
1559 {
1560 cdvd.Result[0] = 0xff;
1561 }
1562 break;
1563
1564 // case 0x0C: // sceCdSetHDMode (1:1)
1565 // break;
1566
1567
1568 case 0x0F: // sceCdPowerOff (0:1)- Call74 from Xcdvdman
1569 SetResultSize(1);
1570 cdvd.Result[0] = 0;
1571 break;
1572
1573 case 0x12: // sceCdReadILinkId (0:9)
1574 SetResultSize(9);
1575 cdvdReadILinkID(&cdvd.Result[1]);
1576 break;
1577
1578 case 0x13: // sceCdWriteILinkID (8:1)
1579 SetResultSize(1);
1580 cdvdWriteILinkID(&cdvd.Param[1]);
1581 break;
1582
1583 case 0x14: // CdCtrlAudioDigitalOut (1:1)
1584 //parameter can be 2, 0, ...
1585 SetResultSize(1);
1586 cdvd.Result[0] = 0; //8 is a flag; not used
1587 break;
1588
1589 case 0x15: // sceCdForbidDVDP (0:1)
1590 //Console.WriteLn("sceCdForbidDVDP");
1591 SetResultSize(1);
1592 cdvd.Result[0] = 5;
1593 break;
1594
1595 case 0x16: // AutoAdjustCtrl - from cdvdman (1:1)
1596 SetResultSize(1);
1597 cdvd.Result[0] = 0;
1598 break;
1599
1600 case 0x17: // CdReadModelNumber (1:9) - from xcdvdman
1601 SetResultSize(9);
1602 cdvdReadModelNumber(&cdvd.Result[1], cdvd.Param[0]);
1603 break;
1604
1605 case 0x18: // CdWriteModelNumber (9:1) - from xcdvdman
1606 SetResultSize(1);
1607 cdvdWriteModelNumber(&cdvd.Param[1], cdvd.Param[0]);
1608 break;
1609
1610 // case 0x19: // sceCdForbidRead (0:1) - from xcdvdman
1611 // break;
1612
1613 case 0x1A: // sceCdBootCertify (4:1)//(4:16 in psx?)
1614 SetResultSize(1);//on input there are 4 bytes: 1;?10;J;C for 18000; 1;60;E;C for 39002 from ROMVER
1615 cdvd.Result[0] = 1;//i guess that means okay
1616 break;
1617
1618 case 0x1B: // sceCdCancelPOffRdy (0:1) - Call73 from Xcdvdman (1:1)
1619 SetResultSize(1);
1620 cdvd.Result[0] = 0;
1621 break;
1622
1623 case 0x1C: // sceCdBlueLEDCtl (1:1) - Call72 from Xcdvdman
1624 SetResultSize(1);
1625 cdvd.Result[0] = 0;
1626 break;
1627
1628 // case 0x1D: // cdvdman_call116 (0:5) - In V10 Bios
1629 // break;
1630
1631 case 0x1E: // sceRemote2Read (0:5) - // 00 14 AA BB CC -> remote key code
1632 SetResultSize(5);
1633 cdvd.Result[0] = 0x00;
1634 cdvd.Result[1] = 0x14;
1635 cdvd.Result[2] = 0x00;
1636 cdvd.Result[3] = 0x00;
1637 cdvd.Result[4] = 0x00;
1638 break;
1639
1640 // case 0x1F: // sceRemote2_7 (2:1) - cdvdman_call117
1641 // break;
1642
1643 case 0x20: // sceRemote2_6 (0:3) // 00 01 00
1644 SetResultSize(3);
1645 cdvd.Result[0] = 0x00;
1646 cdvd.Result[1] = 0x01;
1647 cdvd.Result[2] = 0x00;
1648 break;
1649
1650 // case 0x21: // sceCdWriteWakeUpTime (8:1)
1651 // break;
1652
1653 case 0x22: // sceCdReadWakeUpTime (0:10)
1654 SetResultSize(10);
1655 cdvd.Result[0] = 0;
1656 cdvd.Result[1] = 0;
1657 cdvd.Result[2] = 0;
1658 cdvd.Result[3] = 0;
1659 cdvd.Result[4] = 0;
1660 cdvd.Result[5] = 0;
1661 cdvd.Result[6] = 0;
1662 cdvd.Result[7] = 0;
1663 cdvd.Result[8] = 0;
1664 cdvd.Result[9] = 0;
1665 break;
1666
1667 case 0x24: // sceCdRCBypassCtrl (1:1) - In V10 Bios
1668 // FIXME: because PRId<0x23, the bit 0 of sio2 don't get updated 0xBF808284
1669 SetResultSize(1);
1670 cdvd.Result[0] = 0;
1671 break;
1672
1673 // case 0x25: // cdvdman_call120 (1:1) - In V10 Bios
1674 // break;
1675
1676 // case 0x26: // cdvdman_call128 (0,3) - In V10 Bios
1677 // break;
1678
1679 // case 0x27: // cdvdman_call148 (0:13) - In V10 Bios
1680 // break;
1681
1682 // case 0x28: // cdvdman_call150 (1:1) - In V10 Bios
1683 // break;
1684
1685 case 0x29: //sceCdNoticeGameStart (1:1)
1686 SetResultSize(1);
1687 cdvd.Result[0] = 0;
1688 break;
1689
1690 // case 0x2C: //sceCdXBSPowerCtl (2:2)
1691 // break;
1692
1693 // case 0x2D: //sceCdXLEDCtl (2:2)
1694 // break;
1695
1696 // case 0x2E: //sceCdBuzzerCtl (0:1)
1697 // break;
1698
1699 // case 0x2F: //cdvdman_call167 (16:1)
1700 // break;
1701
1702 // case 0x30: //cdvdman_call169 (1:9)
1703 // break;
1704
1705 case 0x31: //sceCdSetMediumRemoval (1:1)
1706 SetResultSize(1);
1707 cdvd.Result[0] = 0;
1708 break;
1709
1710 case 0x32: //sceCdGetMediumRemoval (0:2)
1711 SetResultSize(2);
1712 cdvd.Result[0] = 0;
1713 //cdvd.Result[0] = 0; // fixme: I'm pretty sure that the same variable shouldn't be set twice here. Perhaps cdvd.Result[1]?
1714 break;
1715
1716 // case 0x33: //sceCdXDVRPReset (1:1)
1717 // break;
1718
1719 case 0x36: //cdvdman_call189 [__sceCdReadRegionParams - made up name] (0:15) i think it is 16, not 15
1720 SetResultSize(15);
1721
1722 cdvdGetMechaVer(&cdvd.Result[1]);
1723 cdvdReadRegionParams(&cdvd.Result[3]);//size==8
1724 Console.WriteLn("REGION PARAMS = %s %s", mg_zones[cdvd.Result[1]], &cdvd.Result[3]);
1725 cdvd.Result[1] = 1 << cdvd.Result[1]; //encryption zone; see offset 0x1C in encrypted headers
1726 //////////////////////////////////////////
1727 cdvd.Result[2] = 0; //??
1728 // cdvd.Result[3] == ROMVER[4] == *0xBFC7FF04
1729 // cdvd.Result[4] == OSDVER[4] == CAP Jjpn, Aeng, Eeng, Heng, Reng, Csch, Kkor?
1730 // cdvd.Result[5] == OSDVER[5] == small
1731 // cdvd.Result[6] == OSDVER[6] == small
1732 // cdvd.Result[7] == OSDVER[7] == small
1733 // cdvd.Result[8] == VERSTR[0x22] == *0xBFC7FF52
1734 // cdvd.Result[9] == DVDID J U O E A R C M
1735 // cdvd.Result[10]== 0; //??
1736 cdvd.Result[11] = 0; //??
1737 cdvd.Result[12] = 0; //??
1738 //////////////////////////////////////////
1739 cdvd.Result[13] = 0; //0xFF - 77001
1740 cdvd.Result[14] = 0; //??
1741 break;
1742
1743 case 0x37: //called from EECONF [sceCdReadMAC - made up name] (0:9)
1744 SetResultSize(9);
1745 cdvdReadMAC(&cdvd.Result[1]);
1746 break;
1747
1748 case 0x38: //used to fix the MAC back after accidentally trashed it :D [sceCdWriteMAC - made up name] (8:1)
1749 SetResultSize(1);
1750 cdvdWriteMAC(&cdvd.Param[0]);
1751 break;
1752
1753 case 0x3E: //[__sceCdWriteRegionParams - made up name] (15:1) [Florin: hum, i was expecting 14:1]
1754 SetResultSize(1);
1755 cdvdWriteRegionParams(&cdvd.Param[2]);
1756 break;
1757
1758 case 0x40: // CdOpenConfig (3:1)
1759 SetResultSize(1);
1760 cdvd.CReadWrite = cdvd.Param[0];
1761 cdvd.COffset = cdvd.Param[1];
1762 cdvd.CNumBlocks = cdvd.Param[2];
1763 cdvd.CBlockIndex= 0;
1764 cdvd.Result[0] = 0;
1765 break;
1766
1767 case 0x41: // CdReadConfig (0:16)
1768 SetResultSize(16);
1769 cdvdReadConfig(&cdvd.Result[0]);
1770 break;
1771
1772 case 0x42: // CdWriteConfig (16:1)
1773 SetResultSize(1);
1774 cdvdWriteConfig(&cdvd.Param[0]);
1775 break;
1776
1777 case 0x43: // CdCloseConfig (0:1)
1778 SetResultSize(1);
1779 cdvd.CReadWrite = 0;
1780 cdvd.COffset = 0;
1781 cdvd.CNumBlocks = 0;
1782 cdvd.CBlockIndex= 0;
1783 cdvd.Result[0] = 0;
1784 break;
1785
1786 case 0x80: // secrman: __mechacon_auth_0x80
1787 SetResultSize(1);//in:1
1788 cdvd.mg_datatype = 0;//data
1789 cdvd.Result[0] = 0;
1790 break;
1791
1792 case 0x81: // secrman: __mechacon_auth_0x81
1793 SetResultSize(1);//in:1
1794 cdvd.mg_datatype = 0;//data
1795 cdvd.Result[0] = 0;
1796 break;
1797
1798 case 0x82: // secrman: __mechacon_auth_0x82
1799 SetResultSize(1);//in:16
1800 cdvd.Result[0] = 0;
1801 break;
1802
1803 case 0x83: // secrman: __mechacon_auth_0x83
1804 SetResultSize(1);//in:8
1805 cdvd.Result[0] = 0;
1806 break;
1807
1808 case 0x84: // secrman: __mechacon_auth_0x84
1809 SetResultSize(1+8+4);//in:0
1810 cdvd.Result[0] = 0;
1811
1812 cdvd.Result[1] = 0x21;
1813 cdvd.Result[2] = 0xdc;
1814 cdvd.Result[3] = 0x31;
1815 cdvd.Result[4] = 0x96;
1816 cdvd.Result[5] = 0xce;
1817 cdvd.Result[6] = 0x72;
1818 cdvd.Result[7] = 0xe0;
1819 cdvd.Result[8] = 0xc8;
1820
1821 cdvd.Result[9] = 0x69;
1822 cdvd.Result[10] = 0xda;
1823 cdvd.Result[11] = 0x34;
1824 cdvd.Result[12] = 0x9b;
1825 break;
1826
1827 case 0x85: // secrman: __mechacon_auth_0x85
1828 SetResultSize(1+4+8);//in:0
1829 cdvd.Result[0] = 0;
1830
1831 cdvd.Result[1] = 0xeb;
1832 cdvd.Result[2] = 0x01;
1833 cdvd.Result[3] = 0xc7;
1834 cdvd.Result[4] = 0xa9;
1835
1836 cdvd.Result[ 5] = 0x3f;
1837 cdvd.Result[ 6] = 0x9c;
1838 cdvd.Result[ 7] = 0x5b;
1839 cdvd.Result[ 8] = 0x19;
1840 cdvd.Result[ 9] = 0x31;
1841 cdvd.Result[10] = 0xa0;
1842 cdvd.Result[11] = 0xb3;
1843 cdvd.Result[12] = 0xa3;
1844 break;
1845
1846 case 0x86: // secrman: __mechacon_auth_0x86
1847 SetResultSize(1);//in:16
1848 cdvd.Result[0] = 0;
1849 break;
1850
1851 case 0x87: // secrman: __mechacon_auth_0x87
1852 SetResultSize(1);//in:8
1853 cdvd.Result[0] = 0;
1854 break;
1855
1856 case 0x8D: // sceMgWriteData
1857 SetResultSize(1);//in:length<=16
1858 if (cdvd.mg_size + cdvd.ParamC > cdvd.mg_maxsize)
1859 {
1860 cdvd.Result[0] = 0x80;
1861 }
1862 else
1863 {
1864 memcpy_fast(cdvd.mg_buffer + cdvd.mg_size, cdvd.Param, cdvd.ParamC);
1865 cdvd.mg_size += cdvd.ParamC;
1866 cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
1867 }
1868 break;
1869
1870 case 0x8E: // sceMgReadData
1871 SetResultSize( std::min(16, cdvd.mg_size) );
1872 memcpy_fast(cdvd.Result, cdvd.mg_buffer, cdvd.ResultC);
1873 cdvd.mg_size -= cdvd.ResultC;
1874 memcpy_fast(cdvd.mg_buffer, cdvd.mg_buffer+cdvd.ResultC, cdvd.mg_size);
1875 break;
1876
1877 case 0x88: // secrman: __mechacon_auth_0x88 //for now it is the same; so, fall;)
1878 case 0x8F: // secrman: __mechacon_auth_0x8F
1879 SetResultSize(1);//in:0
1880 if (cdvd.mg_datatype == 1) // header data
1881 {
1882 u64* psrc, *pdst;
1883 int bit_ofs, i;
1884
1885 if ((cdvd.mg_maxsize != cdvd.mg_size)||(cdvd.mg_size < 0x20) || (cdvd.mg_size != *(u16*)&cdvd.mg_buffer[0x14]))
1886 {
1887 fail_pol_cal();
1888 break;
1889 }
1890
1891 std::string zoneStr;
1892 for (i=0; i<8; i++)
1893 {
1894 if (cdvd.mg_buffer[0x1C] & (1<<i)) zoneStr += mg_zones[i];
1895 }
1896
1897 Console.WriteLn("[MG] ELF_size=0x%X Hdr_size=0x%X unk=0x%X flags=0x%X count=%d zones=%s",
1898 *(u32*)&cdvd.mg_buffer[0x10], *(u16*)&cdvd.mg_buffer[0x14], *(u16*)&cdvd.mg_buffer[0x16],
1899 *(u16*)&cdvd.mg_buffer[0x18], *(u16*)&cdvd.mg_buffer[0x1A],
1900 zoneStr.c_str()
1901 );
1902
1903 bit_ofs = mg_BIToffset(cdvd.mg_buffer);
1904
1905 psrc = (u64*)&cdvd.mg_buffer[bit_ofs-0x20];
1906
1907 pdst = (u64*)cdvd.mg_kbit;
1908 pdst[0] = psrc[0];
1909 pdst[1] = psrc[1];
1910 //memcpy(cdvd.mg_kbit, &cdvd.mg_buffer[bit_ofs-0x20], 0x10);
1911
1912 pdst = (u64*)cdvd.mg_kcon;
1913 pdst[0] = psrc[2];
1914 pdst[1] = psrc[3];
1915 //memcpy(cdvd.mg_kcon, &cdvd.mg_buffer[bit_ofs-0x10], 0x10);
1916
1917 if ((cdvd.mg_buffer[bit_ofs+5] || cdvd.mg_buffer[bit_ofs+6] || cdvd.mg_buffer[bit_ofs+7]) ||
1918 (cdvd.mg_buffer[bit_ofs+4] * 16 + bit_ofs + 8 + 16 != *(u16*)&cdvd.mg_buffer[0x14]))
1919 {
1920 fail_pol_cal();
1921 break;
1922 }
1923 }
1924 cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
1925 break;
1926
1927 case 0x90: // sceMgWriteHeaderStart
1928 SetResultSize(1);//in:5
1929 cdvd.mg_size = 0;
1930 cdvd.mg_datatype = 1;//header data
1931 Console.WriteLn("[MG] hcode=%d cnum=%d a2=%d length=0x%X",
1932 cdvd.Param[0], cdvd.Param[3], cdvd.Param[4], cdvd.mg_maxsize = cdvd.Param[1] | (((int)cdvd.Param[2])<<8));
1933
1934 cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
1935 break;
1936
1937 case 0x91: // sceMgReadBITLength
1938 {
1939 SetResultSize(3);//in:0
1940 int bit_ofs = mg_BIToffset(cdvd.mg_buffer);
1941 memcpy_fast(cdvd.mg_buffer, &cdvd.mg_buffer[bit_ofs], 8+16*cdvd.mg_buffer[bit_ofs+4]);
1942
1943 cdvd.mg_maxsize = 0; // don't allow any write
1944 cdvd.mg_size = 8+16*cdvd.mg_buffer[4];//new offset, i just moved the data
1945 Console.WriteLn("[MG] BIT count=%d", cdvd.mg_buffer[4]);
1946
1947 cdvd.Result[0] = (cdvd.mg_datatype == 1) ? 0 : 0x80; // 0 complete ; 1 busy ; 0x80 error
1948 cdvd.Result[1] = (cdvd.mg_size >> 0) & 0xFF;
1949 cdvd.Result[2] = (cdvd.mg_size >> 8) & 0xFF;
1950 break;
1951 }
1952 case 0x92: // sceMgWriteDatainLength
1953 SetResultSize(1);//in:2
1954 cdvd.mg_size = 0;
1955 cdvd.mg_datatype = 0;//data (encrypted)
1956 cdvd.mg_maxsize = cdvd.Param[0] | (((int)cdvd.Param[1])<<8);
1957 cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
1958 break;
1959
1960 case 0x93: // sceMgWriteDataoutLength
1961 SetResultSize(1);//in:2
1962 if (((cdvd.Param[0] | (((int)cdvd.Param[1])<<8)) == cdvd.mg_size) && (cdvd.mg_datatype == 0))
1963 {
1964 cdvd.mg_maxsize = 0; // don't allow any write
1965 cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
1966 }
1967 else
1968 {
1969 cdvd.Result[0] = 0x80;
1970 }
1971 break;
1972
1973 case 0x94: // sceMgReadKbit - read first half of BIT key
1974 SetResultSize(1+8);//in:0
1975 cdvd.Result[0] = 0;
1976
1977 ((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kbit)[0];
1978 ((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kbit)[1];
1979 //memcpy(cdvd.Result+1, cdvd.mg_kbit, 8);
1980 break;
1981
1982 case 0x95: // sceMgReadKbit2 - read second half of BIT key
1983 SetResultSize(1+8);//in:0
1984 cdvd.Result[0] = 0;
1985 ((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kbit+8))[0];
1986 ((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kbit+8))[1];
1987 //memcpy(cdvd.Result+1, cdvd.mg_kbit+8, 8);
1988 break;
1989
1990 case 0x96: // sceMgReadKcon - read first half of content key
1991 SetResultSize(1+8);//in:0
1992 cdvd.Result[0] = 0;
1993 ((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kcon)[0];
1994 ((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kcon)[1];
1995 //memcpy(cdvd.Result+1, cdvd.mg_kcon, 8);
1996 break;
1997
1998 case 0x97: // sceMgReadKcon2 - read second half of content key
1999 SetResultSize(1+8);//in:0
2000 cdvd.Result[0] = 0;
2001 ((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kcon+8))[0];
2002 ((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kcon+8))[1];
2003 //memcpy(cdvd.Result+1, cdvd.mg_kcon+8, 8);
2004 break;
2005
2006 default:
2007 // fake a 'correct' command
2008 SetResultSize(1); //in:0
2009 cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
2010 Console.WriteLn("SCMD Unknown %x", rt);
2011 break;
2012 } // end switch
2013
2014 //Console.WriteLn("SCMD - 0x%x\n", rt);
2015 cdvd.ParamP = 0;
2016 cdvd.ParamC = 0;
2017 }
2018
2019 static __fi void cdvdWrite17(u8 rt) { // SDATAIN
2020 CDVD_LOG("cdvdWrite17(SDataIn) %x", rt);
2021
2022 if (cdvd.ParamP < 32) {
2023 cdvd.Param[cdvd.ParamP++] = rt;
2024 cdvd.ParamC++;
2025 }
2026 }
2027
2028 static __fi void cdvdWrite18(u8 rt) { // SDATAOUT
2029 CDVD_LOG("cdvdWrite18(SDataOut) %x", rt);
2030 Console.WriteLn("*PCSX2* SDATAOUT");
2031 }
2032
2033 static __fi void cdvdWrite3A(u8 rt) { // DEC-SET
2034 CDVD_LOG("cdvdWrite3A(DecSet) %x", rt);
2035 cdvd.decSet = rt;
2036 Console.WriteLn("DecSet Write: %02X", cdvd.decSet);
2037 }
2038
2039 void cdvdWrite(u8 key, u8 rt)
2040 {
2041 switch (key)
2042 {
2043 case 0x04: cdvdWrite04(rt); break;
2044 case 0x05: cdvdWrite05(rt); break;
2045 case 0x06: cdvdWrite06(rt); break;
2046 case 0x07: cdvdWrite07(rt); break;
2047 case 0x08: cdvdWrite08(rt); break;
2048 case 0x0A: cdvdWrite0A(rt); break;
2049 case 0x0F: cdvdWrite0F(rt); break;
2050 case 0x14: cdvdWrite14(rt); break;
2051 case 0x16: cdvdWrite16(rt); break;
2052 case 0x17: cdvdWrite17(rt); break;
2053 case 0x18: cdvdWrite18(rt); break;
2054 case 0x3A: cdvdWrite3A(rt); break;
2055 default:
2056 Console.Warning("IOP Unknown 8bit write to addr 0x1f4020%x = 0x%x", key, rt);
2057 break;
2058 }
2059 }

  ViewVC Help
Powered by ViewVC 1.1.22