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

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*  cdrdao - write audio CD-Rs in disc-at-once mode
  2.  *
  3.  *  Copyright (C) 1998, 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: TeacCdr55.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:37  mueller
  25.  * Added 'read-toc' support.
  26.  *
  27.  * Revision 1.1  1999/03/21 19:36:08  mueller
  28.  * Initial revision
  29.  *
  30.  */
  31. static char rcsid[] = "$Id: TeacCdr55.cc,v 1.3 1999/04/05 11:04:10 mueller Exp mueller $";
  32. #include <config.h>
  33. #include <string.h>
  34. #include <assert.h>
  35. #include "TeacCdr55.h"
  36. #include "Toc.h"
  37. #include "PQSubChannel16.h"
  38. #include "util.h"
  39. TeacCdr55::TeacCdr55(ScsiIf *scsiIf, unsigned long options)
  40.   : CdrDriver(scsiIf, options)
  41. {
  42.   int i;
  43.   driverName_ = "Teac CD-R50/55 - Version 0.1 (data)";
  44.   
  45.   speed_ = 0;
  46.   simulate_ = 1;
  47.   encodingMode_ = 1;
  48.   scsiTimeout_ = 0;
  49.   actMode_ = TrackData::AUDIO;
  50.   writeEndLba_ = 0;
  51.   memset(modeSelectData_, 0, 12);
  52.   memset(&diskInfo_, 0, sizeof(DiskInfo));
  53.   for (i = 0; i < maxScannedSubChannels_; i++)
  54.     scannedSubChannels_[i] = new PQSubChannel16;
  55.   // reads little endian samples
  56.   audioDataByteOrder_ = 0;
  57. }
  58. TeacCdr55::~TeacCdr55()
  59. {
  60.   int i;
  61.   for (i = 0; i < maxScannedSubChannels_; i++) {
  62.     delete scannedSubChannels_[i];
  63.     scannedSubChannels_[i] = NULL;
  64.   }
  65. }
  66. // static constructor
  67. CdrDriver *TeacCdr55::instance(ScsiIf *scsiIf, unsigned long options)
  68. {
  69.   return new TeacCdr55(scsiIf, options);
  70. }
  71. // sets speed
  72. // return: 0: OK
  73. //         1: illegal speed
  74. int TeacCdr55::speed(int s)
  75. {
  76.   if (s >= 0 && s <= 4 && s != 3) {
  77.     speed_ = s;
  78.   }
  79.   else if (s == 3) {
  80.     speed_ = 2;
  81.   }
  82.   else if (s > 4) {
  83.     speed_ = 4;
  84.   }
  85.   else {
  86.     return 1;
  87.   }
  88.   return 0;
  89. }
  90. // loads ('unload' == 0) or ejects ('unload' == 1) tray
  91. // return: 0: OK
  92. //         1: scsi command failed
  93. int TeacCdr55::loadUnload(int unload) const
  94. {
  95.   
  96.  unsigned char cmd[6];
  97.   memset(cmd, 0, 6);
  98.   cmd[0] = 0x1b; // START/STOP UNIT
  99.   cmd[4] = unload ? 0x02 : 0x03;
  100.   if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) {
  101.     message(-2, "Cannot load/unload medium.");
  102.     return 1;
  103.   }
  104.   return 0;
  105. }
  106. // Retrieves mode select header and block descriptor and stores it in
  107. // class member 'modeSelectData_' for later usage with various mode select
  108. // commands.
  109. // Return: 0: OK, 1: SCSI error
  110. int TeacCdr55::getModeSelectData()
  111. {
  112.   unsigned char cmd[6];
  113.   memset(cmd, 0, 6);
  114.   memset(modeSelectData_, 0, 12);
  115.   cmd[0] = 0x1a; // MODE SENSE
  116.   cmd[4] = 12;
  117.   if (sendCmd(cmd, 6, NULL, 0, modeSelectData_, 12, 1) != 0) {
  118.     message(-2, "Mode Sense failed.");
  119.     return 1;
  120.   }
  121.   return 0;
  122. }
  123. // sets read/write speed and simulation mode
  124. // return: 0: OK
  125. //         1: scsi command failed
  126. int TeacCdr55::setWriteSpeed()
  127. {
  128.   unsigned char mp[4];
  129.   
  130.   mp[0] = 0x31;
  131.   mp[1] = 2;
  132.   mp[2] = 0;
  133.   mp[3] = 0;
  134.   switch (speed_) {
  135.   case 1:
  136.     mp[2] = 0;
  137.     break;
  138.   case 2:
  139.     mp[2] = 1;
  140.     break;
  141.   case 0:
  142.   case 4:
  143.     mp[2] = 2;
  144.     break;
  145.   }
  146.   if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) {
  147.     message(-2, "Cannot set speed mode page.");
  148.     return 1;
  149.   }
  150.     
  151.   return 0;
  152. }
  153. // Sets write parameters via mode page 0x22.
  154. // return: 0: OK
  155. //         1: scsi command failed
  156. int TeacCdr55::setWriteParameters()
  157. {
  158.   unsigned char mp[9];
  159.   memset(mp, 0, 9);
  160.   mp[0] = 0x22;
  161.   mp[1] = 7;
  162.   if (multiSession()) {
  163.     mp[4] = 4; // session at once, keep session open
  164.   }
  165.   else {
  166.     if (diskInfo_.sessionCnt > 0)
  167.       mp[4] = 0x84; // session at once and close disk
  168.     else
  169.       mp[4] = 2; // disk at once
  170.   }
  171.   if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) {
  172.     message(-2, "Cannot set write method mode page.");
  173.     return 1;
  174.   }
  175.   return 0;
  176. }
  177. int TeacCdr55::setSimulationMode()
  178. {
  179.   unsigned char mp[3];
  180.   mp[0] = 0x21;
  181.   mp[1] = 1;
  182.   if (simulate())
  183.     mp[2] = 3; 
  184.   else
  185.     mp[2] = 0; 
  186.   if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) {
  187.     message(-2, "Cannot set preview write mode page.");
  188.     return 1;
  189.   }
  190.   return 0;
  191. }
  192. int TeacCdr55::setWriteDensity(TrackData::Mode mode)
  193. {
  194.   long blockLength = blockSize(mode);
  195.   unsigned char cmd[6];
  196.   unsigned char data[12];
  197.   memset(cmd, 0, 6);
  198.   cmd[0] = 0x15; // MODE SELECT
  199.   cmd[1] = 0x10;
  200.   cmd[4] = 12;
  201.   memcpy(data, modeSelectData_, 12);
  202.   data[0] = 0;
  203.   data[3] = 8;
  204.   data[9] = 0;
  205.   switch (mode) {
  206.   case TrackData::AUDIO:
  207.     data[4] = 0x04;
  208.     break;
  209.   case TrackData::MODE1:
  210.   case TrackData::MODE1_RAW:
  211.     data[4] = 0x01;
  212.     break;
  213.   case TrackData::MODE2:
  214.     data[4] = 0xc1;
  215.     break;
  216.   case TrackData::MODE2_FORM1:
  217.     data[4] = 0x81;
  218.     break;
  219.   case TrackData::MODE2_FORM2:
  220.     data[4] = 0x82;
  221.     break;
  222.   case TrackData::MODE2_RAW:
  223.   case TrackData::MODE2_FORM_MIX:
  224.     data[4] = 0x83; // I'm not sure if this really allows writing of mixed
  225.                     // form 1 and form 2 sectors.
  226.     break;
  227.   case TrackData::MODE0:
  228.     message(-3, "Illegal mode in 'TeacCdr55::setWriteDensity()'.");
  229.     return 0;
  230.     break;
  231.   }
  232.   data[10] = blockLength >> 8;
  233.   data[11] = blockLength;
  234.   message(2, "Changing write density to 0x%02x/0x%02x%02x.", data[4], data[10],
  235.   data[11]);
  236.   if (sendCmd(cmd, 6, data, 12, NULL, 0, 1) != 0) {
  237.     message(-2, "Cannot set density/block size.");
  238.     return 1;
  239.   }
  240.   return 0;
  241. }
  242. // Judges disc and performs power calibration if possible.
  243. // judge: 1: judge disc, 0: don't judge disc
  244. // Return 0: OK
  245. //        1: judge disc rejected inserted medium
  246. //        2: SCSI error occured
  247. int TeacCdr55::executeOPC(int judge)
  248. {
  249.   unsigned char cmd[12];
  250.   const unsigned char *senseCode;
  251.   int senseLen;
  252.   memset(cmd, 0, 12);
  253.   cmd[0] = 0xec; // OPC EXECUTION
  254.   if (judge) {
  255.     cmd[1] = 1; // judge current disc
  256.     message(1, "Judging disk...");
  257.     switch (sendCmd(cmd, 12, NULL, 0, NULL, 0, 0)) {
  258.     case 0: // OK, disc can be written at selected speed
  259.       break;
  260.     case 1:
  261.       message(-2, "Judge disk command failed.");
  262.       return 2;
  263.       break;
  264.       
  265.     case 2: // Check sense code
  266.       senseCode = scsiIf_->getSense(senseLen);
  267.       if (senseLen > 12 && (senseCode[2] & 0x0f) == 5 && senseCode[7] != 0) {
  268. switch (senseCode[12]) {
  269. case 0xcd:
  270.   message(-2, "Cannot ensure reliable writing with inserted disk.");
  271.   return 1;
  272.   break;
  273. case 0xce:
  274.   message(-2, "Cannot ensure reliable writing at selected speed.");
  275.   return 1;
  276.   break;
  277. case 0xcf:
  278.   message(-2, "Cannot ensure reliable writing - disk has no ID code.");
  279.   return 1;
  280.   break;
  281. }
  282.       }
  283.       scsiIf_->printError();
  284.       return 2;
  285.       break;
  286.     }
  287.   }
  288.   if (simulate()) {
  289.     message(1, "Skipping optimum power calibration in simulation mode.");
  290.     return 0;
  291.   }
  292.   cmd[1] = 0;
  293.   message(1, "Performing optimum power calibration...");
  294.   if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) {
  295.     message(-2, "Optimum power calibration failed.");
  296.     return 2;
  297.   }
  298.   return 0;
  299. }
  300. // Clears the drive's subcode data.
  301. // Return: 0: OK, 1: SCSI error
  302. int TeacCdr55::clearSubcode()
  303. {
  304.   unsigned char cmd[12];
  305.   memset(cmd, 0, 12);
  306.   cmd[0] = 0xe4; // CLEAR SUBCODE
  307.   cmd[5] = 0x80;
  308.   if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) {
  309.     message(-2, "Clear subcode failed.");
  310.     return 1;
  311.   }
  312.   
  313.   return 0;
  314. }
  315. // Sets subcode data.
  316. // start:   start LBA 
  317. // end:     end LBA, one greater than last block with specfied subcode data
  318. // ctl:     track mode flags in bits 4-7
  319. // trackNr: track number
  320. // indexNr: index number
  321. // pflag:   P-channel flag
  322. // return: 0: OK, 1: SCSI error
  323. int TeacCdr55::setSubcode(long start, long end, unsigned char ctl, int trackNr,
  324.   int indexNr, int pflag)
  325. {
  326.   assert(start < end);
  327.   unsigned char cmd[12];
  328.   unsigned char data[4];
  329.   long len = end - start;
  330.   message(3,
  331.   "Setting subcode: start: %6ld, end: %6ld, len: %6ld, CTL: %02x P: %d, T: %2d I: %2d",
  332.   start, end, len, ctl, pflag, trackNr, indexNr);
  333.   memset(cmd, 0, 12);
  334.   cmd[0] = 0xb3; // SET LIMITS
  335.   cmd[2] = start >> 24;
  336.   cmd[3] = start >> 16;
  337.   cmd[4] = start >> 8;
  338.   cmd[5] = start;
  339.   cmd[6] = len >> 24;
  340.   cmd[7] = len >> 16;
  341.   cmd[8] = len >> 8;
  342.   cmd[9] = len;
  343.   if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) {
  344.     message(-2, "Cannot set limits.");
  345.     return 1;
  346.   }
  347.   memset(cmd, 0, 10);
  348.   
  349.   cmd[0] = 0xc2; // SET SUBCODE
  350.   cmd[8] = 4; // parameter list length
  351.   data[0] = pflag != 0 ? 1 : 0;
  352.   data[1] = (ctl & 0xf0) | 0x01;
  353.   data[2] = SubChannel::bcd(trackNr);
  354.   data[3] = SubChannel::bcd(indexNr);
  355.   if (sendCmd(cmd, 10, data, 4, NULL, 0, 1) != 0) {
  356.     message(-2, "Cannot set subcode.");
  357.     return 1;
  358.   }
  359.   
  360.   return 0;
  361. }
  362. // Sets the subcodes for given track.
  363. // track: actual track
  364. // trackNr: number of current track
  365. // start: LBA of track start (index 1), pre-gap length is taken from 'track'
  366. // end:   LBA of track end, same as 'nstart' if next track has no pre-gap
  367. // nstart: LBA of next track start (index 1)
  368. // Return: 0: OK
  369. //         1: SCSI command failed
  370. struct SubCodeData {
  371.   long start; // start LBA
  372.   int index;  // index
  373.   int pflag;  // P channel flag
  374. };
  375. int TeacCdr55::setSubcodes(const Track *track, int trackNr,
  376.    long start, long end, long nstart)
  377. {
  378.   assert(start < end);
  379.   assert(end <= nstart);
  380.   unsigned char ctl = trackCtl(track);
  381.   SubCodeData subCodes[102]; // index 0-99 + P-channel entry + end-entry
  382.   int n = 0;
  383.   int i;
  384.   if (track->start().lba() != 0) {
  385.     // pre-gap
  386.     subCodes[n].start = start - track->start().lba();
  387.     subCodes[n].index = 0;
  388.     subCodes[n].pflag = 1;
  389.     n++;
  390.   }
  391.   // track start (index 1)
  392.   subCodes[n].start = start;
  393.   subCodes[n].index = 1;
  394.   subCodes[n].pflag = 0;
  395.   n++;
  396.   // create index marks
  397.   
  398.   // We have to check if we have to add an entry for the P-channel flag if the
  399.   // pre-gap of the following track is shorter than 2 seconds
  400.   // calculate LBA where P-channel must be set for next track, if
  401.   // it is behind 'end' it'll be ignored
  402.   long pChangeLba = nstart - 150;
  403.   int pChangeEntry = 0; // set to 1 if a P-channel entry was created
  404.   long indexStart;
  405.   for (i = 0; i < track->nofIndices(); i++) {
  406.     indexStart = track->getIndex(i).lba() + start;
  407.     if (indexStart > pChangeLba && pChangeEntry == 0) {
  408.       subCodes[n].start = pChangeLba;
  409.       subCodes[n].index = i + 1;
  410.       subCodes[n].pflag = 1;
  411.       n++;
  412.       pChangeEntry = 1;
  413.     }
  414.     else if (indexStart == pChangeLba) {
  415.       // index increment coincides with p channel change position
  416.       // -> no entry required
  417.       pChangeEntry = 1;
  418.     }
  419.     subCodes[n].start = indexStart;
  420.     subCodes[n].index = i + 2;
  421.     subCodes[n].pflag = indexStart >= pChangeLba ? 1 : 0;
  422.     n++;
  423.   }
  424.   if (pChangeEntry == 0 && pChangeLba < end) {
  425.     subCodes[n].start = pChangeLba;
  426.     subCodes[n].index = i + 1;
  427.     subCodes[n].pflag = 1;
  428.     n++;
  429.   }
  430.   
  431.   // add end of track as last entry
  432.   subCodes[n].start = end;
  433.   subCodes[n].index = 0; // not used
  434.   subCodes[n].pflag = 0; // not used
  435.   assert(n <= 101);
  436.   // now issue the subcode commands
  437.   for (i = 0; i < n; i++) {
  438.     if (setSubcode(subCodes[i].start, subCodes[i+1].start, ctl, trackNr,
  439.    subCodes[i].index, subCodes[i].pflag) != 0) {
  440.       return 1;
  441.     }
  442.   }
  443.   return 0;
  444. }
  445. // Sets sub codes for all tracks.
  446. // Return: 0: OK
  447. //         1: toc contains no track
  448. //         2: SCSI error
  449. int TeacCdr55::setSubcodes()
  450. {
  451.   const Track *t, *nt;
  452.   int trackNr;
  453.   Msf start, end;
  454.   Msf nstart, nend;
  455.   long offset = diskInfo_.thisSessionLba;
  456.   int first = 1;
  457.   TrackIterator itr(toc_);
  458.   trackNr = diskInfo_.lastTrackNr;
  459.   if ((nt = itr.first(nstart, nend)) == NULL) {
  460.     return 1;
  461.   }
  462.   if (clearSubcode() != 0)
  463.     return 2;
  464.   do {
  465.     trackNr += 1;
  466.     t = nt;
  467.     start = nstart;
  468.     end = nend;
  469.     if ((nt = itr.next(nstart, nend)) == NULL)
  470.       nstart = Msf(toc_->length()); // start of lead-out
  471.     if (first) {
  472.       // set sub code for pre-gap of first track
  473.       first = 0;
  474.       if (setSubcode(offset - 150, offset, trackCtl(t), trackNr, 0, 1) != 0)
  475. return 2;
  476.     }
  477.     if (setSubcodes(t, trackNr, start.lba() + offset, end.lba() + offset,
  478.     nstart.lba() + offset) != 0) {
  479.       return 2;
  480.     }
  481.   } while (nt != NULL);
  482.   return 0;
  483. }
  484. // Sets toc data.
  485. // Return: 0: OK
  486. //         1: toc contains no track
  487. //         2: SCSI command failed
  488. int TeacCdr55::setToc()
  489. {
  490.   const Track *t;
  491.   int trackNr;
  492.   Msf start, end;
  493.   long offset = diskInfo_.thisSessionLba + 150; // LBA offset
  494.   int trackOffset = diskInfo_.lastTrackNr + 1;
  495.   unsigned char firstTrackCtl;
  496.   unsigned char lastTrackCtl;
  497.   unsigned char ctl;
  498.   int lastTrackNr = 0;
  499.   int sessFormat;
  500.   unsigned char cmd[10];
  501.   unsigned char data[3 + 102 * 5]; // max. 99 tracks + 3 POINT entries
  502.   unsigned char *p = data + 3;
  503.   data[0] = 0;
  504.   data[1] = 0;
  505.   data[2] = 0;
  506.   TrackIterator itr(toc_);
  507.   for (t = itr.first(start, end), trackNr = trackOffset;
  508.        t != NULL && trackNr <= 99;
  509.        t = itr.next(start, end), trackNr++) {
  510.     Msf s(start.lba() + offset);
  511.     ctl = trackCtl(t);
  512.     if (trackNr == trackOffset)
  513.       firstTrackCtl = ctl;
  514.     p[0] = ctl | 0x01;
  515.     p[1] = SubChannel::bcd(trackNr);
  516.     p[2] = SubChannel::bcd(s.min());
  517.     p[3] = SubChannel::bcd(s.sec());
  518.     p[4] = SubChannel::bcd(s.frac());
  519.     p += 5;
  520.     lastTrackNr = trackNr;
  521.     lastTrackCtl = ctl;
  522.   }
  523.   if (lastTrackNr == 0)
  524.     return 1;
  525.   
  526.   // Point A0 entry (first track nr and session format)
  527.   if (diskInfo_.empty) {
  528.     // disk is empty -> take toc type from toc-file
  529.     sessFormat = sessionFormat();
  530.   }
  531.   else {
  532.     // Disk has already a recorded session -> take toc type from
  533.     // previous session if it is well defined.
  534.     switch (diskInfo_.diskTocType) {
  535.     case 0x00:
  536.     case 0x10:
  537.     case 0x20:
  538.       sessFormat = diskInfo_.diskTocType;
  539.       break;
  540.     default:
  541.       sessFormat = sessionFormat();
  542.       break;
  543.     }
  544.   }
  545.   p[0] = firstTrackCtl | 0x01;
  546.   p[1] = 0xa0;
  547.   p[2] = SubChannel::bcd(trackOffset);
  548.   p[3] = SubChannel::bcd(sessFormat);
  549.   p[4] = 0;
  550.   p += 5;
  551.   // Point A1 entry (last track nr)
  552.   p[0] = lastTrackCtl | 0x01;
  553.   p[1] = 0xa1;
  554.   p[2] = SubChannel::bcd(lastTrackNr);
  555.   p[3] = 0;
  556.   p[4] = 0;
  557.   p += 5;
  558.   
  559.   // Point A2 entry (start of lead-out)
  560.   Msf los(toc_->length().lba() + offset);
  561.   p[0] = lastTrackCtl | 0x01;
  562.   p[1] = 0xa2;
  563.   p[2] = SubChannel::bcd(los.min());
  564.   p[3] = SubChannel::bcd(los.sec());
  565.   p[4] = SubChannel::bcd(los.frac());
  566.   p += 5;
  567.   
  568.   long dataLen = p - data;
  569. #if 1
  570.   message(3, "TOC data:");
  571.   long i;
  572.   for (i = 3; i < dataLen; i += 5) {
  573.     message(3, "%02x %02x %02x:%02x:%02x", 
  574.     data[i], data[i+1], data[i+2], data[i+3], data[i+4]);
  575.   }
  576. #endif
  577.   memset(cmd, 0, 10);
  578.   cmd[0] = 0xc2; // SET SUBCODE
  579.   cmd[7] = dataLen >> 8;
  580.   cmd[8] = dataLen;
  581.   if (sendCmd(cmd, 10, data, dataLen, NULL, 0, 1) != 0) {
  582.     message(-2, "Cannot set TOC data.");
  583.     return 2;
  584.   }
  585.    
  586.   return 0;
  587. }
  588. // Sets catalog number.
  589. // Return: 0: OK
  590. //         1: SCSI command failed
  591. int TeacCdr55::setCatalog()
  592. {
  593.   unsigned char cmd[10];
  594.   unsigned char data[15];
  595.   int i;
  596.   if (!toc_->catalogValid())
  597.     return 0;
  598.   data[0] = 0;
  599.   if (toc_->leadInMode() == TrackData::AUDIO)
  600.     data[1] = 0x02;
  601.   else
  602.     data[1] = 0x42;
  603.   for (i = 0; i < 13; i++)
  604.     data[2 + i] = toc_->catalog(i);
  605.   memset(cmd, 0, 10);
  606.   cmd[0] = 0xc2; // SET SUBCODE
  607.   cmd[8] = 15;
  608.   if (sendCmd(cmd, 10, data, 15, NULL, 0, 1) != 0) {
  609.     message(-2, "Cannot set catalog number data.");
  610.     return 2;
  611.   }
  612.   return 0;
  613. }
  614. // Sets ISRC codes for all tracks
  615. int TeacCdr55::setIsrc()
  616. {
  617.   const Track *t;
  618.   int trackNr;
  619.   Msf start, end;
  620.   int trackOffset = diskInfo_.lastTrackNr + 1;
  621.   unsigned char cmd[10];
  622.   unsigned char data[15];
  623.   data[0] = 0;
  624.   memset(cmd, 0, 10);
  625.   cmd[0] = 0xc2; // SET SUBCODE
  626.   cmd[8] = 15;
  627.   TrackIterator itr(toc_);
  628.   for (t = itr.first(start, end), trackNr = trackOffset;
  629.        t != NULL && trackNr <= 99;
  630.        t = itr.next(start, end), trackNr++) {
  631.     if (t->isrcValid()) {
  632.       data[1] = trackCtl(t) | 0x03;
  633.       data[2] = t->isrcCountry(0);
  634.       data[3] = t->isrcCountry(1);
  635.       data[4] = t->isrcOwner(0);
  636.       data[5] = t->isrcOwner(1);
  637.       data[6] = t->isrcOwner(2);
  638.       data[7] = t->isrcYear(0) + '0';
  639.       data[8] = t->isrcYear(1) + '0';
  640.       data[9] = t->isrcSerial(0) + '0';
  641.       data[10] = t->isrcSerial(1) + '0';
  642.       data[11] = t->isrcSerial(2) + '0';
  643.       data[12] = t->isrcSerial(3) + '0';
  644.       data[13] = t->isrcSerial(4) + '0';
  645.       data[14] = 0;
  646.       cmd[6] = trackNr;
  647.       if (sendCmd(cmd, 10, data, 15, NULL, 0, 1) != 0) {
  648. message(-2, "Cannot set ISRC code.");
  649. return 2;
  650.       }
  651.     }
  652.   }
  653.   return 0;
  654. }
  655. // Need to overload this function to set the WriteExtension flag. It'll
  656. // also change the write density if the actual mode changes.
  657. int TeacCdr55::writeData(TrackData::Mode mode, long &lba, const char *buf,
  658.  long len)
  659. {
  660.   assert(blocksPerWrite_ > 0);
  661.   int writeLen = 0;
  662.   unsigned char cmd[10];
  663.   long blockLength = blockSize(mode);
  664.   
  665. #if 0
  666.   long sum, i;
  667.   sum = 0;
  668.   for (i = 0; i < len * blockLength; i++) {
  669.     sum += buf[i];
  670.   }
  671.   message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum);
  672. #endif
  673.   if (mode != actMode_) {
  674.     actMode_ = mode;
  675.     message(2, "Changed write density at LBA %ld.", lba);
  676.     if (setWriteDensity(actMode_) != 0) {
  677.       return 1;
  678.     }
  679.   }
  680.   memset(cmd, 0, 10);
  681.   cmd[0] = 0x2a; // WRITE10
  682.   
  683.   while (len > 0) {
  684.     writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len);
  685.     cmd[2] = lba >> 24;
  686.     cmd[3] = lba >> 16;
  687.     cmd[4] = lba >> 8;
  688.     cmd[5] = lba;
  689.     cmd[7] = writeLen >> 8;
  690.     cmd[8] = writeLen & 0xff;
  691.     if (lba + writeLen >= writeEndLba_) {
  692.       // last write command
  693.       message(3, "Last write command at LBA: %ld", lba);
  694.       cmd[9] = 0;
  695.     }
  696.     else {
  697.       cmd[9] = 0x80; // extended write
  698.     }
  699.     if (sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength,
  700. NULL, 0) != 0) {
  701.       message(-2, "Write data failed.");
  702.       return 1;
  703.     }
  704.     buf += writeLen * blockLength;
  705.     lba += writeLen;
  706.     len -= writeLen;
  707.   }
  708.       
  709.   return 0;
  710. }
  711. int TeacCdr55::initDao(const Toc *toc)
  712. {
  713.   long offset; // LBA offset for this session
  714.   long n;
  715.   
  716.   toc_ = toc;
  717.   blockLength_ = AUDIO_BLOCK_LEN;
  718.   blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_;
  719.   assert(blocksPerWrite_ > 0);
  720.   diskInfo();
  721.   if (!diskInfo_.valid.empty || !diskInfo_.valid.append) {
  722.     message(-2, "Cannot determine status of inserted medium.");
  723.     return 1;
  724.   }
  725.   if (!diskInfo_.append) {
  726.     message(-2, "Inserted medium is not appendable.");
  727.     return 1;
  728.   }
  729.   offset = diskInfo_.thisSessionLba;
  730.   // allocate buffer for writing zeros
  731.   n = blocksPerWrite_ * blockLength_;
  732.   delete[] zeroBuffer_;
  733.   zeroBuffer_ = new char[n];
  734.   memset(zeroBuffer_, 0, n);
  735.   writeEndLba_ = toc_->length().lba() + offset;
  736.   actMode_ = toc_->leadInMode();
  737.   
  738.   if (getModeSelectData() != 0 ||
  739.       setWriteDensity(actMode_) != 0 ||
  740.       setSimulationMode() != 0 ||
  741.       setWriteParameters() != 0 ||
  742.       setWriteSpeed() != 0) {
  743.     return 1;
  744.   }
  745.   return 0;
  746. }
  747. int TeacCdr55::startDao()
  748. {
  749.   scsiTimeout_ = scsiIf_->timeout(3 * 60);
  750.   if (executeOPC(1) != 0 ||
  751.       setSubcodes() != 0 ||
  752.       setCatalog() != 0 ||
  753.       setToc() != 0 ||
  754.       setIsrc() != 0) {
  755.     return 1;
  756.   }
  757.   long lba = diskInfo_.thisSessionLba - 150;
  758.   if (writeZeros(actMode_, lba, lba + 150, 150) != 0) {
  759.     return 1;
  760.   }
  761.   
  762.   return 0;
  763. }
  764. int TeacCdr55::finishDao()
  765. {
  766.   //message(0, "Writing lead-out...");
  767.   // wait until writing of lead-out is finished ???
  768.   scsiIf_->timeout(scsiTimeout_);
  769.   delete[] zeroBuffer_, zeroBuffer_ = NULL;
  770.   return 0;
  771. }
  772. void TeacCdr55::abortDao()
  773. {
  774.   unsigned char cmd[10];
  775.   // Send a zero length write command with cleared extendened write bit.
  776.   // I don't know if it has the expected effect.
  777.   memset(cmd, 0, 10);
  778.   cmd[0] = 0x2a; // WRITE10
  779.   sendCmd(cmd, 10, NULL, 0, NULL, 0, 0);
  780. }
  781. DiskInfo *TeacCdr55::diskInfo()
  782. {
  783.   int i;
  784.   unsigned char cmd[12];
  785.   unsigned char data[12];
  786.   memset(&diskInfo_, 0, sizeof(DiskInfo));
  787.   diskInfo_.cdrw = 0;
  788.   diskInfo_.valid.cdrw = 1;
  789.   memset(cmd, 0, 10);
  790.   memset(data, 0, 8);
  791.   cmd[0] = 0x25; // READ CAPACITY
  792.   cmd[9] = 0x80;
  793.   if (sendCmd(cmd, 10, NULL, 0, data, 8, 1) != 0) {
  794.     message(-1, "Cannot read CD-R capacity.");
  795.   }
  796.   else {
  797.     diskInfo_.capacity = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) |
  798.                         data[3];
  799.     diskInfo_.valid.capacity = 1;
  800.   }
  801.   memset(cmd, 0, 12);
  802.   memset(data, 0, 4);
  803.   cmd[0] = 0xe6; // NEXT WRITABLE ADDRESS
  804.   cmd[2] = 0xff;
  805.   cmd[3] = 0xff;
  806.   cmd[4] = 0xff;
  807.   cmd[5] = 0xff;
  808.   cmd[6] = 0xff;
  809.   cmd[7] = 0xff;
  810.   cmd[8] = 0xff;
  811.   cmd[9] = 0xff;
  812.   long nwa = 0;
  813.   switch (sendCmd(cmd, 12, NULL, 0, data, 4, 0)) {
  814.   case 0: // command succeed -> writable area exists
  815.     diskInfo_.empty = 1;
  816.     diskInfo_.valid.empty = 1;
  817.     nwa = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
  818.     message(3, "Next writable address: %ld", nwa);
  819.     break;
  820.   case 1: // SCSI command failed, no sense data -> cannot tell anything
  821.     message(-1, "Get next writable address failed.");
  822.     break;
  823.   case 2: // SCSI command failed, sense data available
  824.     // assume that disk is not writable
  825.     message(3, "Cannot get next writable address.");
  826.     diskInfo_.empty = 0;
  827.     diskInfo_.valid.empty = 1;
  828.     break;
  829.   }
  830.   // SCSI command failed -> stop further processing
  831.   if (diskInfo_.valid.empty == 0)
  832.     return &diskInfo_;
  833.   memset(cmd, 0, 10);
  834.   memset(data, 0, 4);
  835.   cmd[0] = 0x43; // READ TOC
  836.   cmd[6] = 1;
  837.   cmd[8] = 4;
  838.   if (sendCmd(cmd, 10, NULL, 0, data, 4, 0) == 0) {
  839.     message(3, "First track %u, last track %u", data[2], data[3]);
  840.     diskInfo_.lastTrackNr = data[3];
  841.   }
  842.   else {
  843.     message(3, "READ TOC (format 0) failed.");
  844.   }
  845.   if (diskInfo_.lastTrackNr > 0) {
  846.     diskInfo_.empty = 0;
  847.     diskInfo_.diskTocType = 0xff; // undefined
  848.     memset(cmd, 0, 10);
  849.     memset(data, 0, 12);
  850.     cmd[0] = 0x43; // READ TOC
  851.     cmd[6] = 0;
  852.     cmd[8] = 12;
  853.     cmd[9] = 1 << 6;
  854.     if (sendCmd(cmd, 10, NULL, 0, data, 12) == 0) {
  855.       diskInfo_.sessionCnt = data[3];
  856.       diskInfo_.lastSessionLba = (data[8] << 24) | (data[9] << 16) |
  857.                                  (data[10] << 8) | data[11];
  858.       message(3, "First session %u, last session %u, last session start %ld",
  859.       data[2], data[3], diskInfo_.lastSessionLba);
  860.     }
  861.     else {
  862.       message(3, "READ TOC (format 1) failed.");
  863.     }
  864.     if (diskInfo_.sessionCnt > 0) {
  865.       int len;
  866.       CdRawToc *toc = getRawToc(diskInfo_.sessionCnt, &len);
  867.       if (toc != NULL) {
  868. for (i = 0; i < len; i++) {
  869.   if (toc[i].sessionNr == diskInfo_.sessionCnt) {
  870.     if (toc[i].point == 0xb0 && toc[i].min != 0xff &&
  871. toc[i].sec != 0xff && toc[i].frame != 0xff) {
  872.       int m = SubChannel::bcd2int(toc[i].min);
  873.       int s = SubChannel::bcd2int(toc[i].sec);
  874.       int f = SubChannel::bcd2int(toc[i].frame);
  875.       
  876.       if (m < 90 && s < 60 && f < 75) 
  877. diskInfo_.thisSessionLba = Msf(m, s, f).lba(); // + 150 - 150
  878.     }
  879.     if (toc[i].point == 0xa0) {
  880.       diskInfo_.diskTocType = SubChannel::bcd2int(toc[i].psec);
  881.     }
  882.   }
  883. }
  884. if (diskInfo_.thisSessionLba > 0) {
  885.   if (diskInfo_.lastTrackNr < 99)
  886.     diskInfo_.append = 1;
  887. }
  888. else {
  889.   message(3, "Did not find BO pointer in session %d.",
  890.   diskInfo_.sessionCnt);
  891. }
  892. delete[] toc;
  893.       }
  894.       else {
  895. message(3, "getRawToc failed.");
  896.       }
  897.     }
  898.   }
  899.   else {
  900.     // disk is empty and appendable
  901.     diskInfo_.empty = 1;
  902.     diskInfo_.append = 1;
  903.   }
  904.   diskInfo_.valid.append = 1;
  905.   return &diskInfo_;
  906. }
  907. // tries to read catalog number from disk and adds it to 'toc'
  908. // return: 1 if valid catalog number was found, else 0
  909. int TeacCdr55::readCatalog(Toc *toc, long startLba, long endLba)
  910. {
  911.   unsigned char cmd[10];
  912.   unsigned char data[24];
  913.   char catalog[14];
  914.   int i;
  915.   memset(cmd, 0, 10);
  916.   memset(data, 0, 24);
  917.   cmd[0] = 0x42; // READ SUB-CHANNEL
  918.   cmd[2] = 1 << 6;
  919.   cmd[3] = 0x02; // get media catalog number
  920.   cmd[8] = 24;   // transfer length
  921.   if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
  922.     message(-2, "Cannot get catalog number.");
  923.     return 0;
  924.   }
  925.   if (data[8] & 0x80) {
  926.     for (i = 0; i < 13; i++) {
  927.       catalog[i] = data[0x09 + i];
  928.     }
  929.     catalog[13] = 0;
  930.     if (toc->catalog(catalog) == 0) {
  931.       return 1;
  932.     }
  933.   }
  934.   return 0;
  935. }
  936. int TeacCdr55::readIsrc(int trackNr, char *buf)
  937. {
  938.   unsigned char cmd[10];
  939.   unsigned char data[24];
  940.   int i;
  941.   buf[0] = 0;
  942.   memset(cmd, 0, 10);
  943.   memset(data, 0, 24);
  944.   cmd[0] = 0x42; // READ SUB-CHANNEL
  945.   cmd[2] = 1 << 6;
  946.   cmd[3] = 0x03; // get media catalog number
  947.   cmd[6] = trackNr;
  948.   cmd[8] = 24;   // transfer length
  949.   if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
  950.     message(-2, "Cannot get ISRC code.");
  951.     return 0;
  952.   }
  953.   if (data[8] & 0x80) {
  954.     for (i = 0; i < 12; i++) {
  955.       buf[i] = data[0x09 + i];
  956.     }
  957.     buf[12] = 0;
  958.   }
  959.   return 0;
  960. }
  961. int TeacCdr55::analyzeTrack(TrackData::Mode mode, int trackNr,
  962.     long startLba,
  963.     long endLba, Msf *indexIncrements,
  964.     int *indexIncrementCnt, long *pregap,
  965.     char *isrcCode, unsigned char *ctl)
  966. {
  967.   int ret = analyzeTrackScan(mode, trackNr, startLba, endLba,
  968.      indexIncrements, indexIncrementCnt, pregap,
  969.      isrcCode, ctl);
  970.   if (mode == TrackData::AUDIO)
  971.     readIsrc(trackNr, isrcCode);
  972.   else
  973.     *isrcCode = 0;
  974.   return ret;
  975. }
  976. int TeacCdr55::readSubChannels(long lba, long len, SubChannel ***chans,
  977.        Sample *audioData)
  978. {
  979.   int retries = 5;
  980.   unsigned char cmd[12];
  981.   int i;
  982.   cmd[0] = 0xd8;  // READ CD_DA
  983.   cmd[1] = 0;
  984.   cmd[2] = lba >> 24;
  985.   cmd[3] = lba >> 16;
  986.   cmd[4] = lba >> 8;
  987.   cmd[5] = lba;
  988.   cmd[6] = len >> 24;
  989.   cmd[7] = len >> 16;
  990.   cmd[8] = len >> 8;
  991.   cmd[9] = len;
  992.   cmd[10] = 0x01;  // Q sub-channel data
  993.   cmd[11] = 0;
  994.   while (1) {
  995.     if (sendCmd(cmd, 12, NULL, 0,
  996. transferBuffer_, len * (AUDIO_BLOCK_LEN + 16),
  997. retries == 0 ? 1 : 0) != 0) {
  998.       if (retries == 0) 
  999. return 1;
  1000.     }
  1001.     else {
  1002.       break;
  1003.     }
  1004.     retries--;
  1005.   }
  1006.   for (i = 0; i < len; i++) {
  1007.     PQSubChannel16 *chan = (PQSubChannel16*)scannedSubChannels_[i];
  1008.     unsigned char *p =
  1009.       transferBuffer_  + i * (AUDIO_BLOCK_LEN + 16) + AUDIO_BLOCK_LEN;
  1010.     // slightly reorder the sub-channel so it is suitable for 'PQSubChannel16'
  1011.     p[0] <<= 4;   // ctl/adr
  1012.     p[0] |= p[1];
  1013.     p[1] = p[2];  // track nr
  1014.     p[2] = p[3];  // index nr
  1015.     p[3] = p[4];  // min
  1016.     p[4] = p[5];  // sec
  1017.     p[5] = p[6];  // frame
  1018.     p[6] = 0;     // zero
  1019.     // p[7] is amin
  1020.     // p[8] is asec
  1021.     // p[9] is aframe
  1022.     
  1023.     chan->init(p);
  1024.     
  1025.     if (chan->checkConsistency())
  1026.       chan->calcCrc();
  1027.   }
  1028.   if (audioData != NULL) {
  1029.     unsigned char *p = transferBuffer_;
  1030.     for (i = 0; i < len; i++) {
  1031.       memcpy(audioData, p, AUDIO_BLOCK_LEN);
  1032.       p += AUDIO_BLOCK_LEN + 16;
  1033.       audioData += SAMPLES_PER_BLOCK;
  1034.     }
  1035.   }
  1036.   *chans = scannedSubChannels_;
  1037.   return 0;
  1038. }
  1039. CdRawToc *TeacCdr55::getRawToc(int sessionNr, int *len)
  1040. {
  1041.   unsigned char cmd[10];
  1042.   unsigned short dataLen;
  1043.   unsigned char *data = NULL;;
  1044.   unsigned char reqData[4]; // buffer for requestion the actual length
  1045.   unsigned char *p = NULL;
  1046.   int i, entries;
  1047.   CdRawToc *rawToc;
  1048.   
  1049.   assert(sessionNr >= 1);
  1050.   // read disk toc length
  1051.   memset(cmd, 0, 10);
  1052.   cmd[0] = 0x43; // READ TOC
  1053.   cmd[6] = sessionNr;
  1054.   cmd[8] = 4;
  1055.   cmd[9] |= 2 << 6; // get Q subcodes
  1056.   if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) {
  1057.     message(-2, "Cannot read raw disk toc.");
  1058.     return NULL;
  1059.   }
  1060.   dataLen = ((reqData[0] << 8) | reqData[1]) + 2;
  1061.   message(3, "Raw toc data len: %d", dataLen);
  1062.   if (dataLen == 4)
  1063.     return NULL;
  1064.   data = new (unsigned char)[dataLen];
  1065.   
  1066.   // read disk toc
  1067.   cmd[7] = dataLen >> 8;
  1068.   cmd[8] = dataLen;
  1069.   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
  1070.     message(-2, "Cannot read raw disk toc.");
  1071.     delete[] data;
  1072.     return NULL;
  1073.   }
  1074.   entries = (((data[0] << 8) | data[1]) - 2) / 11;
  1075.   rawToc = new CdRawToc[entries];
  1076.   for (i = 0, p = data + 4; i < entries; i++, p += 11 ) {
  1077. #if 0
  1078.     message(0, "%d %02x %02d %2x %02x:%02x:%02x %02x %02x:%02x:%02x",
  1079.     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]);
  1080. #endif
  1081.     rawToc[i].sessionNr = p[0];
  1082.     rawToc[i].adrCtl = p[1];
  1083.     rawToc[i].point = p[3];
  1084.     rawToc[i].min = p[4];
  1085.     rawToc[i].sec = p[5];
  1086.     rawToc[i].frame = p[6];
  1087.     rawToc[i].pmin = p[8];
  1088.     rawToc[i].psec = p[9];
  1089.     rawToc[i].pframe = p[10];
  1090.   }
  1091.   delete[] data;
  1092.   *len = entries;
  1093.   return rawToc;
  1094. }
  1095. long TeacCdr55::readTrackData(TrackData::Mode mode, long lba, long len,
  1096.       unsigned char *buf)
  1097. {
  1098.   unsigned char cmd[10];
  1099.   long blockLen = 2340;
  1100.   long i;
  1101.   TrackData::Mode actMode;
  1102.   int ok = 0;
  1103.   int softError;
  1104.   const unsigned char *sense;
  1105.   int senseLen;
  1106.   if (setBlockSize(blockLen) != 0)
  1107.     return 0;
  1108.   memset(cmd, 0, 10);
  1109.   cmd[0] = 0x28; // READ10
  1110.   cmd[2] = lba >> 24;
  1111.   cmd[3] = lba >> 16;
  1112.   cmd[4] = lba >> 8;
  1113.   cmd[5] = lba;
  1114.   while (len > 0 && !ok) {
  1115.     cmd[7] = len >> 8;
  1116.     cmd[8] = len;
  1117.     memset(transferBuffer_, 0, len * blockLen);
  1118.     switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) {
  1119.     case 0:
  1120.       ok = 1;
  1121.       break;
  1122.     case 2:
  1123.       softError = 0;
  1124.       sense = scsiIf_->getSense(senseLen);
  1125.       if (senseLen > 0x0c) {
  1126. if ((sense[2] &0x0f) == 5) {
  1127.   switch (sense[12]) {
  1128.   case 0x63: // end of user area encountered on this track
  1129.   case 0x64: // Illegal mode for this track
  1130.     softError = 1;
  1131.     break;
  1132.   }
  1133. }
  1134. else if ((sense[2] & 0x0f) == 3) { // Medium error
  1135.   switch (sense[12]) {
  1136.   case 0x02: // No seek complete, sector not found
  1137.   case 0x11: // L-EC error
  1138.     return -2;
  1139.     break;
  1140.   }
  1141. }
  1142.       }
  1143.       if (!softError) {
  1144. scsiIf_->printError();
  1145. return -1;
  1146.       }
  1147.       break;
  1148.     default:
  1149.       message(-2, "Read error at LBA %ld, len %ld", lba, len);
  1150.       return -1;
  1151.       break;
  1152.     }
  1153.     if (!ok) {
  1154.       len--;
  1155.     }
  1156.   }
  1157.   unsigned char *sector = transferBuffer_;
  1158.   for (i = 0; i < len; i++) {
  1159.     actMode = determineSectorMode(sector);
  1160.     if (!(actMode == mode ||
  1161.   (mode == TrackData::MODE2_FORM_MIX &&
  1162.    (actMode == TrackData::MODE2_FORM1 ||
  1163.     actMode == TrackData::MODE2_FORM2)) ||
  1164.   (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) ||
  1165.   (mode == TrackData::MODE2_RAW &&
  1166.    (actMode == TrackData::MODE2 ||
  1167.     actMode == TrackData::MODE2_FORM1 ||
  1168.     actMode == TrackData::MODE2_FORM2)))) {
  1169.       return i;
  1170.     }
  1171.     if (buf != NULL) {
  1172.       switch (mode) {
  1173.       case TrackData::MODE1:
  1174. memcpy(buf, sector + 4, MODE1_BLOCK_LEN);
  1175. buf += MODE1_BLOCK_LEN;
  1176. break;
  1177.       case TrackData::MODE2:
  1178.       case TrackData::MODE2_FORM_MIX:
  1179. memcpy(buf, sector + 4, MODE2_BLOCK_LEN);
  1180. buf += MODE2_BLOCK_LEN;
  1181. break;
  1182.       case TrackData::MODE2_FORM1:
  1183. memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN);
  1184. buf += MODE2_FORM1_DATA_LEN;
  1185. break;
  1186.       case TrackData::MODE2_FORM2:
  1187. memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN);
  1188. buf += MODE2_FORM2_DATA_LEN;
  1189. break;
  1190.       case TrackData::MODE1_RAW:
  1191.       case TrackData::MODE2_RAW:
  1192. memcpy(buf, syncPattern, 12);
  1193. memcpy(buf + 12, sector, 2340);
  1194. buf += AUDIO_BLOCK_LEN;
  1195. break;
  1196.       case TrackData::MODE0:
  1197.       case TrackData::AUDIO:
  1198. message(-3, "TeacCdr55::readTrackData: Illegal mode.");
  1199. return 0;
  1200. break;
  1201.       }
  1202.     }
  1203.     sector += blockLen;
  1204.   }  
  1205.   return len;
  1206. }
  1207. Toc *TeacCdr55::readDiskToc(int session, const char *audioFilename)
  1208. {
  1209.   Toc *toc = CdrDriver::readDiskToc(session, audioFilename);
  1210.   setBlockSize(MODE1_BLOCK_LEN);
  1211.   
  1212.   return toc;
  1213. }
  1214. Toc *TeacCdr55::readDisk(int session, const char *fname)
  1215. {
  1216.   Toc *toc = CdrDriver::readDisk(session, fname);
  1217.   setBlockSize(MODE1_BLOCK_LEN);
  1218.   return toc;
  1219. }
  1220. int TeacCdr55::readAudioRange(int fd, long start, long end, int startTrack,
  1221.       int endTrack, TrackInfo *info)
  1222. {
  1223.   if (!onTheFly_) {
  1224.     int t;
  1225.     message(1, "Analyzing...");
  1226.     
  1227.     for (t = startTrack; t <= endTrack; t++) {
  1228.       message(1, "Track %d...", t + 1);
  1229.       info[t].isrcCode[0] = 0;
  1230.       readIsrc(t + 1, info[t].isrcCode);
  1231.       if (info[t].isrcCode[0] != 0)
  1232. message(1, "Found ISRC code.");
  1233.     }
  1234.     message(1, "Reading...");
  1235.   }
  1236.   return CdrDriver::readAudioRangeParanoia(fd, start, end, startTrack,
  1237.    endTrack, info);
  1238. }