/* * Find out media capacity. */ uint32_t get_last_possible_lba(cd_device *dev) { uchar_t *di; uint32_t cap; di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); if (!read_disc_info(dev->d_fd, di)) { free(di); return (0); } /* * If we have a DVD+R this field is an LBA. If the media is * a CD-R/W the field is MSF formatted. Otherwise this field * is not valid and will be zero. */ if (device_type == DVD_PLUS) { if (read_scsi32(&di[20]) != 0xffffffff) { cap = read_scsi32(&di[20]); } else { cap = 0; } } else { if ((di[21] != 0) && (di[21] != 0xff)) { cap = MSF2LBA(di[21], di[22], di[23]); } else { cap = 0; } } free(di); return (cap); }
/* * Determine the starting LBA of the the session leadout by parsing the Raw TOC * format of the READ TOC/PMA/ATIP command response data. */ static int rtoc_get_sess_leadout_lba(uchar_t *rtoc, size_t rtoc_len, int sess_num, uint32_t *leadout_lba) { rtoc_td_t *tdp = (rtoc_td_t *)(rtoc + sizeof (rtoc_hdr_t)); rtoc_td_t *last_tdp = (rtoc_td_t *)(rtoc + rtoc_len - sizeof (rtoc_td_t)); while ((tdp = get_rtoc_td(tdp, last_tdp, Q_MODE_1, POINT_LEADOUT_ADDR)) != NULL) { if (tdp->rt_session_num == sess_num) { *leadout_lba = MSF2LBA(tdp->rt_pmin, tdp->rt_psec, tdp->rt_pframe); return (1); } else { ++tdp; } } return (0); }
void DoCommand(cdrom_Device *cd) { int i; /*for(i=0;i<=0x100000;i++) Data[i]=0; DataLen=0;*/ cd->StatusLen=0; cd->Poll &= ~POLST; cd->Poll &= ~POLDT; cd->XbusStatus &= ~CDST_ERRO; cd->XbusStatus &= ~CDST_RDY; switch(cd->Command[0]) { case 0x1: //seek //not used in opera //01 00 ll-bb-aa 00 00. //01 02 mm-ss-ff 00 00. //status 4 bytes //xx xx xx XS (xs=xbus status) // sprintf(str,"#CDROM 0x1 SEEK!!!\n"); // CDebug::DPrint(str); break; case 0x2: //spin up //opera status request = 0 //status 4 bytes //xx xx xx XS (xs=xbus status) if((cd->XbusStatus & CDST_TRAY) && (cd->XbusStatus & CDST_DISC)) { cd->XbusStatus |= CDST_SPIN; cd->XbusStatus |= CDST_RDY; cd->MEIStatus = MEI_CDROM_no_error; } else { cd->XbusStatus |= CDST_ERRO; cd->XbusStatus &= ~CDST_RDY; cd->MEIStatus = MEI_CDROM_recv_ecc; } cd->Poll |= POLST; //status is valid cd->StatusLen=2; cd->Status[0]=0x2; //cd->Status[1]=0x0; //cd->Status[2]=0x0; cd->Status[1] = cd->XbusStatus; break; case 0x3: // spin down //opera status request = 0 // not used in opera //status 4 bytes //xx xx xx XS (xs=xbus status) if((cd->XbusStatus & CDST_TRAY) && (cd->XbusStatus & CDST_DISC)) { cd->XbusStatus &= ~CDST_SPIN; cd->XbusStatus |= CDST_RDY; cd->MEIStatus=MEI_CDROM_no_error; } else { cd->XbusStatus|=CDST_ERRO; cd->XbusStatus|=CDST_RDY; cd->MEIStatus=MEI_CDROM_recv_ecc; } cd->Poll|=POLST; //status is valid cd->StatusLen=2; cd->Status[0]=0x3; //cd->Status[1]=0x0; //cd->Status[2]=0x0; cd->Status[1] = cd->XbusStatus; break; case 0x4: //diagnostics // not used in opera //04 00 ll-bb-aa 00 00. //04 02 mm-ss-ff 00 00. //status 4 bytes //xx S1 S2 XS // sprintf(str,"#CDROM 0x4 Diagnostic!!!\n"); // CDebug::DPrint(str); break; case 0x6: // eject disc //opera status request = 0 //status 4 bytes //xx xx xx XS // 1b command of scsi //emulation --- // Execute EJECT command; // Check Sense, update PollRegister (if medium present) cd->XbusStatus&=~CDST_TRAY; cd->XbusStatus&=~CDST_DISC; cd->XbusStatus&=~CDST_SPIN; cd->XbusStatus&=~CDST_2X; cd->XbusStatus&=~CDST_ERRO; cd->XbusStatus|=CDST_RDY; cd->Poll|=POLST; //status is valid cd->Poll&=~POLMA; cd->MEIStatus=MEI_CDROM_no_error; cd->StatusLen=2; cd->Status[0]=0x6; //cd->Status[1]=0x0; //cd->Status[2]=0x0; cd->Status[1]=cd->XbusStatus; /* ClearCDB(); CDB[0]=0x1b; CDB[4]=0x2; CDBLen=12; */ break; case 0x7: // inject disc //opera status request = 0 //status 4 bytes //xx xx xx XS //1b command of scsi // sprintf(str,"#CDROM 0x7 INJECT!!!\n"); // CDebug::DPrint(str); break; case 0x8: // abort !!! //opera status request = 31 //status 4 bytes //xx xx xx XS // cd->StatusLen=33; cd->Status[0]=0x8; for(i=1;i<32;i++) cd->Status[i]=0; cd->Status[32]=cd->XbusStatus; cd->XbusStatus|=CDST_RDY; cd->MEIStatus=MEI_CDROM_no_error; break; case 0x9: // mode set //09 MM nn 00 00 00 00 // 2048 or 2340 transfer size // to be checked -- wasn't called even once // 2nd byte is type selector // MM = mode nn= value //opera status request = 0 //status 4 bytes //xx xx xx XS // to check!!! // if((XbusStatus&CDST_TRAY) && (XbusStatus&CDST_DISC)) // { cd->XbusStatus |= CDST_RDY; cd->MEIStatus = MEI_CDROM_no_error; //CDMode[Command[1]]=Command[2]; // } // else // { // XbusStatus|=CDST_ERRO; // XbusStatus&=~CDST_RDY; // } cd->Poll |= POLST; //status is valid cd->StatusLen=2; cd->Status[0]=0x9; cd->Status[1] = cd->XbusStatus; break; case 0x0a: // reset //not used in opera //status 4 bytes //xx xx xx XS // sprintf(str,"#CDROM 0xa RESET!!!\n"); // CDebug::DPrint(str); break; case 0x0b: // flush //opera status request = 31 //status 4 bytes //xx xx xx XS //returns data //flush all internal buffer //1+31+1 cd->XbusStatus|=CDST_RDY; cd->StatusLen=33; cd->Status[0]=0xb; for(i=1;i<32;i++) cd->Status[i]=0; cd->Status[32] = cd->XbusStatus; //cd->XbusStatus|=CDST_RDY; cd->MEIStatus=MEI_CDROM_no_error; break; case 0x10: //Read Data !!! //10 01 00 00 00 00 01 // read 0x0 blocks from MSF=1.0.0 //10 xx-xx-xx nn-nn fl. //00 01 02 03 04 05 06 //reads nn blocks from xx //fl=0 xx="lba" //fl=1 xx="msf" //block= 2048 bytes //opera status request = 0 //status 4 bytes //xx xx xx XS //returns data // here we go //olddataptr=DataLen; if((cd->XbusStatus & CDST_TRAY) && (cd->XbusStatus & CDST_DISC) && (cd->XbusStatus & CDST_SPIN)) { cd->XbusStatus |= CDST_RDY; //cd->CDMode[Command[1]] = cd->Command[2]; cd->StatusLen = 2; cd->Status[0] = 0x10; //cd->Status[1]=0x0; //cd->Status[2]=0x0; cd->Status[1] = cd->XbusStatus; //if(cd->Command[6] == Address_Abs_MSF) { cd->DISC.curabsmsf[0] = (cd->Command[1]); cd->DISC.curabsmsf[1] = (cd->Command[2]); cd->DISC.curabsmsf[2] = (cd->Command[3]); cd->DISC.tempmsf[0] = cd->DISC.curabsmsf[0]; cd->DISC.tempmsf[1] = cd->DISC.curabsmsf[1]; cd->DISC.tempmsf[2] = cd->DISC.curabsmsf[2]; MSF2LBA(cd); //if(fiso!=NULL) // fseek(fiso,DISC.templba*2048+iso_off_from_begin,SEEK_SET); { cd->curr_sector = cd->DISC.templba; _3do_OnSector(cd->DISC.templba); } //fseek(fiso,DISC.templba*2048,SEEK_SET); //fseek(fiso,DISC.templba*2336,SEEK_SET); } cd->olddataptr = (cd->Command[5] << 8) + cd->Command[6]; //cd->olddataptr = cd->olddataptr*2048; //!!! cd->Requested = cd->olddataptr; if (cd->Requested) { _3do_OnSector(cd->curr_sector++); _3do_Read2048(cd->Data); cd->DataLen = REQSIZE; cd->Requested--; } else cd->DataLen=0; cd->Poll |= POLDT; cd->Poll |= POLST; cd->MEIStatus = MEI_CDROM_no_error; } else { cd->XbusStatus|=CDST_ERRO; cd->XbusStatus&=~CDST_RDY; cd->Poll|=POLST; //status is valid cd->StatusLen=2; cd->Status[0]=0x10; //cd->Status[1]=0x0; //cd->Status[2]=0x0; cd->Status[1] = cd->XbusStatus; cd->MEIStatus = MEI_CDROM_recv_ecc; } break; case 0x80: // data path chech //opera status request = 2 //MKE =2 // status 4 bytes // 80 AA 55 XS cd->XbusStatus |= CDST_RDY; cd->StatusLen = 4; cd->Status[0]=0x80; cd->Status[1]=0xaa; cd->Status[2]=0x55; cd->Status[3] = cd->XbusStatus; cd->Poll|=POLST; cd->MEIStatus=MEI_CDROM_no_error; break; case 0x82: //read error (get last status???) //opera status request = 8 ---- tests status req=9????? //MKE = 8!!! //00 //11 //22 Current Status //MKE / Opera??? //33 //44 //55 //66 //77 //88 Current Status //TEST cd->Status[0]=0x82; cd->Status[1] = cd->MEIStatus; cd->Status[2] = cd->MEIStatus; cd->Status[3] = cd->MEIStatus; cd->Status[4] = cd->MEIStatus; cd->Status[5] = cd->MEIStatus; cd->Status[6] = cd->MEIStatus; cd->Status[7] = cd->MEIStatus; cd->Status[8] = cd->MEIStatus; cd->XbusStatus|=CDST_RDY; cd->Status[9] = cd->XbusStatus; //cd->Status[9] = cd->XbusStatus; // 1 == disc present cd->StatusLen=10; cd->Poll |= POLST; //Poll|=0x80; //MDACC break; case 0x83: //read id //opera status request = 10 //status 12 bytes (3 words) //MEI text + XS //00 M E I 1 01 00 00 00 00 00 XS cd->XbusStatus|=CDST_RDY; cd->StatusLen=12; cd->Status[0]=0x83; cd->Status[1]=0x00;//manufacture id cd->Status[2]=0x10;//10 cd->Status[3]=0x00;//MANUFACTURE NUM cd->Status[4]=0x01;//01 cd->Status[5]=00; cd->Status[6]=00; cd->Status[7]=0;//REVISION NUMBER: cd->Status[8]=0; cd->Status[9]=0x00;//FLAG BYTES cd->Status[10]=0x00; cd->Status[11] = cd->XbusStatus;//DEV.DRIVER SIZE //cd->Status[11] = cd->XbusStatus; //cd->Status[12] = cd->XbusStatus; cd->Poll|=POLST; cd->MEIStatus=MEI_CDROM_no_error; break; case 0x84: //mode sense //not used in opera //84 mm 00 00 00 00 00. //status 4 bytes //xx S1 S2 XS //xx xx nn XS // cd->StatusLen = 4; cd->Status[0] = 0x0; cd->Status[1] = 0x0; cd->Status[2] = 0x0; if((cd->XbusStatus & CDST_TRAY) && (cd->XbusStatus & CDST_DISC)) { cd->XbusStatus |= CDST_RDY; //CDMode[Command[1]]=Command[2]; //cd->Status[2] = CDMode[Command[1]]; } else { cd->XbusStatus |= CDST_ERRO; cd->XbusStatus &= ~CDST_RDY; } cd->Poll|=POLST; //status is valid cd->Status[3] = cd->XbusStatus; break; case 0x85: //read capacity //status 8 bytes //opera status request = 6 //cc cc cc cc cc cc cc XS //data? //00 85 //11 mm total //22 ss total //33 ff total //44 ?? //55 ?? //66 ?? if((cd->XbusStatus&CDST_TRAY) && (cd->XbusStatus&CDST_DISC)&&(cd->XbusStatus&CDST_SPIN)) { cd->StatusLen=8;//CMD+status+DRVSTAT cd->Status[0]=0x85; cd->Status[1]=0; cd->Status[2]= cd->DISC.totalmsf[0]; //min cd->Status[3]= cd->DISC.totalmsf[1]; //sec cd->Status[4]= cd->DISC.totalmsf[2]; //fra cd->Status[5]=0x00; cd->Status[6]=0x00; cd->XbusStatus|=CDST_RDY; cd->Status[7]= cd->XbusStatus; cd->Poll|=POLST; cd->MEIStatus=MEI_CDROM_no_error; } else { cd->XbusStatus |= CDST_ERRO; cd->XbusStatus &= ~CDST_RDY; cd->StatusLen = 2;//CMD+status+DRVSTAT cd->Status[0] = 0x85; cd->Status[1] = cd->XbusStatus; cd->Poll |= POLST; cd->MEIStatus = MEI_CDROM_recv_ecc; } break; case 0x86: //read header // not used in opera // 86 00 ll-bb-aa 00 00. // 86 02 mm-ss-ff 00 00. // status 8 bytes // data? // sprintf(str,"#CDROM 0x86 READ HEADER!!!\n"); // CDebug::DPrint(str); break; case 0x87: //read subq //opera status request = 10 //87 fl 00 00 00 00 00 //fl=0 "lba" //fl=1 "msf" // //11 00 (if !=00 then break) //22 Subq_ctl_adr=swapnibles(_11_) //33 Subq_trk = but2bcd(_22_) //44 Subq_pnt_idx=byt2bcd(_33_) //55 mm run tot //66 ss run tot //77 ff run tot //88 mm run trk //99 ss run trk //aa ff run trk if((cd->XbusStatus & CDST_TRAY) && (cd->XbusStatus & CDST_DISC) && (cd->XbusStatus & CDST_SPIN)) { cd->StatusLen=12;//CMD+status+DRVSTAT cd->Status[0]=0x87; cd->Status[1]=0;//DISC.totalmsf[0]; //min cd->Status[2]=0; //sec cd->Status[3]=0; //fra cd->Status[4]=0; cd->Status[5]=0; cd->XbusStatus|=CDST_RDY; cd->Status[6]=0x0; cd->Status[7]=0x0; cd->Status[8]=0x0; cd->Status[9]=0x0; cd->Status[10]=0x0; cd->Status[11] = cd->XbusStatus; cd->Poll|=POLST; cd->MEIStatus=MEI_CDROM_no_error; } else { cd->XbusStatus|=CDST_ERRO; cd->XbusStatus&=~CDST_RDY; cd->StatusLen=2;//CMD+status+DRVSTAT cd->Status[0]=0x85; cd->Status[1] = cd->XbusStatus; cd->Poll |= POLST; cd->MEIStatus=MEI_CDROM_recv_ecc; } break; case 0x88: //read upc // not used in opera //88 00 ll-bb-aa 00 00 //88 02 mm-ss-ff 00 00 //status 20(16) bytes //data? // sprintf(str,"#CDROM 0x88 READ UPC!!!\n"); // CDebug::DPrint(str); break; case 0x89: //read isrc // not used in opera //89 00 ll-bb-aa 00 00 //89 02 mm-ss-ff 00 00 //status 16(15) bytes //data? // sprintf(str,"#CDROM 0x89 READ ISRC!!!\n"); // CDebug::DPrint(str); break; case 0x8a: //read disc code //ignore it yet... ////opera status request = 10 // 8a 00 00 00 00 00 00 //status 10 bytes //????? which code??? if((cd->XbusStatus & CDST_TRAY) && (cd->XbusStatus & CDST_DISC) && (cd->XbusStatus & CDST_SPIN)) { cd->StatusLen=12;//CMD+status+DRVSTAT cd->Status[0]=0x8a; cd->Status[1]=0;//DISC.totalmsf[0]; //min cd->Status[2]=0; //sec cd->Status[3]=0; //fra cd->Status[4]=0; cd->Status[5]=0; cd->XbusStatus|=CDST_RDY; cd->Status[6]=0x0; cd->Status[7]=0x0; cd->Status[8]=0x0; cd->Status[9]=0x0; cd->Status[10]=0x0; cd->Status[11] = cd->XbusStatus; cd->Poll|=POLST; cd->MEIStatus=MEI_CDROM_no_error; } else { cd->XbusStatus|=CDST_ERRO; cd->XbusStatus&=~CDST_RDY; cd->StatusLen=2;//CMD+status+DRVSTAT cd->Status[0] = 0x85; cd->Status[1] = cd->XbusStatus; cd->Poll |= POLST; cd->MEIStatus = MEI_CDROM_recv_ecc; } break; case 0x8b: //MKE !!!v the same //read disc information //opera status request = 6 //8b 00 00 00 00 00 00 //status 8(6) bytes //read the toc descritor //00 11 22 33 44 55 XS //00= 8b //command code //11= Disc ID /// XA_BYTE //22= 1st track# //33= last track# //44= minutes //55= seconds //66= frames cd->StatusLen = 8;//6+1 + 1 for what? cd->Status[0] = 0x8b; if(cd->XbusStatus&(CDST_TRAY|CDST_DISC|CDST_SPIN)) { cd->Status[1] = cd->DISC.discid; cd->Status[2] = cd->DISC.firsttrk; cd->Status[3] = cd->DISC.lasttrk; cd->Status[4] = cd->DISC.totalmsf[0]; //minutes cd->Status[5] = cd->DISC.totalmsf[1]; //seconds cd->XbusStatus |= CDST_RDY; cd->Status[6] = cd->DISC.totalmsf[2]; //frames cd->MEIStatus = MEI_CDROM_no_error; cd->Status[7] = cd->XbusStatus; } else { cd->StatusLen=2;//6+1 + 1 for what? cd->XbusStatus|=CDST_ERRO; cd->MEIStatus=MEI_CDROM_recv_ecc; cd->Status[1] = cd->XbusStatus; } cd->Poll |= POLST; //status is valid break; case 0x8c: //read toc //MKE !!!v the same //opera status request = 8 //8c fl nn 00 00 00 00 // reads nn entry //status 12(8) bytes //00 11 22 33 44 55 66 77 XS //00=8c //11=reserved0; // NIX BYTE //22=addressAndControl; //TOCENT_CTL_ADR=swapnibbles(11) ??? UPCCTLADR=_10_ | x02 (_11_ &F0 = _10_) //33=trackNumber; //TOC_ENT NUMBER //44=reserved3; //TOC_ENT FORMAT //55=minutes; //TOCENT ADRESS == 0x00445566 //66=seconds; //77=frames; //88=reserved7; cd->StatusLen = 10;//CMD+status+DRVSTAT cd->Status[0] = 0x8c; if(cd->XbusStatus & (CDST_TRAY|CDST_DISC|CDST_SPIN)) { cd->Status[1] = cd->DISC.DiscTOC[cd->Command[2]].res0; cd->Status[2] = cd->DISC.DiscTOC[cd->Command[2]].CDCTL; cd->Status[3] = cd->DISC.DiscTOC[cd->Command[2]].TRKNUM; cd->Status[4] = cd->DISC.DiscTOC[cd->Command[2]].res1; cd->Status[5] = cd->DISC.DiscTOC[cd->Command[2]].mm; //min cd->XbusStatus |= CDST_RDY; cd->Status[6] = cd->DISC.DiscTOC[cd->Command[2]].ss; //sec cd->Status[7] = cd->DISC.DiscTOC[cd->Command[2]].ff; //frames cd->Status[8] = cd->DISC.DiscTOC[cd->Command[2]].res2; cd->MEIStatus = MEI_CDROM_no_error; cd->Status[9] = cd->XbusStatus; } else { cd->StatusLen = 2; cd->XbusStatus |= CDST_ERRO; cd->MEIStatus = MEI_CDROM_recv_ecc; cd->Status[1] = cd->XbusStatus; } cd->Poll |= POLST; break; case 0x8d: //read session information //MKE !!!v the same //opera status request = 6 //status 8(6) //00 11 22 33 44 55 XS == //00=8d //11=valid; // 0x80 = MULTISESS //22=minutes; //33=seconds; //44=frames; //55=rfu1; //ignore //66=rfu2 //ignore cd->StatusLen = 8;//CMD+status+DRVSTAT cd->Status[0] = 0x8d; if((cd->XbusStatus & CDST_TRAY) && (cd->XbusStatus & CDST_DISC)) { cd->Status[1] = 0x00; cd->Status[2] = 0x0;//DISC.sesmsf[0];//min cd->Status[3] = 0x2;//DISC.sesmsf[1];//sec cd->Status[4] = 0x0;//DISC.sesmsf[2];//fra cd->Status[5] = 0x00; cd->XbusStatus |= CDST_RDY; cd->Status[6] = 0x00; cd->Status[7] = cd->XbusStatus; cd->MEIStatus = MEI_CDROM_no_error; } else { cd->StatusLen = 2;//CMD+status+DRVSTAT cd->XbusStatus |= CDST_ERRO; cd->Status[1] = cd->XbusStatus; cd->MEIStatus = MEI_CDROM_recv_ecc; } cd->Poll|=POLST; break; case 0x8e: //read device driver break; case 0x93: //????? cd->StatusLen=4; cd->Status[0]=0x0; cd->Status[1]=0x0; cd->Status[2]=0x0; if((cd->XbusStatus&CDST_TRAY) && (cd->XbusStatus & CDST_DISC)) { cd->XbusStatus|=CDST_RDY; //CDMode[Command[1]]=Command[2]; // Status[2]=CDMode[Command[1]]; } else { cd->XbusStatus|=CDST_ERRO; cd->XbusStatus|=CDST_RDY; } cd->Poll |= POLST; //status is valid cd->Status[3] = cd->XbusStatus; break; default: // error!!! //sprintf(str,"#CDROM %x!!!\n",Command[0]); //CDebug::DPrint(str); break; } }
void matsucd_command_w( running_machine &machine, UINT8 data ) { UINT8 cmd; /* make sure we're enabled */ if ( cd.enabled == 0 ) return; /* make sure /CMD is asserted */ if ( cd.cmd_signal == 0 ) return; if ( cd.cdda_set == 0 ) { // 2009-10, FP: for some reason, cdda_from_cdrom was not returning the correct // CDDA device. Hence, as a temp workaround, I added the cdda to the struct // and its tag is configured in matsucd_init if ( cd.cdrom ) cdda_set_cdrom( cd.cdda, cd.cdrom); cd.cdda_set = 1; } cd.input[cd.input_pos++] = data; cmd = cd.input[0]; switch( cmd ) { case 0x01: /* seek */ { if ( cd.input_pos < 7 ) return; /* stop CDDA audio if necessary */ matsucd_cdda_stop(machine); cd.motor = 1; memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 0 ); } break; case 0x02: /* read sectors */ { if ( cd.input_pos < 7 ) return; /* stop CDDA audio if necessary */ matsucd_cdda_stop(machine); /* LBA */ cd.lba = cd.input[1]; cd.lba <<= 8; cd.lba |= cd.input[2]; cd.lba <<= 8; cd.lba |= cd.input[3]; /* Number of blocks */ cd.num_blocks = cd.input[4]; cd.num_blocks <<= 8; cd.num_blocks |= cd.input[5]; /* Reset transfer count */ cd.xfer_offset = 0; /* go ahead and cache the first block */ if (!cdrom_read_data(cd.cdrom, cd.lba, cd.sector_buffer, matsucd_getsector_type())) { logerror( "MATSUCD - Warning: Read error on CD!\n" ); matsucd_command_error( machine ); return; } cd.motor = 1; memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 0 ); } break; case 0x04: /* motor on */ { if ( cd.input_pos < 7 ) return; cd.motor = 1; memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 0 ); } break; case 0x05: /* motor off */ { if ( cd.input_pos < 7 ) return; /* stop CDDA audio if necessary */ matsucd_cdda_stop(machine); cd.motor = 0; memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 0 ); } break; case 0x09: /* play audio cd, LBA mode */ { UINT32 lba, numblocks; if ( cd.input_pos < 7 ) return; lba = cd.input[1]; lba <<= 8; lba |= cd.input[2]; lba <<= 8; lba |= cd.input[3]; numblocks = cd.input[4]; numblocks <<= 8; numblocks |= cd.input[5]; numblocks <<= 8; numblocks |= cd.input[6]; matsucd_cdda_play( machine, lba, numblocks ); cd.motor = 1; memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 0 ); } break; case 0x0a: /* play audio cd, MSF mode */ { UINT32 start, end, lba_start, lba_end; if ( cd.input_pos < 7 ) return; start = cd.input[1]; start <<= 8; start |= cd.input[2]; start <<= 8; start |= cd.input[3]; end = cd.input[4]; end <<= 8; end |= cd.input[5]; end <<= 8; end |= cd.input[6]; lba_start = MSF2LBA( start ); lba_end = MSF2LBA( end ); if ( end == 0xffffff ) { lba_end = cdrom_get_track_start(cd.cdrom,cdrom_get_last_track(cd.cdrom)-1); lba_end += cdrom_get_toc(cd.cdrom)->tracks[cdrom_get_last_track(cd.cdrom)-1].frames; } if ( lba_end <= lba_start ) { matsucd_cdda_stop(machine); } else { matsucd_cdda_play( machine, lba_start, lba_end - lba_start ); cd.motor = 1; } memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 0 ); } break; case 0x0b: /* play audio track and index */ { UINT8 track_start = cd.input[1]; UINT8 index_start = cd.input[2]; UINT8 track_end = cd.input[3]; UINT8 index_end = cd.input[4]; UINT32 lba_start, lba_end; /* TODO: Add index support once the CDDA engine supports it */ (void)index_start; (void)index_end; /* sanitize values */ if ( track_start == 0 ) track_start++; if ( track_end == 0 ) track_end++; if ( track_end > cdrom_get_last_track(cd.cdrom) ) track_end = cdrom_get_last_track(cd.cdrom); /* find the start and stop positions */ lba_start = cdrom_get_track_start(cd.cdrom,track_start-1); lba_end = cdrom_get_track_start(cd.cdrom,track_end-1); lba_end += cdrom_get_toc(cd.cdrom)->tracks[track_end-1].frames; if ( lba_end <= lba_start ) { matsucd_cdda_stop(machine); } else { matsucd_cdda_play( machine, lba_start, lba_end - lba_start ); cd.motor = 1; } memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 0 ); } break; case 0x81: /* status read */ { UINT8 newstatus = cd.status; newstatus &= MATSU_STATUS_SUCCESS | MATSU_STATUS_ERROR | MATSU_STATUS_PLAYING; newstatus |= MATSU_STATUS_READY; if (cd.cdrom) { newstatus |= MATSU_STATUS_MEDIA; } if (cd.motor) newstatus |= MATSU_STATUS_MOTOR; cd.output[0] = newstatus; matsucd_set_status( machine, newstatus ); matsucd_complete_cmd( machine, 1 ); } break; case 0x82: /* error read */ { if ( cd.input_pos < 7 ) return; memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 6 ); } break; case 0x84: /* set mode */ { if ( cd.input_pos < 7 ) return; cd.sector_size = cd.input[2]; cd.sector_size <<= 8; cd.sector_size |= cd.input[3]; memset( cd.output, 0, 6 ); matsucd_complete_cmd( machine, 0 ); } break; case 0x87: /* read SUBQ */ { int msfmode; UINT32 lba; UINT8 track; if ( cd.input_pos < 7 ) return; msfmode = (cd.input[1] & 0x02) ? 1 : 0; memset( cd.output, 0, 13 ); cd.output[0] = matsucd_cdda_getstatus( machine, &lba ); if ( lba > 0 ) { UINT32 disk_pos; UINT32 track_pos; track = cdrom_get_track(cd.cdrom, lba); cd.output[1] = cdrom_get_adr_control(cd.cdrom, track); cd.output[2] = track+1; cd.output[3] = 0; /* index */ disk_pos = lba; if ( msfmode ) disk_pos = LBA2MSF(disk_pos); cd.output[4] = (disk_pos >> 24) & 0xff; cd.output[5] = (disk_pos >> 16) & 0xff; cd.output[6] = (disk_pos >> 8) & 0xff; cd.output[7] = (disk_pos) & 0xff; track_pos = lba - cdrom_get_track_start(cd.cdrom, track); if ( msfmode ) track_pos = LBA2MSF(track_pos); cd.output[8] = (track_pos >> 24) & 0xff; cd.output[9] = (track_pos >> 16) & 0xff; cd.output[10] = (track_pos >> 8) & 0xff; cd.output[11] = (track_pos) & 0xff; /* TODO: UPC flag at offset 12 */ cd.output[12] = 0; } matsucd_complete_cmd( machine, 13 ); } break; case 0x89: /* read disk info */ { UINT32 end; if ( cd.input_pos < 7 ) return; memset( cd.output, 0, 5 ); cd.output[0] = cdrom_get_last_track(cd.cdrom) ? 1 : 0; cd.output[1] = cdrom_get_last_track(cd.cdrom); end = cdrom_get_track_start(cd.cdrom,cd.output[1]-1); end += cdrom_get_toc(cd.cdrom)->tracks[cd.output[1]-1].frames; end = LBA2MSF(end); cd.output[2] = (end >> 16) & 0xff; cd.output[3] = (end >> 8) & 0xff; cd.output[4] = (end) & 0xff; matsucd_complete_cmd( machine, 5 ); } break; case 0x8a: /* read toc */ { UINT8 track; int msfmode; UINT32 track_start; if ( cd.input_pos < 7 ) return; /* stop CDDA audio if necessary */ matsucd_cdda_stop(machine); track = cd.input[2]; msfmode = (cd.input[1] & 0x02) ? 1 : 0; if ( cd.cdrom == NULL ) { logerror( "MATSUCD - Warning: Reading TOC without a CD!\n" ); matsucd_command_error( machine ); return; } if ( track > cdrom_get_last_track(cd.cdrom) ) { logerror( "MATSUCD - Warning: Reading invalid track entry from TOC!\n" ); matsucd_command_error( machine ); return; } memset( cd.output, 0, 7 ); track_start = cdrom_get_track_start(cd.cdrom, track > 0 ? (track-1) : track ); if ( msfmode ) track_start = LBA2MSF( track_start ); cd.output[1] = cdrom_get_adr_control(cd.cdrom, track > 0 ? (track-1) : track); cd.output[2] = track; cd.output[3] = (track == 0 ) ? cdrom_get_last_track(cd.cdrom) : 0; cd.output[4] = (track_start >> 24) & 0xff; cd.output[5] = (track_start >> 16) & 0xff; cd.output[6] = (track_start >> 8) & 0xff; cd.output[7] = (track_start) & 0xff; cd.motor = 1; matsucd_complete_cmd( machine, 8 ); } break; case 0x8b: /* pause audio */ { if ( cd.input_pos < 7 ) return; matsucd_cdda_pause( machine, (cd.input[1] == 0) ? 1 : 0 ); memset( cd.output, 0, 7 ); matsucd_complete_cmd( machine, 0 ); } break; case 0xa3: /* front panel */ { if ( cd.input_pos < 7 ) return; /* TODO: ??? */ memset( cd.output, 0, 7 ); matsucd_complete_cmd( machine, 0 ); } break; default: logerror( "MATSUCD: Unknown/inimplemented command %08x\n", cmd ); break; }