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

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: GenericMMCraw.cc,v $
  21.  * Revision 1.10  1999/09/03 15:00:02  mueller
  22.  * Changed message levels from 0 to 1.
  23.  *
  24.  * Revision 1.9  1999/04/05 11:04:10  mueller
  25.  * Added driver option flags.
  26.  *
  27.  * Revision 1.8  1999/03/27 20:51:05  mueller
  28.  * Adapted to changed writing interface.
  29.  *
  30.  * Revision 1.7  1998/10/03 15:07:53  mueller
  31.  * Moved 'writeZeros()' to base class 'CdrDriver'.
  32.  *
  33.  * Revision 1.6  1998/09/27 19:19:18  mueller
  34.  * Added retrieval of control nibbles for track with 'analyzeTrack()'.
  35.  * Added multi session mode.
  36.  *
  37.  * Revision 1.5  1998/09/22 19:15:13  mueller
  38.  * Removed memory allocations during write process.
  39.  *
  40.  * Revision 1.4  1998/09/06 13:34:22  mueller
  41.  * Use 'message()' for printing messages.
  42.  *
  43.  * Revision 1.3  1998/09/02 18:49:45  mueller
  44.  * Added writing with data block type 0x02 using the raw P-W sub channel
  45.  * data format.
  46.  *
  47.  * Revision 1.2  1998/08/30 19:16:51  mueller
  48.  * Added support for different sub-channel data formats.
  49.  * Now 16 byte PQ sub-channel and 96 byte raw P-W sub-channel is
  50.  * supported.
  51.  *
  52.  * Revision 1.1  1998/08/25 19:28:06  mueller
  53.  * Initial revision
  54.  *
  55.  */
  56. static char rcsid[] = "$Id: GenericMMCraw.cc,v 1.10 1999/09/03 15:00:02 mueller Exp mueller $";
  57. #include <config.h>
  58. #include <string.h>
  59. #include <assert.h>
  60. #include "GenericMMCraw.h"
  61. #include "PQSubChannel16.h"
  62. #include "PWSubChannel96.h"
  63. #include "Toc.h"
  64. #include "util.h"
  65. GenericMMCraw::GenericMMCraw(ScsiIf *scsiIf, unsigned long options) 
  66.   : GenericMMC(scsiIf, options), PQChannelEncoder()
  67. {
  68.   driverName_ = "Generic SCSI-3/MMC (raw writing) - Version 1.0";
  69.   encodingMode_ = 0;
  70.   leadInLen_ = leadOutLen_ = 0;
  71.   subChannel_ = NULL;
  72.   encodeBuffer_ = NULL;
  73. }
  74. GenericMMCraw::~GenericMMCraw()
  75. {
  76.   delete subChannel_, subChannel_ = NULL;
  77.   delete[] encodeBuffer_, encodeBuffer_ = NULL;
  78. }
  79. int GenericMMCraw::multiSession(int m)
  80. {
  81.   if (m != 0) {
  82.     return 1; // multi session mode is currently not support for raw writing
  83.   }
  84.   return 0;
  85. }
  86. // static constructor
  87. CdrDriver *GenericMMCraw::instance(ScsiIf *scsiIf, unsigned long options)
  88. {
  89.   return new GenericMMCraw(scsiIf, options);
  90. }
  91. // Sets write parameters via mode page 0x05.
  92. // return: 0: OK
  93. //         1: scsi command failed
  94. int GenericMMCraw::setWriteParameters(int dataBlockType)
  95. {
  96.   unsigned char mp[0x38];
  97.   if (getModePage(5/*write parameters mode page*/, mp, 0x38,
  98.   NULL, NULL, 1) != 0) {
  99.     message(-2, "Cannot retrieve write parameters mode page.");
  100.     return 1;
  101.   }
  102.   mp[0] &= 0x7f; // clear PS flag
  103.   mp[2] &= 0xe0;
  104.   mp[2] |= 0x03; // write type: raw
  105.   if (simulate_) {
  106.     mp[2] |= 1 << 4; // test write
  107.   }
  108.   mp[3] &= 0x3f; // Multi-session: No B0 pointer, next session not allowed
  109.   mp[3] = 0;
  110.   mp[4] &= 0xf0;
  111.   mp[4] = dataBlockType & 0x0f;  // Data Block Type:
  112.                                  // 1: raw data, block size: 2368 PQ sub chan
  113.                                  // 2: raw data, block size: 2448
  114.                                  // 3: raw data, block size: 2448
  115.   mp[8] = 0; // session format: CD-DA or CD-ROM
  116.   if (setModePage(mp, NULL, NULL, 0) != 0) {
  117.     //message(-2, "Cannot set write parameters mode page.");
  118.     return 1;
  119.   }
  120.   return 0;
  121. }
  122. int GenericMMCraw::initDao(const Toc *toc)
  123. {
  124.   long n;
  125.   CdrDriver::toc_ = toc;
  126.   if (selectSpeed(0) != 0 ||
  127.       getSessionInfo() != 0) {
  128.     return 1;
  129.   }
  130.   delete subChannel_;
  131. #if 1
  132.   if (setWriteParameters(1) == 0) {
  133.     subChannel_ = new PQSubChannel16;
  134.     message(1, "Using 16 byte P-Q sub-channel data mode.");
  135.   }
  136.   else if (setWriteParameters(3) == 0) {
  137.     subChannel_ = new PWSubChannel96;
  138.     message(1, "Using 96 byte raw P-W sub-channel data mode.");
  139.   }
  140.   else if (setWriteParameters(2) == 0) {
  141.     // since we don't use the R-W channels it's the same as the latter mode,
  142.     // I think
  143.     subChannel_ = new PWSubChannel96;
  144.     message(1, "Using 96 byte packed P-W sub-channel data mode.");
  145.   }
  146.   else {
  147.     message(-2, "Cannot setup disk-at-once writing for this drive.");
  148.     return 1;
  149.   }
  150. #else
  151.   //subChannel_ = new PWSubChannel96;
  152.   subChannel_ = new PQSubChannel16;
  153. #endif
  154.   blockLength_ = AUDIO_BLOCK_LEN + subChannel_->dataLength();
  155.   blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_;
  156.   assert(blocksPerWrite_ > 0);
  157.   message(3, "Block length: %ld", blockLength_);
  158.   long cueSheetLen;
  159.   unsigned char *cueSheet = createCueSheet(&cueSheetLen);
  160.   if (cueSheet == NULL) {
  161.     return 1;
  162.   }
  163.   
  164.   if (setCueSheet(subChannel_, sessionFormat(), cueSheet, cueSheetLen,
  165.   leadInStart_) != 0) {
  166.     return 1;
  167.   }
  168.   // allocate buffer for write zeros
  169.   n = blocksPerWrite_ * AUDIO_BLOCK_LEN;
  170.   delete[] zeroBuffer_;
  171.   zeroBuffer_ = new char[n];
  172.   memset(zeroBuffer_, 0, n);
  173.   // allocate buffer for sub-channel encoding
  174.   n = blocksPerWrite_ * blockLength_;
  175.   delete[] encodeBuffer_;
  176.   encodeBuffer_ = new (unsigned char)[n];
  177.   
  178.   return 0;
  179. }
  180. int GenericMMCraw::startDao()
  181. {
  182.   //scsiTimeout_ = scsiIf_->timeout(1 * 20);
  183.   message(1, "Writing lead-in and gap...");
  184.   long lba = leadInStart_.lba() - 450150;
  185.   
  186.   if (writeZeros(CdrDriver::toc_->leadInMode(), lba, 0, leadInLen_) != 0) {
  187.     return 1;
  188.   }
  189.   if (writeZeros(CdrDriver::toc_->leadInMode(), lba, 0, 150) != 0) {
  190.     return 1;
  191.   }
  192.   return 0;
  193. }
  194. int GenericMMCraw::finishDao()
  195. {
  196.   message(1, "Writing lead-out...");
  197.   long lba = CdrDriver::toc_->length().lba();
  198.   writeZeros(CdrDriver::toc_->leadOutMode(), lba, lba + 150, leadOutLen_);
  199.   message(1, "nFlushing cache...");
  200.   
  201.   if (flushCache() != 0) {
  202.     return 1;
  203.   }
  204.   message(1, "");
  205.   //scsiIf_->timeout(scsiTimeout_);
  206.   delete[] zeroBuffer_, zeroBuffer_ = NULL;
  207.   delete[] encodeBuffer_, encodeBuffer_ = NULL;
  208.   return 0;
  209. }
  210. long GenericMMCraw::nextWritableAddress()
  211. {
  212.   unsigned char cmd[10];
  213.   unsigned char data[28];
  214.   long lba = 0xffffffff;
  215.   memset(cmd, 0, 10);
  216.   memset(data, 0, 28);
  217.   cmd[0] = 0x52; // READ TRACK INFORMATION
  218.   cmd[1] = 0;
  219.   cmd[2] = lba >> 24;
  220.   cmd[3] = lba >> 16;
  221.   cmd[4] = lba >> 8;
  222.   cmd[5] = lba;
  223.   cmd[8] = 28;
  224.   if (sendCmd(cmd, 10, NULL, 0, data, 28) != 0) {
  225.     message(-2, "Cannt get track information.");
  226.     return 0;
  227.   }
  228.   long adr = (data[12] << 24) | (data[13] << 16) | (data[14] << 8) |
  229.     data[15];
  230.   return adr;
  231. }
  232. // Writes data to target. The encoded sub-channel data is appended to each
  233. // block.
  234. // return: 0: OK
  235. //         1: scsi command failed
  236. int GenericMMCraw::writeData(TrackData::Mode mode, long &lba, const char *buf,
  237.      long len)
  238. {
  239.   assert(blockLength_ > 0);
  240.   assert(blocksPerWrite_ > 0);
  241.   assert(mode == TrackData::AUDIO);
  242.   int nwritten = 0;
  243.   int writeLen = 0;
  244.   unsigned char cmd[10];
  245.   /*
  246.   message(0, "lba: %ld, len: %ld, bpc: %d, bl: %d ", lba, len, blocksPerCmd,
  247.  blockLength_);
  248.    */
  249.   memset(cmd, 0, 10);
  250.   cmd[0] = 0x2a; // WRITE1
  251.   
  252.   while (len > 0) {
  253.     writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len);
  254.     cmd[2] = lba >> 24;
  255.     cmd[3] = lba >> 16;
  256.     cmd[4] = lba >> 8;
  257.     cmd[5] = lba;
  258.     cmd[7] = writeLen >> 8;
  259.     cmd[8] = writeLen;
  260.     encode(lba, (unsigned char*)(buf + (nwritten * AUDIO_BLOCK_LEN)),
  261.    writeLen, encodeBuffer_);
  262. #if 0
  263.     // consistency checks
  264.     long sum1, sum2;
  265.     int i, n;
  266.     const char *p;
  267.     for (i = 0; i < writeLen; i++) {
  268.       message(0, "%ld: ", lba + i);
  269.       SubChannel *chan = subChannel_->makeSubChannel(encodeBuffer_ + i * blockLength_ + AUDIO_BLOCK_LEN);
  270.       chan->print();
  271.       delete chan;
  272.       sum1 = 0;
  273.       for (p = buf + (nwritten + i) * AUDIO_BLOCK_LEN, n = 0;
  274.    n < AUDIO_BLOCK_LEN; n++, p++) {
  275. sum1 += *p;
  276.       }
  277.       sum2 = 0;
  278.       for (n = 0; n < AUDIO_BLOCK_LEN; n++) {
  279. sum2 += *(char *)(encodeBuffer_ + i * blockLength_ + n);
  280.       }
  281.       //message(0, "%ld - %ld", sum1, sum2);
  282.       assert(sum1 == sum2);
  283.     }
  284. #endif
  285. #if 1
  286.     if (sendCmd(cmd, 10, encodeBuffer_, writeLen * blockLength_,
  287. NULL, 0) != 0) {
  288.       message(-2, "Write data failed.");
  289.       return 1;
  290.     }
  291. #endif
  292.     //message(0, ". ");
  293.     lba += writeLen;
  294.     len -= writeLen;
  295.     nwritten += writeLen;
  296.   }
  297.   //message(0, "");
  298.   return 0;
  299. }