git: f4825e91cf77 - main - fwcam: add dynamic resolution and frame rate support

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Wed, 08 Jul 2026 05:42:04 UTC
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=f4825e91cf77d6f0fa6c8d8407956e9e1c52f2df

commit f4825e91cf77d6f0fa6c8d8407956e9e1c52f2df
Author:     Abdelkader Boudih <freebsd@seuros.com>
AuthorDate: 2026-07-08 05:31:03 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-07-08 05:32:43 +0000

    fwcam: add dynamic resolution and frame rate support
    
    Read V_MODE_INQ and V_RATE_INQ registers for all supported formats
    during probe, caching the camera's actual capabilities.  Use these
    to validate SMODE ioctl requests before writing to the camera.
    
    Writing an unsupported combination caused the camera to
    stop responding, requiring a physical power cycle.
    
    Tested with: Apple iSight (external FireWire)
    
    Reviewed by:    adrian
    Differential Revision:  https://reviews.freebsd.org/D58090
---
 sys/dev/firewire/fwcam.c | 33 ++++++++++++++++++++++++++++++---
 sys/dev/firewire/fwcam.h |  2 ++
 2 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/sys/dev/firewire/fwcam.c b/sys/dev/firewire/fwcam.c
index 38a99c359c18..752558a1ecea 100644
--- a/sys/dev/firewire/fwcam.c
+++ b/sys/dev/firewire/fwcam.c
@@ -173,7 +173,7 @@ fwcam_format_name(int format)
 static int
 fwcam_read_capabilities(struct fwcam_softc *sc)
 {
-	int err;
+	int err, f, m;
 
 	err = fwcam_read_quadlet(sc, IIDC_V_FORMAT_INQ, &sc->formats);
 	if (err) {
@@ -189,6 +189,30 @@ fwcam_read_capabilities(struct fwcam_softc *sc)
 		return (err);
 	}
 
+	/* Read mode and rate inquiry registers for each supported format */
+	for (f = 0; f < 8; f++) {
+		if (!(sc->formats & (1 << (31 - f)))) {
+			sc->modes[f] = 0;
+			continue;
+		}
+		err = fwcam_read_quadlet(sc, IIDC_V_MODE_INQ(f),
+		    &sc->modes[f]);
+		if (err) {
+			sc->modes[f] = 0;
+			continue;
+		}
+		for (m = 0; m < 8; m++) {
+			if (!(sc->modes[f] & (1 << (31 - m)))) {
+				sc->rates[f][m] = 0;
+				continue;
+			}
+			err = fwcam_read_quadlet(sc, IIDC_V_RATE_INQ(f, m),
+			    &sc->rates[f][m]);
+			if (err)
+				sc->rates[f][m] = 0;
+		}
+	}
+
 	err = fwcam_read_quadlet(sc, IIDC_FEATURE_HI_INQ, &sc->features_hi);
 	if (err)
 		sc->features_hi = 0;
@@ -815,10 +839,13 @@ fwcam_cdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
 		if (mode->format > 7 || mode->mode > 7 || mode->framerate > 7)
 			return (EINVAL);
 
-		if (mode->format != IIDC_FMT_VGA)
-			return (EINVAL);
 		if (!(sc->formats & (1 << (31 - mode->format))))
 			return (EINVAL);
+		if (!(sc->modes[mode->format] & (1 << (31 - mode->mode))))
+			return (EINVAL);
+		if (!(sc->rates[mode->format][mode->mode] &
+		    (1 << (31 - mode->framerate))))
+			return (EINVAL);
 
 		FWCAM_LOCK(sc);
 		if (sc->state == FWCAM_STATE_DETACHING) {
diff --git a/sys/dev/firewire/fwcam.h b/sys/dev/firewire/fwcam.h
index dcc871f2a249..ac72c8609f13 100644
--- a/sys/dev/firewire/fwcam.h
+++ b/sys/dev/firewire/fwcam.h
@@ -225,6 +225,8 @@ struct fwcam_softc {
 	uint32_t		basic_func;	/* BASIC_FUNC_INQ */
 	uint32_t		features_hi;	/* FEATURE_HI_INQ */
 	uint32_t		features_lo;	/* FEATURE_LO_INQ */
+	uint32_t		modes[8];	/* V_MODE_INQ per format */
+	uint32_t		rates[8][8];	/* V_RATE_INQ per format/mode */
 
 	/* Current settings */
 	uint8_t			cur_format;