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