Commit 3de1929ba61df87a0561c4f1fb7161c401fe3d04
Committed by
Bryan Wu
1 parent
c971ff185f
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 1 changed file with 25 additions and 13 deletions Side-by-side Diff
drivers/leds/leds-ns2.c
... | ... | @@ -308,10 +308,21 @@ |
308 | 308 | }; |
309 | 309 | #endif /* CONFIG_OF_GPIO */ |
310 | 310 | |
311 | +struct ns2_led_priv { | |
312 | + int num_leds; | |
313 | + struct ns2_led_data leds_data[]; | |
314 | +}; | |
315 | + | |
316 | +static inline int sizeof_ns2_led_priv(int num_leds) | |
317 | +{ | |
318 | + return sizeof(struct ns2_led_priv) + | |
319 | + (sizeof(struct ns2_led_data) * num_leds); | |
320 | +} | |
321 | + | |
311 | 322 | static int ns2_led_probe(struct platform_device *pdev) |
312 | 323 | { |
313 | 324 | struct ns2_led_platform_data *pdata = pdev->dev.platform_data; |
314 | - struct ns2_led_data *leds_data; | |
325 | + struct ns2_led_priv *priv; | |
315 | 326 | int i; |
316 | 327 | int ret; |
317 | 328 | |
318 | 329 | |
319 | 330 | |
320 | 331 | |
321 | 332 | |
... | ... | @@ -332,21 +343,23 @@ |
332 | 343 | return -EINVAL; |
333 | 344 | #endif /* CONFIG_OF_GPIO */ |
334 | 345 | |
335 | - leds_data = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_data) * | |
336 | - pdata->num_leds, GFP_KERNEL); | |
337 | - if (!leds_data) | |
346 | + priv = devm_kzalloc(&pdev->dev, | |
347 | + sizeof_ns2_led_priv(pdata->num_leds), GFP_KERNEL); | |
348 | + if (!priv) | |
338 | 349 | return -ENOMEM; |
350 | + priv->num_leds = pdata->num_leds; | |
339 | 351 | |
340 | - for (i = 0; i < pdata->num_leds; i++) { | |
341 | - ret = create_ns2_led(pdev, &leds_data[i], &pdata->leds[i]); | |
352 | + for (i = 0; i < priv->num_leds; i++) { | |
353 | + ret = create_ns2_led(pdev, &priv->leds_data[i], | |
354 | + &pdata->leds[i]); | |
342 | 355 | if (ret < 0) { |
343 | 356 | for (i = i - 1; i >= 0; i--) |
344 | - delete_ns2_led(&leds_data[i]); | |
357 | + delete_ns2_led(&priv->leds_data[i]); | |
345 | 358 | return ret; |
346 | 359 | } |
347 | 360 | } |
348 | 361 | |
349 | - platform_set_drvdata(pdev, leds_data); | |
362 | + platform_set_drvdata(pdev, priv); | |
350 | 363 | |
351 | 364 | return 0; |
352 | 365 | } |
353 | 366 | |
354 | 367 | |
... | ... | @@ -354,13 +367,12 @@ |
354 | 367 | static int ns2_led_remove(struct platform_device *pdev) |
355 | 368 | { |
356 | 369 | int i; |
357 | - struct ns2_led_platform_data *pdata = pdev->dev.platform_data; | |
358 | - struct ns2_led_data *leds_data; | |
370 | + struct ns2_led_priv *priv; | |
359 | 371 | |
360 | - leds_data = platform_get_drvdata(pdev); | |
372 | + priv = platform_get_drvdata(pdev); | |
361 | 373 | |
362 | - for (i = 0; i < pdata->num_leds; i++) | |
363 | - delete_ns2_led(&leds_data[i]); | |
374 | + for (i = 0; i < priv->num_leds; i++) | |
375 | + delete_ns2_led(&priv->leds_data[i]); | |
364 | 376 | |
365 | 377 | platform_set_drvdata(pdev, NULL); |
366 | 378 |