Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / wodim / subchan.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)subchan.c        1.20 05/06/11 Copyright 2000-2004 J. Schilling */
14 /*
15  *      Subchannel processing
16  *
17  *      Copyright (c) 2000-2004 J. Schilling
18  */
19 /*
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.
23  *
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.
28  *
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.
32  */
33
34 #include <mconfig.h>
35 #include <stdio.h>
36 #include <unixstd.h>
37 #include <standard.h>
38 #include <utypes.h>
39 #include <schily.h>
40
41 #include <usal/scsitransp.h>
42
43 #include "wodim.h"
44 #include "crc16.h"
45
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, 
53                                                                  msf_t *mp);
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);
63
64 /*#define       TEST_CRC*/
65 #ifdef  TEST_CRC
66 static  void    testcrc(void);
67 #endif
68
69 /*Die 96 Bits == 12 Bytes haben folgendes Aussehen:*/
70
71 struct q {
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  */
78         Uchar zero;     /*  6 */
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           */
84 };
85
86 Uchar   _subq[110][12];
87 int     _nsubh;
88
89 extern  int     lverbose;
90 extern  int     xdebug;
91
92 /*
93  * Prepare master sunchannel data for RAW TOC.
94  */
95 int
96 do_leadin(track_t *trackp)
97 {
98         int     tracks = trackp->tracks;
99         msf_t   m;
100         int     ctrl;
101         int     i;
102         int     toctype = trackp[0].tracktype & TOC_MASK;
103
104         if (_nsubh) {
105                 if (xdebug)
106                         printf("Using CLONE TOC....\n");
107                 return (0);
108         }
109         if (xdebug)
110                 printf("Leadin TOC Type: %d\n", trackp[0].tracktype & TOC_MASK);
111         if (lverbose > 1) {
112                 for (i = 1; i <= tracks+1; i++)
113                         printf("Track %d start %ld\n", i, trackp[i].trackstart);
114         }
115
116 #ifdef  TEST_CRC
117         testcrc();
118 /*      exit(1);*/
119 #endif
120
121         fillbytes(_subq, sizeof (_subq), '\0');
122
123         /*
124          * Fill in point 0xA0 for first track # on disk
125          */
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;
130         /*
131          * Disk Type: 0 = AUDIO/DATA, 0x10 = CDI, 0x20 = XA mode 2
132          */
133         m.msf_sec = toc2sess[toctype & TOC_MASK];
134         m.msf_sec = from_bcd(m.msf_sec);                /* convert to BCD */
135         m.msf_frame = 0;
136         filltpoint(_subq[0], ctrl|0x01, 0xA0, &m);
137         if (lverbose > 2)
138                 usal_prbytes("", _subq[0], 12);
139
140         /*
141          * Fill in point 0xA1 for last track # on disk
142          */
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;
147         m.msf_sec = 0;
148         m.msf_frame = 0;
149         filltpoint(_subq[1], ctrl|0x01, 0xA1, &m);
150         if (lverbose > 2)
151                 usal_prbytes("", _subq[1], 12);
152
153         /*
154          * Fill in point 0xA2 for lead out start time on disk
155          */
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);
161         if (lverbose > 2)
162                 usal_prbytes("", _subq[2], 12);
163
164         /*
165          * Fill in track start times.
166          */
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 */
173                 if (lverbose > 2)
174                         usal_prbytes("", _subq[i-1+3], 12);
175         }
176         return (0);
177 }
178
179 /*
180  * Write TOC (lead-in)
181  *
182  * Use previously prepared master subchannel data to create the
183  * subchannel frames for the lead-in.
184  */
185 int
186 write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp, int leadinstart)
187 {
188         msf_t   m;
189         int     i;
190         Uint    j;
191         Uchar   *bp = usalp->bufptr;
192         Uchar   *subp;
193         Uchar   *sp;
194         int     secsize;
195         int     secspt;
196         int     bytespt;
197         long    amount;
198         int     startsec;
199         long    bytes = 0L;
200         int     textoff = 0;
201         msf_t   msf;
202
203         secsize = trackp[0].secsize;
204         secspt = trackp[0].secspt;
205         bytespt = secspt * secsize;
206
207         lba_to_msf(leadinstart, &msf);
208
209         fillbytes(bp, bytespt, '\0');
210
211         if (_nsubh) {
212                 if (xdebug)
213                         printf("Using CLONE LEADIN\n");
214         }
215         if (xdebug) {
216                 printf("Leadinstart: %d %d:%d/%d",
217                         leadinstart,
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);
222         }
223
224         startsec = leadinstart;
225         sp = bp;
226         subp = bp + 2352;
227         for (i = leadinstart, j = 0; i < -150; i++, j++) {
228                 /*
229                  * TOC hat folgende unterschiedliche Sub Q Frames:
230                  * A0           First Track
231                  * A1           Last Track
232                  * A3           Lead out start
233                  * 1..99        Tracks
234                  * ==   3 + N* tracks
235                  * Jeder Frame wird 3x wiederholt.
236                  */
237                 if (_nsubh) {
238                         if (j >= (3*_nsubh))
239                                 j = 0;
240                 } else {
241                         if (j >= (3*3 + 3*trackp->tracks))
242                                 j = 0;
243                 }
244                 lba_to_msf((long)i, &m);
245                 fillttime(_subq[j/3], &m);
246                 fillcrc(_subq[j/3], 12);
247                 if (xdebug > 2)
248                         usal_prbytes("", _subq[j/3], 12);
249                 if (is_raw16(&trackp[0])) {
250                         qpto16(subp, _subq[j/3], 0);
251                 } else {
252                         extern Uchar *textsub;
253                         extern int  textlen;
254
255                         qpto96(subp, _subq[j/3], 0);
256                         if (textsub) {
257                                 addrw(subp, &textsub[textoff]);
258                                 textoff += 96;
259                                 if (textoff >= textlen)
260                                         textoff = 0;
261                         }
262 /*                      if (is_raw96p(&trackp[0]))*/
263 /*                              subinterleave(subp);*/
264                 }
265                 if ((startsec+secspt-1) == i || i == -151) {
266                         if ((i-startsec+1) < secspt) {
267                                 secspt = i-startsec+1;
268                                 bytespt = secspt * secsize;
269                         }
270                         encsectors(trackp, bp, startsec, secspt);
271
272                         amount = write_secs(usalp, dp,
273                                         (char *)bp, startsec, bytespt, secspt, FALSE);
274                         if (amount < 0) {
275                                 printf("write leadin data: error after %ld bytes\n",
276                                                         bytes);
277                                 return (-1);
278                         }
279                         bytes += amount;
280                         startsec = i+1;
281                         sp = bp;
282                         subp = bp + 2352;
283                         continue;
284                 }
285                 sp += secsize;
286                 subp += secsize;
287         }
288         return (0);
289 }
290
291 /*
292  * Write Track 0xAA (lead-out)
293  */
294 int
295 write_leadout(SCSI *usalp, cdr_t *dp, track_t *trackp)
296 {
297         int     tracks = trackp->tracks;
298         msf_t   m;
299         msf_t   mr;
300         int     ctrl;
301         int     i;
302         int     j;
303         Uchar   *bp = usalp->bufptr;
304         Uchar   *subp;
305         Uchar   *sp;
306         int     secsize;
307         int     secspt;
308         int     bytespt;
309         long    amount;
310         long    startsec;
311         long    endsec;
312         long    bytes = 0L;
313         int     leadoutstart;
314         Uchar   sub[12];
315         BOOL    p;
316         msf_t   msf;
317
318         fillbytes(sub, 12, '\0');
319
320         secsize = trackp[tracks+1].secsize;
321         secspt = trackp[tracks+1].secspt;
322         bytespt = secspt * secsize;
323
324         leadoutstart = trackp[tracks+1].trackstart;
325         lba_to_msf(leadoutstart, &msf);
326
327         fillbytes(bp, bytespt, '\0');
328
329         if (xdebug) {
330                 printf("Leadoutstart: %d %d:%d/%d amt %ld",
331                         leadoutstart,
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);
337         }
338
339         startsec = leadoutstart;
340         endsec = startsec + trackp[tracks+1].tracksecs;
341         sp = bp;
342         subp = bp + 2352;
343         ctrl = (st2mode[trackp->sectype & ST_MASK]) << 4;
344         if (is_copy(trackp))
345                 ctrl |= TM_ALLOW_COPY << 4;
346
347         for (i = leadoutstart, j = 0; i < endsec; i++, j++) {
348
349                 lba_to_msf((long)i, &m);
350                 sec_to_msf((long)j, &mr);
351                 filldsubq(sub, ctrl|0x01, 0xAA, 1, &mr, &m);
352                 sub[1] = 0xAA;
353                 fillcrc(sub, 12);
354                 p = (j % 150) < 75;
355                 if (j < 150)
356                         p = FALSE;
357                 if (xdebug > 2)
358                         usal_prbytes(p?"P":" ", sub, 12);
359
360                 if (is_raw16(&trackp[0])) {
361                         qpto16(subp, sub, p);
362                 } else {
363                         qpto96(subp, sub, p);
364 /*                      if (is_raw96p(&trackp[0]))*/
365 /*                              subinterleave(subp);*/
366                 }
367                 if ((startsec+secspt-1) == i || i == (endsec-1)) {
368                         if ((i-startsec+1) < secspt) {
369                                 secspt = i-startsec+1;
370                                 bytespt = secspt * secsize;
371                         }
372                         encsectors(trackp, bp, startsec, secspt);
373
374                         amount = write_secs(usalp, dp,
375                                         (char *)bp, startsec, bytespt, secspt, FALSE);
376                         if (amount < 0) {
377                                 printf("write leadout data: error after %ld bytes\n",
378                                                         bytes);
379                                 return (-1);
380                         }
381                         bytes += amount;
382                         startsec = i+1;
383                         sp = bp;
384                         subp = bp + 2352;
385                         continue;
386                 }
387                 sp += secsize;
388                 subp += secsize;
389         }
390         return (0);
391 }
392
393 /*
394  * Fill in subchannel data.
395  *
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).
398  */
399 void
400 fillsubch(track_t *trackp, 
401           Uchar *sp /* Sector data pointer  */, 
402           int secno /* Starting sector #    */, 
403           int nsecs /* # of sectors to fill */)
404 {
405         msf_t   m;
406         msf_t   mr;
407         int     ctrl;
408         int     i;
409         int     rsecno;
410         int     end;
411         int     secsize = trackp->secsize;
412         int     trackno = trackp->trackno;
413         int     nindex = trackp->nindex;
414         int     curindex;
415         long    *tindex = NULL;
416         long    nextindex = 0L;
417         Uchar   sub[12];
418         Uchar   *sup;
419         char    *mcn;
420         /*
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.
424          */
425 static  long    nextmcn = -1000000L;
426 static  long    nextisrc = -1000000L;
427 static  Uchar   lastindex = 255;
428
429         fillbytes(sub, 12, '\0');
430
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");
435         }
436         sup = sp + 2352;
437         if (mcn && (nextmcn < secno || nextmcn > (secno+100))) {
438                 nextmcn = secno/100*100 + 99;
439         }
440         if (trackp->isrc && (nextisrc < secno || nextisrc > (secno+100))) {
441                 nextisrc = secno/100*100 + 49;
442         }
443         ctrl = (st2mode[trackp->sectype & ST_MASK]) << 4;
444         if (is_copy(trackp))
445                 ctrl |= TM_ALLOW_COPY << 4;
446
447 #ifdef  SUB_DEBUG
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);
450 #endif
451
452         if (rsecno < 0) {
453                 /*
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.
457                  */
458                 curindex = 0;
459                 end = trackp->trackstart;
460
461         } else if (rsecno > trackp->index0start) {
462                 /*
463                  * This track contains pregap of next track.
464                  * We currently are inside this pregap.
465                  */
466                 trackno++;
467                 curindex = 0;
468                 end = trackp->trackstart + trackp->tracksecs;
469         } else {
470                 /*
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.
476                  */
477                 end = 0;
478                 curindex = 1;
479                 if (nindex > 1) {
480                         tindex = trackp->tindex;
481                         nextindex = trackp->tracksecs;
482                         /*
483                          * find current index in list
484                          */
485                         for (curindex = nindex; curindex >= 1; curindex--) {
486                                 if (rsecno >= tindex[curindex]) {
487                                         if (curindex < nindex)
488                                                 nextindex = tindex[curindex+1];
489                                         break;
490                                 }
491                         }
492                 }
493         }
494
495         for (i = 0; i < nsecs; i++) {
496
497                 if (tindex != NULL && rsecno >= nextindex) {
498                         /*
499                          * Skip to next index in list.
500                          */
501                         if (curindex < nindex) {
502                                 curindex++;
503                                 nextindex = tindex[curindex+1];
504                         }
505                 }
506                 if (rsecno == trackp->index0start) {
507                         /*
508                          * This track contains pregap of next track.
509                          */
510                         trackno++;
511                         curindex = 0;
512                         end = trackp->trackstart + trackp->tracksecs;
513                 }
514                 lba_to_msf((long)secno, &m);
515                 if (curindex == 0)
516                         sec_to_msf((long)end-1 - secno, &mr);
517                 else
518                         sec_to_msf((long)rsecno, &mr);
519                 if (is_scms(trackp)) {
520                         if ((secno % 8) <= 3) {
521                                 ctrl &= ~(TM_ALLOW_COPY << 4);
522                         } else {
523                                 ctrl |= TM_ALLOW_COPY << 4;
524                         }
525                 }
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;
531                         } else {
532                                 nextmcn++;
533                         }
534                 }
535                 if (trackp->isrc && (secno == nextisrc)) {
536                         if (curindex == lastindex) {
537                                 fillisrc(sub, (Uchar *)trackp->isrc);
538                                 nextisrc = (secno+1)/100*100 + 49;
539                         } else {
540                                 nextisrc++;
541                         }
542                 }
543                 fillcrc(sub, 12);
544                 if (xdebug > 2)
545                         usal_prbytes(curindex == 0 ? "P":" ", sub, 12);
546                 if (is_raw16(trackp)) {
547                         qpto16(sup, sub, curindex == 0);
548                 } else {
549                         qpto96(sup, sub, curindex == 0);
550 /*                      if (is_raw96p(trackp))*/
551 /*                              subinterleave(sup);*/
552                 }
553                 lastindex = curindex;
554                 secno++;
555                 rsecno++;
556                 sup += secsize;
557         }
558 }
559
560
561 /*
562  * Fill TOC Point
563  * Ax Werte einfüllen.
564  */
565 void
566 filltpoint(Uchar *sub, int ctrl_adr, int point, msf_t *mp)
567 {
568         sub[0] = ctrl_adr;
569         sub[2] = point;
570         sub[7] = to_bcd(mp->msf_min);
571         sub[8] = to_bcd(mp->msf_sec);
572         sub[9] = to_bcd(mp->msf_frame);
573 }
574
575 /*
576  * Fill TOC time
577  * Aktuelle Zeit in TOC Sub-Q einfüllen.
578  */
579 void
580 fillttime(Uchar *sub, msf_t *mp)
581 {
582         sub[3] = to_bcd(mp->msf_min);
583         sub[4] = to_bcd(mp->msf_sec);
584         sub[5] = to_bcd(mp->msf_frame);
585 }
586
587 /*
588  * Q-Sub in Datenbereich füllen.
589  */
590 static void
591 filldsubq(Uchar *sub, int ca, int t, int i, msf_t *mrp, msf_t *mp)
592 {
593         sub[0] = ca;
594         sub[1] = to_bcd(t);
595         sub[2] = to_bcd(i);
596         sub[3] = to_bcd(mrp->msf_min);
597         sub[4] = to_bcd(mrp->msf_sec);
598         sub[5] = to_bcd(mrp->msf_frame);
599
600         sub[7] = to_bcd(mp->msf_min);
601         sub[8] = to_bcd(mp->msf_sec);
602         sub[9] = to_bcd(mp->msf_frame);
603 }
604
605 /*
606  * Fill MCN
607  * MCN konvertieren und in Sub-Q einfüllen.
608  */
609 static void
610 fillmcn(Uchar *sub, Uchar *mcn)
611 {
612         register int    i;
613         register int    c;
614
615         sub[0] = ADR_MCN;
616         for (i = 1; i <= 8; i++) {
617                 c = *mcn++;
618                 if (c >= '0' && c <= '9')
619                         sub[i] = (c - '0') << 4;
620                 else
621                         sub[i] = 0;
622
623                 if (c != '\0')
624                         c = *mcn++;
625                 if (c >= '0' && c <= '9')
626                         sub[i] |= (c - '0');
627
628                 if (c == '\0') {
629                         i++;
630                         break;
631                 }
632         }
633         for (; i <= 8; i++)
634                 sub[i] = '\0';
635 }
636
637 /*
638  * Fill ISRC
639  * ISRC konvertieren und in Sub-Q einfüllen.
640  */
641 static void
642 fillisrc(Uchar *sub, Uchar *isrc)
643 {
644         register int    i;
645         register int    j;
646         Uchar           tmp[13];
647         Uchar           *sp;
648
649         sub[0] = ADR_ISRC;
650         sp = &sub[1];
651
652         /*
653          * Convert into Sub-Q character coding
654          */
655         for (i = 0, j = 0; i < 12; i++) {
656                 if (isrc[i+j] == '-')
657                         j++;
658                 if (isrc[i+j] == '\0')
659                         break;
660                 tmp[i] = ascii2q(isrc[i+j]);
661         }
662         for (; i < 13; i++)
663                 tmp[i] = '\0';
664
665         /*
666          * The first 5 chars from e.g. "FI-BAR-99-00312"
667          */
668         sp[0]  = tmp[0] << 2;
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;
674         sp[3]  = tmp[4] << 2;
675
676         /*
677          * Now 7 digits from e.g. "FI-BAR-99-00312"
678          */
679         for (i = 4, j = 5; i < 8; i++) {
680                 sp[i]  = tmp[j++] << 4;
681                 sp[i] |= tmp[j++];
682         }
683 }
684
685 /*
686  * ASCII -> Sub-Q ISRC code conversion
687  */
688 static int
689 ascii2q(int c)
690 {
691         if (c >= '0' && c <= '9')
692                 return (c - '0');
693         else if (c >= '@' && c <= 'o')
694                 return (0x10 + c - '@');
695         return (0);
696 }
697
698 /*
699  * Q-Sub auf 16 Bytes blähen und P-Sub addieren
700  *
701  * OUT: sub, IN: subqptr
702  */
703 static void
704 qpto16(Uchar *sub, Uchar *subqptr, int dop)
705 {
706         if (sub != subqptr)
707                 movebytes(subqptr, sub, 12);
708         sub[12] = '\0';
709         sub[13] = '\0';
710         sub[14] = '\0';
711         sub[15] = '\0';
712         if (dop)
713                 sub[15] |= 0x80;
714
715 }
716
717 /*
718  * Q-Sub auf 96 Bytes blähen und P-Sub addieren
719  *
720  * OUT: sub, IN: subqptr
721  */
722 void
723 qpto96(Uchar *sub, Uchar *subqptr, int dop)
724 {
725         Uchar   tmp[16];
726         Uchar   *p;
727         int     c;
728         int     i;
729
730         if (subqptr == sub) {
731                 /*
732                  * Remember 12 byte subchannel data if subchannel
733                  * is overlapping.
734                  */
735                 movebytes(subqptr, tmp, 12);
736                 subqptr = tmp;
737         }
738         /*
739          * Clear all subchannel bits in the 96 byte target space.
740          */
741         fillbytes(sub, 96, '\0');
742
743         /* BEGIN CSTYLED */
744         if (dop) for (i = 0, p = sub; i < 96; i++) {
745                 *p++ |= 0x80;
746         }
747         for (i = 0, p = sub; i < 12; i++) {
748                 c = subqptr[i] & 0xFF;
749 /*printf("%02X\n", c);*/
750                 if (c & 0x80)
751                         *p++ |= 0x40;
752                 else
753                         p++;
754                 if (c & 0x40)
755                         *p++ |= 0x40;
756                 else
757                         p++;
758                 if (c & 0x20)
759                         *p++ |= 0x40;
760                 else
761                         p++;
762                 if (c & 0x10)
763                         *p++ |= 0x40;
764                 else
765                         p++;
766                 if (c & 0x08)
767                         *p++ |= 0x40;
768                 else
769                         p++;
770                 if (c & 0x04)
771                         *p++ |= 0x40;
772                 else
773                         p++;
774                 if (c & 0x02)
775                         *p++ |= 0x40;
776                 else
777                         p++;
778                 if (c & 0x01)
779                         *p++ |= 0x40;
780                 else
781                         p++;
782         }
783 }
784
785 /*
786  * Add R-W-Sub (96 Bytes) to P-Q-Sub (96 Bytes)
787  *
788  * OUT: sub, IN: subrwptr
789  */
790 void
791 addrw(register Uchar *sub, register Uchar *subrwptr)
792 {
793         register int    i;
794
795 #define DO8(a)  a; a; a; a; a; a; a; a;
796
797         for (i = 0; i < 12; i++) {
798                 DO8(*sub++ |= *subrwptr++ & 0x3F);
799         }
800 }
801
802 /*
803  * Q-W-Sub (96 Bytes) auf 16 Bytes schrumpfen
804  *
805  * OUT: subq, IN: subptr
806  */
807 void
808 qwto16(Uchar *subq, Uchar *subptr)
809 {
810         register int    i;
811         register int    np = 0;
812         register Uchar  *p;
813                 Uchar   tmp[96];
814
815         p = subptr;
816         for (i = 0; i < 96; i++)
817                 if (*p++ & 0x80)
818                         np++;
819         p = subptr;
820         if (subptr == subq) {
821                 /*
822                  * Remember 96 byte subchannel data if subchannel
823                  * is overlapping.
824                  */
825                 movebytes(subptr, tmp, 96);
826                 p = tmp;
827         }
828
829         for (i = 0; i < 12; i++) {
830                 subq[i] = 0;
831                 if (*p++ & 0x40)
832                         subq[i] |= 0x80;
833                 if (*p++ & 0x40)
834                         subq[i] |= 0x40;
835                 if (*p++ & 0x40)
836                         subq[i] |= 0x20;
837                 if (*p++ & 0x40)
838                         subq[i] |= 0x10;
839                 if (*p++ & 0x40)
840                         subq[i] |= 0x08;
841                 if (*p++ & 0x40)
842                         subq[i] |= 0x04;
843                 if (*p++ & 0x40)
844                         subq[i] |= 0x02;
845                 if (*p++ & 0x40)
846                         subq[i] |= 0x01;
847         }
848         subq[12] = 0;
849         subq[13] = 0;
850         subq[14] = 0;
851         if (np > (96/2))
852                 subq[15] = 0x80;
853 }
854
855 /*
856  * Recode subchannels of sectors from 2352 + 96 bytes to 2352 + 16 bytes
857  */
858 void
859 subrecodesecs(track_t *trackp, Uchar *bp, int address, int nsecs)
860 {
861         bp += 2352;
862         while (--nsecs >= 0) {
863                 qwto16(bp, bp);
864                 bp += trackp->isecsize;
865         }
866 }
867
868 #ifndef HAVE_LIB_EDC_ECC
869 void
870 encsectors(track_t *trackp, Uchar *bp, int address, int nsecs)
871 {
872         int     sectype = trackp->sectype;
873
874         if ((sectype & ST_MODE_MASK) == ST_MODE_AUDIO)
875                 return;
876
877         comerrno(EX_BAD, "Can only write audio sectors in RAW mode.\n");
878 }
879
880 void
881 scrsectors(track_t *trackp, Uchar *bp, int address, int nsecs)
882 {
883         comerrno(EX_BAD, "Cannot write in clone RAW mode.\n");
884 }
885 #endif
886
887 /*--------------------------------------------------------------------------*/
888 #ifdef  TEST_CRC
889
890 Uchar   tq[12] = { 0x01, 0x00, 0xA0, 0x98, 0x06, 0x12, 0x00, 0x01, 0x00, 0x00, 0xE3, 0x74 };
891
892 /*
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
906
907 */
908
909 static  int     b(int bcd);
910
911
912 static int
913 b(int bcd)
914 {
915         return ((bcd & 0x0F) + 10 * (((bcd)>> 4) & 0x0F));
916 }
917
918 static void
919 testcrc()
920 {
921         struct q q;
922         int     ocrc;
923         int     crc1;
924         int     crc2;
925
926         movebytes(&tq, &q, 12);
927         crc1 = q.crc1 & 0xFF;
928         crc2 = q.crc2 & 0xFF;
929
930         /*
931          * Per RED Book, CRC Bits on disk are inverted.
932          * Invert them again to make calcCRC() work.
933          */
934         q.crc1 ^= 0xFF;
935         q.crc2 ^= 0xFF;
936
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",
939                 q.ctrl_adr,
940                 b(q.track),
941                 b(q.track) & 0xFF,
942                 b(q.index),
943                 q.index & 0xFF,
944                 b(q.pmin),
945                 b(q.psec),
946                 b(q.pframe),
947                 b(q.amin),
948                 b(q.asec),
949                 b(q.aframe),
950                 crc1, crc2,
951                 ocrc,
952                 fillcrc((Uchar *)&q, 12) & 0xFFFF);
953 }
954 #endif  /* TEST_CRC */
955
956 #ifdef  sss
957 96 / 24 = 4
958
959 index 1 < - > 18
960 index 2 < - > 5
961 index 3 < - > 23
962
963 delay index mod 8
964 #endif
965
966 /*
967  * Sub 96 Bytes Interleave
968  */
969 static void
970 subinterleave(Uchar *sub)
971 {
972         Uchar   *p;
973         int     i;
974
975         for (i = 0, p = sub; i < 4; i++) {
976                 Uchar   save;
977
978                 /*
979                  * index 1 < - > 18
980                  * index 2 < - > 5
981                  * index 3 < - > 23
982                  */
983                 save  = p[1];
984                 p[1]  = p[18];
985                 p[18] = save;
986
987                 save  = p[2];
988                 p[2]  = p[5];
989                 p[5]  = save;
990
991                 save  = p[3];
992                 p[3]  = p[23];
993                 p[23] = save;
994
995                 p += 24;
996         }
997 }