diff options
author | Florian Fainelli <ffainelli@freebox.fr> | 2010-03-10 12:32:18 -0500 |
---|---|---|
committer | Richard Purdie <rpurdie@linux.intel.com> | 2010-03-16 16:27:25 -0400 |
commit | 14b5d6dd40b3091cb5f566568baa4a74dc619286 (patch) | |
tree | a7373270c8a0c90e03addbd1df7f3d849f8a7e52 /drivers/leds/led-class.c | |
parent | 0493a4ff10959ff4c8e0d65efee25b7ffd4fa5db (diff) |
leds: Fix race between LED device uevent and actual attributes creation
If we were to dynamically register/unregister leds and have udev or other
daemons handle the leds class uevents, we would be notified of the adding of a
new LED and if the daemon immediately tries to open one of the attributes of
the led device, it would fail with a "no such file or directory" error since
this the attributes are not yet created. Fix this by switching attributes to be
class-wide, such that the driver core will register these attributes with
device_add_attrs and then emit the kobject_uevent ADD signal.
Signed-off-by: Fainelli <ffainelli@freebox.fr>
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'drivers/leds/led-class.c')
-rw-r--r-- | drivers/leds/led-class.c | 40 |
1 files changed, 8 insertions, 32 deletions
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 349e07350144..69e7d86a5143 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c | |||
@@ -72,11 +72,14 @@ static ssize_t led_max_brightness_show(struct device *dev, | |||
72 | return sprintf(buf, "%u\n", led_cdev->max_brightness); | 72 | return sprintf(buf, "%u\n", led_cdev->max_brightness); |
73 | } | 73 | } |
74 | 74 | ||
75 | static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store); | 75 | static struct device_attribute led_class_attrs[] = { |
76 | static DEVICE_ATTR(max_brightness, 0444, led_max_brightness_show, NULL); | 76 | __ATTR(brightness, 0644, led_brightness_show, led_brightness_store), |
77 | __ATTR(max_brightness, 0644, led_max_brightness_show, NULL), | ||
77 | #ifdef CONFIG_LEDS_TRIGGERS | 78 | #ifdef CONFIG_LEDS_TRIGGERS |
78 | static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store); | 79 | __ATTR(trigger, 0644, led_trigger_show, led_trigger_store), |
79 | #endif | 80 | #endif |
81 | __ATTR_NULL, | ||
82 | }; | ||
80 | 83 | ||
81 | /** | 84 | /** |
82 | * led_classdev_suspend - suspend an led_classdev. | 85 | * led_classdev_suspend - suspend an led_classdev. |
@@ -127,18 +130,11 @@ static int led_resume(struct device *dev) | |||
127 | */ | 130 | */ |
128 | int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) | 131 | int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) |
129 | { | 132 | { |
130 | int rc; | ||
131 | |||
132 | led_cdev->dev = device_create(leds_class, parent, 0, led_cdev, | 133 | led_cdev->dev = device_create(leds_class, parent, 0, led_cdev, |
133 | "%s", led_cdev->name); | 134 | "%s", led_cdev->name); |
134 | if (IS_ERR(led_cdev->dev)) | 135 | if (IS_ERR(led_cdev->dev)) |
135 | return PTR_ERR(led_cdev->dev); | 136 | return PTR_ERR(led_cdev->dev); |
136 | 137 | ||
137 | /* register the attributes */ | ||
138 | rc = device_create_file(led_cdev->dev, &dev_attr_brightness); | ||
139 | if (rc) | ||
140 | goto err_out; | ||
141 | |||
142 | #ifdef CONFIG_LEDS_TRIGGERS | 138 | #ifdef CONFIG_LEDS_TRIGGERS |
143 | init_rwsem(&led_cdev->trigger_lock); | 139 | init_rwsem(&led_cdev->trigger_lock); |
144 | #endif | 140 | #endif |
@@ -150,17 +146,9 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) | |||
150 | if (!led_cdev->max_brightness) | 146 | if (!led_cdev->max_brightness) |
151 | led_cdev->max_brightness = LED_FULL; | 147 | led_cdev->max_brightness = LED_FULL; |
152 | 148 | ||
153 | rc = device_create_file(led_cdev->dev, &dev_attr_max_brightness); | ||
154 | if (rc) | ||
155 | goto err_out_attr_max; | ||
156 | |||
157 | led_update_brightness(led_cdev); | 149 | led_update_brightness(led_cdev); |
158 | 150 | ||
159 | #ifdef CONFIG_LEDS_TRIGGERS | 151 | #ifdef CONFIG_LEDS_TRIGGERS |
160 | rc = device_create_file(led_cdev->dev, &dev_attr_trigger); | ||
161 | if (rc) | ||
162 | goto err_out_led_list; | ||
163 | |||
164 | led_trigger_set_default(led_cdev); | 152 | led_trigger_set_default(led_cdev); |
165 | #endif | 153 | #endif |
166 | 154 | ||
@@ -168,18 +156,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) | |||
168 | led_cdev->name); | 156 | led_cdev->name); |
169 | 157 | ||
170 | return 0; | 158 | return 0; |
171 | |||
172 | #ifdef CONFIG_LEDS_TRIGGERS | ||
173 | err_out_led_list: | ||
174 | device_remove_file(led_cdev->dev, &dev_attr_max_brightness); | ||
175 | #endif | ||
176 | err_out_attr_max: | ||
177 | device_remove_file(led_cdev->dev, &dev_attr_brightness); | ||
178 | list_del(&led_cdev->node); | ||
179 | err_out: | ||
180 | device_unregister(led_cdev->dev); | ||
181 | return rc; | ||
182 | } | 159 | } |
160 | |||
183 | EXPORT_SYMBOL_GPL(led_classdev_register); | 161 | EXPORT_SYMBOL_GPL(led_classdev_register); |
184 | 162 | ||
185 | /** | 163 | /** |
@@ -190,10 +168,7 @@ EXPORT_SYMBOL_GPL(led_classdev_register); | |||
190 | */ | 168 | */ |
191 | void led_classdev_unregister(struct led_classdev *led_cdev) | 169 | void led_classdev_unregister(struct led_classdev *led_cdev) |
192 | { | 170 | { |
193 | device_remove_file(led_cdev->dev, &dev_attr_max_brightness); | ||
194 | device_remove_file(led_cdev->dev, &dev_attr_brightness); | ||
195 | #ifdef CONFIG_LEDS_TRIGGERS | 171 | #ifdef CONFIG_LEDS_TRIGGERS |
196 | device_remove_file(led_cdev->dev, &dev_attr_trigger); | ||
197 | down_write(&led_cdev->trigger_lock); | 172 | down_write(&led_cdev->trigger_lock); |
198 | if (led_cdev->trigger) | 173 | if (led_cdev->trigger) |
199 | led_trigger_set(led_cdev, NULL); | 174 | led_trigger_set(led_cdev, NULL); |
@@ -215,6 +190,7 @@ static int __init leds_init(void) | |||
215 | return PTR_ERR(leds_class); | 190 | return PTR_ERR(leds_class); |
216 | leds_class->suspend = led_suspend; | 191 | leds_class->suspend = led_suspend; |
217 | leds_class->resume = led_resume; | 192 | leds_class->resume = led_resume; |
193 | leds_class->dev_attrs = led_class_attrs; | ||
218 | return 0; | 194 | return 0; |
219 | } | 195 | } |
220 | 196 | ||