Re: [PATCH] leds: core: Support blocking HW blink operations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Nits:

> ALl of this will be handled transparently from the
> led_blink_set() call so all current users can keep
> using that.

"All". Plus, your lines are rather short.

> 
> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
> ---
>  drivers/leds/led-core.c | 49 ++++++++++++++++++++++++++++++++++++++---
>  include/linux/leds.h    |  9 ++++++++
>  2 files changed, 55 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
> index ede4fa0ac2cc..94870a3d59af 100644
> --- a/drivers/leds/led-core.c
> +++ b/drivers/leds/led-core.c
> @@ -108,6 +108,20 @@ static void set_brightness_delayed(struct work_struct *ws)
>  		container_of(ws, struct led_classdev, set_brightness_work);
>  	int ret = 0;
>  
> +	if (test_and_clear_bit(LED_BLINK_HW_SET, &led_cdev->work_flags)) {
> +		if (led_cdev->blink_set)
> +			ret = led_cdev->blink_set(led_cdev,
> +						  &led_cdev->blink_delay_on,
> +						   &led_cdev->blink_delay_off);

How can we get here?

> +		else if (led_cdev->blink_set_blocking)
> +			ret = led_cdev->blink_set_blocking(led_cdev,
> +						&led_cdev->blink_delay_on,
> +						&led_cdev->blink_delay_off);
> +		if (ret)
> +			dev_err(led_cdev->dev,
> +				"setting hardware blink failed (%d)\n", ret);
> +	}

This is a bit sad, as it disallows returning errors back to
userspace. And I'm pretty sure little hardware can support all the
possible delays....

>  	mod_timer(&led_cdev->blink_timer, jiffies + 1);
>  }
>  
> +static int led_set_hardware_blink_nosleep(struct led_classdev *led_cdev,
> +					   unsigned long *delay_on,
> +					   unsigned long *delay_off)
> +{
> +	/* We have a non-blocking call, use it */
> +	if (led_cdev->blink_set)
> +		return led_cdev->blink_set(led_cdev, delay_on, delay_off);
> +
> +	/* Tell the worker to set up the blinking hardware */
> +	if (delay_on)
> +		led_cdev->blink_delay_on = *delay_on;
> +	else
> +		led_cdev->blink_delay_on = 0;
> +	if (delay_off)
> +		led_cdev->blink_delay_off = *delay_off;
> +	else
> +		led_cdev->blink_delay_off = 0;
> +	set_bit(LED_BLINK_HW_SET, &led_cdev->work_flags);
> +	schedule_work(&led_cdev->set_brightness_work);
> +
> +	return 0;
> +}
>  
>  static void led_blink_setup(struct led_classdev *led_cdev,
>  		     unsigned long *delay_on,
>  		     unsigned long *delay_off)
>  {
> +	/*
> +	 * If not oneshot, and we have hardware support for blinking,
> +	 * relay the request to the driver.
> +	 */
>  	if (!test_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags) &&
> -	    led_cdev->blink_set &&
> -	    !led_cdev->blink_set(led_cdev, delay_on, delay_off))
> -		return;
> +	    (led_cdev->blink_set || led_cdev->blink_set_blocking)) {
> +		/* If this fails we fall back to software blink */
> +		if (!led_set_hardware_blink_nosleep(led_cdev,
> +						    delay_on, delay_off))
> +			return;
> +	}
>  

So, when can this actually be called from atomic context?

(And deferring to work queue to set hardware blinking for one shot
... does not make sense.)

led_trigger_blink_setup uses read_lock() -- unsafe from atomic AFAICT.

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux