diff options
author | Grant Grundler <grundler@chromium.org> | 2012-03-05 17:15:59 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-03-07 21:36:45 (GMT) |
commit | dbf717fd9a0d5fddd2dae3314a1e14842f4dc182 (patch) | |
tree | aeaff1723d88c306454ac7cb5409ca00f000e91a /drivers | |
parent | ee6aeff71e2f16b9fe95ce908d098c169e0f4004 (diff) | |
download | linux-fsl-qoriq-dbf717fd9a0d5fddd2dae3314a1e14842f4dc182.tar.xz |
staging:iio:tsl2563 rewrite probe error handling
tsl2563 probe function has two minor issues with it's error handling paths:
1) it is silent (did not report errors to dmesg)
2) did not return failure code (mixed up use of ret and err)
and two major issues:
3) goto fail2 would corrupt a free memory pool ("double free")
4) device registration failure did NOT cancel/flush delayed work.
(and thus dereference a freed data structure later)
The "double free" is subtle and was introduced with this change:
Author: Jonathan Cameron <jic23@cam.ac.uk>
Date: Mon Apr 18 12:58:55 2011 +0100
staging:iio:tsl2563 take advantage of new iio_device_allocate private data.
Originally, chip was allocated seperately. Now it's appended to the
indio_dev by iio_allocate_device(sizeof(*chip)). So we only need one
kfree call as well (in iio_free_device()).
Gory details of tracking this down are here:
http://crosbug.com/26819
Despite iio_device_registration failing, system can at least now boot.
Will follow up with a fix to "double register : in_intensity_both_raw"
error that is included in the bug report.
Signed-off-by: Grant Grundler <grundler@chromium.org>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Reviewed-by: Bryan Freed <bfreed@chromium.org>
Reviewed-by: Benson Leung <bleung@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/iio/light/tsl2563.c | 39 |
1 files changed, 26 insertions, 13 deletions
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index aca1e03..546c95a 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -708,7 +708,6 @@ static int __devinit tsl2563_probe(struct i2c_client *client, struct tsl2563_chip *chip; struct tsl2563_platform_data *pdata = client->dev.platform_data; int err = 0; - int ret; u8 id = 0; indio_dev = iio_allocate_device(sizeof(*chip)); @@ -722,13 +721,15 @@ static int __devinit tsl2563_probe(struct i2c_client *client, err = tsl2563_detect(chip); if (err) { - dev_err(&client->dev, "device not found, error %d\n", -err); + dev_err(&client->dev, "detect error %d\n", -err); goto fail1; } err = tsl2563_read_id(chip, &id); - if (err) + if (err) { + dev_err(&client->dev, "read id error %d\n", -err); goto fail1; + } mutex_init(&chip->lock); @@ -751,40 +752,52 @@ static int __devinit tsl2563_probe(struct i2c_client *client, indio_dev->num_channels = ARRAY_SIZE(tsl2563_channels); indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; + if (client->irq) indio_dev->info = &tsl2563_info; else indio_dev->info = &tsl2563_info_no_irq; + if (client->irq) { - ret = request_threaded_irq(client->irq, + err = request_threaded_irq(client->irq, NULL, &tsl2563_event_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "tsl2563_event", indio_dev); - if (ret) - goto fail2; + if (err) { + dev_err(&client->dev, "irq request error %d\n", -err); + goto fail1; + } } + err = tsl2563_configure(chip); - if (err) - goto fail3; + if (err) { + dev_err(&client->dev, "configure error %d\n", -err); + goto fail2; + } INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work); + /* The interrupt cannot yet be enabled so this is fine without lock */ schedule_delayed_work(&chip->poweroff_work, 5 * HZ); - ret = iio_device_register(indio_dev); - if (ret) + err = iio_device_register(indio_dev); + if (err) { + dev_err(&client->dev, "iio registration error %d\n", -err); goto fail3; + } return 0; + fail3: + cancel_delayed_work(&chip->poweroff_work); + flush_scheduled_work(); +fail2: if (client->irq) free_irq(client->irq, indio_dev); -fail2: - iio_free_device(indio_dev); fail1: - kfree(chip); + iio_free_device(indio_dev); return err; } |