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

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*  cdrdao - write audio CD-Rs in disc-at-once mode
  2.  *
  3.  *  Copyright (C) 1999  Andreas Mueller <mueller@daneb.ping.de>
  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: SonyCDU920.cc,v $
  21.  * Revision 1.2  1999/05/24 17:34:19  mueller
  22.  * Added parameter for data form of lead-in to 'createCueSheet()'.
  23.  *
  24.  * Revision 1.1  1999/05/20 18:40:17  mueller
  25.  * Initial revision
  26.  *
  27.  */
  28. static char rcsid[] = "$Id: SonyCDU920.cc,v 1.2 1999/05/24 17:34:19 mueller Exp mueller $";
  29. #include <config.h>
  30. #include <string.h>
  31. #include <assert.h>
  32. #include <unistd.h>
  33. #include "SonyCDU920.h"
  34. #include "port.h"
  35. #include "Toc.h"
  36. #include "util.h"
  37. #include "PQSubChannel16.h"
  38. SonyCDU920::SonyCDU920(ScsiIf *scsiIf, unsigned long options)
  39.   : CdrDriver(scsiIf, options)
  40. {
  41.   int i;
  42.   driverName_ = "Sony CDU920 - Version 0.1 (data) (alpha)";
  43.   
  44.   speed_ = 2;
  45.   simulate_ = 1;
  46.   encodingMode_ = 1;
  47.   scsiTimeout_ = 0;
  48.   leadInLen_ = 0;
  49.   for (i = 0; i < maxScannedSubChannels_; i++) {
  50.     scannedSubChannels_[i] = new PQSubChannel16;
  51.   }
  52.   // reads little endian samples
  53.   audioDataByteOrder_ = 0;
  54. }
  55. SonyCDU920::~SonyCDU920()
  56. {
  57.   int i;
  58.   for (i = 0; i < maxScannedSubChannels_; i++) {
  59.     delete scannedSubChannels_[i];
  60.     scannedSubChannels_[i] = NULL;
  61.   }
  62. }
  63. // static constructor
  64. CdrDriver *SonyCDU920::instance(ScsiIf *scsiIf, unsigned long options)
  65. {
  66.   return new SonyCDU920(scsiIf, options);
  67. }
  68. int SonyCDU920::bigEndianSamples() const
  69. {
  70.   return 0; // drive takes little endian samples
  71.  }
  72. int SonyCDU920::multiSession(int m)
  73. {
  74.   return 1; // not supported in DAO mode
  75. }
  76. // sets speed
  77. // return: 0: OK
  78. //         1: illegal speed
  79. int SonyCDU920::speed(int s)
  80. {
  81.   if (s >= 0 && s <= 2)
  82.     speed_ = s;
  83.   else if (s > 2)
  84.     speed_ = 2;
  85.   else
  86.     return 1;
  87.   return 0;
  88. }
  89. // loads ('unload' == 0) or ejects ('unload' == 1) tray
  90. // return: 0: OK
  91. //         1: scsi command failed
  92. int SonyCDU920::loadUnload(int unload) const
  93. {
  94.   unsigned char cmd[6];
  95.   memset(cmd, 0, 6);
  96.   cmd[0] = 0x1b; // START/STOP UNIT
  97.   if (unload) {
  98.     cmd[4] = 0x02; // LoUnlo=1, Start=0
  99.   }
  100.   else {
  101.     cmd[4] = 0x01; // LoUnlo=0, Start=1
  102.   }
  103.   
  104.   if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) {
  105.     message(-2, "Cannot load/unload medium.");
  106.     return 1;
  107.   }
  108.   return 0;
  109. }
  110. // sets read/write speed and simulation mode
  111. // return: 0: OK
  112. //         1: scsi command failed
  113. int SonyCDU920::selectSpeed()
  114. {
  115.   unsigned char mp[4];
  116.   
  117.   mp[0] = 0x31;
  118.   mp[1] = 2;
  119.   mp[2] = 0;
  120.   mp[3] = 0;
  121.   switch (speed_) {
  122.   case 0:
  123.     mp[2] = 0xff;
  124.   case 1:
  125.     mp[2] = 0;
  126.     break;
  127.   case 2:
  128.     mp[2] = 1;
  129.     break;
  130.   }
  131.   if (setModePage6(mp, NULL, NULL, 1) != 0) {
  132.     message(-2, "Cannot set speed mode page.");
  133.     return 1;
  134.   }
  135.   return 0;
  136. }
  137. // Determins start and length of lead-in.
  138. // return: 0: OK
  139. //         1: SCSI command failed
  140. int SonyCDU920::getSessionInfo()
  141. {
  142.   unsigned char mp[32];
  143.   if (getModePage6(0x22, mp, 32, NULL, NULL, 1) != 0) {
  144.     message(-2, "Cannot retrieve CD-R disc information mode page.");
  145.     return 1;
  146.   }
  147.   leadInStart_ = Msf(mp[25], mp[26], mp[27]);
  148.   if (leadInStart_.lba() != 0)
  149.     leadInLen_ = 450000 - leadInStart_.lba();
  150.   else
  151.     leadInLen_ = 0;
  152.   message(3, "Lead-in start: %s length: %ld", leadInStart_.str(),
  153.   leadInLen_);
  154.   return 0;
  155. }
  156. // Sets write parameters.
  157. // return: 0: OK
  158. //         1: scsi command failed
  159. int SonyCDU920::setWriteParameters()
  160. {
  161.   unsigned char mp[32];
  162.   memset(mp, 0, 8);
  163.   mp[0] = 0x20;
  164.   mp[1] = 6;
  165.   mp[3] = (simulate_ != 0) ? 2 : 0;
  166.   
  167.   if (setModePage6(mp, NULL, NULL, 1) != 0) {
  168.     message(-2, "Cannot set CD-R mastering information page.");
  169.     return 1;
  170.   }
  171.   memset(mp, 0, 32);
  172.   if (getModePage6(0x22, mp, 32, NULL, NULL, 1) != 0) {
  173.     message(-2, "Cannot retrieve CD-R disc information page.");
  174.     return 1;
  175.   }
  176.   mp[0] &= 0x7f; // clear PS flag
  177.   
  178.   mp[2] = 0; // Disc Style: uninterrupted
  179.   mp[3] = sessionFormat(); // Disc Type: from 'toc_' object
  180.   mp[19] = 0; // no automatic post-gap; required?
  181.   
  182.   if (setModePage6(mp, NULL, NULL, 1) != 0) {
  183.     message(-2, "Cannot set CD-R disc information page.");
  184.     return 1;
  185.   }
  186.   return 0;
  187. }
  188. // Creates cue sheet for current 'toc_' object.
  189. // cueSheetLen: filled with length of cue sheet in bytes
  190. // return: newly allocated cue sheet buffer or 'NULL' on error
  191. unsigned char *SonyCDU920::createCueSheet(unsigned char leadInDataForm,
  192.   long *cueSheetLen)
  193. {
  194.   const Track *t;
  195.   int trackNr;
  196.   Msf start, end, index;
  197.   unsigned char *cueSheet;
  198.   long len;
  199.   long n; // index into cue sheet
  200.   unsigned char ctl; // control nibbles of cue sheet entry CTL/ADR
  201.   long i;
  202.   unsigned char dataMode;
  203.   int firstTrack;
  204.   TrackIterator itr(toc_);
  205.   if (itr.first(start, end) == NULL) {
  206.     return NULL;
  207.   }
  208.   // determine length of cue sheet
  209.   len = 3; // entries for lead-in, 1st pre-gap, lead-out
  210.   for (t = itr.first(start, end), trackNr = 1;
  211.        t != NULL;
  212.        t = itr.next(start, end), trackNr++) {
  213.     len += 1; // entry for track
  214.     if (t->start().lba() != 0 && trackNr > 1) {
  215.       len += 1; // entry for pre-gap
  216.     }
  217.     
  218.     len += t->nofIndices(); // entry for each index increment
  219.   }
  220.   cueSheet = new (unsigned char)[len * 8];
  221.   n = 0;
  222.   // entry for lead-in
  223.   ctl = (toc_->leadInMode() == TrackData::AUDIO) ? 0 : 0x40;
  224.   cueSheet[n*8] = 0x01 | ctl; // CTL/ADR
  225.   cueSheet[n*8+1] = 0;    // Track number
  226.   cueSheet[n*8+2] = 0;    // Index
  227.   cueSheet[n*8+3] = leadInDataForm;
  228.   cueSheet[n*8+4] = 0;    // Serial Copy Management System
  229.   cueSheet[n*8+5] = 0;    // MIN
  230.   cueSheet[n*8+6] = sessionFormat(); // disc type
  231.   cueSheet[n*8+7] = 0;    // FRAME
  232.   n++;
  233.   firstTrack = 1;
  234.   for (t = itr.first(start, end), trackNr = 1;
  235.        t != NULL;
  236.        t = itr.next(start, end), trackNr++) {
  237.     switch (t->type()) {
  238.     case TrackData::AUDIO:
  239.       dataMode = 0x01;
  240.       break;
  241.     case TrackData::MODE1:
  242.     case TrackData::MODE1_RAW:
  243.       dataMode = 0x11;
  244.       break;
  245.     case TrackData::MODE2:
  246.       dataMode = 0x19;
  247.       break;
  248.     case TrackData::MODE2_RAW:
  249.     case TrackData::MODE2_FORM1:
  250.     case TrackData::MODE2_FORM2:
  251.     case TrackData::MODE2_FORM_MIX:
  252.       dataMode = 0x23;
  253.       break;
  254.     default:
  255.       dataMode = 0;
  256.       break;
  257.     }
  258.     ctl = 0;
  259.     if (t->copyPermitted()) {
  260.       ctl |= 0x20;
  261.     }
  262.     if (t->type() == TrackData::AUDIO) {
  263.       // audio track
  264.       if (t->preEmphasis()) {
  265. ctl |= 0x10;
  266.       }
  267.       if (t->audioType() == 1) {
  268. ctl |= 0x80;
  269.       }
  270.     }
  271.     else {
  272.       // data track
  273.       ctl |= 0x40;
  274.     }
  275.     Msf tstart(start.lba() + 150); // start of index 1 of current track
  276.  
  277.     if (firstTrack) {
  278.       // entry for pre-gap before first track
  279.       cueSheet[n*8]   = ctl | 0x01;
  280.       cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  281.       cueSheet[n*8+2] = 0;    // Index 0
  282.       cueSheet[n*8+3] = dataMode; // Data Form
  283.       cueSheet[n*8+4] = 0;    // Serial Copy Management System
  284.       cueSheet[n*8+5] = 0;    // MIN 0
  285.       cueSheet[n*8+6] = 0;    // SEC 0
  286.       cueSheet[n*8+7] = 0;    // FRAME 0
  287.       n++;
  288.     }
  289.     else if (t->start().lba() != 0) {
  290.       // entry for pre-gap
  291.       Msf pstart(tstart.lba() - t->start().lba());
  292.       cueSheet[n*8]   = ctl | 0x01;
  293.       cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  294.       cueSheet[n*8+2] = 0;        // Index 0: pre-gap
  295.       cueSheet[n*8+3] = dataMode; // Data Form
  296.       cueSheet[n*8+4] = 0;        // no alternate copy bit
  297.       cueSheet[n*8+5] = SubChannel::bcd(pstart.min());
  298.       cueSheet[n*8+6] = SubChannel::bcd(pstart.sec());
  299.       cueSheet[n*8+7] = SubChannel::bcd(pstart.frac());
  300.       n++;
  301.     }
  302.     cueSheet[n*8]   = ctl | 0x01;
  303.     cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  304.     cueSheet[n*8+2] = 1; // Index 1
  305.     cueSheet[n*8+3] = dataMode; // Data Form
  306.     cueSheet[n*8+4] = 0; // no alternate copy bit
  307.     cueSheet[n*8+5] = SubChannel::bcd(tstart.min());
  308.     cueSheet[n*8+6] = SubChannel::bcd(tstart.sec());
  309.     cueSheet[n*8+7] = SubChannel::bcd(tstart.frac());
  310.     n++;
  311.     for (i = 0; i < t->nofIndices(); i++) {
  312.       index = tstart + t->getIndex(i);
  313.       cueSheet[n*8]   = ctl | 0x01;
  314.       cueSheet[n*8+1] = SubChannel::bcd(trackNr);
  315.       cueSheet[n*8+2] = SubChannel::bcd(i + 2); // Index
  316.       cueSheet[n*8+3] = dataMode; // Data Form
  317.       cueSheet[n*8+4] = 0; // no alternate copy bit
  318.       cueSheet[n*8+5] = SubChannel::bcd(index.min());
  319.       cueSheet[n*8+6] = SubChannel::bcd(index.sec());
  320.       cueSheet[n*8+7] = SubChannel::bcd(index.frac());
  321.       n++;
  322.     }
  323.     firstTrack = 0;
  324.   }
  325.   assert(n == len - 1);
  326.   // entry for lead out
  327.   Msf lostart(toc_->length().lba() + 150);
  328.   ctl = (toc_->leadOutMode() == TrackData::AUDIO) ? 0 : 0x40;
  329.     
  330.   cueSheet[n*8]   = ctl | 0x01;
  331.   cueSheet[n*8+1] = 0xaa;
  332.   cueSheet[n*8+2] = 1; // Index 1
  333.   cueSheet[n*8+3] = 0x00; // CD-DA data, data generated by device
  334.   cueSheet[n*8+4] = 0; // no alternate copy bit
  335.   cueSheet[n*8+5] = SubChannel::bcd(lostart.min());
  336.   cueSheet[n*8+6] = SubChannel::bcd(lostart.sec());
  337.   cueSheet[n*8+7] = SubChannel::bcd(lostart.frac());
  338.   message(3, "nCue Sheet:");
  339.   message(3, "CTL/  TNO  INDEX  DATA  SCMS  MIN  SEC  FRAME");
  340.   message(3, "ADR               FORM        BCD  BCD  BCD");
  341.   for (n = 0; n < len; n++) {
  342.     message(3, "%02x    %02x    %02x     %02x    %02x   %02x   %02x   %02x",
  343.    cueSheet[n*8],
  344.    cueSheet[n*8+1], cueSheet[n*8+2], cueSheet[n*8+3], cueSheet[n*8+4],
  345.    cueSheet[n*8+5], cueSheet[n*8+6], cueSheet[n*8+7]);
  346.   }
  347.   *cueSheetLen = len * 8;
  348.   return cueSheet;
  349. }
  350. int SonyCDU920::sendCueSheet(unsigned char leadInDataForm)
  351. {
  352.   unsigned char cmd[10];
  353.   long cueSheetLen;
  354.   unsigned char *cueSheet = createCueSheet(leadInDataForm, &cueSheetLen);
  355.   if (cueSheet == NULL) {
  356.     return 1;
  357.   }
  358.   if (cueSheetLen > 3600) {
  359.     message(-2, "Cue sheet too big. Please remove index marks.");
  360.     delete[] cueSheet;
  361.     return 1;
  362.   }
  363.   memset(cmd, 0, 10);
  364.   cmd[0] = 0xe0; // WRITE START
  365.   cmd[1] = (cueSheetLen >> 16) & 0x0f;
  366.   cmd[2] = cueSheetLen >> 8;
  367.   cmd[3] = cueSheetLen;
  368.   if (sendCmd(cmd, 10, cueSheet, cueSheetLen, NULL, 0) != 0) {
  369.     message(-2, "Cannot send cue sheet.");
  370.     delete[] cueSheet;
  371.     return 1;
  372.   }
  373.   delete[] cueSheet;
  374.   return 0;
  375. }
  376. int SonyCDU920::readBufferCapacity(long *capacity)
  377. {
  378.   unsigned char cmd[10];
  379.   unsigned char data[8];
  380.   memset(cmd, 0, 10);
  381.   memset(data, 0, 8);
  382.   cmd[0] = 0xec; // READ BUFFER CAPACITY
  383.   if (sendCmd(cmd, 10, NULL, 0, data, 8) != 0) {
  384.     message(-2, "Read buffer capacity failed.");
  385.     return 1;
  386.   }
  387.   *capacity = (data[5] << 16) | (data[6] << 8) | data[7];
  388.   return 0;
  389. }
  390. int SonyCDU920::initDao(const Toc *toc)
  391. {
  392.   long n;
  393.   toc_ = toc;
  394.   blockLength_ = AUDIO_BLOCK_LEN;
  395.   blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_;
  396.   assert(blocksPerWrite_ > 0);
  397.   if (selectSpeed() != 0 ||
  398.       getSessionInfo() != 0) {
  399.     return 1;
  400.   }
  401.   // allocate buffer for writing zeros
  402.   n = blocksPerWrite_ * blockLength_;
  403.   delete[] zeroBuffer_;
  404.   zeroBuffer_ = new char[n];
  405.   memset(zeroBuffer_, 0, n);
  406.   return 0;
  407. }
  408. int SonyCDU920::startDao()
  409. {
  410.   scsiTimeout_ = scsiIf_->timeout(3 * 60);
  411.   if (setWriteParameters() != 0 ||
  412.       sendCueSheet(0x00/* Data Form: CD-DA, generate data by device */) != 0)
  413.     return 1;
  414.   long lba = -150;
  415.   // write mandatory pre-gap after lead-in
  416.   if (writeZeros(toc_->leadInMode(), lba, 0, 150) != 0) {
  417.     return 1;
  418.   }
  419.   
  420.   return 0;
  421. }
  422. int SonyCDU920::finishDao()
  423. {
  424.   scsiIf_->timeout(scsiTimeout_);
  425.   delete[] zeroBuffer_, zeroBuffer_ = NULL;
  426.   return 0;
  427. }
  428. void SonyCDU920::abortDao()
  429. {
  430.   unsigned char cmd[10];
  431.   memset(cmd, 0, 10);
  432.   cmd[0] = 0xe2; // DISCONTINUE
  433.   
  434.   sendCmd(cmd, 10, NULL, 0, NULL, 0, 1);
  435. }
  436. // Writes data to target, the block length depends on the actual track 'mode'.
  437. // 'len' is number of blocks to write.
  438. // 'lba' specifies the next logical block address for writing and is updated
  439. // by this function.
  440. // return: 0: OK
  441. //         1: scsi command failed
  442. int SonyCDU920::writeData(TrackData::Mode mode, long &lba, const char *buf,
  443.  long len)
  444. {
  445.   assert(blocksPerWrite_ > 0);
  446.   unsigned char cmd[10];
  447.   int writeLen = 0;
  448.   long blockLength = blockSize(mode);
  449.   long byteLen;
  450.   int ret;
  451. #if 0
  452.   long sum, i;
  453.   sum = 0;
  454.   for (i = 0; i < len * blockLength; i++) {
  455.     sum += buf[i];
  456.   }
  457.   message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum);
  458. #endif
  459.   memset(cmd, 0, 10);
  460.   cmd[0] = 0xe1; // WRITE CONTINUE
  461.   
  462.   while (len > 0) {
  463.     writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len);
  464.     byteLen = writeLen * blockLength;
  465.     cmd[1] = (byteLen >> 16) & 0x1f;
  466.     cmd[2] = byteLen >> 8;
  467.     cmd[3] = byteLen;
  468.     if ((ret = sendCmd(cmd, 10, (unsigned char *)buf, byteLen, NULL, 0, 0))
  469. != 0) {
  470.       if(ret == 2) {
  471.         const unsigned char *sense;
  472.         int senseLen;
  473.         sense = scsiIf_->getSense(senseLen);
  474. // The drive logs in the CD-R after write simulation again and
  475. // reports this by Unit Attention. Ceck for this error and ignore it.
  476. if(senseLen >= 14 && (sense[2] & 0x0f) == 0x6 && sense[7] >= 6 &&
  477.    (sense[12] == 0x80 /*this really happened*/ ||
  478.     sense[12] == 0xd4 /*EXIT FROM PSEUDO TRACK AT ONCE RECORDING*/)) {
  479.   sleep(10); // wait until drive becomes ready again
  480.         }
  481. else {
  482.   scsiIf_->printError();
  483.   message(-2, "Write data failed.");
  484.   return 1;
  485. }
  486.       }
  487.       else {
  488. message(-2, "Write data failed.");
  489. return 1;
  490.       }
  491.     }
  492.     buf += byteLen;
  493.     lba += writeLen;
  494.     len -= writeLen;
  495.   }
  496.       
  497.   return 0;
  498. }
  499. DiskInfo *SonyCDU920::diskInfo()
  500. {
  501.   unsigned char mp[32];
  502.   
  503.   memset(&diskInfo_, 0, sizeof(DiskInfo));
  504.   memset(mp, 0, 32);
  505.   if (getModePage6(0x22, mp, 32, NULL, NULL, 1) != 0) {
  506.     message(-2, "Cannot retrieve CD-R disc information mode page.");
  507.     return &diskInfo_;
  508.   }
  509.   diskInfo_.empty = ((mp[16] >> 6) == 0 ? 1 : 0);
  510.   diskInfo_.valid.empty = 1;
  511.   diskInfo_.cdrw = 0;
  512.   diskInfo_.valid.cdrw = 1;
  513.   if (diskInfo_.empty) {
  514.     diskInfo_.manufacturerId = Msf(mp[25], mp[26], mp[27]);
  515.     diskInfo_.valid.manufacturerId = 1;
  516.     diskInfo_.capacity = Msf(mp[13], mp[14], mp[15]).lba();
  517.     diskInfo_.valid.capacity = 1;
  518.   }
  519.   
  520.   return &diskInfo_;
  521. }
  522. Toc *SonyCDU920::readDiskToc(int session, const char *audioFilename)
  523. {
  524.   Toc *toc = CdrDriver::readDiskToc(session, audioFilename);
  525.   setBlockSize(MODE1_BLOCK_LEN);
  526.   
  527.   return toc;
  528. }
  529. // tries to read catalog number from disk and adds it to 'toc'
  530. // return: 1 if valid catalog number was found, else 0
  531. int SonyCDU920::readCatalog(Toc *toc, long startLba, long endLba)
  532. {
  533.   unsigned char cmd[10];
  534.   unsigned char data[24];
  535.   char catalog[14];
  536.   int i;
  537.   memset(cmd, 0, 10);
  538.   memset(data, 0, 24);
  539.   cmd[0] = 0x42; // READ SUB-CHANNEL
  540.   cmd[2] = 1 << 6;
  541.   cmd[3] = 0x02; // get media catalog number
  542.   cmd[8] = 24;   // transfer length
  543.   if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
  544.     message(-2, "Cannot get catalog number.");
  545.     return 0;
  546.   }
  547.   if (data[8] & 0x80) {
  548.     for (i = 0; i < 13; i++) {
  549.       catalog[i] = data[0x09 + i];
  550.     }
  551.     catalog[13] = 0;
  552.     if (toc->catalog(catalog) == 0) {
  553.       return 1;
  554.     }
  555.   }
  556.   return 0;
  557. }
  558. int SonyCDU920::readIsrc(int trackNr, char *buf)
  559. {
  560.   unsigned char cmd[10];
  561.   unsigned char data[24];
  562.   int i;
  563.   buf[0] = 0;
  564.   memset(cmd, 0, 10);
  565.   memset(data, 0, 24);
  566.   cmd[0] = 0x42; // READ SUB-CHANNEL
  567.   cmd[2] = 1 << 6;
  568.   cmd[3] = 0x03; // get media catalog number
  569.   cmd[6] = trackNr;
  570.   cmd[8] = 24;   // transfer length
  571.   if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
  572.     message(-2, "Cannot get ISRC code.");
  573.     return 0;
  574.   }
  575.   if (data[8] & 0x80) {
  576.     for (i = 0; i < 12; i++) {
  577.       buf[i] = data[0x09 + i];
  578.     }
  579.     buf[12] = 0;
  580.   }
  581.   return 0;
  582. }
  583. int SonyCDU920::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba,
  584.      long endLba, Msf *indexIncrements,
  585.      int *indexIncrementCnt, long *pregap,
  586.      char *isrcCode, unsigned char *ctl)
  587. {
  588.   selectSpeed();
  589.   int ret = analyzeTrackScan(mode, trackNr, startLba, endLba,
  590.      indexIncrements, indexIncrementCnt, pregap,
  591.      isrcCode, ctl);
  592.   return ret;
  593. }
  594. int SonyCDU920::readSubChannels(long lba, long len, SubChannel ***chans,
  595. Sample *audioData)
  596. {
  597.   unsigned char cmd[12];
  598.   int i;
  599.   int retries = 5;
  600.   long blockLen = AUDIO_BLOCK_LEN + 16;
  601.   cmd[0] = 0xd8;  // READ CDDA
  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;
  612.   cmd[11] = 0;
  613.   while (1) {
  614.     if (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * blockLen,
  615. retries == 0 ? 1 : 0) != 0) {
  616.       if (retries == 0)
  617. return 1;
  618.     }
  619.     else {
  620.       break;
  621.     }
  622.     retries--;
  623.   }
  624.   
  625.   unsigned char *p =  transferBuffer_ + AUDIO_BLOCK_LEN;
  626.   for (i = 0; i < len; i++) {
  627.     ((PQSubChannel16*)scannedSubChannels_[i])->init(p);
  628.     if (scannedSubChannels_[i]->type() != SubChannel::QMODE_ILLEGAL) {
  629.       // the CRC of the sub-channel data is set to zero -> mark the
  630.       // sub-channel object that it should not try to verify the CRC
  631.       scannedSubChannels_[i]->crcInvalid();
  632.     }
  633.     p += blockLen;
  634.   }
  635.   if (audioData != NULL) {
  636.     p = transferBuffer_;
  637.     for (i = 0; i < len; i++) {
  638.       memcpy(audioData, p, AUDIO_BLOCK_LEN);
  639.       p += blockLen;
  640.       audioData += SAMPLES_PER_BLOCK;
  641.     }
  642.   }
  643.   *chans = scannedSubChannels_;
  644.   return 0;
  645. }
  646. CdRawToc *SonyCDU920::getRawToc(int sessionNr, int *len)
  647. {
  648.   unsigned char cmd[10];
  649.   unsigned short dataLen;
  650.   unsigned char *data = NULL;;
  651.   unsigned char reqData[4]; // buffer for requestion the actual length
  652.   unsigned char *p;
  653.   int i, entries;
  654.   CdRawToc *rawToc;
  655.   assert(sessionNr >= 1);
  656.   // read disk toc length
  657.   memset(cmd, 0, 10);
  658.   cmd[0] = 0x43; // READ TOC
  659.   cmd[6] = sessionNr;
  660.   cmd[8] = 4;
  661.   cmd[9] = (2 << 6);
  662.   if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) {
  663.     message(-2, "Cannot read disk toc.");
  664.     return NULL;
  665.   }
  666.   dataLen = ((reqData[0] << 8) | reqData[1]) + 2;
  667.   
  668.   message(3, "Raw toc data len: %d", dataLen);
  669.   data = new (unsigned char)[dataLen];
  670.   
  671.   // read disk toc
  672.   cmd[7] = dataLen >> 8;
  673.   cmd[8] = dataLen;
  674.   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
  675.     message(-2, "Cannot read disk toc.");
  676.     delete[] data;
  677.     return NULL;
  678.   }
  679.   entries = (((data[0] << 8) | data[1]) - 2) / 11;
  680.   rawToc = new CdRawToc[entries];
  681.   for (i = 0, p = data + 4; i < entries; i++, p += 11 ) {
  682. #if 0
  683.     message(0, "%d %02x %02d %2x %02d:%02d:%02d %02d %02d:%02d:%02d",
  684.     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]);
  685. #endif
  686.     rawToc[i].sessionNr = p[0];
  687.     rawToc[i].adrCtl = p[1];
  688.     rawToc[i].point = p[3];
  689.     rawToc[i].pmin = p[8];
  690.     rawToc[i].psec = p[9];
  691.     rawToc[i].pframe = p[10];
  692.   }
  693.   delete[] data;
  694.   *len = entries;
  695.   return rawToc;
  696. }
  697. long SonyCDU920::readTrackData(TrackData::Mode mode, long lba, long len,
  698.        unsigned char *buf)
  699. {
  700.   unsigned char cmd[10];
  701.   long blockLen = 2340;
  702.   long i;
  703.   TrackData::Mode actMode;
  704.   int ok = 0;
  705.   const unsigned char *sense;
  706.   int senseLen;
  707.   int softError;
  708.   if (setBlockSize(blockLen) != 0)
  709.     return 0;
  710.   memset(cmd, 0, 10);
  711.   cmd[0] = 0x28; // READ10
  712.   cmd[2] = lba >> 24;
  713.   cmd[3] = lba >> 16;
  714.   cmd[4] = lba >> 8;
  715.   cmd[5] = lba;
  716.   while (len > 0 && !ok) {
  717.     cmd[7] = len >> 8;
  718.     cmd[8] = len;
  719.     memset(transferBuffer_, 0, len * blockLen);
  720.     switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) {
  721.     case 0:
  722.       ok = 1;
  723.       break;
  724.     case 2:
  725.       softError = 0;
  726.       sense = scsiIf_->getSense(senseLen);
  727.       if (senseLen > 0x0c) {
  728. if ((sense[2] &0x0f) == 5) {
  729.   switch (sense[12]) {
  730.   case 0x63: // end of user area encountered on this track
  731.   case 0x64: // Illegal mode for this track
  732.     softError = 1;
  733.     break;
  734.   }
  735. }
  736. else if ((sense[2] & 0x0f) == 3) { // Medium error
  737.   switch (sense[12]) {
  738.   case 0x02: // No seek complete, sector not found
  739.   case 0x11: // L-EC error
  740.     return -2;
  741.     break;
  742.   }
  743. }
  744.       }
  745.       if (!softError) {
  746. scsiIf_->printError();
  747. return -1;
  748.       }
  749.       break;
  750.     default:
  751.       message(-2, "Read error at LBA %ld, len %ld", lba, len);
  752.       return -1;
  753.       break;
  754.     }
  755.     if (!ok) {
  756.       len--;
  757.     }
  758.   }
  759.   unsigned char *sector = transferBuffer_;
  760.   for (i = 0; i < len; i++) {
  761.     actMode = determineSectorMode(sector);
  762.     if (!(actMode == mode ||
  763.   (mode == TrackData::MODE2_FORM_MIX &&
  764.    (actMode == TrackData::MODE2_FORM1 ||
  765.     actMode == TrackData::MODE2_FORM2)) ||
  766.   (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) ||
  767.   (mode == TrackData::MODE2_RAW &&
  768.    (actMode == TrackData::MODE2 ||
  769.     actMode == TrackData::MODE2_FORM1 ||
  770.     actMode == TrackData::MODE2_FORM2)))) {
  771.       message(3, "Stopped because sector with not matching mode %s found.",
  772.       TrackData::mode2String(actMode));
  773.       return i;
  774.     }
  775.     if (buf != NULL) {
  776.       switch (mode) {
  777.       case TrackData::MODE1:
  778. memcpy(buf, sector + 4, MODE1_BLOCK_LEN);
  779. buf += MODE1_BLOCK_LEN;
  780. break;
  781.       case TrackData::MODE2:
  782.       case TrackData::MODE2_FORM_MIX:
  783. memcpy(buf, sector + 4, MODE2_BLOCK_LEN);
  784. buf += MODE2_BLOCK_LEN;
  785. break;
  786.       case TrackData::MODE2_FORM1:
  787. memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN);
  788. buf += MODE2_FORM1_DATA_LEN;
  789. break;
  790.       case TrackData::MODE2_FORM2:
  791. memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN);
  792. buf += MODE2_FORM2_DATA_LEN;
  793. break;
  794.       case TrackData::MODE1_RAW:
  795.       case TrackData::MODE2_RAW:
  796. memcpy(buf, syncPattern, 12);
  797. memcpy(buf + 12, sector, 2340);
  798. buf += AUDIO_BLOCK_LEN;
  799. break;
  800.       case TrackData::MODE0:
  801.       case TrackData::AUDIO:
  802. message(-3, "PlextorReader::readTrackData: Illegal mode.");
  803. return 0;
  804. break;
  805.       }
  806.     }
  807.     sector += blockLen;
  808.   }  
  809.   return len;
  810. }
  811. int SonyCDU920::readAudioRange(int fd, long start, long end, int startTrack,
  812.        int endTrack, TrackInfo *info)
  813. {
  814.   return CdrDriver::readAudioRangeParanoia(fd, start, end, startTrack,
  815.    endTrack, info);
  816. }