aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds/leds-pca955x.c
diff options
context:
space:
mode:
authorSven Wegener <sven.wegener@stealer.net>2008-10-03 18:23:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-03 21:22:18 -0400
commit95bf14bff58fd200f0c2147c84582cc2488367d0 (patch)
treeedc4c02c44981aa1a538cf883f8af34a69fbc552 /drivers/leds/leds-pca955x.c
parent07f696c7772fb3501e9531de38333c49143a8d52 (diff)
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: Sven Wegener <sven.wegener@stealer.net> Acked-by: Nate Case <ncase@xes-inc.com> Tested-by: Nate Case <ncase@xes-inc.com> Acked-by: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/leds/leds-pca955x.c')
-rw-r--r--drivers/leds/leds-pca955x.c70
1 files changed, 38 insertions, 32 deletions
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 146c06972863..f508729123b5 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -248,11 +248,10 @@ static int __devinit pca955x_probe(struct i2c_client *client,
248 const struct i2c_device_id *id) 248 const struct i2c_device_id *id)
249{ 249{
250 struct pca955x_led *pca955x; 250 struct pca955x_led *pca955x;
251 int i;
252 int err = -ENODEV;
253 struct pca955x_chipdef *chip; 251 struct pca955x_chipdef *chip;
254 struct i2c_adapter *adapter; 252 struct i2c_adapter *adapter;
255 struct led_platform_data *pdata; 253 struct led_platform_data *pdata;
254 int i, err;
256 255
257 chip = &pca955x_chipdefs[id->driver_data]; 256 chip = &pca955x_chipdefs[id->driver_data];
258 adapter = to_i2c_adapter(client->dev.parent); 257 adapter = to_i2c_adapter(client->dev.parent);
@@ -282,43 +281,41 @@ static int __devinit pca955x_probe(struct i2c_client *client,
282 } 281 }
283 } 282 }
284 283
284 pca955x = kzalloc(sizeof(*pca955x) * chip->bits, GFP_KERNEL);
285 if (!pca955x)
286 return -ENOMEM;
287
288 i2c_set_clientdata(client, pca955x);
289
285 for (i = 0; i < chip->bits; i++) { 290 for (i = 0; i < chip->bits; i++) {
286 pca955x = kzalloc(sizeof(struct pca955x_led), GFP_KERNEL); 291 pca955x[i].chipdef = chip;
287 if (!pca955x) { 292 pca955x[i].client = client;
288 err = -ENOMEM; 293 pca955x[i].led_num = i;
289 goto exit;
290 }
291 294
292 pca955x->chipdef = chip;
293 pca955x->client = client;
294 pca955x->led_num = i;
295 /* Platform data can specify LED names and default triggers */ 295 /* Platform data can specify LED names and default triggers */
296 if (pdata) { 296 if (pdata) {
297 if (pdata->leds[i].name) 297 if (pdata->leds[i].name)
298 snprintf(pca955x->name, 32, "pca955x:%s", 298 snprintf(pca955x[i].name,
299 pdata->leds[i].name); 299 sizeof(pca955x[i].name), "pca955x:%s",
300 pdata->leds[i].name);
300 if (pdata->leds[i].default_trigger) 301 if (pdata->leds[i].default_trigger)
301 pca955x->led_cdev.default_trigger = 302 pca955x[i].led_cdev.default_trigger =
302 pdata->leds[i].default_trigger; 303 pdata->leds[i].default_trigger;
303 } else { 304 } else {
304 snprintf(pca955x->name, 32, "pca955x:%d", i); 305 snprintf(pca955x[i].name, sizeof(pca955x[i].name),
306 "pca955x:%d", i);
305 } 307 }
306 spin_lock_init(&pca955x->lock);
307 308
308 pca955x->led_cdev.name = pca955x->name; 309 spin_lock_init(&pca955x[i].lock);
309 pca955x->led_cdev.brightness_set =
310 pca955x_led_set;
311 310
312 /* 311 pca955x[i].led_cdev.name = pca955x[i].name;
313 * Client data is a pointer to the _first_ pca955x_led 312 pca955x[i].led_cdev.brightness_set = pca955x_led_set;
314 * struct
315 */
316 if (i == 0)
317 i2c_set_clientdata(client, pca955x);
318 313
319 INIT_WORK(&(pca955x->work), pca955x_led_work); 314 INIT_WORK(&pca955x[i].work, pca955x_led_work);
320 315
321 led_classdev_register(&client->dev, &(pca955x->led_cdev)); 316 err = led_classdev_register(&client->dev, &pca955x[i].led_cdev);
317 if (err < 0)
318 goto exit;
322 } 319 }
323 320
324 /* Turn off LEDs */ 321 /* Turn off LEDs */
@@ -336,23 +333,32 @@ static int __devinit pca955x_probe(struct i2c_client *client,
336 pca955x_write_psc(client, 1, 0); 333 pca955x_write_psc(client, 1, 0);
337 334
338 return 0; 335 return 0;
336
339exit: 337exit:
338 while (i--) {
339 led_classdev_unregister(&pca955x[i].led_cdev);
340 cancel_work_sync(&pca955x[i].work);
341 }
342
343 kfree(pca955x);
344 i2c_set_clientdata(client, NULL);
345
340 return err; 346 return err;
341} 347}
342 348
343static int __devexit pca955x_remove(struct i2c_client *client) 349static int __devexit pca955x_remove(struct i2c_client *client)
344{ 350{
345 struct pca955x_led *pca955x = i2c_get_clientdata(client); 351 struct pca955x_led *pca955x = i2c_get_clientdata(client);
346 int leds = pca955x->chipdef->bits;
347 int i; 352 int i;
348 353
349 for (i = 0; i < leds; i++) { 354 for (i = 0; i < pca955x->chipdef->bits; i++) {
350 led_classdev_unregister(&(pca955x->led_cdev)); 355 led_classdev_unregister(&pca955x[i].led_cdev);
351 cancel_work_sync(&(pca955x->work)); 356 cancel_work_sync(&pca955x[i].work);
352 kfree(pca955x);
353 pca955x = pca955x + 1;
354 } 357 }
355 358
359 kfree(pca955x);
360 i2c_set_clientdata(client, NULL);
361
356 return 0; 362 return 0;
357} 363}
358 364