diff options
Diffstat (limited to 'drivers/leds')
-rw-r--r-- | drivers/leds/trigger/ledtrig-pattern.c | 99 |
1 files changed, 80 insertions, 19 deletions
diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c index 1870cf87afe1..718729c89440 100644 --- a/drivers/leds/trigger/ledtrig-pattern.c +++ b/drivers/leds/trigger/ledtrig-pattern.c | |||
@@ -220,22 +220,10 @@ out: | |||
220 | return count; | 220 | return count; |
221 | } | 221 | } |
222 | 222 | ||
223 | static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, | 223 | static int pattern_trig_store_patterns_string(struct pattern_trig_data *data, |
224 | const char *buf, size_t count, | 224 | const char *buf, size_t count) |
225 | bool hw_pattern) | ||
226 | { | 225 | { |
227 | struct pattern_trig_data *data = led_cdev->trigger_data; | 226 | int ccount, cr, offset = 0; |
228 | int ccount, cr, offset = 0, err = 0; | ||
229 | |||
230 | mutex_lock(&data->lock); | ||
231 | |||
232 | del_timer_sync(&data->timer); | ||
233 | |||
234 | if (data->is_hw_pattern) | ||
235 | led_cdev->pattern_clear(led_cdev); | ||
236 | |||
237 | data->is_hw_pattern = hw_pattern; | ||
238 | data->npatterns = 0; | ||
239 | 227 | ||
240 | while (offset < count - 1 && data->npatterns < MAX_PATTERNS) { | 228 | while (offset < count - 1 && data->npatterns < MAX_PATTERNS) { |
241 | cr = 0; | 229 | cr = 0; |
@@ -244,14 +232,54 @@ static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, | |||
244 | &data->patterns[data->npatterns].delta_t, &cr); | 232 | &data->patterns[data->npatterns].delta_t, &cr); |
245 | if (ccount != 2) { | 233 | if (ccount != 2) { |
246 | data->npatterns = 0; | 234 | data->npatterns = 0; |
247 | err = -EINVAL; | 235 | return -EINVAL; |
248 | goto out; | ||
249 | } | 236 | } |
250 | 237 | ||
251 | offset += cr; | 238 | offset += cr; |
252 | data->npatterns++; | 239 | data->npatterns++; |
253 | } | 240 | } |
254 | 241 | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int pattern_trig_store_patterns_int(struct pattern_trig_data *data, | ||
246 | const u32 *buf, size_t count) | ||
247 | { | ||
248 | unsigned int i; | ||
249 | |||
250 | for (i = 0; i < count; i += 2) { | ||
251 | data->patterns[data->npatterns].brightness = buf[i]; | ||
252 | data->patterns[data->npatterns].delta_t = buf[i + 1]; | ||
253 | data->npatterns++; | ||
254 | } | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, | ||
260 | const char *buf, const u32 *buf_int, | ||
261 | size_t count, bool hw_pattern) | ||
262 | { | ||
263 | struct pattern_trig_data *data = led_cdev->trigger_data; | ||
264 | int err = 0; | ||
265 | |||
266 | mutex_lock(&data->lock); | ||
267 | |||
268 | del_timer_sync(&data->timer); | ||
269 | |||
270 | if (data->is_hw_pattern) | ||
271 | led_cdev->pattern_clear(led_cdev); | ||
272 | |||
273 | data->is_hw_pattern = hw_pattern; | ||
274 | data->npatterns = 0; | ||
275 | |||
276 | if (buf) | ||
277 | err = pattern_trig_store_patterns_string(data, buf, count); | ||
278 | else | ||
279 | err = pattern_trig_store_patterns_int(data, buf_int, count); | ||
280 | if (err) | ||
281 | goto out; | ||
282 | |||
255 | err = pattern_trig_start_pattern(led_cdev); | 283 | err = pattern_trig_start_pattern(led_cdev); |
256 | if (err) | 284 | if (err) |
257 | data->npatterns = 0; | 285 | data->npatterns = 0; |
@@ -275,7 +303,7 @@ static ssize_t pattern_store(struct device *dev, struct device_attribute *attr, | |||
275 | { | 303 | { |
276 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | 304 | struct led_classdev *led_cdev = dev_get_drvdata(dev); |
277 | 305 | ||
278 | return pattern_trig_store_patterns(led_cdev, buf, count, false); | 306 | return pattern_trig_store_patterns(led_cdev, buf, NULL, count, false); |
279 | } | 307 | } |
280 | 308 | ||
281 | static DEVICE_ATTR_RW(pattern); | 309 | static DEVICE_ATTR_RW(pattern); |
@@ -295,7 +323,7 @@ static ssize_t hw_pattern_store(struct device *dev, | |||
295 | { | 323 | { |
296 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | 324 | struct led_classdev *led_cdev = dev_get_drvdata(dev); |
297 | 325 | ||
298 | return pattern_trig_store_patterns(led_cdev, buf, count, true); | 326 | return pattern_trig_store_patterns(led_cdev, buf, NULL, count, true); |
299 | } | 327 | } |
300 | 328 | ||
301 | static DEVICE_ATTR_RW(hw_pattern); | 329 | static DEVICE_ATTR_RW(hw_pattern); |
@@ -331,6 +359,30 @@ static const struct attribute_group *pattern_trig_groups[] = { | |||
331 | NULL, | 359 | NULL, |
332 | }; | 360 | }; |
333 | 361 | ||
362 | static void pattern_init(struct led_classdev *led_cdev) | ||
363 | { | ||
364 | unsigned int size = 0; | ||
365 | u32 *pattern; | ||
366 | int err; | ||
367 | |||
368 | pattern = led_get_default_pattern(led_cdev, &size); | ||
369 | if (!pattern) | ||
370 | return; | ||
371 | |||
372 | if (size % 2) { | ||
373 | dev_warn(led_cdev->dev, "Expected pattern of tuples\n"); | ||
374 | goto out; | ||
375 | } | ||
376 | |||
377 | err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, false); | ||
378 | if (err < 0) | ||
379 | dev_warn(led_cdev->dev, | ||
380 | "Pattern initialization failed with error %d\n", err); | ||
381 | |||
382 | out: | ||
383 | kfree(pattern); | ||
384 | } | ||
385 | |||
334 | static int pattern_trig_activate(struct led_classdev *led_cdev) | 386 | static int pattern_trig_activate(struct led_classdev *led_cdev) |
335 | { | 387 | { |
336 | struct pattern_trig_data *data; | 388 | struct pattern_trig_data *data; |
@@ -354,6 +406,15 @@ static int pattern_trig_activate(struct led_classdev *led_cdev) | |||
354 | timer_setup(&data->timer, pattern_trig_timer_function, 0); | 406 | timer_setup(&data->timer, pattern_trig_timer_function, 0); |
355 | led_cdev->activated = true; | 407 | led_cdev->activated = true; |
356 | 408 | ||
409 | if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { | ||
410 | pattern_init(led_cdev); | ||
411 | /* | ||
412 | * Mark as initialized even on pattern_init() error because | ||
413 | * any consecutive call to it would produce the same error. | ||
414 | */ | ||
415 | led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; | ||
416 | } | ||
417 | |||
357 | return 0; | 418 | return 0; |
358 | } | 419 | } |
359 | 420 | ||