]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
pwm: Ensure callbacks exist before calling them
authorUwe Kleine-König <u.kleine-koenig@baylibre.com>
Thu, 23 Jan 2025 17:27:07 +0000 (18:27 +0100)
committerUwe Kleine-König <ukleinek@kernel.org>
Thu, 23 Jan 2025 19:35:53 +0000 (20:35 +0100)
If one of the waveform functions is called for a chip that only supports
.apply(), we want that an error code is returned and not a NULL pointer
exception.

Fixes: 6c5126c6406d ("pwm: Provide new consumer API functions for waveforms")
Cc: stable@vger.kernel.org
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Tested-by: Trevor Gamblin <tgamblin@baylibre.com>
Link: https://lore.kernel.org/r/20250123172709.391349-2-u.kleine-koenig@baylibre.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
drivers/pwm/core.c
include/linux/pwm.h

index 9c733877e98e47ac6548932cb040e91dd1008f81..1a36ee3cab9143fdb09fb74e5eb0ae081c840517 100644 (file)
@@ -242,6 +242,9 @@ int pwm_round_waveform_might_sleep(struct pwm_device *pwm, struct pwm_waveform *
 
        BUG_ON(WFHWSIZE < ops->sizeof_wfhw);
 
+       if (!pwmchip_supports_waveform(chip))
+               return -EOPNOTSUPP;
+
        if (!pwm_wf_valid(wf))
                return -EINVAL;
 
@@ -294,6 +297,9 @@ int pwm_get_waveform_might_sleep(struct pwm_device *pwm, struct pwm_waveform *wf
 
        BUG_ON(WFHWSIZE < ops->sizeof_wfhw);
 
+       if (!pwmchip_supports_waveform(chip) || !ops->read_waveform)
+               return -EOPNOTSUPP;
+
        guard(pwmchip)(chip);
 
        if (!chip->operational)
@@ -320,6 +326,9 @@ static int __pwm_set_waveform(struct pwm_device *pwm,
 
        BUG_ON(WFHWSIZE < ops->sizeof_wfhw);
 
+       if (!pwmchip_supports_waveform(chip))
+               return -EOPNOTSUPP;
+
        if (!pwm_wf_valid(wf))
                return -EINVAL;
 
@@ -592,7 +601,7 @@ static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state)
            state->usage_power == pwm->state.usage_power)
                return 0;
 
-       if (ops->write_waveform) {
+       if (pwmchip_supports_waveform(chip)) {
                struct pwm_waveform wf;
                char wfhw[WFHWSIZE];
 
@@ -746,7 +755,7 @@ int pwm_get_state_hw(struct pwm_device *pwm, struct pwm_state *state)
        if (!chip->operational)
                return -ENODEV;
 
-       if (ops->read_waveform) {
+       if (pwmchip_supports_waveform(chip) && ops->read_waveform) {
                char wfhw[WFHWSIZE];
                struct pwm_waveform wf;
 
index 78827f31240745a31338f1e1deae2b2d5e002d38..b8d78009e7791db2f862b773b669fdad6760219f 100644 (file)
@@ -347,6 +347,23 @@ struct pwm_chip {
        struct pwm_device pwms[] __counted_by(npwm);
 };
 
+/**
+ * pwmchip_supports_waveform() - checks if the given chip supports waveform callbacks
+ * @chip: The pwm_chip to test
+ *
+ * Returns true iff the pwm chip support the waveform functions like
+ * pwm_set_waveform_might_sleep() and pwm_round_waveform_might_sleep()
+ */
+static inline bool pwmchip_supports_waveform(struct pwm_chip *chip)
+{
+       /*
+        * only check for .write_waveform(). If that is available,
+        * .round_waveform_tohw() and .round_waveform_fromhw() asserted to be
+        * available, too, in pwmchip_add().
+        */
+       return chip->ops->write_waveform != NULL;
+}
+
 static inline struct device *pwmchip_parent(const struct pwm_chip *chip)
 {
        return chip->dev.parent;