This driver can cause an oops if si4713_platform_data holding pointer to set_power function is marked as __initdata and when trying to power up the chip after booting e.g. with 'v4l2-ctl -d /dev/radio0 --set-ctrl=mute=0'. This happens because the sdev->platform_data doesn't point to valid data anymore after kernel is initialized. Fix this by taking local copy of si4713_platform_data->set_power. Add also NULL check for this function pointer. Signed-off-by: Jarkko Nikula <jhnikula@xxxxxxxxx> Cc: Eduardo Valentin <eduardo.valentin@xxxxxxxxx> --- drivers/media/radio/si4713-i2c.c | 15 +++++++++------ drivers/media/radio/si4713-i2c.h | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index ab63dd5..cf9858d 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -369,7 +369,8 @@ static int si4713_powerup(struct si4713_device *sdev) if (sdev->power_state) return 0; - sdev->platform_data->set_power(1); + if (sdev->set_power) + sdev->set_power(1); err = si4713_send_command(sdev, SI4713_CMD_POWER_UP, args, ARRAY_SIZE(args), resp, ARRAY_SIZE(resp), @@ -383,8 +384,8 @@ static int si4713_powerup(struct si4713_device *sdev) err = si4713_write_property(sdev, SI4713_GPO_IEN, SI4713_STC_INT | SI4713_CTS); - } else { - sdev->platform_data->set_power(0); + } else if (sdev->set_power) { + sdev->set_power(0); } return err; @@ -411,7 +412,8 @@ static int si4713_powerdown(struct si4713_device *sdev) v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n", resp[0]); v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n"); - sdev->platform_data->set_power(0); + if (sdev->set_power) + sdev->set_power(0); sdev->power_state = POWER_OFF; } @@ -1959,6 +1961,7 @@ static int si4713_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct si4713_device *sdev; + struct si4713_platform_data *pdata = client->dev.platform_data; int rval; sdev = kzalloc(sizeof *sdev, GFP_KERNEL); @@ -1968,12 +1971,12 @@ static int si4713_probe(struct i2c_client *client, goto exit; } - sdev->platform_data = client->dev.platform_data; - if (!sdev->platform_data) { + if (!pdata) { v4l2_err(&sdev->sd, "No platform data registered.\n"); rval = -ENODEV; goto free_sdev; } + sdev->set_power = pdata->set_power; v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops); diff --git a/drivers/media/radio/si4713-i2c.h b/drivers/media/radio/si4713-i2c.h index faf8cff..d1af889 100644 --- a/drivers/media/radio/si4713-i2c.h +++ b/drivers/media/radio/si4713-i2c.h @@ -220,7 +220,7 @@ struct si4713_device { /* private data structures */ struct mutex mutex; struct completion work; - struct si4713_platform_data *platform_data; + int (*set_power)(int power); struct rds_info rds_info; struct limiter_info limiter_info; struct pilot_info pilot_info; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html