Skip to content

fwcam(4)

Source: sys/dev/firewire/fwcam.c, fwcam.h, with shared iso plumbing in fw_helpers.h. Registers with video(4).

A driver for IIDC/DCAM cameras, the 1394 Trade Association’s camera protocol. It matches any unit directory with spec id 0x00a02d and an IIDC software version (1.04, 1.20, 1.30), no vendor list. Control is async quadlet reads and writes into a register block; video arrives as isochronous packets that get assembled into frames and handed to video(4), which owns /dev/videoN.

One CROM wrinkle earns a comment in the code: the command base register offset normally sits in the unit directory, but the Apple iSight buries it inside a nested logical unit directory, so the search recurses two levels deep.

Attach touches no hardware. The camera is powered on and its capabilities read on first open, from a taskqueue, because power-on can take five seconds of polling and nobody wants that in attach.

Openers sleep up to ten seconds waiting for PROBING to resolve. Capabilities are inquiry bitmaps read from the camera itself: supported formats, per-format modes, per-mode frame rates, and a feature matrix from brightness to focus, each feature a live CSR with present, auto, manual, min and max bits.

The enable sequence follows the IIDC spec’s ordering, with one quirk:

  1. Write format, mode, frame rate.
  2. Read the error status register; if the camera flags the combination, fail with EINVAL before touching ISO_EN.
  3. Write the iso channel and speed.
  4. Write ISO_EN. If this returns EIO, power the camera on again and retry once: cameras with a closed lens cover power down the sensor and NAK the enable.
  5. Only then enable the host IR DMA context.

There is no IRM bandwidth or channel allocation; the channel is the hw.firewire.fwcam.iso_channel tunable (default 0), and the OHCI context filters on it in hardware. 256 mbuf-cluster chunks ride the receive ring.

Packets arrive via the firewire taskqueue, not hard interrupt, which is why the handler can take a regular mutex and memcpy entire frames.

If userland has no buffer queued when a frame completes, the frame is dropped silently: video(4)‘s acquire returns NULL and only the driver’s counter notices.

The FireWire core delivers post_busreset callbacks only to bus-level children, and fwcam is a unit child, so it never hears about resets. What that means in practice:

  • Register access self-heals: the node id is re-read from the device structure on every transaction, and bus explore updates it in place.
  • A live stream does not. The IIDC spec has cameras clear ISO_EN on reset, and there is no re-arm path: the stream goes silent, state stays STREAMING, and userland has to stop and restart. No watchdog catches the stall.
  • A camera that disappears ages out of the bus and the unit child is detached properly.

Stop claims ownership by atomically setting dma_ch to -1, disables host DMA first, writes ISO_EN off at the camera, then sleeps until the in-flight input handler drains: the handler sees the dead dma_ch and skips its re-arm. Only then do the ring and frame buffer go away.

Terminal window
kldload firewire fwcam video
ls /dev/video* # the camera is a video(4) node

Controls map to V4L2 ids: brightness, exposure, sharpness, white balance, hue, saturation, gamma, gain, focus. Each get and set is a live quadlet transaction to the feature CSR.