1 /*  cdrdao - write audio CD-Rs in disc-at-once mode
2  *
3  *  Copyright (C) 1998-2001  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 #include <config.h>
21 
22 #include <string.h>
23 #include <assert.h>
24 
25 #include "CDD2600.h"
26 #include "SubChannel.h"
27 #include "PQSubChannel16.h"
28 
29 #include "Toc.h"
30 #include "log.h"
31 
CDD2600(ScsiIf * scsiIf,unsigned long options)32 CDD2600::CDD2600(ScsiIf *scsiIf, unsigned long options)
33   : CdrDriver(scsiIf, options|OPT_DRV_NO_PREGAP_READ), CDD2600Base(this)
34 {
35   driverName_ = "CDD2600 - Version 1.1";
36 
37   leadInLength_ = leadOutLength_ = 0;
38   speed_ = 2;
39   simulate_ = true;
40   encodingMode_ = 0;
41 
42   // reads big endian samples
43   audioDataByteOrder_ = 1;
44 
45   memset(&diskInfo_, 0, sizeof(DiskInfo));
46 }
47 
~CDD2600()48 CDD2600::~CDD2600()
49 {
50 }
51 
52 // static constructor
instance(ScsiIf * scsiIf,unsigned long options)53 CdrDriver *CDD2600::instance(ScsiIf *scsiIf, unsigned long options)
54 {
55   return new CDD2600(scsiIf, options);
56 }
57 
58 // sets speed
59 // return: 0: OK
60 //         1: illegal speed
speed(int s)61 int CDD2600::speed(int s)
62 {
63   if (s >= 0 && s <= 2) {
64     speed_ = s;
65     return 0;
66   }
67   else if (s > 2) {
68     speed_ = 2;
69     return 0;
70   }
71   else {
72     return 1;
73   }
74 }
75 
76 // loads ('unload' == 0) or ejects ('unload' == 1) tray
77 // return: 0: OK
78 //         1: scsi command failed
79 
loadUnload(int unload) const80 int CDD2600::loadUnload(int unload) const
81 {
82   unsigned char cmd[10];
83 
84   memset(cmd, 0, 10);
85 
86   cmd[0] = 0xe7; // MEDIUM LOAD/UNLOAD
87   if (unload) {
88     cmd[8] |= 0x01;
89   }
90 
91   if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) {
92     log_message(-2, "Cannot load/unload medium.");
93     return 1;
94   }
95 
96   return 0;
97 }
98 
99 // sets various audio play parameters, output channels are set to stereo mode
100 // and given volume
101 // immediate: 0: wait until audio play command finished
102 //            1: command finishs immediately after playback has started
103 // sotc:      0: play across track boundaries
104 //            1: stop playing at track boundaries
modeSelectPlay(int immediate,int sotc,unsigned char volume)105 int CDD2600::modeSelectPlay(int immediate, int sotc, unsigned char volume)
106 {
107   unsigned char mp[16];
108 
109   memset(mp, 0, 16);
110 
111   mp[0] = 0x0e; // PLAY page code
112   mp[1] = 14; // parameter length
113   if (immediate != 0) {
114     mp[2] |= 0x04;
115   }
116   if (sotc != 0) {
117     mp[2] |= 0x02;
118   }
119   mp[8]  = 1;
120   mp[9]  = volume;
121   mp[10] = 2;
122   mp[11] = volume;
123 
124   if (setModePage(mp, NULL, NULL, 1) != 0) {
125     log_message(-2, "Cannot set play parameters.");
126     return 1;
127   }
128 
129   return 0;
130 }
131 
initDao(const Toc * toc)132 int CDD2600::initDao(const Toc *toc)
133 {
134   long n;
135   blockLength_ = AUDIO_BLOCK_LEN;
136   blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_;
137 
138   assert(blocksPerWrite_ > 0);
139 
140   toc_ = toc;
141 
142   diskInfo();
143 
144   if (!diskInfo_.valid.empty || !diskInfo_.valid.append) {
145     log_message(-2, "Cannot determine status of inserted medium.");
146     return 1;
147   }
148 
149   if (!diskInfo_.append) {
150     log_message(-2, "Inserted medium is not appendable.");
151     return 1;
152   }
153 
154   if (modeSelectBlockSize(blockLength_, 1) != 0 ||
155       modeSelectSpeed(-1, speed_, simulate_, 1) != 0 ||
156       modeSelectCatalog(toc_) != 0 ||
157       readSessionInfo(&leadInLength_, &leadOutLength_, 1) != 0) {
158     return 1;
159   }
160 
161   // allocate buffer for write zeros
162   n = blocksPerWrite_ * blockLength_;
163   delete[] zeroBuffer_;
164   zeroBuffer_ = new char[n];
165   memset(zeroBuffer_, 0, n);
166 
167   return 0;
168 }
169 
startDao()170 int CDD2600::startDao()
171 {
172   long lba;
173 
174   if (writeSession(toc_, multiSession_, diskInfo_.thisSessionLba) != 0) {
175     return 1;
176   }
177 
178   log_message(2, "Writing lead-in and gap...");
179 
180   lba = diskInfo_.thisSessionLba - 150 - leadInLength_;
181 
182   // write lead-in
183   if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, lba + 150,
184 		 leadInLength_) != 0) {
185     flushCache();
186     return 1;
187   }
188 
189   log_message(5, "Lba after lead-in: %ld", lba);
190 
191   // write gap (2 seconds)
192   if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE,
193 		 lba, lba + 150, 150) != 0) {
194     flushCache();
195     return 1;
196   }
197 
198   log_message(2, "");
199 
200   return 0;
201 }
202 
finishDao()203 int CDD2600::finishDao()
204 {
205   long lba = diskInfo_.thisSessionLba + toc_->length().lba();
206 
207   log_message(2, "Writing lead-out...");
208 
209   // write lead-out
210   if (writeZeros(toc_->leadOutMode(), TrackData::SUBCHAN_NONE, lba, lba + 150,
211 		 leadOutLength_) != 0) {
212     flushCache();
213     return 1;
214   }
215 
216   log_message(2, "\nFlushing cache...");
217 
218   if (flushCache() != 0) {
219     return 1;
220   }
221 
222   log_message(2, "");
223 
224   blockLength_ = MODE1_BLOCK_LEN;
225   modeSelectBlockSize(blockLength_, 1);
226 
227   delete[] zeroBuffer_, zeroBuffer_ = NULL;
228 
229   return 0;
230 }
231 
abortDao()232 void CDD2600::abortDao()
233 {
234   flushCache();
235 
236   blockLength_ = MODE1_BLOCK_LEN;
237   modeSelectBlockSize(blockLength_, 1);
238 }
239 
240 // Writes data to target, the block length depends on the actual writing mode
241 // and is stored internally. 'len' is number of blocks to write.
242 // 'lba' specifies the next logical block address for writing and is updated
243 // by this function but not used for writing
244 // return: 0: OK
245 //         1: scsi command failed
writeData(TrackData::Mode mode,TrackData::SubChannelMode sm,long & lba,const char * buf,long len)246 int CDD2600::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm,
247 		       long &lba, const char *buf, long len)
248 {
249   assert(blocksPerWrite_ > 0);
250   assert(blockLength_ > 0);
251   assert(mode == TrackData::AUDIO);
252   int nwritten = 0;
253   int writeLen = 0;
254   unsigned char cmd[10];
255 
256   memset(cmd, 0, 10);
257   cmd[0] = 0x2a; // WRITE1
258 
259   while (len > 0) {
260     writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len);
261 
262     cmd[7] = writeLen >> 8;
263     cmd[8] = writeLen & 0xff;
264 
265     if (sendCmd(cmd, 10, (unsigned char *)(buf + (nwritten * blockLength_)),
266 		writeLen * blockLength_, NULL, 0) != 0) {
267       log_message(-2, "Write data failed.");
268       return 1;
269     }
270 
271     lba += writeLen;
272 
273     len -= writeLen;
274     nwritten += writeLen;
275   }
276 
277   return 0;
278 }
279 
readDiskToc(int session,const char * audioFilename)280 Toc *CDD2600::readDiskToc(int session, const char *audioFilename)
281 {
282 
283   blockLength_ = AUDIO_BLOCK_LEN;
284   if (modeSelectBlockSize(blockLength_, 1) != 0) {
285     return NULL;
286   }
287 
288   modeSelectSpeed(2, -1, 1, 0);
289 
290   Toc *toc = CdrDriver::readDiskToc(session, audioFilename);
291 
292   setBlockSize(MODE1_BLOCK_LEN);
293 
294   return toc;
295 }
296 
readDisk(int session,const char * fname)297 Toc *CDD2600::readDisk(int session, const char *fname)
298 {
299   Toc *toc = CdrDriver::readDisk(session, fname);
300 
301   setBlockSize(MODE1_BLOCK_LEN);
302 
303   return toc;
304 }
305 
readIsrc(int trackNr,char * buf)306 int CDD2600::readIsrc(int trackNr, char *buf)
307 {
308   unsigned char cmd[10];
309   unsigned short dataLen = 0x30;
310   unsigned char data[0x30];
311   int i;
312 
313   memset(cmd, 0, 10);
314   cmd[0] = 0x42; // READ SUB CHANNEL
315   cmd[2] = 0x40; // get sub channel data
316   cmd[3] = 0x03; // get ISRC code
317   cmd[6] = trackNr;
318   cmd[7] = dataLen >> 8;
319   cmd[8] = dataLen;
320 
321   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
322     log_message(-1, "Cannot read ISRC code.");
323     return 1;
324   }
325   else {
326     if (data[0x08] & 0x80) {
327       for (i = 0; i < 12; i++) {
328 	buf[i] = data[0x09 + i];
329       }
330       buf[12] = 0;
331     }
332   }
333 
334   return 0;
335 }
336 
337 // tries to read catalog number from disk and adds it to 'toc'
338 // return: 1 if valid catalog number was found, else 0
339 
readCatalog(Toc * toc,long startLba,long endLba)340 int CDD2600::readCatalog(Toc *toc, long startLba, long endLba)
341 {
342   unsigned char cmd[10];
343   unsigned short dataLen = 0x30;
344   unsigned char data[0x30];
345   char catalog[14];
346   int i;
347 
348   // read sub channel information
349   memset(cmd, 0, 10);
350   cmd[0] = 0x42; // READ SUB CHANNEL
351   cmd[2] = 0x40; // get sub channel data
352   cmd[3] = 0x02; // get media catalog number
353   cmd[7] = dataLen >> 8;
354   cmd[8] = dataLen;
355 
356   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
357     log_message(-2, "Cannot read sub channel data.");
358     return 0;
359   }
360 
361   if (data[0x08] & 0x80) {
362     for (i = 0; i < 13; i++) {
363       catalog[i] = data[0x09 + i];
364     }
365     catalog[13] = 0;
366 
367     if (toc->catalog(catalog) == 0) {
368       return 1;
369     }
370   }
371 
372   return 0;
373 }
374 
analyzeTrack(TrackData::Mode mode,int trackNr,long startLba,long endLba,Msf * index,int * indexCnt,long * pregap,char * isrcCode,unsigned char * ctl)375 int CDD2600::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba,
376 			  long endLba,
377 			  Msf *index, int *indexCnt, long *pregap,
378 			  char *isrcCode, unsigned char *ctl)
379 {
380   blockLength_ = AUDIO_BLOCK_LEN;
381   modeSelectBlockSize(blockLength_, 1);
382 
383   int ret = analyzeTrackSearch(mode, trackNr, startLba, endLba,
384 			       index, indexCnt, pregap, isrcCode, ctl);
385 
386   *isrcCode = 0;
387 
388   if (mode == TrackData::AUDIO) {
389     // read ISRC code from sub channel
390     readIsrc(trackNr, isrcCode);
391   }
392 
393   return ret;
394 }
395 
getTrackIndex(long lba,int * trackNr,int * indexNr,unsigned char * ctl)396 int CDD2600::getTrackIndex(long lba, int *trackNr, int *indexNr,
397 			   unsigned char *ctl)
398 {
399   long relPos;
400 
401   readBlock(lba);
402 
403   return readSubChannelData(trackNr, indexNr, &relPos, ctl);
404 }
405 
readSubChannelData(int * trackNr,int * indexNr,long * relPos,unsigned char * ctl)406 int CDD2600::readSubChannelData(int *trackNr, int *indexNr, long *relPos,
407 				unsigned char *ctl)
408 {
409   unsigned char cmd[10];
410   unsigned short dataLen = 0x30;
411   unsigned char data[0x30];
412 
413   // read sub channel information
414   memset(cmd, 0, 10);
415   cmd[0] = 0x42; // READ SUB CHANNEL
416   cmd[2] = 0x40; // get sub channel data
417   cmd[3] = 0x00; // get sub Q channel data
418   cmd[6] = 0;
419   cmd[7] = dataLen >> 8;
420   cmd[8] = dataLen;
421 
422   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
423     log_message(-2, "Cannot read sub Q channel data.");
424     return 1;
425   }
426 
427   *trackNr = data[6];
428   *indexNr = data[7];
429   *relPos = 0;
430   *relPos |= data[0x0c] << 24;
431   *relPos |= data[0x0d] << 16;
432   *relPos |= data[0x0e] << 8;
433   *relPos |= data[0x0f];
434 
435   if (ctl != NULL) {
436     *ctl = data[5] & 0x0f;
437   }
438 
439   return 0;
440 }
441 
442 // reads a single block of length 'blockLength_' from given sector
443 // return: 0: OK
444 //         1: error occured
readBlock(unsigned long sector)445 void CDD2600::readBlock(unsigned long sector)
446 {
447   unsigned char cmd[10];
448   unsigned long dataLen = 2 * blockLength_;
449   unsigned char *data = new unsigned char[dataLen];
450 
451 
452   // read sub channel information
453   memset(cmd, 0, 10);
454   cmd[0] = 0x28; // READ10
455   cmd[2] = sector >> 24;
456   cmd[3] = sector >> 16;
457   cmd[4] = sector >> 8;
458   cmd[5] = sector;
459   cmd[7] = 0;
460   cmd[8] = 2;
461 
462   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
463     log_message(-2, "Cannot read block - ignored.");
464   }
465 
466   delete[] data;
467 }
468 
nextWritableAddress(long * lba,int showError)469 int CDD2600::nextWritableAddress(long *lba, int showError)
470 {
471   unsigned char cmd[10];
472   unsigned char data[6];
473 
474   memset(data, 0, 6);
475   memset(cmd, 0, 10);
476 
477   cmd[0] = 0xe2; // FIRST WRITABLE ADDRESS
478   cmd[3] = 1 /*<< 2*/; // AUDIO
479   // cmd[7] = 1; // NPA
480   cmd[8] = 6; // allocation length
481 
482   if (sendCmd(cmd, 10, NULL, 0, data, 6, showError) != 0) {
483     if (showError)
484       log_message(-2, "Cannot retrieve next writable address.");
485     return 1;
486   }
487 
488   *lba = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
489 
490   return 0;
491 }
492 
493 // Retrieve disk information.
494 // return: DiskInfo structure or 'NULL' on error
diskInfo()495 DiskInfo *CDD2600::diskInfo()
496 {
497   unsigned char cmd[10];
498   unsigned char data[34];
499   long nwa;
500   int i;
501 
502   memset(&diskInfo_, 0, sizeof(DiskInfo));
503 
504   if (readCapacity(&(diskInfo_.capacity), 0) == 0) {
505     diskInfo_.valid.capacity = 1;
506   }
507 
508   if (readSessionInfo(&leadInLength_, &leadOutLength_, 0) == 0) {
509     diskInfo_.valid.manufacturerId = 1;
510 
511     // start time of lead-in
512     diskInfo_.manufacturerId = Msf(450150 - leadInLength_ - 150 );
513     diskInfo_.append = 1; // this is for the CDD2000 which does not support
514                          // READ DISK INFORMATION
515   }
516   else {
517     diskInfo_.append = 0; // this is for the CDD2000 which does not support
518                          // READ DISK INFORMATION
519   }
520   diskInfo_.valid.empty = 1;
521   diskInfo_.valid.append = 1;
522 
523   memset(cmd, 0, 10);
524   memset(data, 0, 4);
525 
526   cmd[0] = 0x43; // READ TOC
527   cmd[6] = 0;
528   cmd[8] = 4;
529 
530   if (sendCmd(cmd, 10, NULL, 0, data, 4, 0) == 0) {
531     log_message(5, "First track %u, last track %u", data[2], data[3]);
532     diskInfo_.lastTrackNr = data[3];
533   }
534   else {
535     log_message(5, "READ TOC (format 0) failed.");
536   }
537 
538   if (diskInfo_.lastTrackNr > 0) {
539     // the lead-in length does not specify the manufacturer ID anymore
540     diskInfo_.valid.manufacturerId = 0;
541 
542     diskInfo_.empty = 0; // CD-R is not empty
543     diskInfo_.diskTocType = 0xff; // undefined
544 
545     if (diskInfo_.lastTrackNr < 99 && nextWritableAddress(&nwa, 0) == 0) {
546       log_message(5, "NWA: %ld", nwa);
547       diskInfo_.thisSessionLba = nwa;
548       diskInfo_.append = 1;
549     }
550     else {
551       diskInfo_.append = 0;
552     }
553 
554 
555     memset(cmd, 0, 10);
556     memset(data, 0, 12);
557 
558     cmd[0] = 0x43; // READ TOC
559     cmd[6] = 0;
560     cmd[8] = 12;
561     cmd[9] = 1 << 6;
562 
563     if (sendCmd(cmd, 10, NULL, 0, data, 12) == 0) {
564       diskInfo_.sessionCnt = data[3];
565       diskInfo_.lastSessionLba = (data[8] << 24) | (data[9] << 16) |
566                                  (data[10] << 8) | data[11];
567 
568       log_message(5, "First session %u, last session %u, last session start %ld",
569 	      data[2], data[3], diskInfo_.lastSessionLba);
570     }
571     else {
572       log_message(5, "READ TOC (format 1) failed.");
573     }
574 
575     if (diskInfo_.sessionCnt > 0) {
576       int len;
577       CdRawToc *toc = getRawToc(diskInfo_.sessionCnt, &len);
578 
579       if (toc != NULL) {
580 	for (i = 0; i < len; i++) {
581 	  if (toc[i].sessionNr == diskInfo_.sessionCnt) {
582 #if 0
583 	    if (toc[i].point == 0xb0 && toc[i].min != 0xff &&
584 		toc[i].sec != 0xff && toc[i].frame != 0xff) {
585 	      int m = toc[i].min;
586 	      int s = toc[i].sec;
587 	      int f = toc[i].frame;
588 
589 	      if (m < 90 && s < 60 && f < 75) {
590 		diskInfo_.thisSessionLba = Msf(m, s, f).lba(); // + 150 - 150
591 		diskInfo_.thisSessionLba += leadInLength_;
592 	      }
593 	    }
594 #endif
595 	    if (toc[i].point == 0xa0) {
596 	      diskInfo_.diskTocType = toc[i].psec;
597 	    }
598 	  }
599 
600 	  // The point C0 entry may be only stored in the first session's
601 	  // lead-in
602 	  if (toc[i].point == 0xc0 && toc[i].pmin <= 99 &&
603 	      toc[i].psec < 60 && toc[i].pframe < 75) {
604 	    diskInfo_.manufacturerId =
605 	      Msf(toc[i].pmin, toc[i].psec, toc[i].pframe);
606 	    diskInfo_.valid.manufacturerId = 1;
607 	  }
608 	}
609 
610 #if 0
611 	if (diskInfo_.thisSessionLba > 0) {
612 	  if (diskInfo_.lastTrackNr < 99)
613 	    diskInfo_.append = 1;
614 	}
615 	else {
616 	  log_message(4, "Did not find BO pointer in session %d.",
617 		  diskInfo_.sessionCnt);
618 
619 	}
620 #endif
621 
622 	delete[] toc;
623       }
624       else {
625 	log_message(5, "getRawToc failed.");
626       }
627     }
628   }
629   else {
630     // disk is empty and appendable
631     diskInfo_.empty = 1;
632   }
633 
634   if (diskInfo_.append == 0)
635     diskInfo_.empty = 0;
636 
637   return &diskInfo_;
638 }
639 
getRawToc(int sessionNr,int * len)640 CdRawToc *CDD2600::getRawToc(int sessionNr, int *len)
641 {
642   unsigned char cmd[10];
643   unsigned short dataLen;
644   unsigned char *data = NULL;;
645   unsigned char reqData[4]; // buffer for requestion the actual length
646   unsigned char *p = NULL;
647   int i;
648   CdRawToc *rawToc;
649   int entries;
650 
651   assert(sessionNr >= 1);
652 
653   // read disk toc length
654   memset(cmd, 0, 10);
655   cmd[0] = 0x43; // READ TOC
656   cmd[6] = sessionNr;
657   cmd[8] = 4;
658   cmd[9] |= 2 << 6; // get Q subcodes
659 
660   if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) {
661     log_message(-2, "Cannot read raw disk toc.");
662     return NULL;
663   }
664 
665   dataLen = ((reqData[0] << 8) | reqData[1]) + 2;
666 
667   log_message(5, "Raw toc data len: %d", dataLen);
668 
669   data = new unsigned char[dataLen];
670 
671   // read disk toc
672   cmd[7] = dataLen >> 8;
673   cmd[8] = dataLen;
674 
675   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
676     log_message(-2, "Cannot read raw disk toc.");
677     delete[] data;
678     return NULL;
679   }
680 
681   entries = (((data[0] << 8) | data[1]) - 2) / 11;
682 
683 
684   rawToc = new CdRawToc[entries];
685 
686   for (i = 0, p = data + 4; i < entries; i++, p += 11 ) {
687 #if 0
688     log_message(0, "%d %02x %02d %2x %02d:%02d:%02d %02x %02d:%02d:%02d",
689 	    p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]);
690 #endif
691     rawToc[i].sessionNr = p[0];
692     rawToc[i].adrCtl = p[1];
693     rawToc[i].point = p[3];
694     rawToc[i].min = p[4];
695     rawToc[i].sec = p[5];
696     rawToc[i].frame = p[6];
697     rawToc[i].pmin = p[8];
698     rawToc[i].psec = p[9];
699     rawToc[i].pframe = p[10];
700   }
701 
702   delete[] data;
703 
704   *len = entries;
705 
706   return rawToc;
707 }
708 
readTrackData(TrackData::Mode mode,TrackData::SubChannelMode,long lba,long len,unsigned char * buf)709 long CDD2600::readTrackData(TrackData::Mode mode, TrackData::SubChannelMode,
710 			    long lba, long len, unsigned char *buf)
711 {
712   unsigned char cmd[10];
713   long blockLen = 2340;
714   long i;
715   TrackData::Mode actMode;
716   int ok = 0;
717   const unsigned char *sense;
718   int senseLen;
719   int softError;
720 
721   if (setBlockSize(blockLen) != 0)
722     return 0;
723 
724   memset(cmd, 0, 10);
725 
726   cmd[0] = 0x28; // READ10
727   cmd[2] = lba >> 24;
728   cmd[3] = lba >> 16;
729   cmd[4] = lba >> 8;
730   cmd[5] = lba;
731 
732   /*
733   if (mode == TrackData::MODE2_FORM1 || mode == TrackData::MODE2_FORM2)
734     cmd[9] = 1 << 6; // MIX flag
735     */
736 
737   while (len > 0 && !ok) {
738     cmd[7] = len >> 8;
739     cmd[8] = len;
740 
741     memset(transferBuffer_, 0, len * blockLen);
742     switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) {
743     case 0:
744       ok = 1;
745       break;
746 
747     case 2:
748       softError = 0;
749       sense = scsiIf_->getSense(senseLen);
750 
751       if (senseLen > 0x0c) {
752 	if ((sense[2] &0x0f) == 5) {
753 	  switch (sense[12]) {
754 	  case 0x64: // Illegal mode for this track
755 	    softError = 1;
756 	    break;
757 	  }
758 	}
759 	else if ((sense[2] & 0x0f) == 3) { // Medium error
760 	  switch (sense[12]) {
761 	  case 0x02: // No seek complete, sector not found
762 	  case 0x11: // L-EC error
763 	    return -2;
764 	    break;
765 	  }
766 	}
767       }
768 
769       if (!softError) {
770 	scsiIf_->printError();
771 	return -1;
772       }
773       break;
774 
775     default:
776       log_message(-2, "Read error at LBA %ld, len %ld", lba, len);
777       return -1;
778       break;
779     }
780 
781     if (!ok) {
782       len--;
783     }
784   }
785 
786   unsigned char *sector = transferBuffer_;
787   for (i = 0; i < len; i++) {
788     actMode = determineSectorMode(sector);
789 
790     if (!(actMode == mode ||
791 	  (mode == TrackData::MODE2_FORM_MIX &&
792 	   (actMode == TrackData::MODE2_FORM1 ||
793 	    actMode == TrackData::MODE2_FORM2)) ||
794 
795 	  (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) ||
796 
797 	  (mode == TrackData::MODE2_RAW &&
798 	   (actMode == TrackData::MODE2 ||
799 	    actMode == TrackData::MODE2_FORM1 ||
800 	    actMode == TrackData::MODE2_FORM2)))) {
801       return i;
802     }
803 
804     if (buf != NULL) {
805       switch (mode) {
806       case TrackData::MODE1:
807 	memcpy(buf, sector + 4, MODE1_BLOCK_LEN);
808 	buf += MODE1_BLOCK_LEN;
809 	break;
810       case TrackData::MODE2:
811       case TrackData::MODE2_FORM_MIX:
812 	memcpy(buf, sector + 4, MODE2_BLOCK_LEN);
813 	buf += MODE2_BLOCK_LEN;
814 	break;
815       case TrackData::MODE2_FORM1:
816 	memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN);
817 	buf += MODE2_FORM1_DATA_LEN;
818 	break;
819       case TrackData::MODE2_FORM2:
820 	memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN);
821 	buf += MODE2_FORM2_DATA_LEN;
822 	break;
823       case TrackData::MODE1_RAW:
824       case TrackData::MODE2_RAW:
825 	memcpy(buf, syncPattern, 12);
826 	memcpy(buf + 12, sector, 2340);
827 	buf += AUDIO_BLOCK_LEN;
828 	break;
829       case TrackData::MODE0:
830       case TrackData::AUDIO:
831 	log_message(-3, "CDD2600::readTrackData: Illegal mode.");
832 	return 0;
833 	break;
834       }
835     }
836 
837     sector += blockLen;
838   }
839 
840   return len;
841 }
842 
readSubChannels(TrackData::SubChannelMode,long lba,long len,SubChannel *** chans,Sample * audioData)843 int CDD2600::readSubChannels(TrackData::SubChannelMode, long lba, long len,
844 			     SubChannel ***chans, Sample *audioData)
845 {
846   unsigned char cmd[10];
847   int tries = 5;
848   int ret;
849 
850   if (setBlockSize(AUDIO_BLOCK_LEN) != 0)
851     return 1;
852 
853   memset(cmd, 0, 10);
854 
855   cmd[0] = 0x28; // READ10
856   cmd[2] = lba >> 24;
857   cmd[3] = lba >> 16;
858   cmd[4] = lba >> 8;
859   cmd[5] = lba;
860   cmd[7] = len >> 8;
861   cmd[8] = len;
862 
863   do {
864     ret = sendCmd(cmd, 10, NULL, 0,
865 		  (unsigned char*)audioData, len * AUDIO_BLOCK_LEN,
866 		  (tries == 1) ? 1 : 0);
867 
868     if (ret != 0 && tries == 1) {
869       log_message(-2, "Reading of audio data failed at sector %ld.", lba);
870       return 1;
871     }
872 
873     tries--;
874   } while (ret != 0 && tries > 0);
875 
876   *chans = NULL;
877   return 0;
878 }
879 
readAudioRange(ReadDiskInfo * rinfo,int fd,long start,long end,int startTrack,int endTrack,TrackInfo * info)880 int CDD2600::readAudioRange(ReadDiskInfo *rinfo, int fd, long start, long end,
881 			    int startTrack, int endTrack,
882 			    TrackInfo *info)
883 {
884   if (!onTheFly_) {
885     int t;
886 
887     log_message(1, "Analyzing...");
888 
889     for (t = startTrack; t <= endTrack; t++) {
890       long totalProgress;
891 
892       totalProgress = t * 1000;
893       totalProgress /= rinfo->tracks;
894 
895       sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 0,
896 			    totalProgress);
897 
898       log_message(2, "Track %d...", t + 1);
899       info[t].isrcCode[0] = 0;
900       readIsrc(t + 1, info[t].isrcCode);
901 
902       if (info[t].isrcCode[0] != 0)
903 	log_message(2, "Found ISRC code.");
904 
905       totalProgress = (t + 1) * 1000;
906       totalProgress /= rinfo->tracks;
907 
908       sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 1000,
909 			    totalProgress);
910     }
911 
912     log_message(1, "Reading...");
913   }
914 
915   return CdrDriver::readAudioRangeParanoia(rinfo, fd, start, end, startTrack,
916 					   endTrack, info);
917 }
918