usbloadergx/source/patches/dvd_broadway.c

620 lines
16 KiB
C
Raw Normal View History

/*
* Copyright (C) 2008 Nuke (wiinuke@gmail.com)
*
* this file is part of GeckoOS for USB Gecko
* http://www.usbgecko.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <gcutil.h>
#include <ogc/lwp_queue.h>
#include <gccore.h>
#include "dvd_broadway.h"
#define DI_CMDCTX_CNT 4
#define DVD_DISKIDSIZE 0x20
#define DVD_DRVINFSIZE 0x20
#define IOCTL_DI_INQUIRY 0x12
#define IOCTL_DI_READID 0x70
#define IOCTL_DI_READ 0x71
#define IOCTL_DI_WAITCVRCLOSE 0x79
#define IOCTL_DI_COVER 0x7A
#define IOCTL_DI_RESETNOTIFY 0x7E
#define IOCTL_DI_RESET 0x8A
#define IOCTL_DI_OPENPART 0x8B
#define IOCTL_DI_CLOSEPART 0x8C
#define IOCTL_DI_UNENCREAD 0x8D
#define IOCTL_DI_ENABLE_DVD 0x8E
#define IOCTL_DI_SEEK 0xAB
#define IOCTL_DI_READ_DVDVIDEO 0xD0
#define IOCTL_DI_STOPLASER 0xD2
#define IOCTL_DI_OFFSET 0xD9
#define IOCTL_DI_REQERROR 0xE0
#define IOCTL_DI_STOPMOTOR 0xE3
#define IOCTL_DI_SETOFFBASE 0xF0
#define IOCTL_DI_GETOFFBASE 0xF1
#define IOCTL_DI_SETCRYPTMODE 0xF2
#define IOCTL_DI_GETCRYPTMODE 0xF3
#define IOCTL_DI_SETDVDROMMODE 0xF4
#define IOCTL_DI_GETDVDROMMODE 0xF5
#define _SHIFTL(v, s, w) \
((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
#define _SHIFTR(v, s, w) \
((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
struct dicommand
{
u32 diReg[8];
};
struct dicontext
{
lwp_node node;
dvdcallbacklow cb;
struct dicommand *cmd;
};
static s32 __dvd_fd = -1;
static u32 __dvd_spinupval = 1;
static lwp_queue __di_contextq;
static u32 __dvd_readlength = 0;
static u32 __dvd_cbinprogress = 0;
static u32 __dvd_reqinprogress = 0;
static u32 __dvd_lowinitcalled = 0;
static struct dicommand *__di_commands = NULL;
static struct dicontext __di_contexts[DI_CMDCTX_CNT];
static u32 __di_regbuffer[0x08] ATTRIBUTE_ALIGN( 32 );
static u32 __di_regvalcache[0x08] ATTRIBUTE_ALIGN( 32 );
static u32 __di_lastticketerror[0x08] ATTRIBUTE_ALIGN( 32 );
static ioctlv __di_iovector[0x08] ATTRIBUTE_ALIGN( 32 );
static char __di_fs[] ATTRIBUTE_ALIGN( 32 ) = "/dev/di";
extern u32 __IPC_ClntInit();
static __inline__ lwp_node* __lwp_queue_head( lwp_queue *queue )
{
return ( lwp_node* )queue;
}
static __inline__ lwp_node* __lwp_queue_tail( lwp_queue *queue )
{
return ( lwp_node* )&queue->perm_null;
}
static __inline__ void __lwp_queue_init_empty( lwp_queue *queue )
{
queue->first = __lwp_queue_tail( queue );
queue->perm_null = NULL;
queue->last = __lwp_queue_head( queue );
}
static struct dicontext* __dvd_getcontext( dvdcallbacklow cb )
{
struct dicontext *ctx;
ctx = ( struct dicontext* )__lwp_queue_get( &__di_contextq );
if ( ctx != NULL ) ctx->cb = cb;
return ctx;
}
static s32 __dvd_iostransactionCB( s32 result, void *usrdata )
{
struct dicontext *ctx = ( struct dicontext* )usrdata;
__dvd_reqinprogress = 0;
if ( ctx->cb != NULL )
{
__dvd_cbinprogress = 1;
if ( result != 0 ) __dvd_readlength = 0;
ctx->cb( result );
__dvd_cbinprogress = 0;
}
__lwp_queue_append( &__di_contextq, &ctx->node );
return 0;
}
static s32 __dvd_ioscoverregisterCB( s32 result, void *usrdata )
{
struct dicontext *ctx = ( struct dicontext* )usrdata;
__dvd_reqinprogress = 0;
__di_regvalcache[1] = __di_regbuffer[0];
if ( ctx->cb != NULL )
{
__dvd_cbinprogress = 1;
ctx->cb( result );
__dvd_cbinprogress = 0;
}
__lwp_queue_append( &__di_contextq, &ctx->node );
return 0;
}
static s32 __dvd_ioscovercloseCB( s32 result, void *usrdata )
{
struct dicontext *ctx = ( struct dicontext* )usrdata;
__dvd_reqinprogress = 0;
if ( ctx->cb != NULL )
{
__dvd_cbinprogress = 1;
ctx->cb( result );
__dvd_cbinprogress = 0;
}
__lwp_queue_append( &__di_contextq, &ctx->node );
return 0;
}
s32 bwDVD_LowInit()
{
s32 i, ret = 0;
u32 ipclo, ipchi;
lwp_queue inactives;
struct dicontext *ctx;
if ( __dvd_lowinitcalled == 0 )
{
ret = __IPC_ClntInit();
if ( ret < 0 ) return ret;
ipclo = ( ( ( u32 )IPC_GetBufferLo() + 0x1f )&~0x1f );
ipchi = ( u32 )IPC_GetBufferHi();
if ( ipchi >= ( ipclo + ( sizeof( struct dicommand )*DI_CMDCTX_CNT ) ) )
{
__di_commands = ( struct dicommand* )ipclo;
IPC_SetBufferLo( ( void* )( ipclo + ( sizeof( struct dicommand )*DI_CMDCTX_CNT ) ) );
memset( __di_commands, 0, ( sizeof( struct dicommand )*DI_CMDCTX_CNT ) );
i = 0;
__lwp_queue_init_empty( &__di_contextq );
__lwp_queue_initialize( &inactives, __di_contexts, DI_CMDCTX_CNT, sizeof( struct dicontext ) );
while ( ( ctx = ( struct dicontext* )__lwp_queue_get( &inactives ) ) != NULL )
{
ctx->cmd = &__di_commands[i];
ctx->cb = NULL;
__lwp_queue_append( &__di_contextq, &ctx->node );
i++;
}
}
ret = IOS_Open( __di_fs, 0 );
if ( ret < 0 ) return ret;
__dvd_fd = ret;
// __dvd_lowinitcalled = 1;
// printf("DVD_LowInit(%d)\n",ret);
}
return 0;
}
s32 bwDVD_LowInquiry( dvddrvinfo *info, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_INQUIRY << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_INQUIRY, cmd->diReg, sizeof( struct dicommand ), info, DVD_DRVINFSIZE, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowReadID( dvddiskid *diskID, dvdcallbacklow cb )
{
s32 ret = 0;
struct dicontext *ctx;
struct dicommand *cmd;
// printf("DVD_LowReadID()\n");
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_READID << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_READID, cmd->diReg, sizeof( struct dicommand ), diskID, DVD_DISKIDSIZE, __dvd_iostransactionCB, ctx );
// printf("DVD_LowReadID(%d)\n",ret);
return ret;
}
s32 bwDVD_LowRead( void *buf, u32 len, u32 offset, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
if ( buf == NULL || ( ( u32 )buf % 32 ) != 0 ) return -1;
__dvd_reqinprogress = 1;
__dvd_readlength = len;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_READ << 24 );
cmd->diReg[1] = len;
cmd->diReg[2] = offset;
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_READ, cmd->diReg, sizeof( struct dicommand ), buf, len, __dvd_iostransactionCB, ctx );
return ret;
}
// never got this function working, probably removed from wii
s32 bwDVD_LowReadVideo( void *buf, u32 len, u32 offset, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
__dvd_readlength = len;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_READ_DVDVIDEO << 24 );
cmd->diReg[1] = len;
cmd->diReg[2] = offset;
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_READ_DVDVIDEO, cmd->diReg, sizeof( struct dicommand ), buf, len, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowStopLaser( dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_STOPLASER << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_STOPLASER, cmd->diReg, sizeof( struct dicommand ), __di_regvalcache, 0x20, __dvd_iostransactionCB, ctx );
return ret;
}
// never got this function working, probably removed from wii
s32 bwDVD_EnableVideo( dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_ENABLE_DVD << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_ENABLE_DVD, cmd->diReg, sizeof( struct dicommand ), __di_regvalcache, 0x20, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowSeek( u32 offset, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_SEEK << 24 );
cmd->diReg[1] = offset;
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_SEEK, cmd->diReg, sizeof( struct dicommand ), NULL, 0, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowOffset( u64 offset, dvdcallbacklow cb )
{
s32 ret;
//u32 *off = (u32*)(void*)(&offset);
union { u64 off64; u32 off32[2]; } off; off.off64 = offset;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_OFFSET << 24 );
cmd->diReg[1] = 0;
if ( off.off32[0] ) cmd->diReg[1] = 1;
cmd->diReg[2] = off.off32[1];
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_OFFSET, cmd->diReg, sizeof( struct dicommand ), __di_regvalcache, 0x20, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowPrepareCoverRegister( dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_COVER << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_COVER, cmd->diReg, sizeof( struct dicommand ), __di_regbuffer, 0x20, __dvd_ioscoverregisterCB, ctx );
return ret;
}
s32 bwDVD_LowOpenPartition( u32 offset, void *eticket, u32 certin_len, void *certificate_in, void *certificate_out, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
if ( eticket != NULL && ( ( u32 )eticket % 32 ) != 0 ) return -1;
if ( certificate_in != NULL && ( ( u32 )certificate_in % 32 ) != 0 ) return -1;
if ( certificate_out != NULL && ( ( u32 )certificate_out % 32 ) != 0 ) return -1;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_OPENPART << 24 );
cmd->diReg[1] = offset;
__di_iovector[0].data = cmd;
__di_iovector[0].len = sizeof( struct dicommand );
__di_iovector[1].data = eticket;
if ( eticket == NULL ) __di_iovector[1].len = 0;
else __di_iovector[1].len = 676;
__di_iovector[2].data = certificate_in;
if ( certificate_in == NULL ) __di_iovector[2].len = 0;
else __di_iovector[2].len = certin_len;
__di_iovector[3].data = certificate_out;
__di_iovector[3].len = 18916;
__di_iovector[4].data = __di_lastticketerror;
__di_iovector[4].len = 0x20;
ret = IOS_IoctlvAsync( __dvd_fd, IOCTL_DI_OPENPART, 3, 2, __di_iovector, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowClosePartition( dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_CLOSEPART << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_CLOSEPART, cmd->diReg, sizeof( struct dicommand ), NULL, 0, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowUnencryptedRead( void *buf, u32 len, u32 offset, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
__dvd_readlength = len;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_UNENCREAD << 24 );
cmd->diReg[1] = len;
cmd->diReg[2] = offset;
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_UNENCREAD, cmd->diReg, sizeof( struct dicommand ), buf, len, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowWaitCoverClose( dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_WAITCVRCLOSE << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_WAITCVRCLOSE, cmd->diReg, sizeof( struct dicommand ), NULL, 0, __dvd_ioscovercloseCB, ctx );
return ret;
}
s32 bwDVD_LowResetNotify()
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
if ( __dvd_cbinprogress == 1 ) return -1;
ctx = __dvd_getcontext( NULL );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_RESETNOTIFY << 24 );
ret = IOS_Ioctl( __dvd_fd, IOCTL_DI_RESETNOTIFY, cmd->diReg, sizeof( struct dicommand ), NULL, 0 );
return ret;
}
s32 bwDVD_LowReset( dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
// printf("DVD_LowReset()\n");
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_RESET << 24 );
cmd->diReg[1] = __dvd_spinupval;
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_RESET, cmd->diReg, sizeof( struct dicommand ), NULL, 0, __dvd_iostransactionCB, ctx );
// printf("DVD_LowReset(%d)\n",ret);
return ret;
}
s32 bwDVD_LowStopMotor( u8 stop1, u8 stop2, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_STOPMOTOR << 24 );
cmd->diReg[1] = ( stop1 << 24 );
cmd->diReg[2] = ( stop2 << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_STOPMOTOR, cmd->diReg, sizeof( struct dicommand ), __di_regvalcache, 0x20, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_LowRequestError( dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_REQERROR << 24 );
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_REQERROR, cmd->diReg, sizeof( struct dicommand ), __di_regvalcache, 0x20, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_SetDecryption( s32 mode, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_SETCRYPTMODE << 24 );
cmd->diReg[1] = mode;
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_SETCRYPTMODE, cmd->diReg, sizeof( struct dicommand ), __di_regvalcache, 0x20, __dvd_iostransactionCB, ctx );
return ret;
}
s32 bwDVD_SetOffset( u32 offset, dvdcallbacklow cb )
{
s32 ret;
struct dicontext *ctx;
struct dicommand *cmd;
__dvd_reqinprogress = 1;
ctx = __dvd_getcontext( cb );
if ( ctx == NULL ) return IPC_ENOMEM;
cmd = ctx->cmd;
cmd->diReg[0] = ( IOCTL_DI_SETOFFBASE << 24 );
cmd->diReg[1] = offset;
ret = IOS_IoctlAsync( __dvd_fd, IOCTL_DI_SETOFFBASE, cmd->diReg, sizeof( struct dicommand ), __di_regvalcache, 0x20, __dvd_iostransactionCB, ctx );
return ret;
}