1 /* @(#)subchan.c 1.29 17/07/17 Copyright 2000-2017 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)subchan.c 1.29 17/07/17 Copyright 2000-2017 J. Schilling";
6 #endif
7 /*
8 * Subchannel processing
9 *
10 * Copyright (c) 2000-2017 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/mconfig.h>
27 #include <schily/stdio.h>
28 #include <schily/unistd.h>
29 #include <schily/standard.h>
30 #include <schily/utypes.h>
31 #include <schily/schily.h>
32 #include <schily/nlsdefs.h>
33
34 #include <scg/scsitransp.h>
35
36 #include "cdrecord.h"
37 #include "crc16.h"
38
39 EXPORT int do_leadin __PR((track_t *trackp));
40 EXPORT int write_leadin __PR((SCSI *scgp, cdr_t *dp, track_t *trackp, int leadinstart));
41 EXPORT int write_leadout __PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
42 EXPORT void fillsubch __PR((track_t *trackp, Uchar *sp, int secno, int nsecs));
43 EXPORT void filltpoint __PR((Uchar *sub, int ctrl_adr, int point, msf_t *mp));
44 EXPORT void fillttime __PR((Uchar *sub, msf_t *mp));
45 LOCAL void filldsubq __PR((Uchar *sub, int ca, int t, int i, msf_t *mrp, msf_t *mp));
46 LOCAL void fillmcn __PR((Uchar *sub, Uchar *mcn));
47 LOCAL void fillisrc __PR((Uchar *sub, Uchar *isrc));
48 LOCAL int ascii2q __PR((int c));
49 LOCAL void qpto16 __PR((Uchar *sub, Uchar *subq, int dop));
50 EXPORT void qpto96 __PR((Uchar *sub, Uchar *subq, int dop));
51 EXPORT void addrw __PR((Uchar *sub, Uchar *subrwptr));
52 EXPORT void qwto16 __PR((Uchar *subq, Uchar *subptr));
53 EXPORT void subrecodesecs __PR((track_t *trackp, Uchar *bp, int address, int nsecs));
54 #ifdef DO_SUBINTERLEAVE
55 LOCAL void subinterleave __PR((Uchar *sub));
56 #endif
57
58 /*#define TEST_CRC*/
59 #ifdef TEST_CRC
60 LOCAL void testcrc __PR((void));
61 #endif
62
63 /*Die 96 Bits == 12 Bytes haben folgendes Aussehen:*/
64
65 struct q {
66 Uchar ctrl_adr; /* 0 (ctrl << 4) | adr */
67 Uchar track; /* 1 current track # */
68 Uchar index; /* 2 current index # */
69 Uchar pmin; /* 3 Relative time minutes part */
70 Uchar psec; /* 4 Relative time seconds part */
71 Uchar pframe; /* 5 Relative time frames part */
72 Uchar zero; /* 6 */
73 Uchar amin; /* 7 Absolute time minutes part */
74 Uchar asec; /* 8 Absolute time seconds part */
75 Uchar aframe; /* 9 Absolute time frames part */
76 Uchar crc1; /* 10 all bits inverted. Polynom is */
77 Uchar crc2; /* 11 X^16 + X^12 + X^5 + 1 */
78 };
79
80 EXPORT Uchar _subq[110][12];
81 EXPORT int _nsubh;
82
83 extern int lverbose;
84 extern int xdebug;
85
86 /*
87 * Prepare master sunchannel data for RAW TOC.
88 */
89 EXPORT int
do_leadin(trackp)90 do_leadin(trackp)
91 track_t *trackp;
92 {
93 int tracks = trackp->tracks;
94 msf_t m;
95 int ctrl;
96 int i;
97 int toctype = trackp[0].tracktype & TOC_MASK;
98
99 if (_nsubh) {
100 if (xdebug)
101 printf(_("Using CLONE TOC....\n"));
102 return (0);
103 }
104 if (xdebug)
105 printf(_("Leadin TOC Type: %d\n"), trackp[0].tracktype & TOC_MASK);
106 if (lverbose > 1) {
107 for (i = 1; i <= tracks+1; i++)
108 printf(_("Track %d start %ld\n"), i, trackp[i].trackstart);
109 }
110
111 #ifdef TEST_CRC
112 testcrc();
113 /* exit(1);*/
114 #endif
115
116 fillbytes(_subq, sizeof (_subq), '\0');
117
118 /*
119 * Fill in point 0xA0 for first track # on disk
120 */
121 ctrl = (st2mode[trackp[0].sectype & ST_MASK]) << 4;
122 if (is_copy(&trackp[0]))
123 ctrl |= TM_ALLOW_COPY << 4;
124 m.msf_min = trackp[1].trackno;
125 /*
126 * Disk Type: 0 = AUDIO/DATA, 0x10 = CDI, 0x20 = XA mode 2
127 */
128 m.msf_sec = toc2sess[toctype & TOC_MASK];
129 m.msf_sec = from_bcd(m.msf_sec); /* convert to BCD */
130 m.msf_frame = 0;
131 filltpoint(_subq[0], ctrl|0x01, 0xA0, &m);
132 if (lverbose > 1)
133 scg_prbytes("", _subq[0], 12);
134
135 /*
136 * Fill in point 0xA1 for last track # on disk
137 */
138 ctrl = (st2mode[trackp[tracks].sectype & ST_MASK]) << 4;
139 if (is_copy(&trackp[tracks]))
140 ctrl |= TM_ALLOW_COPY << 4;
141 m.msf_min = trackp[tracks].trackno;
142 m.msf_sec = 0;
143 m.msf_frame = 0;
144 filltpoint(_subq[1], ctrl|0x01, 0xA1, &m);
145 if (lverbose > 1)
146 scg_prbytes("", _subq[1], 12);
147
148 /*
149 * Fill in point 0xA2 for lead out start time on disk
150 */
151 lba_to_msf(trackp[tracks+1].trackstart, &m);
152 ctrl = (st2mode[trackp[tracks].sectype & ST_MASK]) << 4;
153 if (is_copy(&trackp[tracks]))
154 ctrl |= TM_ALLOW_COPY << 4;
155 filltpoint(_subq[2], ctrl|0x01, 0xA2, &m);
156 if (lverbose > 1)
157 scg_prbytes("", _subq[2], 12);
158
159 /*
160 * Fill in track start times.
161 */
162 for (i = 1; i <= tracks; i++) {
163 lba_to_msf(trackp[i].trackstart, &m);
164 ctrl = (st2mode[trackp[i].sectype & ST_MASK]) << 4;
165 if (is_copy(&trackp[i]))
166 ctrl |= TM_ALLOW_COPY << 4;
167 filltpoint(_subq[i-1+3], ctrl|0x01, to_bcd(trackp[i].trackno), &m); /* track n */
168 if (lverbose > 1)
169 scg_prbytes("", _subq[i-1+3], 12);
170 }
171 return (0);
172 }
173
174 /*
175 * Write TOC (lead-in)
176 *
177 * Use previously prepared master subchannel data to create the
178 * subchannel frames for the lead-in.
179 */
180 EXPORT int
write_leadin(scgp,dp,trackp,leadinstart)181 write_leadin(scgp, dp, trackp, leadinstart)
182 SCSI *scgp;
183 cdr_t *dp;
184 track_t *trackp;
185 int leadinstart;
186 {
187 msf_t m;
188 int i;
189 Uint j;
190 Uchar *bp = scgp->bufptr;
191 Uchar *subp;
192 Uchar *sp;
193 int secsize;
194 int secspt;
195 int bytespt;
196 long amount;
197 int startsec;
198 long bytes = 0L;
199 int textoff = 0;
200 msf_t msf;
201
202 secsize = trackp[0].secsize;
203 secspt = trackp[0].secspt;
204 bytespt = secspt * secsize;
205
206 lba_to_msf(leadinstart, &msf);
207
208 fillbytes(bp, bytespt, '\0');
209
210 if (_nsubh) {
211 if (xdebug)
212 printf(_("Using CLONE LEADIN\n"));
213 }
214 if (xdebug) {
215 printf(_("Leadinstart: %d %d:%d/%d"),
216 leadinstart,
217 msf.msf_min, msf.msf_sec, msf.msf_frame);
218 printf(_(" FLAGS: 0x%X sect: %X RAW16:%d secs: %d spt: %d\n"),
219 trackp[0].flags, trackp[0].sectype,
220 is_raw16(&trackp[0]), secsize, secspt);
221 }
222
223 startsec = leadinstart;
224 sp = bp;
225 subp = bp + 2352;
226 for (i = leadinstart, j = 0; i < -150; i++, j++) {
227 /*
228 * TOC hat folgende unterschiedliche Sub Q Frames:
229 * A0 First Track
230 * A1 Last Track
231 * A3 Lead out start
232 * 1..99 Tracks
233 * == 3 + N* tracks
234 * Jeder Frame wird 3x wiederholt.
235 */
236 if (_nsubh) {
237 if (j >= (3*_nsubh))
238 j = 0;
239 } else {
240 if (j >= (3*3 + 3*trackp->tracks))
241 j = 0;
242 }
243 lba_to_msf((long)i, &m);
244 fillttime(_subq[j/3], &m);
245 fillcrc(_subq[j/3], 12);
246 if (xdebug > 2)
247 scg_prbytes("", _subq[j/3], 12);
248 if (is_raw16(&trackp[0])) {
249 qpto16(subp, _subq[j/3], 0);
250 } else {
251 extern Uchar *textsub;
252 extern int textlen;
253
254 qpto96(subp, _subq[j/3], 0);
255 if (textsub) {
256 addrw(subp, &textsub[textoff]);
257 textoff += 96;
258 if (textoff >= textlen)
259 textoff = 0;
260 }
261 #ifdef DO_SUBINTERLEAVE
262 /* if (is_raw96p(&trackp[0]))*/
263 /* subinterleave(subp);*/
264 #endif
265 }
266 if ((startsec+secspt-1) == i || i == -151) {
267 if ((i-startsec+1) < secspt) {
268 secspt = i-startsec+1;
269 bytespt = secspt * secsize;
270 }
271 encsectors(trackp, bp, startsec, secspt);
272
273 amount = write_secs(scgp, dp,
274 (char *)bp, startsec, bytespt, secspt, FALSE);
275 if (amount < 0) {
276 printf(_("write leadin data: error after %ld bytes\n"),
277 bytes);
278 return (-1);
279 }
280 bytes += amount;
281 startsec = i+1;
282 sp = bp;
283 subp = bp + 2352;
284 continue;
285 }
286 sp += secsize;
287 subp += secsize;
288 }
289 return (0);
290 }
291
292 /*
293 * Write Track 0xAA (lead-out)
294 */
295 EXPORT int
write_leadout(scgp,dp,trackp)296 write_leadout(scgp, dp, trackp)
297 SCSI *scgp;
298 cdr_t *dp;
299 track_t *trackp;
300 {
301 int tracks = trackp->tracks;
302 msf_t m;
303 msf_t mr;
304 int ctrl;
305 int i;
306 int j;
307 Uchar *bp = scgp->bufptr;
308 Uchar *subp;
309 Uchar *sp;
310 int secsize;
311 int secspt;
312 int bytespt;
313 long amount;
314 long startsec;
315 long endsec;
316 long bytes = 0L;
317 int leadoutstart;
318 Uchar sub[12];
319 BOOL p;
320 msf_t msf;
321
322 fillbytes(sub, 12, '\0');
323
324 secsize = trackp[tracks+1].secsize;
325 secspt = trackp[tracks+1].secspt;
326 bytespt = secspt * secsize;
327
328 leadoutstart = trackp[tracks+1].trackstart;
329 lba_to_msf(leadoutstart, &msf);
330
331 fillbytes(bp, bytespt, '\0');
332
333 if (xdebug) {
334 printf(_("Leadoutstart: %d %d:%d/%d amt %ld"),
335 leadoutstart,
336 msf.msf_min, msf.msf_sec, msf.msf_frame,
337 trackp[tracks+1].tracksecs);
338 printf(_(" FLAGS: 0x%X sect: %X RAW16:%d secs: %d spt: %d\n"),
339 trackp[tracks+1].flags, trackp[tracks+1].sectype,
340 is_raw16(&trackp[tracks+1]), secsize, secspt);
341 }
342
343 startsec = leadoutstart;
344 endsec = startsec + trackp[tracks+1].tracksecs;
345 sp = bp;
346 subp = bp + 2352;
347 ctrl = (st2mode[trackp->sectype & ST_MASK]) << 4;
348 if (is_copy(trackp))
349 ctrl |= TM_ALLOW_COPY << 4;
350
351 for (i = leadoutstart, j = 0; i < endsec; i++, j++) {
352
353 lba_to_msf((long)i, &m);
354 sec_to_msf((long)j, &mr);
355 filldsubq(sub, ctrl|0x01, 0xAA, 1, &mr, &m);
356 sub[1] = 0xAA;
357 fillcrc(sub, 12);
358 p = (j % 150) < 75;
359 if (j < 150)
360 p = FALSE;
361 if (xdebug > 2)
362 scg_prbytes(p?"P":" ", sub, 12);
363
364 if (is_raw16(&trackp[0])) {
365 qpto16(subp, sub, p);
366 } else {
367 qpto96(subp, sub, p);
368 #ifdef DO_SUBINTERLEAVE
369 /* if (is_raw96p(&trackp[0]))*/
370 /* subinterleave(subp);*/
371 #endif
372 }
373 if ((startsec+secspt-1) == i || i == (endsec-1)) {
374 if ((i-startsec+1) < secspt) {
375 secspt = i-startsec+1;
376 bytespt = secspt * secsize;
377 }
378 encsectors(trackp, bp, startsec, secspt);
379
380 amount = write_secs(scgp, dp,
381 (char *)bp, startsec, bytespt, secspt, FALSE);
382 if (amount < 0) {
383 printf(_("write leadout data: error after %ld bytes\n"),
384 bytes);
385 return (-1);
386 }
387 bytes += amount;
388 startsec = i+1;
389 sp = bp;
390 subp = bp + 2352;
391 continue;
392 }
393 sp += secsize;
394 subp += secsize;
395 }
396 return (0);
397 }
398
399 /*
400 * Fill in subchannel data.
401 *
402 * This function is used to prepare the sub channels when writing
403 * the data part of a CD (bewteen lead-in and lead-out).
404 */
405 EXPORT void
fillsubch(trackp,sp,secno,nsecs)406 fillsubch(trackp, sp, secno, nsecs)
407 track_t *trackp;
408 Uchar *sp; /* Sector data pointer */
409 int secno; /* Starting sector # */
410 int nsecs; /* # of sectors to fill */
411 {
412 msf_t m;
413 msf_t mr;
414 int ctrl;
415 int i;
416 int rsecno;
417 int end;
418 int secsize = trackp->secsize;
419 int trackno = trackp->trackno;
420 int nindex = trackp->nindex;
421 int curindex;
422 long *tindex = NULL;
423 long nextindex = 0L;
424 Uchar sub[12];
425 Uchar *sup;
426 char *mcn;
427 /*
428 * In theory this should make fillsubch() non-reenrtrant but it seems
429 * that the probability check at the beginning of the function is
430 * sufficient to make it work as expected.
431 */
432 static long nextmcn = -1000000L;
433 static long nextisrc = -1000000L;
434 static Uchar lastindex = 255;
435
436 if (trackno == 0 && is_hidden(trackp))
437 trackno = trackp[1].trackno;
438
439 fillbytes(sub, 12, '\0');
440
441 mcn = track_base(trackp)->isrc;
442 rsecno = secno - trackp->trackstart;
443 if ((secno + nsecs) > (trackp->trackstart + trackp->tracksecs)) {
444 comerrno(EX_BAD,
445 _("Implementation botch: track boundary in buffer.\n"));
446 }
447 sup = sp + 2352;
448 if (mcn && (nextmcn < secno || nextmcn > (secno+100))) {
449 nextmcn = secno/100*100 + 99;
450 }
451 if (trackp->isrc && (nextisrc < secno || nextisrc > (secno+100))) {
452 nextisrc = secno/100*100 + 49;
453 }
454 ctrl = (st2mode[trackp->sectype & ST_MASK]) << 4;
455 if (is_copy(trackp))
456 ctrl |= TM_ALLOW_COPY << 4;
457
458 #ifdef SUB_DEBUG
459 error("Tracknl %d nindex %d trackstart %ld rsecno %d index0start %ld nsecs %d\n",
460 trackno, nindex, trackp->trackstart, rsecno, trackp->index0start, nsecs);
461 #endif
462
463 if (rsecno < 0) {
464 /*
465 * Called to manually write pregap null data into the pregap
466 * while 'trackp' points to the curent track. For this reason,
467 * the sectors are before the start of track 'n' index 0.
468 */
469 curindex = 0;
470 end = trackp->trackstart;
471
472 } else if (rsecno > trackp->index0start) {
473 /*
474 * This track contains pregap of next track.
475 * We currently are inside this pregap.
476 */
477 trackno++;
478 curindex = 0;
479 end = trackp->trackstart + trackp->tracksecs;
480 } else {
481 /*
482 * We are inside the normal data part of this track.
483 * This is index_1...index_m for track n.
484 * Set 'end' to 0 in this case although it is only used
485 * if 'index' is 0. But GCC gives a warning that 'end'
486 * might be uninitialized.
487 */
488 end = 0;
489 curindex = 1;
490 if (nindex > 1) {
491 tindex = trackp->tindex;
492 nextindex = trackp->tracksecs;
493 /*
494 * find current index in list
495 */
496 for (curindex = nindex; curindex >= 1; curindex--) {
497 if (rsecno >= tindex[curindex]) {
498 if (curindex < nindex)
499 nextindex = tindex[curindex+1];
500 break;
501 }
502 }
503 }
504 }
505
506 for (i = 0; i < nsecs; i++) {
507
508 if (tindex != NULL && rsecno >= nextindex) {
509 /*
510 * Skip to next index in list.
511 */
512 if (curindex < nindex) {
513 curindex++;
514 nextindex = tindex[curindex+1];
515 }
516 }
517 if (rsecno == trackp->index0start) {
518 /*
519 * This track contains pregap of next track.
520 */
521 trackno++;
522 curindex = 0;
523 end = trackp->trackstart + trackp->tracksecs;
524 }
525 lba_to_msf((long)secno, &m);
526 if (curindex == 0)
527 sec_to_msf((long)end-1 - secno, &mr);
528 else
529 sec_to_msf((long)rsecno, &mr);
530 if (is_scms(trackp)) {
531 if ((secno % 8) <= 3) {
532 ctrl &= ~(TM_ALLOW_COPY << 4);
533 } else {
534 ctrl |= TM_ALLOW_COPY << 4;
535 }
536 }
537 filldsubq(sub, ctrl|0x01, trackno, curindex, &mr, &m);
538 if (mcn && (secno == nextmcn)) {
539 if (curindex == lastindex) {
540 fillmcn(sub, (Uchar *)mcn);
541 nextmcn = (secno+1)/100*100 + 99;
542 } else {
543 nextmcn++;
544 }
545 }
546 if (trackp->isrc && (secno == nextisrc)) {
547 if (curindex == lastindex) {
548 fillisrc(sub, (Uchar *)trackp->isrc);
549 nextisrc = (secno+1)/100*100 + 49;
550 } else {
551 nextisrc++;
552 }
553 }
554 fillcrc(sub, 12);
555 if (xdebug > 2)
556 scg_prbytes(curindex == 0 ? "P":" ", sub, 12);
557 if (is_raw16(trackp)) {
558 qpto16(sup, sub, curindex == 0);
559 } else {
560 qpto96(sup, sub, curindex == 0);
561 #ifdef DO_SUBINTERLEAVE
562 /* if (is_raw96p(trackp))*/
563 /* subinterleave(sup);*/
564 #endif
565 }
566 lastindex = curindex;
567 secno++;
568 rsecno++;
569 sup += secsize;
570 }
571 }
572
573
574 /*
575 * Fill TOC Point
576 * Ax Werte einf�llen.
577 */
578 EXPORT void
filltpoint(sub,ctrl_adr,point,mp)579 filltpoint(sub, ctrl_adr, point, mp)
580 Uchar *sub;
581 int ctrl_adr;
582 int point;
583 msf_t *mp;
584 {
585 sub[0] = ctrl_adr;
586 sub[2] = point;
587 sub[7] = to_bcd(mp->msf_min);
588 sub[8] = to_bcd(mp->msf_sec);
589 sub[9] = to_bcd(mp->msf_frame);
590 }
591
592 /*
593 * Fill TOC time
594 * Aktuelle Zeit in TOC Sub-Q einf�llen.
595 */
596 EXPORT void
fillttime(sub,mp)597 fillttime(sub, mp)
598 Uchar *sub;
599 msf_t *mp;
600 {
601 sub[3] = to_bcd(mp->msf_min);
602 sub[4] = to_bcd(mp->msf_sec);
603 sub[5] = to_bcd(mp->msf_frame);
604 }
605
606 /*
607 * Q-Sub in Datenbereich f�llen.
608 */
609 LOCAL void
filldsubq(sub,ca,t,i,mrp,mp)610 filldsubq(sub, ca, t, i, mrp, mp)
611 Uchar *sub;
612 int ca; /* Control/Addr */
613 int t; /* Track */
614 int i; /* Index */
615 msf_t *mrp; /* Relative time*/
616 msf_t *mp; /* Absolute time*/
617 {
618 sub[0] = ca;
619 sub[1] = to_bcd(t);
620 sub[2] = to_bcd(i);
621 sub[3] = to_bcd(mrp->msf_min);
622 sub[4] = to_bcd(mrp->msf_sec);
623 sub[5] = to_bcd(mrp->msf_frame);
624
625 sub[7] = to_bcd(mp->msf_min);
626 sub[8] = to_bcd(mp->msf_sec);
627 sub[9] = to_bcd(mp->msf_frame);
628 }
629
630 /*
631 * Fill MCN
632 * MCN konvertieren und in Sub-Q einf�llen.
633 */
634 LOCAL void
fillmcn(sub,mcn)635 fillmcn(sub, mcn)
636 Uchar *sub;
637 Uchar *mcn;
638 {
639 register int i;
640 register int c;
641
642 sub[0] = ADR_MCN;
643 for (i = 1; i <= 8; i++) {
644 c = *mcn++;
645 if (c >= '0' && c <= '9')
646 sub[i] = (c - '0') << 4;
647 else
648 sub[i] = 0;
649
650 if (c != '\0')
651 c = *mcn++;
652 if (c >= '0' && c <= '9')
653 sub[i] |= (c - '0');
654
655 if (c == '\0') {
656 i++;
657 break;
658 }
659 }
660 for (; i <= 8; i++)
661 sub[i] = '\0';
662 }
663
664 /*
665 * Fill ISRC
666 * ISRC konvertieren und in Sub-Q einf�llen.
667 */
668 LOCAL void
fillisrc(sub,isrc)669 fillisrc(sub, isrc)
670 Uchar *sub;
671 Uchar *isrc;
672 {
673 register int i;
674 register int j;
675 Uchar tmp[13];
676 Uchar *sp;
677
678 sub[0] = ADR_ISRC;
679 sp = &sub[1];
680
681 /*
682 * Convert into Sub-Q character coding
683 */
684 for (i = 0, j = 0; i < 12; i++) {
685 if (isrc[i+j] == '-')
686 j++;
687 if (isrc[i+j] == '\0')
688 break;
689 tmp[i] = ascii2q(isrc[i+j]);
690 }
691 for (; i < 13; i++)
692 tmp[i] = '\0';
693
694 /*
695 * The first 5 chars from e.g. "FI-BAR-99-00312"
696 */
697 sp[0] = tmp[0] << 2;
698 sp[0] |= (tmp[1] >> 4) & 0x03;
699 sp[1] = (tmp[1] << 4) & 0xF0;
700 sp[1] |= (tmp[2] >> 2) & 0x0F;
701 sp[2] = (tmp[2] << 6) & 0xC0;
702 sp[2] |= tmp[3] & 0x3F;
703 sp[3] = tmp[4] << 2;
704
705 /*
706 * Now 7 digits from e.g. "FI-BAR-99-00312"
707 */
708 for (i = 4, j = 5; i < 8; i++) {
709 sp[i] = tmp[j++] << 4;
710 sp[i] |= tmp[j++];
711 }
712 }
713
714 /*
715 * ASCII -> Sub-Q ISRC code conversion
716 */
717 LOCAL int
ascii2q(c)718 ascii2q(c)
719 int c;
720 {
721 if (c >= '0' && c <= '9')
722 return (c - '0');
723 else if (c >= '@' && c <= 'o')
724 return (0x10 + c - '@');
725 return (0);
726 }
727
728 /*
729 * Q-Sub auf 16 Bytes bl�hen und P-Sub addieren
730 *
731 * OUT: sub, IN: subqptr
732 */
733 LOCAL void
qpto16(sub,subqptr,dop)734 qpto16(sub, subqptr, dop)
735 Uchar *sub;
736 Uchar *subqptr;
737 int dop;
738 {
739 if (sub != subqptr)
740 movebytes(subqptr, sub, 12);
741 sub[12] = '\0';
742 sub[13] = '\0';
743 sub[14] = '\0';
744 sub[15] = '\0';
745 if (dop)
746 sub[15] |= 0x80;
747
748 }
749
750 /*
751 * Q-Sub auf 96 Bytes bl�hen und P-Sub addieren
752 *
753 * OUT: sub, IN: subqptr
754 */
755 EXPORT void
qpto96(sub,subqptr,dop)756 qpto96(sub, subqptr, dop)
757 Uchar *sub;
758 Uchar *subqptr;
759 int dop;
760 {
761 Uchar tmp[16];
762 Uchar *p;
763 int c;
764 int i;
765
766 if (subqptr == sub) {
767 /*
768 * Remember 12 byte subchannel data if subchannel
769 * is overlapping.
770 */
771 movebytes(subqptr, tmp, 12);
772 subqptr = tmp;
773 }
774 /*
775 * Clear all subchannel bits in the 96 byte target space.
776 */
777 fillbytes(sub, 96, '\0');
778
779 /* BEGIN CSTYLED */
780 if (dop) for (i = 0, p = sub; i < 96; i++) {
781 *p++ |= 0x80;
782 }
783 for (i = 0, p = sub; i < 12; i++) {
784 c = subqptr[i] & 0xFF;
785 /*printf("%02X\n", c);*/
786 if (c & 0x80)
787 *p++ |= 0x40;
788 else
789 p++;
790 if (c & 0x40)
791 *p++ |= 0x40;
792 else
793 p++;
794 if (c & 0x20)
795 *p++ |= 0x40;
796 else
797 p++;
798 if (c & 0x10)
799 *p++ |= 0x40;
800 else
801 p++;
802 if (c & 0x08)
803 *p++ |= 0x40;
804 else
805 p++;
806 if (c & 0x04)
807 *p++ |= 0x40;
808 else
809 p++;
810 if (c & 0x02)
811 *p++ |= 0x40;
812 else
813 p++;
814 if (c & 0x01)
815 *p++ |= 0x40;
816 else
817 p++;
818 }
819 }
820
821 /*
822 * Add R-W-Sub (96 Bytes) to P-Q-Sub (96 Bytes)
823 *
824 * OUT: sub, IN: subrwptr
825 */
826 EXPORT void
addrw(sub,subrwptr)827 addrw(sub, subrwptr)
828 register Uchar *sub;
829 register Uchar *subrwptr;
830 {
831 register int i;
832
833 #define DO8(a) a; a; a; a; a; a; a; a;
834
835 for (i = 0; i < 12; i++) {
836 DO8(*sub++ |= *subrwptr++ & 0x3F);
837 }
838 }
839
840 /*
841 * Q-W-Sub (96 Bytes) auf 16 Bytes schrumpfen
842 *
843 * OUT: subq, IN: subptr
844 */
845 EXPORT void
qwto16(subq,subptr)846 qwto16(subq, subptr)
847 Uchar *subq;
848 Uchar *subptr;
849 {
850 register int i;
851 register int np = 0;
852 register Uchar *p;
853 Uchar tmp[96];
854
855 p = subptr;
856 for (i = 0; i < 96; i++)
857 if (*p++ & 0x80)
858 np++;
859 p = subptr;
860 if (subptr == subq) {
861 /*
862 * Remember 96 byte subchannel data if subchannel
863 * is overlapping.
864 */
865 movebytes(subptr, tmp, 96);
866 p = tmp;
867 }
868
869 for (i = 0; i < 12; i++) {
870 subq[i] = 0;
871 if (*p++ & 0x40)
872 subq[i] |= 0x80;
873 if (*p++ & 0x40)
874 subq[i] |= 0x40;
875 if (*p++ & 0x40)
876 subq[i] |= 0x20;
877 if (*p++ & 0x40)
878 subq[i] |= 0x10;
879 if (*p++ & 0x40)
880 subq[i] |= 0x08;
881 if (*p++ & 0x40)
882 subq[i] |= 0x04;
883 if (*p++ & 0x40)
884 subq[i] |= 0x02;
885 if (*p++ & 0x40)
886 subq[i] |= 0x01;
887 }
888 subq[12] = 0;
889 subq[13] = 0;
890 subq[14] = 0;
891 if (np > (96/2))
892 subq[15] = 0x80;
893 }
894
895 /*
896 * Recode subchannels of sectors from 2352 + 96 bytes to 2352 + 16 bytes
897 */
898 EXPORT void
subrecodesecs(trackp,bp,address,nsecs)899 subrecodesecs(trackp, bp, address, nsecs)
900 track_t *trackp;
901 Uchar *bp;
902 int address;
903 int nsecs;
904 {
905 bp += 2352;
906 while (--nsecs >= 0) {
907 qwto16(bp, bp);
908 bp += trackp->isecsize;
909 }
910 }
911
912 #ifndef HAVE_LIB_EDC_ECC
913 EXPORT void
encsectors(trackp,bp,address,nsecs)914 encsectors(trackp, bp, address, nsecs)
915 track_t *trackp;
916 Uchar *bp;
917 int address;
918 int nsecs;
919 {
920 int sectype = trackp->sectype;
921
922 if ((sectype & ST_MODE_MASK) == ST_MODE_AUDIO)
923 return;
924
925 comerrno(EX_BAD, _("Can only write audio sectors in RAW mode.\n"));
926 }
927
928 EXPORT void
scrsectors(trackp,bp,address,nsecs)929 scrsectors(trackp, bp, address, nsecs)
930 track_t *trackp;
931 Uchar *bp;
932 int address;
933 int nsecs;
934 {
935 comerrno(EX_BAD, _("Cannot write in clone RAW mode.\n"));
936 }
937 #endif
938
939 /*--------------------------------------------------------------------------*/
940 #ifdef TEST_CRC
941
942 Uchar tq[12] = { 0x01, 0x00, 0xA0, 0x98, 0x06, 0x12, 0x00, 0x01, 0x00, 0x00, 0xE3, 0x74 };
943
944 /*
945 01 00 A0 98 06 12 00 01 00 00 E3 74
946 01 00 A0 98 06 13 00 01 00 00 49 25
947 01 00 A1 98 06 14 00 13 00 00 44 21
948 01 00 A1 98 06 15 00 13 00 00 EE 70
949 01 00 A1 98 06 16 00 13 00 00 00 A2
950 01 00 A2 98 06 17 00 70 40 73 E3 85
951 01 00 A2 98 06 18 00 70 40 73 86 7C
952 01 00 A2 98 06 19 00 70 40 73 2C 2D
953 01 00 01 98 06 20 00 00 02 00 3B 71
954 01 00 01 98 06 21 00 00 02 00 91 20
955 01 00 01 98 06 22 00 00 02 00 7F F2
956 01 00 02 98 06 23 00 03 48 45 BE E0
957 01 00 02 98 06 24 00 03 48 45 D9 34
958
959 */
960
961 LOCAL int b __PR((int bcd));
962
963
964 LOCAL int
b(bcd)965 b(bcd)
966 int bcd;
967 {
968 return ((bcd & 0x0F) + 10 * (((bcd)>> 4) & 0x0F));
969 }
970
971 LOCAL void
testcrc()972 testcrc()
973 {
974 struct q q;
975 int ocrc;
976 int crc1;
977 int crc2;
978
979 movebytes(&tq, &q, 12);
980 crc1 = q.crc1 & 0xFF;
981 crc2 = q.crc2 & 0xFF;
982
983 /*
984 * Per RED Book, CRC Bits on disk are inverted.
985 * Invert them again to make calcCRC() work.
986 */
987 q.crc1 ^= 0xFF;
988 q.crc2 ^= 0xFF;
989
990 ocrc = calcCRC((Uchar *)&q, 12);
991 printf("AC: %02X t: %3d (%02X) i: %3d (%02X) %d:%d:%d %d:%d:%d %02X%02X %X (%X)\n",
992 q.ctrl_adr,
993 b(q.track),
994 b(q.track) & 0xFF,
995 b(q.index),
996 q.index & 0xFF,
997 b(q.pmin),
998 b(q.psec),
999 b(q.pframe),
1000 b(q.amin),
1001 b(q.asec),
1002 b(q.aframe),
1003 crc1, crc2,
1004 ocrc,
1005 fillcrc((Uchar *)&q, 12) & 0xFFFF);
1006 }
1007 #endif /* TEST_CRC */
1008
1009 #if 0
1010 96 / 24 = 4
1011
1012 index 1 < - > 18
1013 index 2 < - > 5
1014 index 3 < - > 23
1015
1016 delay index mod 8
1017 #endif
1018
1019 #ifdef DO_SUBINTERLEAVE
1020 /*
1021 * Sub 96 Bytes Interleave
1022 */
1023 LOCAL void
subinterleave(sub)1024 subinterleave(sub)
1025 Uchar *sub;
1026 {
1027 Uchar *p;
1028 int i;
1029
1030 for (i = 0, p = sub; i < 4; i++) {
1031 Uchar save;
1032
1033 /*
1034 * index 1 < - > 18
1035 * index 2 < - > 5
1036 * index 3 < - > 23
1037 */
1038 save = p[1];
1039 p[1] = p[18];
1040 p[18] = save;
1041
1042 save = p[2];
1043 p[2] = p[5];
1044 p[5] = save;
1045
1046 save = p[3];
1047 p[3] = p[23];
1048 p[23] = save;
1049
1050 p += 24;
1051 }
1052 }
1053 #endif /* DO_SUBINTERLEAVE */
1054