YamahaCDR10x.cc
上传用户:weiliju62
上传日期:2007-01-06
资源大小:619k
文件大小:25k
- /* cdrdao - write audio CD-Rs in disc-at-once mode
- *
- * Copyright (C) 1999 Cameron G. MacKinnon <C_MacKinnon@yahoo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- /*
- * $Log: YamahaCDR10x.cc,v $
- * Revision 1.3 1999/04/05 11:04:10 mueller
- * Added driver option flags.
- *
- * Revision 1.2 1999/03/27 14:35:17 mueller
- * Added data track support.
- *
- * Revision 1.1 1999/02/28 10:27:49 mueller
- * Initial revision
- */
- /* Cameron's log:
- *
- * Revision 0.4 1999/01/08 21:00:00 cmackin
- * Fixed BCD fields in Cue Sheet
- * Todo: BCD issues for ISRC and Catalog
- * core dump when RO CD inserted for burn functions
- *
- * Revision 0.3 1999/01/08 12:00:00 cmackin
- * Added {g,s}etModePage6(...): Yamaha doesn't support the (10) cmds
- *
- * Revision 0.2 1999/01/08 09:00:00 cmackin
- * Added READ CD-ROM CAPACITY to diskInfo()
- *
- * Revision 0.1 1999/01/07 20:44:58 cmackin
- * Initial revision, based on GenericMMC
- *
- */
- /* Driver for Yamaha CDR10X drives.
- * Written by Cameron G. MacKinnon <C_MacKinnon@yahoo.com>.
- */
- static char rcsid[] = "$Id: YamahaCDR10x.cc,v 1.3 1999/04/05 11:04:10 mueller Exp mueller $";
- #include <config.h>
- #include <unistd.h>
- #include <string.h>
- #include <assert.h>
- #include "YamahaCDR10x.h"
- #include "Toc.h"
- #include "PQSubChannel16.h"
- #include "util.h"
- #include "port.h"
- YamahaCDR10x::YamahaCDR10x(ScsiIf *scsiIf, unsigned long options)
- : CdrDriver(scsiIf, options)
- {
- int i;
- driverName_ = "Yamaha CDR10x - Version 0.5 (data)";
- encodingMode_ = 1;
-
- speed_ = 0;
- simulate_ = 1;
- scsiTimeout_ = 0;
- for (i = 0; i < maxScannedSubChannels_; i++)
- scannedSubChannels_[i] = new PQSubChannel16;
- // reads little endian samples
- audioDataByteOrder_ = 0;
- }
- // static constructor
- CdrDriver *YamahaCDR10x::instance(ScsiIf *scsiIf, unsigned long options)
- {
- return new YamahaCDR10x(scsiIf, options);
- }
- YamahaCDR10x::~YamahaCDR10x()
- {
- int i;
- for (i = 0; i < maxScannedSubChannels_; i++) {
- delete scannedSubChannels_[i];
- scannedSubChannels_[i] = NULL;
- }
- }
- int YamahaCDR10x::multiSession(int m)
- {
- if (m != 0) {
- return 1; // multi session mode is not supported
- }
- return 0;
- }
- // sets speed
- // return: 0: OK
- // 1: illegal speed
- int YamahaCDR10x::speed(int s)
- {
- if (s == 0 || s == 1 || s == 2 || s == 4)
- speed_ = s;
- else if (s == 3)
- speed_ = 2;
- else if (s > 4)
- speed_ = 4;
- else
- return 1;
- if (selectSpeed() != 0)
- return 1;
-
- return 0;
- }
- int YamahaCDR10x::speed()
- {
- DriveInfo di;
- if (driveInfo(&di, 1) != 0) {
- return 0;
- }
- return speed2Mult(di.currentWriteSpeed);
- }
- // loads ('unload' == 0) or ejects ('unload' == 1) tray
- // return: 0: OK
- // 1: scsi command failed
- int YamahaCDR10x::loadUnload(int unload) const
- {
- unsigned char cmd[6];
- memset(cmd, 0, 6);
- cmd[0] = 0x1b; // START/STOP UNIT
- if (unload) {
- cmd[4] = 0x02; // LoUnlo=1, Start=0
- }
- else {
- cmd[4] = 0x01; // LoUnlo=0, Start=1: This is a caddy, and load is reserved
- }
-
- if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) {
- message(-2, "Cannot %s medium.", (unload ? "stop & unload" : "start"));
- return 1;
- }
- return 0;
- }
- // sets read/write speed
- // return: 0: OK
- // 1: scsi command failed
- int YamahaCDR10x::selectSpeed()
- {
- unsigned char mp[4];
- if (getModePage6(0x31/*drive configuration mode page*/, mp, 4,
- NULL, NULL, 1) != 0) {
- message(-2, "Cannot retrieve drive configuration mode page (0x31).");
- return 1;
- }
- mp[3] &= 0x0f;
- if(speed_ == 0 || speed_ == 4) {
- mp[3] |= 0x20; // read at 4x, write at 2x (CDR102) or 4x (CDR100)
- } else if(speed_ == 2) {
- mp[3] |= 0x10; // read at 2x, write at 2x
- } else if(speed_ == 1) {
- ; // read at 1x, write at 1x
- } else {
- message(-2, "Invalid write speed argument %d. 0, 1, 2 or 4 expected.",
- speed_);
- return 1;
- }
- if (setModePage6(mp, NULL, NULL, 1) != 0) {
- message(-2, "Cannot set drive configuration mode page for cd speed.");
- return 1;
- }
- return 0;
- }
- // Sets write parameters via mode pages 0x31 and 0x32.
- // return: 0: OK
- // 1: scsi command failed
- int YamahaCDR10x::setWriteParameters()
- {
- unsigned char mp[8]; // the larger of 4 and 8, gets used twice
- if (getModePage6(0x31/*drive configuration mode page*/, mp, 4,
- NULL, NULL, 1) != 0) {
- message(-2, "Cannot retrieve drive configuration mode page (0x31).");
- return 1;
- }
- mp[3] &= 0xf0; // save speed settings in high nibble
- mp[3] |= (simulate_ ? 1 : 0);
- if (setModePage6(mp, NULL, NULL, 1) != 0) {
- message(-2, "Cannot set drive configuration mode page (0x31).");
- return 1;
- }
- memset(mp, 0, 8);
- if (getModePage6(0x32/*write format mode page*/, mp, 8,
- NULL, NULL, 1) != 0) {
- message(-2, "Cannot retrieve write format mode page (0x32).");
- return 1;
- }
- mp[2] &= 0xf0; // RW subcode internally zero supplied
- mp[3] &= 0xf0;
- mp[3] |= 0x04; // disc at once (single session)
- if (setModePage6(mp, NULL, NULL, 1) != 0) {
- message(-2, "Cannot set write format mode page (0x32).");
- return 1;
- }
- return 0;
- }
- void YamahaCDR10x::cueSheetDataType(TrackData::Mode mode,
- unsigned char *dataType,
- unsigned char *dataForm)
- {
- switch (mode) {
- case TrackData::AUDIO:
- *dataType = 0;
- *dataForm = 0;
- break;
-
- case TrackData::MODE1:
- case TrackData::MODE1_RAW:
- *dataType = 2;
- *dataForm = 3;
- break;
- case TrackData::MODE2:
- *dataType = 3;
- *dataForm = 3;
- break;
- case TrackData::MODE2_RAW:
- case TrackData::MODE2_FORM1:
- case TrackData::MODE2_FORM2:
- case TrackData::MODE2_FORM_MIX:
- if (toc_->tocType() == Toc::CD_I)
- *dataType = 4;
- else
- *dataType = 5;
- *dataForm = 3;
- break;
- case TrackData::MODE0:
- message(-3, "Illegal mode in 'YamahaCDR10x::cueSheetDataType()'.");
- *dataType = 0;
- *dataForm = 0;
- break;
- }
- }
- // Creates cue sheet for current toc.
- // cueSheetLen: filled with length of cue sheet in bytes
- // return: newly allocated cue sheet buffer or 'NULL' on error
- // CHECKS OUT WITH DOS-DAO AND MANUAL
- unsigned char *YamahaCDR10x::createCueSheet(long *cueSheetLen)
- {
- const Track *t;
- int trackNr;
- Msf start, end, index;
- unsigned char *cueSheet;
- long len = 2; // entries for lead-in, lead-out
- long n; // index into cue sheet
- unsigned char ctl; // control nibbles of cue sheet entry CTL/ADR
- long i;
- unsigned char dataForm;
- unsigned char dataType;
- TrackIterator itr(toc_);
- if (itr.first(start, end) == NULL) {
- return NULL;
- }
- if (toc_->catalogValid()) {
- len += 2;
- }
- for (t = itr.first(start, end), trackNr = 1;
- t != NULL; t = itr.next(start, end), trackNr++) {
- len += 2; // entry for track and mandatory pre-gap
- if (t->type() == TrackData::AUDIO && t->isrcValid()) {
- len += 2; // entries for ISRC code
- }
- len += t->nofIndices(); // entry for each index increment
- }
- cueSheet = new (unsigned char)[len * 8];
- n = 0;
- if (toc_->leadInMode() == TrackData::AUDIO)
- ctl = 0;
- else
- ctl = 0x40;
- if (toc_->catalogValid()) {
- // fill catalog number entry
- cueSheet[n*8] = 0x02 | ctl;
- cueSheet[(n+1)*8] = 0x02 | ctl;
- for (i = 1; i <= 13; i++) {
- if (i < 8) {
- cueSheet[n*8 + i] = toc_->catalog(i-1) + '0';
- }
- else {
- cueSheet[(n+1)*8 + i - 7] = toc_->catalog(i-1) + '0';
- }
- }
- cueSheet[(n+1)*8+7] = 0;
- n += 2;
- }
- cueSheetDataType(toc_->leadInMode(), &dataType, &dataForm);
- // entry for lead-in
- cueSheet[n*8] = 0x01 | ctl; // CTL/ADR
- cueSheet[n*8+1] = 0; // Track number
- cueSheet[n*8+2] = 0; // Index
- cueSheet[n*8+3] = dataType; // Data Type
- cueSheet[n*8+4] = 0; // Data Form: always 0 for lead-in
- cueSheet[n*8+5] = 0; // MIN
- cueSheet[n*8+6] = 0; // SEC
- cueSheet[n*8+7] = 0; // FRAME
- n++;
-
- for (t = itr.first(start, end), trackNr = 1;
- t != NULL;
- t = itr.next(start, end), trackNr++) {
- cueSheetDataType(t->type(), &dataType, &dataForm);
- ctl = trackCtl(t);
- if (t->type() == TrackData::AUDIO) {
- // set ISRC code for audio track
- if (t->isrcValid()) {
- cueSheet[n*8] = ctl | 0x03;
- cueSheet[n*8+1] = SubChannel::bcd(trackNr);
- cueSheet[n*8+2] = t->isrcCountry(0);
- cueSheet[n*8+3] = t->isrcCountry(1);
- cueSheet[n*8+4] = t->isrcOwner(0);
- cueSheet[n*8+5] = t->isrcOwner(1);
- cueSheet[n*8+6] = t->isrcOwner(2);
- cueSheet[n*8+7] = t->isrcYear(0) + '0';
- n++;
-
- cueSheet[n*8] = ctl | 0x03;
- cueSheet[n*8+1] = SubChannel::bcd(trackNr);
- cueSheet[n*8+2] = t->isrcYear(1) + '0';
- cueSheet[n*8+3] = t->isrcSerial(0) + '0';
- cueSheet[n*8+4] = t->isrcSerial(1) + '0';
- cueSheet[n*8+5] = t->isrcSerial(2) + '0';
- cueSheet[n*8+6] = t->isrcSerial(3) + '0';
- cueSheet[n*8+7] = t->isrcSerial(4) + '0';
- n++;
- }
- }
- Msf tstart(start.lba() + 150); // start of index 1
- // start of pre-gap, atime equals index 1 if no pre-gap is defined
- Msf pstart(trackNr == 1 ? 0 : tstart.lba() - t->start().lba());
- // entry for pre-gap
- cueSheet[n*8] = ctl | 0x01;
- cueSheet[n*8+1] = SubChannel::bcd(trackNr);
- cueSheet[n*8+2] = 0; // Index 0 indicates pre-gap
- cueSheet[n*8+3] = dataType; // Data Type
- cueSheet[n*8+4] = dataForm; // Data Form
- cueSheet[n*8+5] = SubChannel::bcd(pstart.min());
- cueSheet[n*8+6] = SubChannel::bcd(pstart.sec());
- cueSheet[n*8+7] = SubChannel::bcd(pstart.frac());
- n++;
- cueSheet[n*8] = ctl | 0x01;
- cueSheet[n*8+1] = SubChannel::bcd(trackNr);
- cueSheet[n*8+2] = 1; // Index 1
- cueSheet[n*8+3] = dataType; // Data Type
- cueSheet[n*8+4] = dataForm; // Data Form
- cueSheet[n*8+5] = SubChannel::bcd(tstart.min());
- cueSheet[n*8+6] = SubChannel::bcd(tstart.sec());
- cueSheet[n*8+7] = SubChannel::bcd(tstart.frac());
- n++;
- for (i = 0; i < t->nofIndices(); i++) {
- index = tstart + t->getIndex(i);
- cueSheet[n*8] = ctl | 0x01;
- cueSheet[n*8+1] = SubChannel::bcd(trackNr);
- cueSheet[n*8+2] = SubChannel::bcd(i+2); // Index
- cueSheet[n*8+3] = dataType; // DataType
- cueSheet[n*8+4] = dataForm; // Data Form
- cueSheet[n*8+5] = SubChannel::bcd(index.min());
- cueSheet[n*8+6] = SubChannel::bcd(index.sec());
- cueSheet[n*8+7] = SubChannel::bcd(index.frac());
- n++;
- }
- }
- assert(n == len - 1);
- // entry for lead out
- Msf lostart(toc_->length().lba() + 150);
- cueSheetDataType(toc_->leadOutMode(), &dataType, &dataForm);
- ctl = toc_->leadOutMode() == TrackData::AUDIO ? 0 : 0x40;
-
- cueSheet[n*8] = ctl | 0x01;
- cueSheet[n*8+1] = 0xaa; // This IS BCD
- cueSheet[n*8+2] = 1; // Index 1
- cueSheet[n*8+3] = dataType; // Data for lead-out
- cueSheet[n*8+4] = 0; // Data Form, always 0 for lead-out
- cueSheet[n*8+5] = SubChannel::bcd(lostart.min());
- cueSheet[n*8+6] = SubChannel::bcd(lostart.sec());
- cueSheet[n*8+7] = SubChannel::bcd(lostart.frac());
- message(3, "nCue Sheet:");
- message(3, "CTL/ TNO INDEX DATA DATA MIN SEC FRAME");
- message(3, "ADR BCD BCD TYPE Form BCD BCD BCD <- Note");
- for (n = 0; n < len; n++) {
- message(3, "%02x %02x %02x %02x %02x %02x %02x %02x",
- cueSheet[n*8],
- cueSheet[n*8+1], cueSheet[n*8+2], cueSheet[n*8+3], cueSheet[n*8+4],
- cueSheet[n*8+5], cueSheet[n*8+6], cueSheet[n*8+7]);
- }
- *cueSheetLen = len * 8;
- return cueSheet;
- }
- // LOOKS GOOD
- int YamahaCDR10x::sendCueSheet()
- {
- unsigned char cmd[10];
- long cueSheetLen;
- unsigned char *cueSheet = createCueSheet(&cueSheetLen);
- if (cueSheet == NULL) {
- return 1;
- }
- if(cueSheetLen > 32768) { // Limit imposed by drive.
- message(-2, "Cue sheet too long for this device: Limit is 32k bytes.");
- delete[] cueSheet;
- return 1;
- }
- memset(cmd, 0, 10);
- cmd[0] = 0xea; // Yamaha Vendor Specific WRITE TOC
- cmd[7] = cueSheetLen >> 8;
- cmd[8] = cueSheetLen;
- if (sendCmd(cmd, 10, cueSheet, cueSheetLen, NULL, 0) != 0) {
- message(-2, "Cannot send cue sheet.");
- delete[] cueSheet;
- return 1;
- }
- delete[] cueSheet;
- return 0;
- }
- // DOES NOT TALK TO DRIVE: JUST HOUSEKEEPING
- int YamahaCDR10x::initDao(const Toc *toc)
- {
- long n;
- toc_ = toc;
- blockLength_ = AUDIO_BLOCK_LEN;
- blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_;
- assert(blocksPerWrite_ > 0);
- if (selectSpeed() != 0) {
- return 1;
- }
- // allocate buffer for writing zeros
- n = blocksPerWrite_ * blockLength_;
- delete[] zeroBuffer_;
- zeroBuffer_ = new char[n];
- memset(zeroBuffer_, 0, n);
- return 0;
- }
- // LOOKS OK - dodgy WRITE TRACK parameters, but apparently how DAO16 does it
- int YamahaCDR10x::startDao()
- {
- unsigned char cmd[10];
- scsiTimeout_ = scsiIf_->timeout(3 * 60);
- if (setWriteParameters() != 0 ||
- sendCueSheet() != 0) {
- return 1;
- }
- memset(cmd, 0, 10);
- cmd[0] = 0xe6; // Yamaha WRITE TRACK(10)
- cmd[5] = 0; // Track Number
- cmd[6] &= 0xdf; // R Parity = 0;
- cmd[6] &= 0xef; // Byte Swap = 0 = little endian
- cmd[6] &= 0xf7; // Copy = 0
- cmd[6] &= 0xfb; // Audio = 0 (false)
- cmd[6] &= 0xfc; // Mode=0 NB This combination of mode/audio is reserved
- // so we end up sending a bare e6 command with nine bytes of nulls
- if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) {
- message(-2, "Could not send command 0xE6: WRITE TRACK(10)");
- return 1;
- }
- //message(1, "Writing lead-in and gap...");
- long lba = -150;
- if (writeZeros(toc_->leadInMode(), lba, 0, 150) != 0) {
- return 1;
- }
-
- return 0;
- }
- int YamahaCDR10x::finishDao()
- {
- unsigned char cmd[6];
- const unsigned char *sense;
- int senseLen;
- message(1, "Flushing cache...");
-
- if (flushCache() != 0) {
- return 1;
- }
- memset(cmd, 0, 6);
- // wait until lead-out is written
- while(sendCmd(cmd, 6, NULL, 0, NULL, 0, 0) == 2
- && (sense = scsiIf_->getSense(senseLen)) && senseLen
- && sense[2] == 0x0b && sense[0xc] == 0x50) {
- sleep(1);
- }
- scsiIf_->timeout(scsiTimeout_);
- delete[] zeroBuffer_, zeroBuffer_ = NULL;
- return 0;
- }
- void YamahaCDR10x::abortDao()
- {
- flushCache();
- }
- ///////////////////////// FIXME THE TOP BAR //////////////////////////////
- // NEEDS WORK
- DiskInfo *YamahaCDR10x::diskInfo()
- {
- unsigned char cmd[10];
- unsigned long dataLen = 8;
- unsigned char data[8];
- static DiskInfo di;
- //char spd;
- memset(&di, 0, sizeof(DiskInfo));
- di.valid.cdrw = 0; // by definition, for this device
- memset(cmd, 0, 10);
- memset(data, 0, dataLen);
- // This looks like CdrDevice::readCapacity, but with a difference: we
- // get data for a ROM, and we need to check that our disc is writable
- cmd[0] = 0x25; // READ CD-ROM CAPACITY
-
- if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
- message(-1, "Cannot read CD-ROM capacity.");
- return &di;
- }
- if(data[4] | data[5] | data[6] | data[7]) { // block length field, 0=writable
- di.capacity = 0;
- } else { // disk is writable
- di.capacity = data[0]<<24 | data[1]<<16 | data[2]<<8 | data[3];
- }
- di.valid.capacity = 1;
- // FIXME: need to come up with empty, manufacturerID, recSpeed
- // maybe use READ DISC INFO (0x43) here? se p. 62
- /////////////////////////////////////////
-
- return &di;
- }
- // tries to read catalog number from disk and adds it to 'toc'
- // return: 1 if valid catalog number was found, else 0
- int YamahaCDR10x::readCatalog(Toc *toc, long startLba, long endLba)
- {
- unsigned char cmd[10];
- unsigned char data[24];
- char catalog[14];
- int i;
- memset(cmd, 0, 10);
- memset(data, 0, 24);
- cmd[0] = 0x42; // READ SUB-CHANNEL
- cmd[2] = 1 << 6;
- cmd[3] = 0x02; // get media catalog number
- cmd[8] = 24; // transfer length
- if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
- message(-2, "Cannot get catalog number.");
- return 0;
- }
- if (data[8] & 0x80) {
- for (i = 0; i < 13; i++) {
- catalog[i] = data[0x09 + i];
- }
- catalog[13] = 0;
- if (toc->catalog(catalog) == 0) {
- return 1;
- }
- }
- return 0;
- }
- int YamahaCDR10x::readIsrc(int trackNr, char *buf)
- {
- unsigned char cmd[10];
- unsigned char data[24];
- int i;
- buf[0] = 0;
- memset(cmd, 0, 10);
- memset(data, 0, 24);
- cmd[0] = 0x42; // READ SUB-CHANNEL
- cmd[2] = 1 << 6;
- cmd[3] = 0x03; // get ISRC
- cmd[6] = trackNr;
- cmd[8] = 24; // transfer length
- if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
- message(-2, "Cannot get ISRC code.");
- return 0;
- }
- // FIXME this looks right, but the offsets could be wrong
- if (data[8] & 0x80) {
- for (i = 0; i < 12; i++) {
- buf[i] = data[0x09 + i];
- }
- buf[12] = 0;
- }
- return 0;
- }
- int YamahaCDR10x::analyzeTrack(TrackData::Mode mode, int trackNr,
- long startLba,
- long endLba, Msf *indexIncrements,
- int *indexIncrementCnt, long *pregap,
- char *isrcCode, unsigned char *ctl)
- {
- int ret = analyzeTrackScan(mode, trackNr, startLba, endLba,
- indexIncrements, indexIncrementCnt, pregap,
- isrcCode, ctl);
- if (mode == TrackData::AUDIO)
- readIsrc(trackNr, isrcCode);
- else
- *isrcCode = 0;
- return ret;
- }
- int YamahaCDR10x::readSubChannels(long lba, long len, SubChannel ***chans,
- Sample *audioData)
- {
- int retries = 5;
- int i;
- unsigned char cmd[12];
-
- cmd[0] = 0xd8; // Yamaha READ CD-DA
- cmd[1] = 0;
- cmd[2] = lba >> 24;
- cmd[3] = lba >> 16;
- cmd[4] = lba >> 8;
- cmd[5] = lba;
- cmd[6] = len >> 24;
- cmd[7] = len >> 16;
- cmd[8] = len >> 8;
- cmd[9] = len;
- cmd[10] = 0x01; // 2352 + 10 Q (no CRC) + 6 NULL
- cmd[11] = 0;
- while (1) {
- if (sendCmd(cmd, 12, NULL, 0,
- transferBuffer_, len * (AUDIO_BLOCK_LEN + 16),
- retries == 0 ? 1 : 0) != 0) {
- if (retries == 0)
- return 1;
- }
- else {
- break;
- }
- retries--;
- }
- for (i = 0; i < len; i++) {
- PQSubChannel16 *chan = (PQSubChannel16*)scannedSubChannels_[i];
- unsigned char *p =
- transferBuffer_ + i * (AUDIO_BLOCK_LEN + 16) + AUDIO_BLOCK_LEN;
- // slightly reorder the sub-channel so it is suitable for 'PQSubChannel16'
- p[0] <<= 4; // ctl/adr
- p[0] |= p[1];
- p[1] = p[2]; // track nr
- p[2] = p[3]; // index nr
- p[3] = p[4]; // min
- p[4] = p[5]; // sec
- p[5] = p[6]; // frame
- p[6] = 0; // zero
- // p[7] is amin
- // p[8] is asec
- // p[9] is aframe
- chan->init(p);
-
- if (chan->checkConsistency())
- chan->calcCrc();
- }
- if (audioData != NULL) {
- unsigned char *p = transferBuffer_;
- for (i = 0; i < len; i++) {
- memcpy(audioData, p, AUDIO_BLOCK_LEN);
- p += AUDIO_BLOCK_LEN + 16;
- audioData += SAMPLES_PER_BLOCK;
- }
- }
-
- *chans = scannedSubChannels_;
- return 0;
- }
- // LOOKSGOOD, except for accurate audio stream bit
- int YamahaCDR10x::driveInfo(DriveInfo *info, int showErrorMsg)
- {
- unsigned char mp[4];
- if (getModePage6(0x31, mp, 4, NULL, NULL, showErrorMsg) != 0) {
- if (showErrorMsg) {
- message(-2, "Cannot retrieve drive configuration mode page (0x31).");
- }
- return 1;
- }
- // FIXME
- // info->accurateAudioStream = mp[5] & 0x02 ? 1 : 0;
- info->accurateAudioStream = 0;
- info->maxReadSpeed = mult2Speed(4);
- if(!strncmp(scsiIf_->product(), "CDR100", 6)) {
- info->maxWriteSpeed = mult2Speed(4);
- info->currentWriteSpeed = info->currentReadSpeed =
- mult2Speed(1 << (mp[3] >> 4));
- } else { // CDR102, crippled to 2x write
- info->maxWriteSpeed = mult2Speed(2);
- info->currentReadSpeed = mult2Speed(1 << (mp[3] >> 4));
- info->currentWriteSpeed = mult2Speed((mp[3] >> 4) ? 2 : 1);
- }
- return 0;
- }
- // writeData is overridden here because the CDR10x, while writing the disc
- // lead-in with the buffer full, will return CHECK CONDITION with sense
- // DRIVE BUSY and additional sense 0xb8 = WRITE LEAD-IN IN PROGRESS.
- // This is normal operation and the write should be retried until successful.
- // Writes data to target, the block length depends on the actual writing mode
- // 'len' is number of blocks to write.
- // 'lba' specifies the next logical block address for writing and is updated
- // by this function.
- // return: 0: OK
- // 1: scsi command failed
- int YamahaCDR10x::writeData(TrackData::Mode mode, long &lba, const char *buf,
- long len)
- {
- assert(blocksPerWrite_ > 0);
- int writeLen = 0;
- unsigned char cmd[10];
- int retry;
- int retval;
- long blockLength = blockSize(mode);
- #if 0
- long sum, i;
- sum = 0;
- for (i = 0; i < len * blockLength; i++) {
- sum += buf[i];
- }
- message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum);
- #endif
- memset(cmd, 0, 10);
- cmd[0] = 0x2a; // WRITE1
-
- while (len > 0) {
- writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len);
- cmd[2] = lba >> 24;
- cmd[3] = lba >> 16;
- cmd[4] = lba >> 8;
- cmd[5] = lba;
- cmd[7] = writeLen >> 8;
- cmd[8] = writeLen & 0xff;
- do {
- retry = 0;
- retval = sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength,
- NULL, 0, 0);
- if(retval == 2) {
- const unsigned char *sense;
- int senseLen;
- sense = scsiIf_->getSense(senseLen);
- // we spin on the write here, waiting a reasonable time in between
- // we should really use READ BLOCK LIMIT (0x05)
- if(senseLen && sense[2] == 9 && sense[0xc] == 0xb8) {
- mSleep(40);
- retry = 1;
- }
- else {
- scsiIf_->printError();
- }
- }
- } while(retry == 1);
- if(retval) {
- message(-2, "Write data failed.");
- return 1;
- }
- buf += writeLen * blockLength;
- lba += writeLen;
- len -= writeLen;
- }
-
- return 0;
- }
- CdRawToc *YamahaCDR10x::getRawToc(int sessionNr, int *len)
- {
- // not supported by drive
- return NULL;
- }
- long YamahaCDR10x::readTrackData(TrackData::Mode mode, long lba, long len,
- unsigned char *buf)
- {
- unsigned char cmd[10];
- long blockLen = 2340;
- long i;
- TrackData::Mode actMode;
- int ok = 0;
- int softError;
- const unsigned char *sense;
- int senseLen;
- if (setBlockSize(blockLen) != 0)
- return 0;
- memset(cmd, 0, 10);
- cmd[0] = 0x28; // READ10
- cmd[2] = lba >> 24;
- cmd[3] = lba >> 16;
- cmd[4] = lba >> 8;
- cmd[5] = lba;
- while (len > 0 && !ok) {
- cmd[7] = len >> 8;
- cmd[8] = len;
- memset(transferBuffer_, 0, len * blockLen);
- switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) {
- case 0:
- ok = 1;
- break;
- case 2:
- softError = 0;
- sense = scsiIf_->getSense(senseLen);
- if (senseLen > 0x0c) {
- if ((sense[2] &0x0f) == 5) {
- switch (sense[12]) {
- case 0x63: // end of user area encountered on this track
- case 0x64: // Illegal mode for this track
- softError = 1;
- break;
- }
- }
- else if ((sense[2] & 0x0f) == 3) { // Medium error
- switch (sense[12]) {
- case 0x02: // No seek complete, sector not found
- case 0x11: // L-EC error
- return -2;
- break;
- }
- }
- }
- if (!softError) {
- scsiIf_->printError();
- return -1;
- }
- break;
- default:
- message(-2, "Read error at LBA %ld, len %ld", lba, len);
- return -1;
- break;
- }
- if (!ok) {
- len--;
- }
- }
- unsigned char *sector = transferBuffer_;
- for (i = 0; i < len; i++) {
- actMode = determineSectorMode(sector);
- if (!(actMode == mode ||
- (mode == TrackData::MODE2_FORM_MIX &&
- (actMode == TrackData::MODE2_FORM1 ||
- actMode == TrackData::MODE2_FORM2)) ||
- (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) ||
- (mode == TrackData::MODE2_RAW &&
- (actMode == TrackData::MODE2 ||
- actMode == TrackData::MODE2_FORM1 ||
- actMode == TrackData::MODE2_FORM2)))) {
- return i;
- }
- if (buf != NULL) {
- switch (mode) {
- case TrackData::MODE1:
- memcpy(buf, sector + 4, MODE1_BLOCK_LEN);
- buf += MODE1_BLOCK_LEN;
- break;
- case TrackData::MODE2:
- case TrackData::MODE2_FORM_MIX:
- memcpy(buf, sector + 4, MODE2_BLOCK_LEN);
- buf += MODE2_BLOCK_LEN;
- break;
- case TrackData::MODE2_FORM1:
- memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN);
- buf += MODE2_FORM1_DATA_LEN;
- break;
- case TrackData::MODE2_FORM2:
- memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN);
- buf += MODE2_FORM2_DATA_LEN;
- break;
- case TrackData::MODE1_RAW:
- case TrackData::MODE2_RAW:
- memcpy(buf, syncPattern, 12);
- memcpy(buf + 12, sector, 2340);
- buf += AUDIO_BLOCK_LEN;
- break;
- case TrackData::MODE0:
- case TrackData::AUDIO:
- message(-3, "YamahaCDR10x::readTrackData: Illegal mode.");
- return 0;
- break;
- }
- }
- sector += blockLen;
- }
- return len;
- }
- Toc *YamahaCDR10x::readDiskToc(int session, const char *audioFilename)
- {
- Toc *toc = CdrDriver::readDiskToc(session, audioFilename);
- setBlockSize(MODE1_BLOCK_LEN);
-
- return toc;
- }
- Toc *YamahaCDR10x::readDisk(int session, const char *fname)
- {
- Toc *toc = CdrDriver::readDisk(session, fname);
- setBlockSize(MODE1_BLOCK_LEN);
- return toc;
- }
- int YamahaCDR10x::readAudioRange(int fd, long start, long end,
- int startTrack, int endTrack, TrackInfo *info)
- {
- if (!onTheFly_) {
- int t;
- message(1, "Analyzing...");
-
- for (t = startTrack; t <= endTrack; t++) {
- message(1, "Track %d...", t + 1);
- info[t].isrcCode[0] = 0;
- readIsrc(t + 1, info[t].isrcCode);
- if (info[t].isrcCode[0] != 0)
- message(1, "Found ISRC code.");
- }
- message(1, "Reading...");
- }
- return CdrDriver::readAudioRangeParanoia(fd, start, end, startTrack,
- endTrack, info);
- }