YamahaCDR10x.cc
上传用户:weiliju62
上传日期:2007-01-06
资源大小:619k
文件大小:25k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*  cdrdao - write audio CD-Rs in disc-at-once mode
  2.  *
  3.  *  Copyright (C) 1999  Cameron G. MacKinnon <C_MacKinnon@yahoo.com>
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19. /*
  20.  * $Log: YamahaCDR10x.cc,v $
  21.  * Revision 1.3  1999/04/05 11:04:10  mueller
  22.  * Added driver option flags.
  23.  *
  24.  * Revision 1.2  1999/03/27 14:35:17  mueller
  25.  * Added data track support.
  26.  *
  27.  * Revision 1.1  1999/02/28 10:27:49  mueller
  28.  * Initial revision
  29.  */
  30. /* Cameron's log:
  31.  *
  32.  * Revision 0.4  1999/01/08 21:00:00  cmackin
  33.  * Fixed BCD fields in Cue Sheet
  34.  * Todo: BCD issues for ISRC and Catalog
  35.  *       core dump when RO CD inserted for burn functions
  36.  *
  37.  * Revision 0.3  1999/01/08 12:00:00  cmackin
  38.  * Added {g,s}etModePage6(...): Yamaha doesn't support the (10) cmds
  39.  *
  40.  * Revision 0.2  1999/01/08 09:00:00  cmackin
  41.  * Added READ CD-ROM CAPACITY to diskInfo()
  42.  *
  43.  * Revision 0.1  1999/01/07 20:44:58  cmackin
  44.  * Initial revision, based on GenericMMC
  45.  *
  46.  */
  47. /* Driver for Yamaha CDR10X drives. 
  48.  * Written by Cameron G. MacKinnon <C_MacKinnon@yahoo.com>.
  49.  */
  50. static char rcsid[] = "$Id: YamahaCDR10x.cc,v 1.3 1999/04/05 11:04:10 mueller Exp mueller $";
  51. #include <config.h>
  52. #include <unistd.h>
  53. #include <string.h>
  54. #include <assert.h>
  55. #include "YamahaCDR10x.h"
  56. #include "Toc.h"
  57. #include "PQSubChannel16.h"
  58. #include "util.h"
  59. #include "port.h"
  60. YamahaCDR10x::YamahaCDR10x(ScsiIf *scsiIf, unsigned long options)
  61.   : CdrDriver(scsiIf, options)
  62. {
  63.   int i;
  64.   driverName_ = "Yamaha CDR10x - Version 0.5 (data)";
  65.   encodingMode_ = 1; 
  66.   
  67.   speed_ = 0;
  68.   simulate_ = 1;
  69.   scsiTimeout_ = 0;
  70.   for (i = 0; i < maxScannedSubChannels_; i++)
  71.     scannedSubChannels_[i] = new PQSubChannel16;
  72.   // reads little endian samples
  73.   audioDataByteOrder_ = 0;
  74. }
  75. // static constructor
  76. CdrDriver *YamahaCDR10x::instance(ScsiIf *scsiIf, unsigned long options)
  77. {
  78.   return new YamahaCDR10x(scsiIf, options);
  79. }
  80. YamahaCDR10x::~YamahaCDR10x()
  81. {
  82.   int i;
  83.   for (i = 0; i < maxScannedSubChannels_; i++) {
  84.     delete scannedSubChannels_[i];
  85.     scannedSubChannels_[i] = NULL;
  86.   }
  87. }
  88. int YamahaCDR10x::multiSession(int m)
  89. {
  90.   if (m != 0) {
  91.     return 1; // multi session mode is not supported
  92.   }
  93.   return 0;
  94. }
  95. // sets speed
  96. // return: 0: OK
  97. //         1: illegal speed
  98. int YamahaCDR10x::speed(int s)
  99. {
  100.   if (s == 0 || s == 1 || s == 2 || s == 4)
  101.     speed_ = s;
  102.   else if (s == 3)
  103.     speed_ = 2;
  104.   else if (s > 4)
  105.     speed_ = 4;
  106.   else
  107.     return 1;
  108.   if (selectSpeed() != 0)
  109.     return 1;
  110.   
  111.   return 0;
  112. }
  113. int YamahaCDR10x::speed()
  114. {
  115.   DriveInfo di;
  116.   if (driveInfo(&di, 1) != 0) {
  117.     return 0;
  118.   }
  119.   return speed2Mult(di.currentWriteSpeed);
  120. }
  121. // loads ('unload' == 0) or ejects ('unload' == 1) tray
  122. // return: 0: OK
  123. //         1: scsi command failed
  124. int YamahaCDR10x::loadUnload(int unload) const
  125. {
  126.   unsigned char cmd[6];
  127.   memset(cmd, 0, 6);
  128.   cmd[0] = 0x1b; // START/STOP UNIT
  129.   if (unload) {
  130.     cmd[4] = 0x02; // LoUnlo=1, Start=0
  131.   }
  132.   else {
  133.     cmd[4] = 0x01; // LoUnlo=0, Start=1: This is a caddy, and load is reserved
  134.   }
  135.   
  136.   if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) {
  137.     message(-2, "Cannot %s medium.", (unload ? "stop & unload" : "start"));
  138.     return 1;
  139.   }
  140.   return 0;
  141. }
  142. // sets read/write speed
  143. // return: 0: OK
  144. //         1: scsi command failed
  145. int YamahaCDR10x::selectSpeed()
  146. {
  147.   unsigned char mp[4];
  148.   if (getModePage6(0x31/*drive configuration mode page*/, mp, 4,
  149.    NULL, NULL, 1) != 0) {
  150.     message(-2, "Cannot retrieve drive configuration mode page (0x31).");
  151.     return 1;
  152.   }
  153.   mp[3] &= 0x0f;
  154.   if(speed_ == 0 || speed_ == 4) {
  155. mp[3] |= 0x20;  // read at 4x, write at 2x (CDR102) or 4x (CDR100)
  156.   } else if(speed_ == 2) {
  157. mp[3] |= 0x10;  // read at 2x, write at 2x
  158.   } else if(speed_ == 1) {
  159. ;   // read at 1x, write at 1x
  160.   } else {
  161. message(-2, "Invalid write speed argument %d. 0, 1, 2 or 4 expected.",
  162. speed_);
  163. return 1;
  164.   }
  165.   if (setModePage6(mp, NULL, NULL, 1) != 0) {
  166.     message(-2, "Cannot set drive configuration mode page for cd speed.");
  167.     return 1;
  168.   }
  169.   return 0;
  170. }
  171. // Sets write parameters via mode pages 0x31 and 0x32.
  172. // return: 0: OK
  173. //         1: scsi command failed
  174. int YamahaCDR10x::setWriteParameters()
  175. {
  176.   unsigned char mp[8]; // the larger of 4 and 8, gets used twice
  177.   if (getModePage6(0x31/*drive configuration mode page*/, mp, 4,
  178.    NULL, NULL, 1) != 0) {
  179.     message(-2, "Cannot retrieve drive configuration mode page (0x31).");
  180.     return 1;
  181.   }
  182.   mp[3] &= 0xf0; // save speed settings in high nibble
  183.   mp[3] |= (simulate_ ? 1 : 0);
  184.   if (setModePage6(mp, NULL, NULL, 1) != 0) {
  185.     message(-2, "Cannot set drive configuration mode page (0x31).");
  186.     return 1;
  187.   }
  188.   memset(mp, 0, 8);
  189.   if (getModePage6(0x32/*write format mode page*/, mp, 8,
  190.    NULL, NULL, 1) != 0) {
  191.     message(-2, "Cannot retrieve write format mode page (0x32).");
  192.     return 1;
  193.   }
  194.   mp[2] &= 0xf0; // RW subcode internally zero supplied
  195.   mp[3] &= 0xf0;
  196.   mp[3] |= 0x04; // disc at once (single session)
  197.   if (setModePage6(mp, NULL, NULL, 1) != 0) {
  198.     message(-2, "Cannot set write format mode page (0x32).");
  199.     return 1;
  200.   }
  201.   return 0;
  202. }
  203. void YamahaCDR10x::cueSheetDataType(TrackData::Mode mode,
  204.     unsigned char *dataType,
  205.     unsigned char *dataForm)
  206. {
  207.   switch (mode) {
  208.   case TrackData::AUDIO:
  209.     *dataType = 0;
  210.     *dataForm = 0;
  211.     break;
  212.     
  213.   case TrackData::MODE1:
  214.   case TrackData::MODE1_RAW:
  215.     *dataType = 2;
  216.     *dataForm = 3;
  217.     break;
  218.   case TrackData::MODE2:
  219.     *dataType = 3;
  220.     *dataForm = 3;
  221.     break;
  222.   case TrackData::MODE2_RAW:
  223.   case TrackData::MODE2_FORM1:
  224.   case TrackData::MODE2_FORM2:
  225.   case TrackData::MODE2_FORM_MIX:
  226.     if (toc_->tocType() == Toc::CD_I)
  227.       *dataType = 4;
  228.     else
  229.       *dataType = 5;
  230.     *dataForm = 3;
  231.     break;
  232.   case TrackData::MODE0:
  233.     message(-3, "Illegal mode in 'YamahaCDR10x::cueSheetDataType()'.");
  234.     *dataType = 0;
  235.     *dataForm = 0;
  236.     break;
  237.   }
  238. }
  239. // Creates cue sheet for current toc.
  240. // cueSheetLen: filled with length of cue sheet in bytes
  241. // return: newly allocated cue sheet buffer or 'NULL' on error
  242. // CHECKS OUT WITH DOS-DAO AND MANUAL
  243. unsigned char *YamahaCDR10x::createCueSheet(long *cueSheetLen)
  244. {
  245.   const Track *t;
  246.   int trackNr;
  247.   Msf start, end, index;
  248.   unsigned char *cueSheet;
  249.   long len = 2; // entries for lead-in, lead-out
  250.   long n; // index into cue sheet
  251.   unsigned char ctl; // control nibbles of cue sheet entry CTL/ADR
  252.   long i;
  253.   unsigned char dataForm;
  254.   unsigned char dataType;
  255.   TrackIterator itr(toc_);
  256.   if (itr.first(start, end) == NULL) {
  257.     return NULL;
  258.   }
  259.   if (toc_->catalogValid()) {
  260.     len += 2;
  261.   }
  262.   for (t = itr.first(start, end), trackNr = 1;
  263.        t != NULL; t = itr.next(start, end), trackNr++) {
  264.     len += 2; // entry for track and mandatory pre-gap
  265.     if (t->type() == TrackData::AUDIO && t->isrcValid()) {
  266.       len += 2; // entries for ISRC code
  267.     }
  268.     len += t->nofIndices(); // entry for each index increment
  269.   }
  270.   cueSheet = new (unsigned char)[len * 8];
  271.   n = 0;
  272.   if (toc_->leadInMode() == TrackData::AUDIO)
  273.     ctl = 0;
  274.   else
  275.     ctl = 0x40;
  276.   if (toc_->catalogValid()) {
  277.     // fill catalog number entry
  278.     cueSheet[n*8] = 0x02 | ctl;
  279.     cueSheet[(n+1)*8] = 0x02 | ctl;
  280.     for (i = 1; i <= 13; i++) {
  281.       if (i < 8) {
  282. cueSheet[n*8 + i] = toc_->catalog(i-1) + '0';
  283.       }
  284.       else {
  285. cueSheet[(n+1)*8 + i - 7] = toc_->catalog(i-1) + '0';
  286.       }
  287.     }
  288.     cueSheet[(n+1)*8+7] = 0;
  289.     n += 2;
  290.   }
  291.   cueSheetDataType(toc_->leadInMode(), &dataType, &dataForm);
  292.   // entry for lead-in
  293.   cueSheet[n*8] = 0x01 | ctl; // CTL/ADR
  294.   cueSheet[n*8+1] = 0;        // Track number
  295.   cueSheet[n*8+2] = 0;        // Index
  296.   cueSheet[n*8+3] = dataType; // Data Type
  297.   cueSheet[n*8+4] = 0;        // Data Form: always 0 for lead-in
  298.   cueSheet[n*8+5] = 0;        // MIN
  299.   cueSheet[n*8+6] = 0;        // SEC
  300.   cueSheet[n*8+7] = 0;        // FRAME
  301.   n++;
  302.   
  303.   for (t = itr.first(start, end), trackNr = 1;
  304.        t != NULL;
  305.        t = itr.next(start, end), trackNr++) {
  306.     cueSheetDataType(t->type(), &dataType, &dataForm);
  307.     ctl = trackCtl(t);
  308.     if (t->type() == TrackData::AUDIO) {
  309.       // set ISRC code for audio track
  310.       if (t->isrcValid()) {
  311. cueSheet[n*8] = ctl | 0x03;
  312. cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  313. cueSheet[n*8+2] = t->isrcCountry(0);
  314. cueSheet[n*8+3] = t->isrcCountry(1);
  315. cueSheet[n*8+4] = t->isrcOwner(0);  
  316. cueSheet[n*8+5] = t->isrcOwner(1);   
  317. cueSheet[n*8+6] = t->isrcOwner(2);  
  318. cueSheet[n*8+7] = t->isrcYear(0) + '0';
  319. n++;
  320. cueSheet[n*8] = ctl | 0x03;
  321. cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  322. cueSheet[n*8+2] = t->isrcYear(1) + '0';
  323. cueSheet[n*8+3] = t->isrcSerial(0) + '0';
  324. cueSheet[n*8+4] = t->isrcSerial(1) + '0';
  325. cueSheet[n*8+5] = t->isrcSerial(2) + '0';
  326. cueSheet[n*8+6] = t->isrcSerial(3) + '0';
  327. cueSheet[n*8+7] = t->isrcSerial(4) + '0';
  328. n++;
  329.       }
  330.     }
  331.     Msf tstart(start.lba() + 150); // start of index 1
  332.     // start of pre-gap, atime equals index 1 if no pre-gap is defined
  333.     Msf pstart(trackNr == 1 ? 0 : tstart.lba() - t->start().lba());
  334.     // entry for pre-gap
  335.     cueSheet[n*8]   = ctl | 0x01;
  336.     cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  337.     cueSheet[n*8+2] = 0;        // Index 0 indicates pre-gap
  338.     cueSheet[n*8+3] = dataType; // Data Type
  339.     cueSheet[n*8+4] = dataForm; // Data Form
  340.     cueSheet[n*8+5] = SubChannel::bcd(pstart.min());
  341.     cueSheet[n*8+6] = SubChannel::bcd(pstart.sec());
  342.     cueSheet[n*8+7] = SubChannel::bcd(pstart.frac());
  343.     n++;
  344.     cueSheet[n*8]   = ctl | 0x01;
  345.     cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  346.     cueSheet[n*8+2] = 1;        // Index 1
  347.     cueSheet[n*8+3] = dataType; // Data Type
  348.     cueSheet[n*8+4] = dataForm; // Data Form
  349.     cueSheet[n*8+5] = SubChannel::bcd(tstart.min());
  350.     cueSheet[n*8+6] = SubChannel::bcd(tstart.sec());
  351.     cueSheet[n*8+7] = SubChannel::bcd(tstart.frac());
  352.     n++;
  353.     for (i = 0; i < t->nofIndices(); i++) {
  354.       index = tstart + t->getIndex(i);
  355.       cueSheet[n*8]   = ctl | 0x01;
  356.       cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  357.       cueSheet[n*8+2] = SubChannel::bcd(i+2); // Index
  358.       cueSheet[n*8+3] = dataType;    // DataType
  359.       cueSheet[n*8+4] = dataForm;    // Data Form
  360.       cueSheet[n*8+5] = SubChannel::bcd(index.min());
  361.       cueSheet[n*8+6] = SubChannel::bcd(index.sec());
  362.       cueSheet[n*8+7] = SubChannel::bcd(index.frac());
  363.       n++;
  364.     }
  365.   }
  366.   assert(n == len - 1);
  367.   // entry for lead out
  368.   Msf lostart(toc_->length().lba() + 150);
  369.   cueSheetDataType(toc_->leadOutMode(), &dataType, &dataForm);
  370.   ctl = toc_->leadOutMode() == TrackData::AUDIO ? 0 : 0x40;
  371.     
  372.   cueSheet[n*8]   = ctl | 0x01;
  373.   cueSheet[n*8+1] = 0xaa; // This IS BCD
  374.   cueSheet[n*8+2] = 1; // Index 1
  375.   cueSheet[n*8+3] = dataType; // Data for lead-out
  376.   cueSheet[n*8+4] = 0;        // Data Form, always 0 for lead-out
  377.   cueSheet[n*8+5] = SubChannel::bcd(lostart.min());
  378.   cueSheet[n*8+6] = SubChannel::bcd(lostart.sec());
  379.   cueSheet[n*8+7] = SubChannel::bcd(lostart.frac());
  380.   message(3, "nCue Sheet:");
  381.   message(3, "CTL/  TNO  INDEX  DATA  DATA  MIN  SEC  FRAME");
  382.   message(3, "ADR   BCD  BCD    TYPE  Form  BCD  BCD  BCD <- Note");
  383.   for (n = 0; n < len; n++) {
  384.     message(3, "%02x    %02x    %02x     %02x    %02x   %02x   %02x   %02x",
  385.    cueSheet[n*8],
  386.    cueSheet[n*8+1], cueSheet[n*8+2], cueSheet[n*8+3], cueSheet[n*8+4],
  387.    cueSheet[n*8+5], cueSheet[n*8+6], cueSheet[n*8+7]);
  388.   }
  389.   *cueSheetLen = len * 8;
  390.   return cueSheet;
  391. }
  392. // LOOKS GOOD
  393. int YamahaCDR10x::sendCueSheet()
  394. {
  395.   unsigned char cmd[10];
  396.   long cueSheetLen;
  397.   unsigned char *cueSheet = createCueSheet(&cueSheetLen);
  398.   if (cueSheet == NULL) {
  399.     return 1;
  400.   }
  401.   if(cueSheetLen > 32768) {  // Limit imposed by drive.
  402.     message(-2, "Cue sheet too long for this device: Limit is 32k bytes.");
  403.     delete[] cueSheet;
  404.     return 1;
  405.   }
  406.   memset(cmd, 0, 10);
  407.   cmd[0] = 0xea; // Yamaha Vendor Specific WRITE TOC
  408.   cmd[7] = cueSheetLen >> 8;
  409.   cmd[8] = cueSheetLen;
  410.   if (sendCmd(cmd, 10, cueSheet, cueSheetLen, NULL, 0) != 0) {
  411.     message(-2, "Cannot send cue sheet.");
  412.     delete[] cueSheet;
  413.     return 1;
  414.   }
  415.   delete[] cueSheet;
  416.   return 0;
  417. }
  418. // DOES NOT TALK TO DRIVE: JUST HOUSEKEEPING
  419. int YamahaCDR10x::initDao(const Toc *toc)
  420. {
  421.   long n;
  422.   toc_ = toc;
  423.   blockLength_ = AUDIO_BLOCK_LEN;
  424.   blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_;
  425.   assert(blocksPerWrite_ > 0);
  426.   if (selectSpeed() != 0) {
  427.     return 1;
  428.   }
  429.   // allocate buffer for writing zeros
  430.   n = blocksPerWrite_ * blockLength_;
  431.   delete[] zeroBuffer_;
  432.   zeroBuffer_ = new char[n];
  433.   memset(zeroBuffer_, 0, n);
  434.   return 0;
  435. }
  436. // LOOKS OK - dodgy WRITE TRACK parameters, but apparently how DAO16 does it
  437. int YamahaCDR10x::startDao()
  438. {
  439.   unsigned char cmd[10];
  440.   scsiTimeout_ = scsiIf_->timeout(3 * 60);
  441.   if (setWriteParameters() != 0 ||
  442.       sendCueSheet() != 0) {
  443.     return 1;
  444.   }
  445.   memset(cmd, 0, 10);
  446.   cmd[0] = 0xe6;  // Yamaha WRITE TRACK(10)
  447.   cmd[5] = 0; // Track Number
  448.   cmd[6] &= 0xdf; // R Parity = 0;
  449.   cmd[6] &= 0xef; // Byte Swap = 0 = little endian
  450.   cmd[6] &= 0xf7; // Copy = 0
  451.   cmd[6] &= 0xfb; // Audio = 0 (false)
  452.   cmd[6] &= 0xfc; // Mode=0 NB This combination of mode/audio is reserved
  453.   // so we end up sending a bare e6 command with nine bytes of nulls
  454.   if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) {
  455. message(-2, "Could not send command 0xE6: WRITE TRACK(10)");
  456. return 1;
  457.   }
  458.   //message(1, "Writing lead-in and gap...");
  459.   long lba = -150;
  460.   if (writeZeros(toc_->leadInMode(), lba, 0, 150) != 0) {
  461.     return 1;
  462.   }
  463.   
  464.   return 0;
  465. }
  466. int YamahaCDR10x::finishDao()
  467. {
  468.   unsigned char cmd[6];
  469.   const unsigned char *sense;
  470.   int senseLen;
  471.   message(1, "Flushing cache...");
  472.   
  473.   if (flushCache() != 0) {
  474.     return 1;
  475.   }
  476.   memset(cmd, 0, 6);
  477.   // wait until lead-out is written
  478.   while(sendCmd(cmd, 6, NULL, 0, NULL, 0, 0) == 2
  479. && (sense = scsiIf_->getSense(senseLen)) && senseLen 
  480. && sense[2] == 0x0b  && sense[0xc] == 0x50) {
  481.     sleep(1);
  482.   }
  483.   scsiIf_->timeout(scsiTimeout_);
  484.   delete[] zeroBuffer_, zeroBuffer_ = NULL;
  485.   return 0;
  486. }
  487. void YamahaCDR10x::abortDao()
  488. {
  489.   flushCache();
  490. }
  491. ///////////////////////// FIXME THE TOP BAR //////////////////////////////
  492. // NEEDS WORK
  493. DiskInfo *YamahaCDR10x::diskInfo()
  494. {
  495.   unsigned char cmd[10];
  496.   unsigned long dataLen = 8;
  497.   unsigned char data[8];
  498.   static DiskInfo di;
  499.   //char spd;
  500.   memset(&di, 0, sizeof(DiskInfo));
  501.   di.valid.cdrw = 0; // by definition, for this device
  502.   memset(cmd, 0, 10);
  503.   memset(data, 0, dataLen);
  504.   // This looks like CdrDevice::readCapacity, but with a difference: we
  505.   // get data for a ROM, and we need to check that our disc is writable
  506.   cmd[0] = 0x25; // READ CD-ROM CAPACITY
  507.  
  508.   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
  509.     message(-1, "Cannot read CD-ROM capacity.");
  510.     return &di;
  511.   }
  512.   if(data[4] | data[5] | data[6] | data[7]) { // block length field, 0=writable
  513. di.capacity = 0;
  514.   } else { // disk is writable
  515. di.capacity = data[0]<<24 | data[1]<<16 | data[2]<<8 | data[3];
  516.   }
  517.   di.valid.capacity = 1;
  518.   // FIXME: need to come up with empty, manufacturerID, recSpeed
  519.   // maybe use READ DISC INFO (0x43) here? se p. 62
  520. /////////////////////////////////////////
  521.   
  522.   return &di;
  523. }
  524. // tries to read catalog number from disk and adds it to 'toc'
  525. // return: 1 if valid catalog number was found, else 0
  526. int YamahaCDR10x::readCatalog(Toc *toc, long startLba, long endLba)
  527. {
  528.   unsigned char cmd[10];
  529.   unsigned char data[24];
  530.   char catalog[14];
  531.   int i;
  532.   memset(cmd, 0, 10);
  533.   memset(data, 0, 24);
  534.   cmd[0] = 0x42; // READ SUB-CHANNEL
  535.   cmd[2] = 1 << 6;
  536.   cmd[3] = 0x02; // get media catalog number
  537.   cmd[8] = 24;   // transfer length
  538.   if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
  539.     message(-2, "Cannot get catalog number.");
  540.     return 0;
  541.   }
  542.   if (data[8] & 0x80) {
  543.     for (i = 0; i < 13; i++) {
  544.       catalog[i] = data[0x09 + i];
  545.     }
  546.     catalog[13] = 0;
  547.     if (toc->catalog(catalog) == 0) {
  548.       return 1;
  549.     }
  550.   }
  551.   return 0;
  552. }
  553. int YamahaCDR10x::readIsrc(int trackNr, char *buf)
  554. {
  555.   unsigned char cmd[10];
  556.   unsigned char data[24];
  557.   int i;
  558.   buf[0] = 0;
  559.   memset(cmd, 0, 10);
  560.   memset(data, 0, 24);
  561.   cmd[0] = 0x42; // READ SUB-CHANNEL
  562.   cmd[2] = 1 << 6;
  563.   cmd[3] = 0x03; // get ISRC
  564.   cmd[6] = trackNr;
  565.   cmd[8] = 24;   // transfer length
  566.   if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
  567.     message(-2, "Cannot get ISRC code.");
  568.     return 0;
  569.   }
  570.   // FIXME this looks right, but the offsets could be wrong
  571.   if (data[8] & 0x80) {
  572.     for (i = 0; i < 12; i++) {
  573.       buf[i] = data[0x09 + i];
  574.     }
  575.     buf[12] = 0;
  576.   }
  577.   return 0;
  578. }
  579. int YamahaCDR10x::analyzeTrack(TrackData::Mode mode, int trackNr,
  580.        long startLba,
  581.        long endLba, Msf *indexIncrements,
  582.        int *indexIncrementCnt, long *pregap,
  583.        char *isrcCode, unsigned char *ctl)
  584. {
  585.   int ret = analyzeTrackScan(mode, trackNr, startLba, endLba,
  586.      indexIncrements, indexIncrementCnt, pregap,
  587.      isrcCode, ctl);
  588.   if (mode == TrackData::AUDIO)
  589.     readIsrc(trackNr, isrcCode);
  590.   else
  591.     *isrcCode = 0;
  592.   return ret;
  593. }
  594. int YamahaCDR10x::readSubChannels(long lba, long len, SubChannel ***chans,
  595.   Sample *audioData)
  596. {
  597.   int retries = 5;
  598.   int i;
  599.   unsigned char cmd[12];
  600.   
  601.   cmd[0] = 0xd8;  // Yamaha READ CD-DA
  602.   cmd[1] = 0;
  603.   cmd[2] = lba >> 24;
  604.   cmd[3] = lba >> 16;
  605.   cmd[4] = lba >> 8;
  606.   cmd[5] = lba;
  607.   cmd[6] = len >> 24;
  608.   cmd[7] = len >> 16;
  609.   cmd[8] = len >> 8;
  610.   cmd[9] = len;
  611.   cmd[10] = 0x01;  // 2352 + 10 Q (no CRC) + 6 NULL
  612.   cmd[11] = 0;
  613.   while (1) {
  614.     if (sendCmd(cmd, 12, NULL, 0,
  615. transferBuffer_, len * (AUDIO_BLOCK_LEN + 16),
  616. retries == 0 ? 1 : 0) != 0) {
  617.       if (retries == 0)
  618. return 1;
  619.     }
  620.     else {
  621.       break;
  622.     }
  623.     retries--;
  624.   }
  625.   for (i = 0; i < len; i++) {
  626.     PQSubChannel16 *chan = (PQSubChannel16*)scannedSubChannels_[i];
  627.     unsigned char *p =
  628.       transferBuffer_  + i * (AUDIO_BLOCK_LEN + 16) + AUDIO_BLOCK_LEN;
  629.     // slightly reorder the sub-channel so it is suitable for 'PQSubChannel16'
  630.     p[0] <<= 4;   // ctl/adr
  631.     p[0] |= p[1];
  632.     p[1] = p[2];  // track nr
  633.     p[2] = p[3];  // index nr
  634.     p[3] = p[4];  // min
  635.     p[4] = p[5];  // sec
  636.     p[5] = p[6];  // frame
  637.     p[6] = 0;     // zero
  638.     // p[7] is amin
  639.     // p[8] is asec
  640.     // p[9] is aframe
  641.     chan->init(p);
  642.     
  643.     if (chan->checkConsistency())
  644.       chan->calcCrc();
  645.   }
  646.   if (audioData != NULL) {
  647.     unsigned char *p = transferBuffer_;
  648.     for (i = 0; i < len; i++) {
  649.       memcpy(audioData, p, AUDIO_BLOCK_LEN);
  650.       p += AUDIO_BLOCK_LEN + 16;
  651.       audioData += SAMPLES_PER_BLOCK;
  652.     }
  653.   }
  654.   
  655.   *chans = scannedSubChannels_;
  656.   return 0;
  657. }
  658. // LOOKSGOOD, except for accurate audio stream bit
  659. int YamahaCDR10x::driveInfo(DriveInfo *info, int showErrorMsg)
  660. {
  661.   unsigned char mp[4];
  662.   if (getModePage6(0x31, mp, 4, NULL, NULL, showErrorMsg) != 0) {
  663.     if (showErrorMsg) {
  664.       message(-2, "Cannot retrieve drive configuration mode page (0x31).");
  665.     }
  666.     return 1;
  667.   }
  668.   // FIXME
  669.   // info->accurateAudioStream = mp[5] & 0x02 ? 1 : 0;
  670.   info->accurateAudioStream = 0;
  671.   info->maxReadSpeed = mult2Speed(4);
  672.   if(!strncmp(scsiIf_->product(), "CDR100", 6)) {
  673. info->maxWriteSpeed = mult2Speed(4);
  674. info->currentWriteSpeed = info->currentReadSpeed = 
  675. mult2Speed(1 << (mp[3] >> 4));
  676.   } else { // CDR102, crippled to 2x write
  677. info->maxWriteSpeed = mult2Speed(2);
  678. info->currentReadSpeed = mult2Speed(1 << (mp[3] >> 4));
  679. info->currentWriteSpeed = mult2Speed((mp[3] >> 4) ? 2 : 1);
  680.   }
  681.   return 0;
  682. }
  683. // writeData is overridden here because the CDR10x, while writing the disc
  684. // lead-in with the buffer full, will return CHECK CONDITION with sense
  685. // DRIVE BUSY and additional sense 0xb8 = WRITE LEAD-IN IN PROGRESS.
  686. // This is normal operation and the write should be retried until successful.
  687. // Writes data to target, the block length depends on the actual writing mode
  688. // 'len' is number of blocks to write.
  689. // 'lba' specifies the next logical block address for writing and is updated
  690. // by this function.
  691. // return: 0: OK
  692. //         1: scsi command failed
  693. int YamahaCDR10x::writeData(TrackData::Mode mode, long &lba, const char *buf,
  694.     long len)
  695. {
  696.   assert(blocksPerWrite_ > 0);
  697.   int writeLen = 0;
  698.   unsigned char cmd[10];
  699.   int retry;
  700.   int retval;
  701.   long blockLength = blockSize(mode);
  702. #if 0
  703.   long sum, i;
  704.   sum = 0;
  705.   for (i = 0; i < len * blockLength; i++) {
  706.     sum += buf[i];
  707.   }
  708.   message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum);
  709. #endif
  710.   memset(cmd, 0, 10);
  711.   cmd[0] = 0x2a; // WRITE1
  712.   
  713.   while (len > 0) {
  714.     writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len);
  715.     cmd[2] = lba >> 24;
  716.     cmd[3] = lba >> 16;
  717.     cmd[4] = lba >> 8;
  718.     cmd[5] = lba;
  719.     cmd[7] = writeLen >> 8;
  720.     cmd[8] = writeLen & 0xff;
  721.     do {
  722.       retry = 0;
  723.       retval = sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength,
  724.        NULL, 0, 0);
  725.       if(retval == 2) {
  726.         const unsigned char *sense;
  727.         int senseLen;
  728.         sense = scsiIf_->getSense(senseLen);
  729. // we spin on the write here, waiting a reasonable time in between
  730. // we should really use READ BLOCK LIMIT (0x05)
  731. if(senseLen && sense[2] == 9 && sense[0xc] == 0xb8) {
  732.   mSleep(40);
  733.           retry = 1;
  734.         }
  735. else {
  736.   scsiIf_->printError();
  737. }
  738.       }
  739.     } while(retry == 1);
  740.     if(retval) {
  741.       message(-2, "Write data failed.");
  742.       return 1;
  743.     }
  744.     buf += writeLen * blockLength;
  745.     lba += writeLen;
  746.     len -= writeLen;
  747.   }
  748.       
  749.   return 0;
  750. }
  751. CdRawToc *YamahaCDR10x::getRawToc(int sessionNr, int *len)
  752. {
  753.   // not supported by drive
  754.   return NULL;
  755. }
  756. long YamahaCDR10x::readTrackData(TrackData::Mode mode, long lba, long len,
  757.  unsigned char *buf)
  758. {
  759.   unsigned char cmd[10];
  760.   long blockLen = 2340;
  761.   long i;
  762.   TrackData::Mode actMode;
  763.   int ok = 0;
  764.   int softError;
  765.   const unsigned char *sense;
  766.   int senseLen;
  767.   if (setBlockSize(blockLen) != 0)
  768.     return 0;
  769.   memset(cmd, 0, 10);
  770.   cmd[0] = 0x28; // READ10
  771.   cmd[2] = lba >> 24;
  772.   cmd[3] = lba >> 16;
  773.   cmd[4] = lba >> 8;
  774.   cmd[5] = lba;
  775.   while (len > 0 && !ok) {
  776.     cmd[7] = len >> 8;
  777.     cmd[8] = len;
  778.     memset(transferBuffer_, 0, len * blockLen);
  779.     switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) {
  780.     case 0:
  781.       ok = 1;
  782.       break;
  783.     case 2:
  784.       softError = 0;
  785.       sense = scsiIf_->getSense(senseLen);
  786.       if (senseLen > 0x0c) {
  787. if ((sense[2] &0x0f) == 5) {
  788.   switch (sense[12]) {
  789.   case 0x63: // end of user area encountered on this track
  790.   case 0x64: // Illegal mode for this track
  791.     softError = 1;
  792.     break;
  793.   }
  794. }
  795. else if ((sense[2] & 0x0f) == 3) { // Medium error
  796.   switch (sense[12]) {
  797.   case 0x02: // No seek complete, sector not found
  798.   case 0x11: // L-EC error
  799.     return -2;
  800.     break;
  801.   }
  802. }
  803.       }
  804.       if (!softError) {
  805. scsiIf_->printError();
  806. return -1;
  807.       }
  808.       break;
  809.     default:
  810.       message(-2, "Read error at LBA %ld, len %ld", lba, len);
  811.       return -1;
  812.       break;
  813.     }
  814.     if (!ok) {
  815.       len--;
  816.     }
  817.   }
  818.   unsigned char *sector = transferBuffer_;
  819.   for (i = 0; i < len; i++) {
  820.     actMode = determineSectorMode(sector);
  821.     if (!(actMode == mode ||
  822.   (mode == TrackData::MODE2_FORM_MIX &&
  823.    (actMode == TrackData::MODE2_FORM1 ||
  824.     actMode == TrackData::MODE2_FORM2)) ||
  825.   (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) ||
  826.   (mode == TrackData::MODE2_RAW &&
  827.    (actMode == TrackData::MODE2 ||
  828.     actMode == TrackData::MODE2_FORM1 ||
  829.     actMode == TrackData::MODE2_FORM2)))) {
  830.       return i;
  831.     }
  832.     if (buf != NULL) {
  833.       switch (mode) {
  834.       case TrackData::MODE1:
  835. memcpy(buf, sector + 4, MODE1_BLOCK_LEN);
  836. buf += MODE1_BLOCK_LEN;
  837. break;
  838.       case TrackData::MODE2:
  839.       case TrackData::MODE2_FORM_MIX:
  840. memcpy(buf, sector + 4, MODE2_BLOCK_LEN);
  841. buf += MODE2_BLOCK_LEN;
  842. break;
  843.       case TrackData::MODE2_FORM1:
  844. memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN);
  845. buf += MODE2_FORM1_DATA_LEN;
  846. break;
  847.       case TrackData::MODE2_FORM2:
  848. memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN);
  849. buf += MODE2_FORM2_DATA_LEN;
  850. break;
  851.       case TrackData::MODE1_RAW:
  852.       case TrackData::MODE2_RAW:
  853. memcpy(buf, syncPattern, 12);
  854. memcpy(buf + 12, sector, 2340);
  855. buf += AUDIO_BLOCK_LEN;
  856. break;
  857.       case TrackData::MODE0:
  858.       case TrackData::AUDIO:
  859. message(-3, "YamahaCDR10x::readTrackData: Illegal mode.");
  860. return 0;
  861. break;
  862.       }
  863.     }
  864.     sector += blockLen;
  865.   }  
  866.   return len;
  867. }
  868. Toc *YamahaCDR10x::readDiskToc(int session, const char *audioFilename)
  869. {
  870.   Toc *toc = CdrDriver::readDiskToc(session, audioFilename);
  871.   setBlockSize(MODE1_BLOCK_LEN);
  872.   
  873.   return toc;
  874. }
  875. Toc *YamahaCDR10x::readDisk(int session, const char *fname)
  876. {
  877.   Toc *toc = CdrDriver::readDisk(session, fname);
  878.   setBlockSize(MODE1_BLOCK_LEN);
  879.   return toc;
  880. }
  881. int YamahaCDR10x::readAudioRange(int fd, long start, long end,
  882.  int startTrack, int endTrack, TrackInfo *info)
  883. {
  884.   if (!onTheFly_) {
  885.     int t;
  886.     message(1, "Analyzing...");
  887.     
  888.     for (t = startTrack; t <= endTrack; t++) {
  889.       message(1, "Track %d...", t + 1);
  890.       info[t].isrcCode[0] = 0;
  891.       readIsrc(t + 1, info[t].isrcCode);
  892.       if (info[t].isrcCode[0] != 0)
  893. message(1, "Found ISRC code.");
  894.     }
  895.     message(1, "Reading...");
  896.   }
  897.   return CdrDriver::readAudioRangeParanoia(fd, start, end, startTrack,
  898.    endTrack, info);
  899. }