[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