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