12ff0a95eSJérôme Duval/*
22ff0a95eSJérôme Duval * Copyright (C) 2003
32ff0a95eSJérôme Duval * 	Hidetoshi Shimokawa. All rights reserved.
42ff0a95eSJérôme Duval *
52ff0a95eSJérôme Duval * Redistribution and use in source and binary forms, with or without
62ff0a95eSJérôme Duval * modification, are permitted provided that the following conditions
72ff0a95eSJérôme Duval * are met:
82ff0a95eSJérôme Duval * 1. Redistributions of source code must retain the above copyright
92ff0a95eSJérôme Duval *    notice, this list of conditions and the following disclaimer.
102ff0a95eSJérôme Duval * 2. Redistributions in binary form must reproduce the above copyright
112ff0a95eSJérôme Duval *    notice, this list of conditions and the following disclaimer in the
122ff0a95eSJérôme Duval *    documentation and/or other materials provided with the distribution.
132ff0a95eSJérôme Duval * 3. All advertising materials mentioning features or use of this software
142ff0a95eSJérôme Duval *    must display the following acknowledgement:
152ff0a95eSJérôme Duval *
162ff0a95eSJérôme Duval *	This product includes software developed by Hidetoshi Shimokawa.
172ff0a95eSJérôme Duval *
182ff0a95eSJérôme Duval * 4. Neither the name of the author nor the names of its contributors
192ff0a95eSJérôme Duval *    may be used to endorse or promote products derived from this software
202ff0a95eSJérôme Duval *    without specific prior written permission.
212ff0a95eSJérôme Duval *
222ff0a95eSJérôme Duval * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232ff0a95eSJérôme Duval * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242ff0a95eSJérôme Duval * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252ff0a95eSJérôme Duval * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262ff0a95eSJérôme Duval * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272ff0a95eSJérôme Duval * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282ff0a95eSJérôme Duval * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292ff0a95eSJérôme Duval * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302ff0a95eSJérôme Duval * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312ff0a95eSJérôme Duval * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322ff0a95eSJérôme Duval * SUCH DAMAGE.
332ff0a95eSJérôme Duval *
340d7b06c3SFredrik Modéen * $FreeBSD: src/usr.sbin/fwcontrol/fwdv.c$
352ff0a95eSJérôme Duval */
362ff0a95eSJérôme Duval#include <sys/param.h>
372ff0a95eSJérôme Duval#ifndef __HAIKU__
382ff0a95eSJérôme Duval#include <sys/ioctl.h>
392ff0a95eSJérôme Duval#endif
402ff0a95eSJérôme Duval#include <sys/time.h>
412ff0a95eSJérôme Duval#include <sys/types.h>
422ff0a95eSJérôme Duval#include <sys/uio.h>
432ff0a95eSJérôme Duval
442ff0a95eSJérôme Duval#if __FreeBSD_version >= 500000 || defined(__HAIKU__)
452ff0a95eSJérôme Duval#include <arpa/inet.h>
462ff0a95eSJérôme Duval#endif
472ff0a95eSJérôme Duval
482ff0a95eSJérôme Duval#include <err.h>
492ff0a95eSJérôme Duval#include <errno.h>
502ff0a95eSJérôme Duval#include <unistd.h>
512ff0a95eSJérôme Duval#include <fcntl.h>
522ff0a95eSJérôme Duval#include <stdio.h>
532ff0a95eSJérôme Duval#include <stdlib.h>
542ff0a95eSJérôme Duval#include <string.h>
552ff0a95eSJérôme Duval#ifdef __HAIKU__
562ff0a95eSJérôme Duval#include <stdint.h>
5711b807eaSFrançois Revol#include <strings.h>
58bb5ea4ebSJérôme Duval#include <endian.h>
592ff0a95eSJérôme Duval#include "firewire.h"
602ff0a95eSJérôme Duval#include "iec68113.h"
612ff0a95eSJérôme Duval#else
622ff0a95eSJérôme Duval#include <sysexits.h>
632ff0a95eSJérôme Duval
642ff0a95eSJérôme Duval#include <dev/firewire/firewire.h>
652ff0a95eSJérôme Duval#include <dev/firewire/iec68113.h>
662ff0a95eSJérôme Duval#endif
672ff0a95eSJérôme Duval
682ff0a95eSJérôme Duval#include "fwmethods.h"
692ff0a95eSJérôme Duval
702ff0a95eSJérôme Duval#define DEBUG		0
712ff0a95eSJérôme Duval#define FIX_FRAME	1
722ff0a95eSJérôme Duval
732ff0a95eSJérôme Duvalstruct frac {
742ff0a95eSJérôme Duval	int n,d;
752ff0a95eSJérôme Duval};
762ff0a95eSJérôme Duval
772ff0a95eSJérôme Duvalstruct frac frame_cycle[2]  = {
782ff0a95eSJérôme Duval	{8000*100, 2997},	/* NTSC 8000 cycle / 29.97 Hz */
792ff0a95eSJérôme Duval	{320, 1},		/* PAL  8000 cycle / 25 Hz */
802ff0a95eSJérôme Duval};
812ff0a95eSJérôme Duvalint npackets[] = {
822ff0a95eSJérôme Duval	250		/* NTSC */,
832ff0a95eSJérôme Duval	300		/* PAL */
842ff0a95eSJérôme Duval};
852ff0a95eSJérôme Duvalstruct frac pad_rate[2]  = {
862ff0a95eSJérôme Duval	{203, 2997},	/* = (8000 - 29.97 * 250)/(29.97 * 250) */
872ff0a95eSJérôme Duval	{1, 15},	/* = (8000 - 25 * 300)/(25 * 300) */
882ff0a95eSJérôme Duval};
892ff0a95eSJérôme Duvalchar *system_name[] = {"NTSC", "PAL"};
902ff0a95eSJérôme Duvalint frame_rate[] = {30, 25};
912ff0a95eSJérôme Duval
922ff0a95eSJérôme Duval#define PSIZE 512
932ff0a95eSJérôme Duval#define DSIZE 480
942ff0a95eSJérôme Duval#define NCHUNK 64
952ff0a95eSJérôme Duval
962ff0a95eSJérôme Duval#define NPACKET_R 256
972ff0a95eSJérôme Duval#define NPACKET_T 255
982ff0a95eSJérôme Duval#define TNBUF 100	/* XXX too large value causes block noise */
992ff0a95eSJérôme Duval#define NEMPTY 10	/* depends on TNBUF */
1002ff0a95eSJérôme Duval#define RBUFSIZE (PSIZE * NPACKET_R)
1012ff0a95eSJérôme Duval#define MAXBLOCKS (300)
1022ff0a95eSJérôme Duval#define CYCLE_FRAC 0xc00
1032ff0a95eSJérôme Duval
1042ff0a95eSJérôme Duvalvoid
1052ff0a95eSJérôme Duvaldvrecv(int d, const char *filename, char ich, int count)
1062ff0a95eSJérôme Duval{
1072ff0a95eSJérôme Duval	struct fw_isochreq isoreq;
1082ff0a95eSJérôme Duval	struct fw_isobufreq bufreq;
1092ff0a95eSJérôme Duval	struct dvdbc *dv;
1102ff0a95eSJérôme Duval	struct ciphdr *ciph;
1112ff0a95eSJérôme Duval	struct fw_pkt *pkt;
1122ff0a95eSJérôme Duval	char *pad, *buf;
1132ff0a95eSJérôme Duval	u_int32_t *ptr;
1142ff0a95eSJérôme Duval	int len, tlen, npad, fd, k, m, vec, system = -1, nb;
1152ff0a95eSJérôme Duval	int nblocks[] = {250 /* NTSC */, 300 /* PAL */};
1162ff0a95eSJérôme Duval	struct iovec wbuf[NPACKET_R];
1172ff0a95eSJérôme Duval
1182ff0a95eSJérôme Duval	if(strcmp(filename, "-") == 0) {
1192ff0a95eSJérôme Duval		fd = STDOUT_FILENO;
1202ff0a95eSJérôme Duval	} else {
1212ff0a95eSJérôme Duval		fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0660);
1222ff0a95eSJérôme Duval		if (fd == -1)
1230d7b06c3SFredrik Modéen			err(EX_NOINPUT, "%s", filename);
1242ff0a95eSJérôme Duval	}
1252ff0a95eSJérôme Duval	buf = malloc(RBUFSIZE);
1262ff0a95eSJérôme Duval	pad = malloc(DSIZE*MAXBLOCKS);
1272ff0a95eSJérôme Duval	memset(pad, 0xff, DSIZE*MAXBLOCKS);
1282ff0a95eSJérôme Duval	bzero(wbuf, sizeof(wbuf));
1292ff0a95eSJérôme Duval
1302ff0a95eSJérôme Duval	bufreq.rx.nchunk = NCHUNK;
1312ff0a95eSJérôme Duval	bufreq.rx.npacket = NPACKET_R;
1322ff0a95eSJérôme Duval	bufreq.rx.psize = PSIZE;
1332ff0a95eSJérôme Duval	bufreq.tx.nchunk = 0;
1342ff0a95eSJérôme Duval	bufreq.tx.npacket = 0;
1352ff0a95eSJérôme Duval	bufreq.tx.psize = 0;
1362ff0a95eSJérôme Duval	if (ioctl(d, FW_SSTBUF, &bufreq) < 0)
1372ff0a95eSJérôme Duval		err(1, "ioctl FW_SSTBUF");
1382ff0a95eSJérôme Duval
1392ff0a95eSJérôme Duval	isoreq.ch = ich & 0x3f;
1402ff0a95eSJérôme Duval	isoreq.tag = (ich >> 6) & 3;
1412ff0a95eSJérôme Duval
1422ff0a95eSJérôme Duval	if (ioctl(d, FW_SRSTREAM, &isoreq) < 0)
1432ff0a95eSJérôme Duval       		err(1, "ioctl");
1442ff0a95eSJérôme Duval
1452ff0a95eSJérôme Duval	k = m = 0;
1462ff0a95eSJérôme Duval	while (count <= 0 || k <= count) {
1472ff0a95eSJérôme Duval#if 0
1482ff0a95eSJérôme Duval		tlen = 0;
1492ff0a95eSJérôme Duval		while ((len = read(d, buf + tlen, PSIZE
1502ff0a95eSJérôme Duval						/* RBUFSIZE - tlen */)) > 0) {
1512ff0a95eSJérôme Duval			if (len < 0) {
1522ff0a95eSJérôme Duval				if (errno == EAGAIN) {
1532ff0a95eSJérôme Duval					fprintf(stderr, "(EAGAIN)\n");
1542ff0a95eSJérôme Duval					fflush(stderr);
1552ff0a95eSJérôme Duval					if (len <= 0)
1562ff0a95eSJérôme Duval						continue;
1572ff0a95eSJérôme Duval				} else
1582ff0a95eSJérôme Duval					err(1, "read failed");
1592ff0a95eSJérôme Duval			}
1602ff0a95eSJérôme Duval			tlen += len;
1612ff0a95eSJérôme Duval			if ((RBUFSIZE - tlen) < PSIZE)
1622ff0a95eSJérôme Duval				break;
1632ff0a95eSJérôme Duval		};
1642ff0a95eSJérôme Duval#else
1652ff0a95eSJérôme Duval		tlen = len = read(d, buf, RBUFSIZE);
1662ff0a95eSJérôme Duval		if (len < 0) {
1672ff0a95eSJérôme Duval			if (errno == EAGAIN) {
1682ff0a95eSJérôme Duval				fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
1692ff0a95eSJérôme Duval				fflush(stderr);
1702ff0a95eSJérôme Duval				if (len <= 0)
1712ff0a95eSJérôme Duval					continue;
1722ff0a95eSJérôme Duval			} else
1732ff0a95eSJérôme Duval				err(1, "read failed");
1742ff0a95eSJérôme Duval		}
1752ff0a95eSJérôme Duval#endif
1762ff0a95eSJérôme Duval		vec = 0;
1772ff0a95eSJérôme Duval		ptr = (u_int32_t *) buf;
1782ff0a95eSJérôme Duvalagain:
1792ff0a95eSJérôme Duval		pkt = (struct fw_pkt *) ptr;
1802ff0a95eSJérôme Duval#if DEBUG
1812ff0a95eSJérôme Duval		fprintf(stderr, "%08x %08x %08x %08x\n",
1822ff0a95eSJérôme Duval			htonl(ptr[0]), htonl(ptr[1]),
1832ff0a95eSJérôme Duval			htonl(ptr[2]), htonl(ptr[3]));
1842ff0a95eSJérôme Duval#endif
1852ff0a95eSJérôme Duval		ciph = (struct ciphdr *)(ptr + 1);	/* skip iso header */
1862ff0a95eSJérôme Duval		if (ciph->fmt != CIP_FMT_DVCR)
1872ff0a95eSJérôme Duval			errx(1, "unknown format 0x%x", ciph->fmt);
1882ff0a95eSJérôme Duval		ptr = (u_int32_t *) (ciph + 1);		/* skip cip header */
1892ff0a95eSJérôme Duval#if DEBUG
1902ff0a95eSJérôme Duval		if (ciph->fdf.dv.cyc != 0xffff && k == 0) {
1912ff0a95eSJérôme Duval			fprintf(stderr, "0x%04x\n", ntohs(ciph->fdf.dv.cyc));
1922ff0a95eSJérôme Duval		}
1932ff0a95eSJérôme Duval#endif
1942ff0a95eSJérôme Duval		if (pkt->mode.stream.len <= sizeof(struct ciphdr))
1952ff0a95eSJérôme Duval			/* no payload */
1962ff0a95eSJérôme Duval			goto next;
1972ff0a95eSJérôme Duval		for (dv = (struct dvdbc *)ptr;
1982ff0a95eSJérôme Duval				(char *)dv < (char *)(ptr + ciph->len);
1992ff0a95eSJérôme Duval				dv+=6) {
2002ff0a95eSJérôme Duval
2012ff0a95eSJérôme Duval#if DEBUG
2022ff0a95eSJérôme Duval			fprintf(stderr, "(%d,%d) ", dv->sct, dv->dseq);
2032ff0a95eSJérôme Duval#endif
2042ff0a95eSJérôme Duval			if  (dv->sct == DV_SCT_HEADER && dv->dseq == 0) {
2052ff0a95eSJérôme Duval				if (system < 0) {
2062ff0a95eSJérôme Duval					system = ciph->fdf.dv.fs;
2072ff0a95eSJérôme Duval					fprintf(stderr, "%s\n", system_name[system]);
2082ff0a95eSJérôme Duval				}
2092ff0a95eSJérôme Duval
2102ff0a95eSJérôme Duval				/* Fix DSF bit */
2112ff0a95eSJérôme Duval				if (system == 1 &&
2122ff0a95eSJérôme Duval					(dv->payload[0] & DV_DSF_12) == 0)
2132ff0a95eSJérôme Duval					dv->payload[0] |= DV_DSF_12;
2142ff0a95eSJérôme Duval				nb = nblocks[system];
2151719f7a6SStephan Aßmus 				fprintf(stderr, "%d:%02d:%02d %d\r",
2161719f7a6SStephan Aßmus					k / (3600 * frame_rate[system]),
2171719f7a6SStephan Aßmus					(k / (60 * frame_rate[system])) % 60,
2181719f7a6SStephan Aßmus					(k / frame_rate[system]) % 60,
2191719f7a6SStephan Aßmus					k % frame_rate[system]);
2201719f7a6SStephan Aßmus
2212ff0a95eSJérôme Duval#if FIX_FRAME
2222ff0a95eSJérôme Duval				if (m > 0 && m != nb) {
2232ff0a95eSJérôme Duval					/* padding bad frame */
2242ff0a95eSJérôme Duval					npad = ((nb - m) % nb);
2252ff0a95eSJérôme Duval					if (npad < 0)
2262ff0a95eSJérôme Duval						npad += nb;
2271719f7a6SStephan Aßmus					fprintf(stderr, "\n%d blocks padded\n",
2280d7b06c3SFredrik Modéen					    npad);
2292ff0a95eSJérôme Duval					npad *= DSIZE;
2302ff0a95eSJérôme Duval					wbuf[vec].iov_base = pad;
2312ff0a95eSJérôme Duval					wbuf[vec++].iov_len = npad;
2322ff0a95eSJérôme Duval					if (vec >= NPACKET_R) {
2332ff0a95eSJérôme Duval						writev(fd, wbuf, vec);
2342ff0a95eSJérôme Duval						vec = 0;
2352ff0a95eSJérôme Duval					}
2362ff0a95eSJérôme Duval				}
2372ff0a95eSJérôme Duval#endif
2382ff0a95eSJérôme Duval				k++;
2392ff0a95eSJérôme Duval				fflush(stderr);
2402ff0a95eSJérôme Duval				m = 0;
2412ff0a95eSJérôme Duval			}
2422ff0a95eSJérôme Duval			if (k == 0 || (count > 0 && k > count))
2432ff0a95eSJérôme Duval				continue;
2442ff0a95eSJérôme Duval			m++;
2452ff0a95eSJérôme Duval			wbuf[vec].iov_base = (char *) dv;
2462ff0a95eSJérôme Duval			wbuf[vec++].iov_len = DSIZE;
2472ff0a95eSJérôme Duval			if (vec >= NPACKET_R) {
2482ff0a95eSJérôme Duval				writev(fd, wbuf, vec);
2492ff0a95eSJérôme Duval				vec = 0;
2502ff0a95eSJérôme Duval			}
2512ff0a95eSJérôme Duval		}
2522ff0a95eSJérôme Duval		ptr = (u_int32_t *)dv;
2532ff0a95eSJérôme Duvalnext:
2542ff0a95eSJérôme Duval		if ((char *)ptr < buf + tlen)
2552ff0a95eSJérôme Duval			goto again;
2562ff0a95eSJérôme Duval		if (vec > 0)
2572ff0a95eSJérôme Duval			writev(fd, wbuf, vec);
2582ff0a95eSJérôme Duval	}
2590d7b06c3SFredrik Modéen	if (fd != STDOUT_FILENO)
2602ff0a95eSJérôme Duval		close(fd);
2612ff0a95eSJérôme Duval	fprintf(stderr, "\n");
2622ff0a95eSJérôme Duval}
2632ff0a95eSJérôme Duval
2642ff0a95eSJérôme Duval
2652ff0a95eSJérôme Duvalvoid
2662ff0a95eSJérôme Duvaldvsend(int d, const char *filename, char ich, int count)
2672ff0a95eSJérôme Duval{
2682ff0a95eSJérôme Duval	struct fw_isochreq isoreq;
2692ff0a95eSJérôme Duval	struct fw_isobufreq bufreq;
2702ff0a95eSJérôme Duval	struct dvdbc *dv;
2712ff0a95eSJérôme Duval	struct fw_pkt *pkt;
2722ff0a95eSJérôme Duval	int len, tlen, header, fd, frames, packets, vec, offset, nhdr, i;
2732ff0a95eSJérôme Duval	int system=-1, pad_acc, cycle_acc, cycle, f_cycle, f_frac;
2742ff0a95eSJérôme Duval	struct iovec wbuf[TNBUF*2 + NEMPTY];
2752ff0a95eSJérôme Duval	char *pbuf;
2762ff0a95eSJérôme Duval	u_int32_t iso_data, iso_empty, hdr[TNBUF + NEMPTY][3];
2772ff0a95eSJérôme Duval	struct ciphdr *ciph;
2782ff0a95eSJérôme Duval	struct timeval start, end;
2792ff0a95eSJérôme Duval	double rtime;
2802ff0a95eSJérôme Duval
2812ff0a95eSJérôme Duval	fd = open(filename, O_RDONLY);
2822ff0a95eSJérôme Duval	if (fd == -1)
2830d7b06c3SFredrik Modéen		err(EX_NOINPUT, "%s", filename);
2842ff0a95eSJérôme Duval
2852ff0a95eSJérôme Duval	pbuf = malloc(DSIZE * TNBUF);
2862ff0a95eSJérôme Duval	bzero(wbuf, sizeof(wbuf));
2872ff0a95eSJérôme Duval
2882ff0a95eSJérôme Duval	bufreq.rx.nchunk = 0;
2892ff0a95eSJérôme Duval	bufreq.rx.npacket = 0;
2902ff0a95eSJérôme Duval	bufreq.rx.psize = 0;
2912ff0a95eSJérôme Duval	bufreq.tx.nchunk = NCHUNK;
2922ff0a95eSJérôme Duval	bufreq.tx.npacket = NPACKET_T;
2932ff0a95eSJérôme Duval	bufreq.tx.psize = PSIZE;
2942ff0a95eSJérôme Duval	if (ioctl(d, FW_SSTBUF, &bufreq) < 0)
2952ff0a95eSJérôme Duval		err(1, "ioctl FW_SSTBUF");
2962ff0a95eSJérôme Duval
2972ff0a95eSJérôme Duval	isoreq.ch = ich & 0x3f;
2982ff0a95eSJérôme Duval	isoreq.tag = (ich >> 6) & 3;
2992ff0a95eSJérôme Duval
3002ff0a95eSJérôme Duval	if (ioctl(d, FW_STSTREAM, &isoreq) < 0)
3012ff0a95eSJérôme Duval       		err(1, "ioctl FW_STSTREAM");
3022ff0a95eSJérôme Duval
3032ff0a95eSJérôme Duval	iso_data = 0;
3042ff0a95eSJérôme Duval	pkt = (struct fw_pkt *) &iso_data;
3052ff0a95eSJérôme Duval	pkt->mode.stream.len = DSIZE + sizeof(struct ciphdr);
3062ff0a95eSJérôme Duval	pkt->mode.stream.sy = 0;
3072ff0a95eSJérôme Duval	pkt->mode.stream.tcode = FWTCODE_STREAM;
3082ff0a95eSJérôme Duval	pkt->mode.stream.chtag = ich;
3092ff0a95eSJérôme Duval	iso_empty = iso_data;
3102ff0a95eSJérôme Duval	pkt = (struct fw_pkt *) &iso_empty;
3112ff0a95eSJérôme Duval	pkt->mode.stream.len = sizeof(struct ciphdr);
3122ff0a95eSJérôme Duval
3132ff0a95eSJérôme Duval	bzero(hdr[0], sizeof(hdr[0]));
3142ff0a95eSJérôme Duval	hdr[0][0] = iso_data;
3152ff0a95eSJérôme Duval	ciph = (struct ciphdr *)&hdr[0][1];
3162ff0a95eSJérôme Duval	ciph->src = 0;	 /* XXX */
3172ff0a95eSJérôme Duval	ciph->len = 120;
3182ff0a95eSJérôme Duval	ciph->dbc = 0;
3192ff0a95eSJérôme Duval	ciph->eoh1 = 1;
3202ff0a95eSJérôme Duval	ciph->fdf.dv.cyc = 0xffff;
3212ff0a95eSJérôme Duval
3222ff0a95eSJérôme Duval	for (i = 1; i < TNBUF; i++)
3232ff0a95eSJérôme Duval		bcopy(hdr[0], hdr[i], sizeof(hdr[0]));
3242ff0a95eSJérôme Duval
3252ff0a95eSJérôme Duval	gettimeofday(&start, NULL);
3262ff0a95eSJérôme Duval#if DEBUG
3272ff0a95eSJérôme Duval	fprintf(stderr, "%08x %08x %08x\n",
3282ff0a95eSJérôme Duval			htonl(hdr[0]), htonl(hdr[1]), htonl(hdr[2]));
3292ff0a95eSJérôme Duval#endif
3302ff0a95eSJérôme Duval	frames = 0;
3312ff0a95eSJérôme Duval	packets = 0;
3322ff0a95eSJérôme Duval	pad_acc = 0;
3332ff0a95eSJérôme Duval	while (1) {
3342ff0a95eSJérôme Duval		tlen = 0;
3352ff0a95eSJérôme Duval		while (tlen < DSIZE * TNBUF) {
3362ff0a95eSJérôme Duval			len = read(fd, pbuf + tlen, DSIZE * TNBUF - tlen);
3372ff0a95eSJérôme Duval			if (len <= 0) {
3382ff0a95eSJérôme Duval				if (tlen > 0)
3392ff0a95eSJérôme Duval					break;
3402ff0a95eSJérôme Duval				if (len < 0)
3412ff0a95eSJérôme Duval					warn("read");
3422ff0a95eSJérôme Duval				else
3432ff0a95eSJérôme Duval					fprintf(stderr, "\nend of file\n");
3442ff0a95eSJérôme Duval				goto send_end;
3452ff0a95eSJérôme Duval			}
3462ff0a95eSJérôme Duval			tlen += len;
3472ff0a95eSJérôme Duval		}
3482ff0a95eSJérôme Duval		vec = 0;
3492ff0a95eSJérôme Duval		offset = 0;
3502ff0a95eSJérôme Duval		nhdr = 0;
3512ff0a95eSJérôme Duvalnext:
3522ff0a95eSJérôme Duval		dv = (struct dvdbc *)(pbuf + offset * DSIZE);
3532ff0a95eSJérôme Duval#if 0
3542ff0a95eSJérôme Duval		header = (dv->sct == 0 && dv->dseq == 0);
3552ff0a95eSJérôme Duval#else
3562ff0a95eSJérôme Duval		header = (packets == 0 || packets % npackets[system] == 0);
3572ff0a95eSJérôme Duval#endif
3582ff0a95eSJérôme Duval
3592ff0a95eSJérôme Duval		ciph = (struct ciphdr *)&hdr[nhdr][1];
3602ff0a95eSJérôme Duval		if (header) {
3612ff0a95eSJérôme Duval			if (system < 0) {
3622ff0a95eSJérôme Duval				system = ((dv->payload[0] & DV_DSF_12) != 0);
3632ff0a95eSJérôme Duval				printf("%s\n", system_name[system]);
3642ff0a95eSJérôme Duval				cycle = 1;
3652ff0a95eSJérôme Duval				cycle_acc = frame_cycle[system].d * cycle;
3662ff0a95eSJérôme Duval			}
3672ff0a95eSJérôme Duval			fprintf(stderr, "%d", frames % 10);
3682ff0a95eSJérôme Duval			frames ++;
3692ff0a95eSJérôme Duval			if (count > 0 && frames > count)
3702ff0a95eSJérôme Duval				break;
3712ff0a95eSJérôme Duval			if (frames % frame_rate[system] == 0)
3722ff0a95eSJérôme Duval				fprintf(stderr, "\n");
3732ff0a95eSJérôme Duval			fflush(stderr);
3742ff0a95eSJérôme Duval			f_cycle = (cycle_acc / frame_cycle[system].d) & 0xf;
3752ff0a95eSJérôme Duval			f_frac = (cycle_acc % frame_cycle[system].d
3762ff0a95eSJérôme Duval					* CYCLE_FRAC) / frame_cycle[system].d;
3772ff0a95eSJérôme Duval#if 0
3782ff0a95eSJérôme Duval			ciph->fdf.dv.cyc = htons(f_cycle << 12 | f_frac);
3792ff0a95eSJérôme Duval#else
3802ff0a95eSJérôme Duval			ciph->fdf.dv.cyc = htons(cycle << 12 | f_frac);
3812ff0a95eSJérôme Duval#endif
3822ff0a95eSJérôme Duval			cycle_acc += frame_cycle[system].n;
3832ff0a95eSJérôme Duval			cycle_acc %= frame_cycle[system].d * 0x10;
3842ff0a95eSJérôme Duval
3852ff0a95eSJérôme Duval		} else {
3862ff0a95eSJérôme Duval			ciph->fdf.dv.cyc = 0xffff;
3872ff0a95eSJérôme Duval		}
3882ff0a95eSJérôme Duval		ciph->dbc = packets++ % 256;
3892ff0a95eSJérôme Duval		pad_acc += pad_rate[system].n;
3902ff0a95eSJérôme Duval		if (pad_acc >= pad_rate[system].d) {
3912ff0a95eSJérôme Duval			pad_acc -= pad_rate[system].d;
3922ff0a95eSJérôme Duval			bcopy(hdr[nhdr], hdr[nhdr+1], sizeof(hdr[0]));
3932ff0a95eSJérôme Duval			hdr[nhdr][0] = iso_empty;
3942ff0a95eSJérôme Duval			wbuf[vec].iov_base = (char *)hdr[nhdr];
3952ff0a95eSJérôme Duval			wbuf[vec++].iov_len = sizeof(hdr[0]);
3962ff0a95eSJérôme Duval			nhdr ++;
3972ff0a95eSJérôme Duval			cycle ++;
3982ff0a95eSJérôme Duval		}
3992ff0a95eSJérôme Duval		hdr[nhdr][0] = iso_data;
4002ff0a95eSJérôme Duval		wbuf[vec].iov_base = (char *)hdr[nhdr];
4012ff0a95eSJérôme Duval		wbuf[vec++].iov_len = sizeof(hdr[0]);
4022ff0a95eSJérôme Duval		wbuf[vec].iov_base = (char *)dv;
4032ff0a95eSJérôme Duval		wbuf[vec++].iov_len = DSIZE;
4042ff0a95eSJérôme Duval		nhdr ++;
4052ff0a95eSJérôme Duval		cycle ++;
4062ff0a95eSJérôme Duval		offset ++;
4072ff0a95eSJérôme Duval		if (offset * DSIZE < tlen)
4082ff0a95eSJérôme Duval			goto next;
4092ff0a95eSJérôme Duval
4102ff0a95eSJérôme Duvalagain:
4112ff0a95eSJérôme Duval		len = writev(d, wbuf, vec);
4122ff0a95eSJérôme Duval		if (len < 0) {
4132ff0a95eSJérôme Duval			if (errno == EAGAIN) {
4142ff0a95eSJérôme Duval				fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
4152ff0a95eSJérôme Duval				goto again;
4162ff0a95eSJérôme Duval			}
4172ff0a95eSJérôme Duval			err(1, "write failed");
4182ff0a95eSJérôme Duval		}
4192ff0a95eSJérôme Duval	}
4202ff0a95eSJérôme Duval	close(fd);
4212ff0a95eSJérôme Duval	fprintf(stderr, "\n");
4222ff0a95eSJérôme Duvalsend_end:
4232ff0a95eSJérôme Duval	gettimeofday(&end, NULL);
4242ff0a95eSJérôme Duval	rtime = end.tv_sec - start.tv_sec
4252ff0a95eSJérôme Duval			+ (end.tv_usec - start.tv_usec) * 1e-6;
4262ff0a95eSJérôme Duval	fprintf(stderr, "%d frames, %.2f secs, %.2f frames/sec\n",
4272ff0a95eSJérôme Duval			frames, rtime, frames/rtime);
4282ff0a95eSJérôme Duval}
429