[PATCH] media: go7007: s2250: propagate control I/O failures

From: Yousef Alhouseen

Date: Tue Jun 30 2026 - 07:03:11 EST


The brightness and contrast paths use oldvalue after read_reg_fp()
without checking whether the read succeeded. A failed read leaves
oldvalue uninitialized and can write arbitrary reserved register bits.

Return read and write errors from every control path so failed hardware
access cannot be reported as a successful control update.

Signed-off-by: Yousef Alhouseen <alhouseenyousef@xxxxxxxxx>
---
drivers/media/usb/go7007/s2250-board.c | 54 ++++++++++++++++----------
1 file changed, 33 insertions(+), 21 deletions(-)

diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c
index 0901d79e827d..d11f8e723624 100644
--- a/drivers/media/usb/go7007/s2250-board.c
+++ b/drivers/media/usb/go7007/s2250-board.c
@@ -365,36 +365,48 @@ static int s2250_s_ctrl(struct v4l2_ctrl *ctrl)
struct s2250 *state = container_of(ctrl->handler, struct s2250, hdl);
struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
u16 oldvalue;
+ int ret;

switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue);
- write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0,
- ctrl->val | (oldvalue & ~0xff));
- read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue);
- write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1,
- ctrl->val | (oldvalue & ~0xff));
- write_reg_fp(client, 0x140, 0x60);
- break;
+ ret = read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue);
+ if (ret)
+ return ret;
+ ret = write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0,
+ ctrl->val | (oldvalue & ~0xff));
+ if (ret)
+ return ret;
+ ret = read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue);
+ if (ret)
+ return ret;
+ ret = write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1,
+ ctrl->val | (oldvalue & ~0xff));
+ if (ret)
+ return ret;
+ return write_reg_fp(client, 0x140, 0x60);
case V4L2_CID_CONTRAST:
- read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue);
- write_reg_fp(client, VPX322_ADDR_CONTRAST0,
- ctrl->val | (oldvalue & ~0x3f));
- read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue);
- write_reg_fp(client, VPX322_ADDR_CONTRAST1,
- ctrl->val | (oldvalue & ~0x3f));
- write_reg_fp(client, 0x140, 0x60);
- break;
+ ret = read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue);
+ if (ret)
+ return ret;
+ ret = write_reg_fp(client, VPX322_ADDR_CONTRAST0,
+ ctrl->val | (oldvalue & ~0x3f));
+ if (ret)
+ return ret;
+ ret = read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue);
+ if (ret)
+ return ret;
+ ret = write_reg_fp(client, VPX322_ADDR_CONTRAST1,
+ ctrl->val | (oldvalue & ~0x3f));
+ if (ret)
+ return ret;
+ return write_reg_fp(client, 0x140, 0x60);
case V4L2_CID_SATURATION:
- write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val);
- break;
+ return write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val);
case V4L2_CID_HUE:
- write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val);
- break;
+ return write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val);
default:
return -EINVAL;
}
- return 0;
}

static int s2250_set_fmt(struct v4l2_subdev *sd,
--
2.54.0