1 /* $NetBSD: fwdv.c,v 1.2 2007/11/06 17:02:15 kiyohara Exp $ */
4 * Hidetoshi Shimokawa. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
17 * This product includes software developed by Hidetoshi Shimokawa.
19 * 4. Neither the name of the author nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * $FreeBSD: src/usr.sbin/fwcontrol/fwdv.c,v 1.7 2007/06/17 10:20:55 simokawa Exp $
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
40 #include <sys/types.h>
43 #if __FreeBSD_version >= 500000
44 #include <arpa/inet.h>
56 #if defined(__FreeBSD__)
57 #include <dev/firewire/firewire.h>
58 #include <dev/firewire/iec68113.h>
59 #elif defined(__NetBSD__)
60 #include <dev/ieee1394/firewire.h>
61 #include <dev/ieee1394/iec68113.h>
64 #include "fwmethods.h"
73 struct frac frame_cycle
[2] = {
74 {8000*100, 2997}, /* NTSC 8000 cycle / 29.97 Hz */
75 {320, 1}, /* PAL 8000 cycle / 25 Hz */
81 struct frac pad_rate
[2] = {
82 {203, 2997}, /* = (8000 - 29.97 * 250)/(29.97 * 250) */
83 {1, 15}, /* = (8000 - 25 * 300)/(25 * 300) */
85 const char *system_name
[] = {"NTSC", "PAL"};
86 int frame_rate
[] = {30, 25};
94 #define TNBUF 100 /* XXX too large value causes block noise */
95 #define NEMPTY 10 /* depends on TNBUF */
96 #define RBUFSIZE (PSIZE * NPACKET_R)
97 #define MAXBLOCKS (300)
98 #define CYCLE_FRAC 0xc00
101 dvrecv(int d
, const char *filename
, char ich
, int count
)
103 struct fw_isochreq isoreq
;
104 struct fw_isobufreq bufreq
;
110 int len
, tlen
, npad
, fd
, k
, m
, vec
, lsystem
= -1, nb
;
111 int nblocks
[] = {250 /* NTSC */, 300 /* PAL */};
112 struct iovec wbuf
[NPACKET_R
];
114 if(strcmp(filename
, "-") == 0) {
117 fd
= open(filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0660);
119 err(EX_NOINPUT
, filename
);
121 buf
= malloc(RBUFSIZE
);
122 pad
= malloc(DSIZE
*MAXBLOCKS
);
123 memset(pad
, 0xff, DSIZE
*MAXBLOCKS
);
124 bzero(wbuf
, sizeof(wbuf
));
126 bufreq
.rx
.nchunk
= NCHUNK
;
127 bufreq
.rx
.npacket
= NPACKET_R
;
128 bufreq
.rx
.psize
= PSIZE
;
129 bufreq
.tx
.nchunk
= 0;
130 bufreq
.tx
.npacket
= 0;
132 if (ioctl(d
, FW_SSTBUF
, &bufreq
) < 0)
133 err(1, "ioctl FW_SSTBUF");
135 isoreq
.ch
= ich
& 0x3f;
136 isoreq
.tag
= (ich
>> 6) & 3;
138 if (ioctl(d
, FW_SRSTREAM
, &isoreq
) < 0)
142 while (count
<= 0 || k
<= count
) {
145 while ((len
= read(d
, buf
+ tlen
, PSIZE
146 /* RBUFSIZE - tlen */)) > 0) {
148 if (errno
== EAGAIN
) {
150 "(EAGAIN)- push 'Play'?\n");
155 err(1, "read failed");
158 if ((RBUFSIZE
- tlen
) < PSIZE
)
162 tlen
= len
= read(d
, buf
, RBUFSIZE
);
164 if (errno
== EAGAIN
) {
165 fprintf(stderr
, "(EAGAIN)\n");
170 err(1, "read failed");
174 ptr
= (u_int32_t
*) buf
;
176 pkt
= (struct fw_pkt
*) ptr
;
178 fprintf(stderr
, "%08x %08x %08x %08x\n",
179 htonl(ptr
[0]), htonl(ptr
[1]),
180 htonl(ptr
[2]), htonl(ptr
[3]));
182 ciph
= (struct ciphdr
*)(ptr
+ 1); /* skip iso header */
183 if (ciph
->fmt
!= CIP_FMT_DVCR
)
184 errx(1, "unknown format 0x%x", ciph
->fmt
);
185 ptr
= (u_int32_t
*) (ciph
+ 1); /* skip cip header */
187 if (ciph
->fdf
.dv
.cyc
!= 0xffff && k
== 0) {
188 fprintf(stderr
, "0x%04x\n", ntohs(ciph
->fdf
.dv
.cyc
));
191 if (pkt
->mode
.stream
.len
<= sizeof(struct ciphdr
))
194 for (dv
= (struct dvdbc
*)ptr
;
195 (char *)dv
< (char *)(ptr
+ ciph
->len
);
199 fprintf(stderr
, "(%d,%d) ", dv
->sct
, dv
->dseq
);
201 if (dv
->sct
== DV_SCT_HEADER
&& dv
->dseq
== 0) {
203 lsystem
= ciph
->fdf
.dv
.fs
;
205 "%s\n", system_name
[lsystem
]);
210 (dv
->payload
[0] & DV_DSF_12
) == 0)
211 dv
->payload
[0] |= DV_DSF_12
;
212 nb
= nblocks
[lsystem
];
213 fprintf(stderr
, "%d", k
%10);
215 if (m
> 0 && m
!= nb
) {
216 /* padding bad frame */
217 npad
= ((nb
- m
) % nb
);
220 fprintf(stderr
, "(%d blocks padded)",
223 wbuf
[vec
].iov_base
= pad
;
224 wbuf
[vec
++].iov_len
= npad
;
225 if (vec
>= NPACKET_R
) {
226 writev(fd
, wbuf
, vec
);
232 if (k
% frame_rate
[lsystem
] == 0) {
234 fprintf(stderr
, "\n");
239 if (k
== 0 || (count
> 0 && k
> count
))
242 wbuf
[vec
].iov_base
= (char *) dv
;
243 wbuf
[vec
++].iov_len
= DSIZE
;
244 if (vec
>= NPACKET_R
) {
245 writev(fd
, wbuf
, vec
);
249 ptr
= (u_int32_t
*)dv
;
251 if ((char *)ptr
< buf
+ tlen
)
254 writev(fd
, wbuf
, vec
);
256 if(fd
!= STDOUT_FILENO
) {
259 fprintf(stderr
, "\n");
264 dvsend(int d
, const char *filename
, char ich
, int count
)
266 struct fw_isochreq isoreq
;
267 struct fw_isobufreq bufreq
;
270 int len
, tlen
, header
, fd
, frames
, packets
, vec
, offset
, nhdr
, i
;
271 int lsystem
=-1, pad_acc
, cycle_acc
, cycle
, f_cycle
, f_frac
;
272 struct iovec wbuf
[TNBUF
*2 + NEMPTY
];
274 u_int32_t iso_data
, iso_empty
, hdr
[TNBUF
+ NEMPTY
][3];
276 struct timeval start
, end
;
279 cycle_acc
= cycle
= 0;
281 fd
= open(filename
, O_RDONLY
);
283 err(EX_NOINPUT
, filename
);
285 pbuf
= malloc(DSIZE
* TNBUF
);
286 bzero(wbuf
, sizeof(wbuf
));
288 bufreq
.rx
.nchunk
= 0;
289 bufreq
.rx
.npacket
= 0;
291 bufreq
.tx
.nchunk
= NCHUNK
;
292 bufreq
.tx
.npacket
= NPACKET_T
;
293 bufreq
.tx
.psize
= PSIZE
;
294 if (ioctl(d
, FW_SSTBUF
, &bufreq
) < 0)
295 err(1, "ioctl FW_SSTBUF");
297 isoreq
.ch
= ich
& 0x3f;
298 isoreq
.tag
= (ich
>> 6) & 3;
300 if (ioctl(d
, FW_STSTREAM
, &isoreq
) < 0)
301 err(1, "ioctl FW_STSTREAM");
304 pkt
= (struct fw_pkt
*) &iso_data
;
305 pkt
->mode
.stream
.len
= DSIZE
+ sizeof(struct ciphdr
);
306 pkt
->mode
.stream
.sy
= 0;
307 pkt
->mode
.stream
.tcode
= FWTCODE_STREAM
;
308 pkt
->mode
.stream
.chtag
= ich
;
309 iso_empty
= iso_data
;
310 pkt
= (struct fw_pkt
*) &iso_empty
;
311 pkt
->mode
.stream
.len
= sizeof(struct ciphdr
);
313 bzero(hdr
[0], sizeof(hdr
[0]));
314 hdr
[0][0] = iso_data
;
315 ciph
= (struct ciphdr
*)&hdr
[0][1];
316 ciph
->src
= 0; /* XXX */
320 ciph
->fdf
.dv
.cyc
= 0xffff;
322 for (i
= 1; i
< TNBUF
; i
++)
323 bcopy(hdr
[0], hdr
[i
], sizeof(hdr
[0]));
325 gettimeofday(&start
, NULL
);
327 fprintf(stderr
, "%08x %08x %08x\n",
328 htonl(hdr
[0]), htonl(hdr
[1]), htonl(hdr
[2]));
335 while (tlen
< DSIZE
* TNBUF
) {
336 len
= read(fd
, pbuf
+ tlen
, DSIZE
* TNBUF
- tlen
);
343 fprintf(stderr
, "\nend of file\n");
352 dv
= (struct dvdbc
*)(pbuf
+ offset
* DSIZE
);
354 header
= (dv
->sct
== 0 && dv
->dseq
== 0);
356 header
= (packets
== 0 || packets
% npackets
[lsystem
] == 0);
359 ciph
= (struct ciphdr
*)&hdr
[nhdr
][1];
362 lsystem
= ((dv
->payload
[0] & DV_DSF_12
) != 0);
363 printf("%s\n", system_name
[lsystem
]);
365 cycle_acc
= frame_cycle
[lsystem
].d
* cycle
;
367 fprintf(stderr
, "%d", frames
% 10);
369 if (count
> 0 && frames
> count
)
371 if (frames
% frame_rate
[lsystem
] == 0)
372 fprintf(stderr
, "\n");
374 f_cycle
= (cycle_acc
/ frame_cycle
[lsystem
].d
) & 0xf;
375 f_frac
= (cycle_acc
% frame_cycle
[lsystem
].d
376 * CYCLE_FRAC
) / frame_cycle
[lsystem
].d
;
378 ciph
->fdf
.dv
.cyc
= htons(f_cycle
<< 12 | f_frac
);
380 ciph
->fdf
.dv
.cyc
= htons(cycle
<< 12 | f_frac
);
382 cycle_acc
+= frame_cycle
[lsystem
].n
;
383 cycle_acc
%= frame_cycle
[lsystem
].d
* 0x10;
386 ciph
->fdf
.dv
.cyc
= 0xffff;
388 ciph
->dbc
= packets
++ % 256;
389 pad_acc
+= pad_rate
[lsystem
].n
;
390 if (pad_acc
>= pad_rate
[lsystem
].d
) {
391 pad_acc
-= pad_rate
[lsystem
].d
;
392 bcopy(hdr
[nhdr
], hdr
[nhdr
+1], sizeof(hdr
[0]));
393 hdr
[nhdr
][0] = iso_empty
;
394 wbuf
[vec
].iov_base
= (char *)hdr
[nhdr
];
395 wbuf
[vec
++].iov_len
= sizeof(hdr
[0]);
399 hdr
[nhdr
][0] = iso_data
;
400 wbuf
[vec
].iov_base
= (char *)hdr
[nhdr
];
401 wbuf
[vec
++].iov_len
= sizeof(hdr
[0]);
402 wbuf
[vec
].iov_base
= (char *)dv
;
403 wbuf
[vec
++].iov_len
= DSIZE
;
407 if (offset
* DSIZE
< tlen
)
411 len
= writev(d
, wbuf
, vec
);
413 if (errno
== EAGAIN
) {
414 fprintf(stderr
, "(EAGAIN) - push 'Play'?\n");
417 err(1, "write failed");
421 fprintf(stderr
, "\n");
423 gettimeofday(&end
, NULL
);
424 rtime
= end
.tv_sec
- start
.tv_sec
425 + (end
.tv_usec
- start
.tv_usec
) * 1e-6;
426 fprintf(stderr
, "%d frames, %.2f secs, %.2f frames/sec\n",
427 frames
, rtime
, frames
/rtime
);