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