mirror of
https://github.com/brandonlw/Psychson.git
synced 2026-10-16 21:12:54 +08:00
382 lines
6.6 KiB
C
382 lines
6.6 KiB
C
#include "defs.h"
|
|
#include "equates.h"
|
|
|
|
#define FEATURE_CHANGE_PASSWORD
|
|
//#define FEATURE_EXPOSE_HIDDEN_PARTITION
|
|
//#define FEATURE_PREVENT_BOOT
|
|
|
|
#define NUM_LBAS 0xE6EA40UL //this needs to be even! (round down)
|
|
|
|
//SCSI command codes
|
|
#define SCSI_06 0x06
|
|
#define SCSI_06_XPEEK 0x06
|
|
#define SCSI_06_XPOKE 0x07
|
|
#define SCSI_06_IPEEK 0x08
|
|
#define SCSI_06_IPOKE 0x09
|
|
#define SCSI_06_BOOT 0xBF
|
|
#define SCSI_START_STOP_UNIT 0x1B
|
|
#define SCSI_READ_FORMAT_CAPACITIES 0x23
|
|
#define SCSI_READ_CAPACITY 0x25
|
|
#define SCSI_READ_SECTOR 0x28
|
|
#define SCSI_WRITE_SECTOR 0x2A
|
|
|
|
void memset(BYTE* s, BYTE c, int size)
|
|
{
|
|
int i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
*s = c;
|
|
s++;
|
|
}
|
|
}
|
|
|
|
void SendData(int size)
|
|
{
|
|
int i;
|
|
|
|
while(EP1.cs & bmSTALL);
|
|
while((EP1.r17 & 0x80)==0)
|
|
{
|
|
if ((XVAL(0xF010) & 0x20)==0)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
while(EP1.cs & 0x40);
|
|
while(EP2.cs & 0x40);
|
|
while(EP3.cs & 0x40);
|
|
while(EP4.cs & 0x40);
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
EP1.fifo = EPBUF[i];
|
|
}
|
|
|
|
EP1.len_l = size & 0xFF;
|
|
EP1.len_m = (size >> 8) & 0xFF;
|
|
EP1.len_h = 0;
|
|
EP1.cs = 0x40;
|
|
}
|
|
|
|
void SendCSW(void)
|
|
{
|
|
memset(EPBUF, 0, 13);
|
|
EPBUF[0] = 'U';
|
|
EPBUF[1] = 'S';
|
|
EPBUF[2] = 'B';
|
|
EPBUF[3] = 'S';
|
|
EPBUF[4] = scsi_tag[3];
|
|
EPBUF[5] = scsi_tag[2];
|
|
EPBUF[6] = scsi_tag[1];
|
|
EPBUF[7] = scsi_tag[0];
|
|
SendData(13);
|
|
}
|
|
|
|
//Disconnects and then re-enumerates.
|
|
void RecycleUSBConnection(void)
|
|
{
|
|
USBCTL &= ~bmAttach;
|
|
EPIE = bmEP2IRQ;
|
|
EP1.cs = 0;
|
|
EP2.cs = 0;
|
|
XVAL(0xFE88) = 0;
|
|
XVAL(0xFE82) = 0x10;
|
|
while (XVAL(0xFE88) != 2);
|
|
USBCTL = bmAttach;
|
|
}
|
|
|
|
#ifdef FEATURE_EXPOSE_HIDDEN_PARTITION
|
|
|
|
//HACK: We're using an unused bit of SYSTEM register 0xFA38 to hold the hidden status,
|
|
// since we don't yet know what RAM is safe to use.
|
|
BOOL IsHiddenAreaVisible(void)
|
|
{
|
|
return WARMSTATUS & 0x80;
|
|
}
|
|
|
|
//HACK: We're using an unused bit of SYSTEM register 0xFA38 to hold the hidden status,
|
|
// since we don't yet know what RAM is safe to use.
|
|
void SetHiddenAreaVisibility(BOOL visible)
|
|
{
|
|
if (visible)
|
|
{
|
|
WARMSTATUS |= 0x80;
|
|
}
|
|
else
|
|
{
|
|
WARMSTATUS &= 0x7F;
|
|
}
|
|
}
|
|
|
|
void WaitTenSeconds(void)
|
|
{
|
|
WORD i, j;
|
|
|
|
for (i = 0; i < 65535; i++)
|
|
{
|
|
for (j = 0; j < 1000; j++)
|
|
{
|
|
//Do nothing
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
void HandleControlRequest(void)
|
|
{
|
|
if (bmRequestType & 0x20)
|
|
{
|
|
//Handle class request
|
|
}
|
|
else if (bmRequestType & 0x40)
|
|
{
|
|
//Handle vendor request
|
|
}
|
|
else
|
|
{
|
|
//Handle standard request
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
void EndpointInterrupt(void)
|
|
{
|
|
__asm
|
|
push ACC
|
|
push DPH
|
|
push DPL
|
|
//If no interrupts fired, get out
|
|
mov DPTR, #EPIRQ
|
|
movx A, @DPTR
|
|
jz 000001$
|
|
//Let the firmware know these events happened, so it can handle them
|
|
mov B, A
|
|
mov DPTR, #FW_EPIRQ
|
|
movx A, @DPTR
|
|
orl A, B
|
|
movx @DPTR, A
|
|
//Disable those interrupts so they don't fire again until we're done with them
|
|
mov A, #0xFF
|
|
xrl A, B
|
|
mov DPTR, #EPIE
|
|
movx @DPTR, A
|
|
//Acknowledge the interrupts
|
|
mov A, B
|
|
mov DPTR, #EPIRQ
|
|
movx @DPTR, A
|
|
000001$:pop DPL
|
|
pop DPH
|
|
pop ACC
|
|
reti
|
|
__endasm;
|
|
}
|
|
|
|
void HandleEndpointInterrupt(void)
|
|
{
|
|
//Handle incoming endpoint data
|
|
}
|
|
*/
|
|
|
|
#if defined(FEATURE_EXPOSE_HIDDEN_PARTITION) || defined(FEATURE_PREVENT_BOOT)
|
|
|
|
void HandleCDB(void)
|
|
{
|
|
unsigned long lba;
|
|
|
|
switch(scsi_cdb[0])
|
|
{
|
|
case SCSI_06:
|
|
{
|
|
switch (scsi_cdb[1])
|
|
{
|
|
case SCSI_06_XPEEK:
|
|
{
|
|
EPBUF[0] = XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]);
|
|
SendData(1);
|
|
break;
|
|
}
|
|
case SCSI_06_XPOKE:
|
|
{
|
|
XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]) = scsi_cdb[4];
|
|
SendData(1);
|
|
break;
|
|
}
|
|
case SCSI_06_IPEEK:
|
|
{
|
|
EPBUF[0] = IVAL(scsi_cdb[2]);
|
|
SendData(1);
|
|
break;
|
|
}
|
|
case SCSI_06_IPOKE:
|
|
{
|
|
IVAL(scsi_cdb[2]) = scsi_cdb[3];
|
|
SendData(1);
|
|
break;
|
|
}
|
|
#ifdef FEATURE_PREVENT_BOOT
|
|
case SCSI_06_BOOT:
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
{
|
|
__asm
|
|
ljmp #DEFAULT_CDB_HANDLER
|
|
__endasm;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SCSI_READ_SECTOR: //TODO: we should handle the other READ(X) commands as well
|
|
{
|
|
#ifdef FEATURE_EXPOSE_HIDDEN_PARTITION
|
|
//Get the passed-in LBA
|
|
lba = ((unsigned long)(scsi_cdb[2]) << 24) & 0xFF000000;
|
|
lba |= ((unsigned long)(scsi_cdb[3]) << 16) & 0xFF0000;
|
|
lba |= (scsi_cdb[4] << 8) & 0xFF00;
|
|
lba |= scsi_cdb[5];
|
|
|
|
//Shift it if necessary
|
|
if (IsHiddenAreaVisible())
|
|
{
|
|
lba += NUM_LBAS / 2;
|
|
}
|
|
|
|
//Save it
|
|
scsi_cdb[2] = (lba >> 24) & 0xFF;
|
|
scsi_cdb[3] = (lba >> 16) & 0xFF;
|
|
scsi_cdb[4] = (lba >> 8) & 0xFF;
|
|
scsi_cdb[5] = lba & 0xFF;
|
|
#endif
|
|
//Let the firmware do its thing
|
|
__asm
|
|
ljmp #DEFAULT_READ_SECTOR_HANDLER
|
|
__endasm;
|
|
}
|
|
#ifdef FEATURE_EXPOSE_HIDDEN_PARTITION
|
|
case SCSI_START_STOP_UNIT:
|
|
{
|
|
//Are we being stopped?
|
|
if (scsi_cdb[4] == 0x02)
|
|
{
|
|
//Yes, set the other section as the visible one
|
|
SetHiddenAreaVisibility(!IsHiddenAreaVisible());
|
|
|
|
//Send the CSW
|
|
SendCSW();
|
|
|
|
//Wait and re-enumerate
|
|
WaitTenSeconds();
|
|
RecycleUSBConnection();
|
|
}
|
|
else
|
|
{
|
|
//No, let things continue normally
|
|
__asm
|
|
ljmp #DEFAULT_CDB_HANDLER
|
|
__endasm;
|
|
}
|
|
break;
|
|
}
|
|
case SCSI_READ_FORMAT_CAPACITIES:
|
|
{
|
|
lba = NUM_LBAS / 2;
|
|
|
|
memset(EPBUF, 0, 12);
|
|
EPBUF[3] = 0x08; //capacity list length
|
|
EPBUF[4] = lba >> 24;
|
|
EPBUF[5] = lba >> 16;
|
|
EPBUF[6] = lba >> 8;
|
|
EPBUF[7] = lba & 0xFF;
|
|
EPBUF[8] = 0x02; //descriptor code (formatted media)
|
|
EPBUF[10] = 0x02; //block length (512 bytes/sector)
|
|
SendData(12);
|
|
break;
|
|
}
|
|
case SCSI_READ_CAPACITY:
|
|
{
|
|
lba = (NUM_LBAS / 2) - 1;
|
|
|
|
memset(EPBUF, 0, 8);
|
|
EPBUF[0] = lba >> 24;
|
|
EPBUF[1] = lba >> 16;
|
|
EPBUF[2] = lba >> 8;
|
|
EPBUF[3] = lba & 0xFF;
|
|
EPBUF[6] = 0x02; //block length (512 bytes/sector)
|
|
SendData(8);
|
|
break;
|
|
}
|
|
case SCSI_WRITE_SECTOR: //TODO: we should handle the other WRITE(x) commands as well
|
|
{
|
|
//Get the passed-in LBA
|
|
lba = ((unsigned long)(scsi_cdb[2]) << 24) & 0xFF000000;
|
|
lba |= ((unsigned long)(scsi_cdb[3]) << 16) & 0xFF0000;
|
|
lba |= (scsi_cdb[4] << 8) & 0xFF00;
|
|
lba |= scsi_cdb[5];
|
|
|
|
//Shift it if necessary
|
|
if (IsHiddenAreaVisible())
|
|
{
|
|
lba += NUM_LBAS / 2;
|
|
}
|
|
|
|
//Save it
|
|
scsi_cdb[2] = (lba >> 24) & 0xFF;
|
|
scsi_cdb[3] = (lba >> 16) & 0xFF;
|
|
scsi_cdb[4] = (lba >> 8) & 0xFF;
|
|
scsi_cdb[5] = lba & 0xFF;
|
|
|
|
//Let the firmware do its thing
|
|
__asm
|
|
ljmp #DEFAULT_CDB_HANDLER
|
|
__endasm;
|
|
}
|
|
#endif
|
|
default:
|
|
__asm
|
|
ljmp #DEFAULT_CDB_HANDLER
|
|
__endasm;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//Called in the firmware's infinite loop.
|
|
/*
|
|
void LoopDo(void)
|
|
{
|
|
}
|
|
*/
|
|
|
|
#ifdef FEATURE_CHANGE_PASSWORD
|
|
|
|
void SetPassword(BYTE* address)
|
|
{
|
|
int i;
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
*(address + i) = 'A';
|
|
}
|
|
}
|
|
|
|
void PasswordReceived()
|
|
{
|
|
if (EPBUF[0])
|
|
{
|
|
SetPassword(EPBUF);
|
|
|
|
}
|
|
|
|
if (EPBUF[0x10])
|
|
{
|
|
SetPassword(EPBUF + 0x10);
|
|
}
|
|
}
|
|
|
|
#endif
|