Skip to contentSkip to conversation

media: gspca: Handle SENSOR_HV7131R

PATCH New Philipp Matthias Hahn 2 participants 10 messages Apr 16 – May 5

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 media: gspca: Handle SENSOR_HV7131R

I found an old USB webcam 0c45:602d Microdia VideoCAM ExpressII. vlc triggeres two OOPS as soon as I open the device.

The first patch prevents those OOPSes, while the 2nd fixes a minor spelling mistake.

The camera still does not work and I get the following error:

Quoted 1 line

sonixb 1-3:1.0: i2c error writing c0 11 31 38 2a 2e 00 10

I'm still investigating the old driver sn9c102_hv7131r.c from [1], but so far was unable to make progress. So feel free to apply this now. Thank you.

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c0e11a2a24db782341f456877d19b9390c5998a9

Philipp Matthias Hahn (2):
media: gspca: Handle SENSOR_HV7131R
media: gspca: Fix comment in sd_init()

 drivers/media/usb/gspca/sonixb.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
Signature · 1 line
2.47.3
#1 lore raw

PATCH 1/1 media: gspca: Fix comment in sd_init()

Fix spelling mistake of{ -> f}.

---
 drivers/media/usb/gspca/sonixb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/usb/gspca/sonixb.c +1 -1
index 9a9aba5a35de..27594872de84 100644
@@ -945,7 +945,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-	const __u8 stop = 0x09; /* Disable stream turn of LED */
+	const __u8 stop = 0x09; /* Disable stream, turn off LED */
 
 	reg_w(gspca_dev, 0x01, &stop, 1);
 
Signature · 1 line
2.47.3
#2 lore raw

PATCH 1/1 media: gspca: Handle SENSOR_HV7131R

In reply to Philipp Matthias Hahn

I found an old USB webcam 0c45:602d Microdia VideoCAM ExpressII. vlc triggered an OOPS as soon as I opened the device:

Quoted 10 lines
BUG: kernel NULL pointer dereference, address: 0000000000000068
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
CPU: 8 UID: 1000 PID: 19655 Comm: vlc Tainted: G           O       6.12.74+deb13+1-amd64 #1  Debian 6.12.74-2
Tainted: [O]=OOT_MODULE
Hardware name: Micro-Star International Co., Ltd. MS-7B89/B450M MORTAR MAX (MS-7B89), BIOS 2.P1 09/18/2025
RIP: 0010:do_autogain+0x7d/0x100 [gspca_sonixb]
Code: 74 21 0f af 90 c4 00 00 00 89 d0 48 63 d2 48 69 d2 09 04 02 81 48 c1 ea 20 01 c2 c1 f8 1f c1 fa 06 29 c2 48 8b 83 48 06 00 00 <48> 81 78 68 f3 01 00 00 7f 34 48 89 df e8 41 f1 3b 00 85 c0 74 07

(The out-of-tree-module is v4l2-loopback.)

Adding addition debug information I found out, that the cam is based on an SENSOR_HV7131R:

Quoted 2 lines

gspca_main: sonixb-2.14.0 probing 0c45:602d
sonixb 1-3:1.0: sd_config(sensor=01 bridge=00)

In case of an SENSOR_HV7131R gspca_dev->exposure is not setup. Enabling auto-gain will result in the above OOPS.

1. Check for gspca_dev->exposure != NULL before dereferencing it.

Even after that there's 2nd OOPS:

Quoted 10 lines
BUG: kernel NULL pointer dereference, address: 0000000000000034
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] SMP NOPTI
CPU: 1 UID: 1000 PID: 709 Comm: vlc Tainted: G            E       7.0.0+ #6 PREEMPT(lazy)
Tainted: [E]=UNSIGNED_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 2025.02-8+deb13u1 11/08/2025
RIP: 0010:v4l2_ctrl_g_ctrl+0x36/0x80 [videodev]
Code: 20 65 48 8b 05 63 17 b1 c8 48 89 44 24 18 31 c0 c7 44 24 14 00 00 00 00 48 c7 44 24 04 00 00 00 00 48 c7 44 24 0c 00 00 00 00 <f6> 47 34 20 74 2e 48 8d 74 24 04 c7 44 24 10 00 00 00 00 e8 72 fd

