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 <sys/types.h>
23 #include <sys/stat.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <ctype.h>
32
33 #include "CdrDriver.h"
34 #include "PWSubChannel96.h"
35 #include "Toc.h"
36 #include "util.h"
37 #include "log.h"
38 #include "CdTextItem.h"
39 #include "data.h"
40 #include "port.h"
41
42 // all drivers
43 #include "CDD2600.h"
44 #include "PlextorReader.h"
45 #include "PlextorReaderScan.h"
46 #include "GenericMMC.h"
47 #include "GenericMMCraw.h"
48 #include "RicohMP6200.h"
49 #include "TaiyoYuden.h"
50 #include "YamahaCDR10x.h"
51 #include "TeacCdr55.h"
52 #include "SonyCDU920.h"
53 #include "SonyCDU948.h"
54 #include "ToshibaReader.h"
55
56 // Paranoia DAE related
57 #include "cdda_interface.h"
58 #include "../paranoia/cdda_paranoia.h"
59
60
61 typedef CdrDriver *(*CdrDriverConstructor)(ScsiIf *, unsigned long);
62
63 struct DriverSelectTable {
64 const char *driverId;
65 const char *vendor;
66 const char *model;
67 unsigned long options;
68 struct DriverSelectTable *next;
69 };
70
71 struct DriverTable {
72 const char *driverId;
73 CdrDriverConstructor constructor;
74 };
75
76 static DriverSelectTable *READ_DRIVER_TABLE = NULL;
77 static DriverSelectTable *WRITE_DRIVER_TABLE = NULL;
78
79 static DriverSelectTable BUILTIN_READ_DRIVER_TABLE[] = {
80 { "generic-mmc", "ASUS", "CD-S340", 0, NULL },
81 { "generic-mmc", "ASUS", "CD-S400", 0, NULL },
82 { "generic-mmc", "ASUS", "CD-S500/A", OPT_MMC_NO_SUBCHAN, NULL },
83 { "generic-mmc", "ASUS", "DVD-ROM E608", 0, NULL },
84 { "generic-mmc", "E-IDE", "CD-950E/TKU", 0, NULL },
85 { "generic-mmc", "E-IDE", "CD-ROM 36X/AKU", 0, NULL },
86 { "generic-mmc", "E-IDE", "CD-ROM 52X/AKH", 0, NULL },
87 { "generic-mmc", "FUNAI", "E295X", 0, NULL },
88 { "generic-mmc", "Goldstar", "CD-RW CED-8042B", 0, NULL },
89 { "generic-mmc", "HITACHI", "CDR-7730", 0, NULL },
90 { "generic-mmc", "HITACHI", "CDR-8435", OPT_MMC_NO_SUBCHAN, NULL },
91 { "generic-mmc", "LG", "CD-ROM CRD-8480C", OPT_MMC_NO_SUBCHAN, NULL },
92 { "generic-mmc", "LG", "CD-ROM CRD-8482B", OPT_MMC_NO_SUBCHAN, NULL },
93 { "generic-mmc", "LG", "CD-ROM CRD-8521B", 0, NULL },
94 { "generic-mmc", "LG", "DVD-ROM DRN8080B", OPT_DRV_GET_TOC_GENERIC, NULL },
95 { "generic-mmc", "LITE-ON", "CD-ROM", OPT_DRV_GET_TOC_GENERIC, NULL },
96 { "generic-mmc", "LITE-ON", "LTD-163", 0, NULL },
97 { "generic-mmc", "LITEON", "DVD-ROM LTD163D", 0, NULL },
98 { "generic-mmc", "MATSHITA", "CD-ROM CR-588", 0, NULL },
99 { "generic-mmc", "MATSHITA", "CD-ROM CR-589", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
100 { "generic-mmc", "MATSHITA", "DVD-ROM SR-8585", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
101 { "generic-mmc", "MEMOREX", "CD-233E", 0, NULL },
102 { "generic-mmc", "MITSUMI", "CD-ROM FX4820", OPT_MMC_NO_SUBCHAN, NULL },
103 { "generic-mmc", "OPTICS_S", "8622", 0, NULL },
104 { "generic-mmc", "PHILIPS", "36X/AKU", 0, NULL },
105 { "generic-mmc", "PHILIPS", "CD-ROM PCCD052", 0, NULL },
106 { "generic-mmc", "PHILIPS", "E-IDE CD-ROM 36X", 0, NULL },
107 { "generic-mmc", "PIONEER", "CD-ROM DR-U32", OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
108 { "generic-mmc", "PIONEER", "DVD-103", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
109 { "generic-mmc", "PIONEER", "DVD-104", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
110 { "generic-mmc", "PIONEER", "DVD-105", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
111 { "generic-mmc", "SONY", "CD-ROM CDU31A-02", 0, NULL },
112 { "generic-mmc", "SONY", "CD-ROM CDU4821", 0, NULL },
113 { "generic-mmc", "SONY", "CDU5211", 0, NULL },
114 { "generic-mmc", "TEAC", "CD-524E", OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
115 { "generic-mmc", "TEAC", "CD-532E", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
116 { "generic-mmc", "TEAC", "CD-540E", 0, NULL },
117 { "generic-mmc", "TOSHIBA", "CD-ROM XM-3206B", 0, NULL },
118 { "generic-mmc", "TOSHIBA", "CD-ROM XM-6102B", 0, NULL },
119 { "generic-mmc", "TOSHIBA", "CD-ROM XM-6302B", 0, NULL },
120 { "generic-mmc", "TOSHIBA", "CD-ROM XM-6402B", 0, NULL },
121 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-C2202", 0, NULL },
122 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-C2302", 0, NULL },
123 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-C2402", 0, NULL },
124 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-M1102", 0, NULL },
125 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-M1401", 0, NULL },
126 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-M1402", 0, NULL },
127 { "plextor", "HITACHI", "DVD-ROM GD-2500", 0, NULL },
128 { "plextor", "MATSHITA", "CD-ROM CR-506", OPT_PLEX_DAE_D4_12, NULL },
129 { "plextor", "MATSHITA", "CR-8008", 0, NULL },
130 { "plextor", "NAKAMICH", "MJ-5.16S", 0, NULL },
131 { "plextor", "PIONEER", "CD-ROM DR-U03", OPT_DRV_GET_TOC_GENERIC, NULL },
132 { "plextor", "PIONEER", "CD-ROM DR-U06", OPT_DRV_GET_TOC_GENERIC, NULL },
133 { "plextor", "PIONEER", "CD-ROM DR-U10", OPT_DRV_GET_TOC_GENERIC, NULL },
134 { "plextor", "PIONEER", "CD-ROM DR-U12", OPT_DRV_GET_TOC_GENERIC, NULL },
135 { "plextor", "PIONEER", "CD-ROM DR-U16", OPT_DRV_GET_TOC_GENERIC, NULL },
136 { "plextor", "PIONEER", "DVD-303", 0, NULL },
137 { "plextor", "PIONEER", "DVD-305", 0, NULL },
138 { "plextor", "SAF", "CD-R2006PLUS", 0, NULL },
139 { "plextor", "SONY", "CD-ROM", 0, NULL },
140 { "plextor", "SONY", "CD-ROM CDU-76", 0, NULL },
141 { "plextor", "TOSHIBA", "XM-5401", 0, NULL },
142 { "plextor-scan", "PLEXTOR", "CD-ROM", 0, NULL },
143 { "plextor-scan", "PLEXTOR", "PX-40TS", 0, NULL },
144 { "plextor-scan", "PLEXTOR", "PX-40TW", 0, NULL },
145 { "plextor-scan", "PLEXTOR", "PX-63", 0, NULL },
146 { "plextor-scan", "TEAC", "CD-ROM CD-532S", OPT_PLEX_USE_PQ|OPT_PLEX_PQ_BCD, NULL },
147 { "teac-cdr55", "TEAC", "CD-532S", 0, NULL },
148 { "toshiba", "TOSHIBA", "1504", 0, NULL },
149 { "toshiba", "TOSHIBA", "CD-ROM XM-3601B", 0, NULL },
150 { "toshiba", "TOSHIBA", "CD-ROM XM-5302TA", 0, NULL },
151 { "toshiba", "TOSHIBA", "CD-ROM XM-5701TA", 0, NULL },
152 { "toshiba", "TOSHIBA", "CD-ROM XM-6201TA", 0, NULL },
153 { "toshiba", "TOSHIBA", "CD-ROM XM-6401TA", 0, NULL },
154 { "toshiba", "TOSHIBA", "DVD-ROM SD-2102", 0, NULL },
155 { NULL, NULL, NULL, 0, NULL }};
156
157 static DriverSelectTable BUILTIN_WRITE_DRIVER_TABLE[] = {
158 { "cdd2600", "GRUNDIG", "CDR100IPW", 0, NULL },
159 { "cdd2600", "HP", "CD-Writer 4020", 0, NULL },
160 { "cdd2600", "HP", "CD-Writer 6020", 0, NULL },
161 { "cdd2600", "IMS", "522", 0, NULL },
162 { "cdd2600", "IMS", "CDD2000", 0, NULL },
163 { "cdd2600", "KODAK", "PCD-225", 0, NULL },
164 { "cdd2600", "PHILIPS", "CDD2000", 0, NULL },
165 { "cdd2600", "PHILIPS", "CDD2600", 0, NULL },
166 { "cdd2600", "PHILIPS", "CDD522", 0, NULL },
167 { "generic-mmc", "AOPEN", "CD-RW CRW1632", 0, NULL },
168 { "generic-mmc", "AOPEN", "CD-RW CRW2040", 0, NULL },
169 { "generic-mmc", "AOPEN", "CD-RW-241040", 0, NULL },
170 { "generic-mmc", "AOPEN", "CRW9624", 0, NULL },
171 { "generic-mmc", "CD-RW", "CDR-2440MB", OPT_MMC_CD_TEXT, NULL },
172 { "generic-mmc", "CREATIVE", "CD-RW RW1210E", 0, NULL },
173 { "generic-mmc", "CREATIVE", "CD-RW RW4424", 0, NULL },
174 { "generic-mmc", "CREATIVE", "CD-RW RW8433E", OPT_MMC_CD_TEXT, NULL },
175 { "generic-mmc", "CREATIVE", "CD5233E", 0, NULL },
176 { "generic-mmc", "DELTA", "OME-W141", 0, NULL },
177 { "generic-mmc", "GENERIC", "CRD-BP1600P", 0, NULL },
178 { "generic-mmc", "GENERIC", "CRD-R800S", 0, NULL },
179 { "generic-mmc", "GENERIC", "CRD-RW2", 0, NULL },
180 { "generic-mmc", "HL-DT-ST", "DVDRAM GSA-H42L", OPT_MMC_CD_TEXT, NULL },
181 { "generic-mmc", "HL-DT-ST", "RW/DVD GCC-4120B", OPT_MMC_CD_TEXT, NULL },
182 { "generic-mmc", "HP", "9510i", OPT_MMC_CD_TEXT, NULL },
183 { "generic-mmc", "HP", "CD-Writer+ 7570", OPT_MMC_CD_TEXT, NULL },
184 { "generic-mmc", "HP", "CD-Writer+ 8100", OPT_MMC_CD_TEXT, NULL },
185 { "generic-mmc", "HP", "CD-Writer+ 8200", OPT_MMC_CD_TEXT, NULL },
186 { "generic-mmc", "HP", "CD-Writer+ 8290", OPT_MMC_CD_TEXT, NULL },
187 { "generic-mmc", "HP", "CD-Writer+ 9100", OPT_MMC_CD_TEXT, NULL },
188 { "generic-mmc", "HP", "CD-Writer+ 9110", OPT_MMC_CD_TEXT, NULL },
189 { "generic-mmc", "HP", "CD-Writer+ 9200", OPT_MMC_CD_TEXT, NULL },
190 { "generic-mmc", "HP", "CD-Writer+ 9300", OPT_MMC_CD_TEXT, NULL },
191 { "generic-mmc", "HP", "CD-Writer+ 9600", OPT_MMC_CD_TEXT, NULL },
192 { "generic-mmc", "HP", "CD-Writer+ 9700", OPT_MMC_CD_TEXT, NULL },
193 { "generic-mmc", "HP", "DVD Writer 100j", 0, NULL },
194 { "generic-mmc", "IDE-CD", "R/RW 16x10A", 0, NULL },
195 { "generic-mmc", "IMATION", "IMW121032IAB", 0, NULL },
196 { "generic-mmc", "LG", "8088B", 0, NULL },
197 { "generic-mmc", "LG", "8120B", OPT_MMC_CD_TEXT, NULL },
198 { "generic-mmc", "LG", "CD-ROM CDR-8428B", 0, NULL },
199 { "generic-mmc", "LG", "CD-RW CED-8080B", OPT_MMC_CD_TEXT, NULL },
200 { "generic-mmc", "LG", "CD-RW CED-8081B", OPT_MMC_CD_TEXT, NULL },
201 { "generic-mmc", "LG", "CD-RW CED-8083B", OPT_MMC_CD_TEXT, NULL },
202 { "generic-mmc", "LG", "CD-RW GCE-8240B", OPT_MMC_CD_TEXT, NULL },
203 { "generic-mmc", "LG", "COMBO", 0, NULL },
204 { "generic-mmc", "LG", "HL-DT-ST RW/DVD GCC-4080N", OPT_MMC_CD_TEXT, NULL },
205 { "generic-mmc", "LITE-ON", "LTR-0841", OPT_MMC_CD_TEXT|OPT_MMC_NO_SUBCHAN, NULL },
206 { "generic-mmc", "LITE-ON", "LTR-24102B", 0, NULL },
207 { "generic-mmc", "LITE-ON", "LTR-32125W", OPT_MMC_CD_TEXT, NULL },
208 { "generic-mmc", "MATSHITA", "CD-R CW-7502", 0, NULL },
209 { "generic-mmc", "MATSHITA", "CD-R CW-7503", 0, NULL },
210 { "generic-mmc", "MATSHITA", "CD-R CW-7582", 0, NULL },
211 { "generic-mmc", "MATSHITA", "CD-R CW-7585", 0, NULL },
212 { "generic-mmc", "MATSHITA", "CD-R CW-7586", 0, NULL },
213 { "generic-mmc", "MATSHITA", "CDRRW01", 0, NULL },
214 { "generic-mmc", "MATSHITA", "UJDA360", 0, NULL },
215 { "generic-mmc", "MATSHITA", "UJDA710", OPT_MMC_CD_TEXT, NULL },
216 { "generic-mmc", "MATSHITA", "UJDA720", OPT_MMC_CD_TEXT, NULL },
217 { "generic-mmc", "MEMOREX", "24MAX 1040", 0, NULL },
218 { "generic-mmc", "MEMOREX", "40MAXX 1248AJ", 0, NULL },
219 { "generic-mmc", "MEMOREX", "CD-RW4224", 0, NULL },
220 { "generic-mmc", "MICROSOLUTIONS", "BACKPACK CD REWRITER", 0, NULL },
221 { "generic-mmc", "MITSUMI", "CR-4801", 0, NULL },
222 { "generic-mmc", "MITSUMI", "CR-48X5", 0, NULL },
223 { "generic-mmc", "MITSUMI", "CR-48X5TE", OPT_MMC_CD_TEXT, NULL },
224 { "generic-mmc", "MITSUMI", "CR-48X8TE", 0, NULL },
225 { "generic-mmc", "MITSUMI", "CR-48XATE", 0, NULL },
226 { "generic-mmc", "OLYMPIC", "RWD RW4224", OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ, NULL },
227 { "generic-mmc", "PANASONIC", "CD-R CW-7582", 0, NULL },
228 { "generic-mmc", "PHILIPS", "CDRW1610A", OPT_MMC_CD_TEXT, NULL },
229 { "generic-mmc", "PHILIPS", "CDRW2412A", 0, NULL },
230 { "generic-mmc", "PHILIPS", "PCA460RW", 0, NULL },
231 { "generic-mmc", "PIONEER", "DVD-ROM DVD-114", OPT_MMC_CD_TEXT, NULL },
232 { "generic-mmc", "PLEXTOR", "CD-R PX-R412", OPT_MMC_USE_PQ|OPT_MMC_READ_ISRC, NULL },
233 { "generic-mmc", "PLEXTOR", "CD-R PX-R820", 0, NULL },
234 { "generic-mmc", "PLEXTOR", "CD-R PX-W1210", OPT_MMC_CD_TEXT, NULL },
235 { "generic-mmc", "PLEXTOR", "CD-R PX-W124", OPT_MMC_CD_TEXT, NULL },
236 { "generic-mmc", "PLEXTOR", "CD-R PX-W1610", OPT_MMC_CD_TEXT, NULL },
237 { "generic-mmc", "PLEXTOR", "CD-R PX-W4220", OPT_MMC_CD_TEXT, NULL },
238 { "generic-mmc", "PLEXTOR", "CD-R PX-W8220", OPT_MMC_CD_TEXT, NULL },
239 { "generic-mmc", "PLEXTOR", "CD-R PX-W8432", OPT_MMC_CD_TEXT, NULL },
240 { "generic-mmc", "PLEXTOR", "CD-R PX-W241040", OPT_MMC_CD_TEXT, NULL },
241 { "generic-mmc", "PLEXTOR", "CD-R PX-W2410a", OPT_MMC_CD_TEXT, NULL },
242 { "generic-mmc", "PLEXTOR", "CD-R PX-W4012A", OPT_MMC_CD_TEXT, NULL },
243 { "generic-mmc", "RICOH", "CD-R/RW MP7040", OPT_MMC_CD_TEXT, NULL },
244 { "generic-mmc", "RICOH", "CD-R/RW MP7060", OPT_MMC_CD_TEXT, NULL },
245 { "generic-mmc", "RICOH", "CD-R/RW MP7063A", OPT_MMC_CD_TEXT, NULL },
246 { "generic-mmc", "RICOH", "CD-R/RW MP7080", OPT_MMC_CD_TEXT, NULL },
247 { "generic-mmc", "RICOH", "CD-R/RW MP7083A", OPT_MMC_CD_TEXT, NULL },
248 { "generic-mmc", "RICOH", "DVD/CDRW MP9060", OPT_MMC_CD_TEXT, NULL },
249 { "generic-mmc", "SAF", "CD-R8020", 0, NULL },
250 { "generic-mmc", "SAF", "CD-RW4224A", 0, NULL },
251 { "generic-mmc", "SAF", "CD-RW6424", 0, NULL },
252 { "generic-mmc", "SAMSUNG", "CD-R/RW SW-206", 0, NULL },
253 { "generic-mmc", "SAMSUNG", "CD-R/RW SW-408B", OPT_MMC_CD_TEXT, NULL },
254 { "generic-mmc", "SAMSUNG", "CDRW/DVD SM-308B", OPT_MMC_CD_TEXT, NULL },
255 { "generic-mmc", "SANYO", "CRD-BP3", 0, NULL },
256 { "generic-mmc", "SONY", "CD-RW CRX700E", 0, NULL },
257 { "generic-mmc", "SONY", "CRX-815", OPT_MMC_CD_TEXT, NULL },
258 { "generic-mmc", "SONY", "CRX100", OPT_MMC_CD_TEXT, NULL },
259 { "generic-mmc", "SONY", "CRX120", OPT_MMC_CD_TEXT, NULL },
260 { "generic-mmc", "SONY", "CRX140", OPT_MMC_CD_TEXT, NULL },
261 { "generic-mmc", "SONY", "CRX145", OPT_MMC_CD_TEXT, NULL },
262 { "generic-mmc", "SONY", "CRX160E", OPT_MMC_CD_TEXT, NULL },
263 { "generic-mmc", "SONY", "CRX175A1", 0, NULL },
264 { "generic-mmc", "SONY", "CRX175E", OPT_MMC_CD_TEXT, NULL },
265 { "generic-mmc", "SONY", "CRX185E1", OPT_MMC_CD_TEXT, NULL },
266 { "generic-mmc", "TDK", "4800", OPT_MMC_CD_TEXT, NULL },
267 { "generic-mmc", "TDK", "CDRW121032", OPT_MMC_CD_TEXT, NULL },
268 { "generic-mmc", "TDK", "CDRW321040B", 0, NULL },
269 { "generic-mmc", "TDK", "CDRW8432", OPT_MMC_CD_TEXT, NULL },
270 { "generic-mmc", "TEAC", "CD-R56", OPT_MMC_USE_PQ|OPT_MMC_CD_TEXT, NULL },
271 { "generic-mmc", "TEAC", "CD-R58", OPT_MMC_USE_PQ|OPT_MMC_CD_TEXT, NULL },
272 { "generic-mmc", "TEAC", "CD-W216E", OPT_MMC_CD_TEXT, NULL },
273 { "generic-mmc", "TEAC", "CD-W512EB", OPT_MMC_CD_TEXT, NULL },
274 { "generic-mmc", "TEAC", "CD-W512SB", OPT_MMC_CD_TEXT, NULL },
275 { "generic-mmc", "TEAC", "CD-W516EB", OPT_MMC_CD_TEXT, NULL },
276 { "generic-mmc", "TEAC", "CD-W516EC", OPT_MMC_CD_TEXT, NULL },
277 { "generic-mmc", "TEAC", "CD-W524E", OPT_MMC_CD_TEXT, NULL },
278 { "generic-mmc", "TEAC", "CD-W54E", 0, NULL },
279 { "generic-mmc", "TORiSAN", "CDW-U4424", 0, NULL },
280 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-M1612", 0, NULL },
281 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-R1002", 0, NULL },
282 { "generic-mmc", "TOSHIBA", "DVD-ROM SD-R1202", 0, NULL },
283 { "generic-mmc", "TRAXDATA", "241040", 0, NULL },
284 { "generic-mmc", "TRAXDATA", "CDRW4260", 0, NULL },
285 { "generic-mmc", "WAITEC", "WT624", OPT_MMC_NO_SUBCHAN, NULL },
286 { "generic-mmc", "YAMAHA", "CDR200", 0, NULL },
287 { "generic-mmc", "YAMAHA", "CDR400", 0, NULL },
288 { "generic-mmc", "YAMAHA", "CRW2100", OPT_MMC_CD_TEXT, NULL },
289 { "generic-mmc", "YAMAHA", "CRW2200", OPT_MMC_CD_TEXT, NULL },
290 { "generic-mmc", "YAMAHA", "CRW2260", 0, NULL },
291 { "generic-mmc", "YAMAHA", "CRW3200", OPT_MMC_CD_TEXT, NULL },
292 { "generic-mmc", "YAMAHA", "CRW4001", 0, NULL },
293 { "generic-mmc", "YAMAHA", "CRW4260", 0, NULL },
294 { "generic-mmc", "YAMAHA", "CRW4416", 0, NULL },
295 { "generic-mmc", "YAMAHA", "CRW6416", 0, NULL },
296 { "generic-mmc", "YAMAHA", "CRW8424", 0, NULL },
297 { "generic-mmc", "YAMAHA", "CRW8824", 0, NULL },
298 { "generic-mmc", "_NEC", "NR-7700A", 0, NULL },
299 { "generic-mmc-raw", "ACER", "10x8x32", 0, NULL },
300 { "generic-mmc-raw", "ACER", "2010A", 0, NULL },
301 { "generic-mmc-raw", "ACER", "20x10x40", 0, NULL },
302 { "generic-mmc-raw", "ACER", "4406EU", 0, NULL },
303 { "generic-mmc-raw", "ACER", "4x4x6", 0, NULL },
304 { "generic-mmc-raw", "ACER", "8X4X32", 0, NULL },
305 { "generic-mmc-raw", "ACER", "CD-R/RW 4X4X32", OPT_MMC_NO_SUBCHAN, NULL },
306 { "generic-mmc-raw", "AOPEN", "CD-RW CRW3248", 0, NULL },
307 { "generic-mmc-raw", "AOPEN", "CRW1232", 0, NULL },
308 { "generic-mmc-raw", "ARTEC", "RW241040", 0, NULL },
309 { "generic-mmc-raw", "ARTEC", "WRA-WA48", 0, NULL },
310 { "generic-mmc-raw", "ARTEC", "WRR-4048", 0, NULL },
311 { "generic-mmc-raw", "ASUS", "CRW-1610A", 0, NULL },
312 { "generic-mmc-raw", "ASUS", "CRW-3212A", 0, NULL },
313 { "generic-mmc-raw", "ATAPI", "CD-R/RW 12X8X32", 0, NULL },
314 { "generic-mmc-raw", "ATAPI", "CD-R/RW 4X4X32", 0, NULL },
315 { "generic-mmc-raw", "ATAPI", "CD-R/RW CRW6206A", 0, NULL },
316 { "generic-mmc-raw", "BENQ", "CRW2410A", 0, NULL },
317 { "generic-mmc-raw", "BTC", "BCE1610IM", 0, NULL },
318 { "generic-mmc-raw", "BTC", "BCE2410IM", 0, NULL },
319 { "generic-mmc-raw", "BTC", "BCE621E", 0, NULL },
320 { "generic-mmc-raw", "CyberDrv", "CW018D", 0, NULL },
321 { "generic-mmc-raw", "CyberDrv", "CW038D", 0, NULL },
322 { "generic-mmc-raw", "CyberDrv", "CW058D", 0, NULL },
323 { "generic-mmc-raw", "Goldstar", "8120B", 0, NULL },
324 { "generic-mmc-raw", "HL-DT-ST", "CD-RW GCE-8160B", 0, NULL },
325 { "generic-mmc-raw", "HL-DT-ST", "CD-RW GCE-8320B", 0, NULL },
326 { "generic-mmc-raw", "HP", "CD-Writer+ 7100", 0, NULL },
327 { "generic-mmc-raw", "HP", "CD-Writer+ 7200", 0, NULL },
328 { "generic-mmc-raw", "HP", "DVD Writer 200j", 0, NULL },
329 { "generic-mmc-raw", "IDE-CD", "R/RW 2x2x24", 0, NULL },
330 { "generic-mmc-raw", "IDE-CD", "R/RW 4x4x24", 0, NULL },
331 { "generic-mmc-raw", "IDE-CD", "R/RW 4x4x32", 0, NULL },
332 { "generic-mmc-raw", "IDE-CD", "R/RW 8x4x32", 0, NULL },
333 { "generic-mmc-raw", "IDE-CD", "ReWritable-2x2x6", 0, NULL },
334 { "generic-mmc-raw", "IOMEGA", "ZIPCD 4x650", 0, NULL },
335 { "generic-mmc-raw", "LITE-ON", "LTR-12101B", 0, NULL },
336 { "generic-mmc-raw", "LITE-ON", "LTR-16101B", 0, NULL },
337 { "generic-mmc-raw", "LITE-ON", "LTR-16102C", 0, NULL },
338 { "generic-mmc-raw", "LITE-ON", "LTR-32123S", 0, NULL },
339 { "generic-mmc-raw", "LITE-ON", "LTR-40125S", 0, NULL },
340 { "generic-mmc-raw", "LITE-ON", "LTR-48125W", 0, NULL },
341 { "generic-mmc-raw", "MEMOREX", "CDRW-2216", 0, NULL },
342 { "generic-mmc-raw", "MEMOREX", "CR-622", 0, NULL },
343 { "generic-mmc-raw", "MEMOREX", "CRW-1662", 0, NULL },
344 { "generic-mmc-raw", "MITSUMI", "2801", 0, NULL },
345 { "generic-mmc-raw", "MITSUMI", "CR-4802", 0, NULL },
346 { "generic-mmc-raw", "MITSUMI", "CR-4804", 0, NULL },
347 { "generic-mmc-raw", "OTI", "-975 SOCRATES", 0, NULL },
348 { "generic-mmc-raw", "PHILIPS", "CDD 3801/31", 0, NULL },
349 { "generic-mmc-raw", "PHILIPS", "CDD3600", 0, NULL },
350 { "generic-mmc-raw", "PHILIPS", "CDD3610", 0, NULL },
351 { "generic-mmc-raw", "PHILIPS", "CDD4201", OPT_MMC_NO_SUBCHAN, NULL },
352 { "generic-mmc-raw", "PHILIPS", "CDD4801", 0, NULL },
353 { "generic-mmc-raw", "PHILIPS", "CDRW400", 0, NULL },
354 { "generic-mmc-raw", "PHILIPS", "PCRW1208", 0, NULL },
355 { "generic-mmc-raw", "PHILIPS", "PCRW120899", 0, NULL },
356 { "generic-mmc-raw", "PHILIPS", "PCRW404", 0, NULL },
357 { "generic-mmc-raw", "PHILIPS", "PCRW804", 0, NULL },
358 { "generic-mmc-raw", "QPS", "CRD-BP 1500P", 0, NULL },
359 { "generic-mmc-raw", "SAMSUNG", "CD-R/RW SW-204B", 0, NULL },
360 { "generic-mmc-raw", "SAMSUNG", "CD-R/RW SW-208", 0, NULL },
361 { "generic-mmc-raw", "SAMSUNG", "CD-R/RW SW-212B", 0, NULL },
362 { "generic-mmc-raw", "SAMSUNG", "CD-R/RW SW-224", 0, NULL },
363 { "generic-mmc-raw", "SAMSUNG", "SW-232", 0, NULL },
364 { "generic-mmc-raw", "SONY", "CRX195E1", 0, NULL },
365 { "generic-mmc-raw", "TEAC", "CD-W58E", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL },
366 { "generic-mmc-raw", "TOSHIBA", "R/RW 4x4x24", 0, NULL },
367 { "generic-mmc-raw", "TRAXDATA", "2832", 0, NULL },
368 { "generic-mmc-raw", "TRAXDATA", "CDRW2260+", 0, NULL },
369 { "generic-mmc-raw", "TRAXDATA", "CRW2260 PRO", 0, NULL },
370 { "generic-mmc-raw", "WAITEC", "WT2444EI", 0, NULL },
371 { "generic-mmc-raw", "WAITEC", "WT4424", 0, NULL },
372 { "generic-mmc-raw", "_NEC", "7900", 0, NULL },
373 { "generic-mmc-raw", "_NEC", "NR-7800A", 0, NULL },
374 { "ricoh-mp6200", "AOPEN", "CRW620", 0, NULL },
375 { "ricoh-mp6200", "MEMOREX", "CRW620", 0, NULL },
376 { "ricoh-mp6200", "PHILIPS", "OMNIWRITER26", 0, NULL },
377 { "ricoh-mp6200", "RICOH", "MP6200", 0, NULL },
378 { "ricoh-mp6200", "RICOH", "MP6201", 0, NULL },
379 { "sony-cdu920", "SONY", "CD-R CDU920", 0, NULL },
380 { "sony-cdu920", "SONY", "CD-R CDU924", 0, NULL },
381 { "sony-cdu948", "SONY", "CD-R CDU948", 0, NULL },
382 { "taiyo-yuden", "T.YUDEN", "CD-WO EW-50", 0, NULL },
383 { "teac-cdr55", "JVC", "R2626", 0, NULL },
384 { "teac-cdr55", "JVC", "XR-W2010", 0, NULL },
385 { "teac-cdr55", "SAF", "CD-R2006PLUS", 0, NULL },
386 { "teac-cdr55", "SAF", "CD-R4012", 0, NULL },
387 { "teac-cdr55", "SAF", "CD-RW 226", 0, NULL },
388 { "teac-cdr55", "TEAC", "CD-R50", 0, NULL },
389 { "teac-cdr55", "TEAC", "CD-R55", 0, NULL },
390 { "teac-cdr55", "TRAXDATA", "CDR4120", 0, NULL },
391 { "toshiba", "TOSHIBA", "DVD-ROM SD-R2002", 0, NULL },
392 { "toshiba", "TOSHIBA", "DVD-ROM SD-R2102", 0, NULL },
393 { "yamaha-cdr10x", "YAMAHA", "CDR100", 0, NULL },
394 { "yamaha-cdr10x", "YAMAHA", "CDR102", 0, NULL },
395 { NULL, NULL, NULL, 0, NULL }};
396
397 static DriverTable DRIVERS[] = {
398 { "cdd2600", &CDD2600::instance },
399 { "generic-mmc", &GenericMMC::instance },
400 { "generic-mmc-raw", &GenericMMCraw::instance },
401 { "plextor", &PlextorReader::instance },
402 { "plextor-scan", &PlextorReaderScan::instance },
403 { "ricoh-mp6200", &RicohMP6200::instance },
404 { "sony-cdu920", &SonyCDU920::instance },
405 { "sony-cdu948", &SonyCDU948::instance },
406 { "taiyo-yuden", &TaiyoYuden::instance },
407 { "teac-cdr55", &TeacCdr55::instance },
408 { "toshiba", &ToshibaReader::instance },
409 { "yamaha-cdr10x", &YamahaCDR10x::instance },
410 { NULL, NULL }};
411
412 struct CDRVendorTable {
413 char m1, s1, f1; // 1st vendor code
414 char m2, s2, f2; // 2nd vendor code
415 const char *id; // vendor ID
416 };
417
418 static CDRVendorTable VENDOR_TABLE[] = {
419 // permanent codes
420 { 97,28,30, 97,46,50, "Auvistar Industry Co.,Ltd." },
421 { 97,26,60, 97,46,60, "CMC Magnetics Corporation" },
422 { 97,23,10, 0,0,0, "Doremi Media Co., Ltd." },
423 { 97,26,00, 97,45,00, "FORNET INTERNATIONAL PTE LTD." },
424 { 97,46,40, 97,46,40, "FUJI Photo Film Co., Ltd." },
425 { 97,26,40, 0,0,0, "FUJI Photo Film Co., Ltd." },
426 { 97,28,10, 97,49,10, "GIGASTORAGE CORPORATION" },
427 { 97,25,20, 97,47,10, "Hitachi Maxell, Ltd." },
428 { 97,27,40, 97,48,10, "Kodak Japan Limited" },
429 { 97,26,50, 97,48,60, "Lead Data Inc." },
430 { 97,27,50, 97,48,50, "Mitsui Chemicals, Inc." },
431 { 97,34,20, 97,50,20, "Mitsubishi Chemical Corporation" },
432 { 97,28,20, 97,46,20, "Multi Media Masters & Machinary SA" },
433 { 97,21,40, 0,0,0, "Optical Disc Manufacturing Equipment" },
434 { 97,27,30, 97,48,30, "Pioneer Video Corporation" },
435 { 97,27,10, 97,48,20, "Plasmon Data systems Ltd." },
436 { 97,26,10, 97,47,40, "POSTECH Corporation" },
437 { 97,27,20, 97,47,20, "Princo Corporation" },
438 { 97,32,10, 0,0,0, "Prodisc Technology Inc." },
439 { 97,27,60, 97,48,00, "Ricoh Company Limited" },
440 { 97,31,00, 97,47,50, "Ritek Co." },
441 { 97,26,20, 0,0,0, "SKC Co., Ltd." },
442 { 97,24,10, 0,0,0, "SONY Corporation" },
443 { 97,24,00, 97,46,00, "Taiyo Yuden Company Limited" },
444 { 97,32,00, 97,49,00, "TDK Corporation" },
445 { 97,25,60, 97,45,60, "Xcitek Inc." },
446
447 // tentative codes
448 { 97,22,60, 97,45,20, "Acer Media Technology, Inc" },
449 { 97,25,50, 0,0,0, "AMS Technology Inc." },
450 { 97,23,30, 0,0,0, "AUDIO DISTRIBUTORS CO., LTD." },
451 { 97,21,30, 0,0,0, "Bestdisc Technology Corporation" },
452 { 97,30,10, 97,50,30, "CDA Datentraeger Albrechts GmbH" },
453 { 97,22,40, 97,45,40, "CIS Technology Inc." },
454 { 97,24,20, 97,46,30, "Computer Support Italy s.r.l." },
455 { 97,23,60, 0,0,0, "Customer Pressing Oosterhout" },
456 { 97,28,50, 0,0,0, "DELPHI TECHNOLOGY INC." },
457 { 97,27,00, 97,48,40, "DIGITAL STORAGE TECHNOLOGY CO.,LTD" },
458 { 97,22,30, 0,0,0, "EXIMPO" },
459 { 97,28,60, 0,0,0, "Friendly CD-Tek Co." },
460 { 97,31,30, 97,51,10, "Grand Advance Technology Ltd." },
461 { 97,29,50, 0,0,0, "General Magnetics Ld" },
462 { 97,24,50, 97,45,50, "Guann Yinn Co.,Ltd." },
463 { 97,29,00, 0,0,0, "Harmonic Hall Optical Disc Ltd." },
464 { 97,29,30, 97,51,50, "Hile Optical Disc Technology Corp." },
465 { 97,46,10, 97,22,50, "Hong Kong Digital Technology Co., Ltd." },
466 { 97,25,30, 97,51,20, "INFODISC Technology Co., Ltd." },
467 { 97,24,40, 0,0,0, "kdg mediatech AG" },
468 { 97,28,40, 97,49,20, "King Pro Mediatek Inc." },
469 { 97,23,00, 97,49,60, "Matsushita Electric Industrial Co., Ltd." },
470 { 97,15,20, 0,0,0, "Mitsubishi Chemical Corporation" },
471 { 97,25,00, 0,0,0, "MPO" },
472 { 97,23,20, 0,0,0, "Nacar Media sr" },
473 { 97,26,30, 0,0,0, "OPTICAL DISC CORPRATION" },
474 { 97,28,00, 97,49,30, "Opti.Me.S. S.p.A." },
475 { 97,23,50, 0,0,0, "OPTROM.INC." },
476 { 97,47,60, 0,0,0, "Prodisc Technology Inc." },
477 { 97,15,10, 0,0,0, "Ritek Co." },
478 { 97,22,10, 0,0,0, "Seantram Technology Inc." },
479 { 97,21,50, 0,0,0, "Sound Sound Multi-Media Development Limited" },
480 { 97,29,00, 0,0,0, "Taeil Media Co.,Ltd." },
481 { 97,18,60, 0,0,0, "TAROKO INTERNATIONAL CO.,LTD." },
482 { 97,15,00, 0,0,0, "TDK Corporation." },
483 { 97,29,20, 0,0,0, "UNIDISC TECHNOLOGY CO.,LTD" },
484 { 97,24,30, 97,45,10, "UNITECH JAPAN INC." },
485 { 97,29,10, 97,50,10, "Vanguard Disc Inc." },
486 { 97,49,40, 97,23,40, "VICTOR COMPANY OF JAPAN, LIMITED" },
487 { 97,29,40, 0,0,0, "VIVA MAGNETICS LIMITED" },
488 { 97,25,40, 0,0,0, "VIVASTAR AG" },
489 { 97,18,10, 0,0,0, "WEALTH FAIR INVESTMENT LIMITED" },
490 { 97,22,00, 0,0,0, "Woongjin Media corp." },
491
492 { 0, 0, 0, 0, 0, 0, NULL}
493 };
494
495 unsigned char CdrDriver::syncPattern[12] = {
496 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0
497 };
498
499 unsigned char CdrDriver::REMOTE_MSG_SYNC_[4] = { 0xff, 0x00, 0xff, 0x00 };
500
501
502 /* Maps a string to the corresponding driver option value
503 * Return: 0: string is not a valid driver option sting
504 * else: option value for string
505 */
string2DriverOption(const char * s)506 static unsigned long string2DriverOption(const char *s)
507 {
508 if (strcmp(s, "OPT_DRV_GET_TOC_GENERIC") == 0)
509 return OPT_DRV_GET_TOC_GENERIC;
510 else if (strcmp(s, "OPT_DRV_SWAP_READ_SAMPLES") == 0)
511 return OPT_DRV_SWAP_READ_SAMPLES;
512 else if (strcmp(s, "OPT_DRV_NO_PREGAP_READ") == 0)
513 return OPT_DRV_NO_PREGAP_READ;
514 else if (strcmp(s, "OPT_DRV_RAW_TOC_BCD") == 0)
515 return OPT_DRV_RAW_TOC_BCD;
516 else if (strcmp(s, "OPT_DRV_RAW_TOC_HEX") == 0)
517 return OPT_DRV_RAW_TOC_HEX;
518 else if (strcmp(s, "OPT_MMC_USE_PQ") == 0)
519 return OPT_MMC_USE_PQ;
520 else if (strcmp(s, "OPT_MMC_PQ_BCD") == 0)
521 return OPT_MMC_PQ_BCD;
522 else if (strcmp(s, "OPT_MMC_READ_ISRC") == 0)
523 return OPT_MMC_READ_ISRC;
524 else if (strcmp(s, "OPT_MMC_SCAN_MCN") == 0)
525 return OPT_MMC_SCAN_MCN;
526 else if (strcmp(s, "OPT_MMC_CD_TEXT") == 0)
527 return OPT_MMC_CD_TEXT;
528 else if (strcmp(s, "OPT_MMC_NO_SUBCHAN") == 0)
529 return OPT_MMC_NO_SUBCHAN;
530 else if (strcmp(s, "OPT_MMC_NO_BURNPROOF") == 0)
531 return OPT_MMC_NO_BURNPROOF;
532 else if (strcmp(s, "OPT_MMC_NO_RW_PACKED") == 0)
533 return OPT_MMC_NO_RW_PACKED;
534 else if (strcmp(s, "OPT_MMC_USE_RAW_RW") == 0)
535 return OPT_MMC_USE_RAW_RW;
536 else if (strcmp(s, "OPT_MMC_YAMAHA_FORCE_SPEED") == 0)
537 return OPT_MMC_YAMAHA_FORCE_SPEED;
538 else if (strcmp(s, "OPT_PLEX_USE_PARANOIA") == 0)
539 return OPT_PLEX_USE_PARANOIA;
540 else if (strcmp(s, "OPT_PLEX_DAE_READ10") == 0)
541 return OPT_PLEX_DAE_READ10;
542 else if (strcmp(s, "OPT_PLEX_DAE_D4_12") == 0)
543 return OPT_PLEX_DAE_D4_12;
544 else if (strcmp(s, "OPT_PLEX_USE_PQ") == 0)
545 return OPT_PLEX_USE_PQ;
546 else if (strcmp(s, "OPT_PLEX_PQ_BCD") == 0)
547 return OPT_PLEX_PQ_BCD;
548 else if (strcmp(s, "OPT_PLEX_READ_ISRC") == 0)
549 return OPT_PLEX_READ_ISRC;
550 else
551 return 0;
552 }
553
554
555 /* Checks if 'n' is a valid driver name and returns the driver id string
556 * from the 'DRIVERS' on success.
557 * Return: driver id string
558 * NULL: if 'n' is not a valid driver id
559 */
checkDriverName(const char * n)560 static const char *checkDriverName(const char *n)
561 {
562 DriverTable *run = DRIVERS;
563
564 while (run->driverId != NULL) {
565 if (strcmp(run->driverId, n) == 0)
566 return run->driverId;
567
568 run++;
569 }
570
571 return NULL;
572 }
573
574 /* Reads driver table from specified file.
575 Return: 0: OK, driver table file could be opened
576 1: could not open driver table file
577 */
578
579 #define MAX_DRIVER_TABLE_LINE_LEN 1024
580
readDriverTable(const char * filename)581 static int readDriverTable(const char *filename)
582 {
583 FILE *fp;
584 DriverSelectTable *ent;
585 long i;
586 int lineNr = 0;
587 int count = 0;
588 int rw;
589 int err;
590 char buf[MAX_DRIVER_TABLE_LINE_LEN];
591 char *p, *l;
592 const char *sep = "|";
593 char *vendor;
594 char *model;
595 char *driver;
596 const char *lastDriverName = NULL;
597 const char *driverName;
598 unsigned long opt, options;
599
600 if ((fp = fopen(filename, "r")) == NULL)
601 return 1;
602
603 log_message(4, "Reading driver table from file \"%s\".", filename);
604
605 while (fgets(buf, MAX_DRIVER_TABLE_LINE_LEN, fp) != NULL) {
606 lineNr++;
607
608 vendor = model = driver = NULL;
609 rw = 0;
610 options = 0;
611 err = 0;
612
613 // remove comment
614 if ((p = strchr(buf, '#')) != NULL)
615 *p = 0;
616
617 // remove leading white space
618 for (l = buf; *l != 0 && isspace(*l); l++) ;
619
620 // remove trailing white space
621 for (i = strlen(l) - 1; i >= 0 && isspace(l[i]); i--)
622 l[i] = 0;
623
624
625 if ((p = strtok(l, sep)) != NULL) {
626 if (strcmp(p, "R") == 0) {
627 rw = 1;
628 }
629 else if (strcmp(p, "W") == 0) {
630 rw = 2;
631 }
632 else {
633 log_message(-1,
634 "%s:%d: Expecting 'R' or 'W' as first token - line ignored.",
635 filename, lineNr);
636 }
637
638 if (rw > 0) {
639 if ((p = strtok(NULL, sep)) != NULL) {
640 vendor = strdupCC(p);
641
642 if ((p = strtok(NULL, sep)) != NULL) {
643 model = strdupCC(p);
644
645 if ((p = strtok(NULL, sep)) != NULL) {
646 driver = strdupCC(p);
647
648 if (lastDriverName == NULL ||
649 strcmp(lastDriverName, driver) != 0) {
650 if ((driverName = checkDriverName(driver)) == NULL) {
651 log_message(-1, "%s:%d: Driver '%s' not defined - line ignored.",
652 filename, lineNr, driver);
653 err = 1;
654 }
655 else {
656 lastDriverName = driverName;
657 }
658 }
659
660 while (!err && (p = strtok(NULL, sep)) != NULL) {
661 if ((opt = string2DriverOption(p)) == 0) {
662 log_message(-1, "%s:%d: Driver option string '%s' not defined - line ignored.",
663 filename, lineNr, p);
664 err = 1;
665 }
666
667 options |= opt;
668 }
669
670 if (!err) {
671 ent = new DriverSelectTable;
672
673 ent->vendor = vendor;
674 vendor = NULL;
675 ent->model = model;
676 model = NULL;
677 ent->driverId = driver;
678 driver = NULL;
679 ent->options = options;
680
681 if (rw == 1) {
682 ent->next = READ_DRIVER_TABLE;
683 READ_DRIVER_TABLE = ent;
684 }
685 else {
686 ent->next = WRITE_DRIVER_TABLE;
687 WRITE_DRIVER_TABLE = ent;
688 }
689
690 count++;
691 }
692 }
693 else {
694 log_message(-1, "%s:%d: Missing driver name - line ignored.",
695 filename, lineNr);
696 }
697 }
698 else {
699 log_message(-1, "%s:%d: Missing model name - line ignored.",
700 filename, lineNr);
701 }
702 }
703 else {
704 log_message(-1, "%s:%d: Missing vendor name - line ignored.",
705 filename, lineNr);
706 }
707
708 delete[] vendor;
709 delete[] model;
710 delete[] driver;
711 }
712 }
713 }
714
715 fclose(fp);
716
717 log_message(4, "Found %d valid driver table entries.", count);
718
719 return 0;
720 }
721
722 /* Create driver tables from built-in driver table data.
723 */
createDriverTable()724 static void createDriverTable()
725 {
726 DriverSelectTable *run;
727 DriverSelectTable *ent;
728
729 for (run = BUILTIN_READ_DRIVER_TABLE; run->driverId != NULL; run++) {
730 ent = new DriverSelectTable;
731
732 ent->driverId = strdupCC(run->driverId);
733 ent->vendor = strdupCC(run->vendor);
734 ent->model = strdupCC(run->model);
735 ent->options = run->options;
736
737 ent->next = READ_DRIVER_TABLE;
738 READ_DRIVER_TABLE = ent;
739 }
740
741 for (run = BUILTIN_WRITE_DRIVER_TABLE; run->driverId != NULL; run++) {
742 ent = new DriverSelectTable;
743
744 ent->driverId = strdupCC(run->driverId);
745 ent->vendor = strdupCC(run->vendor);
746 ent->model = strdupCC(run->model);
747 ent->options = run->options;
748
749 ent->next = WRITE_DRIVER_TABLE;
750 WRITE_DRIVER_TABLE = ent;
751 }
752 }
753
754 /* Initialize driver table. First try to read the driver table from file
755 * 'DRIVER_TABLE_FILE'. If it does not exist the built-in driver table data
756 * will be used. After that an user specific driver table file is loaded if
757 * available.
758 */
initDriverTable()759 static void initDriverTable()
760 {
761 static int initialized = 0;
762 const char *home;
763 char *path;
764
765 if (initialized)
766 return;
767
768 if (readDriverTable(DRIVER_TABLE_FILE) != 0) {
769 log_message(2, "Cannot read driver table from file \"%s\" - using built-in table.", DRIVER_TABLE_FILE);
770 createDriverTable();
771 }
772
773 /* read driver table from $HOME/.cdrdao-drivers */
774 if ((home = getenv("HOME")) != NULL) {
775 path = strdup3CC(home, "/.cdrdao-drivers", NULL);
776 readDriverTable(path);
777 delete[] path;
778 }
779
780 initialized = 1;
781 }
782
selectDriver(int readWrite,const char * vendor,const char * model,unsigned long * options)783 const char *CdrDriver::selectDriver(int readWrite, const char *vendor,
784 const char *model, unsigned long *options)
785 {
786 DriverSelectTable *run;
787 DriverSelectTable *match = NULL;
788 unsigned int matchLen = 0;
789 unsigned int len = 0;
790
791 initDriverTable();
792
793 run = (readWrite == 0) ? READ_DRIVER_TABLE : WRITE_DRIVER_TABLE;
794
795 while (run != NULL) {
796 if (strcmp(run->vendor, vendor) == 0 &&
797 strstr(model, run->model) != NULL) {
798 if (match == NULL || (len = strlen(run->model)) > matchLen) {
799 matchLen = (match == NULL) ? strlen(run->model) : len;
800 match = run;
801 }
802 }
803
804 run = run->next;
805 }
806
807 if (match != NULL) {
808 *options = match->options;
809 return match->driverId;
810 }
811
812 return NULL;
813 }
814
815
createDriver(const char * driverId,unsigned long options,ScsiIf * scsiIf)816 CdrDriver *CdrDriver::createDriver(const char *driverId, unsigned long options,
817 ScsiIf *scsiIf)
818 {
819 DriverTable *run = DRIVERS;
820
821 while (run->driverId != NULL) {
822 if (strcmp(run->driverId, driverId) == 0)
823 return run->constructor(scsiIf, options);
824
825 run++;
826 }
827
828 return NULL;
829 }
830
detectDriver(ScsiIf * scsiIf,unsigned long * options)831 const char *CdrDriver::detectDriver(ScsiIf *scsiIf, unsigned long *options)
832 {
833 bool cd_r_read, cd_r_write, cd_rw_read, cd_rw_write;
834 if (scsiIf->checkMmc(&cd_r_read, &cd_r_write, &cd_rw_read, &cd_rw_write)) {
835 return "generic-mmc";
836 }
837
838 return NULL;
839 }
840
printDriverIds()841 void CdrDriver::printDriverIds()
842 {
843 DriverTable *run = DRIVERS;
844
845 while (run->driverId != NULL) {
846 log_message(0, "%s", run->driverId);
847 run++;
848 }
849 }
850
CdrDriver(ScsiIf * scsiIf,unsigned long options)851 CdrDriver::CdrDriver(ScsiIf *scsiIf, unsigned long options)
852 {
853 size16 byteOrderTest = 1;
854 char *byteOrderTestP = (char*)&byteOrderTest;
855
856 options_ = options;
857 scsiIf_ = scsiIf;
858 toc_ = NULL;
859
860 if (*byteOrderTestP == 1)
861 hostByteOrder_ = 0; // little endian
862 else
863 hostByteOrder_ = 1; // big endian
864
865
866 enableBufferUnderRunProtection_ = 1;
867 enableWriteSpeedControl_ = 1;
868
869 readCapabilities_ = 0; // reading capabilities are determined dynamically
870
871 audioDataByteOrder_ = 0; // default to little endian
872
873 fastTocReading_ = false;
874 rawDataReading_ = false;
875 mode2Mixed_ = true;
876 subChanReadMode_ = TrackData::SUBCHAN_NONE;
877 taoSource_ = 0;
878 taoSourceAdjust_ = 2; // usually we have 2 unreadable sectors between tracks
879 // written in TAO mode
880 padFirstPregap_ = 1;
881 onTheFly_ = 0;
882 onTheFlyFd_ = -1;
883 multiSession_ = false;
884 encodingMode_ = 0;
885 force_ = false;
886 remote_ = 0;
887 remoteFd_ = -1;
888
889 blockLength_ = 0;
890 blocksPerWrite_ = 0;
891 zeroBuffer_ = NULL;
892
893 userCapacity_ = 0;
894 fullBurn_ = false;
895
896 scsiMaxDataLen_ = scsiIf_->maxDataLen();
897
898 transferBuffer_ = new unsigned char[scsiMaxDataLen_];
899
900 maxScannedSubChannels_ = scsiMaxDataLen_ / (AUDIO_BLOCK_LEN + PW_SUBCHANNEL_LEN);
901 scannedSubChannels_ = new SubChannel*[maxScannedSubChannels_];
902
903 paranoia_ = NULL;
904 paranoiaDrive_ = NULL;
905 paranoiaMode(3); // full paranoia but allow skip
906 }
907
~CdrDriver()908 CdrDriver::~CdrDriver()
909 {
910 toc_ = NULL;
911
912 delete[] zeroBuffer_;
913 zeroBuffer_ = NULL;
914
915 delete[] transferBuffer_;
916 transferBuffer_ = NULL;
917
918 delete [] scannedSubChannels_;
919 scannedSubChannels_ = NULL;
920 }
921
922 // Sets multi session mode. 0: close session, 1: open next session
923 // Return: 0: OK
924 // 1: multi session not supported by driver
multiSession(bool m)925 int CdrDriver::multiSession(bool m)
926 {
927 multiSession_ = m;
928
929 return 0;
930 }
931
932 // Sets number of adjust sectors for reading TAO source disks.
taoSourceAdjust(int val)933 void CdrDriver::taoSourceAdjust(int val)
934 {
935 if (val >= 0 && val < 100) {
936 taoSourceAdjust_ = val;
937 }
938 }
939
940
onTheFly(int fd)941 void CdrDriver::onTheFly(int fd)
942 {
943 if (fd >= 0) {
944 onTheFly_ = 1;
945 onTheFlyFd_ = fd;
946 }
947 else {
948 onTheFly_ = 0;
949 onTheFlyFd_ = -1;
950 }
951 }
952
remote(int f,int fd)953 void CdrDriver::remote(int f, int fd)
954 {
955 if (f != 0 && fd >= 0) {
956 int flags;
957
958 remote_ = 1;
959 remoteFd_ = fd;
960
961 // switch 'fd' to non blocking IO mode
962 if ((flags = fcntl(fd, F_GETFL)) == -1) {
963 log_message(-1, "Cannot get flags of remote stream: %s", strerror(errno));
964 remote_ = 0;
965 remoteFd_ = -1;
966 return;
967 }
968
969 flags |= O_NONBLOCK;
970
971 if (fcntl(fd, F_SETFL, flags) < 0) {
972 log_message(-1, "Cannot set flags of remote stream: %s", strerror(errno));
973 remote_ = 0;
974 remoteFd_ = -1;
975 }
976 }
977 else {
978 remote_ = 0;
979 remoteFd_ = -1;
980 }
981 }
982
983 // Returns acceptable sub-channel encoding mode for given sub-channel type:
984 // -1: writing of sub-channel type not supported at all
985 // 0: accepts plain data without encoding
986 // 1: accepts only completely encoded data
subChannelEncodingMode(TrackData::SubChannelMode sm) const987 int CdrDriver::subChannelEncodingMode(TrackData::SubChannelMode sm) const
988 {
989 if (sm == TrackData::SUBCHAN_NONE)
990 return 0;
991 else
992 return -1;
993 }
994
995
cdrVendor(Msf & code,const char ** vendorId,const char ** mediumType)996 int CdrDriver::cdrVendor(Msf &code, const char **vendorId,
997 const char **mediumType)
998 {
999 CDRVendorTable *run = VENDOR_TABLE;
1000
1001 *vendorId = NULL;
1002
1003 char m = code.min();
1004 char s = code.sec();
1005 char f = code.frac();
1006
1007 char type = f % 10;
1008 f -= type;
1009
1010 while (run->id != NULL) {
1011 if ((run->m1 == m && run->s1 == s && run->f1 == f) ||
1012 (run->m2 == m && run->s2 == s && run->f2 == f)) {
1013 *vendorId = run->id;
1014 break;
1015 }
1016 run++;
1017 }
1018
1019 if (*vendorId != NULL) {
1020 if (type < 5) {
1021 *mediumType = "Long Strategy Type, e.g. Cyanine";
1022 }
1023 else {
1024 *mediumType = "Short Strategy Type, e.g. Phthalocyanine";
1025 }
1026
1027 return 1;
1028 }
1029
1030 return 0;
1031 }
1032
1033 // Sends SCSI command via 'scsiIf_'.
1034 // return: see 'ScsiIf::sendCmd()'
sendCmd(const unsigned char * cmd,int cmdLen,const unsigned char * dataOut,int dataOutLen,unsigned char * dataIn,int dataInLen,int showErrorMsg) const1035 int CdrDriver::sendCmd(const unsigned char *cmd, int cmdLen,
1036 const unsigned char *dataOut, int dataOutLen,
1037 unsigned char *dataIn, int dataInLen,
1038 int showErrorMsg) const
1039 {
1040 return scsiIf_->sendCmd(cmd, cmdLen, dataOut, dataOutLen, dataIn,
1041 dataInLen, showErrorMsg);
1042 }
1043
1044 // checks if unit is ready
1045 // return: 0: OK
1046 // 1: scsi command failed
1047 // 2: not ready
1048 // 3: not ready, no disk in drive
1049 // 4: not ready, tray out
1050
testUnitReady(int ignoreUnitAttention) const1051 int CdrDriver::testUnitReady(int ignoreUnitAttention) const
1052 {
1053 unsigned char cmd[6];
1054 const unsigned char *sense;
1055 int senseLen;
1056
1057 memset(cmd, 0, 6);
1058
1059 switch (scsiIf_->sendCmd(cmd, 6, NULL, 0, NULL, 0, 0)) {
1060 case 1:
1061 return 1;
1062
1063 case 2:
1064 sense = scsiIf_->getSense(senseLen);
1065
1066 int code = sense[2] & 0x0f;
1067
1068 if (code == 0x02) {
1069 // not ready
1070 return 2;
1071 }
1072 else if (code != 0x06) {
1073 scsiIf_->printError();
1074 return 1;
1075 }
1076 else {
1077 return 0;
1078 }
1079 }
1080
1081 return 0;
1082 }
1083
rspeed(int a)1084 bool CdrDriver::rspeed(int a) {
1085 rspeed_ = a;
1086 return true;
1087 }
1088
speed2Mult(int speed)1089 int CdrDriver::speed2Mult(int speed)
1090 {
1091 return speed / 176;
1092 }
1093
mult2Speed(int mult)1094 int CdrDriver::mult2Speed(int mult)
1095 {
1096 return mult * 177;
1097 }
1098
1099 // start unit ('startStop' == 1) or stop unit ('startStop' == 0)
1100 // return: 0: OK
1101 // 1: scsi command failed
1102
startStopUnit(int startStop) const1103 int CdrDriver::startStopUnit(int startStop) const
1104 {
1105 unsigned char cmd[6];
1106
1107 memset(cmd, 0, 6);
1108
1109 cmd[0] = 0x1b;
1110
1111 if (startStop != 0) {
1112 cmd[4] |= 0x01;
1113 }
1114
1115 if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) {
1116 log_message(-2, "Cannot start/stop unit.");
1117 return 1;
1118 }
1119
1120 return 0;
1121 }
1122
1123
1124 // blocks or unblocks tray
1125 // return: 0: OK
1126 // 1: scsi command failed
1127
preventMediumRemoval(int block) const1128 int CdrDriver::preventMediumRemoval(int block) const
1129 {
1130 unsigned char cmd[6];
1131
1132 memset(cmd, 0, 6);
1133
1134 cmd[0] = 0x1e;
1135
1136 if (block != 0) {
1137 cmd[4] |= 0x01;
1138 }
1139
1140 if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) {
1141 log_message(-2, "Cannot prevent/allow medium removal.");
1142 return 1;
1143 }
1144
1145 return 0;
1146 }
1147
1148 // reset device to initial state
1149 // return: 0: OK
1150 // 1: scsi command failed
1151
rezeroUnit(int showMessage) const1152 int CdrDriver::rezeroUnit(int showMessage) const
1153 {
1154 unsigned char cmd[6];
1155
1156 memset(cmd, 0, 6);
1157
1158 cmd[0] = 0x01;
1159
1160 if (sendCmd(cmd, 6, NULL, 0, NULL, 0, showMessage) != 0) {
1161 if (showMessage)
1162 log_message(-2, "Cannot rezero unit.");
1163 return 1;
1164 }
1165
1166 return 0;
1167 }
1168
1169 // Flushs cache of drive which inidcates end of write action. Errors resulting
1170 // from this command are ignored because everything is already done and
1171 // at most the last part of the lead-out track may be affected.
1172 // return: 0: OK
flushCache() const1173 int CdrDriver::flushCache() const
1174 {
1175 unsigned char cmd[10];
1176
1177 memset(cmd, 0, 10);
1178
1179 cmd[0] = 0x35; // FLUSH CACHE
1180
1181 // Print no message if the flush cache command fails because some drives
1182 // report errors even if all went OK.
1183 sendCmd(cmd, 10, NULL, 0, NULL, 0, 0);
1184
1185 return 0;
1186 }
1187
1188 // Reads the cd-rom capacity and stores the total number of available blocks
1189 // in 'length'.
1190 // return: 0: OK
1191 // 1: SCSI command failed
readCapacity(long * length,int showMessage)1192 int CdrDriver::readCapacity(long *length, int showMessage)
1193 {
1194 unsigned char cmd[10];
1195 unsigned char data[8];
1196
1197 memset(cmd, 0, 10);
1198 memset(data, 0, 8);
1199
1200 cmd[0] = 0x25; // READ CD-ROM CAPACITY
1201
1202 if (sendCmd(cmd, 10, NULL, 0, data, 8, showMessage) != 0) {
1203 if (showMessage)
1204 log_message(-2, "Cannot read capacity.");
1205 return 1;
1206 }
1207
1208 *length = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
1209 // *length += 1;
1210
1211 return 0;
1212 }
1213
blankDisk(BlankingMode)1214 int CdrDriver::blankDisk(BlankingMode)
1215 {
1216 log_message(-2, "Blanking is not supported by this driver.");
1217 return 1;
1218 }
1219
1220 // Writes data to target, the block length depends on the actual writing mode
1221 // 'mode'. 'len' is number of blocks to write.
1222 // 'lba' specifies the next logical block address for writing and is updated
1223 // by this function.
1224 // return: 0: OK
1225 // 1: scsi command failed
writeData(TrackData::Mode mode,TrackData::SubChannelMode sm,long & lba,const char * buf,long len)1226 int CdrDriver::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm,
1227 long &lba, const char *buf, long len)
1228 {
1229 assert(blocksPerWrite_ > 0);
1230 int writeLen = 0;
1231 unsigned char cmd[10];
1232 long blockLength = blockSize(mode, sm);
1233
1234 #if 0
1235 long sum, i;
1236
1237 sum = 0;
1238
1239 for (i = 0; i < len * blockLength; i++) {
1240 sum += buf[i];
1241 }
1242
1243 log_message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum);
1244
1245 #endif
1246
1247
1248 memset(cmd, 0, 10);
1249 cmd[0] = 0x2a; // WRITE1
1250
1251 while (len > 0) {
1252 writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len);
1253
1254 cmd[2] = lba >> 24;
1255 cmd[3] = lba >> 16;
1256 cmd[4] = lba >> 8;
1257 cmd[5] = lba;
1258
1259 cmd[7] = writeLen >> 8;
1260 cmd[8] = writeLen & 0xff;
1261
1262 if (sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength,
1263 NULL, 0) != 0) {
1264 log_message(-2, "Write data failed.");
1265 return 1;
1266 }
1267
1268 buf += writeLen * blockLength;
1269
1270 lba += writeLen;
1271 len -= writeLen;
1272 }
1273
1274 return 0;
1275 }
1276
1277 // Writes 'count' blocks with zero data with 'writeData'.
1278 // m: mode for encoding zero data
1279 // lba: logical block address for the write command, will be updated
1280 // encLba: logical block address used by the LE-C encoder for the
1281 // sector headers
1282 // count: number of zero blocks to write
1283 // Return: 0: OK
1284 // 1: SCSI error occured
writeZeros(TrackData::Mode m,TrackData::SubChannelMode sm,long & lba,long encLba,long count)1285 int CdrDriver::writeZeros(TrackData::Mode m, TrackData::SubChannelMode sm,
1286 long &lba, long encLba, long count)
1287 {
1288 assert(blocksPerWrite_ > 0);
1289 assert(zeroBuffer_ != NULL);
1290
1291 int n, i;
1292 long cnt = 0;
1293 long total;
1294 long cntMb;
1295 long lastMb = 0;
1296 long blockLen;
1297 unsigned char *buf;
1298
1299 blockLen = blockSize(m, sm);
1300
1301 total = count * blockLen;
1302
1303 #if 0
1304 static int wcount = 0;
1305 char fname[100];
1306 sprintf(fname, "zeros%d.out", wcount++);
1307 FILE *fp = fopen(fname, "w");
1308 #endif
1309
1310 while (count > 0) {
1311 n = (count > blocksPerWrite_ ? blocksPerWrite_ : count);
1312
1313 buf = (unsigned char *)zeroBuffer_;
1314
1315 for (i = 0; i < n; i++) {
1316 Track::encodeZeroData(encodingMode_, m, sm, encLba++, buf);
1317
1318 if (encodingMode_ == 0 && bigEndianSamples() == 0) {
1319 // swap encoded data blocks
1320 swapSamples((Sample *)buf, SAMPLES_PER_BLOCK);
1321 }
1322
1323 buf += blockLen;
1324 }
1325
1326
1327 //fwrite(zeroBuffer_, blockLen, n, fp);
1328
1329 if (writeData(encodingMode_ == 0 ? TrackData::AUDIO : m, sm, lba,
1330 zeroBuffer_, n) != 0) {
1331 return 1;
1332 }
1333
1334 cnt += n * blockLen;
1335
1336 cntMb = cnt >> 20;
1337
1338 if (cntMb > lastMb) {
1339 log_message(1, "Wrote %ld of %ld MB.\r", cntMb, total >> 20);
1340 fflush(stdout);
1341 lastMb = cntMb;
1342 }
1343
1344 count -= n;
1345 }
1346
1347 //fclose(fp);
1348
1349 return 0;
1350 }
1351
1352 // Requests mode page 'pageCode' from device and places it into given
1353 // buffer of maximum length 'bufLen'.
1354 // modePageHeader: if != NULL filled with mode page header (8 bytes)
1355 // blockDesc : if != NULL filled with block descriptor (8 bytes),
1356 // buffer is zeroed if no block descriptor is received
1357 // return: 0: OK
1358 // 1: scsi command failed
1359 // 2: buffer too small for requested mode page
getModePage(int pageCode,unsigned char * buf,long bufLen,unsigned char * modePageHeader,unsigned char * blockDesc,int showErrorMsg)1360 int CdrDriver::getModePage(int pageCode, unsigned char *buf, long bufLen,
1361 unsigned char *modePageHeader,
1362 unsigned char *blockDesc,
1363 int showErrorMsg)
1364 {
1365 unsigned char cmd[10];
1366 long dataLen = bufLen + 8/*mode parameter header*/ +
1367 100/*spare for block descriptors*/;
1368 unsigned char *data = new unsigned char[dataLen];
1369
1370 memset(cmd, 0, 10);
1371 memset(data, 0, dataLen);
1372 memset(buf, 0, bufLen);
1373
1374 cmd[0] = 0x5a; // MODE SENSE
1375 cmd[2] = pageCode & 0x3f;
1376 cmd[7] = dataLen >> 8;
1377 cmd[8] = dataLen;
1378
1379 if (sendCmd(cmd, 10, NULL, 0, data, dataLen, showErrorMsg) != 0) {
1380 delete[] data;
1381 return 1;
1382 }
1383
1384 long modeDataLen = (data[0] << 8) | data[1];
1385 long blockDescLen = (data[6] << 8) | data[7];
1386
1387 if (modePageHeader != NULL)
1388 memcpy(modePageHeader, data, 8);
1389
1390 if (blockDesc != NULL) {
1391 if (blockDescLen >= 8)
1392 memcpy(blockDesc, data + 8, 8);
1393 else
1394 memset(blockDesc, 0, 8);
1395 }
1396
1397 if (modeDataLen > blockDescLen + 6) {
1398 unsigned char *modePage = data + blockDescLen + 8;
1399 long modePageLen = modePage[1] + 2;
1400
1401 if (modePageLen > bufLen)
1402 modePageLen = bufLen;
1403
1404 memcpy(buf, modePage, modePageLen);
1405 delete[] data;
1406 return 0;
1407 }
1408 else {
1409 log_message(-2, "No mode page data received.");
1410 delete[] data;
1411 return 1;
1412 }
1413 }
1414
1415 // Sets mode page in device specified in buffer 'modePage'
1416 // modePageHeader: if != NULL used as mode page header (8 bytes)
1417 // blockDesc : if != NULL used as block descriptor (8 bytes),
1418 // Return: 0: OK
1419 // 1: SCSI command failed
setModePage(const unsigned char * modePage,const unsigned char * modePageHeader,const unsigned char * blockDesc,int showErrorMsg)1420 int CdrDriver::setModePage(const unsigned char *modePage,
1421 const unsigned char *modePageHeader,
1422 const unsigned char *blockDesc,
1423 int showErrorMsg)
1424 {
1425 long pageLen = modePage[1] + 2;
1426 unsigned char cmd[10];
1427 long dataLen = pageLen + 8/*mode parameter header*/;
1428
1429 if (blockDesc != NULL)
1430 dataLen += 8;
1431
1432 unsigned char *data = new unsigned char[dataLen];
1433
1434 memset(cmd, 0, 10);
1435 memset(data, 0, dataLen);
1436
1437 if (modePageHeader != NULL)
1438 memcpy(data, modePageHeader, 8);
1439
1440 data[0] = 0;
1441 data[1] = 0;
1442 data[4] = 0;
1443 data[5] = 0;
1444
1445
1446 if (blockDesc != NULL) {
1447 memcpy(data + 8, blockDesc, 8);
1448 memcpy(data + 16, modePage, pageLen);
1449 data[6] = 0;
1450 data[7] = 8;
1451 }
1452 else {
1453 memcpy(data + 8, modePage, pageLen);
1454 data[6] = 0;
1455 data[7] = 0;
1456 }
1457
1458 cmd[0] = 0x55; // MODE SELECT
1459 cmd[1] = 1 << 4;
1460
1461 cmd[7] = dataLen >> 8;
1462 cmd[8] = dataLen;
1463
1464 if (sendCmd(cmd, 10, data, dataLen, NULL, 0, showErrorMsg) != 0) {
1465 delete[] data;
1466 return 1;
1467 }
1468
1469 delete[] data;
1470 return 0;
1471 }
1472
1473 // As above, but implemented with six byte mode commands
1474
1475 // Requests mode page 'pageCode' from device and places it into given
1476 // buffer of maximum length 'bufLen'.
1477 // modePageHeader: if != NULL filled with mode page header (4 bytes)
1478 // blockDesc : if != NULL filled with block descriptor (8 bytes),
1479 // buffer is zeroed if no block descriptor is received
1480 // return: 0: OK
1481 // 1: scsi command failed
1482 // 2: buffer too small for requested mode page
getModePage6(int pageCode,unsigned char * buf,long bufLen,unsigned char * modePageHeader,unsigned char * blockDesc,int showErrorMsg)1483 int CdrDriver::getModePage6(int pageCode, unsigned char *buf, long bufLen,
1484 unsigned char *modePageHeader,
1485 unsigned char *blockDesc,
1486 int showErrorMsg)
1487 {
1488 unsigned char cmd[6];
1489 long dataLen = bufLen + 4/*mode parameter header*/ +
1490 100/*spare for block descriptors*/;
1491 unsigned char *data = new unsigned char[dataLen];
1492
1493 memset(cmd, 0, 6);
1494 memset(data, 0, dataLen);
1495 memset(buf, 0, bufLen);
1496
1497 cmd[0] = 0x1a; // MODE SENSE(6)
1498 cmd[2] = pageCode & 0x3f;
1499 cmd[4] = (dataLen > 255) ? 0 : dataLen;
1500
1501 if (sendCmd(cmd, 6, NULL, 0, data, dataLen, showErrorMsg) != 0) {
1502 delete[] data;
1503 return 1;
1504 }
1505
1506 long modeDataLen = data[0];
1507 long blockDescLen = data[3];
1508
1509 if (modePageHeader != NULL)
1510 memcpy(modePageHeader, data, 4);
1511
1512 if (blockDesc != NULL) {
1513 if (blockDescLen >= 8)
1514 memcpy(blockDesc, data + 4, 8);
1515 else
1516 memset(blockDesc, 0, 8);
1517 }
1518
1519 if (modeDataLen > blockDescLen + 4) {
1520 unsigned char *modePage = data + blockDescLen + 4;
1521 long modePageLen = modePage[1] + 2;
1522
1523 if (modePageLen > bufLen)
1524 modePageLen = bufLen;
1525
1526 memcpy(buf, modePage, modePageLen);
1527 delete[] data;
1528 return 0;
1529 }
1530 else {
1531 log_message(-2, "No mode page data received.");
1532 delete[] data;
1533 return 1;
1534 }
1535 }
1536
1537 // Sets mode page in device specified in buffer 'modePage'
1538 // modePageHeader: if != NULL used as mode page header (4 bytes)
1539 // blockDesc : if != NULL used as block descriptor (8 bytes),
1540 // Return: 0: OK
1541 // 1: SCSI command failed
setModePage6(const unsigned char * modePage,const unsigned char * modePageHeader,const unsigned char * blockDesc,int showErrorMsg)1542 int CdrDriver::setModePage6(const unsigned char *modePage,
1543 const unsigned char *modePageHeader,
1544 const unsigned char *blockDesc,
1545 int showErrorMsg)
1546 {
1547 long pageLen = modePage[1] + 2;
1548 unsigned char cmd[6];
1549 long dataLen = pageLen + 4/*mode parameter header*/;
1550
1551 if (blockDesc != NULL)
1552 dataLen += 8;
1553
1554 unsigned char *data = new unsigned char[dataLen];
1555
1556 memset(cmd, 0, 6);
1557 memset(data, 0, dataLen);
1558
1559 if (modePageHeader != NULL)
1560 memcpy(data, modePageHeader, 4);
1561
1562 data[0] = 0;
1563
1564 if (blockDesc != NULL) {
1565 memcpy(data + 4, blockDesc, 8);
1566 memcpy(data + 12, modePage, pageLen);
1567 data[3] = 8;
1568 }
1569 else {
1570 memcpy(data + 4, modePage, pageLen);
1571 data[3] = 0;
1572 }
1573
1574 cmd[0] = 0x15; // MODE SELECT(6)
1575 cmd[1] = 1 << 4;
1576
1577 cmd[4] = dataLen;
1578
1579 if (sendCmd(cmd, 6, data, dataLen, NULL, 0, showErrorMsg) != 0) {
1580 delete[] data;
1581 return 1;
1582 }
1583
1584 delete[] data;
1585 return 0;
1586 }
1587
1588
1589 // Retrieves TOC data of inserted CD. It won't distinguish between different
1590 // sessions.
1591 // The track information is returned either for all sessions or for the
1592 // first session depending on the drive. 'cdTocLen' is filled with number
1593 // of entries including the lead-out track.
1594 // Return: 'NULL' on error, else array of 'CdToc' structures with '*cdTocLen'
1595 // entries
getTocGeneric(int * cdTocLen)1596 CdToc *CdrDriver::getTocGeneric(int *cdTocLen)
1597 {
1598 unsigned char cmd[10];
1599 unsigned short dataLen;
1600 unsigned char *data = NULL;;
1601 unsigned char reqData[4]; // buffer for requestion the actual length
1602 unsigned char *p = NULL;
1603 int i;
1604 CdToc *toc;
1605 int nTracks;
1606
1607 // read disk toc length
1608 memset(cmd, 0, 10);
1609 cmd[0] = 0x43; // READ TOC
1610 cmd[6] = 0; // return info for all tracks
1611 cmd[8] = 4;
1612
1613 if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) {
1614 log_message(-2, "Cannot read disk toc.");
1615 return NULL;
1616 }
1617
1618 dataLen = (reqData[0] << 8) | reqData[1];
1619 dataLen += 2;
1620
1621 log_message(4, "getTocGeneric: data len %d", dataLen);
1622
1623 if (dataLen < 12) {
1624 dataLen = (100 * 8) + 4;
1625 }
1626
1627 data = new unsigned char[dataLen];
1628 memset(data, 0, dataLen);
1629
1630 // read disk toc
1631 cmd[7] = dataLen >> 8;
1632 cmd[8] = dataLen;
1633
1634 if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) {
1635 log_message(-2, "Cannot read disk toc.");
1636 delete[] data;
1637 return NULL;
1638 }
1639
1640 nTracks = data[3] - data[2] + 1;
1641 if (nTracks > 99) {
1642 log_message(-2, "Got illegal toc data.");
1643 delete[] data;
1644 return NULL;
1645 }
1646
1647 toc = new CdToc[nTracks + 1];
1648
1649 for (i = 0, p = data + 4; i <= nTracks; i++, p += 8) {
1650 toc[i].track = p[2];
1651 toc[i].adrCtl = p[1];
1652 toc[i].start = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
1653 }
1654
1655 *cdTocLen = nTracks + 1;
1656
1657 delete[] data;
1658
1659 return toc;
1660 }
1661
1662 // Retrieves TOC data of inserted CD. The track information is returend for
1663 // specified session number only. The lead-out start is taken from the
1664 // correct session so that it can be used to calculate the length of the
1665 // last track.
1666 // 'cdTocLen' is filled with number of entries including the lead-out track.
1667 // Return: 'NULL' on error, else array of 'CdToc' structures with '*cdTocLen'
1668 // entries
1669
1670 #define IS_BCD(v) (((v) & 0xf0) <= 0x90 && ((v) & 0x0f) <= 0x09)
getToc(int sessionNr,int * cdTocLen)1671 CdToc *CdrDriver::getToc(int sessionNr, int *cdTocLen)
1672 {
1673 int rawTocLen;
1674 int completeTocLen;
1675 CdToc *completeToc; // toc retrieved with generic method to verify with raw
1676 // toc data
1677 CdToc *cdToc;
1678 CdRawToc *rawToc;
1679 int i, j, tocEnt;
1680 int nTracks = 0;
1681 int trackNr;
1682 long trackStart;
1683 int isBcd = -1;
1684 int lastTrack;
1685 int min, sec, frame;
1686
1687 if ((completeToc = getTocGeneric(&completeTocLen)) == NULL)
1688 return NULL;
1689
1690 if (options_ & OPT_DRV_GET_TOC_GENERIC) {
1691 *cdTocLen = completeTocLen;
1692 return completeToc;
1693 }
1694
1695 if ((rawToc = getRawToc(1, &rawTocLen)) == NULL) {
1696 *cdTocLen = completeTocLen;
1697 return completeToc;
1698 }
1699
1700 // Try to determine if raw toc data contains BCD or HEX numbers.
1701 for (i = 0; i < rawTocLen; i++) {
1702 if ((rawToc[i].adrCtl & 0xf0) == 0x10) { // only process QMODE1 entries
1703 if (rawToc[i].point < 0xa0 && !IS_BCD(rawToc[i].point)) {
1704 isBcd = 0;
1705 }
1706
1707 if (rawToc[i].point < 0xa0 || rawToc[i].point == 0xa2) {
1708 if (!IS_BCD(rawToc[i].pmin) || !IS_BCD(rawToc[i].psec) ||
1709 !IS_BCD(rawToc[i].pframe)) {
1710 isBcd = 0;
1711 break;
1712 }
1713 }
1714 }
1715 }
1716
1717 if (options_ & OPT_DRV_RAW_TOC_BCD) {
1718 if (isBcd == 0) {
1719 log_message(-2, "The driver option 0x%lx indicates that the raw TOC data",
1720 OPT_DRV_RAW_TOC_BCD);
1721 log_message(-2, "contains BCD values but a non BCD value was found.");
1722 log_message(-2, "Please adjust the driver options.");
1723 log_message(-1, "Using TOC data retrieved with generic method (no multi session support).");
1724
1725 delete[] rawToc;
1726 *cdTocLen = completeTocLen;
1727 return completeToc;
1728 }
1729 isBcd = 1;
1730 }
1731 else if (options_ & OPT_DRV_RAW_TOC_HEX) {
1732 isBcd = 0;
1733 }
1734 else {
1735 if (isBcd == -1) {
1736 // We still don't know if the values are BCD or HEX but we've ensured
1737 // so far that all values are valid BCD numbers.
1738
1739 // Assume that we have BCD numbers and compare with the generic toc data.
1740 isBcd = 1;
1741 for (i = 0; i < rawTocLen && isBcd == 1; i++) {
1742 if ((rawToc[i].adrCtl & 0xf0) == 0x10 && // only process QMODE1 entries
1743 rawToc[i].point < 0xa0) {
1744 trackNr = SubChannel::bcd2int(rawToc[i].point);
1745
1746 for (j = 0; j < completeTocLen; j++) {
1747 if (completeToc[j].track == trackNr) {
1748 break;
1749 }
1750 }
1751
1752 if (j < completeTocLen) {
1753 min = SubChannel::bcd2int(rawToc[i].pmin);
1754 sec = SubChannel::bcd2int(rawToc[i].psec);
1755 frame = SubChannel::bcd2int(rawToc[i].pframe);
1756
1757 if (min <= 99 && sec < 60 && frame < 75) {
1758 trackStart = Msf(min, sec, frame).lba() - 150;
1759 if (completeToc[j].start != trackStart) {
1760 // start does not match -> values are not BCD
1761 isBcd = 0;
1762 }
1763 }
1764 else {
1765 // bogus time code -> values are not BCD
1766 isBcd = 0;
1767 }
1768 }
1769 else {
1770 // track not found -> values are not BCD
1771 isBcd = 0;
1772 }
1773 }
1774 }
1775
1776 if (isBcd == 1) {
1777 // verify last lead-out pointer
1778 trackStart = 0; // start of lead-out
1779 for (i = rawTocLen - 1; i >= 0; i--) {
1780 if ((rawToc[i].adrCtl & 0xf0) == 0x10 && // QMODE1 entry
1781 rawToc[i].point == 0xa2) {
1782 min = SubChannel::bcd2int(rawToc[i].pmin);
1783 sec = SubChannel::bcd2int(rawToc[i].psec);
1784 frame = SubChannel::bcd2int(rawToc[i].pframe);
1785
1786 if (min <= 99 && sec < 60 && frame < 75)
1787 trackStart = Msf(min, sec, frame).lba() - 150;
1788 break;
1789 }
1790 }
1791
1792 if (i < 0) {
1793 log_message(-1, "Found bogus toc data (no lead-out entry in raw data).");
1794 log_message(-1, "Your drive probably does not support raw toc reading.");
1795 log_message(-1, "Using TOC data retrieved with generic method (no multi session support).");
1796 log_message(-1, "Use driver option 0x%lx to suppress this message.",
1797 OPT_DRV_GET_TOC_GENERIC);
1798
1799 delete[] rawToc;
1800 *cdTocLen = completeTocLen;
1801 return completeToc;
1802 }
1803
1804 for (j = 0; j < completeTocLen; j++) {
1805 if (completeToc[j].track == 0xaa) {
1806 break;
1807 }
1808 }
1809
1810 if (j < completeTocLen) {
1811 if (trackStart != completeToc[j].start) {
1812 // lead-out start does not match -> values are not BCD
1813 isBcd = 0;
1814 }
1815 }
1816 else {
1817 log_message(-2, "Found bogus toc data (no lead-out entry).");
1818
1819 delete[] completeToc;
1820 delete[] rawToc;
1821 return NULL;
1822 }
1823 }
1824
1825 }
1826
1827 if (isBcd == 0) {
1828 // verify that the decision is really correct.
1829 for (i = 0; i < rawTocLen && isBcd == 0; i++) {
1830 if ((rawToc[i].adrCtl & 0xf0) == 0x10 && // only process QMODE1 entries
1831 rawToc[i].point < 0xa0) {
1832
1833 trackNr = rawToc[i].point;
1834
1835 for (j = 0; j < completeTocLen; j++) {
1836 if (completeToc[j].track == trackNr) {
1837 break;
1838 }
1839 }
1840
1841 if (j < completeTocLen) {
1842 min = rawToc[i].pmin;
1843 sec = rawToc[i].psec;
1844 frame = rawToc[i].pframe;
1845
1846 if (min <= 99 && sec < 60 && frame < 75) {
1847 trackStart = Msf(min, sec, frame).lba() - 150;
1848 if (completeToc[j].start != trackStart) {
1849 // start does not match -> values are not HEX
1850 isBcd = -1;
1851 }
1852 }
1853 else {
1854 // bogus time code -> values are not HEX
1855 isBcd = -1;
1856 }
1857 }
1858 else {
1859 // track not found -> values are not BCD
1860 isBcd = -1;
1861 }
1862 }
1863 }
1864
1865 // verify last lead-out pointer
1866 trackStart = 0; // start of lead-out
1867 for (i = rawTocLen - 1; i >= 0; i--) {
1868 if ((rawToc[i].adrCtl & 0xf0) == 0x10 && // QMODE1 entry
1869 rawToc[i].point == 0xa2) {
1870 min = rawToc[i].pmin;
1871 sec = rawToc[i].psec;
1872 frame = rawToc[i].pframe;
1873
1874 if (min <= 99 && sec < 60 && frame < 75)
1875 trackStart = Msf(min, sec, frame).lba() - 150;
1876 break;
1877 }
1878 }
1879
1880 if (i < 0) {
1881 log_message(-1, "Found bogus toc data (no lead-out entry in raw data).");
1882 log_message(-1, "Your drive probably does not support raw toc reading.");
1883 log_message(-1, "Using TOC data retrieved with generic method (no multi session support).");
1884 log_message(-1, "Use driver option 0x%lx to suppress this message.",
1885 OPT_DRV_GET_TOC_GENERIC);
1886
1887 delete[] rawToc;
1888 *cdTocLen = completeTocLen;
1889 return completeToc;
1890 }
1891
1892 for (j = 0; j < completeTocLen; j++) {
1893 if (completeToc[j].track == 0xaa) {
1894 break;
1895 }
1896 }
1897
1898 if (j < completeTocLen) {
1899 if (trackStart != completeToc[j].start) {
1900 // lead-out start does not match -> values are not BCD
1901 isBcd = -1;
1902 }
1903 }
1904 else {
1905 log_message(-1, "Found bogus toc data (no lead-out entry).");
1906
1907 delete[] rawToc;
1908 delete[] completeToc;
1909 return NULL;
1910 }
1911 }
1912
1913 if (isBcd == -1) {
1914 log_message(-1, "Could not determine if raw toc data is BCD or HEX. Please report!");
1915 log_message(-1, "Using TOC data retrieved with generic method (no multi session support).");
1916 log_message(-1,
1917 "Use driver option 0x%lx or 0x%lx to assume BCD or HEX data.",
1918 OPT_DRV_RAW_TOC_BCD, OPT_DRV_RAW_TOC_HEX);
1919
1920 delete[] rawToc;
1921 *cdTocLen = completeTocLen;
1922 return completeToc;
1923 }
1924 }
1925
1926 log_message(4, "Raw toc contains %s values.", isBcd == 0 ? "HEX" : "BCD");
1927
1928 for (i = 0; i < rawTocLen; i++) {
1929 if (rawToc[i].sessionNr == sessionNr &&
1930 (rawToc[i].adrCtl & 0xf0) == 0x10 && /* QMODE1 entry */
1931 rawToc[i].point < 0xa0) {
1932 nTracks++;
1933 }
1934 }
1935
1936 if (nTracks == 0 || nTracks > 99) {
1937 log_message(-1, "Found bogus toc data (0 or > 99 tracks). Please report!");
1938 log_message(-1, "Your drive probably does not support raw toc reading.");
1939 log_message(-1, "Using TOC data retrieved with generic method (no multi session support).");
1940 log_message(-1, "Use driver option 0x%lx to suppress this message.",
1941 OPT_DRV_GET_TOC_GENERIC);
1942
1943 delete[] rawToc;
1944 *cdTocLen = completeTocLen;
1945 return completeToc;
1946 }
1947
1948 cdToc = new CdToc[nTracks + 1];
1949 tocEnt = 0;
1950 lastTrack = -1;
1951
1952 for (i = 0; i < rawTocLen; i++) {
1953 if (rawToc[i].sessionNr == sessionNr &&
1954 (rawToc[i].adrCtl & 0xf0) == 0x10 && // QMODE1 entry
1955 rawToc[i].point < 0xa0) {
1956
1957 if (isBcd) {
1958 trackNr = SubChannel::bcd2int(rawToc[i].point);
1959 trackStart = Msf(SubChannel::bcd2int(rawToc[i].pmin),
1960 SubChannel::bcd2int(rawToc[i].psec),
1961 SubChannel::bcd2int(rawToc[i].pframe)).lba();
1962 }
1963 else {
1964 trackNr = rawToc[i].point;
1965 trackStart =
1966 Msf(rawToc[i].pmin, rawToc[i].psec, rawToc[i].pframe).lba();
1967 }
1968
1969 if (lastTrack != -1 && trackNr != lastTrack + 1) {
1970 log_message(-1, "Found bogus toc data (track number sequence). Please report!");
1971 log_message(-1, "Your drive probably does not support raw toc reading.");
1972 log_message(-1, "Using TOC data retrieved with generic method (no multi session support).");
1973 log_message(-1, "Use driver option 0x%lx to suppress this message.",
1974 OPT_DRV_GET_TOC_GENERIC);
1975
1976 delete[] cdToc;
1977 delete[] rawToc;
1978 *cdTocLen = completeTocLen;
1979 return completeToc;
1980 }
1981
1982 lastTrack = trackNr;
1983
1984 cdToc[tocEnt].adrCtl = rawToc[i].adrCtl;
1985 cdToc[tocEnt].track = trackNr;
1986 cdToc[tocEnt].start = trackStart - 150;
1987 tocEnt++;
1988 }
1989 }
1990
1991 // find lead-out pointer
1992 for (i = 0; i < rawTocLen; i++) {
1993 if (rawToc[i].sessionNr == sessionNr &&
1994 (rawToc[i].adrCtl & 0xf0) == 0x10 && // QMODE1 entry
1995 rawToc[i].point == 0xa2 /* Lead-out pointer */) {
1996
1997 if (isBcd) {
1998 trackStart = Msf(SubChannel::bcd2int(rawToc[i].pmin),
1999 SubChannel::bcd2int(rawToc[i].psec),
2000 SubChannel::bcd2int(rawToc[i].pframe)).lba();
2001 }
2002 else {
2003 trackStart =
2004 Msf(rawToc[i].pmin, rawToc[i].psec, rawToc[i].pframe).lba();
2005 }
2006
2007 cdToc[tocEnt].adrCtl = rawToc[i].adrCtl;
2008 cdToc[tocEnt].track = 0xaa;
2009 cdToc[tocEnt].start = trackStart - 150;
2010 tocEnt++;
2011
2012 break;
2013 }
2014 }
2015
2016 if (tocEnt != nTracks + 1) {
2017 log_message(-1, "Found bogus toc data (no lead-out pointer for session). Please report!");
2018 log_message(-1, "Your drive probably does not support raw toc reading.");
2019 log_message(-1, "Using TOC data retrieved with generic method (no multi session support).");
2020 log_message(-1, "Use driver option 0x%lx to suppress this message.",
2021 OPT_DRV_GET_TOC_GENERIC);
2022
2023 delete[] cdToc;
2024 delete[] rawToc;
2025 *cdTocLen = completeTocLen;
2026 return completeToc;
2027 }
2028
2029
2030 delete[] rawToc;
2031 delete[] completeToc;
2032
2033 *cdTocLen = nTracks + 1;
2034 return cdToc;
2035 }
2036
buildDataFileName(int trackNr,CdToc * toc,int nofTracks,const char * basename,const char * extension)2037 static char *buildDataFileName(int trackNr, CdToc *toc, int nofTracks,
2038 const char *basename, const char *extension)
2039 {
2040 char buf[30];
2041 int start, end;
2042 int run;
2043 int onlyOneAudioRange = 1;
2044
2045 // don't modify the STDIN filename
2046 if (strcmp(basename, "-") == 0)
2047 return strdupCC(basename);
2048
2049
2050 if ((toc[trackNr].adrCtl & 0x04) != 0) {
2051 // data track
2052 sprintf(buf, "_%d", trackNr + 1);
2053 return strdup3CC(basename, buf, NULL);
2054 }
2055
2056 // audio track, find continues range of audio tracks
2057 start = trackNr;
2058 while (start > 0 && (toc[start - 1].adrCtl & 0x04) == 0)
2059 start--;
2060
2061 if (start > 0) {
2062 run = start - 1;
2063 while (run >= 0) {
2064 if ((toc[run].adrCtl & 0x04) == 0) {
2065 onlyOneAudioRange = 0;
2066 break;
2067 }
2068 run--;
2069 }
2070 }
2071
2072 end = trackNr;
2073 while (end < nofTracks - 1 && (toc[end + 1].adrCtl & 0x04) == 0)
2074 end++;
2075
2076 if (onlyOneAudioRange && end < nofTracks - 1) {
2077 run = end + 1;
2078 while (run < nofTracks) {
2079 if ((toc[run].adrCtl & 0x04) == 0) {
2080 onlyOneAudioRange = 0;
2081 break;
2082 }
2083 run++;
2084 }
2085 }
2086
2087 if (onlyOneAudioRange) {
2088 return strdup3CC(basename, extension, NULL);
2089 }
2090 else {
2091 sprintf(buf, "_%d-%d", start + 1, end + 1);
2092 return strdup3CC(basename, buf, extension);
2093 }
2094 }
2095
2096 /* Checks if drive's capabilites support the selected sub-channel reading
2097 mode for given track mode.
2098 mode: track mode
2099 caps: capabilities bits
2100 Return: 1: current sub-channel reading mode is supported
2101 0: current sub-channel reading mode is not supported
2102 */
checkSubChanReadCaps(TrackData::Mode mode,unsigned long caps)2103 int CdrDriver::checkSubChanReadCaps(TrackData::Mode mode, unsigned long caps)
2104 {
2105 int ret = 0;
2106
2107 switch (subChanReadMode_) {
2108 case TrackData::SUBCHAN_NONE:
2109 ret = 1;
2110 break;
2111
2112 case TrackData::SUBCHAN_RW_RAW:
2113 if (mode == TrackData::AUDIO) {
2114 if ((caps & (CDR_READ_CAP_AUDIO_RW_RAW|CDR_READ_CAP_AUDIO_PW_RAW)) != 0)
2115 ret = 1;
2116 }
2117 else {
2118 if ((caps & (CDR_READ_CAP_DATA_RW_RAW|CDR_READ_CAP_DATA_PW_RAW)) != 0)
2119 ret = 1;
2120 }
2121 break;
2122
2123 case TrackData::SUBCHAN_RW:
2124 if (mode == TrackData::AUDIO) {
2125 if ((caps & CDR_READ_CAP_AUDIO_RW_COOKED) != 0)
2126 ret = 1;
2127 }
2128 else {
2129 if ((caps & CDR_READ_CAP_DATA_RW_COOKED) != 0)
2130 ret = 1;
2131 }
2132 break;
2133 }
2134
2135 return ret;
2136 }
2137
2138 // Creates 'Toc' object for inserted CD.
2139 // session: session that should be analyzed
2140 // audioFilename: name of audio file that is placed into TOC
2141 // Return: newly allocated 'Toc' object or 'NULL' on error
readDiskToc(int session,const char * dataFilename)2142 Toc *CdrDriver::readDiskToc(int session, const char *dataFilename)
2143 {
2144 int nofTracks = 0;
2145 int i, j;
2146 CdToc *cdToc = getToc(session, &nofTracks);
2147 Msf indexIncrements[98];
2148 int indexIncrementCnt = 0;
2149 char isrcCode[13];
2150 unsigned char trackCtl; // control nibbles of track
2151 int ctlCheckOk;
2152 char *fname;
2153 char *extension = NULL;
2154 char *p;
2155 TrackInfo *trackInfos;
2156
2157 if (cdToc == NULL) {
2158 return NULL;
2159 }
2160
2161 if (nofTracks <= 1) {
2162 log_message(-1, "No tracks on disk.");
2163 delete[] cdToc;
2164 return NULL;
2165 }
2166
2167 log_message(1, "");
2168 printCdToc(cdToc, nofTracks);
2169 log_message(1, "");
2170 //return NULL;
2171
2172 nofTracks -= 1; // do not count lead-out
2173
2174 readCapabilities_ = getReadCapabilities(cdToc, nofTracks);
2175
2176 fname = strdupCC(dataFilename);
2177 if ((p = strrchr(fname, '.')) != NULL) {
2178 extension = strdupCC(p);
2179 *p = 0;
2180 }
2181
2182 trackInfos = new TrackInfo[nofTracks + 1];
2183 memset(trackInfos, 0, (nofTracks + 1) * sizeof(TrackInfo));
2184
2185 for (i = 0; i < nofTracks; i++) {
2186 TrackData::Mode trackMode;
2187
2188 if ((cdToc[i].adrCtl & 0x04) != 0) {
2189 if ((trackMode = getTrackMode(i + 1, cdToc[i].start)) ==
2190 TrackData::MODE0) {
2191 log_message(-1, "Cannot determine mode of data track %d - asuming MODE1.",
2192 i + 1);
2193 trackMode = TrackData::MODE1;
2194 }
2195
2196 if (rawDataReading_) {
2197 if (trackMode == TrackData::MODE1) {
2198 trackMode = TrackData::MODE1_RAW;
2199 }
2200 else if (trackMode == TrackData::MODE2) {
2201 trackMode = TrackData::MODE2_RAW;
2202 }
2203 else if (trackMode == TrackData::MODE2_FORM1 ||
2204 trackMode == TrackData::MODE2_FORM2 ||
2205 trackMode == TrackData::MODE2_FORM_MIX) {
2206 trackMode = TrackData::MODE2_RAW;
2207 }
2208 }
2209 else if (mode2Mixed_) {
2210 if (trackMode == TrackData::MODE2_FORM1 ||
2211 trackMode == TrackData::MODE2_FORM2) {
2212 trackMode = TrackData::MODE2_FORM_MIX;
2213 }
2214 }
2215 }
2216 else {
2217 trackMode = TrackData::AUDIO;
2218 }
2219
2220 if (!checkSubChanReadCaps(trackMode, readCapabilities_)) {
2221 log_message(-2, "This drive does not support %s sub-channel reading.",
2222 TrackData::subChannelMode2String(subChanReadMode_));
2223 delete[] cdToc;
2224 delete[] trackInfos;
2225 delete[] fname;
2226 return NULL;
2227 }
2228
2229 trackInfos[i].trackNr = cdToc[i].track;
2230 trackInfos[i].ctl = cdToc[i].adrCtl & 0x0f;
2231 trackInfos[i].mode = trackMode;
2232 trackInfos[i].start = cdToc[i].start;
2233 trackInfos[i].pregap = 0;
2234 trackInfos[i].fill = 0;
2235 trackInfos[i].indexCnt = 0;
2236 trackInfos[i].isrcCode[0] = 0;
2237 trackInfos[i].filename = buildDataFileName(i, cdToc, nofTracks, fname,
2238 extension);
2239 trackInfos[i].bytesWritten = 0;
2240 }
2241
2242 // lead-out entry
2243 trackInfos[nofTracks].trackNr = 0xaa;
2244 trackInfos[nofTracks].ctl = 0;
2245 trackInfos[nofTracks].mode = trackInfos[nofTracks - 1].mode;
2246 trackInfos[nofTracks].start = cdToc[nofTracks].start;
2247 if (taoSource()) {
2248 trackInfos[nofTracks].start -= taoSourceAdjust_;
2249 }
2250 trackInfos[nofTracks].pregap = 0;
2251 trackInfos[nofTracks].fill = 0;
2252 trackInfos[nofTracks].indexCnt = 0;
2253 trackInfos[nofTracks].isrcCode[0] = 0;
2254 trackInfos[nofTracks].filename = NULL;
2255 trackInfos[nofTracks].bytesWritten = 0;
2256
2257 long pregap = 0;
2258 long defaultPregap;
2259 long slba, elba;
2260
2261 if (session == 1) {
2262 pregap = cdToc[0].start; // pre-gap of first track
2263 }
2264
2265 for (i = 0; i < nofTracks; i++) {
2266 trackInfos[i].pregap = pregap;
2267
2268 slba = trackInfos[i].start;
2269 elba = trackInfos[i + 1].start;
2270
2271 defaultPregap = 0;
2272
2273 if (taoSource()) {
2274 // assume always a pre-gap of 150 + # link blocks between two tracks
2275 // except between two audio tracks
2276 if ((trackInfos[i].mode != TrackData::AUDIO ||
2277 trackInfos[i + 1].mode != TrackData::AUDIO) &&
2278 i < nofTracks - 1) {
2279 defaultPregap = 150 + taoSourceAdjust_;
2280 }
2281 }
2282 else {
2283 // assume a pre-gap of 150 between tracks of different mode
2284 if (trackInfos[i].mode != trackInfos[i + 1].mode) {
2285 defaultPregap = 150;
2286 }
2287 }
2288
2289 elba -= defaultPregap;
2290
2291
2292 Msf trackLength(elba - slba);
2293
2294 log_message(1, "Analyzing track %02d (%s): start %s, ", i + 1,
2295 TrackData::mode2String(trackInfos[i].mode),
2296 Msf(cdToc[i].start).str());
2297 log_message(1, "length %s...", trackLength.str());
2298
2299 if (pregap > 0) {
2300 log_message(2, "Found pre-gap: %s", Msf(pregap).str());
2301 }
2302
2303 isrcCode[0] = 0;
2304 indexIncrementCnt = 0;
2305 pregap = 0;
2306 trackCtl = 0;
2307
2308 if (!fastTocReading_) {
2309 // Find index increments and pre-gap of next track
2310 if (trackInfos[i].mode == TrackData::AUDIO) {
2311 analyzeTrack(TrackData::AUDIO, i + 1, slba, elba,
2312 indexIncrements, &indexIncrementCnt,
2313 i < nofTracks - 1 ? &pregap : 0, isrcCode, &trackCtl);
2314 if (defaultPregap != 0)
2315 pregap = defaultPregap;
2316 }
2317 }
2318 else {
2319 if (trackInfos[i].mode == TrackData::AUDIO) {
2320 if (readIsrc(i + 1, isrcCode) != 0) {
2321 isrcCode[0] = 0;
2322 }
2323 }
2324 }
2325
2326 if (pregap == 0) {
2327 pregap = defaultPregap;
2328 }
2329
2330 if (isrcCode[0] != 0) {
2331 log_message(2, "Found ISRC code.");
2332 memcpy(trackInfos[i].isrcCode, isrcCode, 13);
2333 }
2334
2335 for (j = 0; j < indexIncrementCnt; j++)
2336 trackInfos[i].index[j] = indexIncrements[j].lba();
2337
2338 trackInfos[i].indexCnt = indexIncrementCnt;
2339
2340 if ((trackCtl & 0x80) != 0) {
2341 // Check track against TOC control nibbles
2342 ctlCheckOk = 1;
2343 if ((trackCtl & 0x01) != (cdToc[i].adrCtl & 0x01)) {
2344 log_message(-1, "Pre-emphasis flag of track differs from TOC - toc file contains TOC setting.");
2345 ctlCheckOk = 0;
2346 }
2347 if ((trackCtl & 0x08) != (cdToc[i].adrCtl & 0x08)) {
2348 log_message(-1, "2-/4-channel-audio flag of track differs from TOC - toc file contains TOC setting.");
2349 ctlCheckOk = 0;
2350 }
2351
2352 if (ctlCheckOk) {
2353 log_message(2, "Control nibbles of track match CD-TOC settings.");
2354 }
2355 }
2356 }
2357
2358 int padFirstPregap;
2359
2360 if (onTheFly_) {
2361 if (session == 1 && (options_ & OPT_DRV_NO_PREGAP_READ) == 0)
2362 padFirstPregap = 0;
2363 else
2364 padFirstPregap = 1;
2365 }
2366 else {
2367 padFirstPregap = (session != 1) || padFirstPregap_;
2368 }
2369
2370
2371 Toc *toc = buildToc(trackInfos, nofTracks + 1, padFirstPregap);
2372
2373 if (toc != NULL) {
2374 if ((options_ & OPT_DRV_NO_CDTEXT_READ) == 0)
2375 readCdTextData(toc);
2376
2377 if (readCatalog(toc, trackInfos[0].start, trackInfos[nofTracks].start))
2378 log_message(2, "Found disk catalogue number.");
2379 }
2380
2381 // overwrite last time message
2382 log_message(1, " \t");
2383
2384 delete[] cdToc;
2385 delete[] trackInfos;
2386
2387 delete[] fname;
2388 if (extension != NULL)
2389 delete[] extension;
2390
2391 return toc;
2392 }
2393
2394 // Implementation is based on binary search over all sectors of actual
2395 // track. ISRC codes are not extracted here.
analyzeTrackSearch(TrackData::Mode,int trackNr,long startLba,long endLba,Msf * index,int * indexCnt,long * pregap,char * isrcCode,unsigned char * ctl)2396 int CdrDriver::analyzeTrackSearch(TrackData::Mode, int trackNr, long startLba,
2397 long endLba, Msf *index, int *indexCnt,
2398 long *pregap, char *isrcCode,
2399 unsigned char *ctl)
2400 {
2401 isrcCode[0] = 0;
2402 *ctl = 0;
2403
2404
2405 if (pregap != NULL) {
2406 *pregap = findIndex(trackNr + 1, 0, startLba, endLba - 1);
2407 if (*pregap >= endLba) {
2408 *pregap = 0;
2409 }
2410 else if (*pregap > 0) {
2411 *pregap = endLba - *pregap;
2412 }
2413 }
2414
2415 // check for index increments
2416 int ind = 2;
2417 long indexLba = startLba;
2418 *indexCnt = 0;
2419
2420 do {
2421 if ((indexLba = findIndex(trackNr, ind, indexLba, endLba - 1)) > 0) {
2422 log_message(2, "Found index %d at %s", ind, Msf(indexLba).str());
2423 if (*indexCnt < 98 && indexLba > startLba) {
2424 index[*indexCnt] = Msf(indexLba - startLba);
2425 *indexCnt += 1;
2426 }
2427 ind++;
2428 }
2429 } while (indexLba > 0 && indexLba < endLba);
2430
2431
2432 // Retrieve control nibbles of track, add 75 to track start so we
2433 // surely get a block of current track.
2434 int dummy, track;
2435 if (getTrackIndex(startLba + 75, &track, &dummy, ctl) == 0 &&
2436 track == trackNr) {
2437 *ctl |= 0x80;
2438 }
2439
2440 return 0;
2441 }
2442
getTrackIndex(long lba,int * trackNr,int * indexNr,unsigned char * ctl)2443 int CdrDriver::getTrackIndex(long lba, int *trackNr, int *indexNr,
2444 unsigned char *ctl)
2445 {
2446 return 1;
2447 }
2448
2449 // Scan from lba 'trackStart' to 'trackEnd' for the position at which the
2450 // index switchs to 'index' of track number 'track'.
2451 // return: lba of index start postion or 0 if index was not found
findIndex(int track,int index,long trackStart,long trackEnd)2452 long CdrDriver::findIndex(int track, int index, long trackStart,
2453 long trackEnd)
2454 {
2455 int actTrack;
2456 int actIndex;
2457 long start = trackStart;
2458 long end = trackEnd;
2459 long mid;
2460
2461 //log_message(0, "findIndex: %ld - %ld", trackStart, trackEnd);
2462
2463 while (start < end) {
2464 mid = start + ((end - start) / 2);
2465
2466 //log_message(0, "Checking block %ld...", mid);
2467 if (getTrackIndex(mid, &actTrack, &actIndex, NULL) != 0) {
2468 return 0;
2469 }
2470 //log_message(0, "Found track %d, index %d", actTrack, actIndex);
2471 if ((actTrack < track || actIndex < index) && mid + 1 < trackEnd) {
2472 //log_message(0, " Checking block %ld...", mid + 1);
2473 if (getTrackIndex(mid + 1, &actTrack, &actIndex, NULL) != 0) {
2474 return 0;
2475 }
2476 //log_message(0, " Found track %d, index %d", actTrack, actIndex);
2477 if (actTrack == track && actIndex == index) {
2478 //log_message(0, "Found pregap at %ld", mid + 1);
2479 return mid;
2480 }
2481 else {
2482 start = mid + 1;
2483 }
2484
2485 }
2486 else {
2487 end = mid;
2488 }
2489 }
2490
2491 return 0;
2492 }
2493
analyzeTrackScan(TrackData::Mode,int trackNr,long startLba,long endLba,Msf * index,int * indexCnt,long * pregap,char * isrcCode,unsigned char * ctl)2494 int CdrDriver::analyzeTrackScan(TrackData::Mode, int trackNr, long startLba,
2495 long endLba,
2496 Msf *index, int *indexCnt, long *pregap,
2497 char *isrcCode, unsigned char *ctl)
2498 {
2499 SubChannel **subChannels;
2500 int n, i;
2501 int actIndex = 1;
2502 long length;
2503 long crcErrCnt = 0;
2504 long timeCnt = 0;
2505 int ctlSet = 0;
2506 int isrcCodeFound = 0;
2507 long trackStartLba = startLba;
2508
2509 *isrcCode = 0;
2510
2511 if (pregap != NULL)
2512 *pregap = 0;
2513
2514 *indexCnt = 0;
2515 *ctl = 0;
2516
2517 //startLba -= 75;
2518 if (startLba < 0) {
2519 startLba = 0;
2520 }
2521 length = endLba - startLba;
2522
2523 while (length > 0) {
2524 n = (length > maxScannedSubChannels_) ? maxScannedSubChannels_ : length;
2525
2526 if (readSubChannels(TrackData::SUBCHAN_NONE, startLba, n, &subChannels,
2527 NULL) != 0 ||
2528 subChannels == NULL) {
2529 return 1;
2530 }
2531
2532 for (i = 0; i < n; i++) {
2533 SubChannel *chan = subChannels[i];
2534 //chan->print();
2535
2536 if (chan->checkCrc() && chan->checkConsistency()) {
2537 if (chan->type() == SubChannel::QMODE1DATA) {
2538 int t = chan->trackNr();
2539 Msf time(chan->min(), chan->sec(), chan->frame()); // track rel time
2540 Msf atime(chan->amin(), chan->asec(), chan->aframe()); // abs time
2541
2542 if (timeCnt > 74) {
2543 log_message(1, "%s\r", time.str());
2544 timeCnt = 0;
2545 }
2546
2547 if (t == trackNr && !ctlSet) {
2548 *ctl = chan->ctl();
2549 *ctl |= 0x80;
2550 ctlSet = 1;
2551 }
2552 if (t == trackNr && chan->indexNr() == actIndex + 1) {
2553 actIndex = chan->indexNr();
2554 log_message(2, "Found index %d at: %s", actIndex, time.str());
2555 if ((*indexCnt) < 98) {
2556 index[*indexCnt] = time;
2557 *indexCnt += 1;
2558 }
2559 }
2560 else if (t == trackNr + 1) {
2561 if (chan->indexNr() == 0) {
2562 if (pregap != NULL) {
2563 // don't use time.lba() to calculate pre-gap length; it would
2564 // count one frame too many if the CD counts the pre-gap down
2565 // to 00:00:00 instead of 00:00:01
2566 // Instead, count number of frames until start of Index 01
2567 // See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=102171
2568 // atime starts at 02:00, so subtract it
2569 *pregap = endLba - (atime.lba() - 150);
2570 }
2571 if (crcErrCnt != 0)
2572 log_message(2, "Found %ld Q sub-channels with CRC errors.",
2573 crcErrCnt);
2574
2575 return 0;
2576 }
2577 }
2578 }
2579 else if (chan->type() == SubChannel::QMODE3) {
2580 if (!isrcCodeFound && startLba > trackStartLba) {
2581 strcpy(isrcCode, chan->isrc());
2582 isrcCodeFound = 1;
2583 }
2584 }
2585 }
2586 else {
2587 crcErrCnt++;
2588 #if 0
2589 if (chan->type() == SubChannel::QMODE1DATA) {
2590 log_message(2, "Q sub-channel data at %02d:%02d:%02d failed CRC check - ignored",
2591 chan->min(), chan->sec(), chan->frame());
2592 }
2593 else {
2594 log_message(2, "Q sub-channel data failed CRC check - ignored.");
2595 }
2596 chan->print();
2597 #endif
2598 }
2599
2600 timeCnt++;
2601 }
2602
2603 length -= n;
2604 startLba += n;
2605 }
2606
2607 if (crcErrCnt != 0)
2608 log_message(2, "Found %ld Q sub-channels with CRC errors.", crcErrCnt);
2609
2610 return 0;
2611 }
2612
2613 // Checks if toc is suitable for writing. Usually all tocs are OK so
2614 // return just 0 here.
2615 // Return: 0: OK
2616 // 1: toc may not be suitable
2617 // 2: toc is not suitable
checkToc(const Toc * toc)2618 int CdrDriver::checkToc(const Toc *toc)
2619 {
2620 int ret = 0;
2621
2622 if (multiSession_ && toc->tocType() != Toc::CD_ROM_XA) {
2623 log_message(-1, "The toc type should be set to CD_ROM_XA if a multi session");
2624 log_message(-1, "CD is recorded.");
2625 ret = 1;
2626 }
2627
2628 TrackIterator itr(toc);
2629 const Track *run;
2630 int tracknr;
2631
2632 for (run = itr.first(), tracknr = 1; run != NULL;
2633 run = itr.next(), tracknr++) {
2634 if (run->subChannelType() != TrackData::SUBCHAN_NONE) {
2635 if (subChannelEncodingMode(run->subChannelType()) == -1) {
2636 log_message(-2, "Track %d: sub-channel writing mode is not supported by driver.", tracknr);
2637 ret = 2;
2638 }
2639 }
2640 }
2641
2642 return ret;
2643 }
2644
2645 // Returns block size for given mode and actual 'encodingMode_' that must
2646 // be used to send data to the recorder.
blockSize(TrackData::Mode m,TrackData::SubChannelMode sm) const2647 long CdrDriver::blockSize(TrackData::Mode m,
2648 TrackData::SubChannelMode sm) const
2649 {
2650 long bsize = 0;
2651
2652 if (encodingMode_ == 0) {
2653 // only audio blocks are written
2654 bsize = AUDIO_BLOCK_LEN;
2655 }
2656 else if (encodingMode_ == 1) {
2657 // encoding for SCSI-3/mmc drives in session-at-once mode
2658 switch (m) {
2659 case TrackData::AUDIO:
2660 bsize = AUDIO_BLOCK_LEN;
2661 break;
2662 case TrackData::MODE1:
2663 case TrackData::MODE1_RAW:
2664 bsize = MODE1_BLOCK_LEN;
2665 break;
2666 case TrackData::MODE2:
2667 case TrackData::MODE2_RAW:
2668 case TrackData::MODE2_FORM1:
2669 case TrackData::MODE2_FORM2:
2670 case TrackData::MODE2_FORM_MIX:
2671 bsize = MODE2_BLOCK_LEN;
2672 break;
2673 case TrackData::MODE0:
2674 log_message(-3, "Illegal mode in 'CdrDriver::blockSize()'.");
2675 break;
2676 }
2677 }
2678 else {
2679 log_message(-3, "Illegal encoding mode in 'CdrDriver::blockSize()'.");
2680 }
2681
2682 bsize += TrackData::subChannelSize(sm);
2683
2684 return bsize;
2685 }
2686
printCdToc(CdToc * toc,int tocLen)2687 void CdrDriver::printCdToc(CdToc *toc, int tocLen)
2688 {
2689 int t;
2690 long len;
2691
2692 log_message(1, "Track Mode Flags Start Length");
2693 log_message(1, "------------------------------------------------------------");
2694
2695 for (t = 0; t < tocLen; t++) {
2696 if (t == tocLen - 1) {
2697 log_message(1, "Leadout %s %x %s(%6ld)",
2698 (toc[t].adrCtl & 0x04) != 0 ? "DATA " : "AUDIO",
2699 toc[t].adrCtl & 0x0f,
2700 Msf(toc[t].start).str(), toc[t].start);
2701 }
2702 else {
2703 len = toc[t + 1].start - toc[t].start;
2704 log_message(1, "%2d %s %x %s(%6ld) ", toc[t].track,
2705 (toc[t].adrCtl & 0x04) != 0 ? "DATA " : "AUDIO",
2706 toc[t].adrCtl & 0x0f,
2707 Msf(toc[t].start).str(), toc[t].start);
2708 log_message(1, " %s(%6ld)", Msf(len).str(), len);
2709 }
2710 }
2711 }
2712
2713
getTrackMode(int,long trackStartLba)2714 TrackData::Mode CdrDriver::getTrackMode(int, long trackStartLba)
2715 {
2716 unsigned char cmd[10];
2717 unsigned char data[2340];
2718 int blockLength = 2340;
2719 TrackData::Mode mode;
2720
2721 if (setBlockSize(blockLength) != 0) {
2722 return TrackData::MODE0;
2723 }
2724
2725 memset(cmd, 0, 10);
2726
2727 cmd[0] = 0x28; // READ10
2728 cmd[2] = trackStartLba >> 24;
2729 cmd[3] = trackStartLba >> 16;
2730 cmd[4] = trackStartLba >> 8;
2731 cmd[5] = trackStartLba;
2732 cmd[8] = 1;
2733
2734 if (sendCmd(cmd, 10, NULL, 0, data, blockLength) != 0) {
2735 setBlockSize(MODE1_BLOCK_LEN);
2736 return TrackData::MODE0;
2737 }
2738
2739 setBlockSize(MODE1_BLOCK_LEN);
2740
2741 mode = determineSectorMode(data);
2742
2743 if (mode == TrackData::MODE0) {
2744 log_message(-2, "Found illegal mode in sector %ld.", trackStartLba);
2745 }
2746
2747 return mode;
2748 }
2749
determineSectorMode(unsigned char * buf)2750 TrackData::Mode CdrDriver::determineSectorMode(unsigned char *buf)
2751 {
2752 switch (buf[3]) {
2753 case 1:
2754 return TrackData::MODE1;
2755 break;
2756
2757 case 2:
2758 return analyzeSubHeader(buf + 4);
2759 break;
2760 }
2761
2762 // illegal mode found
2763 return TrackData::MODE0;
2764 }
2765
2766 // Analyzes given 8 byte sub head and tries to determine if it belongs
2767 // to a form 1, form 2 or a plain mode 2 sector.
analyzeSubHeader(unsigned char * sh)2768 TrackData::Mode CdrDriver::analyzeSubHeader(unsigned char *sh)
2769 {
2770 if (sh[0] == sh[4] && sh[1] == sh[5] && sh[2] == sh[6] && sh[3] == sh[7]) {
2771 // check first copy
2772 //if (sh[0] < 8 && sh[1] < 8 && sh[2] != 0) {
2773 if ((sh[2] & 0x20) != 0)
2774 return TrackData::MODE2_FORM2;
2775 else
2776 return TrackData::MODE2_FORM1;
2777 //}
2778
2779 #if 0
2780 // check second copy
2781 if (sh[4] < 8 && sh[5] < 8 && sh[6] != 0) {
2782 if (sh[6] & 0x20 != 0)
2783 return TrackData::MODE2_FORM2;
2784 else
2785 return TrackData::MODE2_FORM1;
2786 }
2787 #endif
2788 }
2789 else {
2790 // no valid sub-header data, sector is a plain MODE2 sector
2791 return TrackData::MODE2;
2792 }
2793 }
2794
2795
2796 // Sets block size for read/write operation to given value.
2797 // blocksize: block size in bytes
2798 // density: (optional, default: 0) density code
2799 // Return: 0: OK
2800 // 1: SCSI command failed
setBlockSize(long blocksize,unsigned char density)2801 int CdrDriver::setBlockSize(long blocksize, unsigned char density)
2802 {
2803 unsigned char cmd[10];
2804 unsigned char ms[16];
2805
2806 if (blockLength_ == blocksize)
2807 return 0;
2808
2809 memset(ms, 0, 16);
2810
2811 ms[3] = 8;
2812 ms[4] = density;
2813 ms[10] = blocksize >> 8;
2814 ms[11] = blocksize;
2815
2816 memset(cmd, 0, 10);
2817
2818 cmd[0] = 0x15; // MODE SELECT6
2819 cmd[4] = 12;
2820
2821 if (sendCmd(cmd, 6, ms, 12, NULL, 0) != 0) {
2822 log_message(-2, "Cannot set block size.");
2823 return 1;
2824 }
2825
2826 blockLength_ = blocksize;
2827
2828 return 0;
2829 }
2830
2831
2832 // Returns control flags for given track.
trackCtl(const Track * track)2833 unsigned char CdrDriver::trackCtl(const Track *track)
2834 {
2835 unsigned char ctl = 0;
2836
2837 if (track->copyPermitted()) {
2838 ctl |= 0x20;
2839 }
2840
2841 if (track->type() == TrackData::AUDIO) {
2842 // audio track
2843 if (track->preEmphasis()) {
2844 ctl |= 0x10;
2845 }
2846 if (track->audioType() == 1) {
2847 ctl |= 0x80;
2848 }
2849 }
2850 else {
2851 // data track
2852 ctl |= 0x40;
2853 }
2854
2855 return ctl;
2856 }
2857
2858 // Returns session format for point A0 toc entry depending on Toc type.
sessionFormat()2859 unsigned char CdrDriver::sessionFormat()
2860 {
2861 unsigned char ret = 0;
2862 int nofMode1Tracks;
2863 int nofMode2Tracks;
2864
2865 switch (toc_->tocType()) {
2866 case Toc::CD_DA:
2867 case Toc::CD_ROM:
2868 ret = 0x00;
2869 break;
2870
2871 case Toc::CD_I:
2872 ret = 0x10;
2873 break;
2874
2875 case Toc::CD_ROM_XA:
2876 /* The toc type can only be set to CD_ROM_XA if the session contains
2877 at least one data track. Otherwise the toc type must be CD_DA even
2878 in multi session mode.
2879 */
2880 toc_->trackSummary(NULL, &nofMode1Tracks, &nofMode2Tracks);
2881 if (nofMode1Tracks + nofMode2Tracks > 0)
2882 ret = 0x20;
2883 else
2884 ret = 0x0;
2885 break;
2886 }
2887
2888 log_message(3, "Session format: %x", ret);
2889
2890 return ret;
2891 }
2892
2893 // Generic method to read CD-TEXT packs according to the MMC-2 specification.
2894 // nofPacks: filled with number of found CD-TEXT packs
2895 // return: array of CD-TEXT packs or 'NULL' if no packs where retrieved
readCdTextPacks(long * nofPacks)2896 CdTextPack *CdrDriver::readCdTextPacks(long *nofPacks)
2897 {
2898 unsigned char cmd[12];
2899 unsigned char *data;
2900 unsigned char reqData[4];
2901
2902 #if 0
2903 memset(cmd, 0, 12);
2904
2905 cmd[0] = 0xbe;
2906 cmd[2] = 0xf0;
2907 cmd[3] = 0x00;
2908 cmd[4] = 0x00;
2909 cmd[5] = 0x00;
2910 cmd[8] = 15;
2911 cmd[9] = 0x0;
2912 cmd[10] = 0x1;
2913
2914 long len1 = 15 * (AUDIO_BLOCK_LEN + 96);
2915 data = new unsigned char [len1];
2916
2917 if (sendCmd(cmd, 12, NULL, 0, data, len1) != 0) {
2918 log_message(1, "Cannot read raw CD-TEXT data.");
2919 }
2920
2921 long i, j;
2922 unsigned char *p = data + AUDIO_BLOCK_LEN;
2923
2924 log_message(0, "Raw CD-TEXT data");
2925
2926 for (i = 0; i < 15; i++) {
2927 unsigned char packs[72];
2928 PWSubChannel96 chan(p);
2929
2930 chan.getRawRWdata(packs);
2931
2932 for (j = 0; j < 4; j++) {
2933 log_message(0, "%02x %02x %02x %02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x CRC: %02x %02x",
2934 packs[j*18+0], packs[j*18+1], packs[j*18+2], packs[j*18+3],
2935 packs[j*18+4], packs[j*18+5], packs[j*18+6], packs[j*18+7],
2936 packs[j*18+8], packs[j*18+9], packs[j*18+10], packs[j*18+11],
2937 packs[j*18+12], packs[j*18+13], packs[j*18+14], packs[j*18+15],
2938 packs[j*18+16], packs[j*18+17]);
2939 }
2940
2941 p += AUDIO_BLOCK_LEN + 96;
2942 }
2943
2944 delete[] data;
2945
2946
2947 log_message(0, "Raw CD-TEXT data - end");
2948 #endif
2949
2950 memset(cmd, 0, 10);
2951
2952 cmd[0] = 0x43; // READ TOC/PMA/ATIP
2953 cmd[2] = 5; // CD-TEXT
2954 cmd[8] = 4;
2955
2956 if (sendCmd(cmd, 10, NULL, 0, reqData, 4, 0) != 0) {
2957 log_message(3, "Cannot read CD-TEXT data - maybe not supported by drive.");
2958 return NULL;
2959 }
2960
2961 long len = ((reqData[0] << 8 ) | reqData[1]) + 2;
2962
2963 log_message(4, "CD-TEXT data len: %ld", len);
2964
2965 if (len <= 4)
2966 return NULL;
2967
2968 if (len > scsiMaxDataLen_) {
2969 log_message(-2, "CD-TEXT data too big for maximum SCSI transfer length.");
2970 return NULL;
2971 }
2972
2973 data = new unsigned char[len];
2974
2975 cmd[7] = len >> 8;
2976 cmd[8] = len;
2977
2978 if (sendCmd(cmd, 10, NULL, 0, data, len, 1) != 0) {
2979 log_message(-2, "Reading of CD-TEXT data failed.");
2980 delete[] data;
2981 return NULL;
2982 }
2983
2984 *nofPacks = (len - 4) / sizeof(CdTextPack);
2985
2986 CdTextPack *packs = new CdTextPack[*nofPacks];
2987
2988 memcpy(packs, data + 4, *nofPacks * sizeof(CdTextPack));
2989
2990 delete[] data;
2991
2992 return packs;
2993 }
2994
2995 // Analyzes CD-TEXT packs and stores read data in given 'Toc' object.
2996 // Return: 0: OK
2997 // 1: error occured
readCdTextData(Toc * toc)2998 int CdrDriver::readCdTextData(Toc *toc)
2999 {
3000 long i, j;
3001 long nofPacks;
3002 CdTextPack *packs = readCdTextPacks(&nofPacks);
3003 unsigned char buf[256 * 12];
3004 unsigned char lastType;
3005 int lastBlockNumber;
3006 int blockNumber;
3007 int pos;
3008 int actTrack;
3009 CdTextItem::PackType packType;
3010 CdTextItem *sizeInfoItem = NULL;
3011 CdTextItem *item;
3012
3013 if (packs == NULL)
3014 return 1;
3015
3016 log_message(1, "Found CD-TEXT data.");
3017
3018 pos = 0;
3019 lastType = packs[0].packType;
3020 lastBlockNumber = (packs[0].blockCharacter >> 4) & 0x07;
3021 actTrack = 0;
3022
3023 for (i = 0; i < nofPacks; i++) {
3024 CdTextPack &p = packs[i];
3025
3026 #if 1
3027 log_message(4, "%02x %02x %02x %02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x CRC: %02x %02x", p.packType, p.trackNumber,
3028 p.sequenceNumber, p.blockCharacter, p.data[0], p.data[1],
3029 p.data[2], p.data[3], p.data[4], p.data[5], p.data[6], p.data[7],
3030 p.data[8], p.data[9], p.data[10], p.data[11],
3031 p.crc0, p.crc1);
3032 #endif
3033
3034 blockNumber = (p.blockCharacter >> 4) & 0x07;
3035
3036 if (lastType != p.packType || lastBlockNumber != blockNumber) {
3037 if (lastType >= 0x80 && lastType <= 0x8f) {
3038 packType = CdTextItem::int2PackType(lastType);
3039
3040 if (CdTextItem::isBinaryPack(packType)) {
3041 // finish binary data
3042
3043 if (packType == CdTextItem::CDTEXT_GENRE) {
3044 // The two genre codes may be followed by a string. Adjust 'pos'
3045 // so that all extra 0 bytes at the end of the data are stripped
3046 // off.
3047 for (j = 2; j < pos && buf[j] != 0; j++) ;
3048 if (j < pos)
3049 pos = j + 1;
3050 }
3051
3052 item = new CdTextItem(packType, lastBlockNumber, buf, pos);
3053
3054 if (packType == CdTextItem::CDTEXT_SIZE_INFO)
3055 sizeInfoItem = item;
3056
3057 toc->addCdTextItem(0, item);
3058 }
3059 }
3060 else {
3061 log_message(-2, "CD-TEXT: Found invalid pack type: %02x", lastType);
3062 delete[] packs;
3063 return 1;
3064 }
3065
3066 lastType = p.packType;
3067 lastBlockNumber = blockNumber;
3068 pos = 0;
3069 actTrack = 0;
3070 }
3071
3072 if (p.packType >= 0x80 && p.packType <= 0x8f) {
3073 packType = CdTextItem::int2PackType(p.packType);
3074
3075 if (CdTextItem::isBinaryPack(packType)) {
3076 memcpy(buf + pos, p.data, 12);
3077 pos += 12;
3078 }
3079 else {
3080 // pack contains text -> read all string from it
3081 j = 0;
3082
3083 while (j < 12 && actTrack <= toc->nofTracks()) {
3084 for (; j < 12 && p.data[j] != 0; j++)
3085 buf[pos++] = p.data[j];
3086
3087 if (j < 12) {
3088 // string is finished
3089 buf[pos] = 0;
3090
3091 #if 0
3092 log_message(0, "%02x %02x: %s", p.packType, p.trackNumber, buf);
3093 #endif
3094
3095 toc->addCdTextItem(actTrack,
3096 new CdTextItem(packType, blockNumber,
3097 (char*)buf));
3098 actTrack++;
3099 pos = 0;
3100
3101 if (CdTextItem::isTrackPack(packType)) {
3102 j++; // skip zero
3103 }
3104 else {
3105 j = 12; // don't use remaining zeros to build track packs
3106 }
3107 }
3108 }
3109 }
3110 }
3111 else {
3112 log_message(-2, "CD-TEXT: Found invalid pack type: %02x", p.packType);
3113 delete[] packs;
3114 return 1;
3115 }
3116 }
3117
3118 if (pos != 0 && lastType >= 0x80 && lastType <= 0x8f) {
3119 packType = CdTextItem::int2PackType(lastType);
3120
3121 if (CdTextItem::isBinaryPack(packType)) {
3122 // finish binary data
3123
3124 if (packType == CdTextItem::CDTEXT_GENRE) {
3125 // The two genre codes may be followed by a string. Adjust 'pos'
3126 // so that all extra 0 bytes at the end of the data are stripped
3127 // off.
3128 for (j = 2; j < pos && buf[j] != 0; j++) ;
3129 if (j < pos)
3130 pos = j + 1;
3131 }
3132
3133 item = new CdTextItem(packType, lastBlockNumber, buf, pos);
3134 toc->addCdTextItem(0, item);
3135
3136 if (packType == CdTextItem::CDTEXT_SIZE_INFO)
3137 sizeInfoItem = item;
3138 }
3139 }
3140
3141 delete[] packs;
3142
3143 // update language mapping from SIZE INFO pack data
3144 if (sizeInfoItem != NULL && sizeInfoItem->dataLen() >= 36) {
3145 const unsigned char *data = sizeInfoItem->data();
3146 for (i = 0; i < 8; i++) {
3147 if (data[28 + i] > 0)
3148 toc->cdTextLanguage(i, data[28 + i]);
3149 else
3150 toc->cdTextLanguage(i, -1);
3151 }
3152 }
3153 else {
3154 log_message(-1, "Cannot determine language mapping from CD-TEXT data.");
3155 log_message(-1, "Using default mapping.");
3156 }
3157
3158 return 0;
3159 }
3160
analyzeDataTrack(TrackData::Mode mode,int trackNr,long startLba,long endLba,long * pregap)3161 int CdrDriver::analyzeDataTrack(TrackData::Mode mode, int trackNr,
3162 long startLba, long endLba, long *pregap)
3163 {
3164 long maxLen = scsiMaxDataLen_ / AUDIO_BLOCK_LEN;
3165 long lba = startLba;
3166 long len = endLba - startLba;
3167 long actLen, n;
3168
3169 *pregap = 0;
3170
3171 while (len > 0) {
3172 n = len > maxLen ? maxLen : len;
3173
3174 if ((actLen = readTrackData(mode, TrackData::SUBCHAN_NONE, lba, n,
3175 transferBuffer_)) < 0) {
3176 log_message(-2, "Analyzing of track %d failed.", trackNr);
3177 return 1;
3178 }
3179
3180 log_message(1, "%s\r", Msf(lba).str());
3181
3182 if (actLen != n) {
3183 //log_message(0, "Data track pre-gap: %ld", len - actLen);
3184 *pregap = len - actLen;
3185
3186 if (*pregap > 300) {
3187 log_message(-1,
3188 "The pre-gap of the following track appears to have length %s.",
3189 Msf(*pregap).str());
3190 log_message(-1, "This value is probably bogus and may be caused by unexpected");
3191 log_message(-1, "behavior of the drive. Try to verify with other tools how");
3192 log_message(-1, "much data can be read from the current track and compare it");
3193 log_message(-1, "to the value stored in the toc-file. Usually, the pre-gap");
3194 log_message(-1, "should have length 00:02:00.");
3195 }
3196
3197 return 0;
3198 }
3199
3200 len -= n;
3201 lba += n;
3202 }
3203
3204 return 0;
3205 }
3206
3207 /* Reads toc and audio data from CD for specified 'session' number.
3208 * The data is written to file 'dataFilename' unless on-the-fly writing
3209 * is active in which case the data is written to the file descriptor
3210 * 'onTheFlyFd'.
3211 * Return: newly created 'Toc' object or 'NULL' if an error occured
3212 */
3213
readDisk(int session,const char * dataFilename)3214 Toc *CdrDriver::readDisk(int session, const char *dataFilename)
3215 {
3216 int padFirstPregap = 1;
3217 int nofTracks = 0;
3218 int i;
3219 CdToc *cdToc = getToc(session, &nofTracks);
3220 //unsigned char trackCtl; // control nibbles of track
3221 //int ctlCheckOk;
3222 TrackInfo *trackInfos;
3223 TrackData::Mode trackMode;
3224 int fp = -1;
3225 char *fname = strdupCC(dataFilename);
3226 Toc *toc = NULL;
3227 int trs = 0;
3228 int tre = 0;
3229 long slba, elba;
3230 ReadDiskInfo info;
3231
3232 if (cdToc == NULL) {
3233 return NULL;
3234 }
3235
3236 if (nofTracks <= 1) {
3237 log_message(-1, "No tracks on disk.");
3238 delete[] cdToc;
3239 return NULL;
3240 }
3241
3242 log_message(1, "");
3243 printCdToc(cdToc, nofTracks);
3244 log_message(1, "");
3245 //return NULL;
3246
3247 nofTracks -= 1; // do not count lead-out
3248
3249 readCapabilities_ = getReadCapabilities(cdToc, nofTracks);
3250
3251 trackInfos = new TrackInfo[nofTracks + 1];
3252
3253 for (i = 0; i < nofTracks; i++) {
3254 if ((cdToc[i].adrCtl & 0x04) != 0) {
3255 if ((trackMode = getTrackMode(i + 1, cdToc[i].start)) ==
3256 TrackData::MODE0) {
3257 log_message(-1, "Cannot determine mode of data track %d - asuming MODE1.",
3258 i + 1);
3259 trackMode = TrackData::MODE1;
3260 }
3261
3262 if (rawDataReading_) {
3263 if (trackMode == TrackData::MODE1) {
3264 trackMode = TrackData::MODE1_RAW;
3265 }
3266 else if (trackMode == TrackData::MODE2_FORM1 ||
3267 trackMode == TrackData::MODE2_FORM2 ||
3268 trackMode == TrackData::MODE2_FORM_MIX) {
3269 trackMode = TrackData::MODE2_RAW;
3270 }
3271 }
3272 else if (mode2Mixed_) {
3273 if (trackMode == TrackData::MODE2_FORM1 ||
3274 trackMode == TrackData::MODE2_FORM2 ||
3275 trackMode == TrackData::MODE2_FORM_MIX) {
3276 trackMode = TrackData::MODE2_FORM_MIX;
3277 }
3278 }
3279 }
3280 else {
3281 trackMode = TrackData::AUDIO;
3282 }
3283
3284 if (!checkSubChanReadCaps(trackMode, readCapabilities_)) {
3285 log_message(-2, "This drive does not support %s sub-channel reading.",
3286 TrackData::subChannelMode2String(subChanReadMode_));
3287 goto fail;
3288 }
3289
3290 trackInfos[i].trackNr = cdToc[i].track;
3291 trackInfos[i].ctl = cdToc[i].adrCtl & 0x0f;
3292 trackInfos[i].mode = trackMode;
3293 trackInfos[i].start = cdToc[i].start;
3294 trackInfos[i].pregap = 0;
3295 trackInfos[i].fill = 0;
3296 trackInfos[i].indexCnt = 0;
3297 trackInfos[i].isrcCode[0] = 0;
3298 trackInfos[i].filename = fname;
3299 trackInfos[i].bytesWritten = 0;
3300 }
3301
3302 // lead-out entry
3303 trackInfos[nofTracks].trackNr = 0xaa;
3304 trackInfos[nofTracks].ctl = 0;
3305 trackInfos[nofTracks].mode = trackInfos[nofTracks - 1].mode;
3306 trackInfos[nofTracks].start = cdToc[nofTracks].start;
3307 if (taoSource()) {
3308 trackInfos[nofTracks].start -= taoSourceAdjust_;
3309 }
3310 trackInfos[nofTracks].pregap = 0;
3311 trackInfos[nofTracks].indexCnt = 0;
3312 trackInfos[nofTracks].isrcCode[0] = 0;
3313 trackInfos[nofTracks].filename = NULL;
3314 trackInfos[nofTracks].bytesWritten = 0;
3315
3316
3317 if (onTheFly_) {
3318 fp = onTheFlyFd_;
3319 }
3320 else {
3321
3322 giveUpRootPrivileges();
3323
3324 #ifdef __CYGWIN__
3325 if ((fp = open(dataFilename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
3326 0666)) < 0)
3327 #else
3328 if ((fp = open(dataFilename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
3329 #endif
3330 {
3331 log_message(-2, "Cannot open \"%s\" for writing: %s", dataFilename,
3332 strerror(errno));
3333 delete[] cdToc;
3334 return NULL;
3335 }
3336 }
3337
3338 info.tracks = nofTracks;
3339 info.startLba = trackInfos[0].start;
3340 info.endLba = trackInfos[nofTracks].start;
3341
3342
3343 while (trs < nofTracks) {
3344 if (trackInfos[trs].mode != TrackData::AUDIO) {
3345 if (trs == 0) {
3346 if (session == 1)
3347 trackInfos[trs].pregap = trackInfos[trs].start;
3348 }
3349 else {
3350 if (taoSource()) {
3351 trackInfos[trs].pregap = 150 + taoSourceAdjust_;
3352 }
3353 else {
3354 if (trackInfos[trs].mode != trackInfos[trs - 1].mode)
3355 trackInfos[trs].pregap = 150;
3356 }
3357 }
3358
3359 slba = trackInfos[trs].start;
3360 elba = trackInfos[trs + 1].start;
3361
3362 if (taoSource()) {
3363 if (trs < nofTracks - 1)
3364 elba -= 150 + taoSourceAdjust_;
3365 }
3366 else {
3367 if (trackInfos[trs].mode != trackInfos[trs + 1].mode) {
3368 elba -= 150;
3369 }
3370 }
3371
3372
3373 log_message(1, "Copying data track %d (%s): start %s, ", trs + 1,
3374 TrackData::mode2String(trackInfos[trs].mode),
3375 Msf(cdToc[trs].start).str());
3376 log_message(1, "length %s to \"%s\"...", Msf(elba - slba).str(),
3377 trackInfos[trs].filename);
3378
3379 if (readDataTrack(&info, fp, slba, elba, &trackInfos[trs]) != 0)
3380 goto fail;
3381
3382 trs++;
3383 }
3384 else {
3385 // find continuous range of audio tracks
3386 tre = trs;
3387 while (tre < nofTracks && trackInfos[tre].mode == TrackData::AUDIO)
3388 tre++;
3389
3390 if (trs == 0) {
3391 if (session == 1)
3392 trackInfos[trs].pregap = trackInfos[trs].start;
3393 }
3394 else {
3395 // previous track must be of different mode so assume a standard
3396 // pre-gap here
3397 if (taoSource()) {
3398 trackInfos[trs].pregap = 150 + taoSourceAdjust_;
3399 }
3400 else {
3401 trackInfos[trs].pregap = 150;
3402 }
3403 }
3404
3405 slba = cdToc[trs].start;
3406 elba = cdToc[tre].start;
3407
3408 // If we have the first track of the first session we can start ripping
3409 // from lba 0 to extract the pre-gap data.
3410 // But only if the drive supports it as indicated by 'options_'.
3411 if (session == 1 && trs == 0 &&
3412 (options_ & OPT_DRV_NO_PREGAP_READ) == 0) {
3413 slba = 0;
3414 }
3415
3416 // Assume that the pre-gap length conforms to the standard if the track
3417 // mode changes.
3418 if (taoSource()) {
3419 if (tre < nofTracks)
3420 elba -= 150 + taoSourceAdjust_;
3421 }
3422 else {
3423 if (trackInfos[tre - 1].mode != trackInfos[tre].mode) {
3424 elba -= 150;
3425 }
3426 }
3427
3428 log_message(1, "Copying audio tracks %d-%d: start %s, ", trs + 1, tre,
3429 Msf(slba).str());
3430 log_message(1, "length %s to \"%s\"...", Msf(elba - slba).str(),
3431 trackInfos[trs].filename);
3432
3433 if (readAudioRange(&info, fp, slba, elba, trs, tre - 1, trackInfos) != 0)
3434 goto fail;
3435
3436 trs = tre;
3437 }
3438 }
3439
3440 // if the drive allows to read audio data from the first track's
3441 // pre-gap the data will be written to the output file and
3442 // 'buildToc()' must not create zero data for the pre-gap
3443 padFirstPregap = 1;
3444
3445 if (session == 1 && (options_ & OPT_DRV_NO_PREGAP_READ) == 0)
3446 padFirstPregap = 0;
3447
3448 toc = buildToc(trackInfos, nofTracks + 1, padFirstPregap);
3449
3450 if (!onTheFly_ && toc != NULL) {
3451 if ((options_ & OPT_DRV_NO_CDTEXT_READ) == 0)
3452 readCdTextData(toc);
3453
3454 if (readCatalog(toc, trackInfos[0].start, trackInfos[nofTracks].start)) {
3455 log_message(2, "Found disk catalogue number.");
3456 }
3457 }
3458
3459 sendReadCdProgressMsg(RCD_EXTRACTING, nofTracks, nofTracks, 1000, 1000);
3460
3461 fail:
3462 delete[] cdToc;
3463 delete[] trackInfos;
3464
3465 delete[] fname;
3466
3467 if (!onTheFly_ && fp >= 0) {
3468 if (close(fp) != 0) {
3469 log_message(-2, "Writing to \"%s\" failed: %s", dataFilename,
3470 strerror(errno));
3471 delete toc;
3472 return NULL;
3473 }
3474 }
3475
3476 return toc;
3477 }
3478
3479
buildToc(TrackInfo * trackInfos,long nofTrackInfos,int padFirstPregap)3480 Toc *CdrDriver::buildToc(TrackInfo *trackInfos, long nofTrackInfos,
3481 int padFirstPregap)
3482 {
3483 long i, j;
3484 long nofTracks = nofTrackInfos - 1;
3485 int foundDataTrack = 0;
3486 int foundAudioTrack = 0;
3487 int foundXATrack = 0;
3488 long modeStartLba = 0; // start LBA for current mode
3489 unsigned long dataLen;
3490 TrackData::Mode trackMode;
3491 TrackData::Mode lastMode = TrackData::MODE0; // illegal in this context
3492 TrackData::SubChannelMode trackSubChanMode;
3493 int newMode;
3494 long byteOffset = 0;
3495
3496 if (nofTrackInfos < 2)
3497 return NULL;
3498
3499 Toc *toc = new Toc;
3500
3501 // build the Toc
3502
3503 for (i = 0; i < nofTracks; i++) {
3504 TrackInfo &ati = trackInfos[i]; // actual track info
3505 TrackInfo &nti = trackInfos[i + 1]; // next track info
3506
3507 newMode = 0;
3508 trackMode = ati.mode;
3509 trackSubChanMode = subChanReadMode_;
3510
3511 switch (trackMode) {
3512 case TrackData::AUDIO:
3513 foundAudioTrack = 1;
3514 break;
3515 case TrackData::MODE1:
3516 case TrackData::MODE1_RAW:
3517 case TrackData::MODE2:
3518 foundDataTrack = 1;
3519 break;
3520 case TrackData::MODE2_RAW:
3521 case TrackData::MODE2_FORM1:
3522 case TrackData::MODE2_FORM2:
3523 case TrackData::MODE2_FORM_MIX:
3524 foundXATrack = 1;
3525 break;
3526 case TrackData::MODE0:
3527 // should not happen
3528 break;
3529 }
3530
3531 if (trackMode != lastMode) {
3532 newMode = 1;
3533 if (i == 0 && !padFirstPregap)
3534 modeStartLba = 0;
3535 else
3536 modeStartLba = ati.start;
3537 lastMode = trackMode;
3538 }
3539
3540 Track t(trackMode, trackSubChanMode);
3541
3542 t.preEmphasis(ati.ctl & 0x01);
3543 t.copyPermitted(ati.ctl & 0x02);
3544 t.audioType(ati.ctl & 0x08);
3545
3546 if (ati.isrcCode[0] != 0)
3547 t.isrc(ati.isrcCode);
3548
3549 if (trackMode == TrackData::AUDIO) {
3550 if (trackSubChanMode == TrackData::SUBCHAN_NONE) {
3551 if (newMode && (i > 0 || padFirstPregap)) {
3552 Msf trackLength(nti.start - ati.start - nti.pregap);
3553 if (ati.pregap > 0) {
3554 t.append(SubTrack(SubTrack::DATA,
3555 TrackData(Msf(ati.pregap).samples())));
3556 }
3557 t.append(SubTrack(SubTrack::DATA,
3558 TrackData(ati.filename, byteOffset,
3559 0, trackLength.samples())));
3560 }
3561 else {
3562 Msf trackLength(nti.start - ati.start - nti.pregap + ati.pregap);
3563 t.append(SubTrack(SubTrack::DATA,
3564 TrackData(ati.filename, byteOffset,
3565 Msf(ati.start - modeStartLba
3566 - ati.pregap).samples(),
3567 trackLength.samples())));
3568 }
3569 }
3570 else {
3571 if (newMode && (i > 0 || padFirstPregap)) {
3572 long trackLength = nti.start - ati.start - nti.pregap;
3573
3574 if (ati.pregap > 0) {
3575 dataLen = ati.pregap * TrackData::dataBlockSize(trackMode,
3576 trackSubChanMode);
3577 t.append(SubTrack(SubTrack::DATA,
3578 TrackData(trackMode, trackSubChanMode,
3579 dataLen)));
3580 }
3581 dataLen = trackLength * TrackData::dataBlockSize(trackMode,
3582 trackSubChanMode);
3583 t.append(SubTrack(SubTrack::DATA,
3584 TrackData(trackMode, trackSubChanMode,
3585 ati.filename, byteOffset, dataLen)));
3586 }
3587 else {
3588 long trackLength = nti.start - ati.start - nti.pregap + ati.pregap;
3589 dataLen = trackLength * TrackData::dataBlockSize(trackMode,
3590 trackSubChanMode);
3591 long offset =
3592 (ati.start - modeStartLba - ati.pregap) *
3593 TrackData::dataBlockSize(trackMode, trackSubChanMode);
3594
3595
3596 t.append(SubTrack(SubTrack::DATA,
3597 TrackData(trackMode, trackSubChanMode,
3598 ati.filename, byteOffset + offset,
3599 dataLen)));
3600 }
3601 }
3602
3603 t.start(Msf(ati.pregap));
3604 }
3605 else {
3606 long trackLength = nti.start - ati.start - nti.pregap - ati.fill;
3607
3608 if (ati.pregap != 0) {
3609 // add zero data for pre-gap
3610 dataLen = ati.pregap * TrackData::dataBlockSize(trackMode,
3611 trackSubChanMode);
3612 t.append(SubTrack(SubTrack::DATA,
3613 TrackData(trackMode, trackSubChanMode, dataLen)));
3614 }
3615
3616 dataLen = trackLength * TrackData::dataBlockSize(trackMode,
3617 trackSubChanMode);
3618 t.append(SubTrack(SubTrack::DATA,
3619 TrackData(trackMode, trackSubChanMode, ati.filename,
3620 byteOffset, dataLen)));
3621
3622 if (ati.fill > 0) {
3623 dataLen = ati.fill * TrackData::dataBlockSize(trackMode,
3624 trackSubChanMode);
3625 t.append(SubTrack(SubTrack::DATA,
3626 TrackData(trackMode, trackSubChanMode, dataLen)));
3627 }
3628
3629 t.start(Msf(ati.pregap));
3630 }
3631
3632 for (j = 0; j < ati.indexCnt; j++)
3633 t.appendIndex(Msf(ati.index[j]));
3634
3635 toc->append(&t);
3636
3637 byteOffset += ati.bytesWritten;
3638 }
3639
3640 if (foundXATrack)
3641 toc->tocType(Toc::CD_ROM_XA);
3642 else if (foundDataTrack)
3643 toc->tocType(Toc::CD_ROM);
3644 else
3645 toc->tocType(Toc::CD_DA);
3646
3647 return toc;
3648 }
3649
3650 // Reads a complete data track.
3651 // start: start of data track from TOC
3652 // end: start of next track from TOC
3653 // trackInfo: info about current track, updated by this function
3654 // Return: 0: OK
3655 // 1: error occured
readDataTrack(ReadDiskInfo * info,int fd,long start,long end,TrackInfo * trackInfo)3656 int CdrDriver::readDataTrack(ReadDiskInfo *info, int fd, long start, long end,
3657 TrackInfo *trackInfo)
3658 {
3659 long len = end - start;
3660 long totalLen = len;
3661 long lba;
3662 long lastLba;
3663 long blockLen = 0;
3664 long blocking;
3665 long burst;
3666 long iterationsWithoutError = 0;
3667 long n, ret;
3668 long act;
3669 int foundLECError;
3670 unsigned char *buf;
3671 TrackData::Mode mode = TrackData::AUDIO;
3672
3673 switch (trackInfo->mode) {
3674 case TrackData::MODE1:
3675 mode = TrackData::MODE1;
3676 blockLen = MODE1_BLOCK_LEN;
3677 break;
3678 case TrackData::MODE1_RAW:
3679 mode = TrackData::MODE1_RAW;
3680 blockLen = AUDIO_BLOCK_LEN;
3681 break;
3682 case TrackData::MODE2:
3683 mode = TrackData::MODE2;
3684 blockLen = MODE2_BLOCK_LEN;
3685 break;
3686 case TrackData::MODE2_RAW:
3687 mode = TrackData::MODE2_RAW;
3688 blockLen = AUDIO_BLOCK_LEN;
3689 break;
3690 case TrackData::MODE2_FORM1:
3691 mode = TrackData::MODE2_FORM1;
3692 blockLen = MODE2_FORM1_DATA_LEN;
3693 break;
3694 case TrackData::MODE2_FORM2:
3695 mode = TrackData::MODE2_FORM2;
3696 blockLen = MODE2_FORM2_DATA_LEN;
3697 break;
3698 case TrackData::MODE2_FORM_MIX:
3699 mode = TrackData::MODE2_FORM_MIX;
3700 blockLen = MODE2_BLOCK_LEN;
3701 break;
3702 case TrackData::MODE0:
3703 case TrackData::AUDIO:
3704 log_message(-3, "CdrDriver::readDataTrack: Illegal mode.");
3705 return 1;
3706 break;
3707 }
3708
3709 blockLen += TrackData::subChannelSize(subChanReadMode_);
3710
3711 // adjust mode in 'trackInfo'
3712 trackInfo->mode = mode;
3713
3714 trackInfo->bytesWritten = 0;
3715
3716 blocking = scsiMaxDataLen_ / (AUDIO_BLOCK_LEN + PW_SUBCHANNEL_LEN);
3717 assert(blocking > 0);
3718
3719 buf = new unsigned char[blocking * blockLen];
3720
3721 lba = lastLba = start;
3722 burst = blocking;
3723
3724 while (len > 0) {
3725 if (burst != blocking && iterationsWithoutError > 2 * blocking)
3726 burst = blocking;
3727
3728 n = (len > burst) ? burst : len;
3729
3730 foundLECError = 0;
3731
3732 if ((act = readTrackData(mode, subChanReadMode_, lba, n, buf)) == -1) {
3733 log_message(-2, "Read error while copying data from track.");
3734 delete[] buf;
3735 return 1;
3736 }
3737
3738 if (act == -2) {
3739 // L-EC error encountered
3740 if (trackInfo->mode == TrackData::MODE1_RAW ||
3741 trackInfo->mode == TrackData::MODE2_RAW) {
3742
3743 if (n > 1) {
3744 // switch to single step mode
3745 iterationsWithoutError = 0;
3746 burst = 1;
3747 continue;
3748 }
3749 else {
3750 foundLECError = 1;
3751 act = n = 0;
3752 }
3753 }
3754 else {
3755 log_message(-2, "L-EC error around sector %ld while copying data from track.", lba);
3756 log_message(-2, "Use option '--read-raw' to ignore L-EC errors.");
3757 delete[] buf;
3758 return 1;
3759 }
3760 }
3761
3762 if (foundLECError) {
3763 iterationsWithoutError = 0;
3764
3765 log_message(2, "Found L-EC error at sector %ld - ignored.", lba);
3766
3767 // create a dummy sector for the sector with L-EC errors
3768 Msf m(lba + 150);
3769
3770 memcpy(buf, syncPattern, 12);
3771 buf[12] = SubChannel::bcd(m.min());
3772 buf[13] = SubChannel::bcd(m.sec());
3773 buf[14] = SubChannel::bcd(m.frac());
3774 if (trackInfo->mode == TrackData::MODE1_RAW)
3775 buf[15] = 1;
3776 else
3777 buf[15] = 2;
3778
3779 memcpy(buf + 16, SECTOR_ERROR_DATA, blockLen - 16);
3780
3781 if ((ret = fullWrite(fd, buf, blockLen)) != blockLen) {
3782 if (ret < 0)
3783 log_message(-2, "Writing of data failed: %s", strerror(errno));
3784 else
3785 log_message(-2, "Writing of data failed: Disk full");
3786
3787 delete[] buf;
3788 return 1;
3789 }
3790
3791 trackInfo->bytesWritten += blockLen;
3792
3793 lba += 1;
3794 len -= 1;
3795 }
3796 else {
3797 iterationsWithoutError++;
3798
3799 if (act > 0) {
3800 if ((ret = fullWrite(fd, buf, blockLen * act)) != blockLen * act) {
3801 if (ret < 0)
3802 log_message(-2, "Writing of data failed: %s", strerror(errno));
3803 else
3804 log_message(-2, "Writing of data failed: Disk full");
3805
3806 delete[] buf;
3807 return 1;
3808 }
3809 }
3810
3811 trackInfo->bytesWritten += blockLen * act;
3812
3813 if (lba > lastLba + 75) {
3814 Msf lbatime(lba);
3815 log_message(1, "%02d:%02d:00\r", lbatime.min(), lbatime.sec());
3816 lastLba = lba;
3817
3818 if (remote_) {
3819 long totalProgress;
3820 long progress;
3821
3822 progress = (totalLen - len) * 1000;
3823 progress /= totalLen;
3824
3825 totalProgress = lba - info->startLba;
3826
3827 if (totalProgress > 0) {
3828 totalProgress *= 1000;
3829 totalProgress /= (info->endLba - info->startLba);
3830 }
3831 else {
3832 totalProgress = 0;
3833 }
3834
3835 sendReadCdProgressMsg(RCD_EXTRACTING, info->tracks,
3836 trackInfo->trackNr, progress, totalProgress);
3837 }
3838 }
3839
3840 lba += act;
3841 len -= act;
3842
3843 if (act != n)
3844 break;
3845 }
3846 }
3847
3848 // pad remaining blocks with zero data, e.g. for disks written in TAO mode
3849
3850 if (len > 0) {
3851 log_message(-1, "Padding with %ld zero sectors.", len);
3852
3853 if (mode == TrackData::MODE1_RAW || mode == TrackData::MODE2_RAW) {
3854 memcpy(buf, syncPattern, 12);
3855
3856 if (mode == TrackData::MODE1_RAW)
3857 buf[15] = 1;
3858 else
3859 buf[15] = 2;
3860
3861 memset(buf + 16, 0, blockLen - 16);
3862 }
3863 else {
3864 memset(buf, 0, blockLen);
3865 }
3866
3867 while (len > 0) {
3868 if (mode == TrackData::MODE1_RAW || mode == TrackData::MODE2_RAW) {
3869 Msf m(lba + 150);
3870
3871 buf[12] = SubChannel::bcd(m.min());
3872 buf[13] = SubChannel::bcd(m.sec());
3873 buf[14] = SubChannel::bcd(m.frac());
3874 }
3875
3876 if ((ret = fullWrite(fd, buf, blockLen)) != blockLen) {
3877 if (ret < 0)
3878 log_message(-2, "Writing of data failed: %s", strerror(errno));
3879 else
3880 log_message(-2, "Writing of data failed: Disk full");
3881
3882 delete[] buf;
3883 return 1;
3884 }
3885
3886 trackInfo->bytesWritten += blockLen;
3887
3888 len--;
3889 lba++;
3890 }
3891 }
3892
3893 delete[] buf;
3894
3895 return 0;
3896 }
3897
3898 // Tries to read the catalog number from the sub-channels starting at LBA 0.
3899 // If a catalog number is found it will be placed into the provided 14 byte
3900 // buffer 'mcnCode'. Otherwise 'mcnCode[0]' is set to 0.
3901 // Return: 0: OK
3902 // 1: SCSI error occured
3903 #define N_ELEM 11
3904 #define MCN_LEN 13
3905 #define MAX_MCN_SCAN_LENGTH 5000
3906
cmpMcn(const void * p1,const void * p2)3907 static int cmpMcn(const void *p1, const void *p2)
3908 {
3909 const char *s1 = (const char *)p1;
3910 const char *s2 = (const char *)p2;
3911
3912 return strcmp(s1, s2);
3913 }
3914
readCatalogScan(char * mcnCode,long startLba,long endLba)3915 int CdrDriver::readCatalogScan(char *mcnCode, long startLba, long endLba)
3916 {
3917
3918 SubChannel **subChannels;
3919 int n, i;
3920 long length;
3921 int mcnCodeFound = 0;
3922 char mcn[N_ELEM][MCN_LEN+1];
3923
3924 *mcnCode = 0;
3925
3926 length = endLba - startLba;
3927
3928 if (length > MAX_MCN_SCAN_LENGTH)
3929 length = MAX_MCN_SCAN_LENGTH;
3930
3931
3932 while ((length > 0) && (mcnCodeFound < N_ELEM)) {
3933 n = (length > maxScannedSubChannels_ ? maxScannedSubChannels_ : length);
3934
3935 if (readSubChannels(TrackData::SUBCHAN_NONE, startLba, n, &subChannels,
3936 NULL) != 0 ||
3937 subChannels == NULL) {
3938 return 1;
3939 }
3940
3941 for (i = 0; i < n; i++) {
3942 SubChannel *chan = subChannels[i];
3943 //chan->print();
3944
3945 if (chan->checkCrc() && chan->checkConsistency()) {
3946 if (chan->type() == SubChannel::QMODE2) {
3947 if (mcnCodeFound < N_ELEM) {
3948 strcpy(mcn[mcnCodeFound++], chan->catalog());
3949 }
3950 }
3951 }
3952 }
3953
3954 length -= n;
3955 startLba += n;
3956 }
3957
3958 if(mcnCodeFound > 0) {
3959 qsort(mcn, mcnCodeFound, MCN_LEN + 1, cmpMcn);
3960 strcpy(mcnCode, mcn[(mcnCodeFound >> 1)]);
3961 }
3962
3963 return 0;
3964 }
3965
3966 #undef N_ELEM
3967 #undef MCN_LEN
3968 #undef MAX_MCN_SCAN_LENGTH
3969
3970
3971 // Sends a read cd progress message without blocking the actual process.
sendReadCdProgressMsg(ReadCdProgressType type,int totalTracks,int track,int trackProgress,int totalProgress)3972 void CdrDriver::sendReadCdProgressMsg(ReadCdProgressType type, int totalTracks,
3973 int track, int trackProgress,
3974 int totalProgress)
3975 {
3976 if (remote_) {
3977 int fd = remoteFd_;
3978 ProgressMsg p;
3979
3980 p.status = type;
3981 p.totalTracks = totalTracks;
3982 p.track = track;
3983 p.trackProgress = trackProgress;
3984 p.totalProgress = totalProgress;
3985 p.bufferFillRate = 0;
3986 p.writerFillRate = 0;
3987
3988 if (write(fd, REMOTE_MSG_SYNC_, sizeof(REMOTE_MSG_SYNC_)) != sizeof(REMOTE_MSG_SYNC_) ||
3989 write(fd, (const char*)&p, sizeof(p)) != sizeof(p)) {
3990 log_message(-1, "Failed to send read CD remote progress message.");
3991 }
3992 }
3993 }
3994
3995 // Sends a write cd progress message without blocking the actual process.
sendWriteCdProgressMsg(WriteCdProgressType type,int totalTracks,int track,int trackProgress,int totalProgress,int bufferFillRate,int writeFill)3996 int CdrDriver::sendWriteCdProgressMsg(WriteCdProgressType type,
3997 int totalTracks, int track,
3998 int trackProgress, int totalProgress,
3999 int bufferFillRate, int writeFill)
4000 {
4001 if (remote_) {
4002 int fd = remoteFd_;
4003 ProgressMsg p;
4004
4005 p.status = type;
4006 p.totalTracks = totalTracks;
4007 p.track = track;
4008 p.trackProgress = trackProgress;
4009 p.totalProgress = totalProgress;
4010 p.bufferFillRate = bufferFillRate;
4011 p.writerFillRate = writeFill;
4012
4013 if (write(fd, REMOTE_MSG_SYNC_, sizeof(REMOTE_MSG_SYNC_)) != sizeof(REMOTE_MSG_SYNC_) ||
4014 write(fd, (const char*)&p, sizeof(p)) != sizeof(p)) {
4015 log_message(-1, "Failed to send write CD remote progress message.");
4016 return 1;
4017 }
4018 }
4019
4020 return 0;
4021 }
4022
4023 // Sends a blank cd progress message without blocking the actual process.
sendBlankCdProgressMsg(int totalProgress)4024 int CdrDriver::sendBlankCdProgressMsg(int totalProgress)
4025 {
4026 if (remote_) {
4027 int fd = remoteFd_;
4028 ProgressMsg p;
4029
4030 p.status = PGSMSG_BLK;
4031 p.totalTracks = 0;
4032 p.track = 0;
4033 p.trackProgress = 0;
4034 p.totalProgress = totalProgress;
4035 p.bufferFillRate = 0;
4036 p.writerFillRate = 0;
4037
4038 if (write(fd, REMOTE_MSG_SYNC_, sizeof(REMOTE_MSG_SYNC_)) != sizeof(REMOTE_MSG_SYNC_) ||
4039 write(fd, (const char*)&p, sizeof(p)) != sizeof(p)) {
4040 log_message(-1, "Failed to send write CD remote progress message.");
4041 return 1;
4042 }
4043 }
4044
4045 return 0;
4046 }
4047
audioRead(TrackData::SubChannelMode sm,int byteOrder,Sample * buffer,long startLba,long len)4048 long CdrDriver::audioRead(TrackData::SubChannelMode sm, int byteOrder,
4049 Sample *buffer, long startLba, long len)
4050 {
4051 SubChannel **chans;
4052 int i;
4053 int swap;
4054 long blockLen = AUDIO_BLOCK_LEN + TrackData::subChannelSize(sm);
4055
4056 if (readSubChannels(sm, startLba, len, &chans, buffer) != 0) {
4057 memset(buffer, 0, len * blockLen);
4058 audioReadError_ = 1;
4059 return len;
4060 }
4061
4062 swap = (audioDataByteOrder_ == byteOrder) ? 0 : 1;
4063
4064 if (options_ & OPT_DRV_SWAP_READ_SAMPLES)
4065 swap = !swap;
4066
4067 if (swap) {
4068 unsigned char *b = (unsigned char*)buffer;
4069
4070 for (i = 0; i < len; i++) {
4071 swapSamples((Sample *)b, SAMPLES_PER_BLOCK);
4072 b += blockLen;
4073 }
4074 }
4075
4076
4077 if (remote_ && startLba > audioReadLastLba_) {
4078 long totalTrackLen = audioReadTrackInfo_[audioReadActTrack_ + 1].start -
4079 audioReadTrackInfo_[audioReadActTrack_ ].start;
4080 long progress = startLba - audioReadTrackInfo_[audioReadActTrack_ ].start;
4081 long totalProgress;
4082
4083 if (progress > 0) {
4084 progress *= 1000;
4085 progress /= totalTrackLen;
4086 }
4087 else {
4088 progress = 0;
4089 }
4090
4091 totalProgress = startLba + len - audioReadInfo_->startLba;
4092
4093 if (totalProgress > 0) {
4094 totalProgress *= 1000;
4095 totalProgress /= audioReadInfo_->endLba - audioReadInfo_->startLba;
4096 }
4097 else {
4098 totalProgress = 0;
4099 }
4100
4101 sendReadCdProgressMsg(RCD_EXTRACTING, audioReadInfo_->tracks,
4102 audioReadActTrack_ + 1, progress, totalProgress);
4103
4104 audioReadLastLba_ = startLba;
4105 }
4106
4107
4108 if (chans == NULL) {
4109 // drive does not provide sub channel data so that's all we could do here:
4110
4111 if (startLba > audioReadTrackInfo_[audioReadActTrack_ + 1].start) {
4112 audioReadActTrack_++;
4113 log_message(1, "Track %d...", audioReadActTrack_ + 1);
4114 }
4115
4116 if (startLba - audioReadProgress_ > 75) {
4117 audioReadProgress_ = startLba;
4118 Msf m(audioReadProgress_);
4119 log_message(1, "%02d:%02d:00\r", m.min(), m.sec());
4120 }
4121
4122 return len;
4123 }
4124
4125 // analyze sub-channels to find pre-gaps, index marks and ISRC codes
4126 for (i = 0; i < len; i++) {
4127 SubChannel *chan = chans[i];
4128 //chan->print();
4129
4130 if (chan->checkCrc() && chan->checkConsistency()) {
4131 if (chan->type() == SubChannel::QMODE1DATA) {
4132 int t = chan->trackNr() - 1;
4133 Msf atime = Msf(chan->amin(), chan->asec(), chan->aframe());
4134
4135 //log_message(0, "LastLba: %ld, ActLba: %ld", audioReadActLba_, atime.lba());
4136
4137 if (t >= audioReadStartTrack_ && t <= audioReadEndTrack_ &&
4138 atime.lba() > audioReadActLba_ &&
4139 atime.lba() - 150 < audioReadTrackInfo_[t + 1].start) {
4140 Msf time(chan->min(), chan->sec(), chan->frame()); // track rel time
4141
4142 audioReadActLba_ = atime.lba();
4143
4144 if (audioReadActLba_ - audioReadProgress_ > 75) {
4145 audioReadProgress_ = audioReadActLba_;
4146 Msf m(audioReadProgress_ - 150);
4147 log_message(1, "%02d:%02d:00\r", m.min(), m.sec());
4148 }
4149
4150 if (t == audioReadActTrack_ &&
4151 chan->indexNr() == audioReadActIndex_ + 1) {
4152
4153 if (chan->indexNr() > 1) {
4154 log_message(2, "Found index %d at: %s", chan->indexNr(),
4155 time.str());
4156
4157 if (audioReadTrackInfo_[t].indexCnt < 98) {
4158 audioReadTrackInfo_[t].index[audioReadTrackInfo_[t].indexCnt] = time.lba();
4159 audioReadTrackInfo_[t].indexCnt += 1;
4160 }
4161 }
4162 }
4163 else if (t == audioReadActTrack_ + 1) {
4164 log_message(1, "Track %d...", t + 1);
4165 //chan->print();
4166 if (chan->indexNr() == 0) {
4167 // don't use time.lba() to calculate pre-gap length; it would
4168 // count one frame too many if the CD counts the pre-gap down
4169 // to 00:00:00 instead of 00:00:01
4170 // Instead, count number of frames until start of Index 01
4171 // See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=102171
4172 // atime starts at 02:00, so subtract it
4173 audioReadTrackInfo_[t].pregap = (startLba + len + 1) - \
4174 (atime.lba() - 150);
4175 log_message(2, "Found pre-gap: %s",
4176 Msf(audioReadTrackInfo_[t].pregap).str());
4177 }
4178 }
4179
4180 audioReadActIndex_ = chan->indexNr();
4181 audioReadActTrack_ = t;
4182 }
4183 }
4184 else if (chan->type() == SubChannel::QMODE3) {
4185 if (audioReadTrackInfo_[audioReadActTrack_].isrcCode[0] == 0) {
4186 log_message(2, "Found ISRC code.");
4187 strcpy(audioReadTrackInfo_[audioReadActTrack_].isrcCode,
4188 chan->isrc());
4189 }
4190 }
4191 }
4192 else {
4193 audioReadCrcCount_++;
4194 }
4195 }
4196
4197 return len;
4198 }
4199
readAudioRangeStream(ReadDiskInfo * info,int fd,long start,long end,int startTrack,int endTrack,TrackInfo * trackInfo)4200 int CdrDriver::readAudioRangeStream(ReadDiskInfo *info, int fd, long start,
4201 long end, int startTrack, int endTrack,
4202 TrackInfo *trackInfo)
4203 {
4204 long startLba = start;
4205 long endLba = end - 1;
4206 long len, ret;
4207 long blocking, blockLen;
4208 long lba = startLba;
4209 unsigned char *buf;
4210
4211 blockLen = AUDIO_BLOCK_LEN + TrackData::subChannelSize(subChanReadMode_);
4212 blocking = scsiMaxDataLen_ / blockLen;
4213 assert(blocking > 0);
4214
4215 buf = new unsigned char[blocking * blockLen];
4216
4217 audioReadInfo_ = info;
4218 audioReadTrackInfo_ = trackInfo;
4219 audioReadStartTrack_ = startTrack;
4220 audioReadEndTrack_ = endTrack;
4221 audioReadLastLba_ = audioReadActLba_ = startLba + 149;
4222 audioReadActTrack_ = startTrack;
4223 audioReadActIndex_ = 1;
4224 audioReadCrcCount_ = 0;
4225 audioReadError_ = 0;
4226 audioReadProgress_ = 0;
4227
4228 len = endLba - startLba + 1;
4229
4230 log_message(1, "Track %d...", startTrack + 1);
4231
4232 trackInfo[endTrack].bytesWritten = 0;
4233
4234 while (len > 0) {
4235 long n = len > blocking ? blocking : len;
4236 long bytesToWrite = n * blockLen;
4237
4238 CdrDriver::audioRead(subChanReadMode_, 1/*big endian byte order*/,
4239 (Sample *)buf, lba, n);
4240
4241 lba += n;
4242
4243 if ((ret = fullWrite(fd, buf, bytesToWrite)) != bytesToWrite) {
4244 if (ret < 0)
4245 log_message(-2, "Writing of data failed: %s", strerror(errno));
4246 else
4247 log_message(-2, "Writing of data failed: Disk full");
4248
4249 delete[] buf;
4250 return 1;
4251 }
4252
4253 trackInfo[endTrack].bytesWritten += bytesToWrite;
4254
4255 len -= n;
4256 }
4257
4258
4259 if (audioReadCrcCount_ != 0)
4260 log_message(2, "Found %ld Q sub-channels with CRC errors.", audioReadCrcCount_);
4261
4262 delete[] buf;
4263 return 0;
4264 }
4265
4266
4267 // read cdda paranoia related:
4268
paranoiaMode(int mode)4269 void CdrDriver::paranoiaMode(int mode)
4270 {
4271 paranoiaMode_ = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;
4272
4273 switch (mode) {
4274 case 0:
4275 paranoiaMode_ = PARANOIA_MODE_DISABLE;
4276 break;
4277
4278 case 1:
4279 paranoiaMode_ |= PARANOIA_MODE_OVERLAP;
4280 paranoiaMode_ &= ~PARANOIA_MODE_VERIFY;
4281 break;
4282
4283 case 2:
4284 paranoiaMode_ &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);
4285 break;
4286 }
4287 }
4288
4289
readAudioRangeParanoia(ReadDiskInfo * info,int fd,long start,long end,int startTrack,int endTrack,TrackInfo * trackInfo)4290 int CdrDriver::readAudioRangeParanoia(ReadDiskInfo *info, int fd, long start,
4291 long end, int startTrack, int endTrack,
4292 TrackInfo *trackInfo)
4293 {
4294 long startLba = start;
4295 long endLba = end - 1;
4296 long len, ret;
4297 size16 *buf;
4298
4299 if (paranoia_ == NULL) {
4300 // first time -> allocate paranoia structure
4301 paranoiaDrive_ = new cdrom_drive;
4302 paranoiaDrive_->cdr = this;
4303 paranoiaDrive_->nsectors = maxScannedSubChannels_;
4304 paranoia_ = paranoia_init(paranoiaDrive_);
4305 }
4306
4307 paranoia_set_range(paranoia_, startLba, endLba);
4308 paranoia_modeset(paranoia_, paranoiaMode_);
4309
4310 audioReadInfo_ = info;
4311 audioReadTrackInfo_ = trackInfo;
4312 audioReadStartTrack_ = startTrack;
4313 audioReadEndTrack_ = endTrack;
4314 audioReadLastLba_ = audioReadActLba_ = startLba + 149;
4315 audioReadActTrack_ = startTrack;
4316 audioReadActIndex_ = 1;
4317 audioReadCrcCount_ = 0;
4318 audioReadError_ = 0;
4319 audioReadProgress_ = 0;
4320
4321 len = endLba - startLba + 1;
4322
4323 log_message(1, "Track %d...", startTrack + 1);
4324
4325 trackInfo[endTrack].bytesWritten = 0;
4326
4327 while (len > 0) {
4328 buf = paranoia_read(paranoia_, &CdrDriver::paranoiaCallback);
4329
4330 // The returned samples are always in host byte order. We want to
4331 // output in big endian byte order so swap if we are a little
4332 // endian host.
4333 if (hostByteOrder_ == 0)
4334 swapSamples((Sample*)buf, SAMPLES_PER_BLOCK);
4335
4336 if ((ret = fullWrite(fd, buf, AUDIO_BLOCK_LEN)) != AUDIO_BLOCK_LEN) {
4337 if (ret < 0)
4338 log_message(-2, "Writing of data failed: %s", strerror(errno));
4339 else
4340 log_message(-2, "Writing of data failed: Disk full");
4341
4342 return 1;
4343 }
4344
4345 trackInfo[endTrack].bytesWritten += AUDIO_BLOCK_LEN;
4346
4347 len--;
4348 }
4349
4350
4351 if (audioReadCrcCount_ != 0)
4352 log_message(2, "Found %ld Q sub-channels with CRC errors.", audioReadCrcCount_);
4353
4354 return 0;
4355 }
4356
4357
cdda_read(cdrom_drive * d,void * buffer,long beginsector,long sectors)4358 long cdda_read(cdrom_drive *d, void *buffer, long beginsector, long sectors)
4359 {
4360 CdrDriver *cdr = (CdrDriver*)d->cdr;
4361
4362 return cdr->audioRead(TrackData::SUBCHAN_NONE, cdr->hostByteOrder(),
4363 (Sample*)buffer, beginsector, sectors);
4364 }
4365
paranoiaCallback(long,int)4366 void CdrDriver::paranoiaCallback(long, int)
4367 {
4368 }
4369