2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)subchan.c 1.20 05/06/11 Copyright 2000-2004 J. Schilling */
15 * Subchannel processing
17 * Copyright (c) 2000-2004 J. Schilling
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License version 2
22 * as published by the Free Software Foundation.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License along with
30 * this program; see the file COPYING. If not, write to the Free Software
31 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 #include <usal/scsitransp.h>
46 int do_leadin(track_t *trackp);
47 int write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp, int leadinstart);
48 int write_leadout(SCSI *usalp, cdr_t *dp, track_t *trackp);
49 void fillsubch(track_t *trackp, Uchar *sp, int secno, int nsecs);
50 void filltpoint(Uchar *sub, int ctrl_adr, int point, msf_t *mp);
51 void fillttime(Uchar *sub, msf_t *mp);
52 static void filldsubq(Uchar *sub, int ca, int t, int i, msf_t *mrp,
54 static void fillmcn(Uchar *sub, Uchar *mcn);
55 static void fillisrc(Uchar *sub, Uchar *isrc);
56 static int ascii2q(int c);
57 static void qpto16(Uchar *sub, Uchar *subq, int dop);
58 void qpto96(Uchar *sub, Uchar *subq, int dop);
59 void addrw(Uchar *sub, Uchar *subrwptr);
60 void qwto16(Uchar *subq, Uchar *subptr);
61 void subrecodesecs(track_t *trackp, Uchar *bp, int address, int nsecs);
62 static void subinterleave(Uchar *sub);
66 static void testcrc(void);
69 /*Die 96 Bits == 12 Bytes haben folgendes Aussehen:*/
72 Uchar ctrl_adr; /* 0 (ctrl << 4) | adr */
73 Uchar track; /* 1 current track # */
74 Uchar index; /* 2 current index # */
75 Uchar pmin; /* 3 Relative time minutes part */
76 Uchar psec; /* 4 Relative time seconds part */
77 Uchar pframe; /* 5 Relative time frames part */
79 Uchar amin; /* 7 Absolute time minutes part */
80 Uchar asec; /* 8 Absolute time seconds part */
81 Uchar aframe; /* 9 Absolute time frames part */
82 Uchar crc1; /* 10 all bits inverted. Polynom is */
83 Uchar crc2; /* 11 X^16 + X^12 + X^5 + 1 */
93 * Prepare master sunchannel data for RAW TOC.
96 do_leadin(track_t *trackp)
98 int tracks = trackp->tracks;
102 int toctype = trackp[0].tracktype & TOC_MASK;
106 printf("Using CLONE TOC....\n");
110 printf("Leadin TOC Type: %d\n", trackp[0].tracktype & TOC_MASK);
112 for (i = 1; i <= tracks+1; i++)
113 printf("Track %d start %ld\n", i, trackp[i].trackstart);
121 fillbytes(_subq, sizeof (_subq), '\0');
124 * Fill in point 0xA0 for first track # on disk
126 ctrl = (st2mode[trackp[0].sectype & ST_MASK]) << 4;
127 if (is_copy(&trackp[0]))
128 ctrl |= TM_ALLOW_COPY << 4;
129 m.msf_min = trackp[1].trackno;
131 * Disk Type: 0 = AUDIO/DATA, 0x10 = CDI, 0x20 = XA mode 2
133 m.msf_sec = toc2sess[toctype & TOC_MASK];
134 m.msf_sec = from_bcd(m.msf_sec); /* convert to BCD */
136 filltpoint(_subq[0], ctrl|0x01, 0xA0, &m);
138 usal_prbytes("", _subq[0], 12);
141 * Fill in point 0xA1 for last track # on disk
143 ctrl = (st2mode[trackp[tracks].sectype & ST_MASK]) << 4;
144 if (is_copy(&trackp[tracks]))
145 ctrl |= TM_ALLOW_COPY << 4;
146 m.msf_min = trackp[tracks].trackno;
149 filltpoint(_subq[1], ctrl|0x01, 0xA1, &m);
151 usal_prbytes("", _subq[1], 12);
154 * Fill in point 0xA2 for lead out start time on disk
156 lba_to_msf(trackp[tracks+1].trackstart, &m);
157 ctrl = (st2mode[trackp[tracks].sectype & ST_MASK]) << 4;
158 if (is_copy(&trackp[tracks]))
159 ctrl |= TM_ALLOW_COPY << 4;
160 filltpoint(_subq[2], ctrl|0x01, 0xA2, &m);
162 usal_prbytes("", _subq[2], 12);
165 * Fill in track start times.
167 for (i = 1; i <= tracks; i++) {
168 lba_to_msf(trackp[i].trackstart, &m);
169 ctrl = (st2mode[trackp[i].sectype & ST_MASK]) << 4;
170 if (is_copy(&trackp[i]))
171 ctrl |= TM_ALLOW_COPY << 4;
172 filltpoint(_subq[i-1+3], ctrl|0x01, to_bcd(trackp[i].trackno), &m); /* track n */
174 usal_prbytes("", _subq[i-1+3], 12);
180 * Write TOC (lead-in)
182 * Use previously prepared master subchannel data to create the
183 * subchannel frames for the lead-in.
186 write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp, int leadinstart)
191 Uchar *bp = usalp->bufptr;
203 secsize = trackp[0].secsize;
204 secspt = trackp[0].secspt;
205 bytespt = secspt * secsize;
207 lba_to_msf(leadinstart, &msf);
209 fillbytes(bp, bytespt, '\0');
213 printf("Using CLONE LEADIN\n");
216 printf("Leadinstart: %d %d:%d/%d",
218 msf.msf_min, msf.msf_sec, msf.msf_frame);
219 printf(" FLAGS: 0x%X sect: %X RAW16:%d secs: %d spt: %d\n",
220 trackp[0].flags, trackp[0].sectype,
221 is_raw16(&trackp[0]), secsize, secspt);
224 startsec = leadinstart;
227 for (i = leadinstart, j = 0; i < -150; i++, j++) {
229 * TOC hat folgende unterschiedliche Sub Q Frames:
235 * Jeder Frame wird 3x wiederholt.
241 if (j >= (3*3 + 3*trackp->tracks))
244 lba_to_msf((long)i, &m);
245 fillttime(_subq[j/3], &m);
246 fillcrc(_subq[j/3], 12);
248 usal_prbytes("", _subq[j/3], 12);
249 if (is_raw16(&trackp[0])) {
250 qpto16(subp, _subq[j/3], 0);
252 extern Uchar *textsub;
255 qpto96(subp, _subq[j/3], 0);
257 addrw(subp, &textsub[textoff]);
259 if (textoff >= textlen)
262 /* if (is_raw96p(&trackp[0]))*/
263 /* subinterleave(subp);*/
265 if ((startsec+secspt-1) == i || i == -151) {
266 if ((i-startsec+1) < secspt) {
267 secspt = i-startsec+1;
268 bytespt = secspt * secsize;
270 encsectors(trackp, bp, startsec, secspt);
272 amount = write_secs(usalp, dp,
273 (char *)bp, startsec, bytespt, secspt, FALSE);
275 printf("write leadin data: error after %ld bytes\n",
292 * Write Track 0xAA (lead-out)
295 write_leadout(SCSI *usalp, cdr_t *dp, track_t *trackp)
297 int tracks = trackp->tracks;
303 Uchar *bp = usalp->bufptr;
318 fillbytes(sub, 12, '\0');
320 secsize = trackp[tracks+1].secsize;
321 secspt = trackp[tracks+1].secspt;
322 bytespt = secspt * secsize;
324 leadoutstart = trackp[tracks+1].trackstart;
325 lba_to_msf(leadoutstart, &msf);
327 fillbytes(bp, bytespt, '\0');
330 printf("Leadoutstart: %d %d:%d/%d amt %ld",
332 msf.msf_min, msf.msf_sec, msf.msf_frame,
333 trackp[tracks+1].tracksecs);
334 printf(" FLAGS: 0x%X sect: %X RAW16:%d secs: %d spt: %d\n",
335 trackp[tracks+1].flags, trackp[tracks+1].sectype,
336 is_raw16(&trackp[tracks+1]), secsize, secspt);
339 startsec = leadoutstart;
340 endsec = startsec + trackp[tracks+1].tracksecs;
343 ctrl = (st2mode[trackp->sectype & ST_MASK]) << 4;
345 ctrl |= TM_ALLOW_COPY << 4;
347 for (i = leadoutstart, j = 0; i < endsec; i++, j++) {
349 lba_to_msf((long)i, &m);
350 sec_to_msf((long)j, &mr);
351 filldsubq(sub, ctrl|0x01, 0xAA, 1, &mr, &m);
358 usal_prbytes(p?"P":" ", sub, 12);
360 if (is_raw16(&trackp[0])) {
361 qpto16(subp, sub, p);
363 qpto96(subp, sub, p);
364 /* if (is_raw96p(&trackp[0]))*/
365 /* subinterleave(subp);*/
367 if ((startsec+secspt-1) == i || i == (endsec-1)) {
368 if ((i-startsec+1) < secspt) {
369 secspt = i-startsec+1;
370 bytespt = secspt * secsize;
372 encsectors(trackp, bp, startsec, secspt);
374 amount = write_secs(usalp, dp,
375 (char *)bp, startsec, bytespt, secspt, FALSE);
377 printf("write leadout data: error after %ld bytes\n",
394 * Fill in subchannel data.
396 * This function is used to prepare the sub channels when writing
397 * the data part of a CD (bewteen lead-in and lead-out).
400 fillsubch(track_t *trackp,
401 Uchar *sp /* Sector data pointer */,
402 int secno /* Starting sector # */,
403 int nsecs /* # of sectors to fill */)
411 int secsize = trackp->secsize;
412 int trackno = trackp->trackno;
413 int nindex = trackp->nindex;
421 * In theory this should make fillsubch() non-reenrtrant but it seems
422 * that the probability check at the beginning of the function is
423 * sufficient to make it work as expected.
425 static long nextmcn = -1000000L;
426 static long nextisrc = -1000000L;
427 static Uchar lastindex = 255;
429 fillbytes(sub, 12, '\0');
431 mcn = track_base(trackp)->isrc;
432 rsecno = secno - trackp->trackstart;
433 if ((secno + nsecs) > (trackp->trackstart + trackp->tracksecs)) {
434 comerrno(EX_BAD, "Implementation botch: track boundary in buffer.\n");
437 if (mcn && (nextmcn < secno || nextmcn > (secno+100))) {
438 nextmcn = secno/100*100 + 99;
440 if (trackp->isrc && (nextisrc < secno || nextisrc > (secno+100))) {
441 nextisrc = secno/100*100 + 49;
443 ctrl = (st2mode[trackp->sectype & ST_MASK]) << 4;
445 ctrl |= TM_ALLOW_COPY << 4;
448 fprintf(stderr, "Tracknl %d nindex %d trackstart %ld rsecno %d index0start %ld nsecs %d\n",
449 trackno, nindex, trackp->trackstart, rsecno, trackp->index0start, nsecs);
454 * Called to manually write pregap null data into the pregap
455 * while 'trackp' points to the curent track. For this reason,
456 * the sectors are before the start of track 'n' index 0.
459 end = trackp->trackstart;
461 } else if (rsecno > trackp->index0start) {
463 * This track contains pregap of next track.
464 * We currently are inside this pregap.
468 end = trackp->trackstart + trackp->tracksecs;
471 * We are inside the normal data part of this track.
472 * This is index_1...index_m for track n.
473 * Set 'end' to 0 in this case although it is only used
474 * if 'index' is 0. But GCC gives a warning that 'end'
475 * might be uninitialized.
480 tindex = trackp->tindex;
481 nextindex = trackp->tracksecs;
483 * find current index in list
485 for (curindex = nindex; curindex >= 1; curindex--) {
486 if (rsecno >= tindex[curindex]) {
487 if (curindex < nindex)
488 nextindex = tindex[curindex+1];
495 for (i = 0; i < nsecs; i++) {
497 if (tindex != NULL && rsecno >= nextindex) {
499 * Skip to next index in list.
501 if (curindex < nindex) {
503 nextindex = tindex[curindex+1];
506 if (rsecno == trackp->index0start) {
508 * This track contains pregap of next track.
512 end = trackp->trackstart + trackp->tracksecs;
514 lba_to_msf((long)secno, &m);
516 sec_to_msf((long)end-1 - secno, &mr);
518 sec_to_msf((long)rsecno, &mr);
519 if (is_scms(trackp)) {
520 if ((secno % 8) <= 3) {
521 ctrl &= ~(TM_ALLOW_COPY << 4);
523 ctrl |= TM_ALLOW_COPY << 4;
526 filldsubq(sub, ctrl|0x01, trackno, curindex, &mr, &m);
527 if (mcn && (secno == nextmcn)) {
528 if (curindex == lastindex) {
529 fillmcn(sub, (Uchar *)mcn);
530 nextmcn = (secno+1)/100*100 + 99;
535 if (trackp->isrc && (secno == nextisrc)) {
536 if (curindex == lastindex) {
537 fillisrc(sub, (Uchar *)trackp->isrc);
538 nextisrc = (secno+1)/100*100 + 49;
545 usal_prbytes(curindex == 0 ? "P":" ", sub, 12);
546 if (is_raw16(trackp)) {
547 qpto16(sup, sub, curindex == 0);
549 qpto96(sup, sub, curindex == 0);
550 /* if (is_raw96p(trackp))*/
551 /* subinterleave(sup);*/
553 lastindex = curindex;
563 * Ax Werte einfüllen.
566 filltpoint(Uchar *sub, int ctrl_adr, int point, msf_t *mp)
570 sub[7] = to_bcd(mp->msf_min);
571 sub[8] = to_bcd(mp->msf_sec);
572 sub[9] = to_bcd(mp->msf_frame);
577 * Aktuelle Zeit in TOC Sub-Q einfüllen.
580 fillttime(Uchar *sub, msf_t *mp)
582 sub[3] = to_bcd(mp->msf_min);
583 sub[4] = to_bcd(mp->msf_sec);
584 sub[5] = to_bcd(mp->msf_frame);
588 * Q-Sub in Datenbereich füllen.
591 filldsubq(Uchar *sub, int ca, int t, int i, msf_t *mrp, msf_t *mp)
596 sub[3] = to_bcd(mrp->msf_min);
597 sub[4] = to_bcd(mrp->msf_sec);
598 sub[5] = to_bcd(mrp->msf_frame);
600 sub[7] = to_bcd(mp->msf_min);
601 sub[8] = to_bcd(mp->msf_sec);
602 sub[9] = to_bcd(mp->msf_frame);
607 * MCN konvertieren und in Sub-Q einfüllen.
610 fillmcn(Uchar *sub, Uchar *mcn)
616 for (i = 1; i <= 8; i++) {
618 if (c >= '0' && c <= '9')
619 sub[i] = (c - '0') << 4;
625 if (c >= '0' && c <= '9')
639 * ISRC konvertieren und in Sub-Q einfüllen.
642 fillisrc(Uchar *sub, Uchar *isrc)
653 * Convert into Sub-Q character coding
655 for (i = 0, j = 0; i < 12; i++) {
656 if (isrc[i+j] == '-')
658 if (isrc[i+j] == '\0')
660 tmp[i] = ascii2q(isrc[i+j]);
666 * The first 5 chars from e.g. "FI-BAR-99-00312"
669 sp[0] |= (tmp[1] >> 4) & 0x03;
670 sp[1] = (tmp[1] << 4) & 0xF0;
671 sp[1] |= (tmp[2] >> 2) & 0x0F;
672 sp[2] = (tmp[2] << 6) & 0xC0;
673 sp[2] |= tmp[3] & 0x3F;
677 * Now 7 digits from e.g. "FI-BAR-99-00312"
679 for (i = 4, j = 5; i < 8; i++) {
680 sp[i] = tmp[j++] << 4;
686 * ASCII -> Sub-Q ISRC code conversion
691 if (c >= '0' && c <= '9')
693 else if (c >= '@' && c <= 'o')
694 return (0x10 + c - '@');
699 * Q-Sub auf 16 Bytes blähen und P-Sub addieren
701 * OUT: sub, IN: subqptr
704 qpto16(Uchar *sub, Uchar *subqptr, int dop)
707 movebytes(subqptr, sub, 12);
718 * Q-Sub auf 96 Bytes blähen und P-Sub addieren
720 * OUT: sub, IN: subqptr
723 qpto96(Uchar *sub, Uchar *subqptr, int dop)
730 if (subqptr == sub) {
732 * Remember 12 byte subchannel data if subchannel
735 movebytes(subqptr, tmp, 12);
739 * Clear all subchannel bits in the 96 byte target space.
741 fillbytes(sub, 96, '\0');
744 if (dop) for (i = 0, p = sub; i < 96; i++) {
747 for (i = 0, p = sub; i < 12; i++) {
748 c = subqptr[i] & 0xFF;
749 /*printf("%02X\n", c);*/
786 * Add R-W-Sub (96 Bytes) to P-Q-Sub (96 Bytes)
788 * OUT: sub, IN: subrwptr
791 addrw(register Uchar *sub, register Uchar *subrwptr)
795 #define DO8(a) a; a; a; a; a; a; a; a;
797 for (i = 0; i < 12; i++) {
798 DO8(*sub++ |= *subrwptr++ & 0x3F);
803 * Q-W-Sub (96 Bytes) auf 16 Bytes schrumpfen
805 * OUT: subq, IN: subptr
808 qwto16(Uchar *subq, Uchar *subptr)
816 for (i = 0; i < 96; i++)
820 if (subptr == subq) {
822 * Remember 96 byte subchannel data if subchannel
825 movebytes(subptr, tmp, 96);
829 for (i = 0; i < 12; i++) {
856 * Recode subchannels of sectors from 2352 + 96 bytes to 2352 + 16 bytes
859 subrecodesecs(track_t *trackp, Uchar *bp, int address, int nsecs)
862 while (--nsecs >= 0) {
864 bp += trackp->isecsize;
868 #ifndef HAVE_LIB_EDC_ECC
870 encsectors(track_t *trackp, Uchar *bp, int address, int nsecs)
872 int sectype = trackp->sectype;
874 if ((sectype & ST_MODE_MASK) == ST_MODE_AUDIO)
877 comerrno(EX_BAD, "Can only write audio sectors in RAW mode.\n");
881 scrsectors(track_t *trackp, Uchar *bp, int address, int nsecs)
883 comerrno(EX_BAD, "Cannot write in clone RAW mode.\n");
887 /*--------------------------------------------------------------------------*/
890 Uchar tq[12] = { 0x01, 0x00, 0xA0, 0x98, 0x06, 0x12, 0x00, 0x01, 0x00, 0x00, 0xE3, 0x74 };
893 01 00 A0 98 06 12 00 01 00 00 E3 74
894 01 00 A0 98 06 13 00 01 00 00 49 25
895 01 00 A1 98 06 14 00 13 00 00 44 21
896 01 00 A1 98 06 15 00 13 00 00 EE 70
897 01 00 A1 98 06 16 00 13 00 00 00 A2
898 01 00 A2 98 06 17 00 70 40 73 E3 85
899 01 00 A2 98 06 18 00 70 40 73 86 7C
900 01 00 A2 98 06 19 00 70 40 73 2C 2D
901 01 00 01 98 06 20 00 00 02 00 3B 71
902 01 00 01 98 06 21 00 00 02 00 91 20
903 01 00 01 98 06 22 00 00 02 00 7F F2
904 01 00 02 98 06 23 00 03 48 45 BE E0
905 01 00 02 98 06 24 00 03 48 45 D9 34
909 static int b(int bcd);
915 return ((bcd & 0x0F) + 10 * (((bcd)>> 4) & 0x0F));
926 movebytes(&tq, &q, 12);
927 crc1 = q.crc1 & 0xFF;
928 crc2 = q.crc2 & 0xFF;
931 * Per RED Book, CRC Bits on disk are inverted.
932 * Invert them again to make calcCRC() work.
937 ocrc = calcCRC((Uchar *)&q, 12);
938 printf("AC: %02X t: %3d (%02X) i: %3d (%02X) %d:%d:%d %d:%d:%d %02X%02X %X (%X)\n",
952 fillcrc((Uchar *)&q, 12) & 0xFFFF);
954 #endif /* TEST_CRC */
967 * Sub 96 Bytes Interleave
970 subinterleave(Uchar *sub)
975 for (i = 0, p = sub; i < 4; i++) {