/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include #include "SonyCDU948.h" #include "PWSubChannel96.h" #include "util.h" #include "Toc.h" #include "CdTextEncoder.h" SonyCDU948::SonyCDU948(ScsiIf *scsiIf, unsigned long options) : SonyCDU920(scsiIf, options) { driverName_ = "Sony CDU948 - Version 0.1 (data) (alpha)"; speed_ = 4; cdTextEncoder_ = NULL; } SonyCDU948::~SonyCDU948() { delete cdTextEncoder_; cdTextEncoder_ = NULL; } // static constructor CdrDriver *SonyCDU948::instance(ScsiIf *scsiIf, unsigned long options) { return new SonyCDU948(scsiIf, options); } int SonyCDU948::checkToc(const Toc *toc) { int err = SonyCDU920::checkToc(toc); int e; if ((e = toc->checkCdTextData()) > err) err = e; return err; } int SonyCDU948::multiSession(int m) { multiSession_ = m != 0 ? 1 : 0; return 0; } // sets speed // return: 0: OK // 1: illegal speed int SonyCDU948::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; return 0; } // sets read/write speed and simulation mode // return: 0: OK // 1: scsi command failed int SonyCDU948::selectSpeed() { unsigned char mp[4]; mp[0] = 0x31; mp[1] = 2; mp[2] = 0; mp[3] = 0; switch (speed_) { case 0: mp[2] = 0xff; case 1: mp[2] = 0; break; case 2: mp[2] = 1; break; case 4: mp[2] = 3; break; } if (setModePage6(mp, NULL, NULL, 1) != 0) { message(-2, "Cannot set speed mode page."); return 1; } return 0; } // Sets write parameters. // return: 0: OK // 1: scsi command failed int SonyCDU948::setWriteParameters() { unsigned char cmd[10]; unsigned char data[52]; if (SonyCDU920::setWriteParameters() != 0) return 1; memset(cmd, 0, 10); memset(data, 0, 52); cmd[0] = 0xf8; // SET WRITE PARAMETERS cmd[7] = 0; cmd[8] = 52; data[1] = 50; data[3] = (multiSession_ != 0 ? (3 << 6) : 0); if (sendCmd(cmd, 10, data, 52, NULL, 0, 1) != 0) { message(-1, "Cannot set write parameters."); return 1; } return 0; } int SonyCDU948::initDao(const Toc *toc) { long n; delete cdTextEncoder_; cdTextEncoder_ = new CdTextEncoder(toc); if (cdTextEncoder_->encode() != 0) { message(-2, "CD-TEXT encoding failed."); return 1; } if (cdTextEncoder_->getSubChannels(&n) == NULL || n == 0) { // there is no CD-TEXT data to write delete cdTextEncoder_; cdTextEncoder_ = NULL; } return SonyCDU920::initDao(toc); } int SonyCDU948::startDao() { unsigned char leadInDataForm = 0x00; // CD-DA, generate data by device scsiTimeout_ = scsiIf_->timeout(3 * 60); if (cdTextEncoder_ != NULL) leadInDataForm = 0xc0; // CD-DA with P-W sub-channel data if (setWriteParameters() != 0 || sendCueSheet(leadInDataForm) != 0) return 1; if (writeCdTextLeadIn() != 0) { return 1; } long lba = -150; // write mandatory pre-gap after lead-in if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, 150) != 0) { return 1; } return 0; } int SonyCDU948::writeCdTextLeadIn() { unsigned char cmd[10]; const PWSubChannel96 **cdTextSubChannels; long cdTextSubChannelCount; long channelsPerCmd = scsiIf_->maxDataLen() / 96; long scp = 0; long byteLen; long len = leadInLen_; long n; long i; unsigned char *p; if (cdTextEncoder_ == NULL) return 0; if (leadInLen_ == 0) { message(-2, "Cannot write CD-TEXT lead-in because lead-in length is not known."); return 1; } cdTextSubChannels = cdTextEncoder_->getSubChannels(&cdTextSubChannelCount); assert(channelsPerCmd > 0); assert(cdTextSubChannels != NULL); assert(cdTextSubChannelCount > 0); message(2, "Writing CD-TEXT lead-in..."); memset(cmd, 0, 10); cmd[0] = 0xe1; // WRITE CONTINUE while (len > 0) { n = (len > channelsPerCmd) ? channelsPerCmd : len; byteLen = n * 96; cmd[1] = (byteLen >> 16) & 0x1f; cmd[2] = byteLen >> 8; cmd[3] = byteLen; p = transferBuffer_; for (i = 0; i < n; i++) { memcpy(p, cdTextSubChannels[scp]->data(), 96); p += 96; scp++; if (scp >= cdTextSubChannelCount) scp = 0; } if (sendCmd(cmd, 10, transferBuffer_, byteLen, NULL, 0) != 0) { message(-2, "Writing of CD-TEXT data failed."); return 1; } len -= n; } return 0; }