This is caused by v4l2_ctrl_g_ctrl() dereferencing gspca_dev->autogain, which remains NULL as gspca_dev->exposure is NULL.

Check for gspca_dev->autogain != NULL before dereferencing it via gspca_expo_autogain().

---
 drivers/media/usb/gspca/sonixb.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/media/usb/gspca/sonixb.c +6 -4
index 4d655e2da9cb..9a9aba5a35de 100644
@@ -900,11 +900,11 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 	if (sd->brightness)
 		desired_avg_lum = sd->brightness->val * desired_avg_lum / 127;
 
-	if (gspca_dev->exposure->maximum < 500) {
+	if (gspca_dev->exposure && gspca_dev->exposure->maximum < 500) {
 		if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
 				desired_avg_lum, deadzone))
 			sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
-	} else {
+	} else if (gspca_dev->autogain) {
 		int gain_knee = (s32)gspca_dev->gain->maximum * 9 / 10;
 		if (gspca_expo_autogain(gspca_dev, avg_lum, desired_avg_lum,
 				deadzone, gain_knee, sd->exposure_knee))
@@ -927,6 +927,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->sensor = id->driver_info >> 8;
 	sd->bridge = id->driver_info & 0xff;
 
+	dev_info(gspca_dev->v4l2_dev.dev, "sd_config(sensor=%02x bridge=%02x)\n", sd->sensor, sd->bridge);
+
 	cam = &gspca_dev->cam;
 	if (!(sensor_data[sd->sensor].flags & F_SIF)) {
 		cam->cam_mode = vga_mode;
@@ -958,7 +960,7 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	gspca_dev->usb_err = 0;
 
-	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
+	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val && gspca_dev->exposure) {
 		/* when switching to autogain set defaults to make sure
 		   we are on a valid point of the autogain gain /
 		   exposure knee graph, and give this change time to
@@ -976,7 +978,7 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 		setbrightness(gspca_dev);
 		break;
 	case V4L2_CID_AUTOGAIN:
-		if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
+		if ((gspca_dev->exposure && gspca_dev->exposure->is_new) || (ctrl->is_new && ctrl->val))
 			setexposure(gspca_dev);
 		if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
 			setgain(gspca_dev);
Signature · 1 line
2.47.3
#3 lore raw

PATCH v2 1/1 media: gspca: Handle SENSOR_HV7131R

In reply to Philipp Matthias Hahn

I found an old USB webcam 0c45:602d Microdia VideoCAM ExpressII. vlc triggeres two OOPS as soon as I open the device.

The first patch prevents those OOPSes, while the 2nd fixes a minor spelling mistake.

The camera still does not work and I get the following error:

Quoted 1 line

sonixb 1-3:1.0: i2c error writing c0 11 31 38 2a 2e 00 10

I'm still investigating the old driver sn9c102_hv7131r.c from [1], but so far was unable to make progress. So feel free to apply this now. Thank you.

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c0e11a2a24db782341f456877d19b9390c5998a9

---
v1 -> v2:
- Use __func__ instead of hard-coding the function name
- Break long code lines over 100 character long
- Break long commit message lines over 72 character long

Philipp Matthias Hahn (2):
media: gspca: Handle SENSOR_HV7131R
media: gspca: Fix comment in sd_init()

 drivers/media/usb/gspca/sonixb.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)
Signature · 1 line
2.47.3
#4 lore raw

PATCH v2 1/1 media: gspca: Handle SENSOR_HV7131R

I found an old USB webcam 0c45:602d Microdia VideoCAM ExpressII. vlc triggered an OOPS as soon as I opened the device:

Quoted 11 lines
BUG: kernel NULL pointer dereference, address: 0000000000000068
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
CPU: 8 UID: 1000 PID: 19655 Comm: vlc Tainted: G O 7.0.0+ #1 Debian
Tainted: [O]=OOT_MODULE
RIP: 0010:do_autogain+0x7d/0x100 [gspca_sonixb]
Code: 74 21 0f af 90 c4 00 00 00 89 d0 48 63 d2 48 69 d2 09 04 02 81

48 c1 ea 20 01 c2 c1 f8 1f c1 fa 06 29 c2 48 8b 83 48 06 00 00 <48> 81 78 68 f3 01 00 00 7f 34 48 89 df e8 41 f1 3b 00 85 c0 74 07

(The out-of-tree-module is v4l2-loopback.)

Adding addition debug information I found out, that the cam is based on an SENSOR_HV7131R:

Quoted 2 lines

gspca_main: sonixb-2.14.0 probing 0c45:602d
sonixb 1-3:1.0: sd_config(sensor=01 bridge=00)

In case of an SENSOR_HV7131R gspca_dev->exposure is not setup. Enabling auto-gain will result in the above OOPS.

1. Check for gspca_dev->exposure != NULL before dereferencing it.

Even after that there's 2nd OOPS:

Quoted 11 lines
BUG: kernel NULL pointer dereference, address: 0000000000000034
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] SMP NOPTI
CPU: 1 UID: 1000 PID: 709 Comm: vlc Tainted: G E 7.0.0+ #6 Debian
Tainted: [E]=UNSIGNED_MODULE
RIP: 0010:v4l2_ctrl_g_ctrl+0x36/0x80 [videodev]
Code: 20 65 48 8b 05 63 17 b1 c8 48 89 44 24 18 31 c0 c7 44 24 14 00

00 00 00 48 c7 44 24 04 00 00 00 00 48 c7 44 24 0c 00 00 00 00 <f6> 47 34 20 74 2e 48 8d 74 24 04 c7 44 24 10 00 00 00 00 e8 72 fd

This is caused by v4l2_ctrl_g_ctrl() dereferencing gspca_dev->autogain, which remains NULL as gspca_dev->exposure is NULL.

Check for gspca_dev->autogain != NULL before dereferencing it via gspca_expo_autogain().

---
v1 -> v2:
- Use __func__ instead of hard-coding the function name
- Break long code lines over 100 character long
- Break long commit message lines over 72 character long

 drivers/media/usb/gspca/sonixb.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/media/usb/gspca/sonixb.c +8 -4
index 4d655e2da9cb..d1c7868b4a6b 100644
@@ -900,11 +900,11 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 	if (sd->brightness)
 		desired_avg_lum = sd->brightness->val * desired_avg_lum / 127;
 
-	if (gspca_dev->exposure->maximum < 500) {
+	if (gspca_dev->exposure && gspca_dev->exposure->maximum < 500) {
 		if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
 				desired_avg_lum, deadzone))
 			sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
-	} else {
+	} else if (gspca_dev->autogain) {
 		int gain_knee = (s32)gspca_dev->gain->maximum * 9 / 10;
 		if (gspca_expo_autogain(gspca_dev, avg_lum, desired_avg_lum,
 				deadzone, gain_knee, sd->exposure_knee))
@@ -927,6 +927,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->sensor = id->driver_info >> 8;
 	sd->bridge = id->driver_info & 0xff;
 
+	dev_info(gspca_dev->v4l2_dev.dev, "%s(sensor=%02x bridge=%02x)\n",
+		__func__, sd->sensor, sd->bridge);
+
 	cam = &gspca_dev->cam;
 	if (!(sensor_data[sd->sensor].flags & F_SIF)) {
 		cam->cam_mode = vga_mode;
@@ -958,7 +961,7 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	gspca_dev->usb_err = 0;
 
-	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
+	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val && gspca_dev->exposure) {
 		/* when switching to autogain set defaults to make sure
 		   we are on a valid point of the autogain gain /
 		   exposure knee graph, and give this change time to
@@ -976,7 +979,8 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 		setbrightness(gspca_dev);
 		break;
 	case V4L2_CID_AUTOGAIN:
-		if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
+		if ((gspca_dev->exposure && gspca_dev->exposure->is_new) ||
+			(ctrl->is_new && ctrl->val))
 			setexposure(gspca_dev);
 		if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
 			setgain(gspca_dev);
Signature · 1 line
2.47.3
#5 lore raw

PATCH v2 1/1 media: gspca: Fix comment in sd_init()

In reply to Philipp Matthias Hahn

Fix spelling mistake of{ -> f}.

---
 drivers/media/usb/gspca/sonixb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/usb/gspca/sonixb.c +1 -1
index d1c7868b4a6b..f373b5734d83 100644
@@ -946,7 +946,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-	const __u8 stop = 0x09; /* Disable stream turn of LED */
+	const __u8 stop = 0x09; /* Disable stream, turn off LED */
 
 	reg_w(gspca_dev, 0x01, &stop, 1);
 
Signature · 1 line
2.47.3
#6 lore raw

PATCH v3 1/1 media: gspca: Handle SENSOR_HV7131R

In reply to Philipp Matthias Hahn

I found an old USB webcam 0c45:602d Microdia VideoCAM ExpressII. vlc triggeres two OOPS as soon as I open the device.

The first patch prevents those OOPSes, while the 2nd fixes a minor spelling mistake.

The camera still does not work and I get the following error:

Quoted 1 line

sonixb 1-3:1.0: i2c error writing c0 11 31 38 2a 2e 00 10

I'm still investigating the old driver sn9c102_hv7131r.c from [1], but so far was unable to make progress. So feel free to apply this now. Thank you.

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c0e11a2a24db782341f456877d19b9390c5998a9

---
v3 -> v2:
- Fix alignment to match open parenthesis
v1 -> v2:
- Use __func__ instead of hard-coding the function name
- Break long code lines over 100 character long
- Break long commit message lines over 72 character long

Philipp Matthias Hahn (2):
media: gspca: Handle SENSOR_HV7131R
media: gspca: Fix comment in sd_init()

 drivers/media/usb/gspca/sonixb.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)
Signature · 1 line
2.47.3
#7 lore raw

PATCH v3 1/1 media: gspca: Fix comment in sd_init()

Fix spelling mistake of{ -> f}.

---
 drivers/media/usb/gspca/sonixb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/usb/gspca/sonixb.c +1 -1
index 09725d62d904..60b5d4bc528f 100644
@@ -946,7 +946,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-	const __u8 stop = 0x09; /* Disable stream turn of LED */
+	const __u8 stop = 0x09; /* Disable stream, turn off LED */
 
 	reg_w(gspca_dev, 0x01, &stop, 1);
 
Signature · 1 line
2.47.3
#8 lore raw

PATCH v3 1/1 media: gspca: Handle SENSOR_HV7131R

In reply to Philipp Matthias Hahn

I found an old USB webcam 0c45:602d Microdia VideoCAM ExpressII. vlc triggered an OOPS as soon as I opened the device:

Quoted 11 lines
BUG: kernel NULL pointer dereference, address: 0000000000000068
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
CPU: 8 UID: 1000 PID: 19655 Comm: vlc Tainted: G O 7.0.0+ #1 Debian
Tainted: [O]=OOT_MODULE
RIP: 0010:do_autogain+0x7d/0x100 [gspca_sonixb]
Code: 74 21 0f af 90 c4 00 00 00 89 d0 48 63 d2 48 69 d2 09 04 02 81

48 c1 ea 20 01 c2 c1 f8 1f c1 fa 06 29 c2 48 8b 83 48 06 00 00 <48> 81 78 68 f3 01 00 00 7f 34 48 89 df e8 41 f1 3b 00 85 c0 74 07

(The out-of-tree-module is v4l2-loopback.)

Adding addition debug information I found out, that the cam is based on an SENSOR_HV7131R:

Quoted 2 lines

gspca_main: sonixb-2.14.0 probing 0c45:602d
sonixb 1-3:1.0: sd_config(sensor=01 bridge=00)

In case of an SENSOR_HV7131R gspca_dev->exposure is not setup. Enabling auto-gain will result in the above OOPS.

1. Check for gspca_dev->exposure != NULL before dereferencing it.

Even after that there's 2nd OOPS:

Quoted 11 lines
BUG: kernel NULL pointer dereference, address: 0000000000000034
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] SMP NOPTI
CPU: 1 UID: 1000 PID: 709 Comm: vlc Tainted: G E 7.0.0+ #6 Debian
Tainted: [E]=UNSIGNED_MODULE
RIP: 0010:v4l2_ctrl_g_ctrl+0x36/0x80 [videodev]
Code: 20 65 48 8b 05 63 17 b1 c8 48 89 44 24 18 31 c0 c7 44 24 14 00

