Files
2014-10-05 04:18:02 -04:00

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