media: v4l2-flash: Add sanity checks for flash and indicator controls
authorSakari Ailus <sakari.ailus@linux.intel.com>
Thu, 24 Jun 2021 12:05:24 +0000 (14:05 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Wed, 4 Aug 2021 12:43:51 +0000 (14:43 +0200)
The V4L2 flash API supports combinations of indicator and flash LEDs. Due
to this, there's a fair amount of code that deals with all the possible
options and just reading one part of the file doesn't really tell which
combinations are really possible.

Make the checks more explicit to keep static analysers happy and to make
the code more resilient to future mishaps.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/v4l2-core/v4l2-flash-led-class.c

index 10ddcc4..4c096ae 100644 (file)
@@ -80,6 +80,7 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash,
                                        struct v4l2_ctrl *ctrl)
 {
        struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
+       struct led_classdev *led_cdev;
        enum led_brightness brightness;
 
        if (has_flash_op(v4l2_flash, intensity_to_led_brightness))
@@ -104,12 +105,18 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash,
                if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
                        return;
 
-               led_set_brightness_sync(&v4l2_flash->fled_cdev->led_cdev,
-                                       brightness);
+               if (WARN_ON_ONCE(!v4l2_flash->fled_cdev))
+                       return;
+
+               led_cdev = &v4l2_flash->fled_cdev->led_cdev;
        } else {
-               led_set_brightness_sync(v4l2_flash->iled_cdev,
-                                       brightness);
+               if (WARN_ON_ONCE(!v4l2_flash->iled_cdev))
+                       return;
+
+               led_cdev = v4l2_flash->iled_cdev;
        }
+
+       led_set_brightness_sync(led_cdev, brightness);
 }
 
 static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash,
@@ -128,8 +135,15 @@ static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash,
                 */
                if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
                        return 0;
+
+               if (WARN_ON_ONCE(!v4l2_flash->fled_cdev))
+                       return -EINVAL;
+
                led_cdev = &v4l2_flash->fled_cdev->led_cdev;
        } else {
+               if (WARN_ON_ONCE(!v4l2_flash->iled_cdev))
+                       return -EINVAL;
+
                led_cdev = v4l2_flash->iled_cdev;
        }
 
@@ -159,6 +173,12 @@ static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c)
        case V4L2_CID_FLASH_TORCH_INTENSITY:
        case V4L2_CID_FLASH_INDICATOR_INTENSITY:
                return v4l2_flash_update_led_brightness(v4l2_flash, c);
+       }
+
+       if (!fled_cdev)
+               return -EINVAL;
+
+       switch (c->id) {
        case V4L2_CID_FLASH_INTENSITY:
                ret = led_update_flash_brightness(fled_cdev);
                if (ret < 0)
@@ -194,12 +214,24 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
 {
        struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c);
        struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
-       struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
+       struct led_classdev *led_cdev;
        struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
        bool external_strobe;
        int ret = 0;
 
        switch (c->id) {
+       case V4L2_CID_FLASH_TORCH_INTENSITY:
+       case V4L2_CID_FLASH_INDICATOR_INTENSITY:
+               v4l2_flash_set_led_brightness(v4l2_flash, c);
+               return 0;
+       }
+
+       if (!fled_cdev)
+               return -EINVAL;
+
+       led_cdev = &fled_cdev->led_cdev;
+
+       switch (c->id) {
        case V4L2_CID_FLASH_LED_MODE:
                switch (c->val) {
                case V4L2_FLASH_LED_MODE_NONE:
@@ -268,10 +300,6 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
                 * microamperes for flash intensity units.
                 */
                return led_set_flash_brightness(fled_cdev, c->val);
-       case V4L2_CID_FLASH_TORCH_INTENSITY:
-       case V4L2_CID_FLASH_INDICATOR_INTENSITY:
-               v4l2_flash_set_led_brightness(v4l2_flash, c);
-               return 0;
        }
 
        return -EINVAL;
@@ -492,6 +520,9 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash)
                                                ctrls[INDICATOR_INTENSITY]);
 
        if (ctrls[FLASH_TIMEOUT]) {
+               if (WARN_ON_ONCE(!fled_cdev))
+                       return -EINVAL;
+
                ret = led_set_flash_timeout(fled_cdev,
                                        ctrls[FLASH_TIMEOUT]->val);
                if (ret < 0)
@@ -499,6 +530,9 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash)
        }
 
        if (ctrls[FLASH_INTENSITY]) {
+               if (WARN_ON_ONCE(!fled_cdev))
+                       return -EINVAL;
+
                ret = led_set_flash_brightness(fled_cdev,
                                        ctrls[FLASH_INTENSITY]->val);
                if (ret < 0)