From 3051e41ab7daaa59d4564f20b25dcb8c03f35f2b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 25 Aug 2008 11:49:20 +0100 Subject: ALSA: ASoC: Fix double free and memory leak in many codec drivers Many SoC audio codec drivers have improper freeing of memory in error paths. * codec is allocated in the platform device probe function, but is not freed there in case of error. Instead it is freed in the i2c device probe function's error path. However the success or failure of both functions is not linked, so this could result in a double free (if the platform device is successfully probed, the i2c device probing fails and then the platform driver is unregistered.) * codec->private_data is allocated in many platform device probe functions but not freed in their error paths. This patch hopefully solves all these problems. Signed-off-by: Jean Delvare Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8990.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs/wm8990.c') diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index e44153fa38de..dd995ef448b4 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1500,10 +1500,9 @@ static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) client_template.addr = addr; i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); + if (i2c == NULL) return -ENOMEM; - } + i2c_set_clientdata(i2c, codec); codec->control_data = i2c; @@ -1521,7 +1520,6 @@ static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) return ret; err: - kfree(codec); kfree(i2c); return ret; } @@ -1595,6 +1593,11 @@ static int wm8990_probe(struct platform_device *pdev) #else /* Add other interfaces here */ #endif + + if (ret != 0) { + kfree(codec->private_data); + kfree(codec); + } return ret; } -- cgit v1.2.3 From e5d3fd38f93755c5ab1e04b8e40196135f576355 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 1 Sep 2008 18:47:02 +0100 Subject: ALSA: ASoC: Convert wm8990 to a new-style i2c driver Convert the wm8990 codec driver to the new (standard) device driver binding model. After this change, WM8990 devices are no longer discovered automatically and must instead be instantiated explicitly. Signed-off-by: Jean Delvare Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8990.c | 103 ++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 50 deletions(-) (limited to 'sound/soc/codecs/wm8990.c') diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index dd995ef448b4..e1bb5059755a 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1477,81 +1477,86 @@ static struct snd_soc_device *wm8990_socdev; * low = 0x34 * high = 0x36 */ -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver wm8990_i2c_driver; -static struct i2c_client client_template; - -static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) +static int wm8990_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct snd_soc_device *socdev = wm8990_socdev; - struct wm8990_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; int ret; - if (addr != setup->i2c_address) - return -ENODEV; - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) - return -ENOMEM; - i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = i2c_attach_client(i2c); - if (ret < 0) { - pr_err("failed to attach codec at addr %x\n", addr); - goto err; - } - ret = wm8990_init(socdev); - if (ret < 0) { + if (ret < 0) pr_err("failed to initialise WM8990\n"); - goto err; - } - return ret; -err: - kfree(i2c); return ret; } -static int wm8990_i2c_detach(struct i2c_client *client) +static int wm8990_i2c_remove(struct i2c_client *client) { struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); kfree(codec->reg_cache); - kfree(client); return 0; } -static int wm8990_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, wm8990_codec_probe); -} +static const struct i2c_device_id wm8990_i2c_id[] = { + { "wm8990", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id); static struct i2c_driver wm8990_i2c_driver = { .driver = { .name = "WM8990 I2C Codec", .owner = THIS_MODULE, }, - .attach_adapter = wm8990_i2c_attach, - .detach_client = wm8990_i2c_detach, - .command = NULL, + .probe = wm8990_i2c_probe, + .remove = wm8990_i2c_remove, + .id_table = wm8990_i2c_id, }; -static struct i2c_client client_template = { - .name = "WM8990", - .driver = &wm8990_i2c_driver, -}; +static int wm8990_add_i2c_device(struct platform_device *pdev, + const struct wm8990_setup_data *setup) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + int ret; + + ret = i2c_add_driver(&wm8990_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = setup->i2c_address; + strlcpy(info.type, "wm8990", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(setup->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "can't get i2c adapter %d\n", + setup->i2c_bus); + goto err_driver; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + goto err_driver; + } + + return 0; + +err_driver: + i2c_del_driver(&wm8990_i2c_driver); + return -ENODEV; +} #endif static int wm8990_probe(struct platform_device *pdev) @@ -1584,11 +1589,8 @@ static int wm8990_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8990_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); + ret = wm8990_add_i2c_device(pdev, setup); } #else /* Add other interfaces here */ @@ -1612,6 +1614,7 @@ static int wm8990_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_unregister_device(codec->control_data); i2c_del_driver(&wm8990_i2c_driver); #endif kfree(codec->private_data); -- cgit v1.2.3 From b7c9d8520564eca89da8733e5248c7ce8ee8e1b0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Sep 2008 18:47:04 +0100 Subject: ALSA: ASoC: Don't suggest compile time selection of codec access Currently the boiler plate code used by most ASoC codecs to provide a placeholder for SPI access suggests making the selection of SPI a compile time option which is suboptimal when trying to build kernels supporting multiple systems. Change this template to suggest allowing runtime selection instead. Leave the drivers not yet converted to new style I2C access for now to avoid collisions. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8990.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs/wm8990.c') diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index e1bb5059755a..63410d7b5efb 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1565,7 +1565,7 @@ static int wm8990_probe(struct platform_device *pdev) struct wm8990_setup_data *setup; struct snd_soc_codec *codec; struct wm8990_priv *wm8990; - int ret = 0; + int ret; pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); @@ -1587,13 +1587,13 @@ static int wm8990_probe(struct platform_device *pdev) INIT_LIST_HEAD(&codec->dapm_paths); wm8990_socdev = socdev; + ret = -ENODEV; + #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8990_add_i2c_device(pdev, setup); } -#else - /* Add other interfaces here */ #endif if (ret != 0) { -- cgit v1.2.3 From 3ab57fbe91994e5d6fb371a34390520c6c905bee Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 7 Oct 2008 14:49:22 +0300 Subject: ALSA: ASoC: Remove unused AUDIO_NAME define from codec drivers Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8990.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc/codecs/wm8990.c') diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 63410d7b5efb..572d22b0880b 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -30,7 +30,6 @@ #include "wm8990.h" -#define AUDIO_NAME "wm8990" #define WM8990_VERSION "0.2" /* codec private data */ -- cgit v1.2.3