00 00 00 48 c7 44 24 04 00 00 00 00 48 c7 44 24 0c 00 00 00 00 <f6> 47 34 20 74 2e 48 8d 74 24 04 c7 44 24 10 00 00 00 00 e8 72 fd

This is caused by v4l2_ctrl_g_ctrl() dereferencing gspca_dev->autogain, which remains NULL as gspca_dev->exposure is NULL.

Check for gspca_dev->autogain != NULL before dereferencing it via gspca_expo_autogain().

---
 drivers/media/usb/gspca/sonixb.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/media/usb/gspca/sonixb.c +8 -4
index 4d655e2da9cb..09725d62d904 100644
@@ -900,11 +900,11 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 	if (sd->brightness)
 		desired_avg_lum = sd->brightness->val * desired_avg_lum / 127;
 
-	if (gspca_dev->exposure->maximum < 500) {
+	if (gspca_dev->exposure && gspca_dev->exposure->maximum < 500) {
 		if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
 				desired_avg_lum, deadzone))
 			sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
-	} else {
+	} else if (gspca_dev->autogain) {
 		int gain_knee = (s32)gspca_dev->gain->maximum * 9 / 10;
 		if (gspca_expo_autogain(gspca_dev, avg_lum, desired_avg_lum,
 				deadzone, gain_knee, sd->exposure_knee))
@@ -927,6 +927,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->sensor = id->driver_info >> 8;
 	sd->bridge = id->driver_info & 0xff;
 
+	dev_info(gspca_dev->v4l2_dev.dev, "%s(sensor=%02x bridge=%02x)\n",
+		 __func__, sd->sensor, sd->bridge);
+
 	cam = &gspca_dev->cam;
 	if (!(sensor_data[sd->sensor].flags & F_SIF)) {
 		cam->cam_mode = vga_mode;
@@ -958,7 +961,7 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	gspca_dev->usb_err = 0;
 
-	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
+	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val && gspca_dev->exposure) {
 		/* when switching to autogain set defaults to make sure
 		   we are on a valid point of the autogain gain /
 		   exposure knee graph, and give this change time to
@@ -976,7 +979,8 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 		setbrightness(gspca_dev);
 		break;
 	case V4L2_CID_AUTOGAIN:
-		if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
+		if ((gspca_dev->exposure && gspca_dev->exposure->is_new) ||
+		    (ctrl->is_new && ctrl->val))
 			setexposure(gspca_dev);
 		if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
 			setgain(gspca_dev);
Signature · 1 line
2.47.3
#9 lore raw

Hi Philipp,

Quoted 42 lines · Philipp Matthias Hahn

I found an old USB webcam 0c45:602d Microdia VideoCAM ExpressII. vlc triggered an OOPS as soon as I opened the device:

Quoted 11 lines
BUG: kernel NULL pointer dereference, address: 0000000000000068
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
CPU: 8 UID: 1000 PID: 19655 Comm: vlc Tainted: G O 7.0.0+ #1 Debian
Tainted: [O]=OOT_MODULE
RIP: 0010:do_autogain+0x7d/0x100 [gspca_sonixb]
Code: 74 21 0f af 90 c4 00 00 00 89 d0 48 63 d2 48 69 d2 09 04 02 81

48 c1 ea 20 01 c2 c1 f8 1f c1 fa 06 29 c2 48 8b 83 48 06 00 00 <48> 81 78 68 f3 01 00 00 7f 34 48 89 df e8 41 f1 3b 00 85 c0 74 07

(The out-of-tree-module is v4l2-loopback.)

Adding addition debug information I found out, that the cam is based on an SENSOR_HV7131R:

Quoted 2 lines

gspca_main: sonixb-2.14.0 probing 0c45:602d
sonixb 1-3:1.0: sd_config(sensor=01 bridge=00)

In case of an SENSOR_HV7131R gspca_dev->exposure is not setup. Enabling auto-gain will result in the above OOPS.

1. Check for gspca_dev->exposure != NULL before dereferencing it.

Even after that there's 2nd OOPS:

Quoted 11 lines
BUG: kernel NULL pointer dereference, address: 0000000000000034
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] SMP NOPTI
CPU: 1 UID: 1000 PID: 709 Comm: vlc Tainted: G E 7.0.0+ #6 Debian
Tainted: [E]=UNSIGNED_MODULE
RIP: 0010:v4l2_ctrl_g_ctrl+0x36/0x80 [videodev]
Code: 20 65 48 8b 05 63 17 b1 c8 48 89 44 24 18 31 c0 c7 44 24 14 00

00 00 00 48 c7 44 24 04 00 00 00 00 48 c7 44 24 0c 00 00 00 00 <f6> 47 34 20 74 2e 48 8d 74 24 04 c7 44 24 10 00 00 00 00 e8 72 fd

Quoted 5 lines

This is caused by v4l2_ctrl_g_ctrl() dereferencing gspca_dev->autogain, which remains NULL as gspca_dev->exposure is NULL.

Check for gspca_dev->autogain != NULL before dereferencing it via gspca_expo_autogain().

I see no sign of adding that check in gspca_expo_autogain(): I think you missed that in your patch.

Quoted 35 lines
---
 drivers/media/usb/gspca/sonixb.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/media/usb/gspca/sonixb.c +5 -2
index 4d655e2da9cb..09725d62d904 100644
@@ -900,11 +900,11 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 	if (sd->brightness)
 		desired_avg_lum = sd->brightness->val * desired_avg_lum / 127;
 
-	if (gspca_dev->exposure->maximum < 500) {
+	if (gspca_dev->exposure && gspca_dev->exposure->maximum < 500) {
 		if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
 				desired_avg_lum, deadzone))
 			sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
-	} else {
+	} else if (gspca_dev->autogain) {
 		int gain_knee = (s32)gspca_dev->gain->maximum * 9 / 10;
 		if (gspca_expo_autogain(gspca_dev, avg_lum, desired_avg_lum,
 				deadzone, gain_knee, sd->exposure_knee))
@@ -927,6 +927,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->sensor = id->driver_info >> 8;
 	sd->bridge = id->driver_info & 0xff;
 
+	dev_info(gspca_dev->v4l2_dev.dev, "%s(sensor=%02x bridge=%02x)\n",
+		 __func__, sd->sensor, sd->bridge);
+
 	cam = &gspca_dev->cam;
 	if (!(sensor_data[sd->sensor].flags & F_SIF)) {
 		cam->cam_mode = vga_mode;

drivers/media/usb/gspca/sonixb.c static int sd_s_ctrl(struct v4l2_ctrl *ctrl) · line 964

Quoted 5 lines
drivers/media/usb/gspca/sonixb.c +1 -1
@@ -958,7 +961,7 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	gspca_dev->usb_err = 0;
 
-	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
+	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val && gspca_dev->exposure) {

Is this really needed? We should only be able to get here if the AUTOGAIN control was added, and that's only added if the EXPOSURE control is also present.

Does it still crash if you drop this change?

drivers/media/usb/gspca/sonixb.c static int sd_s_ctrl(struct v4l2_ctrl *ctrl) · line 983

Quoted 10 lines
drivers/media/usb/gspca/sonixb.c +2 -1
 		/* when switching to autogain set defaults to make sure
 		   we are on a valid point of the autogain gain /
 		   exposure knee graph, and give this change time to
@@ -976,7 +979,8 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 		setbrightness(gspca_dev);
 		break;
 	case V4L2_CID_AUTOGAIN:
-		if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
+		if ((gspca_dev->exposure && gspca_dev->exposure->is_new) ||
+		    (ctrl->is_new && ctrl->val))

Same here.

drivers/media/usb/gspca/sonixb.c static int sd_s_ctrl(struct v4l2_ctrl *ctrl) · line 986

Quoted 3 lines
drivers/media/usb/gspca/sonixb.c +0 -0
 			setexposure(gspca_dev);
 		if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
 			setgain(gspca_dev);

Regards,

Hans