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

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*  cdrdao - write audio CD-Rs in disc-at-once mode
  2.  *
  3.  *  Copyright (C) 1998  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: PlextorReader.cc,v $
  21.  * Revision 1.9  1999/04/05 18:48:37  mueller
  22.  * Added driver options.
  23.  * Added read-cd patch from Leon Woestenberg.
  24.  *
  25.  * Revision 1.8  1999/03/27 20:56:39  mueller
  26.  * Changed toc analysis interface.
  27.  * Added support for toc analysis of data disks.
  28.  *
  29.  * Revision 1.7  1998/09/27 19:20:05  mueller
  30.  * Added retrieval of control nibbles for track with 'analyzeTrack()'.
  31.  *
  32.  * Revision 1.6  1998/09/08 11:54:22  mueller
  33.  * Extended disk info structure because CDD2000 does not support the
  34.  * 'READ DISK INFO' command.
  35.  *
  36.  * Revision 1.5  1998/09/07 15:20:20  mueller
  37.  * Reorganized read-toc related code.
  38.  *
  39.  * Revision 1.4  1998/09/06 13:34:22  mueller
  40.  * Use 'message()' for printing messages.
  41.  *
  42.  * Revision 1.3  1998/08/30 19:25:43  mueller
  43.  * Added function 'diskInfo()'.
  44.  * Changed sub channel data field in 'readSubChannelData()' to be more
  45.  * compatible to other drives.
  46.  *
  47.  * Revision 1.2  1998/08/25 19:26:07  mueller
  48.  * Moved basic index extraction algorithm to class 'CdrDriver'.
  49.  *
  50.  */
  51. static char rcsid[] = "$Id: PlextorReader.cc,v 1.9 1999/04/05 18:48:37 mueller Exp mueller $";
  52. #include <config.h>
  53. #include <unistd.h>
  54. #include <string.h>
  55. #include <assert.h>
  56. #include <errno.h>
  57. #include "PlextorReader.h"
  58. #include "Toc.h"
  59. #include "util.h"
  60. #include "PWSubChannel96.h"
  61. PlextorReader::PlextorReader(ScsiIf *scsiIf, unsigned long options)
  62.   : CdrDriver(scsiIf, options)
  63. {
  64.   driverName_ = "Plextor CD-ROM Reader - Version 1.1";
  65.   
  66.   speed_ = 0;
  67.   simulate_ = 0;
  68.   audioDataByteOrder_ = 0;
  69.   memset(&diskInfo_, 0, sizeof(DiskInfo));
  70.   diskInfo_.valid.empty = 1;
  71.   {
  72.     struct
  73.     {   
  74.       int number;
  75.       char *productid; // as obtained through INQUIRY
  76.     } models[] =
  77.       {
  78.       { 1,"CD-ROM PX-4XCH" },
  79.       { 2,"CD-ROM PX-4XCS" },
  80.       { 3,"CD-ROM PX-4XCE" },
  81.       { 4,"CD-ROM PX-6X" },
  82.       { 5,"CD-ROM PX-8X" },
  83.       { 6,"CD-ROM PX-12" },
  84.       { 7,"CD-ROM PX-20" },
  85.       { 8,"CD-ROM PX-32" },
  86.       { 9,"CD-ROM PX-40" },
  87.       { 0,NULL }
  88.     };
  89.     int m = 0;
  90.     while (models[m].number)
  91.     {
  92.       if (strncmp(scsiIf_->product(), models[m].productid,
  93.   strlen(models[m].productid)) == 0)
  94.         break;
  95.       else
  96.         m++;
  97.     }
  98.     model_ = models[m].number; // zero if not found
  99.     message(3, "model number %dn",model_);
  100.     message(3, "PRODUCT ID: '%s'n", scsiIf_->product());
  101.   }
  102. }
  103. // static constructor
  104. CdrDriver *PlextorReader::instance(ScsiIf *scsiIf, unsigned long options)
  105. {
  106.   return new PlextorReader(scsiIf, options);
  107. }
  108. // sets speed
  109. // return: 0: OK
  110. //         1: illegal speed (n/a; the strategy is to map to a valid speed)
  111. int PlextorReader::speed(int speed)
  112. {
  113.   unsigned short dataLen = 56;
  114.   unsigned char data[56];
  115.   char speedvalue=0;
  116.   if (model_ == 0) // not a Plextor device
  117.     return 0;
  118.   switch (model_) {
  119.   case 4:
  120.     speedvalue = (speed-1)/2;
  121.     break;
  122.   default:
  123.     speedvalue = speed/2;
  124.     break;
  125.   }
  126.   
  127.   getModePage6((long)0x31,data,dataLen,NULL,NULL,1);
  128.   //message(0,"page code %0xn",data[0]);
  129.   //message(0,"speed value was %dn",data[2]);
  130.   data[2]=speedvalue;
  131.   //message(0,"new speedvalue %dn",speedvalue);    
  132.   setModePage6(data,NULL,NULL,1);
  133.   return 0;  
  134. }
  135. DiskInfo *PlextorReader::diskInfo()
  136. {
  137.   return &diskInfo_;
  138. }
  139. int PlextorReader::initDao(const Toc *toc)
  140. {
  141.   message(-2, "Writing is not supported by this driver.");
  142.   return 1;
  143. }
  144. int PlextorReader::startDao()
  145. {
  146.   return 1;
  147. }
  148. int PlextorReader::finishDao()
  149. {
  150.   return 1;
  151. }
  152. void PlextorReader::abortDao()
  153. {
  154. }
  155. // tries to read catalog number from disk and adds it to 'toc'
  156. // return: 1 if valid catalog number was found, else 0
  157. int PlextorReader::readCatalog(Toc *toc, long startLba, long endLba)
  158. {
  159.   unsigned char cmd[10];
  160.   unsigned short dataLen = 0x30;
  161.   unsigned char data[0x30];
  162.   char catalog[14];
  163.   int i;
  164.   // read sub channel information
  165.   memset(cmd, 0, 10);
  166.   cmd[0] = 0x42; // READ SUB CHANNEL
  167.   cmd[2] = 0x40; // get sub channel data
  168.   cmd[3] = 0x02; // get media catalog number
  169.   cmd[7] = dataLen >> 8;
  170.   cmd[8] = dataLen;
  171.   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
  172.     message(-2, "Cannot read sub channel data.");
  173.     return 0;
  174.   }
  175.   if (data[0x08] & 0x80) {
  176.     for (i = 0; i < 13; i++) {
  177.       catalog[i] = data[0x09 + i];
  178.     }
  179.     catalog[13] = 0;
  180.     if (toc->catalog(catalog) == 0) {
  181.       return 1;
  182.     }
  183.   }
  184.   return 0;
  185. }
  186. // plays one audio block starting from given position
  187. void PlextorReader::playAudioBlock(long start, long len)
  188. {
  189.   unsigned char cmd[10];
  190.   // play one audio block
  191.   memset(cmd, 0, 10);
  192.   cmd[0] = 0x45; // PLAY AUDIO
  193.   cmd[2] = start >> 24;
  194.   cmd[3] = start >> 16;
  195.   cmd[4] = start >> 8;
  196.   cmd[5] = start;
  197.   cmd[7] = len >> 8;
  198.   cmd[8] = len;
  199.   if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) {
  200.     message(-2, "Cannot play audio block.");
  201.     return;
  202.   }
  203. }
  204. int PlextorReader::analyzeTrack(TrackData::Mode mode, int trackNr,
  205. long startLba, long endLba,
  206. Msf *index, int *indexCnt, long *pregap,
  207. char *isrcCode, unsigned char *ctl)
  208. {
  209.   int ret = analyzeTrackSearch(mode, trackNr, startLba, endLba,
  210.        index, indexCnt, pregap, isrcCode, ctl);
  211.   if (mode == TrackData::AUDIO)
  212.     readIsrc(trackNr, isrcCode);
  213.   else
  214.     *isrcCode = 0;
  215.   return ret;
  216. }
  217. // tries to read ISRC code of given track number and stores it in
  218. // given buffer.
  219. // return: 1 if valid ISRC code was found, else 0
  220. int PlextorReader::readIsrc(int trackNr, char *buf)
  221. {
  222.   unsigned char cmd[10];
  223.   unsigned short dataLen = 0x30;
  224.   unsigned char data[0x30];
  225.   int i;
  226.   // time to finish the last audio play operation
  227.   sleep(1);
  228.   buf[0] = 0;
  229.   // read sub channel information
  230.   memset(cmd, 0, 10);
  231.   cmd[0] = 0x42; // READ SUB CHANNEL
  232.   cmd[2] = 0x40; // get sub channel data
  233.   cmd[3] = 0x03; // get ISRC code
  234.   cmd[6] = trackNr;
  235.   cmd[7] = dataLen >> 8;
  236.   cmd[8] = dataLen;
  237.   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
  238.     message(-1, "Cannot read ISRC code.");
  239.     return 0;
  240.   }
  241.   if (data[0x08] & 0x80) {
  242.     for (i = 0; i < 12; i++) {
  243.       buf[i] = data[0x09 + i];
  244.     }
  245.     buf[12] = 0;
  246.   }
  247.   return 0;
  248. }
  249. // Reads actual track number, index and relative position from sub channel.
  250. // return: 0 OK, 1: SCSI command failed
  251. int PlextorReader::readSubChannelData(int *trackNr, int *indexNr,
  252.       long *relPos, unsigned char *ctl)
  253. {
  254.   unsigned char cmd[10];
  255.   unsigned short dataLen = 0x30;
  256.   unsigned char data[0x30];
  257.   // read sub channel information
  258.   memset(cmd, 0, 10);
  259.   cmd[0] = 0x42; // READ SUB CHANNEL
  260.   cmd[2] = 0x40; // get sub channel data
  261.   cmd[3] = 0x01; // get sub Q channel data
  262.   cmd[6] = 0;
  263.   cmd[7] = dataLen >> 8;
  264.   cmd[8] = dataLen;
  265.   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
  266.     message(-2, "Cannot read sub Q channel data.");
  267.   }
  268.   *trackNr = data[6];
  269.   *indexNr = data[7];
  270.   *relPos = 0;
  271.   *relPos |= data[0x0c] << 24;
  272.   *relPos |= data[0x0d] << 16;
  273.   *relPos |= data[0x0e] << 8;
  274.   *relPos |= data[0x0f];
  275.   
  276.   if (ctl != NULL) {
  277.     *ctl = data[5] & 0x0f;
  278.   }
  279.   return 0;
  280. }
  281. // Retrieves track and index at given block address 'lba'.
  282. // Return: 0: OK, 1: SCSI command failed
  283. int PlextorReader::getTrackIndex(long lba, int *trackNr, int *indexNr,
  284.  unsigned char *ctl)
  285. {
  286.   long relPos;
  287.   playAudioBlock(lba, 1);
  288.   return readSubChannelData(trackNr, indexNr, &relPos, ctl);
  289. }
  290. CdRawToc *PlextorReader::getRawToc(int sessionNr, int *len)
  291. {
  292.   unsigned char cmd[10];
  293.   unsigned short dataLen;
  294.   unsigned char *data = NULL;;
  295.   unsigned char reqData[4]; // buffer for requestion the actual length
  296.   unsigned char *p = NULL;
  297.   int i, entries;
  298.   CdRawToc *rawToc;
  299.   
  300.   assert(sessionNr >= 1);
  301.   // read disk toc length
  302.   memset(cmd, 0, 10);
  303.   cmd[0] = 0x43; // READ TOC
  304.   cmd[6] = sessionNr;
  305.   cmd[8] = 4;
  306.   cmd[9] |= 2 << 6; // get Q subcodes
  307.   if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) {
  308.     message(-2, "Cannot read raw disk toc.");
  309.     return NULL;
  310.   }
  311.   dataLen = ((reqData[0] << 8) | reqData[1]) + 2;
  312.   message(3, "Raw toc data len: %d", dataLen);
  313.   data = new (unsigned char)[dataLen];
  314.   
  315.   // read disk toc
  316.   cmd[7] = dataLen >> 8;
  317.   cmd[8] = dataLen;
  318.   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
  319.     message(-2, "Cannot read raw disk toc.");
  320.     delete[] data;
  321.     return NULL;
  322.   }
  323.   entries = (((data[0] << 8) | data[1]) - 2) / 11;
  324.   rawToc = new CdRawToc[entries];
  325.   for (i = 0, p = data + 4; i < entries; i++, p += 11 ) {
  326. #if 0
  327.     message(0, "%d %02x %02d %2x %02x:%02x:%02x %02x %02x:%02x:%02x",
  328.     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]);
  329. #endif
  330.     rawToc[i].sessionNr = p[0];
  331.     rawToc[i].adrCtl = p[1];
  332.     rawToc[i].point = p[3];
  333.     rawToc[i].pmin = p[8];
  334.     rawToc[i].psec = p[9];
  335.     rawToc[i].pframe = p[10];
  336.   }
  337.   delete[] data;
  338.   *len = entries;
  339.   return rawToc;
  340. }
  341. long PlextorReader::readTrackData(TrackData::Mode mode, long lba, long len,
  342.   unsigned char *buf)
  343. {
  344.   unsigned char cmd[10];
  345.   long blockLen = 2340;
  346.   long i;
  347.   TrackData::Mode actMode;
  348.   int ok = 0;
  349.   const unsigned char *sense;
  350.   int senseLen;
  351.   int softError;
  352.   if (setBlockSize(blockLen) != 0)
  353.     return 0;
  354.   memset(cmd, 0, 10);
  355.   cmd[0] = 0x28; // READ10
  356.   cmd[2] = lba >> 24;
  357.   cmd[3] = lba >> 16;
  358.   cmd[4] = lba >> 8;
  359.   cmd[5] = lba;
  360.   while (len > 0 && !ok) {
  361.     cmd[7] = len >> 8;
  362.     cmd[8] = len;
  363.     memset(transferBuffer_, 0, len * blockLen);
  364.     switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) {
  365.     case 0:
  366.       ok = 1;
  367.       break;
  368.     case 2:
  369.       softError = 0;
  370.       sense = scsiIf_->getSense(senseLen);
  371.       if (senseLen > 0x0c) {
  372. if ((sense[2] &0x0f) == 5) { // Illegal request
  373.   switch (sense[12]) {
  374.   case 0x63: // End of user area encountered on this track
  375.   case 0x64: // Illegal mode for this track
  376.     softError = 1;
  377.     break;
  378.   }
  379. }
  380. else if ((sense[2] & 0x0f) == 3) { // Medium error
  381.   switch (sense[12]) {
  382.   case 0x02: // No seek complete, sector not found
  383.   case 0x11: // L-EC error
  384.     return -2;
  385.     break;
  386.   }
  387. }
  388.       }
  389.       if (!softError) {
  390. scsiIf_->printError();
  391. return -1;
  392.       }
  393.       break;
  394.     default:
  395.       message(-2, "Read error at LBA %ld, len %ld", lba, len);
  396.       return -1;
  397.       break;
  398.     }
  399.     if (!ok) {
  400.       len--;
  401.     }
  402.   }
  403.   unsigned char *sector = transferBuffer_;
  404.   for (i = 0; i < len; i++) {
  405.     actMode = determineSectorMode(sector);
  406.     if (!(actMode == mode ||
  407.   (mode == TrackData::MODE2_FORM_MIX &&
  408.    (actMode == TrackData::MODE2_FORM1 ||
  409.     actMode == TrackData::MODE2_FORM2)) ||
  410.   (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) ||
  411.   (mode == TrackData::MODE2_RAW &&
  412.    (actMode == TrackData::MODE2 ||
  413.     actMode == TrackData::MODE2_FORM1 ||
  414.     actMode == TrackData::MODE2_FORM2)))) {
  415.       message(3, "Stopped because sector with not matching mode %s found.",
  416.       TrackData::mode2String(actMode));
  417.       message(3, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
  418.       sector[0], sector[1], sector[2], sector[3],  sector[4],
  419.       sector[5], sector[6], sector[7], sector[8], sector[9],
  420.       sector[10], sector[11]);
  421.       return i;
  422.     }
  423.     if (buf != NULL) {
  424.       switch (mode) {
  425.       case TrackData::MODE1:
  426. memcpy(buf, sector + 4, MODE1_BLOCK_LEN);
  427. buf += MODE1_BLOCK_LEN;
  428. break;
  429.       case TrackData::MODE2:
  430.       case TrackData::MODE2_FORM_MIX:
  431. memcpy(buf, sector + 4, MODE2_BLOCK_LEN);
  432. buf += MODE2_BLOCK_LEN;
  433. break;
  434.       case TrackData::MODE2_FORM1:
  435. memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN);
  436. buf += MODE2_FORM1_DATA_LEN;
  437. break;
  438.       case TrackData::MODE2_FORM2:
  439. memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN);
  440. buf += MODE2_FORM2_DATA_LEN;
  441. break;
  442.       case TrackData::MODE1_RAW:
  443.       case TrackData::MODE2_RAW:
  444. memcpy(buf, syncPattern, 12);
  445. memcpy(buf + 12, sector, 2340);
  446. buf += AUDIO_BLOCK_LEN;
  447. break;
  448.       case TrackData::MODE0:
  449.       case TrackData::AUDIO:
  450. message(-3, "PlextorReader::readTrackData: Illegal mode.");
  451. return 0;
  452. break;
  453.       }
  454.     }
  455.     sector += blockLen;
  456.   }  
  457.   return len;
  458. }
  459. Toc *PlextorReader::readDiskToc(int session, const char *audioFilename)
  460. {
  461.   Toc *toc = CdrDriver::readDiskToc(session, audioFilename);
  462.   setBlockSize(MODE1_BLOCK_LEN);
  463.   
  464.   return toc;
  465. }
  466. Toc *PlextorReader::readDisk(int session, const char *dataFilename)
  467. {
  468.   Toc *toc = CdrDriver::readDisk(session, dataFilename);
  469.   setBlockSize(MODE1_BLOCK_LEN);
  470.   
  471.   return toc;
  472. }
  473. // Creates 'Toc' object for inserted CD.
  474. // audioFilename: name of audio file that is placed into TOC
  475. // Return: newly allocated 'Toc' object or 'NULL' on error
  476. int PlextorReader::readAudioRangePlextor(int fd,  long startLba, long endLba,
  477.  int startTrack, int endTrack, 
  478.  TrackInfo *info)
  479. {
  480.   int i;
  481.   int ret;
  482.   //unsigned char trackCtl; // control nibbles of track
  483.   //int ctlCheckOk;
  484.  
  485.   int blockLength = AUDIO_BLOCK_LEN + 1 + 294 + 96;
  486.   long  blocksPerRead = scsiIf_->maxDataLen() / blockLength;
  487.   // first, last, current and number of recorded tracks
  488.   int fat=-1,lat=-1,cat,nat=0;
  489.   // first, last, number, current, remaining and read (audio blocks)
  490.   long fab,lab,nab,cab,rab,n;
  491.   
  492.   // SCSI command 
  493.   unsigned char cmd[12];   
  494.   unsigned char *data;
  495.   // number of byte errors in current audio block (cab)
  496.   int cabFaulty;
  497.   // number of retries and goods of current audio block (cab)
  498.   unsigned long cabRetries=0,cabGoods=0,scsiRetries=0;
  499.   // audio repair block
  500.   unsigned char repairBlock[AUDIO_BLOCK_LEN + 1 + 294 + 96];
  501.   //unsigned char referBlock[AUDIO_BLOCK_LEN + 1 + 294 + 96];
  502.   int repairErrors=-1;  
  503.   int overspeed,cai=-1;
  504.   data = new (unsigned char)[blocksPerRead * blockLength];  
  505.   fat = startTrack;
  506.   lat = endTrack;
  507.   nat = endTrack - startTrack + 1;
  508.   info[lat].bytesWritten = 0;
  509.   // set first, last and number of audio blocks
  510.   fab = startLba;
  511.   lab = endLba;
  512.   nab=lab-fab;
  513.   message(1, "Reading CDDA tracks in range [%lu,%lu].", fat+1,lat+1);
  514.   cat = fat + 1;
  515.  
  516.   message(1, "Reading CDDA blocks in range [%lu,%lu>"
  517.     " (%lu blocks=%lu bytes).",fab,lab,nab,nab*2352);
  518.   memset(cmd,0,12);
  519.   cmd[0]=0xd8;
  520.   cmd[10]=0x09; 
  521.  
  522. #if 0 // for testing purposes I set the position/length of a scratch here
  523.   fab+=3000;
  524.   nab=921;
  525. #endif
  526.   // set current audio block
  527.   cab=fab;
  528.   // set remaining audio blocks
  529.   rab=nab;
  530.   // start optimistic
  531.   speed(overspeed=20);
  532.   // while still audio blocks left to read
  533.   while (rab != 0)
  534.   { 
  535.     // the maximum number of blocks to read, or just those which are left
  536.     n=(rab > blocksPerRead ? blocksPerRead : rab);
  537.     
  538.     // set starting audio block
  539.     cmd[2] = cab >> 24;
  540.     cmd[3] = cab >> 16;
  541.     cmd[4] = cab >> 8;
  542.     cmd[5] = cab;
  543.     // set number of blocks
  544.     cmd[6] = n >> 24;
  545.     cmd[7] = n >> 16;
  546.     cmd[8] = n >> 8;
  547.     cmd[9] = n;
  548.     message(1, "block %6ldr",cab);
  549.     // SCSI command failed?
  550.     while (sendCmd(cmd,12,NULL,0,data,n*blockLength))
  551.     {
  552.       scsiRetries++;
  553.       if (cabRetries==0)
  554.       {
  555.         if (scsiRetries==10)
  556.         {
  557.           delete[] data;
  558.           return 1;
  559.         }
  560.       }
  561.       else
  562.       {
  563.         scsiRetries=0;
  564.         //cabRetries++;
  565.         break;
  566.       }
  567.     }
  568.     // iterate through the read audio blocks
  569.     for (i=0;i<n;i++)
  570.     {
  571.       // create subchannel object
  572.       PWSubChannel96 chan(data + i*blockLength + AUDIO_BLOCK_LEN + 1 + 294); 
  573.  
  574.       // q subchannel error?
  575.       if (!chan.checkCrc())
  576.       {
  577.         // TODO: Implement heuristic subchannel error correction here
  578.       }
  579.       // q subchannel ok?
  580.       if (chan.checkCrc() && chan.checkConsistency())
  581.       {
  582.         // q subchannel contains mode 1 data?
  583.         if(chan.type() == SubChannel::QMODE1DATA)
  584. {
  585.           // track relative time as it occurs in subchannel
  586.           Msf qRelTime(chan.min(),chan.sec(),chan.frame());
  587.           // disc absolute time as it occurs in subchannel
  588.           Msf qAbsTime(chan.amin(),chan.asec(),chan.aframe());
  589.           if ((chan.indexNr()!=cai) || (chan.trackNr()!=cat))
  590.           {
  591.             message(1, "(track,index,absolute)=(%2d,%2d,%s)",
  592.               chan.trackNr(),chan.indexNr(),qAbsTime.str());
  593.             // first track start?
  594.             if ((chan.trackNr()==1) && (chan.indexNr()==1))
  595.             {
  596.               message(1, "Found track number %02d at %s (block %d).",
  597.       chan.trackNr(),qAbsTime.str(),cab);
  598.               if ((qAbsTime.lba()-150)!=info[0].start)
  599.               {
  600.                 message(1, "TOC SAYS TRACK STARTS AT %s!",
  601.                   Msf(info[0].start).str());
  602.               }
  603.             }
  604.             // next track start?
  605.             else if ((chan.trackNr()==(cat+1)) && (chan.indexNr()==1))
  606.             {
  607.               message(1, "Found track number %02d at %s.",
  608.                 chan.trackNr(),qAbsTime.str());
  609.               if ((qAbsTime.lba()-150)!=info[cat].start)
  610.               {
  611.                 message(1, "TOC SAYS TRACK STARTS AT %s!",
  612. Msf(info[cat].start).str());
  613.               }
  614.             }
  615.             // pregap of next track?
  616.             else if ((chan.trackNr()==(cat+1)) && (chan.indexNr()==0))
  617.             {
  618.               message(1, "Found pregap of track %02d with size %s at ",
  619.       chan.trackNr(), qRelTime.str());
  620.       message(1, "%s", qAbsTime.str());
  621.       if (cat <= lat) {
  622. info[cat].pregap = qRelTime.lba();
  623.       }
  624.             }
  625.             // index increment?
  626.             else if ((chan.trackNr()==cat) && (chan.indexNr()==(cai+1)))
  627.             {
  628.               if (chan.indexNr() > 1)
  629.               {
  630. message(1, "Found index number %02d at %s.",
  631. chan.indexNr(),qAbsTime.str());
  632. int indexCnt = info[cat - 1].indexCnt;
  633. if (cat - 1 <= lat && indexCnt < 98) {
  634.   info[cat - 1].index[indexCnt] = qRelTime.lba();
  635.   info[cat - 1].indexCnt += 1;
  636. }
  637.               }
  638.             }
  639.             else if (chan.trackNr()==0xAA)
  640.             {
  641.               message(1, "LEAD OUT TRACK ENCOUNTERED!");
  642.               n=0;
  643.               i=0;
  644.               rab=0;
  645.               cab-=1;
  646.               lab=cab;
  647.               break;
  648.             }
  649.             else if ((chan.trackNr()==cat) && (chan.indexNr()==cai))
  650.             {
  651.             }
  652.             else
  653.             {
  654.               message(1, "UNEXPECTED!");
  655.             }
  656.             cat=chan.trackNr();
  657.             cai=chan.indexNr();
  658.           }
  659.         }
  660. else if (chan.type() == SubChannel::QMODE3)
  661.         {
  662.   // subchannel contains ISRC code
  663.   if (info[cat - 1].isrcCode[0] == 0) {
  664.     memcpy(info[cat - 1].isrcCode, chan.isrc(), 13);
  665.     message(1, "Found ISRC code of track %02d.", cat);
  666.   }
  667. }
  668.       }
  669.       // erronous subchannel data     
  670.       else
  671.       {
  672.       }
  673.  
  674.       // read CIRC error indicator
  675.       cabFaulty=data[i*blockLength+AUDIO_BLOCK_LEN];
  676.       // only errorless blocks or often retried blocks are accepted
  677.       if ((cabFaulty==0) || (repairErrors==0) || (cabRetries>80))
  678.       {
  679.         unsigned char *block;
  680.         // the current audio block in the data buffer is perfect
  681.         if (cabFaulty==0)
  682.         {
  683.           block=data + i*blockLength;
  684.           // write this block's audio data
  685.           //fwrite(data + i*blockLength,1,AUDIO_BLOCK_LEN,fd);
  686.           // increment number of consecutive good blocks
  687.           cabGoods++;  
  688.           if (cabRetries)
  689.           {
  690.             message(1,"block %6ld read and written without errors now. n", cab);
  691.           }
  692.         }
  693.         // we have a fully repaired block
  694.         else if (repairErrors==0)
  695.         {
  696.           // write this block's audio data
  697.           block=repairBlock;
  698.           //fwrite(repairBlock,1,AUDIO_BLOCK_LEN,fd);
  699.           message(1,"block %6ld written after fully being repaired...", cab);
  700.         }
  701.         // we have a partially repaired block
  702.         else if (cabRetries>=0)
  703.         {
  704.           // write this block's audio data
  705.           block=repairBlock;
  706.   //fwrite(repairBlock,1,AUDIO_BLOCK_LEN,fd);
  707.           message(1,"block %6ld written with %4ld erronous bytes in it!", cab, repairErrors);
  708.         }
  709.         else
  710.         {
  711.            message(1,"PROGRAM BUG!!!! BUG #1! ENTERED ILLEGAL STATEn");
  712.         }
  713. #if 1 // not if we test please
  714. if (options_ & OPT_DRV_SWAP_READ_SAMPLES)
  715.   swapSamples((Sample*)block, SAMPLES_PER_BLOCK);
  716. if ((ret = fullWrite(fd, block, AUDIO_BLOCK_LEN)) != AUDIO_BLOCK_LEN) {
  717.   if (ret < 0)
  718.     message(-2, "Writing of data failed: %s", strerror(errno));
  719.   else
  720.     message(-2, "Writing of data failed: Disk full");
  721.           delete[] data;
  722.           return 1;
  723. }
  724. info[lat].bytesWritten += AUDIO_BLOCK_LEN;
  725. #endif
  726.         repairErrors=-1;
  727.         cabRetries=0;
  728.         // proceed to next audio block
  729.         //message(0,"PROCEEDING TO NEXT BLOCK");
  730.         cab++;
  731.         rab--;
  732.         if (cabGoods == 1000)
  733.         {
  734.           if (overspeed<20)
  735.           {
  736.             overspeed=((overspeed*2)>=20?20:overspeed*2);
  737.             // crank up the speed again
  738.             // message(0,"Speeding up to %ld overspeed...r",overspeed);
  739.             speed(overspeed);
  740.             cabGoods=0;
  741.           }
  742.         }
  743.       }
  744.       else
  745.       // the current block contains errors
  746.       {
  747.         int j;
  748.         // first time error on this block?
  749.         if (cabRetries==0)
  750.         {
  751.           // copy faulty block into our repair buffer
  752.           memcpy(repairBlock,data+i*blockLength,AUDIO_BLOCK_LEN+1+294+96);
  753.           // slow down to lower error rate (we hope so!?)
  754.           if (overspeed>1) overspeed/=2;
  755.           // message(0,"Slowing down to %ld...r",overspeed);
  756.           speed(overspeed);
  757.         }
  758.         // iterate through all audio samples, merge all good samples into
  759.         // a repair audio block
  760.         // Implementor's note: The following info is NOT mentioned in the
  761.         // official Plextor documentation I have, but IS confirmed by
  762.         // Plextor. -- Leon Woestenberg <leon@stack.nl>.
  763.         // NOTE: Any two bytes of a sample (or both) can be damaged.
  764.         // Although the error bit flag can be set for just one byte, the
  765.         // other byte can be changed due to the fact that DSP interpolation
  766.         // is applied to the whole (two-byte) sample.
  767.         // THEREFORE, any of the two bits relating to a two-byte sample
  768.         // indicate the WHOLE sample is incorrect, and we will try to
  769.         // repair the whole sample, not just the one byte.
  770.         // THIS will ensure we have a 100% bit-wise accurate copy of
  771.         // the audio data. 
  772.         repairErrors=0;
  773.         for (j=0;j<AUDIO_BLOCK_LEN;j+=2) // iterate by steps of 1 sample
  774.         {
  775.           // sample erronous in repair block? (bits 7-j and/or 6-j set?)
  776.           if (repairBlock[AUDIO_BLOCK_LEN+1+(j/8)] & (192>>(j%8)))
  777.           {
  778.             // sample good in fresh data block?
  779.             if (!(data[i*blockLength+AUDIO_BLOCK_LEN+1+(j/8)] & (192>>(j%8))))
  780.             {
  781. #if 0
  782.               printf("nerrenous sample %d (bytes %d/%d) being repaired with %04x",
  783.                 j/2,j,j+1,data[i*blockLength+j]*256+data[i*blockLength+j+1]);
  784. #endif
  785.               // then copy it into the repairBlock;
  786.               repairBlock[j]=data[i*blockLength+j];
  787.               repairBlock[j+1]=data[i*blockLength+j+1];
  788.               // clear error bit in repair block
  789.               repairBlock[AUDIO_BLOCK_LEN+1+(j/8)] &= (~(192>>(j%8)));
  790.             }
  791.             // erronous sample could not be replaced by the good one
  792.             else
  793.             {
  794. #if 0
  795.               printf("%d, ",j/2);
  796. #endif
  797.               // increment number of repair block erronous samples
  798.               repairErrors++; 
  799.             }
  800. #if 0
  801.               message(0,"bits %ld/%ld (bits %ld/%ld of byte %ld) was 1",
  802.                 j,j+1,7-(j%8),6-(j%8),j/8);
  803. #endif
  804.           }
  805. #if 0
  806.           else
  807.           {
  808.             message(0,"bits %ld/%ld (bits %ld/%ld of byte %ld) were 0",
  809.               j,j+1,7-(j%8),6-(j%8),j/8);
  810.           }
  811. #endif
  812.         }
  813.         if (cabRetries==0)
  814.         {
  815.           message(1,"nblock %6ld has %3ld error samplesr",
  816.             cab,repairErrors);
  817.         }
  818.         else
  819.         {
  820.           message(1,"block %6ld has %3ld error samples left after %3ld retriesr",
  821.             cab,repairErrors,cabRetries);
  822.         }
  823.         // increase number of retries
  824.         cabRetries++;
  825.         cabGoods=0;
  826.         // break out of for-loop (into while-loop) to re-read current block
  827.         break;
  828.       }
  829.     }
  830.   }  
  831.  
  832.   delete[] data;
  833.   return 0;
  834. }
  835. int PlextorReader::readSubChannels(long lba, long len, SubChannel ***chans,
  836.    Sample *audioData)
  837. {
  838.   unsigned char cmd[12];
  839.   int cmdLen;
  840.   int tries = 5;
  841.   int ret;
  842.   memset(cmd, 0, 12);
  843.   if (options_ & OPT_PLEX_DAE_READ10) {
  844.     if (setBlockSize(AUDIO_BLOCK_LEN) != 0)
  845.       return 1;
  846.     cmd[0] = 0x28; // READ10
  847.     cmd[2] = lba >> 24;
  848.     cmd[3] = lba >> 16;
  849.     cmd[4] = lba >> 8;
  850.     cmd[5] = lba;
  851.     cmd[7] = len >> 8;
  852.     cmd[8] = len;
  853.     cmdLen = 10;
  854.   }
  855.   else {
  856.     cmd[0]=0xd8; // READ CDDA
  857.     cmd[2] = lba >> 24;
  858.     cmd[3] = lba >> 16;
  859.     cmd[4] = lba >> 8;
  860.     cmd[5] = lba;
  861.     cmd[6] = len >> 24;
  862.     cmd[7] = len >> 16;
  863.     cmd[8] = len >> 8;
  864.     cmd[9] = len;
  865.     cmdLen = 12;
  866.   }
  867.   do {
  868.     ret = sendCmd(cmd, cmdLen, NULL, 0, 
  869.   (unsigned char*)audioData, len * AUDIO_BLOCK_LEN,
  870.   (tries == 1) ? 1 : 0);
  871.     if (ret != 0 && tries == 1) {
  872.       message(-2, "Reading of audio data failed at sector %ld.", lba);
  873.       return 1;
  874.     }
  875.     
  876.     tries--;
  877.   } while (ret != 0 && tries > 0);
  878.   *chans = NULL;
  879.   return 0;
  880. }
  881. int PlextorReader::readAudioRange(int fd, long start, long end,
  882.   int startTrack, int endTrack, 
  883.   TrackInfo *info)
  884. {
  885.   if (model_ != 0 && (options_ & OPT_PLEX_USE_PARANOIA) == 0) {
  886.     // we have a plextor drive -> use the special plextor method which
  887.     // will also detect pre-gaps, index marks and ISRC codes
  888.     return readAudioRangePlextor(fd, start, end, startTrack, endTrack, info);
  889.   }
  890.   
  891.   if (!onTheFly_) {
  892.     int t, i;
  893.     long pregap = 0;
  894.     int indexCnt = 0;
  895.     Msf index[98];
  896.     unsigned char ctl;
  897.     long slba, elba;
  898.     message(1, "Analyzing...");
  899.     
  900.     for (t = startTrack; t <= endTrack; t++) {
  901.       message(1, "Track %d...", t + 1);
  902.       if (!fastTocReading_) {
  903. if (pregap != 0)
  904.   message(1, "Found pre-gap: %s", Msf(pregap).str());
  905. slba = info[t].start;
  906. if (info[t].mode == info[t + 1].mode)
  907.   elba = info[t + 1].start;
  908. else
  909.   elba = info[t + 1].start - 150;
  910. pregap = 0;
  911. if (analyzeTrackSearch(TrackData::AUDIO, t + 1, slba, elba,
  912.        index, &indexCnt, &pregap, info[t].isrcCode,
  913.        &ctl) != 0)
  914.   return 1;
  915. for (i = 0; i < indexCnt; i++)
  916.   info[t].index[i] = index[i].lba();
  917. info[t].indexCnt = indexCnt;
  918. if (t < endTrack)
  919.   info[t + 1].pregap = pregap;
  920.       }
  921.       else {
  922. info[t].indexCnt = 0;
  923. info[t + 1].pregap = 0;
  924.       }
  925.       
  926.       info[t].isrcCode[0] = 0;
  927.       readIsrc(t + 1, info[t].isrcCode);
  928.       if (info[t].isrcCode[0] != 0)
  929. message(1, "Found ISRC code.");
  930.     }
  931.     message(1, "Reading...");
  932.   }
  933.   return CdrDriver::readAudioRangeParanoia(fd, start, end, startTrack,
  934.    endTrack, info);
  935. }