/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ /* @(#)scsi_cmds.c 1.29 03/03/31 Copyright 1998-2002 Heiko Eissfeldt */ /* file for all SCSI commands * FUA (Force Unit Access) bit handling copied from Monty's cdparanoia. */ #undef DEBUG_FULLTOC #undef WARN_FULLTOC #define TESTSUBQFALLBACK 0 #include "config.h" #include #include #include #include #include #include #define g5x_cdblen(cdb, len) ((cdb)->count[0] = ((len) >> 16L)& 0xFF,\ (cdb)->count[1] = ((len) >> 8L) & 0xFF,\ (cdb)->count[2] = (len) & 0xFF) #include #include #include #include #include "mytype.h" #include "icedax.h" #include "interface.h" #include "byteorder.h" #include "global.h" #include "wodim.h" #include "toc.h" #include "scsi_cmds.h" #include "exitcodes.h" unsigned char *bufferTOC; subq_chnl *SubQbuffer; unsigned char *cmd; static unsigned ReadFullTOCSony(SCSI *usalp); static unsigned ReadFullTOCMMC(SCSI *usalp); int SCSI_emulated_ATAPI_on(SCSI *usalp) { /* return is_atapi;*/ if (usal_isatapi(usalp) > 0) return (TRUE); (void) allow_atapi(usalp, TRUE); return (allow_atapi(usalp, TRUE)); } int heiko_mmc(SCSI *usalp) { unsigned char mode[0x100]; int was_atapi; struct cd_mode_page_2A *mp; int retval; fillbytes((caddr_t)mode, sizeof(mode), '\0'); was_atapi = allow_atapi(usalp, 1); usalp->silent++; mp = mmc_cap(usalp, mode); usalp->silent--; allow_atapi(usalp, was_atapi); if (mp == NULL) return (0); /* have a look at the capabilities */ if (mp->cd_da_supported == 0) { retval = -1; } else { retval = 1 + mp->cd_da_accurate; } return retval; } int accepts_fua_bit; unsigned char density = 0; unsigned char orgmode4 = 0; unsigned char orgmode10, orgmode11; /* get current sector size from SCSI cdrom drive */ unsigned int get_orig_sectorsize(SCSI *usalp, unsigned char *m4, unsigned char *m10, unsigned char *m11) { /* first get current values for density, etc. */ static unsigned char *modesense = NULL; if (modesense == NULL) { modesense = malloc(12); if (modesense == NULL) { fprintf(stderr, "Cannot allocate memory for mode sense command in line %d\n", __LINE__); return 0; } } /* do the scsi cmd */ if (usalp->verbose) fprintf(stderr, "\nget density and sector size..."); if (mode_sense(usalp, modesense, 12, 0x01, 0) < 0) fprintf(stderr, "get_orig_sectorsize mode sense failed\n"); /* FIXME: some drives dont deliver block descriptors !!! */ if (modesense[3] == 0) return 0; #if 0 modesense[4] = 0x81; modesense[10] = 0x08; modesense[11] = 0x00; #endif if (m4 != NULL) /* density */ *m4 = modesense[4]; if (m10 != NULL) /* MSB sector size */ *m10 = modesense[10]; if (m11 != NULL) /* LSB sector size */ *m11 = modesense[11]; return (modesense[10] << 8) + modesense[11]; } /* switch CDROM scsi drives to given sector size */ int set_sectorsize(SCSI *usalp, unsigned int secsize) { static unsigned char mode [4 + 8]; int retval; if (orgmode4 == 0xff) { get_orig_sectorsize(usalp, &orgmode4, &orgmode10, &orgmode11); } if (orgmode4 == 0x82 && secsize == 2048) orgmode4 = 0x81; /* prepare to read cds in the previous mode */ fillbytes((caddr_t)mode, sizeof(mode), '\0'); mode[ 3] = 8; /* Block Descriptor Length */ mode[ 4] = orgmode4; /* normal density */ mode[10] = secsize >> 8; /* block length "msb" */ mode[11] = secsize & 0xFF; /* block length lsb */ if (usalp->verbose) fprintf(stderr, "\nset density and sector size..."); /* do the scsi cmd */ if ((retval = mode_select(usalp, mode, 12, 0, usalp->inq->data_format >= 2)) < 0) fprintf (stderr, "setting sector size failed\n"); return retval; } /* switch Toshiba/DEC and HP drives from/to cdda density */ void EnableCddaModeSelect(SCSI *usalp, int fAudioMode, unsigned uSectorsize) { /* reserved, Medium type=0, Dev spec Parm = 0, block descriptor len 0 oder 8, Density (cd format) (0=YellowBook, XA Mode 2=81h, XA Mode1=83h and raw audio via SCSI=82h), # blks msb, #blks, #blks lsb, reserved, blocksize, blocklen msb, blocklen lsb, */ /* MODE_SELECT, page = SCSI-2 save page disabled, reserved, reserved, parm list len, flags */ static unsigned char mode [4 + 8] = { /* mode section */ 0, 0, 0, 8, /* Block Descriptor Length */ /* block descriptor */ 0, /* Density Code */ 0, 0, 0, /* # of Blocks */ 0, /* reserved */ 0, 0, 0};/* Blocklen */ if (orgmode4 == 0 && fAudioMode) { if (0 == get_orig_sectorsize(usalp, &orgmode4, &orgmode10, &orgmode11)) { /* cannot retrieve density, sectorsize */ orgmode10 = (CD_FRAMESIZE >> 8L); orgmode11 = (CD_FRAMESIZE & 0xFF); } } if (fAudioMode) { /* prepare to read audio cdda */ mode [4] = density; /* cdda density */ mode [10] = (uSectorsize >> 8L); /* block length "msb" */ mode [11] = (uSectorsize & 0xFF); /* block length "lsb" */ } else { /* prepare to read cds in the previous mode */ mode [4] = orgmode4; /* 0x00; \* normal density */ mode [10] = orgmode10; /* (CD_FRAMESIZE >> 8L); \* block length "msb" */ mode [11] = orgmode11; /* (CD_FRAMESIZE & 0xFF); \* block length lsb */ } if (usalp->verbose) fprintf(stderr, "\nset density/sector size (EnableCddaModeSelect)...\n"); /* do the scsi cmd */ if (mode_select(usalp, mode, 12, 0, usalp->inq->data_format >= 2) < 0) fprintf (stderr, "Audio mode switch failed\n"); } /* read CD Text information from the table of contents */ void ReadTocTextSCSIMMC(SCSI *usalp) { short datalength; #if 1 /* READTOC, MSF, format, res, res, res, Start track/session, len msb, len lsb, control */ unsigned char *p = bufferTOC; register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)bufferTOC; scmd->size = 4; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x43; /* Read TOC command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[0] = 5; /* format field */ scmd->cdb.g1_cdb.res6 = 0; /* track/session is reserved */ g1_cdblen(&scmd->cdb.g1_cdb, 4); usalp->silent++; if (usalp->verbose) fprintf(stderr, "\nRead TOC CD Text size ..."); usalp->cmdname = "read toc size (text)"; if (usal_cmd(usalp) < 0) { usalp->silent--; if (global.quiet != 1) fprintf (stderr, "Read TOC CD Text failed (probably not supported).\n"); p[0] = p[1] = '\0'; return ; } usalp->silent--; datalength = (p[0] << 8) | (p[1]); if (datalength <= 2) return; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)bufferTOC; scmd->size = 2+datalength; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x43; /* Read TOC command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[0] = 5; /* format field */ scmd->cdb.g1_cdb.res6 = 0; /* track/session is reserved */ g1_cdblen(&scmd->cdb.g1_cdb, 2+datalength); usalp->silent++; if (usalp->verbose) fprintf(stderr, "\nRead TOC CD Text data (length %hd)...", 2+datalength); usalp->cmdname = "read toc data (text)"; if (usal_cmd(usalp) < 0) { usalp->silent--; if (global.quiet != 1) fprintf (stderr, "Read TOC CD Text data failed (probably not supported).\n"); p[0] = p[1] = '\0'; return ; } usalp->silent--; #else { FILE *fp; int read_; /*fp = fopen("PearlJam.cdtext", "rb");*/ /*fp = fopen("celine.cdtext", "rb");*/ fp = fopen("japan.cdtext", "rb"); if (fp == NULL) { perror(""); return; } fillbytes(bufferTOC, CD_FRAMESIZE, '\0'); read_ = fread(bufferTOC, 1, CD_FRAMESIZE, fp ); fprintf(stderr, "read %d bytes. sizeof(bufferTOC)=%u\n", read_, CD_FRAMESIZE); datalength = (bufferTOC[0] << 8) | (bufferTOC[1]); fclose(fp); } #endif } /* read the full TOC */ static unsigned ReadFullTOCSony(SCSI *usalp) { /* READTOC, MSF, format, res, res, res, Start track/session, len msb, len lsb, control */ register struct usal_cmd *scmd = usalp->scmd; unsigned tracks = 99; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)bufferTOC; scmd->size = 4 + (3 + tracks + 6) * 11; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x43; /* Read TOC command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.res6 = 1; /* session */ g1_cdblen(&scmd->cdb.g1_cdb, 4 + (3 + tracks + 6) * 11); scmd->cdb.g1_cdb.vu_97 = 1; /* format */ usalp->silent++; if (usalp->verbose) fprintf(stderr, "\nRead Full TOC Sony ..."); usalp->cmdname = "read full toc sony"; if (usal_cmd(usalp) < 0) { usalp->silent--; if (global.quiet != 1) fprintf (stderr, "Read Full TOC Sony failed (probably not supported).\n"); return 0; } usalp->silent--; return (unsigned)((bufferTOC[0] << 8) | bufferTOC[1]); } struct msf_address { unsigned char mins; unsigned char secs; unsigned char frame; }; struct zmsf_address { unsigned char zero; unsigned char mins; unsigned char secs; unsigned char frame; }; #ifdef WARN_FULLTOC static unsigned lba(struct msf_address *ad); static unsigned lba(struct msf_address *ad) { return ad->mins*60*75 + ad->secs*75 + ad->frame; } #endif static unsigned dvd_lba(struct zmsf_address *ad); static unsigned dvd_lba(struct zmsf_address *ad) { return ad->zero*1053696 + ad->mins*60*75 + ad->secs*75 + ad->frame; } struct tocdesc { unsigned char session; unsigned char adrctl; unsigned char tno; unsigned char point; struct msf_address adr1; struct zmsf_address padr2; }; struct outer { unsigned char len_msb; unsigned char len_lsb; unsigned char first_track; unsigned char last_track; struct tocdesc ent[1]; }; static unsigned long first_session_leadout = 0; static unsigned collect_tracks(struct outer *po, unsigned entries, BOOL bcd_flag); static unsigned collect_tracks(struct outer *po, unsigned entries, BOOL bcd_flag) { unsigned tracks = 0; int i; unsigned session; unsigned last_start; unsigned leadout_start_orig; unsigned leadout_start; unsigned max_leadout = 0; #ifdef DEBUG_FULLTOC for (i = 0; i < entries; i++) { fprintf(stderr, "%3d: %d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n" ,i ,bufferTOC[4+0 + (i * 11)] ,bufferTOC[4+1 + (i * 11)] ,bufferTOC[4+2 + (i * 11)] ,bufferTOC[4+3 + (i * 11)] ,bufferTOC[4+4 + (i * 11)] ,bufferTOC[4+5 + (i * 11)] ,bufferTOC[4+6 + (i * 11)] ,bufferTOC[4+7 + (i * 11)] ,bufferTOC[4+8 + (i * 11)] ,bufferTOC[4+9 + (i * 11)] ,bufferTOC[4+10 + (i * 11)] ); } #endif /* reformat to standard toc format */ bufferTOC[2] = 0; bufferTOC[3] = 0; session = 0; last_start = 0; leadout_start_orig = 0; leadout_start = 0; for (i = 0; i < entries; i++) { #ifdef WARN_FULLTOC if (po->ent[i].tno != 0) { fprintf(stderr, "entry %d, tno is not 0: %d!\n", i, po->ent[i].tno); } #endif if (bcd_flag) { po->ent[i].session = from_bcd(po->ent[i].session); po->ent[i].adr1.mins = from_bcd(po->ent[i].adr1.mins); po->ent[i].adr1.secs = from_bcd(po->ent[i].adr1.secs); po->ent[i].adr1.frame = from_bcd(po->ent[i].adr1.frame); po->ent[i].padr2.mins = from_bcd(po->ent[i].padr2.mins); po->ent[i].padr2.secs = from_bcd(po->ent[i].padr2.secs); po->ent[i].padr2.frame = from_bcd(po->ent[i].padr2.frame); } switch (po->ent[i].point) { case 0xa0: /* check if session is monotonous increasing */ if (session+1 == po->ent[i].session) { session = po->ent[i].session; } #ifdef WARN_FULLTOC else fprintf(stderr, "entry %d, session anomaly %d != %d!\n", i, session+1, po->ent[i].session); /* check the adrctl field */ if (0x10 != (po->ent[i].adrctl & 0x10)) { fprintf(stderr, "entry %d, incorrect adrctl field %x!\n", i, po->ent[i].adrctl); } #endif /* first track number */ if (bufferTOC[2] < po->ent[i].padr2.mins && bufferTOC[3] < po->ent[i].padr2.mins) { bufferTOC[2] = po->ent[i].padr2.mins; } #ifdef WARN_FULLTOC else fprintf(stderr, "entry %d, session %d: start tracknumber anomaly: %d <= %d,%d(last)!\n", i, session, po->ent[i].padr2.mins, bufferTOC[2], bufferTOC[3]); #endif break; case 0xa1: #ifdef WARN_FULLTOC /* check if session is constant */ if (session != po->ent[i].session) { fprintf(stderr, "entry %d, session anomaly %d != %d!\n", i, session, po->ent[i].session); } /* check the adrctl field */ if (0x10 != (po->ent[i].adrctl & 0x10)) { fprintf(stderr, "entry %d, incorrect adrctl field %x!\n", i, po->ent[i].adrctl); } #endif /* last track number */ if (bufferTOC[2] <= po->ent[i].padr2.mins && bufferTOC[3] < po->ent[i].padr2.mins) { bufferTOC[3] = po->ent[i].padr2.mins; } #ifdef WARN_FULLTOC else fprintf(stderr, "entry %d, session %d: end tracknumber anomaly: %d <= %d,%d(last)!\n", i, session, po->ent[i].padr2.mins, bufferTOC[2], bufferTOC[3]); #endif break; case 0xa2: #ifdef WARN_FULLTOC /* check if session is constant */ if (session != po->ent[i].session) { fprintf(stderr, "entry %d, session anomaly %d != %d!\n", i, session, po->ent[i].session); } /* check the adrctl field */ if (0x10 != (po->ent[i].adrctl & 0x10)) { fprintf(stderr, "entry %d, incorrect adrctl field %x!\n", i, po->ent[i].adrctl); } #endif /* register leadout position */ { unsigned leadout_start_tmp = dvd_lba(&po->ent[i].padr2); if (first_session_leadout == 0) first_session_leadout = leadout_start_tmp - 150; if (leadout_start_tmp > leadout_start) { leadout_start_orig = leadout_start_tmp; leadout_start = leadout_start_tmp; } #ifdef WARN_FULLTOC else fprintf(stderr, "entry %d, leadout position anomaly %u!\n", i, leadout_start_tmp); #endif } break; case 0xb0: #ifdef WARN_FULLTOC /* check if session is constant */ if (session != po->ent[i].session) { fprintf(stderr, "entry %d, session anomaly %d != %d!\n", i, session, po->ent[i].session); } /* check the adrctl field */ if (0x50 != (po->ent[i].adrctl & 0x50)) { fprintf(stderr, "entry %d, incorrect adrctl field %x!\n", i, po->ent[i].adrctl); } /* check the next program area */ if (lba(&po->ent[i].adr1) < 6750 + leadout_start) { fprintf(stderr, "entry %d, next program area %u < leadout_start + 6750 = %u!\n", i, lba(&po->ent[i].adr1), 6750 + leadout_start); } /* check the maximum leadout_start */ if (max_leadout != 0 && dvd_lba(&po->ent[i].padr2) != max_leadout) { fprintf(stderr, "entry %d, max leadout_start %u != last max_leadout_start %u!\n", i, dvd_lba(&po->ent[i].padr2), max_leadout); } #endif if (max_leadout == 0) max_leadout = dvd_lba(&po->ent[i].padr2); break; case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: break; case 0xc0: case 0xc1: break; default: /* check if session is constant */ if (session != po->ent[i].session) { #ifdef WARN_FULLTOC fprintf(stderr, "entry %d, session anomaly %d != %d!\n", i, session, po->ent[i].session); #endif continue; } /* check tno */ if (bcd_flag) po->ent[i].point = from_bcd(po->ent[i].point); if (po->ent[i].point < bufferTOC[2] || po->ent[i].point > bufferTOC[3]) { #ifdef WARN_FULLTOC fprintf(stderr, "entry %d, track number anomaly %d - %d - %d!\n", i, bufferTOC[2], po->ent[i].point, bufferTOC[3]); #endif } else { /* check start position */ unsigned trackstart = dvd_lba(&po->ent[i].padr2); /* correct illegal leadouts */ if (leadout_start < trackstart) { leadout_start = trackstart+1; } if (trackstart < last_start || trackstart >= leadout_start) { #ifdef WARN_FULLTOC fprintf(stderr, "entry %d, track %d start position anomaly %d - %d - %d!\n", i, po->ent[i].point, last_start, trackstart, leadout_start); #endif } else { last_start = trackstart; memcpy(&po->ent[tracks], &po->ent[i], sizeof(struct tocdesc)); tracks++; } } } /* switch */ } /* for */ /* patch leadout track */ po->ent[tracks].session = session; po->ent[tracks].adrctl = 0x10; po->ent[tracks].tno = 0; po->ent[tracks].point = 0xAA; po->ent[tracks].adr1.mins = 0; po->ent[tracks].adr1.secs = 0; po->ent[tracks].adr1.frame = 0; po->ent[tracks].padr2.zero = leadout_start_orig / (1053696); po->ent[tracks].padr2.mins = (leadout_start_orig / (60*75)) % 100; po->ent[tracks].padr2.secs = (leadout_start_orig / 75) % 60; po->ent[tracks].padr2.frame = leadout_start_orig % 75; tracks++; /* length */ bufferTOC[0] = ((tracks * 8) + 2) >> 8; bufferTOC[1] = ((tracks * 8) + 2) & 0xff; /* reformat 11 byte blocks to 8 byte entries */ /* 1: Session \ / reserved 2: adr ctrl | | adr ctrl 3: TNO | | track number 4: Point | | reserved 5: Min +-->----+ 0 6: Sec | | Min 7: Frame | | Sec 8: Zero | \ Frame 9: PMin | 10: PSec | 11: PFrame / */ for (i = 0; i < tracks; i++) { bufferTOC[4+0 + (i << 3)] = 0; bufferTOC[4+1 + (i << 3)] = bufferTOC[4+1 + (i*11)]; bufferTOC[4+1 + (i << 3)] = (bufferTOC[4+1 + (i << 3)] >> 4) | (bufferTOC[4+1 + (i << 3)] << 4); bufferTOC[4+2 + (i << 3)] = bufferTOC[4+3 + (i*11)]; bufferTOC[4+3 + (i << 3)] = 0; bufferTOC[4+4 + (i << 3)] = bufferTOC[4+7 + (i*11)]; bufferTOC[4+5 + (i << 3)] = bufferTOC[4+8 + (i*11)]; bufferTOC[4+6 + (i << 3)] = bufferTOC[4+9 + (i*11)]; bufferTOC[4+7 + (i << 3)] = bufferTOC[4+10 + (i*11)]; #ifdef DEBUG_FULLTOC fprintf(stderr, "%02x %02x %02x %02x %02x %02x\n" ,bufferTOC[4+ 1 + i*8] ,bufferTOC[4+ 2 + i*8] ,bufferTOC[4+ 4 + i*8] ,bufferTOC[4+ 5 + i*8] ,bufferTOC[4+ 6 + i*8] ,bufferTOC[4+ 7 + i*8] ); #endif } TOC_entries(tracks, NULL, bufferTOC+4, 0); return tracks; } /* read the table of contents from the cd and fill the TOC array */ unsigned ReadTocSony(SCSI *usalp) { unsigned tracks = 0; unsigned return_length; struct outer *po = (struct outer *)bufferTOC; return_length = ReadFullTOCSony(usalp); /* Check if the format was understood */ if ((return_length & 7) == 2 && (bufferTOC[3] - bufferTOC[2]) == (return_length >> 3)) { /* The extended format seems not be understood, fallback to * the classical format. */ return ReadTocSCSI( usalp ); } tracks = collect_tracks(po, ((return_length - 2) / 11), TRUE); return --tracks; /* without lead-out */ } /* read the start of the lead-out from the first session TOC */ unsigned ReadFirstSessionTOCSony(SCSI *usalp) { unsigned return_length; if (first_session_leadout != 0) return first_session_leadout; return_length = ReadFullTOCSony(usalp); if (return_length >= 4 + (3 * 11) -2) { unsigned off; /* We want the entry with POINT = 0xA2, which has the start position of the first session lead out */ off = 4 + 2 * 11 + 3; if (bufferTOC[off-3] == 1 && bufferTOC[off] == 0xA2) { unsigned retval; off = 4 + 2 * 11 + 8; retval = bufferTOC[off] >> 4; retval *= 10; retval += bufferTOC[off] & 0xf; retval *= 60; off++; retval += 10 * (bufferTOC[off] >> 4) + (bufferTOC[off] & 0xf); retval *= 75; off++; retval += 10 * (bufferTOC[off] >> 4) + (bufferTOC[off] & 0xf); retval -= 150; return retval; } } return 0; } /* read the full TOC */ static unsigned ReadFullTOCMMC(SCSI *usalp) { /* READTOC, MSF, format, res, res, res, Start track/session, len msb, len lsb, control */ register struct usal_cmd *scmd = usalp->scmd; unsigned tracks = 99; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)bufferTOC; scmd->size = 4 + (tracks + 8) * 11; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x43; /* Read TOC command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[0] = 2; /* format */ scmd->cdb.g1_cdb.res6 = 1; /* session */ g1_cdblen(&scmd->cdb.g1_cdb, 4 + (tracks + 8) * 11); usalp->silent++; if (usalp->verbose) fprintf(stderr, "\nRead Full TOC MMC..."); usalp->cmdname = "read full toc mmc"; if (usal_cmd(usalp) < 0) { if (global.quiet != 1) fprintf (stderr, "Read Full TOC MMC failed (probably not supported).\n"); #ifdef B_BEOS_VERSION #else usalp->silent--; return 0; #endif } usalp->silent--; return (unsigned)((bufferTOC[0] << 8) | bufferTOC[1]); } /* read the start of the lead-out from the first session TOC */ unsigned ReadFirstSessionTOCMMC(SCSI *usalp) { unsigned off; unsigned return_length; if (first_session_leadout != 0) return first_session_leadout; return_length = ReadFullTOCMMC(usalp); /* We want the entry with POINT = 0xA2, which has the start position of the first session lead out */ off = 4 + 3; while (off < return_length && bufferTOC[off] != 0xA2) { off += 11; } if (off < return_length) { off += 5; return (bufferTOC[off]*60 + bufferTOC[off+1])*75 + bufferTOC[off+2] - 150; } return 0; } /* read the table of contents from the cd and fill the TOC array */ unsigned ReadTocMMC(SCSI *usalp) { unsigned tracks = 0; unsigned return_length; struct outer *po = (struct outer *)bufferTOC; return_length = ReadFullTOCMMC(usalp); if (return_length - 2 < 4*11 || ((return_length - 2) % 11) != 0) return ReadTocSCSI(usalp); tracks = collect_tracks(po, ((return_length - 2) / 11), FALSE); return --tracks; /* without lead-out */ } /* read the table of contents from the cd and fill the TOC array */ unsigned ReadTocSCSI(SCSI *usalp) { unsigned tracks; int result; unsigned char bufferTOCMSF[CD_FRAMESIZE]; /* first read the first and last track number */ /* READTOC, MSF format flag, res, res, res, res, Start track, len msb, len lsb, flags */ register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)bufferTOC; scmd->size = 4; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x43; /* read TOC command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.res6 = 1; /* start track */ g1_cdblen(&scmd->cdb.g1_cdb, 4); if (usalp->verbose) fprintf(stderr, "\nRead TOC size (standard)..."); /* do the scsi cmd (read table of contents) */ usalp->cmdname = "read toc size"; if (usal_cmd(usalp) < 0) FatalError ("Read TOC size failed.\n"); tracks = ((bufferTOC [3] ) - bufferTOC [2] + 2) ; if (tracks > MAXTRK) return 0; if (tracks == 0) return 0; memset(bufferTOCMSF, 0, sizeof(bufferTOCMSF)); fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)bufferTOCMSF; scmd->size = 4 + tracks * 8; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x43; /* read TOC command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.res = 1; /* MSF format */ scmd->cdb.g1_cdb.res6 = 1; /* start track */ g1_cdblen(&scmd->cdb.g1_cdb, 4 + tracks * 8); if (usalp->verbose) fprintf(stderr, "\nRead TOC tracks (standard MSF)..."); /* do the scsi cmd (read table of contents) */ usalp->cmdname = "read toc tracks "; result = usal_cmd(usalp); if (result < 0) { /* MSF format did not succeeded */ memset(bufferTOCMSF, 0, sizeof(bufferTOCMSF)); } else { int i; for (i = 0; i < tracks; i++) { bufferTOCMSF[4+1 + (i << 3)] = (bufferTOCMSF[4+1 + (i << 3)] >> 4) | (bufferTOCMSF[4+1 + (i << 3)] << 4); #if 0 fprintf(stderr, "MSF %d %02x %02x %02x %02x %02x %02x %02x %02x\n" ,i ,bufferTOCMSF[4+0 + (i * 8)] ,bufferTOCMSF[4+1 + (i * 8)] ,bufferTOCMSF[4+2 + (i * 8)] ,bufferTOCMSF[4+3 + (i * 8)] ,bufferTOCMSF[4+4 + (i * 8)] ,bufferTOCMSF[4+5 + (i * 8)] ,bufferTOCMSF[4+6 + (i * 8)] ,bufferTOCMSF[4+7 + (i * 8)] ); #endif } } /* LBA format for cd burners like Philips CD-522 */ fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)bufferTOC; scmd->size = 4 + tracks * 8; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x43; /* read TOC command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.res = 0; /* LBA format */ scmd->cdb.g1_cdb.res6 = 1; /* start track */ g1_cdblen(&scmd->cdb.g1_cdb, 4 + tracks * 8); if (usalp->verbose) fprintf(stderr, "\nRead TOC tracks (standard LBA)..."); /* do the scsi cmd (read table of contents) */ usalp->cmdname = "read toc tracks "; if (usal_cmd(usalp) < 0) { FatalError ("Read TOC tracks (lba) failed.\n"); } { int i; for (i = 0; i < tracks; i++) { bufferTOC[4+1 + (i << 3)] = (bufferTOC[4+1 + (i << 3)] >> 4) | (bufferTOC[4+1 + (i << 3)] << 4); #if 0 fprintf(stderr, "LBA %d %02x %02x %02x %02x %02x %02x %02x %02x\n" ,i ,bufferTOC[4+0 + (i * 8)] ,bufferTOC[4+1 + (i * 8)] ,bufferTOC[4+2 + (i * 8)] ,bufferTOC[4+3 + (i * 8)] ,bufferTOC[4+4 + (i * 8)] ,bufferTOC[4+5 + (i * 8)] ,bufferTOC[4+6 + (i * 8)] ,bufferTOC[4+7 + (i * 8)] ); #endif } } TOC_entries(tracks, bufferTOC+4, bufferTOCMSF+4, result); return --tracks; /* without lead-out */ } /* ---------------- Read methods ------------------------------ */ /* Read max. SectorBurst of cdda sectors to buffer via standard SCSI-2 Read(10) command */ static int ReadStandardLowlevel(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal, unsigned secsize); static int ReadStandardLowlevel(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal, unsigned secsize) { /* READ10, flags, block1 msb, block2, block3, block4 lsb, reserved, transfer len msb, transfer len lsb, block addressing mode */ register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)p; scmd->size = SectorBurstVal * secsize; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x28; /* read 10 command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); g1_cdbaddr(&scmd->cdb.g1_cdb, lSector); g1_cdblen(&scmd->cdb.g1_cdb, SectorBurstVal); if (usalp->verbose) fprintf(stderr, "\nReadStandard10 %s (%u)...", secsize > 2048 ? "CDDA" : "CD_DATA", secsize); usalp->cmdname = "ReadStandard10"; if (usal_cmd(usalp)) return 0; /* has all or something been read? */ return SectorBurstVal - usal_getresid(usalp)/secsize; } int ReadStandard(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { return ReadStandardLowlevel(usalp, p, lSector, SectorBurstVal, CD_FRAMESIZE_RAW); } int ReadStandardData(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { return ReadStandardLowlevel(usalp, p, lSector, SectorBurstVal, CD_FRAMESIZE); } /* Read max. SectorBurst of cdda sectors to buffer via vendor-specific ReadCdda(10) command */ int ReadCdda10(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { /* READ10, flags, block1 msb, block2, block3, block4 lsb, reserved, transfer len msb, transfer len lsb, block addressing mode */ register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)p; scmd->size = SectorBurstVal*CD_FRAMESIZE_RAW; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0xd4; /* Read audio command */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); g1_cdbaddr(&scmd->cdb.g1_cdb, lSector); g1_cdblen(&scmd->cdb.g1_cdb, SectorBurstVal); if (usalp->verbose) fprintf(stderr, "\nReadNEC10 CDDA..."); usalp->cmdname = "Read10 NEC"; if (usal_cmd(usalp)) return 0; /* has all or something been read? */ return SectorBurstVal - usal_getresid(usalp)/CD_FRAMESIZE_RAW; } /* Read max. SectorBurst of cdda sectors to buffer via vendor-specific ReadCdda(12) command */ int ReadCdda12(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)p; scmd->size = SectorBurstVal*CD_FRAMESIZE_RAW; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xd8; /* read audio command */ scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g5_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); g5_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); if (usalp->verbose) fprintf(stderr, "\nReadSony12 CDDA..."); usalp->cmdname = "Read12"; if (usal_cmd(usalp)) return 0; /* has all or something been read? */ return SectorBurstVal - usal_getresid(usalp)/CD_FRAMESIZE_RAW; } /* Read max. SectorBurst of cdda sectors to buffer via vendor-specific ReadCdda(12) command */ /* > It uses a 12 Byte CDB with 0xd4 as opcode, the start sector is coded as > normal and the number of sectors is coded in Byte 8 and 9 (begining with 0). */ int ReadCdda12Matsushita(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)p; scmd->size = SectorBurstVal*CD_FRAMESIZE_RAW; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xd4; /* read audio command */ scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g5_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); g5_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); if (usalp->verbose) fprintf(stderr, "\nReadMatsushita12 CDDA..."); usalp->cmdname = "Read12Matsushita"; if (usal_cmd(usalp)) return 0; /* has all or something been read? */ return SectorBurstVal - usal_getresid(usalp)/CD_FRAMESIZE_RAW; } /* Read max. SectorBurst of cdda sectors to buffer via MMC standard READ CD command */ int ReadCddaMMC12(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { register struct usal_cmd *scmd; scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)p; scmd->size = SectorBurstVal*CD_FRAMESIZE_RAW; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xbe; /* read cd command */ scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g5_cdb.res = 1 << 1; /* expected sector type field CDDA */ g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); g5x_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); scmd->cdb.g5_cdb.count[3] = 1 << 4; /* User data */ if (usalp->verbose) fprintf(stderr, "\nReadMMC12 CDDA..."); usalp->cmdname = "ReadCD MMC 12"; if (usal_cmd(usalp)) return 0; /* has all or something been read? */ return SectorBurstVal - usal_getresid(usalp)/CD_FRAMESIZE_RAW; } int ReadCddaFallbackMMC(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { static int ReadCdda12_unknown = 0; int retval = -999; usalp->silent++; if (ReadCdda12_unknown || ((retval = ReadCdda12(usalp, p, lSector, SectorBurstVal)) <= 0)) { /* if the command is not available, use the regular * MMC ReadCd */ if (retval <= 0 && usal_sense_key(usalp) == 0x05) { ReadCdda12_unknown = 1; } usalp->silent--; ReadCdRom = ReadCddaMMC12; ReadCdRomSub = ReadCddaSubMMC12; return ReadCddaMMC12(usalp, p, lSector, SectorBurstVal); } usalp->silent--; return retval; } /* Read the Sub-Q-Channel to SubQbuffer. This is the method for * drives that do not support subchannel parameters. */ #ifdef PROTOTYPES static subq_chnl *ReadSubQFallback (SCSI *usalp, unsigned char sq_format, unsigned char track) #else static subq_chnl * ReadSubQFallback(SCSI *usalp, unsigned char sq_format, unsigned char track) #endif { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)SubQbuffer; scmd->size = 24; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x42; /* Read SubQChannel */ /* use LBA */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[0] = 0x40; /* SubQ info */ scmd->cdb.g1_cdb.addr[1] = 0; /* parameter list: all */ scmd->cdb.g1_cdb.res6 = track; /* track number */ g1_cdblen(&scmd->cdb.g1_cdb, 24); if (usalp->verbose) fprintf(stderr, "\nRead Subchannel_dumb..."); usalp->cmdname = "Read Subchannel_dumb"; if (usal_cmd(usalp) < 0) { fprintf( stderr, "Read SubQ failed\n"); } /* check, if the requested format is delivered */ { unsigned char *p = (unsigned char *) SubQbuffer; if ((((unsigned)p[2] << 8) | p[3]) /* LENGTH */ > ULONG_C(11) && (p[5] >> 4) /* ADR */ == sq_format) { if (sq_format == GET_POSITIONDATA) p[5] = (p[5] << 4) | (p[5] >> 4); return SubQbuffer; } } /* FIXME: we might actively search for the requested info ... */ return NULL; } /* Read the Sub-Q-Channel to SubQbuffer */ #ifdef PROTOTYPES subq_chnl *ReadSubQSCSI (SCSI *usalp, unsigned char sq_format, unsigned char track) #else subq_chnl * ReadSubQSCSI(SCSI *usalp, unsigned char sq_format, unsigned char track) #endif { int resp_size; register struct usal_cmd *scmd = usalp->scmd; switch (sq_format) { case GET_POSITIONDATA: resp_size = 16; track = 0; break; case GET_CATALOGNUMBER: resp_size = 24; track = 0; break; case GET_TRACK_ISRC: resp_size = 24; break; default: fprintf(stderr, "ReadSubQSCSI: unknown format %d\n", sq_format); return NULL; } fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)SubQbuffer; scmd->size = resp_size; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x42; /* use LBA */ scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[0] = 0x40; /* SubQ info */ scmd->cdb.g1_cdb.addr[1] = sq_format; /* parameter list: all */ scmd->cdb.g1_cdb.res6 = track; /* track number */ g1_cdblen(&scmd->cdb.g1_cdb, resp_size); if (usalp->verbose) fprintf(stderr, "\nRead Subchannel..."); usalp->cmdname = "Read Subchannel"; if (usal_cmd(usalp) < 0) { /* in case of error do a fallback for dumb firmwares */ return ReadSubQFallback(usalp, sq_format, track); } if (sq_format == GET_POSITIONDATA) SubQbuffer->control_adr = (SubQbuffer->control_adr << 4) | (SubQbuffer->control_adr >> 4); return SubQbuffer; } static subq_chnl sc; static subq_chnl* fill_subchannel(unsigned char bufferwithQ[]); static subq_chnl* fill_subchannel(unsigned char bufferwithQ[]) { sc.subq_length = 0; sc.control_adr = bufferwithQ[CD_FRAMESIZE_RAW + 0]; sc.track = bufferwithQ[CD_FRAMESIZE_RAW + 1]; sc.index = bufferwithQ[CD_FRAMESIZE_RAW + 2]; return ≻ } int ReadCddaSubSony(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)p; scmd->size = SectorBurstVal*(CD_FRAMESIZE_RAW + 16); scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xd8; /* read audio command */ scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g5_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); scmd->cdb.g5_cdb.res10 = 0x01; /* subcode 1 -> cdda + 16 * q sub */ g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); g5_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); if (usalp->verbose) fprintf(stderr, "\nReadSony12 CDDA + SubChannels..."); usalp->cmdname = "Read12SubChannelsSony"; if (usal_cmd(usalp)) return -1; /* has all or something been read? */ return usal_getresid(usalp) != 0; } int ReadCddaSub96Sony(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal); int ReadCddaSub96Sony(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)p; scmd->size = SectorBurstVal*(CD_FRAMESIZE_RAW + 96); scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xd8; /* read audio command */ scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g5_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); scmd->cdb.g5_cdb.res10 = 0x02; /* subcode 2 -> cdda + 96 * q sub */ g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); g5_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); if (usalp->verbose) fprintf(stderr, "\nReadSony12 CDDA + 96 byte SubChannels..."); usalp->cmdname = "Read12SubChannelsSony"; if (usal_cmd(usalp)) return -1; /* has all or something been read? */ return usal_getresid(usalp) != 0; } subq_chnl *ReadSubChannelsSony(SCSI *usalp, unsigned lSector) { /*int retval = ReadCddaSub96Sony(usalp, (UINT4 *)bufferTOC, lSector, 1);*/ int retval = ReadCddaSubSony(usalp, (UINT4 *)bufferTOC, lSector, 1); if (retval != 0) return NULL; return fill_subchannel(bufferTOC); } /* Read max. SectorBurst of cdda sectors to buffer via MMC standard READ CD command */ int ReadCddaSubMMC12(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { register struct usal_cmd *scmd; scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)p; scmd->size = SectorBurstVal*(CD_FRAMESIZE_RAW + 16); scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xbe; /* read cd command */ scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g5_cdb.res = 1 << 1; /* expected sector type field CDDA */ g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); g5x_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); scmd->cdb.g5_cdb.count[3] = 1 << 4; /* User data */ scmd->cdb.g5_cdb.res10 = 0x02; /* subcode 2 -> cdda + 16 * q sub */ if (usalp->verbose) fprintf(stderr, "\nReadMMC12 CDDA + SUB..."); usalp->cmdname = "ReadCD Sub MMC 12"; if (usal_cmd(usalp)) return -1; /* has all or something been read? */ return usal_getresid(usalp) != 0; } static subq_chnl *ReadSubChannelsMMC(SCSI *usalp, unsigned lSector); static subq_chnl *ReadSubChannelsMMC(SCSI *usalp, unsigned lSector) { int retval = ReadCddaSubMMC12(usalp, (UINT4 *)bufferTOC, lSector, 1); if (retval != 0) return NULL; return fill_subchannel(bufferTOC); } subq_chnl *ReadSubChannelsFallbackMMC(SCSI *usalp, unsigned lSector) { static int ReadSubSony_unknown = 0; subq_chnl *retval = NULL; usalp->silent++; if (ReadSubSony_unknown || ((retval = ReadSubChannelsSony(usalp, lSector)) == NULL)) { /* if the command is not available, use the regular * MMC ReadCd */ if (retval == NULL && usal_sense_key(usalp) == 0x05) { ReadSubSony_unknown = 1; } usalp->silent--; return ReadSubChannelsMMC(usalp, lSector); } usalp->silent--; return retval; } subq_chnl *ReadStandardSub(usalp, lSector) SCSI *usalp; unsigned lSector; { if (0 == ReadStandardLowlevel (usalp, (UINT4 *)bufferTOC, lSector, 1, CD_FRAMESIZE_RAW + 16 )) { return NULL; } #if 0 fprintf(stderr, "Subchannel Sec %x: %02x %02x %02x %02x\n" ,lSector ,bufferTOC[CD_FRAMESIZE_RAW + 0] ,bufferTOC[CD_FRAMESIZE_RAW + 1] ,bufferTOC[CD_FRAMESIZE_RAW + 2] ,bufferTOC[CD_FRAMESIZE_RAW + 3] ); #endif sc.control_adr = (bufferTOC[CD_FRAMESIZE_RAW + 0] << 4) | bufferTOC[CD_FRAMESIZE_RAW + 1]; sc.track = from_bcd(bufferTOC[CD_FRAMESIZE_RAW + 2]); sc.index = from_bcd(bufferTOC[CD_FRAMESIZE_RAW + 3]); return ≻ } /********* non standardized speed selects ***********************/ void SpeedSelectSCSIToshiba(SCSI *usalp, unsigned speed) { static unsigned char mode [4 + 3]; unsigned char *page = mode + 4; int retval; fillbytes((caddr_t)mode, sizeof(mode), '\0'); /* the first 4 mode bytes are zero. */ page[0] = 0x20; page[1] = 1; page[2] = speed; /* 0 for single speed, 1 for double speed (3401) */ if (usalp->verbose) fprintf(stderr, "\nspeed select Toshiba..."); usalp->silent++; /* do the scsi cmd */ if ((retval = mode_select(usalp, mode, 7, 0, usalp->inq->data_format >= 2)) < 0) fprintf (stderr, "speed select Toshiba failed\n"); usalp->silent--; } void SpeedSelectSCSINEC(SCSI *usalp, unsigned speed) { static unsigned char mode [4 + 8]; unsigned char *page = mode + 4; int retval; register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)mode, sizeof(mode), '\0'); /* the first 4 mode bytes are zero. */ page [0] = 0x0f; /* page code */ page [1] = 6; /* parameter length */ /* bit 5 == 1 for single speed, otherwise double speed */ page [2] = speed == 1 ? 1 << 5 : 0; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)mode; scmd->size = 12; scmd->flags = SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0xC5; scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[0] = 0 ? 1 : 0 | 1 ? 0x10 : 0; g1_cdblen(&scmd->cdb.g1_cdb, 12); if (usalp->verbose) fprintf(stderr, "\nspeed select NEC..."); /* do the scsi cmd */ usalp->cmdname = "speed select NEC"; if ((retval = usal_cmd(usalp)) < 0) fprintf(stderr ,"speed select NEC failed\n"); } void SpeedSelectSCSIPhilipsCDD2600(SCSI *usalp, unsigned speed) { /* MODE_SELECT, page = SCSI-2 save page disabled, reserved, reserved, parm list len, flags */ static unsigned char mode [4 + 8]; unsigned char *page = mode + 4; int retval; fillbytes((caddr_t)mode, sizeof(mode), '\0'); /* the first 4 mode bytes are zero. */ page[0] = 0x23; page[1] = 6; page[2] = page [4] = speed; page[3] = 1; if (usalp->verbose) fprintf(stderr, "\nspeed select Philips..."); /* do the scsi cmd */ if ((retval = mode_select(usalp, mode, 12, 0, usalp->inq->data_format >= 2)) < 0) fprintf (stderr, "speed select PhilipsCDD2600 failed\n"); } void SpeedSelectSCSISony(SCSI *usalp, unsigned speed) { static unsigned char mode [4 + 4]; unsigned char *page = mode + 4; int retval; fillbytes((caddr_t)mode, sizeof(mode), '\0'); /* the first 4 mode bytes are zero. */ page[0] = 0x31; page[1] = 2; page[2] = speed; if (usalp->verbose) fprintf(stderr, "\nspeed select Sony..."); /* do the scsi cmd */ usalp->silent++; if ((retval = mode_select(usalp, mode, 8, 0, usalp->inq->data_format >= 2)) < 0) fprintf (stderr, "speed select Sony failed\n"); usalp->silent--; } void SpeedSelectSCSIYamaha (usalp, speed) SCSI *usalp; unsigned speed; { static unsigned char mode [4 + 4]; unsigned char *page = mode + 4; int retval; fillbytes((caddr_t)mode, sizeof(mode), '\0'); /* the first 4 mode bytes are zero. */ page[0] = 0x31; page[1] = 2; page[2] = speed; if (usalp->verbose) fprintf(stderr, "\nspeed select Yamaha..."); /* do the scsi cmd */ if ((retval = mode_select(usalp, mode, 8, 0, usalp->inq->data_format >= 2)) < 0) fprintf (stderr, "speed select Yamaha failed\n"); } void SpeedSelectSCSIMMC(SCSI *usalp, unsigned speed) { int spd; register struct usal_cmd *scmd = usalp->scmd; if (speed == 0 || speed == 0xFFFF) { spd = 0xFFFF; } else { spd = (1764 * speed) / 10; } fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->flags = SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xBB; scmd->cdb.g5_cdb.lun = usal_lun(usalp); i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], spd); i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], 0xffff); if (usalp->verbose) fprintf(stderr, "\nspeed select MMC..."); usalp->cmdname = "set cd speed"; usalp->silent++; if (usal_cmd(usalp) < 0) { if (usal_sense_key(usalp) == 0x05 && usal_sense_code(usalp) == 0x20 && usal_sense_qual(usalp) == 0x00) { /* this optional command is not implemented */ } else { usal_printerr(usalp); fprintf (stderr, "speed select MMC failed\n"); } } usalp->silent--; } /* request vendor brand and model */ unsigned char *Inquiry(SCSI *usalp) { static unsigned char *Inqbuffer = NULL; register struct usal_cmd *scmd = usalp->scmd; if (Inqbuffer == NULL) { Inqbuffer = malloc(36); if (Inqbuffer == NULL) { fprintf(stderr, "Cannot allocate memory for inquiry command in line %d\n", __LINE__); return NULL; } } fillbytes(Inqbuffer, 36, '\0'); fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)Inqbuffer; scmd->size = 36; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G0_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g0_cdb.cmd = SC_INQUIRY; scmd->cdb.g0_cdb.lun = usal_lun(usalp); scmd->cdb.g0_cdb.count = 36; usalp->cmdname = "inquiry"; if (usal_cmd(usalp) < 0) return (NULL); /* define structure with inquiry data */ memcpy(usalp->inq, Inqbuffer, sizeof(*usalp->inq)); if (usalp->verbose) usal_prbytes("Inquiry Data :", (Uchar *)Inqbuffer, 22 - scmd->resid); return (Inqbuffer); } #define SC_CLASS_EXTENDED_SENSE 0x07 #define TESTUNITREADY_CMD 0 #define TESTUNITREADY_CMDLEN 6 #define ADD_SENSECODE 12 #define ADD_SC_QUALIFIER 13 #define NO_MEDIA_SC 0x3a #define NO_MEDIA_SCQ 0x00 int TestForMedium(SCSI *usalp) { register struct usal_cmd *scmd = usalp->scmd; if (interface != GENERIC_SCSI) { return 1; } /* request READY status */ fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = (caddr_t)0; scmd->size = 0; scmd->flags = SCG_DISRE_ENA | (1 ? SCG_SILENT:0); scmd->cdb_len = SC_G0_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY; scmd->cdb.g0_cdb.lun = usal_lun(usalp); if (usalp->verbose) fprintf(stderr, "\ntest unit ready..."); usalp->silent++; usalp->cmdname = "test unit ready"; if (usal_cmd(usalp) >= 0) { usalp->silent--; return 1; } usalp->silent--; if (scmd->sense.code >= SC_CLASS_EXTENDED_SENSE) { return scmd->u_sense.cmd_sense[ADD_SENSECODE] != NO_MEDIA_SC || scmd->u_sense.cmd_sense[ADD_SC_QUALIFIER] != NO_MEDIA_SCQ; } else { /* analyse status. */ /* 'check condition' is interpreted as not ready. */ return (scmd->u_scb.cmd_scb[0] & 0x1e) != 0x02; } } int StopPlaySCSI(SCSI *usalp) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = NULL; scmd->size = 0; scmd->flags = SCG_DISRE_ENA; scmd->cdb_len = SC_G0_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g0_cdb.cmd = 0x1b; scmd->cdb.g0_cdb.lun = usal_lun(usalp); if (usalp->verbose) fprintf(stderr, "\nstop audio play"); /* do the scsi cmd */ usalp->cmdname = "stop audio play"; return usal_cmd(usalp) >= 0 ? 0 : -1; } int Play_atSCSI(SCSI *usalp, unsigned int from_sector, unsigned int sectors) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); scmd->addr = NULL; scmd->size = 0; scmd->flags = SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x47; scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[1] = (from_sector + 150) / (60*75); scmd->cdb.g1_cdb.addr[2] = ((from_sector + 150) / 75) % 60; scmd->cdb.g1_cdb.addr[3] = (from_sector + 150) % 75; scmd->cdb.g1_cdb.res6 = (from_sector + 150 + sectors) / (60*75); scmd->cdb.g1_cdb.count[0] = ((from_sector + 150 + sectors) / 75) % 60; scmd->cdb.g1_cdb.count[1] = (from_sector + 150 + sectors) % 75; if (usalp->verbose) fprintf(stderr, "\nplay sectors..."); /* do the scsi cmd */ usalp->cmdname = "play sectors"; return usal_cmd(usalp) >= 0 ? 0 : -1; } static caddr_t scsibuffer; /* page aligned scsi transfer buffer */ void init_scsibuf(SCSI *scsp, unsigned amt); void init_scsibuf(SCSI *usalp, unsigned amt) { if (scsibuffer != NULL) { fprintf(stderr, "the SCSI transfer buffer has already been allocated!\n"); exit(SETUPSCSI_ERROR); } scsibuffer = usal_getbuf(usalp, amt); if (scsibuffer == NULL) { fprintf(stderr, "could not get SCSI transfer buffer!\n"); exit(SETUPSCSI_ERROR); } }