change function names to match
[libogc.git] / libdi / di.c
blob3ff77634dd764783f240dad991177942b6a893fe
1 /*-------------------------------------------------------------
3 di.c -- Drive Interface library
5 Team Twiizers
6 Copyright (C) 2008
8 Erant
9 marcan
11 rodries
12 emukidid
14 This software is provided 'as-is', without any express or implied
15 warranty. In no event will the authors be held liable for any
16 damages arising from the use of this software.
18 Permission is granted to anyone to use this software for any
19 purpose, including commercial applications, and to alter it and
20 redistribute it freely, subject to the following restrictions:
22 1. The origin of this software must not be misrepresented; you
23 must not claim that you wrote the original software. If you use
24 this software in a product, an acknowledgment in the product
25 documentation would be appreciated but is not required.
27 2. Altered source versions must be plainly marked as such, and
28 must not be misrepresented as being the original software.
30 3. This notice may not be removed or altered from any source
31 distribution.
33 -------------------------------------------------------------*/
35 #include <errno.h>
36 #include <string.h>
37 #include <malloc.h>
38 #include <unistd.h>
40 #include <di/di.h>
41 #include <ogc/cache.h>
42 #include <ogc/ipc.h>
43 #include <ogc/ios.h>
44 #include <ogc/mutex.h>
45 #include <ogc/lwp_watchdog.h>
47 #define MOUNT_TIMEOUT 15000 // 15 seconds
49 int di_fd = -1;
50 static bool load_dvdx = false;
51 static bool use_dvd_cache = true;
52 static int have_ahbprot = 0;
53 static int state = DVD_INIT | DVD_NO_DISC;
55 static int _cover_callback(int ret, void* usrdata);
57 static unsigned int bufferMutex = 0;
58 static uint32_t outbuf[8] __attribute__((aligned(32)));
59 static uint32_t dic[8] __attribute__((aligned(32)));
60 static const char di_path[] ATTRIBUTE_ALIGN(32) = "/dev/di";
62 static read_func DI_ReadDVDptr = NULL;
63 static read_func_async DI_ReadDVDAsyncptr = NULL;
64 static di_callback di_cb = NULL;
66 static vu32* const _dvdReg = (u32*)0xCD806000;
68 static int _DI_ReadDVD_A8_Async(void* buf, uint32_t len, uint32_t lba, ipccallback ipc_cb){
69 int ret;
71 if(!buf)
72 return -EINVAL;
74 if((uint32_t)buf & 0x1F) // This only works with 32 byte aligned addresses!
75 return -EFAULT;
77 dic[0] = DVD_READ_UNENCRYPTED << 24;
78 dic[1] = len << 11; // 1 LB is 2048 bytes
79 dic[2] = lba << 9; // Nintendo's read function uses byteOffset >> 2, so we only shift 9 left, not 11.
81 ret = IOS_IoctlAsync(di_fd, DVD_READ_UNENCRYPTED, dic, 0x20, buf, len << 11,ipc_cb, buf);
83 if(ret == 2)
84 ret = EIO;
86 return (ret == 1)? 0 : -ret;
89 static int _DI_ReadDVD_D0_Async(void* buf, uint32_t len, uint32_t lba, ipccallback ipc_cb){
90 int ret;
92 if(!buf)
93 return -EINVAL;
95 if((uint32_t)buf & 0x1F)
96 return -EFAULT;
98 dic[0] = DVD_READ << 24;
99 dic[1] = 0; // Unknown what this does as of now. (Sets some value to 0x10 in the drive if set).
100 dic[2] = 0; // USE_DEFAULT_CONFIG flag. Drive will use default config if this bit is set.
101 dic[3] = len;
102 dic[4] = lba;
104 ret = IOS_IoctlAsync(di_fd, DVD_READ, dic, 0x20, buf, len << 11,ipc_cb, buf);
106 if(ret == 2)
107 ret = EIO;
109 return (ret == 1)? 0 : -ret;
112 static int _DI_ReadDVD(void* buf, uint32_t len, uint32_t lba, uint32_t read_cmd){
113 if ((((int) buf) & 0xC0000000) == 0x80000000) // cached?
114 _dvdReg[0] = 0x2E;
115 _dvdReg[1] = 0;
116 _dvdReg[2] = read_cmd;
117 _dvdReg[3] = read_cmd == 0xD0000000 ? lba : lba << 9;
118 _dvdReg[4] = read_cmd == 0xD0000000 ? len : len << 11;
119 _dvdReg[5] = (unsigned long) buf;
120 _dvdReg[6] = len << 11;
121 _dvdReg[7] = 3; // enable reading!
122 DCInvalidateRange(buf, len << 11);
123 while (_dvdReg[7] & 1);
125 if (_dvdReg[0] & 0x4)
126 return 1;
127 return 0;
130 static int _DI_ReadDVD_A8(void* buf, uint32_t len, uint32_t lba){
131 int ret, retry_count = LIBDI_MAX_RETRIES;
133 if(!buf)
134 return -EINVAL;
136 if((uint32_t)buf & 0x1F) // This only works with 32 byte aligned addresses!
137 return -EFAULT;
139 if(have_ahbprot)
140 return _DI_ReadDVD(buf, len, lba, 0xA8000000);
142 dic[0] = DVD_READ_UNENCRYPTED << 24;
143 dic[1] = len << 11; // 1 LB is 2048 bytes
144 dic[2] = lba << 9; // Nintendo's read function uses byteOffset >> 2, so we only shift 9 left, not 11.
146 do{
147 ret = IOS_Ioctl(di_fd, DVD_READ_UNENCRYPTED, dic, 0x20, buf, len << 11);
148 retry_count--;
149 }while(ret != 1 && retry_count > 0);
151 if(ret == 2)
152 ret = EIO;
154 return (ret == 1)? 0 : -ret;
157 static int _DI_ReadDVD_D0(void* buf, uint32_t len, uint32_t lba){
158 int ret, retry_count = LIBDI_MAX_RETRIES;
160 if(!buf)
161 return -EINVAL;
163 if((uint32_t)buf & 0x1F)
164 return -EFAULT;
166 if(have_ahbprot)
167 return _DI_ReadDVD(buf, len, lba, 0xD0000000);
169 dic[0] = DVD_READ << 24;
170 dic[1] = 0; // Unknown what this does as of now. (Sets some value to 0x10 in the drive if set).
171 dic[2] = 0; // USE_DEFAULT_CONFIG flag. Drive will use default config if this bit is set.
172 dic[3] = len;
173 dic[4] = lba;
175 do{
176 ret = IOS_Ioctl(di_fd, DVD_READ, dic, 0x20, buf, len << 11);
177 retry_count--;
178 }while(ret != 1 && retry_count > 0);
180 if(ret == 2)
181 ret = EIO;
183 return (ret == 1)? 0 : -ret;
186 ///// Cache
187 #define CACHE_FREE 0xFFFFFFFF
188 #define BLOCK_SIZE 0x800
189 #define CACHEBLOCKS 26
190 typedef struct
192 uint32_t block;
193 void *ptr;
194 } cache_page;
195 static cache_page *cache_read = NULL;
197 static void CreateDVDCache()
199 if (cache_read != NULL)
200 return;
201 cache_read = (cache_page *) malloc(sizeof(cache_page));
202 if (cache_read == NULL)
203 return;
205 cache_read->block = CACHE_FREE;
206 cache_read->ptr = memalign(32, BLOCK_SIZE * CACHEBLOCKS);
207 if (cache_read->ptr == NULL)
209 free(cache_read);
210 cache_read = NULL;
211 return;
213 memset(cache_read->ptr, 0, BLOCK_SIZE);
216 static int ReadBlockFromCache(void *buf, uint32_t len, uint32_t block)
218 int retval;
220 if (cache_read == NULL)
221 return DI_ReadDVDptr(buf, len, block);
223 if ((block >= cache_read->block) && (block + len < (cache_read->block + CACHEBLOCKS)))
225 memcpy(buf, cache_read->ptr + ((block - cache_read->block) * BLOCK_SIZE), BLOCK_SIZE * len);
226 return 0;
229 if (len > CACHEBLOCKS)
230 return DI_ReadDVDptr(buf, len, block);
232 retval = DI_ReadDVDptr(cache_read->ptr, CACHEBLOCKS, block);
233 if (retval)
235 cache_read->block = CACHE_FREE;
236 return retval;
239 cache_read->block = block;
240 memcpy(buf, cache_read->ptr, len * BLOCK_SIZE);
242 return 0;
246 Initialize the DI interface, should always be called first!
249 s32 __DI_StubLaunch(void);
250 u32 __di_check_ahbprot(void);
252 int DI_Init() {
253 if(di_fd >= 0)
254 return 1;
256 state = DVD_INIT | DVD_NO_DISC;
257 have_ahbprot = __di_check_ahbprot();
259 if(have_ahbprot != 1 && load_dvdx) {
260 int res = __DI_StubLaunch(); // Marcan's 1337 magics happen here!
262 if (res < 0)
263 return res;
266 if (di_fd < 0)
267 di_fd = IOS_Open(di_path, 2);
269 if (di_fd < 0)
270 return di_fd;
272 if (!bufferMutex)
273 LWP_MutexInit(&bufferMutex, false);
275 if(use_dvd_cache)
276 CreateDVDCache();
278 return 0;
281 void DI_LoadDVDX(bool load) {
282 load_dvdx = load;
285 void DI_UseCache(bool use) {
286 use_dvd_cache = use;
289 void DI_Mount() {
290 if(di_fd < 0)
291 return;
293 uint32_t status;
295 if (DI_GetCoverRegister(&status) != 0) {
296 state = DVD_NO_DISC;
297 return;
300 if ((status & DVD_COVER_DISC_INSERTED) == 0) {
301 state = DVD_NO_DISC;
302 return;
305 state = DVD_INIT | DVD_NO_DISC;
306 _cover_callback(1, NULL); // Initialize the callback chain.
308 if (cache_read != NULL)
309 cache_read->block = CACHE_FREE; // reset cache
312 void DI_Close(){
313 if(di_fd < 0)
314 return;
316 if (di_fd > 0)
317 IOS_Close(di_fd);
319 di_fd = -1;
321 DI_ReadDVDptr = NULL;
322 DI_ReadDVDAsyncptr = NULL;
323 state = DVD_INIT | DVD_NO_DISC;
325 if (bufferMutex) {
326 LWP_MutexDestroy(bufferMutex);
327 bufferMutex = 0;
331 static int _DI_ReadDVD_Check(void* buf, uint32_t len, uint32_t lba)
333 int ret;
335 ret = _DI_ReadDVD_D0(buf, len, lba);
336 if (ret == 0)
338 state = state | DVD_D0;
339 DI_ReadDVDptr = _DI_ReadDVD_D0;
340 DI_ReadDVDAsyncptr = _DI_ReadDVD_D0_Async;
341 return ret;
343 ret = _DI_ReadDVD_A8(buf, len, lba);
344 if (ret == 0)
346 state = state | DVD_A8;
347 DI_ReadDVDptr = _DI_ReadDVD_A8;
348 DI_ReadDVDAsyncptr = _DI_ReadDVD_A8_Async;
349 return ret;
351 return ret;
354 static int _DI_ReadDVD_Check_Async(void* buf, uint32_t len, uint32_t lba, ipccallback ipc_cb)
356 int ret;
358 ret = _DI_ReadDVD_D0_Async(buf, len, lba, ipc_cb);
359 if (ret == 0)
361 state = state | DVD_D0;
362 DI_ReadDVDptr = _DI_ReadDVD_D0;
363 DI_ReadDVDAsyncptr = _DI_ReadDVD_D0_Async;
364 return ret;
366 ret = _DI_ReadDVD_A8_Async(buf, len, lba, ipc_cb);
367 if (ret == 0)
369 state = state | DVD_A8;
370 DI_ReadDVDptr = _DI_ReadDVD_A8;
371 DI_ReadDVDAsyncptr = _DI_ReadDVD_A8_Async;
372 return ret;
374 return ret;
377 static void _DI_SetCallback(int ioctl_nr, ipccallback ipc_cb){
378 if ((di_fd < 0) || !ipc_cb)
379 return;
381 LWP_MutexLock(bufferMutex);
383 memset(dic, 0x00, sizeof(dic));
385 dic[0] = ioctl_nr << 24;
386 dic[1] = (ioctl_nr == DVD_RESET)? 1 : 0; // For reset callback. Dirty, I know...
388 IOS_IoctlAsync(di_fd,ioctl_nr, dic, 0x20, outbuf, 0x20, ipc_cb, outbuf);
389 LWP_MutexUnlock(bufferMutex);
392 #define COVER_CLOSED (*((uint32_t*)usrdata) & DVD_COVER_DISC_INSERTED)
394 static int _cover_callback(int ret, void* usrdata){
395 static int cur_state = 0;
396 static int retry_count = LIBDI_MAX_RETRIES;
397 const int callback_table[] = {
398 DVD_GETCOVER,
399 DVD_WAITFORCOVERCLOSE,
400 DVD_RESET,
401 DVD_IDENTIFY, // This one will complete when the drive is ready.
402 DVD_READ_DISCID,
404 const int return_table[] = {1,1,4,1,1};
406 if(cur_state > 1)
407 state &= ~DVD_NO_DISC;
409 if(callback_table[cur_state]){
410 if(ret == return_table[cur_state]){
411 if(cur_state == 1 && COVER_CLOSED) // Disc inside, skipping wait for cover.
412 cur_state += 2;
413 else
414 cur_state++; // If the previous callback succeeded, moving on to the next
416 retry_count = LIBDI_MAX_RETRIES;
418 else
420 retry_count--;
421 if(retry_count < 0){ // Drive init failed for unknown reasons.
422 retry_count = LIBDI_MAX_RETRIES;
423 cur_state = 0;
424 state = DVD_UNKNOWN;
425 return 0;
428 _DI_SetCallback(callback_table[cur_state - 1], _cover_callback);
431 else // Callback chain has completed OK. The drive is ready.
433 state = DVD_READY;
434 DI_ReadDVDptr = _DI_ReadDVD_Check;
435 DI_ReadDVDAsyncptr = _DI_ReadDVD_Check_Async;
438 if(di_cb)
439 di_cb(state,0);
441 retry_count = LIBDI_MAX_RETRIES;
442 cur_state = 0;
444 return 0;
447 /* Get current status, will return the API status */
448 int DI_GetStatus(){
449 return state;
452 void DI_SetInitCallback(di_callback cb){
453 di_cb = cb;
457 Request an identification from the drive, returned in a DI_DriveID struct
459 int DI_Identify(DI_DriveID* id){
460 if(di_fd < 0)
461 return -ENXIO;
463 if(!id)
464 return -EINVAL;
466 LWP_MutexLock(bufferMutex);
468 dic[0] = DVD_IDENTIFY << 24;
470 int ret = IOS_Ioctl(di_fd, DVD_IDENTIFY, dic, 0x20, outbuf, 0x20);
472 if(ret == 2)
473 ret = EIO;
475 memcpy(id,outbuf,sizeof(DI_DriveID));
477 LWP_MutexUnlock(bufferMutex);
478 return (ret == 1)? 0 : -ret;
482 Returns the current error code on the drive.
483 yagcd has a pretty comprehensive list of possible error codes
485 int DI_GetError(uint32_t* error){
486 if(di_fd < 0)
487 return -ENXIO;
489 if(!error)
490 return -EINVAL;
492 LWP_MutexLock(bufferMutex);
494 dic[0] = DVD_GET_ERROR << 24;
496 int ret = IOS_Ioctl(di_fd, DVD_GET_ERROR, dic, 0x20, outbuf, 0x20);
498 if(ret == 2)
499 ret = EIO;
501 *error = outbuf[0]; // Error code is returned as an int in the first four bytes of outbuf.
503 LWP_MutexUnlock(bufferMutex);
504 return (ret == 1)? 0 : -ret;
508 Reset the drive.
510 int DI_Reset(){
511 if(di_fd < 0)
512 return -ENXIO;
514 LWP_MutexLock(bufferMutex);
516 dic[0] = DVD_RESET << 24;
517 dic[1] = 1;
519 int ret = IOS_Ioctl(di_fd, DVD_RESET, dic, 0x20, outbuf, 0x20);
521 if(ret == 2)
522 ret = EIO;
524 LWP_MutexUnlock(bufferMutex);
525 return (ret == 1)? 0 : -ret;
529 Main read function, basically just a wrapper to the function pointer.
530 Nicer then just exposing the pointer itself
532 int DI_ReadDVD(void* buf, uint32_t len, uint32_t lba){
533 if(di_fd < 0)
534 return -ENXIO;
536 int ret;
537 if(DI_ReadDVDptr){
538 LWP_MutexLock(bufferMutex);
539 ret = ReadBlockFromCache(buf,len,lba);
540 LWP_MutexUnlock(bufferMutex);
541 return ret;
543 return -1;
546 int DI_ReadDVDAsync(void* buf, uint32_t len, uint32_t lba,ipccallback ipc_cb){
547 if(di_fd < 0)
548 return -ENXIO;
550 int ret;
551 if(DI_ReadDVDAsyncptr){
552 LWP_MutexLock(bufferMutex);
553 ret = DI_ReadDVDAsyncptr(buf,len,lba,ipc_cb);
554 LWP_MutexUnlock(bufferMutex);
555 return ret;
557 return -1;
561 Unknown what this does as of now...
563 int DI_ReadDVDConfig(uint32_t* val, uint32_t flag){
564 if(di_fd < 0)
565 return -ENXIO;
567 if(!val)
568 return -EINVAL;
570 LWP_MutexLock(bufferMutex);
572 dic[0] = DVD_READ_CONFIG << 24;
573 dic[1] = flag & 0x1; // Update flag, val will be written if this is 1, val won't be written if it's 0.
574 dic[2] = 0; // Command will fail driveside if this is not zero.
575 dic[3] = *val;
577 int ret = IOS_Ioctl(di_fd, DVD_READ_CONFIG, dic, 0x20, outbuf, 0x20);
579 if(ret == 2)
580 ret = EIO;
582 *val = outbuf[0];
583 LWP_MutexUnlock(bufferMutex);
584 return (ret == 1)? 0 : -ret;
588 Read the copyright information on a DVDVideo
590 int DI_ReadDVDCopyright(uint32_t* copyright){
591 if(di_fd < 0)
592 return -ENXIO;
594 if(!copyright)
595 return -EINVAL;
597 LWP_MutexLock(bufferMutex);
599 dic[0] = DVD_READ_COPYRIGHT << 24;
600 dic[1] = 0;
602 int ret = IOS_Ioctl(di_fd, DVD_READ_COPYRIGHT, dic, 0x20, outbuf, 0x20);
603 *copyright = *((uint32_t*)outbuf); // Copyright information is returned as an int in the first four bytes of outbuf.
605 if(ret == 2)
606 ret = EIO;
608 LWP_MutexUnlock(bufferMutex);
609 return (ret == 1)? 0 : -ret;
612 int DI_Read_BCA(void *outbuf)
614 if(di_fd < 0)
615 return -ENXIO;
617 if(!outbuf)
618 return -EINVAL;
620 memset(dic, 0, sizeof(dic));
621 dic[0] = DVD_READ_BCA << 24;
623 int ret = IOS_Ioctl(di_fd, DVD_READ_BCA, dic, 0x20, outbuf, 64);
625 if(ret == 2)
626 ret = EIO;
628 LWP_MutexUnlock(bufferMutex);
629 return (ret == 1)? 0 : -ret;
633 Returns 0x800 bytes worth of Disc key
635 int DI_ReadDVDDiscKey(void* buf){
636 int ret;
637 int retry_count = LIBDI_MAX_RETRIES;
639 if(di_fd < 0)
640 return -ENXIO;
642 if(!buf)
643 return -EINVAL;
645 if((uint32_t)buf & 0x1F)
646 return -EFAULT;
648 LWP_MutexLock(bufferMutex);
650 dic[0] = DVD_READ_DISCKEY << 24;
651 dic[1] = 0; // Unknown what this flag does.
653 ret = IOS_Ioctl(di_fd, DVD_READ_DISCKEY, dic, 0x20, buf, 0x800);
654 retry_count--;
655 }while(ret != 1 && retry_count > 0);
657 if(ret == 2)
658 ret = EIO;
660 LWP_MutexUnlock(bufferMutex);
661 return (ret == 1)? 0 : -ret;
665 This function will read the initial sector on the DVD, which contains stuff like the booktype
667 int DI_ReadDVDPhysical(void* buf){
668 int ret;
669 int retry_count = LIBDI_MAX_RETRIES;
671 if(di_fd < 0)
672 return -ENXIO;
674 if(!buf)
675 return -EINVAL;
677 if((uint32_t)buf & 0x1F)
678 return -EFAULT;
680 LWP_MutexLock(bufferMutex);
682 dic[0] = DVD_READ_PHYSICAL << 24;
683 dic[1] = 0; // Unknown what this flag does.
686 ret = IOS_Ioctl(di_fd, DVD_READ_PHYSICAL, dic, 0x20, buf, 0x800);
687 retry_count--;
688 }while(ret != 1 && retry_count > 0);
690 if(ret == 2)
691 ret = EIO;
693 LWP_MutexUnlock(bufferMutex);
694 return (ret == 1)? 0 : -ret;
697 int DI_ReportKey(int keytype, uint32_t lba, void* buf){
698 if(di_fd < 0)
699 return -ENXIO;
701 if(!buf)
702 return -EINVAL;
704 if((uint32_t)buf & 0x1F)
705 return -EFAULT;
707 LWP_MutexLock(bufferMutex);
709 dic[0] = DVD_REPORTKEY << 24;
710 dic[1] = keytype & 0xFF;
711 dic[2] = lba;
713 int ret = IOS_Ioctl(di_fd, DVD_REPORTKEY, dic, 0x20, buf, 0x20);
715 if(ret == 2)
716 ret = EIO;
718 LWP_MutexUnlock(bufferMutex);
719 return (ret == 1)? 0 : -ret;
722 int DI_GetCoverRegister(uint32_t* status){
723 if(di_fd < 0)
724 return -ENXIO;
726 LWP_MutexLock(bufferMutex);
727 memset(dic, 0x00, 0x20);
729 int ret = IOS_Ioctl(di_fd, DVD_GETCOVER, dic, 0x20, outbuf, 0x20);
730 if(ret == 2)
731 ret = EIO;
733 *status = outbuf[0];
735 LWP_MutexUnlock(bufferMutex);
736 return (ret == 1)? 0 : -ret;
739 /* Internal function for controlling motor operations */
740 static int _DI_SetMotor(int flag){
741 if(di_fd < 0)
742 return -ENXIO;
744 LWP_MutexLock(bufferMutex);
746 dic[0] = DVD_SET_MOTOR << 24;
747 dic[1] = flag & 0x1; // Eject flag.
748 dic[2] = (flag >> 1) & 0x1; // Don't use this flag, it kills the drive until next reset.
750 int ret = IOS_Ioctl(di_fd, DVD_SET_MOTOR, dic, 0x20, outbuf, 0x20);
752 if(ret == 2)
753 ret = EIO;
755 LWP_MutexUnlock(bufferMutex);
756 return(ret == 1)? 0 : -ret;
759 /* Stop the drives motor */
760 int DI_StopMotor(){
761 return _DI_SetMotor(0);
764 /* Stop the motor, and eject the disc. Also needs a reset afterwards for normal operation */
765 int DI_Eject(){
766 return _DI_SetMotor(1);
769 /* Warning, this will kill your drive untill the next reset. Will not respond to DI commands,
770 will not take in or eject the disc. Your drive will be d - e - d, dead.
772 I deem this function to be harmless, as normal operation will resume after a reset.
773 However, I am not liable for anyones drive exploding as a result from using this function.
775 int DI_KillDrive(){
776 return _DI_SetMotor(2);
779 int DI_ClosePartition() {
780 if(di_fd < 0)
781 return -ENXIO;
783 LWP_MutexLock(bufferMutex);
785 dic[0] = DVD_CLOSE_PARTITION << 24;
787 int ret = IOS_Ioctl(di_fd, DVD_CLOSE_PARTITION, dic, 0x20, outbuf, 0x20);
789 if(ret == 2)
790 ret = EIO;
792 LWP_MutexUnlock(bufferMutex);
793 return(ret == 1)? 0 : -ret;
796 int DI_OpenPartition(uint32_t offset)
798 if(di_fd < 0)
799 return -ENXIO;
801 static ioctlv vectors[5] __attribute__((aligned(32)));
802 static char certs[0x49e4] __attribute__((aligned(32)));
803 LWP_MutexLock(bufferMutex);
805 dic[0] = DVD_OPEN_PARTITION << 24;
806 dic[1] = offset;
808 vectors[0].data = dic;
809 vectors[0].len = 0x20;
810 vectors[1].data = NULL;
811 vectors[1].len = 0x2a4;
812 vectors[2].data = NULL;
813 vectors[2].len = 0;
815 vectors[3].data = certs;
816 vectors[3].len = 0x49e4;
817 vectors[4].data = outbuf;
818 vectors[4].len = 0x20;
820 int ret = IOS_Ioctlv(di_fd, DVD_OPEN_PARTITION, 3, 2, vectors);
822 if(ret == 2)
823 ret = EIO;
825 LWP_MutexUnlock(bufferMutex);
826 return(ret == 1)? 0 : -ret;
830 int DI_Read(void *buf, uint32_t size, uint32_t offset)
832 if(di_fd < 0)
833 return -ENXIO;
835 if(!buf)
836 return -EINVAL;
838 if((uint32_t)buf & 0x1F)
839 return -EFAULT;
841 LWP_MutexLock(bufferMutex);
843 dic[0] = DVD_LOW_READ << 24;
844 dic[1] = size;
845 dic[2] = offset;
847 int ret = IOS_Ioctl(di_fd, DVD_LOW_READ, dic, 0x20, buf, size);
849 if(ret == 2)
850 ret = EIO;
852 LWP_MutexUnlock(bufferMutex);
853 return(ret == 1)? 0 : -ret;
856 int DI_UnencryptedRead(void *buf, uint32_t size, uint32_t offset)
858 int ret, retry_count = LIBDI_MAX_RETRIES;
860 if(di_fd < 0)
861 return -ENXIO;
863 if(!buf)
864 return -EINVAL;
866 if((uint32_t)buf & 0x1F) // This only works with 32 byte aligned addresses!
867 return -EFAULT;
869 LWP_MutexLock(bufferMutex);
871 dic[0] = DVD_READ_UNENCRYPTED << 24;
872 dic[1] = size;
873 dic[2] = offset;
875 do{
876 ret = IOS_Ioctl(di_fd, DVD_READ_UNENCRYPTED, dic, 0x20, buf, size);
877 retry_count--;
878 }while(ret != 1 && retry_count > 0);
880 if(ret == 2)
881 ret = EIO;
883 LWP_MutexUnlock(bufferMutex);
885 return (ret == 1)? 0 : -ret;
888 int DI_ReadDiscID(uint64_t *id)
890 if(di_fd < 0)
891 return -ENXIO;
893 LWP_MutexLock(bufferMutex);
895 dic[0] = DVD_READ_DISCID << 24;
897 int ret = IOS_Ioctl(di_fd, DVD_READ_DISCID, dic, 0x20, outbuf, 0x20);
899 if(ret == 2)
900 ret = EIO;
902 memcpy(id, outbuf, sizeof(*id));
904 LWP_MutexUnlock(bufferMutex);
905 return(ret == 1)? 0 : -ret;
908 static bool diio_Startup()
910 u64 t1,t2;
912 if(di_fd < 0)
913 return false;
915 DI_Mount();
917 t1=ticks_to_millisecs(gettime());
919 while(state & DVD_INIT)
921 usleep(500);
922 t2=ticks_to_millisecs(gettime());
923 if( (t2 - t1) > MOUNT_TIMEOUT)
924 return false; // timeout
927 if(state & DVD_READY)
928 return true;
929 return false;
932 static bool diio_IsInserted()
934 u32 val;
936 if(di_fd < 0)
937 return false;
939 DI_GetCoverRegister(&val);
940 if(val & 0x2)
941 return true;
943 return false;
946 static bool diio_ReadSectors(sec_t sector,sec_t numSectors,void *buffer)
948 if(DI_ReadDVD(buffer, numSectors, sector) == 0)
949 return true;
950 return false;
953 static bool diio_WriteSectors(sec_t sector,sec_t numSectors,const void *buffer)
955 return true;
958 static bool diio_ClearStatus()
960 return true;
963 static bool diio_Shutdown()
965 DI_StopMotor();
966 return true;
969 const DISC_INTERFACE __io_wiidvd = {
970 DEVICE_TYPE_WII_DVD,
971 FEATURE_MEDIUM_CANREAD | FEATURE_WII_DVD,
972 (FN_MEDIUM_STARTUP)&diio_Startup,
973 (FN_MEDIUM_ISINSERTED)&diio_IsInserted,
974 (FN_MEDIUM_READSECTORS)&diio_ReadSectors,
975 (FN_MEDIUM_WRITESECTORS)&diio_WriteSectors,
976 (FN_MEDIUM_CLEARSTATUS)&diio_ClearStatus,
977 (FN_MEDIUM_SHUTDOWN)&diio_Shutdown