Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162722878
D58202.id181858.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D58202.id181858.diff
View Options
diff --git a/share/man/man4/fwcam.4 b/share/man/man4/fwcam.4
--- a/share/man/man4/fwcam.4
+++ b/share/man/man4/fwcam.4
@@ -3,7 +3,7 @@
.\"
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
-.Dd June 19, 2026
+.Dd July 12, 2026
.Dt FWCAM 4
.Os
.Sh NAME
@@ -16,7 +16,20 @@
The
.Nm
driver provides support for IIDC (Instrumentation and Industrial Digital
-Camera) v1.30 cameras attached via IEEE 1394 (FireWire).
+Camera) v1.04/v1.20/v1.30 cameras attached via IEEE 1394 (FireWire).
+.Pp
+The driver attaches to unit directories in the device CSR configuration ROM
+with
+.Va unit_spec_id
+0x00a02d (1394 Trade Association) and
+.Va unit_sw_version
+matching IIDC v1.04, v1.20, or v1.30.
+The IIDC command base address is located within the unit directory
+or a nested logical unit directory.
+.Pp
+Camera hardware probing is deferred until the device is first opened.
+This avoids bus resets on controllers where early register access
+destabilizes the link.
.Pp
Video frames are received over an isochronous DMA channel and exposed
through a character device.
diff --git a/sys/dev/firewire/fwcam.h b/sys/dev/firewire/fwcam.h
--- a/sys/dev/firewire/fwcam.h
+++ b/sys/dev/firewire/fwcam.h
@@ -203,9 +203,10 @@
/* fwcam state values (visible to userland via fwcam_info.state) */
#define FWCAM_STATE_IDLE 0
-#define FWCAM_STATE_PROBED 1
-#define FWCAM_STATE_STREAMING 2
-#define FWCAM_STATE_DETACHING 3
+#define FWCAM_STATE_PROBING 1
+#define FWCAM_STATE_PROBED 2
+#define FWCAM_STATE_STREAMING 3
+#define FWCAM_STATE_DETACHING 4
/* IIDC format/mode/rate/feature/state name tables for userland and driver */
#define FWCAM_FMT_NMAX 8
@@ -248,6 +249,7 @@
static const char * const fwcam_state_names[] = {
[FWCAM_STATE_IDLE] = "idle",
+ [FWCAM_STATE_PROBING] = "probing",
[FWCAM_STATE_PROBED] = "probed",
[FWCAM_STATE_STREAMING] = "streaming",
[FWCAM_STATE_DETACHING] = "detaching",
diff --git a/sys/dev/firewire/fwcam.c b/sys/dev/firewire/fwcam.c
--- a/sys/dev/firewire/fwcam.c
+++ b/sys/dev/firewire/fwcam.c
@@ -52,13 +52,10 @@
printf("fwcam: " fmt, ## __VA_ARGS__); \
} while (0)
-static void fwcam_identify(driver_t *, device_t);
static int fwcam_probe(device_t);
static int fwcam_attach(device_t);
static int fwcam_detach(device_t);
-static void fwcam_post_busreset(void *);
static void fwcam_probe_task(void *, int);
-static void fwcam_post_explore(void *);
static int fwcam_iso_start(struct fwcam_softc *);
static void fwcam_iso_stop(struct fwcam_softc *);
static void fwcam_iso_input(struct fw_xferq *);
@@ -80,25 +77,56 @@
.d_name = "fwcam",
};
+/*
+ * Search a CSR directory for the IIDC command base register (key 0x40).
+ * The iSight places cmd_base inside a logical_unit_directory nested
+ * within the IIDC unit directory, so we recurse into sub-directories
+ * up to max_depth levels.
+ */
static uint32_t
-fwcam_find_iidc(struct fw_device *fwdev)
+fwcam_search_dir_cmd_base(uint32_t *csrrom, uint32_t dir_qoff,
+ uint32_t rom_quads, int max_depth)
{
- struct crom_context cc;
+ struct csrdirectory *dir;
struct csrreg *reg;
- uint32_t cmd_base;
+ uint32_t dir_len, sub_qoff, val;
+ int i;
- if (!crom_has_specver(fwdev->csrrom, CSRVAL_1394TA, CSR_PROTCAM130) &&
- !crom_has_specver(fwdev->csrrom, CSRVAL_1394TA, CSR_PROTCAM120) &&
- !crom_has_specver(fwdev->csrrom, CSRVAL_1394TA, CSR_PROTCAM104))
+ if (dir_qoff >= rom_quads || max_depth <= 0)
+ return (0);
+ dir = (struct csrdirectory *)&csrrom[dir_qoff];
+ dir_len = dir->crc_len;
+ if (dir_qoff + 1 + dir_len > rom_quads)
return (0);
- cmd_base = 0;
- crom_init_context(&cc, fwdev->csrrom);
- reg = crom_search_key(&cc, IIDC_CROM_CMD_BASE);
- if (reg != NULL && reg->val != 0)
- cmd_base = reg->val;
+ for (i = 0; i < (int)dir_len; i++) {
+ if (dir_qoff + 1 + i >= rom_quads)
+ break;
+ reg = &dir->entry[i];
+ if (reg->key == IIDC_CROM_CMD_BASE && reg->val != 0)
+ return (reg->val);
+ if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) {
+ sub_qoff = dir_qoff + 1 + i + reg->val;
+ val = fwcam_search_dir_cmd_base(csrrom, sub_qoff,
+ rom_quads, max_depth - 1);
+ if (val != 0)
+ return (val);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Extract IIDC command base register from the unit directory.
+ * Searches the unit directory and any sub-directories (the iSight
+ * places cmd_base inside a logical_unit_directory).
+ */
+static uint32_t
+fwcam_find_iidc_cmd_base(struct fw_unit *unit)
+{
- return (cmd_base);
+ return (fwcam_search_dir_cmd_base(unit->fwdev->csrrom,
+ unit->dir_offset / 4, CSRROMSIZE / 4, 2));
}
static int
@@ -286,11 +314,18 @@
return;
}
sc->state = FWCAM_STATE_PROBED;
+ wakeup(sc);
FWCAM_UNLOCK(sc);
if (sc->dma_ch >= 0 &&
sc->state != FWCAM_STATE_DETACHING)
fwcam_iso_start(sc);
+ } else {
+ FWCAM_LOCK(sc);
+ if (sc->state == FWCAM_STATE_PROBING)
+ sc->state = FWCAM_STATE_IDLE;
+ wakeup(sc);
+ FWCAM_UNLOCK(sc);
}
}
@@ -616,16 +651,33 @@
fwcam_cdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
struct fwcam_softc *sc = dev->si_drv1;
+ int err;
FWCAM_LOCK(sc);
if (sc->state == FWCAM_STATE_DETACHING) {
FWCAM_UNLOCK(sc);
return (ENXIO);
}
+
+ if (sc->state == FWCAM_STATE_IDLE) {
+ sc->state = FWCAM_STATE_PROBING;
+ FWCAM_UNLOCK(sc);
+ taskqueue_enqueue(taskqueue_thread, &sc->probe_task);
+ FWCAM_LOCK(sc);
+ }
+
+ while (sc->state == FWCAM_STATE_PROBING) {
+ err = msleep(sc, &sc->mtx, PCATCH, "fwcampr", 10 * hz);
+ if (err) {
+ FWCAM_UNLOCK(sc);
+ return (err == EWOULDBLOCK ? ETIMEDOUT : err);
+ }
+ }
+
if (sc->state != FWCAM_STATE_PROBED &&
sc->state != FWCAM_STATE_STREAMING) {
FWCAM_UNLOCK(sc);
- return (EAGAIN); /* not yet probed */
+ return (ENXIO);
}
sc->open_count++;
@@ -937,103 +989,53 @@
}
}
-static void
-fwcam_post_explore(void *arg)
-{
- struct fwcam_softc *sc = (struct fwcam_softc *)arg;
- struct fw_device *fwdev;
- uint32_t cmd_base;
- int was_streaming, err;
-
- FWCAM_LOCK(sc);
-
- if (sc->state == FWCAM_STATE_DETACHING) {
- FWCAM_UNLOCK(sc);
- return;
- }
-
- if (sc->fwdev != NULL) {
- STAILQ_FOREACH(fwdev, &sc->fd.fc->devices, link) {
- if (fwdev == sc->fwdev &&
- fwdev->status == FWDEVATTACHED)
- break;
- }
- if (fwdev == NULL) {
- was_streaming = (sc->state == FWCAM_STATE_STREAMING);
- device_printf(sc->fd.dev, "camera disconnected%s\n",
- was_streaming ? " (was streaming)" : "");
- sc->fwdev = NULL;
- sc->state = FWCAM_STATE_IDLE;
- wakeup(sc); /* unblock readers */
- selwakeup(&sc->rsel);
- FWCAM_UNLOCK(sc);
-
- if (was_streaming)
- fwcam_iso_stop(sc);
- FWCAM_LOCK(sc);
- }
- }
-
- if (sc->fwdev == NULL) {
- STAILQ_FOREACH(fwdev, &sc->fd.fc->devices, link) {
- if (fwdev->status != FWDEVATTACHED)
- continue;
-
- cmd_base = fwcam_find_iidc(fwdev);
- if (cmd_base == 0)
- continue;
-
- sc->fwdev = fwdev;
- sc->cmd_hi = 0xffff;
- sc->cmd_lo = 0xf0000000 | (cmd_base << 2);
- sc->iso_speed = min(fwdev->speed, FWSPD_S400);
-
- FWCAM_UNLOCK(sc);
- err = taskqueue_enqueue(taskqueue_thread,
- &sc->probe_task);
- if (err)
- device_printf(sc->fd.dev,
- "taskqueue_enqueue failed: %d\n", err);
- return;
- }
- }
-
- FWCAM_UNLOCK(sc);
-}
-
-static void
-fwcam_post_busreset(void *arg __unused)
-{
-
-}
-
-static void
-fwcam_identify(driver_t *driver, device_t parent)
-{
-
- if (device_find_child(parent, "fwcam", DEVICE_UNIT_ANY) == NULL)
- BUS_ADD_CHILD(parent, 0, "fwcam", DEVICE_UNIT_ANY);
-}
static int
fwcam_probe(device_t dev)
{
+ struct fw_unit *unit;
+
+ unit = fw_get_unit(dev);
+ if (unit == NULL)
+ return (ENXIO);
+
+ if (unit->spec_id != CSRVAL_1394TA)
+ return (ENXIO);
+ if (unit->sw_version != CSR_PROTCAM130 &&
+ unit->sw_version != CSR_PROTCAM120 &&
+ unit->sw_version != CSR_PROTCAM104)
+ return (ENXIO);
device_set_desc(dev, "IIDC Digital Camera over FireWire");
- return (0);
+ return (BUS_PROBE_DEFAULT);
}
static int
fwcam_attach(device_t dev)
{
struct fwcam_softc *sc;
+ struct fw_unit *unit;
+ uint32_t cmd_base;
+
+ unit = fw_get_unit(dev);
+ if (unit == NULL || unit->fwdev == NULL)
+ return (ENXIO);
+
+ cmd_base = fwcam_find_iidc_cmd_base(unit);
+ if (cmd_base == 0) {
+ device_printf(dev, "no IIDC command base in unit directory\n");
+ return (ENXIO);
+ }
sc = device_get_softc(dev);
sc->fd.dev = dev;
- sc->fd.fc = device_get_ivars(dev);
+ sc->fd.fc = fw_get_comm(dev);
mtx_init(&sc->mtx, "fwcam", NULL, MTX_DEF);
- sc->fwdev = NULL;
+ sc->fwdev = unit->fwdev;
+ sc->cmd_hi = 0xffff;
+ sc->cmd_lo = 0xf0000000 | (cmd_base << 2);
+ sc->iso_speed = min(unit->fwdev->speed, FWSPD_S400);
sc->state = FWCAM_STATE_IDLE;
sc->dma_ch = -1;
sc->iso_active = 0;
@@ -1045,11 +1047,6 @@
UID_ROOT, GID_OPERATOR, 0660, "fwcam%d", device_get_unit(dev));
sc->cdev->si_drv1 = sc;
- sc->fd.post_busreset = fwcam_post_busreset;
- sc->fd.post_explore = fwcam_post_explore;
-
- fwcam_post_explore(sc);
-
return (0);
}
@@ -1084,7 +1081,6 @@
}
static device_method_t fwcam_methods[] = {
- DEVMETHOD(device_identify, fwcam_identify),
DEVMETHOD(device_probe, fwcam_probe),
DEVMETHOD(device_attach, fwcam_attach),
DEVMETHOD(device_detach, fwcam_detach),
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jul 17, 4:12 AM (19 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35117660
Default Alt Text
D58202.id181858.diff (9 KB)
Attached To
Mode
D58202: fwcam: match unit directories, defer probe to first open
Attached
Detach File
Event Timeline
Log In to Comment