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 "PlextorReaderScan.h"
26 #include "PWSubChannel96.h"
27 #include "PQSubChannel16.h"
28 
29 #include "Toc.h"
30 #include "log.h"
31 
PlextorReaderScan(ScsiIf * scsiIf,unsigned long options)32 PlextorReaderScan::PlextorReaderScan(ScsiIf *scsiIf, unsigned long options)
33   : PlextorReader(scsiIf, options)
34 {
35   int i;
36 
37   driverName_ = "Plextor CD-ROM Reader (scanning) - Version 1.0";
38 
39   for (i = 0; i < maxScannedSubChannels_; i++) {
40     if (options_ & OPT_PLEX_USE_PQ)
41       scannedSubChannels_[i] = new PQSubChannel16;
42     else
43       scannedSubChannels_[i] = new PWSubChannel96;
44   }
45 }
46 
~PlextorReaderScan()47 PlextorReaderScan::~PlextorReaderScan()
48 {
49   int i;
50 
51   for (i = 0; i < maxScannedSubChannels_; i++) {
52     delete scannedSubChannels_[i];
53     scannedSubChannels_[i] = NULL;
54   }
55 }
56 
57 // static constructor
instance(ScsiIf * scsiIf,unsigned long options)58 CdrDriver *PlextorReaderScan::instance(ScsiIf *scsiIf, unsigned long options)
59 {
60   return new PlextorReaderScan(scsiIf, options);
61 }
62 
readDisk(int session,const char * fname)63 Toc *PlextorReaderScan::readDisk(int session, const char *fname)
64 {
65   Toc *toc = CdrDriver::readDisk(session, fname);
66 
67   setBlockSize(MODE1_BLOCK_LEN);
68 
69   return toc;
70 }
71 
analyzeTrack(TrackData::Mode mode,int trackNr,long startLba,long endLba,Msf * indexIncrements,int * indexIncrementCnt,long * pregap,char * isrcCode,unsigned char * ctl)72 int PlextorReaderScan::analyzeTrack(TrackData::Mode mode, int trackNr,
73 				    long startLba,
74 				    long endLba, Msf *indexIncrements,
75 				    int *indexIncrementCnt, long *pregap,
76 				    char *isrcCode, unsigned char *ctl)
77 {
78   int ret = analyzeTrackScan(mode, trackNr, startLba, endLba,
79 			     indexIncrements, indexIncrementCnt, pregap,
80 			     isrcCode, ctl);
81 
82   if ((options_ & OPT_PLEX_READ_ISRC) ||
83       ((options_ & OPT_PLEX_USE_PQ) && !(options_ & OPT_PLEX_PQ_BCD))) {
84     // The ISRC code is usually not usable if the PQ channel data is
85     // converted to hex numbers by the drive. Read them with the
86     // appropriate command in this case
87 
88     *isrcCode = 0;
89     if (mode == TrackData::AUDIO)
90       readIsrc(trackNr, isrcCode);
91   }
92 
93   return ret;
94 }
95 
readSubChannels(TrackData::SubChannelMode sm,long lba,long len,SubChannel *** chans,Sample * audioData)96 int PlextorReaderScan::readSubChannels(TrackData::SubChannelMode sm,
97 				       long lba, long len, SubChannel ***chans,
98 				       Sample *audioData)
99 {
100   unsigned char cmd[12];
101   int i;
102   int retries = 5;
103   long blockLen;
104 
105   if (options_ & OPT_PLEX_USE_PQ)
106     blockLen = AUDIO_BLOCK_LEN + 16;
107   else
108     blockLen = AUDIO_BLOCK_LEN + 96;
109 
110   cmd[0] = 0xd8;  // READ CDDA
111   cmd[1] = 0;
112   cmd[2] = lba >> 24;
113   cmd[3] = lba >> 16;
114   cmd[4] = lba >> 8;
115   cmd[5] = lba;
116   cmd[6] = 0;
117   cmd[7] = len >> 16;
118   cmd[8] = len >> 8;
119   cmd[9] = len;
120 
121   if (options_ & OPT_PLEX_USE_PQ)
122     cmd[10] = 0x01;
123   else
124     cmd[10] = 0x02;
125 
126   cmd[11] = 0;
127 
128   while (1) {
129     if (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * blockLen,
130 		retries == 0 ? 1 : 0) != 0) {
131       if (retries == 0)
132 	return 1;
133     }
134     else {
135       break;
136     }
137 
138     retries--;
139   }
140 
141 #if 0
142   if (lba > 5000) {
143     char fname[200];
144     sprintf(fname, "testout_%ld", lba);
145     FILE *fp = fopen(fname, "w");
146     fwrite(transferBuffer_, blockLen, len, fp);
147     fclose(fp);
148   }
149 #endif
150 
151   unsigned char *p =  transferBuffer_ + AUDIO_BLOCK_LEN;
152 
153   for (i = 0; i < len; i++) {
154     if (options_ & OPT_PLEX_USE_PQ) {
155       if (!(options_ & OPT_PLEX_PQ_BCD)) {
156 	// Numbers in sub-channel data are hex instead of BCD.
157 	// We have to convert them back to BCD for the 'SubChannel' class.
158 	p[1] = SubChannel::bcd(p[1]);
159 	p[2] = SubChannel::bcd(p[2]);
160 	p[3] = SubChannel::bcd(p[3]);
161 	p[4] = SubChannel::bcd(p[4]);
162 	p[5] = SubChannel::bcd(p[5]);
163 	p[6] = SubChannel::bcd(p[6]);
164 	p[7] = SubChannel::bcd(p[7]);
165 	p[8] = SubChannel::bcd(p[8]);
166 	p[9] = SubChannel::bcd(p[9]);
167       }
168 
169       ((PQSubChannel16*)scannedSubChannels_[i])->init(p);
170 
171       if (scannedSubChannels_[i]->type() != SubChannel::QMODE_ILLEGAL) {
172 	// the CRC of the sub-channel data is usually invalid -> mark the
173 	// sub-channel object that it should not try to verify the CRC
174 	scannedSubChannels_[i]->crcInvalid();
175       }
176     }
177     else {
178       ((PWSubChannel96*)scannedSubChannels_[i])->init(p);
179     }
180 
181     p += blockLen;
182   }
183 
184   if (audioData != NULL) {
185     p = transferBuffer_;
186 
187     for (i = 0; i < len; i++) {
188       memcpy(audioData, p, AUDIO_BLOCK_LEN);
189 
190       p += blockLen;
191       audioData += SAMPLES_PER_BLOCK;
192     }
193   }
194 
195   *chans = scannedSubChannels_;
196   return 0;
197 }
198 
readAudioRange(ReadDiskInfo * info,int fd,long start,long end,int startTrack,int endTrack,TrackInfo * trackInfo)199 int PlextorReaderScan::readAudioRange(ReadDiskInfo *info, int fd, long start,
200 				      long end, int startTrack, int endTrack,
201 				      TrackInfo *trackInfo)
202 {
203   if (!onTheFly_) {
204     if ((options_ & OPT_PLEX_READ_ISRC) ||
205 	((options_ & OPT_PLEX_USE_PQ) && !(options_ & OPT_PLEX_PQ_BCD))) {
206       int t;
207 
208       log_message(1, "Analyzing...");
209 
210       for (t = startTrack; t <= endTrack; t++) {
211 	long totalProgress;
212 
213 	log_message(1, "Track %d...", t + 1);
214 
215 	totalProgress = t * 1000;
216 	totalProgress /= info->tracks;
217 	sendReadCdProgressMsg(RCD_ANALYZING, info->tracks, t + 1, 0,
218 			      totalProgress);
219 
220 	trackInfo[t].isrcCode[0] = 0;
221 	readIsrc(t + 1, trackInfo[t].isrcCode);
222 	if (trackInfo[t].isrcCode[0] != 0)
223 	  log_message(2, "Found ISRC code.");
224 
225 	totalProgress = (t + 1) * 1000;
226 	totalProgress /= info->tracks;
227 	sendReadCdProgressMsg(RCD_ANALYZING, info->tracks, t + 1, 1000,
228 			      totalProgress);
229       }
230 
231       log_message(1, "Reading...");
232     }
233   }
234 
235   return CdrDriver::readAudioRangeParanoia(info, fd, start, end, startTrack,
236 					   endTrack, trackInfo);
237 }
238