Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dbf717fd authored by Grant Grundler's avatar Grant Grundler Committed by Greg Kroah-Hartman
Browse files

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: default avatarGrant Grundler <grundler@chromium.org>
Acked-by: default avatarJonathan Cameron <jic23@kernel.org>
Reviewed-by: default avatarBryan Freed <bfreed@chromium.org>
Reviewed-by: default avatarBenson Leung <bleung@chromium.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ee6aeff7
Loading
Loading
Loading
Loading
+26 −13
Original line number Diff line number Diff line
@@ -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;
}