[kernel] r12402 - in dists/sid/linux-2.6/debian: . patches/features/arm patches/series
Martin Michlmayr
tbm at alioth.debian.org
Wed Nov 19 22:25:16 UTC 2008
Author: tbm
Date: Wed Nov 19 22:25:15 2008
New Revision: 12402
Log:
leds-pca9532 fixes
Added:
dists/sid/linux-2.6/debian/patches/features/arm/led-pca9532-mem-leak.patch
dists/sid/linux-2.6/debian/patches/features/arm/led-pca9532-workqueque.patch
Modified:
dists/sid/linux-2.6/debian/changelog
dists/sid/linux-2.6/debian/patches/series/11
Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog (original)
+++ dists/sid/linux-2.6/debian/changelog Wed Nov 19 22:25:15 2008
@@ -44,6 +44,9 @@
[ Martin Michlmayr ]
* [arm/iop32x, arm/ixp4xx, arm/orion5x] Enable support for more partition
tables, including MAC_PARTITION (requested by Benoît Knecht).
+ * leds-pca9532: Fix memory leak and properly handle errors (Sven Wegener)
+ * leds-pca9532: Move i2c work to a workqueque (Riku Voipio). (closes:
+ #506116)
-- dann frazier <dannf at debian.org> Mon, 17 Nov 2008 23:14:13 -0700
Added: dists/sid/linux-2.6/debian/patches/features/arm/led-pca9532-mem-leak.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/arm/led-pca9532-mem-leak.patch Wed Nov 19 22:25:15 2008
@@ -0,0 +1,79 @@
+From: Sven Wegener <sven.wegener at stealer.net>
+Subject: [PATCH] leds-pca9532: Fix memory leak and properly handle errors
+
+When the registration fails, we need to release the memory we allocated. Also
+we need to save the error from led_classdev_register and propagate it up, else
+we'll return success, even if we failed.
+
+Signed-off-by: Riku Voipio <riku.voipio at iki.fi>
+---
+ drivers/leds/leds-pca9532.c | 22 +++++++++++++---------
+ 1 files changed, 13 insertions(+), 9 deletions(-)
+
+I don't have the hardware. Riku, can you please test if it still works as
+expected.
+
+diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
+index 4064d4f..16af817 100644
+--- a/drivers/leds/leds-pca9532.c
++++ b/drivers/leds/leds-pca9532.c
+@@ -204,8 +204,8 @@ static int pca9532_configure(struct i2c_client *client,
+ led->ldev.brightness = LED_OFF;
+ led->ldev.brightness_set = pca9532_set_brightness;
+ led->ldev.blink_set = pca9532_set_blink;
+- if (led_classdev_register(&client->dev,
+- &led->ldev) < 0) {
++ err = led_classdev_register(&client->dev, &led->ldev);
++ if (err < 0) {
+ dev_err(&client->dev,
+ "couldn't register LED %s\n",
+ led->name);
+@@ -263,7 +263,6 @@ exit:
+ }
+
+ return err;
+-
+ }
+
+ static int pca9532_probe(struct i2c_client *client,
+@@ -271,12 +270,16 @@ static int pca9532_probe(struct i2c_client *client,
+ {
+ struct pca9532_data *data = i2c_get_clientdata(client);
+ struct pca9532_platform_data *pca9532_pdata = client->dev.platform_data;
++ int err;
++
++ if (!pca9532_pdata)
++ return -EIO;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+- data = kzalloc(sizeof(struct pca9532_data), GFP_KERNEL);
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+@@ -285,12 +288,13 @@ static int pca9532_probe(struct i2c_client *client,
+ data->client = client;
+ mutex_init(&data->update_lock);
+
+- if (pca9532_pdata == NULL)
+- return -EIO;
+-
+- pca9532_configure(client, data, pca9532_pdata);
+- return 0;
++ err = pca9532_configure(client, data, pca9532_pdata);
++ if (err) {
++ kfree(data);
++ i2c_set_clientdata(client, NULL);
++ }
+
++ return err;
+ }
+
+ static int pca9532_remove(struct i2c_client *client)
+
+
+--
+"rm -rf" only sounds scary if you don't have backups
Added: dists/sid/linux-2.6/debian/patches/features/arm/led-pca9532-workqueque.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/arm/led-pca9532-workqueque.patch Wed Nov 19 22:25:15 2008
@@ -0,0 +1,191 @@
+From: Riku Voipio <riku.voipio at iki.fi>
+Subject: [PATCH] Move i2c work to a workqueque
+
+Apparently these might be called under atomic context,
+and i2c operations may sleep. BUG found by
+Ross Burton <ross at burtonini.com>
+
+Signed-off-by: Riku Voipio <riku.voipio at iki.fi>
+---
+ drivers/leds/leds-pca9532.c | 51 +++++++++++++++++++++++++++++++++++------
+ include/linux/leds-pca9532.h | 2 +
+ 2 files changed, 45 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
+index 62b60a0..cb8e517 100644
+--- a/drivers/leds/leds-pca9532.c
++++ b/drivers/leds/leds-pca9532.c
+@@ -16,6 +16,7 @@
+ #include <linux/leds.h>
+ #include <linux/input.h>
+ #include <linux/mutex.h>
++#include <linux/workqueue.h>
+ #include <linux/leds-pca9532.h>
+
+ static const unsigned short normal_i2c[] = { /*0x60,*/ I2C_CLIENT_END};
+@@ -34,6 +35,7 @@ struct pca9532_data {
+ struct pca9532_led leds[16];
+ struct mutex update_lock;
+ struct input_dev *idev;
++ struct work_struct work;
+ u8 pwm[2];
+ u8 psc[2];
+ };
+@@ -63,7 +65,7 @@ static struct i2c_driver pca9532_driver = {
+ * as a compromise we average one pwm to the values requested by all
+ * leds that are not ON/OFF.
+ * */
+-static int pca9532_setpwm(struct i2c_client *client, int pwm, int blink,
++static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
+ enum led_brightness value)
+ {
+ int a = 0, b = 0, i = 0;
+@@ -84,11 +86,17 @@ static int pca9532_setpwm(struct i2c_client *client, int pwm, int blink,
+ b = b/a;
+ if (b > 0xFF)
+ return -EINVAL;
+- mutex_lock(&data->update_lock);
+ data->pwm[pwm] = b;
++ data->psc[pwm] = blink;
++ return 0;
++}
++
++static int pca9532_setpwm(struct i2c_client *client, int pwm)
++{
++ struct pca9532_data *data = i2c_get_clientdata(client);
++ mutex_lock(&data->update_lock);
+ i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
+ data->pwm[pwm]);
+- data->psc[pwm] = blink;
+ i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
+ data->psc[pwm]);
+ mutex_unlock(&data->update_lock);
+@@ -124,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
+ led->state = PCA9532_ON;
+ else {
+ led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
+- err = pca9532_setpwm(led->client, 0, 0, value);
++ err = pca9532_calcpwm(led->client, 0, 0, value);
+ if (err)
+ return; /* XXX: led api doesn't allow error code? */
+ }
+- pca9532_setled(led);
++ schedule_work(&led->work);
+ }
+
+ static int pca9532_set_blink(struct led_classdev *led_cdev,
+@@ -137,6 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
+ struct pca9532_led *led = ldev_to_led(led_cdev);
+ struct i2c_client *client = led->client;
+ int psc;
++ int err = 0;
+
+ if (*delay_on == 0 && *delay_off == 0) {
+ /* led subsystem ask us for a blink rate */
+@@ -148,7 +157,11 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
+
+ /* Thecus specific: only use PSC/PWM 0 */
+ psc = (*delay_on * 152-1)/1000;
+- return pca9532_setpwm(client, 0, psc, led_cdev->brightness);
++ err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
++ if (err)
++ return err;
++ schedule_work(&led->work);
++ return 0;
+ }
+
+ static int pca9532_event(struct input_dev *dev, unsigned int type,
+@@ -165,13 +178,28 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
+ else
+ data->pwm[1] = 0;
+
+- dev_info(&dev->dev, "setting beep to %d \n", data->pwm[1]);
++ schedule_work(&data->work);
++
++ return 0;
++}
++
++static void pca9532_input_work(struct work_struct *work)
++{
++ struct pca9532_data *data;
++ data = container_of(work, struct pca9532_data, work);
+ mutex_lock(&data->update_lock);
+ i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
+ data->pwm[1]);
+ mutex_unlock(&data->update_lock);
++}
+
+- return 0;
++static void pca9532_led_work(struct work_struct *work)
++{
++ struct pca9532_led *led;
++ led = container_of(work, struct pca9532_led, work);
++ if (led->state == PCA9532_PWM0)
++ pca9532_setpwm(led->client, 0);
++ pca9532_setled(led);
+ }
+
+ static int pca9532_configure(struct i2c_client *client,
+@@ -233,9 +262,11 @@ static int pca9532_configure(struct i2c_client *client,
+ BIT_MASK(SND_TONE);
+ data->idev->event = pca9532_event;
+ input_set_drvdata(data->idev, data);
++ INIT_WORK(&data->work, pca9532_input_work);
+ err = input_register_device(data->idev);
+ if (err) {
+ input_free_device(data->idev);
++ cancel_work_sync(&data->work);
+ data->idev = NULL;
+ goto exit;
+ }
+@@ -252,11 +283,13 @@ exit:
+ break;
+ case PCA9532_TYPE_LED:
+ led_classdev_unregister(&data->leds[i].ldev);
++ cancel_work_sync(&data->leds[i].work);
+ break;
+ case PCA9532_TYPE_N2100_BEEP:
+ if (data->idev != NULL) {
+ input_unregister_device(data->idev);
+ input_free_device(data->idev);
++ cancel_work_sync(&data->work);
+ data->idev = NULL;
+ }
+ break;
+@@ -307,11 +340,13 @@ static int pca9532_remove(struct i2c_client *client)
+ break;
+ case PCA9532_TYPE_LED:
+ led_classdev_unregister(&data->leds[i].ldev);
++ cancel_work_sync(&data->leds[i].work);
+ break;
+ case PCA9532_TYPE_N2100_BEEP:
+ if (data->idev != NULL) {
+ input_unregister_device(data->idev);
+ input_free_device(data->idev);
++ cancel_work_sync(&data->work);
+ data->idev = NULL;
+ }
+ break;
+diff --git a/include/linux/leds-pca9532.h b/include/linux/leds-pca9532.h
+index 81b4207..f158eb1 100644
+--- a/include/linux/leds-pca9532.h
++++ b/include/linux/leds-pca9532.h
+@@ -15,6 +15,7 @@
+ #define __LINUX_PCA9532_H
+
+ #include <linux/leds.h>
++#include <linux/workqueue.h>
+
+ enum pca9532_state {
+ PCA9532_OFF = 0x0,
+@@ -31,6 +32,7 @@ struct pca9532_led {
+ struct i2c_client *client;
+ char *name;
+ struct led_classdev ldev;
++ struct work_struct work;
+ enum pca9532_type type;
+ enum pca9532_state state;
+ };
+--
+1.5.6.5
+
Modified: dists/sid/linux-2.6/debian/patches/series/11
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/11 (original)
+++ dists/sid/linux-2.6/debian/patches/series/11 Wed Nov 19 22:25:15 2008
@@ -8,3 +8,5 @@
+ bugfix/all/tvaudio-treble-bass-control-oops.patch
+ bugfix/all/stable/2.6.26.6-revert_kernel_tick_broadcast_oneshot_1.patch
+ bugfix/all/stable/2.6.26.6-revert_kernel_tick_broadcast_oneshot_2.patch
++ features/arm/led-pca9532-mem-leak.patch
++ features/arm/led-pca9532-workqueque.patch
More information about the Kernel-svn-changes
mailing list