SAROO/Firm_MCU/Saturn/saturn_cdc.c
tpu b403a6804a init_cdblock增加HIRQ_EHST返回值。
移除为InTheHunt做的hack代码。
2024-03-11 17:02:28 +08:00

2067 lines
40 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "main.h"
#include "ff.h"
#include "cdc.h"
/******************************************************************************/
CDBLOCK cdb;
/******************************************************************************/
// 数据传输
BLOCK *alloc_block(void)
{
int i, irqs;
BLOCK *blk;
blk = NULL;
irqs = disable_irq();
for(i=0; i<MAX_BLOCKS; i++){
if(cdb.block[i].size==-1){
cdb.block_free -= 1;
cdb.block[i].size = cdb.sector_size;
blk = &cdb.block[i];
break;
}
}
if(cdb.block_free==0){
HIRQ = HIRQ_BFUL;
}
restore_irq(irqs);
return blk;
}
void free_block(BLOCK *block)
{
int irqs;
irqs = disable_irq();
block->size = -1;
cdb.block_free += 1;
restore_irq(irqs);
if(cdb.play_wait==1 && cdb.block_free>16){
cdb.play_wait = 0;
disk_task_wakeup();
}
}
BLOCK *find_block(PARTITION *part, int index)
{
BLOCK *p;
int i, irqs;
if(part->numblocks==0)
return NULL;
irqs = disable_irq();
p = part->head;
i = 0;
while(p){
if(i==index){
restore_irq(irqs);
return p;
}
i += 1;
p = p->next;
}
restore_irq(irqs);
return NULL;
}
void remove_block(PARTITION *part, int index)
{
BLOCK *p, *prev;
int i, irqs;
irqs = disable_irq();
prev = NULL;
p = part->head;
i = 0;
while(p){
if(i==index){
if(prev==NULL){
part->head = p->next;
}else{
prev->next = p->next;
}
if(part->tail==p){
part->tail = prev;
}
part->size -= p->size;
part->numblocks -= 1;
free_block(p);
break;
}
i += 1;
prev = p;
p = p->next;
}
restore_irq(irqs);
}
void fill_fifo(u8 *addr, int size)
{
int i;
for(i=0; i<size; i+=2){
FIFO_DATA = *(u16*)(addr+i);
}
}
static int min_num;
void trans_start(void)
{
u8 *dp = NULL;
min_num = 40960;
cdb.cdwnum = 0;
cdb.trans_finish = 0;
if(cdb.trans_type==TRANS_DATA || cdb.trans_type==TRANS_DATA_DEL){
PARTITION *pt = &cdb.part[cdb.trans_part_index];
BLOCK *bt = find_block(pt, cdb.trans_block_start);
SSLOG(_TRANS, "trans_start: pt=%d start=%d size=%d\n",
cdb.trans_part_index, cdb.trans_block_start, cdb.trans_block_end-cdb.trans_block_start);
cdb.trans_bk = cdb.trans_block_start;
if(cdb.sector_size==2352){
dp = bt->data;
}else if(cdb.sector_size==2340){
dp = bt->data+12;
}else if(cdb.sector_size==2336){
dp = bt->data+16;
}else{
dp = bt->data+24;
}
if(cdb.sector_size==2048 && bt->size==2324){
cdb.trans_size = 2324;
}else{
cdb.trans_size = cdb.sector_size;
}
cdb.trans_block = bt;
cdb.trans_bk += 1;
}else if(cdb.trans_type==TRANS_TOC){
dp = (u8*)cdb.TOC;
cdb.trans_size = 102*4;
}else if(cdb.trans_type==TRANS_FINFO_ALL){
dp = (u8*)cdb.FINFO;
cdb.trans_size = cdb.cdir_pfnum*12;
}else if(cdb.trans_type==TRANS_FINFO_ONE){
dp = (u8*)cdb.FINFO;
cdb.trans_size = 12;
}else if(cdb.trans_type==TRANS_SUBQ){
dp = (u8*)cdb.SUBH;
cdb.trans_size = 10;
}else if(cdb.trans_type==TRANS_SUBRW){
dp = (u8*)cdb.SUBH;
cdb.trans_size = 24;
}
FIFO_RCNT = 0;
ST_CTRL &= ~0x0200;
fill_fifo(dp, cdb.trans_size);
ST_STAT = STIRQ_DAT;
ST_CTRL |= STIRQ_DAT;
}
// 一个block的数据已经写入FIFO中
// 准备写入下一个block的数据或者删除已经写完的block
void trans_handle(void)
{
if(cdb.trans_type==TRANS_PUT){
if(cdb.trans_bk==0)
return;
PARTITION *pt = &cdb.part[cdb.trans_part_index];
BLOCK *bt = pt->tail;
if(bt==NULL){
// PARTITION为空
bt = alloc_block();
bt->size = 0;
bt->next = NULL;
pt->head = bt;
pt->tail = bt;
pt->numblocks += 1;
}else if(bt->size >= cdb.put_sector_size){
// PARTITION的最后的block已经有数据了
BLOCK *nbt = alloc_block();
nbt->size = 0;
nbt->next = NULL;
bt->next = nbt;
pt->tail = nbt;
pt->numblocks += 1;
bt = nbt;
}
ST_CTRL &= ~STIRQ_DAT;
//printk("trans_put: FIFO_STAT=%04x\n", FIFO_STAT);
int cnt = 2048;
int offs = 0;
if(cdb.put_sector_size==2048){
offs = 24;
}else if(cdb.put_sector_size==2336){
offs = 16;
}else if(cdb.put_sector_size==2340){
offs= 12;
}
while(cnt){
*(u16*)(bt->data + offs + bt->size) = FIFO_DATA;
bt->size += 2;
cnt -= 2;
if(bt->size == cdb.put_sector_size){
//printk(" trans_bk=%d\n", cdb.trans_bk);
pt->size += cdb.put_sector_size;
cdb.trans_bk -= 1;
if(cdb.trans_bk==0){
ST_CTRL &= ~(STIRQ_DAT|0x0200);
ST_STAT = STIRQ_DAT;
return;
}else{
BLOCK *nbt = alloc_block();
nbt->size = 0;
nbt->next = 0;
bt->next = nbt;
pt->tail = nbt;
pt->numblocks += 1;
bt = nbt;
}
}
}
ST_STAT = STIRQ_DAT;
ST_CTRL |= STIRQ_DAT;
return;
}
if(cdb.trans_finish==0){
// 中断在传输结束时会重复进入一次。这里做个判断,以免误加。
cdb.cdwnum += cdb.trans_size;
}
if(cdb.trans_type==TRANS_DATA || cdb.trans_type==TRANS_DATA_DEL){
if(cdb.trans_bk==cdb.trans_block_end){
cdb.trans_finish = 1;
ST_CTRL &= ~STIRQ_DAT;
}else{
BLOCK *bt = cdb.trans_block->next;
u8 *dp;
int stat;
if(cdb.sector_size==2352){
dp = bt->data;
}else if(cdb.sector_size==2340){
dp = bt->data+12;
}else if(cdb.sector_size==2336){
dp = bt->data+16;
}else{
dp = bt->data+24;
}
if(cdb.sector_size==2048 && bt->size==2324){
cdb.trans_size = 2324;
}else{
cdb.trans_size = cdb.sector_size;
}
cdb.trans_block = bt;
cdb.trans_bk += 1;
stat = FIFO_STAT;
stat &= 0x0fff;
if(stat<min_num)
min_num = stat;
ST_CTRL &= ~STIRQ_DAT;
fill_fifo(dp, cdb.trans_size);
ST_STAT = STIRQ_DAT;
ST_CTRL |= STIRQ_DAT;
HIRQ = HIRQ_SCDQ;
}
}else{
cdb.trans_finish = 1;
ST_CTRL &= ~STIRQ_DAT;
}
}
/******************************************************************************/
void set_report(u8 status)
{
int irqs;
irqs = disable_irq();
SSCR1 = (status<<8) | ((cdb.options&0x0f)<<4) | (cdb.repcnt&0x0f);
SSCR2 = (cdb.ctrladdr<<8) | cdb.track;
SSCR3 = (cdb.index<<8) | ((cdb.fad>>16)&0xff);
SSCR4 = cdb.fad&0xffff;
restore_irq(irqs);
}
void set_status(u8 status)
{
int irqs = disable_irq();
SSCR1 = (status<<8) | (SSCR1&0x00ff);
restore_irq(irqs);
}
int filter_sector(TRACK_INFO *track, BLOCK *wblk)
{
PARTITION *pt;
FILTER *ft;
BLOCK *blk;
int retv, irqs;
if(cdb.cddev_filter==0xff){
return 1;
}
ft = &cdb.filter[cdb.cddev_filter];
//printk("filter %08x to %d ...\n", wblk->fad, cdb.cddev_filter);
while(1){
retv = 1;
if(track->mode!=3 && track->sector_size==2352 && wblk->data[0x0f]==2){
//printk("wblk: fn=%02x cn=%02x sm=%02x ci=%02x\n", wblk->fn, wblk->cn, wblk->sm, wblk->ci);
if(ft->mode&0x01){
if(wblk->fn!=ft->fid)
retv = 0;
}
if(ft->mode&0x02){
if(wblk->cn!=ft->chan)
retv = 0;
}
if(ft->mode&0x04){
if((wblk->sm&ft->smmask)!=ft->smval)
retv = 0;
}
if(ft->mode&0x08){
if((wblk->ci&ft->cimask)!=ft->cival)
retv = 0;
}
if(ft->mode&0x10){
retv ^= 1;
}
}
if(ft->mode&0x40){
if( (wblk->fad < ft->fad) || (wblk->fad >= (ft->fad+ft->range)) )
retv = 0;
}
if(retv==1){
cdb.last_buffer = ft->c_true;
break;
}else{
if(ft->c_false==0xff){
if(track->mode==1)
printk(" c_false is FF!\n");
return 1;
}
ft = &cdb.filter[ft->c_false];
}
}
//printk(" ft->pt: %02x\n", ft->c_true);
pt = &cdb.part[ft->c_true];
blk = alloc_block();
if(blk==NULL){
return 2;
}
blk->size = cdb.sector_size;
blk->fad = wblk->fad;
blk->fn = wblk->fn;
blk->cn = wblk->cn;
blk->sm = wblk->sm;
blk->ci = wblk->ci;
if(wblk->size==2048){
memset(blk->data, 0, 24);
memcpy32(blk->data+24, wblk->data, 2048);
}else if(wblk->size==2352){
if(track->mode==3 || wblk->data[15]==2){
// MODE2 or AUDIO
memcpy32(blk->data, wblk->data, 2352);
if(wblk->sm & 0x20){
blk->size = 2324;
}
}else{
// MODE1
memcpy32(blk->data, wblk->data, 16);
memset(blk->data+16, 0, 8);
memcpy32(blk->data+24, wblk->data+16, 2048);
}
}
irqs = disable_irq();
if(pt->size==-1)
pt->size = 0;
// 疑问: partition中的size, 是按wblk的size算,还是按sector_size算?
// 已经确认,是按设置的sector_size算.
pt->size += blk->size;
pt->numblocks += 1;
if(pt->head==NULL){
pt->head = blk;
pt->tail = blk;
}else{
pt->tail->next = blk;
pt->tail = blk;
}
blk->next = NULL;
restore_irq(irqs);
//printk(" filter done.\n");
return 0;
}
/******************************************************************************/
// 普通命令
static int old_status;
// 0x00 [SR]
int get_cd_status(void)
{
set_report(cdb.status);
if(old_status!=cdb.status){
SSLOG(_DEBUG, " %02x\n", cdb.status);
old_status = cdb.status;
}
return 0;
}
// 0x01 [S-]
int get_hw_info(void)
{
SSLOG(_INFO, "get_hw_info\n");
SSCR1 = (cdb.status<<8);
SSCR2 = 0x0001;
SSCR3 = 0x0000;
SSCR4 = 0x0400;
return 0;
}
// 0x02 [S-]
int get_toc_info(void)
{
SSLOG(_INFO, "get_toc_info\n");
if(cdb.trans_type){
set_status(STAT_WAIT | cdb.status);
return 0;
}
SSCR1 = 0x4000|(cdb.status<<8);
SSCR2 = 0x00cc;
SSCR3 = 0x0000;
SSCR4 = 0x0000;
cdb.trans_type = TRANS_TOC;
trans_start();
return HIRQ_DRDY;
}
// 0x03 [S-]
int get_session_info(void)
{
int sid, fad;
sid = cdb.cr1&0xff;
SSLOG(_INFO, "get_session_info: sid=%d\n", sid);
SSCR1 = (cdb.status<<8);
SSCR2 = 0x0000;
if(sid==0){
fad = bswap32(cdb.TOC[101]);
SSCR3 = 0x0100 | ((fad>>16)&0xff);
SSCR4 = fad&0xffff;
}else if(sid==1){
SSCR3 = 0x0100;
SSCR4 = 0x0000;
}else{
SSCR3 = 0xffff;
SSCR4 = 0xffff;
}
return 0;
}
// 0x04 [SR]
int init_cdblock(void)
{
int i;
SSLOG(_INFO, "init_cdblock\n");
// Stop Play task
if(cdb.play_type!=0){
cdb.pause_request = 1;
cdb.play_wait = 0;
disk_task_wakeup();
do{
wait_pause_ok();
}while(cdb.pause_request);
}
// disable fifo irq
ST_CTRL &= ~STIRQ_DAT;
// reset fifo
ST_CTRL |= 0x0100;
ST_CTRL &=~0x0100;
cdb.trans_type = 0;
cdb.cdwnum = 0;
// Galaxy Fight: 在play之后发出init_cdblock命令. 此处不能设置当前fad否则会破坏之前的play。
//cdb.fad = 150;
cdb.cdir_lba = 0;
cdb.root_lba = 0;
// free all block
cdb.block_free = MAX_BLOCKS;
for(i=0; i<MAX_BLOCKS; i++){
cdb.block[i].size = -1;
}
// reset all filter
for(i=0; i<MAX_SELECTORS; i++){
cdb.part[i].size = -1;
cdb.part[i].numblocks = 0;
cdb.part[i].head = NULL;
cdb.part[i].tail = NULL;
cdb.filter[i].c_false = 0xff;
cdb.filter[i].c_true = i;
cdb.filter[i].mode = 0;
cdb.filter[i].fad = 0;
cdb.filter[i].range = 0;
cdb.filter[i].chan = 0;
cdb.filter[i].smmask = 0;
cdb.filter[i].cimask = 0;
cdb.filter[i].smval = 0;
cdb.filter[i].cival = 0;
}
cdb.saturn_auth = 0;
cdb.mpeg_auth = 0;
HIRQ_CLR = HIRQ_PEND | HIRQ_DRDY | HIRQ_BFUL;
set_report(cdb.status);
return HIRQ_ESEL|HIRQ_EHST;
}
// 0x05 [S-]
int open_tray(void)
{
SSLOG(_INFO, "open_tray\n");
SSCR1 = (cdb.status<<8);
SSCR2 = 0x0000;
SSCR3 = 0x0000;
SSCR4 = 0x0000;
return 0;
}
// 0x06 [S-]
int end_trans(void)
{
int fifo_remain;
// disable fifo irq
ST_CTRL &= ~STIRQ_DAT;
ST_STAT = STIRQ_DAT;
if(cdb.trans_type==TRANS_PUT){
if(cdb.trans_bk){
SSLOG(_BUFIO, "end_trans: wait trans_put ...\n");
while(cdb.trans_bk){
trans_handle();
cdc_delay(1);
}
}
}else{
SSLOG(_BUFIO, "end_trans: cdwnum=%08x FIFO_STAT=%08x RCNT=%04x min_num=%d\n", cdb.cdwnum, FIFO_STAT, FIFO_RCNT, min_num);
fifo_remain = (FIFO_STAT&0x0fff)*2; // FIFO中还有多少字节未读
if(fifo_remain>=512){
//FIFO中的数据大于512字节不会产生中断。cdwnum会少记一次。
cdb.cdwnum += 0x800;
}
cdb.cdwnum -= fifo_remain;
SSLOG(_BUFIO, " : cdwnum=%08x\n", cdb.cdwnum);
}
// reset fifo
ST_CTRL |= 0x0100;
ST_CTRL &=~0x0100;
if(cdb.trans_type==TRANS_DATA_DEL){
PARTITION *pp = &cdb.part[cdb.trans_part_index];
int spos = cdb.trans_block_start;
int snum = cdb.trans_block_end-spos;
while(snum){
remove_block(pp, spos);
snum -= 1;
}
}
if(cdb.cdwnum){
SSCR1 = (cdb.status<<8) | ((cdb.cdwnum>>17)&0xff);
SSCR2 = (cdb.cdwnum>>1)&0xffff;
}else{
SSCR1 = (cdb.status<<8) | 0xff;
SSCR2 = 0xffff;
}
SSCR3 = 0;
SSCR4 = 0;
cdb.cdwnum = 0;
cdb.trans_type = 0;
return HIRQ_EHST;
}
/******************************************************************************/
// CD drive 相关命令
// cdb.fad: 当前播放的位置
// 0x10 [SR]
int play_cd(void)
{
int start_pos, end_pos, mode;
start_pos = ((cdb.cr1&0xff)<<16) | cdb.cr2;
end_pos = ((cdb.cr3&0xff)<<16) | cdb.cr4;
mode = cdb.cr3>>8;
if(cdb.play_type!=0){
cdb.pause_request = 1;
cdb.play_wait = 0;
SSLOG(_CDRV, "play_cd: Send PAUSE request!\n");
do{
wait_pause_ok();
}while(cdb.pause_request);
}
SSLOG(_CDRV, "play_cd: start=%08x end=%08x mode=%02x\n", start_pos, end_pos, mode);
HIRQ_CLR = HIRQ_PEND;
int play_tno = 0;
if(start_pos==0xffffff){
// PTYPE_NOCHG
}else if(start_pos&0x800000){
// PTYPE_FAD
cdb.play_fad_start = start_pos&0x0fffff;
cdb.track = fad_to_track(cdb.play_fad_start);
cdb.index = 1;
}else{
// PTYPE_TNO or PTYPE_DFL
if(start_pos==0)
start_pos = 0x0100;
cdb.play_fad_start = track_to_fad(start_pos);
cdb.track = (start_pos>>8)&0xff;
cdb.index = start_pos&0xff;
play_tno = 1;
}
if(end_pos==0xffffff){
// PTYPE_NOCHG
}else if(end_pos&0x800000){
// PTYPE_FAD
cdb.play_fad_end = cdb.play_fad_start+end_pos&0x0fffff;
}else if(end_pos){
// PTYPE_TNO
if((end_pos&0xff)>1)
cdb.play_fad_end = track_to_fad(end_pos);
else
cdb.play_fad_end = track_to_fad((end_pos&0xff00)|0x63);
if(play_tno){
// STEAM-HEART'S fixup
// 明确指定start与stop的情况下,强制更新fad.
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
}
}else{
// PTYPE_DFL
cdb.play_fad_end = track_to_fad(0xffff);
}
if((mode&0x80)==0){
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
}
if((mode&0x7f)!=0x7f)
cdb.max_repeat = mode&0x0f;
cdb.repcnt = 0;
cdb.pause_request = 0;
cdb.play_type = PLAYTYPE_SECTOR;
disk_task_wakeup();
set_report(STAT_BUSY);
return 0;
}
// 0x11 [SR]
int seek_cd(void)
{
int pos;
TRACK_INFO *ti;
pos = ((cdb.cr1&0xff)<<16) | cdb.cr2;
SSLOG(_CDRV, "\nseek_cd: pos=%08x\n", pos);
if(cdb.play_type!=0){
cdb.pause_request = 1;
cdb.play_wait = 0;
SSLOG(_CDRV, " : Send PAUSE request!\n");
do{
wait_pause_ok();
}while(cdb.pause_request);
}
cdb.status = STAT_PAUSE;
if(pos==0xffffff){
// act as PAUSE cmd
SSLOG(_CDRV, " : PAUSE cmd\n");
}else if(pos&0x800000){
// PTYPE_FAD
cdb.play_fad_start = pos&0x0fffff;
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
cdb.track = fad_to_track(cdb.play_fad_start);
cdb.index = 1;
cdb.options = 0x00;
cdb.repcnt = 0;
ti = &cdb.tracks[cdb.track-1];
if(ti->mode==3){
// Steam Heart
// 使用Seek, Play(00ffffff, 00ffffff, ff)来继续播放音轨
// 需要指定play_fad_end.
cdb.play_fad_end = ti->fad_end;
}else{
// 三国志: 吞食天地2
// Seek后, Play(00ffffff, 00ffffff, ff).
// 需要指定play_fad_end以免Play多读数据.
cdb.old_fad = cdb.fad;
cdb.play_fad_end = cdb.fad;
}
}else{
// PTYPE_TNO
if(pos){
cdb.play_fad_start = track_to_fad(pos);
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
cdb.track = (pos>>8)&0xff;
cdb.index = pos&0xff;
cdb.options = 0x00;
cdb.repcnt = 0;
ti = get_track_info(pos);
cdb.ctrladdr = ti->ctrl_addr;
}else{
cdb.status = STAT_STANDBY;
cdb.fad = 0xffffffff;
cdb.track = 0xff;
cdb.index = 0xff;
cdb.ctrladdr = 0xff;
cdb.repcnt = 0xff;
cdb.options = 0xff;
}
}
SSLOG(_CDRV, " : fad=%08x track=%d index=%d ctladr=%02x opt=%02x\n",
cdb.fad, cdb.track, cdb.index, cdb.ctrladdr, cdb.options);
set_report(cdb.status);
return 0;
}
// 0x12 [SR]
// Scan not support
/******************************************************************************/
// Subcode 相关命令
int TOBCD(int val)
{
return ((val/10)<<4) | (val%10);
}
void fad_to_msf(int fad, int *m, int *s, int *f)
{
*m = fad/4500;
fad %= 4500;
*s = fad/75;
*f = fad%75;
}
// 0x20 [S-]
int get_subcode(void)
{
int type;
int rel_fad, rm, rs, rf, m, s, f;
if(cdb.trans_type){
set_status(STAT_WAIT | cdb.status);
return 0;
}
type = cdb.cr1&0xff;
//SSLOG(_INFO, "get_subcode: type=%d\n", type);
if(type==0){
// Get Q Channel
SSCR1 = 0x4000 | (cdb.status<<8);
SSCR2 = 5;
SSCR3 = 0;
SSCR4 = 0;
rel_fad = cdb.fad-cdb.tracks[cdb.track-1].fad_start;
fad_to_msf(rel_fad, &rm, &rs, &rf);
fad_to_msf(cdb.fad, &m, &s, &f);
cdb.SUBH[0] = cdb.ctrladdr;
cdb.SUBH[1] = TOBCD(cdb.track);
cdb.SUBH[2] = TOBCD(cdb.index);
cdb.SUBH[3] = TOBCD(rm);
cdb.SUBH[4] = TOBCD(rs);
cdb.SUBH[5] = TOBCD(rf);
cdb.SUBH[6] = 0;
cdb.SUBH[7] = TOBCD(m);
cdb.SUBH[8] = TOBCD(s);
cdb.SUBH[9] = TOBCD(f);
cdb.trans_type = TRANS_SUBQ;
trans_start();
}else if(type==1){
// Get RW Channel
SSCR1 = 0x4000 | (cdb.status<<8);
SSCR2 = 12;
SSCR3 = 0;
SSCR4 = 0;
cdb.trans_type = TRANS_SUBRW;
trans_start();
}
return HIRQ_DRDY;
}
/******************************************************************************/
// CD-ROM device 相关命令
// 0x30 [SR]
int set_cdev_connect(void)
{
SSLOG(_CDRV, "set_cdev_connect: %d\n", cdb.cr3>>8);
cdb.cddev_filter = cdb.cr3>>8;
return HIRQ_ESEL;
}
// 0x31 [S-]
int get_cdev_connect(void)
{
SSCR1 = (cdb.status<<8);
SSCR2 = 0;
SSCR3 = cdb.cddev_filter<<8;
SSCR4 = 0;
return 0;
}
// 0x32 [S-]
int get_last_buffer(void)
{
SSCR1 = (cdb.status<<8);
SSCR2 = 0;
SSCR3 = cdb.last_buffer<<8;
SSCR4 = 0;
return 0;
}
/******************************************************************************/
// 过滤器相关命令
static void _set_filter(int fid, int mode, int fad, int range)
{
FILTER *ft = &cdb.filter[fid];
ft->mode = mode;
ft->fad = fad;
ft->range = range;
}
// 0x40 [SR]
int set_filter_range(void)
{
int fid;
fid = cdb.cr3>>8;
cdb.filter[fid].fad = ((cdb.cr1&0xff)<<16) | cdb.cr2;
cdb.filter[fid].range = ((cdb.cr3&0xff)<<16) | cdb.cr4;
SSLOG(_FILTER, "set_filter_range: fid=%d fad=%08x range=%08x\n", fid, cdb.filter[fid].fad, cdb.filter[fid].range);
return HIRQ_ESEL;
}
// 0x41 [S-]
int get_filter_range(void)
{
int fid;
int fad, range;
fid = cdb.cr3>>8;
fad = cdb.filter[fid].fad;
range = cdb.filter[fid].range;
SSCR1 = (cdb.status<<8) | ((fad>>16)&0xff);
SSCR2 = fad&0xffff;
SSCR3 = (range>>16)&0xff;
SSCR4 = range&0xffff;
return 0;
}
// 0x42 [SR]
int set_filter_subheader(void)
{
int fid;
fid = cdb.cr3>>8;
cdb.filter[fid].chan = cdb.cr1&0xff;
cdb.filter[fid].smmask = cdb.cr2>>8;
cdb.filter[fid].cimask = cdb.cr2&0xff;
cdb.filter[fid].fid = cdb.cr3&0xff;
cdb.filter[fid].smval = cdb.cr4>>8;
cdb.filter[fid].cival = cdb.cr4&0xff;
SSLOG(_FILTER, "set_filter_subh: fid=%d FN=%02x CN=%02x SMM=%02x CIM=%02x SM=%02x CI=%02x\n", fid,
cdb.filter[fid].fid, cdb.filter[fid].chan,
cdb.filter[fid].smmask, cdb.filter[fid].cimask,
cdb.filter[fid].smval, cdb.filter[fid].cival
);
return HIRQ_ESEL;
}
// 0x43 [S-]
int get_filter_subheader(void)
{
int fid;
fid = cdb.cr3>>8;
SSCR1 = (cdb.status) | cdb.filter[fid].chan;
SSCR2 = (cdb.filter[fid].smmask<<8) | cdb.filter[fid].cimask;
SSCR3 = cdb.filter[fid].fid;
SSCR4 = (cdb.filter[fid].smval<<8) | cdb.filter[fid].cival;
return 0;
}
// 0x44 [SR]
int set_filter_mode(void)
{
int fid;
fid = cdb.cr3>>8;
cdb.filter[fid].mode = cdb.cr1&0xff;
SSLOG(_FILTER, "set_filter_mode: fid=%d mode=%02x\n", fid, cdb.cr1&0xff);
if(cdb.filter[fid].mode&0x80){
cdb.filter[fid].mode = 0;
cdb.filter[fid].fad = 0;
cdb.filter[fid].range = 0;
cdb.filter[fid].chan = 0;
cdb.filter[fid].smmask = 0;
cdb.filter[fid].cimask = 0;
cdb.filter[fid].smval = 0;
cdb.filter[fid].cival = 0;
}
return HIRQ_ESEL;
}
// 0x45 [S-]
int get_filter_mode(void)
{
int fid;
fid = cdb.cr3>>8;
SSCR1 = (cdb.status<<8) | cdb.filter[fid].mode;
SSCR2 = 0;
SSCR3 = 0;
SSCR4 = 0;
return 0;
}
// 0x46 [SR]
int set_filter_connection(void)
{
int fid, flag, ct, cf;
flag = cdb.cr1&0xff;
ct = cdb.cr2>>8;
cf = cdb.cr2&0xff;
fid = cdb.cr3>>8;
SSLOG(_FILTER, "set_filter_connection: fid=%d flag=%d true=%02x false=%02x\n", fid, flag, ct, cf);
if(fid>=24)
return 0;
if(flag&1){
if(ct>=24 && ct!=0xff)
return 0;
cdb.filter[fid].c_true = ct;
}
if(flag&2){
if(cf>=24 && cf!=0xff)
return 0;
cdb.filter[fid].c_false = cf;
}
return HIRQ_ESEL;
}
// 0x47 [S-]
int get_filter_connection(void)
{
int fid;
fid = cdb.cr3>>8;
SSCR1 = (cdb.status<<8);
SSCR2 = (cdb.filter[fid].c_true<<8) | cdb.filter[fid].c_false;
SSCR3 = 0;
SSCR4 = 0;
return 0;
}
void free_partition(PARTITION *pt)
{
BLOCK *bp = pt->head;
while(bp){
free_block(bp);
bp = bp->next;
}
pt->head = NULL;
pt->tail = NULL;
pt->numblocks = 0;
pt->size = -1;
}
// 0x48 [SR]
int reset_filter(void)
{
int mode, fid;
int i, j;
mode = cdb.cr1&0xff;
fid = cdb.cr3>>8;
SSLOG(_FILTER, "reset_filter: mode=%02x fid=%d\n", mode, fid);
if(fid==cdb.cddev_filter && cdb.play_type!=0 && cdb.play_track->mode!=3){
cdb.pause_request = 1;
cdb.play_wait = 0;
SSLOG(_CDRV, "reset_filter: Send PAUSE request!\n");
do{
wait_pause_ok();
}while(cdb.pause_request);
}
if(mode==0){
if(fid<MAX_SELECTORS){
free_partition(&cdb.part[fid]);
}
}else{
for(i=0; i<MAX_SELECTORS; i++){
if(mode&0x80){
cdb.filter[i].c_false = 0xff;
}
if(mode&0x40){
cdb.filter[i].c_true = i;
}
if(mode&0x10){
cdb.filter[i].mode = 0;
cdb.filter[i].fad = 0;
cdb.filter[i].range = 0;
cdb.filter[i].chan = 0;
cdb.filter[i].smmask = 0;
cdb.filter[i].cimask = 0;
cdb.filter[i].smval = 0;
cdb.filter[i].cival = 0;
}
if(mode&0x04){
free_partition(&cdb.part[i]);
}
}
if(mode&0x04){
cdb.block_free = MAX_BLOCKS;
for(j=0; j<MAX_BLOCKS; j++){
cdb.block[j].size = -1;;
}
}
}
return HIRQ_ESEL;
}
/******************************************************************************/
// buffer info 相关命令
u8 old_block_free;
// 0x50 [S-]
int get_buffer_size(void)
{
SSCR1 = (cdb.status<<8);
SSCR2 = cdb.block_free;
SSCR3 = MAX_SELECTORS<<8;
SSCR4 = MAX_BLOCKS;
if(old_block_free!=cdb.block_free){
SSLOG(_BUFINFO, "get_buffer_size: free=%d\n", cdb.block_free);
}
old_block_free = cdb.block_free;
return 0;
}
int old_numblocks;
// 0x51 [S-]
int get_sector_num(void)
{
int pt;
pt = cdb.cr3>>8;
SSCR1 = (cdb.status<<8);
SSCR2 = 0;
SSCR3 = 0;
SSCR4 = cdb.part[pt].numblocks;
if(old_numblocks != cdb.part[pt].numblocks){
SSLOG(_BUFINFO, "get_sector_num: part=%d(%d)\n", pt, cdb.part[pt].numblocks);
}
old_numblocks = cdb.part[pt].numblocks;
return 0;
}
// 0x52 [SR]
int cal_actual_size(void)
{
int pt, spos, snum, size;
BLOCK *bp;
spos = cdb.cr2;
pt = cdb.cr3>>8;
snum = cdb.cr4;
SSLOG(_BUFINFO, "cacl_act_size: pt=%d spos=%d snum=%d\n", pt, spos, snum);
size = 0;
bp = find_block(&cdb.part[pt], spos);
while(bp && snum){
size += bp->size;
bp = bp->next;
snum -= 1;
}
cdb.actsize = size;
return HIRQ_ESEL;
}
// 0x53 [S-]
int get_actual_size(void)
{
SSCR1 = (cdb.status<<8) | (((cdb.actsize/2)>>16)&0xff);
SSCR2 = (cdb.actsize/2)&0xffff;
SSCR3 = 0;
SSCR4 = 0;
SSLOG(_BUFINFO, "get_actual_size: %08x\n", cdb.actsize);
return 0;
}
// 0x54 [S-]
int get_sector_info(void)
{
int pt, st;
PARTITION *pp;
BLOCK *bp;
pt = cdb.cr3>>8;
st = cdb.cr2&0xff;
pp = &cdb.part[pt];
bp = find_block(pp, st);
SSCR1 = (cdb.status<<8) | (bp->fad>>16)&0xff;
SSCR2 = (bp->fad)&0xffff;
SSCR3 = (bp->fn<<8) | (bp->cn);
SSCR4 = (bp->sm<<8) | (bp->ci);
return 0;
}
// 0x55 [SR]
// 0x56 [SR]
/******************************************************************************/
// buffer I/O相关命令
u32 sector_len_table[4] = {2048, 2336, 2340, 2352};
// 0x60 [SR]
int set_sector_length(void)
{
int id_get, id_put;
id_get = SSCR1&0xff;
id_put = SSCR2>>8;
SSLOG(_INFO, "set_sector_length: get=%d put=%d\n", id_get, id_put);
if(id_get<4){
cdb.sector_size = sector_len_table[id_get];
}
if(id_put<4){
cdb.put_sector_size = sector_len_table[id_put];
}
return HIRQ_ESEL;
}
// 0x61 [SR]
int get_sector_data(void)
{
int pt, spos, snum;
PARTITION *pp;
if(cdb.trans_type){
set_status(STAT_WAIT | cdb.status);
return 0;
}
pt = cdb.cr3>>8;
spos = cdb.cr2;
snum = cdb.cr4;
pp = &cdb.part[pt];
if(spos==0xffff){
spos = pp->numblocks-1;
}
if(snum==0xffff){
snum = pp->numblocks-spos;
}
SSLOG(_BUFIO, "get_sector_data: part=%d(%d) spos=%d snum=%d\n", pt, pp->numblocks, spos, snum);
if(spos<0 || snum<=0 || (spos+snum) > pp->numblocks){
set_status(STAT_WAIT | cdb.status);
return 0;
}
cdb.trans_type = TRANS_DATA;
cdb.trans_part_index = pt;
cdb.trans_block_start = spos;
cdb.trans_block_end = spos+snum;
trans_start();
set_status(STAT_TRNS | cdb.status);
return HIRQ_DRDY|HIRQ_EHST;
}
// 0x62 [SR]
int del_sector_data(void)
{
int pt, spos, snum;
PARTITION *pp;
pt = cdb.cr3>>8;
spos = cdb.cr2;
snum = cdb.cr4;
pp = &cdb.part[pt];
if(spos==0xffff){
spos = pp->numblocks-1;
}
if(snum==0xffff){
snum = pp->numblocks-spos;
}
SSLOG(_BUFIO, "del_sector_data: part=%d spos=%d snum=%d\n", pt, spos, snum);
if(spos<0 || snum<=0 || (spos+snum) > pp->numblocks){
// 梦幻之星1会传入spos=180导致后续错误
set_status(STAT_WAIT | cdb.status);
return 0;
}
while(snum){
remove_block(pp, spos);
snum -= 1;
}
return HIRQ_EHST;
}
// 0x63 [SR]
int get_del_sector_data(void)
{
int pt, spos, snum;
PARTITION *pp;
if(cdb.trans_type){
set_status(STAT_WAIT | cdb.status);
return 0;
}
pt = cdb.cr3>>8;
spos = cdb.cr2;
snum = cdb.cr4;
pp = &cdb.part[pt];
SSLOG(_BUFIO, "get_del_sector_data: part=%d(%d) spos=%d snum=%d\n", pt, pp->numblocks, spos, snum);
if(spos==0xffff){
spos = pp->numblocks-1;
}
if(snum==0xffff){
snum = pp->numblocks-spos;
}
SSLOG(_BUFIO, " : part=%d(%d) spos=%d snum=%d\n", pt, pp->numblocks, spos, snum);
if(spos<0 || snum<=0 || (spos+snum) > pp->numblocks){
// 格兰蒂亚: 传入了snum=0. 似乎应该直接返回.
set_status(STAT_WAIT | cdb.status);
return 0;
}
cdb.trans_type = TRANS_DATA_DEL;
cdb.trans_part_index = pt;
cdb.trans_block_start = spos;
cdb.trans_block_end = spos+snum;
trans_start();
set_status(STAT_TRNS | cdb.status);
return HIRQ_DRDY|HIRQ_EHST;
}
// 0x64 [SR]
int put_sector_data(void)
{
int pt, snum;
PARTITION *pp;
if(cdb.trans_type){
set_status(STAT_WAIT | cdb.status);
return 0;
}
pt = cdb.cr3>>8;
snum = cdb.cr4;
SSLOG(_BUFIO, "put_sector_data: part=%d snum=%d put_sector_size=%d\n", pt, snum, cdb.put_sector_size);
cdb.trans_type = TRANS_PUT;
cdb.trans_part_index = pt;
cdb.trans_bk = snum;
// reset fifo
ST_CTRL |= 0x0100;
ST_CTRL &=~0x0100;
ST_STAT = STIRQ_DAT;
ST_CTRL |= 0x0200 | STIRQ_DAT;
set_status(cdb.status);
return HIRQ_DRDY;
}
// 0x67 [S-]
int get_copy_error(void)
{
SSCR1 = (cdb.status<<8);
SSCR2 = 0;
SSCR3 = 0;
SSCR4 = 0;
return 0;
}
/******************************************************************************/
static u32 isonum_711(u8 *p)
{
return p[0];
}
static u32 isonum_733(u8 *p)
{
return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
}
void fill_fileinfo(void)
{
int ptid = cdb.filter[cdb.dir_filter].c_true;
PARTITION *pt = &cdb.part[ptid];
BLOCK *blk = pt->head;
u8 *buf = blk->data+24;
int rsize, p, start, end, pfn, fid;
rsize = cdb.cdir_size-1;
p = 0;
start = cdb.cdir_pfid;
if(start<2){
end = 256;
pfn = 0;
cdb.cdir_pfid = 2;
}else{
end = start+254;
pfn = 2;
cdb.cdir_pfid = start;
}
cdb.cdir_drend = 0;
fid = 0;
while(fid<end){
if(fid>=start){
cdb.fi[pfn].lba = isonum_733(buf+p+2);
cdb.fi[pfn].size = isonum_733(buf+p+10);
cdb.fi[pfn].attr = isonum_711(buf+p+25);
cdb.fi[pfn].unit = isonum_711(buf+p+26);
cdb.fi[pfn].gap = isonum_711(buf+p+27);
cdb.fi[pfn].fid = 0;
#if 1
int nlen = *(u8*)(buf+p+32);
char *fname = (char*)(buf+p+33);
if(nlen>2)
nlen -= 2;
u8 save_byte = fname[nlen];
fname[nlen] = 0;
SSLOG(_FILEIO, " fid %3d: lba=%08x size=%08x attr=%02x %d %s\n",
fid, cdb.fi[pfn].lba, cdb.fi[pfn].size, cdb.fi[pfn].attr, nlen, buf+p+33);
fname[nlen] = save_byte;
#endif
if(fid>1 && cdb.fi[pfn].attr&0x02)
cdb.cdir_drend = 1;
pfn += 1;
}
fid += 1;
p += buf[p];
if(p>=2048 || buf[p]==0){
if(rsize==0)
break;
rsize -= 1;
p = 0;
blk = blk->next;
buf = blk->data+24;
}
}
cdb.cdir_pfnum = pfn-2;
SSLOG(_FILEIO, " cdir_pfid=%d fnum=%d\n", cdb.cdir_pfid, cdb.cdir_pfnum);
}
int handle_diread(void)
{
int ptid = cdb.filter[cdb.dir_filter].c_true;
PARTITION *pt = &cdb.part[ptid];
BLOCK *blk = pt->head;
u8 *buf = blk->data+24;
SSLOG(_FILEIO, "handle_diread %d\n", cdb.rdir_state);
if(cdb.rdir_state==1){
// 主描述符已读
cdb.root_lba = isonum_733(buf+0x9c+2);
cdb.root_size = isonum_733(buf+0x9c+10)/2048;
free_partition(pt);
SSLOG(_FILEIO, " root_lba=%08x size=%08x\n", cdb.root_lba, cdb.root_size);
cdb.cdir_lba = cdb.root_lba;
cdb.cdir_size = cdb.root_size;
// 准备读根目录
cdb.rdir_state = 2;
cdb.pause_request = 0;
cdb.play_type = PLAYTYPE_DIR;
cdb.play_fad_start = cdb.cdir_lba+150;
cdb.track = fad_to_track(cdb.play_fad_start);
cdb.play_fad_end = cdb.play_fad_start+cdb.cdir_size;
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
_set_filter(cdb.dir_filter, 0x40, cdb.play_fad_start, cdb.cdir_size);
return 1;
}else if(cdb.rdir_state==2){
// 目录数据已读。开始填充文件信息
SSLOG(_FILEIO, " cdir_lba=%08x size=%08x\n", cdb.cdir_lba, cdb.cdir_size);
fill_fileinfo();
free_partition(pt);
HIRQ = HIRQ_EFLS;
}
return 0;
}
// 0x70 [SR]
int change_dir(void)
{
int selnum, fid;
FILE_INFO *fi;
selnum = cdb.cr3>>8;
fid = ((cdb.cr3&0xff)<<16) | (cdb.cr4);
SSLOG(_FILEIO, "change_dir: sel=%d fid=%08x root_lba=%08x\n", selnum, fid, cdb.root_lba);
cdb.dir_filter = selnum;
if(fid==0xffffff){
// 切换到根目录
cdb.cdir_pfid = 0;
if(cdb.root_lba==0){
// 需要先读主描述符扇区,以便取得根目录的LBA地址
cdb.rdir_state = 1;
cdb.cddev_filter = selnum;
cdb.pause_request = 0;
cdb.play_type = PLAYTYPE_DIR;
cdb.play_fad_start = 16+150;
cdb.track = fad_to_track(cdb.play_fad_start);
cdb.play_fad_end = cdb.play_fad_start+1;
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
_set_filter(selnum, 0x40, cdb.play_fad_start, 1);
disk_task_wakeup();
}else{
// 已经有根目录的LBA地址
cdb.cdir_lba = cdb.root_lba;
cdb.cdir_size = cdb.root_size;
cdb.rdir_state = 2;
cdb.cddev_filter = selnum;
cdb.pause_request = 0;
cdb.play_type = PLAYTYPE_DIR;
cdb.play_fad_start = cdb.cdir_lba+150;
cdb.track = fad_to_track(cdb.play_fad_start);
cdb.play_fad_end = cdb.play_fad_start+cdb.cdir_size;
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
_set_filter(selnum, 0x40, cdb.play_fad_start, cdb.cdir_size);
disk_task_wakeup();
}
}else{
// 切换到fid所指的目录
if(cdb.cdir_lba){
if(fid<2){
fi = &cdb.fi[fid];
}else{
if(fid<cdb.cdir_pfid || fid>=(cdb.cdir_pfid+cdb.cdir_pfnum)){
set_status(STAT_REJECT);
return 0;
}else{
fi = &cdb.fi[fid-cdb.cdir_pfid+2];
}
}
cdb.cdir_lba = fi->lba;
cdb.cdir_size = fi->size/2048;
cdb.cdir_pfid = 0;
cdb.rdir_state = 2;
cdb.cddev_filter = selnum;
cdb.pause_request = 0;
cdb.play_type = PLAYTYPE_DIR;
cdb.play_fad_start = cdb.cdir_lba+150;
cdb.track = fad_to_track(cdb.play_fad_start);
cdb.play_fad_end = cdb.play_fad_start+cdb.cdir_size;
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
_set_filter(selnum, 0x40, cdb.play_fad_start, cdb.cdir_size);
disk_task_wakeup();
}else{
set_status(STAT_REJECT);
return 0;
}
}
set_report(cdb.status);
return 0;
}
// 0x71 [SR]
int read_dir(void)
{
int selnum, fid;
selnum = cdb.cr3>>8;
fid = ((cdb.cr3&0xff)<<16) | (cdb.cr4);
SSLOG(_FILEIO, "read_dir: sel=%d fid=%08x\n", selnum, fid);
if(cdb.cdir_lba){
cdb.cdir_pfid = fid;
cdb.rdir_state = 2;
cdb.cddev_filter = selnum;
cdb.pause_request = 0;
cdb.play_type = PLAYTYPE_DIR;
cdb.play_fad_start = cdb.cdir_lba+150;
cdb.track = fad_to_track(cdb.play_fad_start);
cdb.play_fad_end = cdb.play_fad_start+cdb.cdir_size;
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
_set_filter(selnum, 0x40, cdb.play_fad_start, cdb.cdir_size);
disk_task_wakeup();
}else{
set_status(STAT_REJECT);
return 0;
}
set_report(cdb.status);
return 0;
}
// 0x72 [S-]
int get_file_scope(void)
{
SSLOG(_FILEIO, "get_file_scope: pfid=%d pfnum=%d\n", cdb.cdir_pfid, cdb.cdir_pfnum);
SSCR1 = (cdb.status<<8);
SSCR2 = cdb.cdir_pfnum;
SSCR3 = cdb.cdir_drend<<8;
SSCR4 = cdb.cdir_pfid;
return HIRQ_EFLS;
}
// 0x73 [S-]
int get_file_info(void)
{
int i;
if(cdb.trans_type){
set_status(STAT_WAIT | cdb.status);
return 0;
}
i = ((cdb.cr3&0xff)<<16) | cdb.cr4;
SSLOG(_FILEIO, "get_file_info: fid=%08x\n", i);
if(i==0xffffff){
// 不返回当前目录和根目录信息
for(i=0; i<cdb.cdir_pfnum; i++){
*(u32*)(cdb.FINFO+i*12+0) = bswap32(cdb.fi[i+2].lba+150);
*(u32*)(cdb.FINFO+i*12+4) = bswap32(cdb.fi[i+2].size);
*(u8 *)(cdb.FINFO+i*12+8) = cdb.fi[i+2].gap;
*(u8 *)(cdb.FINFO+i*12+9) = cdb.fi[i+2].unit;
*(u8 *)(cdb.FINFO+i*12+10)= cdb.fi[i+2].fid;
*(u8 *)(cdb.FINFO+i*12+11)= cdb.fi[i+2].attr;
}
cdb.trans_type = TRANS_FINFO_ALL;
trans_start();
SSCR1 = 0x4000 | (cdb.status<<8);
SSCR2 = (cdb.cdir_pfnum*12)/2;
SSCR3 = 0x0000;
SSCR4 = 0x0000;
}else{
if(i<cdb.cdir_pfid || i>=(cdb.cdir_pfid+cdb.cdir_pfnum)){
// fid不在当前目录页的范围内
set_status(STAT_REJECT);
return 0;
}
i = i-cdb.cdir_pfid+2;
*(u32*)(cdb.FINFO+0) = bswap32(cdb.fi[i].lba+150);
*(u32*)(cdb.FINFO+4) = bswap32(cdb.fi[i].size);
*(u8 *)(cdb.FINFO+8) = cdb.fi[i].gap;
*(u8 *)(cdb.FINFO+9) = cdb.fi[i].unit;
*(u8 *)(cdb.FINFO+10)= cdb.fi[i].fid;
*(u8 *)(cdb.FINFO+11)= cdb.fi[i].attr;
cdb.trans_type = TRANS_FINFO_ONE;
trans_start();
SSCR1 = 0x4000 | (cdb.status<<8);
SSCR2 = 0x0006;
SSCR3 = 0x0000;
SSCR4 = 0x0000;
}
return HIRQ_DRDY;
}
// 0x74 [SR]
int read_file(void)
{
int selnum, fid, offset, lba_size;
FILTER *fsl;
FILE_INFO *fi;
if(cdb.play_type){
SSLOG(_FILEIO, "read_file: waiting ...\n");
while(cdb.play_type){
cdc_delay(10);
}
}
selnum = cdb.cr3>>8;
offset = ((cdb.cr1&0xff)<<16) | cdb.cr2;
fid = ((cdb.cr3&0xff)<<16) | cdb.cr4;
SSLOG(_FILEIO, "read_file: sel=%d fid=%08x\n", selnum, fid);
if(fid<cdb.cdir_pfid || fid>=(cdb.cdir_pfid+cdb.cdir_pfnum)){
set_status(STAT_REJECT);
return 0;
}
fid = fid-cdb.cdir_pfid+2;
fi = &cdb.fi[fid];
lba_size = (fi->size+2047)/2048;
if(offset>=lba_size){
set_status(STAT_REJECT);
return 0;
}
fsl = &cdb.filter[selnum];
free_partition(&cdb.part[fsl->c_true]);
cdb.cddev_filter = selnum;
cdb.repcnt = 0;
cdb.pause_request = 0;
cdb.play_type = PLAYTYPE_FILE;
cdb.play_fad_start = fi->lba+offset+150;
cdb.track = fad_to_track(cdb.play_fad_start);
cdb.play_fad_end = cdb.play_fad_start + lba_size-offset;
cdb.old_fad = cdb.fad;
cdb.fad = cdb.play_fad_start;
cdb.options = 0x08;
_set_filter(selnum, 0x40, cdb.play_fad_start, lba_size-offset);
disk_task_wakeup();
set_report(cdb.status);
return 0;
}
// 0x75 [SR]
int abort_file(void)
{
SSLOG(_FILEIO, "abort_file\n");
if(cdb.play_type==PLAYTYPE_FILE){
cdb.pause_request = 1;
cdb.play_wait = 0;
disk_task_wakeup();
do{
wait_pause_ok();
}while(cdb.pause_request);
}
return HIRQ_EFLS;
}
/******************************************************************************/
// 0xe0 [S-]
int auth_device(void)
{
int mpeg_auth, hirq;
SSLOG(_INFO, "auth_device\n");
mpeg_auth = cdb.cr2&0xff;
if(mpeg_auth){
hirq = HIRQ_MPED;
cdb.mpeg_auth = 2;
}else{
hirq = HIRQ_EFLS | HIRQ_CSCT;
cdb.saturn_auth = 4;
}
SSCR1 = (STAT_BUSY<<8) | 0xff;
SSCR2 = 0xffff;
SSCR3 = 0xffff;
SSCR4 = 0xffff;
return hirq;
}
// 0xe1 [S-]
int get_auth_status(void)
{
SSLOG(_INFO, "get_auth_status\n");
if(cdb.cr2&0xff){
SSCR2 = cdb.mpeg_auth;
}else{
SSCR2 = cdb.saturn_auth;
}
SSCR1 = (cdb.status<<8);
SSCR3 = 0;
SSCR4 = 0;
return 0;
}
/******************************************************************************/
char *cmd_str(int cmd)
{
switch(cmd){
// common
case 0x00: return "get_cd_status";
case 0x01: return "get_hw_info";
case 0x02: return "get_toc_info";
case 0x03: return "get_session_info";
case 0x04: return "init_cdblock";
case 0x06: return "end_trans";
// cd drive
case 0x10: return "play_cd";
case 0x11: return "seek_cd";
// subcode
case 0x20: return "get_subcode";
// cd device
case 0x30: return "set_cdev_connect";
case 0x31: return "get_cdev_connect";
case 0x32: return "get_last_buffer";
// filter
case 0x40: return "set_filter_range";
case 0x41: return "get_filter_range";
case 0x42: return "set_filter_subheader";
case 0x43: return "get_filter_subheader";
case 0x44: return "set_filter_mode";
case 0x45: return "get_filter_mode";
case 0x46: return "set_filter_connection";
case 0x47: return "get_filter_connection";
case 0x48: return "reset_filter";
// buffer info
case 0x50: return "get_buffer_size";
case 0x51: return "get_sector_num";
case 0x52: return "cal_actual_size";
case 0x53: return "get_actual_size";
case 0x54: return "get_sector_info";
// buffer io
case 0x60: return "set_sector_length";
case 0x61: return "get_sector_data";
case 0x62: return "del_sector_data";
case 0x63: return "get_del_sector_data";
case 0x64: return "put_sector_data";
case 0x67: return "get_copy_error";
// file io
case 0x70: return "change_dir";
case 0x71: return "read_dir";
case 0x72: return "get_file_scope";
case 0x73: return "get_file_info";
case 0x74: return "read_file";
case 0x75: return "abort_file";
case 0xe0: return "auth_device";
case 0xe1: return "get_auth_status";
default : return "unkonw_cmd";
}
}
void cdc_cmd_process(void)
{
u32 cmd, hirq;
if((SS_CTRL&0x8000)==0)
return;
cmd = (cdb.cr1>>8)&0xff;
//if(cmd!=0)
SSLOG(_DEBUG, "\nSS CDC: %s\n", cmd_str(cmd));
cmd = (cdb.cr1>>8)&0xff;
switch(cmd){
// common
case 0x00: hirq = get_cd_status();
break;
case 0x01: hirq = get_hw_info();
break;
case 0x02: hirq = get_toc_info();
break;
case 0x03: hirq = get_session_info();
break;
case 0x04: hirq = init_cdblock();
break;
case 0x05: hirq = open_tray();
break;
case 0x06: hirq = end_trans();
break;
// cd drive
case 0x10: hirq = play_cd();
break;
case 0x11: hirq = seek_cd();
break;
// subcode
case 0x20: hirq = get_subcode();
break;
// cd device
case 0x30: hirq = set_cdev_connect();
break;
case 0x31: hirq = get_cdev_connect();
break;
case 0x32: hirq = get_last_buffer();
break;
// filter
case 0x40: hirq = set_filter_range();
break;
case 0x41: hirq = get_filter_range();
break;
case 0x42: hirq = set_filter_subheader();
break;
case 0x43: hirq = get_filter_subheader();
break;
case 0x44: hirq = set_filter_mode();
break;
case 0x45: hirq = get_filter_mode();
break;
case 0x46: hirq = set_filter_connection();
break;
case 0x47: hirq = get_filter_connection();
break;
case 0x48: hirq = reset_filter();
break;
// buffer info
case 0x50: hirq = get_buffer_size();
break;
case 0x51: hirq = get_sector_num();
break;
case 0x52: hirq = cal_actual_size();
break;
case 0x53: hirq = get_actual_size();
break;
case 0x54: hirq = get_sector_info();
break;
// buffer io
case 0x60: hirq = set_sector_length();
break;
case 0x61: hirq = get_sector_data();
break;
case 0x62: hirq = del_sector_data();
break;
case 0x63: hirq = get_del_sector_data();
break;
case 0x64: hirq = put_sector_data();
break;
case 0x67: hirq = get_copy_error();
break;
// file io
case 0x70: hirq = change_dir();
break;
case 0x71: hirq = read_dir();
break;
case 0x72: hirq = get_file_scope();
break;
case 0x73: hirq = get_file_info();
break;
case 0x74: hirq = read_file();
break;
case 0x75: hirq = abort_file();
break;
case 0xe0: hirq = auth_device();
break;
case 0xe1: hirq = get_auth_status();
break;
default:
printk("SS CDC: unknow cmd! CR1=%04x CR2=%04x CR3=%04x CR4=%04x\n",
cdb.cr1, cdb.cr2, cdb.cr3, cdb.cr4);
hirq = 0;
break;
}
// 很多游戏依靠检测SCDQ来等待数据。这里当有数据时始终发送SCDQ。
if(cdb.block_free!=MAX_BLOCKS){
hirq |= HIRQ_SCDQ;
}
HIRQ = hirq | HIRQ_CMOK;
#if 0
if(cmd!=0)
printk(" : CR1=%04x CR2=%04x CR3=%04x CR4=%04x HIRQ=%04x\n", RESP1, RESP2, RESP3, RESP4, HIRQ);
#endif
}
/******************************************************************************/