1 /*  cdrdao - write audio CD-Rs in disc-at-once mode
2  *
3  *  Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 <time.h>
24 #include <assert.h>
25 
26 #include "GenericMMC.h"
27 
28 #include "port.h"
29 #include "Toc.h"
30 #include "log.h"
31 #include "PQSubChannel16.h"
32 #include "PWSubChannel96.h"
33 #include "CdTextEncoder.h"
34 
35 
36 
37 // Variants for cue sheet generation
38 
39 // do not set ctl flags for ISRC cue sheet entries
40 #define CUE_VAR_ISRC_NO_CTL 0x1
41 
42 // do not set start of lead-in time in lead-in cue sheet entry
43 #define CUE_VAR_CDTEXT_NO_TIME 0x2
44 
45 #define CUE_VAR_MAX 0x3
46 
47 
48 // Variants for write parameters mode page
49 
50 //do not set data block type to block size 2448 if a CD-TEXT lead-in is written
51 #define WMP_VAR_CDTEXT_NO_DATA_BLOCK_TYPE 0x1
52 
53 #define WMP_VAR_MAX 0x1
54 
55 
GenericMMC(ScsiIf * scsiIf,unsigned long options)56 GenericMMC::GenericMMC(ScsiIf *scsiIf, unsigned long options)
57   : CdrDriver(scsiIf, options)
58 {
59   int i;
60   driverName_ = "Generic SCSI-3/MMC - Version 2.0";
61 
62   speed_ = 0;
63   rspeed_ = 0;
64   simulate_ = true;
65   encodingMode_ = 1;
66 
67   scsiTimeout_ = 0;
68 
69   cdTextEncoder_ = NULL;
70 
71   driveInfo_ = NULL;
72 
73   memset(&diskInfo_, 0, sizeof(DiskInfo));
74 
75   for (i = 0; i < maxScannedSubChannels_; i++) {
76     if (options_ & OPT_MMC_USE_PQ)
77       scannedSubChannels_[i] = new PQSubChannel16;
78     else
79       scannedSubChannels_[i] = new PWSubChannel96;
80   }
81 
82   // MMC drives usually return little endian samples
83   audioDataByteOrder_ = 0;
84 }
85 
~GenericMMC()86 GenericMMC::~GenericMMC()
87 {
88   int i;
89 
90   for (i = 0; i < maxScannedSubChannels_; i++) {
91     delete scannedSubChannels_[i];
92     scannedSubChannels_[i] = NULL;
93   }
94 
95   delete cdTextEncoder_;
96   cdTextEncoder_ = NULL;
97 
98   delete driveInfo_;
99   driveInfo_ = NULL;
100 }
101 
102 // static constructor
instance(ScsiIf * scsiIf,unsigned long options)103 CdrDriver *GenericMMC::instance(ScsiIf *scsiIf, unsigned long options)
104 {
105   return new GenericMMC(scsiIf, options);
106 }
107 
108 
checkToc(const Toc * toc)109 int GenericMMC::checkToc(const Toc *toc)
110 {
111   int err = CdrDriver::checkToc(toc);
112   int e;
113 
114   if (options_ & OPT_MMC_CD_TEXT) {
115     if ((e = toc->checkCdTextData()) > err)
116       err = e;
117   }
118 
119   return err;
120 }
121 
subChannelEncodingMode(TrackData::SubChannelMode sm) const122 int GenericMMC::subChannelEncodingMode(TrackData::SubChannelMode sm) const
123 {
124   int ret = 0;
125 
126   switch (sm) {
127   case TrackData::SUBCHAN_NONE:
128     ret = 0;
129     break;
130 
131   case TrackData::SUBCHAN_RW:
132 #if 0
133     if (options_ & OPT_MMC_NO_RW_PACKED)
134       ret = 1; // have to encode the R-W sub-channel data
135     else
136       ret = 0;
137 #endif
138     ret = 0;
139     break;
140 
141   case TrackData::SUBCHAN_RW_RAW:
142     // raw R-W sub-channel writing is assumed to be always supported
143     ret = 1;
144     break;
145   }
146 
147   return ret;
148 }
149 
150 // sets speed
151 // return: 0: OK
152 //         1: illegal speed
speed(int s)153 int GenericMMC::speed(int s)
154 {
155   speed_ = s;
156 
157   if (selectSpeed() != 0)
158     return 1;
159 
160   return 0;
161 }
162 
speed()163 int GenericMMC::speed()
164 {
165   const DriveInfo *di;
166 
167   delete driveInfo_;
168   driveInfo_ = NULL;
169 
170   if ((di = driveInfo(true)) == NULL) {
171     return 0;
172   }
173 
174   return speed2Mult(di->currentWriteSpeed);
175 
176 }
177 
178 // sets fspeed
179 // return: true: OK
180 //         false: illegal speed
rspeed(int s)181 bool GenericMMC::rspeed(int s)
182 {
183   rspeed_ = s;
184 
185   if (selectSpeed() != 0)
186     return false;
187 
188   return true;
189 }
190 
rspeed()191 int GenericMMC::rspeed()
192 {
193   const DriveInfo *di;
194 
195   delete driveInfo_;
196   driveInfo_ = NULL;
197 
198   if ((di = driveInfo(true)) == NULL) {
199     return 0;
200   }
201 
202   return speed2Mult(di->currentReadSpeed);
203 }
204 
205 
206 // loads ('unload' == 0) or ejects ('unload' == 1) tray
207 // return: 0: OK
208 //         1: scsi command failed
loadUnload(int unload) const209 int GenericMMC::loadUnload(int unload) const
210 {
211   unsigned char cmd[6];
212 
213   memset(cmd, 0, 6);
214 
215   cmd[0] = 0x1b; // START/STOP UNIT
216   if (unload) {
217     cmd[4] = 0x02; // LoUnlo=1, Start=0
218   }
219   else {
220     cmd[4] = 0x03; // LoUnlo=1, Start=1
221   }
222 
223   if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) {
224     log_message(-2, "Cannot load/unload medium.");
225     return 1;
226   }
227 
228   return 0;
229 }
230 
231 // Checks for ready status of the drive after a write operation
232 // Return: 0: drive ready
233 //         1: error occured
234 //         2: drive not ready
235 
checkDriveReady() const236 int GenericMMC::checkDriveReady() const
237 {
238   unsigned char cmd[10];
239   unsigned char data[4];
240   int ret;
241 
242   ret = testUnitReady(0);
243 
244   if (ret == 0) {
245     // testUnitReady reports ready status but this might actually not
246     // be the truth -> additionally check the READ DISK INFO command
247 
248     memset(cmd, 0, 10);
249 
250     cmd[0] = 0x51; // READ DISK INFORMATION
251     cmd[8] = 4;
252 
253     ret = sendCmd(cmd, 10, NULL, 0, data, 4, 0);
254 
255     if (ret == 2) {
256       const unsigned char *sense;
257       int senseLen;
258 
259       ret = 0; // indicates ready status
260 
261       sense = scsiIf_->getSense(senseLen);
262 
263       if (senseLen >= 14 && (sense[2] & 0x0f) == 0x2 && sense[7] >= 6 &&
264           sense[12] == 0x4 &&
265           (sense[13] == 0x8 || sense[13] == 0x7)) {
266         // Not Ready, long write in progress
267         ret = 2; // indicates not ready status
268       }
269     }
270   }
271 
272   return ret;
273 }
274 
275 // Performs complete blanking of a CD-RW.
276 // return: 0: OK
277 //         1: scsi command failed
blankDisk(BlankingMode mode)278 int GenericMMC::blankDisk(BlankingMode mode)
279 {
280   unsigned char cmd[12];
281   int ret, progress;
282   time_t startTime, endTime;
283 
284   setSimulationMode(0);
285 
286 
287   memset(cmd, 0, 12);
288 
289   cmd[0] = 0xa1; // BLANK
290 
291   switch (mode) {
292   case BLANK_FULL:
293     cmd[1] = 0x0; // erase complete disk
294     break;
295   case BLANK_MINIMAL:
296     cmd[1] = 0x1; // erase PMA, lead-in and 1st track's pre-gap
297     break;
298   }
299 
300   cmd[1] |= 1 << 4; // immediate return
301 
302   sendBlankCdProgressMsg(0);
303 
304   if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) {
305     log_message(-2, "Cannot erase CD-RW.");
306     return 1;
307   }
308 
309   time(&startTime);
310   progress = 0;
311 
312   do {
313     mSleep(2000);
314 
315     ret = checkDriveReady();
316 
317     if (ret == 1) {
318       log_message(-2, "Test Unit Ready command failed.");
319     }
320 
321     progress += 10;
322     sendBlankCdProgressMsg(progress);
323 
324     if (progress >= 1000)
325       progress = 0;
326 
327   } while (ret == 2);
328 
329   if (ret == 0)
330     sendBlankCdProgressMsg(1000);
331 
332   time(&endTime);
333 
334   log_message(2, "Blanking time: %ld seconds", endTime - startTime);
335 
336   return ret;
337 }
338 
339 // sets read/write speed and simulation mode
340 // return: 0: OK
341 //         1: scsi command failed
selectSpeed()342 int GenericMMC::selectSpeed()
343 {
344   unsigned char cmd[12];
345   int spd;
346 
347   memset(cmd, 0, 12);
348 
349   cmd[0] = 0xbb; // SET CD SPEED
350 
351   // select maximum read speed
352   if (rspeed_ == 0) {
353     cmd[2] = 0xff;
354     cmd[3] = 0xff;
355   }
356   else {
357     spd = mult2Speed(rspeed_);
358     cmd[2] = spd >> 8;
359     cmd[3] = spd;
360   }
361 
362   // select maximum write speed
363   if (speed_ == 0) {
364     cmd[4] = 0xff;
365     cmd[5] = 0xff;
366   }
367   else {
368     spd = mult2Speed(speed_);
369     cmd[4] = spd >> 8;
370     cmd[5] = spd;
371   }
372 
373   if ((options_ & OPT_MMC_YAMAHA_FORCE_SPEED) != 0 &&
374       writeSpeedControl())
375     cmd[11] = 0x80; // enable Yamaha's force speed
376 
377   if (sendCmd(cmd, 12, NULL, 0, NULL, 0) != 0) {
378     log_message(-2, "Cannot set cd speed.");
379     return 1;
380   }
381 
382   return 0;
383 }
384 
385 // Determins start and length of lead-in and length of lead-out.
386 // return: 0: OK
387 //         1: SCSI command failed
getSessionInfo()388 int GenericMMC::getSessionInfo()
389 {
390   unsigned char cmd[10];
391   unsigned long dataLen = 34;
392   unsigned char data[34];
393 
394   memset(cmd, 0, 10);
395   memset(data, 0, dataLen);
396 
397   cmd[0] = 0x51; // READ DISK INFORMATION
398   cmd[7] = dataLen >> 8;
399   cmd[8] = dataLen;
400 
401   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
402     log_message(-2, "Cannot retrieve disk information.");
403     return 1;
404   }
405 
406   leadInStart_ = Msf(data[17], data[18], data[19]);
407 
408   if (leadInStart_.lba() >= Msf(80, 0, 0).lba()) {
409     leadInLen_ = 450000 - leadInStart_.lba();
410 
411     if (fullBurn_) {
412     	leadOutLen_ = (userCapacity_ ? Msf(userCapacity_, 0, 0).lba() : diskInfo_.capacity) + Msf(1, 30, 0).lba() - toc_->length().lba() - diskInfo_.thisSessionLba - 150; // Fill all rest space <vladux>
413 	if (leadOutLen_ < Msf(1, 30, 0).lba()) {
414 		leadOutLen_ = Msf(1, 30, 0).lba(); // 90 seconds lead-out
415 	}
416     } else {
417     	leadOutLen_ = Msf(1, 30, 0).lba(); // 90 seconds lead-out
418     }
419   }
420   else {
421     leadInLen_ = Msf(1, 0, 0).lba();
422     leadOutLen_ = Msf(0, 30, 0).lba();
423   }
424 
425 
426   log_message(4, "Lead-in start: %s length: %ld", leadInStart_.str(),
427 	  leadInLen_);
428   log_message(4, "Lead-out length: %ld", leadOutLen_);
429 
430   return 0;
431 }
432 
readBufferCapacity(long * capacity,long * available)433 bool GenericMMC::readBufferCapacity(long *capacity, long *available)
434 {
435   unsigned char cmd[10];
436   unsigned char data[12];
437   long bufsize;
438 
439   memset(cmd, 0, 10);
440   memset(data, 0, 12);
441 
442   cmd[0] = 0x5c; // READ BUFFER CAPACITY
443   cmd[8] = 12;
444 
445   if (sendCmd(cmd, 10, NULL, 0, data, 12) != 0) {
446     log_message(-2, "Read buffer capacity failed.");
447     return false;
448   }
449 
450   *capacity = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
451   *available = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11];
452 
453   return true;
454 }
455 
performPowerCalibration()456 int GenericMMC::performPowerCalibration()
457 {
458   unsigned char cmd[10];
459   int ret;
460   long old_timeout;
461 
462   memset(cmd, 0, 10);
463 
464   cmd[0] = 0x54; // SEND OPC INFORMATION
465   cmd[1] = 1;
466 
467   log_message(2, "Executing power calibration...");
468 
469   old_timeout = scsiIf_->timeout(30);
470   ret = sendCmd(cmd, 10, NULL, 0, NULL, 0);
471   (void)scsiIf_->timeout(old_timeout);
472 
473   if (ret == 0) {
474     log_message(2, "Power calibration successful.");
475     return 0;
476   }
477   if (ret == 2) {
478     const unsigned char *sense;
479     int senseLen;
480 
481     sense = scsiIf_->getSense(senseLen);
482 
483     if (senseLen >= 14 && (sense[2] & 0x0f) == 0x5 && sense[7] >= 6 &&
484       sense[12] == 0x20 && sense[13] == 0x0) {
485       log_message(2, "Power calibration not supported.");
486       return 0;
487     } /* else fall trough */
488   }
489   log_message(-2, "Power calibration failed.");
490   return 1;
491 }
492 
493 // Sets write parameters via mode page 0x05.
494 // return: 0: OK
495 //         1: scsi command failed
setWriteParameters(unsigned long variant)496 int GenericMMC::setWriteParameters(unsigned long variant)
497 {
498   unsigned char mp[0x38];
499   unsigned char mpHeader[8];
500   unsigned char blockDesc[8];
501 
502   if (getModePage(5/*write parameters mode page*/, mp, 0x38,
503 		  mpHeader, blockDesc, 1) != 0) {
504     log_message(-2, "Cannot retrieve write parameters mode page.");
505     return 1;
506   }
507 
508   mp[0] &= 0x7f; // clear PS flag
509 
510   mp[2] &= 0xe0;
511   mp[2] |= 0x02; // write type: Session-at-once
512   if (simulate_) {
513     mp[2] |= 1 << 4; // test write
514   }
515 
516   const DriveInfo *di;
517   if ((di = driveInfo(true)) != NULL) {
518     if (di->burnProof) {
519       // This drive has BURN-Proof function.
520       // Enable it unless explicitly disabled.
521       if (bufferUnderRunProtection()) {
522 	log_message(2, "Turning BURN-Proof on");
523 	mp[2] |= 0x40;
524       }
525       else {
526 	log_message(2, "Turning BURN-Proof off");
527 	mp[2] &= ~0x40;
528       }
529     }
530 
531     RicohSetWriteOptions(di);
532   }
533 
534   mp[3] &= 0x3f; // Multi-session: No B0 pointer, next session not allowed
535 
536   if (multiSession_)
537     mp[3] |= 0x03 << 6; // open next session
538   else if (!diskInfo_.empty)
539     mp[3] |= 0x01 << 6; // use B0=FF:FF:FF when closing last session of a
540                         // multi session CD-R
541 
542   log_message(4, "Multi session mode: %d", mp[3] >> 6);
543 
544   mp[4] &= 0xf0; // Data Block Type: raw data, block size: 2352 (I think not
545                  // used for session at once writing)
546 
547   if (cdTextEncoder_ != NULL) {
548     if ((variant & WMP_VAR_CDTEXT_NO_DATA_BLOCK_TYPE) == 0)
549       mp[4] |= 3; /* Data Block Type: raw data with raw P-W sub-channel data,
550 		     block size 2448, required for CD-TEXT lead-in writing
551 		     according to the SCSI/MMC-3 manual
552 		  */
553   }
554 
555   log_message(4, "Data block type: %u",  mp[4] & 0x0f);
556 
557   mp[8] = sessionFormat();
558 
559   if (!diskInfo_.empty) {
560     // use the toc type of the already recorded sessions
561     switch (diskInfo_.diskTocType) {
562     case 0x00:
563     case 0x10:
564     case 0x20:
565       mp[8] = diskInfo_.diskTocType;
566       break;
567     }
568   }
569 
570   log_message(4, "Toc type: 0x%x", mp[8]);
571 
572   if (setModePage(mp, mpHeader, NULL, 0) != 0) {
573     log_message(-2, "Cannot set write parameters mode page.");
574     return 1;
575   }
576 
577   return 0;
578 }
579 
580 // Sets simulation mode via mode page 0x05.
581 // return: 0: OK
582 //         1: scsi command failed
setSimulationMode(int showMessage)583 int GenericMMC::setSimulationMode(int showMessage)
584 {
585   unsigned char mp[0x38];
586   unsigned char mpHeader[8];
587 
588   if (getModePage(5/*write parameters mode page*/, mp, 0x38,
589 		  mpHeader, NULL, showMessage) != 0) {
590     if (showMessage)
591       log_message(-2, "Cannot retrieve write parameters mode page.");
592     return 1;
593   }
594 
595   mp[0] &= 0x7f; // clear PS flag
596 
597   if (simulate_)
598     mp[2] |= 1 << 4; // test write
599   else
600     mp[2] &= ~(1 << 4);
601 
602   if (setModePage(mp, mpHeader, NULL, showMessage) != 0) {
603     if (showMessage)
604       log_message(-2, "Cannot set write parameters mode page.");
605     return 1;
606   }
607 
608   return 0;
609 }
610 
getNWA(long * nwa)611 int GenericMMC::getNWA(long *nwa)
612 {
613   unsigned char cmd[10];
614   int infoblocklen = 16;
615   unsigned char info[16];
616   long lba = 0;
617 
618   cmd[0] = 0x52; // READ TRACK INFORMATION
619   cmd[1] = 0x01; // track instead of lba designation
620   cmd[2] = 0x00;
621   cmd[3] = 0x00;
622   cmd[4] = 0x00;
623   cmd[5] = 0xff; // invisible track
624   cmd[6] = 0x00; // reserved
625   cmd[7] = infoblocklen << 8;
626   cmd[8] = infoblocklen; // alloc length
627   cmd[9] = 0x00; // Control Byte
628 
629   if (sendCmd(cmd, 10, NULL, 0, info, infoblocklen) != 0) {
630     log_message(-2, "Cannot get Track Information Block.");
631     return 1;
632   }
633 
634 #if 0
635   log_message(3,"Track Information Block");
636   for (int i=0;i<infoblocklen;i++) log_message(3,"byte %02x : %02x",i,info[i]);
637 #endif
638 
639   if ((info[6] & 0x40) && (info[7] & 0x01) && !(info[6] & 0xb0))
640   {
641       log_message(4,"Track is Blank, Next Writable Address is valid");
642       lba |= info[12] << 24; // MSB of LBA
643       lba |= info[13] << 16;
644       lba |= info[14] << 8;
645       lba |= info[15];       // LSB of LBA
646   }
647 
648   log_message(4, "NWA: %ld", lba);
649 
650   if (nwa != NULL)
651     *nwa = lba;
652 
653   return 0;
654 }
655 
656 // Determines first writable address of data area of current empty session.
657 // lba: set to start of data area
658 // return: 0: OK
659 //         1: error occured
getStartOfSession(long * lba)660 int GenericMMC::getStartOfSession(long *lba)
661 {
662   unsigned char mp[0x38];
663   unsigned char mpHeader[8];
664 
665   // first set the writing mode because it influences which address is
666   // returned with 'READ TRACK INFORMATION'
667 
668   if (getModePage(5/*write parameters mode page*/, mp, 0x38,
669 		  mpHeader, NULL, 0) != 0) {
670     return 1;
671   }
672 
673   mp[0] &= 0x7f; // clear PS flag
674 
675   mp[2] &= 0xe0;
676   mp[2] |= 0x02; // write type: Session-at-once
677 
678   if (setModePage(mp, mpHeader, NULL, 1) != 0) {
679     log_message(-2, "Cannot set write parameters mode page.");
680     return 1;
681   }
682 
683   return getNWA(lba);
684 }
685 
leadInOutDataMode(TrackData::Mode mode)686 static unsigned char leadInOutDataMode(TrackData::Mode mode)
687 {
688   unsigned char ret = 0;
689 
690   switch (mode) {
691   case TrackData::AUDIO:
692     ret = 0x01;
693     break;
694 
695   case TrackData::MODE0: // should not happen
696   case TrackData::MODE1:
697   case TrackData::MODE1_RAW:
698     ret = 0x14;
699     break;
700 
701   case TrackData::MODE2_FORM1:
702   case TrackData::MODE2_FORM2:
703   case TrackData::MODE2_FORM_MIX:
704   case TrackData::MODE2_RAW: // assume it contains XA sectors
705     ret = 0x24;
706     break;
707 
708   case TrackData::MODE2:
709     ret = 0x34;
710     break;
711   }
712 
713   return ret;
714 }
715 
716 
subChannelDataForm(TrackData::SubChannelMode sm,int encodingMode)717 unsigned char GenericMMC::subChannelDataForm(TrackData::SubChannelMode sm,
718 					     int encodingMode)
719 {
720   unsigned char ret = 0;
721 
722   switch (sm) {
723   case TrackData::SUBCHAN_NONE:
724     break;
725 
726   case TrackData::SUBCHAN_RW:
727   case TrackData::SUBCHAN_RW_RAW:
728     if (encodingMode == 0)
729       ret = 0xc0;
730     else
731       ret = 0x40;
732     break;
733   }
734 
735   return ret;
736 }
737 
738 
739 // Creates cue sheet for current toc.
740 // cueSheetLen: filled with length of cue sheet in bytes
741 // return: newly allocated cue sheet buffer or 'NULL' on error
createCueSheet(unsigned long variant,long * cueSheetLen)742 unsigned char *GenericMMC::createCueSheet(unsigned long variant,
743 					  long *cueSheetLen)
744 {
745   const Track *t;
746   int trackNr;
747   Msf start, end, index;
748   unsigned char *cueSheet;
749   long len = 3; // entries for lead-in, gap, lead-out
750   long n; // index into cue sheet
751   unsigned char ctl; // control nibbles of cue sheet entry CTL/ADR
752   long i;
753   unsigned char dataMode;
754   int trackOffset;
755   long lbaOffset;
756 
757   if (!diskInfo_.empty && diskInfo_.append) {
758     if (toc_->firstTrackNo() != 0 && toc_->firstTrackNo() != diskInfo_.lastTrackNr + 1) {
759       log_message(-2, "Number of first track doesn't match");
760       return NULL;
761     }
762 #if 0
763     /* for progress message */
764     toc_->firstTrackNo(diskInfo_.lastTrackNr + 1);
765 #endif
766     trackOffset = diskInfo_.lastTrackNr;
767     lbaOffset = diskInfo_.thisSessionLba;
768   } else {
769     trackOffset = toc_->firstTrackNo() == 0 ? 0 : toc_->firstTrackNo() - 1;
770     lbaOffset = 0;
771   }
772   if (trackOffset + toc_->nofTracks() > 99) {
773     log_message(-2, "Track numbers too large");
774     return NULL;
775   }
776 
777   TrackIterator itr(toc_);
778 
779   if (itr.first(start, end) == NULL) {
780     return NULL;
781   }
782 
783   if (toc_->catalogValid()) {
784     len += 2;
785   }
786 
787   for (t = itr.first(start, end), trackNr = 1;
788        t != NULL; t = itr.next(start, end), trackNr++) {
789     len += 1; // entry for track
790     if (t->start().lba() != 0 && trackNr > 1) {
791       len += 1; // entry for pre-gap
792     }
793     if (t->type() == TrackData::AUDIO && t->isrcValid()) {
794       len += 2; // entries for ISRC code
795     }
796     len += t->nofIndices(); // entry for each index increment
797   }
798 
799   cueSheet = new unsigned char[len * 8];
800   n = 0;
801 
802   if (toc_->leadInMode() == TrackData::AUDIO) {
803     ctl = 0;
804   }
805   else {
806     ctl = 0x40;
807   }
808 
809   if (toc_->catalogValid()) {
810     // fill catalog number entry
811     cueSheet[n*8] = 0x02 | ctl;
812     cueSheet[(n+1)*8] = 0x02 | ctl;
813     for (i = 1; i <= 13; i++) {
814       if (i < 8) {
815 	cueSheet[n*8 + i] = toc_->catalog(i-1) + '0';
816       }
817       else {
818 	cueSheet[(n+1)*8 + i - 7] = toc_->catalog(i-1) + '0';
819       }
820     }
821     cueSheet[(n+1)*8+7] = 0;
822     n += 2;
823   }
824 
825   // entry for lead-in
826   cueSheet[n*8] = 0x01 | ctl; // CTL/ADR
827   cueSheet[n*8+1] = 0;    // Track number
828   cueSheet[n*8+2] = 0;    // Index
829 
830   if (cdTextEncoder_ != NULL) {
831     cueSheet[n*8+3] = 0x41; // Data Form: CD-DA with P-W sub-channels,
832                             // main channel data generated by device
833   }
834   else {
835     cueSheet[n*8+3] = leadInOutDataMode(toc_->leadInMode());
836   }
837 
838   cueSheet[n*8+4] = 0;    // Serial Copy Management System
839 
840   if (cdTextEncoder_ != NULL &&
841       (variant & CUE_VAR_CDTEXT_NO_TIME) == 0) {
842     cueSheet[n*8+5] = leadInStart_.min();
843     cueSheet[n*8+6] = leadInStart_.sec();
844     cueSheet[n*8+7] = leadInStart_.frac();
845   }
846   else {
847     cueSheet[n*8+5] = 0;    // MIN
848     cueSheet[n*8+6] = 0;    // SEC
849     cueSheet[n*8+7] = 0;    // FRAME
850   }
851 
852   n++;
853 
854   int firstTrack = 1;
855 
856   for (t = itr.first(start, end), trackNr = trackOffset + 1;
857        t != NULL;
858        t = itr.next(start, end), trackNr++) {
859     if (encodingMode_ == 0) {
860       // just used for some experiments with raw writing
861       dataMode = 0;
862     }
863     else {
864       switch (t->type()) {
865       case TrackData::AUDIO:
866 	dataMode = 0;
867 	break;
868       case TrackData::MODE1:
869       case TrackData::MODE1_RAW:
870 	dataMode = 0x10;
871 	break;
872       case TrackData::MODE2:
873 	dataMode = 0x30;
874 	break;
875       case TrackData::MODE2_RAW: // assume it contains XA sectors
876       case TrackData::MODE2_FORM1:
877       case TrackData::MODE2_FORM2:
878       case TrackData::MODE2_FORM_MIX:
879 	dataMode = 0x20;
880 	break;
881       default:
882 	dataMode = 0;
883 	break;
884       }
885     }
886 
887     // add mode for sub-channel writing
888     dataMode |= subChannelDataForm(t->subChannelType(),
889 				   subChannelEncodingMode(t->subChannelType()));
890 
891     ctl = 0;
892     if (t->copyPermitted()) {
893       ctl |= 0x20;
894     }
895 
896     if (t->type() == TrackData::AUDIO) {
897       // audio track
898       if (t->preEmphasis()) {
899 	ctl |= 0x10;
900       }
901       if (t->audioType() == 1) {
902 	ctl |= 0x80;
903       }
904 
905       if (t->isrcValid()) {
906 	if ((variant & CUE_VAR_ISRC_NO_CTL) == 0)
907 	  cueSheet[n*8] = ctl | 0x03;
908 	else
909 	  cueSheet[n*8] = 0x03;
910 
911 	cueSheet[n*8+1] = trackNr;
912 	cueSheet[n*8+2] = t->isrcCountry(0);
913 	cueSheet[n*8+3] = t->isrcCountry(1);
914 	cueSheet[n*8+4] = t->isrcOwner(0);
915 	cueSheet[n*8+5] = t->isrcOwner(1);
916 	cueSheet[n*8+6] = t->isrcOwner(2);
917 	cueSheet[n*8+7] = t->isrcYear(0) + '0';
918 	n++;
919 
920 	if ((variant & CUE_VAR_ISRC_NO_CTL) == 0)
921 	  cueSheet[n*8] = ctl | 0x03;
922 	else
923 	  cueSheet[n*8] = 0x03;
924 
925 	cueSheet[n*8+1] = trackNr;
926 	cueSheet[n*8+2] = t->isrcYear(1) + '0';
927 	cueSheet[n*8+3] = t->isrcSerial(0) + '0';
928 	cueSheet[n*8+4] = t->isrcSerial(1) + '0';
929 	cueSheet[n*8+5] = t->isrcSerial(2) + '0';
930 	cueSheet[n*8+6] = t->isrcSerial(3) + '0';
931 	cueSheet[n*8+7] = t->isrcSerial(4) + '0';
932 	n++;
933       }
934     }
935     else {
936       // data track
937       ctl |= 0x40;
938     }
939 
940 
941     if (firstTrack) {
942       Msf sessionStart(lbaOffset);
943 
944       // entry for gap before first track
945       cueSheet[n*8]   = ctl | 0x01;
946       cueSheet[n*8+1] = trackNr;
947       cueSheet[n*8+2] = 0;    // Index 0
948       cueSheet[n*8+3] = dataMode;    // Data Form
949       cueSheet[n*8+4] = 0;    // Serial Copy Management System
950       cueSheet[n*8+5] = sessionStart.min();
951       cueSheet[n*8+6] = sessionStart.sec();
952       cueSheet[n*8+7] = sessionStart.frac();
953       n++;
954     }
955     else if (t->start().lba() != 0) {
956       // entry for pre-gap
957       Msf pstart(lbaOffset + start.lba() - t->start().lba() + 150);
958 
959       cueSheet[n*8]   = ctl | 0x01;
960       cueSheet[n*8+1] = trackNr;
961       cueSheet[n*8+2] = 0; // Index 0 indicates pre-gap
962       cueSheet[n*8+3] = dataMode; // Data Form
963       cueSheet[n*8+4] = 0; // no alternate copy bit
964       cueSheet[n*8+5] = pstart.min();
965       cueSheet[n*8+6] = pstart.sec();
966       cueSheet[n*8+7] = pstart.frac();
967       n++;
968     }
969 
970     Msf tstart(lbaOffset + start.lba() + 150);
971 
972     cueSheet[n*8]   = ctl | 0x01;
973     cueSheet[n*8+1] = trackNr;
974     cueSheet[n*8+2] = 1; // Index 1
975     cueSheet[n*8+3] = dataMode; // Data Form
976     cueSheet[n*8+4] = 0; // no alternate copy bit
977     cueSheet[n*8+5] = tstart.min();
978     cueSheet[n*8+6] = tstart.sec();
979     cueSheet[n*8+7] = tstart.frac();
980     n++;
981 
982     for (i = 0; i < t->nofIndices(); i++) {
983       index = tstart + t->getIndex(i);
984       cueSheet[n*8]   = ctl | 0x01;
985       cueSheet[n*8+1] = trackNr;
986       cueSheet[n*8+2] = i+2; // Index
987       cueSheet[n*8+3] = dataMode; // Data Form
988       cueSheet[n*8+4] = 0; // no alternate copy bit
989       cueSheet[n*8+5] = index.min();
990       cueSheet[n*8+6] = index.sec();
991       cueSheet[n*8+7] = index.frac();
992       n++;
993     }
994 
995     firstTrack = 0;
996   }
997 
998   assert(n == len - 1);
999 
1000   // entry for lead out
1001   Msf lostart(lbaOffset + toc_->length().lba() + 150);
1002   ctl = toc_->leadOutMode() == TrackData::AUDIO ? 0 : 0x40;
1003 
1004   cueSheet[n*8]   = ctl | 0x01;
1005   cueSheet[n*8+1] = 0xaa;
1006   cueSheet[n*8+2] = 1; // Index 1
1007   cueSheet[n*8+3] = leadInOutDataMode(toc_->leadOutMode());
1008   cueSheet[n*8+4] = 0; // no alternate copy bit
1009   cueSheet[n*8+5] = lostart.min();
1010   cueSheet[n*8+6] = lostart.sec();
1011   cueSheet[n*8+7] = lostart.frac();
1012 
1013   log_message(3, "\nCue Sheet (variant %lx):", variant);
1014   log_message(3, "CTL/  TNO  INDEX  DATA  SCMS  MIN  SEC  FRAME");
1015   log_message(3, "ADR               FORM");
1016   for (n = 0; n < len; n++) {
1017     log_message(3, "%02x    %02x    %02x     %02x    %02x   %02d   %02d   %02d",
1018 	   cueSheet[n*8],
1019 	   cueSheet[n*8+1], cueSheet[n*8+2], cueSheet[n*8+3], cueSheet[n*8+4],
1020 	   cueSheet[n*8+5], cueSheet[n*8+6], cueSheet[n*8+7]);
1021   }
1022 
1023   *cueSheetLen = len * 8;
1024   return cueSheet;
1025 }
1026 
sendCueSheet()1027 int GenericMMC::sendCueSheet()
1028 {
1029   unsigned char cmd[10];
1030   long cueSheetLen;
1031   unsigned long variant;
1032   unsigned char *cueSheet;
1033   int cueSheetSent = 0;
1034 
1035   for (variant = 0; variant <= CUE_VAR_MAX; variant++) {
1036 
1037     if (cdTextEncoder_ == NULL &&
1038 	(variant & CUE_VAR_CDTEXT_NO_TIME) != 0) {
1039       // skip CD-TEXT variants if no CD-TEXT has to be written
1040       continue;
1041     }
1042 
1043     cueSheet = createCueSheet(variant, &cueSheetLen);
1044 
1045     if (cueSheet != NULL) {
1046       memset(cmd, 0, 10);
1047 
1048       cmd[0] = 0x5d; // SEND CUE SHEET
1049 
1050       cmd[6] = cueSheetLen >> 16;
1051       cmd[7] = cueSheetLen >> 8;
1052       cmd[8] = cueSheetLen;
1053 
1054       if (sendCmd(cmd, 10, cueSheet, cueSheetLen, NULL, 0, 0) != 0) {
1055 	delete[] cueSheet;
1056       }
1057       else {
1058 	log_message(3, "Drive accepted cue sheet variant %lx.", variant);
1059 	delete[] cueSheet;
1060 	cueSheetSent = 1;
1061 	break;
1062       }
1063     }
1064   }
1065 
1066   if (cueSheetSent) {
1067     return 0;
1068   }
1069   else {
1070     log_message(-2,
1071 	    "Drive does not accept any cue sheet variant - please report.");
1072     return 1;
1073   }
1074 }
1075 
initDao(const Toc * toc)1076 int GenericMMC::initDao(const Toc *toc)
1077 {
1078   long n;
1079   blockLength_ = AUDIO_BLOCK_LEN + MAX_SUBCHANNEL_LEN;
1080   blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_;
1081 
1082   assert(blocksPerWrite_ > 0);
1083 
1084   toc_ = toc;
1085 
1086   if (options_ & OPT_MMC_CD_TEXT) {
1087     delete cdTextEncoder_;
1088     cdTextEncoder_ = new CdTextEncoder(toc_);
1089     if (cdTextEncoder_->encode() != 0) {
1090       log_message(-2, "CD-TEXT encoding failed.");
1091       return 1;
1092     }
1093 
1094     if (cdTextEncoder_->getSubChannels(&n) == NULL || n == 0) {
1095       delete cdTextEncoder_;
1096       cdTextEncoder_ = NULL;
1097     }
1098 
1099     //return 1;
1100   }
1101 
1102   diskInfo();
1103 
1104   if (!diskInfo_.valid.empty || !diskInfo_.valid.append) {
1105     log_message(-2, "Cannot determine status of inserted medium.");
1106     return 1;
1107   }
1108 
1109   if (!diskInfo_.append) {
1110     log_message(-2, "Inserted medium is not appendable.");
1111     return 1;
1112   }
1113 
1114   if ((!diskInfo_.empty && diskInfo_.append) && toc_->firstTrackNo() != 0 ) {
1115     log_message(-1, "Cannot choose number of first track in append mode.");
1116     return 1;
1117   }
1118 
1119   if (selectSpeed() != 0 ||
1120       getSessionInfo() != 0) {
1121     return 1;
1122   }
1123 
1124 
1125   // allocate buffer for writing zeros
1126   n = blocksPerWrite_ * blockLength_;
1127   delete[] zeroBuffer_;
1128   zeroBuffer_ = new char[n];
1129   memset(zeroBuffer_, 0, n);
1130 
1131   return 0;
1132 }
1133 
startDao()1134 int GenericMMC::startDao()
1135 {
1136   unsigned long variant;
1137   int writeParametersSet = 0;
1138 
1139   scsiTimeout_ = scsiIf_->timeout(3 * 60);
1140 
1141   for (variant = 0; variant <= WMP_VAR_MAX; variant++) {
1142     if (cdTextEncoder_ == NULL &&
1143 	(variant & WMP_VAR_CDTEXT_NO_DATA_BLOCK_TYPE) != 0) {
1144       // skip CD-TEXT variants if no CD-TEXT has to be written
1145       continue;
1146     }
1147 
1148     if (setWriteParameters(variant) == 0) {
1149       log_message(3, "Drive accepted write parameter mode page variant %lx.",
1150 	      variant);
1151       writeParametersSet = 1;
1152       break;
1153     }
1154   }
1155 
1156   if (!writeParametersSet) {
1157     log_message(-2, "Cannot setup write parameters for session-at-once mode.");
1158     log_message(-2, "Please try to use the 'generic-mmc-raw' driver.");
1159     return 1;
1160   }
1161 
1162   if (!simulate_) {
1163     if (performPowerCalibration() != 0) {
1164       if (!force()) {
1165 	log_message(-2, "Use option --force to ignore this error.");
1166 	return 1;
1167       }
1168       else {
1169 	log_message(-2, "Ignored because of option --force.");
1170       }
1171     }
1172   }
1173 
1174   // It does not hurt if the following command fails.
1175   // The Panasonic CW-7502 needs it, unfortunately it returns the wrong
1176   // data so we ignore the returned data and start writing always with
1177   // LBA -150.
1178   getNWA(NULL);
1179 
1180   if (sendCueSheet() != 0)
1181     return 1;
1182 
1183   //log_message(2, "Writing lead-in and gap...");
1184 
1185   if (writeCdTextLeadIn() != 0) {
1186     return 1;
1187   }
1188 
1189 
1190   long lba = diskInfo_.thisSessionLba - 150;
1191 
1192   TrackData::Mode mode = TrackData::AUDIO;
1193   TrackData::SubChannelMode subChanMode = TrackData::SUBCHAN_NONE;
1194   TrackIterator itr(toc_);
1195   const Track *tr;
1196 
1197   if ((tr = itr.first()) != NULL) {
1198     mode = tr->type();
1199     subChanMode = tr->subChannelType();
1200   }
1201 
1202   if (writeZeros(mode, subChanMode, lba, lba + 150, 150) != 0) {
1203     return 1;
1204   }
1205 
1206   return 0;
1207 }
1208 
finishDao()1209 int GenericMMC::finishDao()
1210 {
1211   int ret;
1212 
1213   flushCache(); /* Some drives never return to a ready state after writing
1214 		 * the lead-out. This is a try to solve this problem.
1215 		 */
1216 
1217   while ((ret = checkDriveReady()) == 2) {
1218     mSleep(2000);
1219   }
1220 
1221   if (ret != 0)
1222     log_message(-1, "TEST UNIT READY failed after recording.");
1223 
1224   log_message(2, "Flushing cache...");
1225 
1226   if (flushCache() != 0) {
1227     return 1;
1228   }
1229 
1230   scsiIf_->timeout(scsiTimeout_);
1231 
1232   delete cdTextEncoder_;
1233   cdTextEncoder_ = NULL;
1234 
1235   delete[] zeroBuffer_, zeroBuffer_ = NULL;
1236 
1237   return 0;
1238 }
1239 
abortDao()1240 void GenericMMC::abortDao()
1241 {
1242   flushCache();
1243 
1244   delete cdTextEncoder_;
1245   cdTextEncoder_ = NULL;
1246 }
1247 
1248 // Writes data to target, the block length depends on the actual writing
1249 // 'mode'. 'len' is number of blocks to write.
1250 // 'lba' specifies the next logical block address for writing and is updated
1251 // by this function.
1252 // return: 0: OK
1253 //         1: scsi command failed
writeData(TrackData::Mode mode,TrackData::SubChannelMode sm,long & lba,const char * buf,long len)1254 int GenericMMC::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm,
1255 			  long &lba, const char *buf, long len)
1256 {
1257   assert(blocksPerWrite_ > 0);
1258   int writeLen = 0;
1259   unsigned char cmd[10];
1260   long blockLength = blockSize(mode, sm);
1261   int retry;
1262   int ret;
1263 
1264 #if 0
1265   long bufferCapacity;
1266   int waitForBuffer;
1267   int speedFrac;
1268 
1269   if (speed_ > 0)
1270     speedFrac = 75 * speed_;
1271   else
1272     speedFrac = 75 * 10; // adjust this value when the first >10x burner is out
1273 #endif
1274 
1275 #if 0
1276   long sum, i;
1277 
1278   sum = 0;
1279 
1280   for (i = 0; i < len * blockLength; i++) {
1281     sum += buf[i];
1282   }
1283 
1284   log_message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum);
1285 #endif
1286 
1287   memset(cmd, 0, 10);
1288   cmd[0] = 0x2a; // WRITE1
1289 
1290   while (len > 0) {
1291     writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len);
1292 
1293     cmd[2] = lba >> 24;
1294     cmd[3] = lba >> 16;
1295     cmd[4] = lba >> 8;
1296     cmd[5] = lba;
1297 
1298     cmd[7] = writeLen >> 8;
1299     cmd[8] = writeLen & 0xff;
1300 
1301 #if 0
1302     do {
1303       long available
1304       waitForBuffer = 0;
1305 
1306       if (readBufferCapacity(&bufferCapacity, &available) == 0) {
1307 	//log_message(0, "Buffer Capacity: %ld", bufferCapacity);
1308 	if (bufferCapacity < writeLen * blockLength) {
1309 	  long t = 1000 * writeLen;
1310 	  t /= speedFrac;
1311 	  if (t <= 0)
1312 	    t = 1;
1313 
1314 	  log_message(0, "Waiting for %ld msec at lba %ld", t, lba);
1315 
1316 	  mSleep(t);
1317 	  waitForBuffer = 1;
1318 	}
1319       }
1320     } while (waitForBuffer);
1321 #endif
1322 
1323     do {
1324       retry = 0;
1325 
1326       ret = sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength,
1327 		    NULL, 0, 0);
1328 
1329       if(ret == 2) {
1330         const unsigned char *sense;
1331         int senseLen;
1332 
1333         sense = scsiIf_->getSense(senseLen);
1334 
1335 	// check if drive rejected the command because the internal buffer
1336 	// is filled
1337 	if(senseLen >= 14 && (sense[2] & 0x0f) == 0x2 && sense[7] >= 6 &&
1338 	   sense[12] == 0x4 && sense[13] == 0x8) {
1339 	  // Not Ready, long write in progress
1340 	  mSleep(40);
1341           retry = 1;
1342         }
1343 	else {
1344 	  scsiIf_->printError();
1345 	}
1346       }
1347     } while (retry);
1348 
1349     if (ret != 0) {
1350       log_message(-2, "Write data failed.");
1351       return 1;
1352     }
1353 
1354     buf += writeLen * blockLength;
1355 
1356     lba += writeLen;
1357     len -= writeLen;
1358   }
1359 
1360   return 0;
1361 }
1362 
writeCdTextLeadIn()1363 int GenericMMC::writeCdTextLeadIn()
1364 {
1365   unsigned char cmd[10];
1366   const PWSubChannel96 **cdTextSubChannels;
1367   long cdTextSubChannelCount;
1368   long channelsPerCmd;
1369   long scp = 0;
1370   long lba = -150 - leadInLen_;
1371   long len = leadInLen_;
1372   long n;
1373   long i;
1374   int retry;
1375   int ret;
1376   unsigned char *p;
1377 
1378   if (cdTextEncoder_ == NULL)
1379     return 0;
1380 
1381   channelsPerCmd = scsiIf_->maxDataLen() / 96;
1382 
1383   cdTextSubChannels = cdTextEncoder_->getSubChannels(&cdTextSubChannelCount);
1384 
1385   assert(channelsPerCmd > 0);
1386   assert(cdTextSubChannels != NULL);
1387   assert(cdTextSubChannelCount > 0);
1388 
1389   log_message(2, "Writing CD-TEXT lead-in...");
1390 
1391   log_message(4, "Start LBA: %ld, length: %ld", lba, len);
1392 
1393   memset(cmd, 0, 10);
1394   cmd[0] = 0x2a; // WRITE1
1395 
1396   while (len > 0) {
1397     n = (len > channelsPerCmd) ? channelsPerCmd : len;
1398 
1399     cmd[2] = lba >> 24;
1400     cmd[3] = lba >> 16;
1401     cmd[4] = lba >> 8;
1402     cmd[5] = lba;
1403 
1404     cmd[7] = n >> 8;
1405     cmd[8] = n;
1406 
1407     p = transferBuffer_;
1408 
1409     for (i = 0; i < n; i++) {
1410       memcpy(p, cdTextSubChannels[scp]->data(), 96);
1411       p += 96;
1412 
1413       scp++;
1414       if (scp >= cdTextSubChannelCount)
1415 	scp = 0;
1416     }
1417 
1418     log_message(5, "Writing %ld CD-TEXT sub-channels at LBA %ld.", n, lba);
1419 
1420     do {
1421       retry = 0;
1422 
1423       ret = sendCmd(cmd, 10, transferBuffer_, n * 96, NULL, 0, 0);
1424 
1425       if(ret == 2) {
1426         const unsigned char *sense;
1427         int senseLen;
1428 
1429         sense = scsiIf_->getSense(senseLen);
1430 
1431 	// check if drive rejected the command because the internal buffer
1432 	// is filled
1433 	if(senseLen >= 14 && (sense[2] & 0x0f) == 0x2 && sense[7] >= 6 &&
1434 	   sense[12] == 0x4 && sense[13] == 0x8) {
1435 	  // Not Ready, long write in progress
1436 	  mSleep(40);
1437           retry = 1;
1438         }
1439 	else {
1440 	  scsiIf_->printError();
1441 	}
1442       }
1443     } while (retry);
1444 
1445     if (ret != 0) {
1446       log_message(-2, "Writing of CD-TEXT data failed.");
1447       return 1;
1448     }
1449 
1450 
1451     len -= n;
1452     lba += n;
1453   }
1454 
1455   return 0;
1456 }
1457 
diskInfo()1458 DiskInfo *GenericMMC::diskInfo()
1459 {
1460   unsigned char cmd[10];
1461   unsigned long dataLen = 34;
1462   unsigned char data[34];
1463   char spd;
1464 
1465   memset(&diskInfo_, 0, sizeof(DiskInfo));
1466 
1467   // perform READ DISK INFORMATION
1468   memset(cmd, 0, 10);
1469   memset(data, 0, dataLen);
1470 
1471   cmd[0] = 0x51; // READ DISK INFORMATION
1472   cmd[7] = dataLen >> 8;
1473   cmd[8] = dataLen;
1474 
1475   if (sendCmd(cmd, 10, NULL, 0, data, dataLen, 0) == 0) {
1476     diskInfo_.cdrw = (data[2] & 0x10) ? 1 : 0;
1477     diskInfo_.valid.cdrw = 1;
1478 
1479     switch (data[2] & 0x03) {
1480     case 0:
1481       // disc is empty
1482       diskInfo_.empty = 1;
1483       diskInfo_.append = 1;
1484 
1485       diskInfo_.manufacturerId = Msf(data[17], data[18], data[19]);
1486       diskInfo_.valid.manufacturerId = 1;
1487       break;
1488 
1489     case 1:
1490       // disc is not empty but appendable
1491       diskInfo_.sessionCnt = data[4];
1492       diskInfo_.lastTrackNr = data[6];
1493 
1494       diskInfo_.diskTocType = data[8];
1495 
1496       switch ((data[2] >> 2) & 0x03) {
1497       case 0:
1498 	// last session is empty
1499 	diskInfo_.append = 1;
1500 
1501 	// don't count the empty session and invisible track
1502 	diskInfo_.sessionCnt -= 1;
1503 	diskInfo_.lastTrackNr -= 1;
1504 
1505 	if (getStartOfSession(&(diskInfo_.thisSessionLba)) == 0) {
1506 	  // reserve space for pre-gap after lead-in
1507 	  diskInfo_.thisSessionLba += 150;
1508 	}
1509 	else {
1510 	  // try to guess start of data area from start of lead-in
1511 	  // reserve space for 4500 lead-in and 150 pre-gap sectors
1512 	  diskInfo_.thisSessionLba = Msf(data[17], data[18],
1513 					 data[19]).lba() - 150 + 4650;
1514 	}
1515 	break;
1516 
1517       case 1:
1518 	// last session is incomplete (not fixated)
1519 	// we cannot append in DAO mode, just update the statistic data
1520 
1521 	diskInfo_.diskTocType = data[8];
1522 
1523 	// don't count the invisible track
1524 	diskInfo_.lastTrackNr -= 1;
1525 	break;
1526       }
1527       break;
1528 
1529     case 2:
1530       // disk is complete
1531       diskInfo_.sessionCnt = data[4];
1532       diskInfo_.lastTrackNr = data[6];
1533       diskInfo_.diskTocType = data[8];
1534       break;
1535     }
1536 
1537     diskInfo_.valid.empty = 1;
1538     diskInfo_.valid.append = 1;
1539 
1540     if (data[21] != 0xff || data[22] != 0xff || data[23] != 0xff) {
1541       diskInfo_.valid.capacity = 1;
1542       diskInfo_.capacity = Msf(data[21], data[22], data[23]).lba() - 150;
1543     }
1544   }
1545 
1546   // perform READ TOC to get session info
1547   memset(cmd, 0, 10);
1548   dataLen = 12;
1549   memset(data, 0, dataLen);
1550 
1551   cmd[0] = 0x43; // READ TOC
1552   cmd[2] = 1; // get session info
1553   cmd[8] = dataLen; // allocation length
1554 
1555   if (sendCmd(cmd, 10, NULL, 0, data, dataLen, 0) == 0) {
1556     diskInfo_.lastSessionLba = (data[8] << 24) | (data[9] << 16) |
1557                                (data[10] << 8) | data[11];
1558 
1559     if (!diskInfo_.valid.empty) {
1560       diskInfo_.valid.empty = 1;
1561       diskInfo_.empty = (data[3] == 0) ? 1 : 0;
1562 
1563       diskInfo_.sessionCnt = data[3];
1564     }
1565   }
1566 
1567   // read ATIP data
1568   dataLen = 28;
1569   memset(cmd, 0, 10);
1570   memset(data, 0, dataLen);
1571 
1572   cmd[0] = 0x43; // READ TOC/PMA/ATIP
1573   cmd[1] = 0x00;
1574   cmd[2] = 4; // get ATIP
1575   cmd[7] = 0;
1576   cmd[8] = dataLen; // data length
1577 
1578   if (sendCmd(cmd, 10, NULL, 0, data, dataLen, 0) == 0) {
1579     if (data[6] & 0x04) {
1580       diskInfo_.valid.recSpeed = 1;
1581       spd = (data[16] >> 4) & 0x07;
1582       diskInfo_.recSpeedLow = spd == 1 ? 2 : 0;
1583 
1584       spd = (data[16] & 0x0f);
1585       diskInfo_.recSpeedHigh = spd >= 1 && spd <= 4 ? spd * 2 : 0;
1586     }
1587 
1588     if (data[8] >= 80 && data[8] <= 99) {
1589       diskInfo_.manufacturerId = Msf(data[8], data[9], data[10]);
1590       diskInfo_.valid.manufacturerId = 1;
1591     }
1592   }
1593 
1594   return &diskInfo_;
1595 }
1596 
1597 
1598 // tries to read catalog number from disk and adds it to 'toc'
1599 // return: 1 if valid catalog number was found, else 0
readCatalog(Toc * toc,long startLba,long endLba)1600 int GenericMMC::readCatalog(Toc *toc, long startLba, long endLba)
1601 {
1602   unsigned char cmd[10];
1603   unsigned char data[24];
1604   char catalog[14];
1605   int i;
1606 
1607   if (options_ & OPT_MMC_SCAN_MCN) {
1608     if (readCatalogScan(catalog, startLba, endLba) == 0) {
1609       if (catalog[0] != 0) {
1610 	if (toc->catalog(catalog) == 0)
1611 	  return 1;
1612 	else
1613 	  log_message(-1, "Found illegal MCN data: %s", catalog);
1614       }
1615     }
1616   }
1617   else {
1618     memset(cmd, 0, 10);
1619     memset(data, 0, 24);
1620 
1621     cmd[0] = 0x42; // READ SUB-CHANNEL
1622     cmd[2] = 1 << 6;
1623     cmd[3] = 0x02; // get media catalog number
1624     cmd[8] = 24;   // transfer length
1625 
1626     if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
1627       log_message(-2, "Cannot get catalog number.");
1628       return 0;
1629     }
1630 
1631     if (data[8] & 0x80) {
1632       for (i = 0; i < 13; i++) {
1633 	catalog[i] = data[0x09 + i];
1634       }
1635       catalog[13] = 0;
1636 
1637       if (toc->catalog(catalog) == 0) {
1638 	return 1;
1639       }
1640     }
1641   }
1642 
1643   return 0;
1644 }
1645 
readIsrc(int trackNr,char * buf)1646 int GenericMMC::readIsrc(int trackNr, char *buf)
1647 {
1648   unsigned char cmd[10];
1649   unsigned char data[24];
1650   int i;
1651 
1652   buf[0] = 0;
1653 
1654   memset(cmd, 0, 10);
1655   memset(data, 0, 24);
1656 
1657   cmd[0] = 0x42; // READ SUB-CHANNEL
1658   cmd[2] = 1 << 6;
1659   cmd[3] = 0x03; // get ISRC
1660   cmd[6] = trackNr;
1661   cmd[8] = 24;   // transfer length
1662 
1663   if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) {
1664     log_message(-2, "Cannot get ISRC code.");
1665     return 0;
1666   }
1667 
1668   if (data[8] & 0x80) {
1669     for (i = 0; i < 12; i++) {
1670       buf[i] = data[0x09 + i];
1671     }
1672     buf[12] = 0;
1673   }
1674 
1675   return 0;
1676 }
1677 
analyzeTrack(TrackData::Mode mode,int trackNr,long startLba,long endLba,Msf * indexIncrements,int * indexIncrementCnt,long * pregap,char * isrcCode,unsigned char * ctl)1678 int GenericMMC::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba,
1679 			     long endLba, Msf *indexIncrements,
1680 			     int *indexIncrementCnt, long *pregap,
1681 			     char *isrcCode, unsigned char *ctl)
1682 {
1683   int ret;
1684   int noScan = 0;
1685 
1686   selectSpeed();
1687 
1688   if ((readCapabilities_ & CDR_AUDIO_SCAN_CAP) == 0) {
1689     ret = analyzeTrackSearch(mode, trackNr, startLba, endLba, indexIncrements,
1690 			     indexIncrementCnt, pregap, isrcCode, ctl);
1691     noScan = 1;
1692   }
1693   else {
1694     ret = analyzeTrackScan(mode, trackNr, startLba, endLba,
1695 			   indexIncrements, indexIncrementCnt, pregap,
1696 			   isrcCode, ctl);
1697   }
1698 
1699   if (noScan || (options_ & OPT_MMC_READ_ISRC) != 0 ||
1700       (readCapabilities_ & CDR_READ_CAP_AUDIO_PQ_HEX) != 0) {
1701     // The ISRC code is usually not usable if the PQ channel data is
1702     // converted to hex numbers by the drive. Read them with the
1703     // appropriate command in this case
1704 
1705     *isrcCode = 0;
1706     if (mode == TrackData::AUDIO)
1707       readIsrc(trackNr, isrcCode);
1708   }
1709 
1710   return ret;
1711 }
1712 
readSubChannels(TrackData::SubChannelMode sm,long lba,long len,SubChannel *** chans,Sample * audioData)1713 int GenericMMC::readSubChannels(TrackData::SubChannelMode sm,
1714 				long lba, long len, SubChannel ***chans,
1715 				Sample *audioData)
1716 {
1717   int retries = 5;
1718   unsigned char cmd[12];
1719   int i;
1720   long blockLen = 0;
1721   unsigned long subChanMode = 0;
1722 
1723   cmd[0] = 0xbe;  // READ CD
1724   cmd[1] = 0;
1725   cmd[2] = lba >> 24;
1726   cmd[3] = lba >> 16;
1727   cmd[4] = lba >> 8;
1728   cmd[5] = lba;
1729   cmd[6] = len >> 16;
1730   cmd[7] = len >> 8;
1731   cmd[8] = len;
1732   cmd[9] = 0xf8;
1733   cmd[11] = 0;
1734 
1735   switch (sm) {
1736   case TrackData::SUBCHAN_NONE:
1737     // no sub-channel data selected choose what is available
1738 
1739     if ((readCapabilities_ & CDR_READ_CAP_AUDIO_PW_RAW) != 0) {
1740       // reading of raw P-W sub-channel data is supported
1741       blockLen = AUDIO_BLOCK_LEN + 96;
1742       cmd[10] = 0x01;  // raw P-W sub-channel data
1743 
1744       subChanMode = CDR_READ_CAP_AUDIO_PW_RAW;
1745     }
1746     else if ((readCapabilities_ &
1747 	      (CDR_READ_CAP_AUDIO_PQ_BCD|CDR_READ_CAP_AUDIO_PQ_HEX)) != 0) {
1748       // reading of PQ sub-channel data is supported
1749       blockLen = AUDIO_BLOCK_LEN + 16;
1750       cmd[10] = 0x02;  // PQ sub-channel data
1751 
1752       if ((readCapabilities_ & CDR_READ_CAP_AUDIO_PQ_BCD) != 0)
1753 	subChanMode = CDR_READ_CAP_AUDIO_PQ_BCD;
1754       else
1755 	subChanMode = CDR_READ_CAP_AUDIO_PQ_HEX;
1756     }
1757     else {
1758       // no usable sub-channel reading mode is supported
1759       blockLen = AUDIO_BLOCK_LEN;
1760       cmd[10] = 0;
1761 
1762       subChanMode = 0;
1763     }
1764     break;
1765 
1766   case TrackData::SUBCHAN_RW:
1767     blockLen = AUDIO_BLOCK_LEN + 96;
1768     cmd[10] = 0x04;
1769     break;
1770 
1771   case TrackData::SUBCHAN_RW_RAW:
1772     blockLen = AUDIO_BLOCK_LEN + 96;
1773     cmd[10] = 0x01;
1774     break;
1775   }
1776 
1777   while (1) {
1778     if (sendCmd(cmd, 12, NULL, 0,
1779 		transferBuffer_, len * blockLen, retries == 0 ? 1 : 0) != 0) {
1780       if (retries == 0)
1781 	return 1;
1782     }
1783     else {
1784       break;
1785     }
1786 
1787     retries--;
1788   }
1789 
1790 #if 0
1791   if (lba > 5000) {
1792     char fname[200];
1793     sprintf(fname, "testout_%ld", lba);
1794     FILE *fp = fopen(fname, "w");
1795     fwrite(transferBuffer_, blockLen, len, fp);
1796     fclose(fp);
1797   }
1798 #endif
1799 
1800   if (subChanMode != 0) {
1801     unsigned char *buf = transferBuffer_ + AUDIO_BLOCK_LEN;
1802 
1803     for (i = 0; i < len; i++) {
1804       switch (subChanMode) {
1805       case CDR_READ_CAP_AUDIO_PQ_HEX:
1806 	// All numbers in sub-channel data are hex conforming to the
1807 	// MMC standard. We have to convert them back to BCD for the
1808 	// 'SubChannel' class.
1809 	buf[1] = SubChannel::bcd(buf[1]);
1810 	buf[2] = SubChannel::bcd(buf[2]);
1811 	buf[3] = SubChannel::bcd(buf[3]);
1812 	buf[4] = SubChannel::bcd(buf[4]);
1813 	buf[5] = SubChannel::bcd(buf[5]);
1814 	buf[6] = SubChannel::bcd(buf[6]);
1815 	buf[7] = SubChannel::bcd(buf[7]);
1816 	buf[8] = SubChannel::bcd(buf[8]);
1817 	buf[9] = SubChannel::bcd(buf[9]);
1818 	// fall through
1819 
1820       case CDR_READ_CAP_AUDIO_PQ_BCD:
1821 	((PQSubChannel16*)scannedSubChannels_[i])->init(buf);
1822 	if (scannedSubChannels_[i]->type() != SubChannel::QMODE_ILLEGAL) {
1823 	  // the CRC of the sub-channel data is usually invalid -> mark the
1824 	  // sub-channel object that it should not try to verify the CRC
1825 	  scannedSubChannels_[i]->crcInvalid();
1826 	}
1827 	break;
1828 
1829       case CDR_READ_CAP_AUDIO_PW_RAW:
1830 	((PWSubChannel96*)scannedSubChannels_[i])->init(buf);
1831 	break;
1832       }
1833 
1834 #if 0
1835       if (subChanMode == CDR_READ_CAP_AUDIO_PW_RAW) {
1836 	// xxam!
1837 	int j, k;
1838 
1839 	log_message(0, "");
1840 	for (j = 0; j < 4; j++) {
1841 	  for (k = 0; k < 24; k++) {
1842 	    unsigned char data = buf[j * 24 + k];
1843 	    log_message(0, "%02x ", data&0x3f);
1844 	  }
1845 	  log_message(0, "");
1846 	}
1847       }
1848 #endif
1849 
1850       buf += blockLen;
1851     }
1852   }
1853 
1854   if (audioData != NULL) {
1855     unsigned char *p = transferBuffer_;
1856 
1857     for (i = 0; i < len; i++) {
1858       memcpy(audioData, p, AUDIO_BLOCK_LEN);
1859 
1860       audioData += SAMPLES_PER_BLOCK;
1861 
1862       switch (sm) {
1863       case TrackData::SUBCHAN_NONE:
1864 	break;
1865 
1866       case TrackData::SUBCHAN_RW:
1867       case TrackData::SUBCHAN_RW_RAW:
1868 	memcpy(audioData, p + AUDIO_BLOCK_LEN, PW_SUBCHANNEL_LEN);
1869 	audioData += PW_SUBCHANNEL_LEN / SAMPLE_LEN;
1870 	break;
1871       }
1872 
1873       p += blockLen;
1874     }
1875   }
1876 
1877   if (subChanMode == 0)
1878     *chans = NULL;
1879   else
1880     *chans = scannedSubChannels_;
1881 
1882   return 0;
1883 }
1884 
1885 
1886 // Tries to retrieve configuration feature 'feature' and fills data to
1887 // provided buffer 'buf' with maximum length 'bufLen'.
1888 // Return: 0: OK
1889 //         1: feature not available
1890 //         2: SCSI error
getFeature(unsigned int feature,unsigned char * buf,unsigned long bufLen,int showMsg)1891 int GenericMMC::getFeature(unsigned int feature, unsigned char *buf,
1892 			   unsigned long bufLen, int showMsg)
1893 {
1894   unsigned char header[8];
1895   unsigned char *data;
1896   unsigned char cmd[10];
1897   unsigned long len;
1898 
1899   memset(cmd, 0, 10);
1900   memset(header, 0, 8);
1901 
1902   cmd[0] = 0x46; // GET CONFIGURATION
1903   cmd[1] = 0x02; // return single feature descriptor
1904   cmd[2] = feature >> 8;
1905   cmd[3] = feature;
1906   cmd[8] = 8; // allocation length
1907 
1908   if (sendCmd(cmd, 10, NULL, 0, header, 8, showMsg) != 0) {
1909     if (showMsg)
1910       log_message(-2, "Cannot get feature 0x%x.", feature);
1911     return 2;
1912   }
1913 
1914   len = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
1915 
1916   log_message(4, "getFeature: data len: %lu", len);
1917 
1918   if (len < 8)
1919     return 1; // feature not defined
1920 
1921   if (bufLen == 0)
1922     return 0;
1923 
1924   len -= 4;
1925 
1926   if (len > bufLen)
1927     len = bufLen;
1928 
1929   data = new unsigned char[len + 8];
1930 
1931   cmd[7] = (len + 8) >> 8;
1932   cmd[8] = (len + 8);
1933 
1934   if (sendCmd(cmd, 10, NULL, 0, data, len + 8, showMsg) != 0) {
1935     if (showMsg)
1936       log_message(-2, "Cannot get data for feature 0x%x.", feature);
1937 
1938     delete[] data;
1939     return 2;
1940   }
1941 
1942   len = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
1943 
1944   log_message(4, "getFeature: data len: %lu", len);
1945 
1946   if (len < 8) {
1947     delete[] data;
1948     return 1; // feature not defined
1949   }
1950 
1951   len -= 4;
1952 
1953   if (len > bufLen)
1954     len = bufLen;
1955 
1956   memcpy(buf, data + 8, len);
1957 
1958   delete[] data;
1959 
1960   return 0;
1961 }
1962 
driveInfo(bool showErrorMsg)1963 const DriveInfo *GenericMMC::driveInfo(bool showErrorMsg)
1964 {
1965   unsigned char mp[32];
1966 
1967   if (driveInfo_ != NULL)
1968     return driveInfo_;
1969 
1970   driveInfo_ = new DriveInfo;
1971 
1972   if (getModePage(0x2a, mp, 32, NULL, NULL, showErrorMsg) != 0) {
1973     if (showErrorMsg) {
1974       log_message(-2, "Cannot retrieve drive capabilities mode page.");
1975     }
1976     delete driveInfo_;
1977     driveInfo_ = NULL;
1978     return NULL;
1979   }
1980 
1981   driveInfo_->burnProof = (mp[4] & 0x80) ? 1 : 0;
1982   driveInfo_->accurateAudioStream = mp[5] & 0x02 ? 1 : 0;
1983 
1984   driveInfo_->maxReadSpeed = (mp[8] << 8) | mp[9];
1985   driveInfo_->currentReadSpeed = (mp[14] << 8) | mp[15];
1986 
1987   driveInfo_->maxWriteSpeed = (mp[18] << 8) | mp[19];
1988   driveInfo_->currentWriteSpeed = (mp[20] << 8) | mp[21];
1989 
1990 #if 0
1991   unsigned char cdMasteringFeature[8];
1992   if (getFeature(0x2e, cdMasteringFeature, 8, 1) == 0) {
1993     log_message(0, "Feature: %x %x %x %x %x %x %x %x", cdMasteringFeature[0],
1994 	    cdMasteringFeature[1], cdMasteringFeature[2],
1995 	    cdMasteringFeature[3], cdMasteringFeature[4],
1996 	    cdMasteringFeature[5], cdMasteringFeature[6],
1997 	    cdMasteringFeature[7]);
1998   }
1999 #endif
2000 
2001   RicohGetWriteOptions();
2002 
2003   return driveInfo_;
2004 }
2005 
getTrackMode(int,long trackStartLba)2006 TrackData::Mode GenericMMC::getTrackMode(int, long trackStartLba)
2007 {
2008   unsigned char cmd[12];
2009   unsigned char data[AUDIO_BLOCK_LEN];
2010 
2011   memset(cmd, 0, 12);
2012   cmd[0] = 0xbe;  // READ CD
2013 
2014   cmd[2] = trackStartLba >> 24;
2015   cmd[3] = trackStartLba >> 16;
2016   cmd[4] = trackStartLba >> 8;
2017   cmd[5] = trackStartLba;
2018 
2019   cmd[8] = 1;
2020 
2021   cmd[9] = 0xf8;
2022 
2023   if (sendCmd(cmd, 12, NULL, 0, data, AUDIO_BLOCK_LEN) != 0) {
2024     log_message(-2, "Cannot read sector of track.");
2025     return TrackData::MODE0;
2026   }
2027 
2028   if (memcmp(CdrDriver::syncPattern, data, 12) != 0) {
2029     // cannot be a data sector
2030     return TrackData::MODE0;
2031   }
2032 
2033   TrackData::Mode mode = determineSectorMode(data + 12);
2034 
2035   if (mode == TrackData::MODE0) {
2036     // illegal
2037     log_message(-2, "Found illegal mode in sector %ld.", trackStartLba);
2038   }
2039 
2040   return mode;
2041 }
2042 
getRawToc(int sessionNr,int * len)2043 CdRawToc *GenericMMC::getRawToc(int sessionNr, int *len)
2044 {
2045   unsigned char cmd[10];
2046   unsigned short dataLen;
2047   unsigned char *data = NULL;;
2048   unsigned char reqData[4]; // buffer for requestion the actual length
2049   unsigned char *p;
2050   int i, entries;
2051   CdRawToc *rawToc;
2052 
2053   assert(sessionNr >= 1);
2054 
2055   // read disk toc length
2056   memset(cmd, 0, 10);
2057   cmd[0] = 0x43; // READ TOC
2058   cmd[2] = 2;
2059   cmd[6] = sessionNr;
2060   cmd[8] = 4;
2061 
2062   if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) {
2063     log_message(-2, "Cannot read disk toc.");
2064     return NULL;
2065   }
2066 
2067   dataLen = ((reqData[0] << 8) | reqData[1]) + 2;
2068 
2069   log_message(4, "Raw toc data len: %d", dataLen);
2070 
2071   data = new unsigned char[dataLen];
2072 
2073   // read disk toc
2074   cmd[7] = dataLen >> 8;
2075   cmd[8] = dataLen;
2076 
2077   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
2078     log_message(-2, "Cannot read disk toc.");
2079     delete[] data;
2080     return NULL;
2081   }
2082 
2083   entries = (((data[0] << 8) | data[1]) - 2) / 11;
2084 
2085   rawToc = new CdRawToc[entries];
2086 
2087   for (i = 0, p = data + 4; i < entries; i++, p += 11 ) {
2088 #if 0
2089     log_message(5, "%d %02x %02d %2x %02d:%02d:%02d %02d %02d:%02d:%02d",
2090 	    p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]);
2091 #endif
2092     rawToc[i].sessionNr = p[0];
2093     rawToc[i].adrCtl = p[1];
2094     rawToc[i].point = p[3];
2095     rawToc[i].pmin = p[8];
2096     rawToc[i].psec = p[9];
2097     rawToc[i].pframe = p[10];
2098   }
2099 
2100   delete[] data;
2101 
2102   *len = entries;
2103 
2104   return rawToc;
2105 }
2106 
readTrackData(TrackData::Mode mode,TrackData::SubChannelMode sm,long lba,long len,unsigned char * buf)2107 long GenericMMC::readTrackData(TrackData::Mode mode,
2108 			       TrackData::SubChannelMode sm,
2109 			       long lba, long len, unsigned char *buf)
2110 {
2111   long i;
2112   long inBlockLen = AUDIO_BLOCK_LEN;
2113   unsigned char cmd[12];
2114   const unsigned char *sense;
2115   int senseLen;
2116 
2117   memset(cmd, 0, 12);
2118 
2119   cmd[0] = 0xbe; // READ CD
2120   cmd[1] = 0;
2121   cmd[2] = lba >> 24;
2122   cmd[3] = lba >> 16;
2123   cmd[4] = lba >> 8;
2124   cmd[5] = lba;
2125   cmd[6] = len >> 16;
2126   cmd[7] = len >> 8;
2127   cmd[8] = len;
2128   cmd[9] = 0xf8;
2129 
2130   switch (sm) {
2131   case TrackData::SUBCHAN_NONE:
2132     cmd[10] = 0; // no sub-channel reading
2133     break;
2134 
2135   case TrackData::SUBCHAN_RW:
2136     cmd[10] = 0x4;
2137     inBlockLen += PW_SUBCHANNEL_LEN;
2138     break;
2139 
2140   case TrackData::SUBCHAN_RW_RAW:
2141     cmd[10] = 0x1;
2142     inBlockLen += PW_SUBCHANNEL_LEN;
2143     break;
2144   }
2145 
2146   switch (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * inBlockLen, 0)) {
2147   case 0:
2148     break;
2149 
2150   case 2:
2151     sense = scsiIf_->getSense(senseLen);
2152 
2153     if (senseLen > 0x0c) {
2154       if ((sense[2] & 0x0f) == 5) { // Illegal request
2155 	switch (sense[12]) {
2156 	case 0x63: // End of user area encountered on this track
2157 	case 0x64: // Illegal mode for this track
2158 	  return -2;
2159 	  break;
2160 
2161 	case 0x20: // INVALID COMMAND OPERATION CODE
2162 	case 0x24: // INVALID FIELD IN CDB
2163 	case 0x26: // INVALID FIELD IN PARAMETER LIST
2164 	  /* These error codes mean that something was wrong with the
2165 	   * command we are sending. Report them as hard errors to the
2166 	   * upper level.
2167 	   */
2168 	  scsiIf_->printError();
2169 	  return -1;
2170 	  break;
2171 	}
2172       }
2173       else if ((sense[2] & 0x0f) == 4) { // Hardware Error
2174 	switch (sense[12]) {
2175 	case 0x9: // focus servo failure
2176 	  return -2;
2177 	  break;
2178 	}
2179       }
2180       else if ((sense[2] & 0x0f) == 3) { // Medium error
2181 	switch (sense[12]) {
2182 	case 0x02: // No seek complete, sector not found
2183 	case 0x06: // no reference position found
2184 	case 0x11: // L-EC error
2185 	case 0x15: // random positioning error
2186 	  return -2;
2187 	  break;
2188 	}
2189       }
2190     }
2191 
2192     /* All other errors are unexpected. They will be treated like L-EC errors
2193      * by the upper layer. Just print the error code so that we can decice
2194      * later to add the errors to the known possible error list.
2195      */
2196 
2197     scsiIf_->printError();
2198     return -2;
2199     break;
2200 
2201   default:
2202     log_message(-2, "Read error at LBA %ld, len %ld", lba, len);
2203     return -2;
2204     break;
2205   }
2206 
2207   unsigned char *sector = transferBuffer_;
2208   for (i = 0; i < len; i++) {
2209     if (buf != NULL) {
2210       switch (mode) {
2211       case TrackData::MODE1:
2212 	memcpy(buf, sector + 16, MODE1_BLOCK_LEN);
2213 	buf += MODE1_BLOCK_LEN;
2214 	break;
2215       case TrackData::MODE1_RAW:
2216 	memcpy(buf, sector, AUDIO_BLOCK_LEN);
2217 	buf += AUDIO_BLOCK_LEN;
2218 	break;
2219       case TrackData::MODE2:
2220       case TrackData::MODE2_FORM_MIX:
2221 	memcpy(buf, sector + 16, MODE2_BLOCK_LEN);
2222 	buf += MODE2_BLOCK_LEN;
2223 	break;
2224       case TrackData::MODE2_FORM1:
2225 	memcpy(buf, sector + 24, MODE2_FORM1_DATA_LEN);
2226 	buf += MODE2_FORM1_DATA_LEN;
2227 	break;
2228       case TrackData::MODE2_FORM2:
2229 	memcpy(buf, sector + 24, MODE2_FORM2_DATA_LEN);
2230 	buf += MODE2_FORM2_DATA_LEN;
2231 	break;
2232       case TrackData::MODE2_RAW:
2233 	memcpy(buf, sector, AUDIO_BLOCK_LEN);
2234 	buf += AUDIO_BLOCK_LEN;
2235 	break;
2236       case TrackData::MODE0:
2237       case TrackData::AUDIO:
2238 	log_message(-3, "GenericMMC::readTrackData: Illegal mode.");
2239 	return 0;
2240 	break;
2241       }
2242 
2243       // copy sub-channel data
2244       switch (sm) {
2245       case TrackData::SUBCHAN_NONE:
2246 	break;
2247 
2248       case TrackData::SUBCHAN_RW:
2249       case TrackData::SUBCHAN_RW_RAW:
2250 	memcpy(buf, sector + AUDIO_BLOCK_LEN, PW_SUBCHANNEL_LEN);
2251 	buf += PW_SUBCHANNEL_LEN;
2252 	break;
2253       }
2254     }
2255 
2256 #if 0
2257     // xxam!
2258     int j, k;
2259 
2260     log_message(0, "");
2261     for (j = 0; j < 4; j++) {
2262       for (k = 0; k < 24; k++) {
2263 	unsigned char data = sector[AUDIO_BLOCK_LEN + j * 24 + k];
2264 	log_message(0, "%02x ", data&0x3f);
2265       }
2266       log_message(0, "");
2267     }
2268 #endif
2269 
2270     sector += inBlockLen;
2271   }
2272 
2273   return len;
2274 }
2275 
readAudioRange(ReadDiskInfo * rinfo,int fd,long start,long end,int startTrack,int endTrack,TrackInfo * info)2276 int GenericMMC::readAudioRange(ReadDiskInfo *rinfo, int fd, long start,
2277 			       long end, int startTrack,
2278 			       int endTrack, TrackInfo *info)
2279 {
2280   if (!onTheFly_) {
2281     if (((readCapabilities_ & CDR_READ_CAP_AUDIO_PQ_BCD) == 0 &&
2282 	 (readCapabilities_ & CDR_READ_CAP_AUDIO_PW_RAW) == 0) ||
2283 	(options_ & OPT_MMC_READ_ISRC) != 0) {
2284       int t;
2285       long pregap = 0;
2286 
2287       // The ISRC code is usually not usable if the PQ channel data is
2288       // converted to hex numbers by the drive. Read them with the
2289       // appropriate command in this case
2290 
2291       log_message(1, "Analyzing...");
2292 
2293 
2294       for (t = startTrack; t <= endTrack; t++) {
2295 	long totalProgress;
2296 
2297 	log_message(1, "Track %d...", t + 1);
2298 
2299 	totalProgress = t * 1000;
2300 	totalProgress /= rinfo->tracks;
2301 	sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 0,
2302 			      totalProgress);
2303 
2304 	if ((readCapabilities_ & CDR_AUDIO_SCAN_CAP) == 0) {
2305 	  // we have to use the binary search method to find pre-gap and
2306 	  // index marks if the drive cannot read sub-channel data
2307 	  if (!fastTocReading_) {
2308 	    long slba, elba;
2309 	    int i, indexCnt;
2310 	    Msf index[98];
2311 	    unsigned char ctl;
2312 
2313 	    if (pregap > 0)
2314 	      log_message(2, "Found pre-gap: %s", Msf(pregap).str());
2315 
2316 	    slba = info[t].start;
2317 	    if (info[t].mode == info[t + 1].mode)
2318 	      elba = info[t + 1].start;
2319 	    else
2320 	      elba = info[t + 1].start - 150;
2321 
2322 	    pregap = 0;
2323 	    if (analyzeTrackSearch(TrackData::AUDIO, t + 1, slba, elba,
2324 				   index, &indexCnt, &pregap, info[t].isrcCode,
2325 				   &ctl) != 0)
2326 	      return 1;
2327 
2328 	    for (i = 0; i < indexCnt; i++)
2329 	      info[t].index[i] = index[i].lba();
2330 
2331 	    info[t].indexCnt = indexCnt;
2332 
2333 	    if (t < endTrack)
2334 	      info[t + 1].pregap = pregap;
2335 	  }
2336 	  else {
2337 	    info[t].indexCnt = 0;
2338 	    info[t + 1].pregap = 0;
2339 	  }
2340 	}
2341 
2342 
2343 	info[t].isrcCode[0] = 0;
2344 	readIsrc(t + 1, info[t].isrcCode);
2345 	if (info[t].isrcCode[0] != 0)
2346 	  log_message(2, "Found ISRC code.");
2347 
2348 	totalProgress = (t + 1) * 1000;
2349 	totalProgress /= rinfo->tracks;
2350 	sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 1000,
2351 			      totalProgress);
2352       }
2353 
2354       log_message(1, "Reading...");
2355     }
2356   }
2357 
2358   if (subChanReadMode_ == TrackData::SUBCHAN_NONE) {
2359     return CdrDriver::readAudioRangeParanoia(rinfo, fd, start, end, startTrack,
2360 					     endTrack, info);
2361   }
2362   else {
2363     return CdrDriver::readAudioRangeStream(rinfo, fd, start, end, startTrack,
2364 					   endTrack, info);
2365   }
2366 }
2367 
getTrackIndex(long lba,int * trackNr,int * indexNr,unsigned char * ctl)2368 int GenericMMC::getTrackIndex(long lba, int *trackNr, int *indexNr,
2369 			      unsigned char *ctl)
2370 {
2371   unsigned char cmd[12];
2372   unsigned short dataLen = 0x30;
2373   unsigned char data[0x30];
2374   int waitLoops = 10;
2375   int waitFailed = 0;
2376 
2377   // play one audio block
2378   memset(cmd, 0, 10);
2379   cmd[0] = 0x45; // PLAY AUDIO
2380   cmd[2] = lba >> 24;
2381   cmd[3] = lba >> 16;
2382   cmd[4] = lba >> 8;
2383   cmd[5] = lba;
2384   cmd[7] = 0;
2385   cmd[8] = 1;
2386 
2387   if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) {
2388     log_message(-2, "Cannot play audio block.");
2389     return 1;
2390   }
2391 
2392   // wait until the play command finished
2393   memset(cmd, 0, 12);
2394   cmd[0] = 0xbd; // MECHANISM STATUS
2395   cmd[9] = 8;
2396 
2397   while (waitLoops > 0) {
2398     if (sendCmd(cmd, 12, NULL, 0, data, 8, 0) == 0) {
2399       //log_message(0, "%d, %x", waitLoops, data[1]);
2400       if ((data[1] >> 5) == 1) // still playing?
2401 	waitLoops--;
2402       else
2403 	waitLoops = 0;
2404     }
2405     else {
2406       waitFailed = 1;
2407       waitLoops = 0;
2408     }
2409   }
2410 
2411   if (waitFailed) {
2412     // The play operation immediately returns success status and the waiting
2413     // loop above failed. Wait here for a while until the desired block is
2414     // played. It takes ~13 msecs to play a block but access time is in the
2415     // order of several 100 msecs
2416     mSleep(300);
2417   }
2418 
2419   // read sub channel information
2420   memset(cmd, 0, 10);
2421   cmd[0] = 0x42; // READ SUB CHANNEL
2422   cmd[2] = 0x40; // get sub channel data
2423   cmd[3] = 0x01; // get sub Q channel data
2424   cmd[6] = 0;
2425   cmd[7] = dataLen >> 8;
2426   cmd[8] = dataLen;
2427 
2428   if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
2429     log_message(-2, "Cannot read sub Q channel data.");
2430     return 1;
2431   }
2432 
2433   *trackNr = data[6];
2434   *indexNr = data[7];
2435   if (ctl != NULL) {
2436     *ctl = data[5] & 0x0f;
2437   }
2438 
2439   //log_message(0, "%d %d", *trackNr, *indexNr);
2440 
2441   return 0;
2442 }
2443 
2444 /*
2445  * Checks if a certain sub-channel reading mode is supported.
2446  * lba: start address for reading
2447  * len: maximum number of sectors available for testing
2448  * subChanMode: 1: read PQ sub-channels
2449  *              2: read raw P-W sub-channels
2450  *              3: read cooked R-W sub-channels
2451  * Return: 0 sub-channel read mode not supported
2452  *         1 sub-channel read mode supported (BCD for PQ)
2453  *         2 sub-channel read mode supported (HEX for PQ)
2454  *         3 sub-channel read mode PQ supported but cannot determine data
2455  *           format
2456 */
2457 
readCdTest(long lba,long len,int subChanMode) const2458 int GenericMMC::readCdTest(long lba, long len, int subChanMode) const
2459 {
2460   unsigned char cmd[12];
2461   long blockLen;
2462   int ret;
2463   int successRead = 0;
2464   int pqSubChanBcdOk = 0;
2465   int pqSubChanHexOk = 0;
2466 
2467   memset(cmd, 0, sizeof(cmd));
2468 
2469   //log_message(0, "readCdTest: %ld %ld %d", lba, len, subChanMode);
2470 
2471   if (len <= 0)
2472     return 0;
2473 
2474   cmd[0] = 0xbe;  // READ CD
2475   cmd[8] = 1; // transfer length: 1
2476   cmd[9] = 0xf8;
2477 
2478   blockLen = AUDIO_BLOCK_LEN;
2479 
2480   switch (subChanMode) {
2481   case 1: // PQ
2482     blockLen += PQ_SUBCHANNEL_LEN;
2483     cmd[10] = 0x02;
2484     if (len > 300)
2485       len = 300; /* we have to check many sub-channels here to determine the
2486 		  * data mode (BCD or HEX)
2487 		  */
2488     break;
2489 
2490   case 2: // PW_RAW
2491     cmd[10] = 0x01;
2492     blockLen +=  PW_SUBCHANNEL_LEN;
2493     if (len > 10)
2494       len = 10;
2495     break;
2496 
2497   case 3: // RW_COOKED
2498     cmd[10] = 0x04;
2499     blockLen +=  PW_SUBCHANNEL_LEN;
2500     if (len > 10)
2501       len = 10;
2502     break;
2503   }
2504 
2505   while (len > 0) {
2506     cmd[2] = lba >> 24;
2507     cmd[3] = lba >> 16;
2508     cmd[4] = lba >> 8;
2509     cmd[5] = lba;
2510 
2511     if ((ret = sendCmd(cmd, 12, NULL, 0, transferBuffer_, blockLen, 0)) == 0) {
2512       successRead++;
2513 
2514       if (subChanMode == 1) {
2515 	unsigned char *buf = transferBuffer_ + AUDIO_BLOCK_LEN;
2516 
2517 #if 0
2518 	{
2519  	  PQSubChannel16 chan;
2520 	  chan.init(buf);
2521 	  chan.print();
2522 	}
2523 #endif
2524 
2525 	// check if Q sub-channel values are in BCD or HEX format
2526 	if (SubChannel::isBcd(buf[1]) &&
2527 	    SubChannel::isBcd(buf[2]) &&
2528 	    SubChannel::isBcd(buf[3]) &&
2529 	    SubChannel::isBcd(buf[4]) &&
2530 	    SubChannel::isBcd(buf[5]) &&
2531 	    SubChannel::isBcd(buf[6]) &&
2532 	    SubChannel::isBcd(buf[7]) &&
2533 	    SubChannel::isBcd(buf[8]) &&
2534 	    SubChannel::isBcd(buf[9])) {
2535 	  PQSubChannel16 chan;
2536 	  chan.init(buf);
2537 
2538 	  chan.type(SubChannel::QMODE1DATA);
2539 
2540 	  int min = chan.amin();
2541 	  int sec = chan.asec();
2542 	  int frac = chan.aframe();
2543 
2544 	  if ((frac >= 0 && frac < 75) &&
2545           (sec >= 0 && sec < 60) &&
2546           (min >= 0)) {
2547 	  long pqlba = Msf(min, sec, frac).lba() - 150;
2548 
2549 	  long diff = pqlba - lba;
2550 	  if (diff < 0)
2551 	    diff = -diff;
2552 
2553 	  if (diff < 20) {
2554 	    pqSubChanBcdOk++;
2555 	  }
2556 	  }
2557 	}
2558 
2559 	if (buf[7] < 100 && buf[8] < 60 && buf[9] < 75) {
2560 	  long pqlba = Msf(buf[7], buf[8], buf[9]).lba() - 150;
2561 
2562 	  //log_message(0, "readCdTest: pqlba: %ld", pqlba);
2563 	  long diff = pqlba - lba;
2564 	  if (diff < 0)
2565 	    diff = -diff;
2566 
2567 	  if (diff < 20) {
2568 	    pqSubChanHexOk++;
2569 	  }
2570 	}
2571       }
2572     }
2573 
2574 
2575     len--;
2576     lba++;
2577   }
2578 
2579   if (successRead) {
2580     if (subChanMode == 1) {
2581       if (pqSubChanBcdOk > pqSubChanHexOk)
2582 	return 1;
2583       else if (pqSubChanHexOk > pqSubChanBcdOk)
2584 	return 2;
2585       else return 3;
2586     }
2587     else {
2588       return 1;
2589     }
2590   }
2591 
2592   return 0;
2593 }
2594 
getReadCapabilities(const CdToc * toc,int nofTracks) const2595 unsigned long GenericMMC::getReadCapabilities(const CdToc *toc,
2596 					      int nofTracks) const
2597 {
2598   unsigned long caps = 0;
2599   int audioRawPWChecked = 0;
2600   int audioPQChecked = 0;
2601   int audioCookedRWChecked = 0;
2602   int dataRawPWChecked = 0;
2603   int dataPQChecked = 0;
2604   int dataCookedRWChecked = 0;
2605   int t;
2606 
2607   if ((options_ & OPT_MMC_NO_SUBCHAN) != 0) {
2608     // driver options indicate that PQ and raw RW sub-channel reading for
2609     // audio tracks is not supported so skip all corresponding tests
2610     audioPQChecked = 1;
2611     audioRawPWChecked = 1;
2612   }
2613   else if ((options_ & OPT_MMC_USE_PQ) != 0) {
2614     // driver options indicated that PQ sub-channel reading is supported for
2615     // audio/data tracks and RW sub-channel reading is not supported, skip
2616     // the corresponding checks and set the capabilities appropriately
2617     audioPQChecked = 1;
2618     audioRawPWChecked = 1;
2619     dataPQChecked = 1;
2620 
2621     if ((options_ & OPT_MMC_PQ_BCD) != 0)
2622       caps |= CDR_READ_CAP_AUDIO_PQ_BCD | CDR_READ_CAP_DATA_PQ_BCD;
2623     else
2624       caps |= CDR_READ_CAP_AUDIO_PQ_HEX | CDR_READ_CAP_DATA_PQ_HEX;
2625   }
2626   else if ((options_ & OPT_MMC_USE_RAW_RW) != 0) {
2627     // driver options indicated that raw PW sub-channel reading is supported
2628     // audio tracks and raw PW sub-channel reading is not supported, skip
2629     // the corresponding checks and set the capabilities appropriately
2630     audioPQChecked = 1;
2631     audioRawPWChecked = 1;
2632 
2633     caps |= CDR_READ_CAP_DATA_PW_RAW;
2634   }
2635 
2636   for (t = 0; t < nofTracks; t++) {
2637     long tlen = toc[t+1].start - toc[t].start;
2638 
2639     if ((toc[t].adrCtl & 0x04) != 0) {
2640       // data track
2641       if (!dataPQChecked) {
2642 	dataPQChecked = 1;
2643 
2644 	log_message(3, "Checking for PQ sub-channel reading support (data track)...");
2645 	switch (readCdTest(toc[t].start, tlen, 1)) {
2646 	case 0:
2647 	  log_message(3, "PQ sub-channel reading (data track) not supported.");
2648 	  break;
2649 
2650 	case 1:
2651 	  log_message(2, "PQ sub-channel reading (data track) is supported, data format is BCD.");
2652 	  caps |= CDR_READ_CAP_DATA_PQ_BCD;
2653 	  break;
2654 
2655 	case 2:
2656 	  log_message(2, "PQ sub-channel reading (data track) is supported, data format is HEX.");
2657 	  caps |= CDR_READ_CAP_DATA_PQ_HEX;
2658 	  break;
2659 
2660 	case 3:
2661 	  log_message(2, "PQ sub-channel reading (data track) seems to be supported but cannot determine data format.");
2662 	  log_message(2, "Please use driver option '--driver generic-mmc:0x1' or '--driver generic-mmc:0x3' to set the data format explicitly.");
2663 	  break;
2664 	}
2665       }
2666 
2667       if (!dataRawPWChecked) {
2668 	dataRawPWChecked = 1;
2669 
2670 	log_message(3, "Checking for raw P-W sub-channel reading support (data track)...");
2671 	if (readCdTest(toc[t].start, tlen, 2)) {
2672 	  log_message(2, "Raw P-W sub-channel reading (data track) is supported.");
2673 	  caps |= CDR_READ_CAP_DATA_PW_RAW;
2674 	}
2675 	else {
2676 	  log_message(3, "Raw P-W sub-channel reading (data track) is not supported.");
2677 	}
2678       }
2679 
2680       if (!dataCookedRWChecked) {
2681 	dataCookedRWChecked = 1;
2682 
2683 	log_message(3, "Checking for cooked R-W sub-channel reading support (data track)...");
2684 	if (readCdTest(toc[t].start, tlen, 3)) {
2685 	  log_message(2, "Cooked R-W sub-channel reading (data track) is supported.");
2686 	  caps |= CDR_READ_CAP_DATA_RW_COOKED;
2687 	}
2688 	else {
2689 	  log_message(3, "Cooked R-W sub-channel reading (data track) is not supported.");
2690 	}
2691       }
2692     }
2693     else {
2694       // audio track
2695       if (!audioPQChecked) {
2696 	audioPQChecked = 1;
2697 
2698 	log_message(3, "Checking for PQ sub-channel reading support (audio track)...");
2699 	switch (readCdTest(toc[t].start, tlen, 1)) {
2700 	case 0:
2701 	  log_message(3, "PQ sub-channel reading (audio track) is not supported.");
2702 	  break;
2703 
2704 	case 1:
2705 	  log_message(2, "PQ sub-channel reading (audio track) is supported, data format is BCD.");
2706 	  caps |= CDR_READ_CAP_AUDIO_PQ_BCD;
2707 	  break;
2708 
2709 	case 2:
2710 	  log_message(2, "PQ sub-channel reading (audio track) is supported, data format is HEX.");
2711 	  caps |= CDR_READ_CAP_AUDIO_PQ_HEX;
2712 	  break;
2713 
2714 	case 3:
2715 	  log_message(2, "PQ sub-channel reading (audio track) seems to be supported but cannot determine data format.");
2716 	  log_message(2, "Please use driver option '--driver generic-mmc:0x1' or '--driver generic-mmc:0x3' to set the data format explicitly.");
2717 	  break;
2718 	}
2719       }
2720 
2721       if (!audioRawPWChecked) {
2722 	audioRawPWChecked = 1;
2723 
2724 	log_message(3, "Checking for raw P-W sub-channel reading support (audio track)...");
2725 	if (readCdTest(toc[t].start, tlen, 2)) {
2726 	  log_message(2, "Raw P-W sub-channel reading (audio track) is supported.");
2727 	  caps |= CDR_READ_CAP_AUDIO_PW_RAW;
2728 	}
2729 	else {
2730 	  log_message(3, "Raw P-W sub-channel reading (audio track) is not supported.");
2731 	}
2732       }
2733 
2734       if (!audioCookedRWChecked) {
2735 	audioCookedRWChecked = 1;
2736 
2737 	log_message(3, "Checking for cooked R-W sub-channel reading support (audio track)...");
2738 	if (readCdTest(toc[t].start, tlen, 3)) {
2739 	  log_message(2, "Cooked R-W sub-channel reading (audio track) is supported.");
2740 	  caps |= CDR_READ_CAP_AUDIO_RW_COOKED;
2741 	}
2742 	else {
2743 	  log_message(3, "Raw R-W sub-channel reading (audio track) is not supported.");
2744 	}
2745       }
2746     }
2747   }
2748 
2749   return caps;
2750 }
2751 
RicohGetWriteOptions()2752 int GenericMMC::RicohGetWriteOptions()
2753 {
2754   unsigned char mp[14];
2755 
2756   driveInfo_->ricohJustLink = 0;
2757   driveInfo_->ricohJustSpeed = 0;
2758 
2759   if (getModePage(0x30, mp, 14, NULL, NULL, 0) != 0) {
2760     return 1;
2761   }
2762 
2763   if (mp[1] != 14)
2764     return 1;
2765 
2766   if (mp[2] & (1 << 5))
2767     driveInfo_->ricohJustSpeed = 1;
2768 
2769   if (mp[2] & 0x01)
2770     driveInfo_->ricohJustLink = 1;
2771 
2772   return 0;
2773 }
2774 
RicohSetWriteOptions(const DriveInfo * di)2775 int GenericMMC::RicohSetWriteOptions(const DriveInfo *di)
2776 {
2777   unsigned char mp[14];
2778 
2779   if (di->ricohJustLink == 0 && di->ricohJustSpeed == 0)
2780     return 0;
2781 
2782   if (getModePage(0x30, mp, 14, NULL, NULL, 1) != 0) {
2783     log_message(-2, "Cannot retrieve Ricoh mode page 30.");
2784     return 1;
2785   }
2786 
2787   if (di->ricohJustLink) {
2788     if (bufferUnderRunProtection()) {
2789       log_message(2, "Enabling JustLink.");
2790       mp[3] |= 0x1;
2791     }
2792     else {
2793       log_message(2, "Disabling JustLink.");
2794       mp[3] &= ~0x1;
2795     }
2796   }
2797 
2798   if (di->ricohJustSpeed) {
2799     if (writeSpeedControl()) {
2800       log_message(2, "Enabling JustSpeed.");
2801       mp[3] &= ~(1 << 5); // clear bit to enable write speed control
2802     }
2803     else {
2804       log_message(2, "Disabling JustSpeed.");
2805       mp[3] |= (1 << 5);  // set bit to disable write speed control
2806     }
2807   }
2808 
2809   if (setModePage(mp, NULL, NULL, 1) != 0) {
2810     log_message(-2, "Cannot set Ricoh mode page 30.");
2811     return 1;
2812   }
2813 
2814   return 0;
2815 }
2816