cdrtools/cdrecord/subchan.c

1054 lines
21 KiB
C
Raw Permalink Normal View History

2025-06-15 04:19:58 +08:00
/* @(#)subchan.c 1.29 17/07/17 Copyright 2000-2017 J. Schilling */
#include <schily/mconfig.h>
#ifndef lint
static UConst char sccsid[] =
"@(#)subchan.c 1.29 17/07/17 Copyright 2000-2017 J. Schilling";
#endif
/*
* Subchannel processing
*
* Copyright (c) 2000-2017 J. Schilling
*/
/*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* See the file CDDL.Schily.txt in this distribution for details.
* A copy of the CDDL is also available via the Internet at
* http://www.opensource.org/licenses/cddl1.txt
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file CDDL.Schily.txt from this distribution.
*/
#include <schily/mconfig.h>
#include <schily/stdio.h>
#include <schily/unistd.h>
#include <schily/standard.h>
#include <schily/utypes.h>
#include <schily/schily.h>
#include <schily/nlsdefs.h>
#include <scg/scsitransp.h>
#include "cdrecord.h"
#include "crc16.h"
EXPORT int do_leadin __PR((track_t *trackp));
EXPORT int write_leadin __PR((SCSI *scgp, cdr_t *dp, track_t *trackp, int leadinstart));
EXPORT int write_leadout __PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
EXPORT void fillsubch __PR((track_t *trackp, Uchar *sp, int secno, int nsecs));
EXPORT void filltpoint __PR((Uchar *sub, int ctrl_adr, int point, msf_t *mp));
EXPORT void fillttime __PR((Uchar *sub, msf_t *mp));
LOCAL void filldsubq __PR((Uchar *sub, int ca, int t, int i, msf_t *mrp, msf_t *mp));
LOCAL void fillmcn __PR((Uchar *sub, Uchar *mcn));
LOCAL void fillisrc __PR((Uchar *sub, Uchar *isrc));
LOCAL int ascii2q __PR((int c));
LOCAL void qpto16 __PR((Uchar *sub, Uchar *subq, int dop));
EXPORT void qpto96 __PR((Uchar *sub, Uchar *subq, int dop));
EXPORT void addrw __PR((Uchar *sub, Uchar *subrwptr));
EXPORT void qwto16 __PR((Uchar *subq, Uchar *subptr));
EXPORT void subrecodesecs __PR((track_t *trackp, Uchar *bp, int address, int nsecs));
#ifdef DO_SUBINTERLEAVE
LOCAL void subinterleave __PR((Uchar *sub));
#endif
/*#define TEST_CRC*/
#ifdef TEST_CRC
LOCAL void testcrc __PR((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 */
};
EXPORT Uchar _subq[110][12];
EXPORT int _nsubh;
extern int lverbose;
extern int xdebug;
/*
* Prepare master sunchannel data for RAW TOC.
*/
EXPORT int
do_leadin(trackp)
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 > 1)
scg_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 > 1)
scg_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 > 1)
scg_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 > 1)
scg_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.
*/
EXPORT int
write_leadin(scgp, dp, trackp, leadinstart)
SCSI *scgp;
cdr_t *dp;
track_t *trackp;
int leadinstart;
{
msf_t m;
int i;
Uint j;
Uchar *bp = scgp->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)
scg_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;
}
#ifdef DO_SUBINTERLEAVE
/* if (is_raw96p(&trackp[0]))*/
/* subinterleave(subp);*/
#endif
}
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(scgp, 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)
*/
EXPORT int
write_leadout(scgp, dp, trackp)
SCSI *scgp;
cdr_t *dp;
track_t *trackp;
{
int tracks = trackp->tracks;
msf_t m;
msf_t mr;
int ctrl;
int i;
int j;
Uchar *bp = scgp->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)
scg_prbytes(p?"P":" ", sub, 12);
if (is_raw16(&trackp[0])) {
qpto16(subp, sub, p);
} else {
qpto96(subp, sub, p);
#ifdef DO_SUBINTERLEAVE
/* if (is_raw96p(&trackp[0]))*/
/* subinterleave(subp);*/
#endif
}
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(scgp, 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).
*/
EXPORT void
fillsubch(trackp, sp, secno, nsecs)
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;
if (trackno == 0 && is_hidden(trackp))
trackno = trackp[1].trackno;
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
error("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)
scg_prbytes(curindex == 0 ? "P":" ", sub, 12);
if (is_raw16(trackp)) {
qpto16(sup, sub, curindex == 0);
} else {
qpto96(sup, sub, curindex == 0);
#ifdef DO_SUBINTERLEAVE
/* if (is_raw96p(trackp))*/
/* subinterleave(sup);*/
#endif
}
lastindex = curindex;
secno++;
rsecno++;
sup += secsize;
}
}
/*
* Fill TOC Point
* Ax Werte einf<EFBFBD>llen.
*/
EXPORT void
filltpoint(sub, ctrl_adr, point, mp)
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<EFBFBD>llen.
*/
EXPORT void
fillttime(sub, mp)
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<EFBFBD>llen.
*/
LOCAL void
filldsubq(sub, ca, t, i, mrp, mp)
Uchar *sub;
int ca; /* Control/Addr */
int t; /* Track */
int i; /* Index */
msf_t *mrp; /* Relative time*/
msf_t *mp; /* Absolute time*/
{
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<EFBFBD>llen.
*/
LOCAL void
fillmcn(sub, mcn)
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<EFBFBD>llen.
*/
LOCAL void
fillisrc(sub, isrc)
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
*/
LOCAL int
ascii2q(c)
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<EFBFBD>hen und P-Sub addieren
*
* OUT: sub, IN: subqptr
*/
LOCAL void
qpto16(sub, subqptr, dop)
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<EFBFBD>hen und P-Sub addieren
*
* OUT: sub, IN: subqptr
*/
EXPORT void
qpto96(sub, subqptr, dop)
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
*/
EXPORT void
addrw(sub, subrwptr)
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
*/
EXPORT void
qwto16(subq, subptr)
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
*/
EXPORT void
subrecodesecs(trackp, bp, address, nsecs)
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
EXPORT void
encsectors(trackp, bp, address, nsecs)
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"));
}
EXPORT void
scrsectors(trackp, bp, address, nsecs)
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
*/
LOCAL int b __PR((int bcd));
LOCAL int
b(bcd)
int bcd;
{
return ((bcd & 0x0F) + 10 * (((bcd)>> 4) & 0x0F));
}
LOCAL 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 */
#if 0
96 / 24 = 4
index 1 < - > 18
index 2 < - > 5
index 3 < - > 23
delay index mod 8
#endif
#ifdef DO_SUBINTERLEAVE
/*
* Sub 96 Bytes Interleave
*/
LOCAL void
subinterleave(sub)
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;
}
}
#endif /* DO_SUBINTERLEAVE */