psxsdk/libpsx/src/cdrom.c

241 lines
4.1 KiB
C

/*
* Low-level CDROM library
*/
#include <stdio.h>
#include <stdarg.h>
#include <psx.h>
#define CDREG(x) *((unsigned char*)(0x1f801800+x))
void _internal_cdrom_handler();
void (*cdrom_handler_callback)();
volatile int cdrom_command_direct = 0;
volatile int cdrom_command_done = 0;
volatile int cdrom_direct_cmd;
volatile int cdrom_command_dpos = 0;
volatile unsigned char cdrom_last_command;
volatile unsigned char cdrom_command_stat[2];
unsigned int cdrom_queue_buf[4] = {0x0, /* Will contain next interrupt handler in queue */
0x0, /* func1 */
(unsigned int)_internal_cdrom_handler, /* func2 */
0x0, /* pad */
};
static const unsigned char cdrom_command_type[0x1F] = // 0 = single int, 1 = double int, 2,3,... = others
{
0, // Sync 0
0, // GetStat/Nop 1
0, // Setloc 2
0, // Play 3
0, // Forward 4
0, // Backward 5
0, // ReadN 6
0, // Standby 7
0, // Stop 8
1, // Pause 9
1, // Init A
0, // Mute B
0, // Demute C
0, // Setfilter D
0, // Setmode E
0, // Getmode F
0, // GetlocL 10
0, // GetlocP 11
0xFF, // ??? 12
0, // GetTN 13
0, // GetTD 14
1, // SeekL 15
1, // SeekP 16
0xFF, // ??? 17
0xFF, // ??? 18
0, // Test 19
1, // ID 1A
0, // ReadS 1B
0, // Reset 1C
0xFF, // ??? 1D
1, // ReadToc 1E
};
void CdSendCommand(int cmd, int num, ...)
{
int x;
va_list ap;
va_start(ap, num);
// Wait for command execution to end
// while(CDREG(0) & 128);
// Flush old interrupts
// If this is not done, some events (like the opening of the shell) will hang the CD controller.
CDREG(0) = 1;
CDREG(3) = 7;
// Send parameters
CDREG(0) = 0;
while(num)
{
CDREG(2) = (unsigned char)va_arg(ap, unsigned int);
num--;
}
// Send command
CDREG(0) = 0;
CDREG(1) = cmd;
// Depending on the number of INTs we expect for a command,
// we wait for an INT to occur, we store the response data returned,
// and we flush the INT.
for(x = 0; x < (cdrom_command_type[cmd] + 1); x++)
{
CDREG(0) = 1;
while((CDREG(3) & 7) == 0);
cdrom_command_stat[x] = CDREG(1);
CDREG(0) = 1;
CDREG(3) = 7;
}
// Store ID number of last executed command (this)
cdrom_last_command = cmd;
va_end(ap);
}
int CdReadResults(unsigned char *out, int max)
{
int x;
unsigned char *outo = out;
unsigned char b;
for(x = 0; x < (cdrom_command_type[cdrom_last_command] + 1); x++)
{
if(max > 0)
{
*(out++) = cdrom_command_stat[x];
max--;
}
}
CDREG(0) = 1;
while(CDREG(0) & 0x20)
{
b = CDREG(1);
if(max>0)
{
*(out++) = b;
max--;
}
}
return (out-outo);
}
void _internal_cdromlib_callback()
{
// 0 = ACKNOWLEDGE (0x*2)
// 1 = ACKNOWLEDGE (0x*2), COMPLETE (0x*3)
/* int x;
unsigned char i;
if(cdrom_command_done)
return;
for(x = 0; x < 100; x++); // Waste time
CDREG(0) = 1;
i=CDREG(3);
if((i&0xf)==5) // Error
cdrom_command_done = 1;
//printf("i&0xf = %x\n", i&0xf);
// printf("cdrom_direct_cmd = %x\n", cdrom_direct_cmd);
switch(kind[cdrom_direct_cmd])
{
case 0:
if(((i&0xf)==3) || ((i&0xf) == 2))
cdrom_command_done = 1;
break;
case 1:
if((i&0xf)==2)
cdrom_command_done = 1;
break;
case 0xFF: // Unknown command!
cdrom_command_done = 1;
return;
break;
}
cdrom_command_stat[0] = i;
for(x = 0; x < 100; x++); // Waste time
CDREG(0) = 1;
CDREG(3) = 7;
i = CDREG(1);
cdrom_command_stat[1] = i;
//printf("cdrom_command_done = %d\n", cdrom_command_done);*/
}
void _internal_cdromlib_init()
{
printf("Starting CDROMlib...\n");
EnterCriticalSection(); // Disable IRQs
SysEnqIntRP(0, cdrom_queue_buf);
IMASK|=4;
cdrom_handler_callback = _internal_cdromlib_callback;
ExitCriticalSection(); // Enable IRQs
}
int CdGetStatus()
{
unsigned char out;
CdSendCommand(CdlGetstat, 0);
CdReadResults(&out, 1);
return out;
}
int CdPlayTrack(unsigned int track)
{
while(CdGetStatus() & CDSTATUS_SEEK);
CdSendCommand(CdlSetmode, 1, 0x20);
CdSendCommand(CdlPlay, 1, ((track/10)<<4)|(track%10));
return 1;
}
unsigned char CdRamRead(unsigned short addr)
{
unsigned char b;
addr &= 0x3ff;
CdSendCommand(0x19, 0x60, addr&0xff, addr >> 8);
CdReadResults(&b, 1);
return b;
}