summaryrefslogtreecommitdiff
path: root/wodim/subchan.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-12-31 05:04:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2012-12-31 05:04:42 +0400
commit71dc8760ff4de5f365330d1bc571d934deb54af9 (patch)
tree7346d42a282562a3937d82307012b5857d642ce6 /wodim/subchan.c
downloadcdrkit-71dc8760ff4de5f365330d1bc571d934deb54af9.tar.gz
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'wodim/subchan.c')
-rw-r--r--wodim/subchan.c997
1 files changed, 997 insertions, 0 deletions
diff --git a/wodim/subchan.c b/wodim/subchan.c
new file mode 100644
index 0000000..7195992
--- /dev/null
+++ b/wodim/subchan.c
@@ -0,0 +1,997 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)subchan.c 1.20 05/06/11 Copyright 2000-2004 J. Schilling */
+/*
+ * Subchannel processing
+ *
+ * Copyright (c) 2000-2004 J. Schilling
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <mconfig.h>
+#include <stdio.h>
+#include <unixstd.h>
+#include <standard.h>
+#include <utypes.h>
+#include <schily.h>
+
+#include <usal/scsitransp.h>
+
+#include "wodim.h"
+#include "crc16.h"
+
+int do_leadin(track_t *trackp);
+int write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp, int leadinstart);
+int write_leadout(SCSI *usalp, cdr_t *dp, track_t *trackp);
+void fillsubch(track_t *trackp, Uchar *sp, int secno, int nsecs);
+void filltpoint(Uchar *sub, int ctrl_adr, int point, msf_t *mp);
+void fillttime(Uchar *sub, msf_t *mp);
+static void filldsubq(Uchar *sub, int ca, int t, int i, msf_t *mrp,
+ msf_t *mp);
+static void fillmcn(Uchar *sub, Uchar *mcn);
+static void fillisrc(Uchar *sub, Uchar *isrc);
+static int ascii2q(int c);
+static void qpto16(Uchar *sub, Uchar *subq, int dop);
+void qpto96(Uchar *sub, Uchar *subq, int dop);
+void addrw(Uchar *sub, Uchar *subrwptr);
+void qwto16(Uchar *subq, Uchar *subptr);
+void subrecodesecs(track_t *trackp, Uchar *bp, int address, int nsecs);
+static void subinterleave(Uchar *sub);
+
+/*#define TEST_CRC*/
+#ifdef TEST_CRC
+static void testcrc(void);
+#endif
+
+/*Die 96 Bits == 12 Bytes haben folgendes Aussehen:*/
+
+struct q {
+ Uchar ctrl_adr; /* 0 (ctrl << 4) | adr */
+ Uchar track; /* 1 current track # */
+ Uchar index; /* 2 current index # */
+ Uchar pmin; /* 3 Relative time minutes part */
+ Uchar psec; /* 4 Relative time seconds part */
+ Uchar pframe; /* 5 Relative time frames part */
+ Uchar zero; /* 6 */
+ Uchar amin; /* 7 Absolute time minutes part */
+ Uchar asec; /* 8 Absolute time seconds part */
+ Uchar aframe; /* 9 Absolute time frames part */
+ Uchar crc1; /* 10 all bits inverted. Polynom is */
+ Uchar crc2; /* 11 X^16 + X^12 + X^5 + 1 */
+};
+
+Uchar _subq[110][12];
+int _nsubh;
+
+extern int lverbose;
+extern int xdebug;
+
+/*
+ * Prepare master sunchannel data for RAW TOC.
+ */
+int
+do_leadin(track_t *trackp)
+{
+ int tracks = trackp->tracks;
+ msf_t m;
+ int ctrl;
+ int i;
+ int toctype = trackp[0].tracktype & TOC_MASK;
+
+ if (_nsubh) {
+ if (xdebug)
+ printf("Using CLONE TOC....\n");
+ return (0);
+ }
+ if (xdebug)
+ printf("Leadin TOC Type: %d\n", trackp[0].tracktype & TOC_MASK);
+ if (lverbose > 1) {
+ for (i = 1; i <= tracks+1; i++)
+ printf("Track %d start %ld\n", i, trackp[i].trackstart);
+ }
+
+#ifdef TEST_CRC
+ testcrc();
+/* exit(1);*/
+#endif
+
+ fillbytes(_subq, sizeof (_subq), '\0');
+
+ /*
+ * Fill in point 0xA0 for first track # on disk
+ */
+ ctrl = (st2mode[trackp[0].sectype & ST_MASK]) << 4;
+ if (is_copy(&trackp[0]))
+ ctrl |= TM_ALLOW_COPY << 4;
+ m.msf_min = trackp[1].trackno;
+ /*
+ * Disk Type: 0 = AUDIO/DATA, 0x10 = CDI, 0x20 = XA mode 2
+ */
+ m.msf_sec = toc2sess[toctype & TOC_MASK];
+ m.msf_sec = from_bcd(m.msf_sec); /* convert to BCD */
+ m.msf_frame = 0;
+ filltpoint(_subq[0], ctrl|0x01, 0xA0, &m);
+ if (lverbose > 2)
+ usal_prbytes("", _subq[0], 12);
+
+ /*
+ * Fill in point 0xA1 for last track # on disk
+ */
+ ctrl = (st2mode[trackp[tracks].sectype & ST_MASK]) << 4;
+ if (is_copy(&trackp[tracks]))
+ ctrl |= TM_ALLOW_COPY << 4;
+ m.msf_min = trackp[tracks].trackno;
+ m.msf_sec = 0;
+ m.msf_frame = 0;
+ filltpoint(_subq[1], ctrl|0x01, 0xA1, &m);
+ if (lverbose > 2)
+ usal_prbytes("", _subq[1], 12);
+
+ /*
+ * Fill in point 0xA2 for lead out start time on disk
+ */
+ lba_to_msf(trackp[tracks+1].trackstart, &m);
+ ctrl = (st2mode[trackp[tracks].sectype & ST_MASK]) << 4;
+ if (is_copy(&trackp[tracks]))
+ ctrl |= TM_ALLOW_COPY << 4;
+ filltpoint(_subq[2], ctrl|0x01, 0xA2, &m);
+ if (lverbose > 2)
+ usal_prbytes("", _subq[2], 12);
+
+ /*
+ * Fill in track start times.
+ */
+ for (i = 1; i <= tracks; i++) {
+ lba_to_msf(trackp[i].trackstart, &m);
+ ctrl = (st2mode[trackp[i].sectype & ST_MASK]) << 4;
+ if (is_copy(&trackp[i]))
+ ctrl |= TM_ALLOW_COPY << 4;
+ filltpoint(_subq[i-1+3], ctrl|0x01, to_bcd(trackp[i].trackno), &m); /* track n */
+ if (lverbose > 2)
+ usal_prbytes("", _subq[i-1+3], 12);
+ }
+ return (0);
+}
+
+/*
+ * Write TOC (lead-in)
+ *
+ * Use previously prepared master subchannel data to create the
+ * subchannel frames for the lead-in.
+ */
+int
+write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp, int leadinstart)
+{
+ msf_t m;
+ int i;
+ Uint j;
+ Uchar *bp = usalp->bufptr;
+ Uchar *subp;
+ Uchar *sp;
+ int secsize;
+ int secspt;
+ int bytespt;
+ long amount;
+ int startsec;
+ long bytes = 0L;
+ int textoff = 0;
+ msf_t msf;
+
+ secsize = trackp[0].secsize;
+ secspt = trackp[0].secspt;
+ bytespt = secspt * secsize;
+
+ lba_to_msf(leadinstart, &msf);
+
+ fillbytes(bp, bytespt, '\0');
+
+ if (_nsubh) {
+ if (xdebug)
+ printf("Using CLONE LEADIN\n");
+ }
+ if (xdebug) {
+ printf("Leadinstart: %d %d:%d/%d",
+ leadinstart,
+ msf.msf_min, msf.msf_sec, msf.msf_frame);
+ printf(" FLAGS: 0x%X sect: %X RAW16:%d secs: %d spt: %d\n",
+ trackp[0].flags, trackp[0].sectype,
+ is_raw16(&trackp[0]), secsize, secspt);
+ }
+
+ startsec = leadinstart;
+ sp = bp;
+ subp = bp + 2352;
+ for (i = leadinstart, j = 0; i < -150; i++, j++) {
+ /*
+ * TOC hat folgende unterschiedliche Sub Q Frames:
+ * A0 First Track
+ * A1 Last Track
+ * A3 Lead out start
+ * 1..99 Tracks
+ * == 3 + N* tracks
+ * Jeder Frame wird 3x wiederholt.
+ */
+ if (_nsubh) {
+ if (j >= (3*_nsubh))
+ j = 0;
+ } else {
+ if (j >= (3*3 + 3*trackp->tracks))
+ j = 0;
+ }
+ lba_to_msf((long)i, &m);
+ fillttime(_subq[j/3], &m);
+ fillcrc(_subq[j/3], 12);
+ if (xdebug > 2)
+ usal_prbytes("", _subq[j/3], 12);
+ if (is_raw16(&trackp[0])) {
+ qpto16(subp, _subq[j/3], 0);
+ } else {
+ extern Uchar *textsub;
+ extern int textlen;
+
+ qpto96(subp, _subq[j/3], 0);
+ if (textsub) {
+ addrw(subp, &textsub[textoff]);
+ textoff += 96;
+ if (textoff >= textlen)
+ textoff = 0;
+ }
+/* if (is_raw96p(&trackp[0]))*/
+/* subinterleave(subp);*/
+ }
+ if ((startsec+secspt-1) == i || i == -151) {
+ if ((i-startsec+1) < secspt) {
+ secspt = i-startsec+1;
+ bytespt = secspt * secsize;
+ }
+ encsectors(trackp, bp, startsec, secspt);
+
+ amount = write_secs(usalp, dp,
+ (char *)bp, startsec, bytespt, secspt, FALSE);
+ if (amount < 0) {
+ printf("write leadin data: error after %ld bytes\n",
+ bytes);
+ return (-1);
+ }
+ bytes += amount;
+ startsec = i+1;
+ sp = bp;
+ subp = bp + 2352;
+ continue;
+ }
+ sp += secsize;
+ subp += secsize;
+ }
+ return (0);
+}
+
+/*
+ * Write Track 0xAA (lead-out)
+ */
+int
+write_leadout(SCSI *usalp, cdr_t *dp, track_t *trackp)
+{
+ int tracks = trackp->tracks;
+ msf_t m;
+ msf_t mr;
+ int ctrl;
+ int i;
+ int j;
+ Uchar *bp = usalp->bufptr;
+ Uchar *subp;
+ Uchar *sp;
+ int secsize;
+ int secspt;
+ int bytespt;
+ long amount;
+ long startsec;
+ long endsec;
+ long bytes = 0L;
+ int leadoutstart;
+ Uchar sub[12];
+ BOOL p;
+ msf_t msf;
+
+ fillbytes(sub, 12, '\0');
+
+ secsize = trackp[tracks+1].secsize;
+ secspt = trackp[tracks+1].secspt;
+ bytespt = secspt * secsize;
+
+ leadoutstart = trackp[tracks+1].trackstart;
+ lba_to_msf(leadoutstart, &msf);
+
+ fillbytes(bp, bytespt, '\0');
+
+ if (xdebug) {
+ printf("Leadoutstart: %d %d:%d/%d amt %ld",
+ leadoutstart,
+ msf.msf_min, msf.msf_sec, msf.msf_frame,
+ trackp[tracks+1].tracksecs);
+ printf(" FLAGS: 0x%X sect: %X RAW16:%d secs: %d spt: %d\n",
+ trackp[tracks+1].flags, trackp[tracks+1].sectype,
+ is_raw16(&trackp[tracks+1]), secsize, secspt);
+ }
+
+ startsec = leadoutstart;
+ endsec = startsec + trackp[tracks+1].tracksecs;
+ sp = bp;
+ subp = bp + 2352;
+ ctrl = (st2mode[trackp->sectype & ST_MASK]) << 4;
+ if (is_copy(trackp))
+ ctrl |= TM_ALLOW_COPY << 4;
+
+ for (i = leadoutstart, j = 0; i < endsec; i++, j++) {
+
+ lba_to_msf((long)i, &m);
+ sec_to_msf((long)j, &mr);
+ filldsubq(sub, ctrl|0x01, 0xAA, 1, &mr, &m);
+ sub[1] = 0xAA;
+ fillcrc(sub, 12);
+ p = (j % 150) < 75;
+ if (j < 150)
+ p = FALSE;
+ if (xdebug > 2)
+ usal_prbytes(p?"P":" ", sub, 12);
+
+ if (is_raw16(&trackp[0])) {
+ qpto16(subp, sub, p);
+ } else {
+ qpto96(subp, sub, p);
+/* if (is_raw96p(&trackp[0]))*/
+/* subinterleave(subp);*/
+ }
+ if ((startsec+secspt-1) == i || i == (endsec-1)) {
+ if ((i-startsec+1) < secspt) {
+ secspt = i-startsec+1;
+ bytespt = secspt * secsize;
+ }
+ encsectors(trackp, bp, startsec, secspt);
+
+ amount = write_secs(usalp, dp,
+ (char *)bp, startsec, bytespt, secspt, FALSE);
+ if (amount < 0) {
+ printf("write leadout data: error after %ld bytes\n",
+ bytes);
+ return (-1);
+ }
+ bytes += amount;
+ startsec = i+1;
+ sp = bp;
+ subp = bp + 2352;
+ continue;
+ }
+ sp += secsize;
+ subp += secsize;
+ }
+ return (0);
+}
+
+/*
+ * Fill in subchannel data.
+ *
+ * This function is used to prepare the sub channels when writing
+ * the data part of a CD (bewteen lead-in and lead-out).
+ */
+void
+fillsubch(track_t *trackp,
+ Uchar *sp /* Sector data pointer */,
+ int secno /* Starting sector # */,
+ int nsecs /* # of sectors to fill */)
+{
+ msf_t m;
+ msf_t mr;
+ int ctrl;
+ int i;
+ int rsecno;
+ int end;
+ int secsize = trackp->secsize;
+ int trackno = trackp->trackno;
+ int nindex = trackp->nindex;
+ int curindex;
+ long *tindex = NULL;
+ long nextindex = 0L;
+ Uchar sub[12];
+ Uchar *sup;
+ char *mcn;
+ /*
+ * In theory this should make fillsubch() non-reenrtrant but it seems
+ * that the probability check at the beginning of the function is
+ * sufficient to make it work as expected.
+ */
+static long nextmcn = -1000000L;
+static long nextisrc = -1000000L;
+static Uchar lastindex = 255;
+
+ fillbytes(sub, 12, '\0');
+
+ mcn = track_base(trackp)->isrc;
+ rsecno = secno - trackp->trackstart;
+ if ((secno + nsecs) > (trackp->trackstart + trackp->tracksecs)) {
+ comerrno(EX_BAD, "Implementation botch: track boundary in buffer.\n");
+ }
+ sup = sp + 2352;
+ if (mcn && (nextmcn < secno || nextmcn > (secno+100))) {
+ nextmcn = secno/100*100 + 99;
+ }
+ if (trackp->isrc && (nextisrc < secno || nextisrc > (secno+100))) {
+ nextisrc = secno/100*100 + 49;
+ }
+ ctrl = (st2mode[trackp->sectype & ST_MASK]) << 4;
+ if (is_copy(trackp))
+ ctrl |= TM_ALLOW_COPY << 4;
+
+#ifdef SUB_DEBUG
+ fprintf(stderr, "Tracknl %d nindex %d trackstart %ld rsecno %d index0start %ld nsecs %d\n",
+ trackno, nindex, trackp->trackstart, rsecno, trackp->index0start, nsecs);
+#endif
+
+ if (rsecno < 0) {
+ /*
+ * Called to manually write pregap null data into the pregap
+ * while 'trackp' points to the curent track. For this reason,
+ * the sectors are before the start of track 'n' index 0.
+ */
+ curindex = 0;
+ end = trackp->trackstart;
+
+ } else if (rsecno > trackp->index0start) {
+ /*
+ * This track contains pregap of next track.
+ * We currently are inside this pregap.
+ */
+ trackno++;
+ curindex = 0;
+ end = trackp->trackstart + trackp->tracksecs;
+ } else {
+ /*
+ * We are inside the normal data part of this track.
+ * This is index_1...index_m for track n.
+ * Set 'end' to 0 in this case although it is only used
+ * if 'index' is 0. But GCC gives a warning that 'end'
+ * might be uninitialized.
+ */
+ end = 0;
+ curindex = 1;
+ if (nindex > 1) {
+ tindex = trackp->tindex;
+ nextindex = trackp->tracksecs;
+ /*
+ * find current index in list
+ */
+ for (curindex = nindex; curindex >= 1; curindex--) {
+ if (rsecno >= tindex[curindex]) {
+ if (curindex < nindex)
+ nextindex = tindex[curindex+1];
+ break;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < nsecs; i++) {
+
+ if (tindex != NULL && rsecno >= nextindex) {
+ /*
+ * Skip to next index in list.
+ */
+ if (curindex < nindex) {
+ curindex++;
+ nextindex = tindex[curindex+1];
+ }
+ }
+ if (rsecno == trackp->index0start) {
+ /*
+ * This track contains pregap of next track.
+ */
+ trackno++;
+ curindex = 0;
+ end = trackp->trackstart + trackp->tracksecs;
+ }
+ lba_to_msf((long)secno, &m);
+ if (curindex == 0)
+ sec_to_msf((long)end-1 - secno, &mr);
+ else
+ sec_to_msf((long)rsecno, &mr);
+ if (is_scms(trackp)) {
+ if ((secno % 8) <= 3) {
+ ctrl &= ~(TM_ALLOW_COPY << 4);
+ } else {
+ ctrl |= TM_ALLOW_COPY << 4;
+ }
+ }
+ filldsubq(sub, ctrl|0x01, trackno, curindex, &mr, &m);
+ if (mcn && (secno == nextmcn)) {
+ if (curindex == lastindex) {
+ fillmcn(sub, (Uchar *)mcn);
+ nextmcn = (secno+1)/100*100 + 99;
+ } else {
+ nextmcn++;
+ }
+ }
+ if (trackp->isrc && (secno == nextisrc)) {
+ if (curindex == lastindex) {
+ fillisrc(sub, (Uchar *)trackp->isrc);
+ nextisrc = (secno+1)/100*100 + 49;
+ } else {
+ nextisrc++;
+ }
+ }
+ fillcrc(sub, 12);
+ if (xdebug > 2)
+ usal_prbytes(curindex == 0 ? "P":" ", sub, 12);
+ if (is_raw16(trackp)) {
+ qpto16(sup, sub, curindex == 0);
+ } else {
+ qpto96(sup, sub, curindex == 0);
+/* if (is_raw96p(trackp))*/
+/* subinterleave(sup);*/
+ }
+ lastindex = curindex;
+ secno++;
+ rsecno++;
+ sup += secsize;
+ }
+}
+
+
+/*
+ * Fill TOC Point
+ * Ax Werte einfüllen.
+ */
+void
+filltpoint(Uchar *sub, int ctrl_adr, int point, msf_t *mp)
+{
+ sub[0] = ctrl_adr;
+ sub[2] = point;
+ sub[7] = to_bcd(mp->msf_min);
+ sub[8] = to_bcd(mp->msf_sec);
+ sub[9] = to_bcd(mp->msf_frame);
+}
+
+/*
+ * Fill TOC time
+ * Aktuelle Zeit in TOC Sub-Q einfüllen.
+ */
+void
+fillttime(Uchar *sub, msf_t *mp)
+{
+ sub[3] = to_bcd(mp->msf_min);
+ sub[4] = to_bcd(mp->msf_sec);
+ sub[5] = to_bcd(mp->msf_frame);
+}
+
+/*
+ * Q-Sub in Datenbereich füllen.
+ */
+static void
+filldsubq(Uchar *sub, int ca, int t, int i, msf_t *mrp, msf_t *mp)
+{
+ sub[0] = ca;
+ sub[1] = to_bcd(t);
+ sub[2] = to_bcd(i);
+ sub[3] = to_bcd(mrp->msf_min);
+ sub[4] = to_bcd(mrp->msf_sec);
+ sub[5] = to_bcd(mrp->msf_frame);
+
+ sub[7] = to_bcd(mp->msf_min);
+ sub[8] = to_bcd(mp->msf_sec);
+ sub[9] = to_bcd(mp->msf_frame);
+}
+
+/*
+ * Fill MCN
+ * MCN konvertieren und in Sub-Q einfüllen.
+ */
+static void
+fillmcn(Uchar *sub, Uchar *mcn)
+{
+ register int i;
+ register int c;
+
+ sub[0] = ADR_MCN;
+ for (i = 1; i <= 8; i++) {
+ c = *mcn++;
+ if (c >= '0' && c <= '9')
+ sub[i] = (c - '0') << 4;
+ else
+ sub[i] = 0;
+
+ if (c != '\0')
+ c = *mcn++;
+ if (c >= '0' && c <= '9')
+ sub[i] |= (c - '0');
+
+ if (c == '\0') {
+ i++;
+ break;
+ }
+ }
+ for (; i <= 8; i++)
+ sub[i] = '\0';
+}
+
+/*
+ * Fill ISRC
+ * ISRC konvertieren und in Sub-Q einfüllen.
+ */
+static void
+fillisrc(Uchar *sub, Uchar *isrc)
+{
+ register int i;
+ register int j;
+ Uchar tmp[13];
+ Uchar *sp;
+
+ sub[0] = ADR_ISRC;
+ sp = &sub[1];
+
+ /*
+ * Convert into Sub-Q character coding
+ */
+ for (i = 0, j = 0; i < 12; i++) {
+ if (isrc[i+j] == '-')
+ j++;
+ if (isrc[i+j] == '\0')
+ break;
+ tmp[i] = ascii2q(isrc[i+j]);
+ }
+ for (; i < 13; i++)
+ tmp[i] = '\0';
+
+ /*
+ * The first 5 chars from e.g. "FI-BAR-99-00312"
+ */
+ sp[0] = tmp[0] << 2;
+ sp[0] |= (tmp[1] >> 4) & 0x03;
+ sp[1] = (tmp[1] << 4) & 0xF0;
+ sp[1] |= (tmp[2] >> 2) & 0x0F;
+ sp[2] = (tmp[2] << 6) & 0xC0;
+ sp[2] |= tmp[3] & 0x3F;
+ sp[3] = tmp[4] << 2;
+
+ /*
+ * Now 7 digits from e.g. "FI-BAR-99-00312"
+ */
+ for (i = 4, j = 5; i < 8; i++) {
+ sp[i] = tmp[j++] << 4;
+ sp[i] |= tmp[j++];
+ }
+}
+
+/*
+ * ASCII -> Sub-Q ISRC code conversion
+ */
+static int
+ascii2q(int c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= '@' && c <= 'o')
+ return (0x10 + c - '@');
+ return (0);
+}
+
+/*
+ * Q-Sub auf 16 Bytes blähen und P-Sub addieren
+ *
+ * OUT: sub, IN: subqptr
+ */
+static void
+qpto16(Uchar *sub, Uchar *subqptr, int dop)
+{
+ if (sub != subqptr)
+ movebytes(subqptr, sub, 12);
+ sub[12] = '\0';
+ sub[13] = '\0';
+ sub[14] = '\0';
+ sub[15] = '\0';
+ if (dop)
+ sub[15] |= 0x80;
+
+}
+
+/*
+ * Q-Sub auf 96 Bytes blähen und P-Sub addieren
+ *
+ * OUT: sub, IN: subqptr
+ */
+void
+qpto96(Uchar *sub, Uchar *subqptr, int dop)
+{
+ Uchar tmp[16];
+ Uchar *p;
+ int c;
+ int i;
+
+ if (subqptr == sub) {
+ /*
+ * Remember 12 byte subchannel data if subchannel
+ * is overlapping.
+ */
+ movebytes(subqptr, tmp, 12);
+ subqptr = tmp;
+ }
+ /*
+ * Clear all subchannel bits in the 96 byte target space.
+ */
+ fillbytes(sub, 96, '\0');
+
+ /* BEGIN CSTYLED */
+ if (dop) for (i = 0, p = sub; i < 96; i++) {
+ *p++ |= 0x80;
+ }
+ for (i = 0, p = sub; i < 12; i++) {
+ c = subqptr[i] & 0xFF;
+/*printf("%02X\n", c);*/
+ if (c & 0x80)
+ *p++ |= 0x40;
+ else
+ p++;
+ if (c & 0x40)
+ *p++ |= 0x40;
+ else
+ p++;
+ if (c & 0x20)
+ *p++ |= 0x40;
+ else
+ p++;
+ if (c & 0x10)
+ *p++ |= 0x40;
+ else
+ p++;
+ if (c & 0x08)
+ *p++ |= 0x40;
+ else
+ p++;
+ if (c & 0x04)
+ *p++ |= 0x40;
+ else
+ p++;
+ if (c & 0x02)
+ *p++ |= 0x40;
+ else
+ p++;
+ if (c & 0x01)
+ *p++ |= 0x40;
+ else
+ p++;
+ }
+}
+
+/*
+ * Add R-W-Sub (96 Bytes) to P-Q-Sub (96 Bytes)
+ *
+ * OUT: sub, IN: subrwptr
+ */
+void
+addrw(register Uchar *sub, register Uchar *subrwptr)
+{
+ register int i;
+
+#define DO8(a) a; a; a; a; a; a; a; a;
+
+ for (i = 0; i < 12; i++) {
+ DO8(*sub++ |= *subrwptr++ & 0x3F);
+ }
+}
+
+/*
+ * Q-W-Sub (96 Bytes) auf 16 Bytes schrumpfen
+ *
+ * OUT: subq, IN: subptr
+ */
+void
+qwto16(Uchar *subq, Uchar *subptr)
+{
+ register int i;
+ register int np = 0;
+ register Uchar *p;
+ Uchar tmp[96];
+
+ p = subptr;
+ for (i = 0; i < 96; i++)
+ if (*p++ & 0x80)
+ np++;
+ p = subptr;
+ if (subptr == subq) {
+ /*
+ * Remember 96 byte subchannel data if subchannel
+ * is overlapping.
+ */
+ movebytes(subptr, tmp, 96);
+ p = tmp;
+ }
+
+ for (i = 0; i < 12; i++) {
+ subq[i] = 0;
+ if (*p++ & 0x40)
+ subq[i] |= 0x80;
+ if (*p++ & 0x40)
+ subq[i] |= 0x40;
+ if (*p++ & 0x40)
+ subq[i] |= 0x20;
+ if (*p++ & 0x40)
+ subq[i] |= 0x10;
+ if (*p++ & 0x40)
+ subq[i] |= 0x08;
+ if (*p++ & 0x40)
+ subq[i] |= 0x04;
+ if (*p++ & 0x40)
+ subq[i] |= 0x02;
+ if (*p++ & 0x40)
+ subq[i] |= 0x01;
+ }
+ subq[12] = 0;
+ subq[13] = 0;
+ subq[14] = 0;
+ if (np > (96/2))
+ subq[15] = 0x80;
+}
+
+/*
+ * Recode subchannels of sectors from 2352 + 96 bytes to 2352 + 16 bytes
+ */
+void
+subrecodesecs(track_t *trackp, Uchar *bp, int address, int nsecs)
+{
+ bp += 2352;
+ while (--nsecs >= 0) {
+ qwto16(bp, bp);
+ bp += trackp->isecsize;
+ }
+}
+
+#ifndef HAVE_LIB_EDC_ECC
+void
+encsectors(track_t *trackp, Uchar *bp, int address, int nsecs)
+{
+ int sectype = trackp->sectype;
+
+ if ((sectype & ST_MODE_MASK) == ST_MODE_AUDIO)
+ return;
+
+ comerrno(EX_BAD, "Can only write audio sectors in RAW mode.\n");
+}
+
+void
+scrsectors(track_t *trackp, Uchar *bp, int address, int nsecs)
+{
+ comerrno(EX_BAD, "Cannot write in clone RAW mode.\n");
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+#ifdef TEST_CRC
+
+Uchar tq[12] = { 0x01, 0x00, 0xA0, 0x98, 0x06, 0x12, 0x00, 0x01, 0x00, 0x00, 0xE3, 0x74 };
+
+/*
+01 00 A0 98 06 12 00 01 00 00 E3 74
+01 00 A0 98 06 13 00 01 00 00 49 25
+01 00 A1 98 06 14 00 13 00 00 44 21
+01 00 A1 98 06 15 00 13 00 00 EE 70
+01 00 A1 98 06 16 00 13 00 00 00 A2
+01 00 A2 98 06 17 00 70 40 73 E3 85
+01 00 A2 98 06 18 00 70 40 73 86 7C
+01 00 A2 98 06 19 00 70 40 73 2C 2D
+01 00 01 98 06 20 00 00 02 00 3B 71
+01 00 01 98 06 21 00 00 02 00 91 20
+01 00 01 98 06 22 00 00 02 00 7F F2
+01 00 02 98 06 23 00 03 48 45 BE E0
+01 00 02 98 06 24 00 03 48 45 D9 34
+
+*/
+
+static int b(int bcd);
+
+
+static int
+b(int bcd)
+{
+ return ((bcd & 0x0F) + 10 * (((bcd)>> 4) & 0x0F));
+}
+
+static void
+testcrc()
+{
+ struct q q;
+ int ocrc;
+ int crc1;
+ int crc2;
+
+ movebytes(&tq, &q, 12);
+ crc1 = q.crc1 & 0xFF;
+ crc2 = q.crc2 & 0xFF;
+
+ /*
+ * Per RED Book, CRC Bits on disk are inverted.
+ * Invert them again to make calcCRC() work.
+ */
+ q.crc1 ^= 0xFF;
+ q.crc2 ^= 0xFF;
+
+ ocrc = calcCRC((Uchar *)&q, 12);
+ printf("AC: %02X t: %3d (%02X) i: %3d (%02X) %d:%d:%d %d:%d:%d %02X%02X %X (%X)\n",
+ q.ctrl_adr,
+ b(q.track),
+ b(q.track) & 0xFF,
+ b(q.index),
+ q.index & 0xFF,
+ b(q.pmin),
+ b(q.psec),
+ b(q.pframe),
+ b(q.amin),
+ b(q.asec),
+ b(q.aframe),
+ crc1, crc2,
+ ocrc,
+ fillcrc((Uchar *)&q, 12) & 0xFFFF);
+}
+#endif /* TEST_CRC */
+
+#ifdef sss
+96 / 24 = 4
+
+index 1 < - > 18
+index 2 < - > 5
+index 3 < - > 23
+
+delay index mod 8
+#endif
+
+/*
+ * Sub 96 Bytes Interleave
+ */
+static void
+subinterleave(Uchar *sub)
+{
+ Uchar *p;
+ int i;
+
+ for (i = 0, p = sub; i < 4; i++) {
+ Uchar save;
+
+ /*
+ * index 1 < - > 18
+ * index 2 < - > 5
+ * index 3 < - > 23
+ */
+ save = p[1];
+ p[1] = p[18];
+ p[18] = save;
+
+ save = p[2];
+ p[2] = p[5];
+ p[5] = save;
+
+ save = p[3];
+ p[3] = p[23];
+ p[23] = save;
+
+ p += 24;
+ }
+}