Skip to content

fwdv(4)

Source: sys/dev/firewire/fwdv.c, fwdv.h, CIP and DIF structures in iec68113.h, shared iso plumbing in fw_helpers.h.

A receive-only driver for DV camcorders: IEC 61883-2 isochronous input plus AV/C tape transport control over FCP. It matches any 1394TA AV/C unit (spec id 0x00a02d, version 0x010001), presents /dev/fwdvN, and each read(2) returns one complete raw DIF frame: concatenate them and you have a .dv file ffmpeg plays directly.

It is a listener, deliberately. No IRM bandwidth allocation, no oPCR connection management; it reads the camcorder’s oPCR[0] once, and if the output is online, uses whatever channel the camera already broadcasts on (default tunable: channel 63, the broadcast channel).

Transport control is the AV/C command set carried by FCP: block writes to 0xfffff0000b00 on the target, responses arriving as writes back to 0xfffff0000d00 on the host, where the driver holds a bind with four pre-posted receive buffers. Commands serialize on a busy flag; a response of INTERIM re-arms the wait, up to three times three seconds.

Four ioctls map to tape subunit opcodes: FWDV_PLAY, FWDV_STOP, FWDV_FFWD, FWDV_REW. Success means the deck answered ACCEPTED, not that the tape moved: it is a camcorder, promises are aspirational.

First open starts the stream, further opens share it, last close tears it down.

A concurrent open during STARTING sleeps up to five seconds for the race winner to finish.

Each iso packet is a 4-byte iso header, an 8-byte CIP header, then 80-byte DIF blocks. The CIP header carries the format (only DVCR is accepted), and its FDF field says NTSC or PAL and SD or HD. The first data packet latches the frame size: 120,000 bytes NTSC, 144,000 PAL, 200,000 DVCPRO-HD.

Frame boundaries come from the DIF blocks themselves: a HEADER-section block with sequence number 0 starts a frame. SYT timestamps in the CIP header are ignored entirely; cadence is DIF structure, nothing else.

Double buffering with freshest-frame-wins: if the previous frame was never read, the swap still happens and the old one counts as dropped. The reader sets read_in_progress before its unlocked uiomove, and the iso side drops rather than swaps into a buffer being copied out. One PAL quirk: some cameras signal PAL in the CIP but leave the DSF bit clear in the header DIF, so the driver forces it.

Unit children get no bus reset callbacks, and the running IR context is not stopped by one: capture just resumes when the talker does, on the same channel. If the camera renegotiates onto a different channel, the stream goes silent until close and reopen, since the channel is chosen only at stream start. AV/C keeps working across resets because the node id is re-read per command. And the OHCI resume path re-arms running IR contexts, so capture even survives S3.

Terminal window
kldload firewire fwdv
./dvctl play # FWDV_PLAY ioctl
cat /dev/fwdv0 > tape.dv # one DIF frame per read
ffplay tape.dv

FWDV_GINFO returns state, channel, detected system, frame size, frame and drop counters, the EUI-64 and the CROM vendor/model strings.