TeacCdr55.cc
上传用户:weiliju62
上传日期:2007-01-06
资源大小:619k
文件大小:32k
- /* cdrdao - write audio CD-Rs in disc-at-once mode
- *
- * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.de>
- *
- * 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: TeacCdr55.cc,v $
- * Revision 1.3 1999/04/05 11:04:10 mueller
- * Added driver option flags.
- *
- * Revision 1.2 1999/03/27 14:35:37 mueller
- * Added 'read-toc' support.
- *
- * Revision 1.1 1999/03/21 19:36:08 mueller
- * Initial revision
- *
- */
- static char rcsid[] = "$Id: TeacCdr55.cc,v 1.3 1999/04/05 11:04:10 mueller Exp mueller $";
- #include <config.h>
- #include <string.h>
- #include <assert.h>
- #include "TeacCdr55.h"
- #include "Toc.h"
- #include "PQSubChannel16.h"
- #include "util.h"
- TeacCdr55::TeacCdr55(ScsiIf *scsiIf, unsigned long options)
- : CdrDriver(scsiIf, options)
- {
- int i;
- driverName_ = "Teac CD-R50/55 - Version 0.1 (data)";
-
- speed_ = 0;
- simulate_ = 1;
- encodingMode_ = 1;
- scsiTimeout_ = 0;
- actMode_ = TrackData::AUDIO;
- writeEndLba_ = 0;
- memset(modeSelectData_, 0, 12);
- memset(&diskInfo_, 0, sizeof(DiskInfo));
- for (i = 0; i < maxScannedSubChannels_; i++)
- scannedSubChannels_[i] = new PQSubChannel16;
- // reads little endian samples
- audioDataByteOrder_ = 0;
- }
- TeacCdr55::~TeacCdr55()
- {
- int i;
- for (i = 0; i < maxScannedSubChannels_; i++) {
- delete scannedSubChannels_[i];
- scannedSubChannels_[i] = NULL;
- }
- }
- // static constructor
- CdrDriver *TeacCdr55::instance(ScsiIf *scsiIf, unsigned long options)
- {
- return new TeacCdr55(scsiIf, options);
- }
- // sets speed
- // return: 0: OK
- // 1: illegal speed
- int TeacCdr55::speed(int s)
- {
- if (s >= 0 && s <= 4 && s != 3) {
- speed_ = s;
- }
- else if (s == 3) {
- speed_ = 2;
- }
- else if (s > 4) {
- speed_ = 4;
- }
- else {
- return 1;
- }
- return 0;
- }
- // loads ('unload' == 0) or ejects ('unload' == 1) tray
- // return: 0: OK
- // 1: scsi command failed
- int TeacCdr55::loadUnload(int unload) const
- {
-
- unsigned char cmd[6];
- memset(cmd, 0, 6);
- cmd[0] = 0x1b; // START/STOP UNIT
- cmd[4] = unload ? 0x02 : 0x03;
- if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) {
- message(-2, "Cannot load/unload medium.");
- return 1;
- }
- return 0;
- }
- // Retrieves mode select header and block descriptor and stores it in
- // class member 'modeSelectData_' for later usage with various mode select
- // commands.
- // Return: 0: OK, 1: SCSI error
- int TeacCdr55::getModeSelectData()
- {
- unsigned char cmd[6];
- memset(cmd, 0, 6);
- memset(modeSelectData_, 0, 12);
- cmd[0] = 0x1a; // MODE SENSE
- cmd[4] = 12;
- if (sendCmd(cmd, 6, NULL, 0, modeSelectData_, 12, 1) != 0) {
- message(-2, "Mode Sense failed.");
- return 1;
- }
- return 0;
- }
- // sets read/write speed and simulation mode
- // return: 0: OK
- // 1: scsi command failed
- int TeacCdr55::setWriteSpeed()
- {
- unsigned char mp[4];
-
- mp[0] = 0x31;
- mp[1] = 2;
- mp[2] = 0;
- mp[3] = 0;
- switch (speed_) {
- case 1:
- mp[2] = 0;
- break;
- case 2:
- mp[2] = 1;
- break;
- case 0:
- case 4:
- mp[2] = 2;
- break;
- }
- if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) {
- message(-2, "Cannot set speed mode page.");
- return 1;
- }
-
- return 0;
- }
- // Sets write parameters via mode page 0x22.
- // return: 0: OK
- // 1: scsi command failed
- int TeacCdr55::setWriteParameters()
- {
- unsigned char mp[9];
- memset(mp, 0, 9);
- mp[0] = 0x22;
- mp[1] = 7;
- if (multiSession()) {
- mp[4] = 4; // session at once, keep session open
- }
- else {
- if (diskInfo_.sessionCnt > 0)
- mp[4] = 0x84; // session at once and close disk
- else
- mp[4] = 2; // disk at once
- }
- if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) {
- message(-2, "Cannot set write method mode page.");
- return 1;
- }
- return 0;
- }
- int TeacCdr55::setSimulationMode()
- {
- unsigned char mp[3];
- mp[0] = 0x21;
- mp[1] = 1;
- if (simulate())
- mp[2] = 3;
- else
- mp[2] = 0;
- if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) {
- message(-2, "Cannot set preview write mode page.");
- return 1;
- }
- return 0;
- }
- int TeacCdr55::setWriteDensity(TrackData::Mode mode)
- {
- long blockLength = blockSize(mode);
- unsigned char cmd[6];
- unsigned char data[12];
- memset(cmd, 0, 6);
- cmd[0] = 0x15; // MODE SELECT
- cmd[1] = 0x10;
- cmd[4] = 12;
- memcpy(data, modeSelectData_, 12);
- data[0] = 0;
- data[3] = 8;
- data[9] = 0;
- switch (mode) {
- case TrackData::AUDIO:
- data[4] = 0x04;
- break;
- case TrackData::MODE1:
- case TrackData::MODE1_RAW:
- data[4] = 0x01;
- break;
- case TrackData::MODE2:
- data[4] = 0xc1;
- break;
- case TrackData::MODE2_FORM1:
- data[4] = 0x81;
- break;
- case TrackData::MODE2_FORM2:
- data[4] = 0x82;
- break;
- case TrackData::MODE2_RAW:
- case TrackData::MODE2_FORM_MIX:
- data[4] = 0x83; // I'm not sure if this really allows writing of mixed
- // form 1 and form 2 sectors.
- break;
- case TrackData::MODE0:
- message(-3, "Illegal mode in 'TeacCdr55::setWriteDensity()'.");
- return 0;
- break;
- }
- data[10] = blockLength >> 8;
- data[11] = blockLength;
- message(2, "Changing write density to 0x%02x/0x%02x%02x.", data[4], data[10],
- data[11]);
- if (sendCmd(cmd, 6, data, 12, NULL, 0, 1) != 0) {
- message(-2, "Cannot set density/block size.");
- return 1;
- }
- return 0;
- }
- // Judges disc and performs power calibration if possible.
- // judge: 1: judge disc, 0: don't judge disc
- // Return 0: OK
- // 1: judge disc rejected inserted medium
- // 2: SCSI error occured
- int TeacCdr55::executeOPC(int judge)
- {
- unsigned char cmd[12];
- const unsigned char *senseCode;
- int senseLen;
- memset(cmd, 0, 12);
- cmd[0] = 0xec; // OPC EXECUTION
- if (judge) {
- cmd[1] = 1; // judge current disc
- message(1, "Judging disk...");
- switch (sendCmd(cmd, 12, NULL, 0, NULL, 0, 0)) {
- case 0: // OK, disc can be written at selected speed
- break;
- case 1:
- message(-2, "Judge disk command failed.");
- return 2;
- break;
-
- case 2: // Check sense code
- senseCode = scsiIf_->getSense(senseLen);
- if (senseLen > 12 && (senseCode[2] & 0x0f) == 5 && senseCode[7] != 0) {
- switch (senseCode[12]) {
- case 0xcd:
- message(-2, "Cannot ensure reliable writing with inserted disk.");
- return 1;
- break;
- case 0xce:
- message(-2, "Cannot ensure reliable writing at selected speed.");
- return 1;
- break;
- case 0xcf:
- message(-2, "Cannot ensure reliable writing - disk has no ID code.");
- return 1;
- break;
- }
- }
- scsiIf_->printError();
- return 2;
- break;
- }
- }
- if (simulate()) {
- message(1, "Skipping optimum power calibration in simulation mode.");
- return 0;
- }
- cmd[1] = 0;
- message(1, "Performing optimum power calibration...");
- if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) {
- message(-2, "Optimum power calibration failed.");
- return 2;
- }
- return 0;
- }
- // Clears the drive's subcode data.
- // Return: 0: OK, 1: SCSI error
- int TeacCdr55::clearSubcode()
- {
- unsigned char cmd[12];
- memset(cmd, 0, 12);
- cmd[0] = 0xe4; // CLEAR SUBCODE
- cmd[5] = 0x80;
- if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) {
- message(-2, "Clear subcode failed.");
- return 1;
- }
-
- return 0;
- }
- // Sets subcode data.
- // start: start LBA
- // end: end LBA, one greater than last block with specfied subcode data
- // ctl: track mode flags in bits 4-7
- // trackNr: track number
- // indexNr: index number
- // pflag: P-channel flag
- // return: 0: OK, 1: SCSI error
- int TeacCdr55::setSubcode(long start, long end, unsigned char ctl, int trackNr,
- int indexNr, int pflag)
- {
- assert(start < end);
- unsigned char cmd[12];
- unsigned char data[4];
- long len = end - start;
- message(3,
- "Setting subcode: start: %6ld, end: %6ld, len: %6ld, CTL: %02x P: %d, T: %2d I: %2d",
- start, end, len, ctl, pflag, trackNr, indexNr);
- memset(cmd, 0, 12);
- cmd[0] = 0xb3; // SET LIMITS
- cmd[2] = start >> 24;
- cmd[3] = start >> 16;
- cmd[4] = start >> 8;
- cmd[5] = start;
- cmd[6] = len >> 24;
- cmd[7] = len >> 16;
- cmd[8] = len >> 8;
- cmd[9] = len;
- if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) {
- message(-2, "Cannot set limits.");
- return 1;
- }
- memset(cmd, 0, 10);
-
- cmd[0] = 0xc2; // SET SUBCODE
- cmd[8] = 4; // parameter list length
- data[0] = pflag != 0 ? 1 : 0;
- data[1] = (ctl & 0xf0) | 0x01;
- data[2] = SubChannel::bcd(trackNr);
- data[3] = SubChannel::bcd(indexNr);
- if (sendCmd(cmd, 10, data, 4, NULL, 0, 1) != 0) {
- message(-2, "Cannot set subcode.");
- return 1;
- }
-
- return 0;
- }
-
- // Sets the subcodes for given track.
- // track: actual track
- // trackNr: number of current track
- // start: LBA of track start (index 1), pre-gap length is taken from 'track'
- // end: LBA of track end, same as 'nstart' if next track has no pre-gap
- // nstart: LBA of next track start (index 1)
- // Return: 0: OK
- // 1: SCSI command failed
- struct SubCodeData {
- long start; // start LBA
- int index; // index
- int pflag; // P channel flag
- };
- int TeacCdr55::setSubcodes(const Track *track, int trackNr,
- long start, long end, long nstart)
- {
- assert(start < end);
- assert(end <= nstart);
- unsigned char ctl = trackCtl(track);
- SubCodeData subCodes[102]; // index 0-99 + P-channel entry + end-entry
- int n = 0;
- int i;
- if (track->start().lba() != 0) {
- // pre-gap
- subCodes[n].start = start - track->start().lba();
- subCodes[n].index = 0;
- subCodes[n].pflag = 1;
- n++;
- }
- // track start (index 1)
- subCodes[n].start = start;
- subCodes[n].index = 1;
- subCodes[n].pflag = 0;
- n++;
- // create index marks
-
- // We have to check if we have to add an entry for the P-channel flag if the
- // pre-gap of the following track is shorter than 2 seconds
- // calculate LBA where P-channel must be set for next track, if
- // it is behind 'end' it'll be ignored
- long pChangeLba = nstart - 150;
- int pChangeEntry = 0; // set to 1 if a P-channel entry was created
- long indexStart;
- for (i = 0; i < track->nofIndices(); i++) {
- indexStart = track->getIndex(i).lba() + start;
- if (indexStart > pChangeLba && pChangeEntry == 0) {
- subCodes[n].start = pChangeLba;
- subCodes[n].index = i + 1;
- subCodes[n].pflag = 1;
- n++;
- pChangeEntry = 1;
- }
- else if (indexStart == pChangeLba) {
- // index increment coincides with p channel change position
- // -> no entry required
- pChangeEntry = 1;
- }
- subCodes[n].start = indexStart;
- subCodes[n].index = i + 2;
- subCodes[n].pflag = indexStart >= pChangeLba ? 1 : 0;
- n++;
- }
- if (pChangeEntry == 0 && pChangeLba < end) {
- subCodes[n].start = pChangeLba;
- subCodes[n].index = i + 1;
- subCodes[n].pflag = 1;
- n++;
- }
-
- // add end of track as last entry
- subCodes[n].start = end;
- subCodes[n].index = 0; // not used
- subCodes[n].pflag = 0; // not used
- assert(n <= 101);
- // now issue the subcode commands
- for (i = 0; i < n; i++) {
- if (setSubcode(subCodes[i].start, subCodes[i+1].start, ctl, trackNr,
- subCodes[i].index, subCodes[i].pflag) != 0) {
- return 1;
- }
- }
- return 0;
- }
- // Sets sub codes for all tracks.
- // Return: 0: OK
- // 1: toc contains no track
- // 2: SCSI error
- int TeacCdr55::setSubcodes()
- {
- const Track *t, *nt;
- int trackNr;
- Msf start, end;
- Msf nstart, nend;
- long offset = diskInfo_.thisSessionLba;
- int first = 1;
- TrackIterator itr(toc_);
- trackNr = diskInfo_.lastTrackNr;
- if ((nt = itr.first(nstart, nend)) == NULL) {
- return 1;
- }
- if (clearSubcode() != 0)
- return 2;
- do {
- trackNr += 1;
- t = nt;
- start = nstart;
- end = nend;
- if ((nt = itr.next(nstart, nend)) == NULL)
- nstart = Msf(toc_->length()); // start of lead-out
- if (first) {
- // set sub code for pre-gap of first track
- first = 0;
- if (setSubcode(offset - 150, offset, trackCtl(t), trackNr, 0, 1) != 0)
- return 2;
- }
- if (setSubcodes(t, trackNr, start.lba() + offset, end.lba() + offset,
- nstart.lba() + offset) != 0) {
- return 2;
- }
- } while (nt != NULL);
- return 0;
- }
- // Sets toc data.
- // Return: 0: OK
- // 1: toc contains no track
- // 2: SCSI command failed
- int TeacCdr55::setToc()
- {
- const Track *t;
- int trackNr;
- Msf start, end;
- long offset = diskInfo_.thisSessionLba + 150; // LBA offset
- int trackOffset = diskInfo_.lastTrackNr + 1;
- unsigned char firstTrackCtl;
- unsigned char lastTrackCtl;
- unsigned char ctl;
- int lastTrackNr = 0;
- int sessFormat;
- unsigned char cmd[10];
- unsigned char data[3 + 102 * 5]; // max. 99 tracks + 3 POINT entries
- unsigned char *p = data + 3;
- data[0] = 0;
- data[1] = 0;
- data[2] = 0;
- TrackIterator itr(toc_);
- for (t = itr.first(start, end), trackNr = trackOffset;
- t != NULL && trackNr <= 99;
- t = itr.next(start, end), trackNr++) {
- Msf s(start.lba() + offset);
- ctl = trackCtl(t);
- if (trackNr == trackOffset)
- firstTrackCtl = ctl;
- p[0] = ctl | 0x01;
- p[1] = SubChannel::bcd(trackNr);
- p[2] = SubChannel::bcd(s.min());
- p[3] = SubChannel::bcd(s.sec());
- p[4] = SubChannel::bcd(s.frac());
- p += 5;
- lastTrackNr = trackNr;
- lastTrackCtl = ctl;
- }
- if (lastTrackNr == 0)
- return 1;
-
- // Point A0 entry (first track nr and session format)
- if (diskInfo_.empty) {
- // disk is empty -> take toc type from toc-file
- sessFormat = sessionFormat();
- }
- else {
- // Disk has already a recorded session -> take toc type from
- // previous session if it is well defined.
- switch (diskInfo_.diskTocType) {
- case 0x00:
- case 0x10:
- case 0x20:
- sessFormat = diskInfo_.diskTocType;
- break;
- default:
- sessFormat = sessionFormat();
- break;
- }
- }
- p[0] = firstTrackCtl | 0x01;
- p[1] = 0xa0;
- p[2] = SubChannel::bcd(trackOffset);
- p[3] = SubChannel::bcd(sessFormat);
- p[4] = 0;
- p += 5;
- // Point A1 entry (last track nr)
- p[0] = lastTrackCtl | 0x01;
- p[1] = 0xa1;
- p[2] = SubChannel::bcd(lastTrackNr);
- p[3] = 0;
- p[4] = 0;
- p += 5;
-
- // Point A2 entry (start of lead-out)
- Msf los(toc_->length().lba() + offset);
- p[0] = lastTrackCtl | 0x01;
- p[1] = 0xa2;
- p[2] = SubChannel::bcd(los.min());
- p[3] = SubChannel::bcd(los.sec());
- p[4] = SubChannel::bcd(los.frac());
- p += 5;
-
- long dataLen = p - data;
- #if 1
- message(3, "TOC data:");
- long i;
- for (i = 3; i < dataLen; i += 5) {
- message(3, "%02x %02x %02x:%02x:%02x",
- data[i], data[i+1], data[i+2], data[i+3], data[i+4]);
- }
- #endif
- memset(cmd, 0, 10);
- cmd[0] = 0xc2; // SET SUBCODE
- cmd[7] = dataLen >> 8;
- cmd[8] = dataLen;
- if (sendCmd(cmd, 10, data, dataLen, NULL, 0, 1) != 0) {
- message(-2, "Cannot set TOC data.");
- return 2;
- }
-
- return 0;
- }
- // Sets catalog number.
- // Return: 0: OK
- // 1: SCSI command failed
- int TeacCdr55::setCatalog()
- {
- unsigned char cmd[10];
- unsigned char data[15];
- int i;
- if (!toc_->catalogValid())
- return 0;
- data[0] = 0;
- if (toc_->leadInMode() == TrackData::AUDIO)
- data[1] = 0x02;
- else
- data[1] = 0x42;
- for (i = 0; i < 13; i++)
- data[2 + i] = toc_->catalog(i);
- memset(cmd, 0, 10);
- cmd[0] = 0xc2; // SET SUBCODE
- cmd[8] = 15;
- if (sendCmd(cmd, 10, data, 15, NULL, 0, 1) != 0) {
- message(-2, "Cannot set catalog number data.");
- return 2;
- }
- return 0;
- }
- // Sets ISRC codes for all tracks
- int TeacCdr55::setIsrc()
- {
- const Track *t;
- int trackNr;
- Msf start, end;
- int trackOffset = diskInfo_.lastTrackNr + 1;
- unsigned char cmd[10];
- unsigned char data[15];
- data[0] = 0;
- memset(cmd, 0, 10);
- cmd[0] = 0xc2; // SET SUBCODE
- cmd[8] = 15;
- TrackIterator itr(toc_);
- for (t = itr.first(start, end), trackNr = trackOffset;
- t != NULL && trackNr <= 99;
- t = itr.next(start, end), trackNr++) {
- if (t->isrcValid()) {
- data[1] = trackCtl(t) | 0x03;
- data[2] = t->isrcCountry(0);
- data[3] = t->isrcCountry(1);
- data[4] = t->isrcOwner(0);
- data[5] = t->isrcOwner(1);
- data[6] = t->isrcOwner(2);
- data[7] = t->isrcYear(0) + '0';
- data[8] = t->isrcYear(1) + '0';
- data[9] = t->isrcSerial(0) + '0';
- data[10] = t->isrcSerial(1) + '0';
- data[11] = t->isrcSerial(2) + '0';
- data[12] = t->isrcSerial(3) + '0';
- data[13] = t->isrcSerial(4) + '0';
- data[14] = 0;
- cmd[6] = trackNr;
- if (sendCmd(cmd, 10, data, 15, NULL, 0, 1) != 0) {
- message(-2, "Cannot set ISRC code.");
- return 2;
- }
- }
- }
- return 0;
- }
- // Need to overload this function to set the WriteExtension flag. It'll
- // also change the write density if the actual mode changes.
- int TeacCdr55::writeData(TrackData::Mode mode, long &lba, const char *buf,
- long len)
- {
- assert(blocksPerWrite_ > 0);
- int writeLen = 0;
- unsigned char cmd[10];
- 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
- if (mode != actMode_) {
- actMode_ = mode;
- message(2, "Changed write density at LBA %ld.", lba);
- if (setWriteDensity(actMode_) != 0) {
- return 1;
- }
- }
- memset(cmd, 0, 10);
- cmd[0] = 0x2a; // WRITE10
-
- 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;
- if (lba + writeLen >= writeEndLba_) {
- // last write command
- message(3, "Last write command at LBA: %ld", lba);
- cmd[9] = 0;
- }
- else {
- cmd[9] = 0x80; // extended write
- }
- if (sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength,
- NULL, 0) != 0) {
- message(-2, "Write data failed.");
- return 1;
- }
- buf += writeLen * blockLength;
- lba += writeLen;
- len -= writeLen;
- }
-
- return 0;
- }
- int TeacCdr55::initDao(const Toc *toc)
- {
- long offset; // LBA offset for this session
- long n;
-
- toc_ = toc;
- blockLength_ = AUDIO_BLOCK_LEN;
- blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_;
- assert(blocksPerWrite_ > 0);
- diskInfo();
- if (!diskInfo_.valid.empty || !diskInfo_.valid.append) {
- message(-2, "Cannot determine status of inserted medium.");
- return 1;
- }
- if (!diskInfo_.append) {
- message(-2, "Inserted medium is not appendable.");
- return 1;
- }
- offset = diskInfo_.thisSessionLba;
- // allocate buffer for writing zeros
- n = blocksPerWrite_ * blockLength_;
- delete[] zeroBuffer_;
- zeroBuffer_ = new char[n];
- memset(zeroBuffer_, 0, n);
- writeEndLba_ = toc_->length().lba() + offset;
- actMode_ = toc_->leadInMode();
-
- if (getModeSelectData() != 0 ||
- setWriteDensity(actMode_) != 0 ||
- setSimulationMode() != 0 ||
- setWriteParameters() != 0 ||
- setWriteSpeed() != 0) {
- return 1;
- }
- return 0;
- }
- int TeacCdr55::startDao()
- {
- scsiTimeout_ = scsiIf_->timeout(3 * 60);
- if (executeOPC(1) != 0 ||
- setSubcodes() != 0 ||
- setCatalog() != 0 ||
- setToc() != 0 ||
- setIsrc() != 0) {
- return 1;
- }
- long lba = diskInfo_.thisSessionLba - 150;
- if (writeZeros(actMode_, lba, lba + 150, 150) != 0) {
- return 1;
- }
-
- return 0;
- }
- int TeacCdr55::finishDao()
- {
- //message(0, "Writing lead-out...");
- // wait until writing of lead-out is finished ???
- scsiIf_->timeout(scsiTimeout_);
- delete[] zeroBuffer_, zeroBuffer_ = NULL;
- return 0;
- }
- void TeacCdr55::abortDao()
- {
- unsigned char cmd[10];
- // Send a zero length write command with cleared extendened write bit.
- // I don't know if it has the expected effect.
- memset(cmd, 0, 10);
- cmd[0] = 0x2a; // WRITE10
- sendCmd(cmd, 10, NULL, 0, NULL, 0, 0);
- }
- DiskInfo *TeacCdr55::diskInfo()
- {
- int i;
- unsigned char cmd[12];
- unsigned char data[12];
- memset(&diskInfo_, 0, sizeof(DiskInfo));
- diskInfo_.cdrw = 0;
- diskInfo_.valid.cdrw = 1;
- memset(cmd, 0, 10);
- memset(data, 0, 8);
- cmd[0] = 0x25; // READ CAPACITY
- cmd[9] = 0x80;
- if (sendCmd(cmd, 10, NULL, 0, data, 8, 1) != 0) {
- message(-1, "Cannot read CD-R capacity.");
- }
- else {
- diskInfo_.capacity = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) |
- data[3];
- diskInfo_.valid.capacity = 1;
- }
- memset(cmd, 0, 12);
- memset(data, 0, 4);
- cmd[0] = 0xe6; // NEXT WRITABLE ADDRESS
- cmd[2] = 0xff;
- cmd[3] = 0xff;
- cmd[4] = 0xff;
- cmd[5] = 0xff;
- cmd[6] = 0xff;
- cmd[7] = 0xff;
- cmd[8] = 0xff;
- cmd[9] = 0xff;
- long nwa = 0;
- switch (sendCmd(cmd, 12, NULL, 0, data, 4, 0)) {
- case 0: // command succeed -> writable area exists
- diskInfo_.empty = 1;
- diskInfo_.valid.empty = 1;
- nwa = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
- message(3, "Next writable address: %ld", nwa);
- break;
- case 1: // SCSI command failed, no sense data -> cannot tell anything
- message(-1, "Get next writable address failed.");
- break;
- case 2: // SCSI command failed, sense data available
- // assume that disk is not writable
- message(3, "Cannot get next writable address.");
- diskInfo_.empty = 0;
- diskInfo_.valid.empty = 1;
- break;
- }
- // SCSI command failed -> stop further processing
- if (diskInfo_.valid.empty == 0)
- return &diskInfo_;
- memset(cmd, 0, 10);
- memset(data, 0, 4);
- cmd[0] = 0x43; // READ TOC
- cmd[6] = 1;
- cmd[8] = 4;
- if (sendCmd(cmd, 10, NULL, 0, data, 4, 0) == 0) {
- message(3, "First track %u, last track %u", data[2], data[3]);
- diskInfo_.lastTrackNr = data[3];
- }
- else {
- message(3, "READ TOC (format 0) failed.");
- }
- if (diskInfo_.lastTrackNr > 0) {
- diskInfo_.empty = 0;
- diskInfo_.diskTocType = 0xff; // undefined
- memset(cmd, 0, 10);
- memset(data, 0, 12);
- cmd[0] = 0x43; // READ TOC
- cmd[6] = 0;
- cmd[8] = 12;
- cmd[9] = 1 << 6;
- if (sendCmd(cmd, 10, NULL, 0, data, 12) == 0) {
- diskInfo_.sessionCnt = data[3];
- diskInfo_.lastSessionLba = (data[8] << 24) | (data[9] << 16) |
- (data[10] << 8) | data[11];
- message(3, "First session %u, last session %u, last session start %ld",
- data[2], data[3], diskInfo_.lastSessionLba);
- }
- else {
- message(3, "READ TOC (format 1) failed.");
- }
- if (diskInfo_.sessionCnt > 0) {
- int len;
- CdRawToc *toc = getRawToc(diskInfo_.sessionCnt, &len);
- if (toc != NULL) {
- for (i = 0; i < len; i++) {
- if (toc[i].sessionNr == diskInfo_.sessionCnt) {
- if (toc[i].point == 0xb0 && toc[i].min != 0xff &&
- toc[i].sec != 0xff && toc[i].frame != 0xff) {
- int m = SubChannel::bcd2int(toc[i].min);
- int s = SubChannel::bcd2int(toc[i].sec);
- int f = SubChannel::bcd2int(toc[i].frame);
-
- if (m < 90 && s < 60 && f < 75)
- diskInfo_.thisSessionLba = Msf(m, s, f).lba(); // + 150 - 150
- }
- if (toc[i].point == 0xa0) {
- diskInfo_.diskTocType = SubChannel::bcd2int(toc[i].psec);
- }
- }
- }
- if (diskInfo_.thisSessionLba > 0) {
- if (diskInfo_.lastTrackNr < 99)
- diskInfo_.append = 1;
- }
- else {
- message(3, "Did not find BO pointer in session %d.",
- diskInfo_.sessionCnt);
- }
- delete[] toc;
- }
- else {
- message(3, "getRawToc failed.");
- }
- }
- }
- else {
- // disk is empty and appendable
- diskInfo_.empty = 1;
- diskInfo_.append = 1;
- }
- diskInfo_.valid.append = 1;
- return &diskInfo_;
- }
- // tries to read catalog number from disk and adds it to 'toc'
- // return: 1 if valid catalog number was found, else 0
- int TeacCdr55::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 TeacCdr55::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 media catalog number
- 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;
- }
- if (data[8] & 0x80) {
- for (i = 0; i < 12; i++) {
- buf[i] = data[0x09 + i];
- }
- buf[12] = 0;
- }
- return 0;
- }
- int TeacCdr55::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 TeacCdr55::readSubChannels(long lba, long len, SubChannel ***chans,
- Sample *audioData)
- {
- int retries = 5;
- unsigned char cmd[12];
- int i;
- cmd[0] = 0xd8; // 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; // Q sub-channel data
- 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;
- }
- CdRawToc *TeacCdr55::getRawToc(int sessionNr, int *len)
- {
- unsigned char cmd[10];
- unsigned short dataLen;
- unsigned char *data = NULL;;
- unsigned char reqData[4]; // buffer for requestion the actual length
- unsigned char *p = NULL;
- int i, entries;
- CdRawToc *rawToc;
-
- assert(sessionNr >= 1);
- // read disk toc length
- memset(cmd, 0, 10);
- cmd[0] = 0x43; // READ TOC
- cmd[6] = sessionNr;
- cmd[8] = 4;
- cmd[9] |= 2 << 6; // get Q subcodes
- if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) {
- message(-2, "Cannot read raw disk toc.");
- return NULL;
- }
- dataLen = ((reqData[0] << 8) | reqData[1]) + 2;
- message(3, "Raw toc data len: %d", dataLen);
- if (dataLen == 4)
- return NULL;
- data = new (unsigned char)[dataLen];
-
- // read disk toc
- cmd[7] = dataLen >> 8;
- cmd[8] = dataLen;
- if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
- message(-2, "Cannot read raw disk toc.");
- delete[] data;
- return NULL;
- }
- entries = (((data[0] << 8) | data[1]) - 2) / 11;
- rawToc = new CdRawToc[entries];
- for (i = 0, p = data + 4; i < entries; i++, p += 11 ) {
- #if 0
- message(0, "%d %02x %02d %2x %02x:%02x:%02x %02x %02x:%02x:%02x",
- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]);
- #endif
- rawToc[i].sessionNr = p[0];
- rawToc[i].adrCtl = p[1];
- rawToc[i].point = p[3];
- rawToc[i].min = p[4];
- rawToc[i].sec = p[5];
- rawToc[i].frame = p[6];
- rawToc[i].pmin = p[8];
- rawToc[i].psec = p[9];
- rawToc[i].pframe = p[10];
- }
- delete[] data;
- *len = entries;
- return rawToc;
- }
- long TeacCdr55::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, "TeacCdr55::readTrackData: Illegal mode.");
- return 0;
- break;
- }
- }
- sector += blockLen;
- }
- return len;
- }
- Toc *TeacCdr55::readDiskToc(int session, const char *audioFilename)
- {
- Toc *toc = CdrDriver::readDiskToc(session, audioFilename);
- setBlockSize(MODE1_BLOCK_LEN);
-
- return toc;
- }
- Toc *TeacCdr55::readDisk(int session, const char *fname)
- {
- Toc *toc = CdrDriver::readDisk(session, fname);
- setBlockSize(MODE1_BLOCK_LEN);
- return toc;
- }
- int TeacCdr55::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);
- }