diff options
author | Simon Guinot <simon.guinot@sequanux.org> | 2013-03-19 11:07:29 -0700 |
---|---|---|
committer | Bryan Wu <cooloney@gmail.com> | 2013-04-01 11:04:52 -0700 |
commit | 3de1929ba61df87a0561c4f1fb7161c401fe3d04 (patch) | |
tree | 92d07b007a17379e26fc1d77851a260ea537b519 | |
parent | c971ff185f6443e834686f140ba6d6e341ced600 (diff) | |
download | op-kernel-dev-3de1929ba61df87a0561c4f1fb7161c401fe3d04.zip op-kernel-dev-3de1929ba61df87a0561c4f1fb7161c401fe3d04.tar.gz |
leds: leds-ns2: fix oops at module removal
This patch fixes a regression introduced by commit 72052fcc10
("leds: leds-ns2: add device tree binding").
When the driver is initialized with device tree data, platform_data
pointer is NULL. This causes a kernel oops at removal.
To fix this bug, num_leds is moved into driver_data and platform_data
is not longer used from ns2_led_remove().
Signed-off-by: Simon Guinot <simon.guinot@sequanux.org>
Signed-off-by: Bryan Wu <cooloney@gmail.com>
-rw-r--r-- | drivers/leds/leds-ns2.c | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index e02b313..70137b1 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -308,10 +308,21 @@ static const struct of_device_id of_ns2_leds_match[] = { }; #endif /* CONFIG_OF_GPIO */ +struct ns2_led_priv { + int num_leds; + struct ns2_led_data leds_data[]; +}; + +static inline int sizeof_ns2_led_priv(int num_leds) +{ + return sizeof(struct ns2_led_priv) + + (sizeof(struct ns2_led_data) * num_leds); +} + static int ns2_led_probe(struct platform_device *pdev) { struct ns2_led_platform_data *pdata = pdev->dev.platform_data; - struct ns2_led_data *leds_data; + struct ns2_led_priv *priv; int i; int ret; @@ -332,21 +343,23 @@ static int ns2_led_probe(struct platform_device *pdev) return -EINVAL; #endif /* CONFIG_OF_GPIO */ - leds_data = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_data) * - pdata->num_leds, GFP_KERNEL); - if (!leds_data) + priv = devm_kzalloc(&pdev->dev, + sizeof_ns2_led_priv(pdata->num_leds), GFP_KERNEL); + if (!priv) return -ENOMEM; + priv->num_leds = pdata->num_leds; - for (i = 0; i < pdata->num_leds; i++) { - ret = create_ns2_led(pdev, &leds_data[i], &pdata->leds[i]); + for (i = 0; i < priv->num_leds; i++) { + ret = create_ns2_led(pdev, &priv->leds_data[i], + &pdata->leds[i]); if (ret < 0) { for (i = i - 1; i >= 0; i--) - delete_ns2_led(&leds_data[i]); + delete_ns2_led(&priv->leds_data[i]); return ret; } } - platform_set_drvdata(pdev, leds_data); + platform_set_drvdata(pdev, priv); return 0; } @@ -354,13 +367,12 @@ static int ns2_led_probe(struct platform_device *pdev) static int ns2_led_remove(struct platform_device *pdev) { int i; - struct ns2_led_platform_data *pdata = pdev->dev.platform_data; - struct ns2_led_data *leds_data; + struct ns2_led_priv *priv; - leds_data = platform_get_drvdata(pdev); + priv = platform_get_drvdata(pdev); - for (i = 0; i < pdata->num_leds; i++) - delete_ns2_led(&leds_data[i]); + for (i = 0; i < priv->num_leds; i++) + delete_ns2_led(&priv->leds_data[i]); platform_set_drvdata(pdev, NULL); |