Commit 95bf14bf authored by Sven Wegener's avatar Sven Wegener Committed by Linus Torvalds

leds-pca955x: add proper error handling and fix bogus memory handling

Check the return value of led_classdev_register and unregister all
registered devices, if registering one device fails.  Also the dynamic
memory handling is totally bogus.  You can't allocate multiple chunks via
kzalloc() and expect them to be in order later.  I wonder how this ever
worked.
Signed-off-by: default avatarSven Wegener <sven.wegener@stealer.net>
Acked-by: default avatarNate Case <ncase@xes-inc.com>
Tested-by: default avatarNate Case <ncase@xes-inc.com>
Acked-by: default avatarRichard Purdie <rpurdie@rpsys.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 07f696c7
...@@ -248,11 +248,10 @@ static int __devinit pca955x_probe(struct i2c_client *client, ...@@ -248,11 +248,10 @@ static int __devinit pca955x_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct pca955x_led *pca955x; struct pca955x_led *pca955x;
int i;
int err = -ENODEV;
struct pca955x_chipdef *chip; struct pca955x_chipdef *chip;
struct i2c_adapter *adapter; struct i2c_adapter *adapter;
struct led_platform_data *pdata; struct led_platform_data *pdata;
int i, err;
chip = &pca955x_chipdefs[id->driver_data]; chip = &pca955x_chipdefs[id->driver_data];
adapter = to_i2c_adapter(client->dev.parent); adapter = to_i2c_adapter(client->dev.parent);
...@@ -282,43 +281,41 @@ static int __devinit pca955x_probe(struct i2c_client *client, ...@@ -282,43 +281,41 @@ static int __devinit pca955x_probe(struct i2c_client *client,
} }
} }
pca955x = kzalloc(sizeof(*pca955x) * chip->bits, GFP_KERNEL);
if (!pca955x)
return -ENOMEM;
i2c_set_clientdata(client, pca955x);
for (i = 0; i < chip->bits; i++) { for (i = 0; i < chip->bits; i++) {
pca955x = kzalloc(sizeof(struct pca955x_led), GFP_KERNEL); pca955x[i].chipdef = chip;
if (!pca955x) { pca955x[i].client = client;
err = -ENOMEM; pca955x[i].led_num = i;
goto exit;
}
pca955x->chipdef = chip;
pca955x->client = client;
pca955x->led_num = i;
/* Platform data can specify LED names and default triggers */ /* Platform data can specify LED names and default triggers */
if (pdata) { if (pdata) {
if (pdata->leds[i].name) if (pdata->leds[i].name)
snprintf(pca955x->name, 32, "pca955x:%s", snprintf(pca955x[i].name,
pdata->leds[i].name); sizeof(pca955x[i].name), "pca955x:%s",
pdata->leds[i].name);
if (pdata->leds[i].default_trigger) if (pdata->leds[i].default_trigger)
pca955x->led_cdev.default_trigger = pca955x[i].led_cdev.default_trigger =
pdata->leds[i].default_trigger; pdata->leds[i].default_trigger;
} else { } else {
snprintf(pca955x->name, 32, "pca955x:%d", i); snprintf(pca955x[i].name, sizeof(pca955x[i].name),
"pca955x:%d", i);
} }
spin_lock_init(&pca955x->lock);
pca955x->led_cdev.name = pca955x->name; spin_lock_init(&pca955x[i].lock);
pca955x->led_cdev.brightness_set =
pca955x_led_set;
/* pca955x[i].led_cdev.name = pca955x[i].name;
* Client data is a pointer to the _first_ pca955x_led pca955x[i].led_cdev.brightness_set = pca955x_led_set;
* struct
*/
if (i == 0)
i2c_set_clientdata(client, pca955x);
INIT_WORK(&(pca955x->work), pca955x_led_work); INIT_WORK(&pca955x[i].work, pca955x_led_work);
led_classdev_register(&client->dev, &(pca955x->led_cdev)); err = led_classdev_register(&client->dev, &pca955x[i].led_cdev);
if (err < 0)
goto exit;
} }
/* Turn off LEDs */ /* Turn off LEDs */
...@@ -336,23 +333,32 @@ static int __devinit pca955x_probe(struct i2c_client *client, ...@@ -336,23 +333,32 @@ static int __devinit pca955x_probe(struct i2c_client *client,
pca955x_write_psc(client, 1, 0); pca955x_write_psc(client, 1, 0);
return 0; return 0;
exit: exit:
while (i--) {
led_classdev_unregister(&pca955x[i].led_cdev);
cancel_work_sync(&pca955x[i].work);
}
kfree(pca955x);
i2c_set_clientdata(client, NULL);
return err; return err;
} }
static int __devexit pca955x_remove(struct i2c_client *client) static int __devexit pca955x_remove(struct i2c_client *client)
{ {
struct pca955x_led *pca955x = i2c_get_clientdata(client); struct pca955x_led *pca955x = i2c_get_clientdata(client);
int leds = pca955x->chipdef->bits;
int i; int i;
for (i = 0; i < leds; i++) { for (i = 0; i < pca955x->chipdef->bits; i++) {
led_classdev_unregister(&(pca955x->led_cdev)); led_classdev_unregister(&pca955x[i].led_cdev);
cancel_work_sync(&(pca955x->work)); cancel_work_sync(&pca955x[i].work);
kfree(pca955x);
pca955x = pca955x + 1;
} }
kfree(pca955x);
i2c_set_clientdata(client, NULL);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment