if (test_and_clear_bit(LED_BLINK_ONESHOT_STOP,
&led_cdev->work_flags)) {
clear_bit(LED_BLINK_SW, &led_cdev->work_flags); return;
}
brightness = led_get_brightness(led_cdev); if (!brightness) { /* Time to switch the LED on. */ if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE,
&led_cdev->work_flags))
brightness = led_cdev->new_blink_brightness; else
brightness = led_cdev->blink_brightness;
delay = led_cdev->blink_delay_on;
} else { /* Store the current brightness value to be able * to restore it when the delay_off period is over.
*/
led_cdev->blink_brightness = brightness;
brightness = LED_OFF;
delay = led_cdev->blink_delay_off;
}
led_set_brightness_nosleep(led_cdev, brightness);
/* Return in next iteration if led is in one-shot mode and we are in * the final blink state so that the led is toggled each delay_on + * delay_off milliseconds in worst case.
*/ if (test_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags)) { if (test_bit(LED_BLINK_INVERT, &led_cdev->work_flags)) { if (brightness)
set_bit(LED_BLINK_ONESHOT_STOP,
&led_cdev->work_flags);
} else { if (!brightness)
set_bit(LED_BLINK_ONESHOT_STOP,
&led_cdev->work_flags);
}
}
staticvoid set_brightness_delayed_set_brightness(struct led_classdev *led_cdev, unsignedint value)
{ int ret;
ret = __led_set_brightness(led_cdev, value); if (ret == -ENOTSUPP) {
ret = __led_set_brightness_blocking(led_cdev, value); if (ret == -ENOTSUPP) /* No back-end support to set a fixed brightness value */ return;
}
/* LED HW might have been unplugged, therefore don't warn */ if (ret == -ENODEV && led_cdev->flags & LED_UNREGISTERING &&
led_cdev->flags & LED_HW_PLUGGABLE) return;
if (ret < 0)
dev_err(led_cdev->dev, "Setting an LED's brightness failed (%d)\n", ret);
}
if (test_and_clear_bit(LED_BLINK_DISABLE, &led_cdev->work_flags)) {
led_stop_software_blink(led_cdev);
set_bit(LED_SET_BRIGHTNESS_OFF, &led_cdev->work_flags);
}
/* * Triggers may call led_set_brightness(LED_OFF), * led_set_brightness(LED_FULL) in quick succession to disable blinking * and turn the LED on. Both actions may have been scheduled to run * before this work item runs once. To make sure this works properly * handle LED_SET_BRIGHTNESS_OFF first.
*/ if (test_and_clear_bit(LED_SET_BRIGHTNESS_OFF, &led_cdev->work_flags)) {
set_brightness_delayed_set_brightness(led_cdev, LED_OFF); /* * The consecutives led_set_brightness(LED_OFF), * led_set_brightness(LED_FULL) could have been executed out of * order (LED_FULL first), if the work_flags has been set * between LED_SET_BRIGHTNESS_OFF and LED_SET_BRIGHTNESS of this * work. To avoid ending with the LED turned off, turn the LED * on again.
*/ if (led_cdev->delayed_set_value != LED_OFF)
set_bit(LED_SET_BRIGHTNESS, &led_cdev->work_flags);
}
if (test_and_clear_bit(LED_SET_BRIGHTNESS, &led_cdev->work_flags))
set_brightness_delayed_set_brightness(led_cdev, led_cdev->delayed_set_value);
void led_set_brightness(struct led_classdev *led_cdev, unsignedint brightness)
{ /* * If software blink is active, delay brightness setting * until the next timer tick.
*/ if (test_bit(LED_BLINK_SW, &led_cdev->work_flags)) { /* * If we need to disable soft blinking delegate this to the * work queue task to avoid problems in case we are called * from hard irq context.
*/ if (!brightness) {
set_bit(LED_BLINK_DISABLE, &led_cdev->work_flags);
queue_work(led_cdev->wq, &led_cdev->set_brightness_work);
} else {
set_bit(LED_BLINK_BRIGHTNESS_CHANGE,
&led_cdev->work_flags);
led_cdev->new_blink_brightness = brightness;
} return;
}
void led_set_brightness_nopm(struct led_classdev *led_cdev, unsignedint value)
{ /* Use brightness_set op if available, it is guaranteed not to sleep */ if (!__led_set_brightness(led_cdev, value)) return;
/* * Brightness setting can sleep, delegate it to a work queue task. * value 0 / LED_OFF is special, since it also disables hw-blinking * (sw-blink disable is handled in led_set_brightness()). * To avoid a hw-blink-disable getting lost when a second brightness * change is done immediately afterwards (before the work runs), * it uses a separate work_flag.
*/
led_cdev->delayed_set_value = value; /* Ensure delayed_set_value is seen before work_flags modification */
smp_mb__before_atomic();
/* * This is a led-core function because just like led_set_brightness() * it is used in the kernel by e.g. triggers.
*/ void led_mc_set_brightness(struct led_classdev *led_cdev, unsignedint *intensity_value, unsignedint num_colors, unsignedint brightness)
{ struct led_classdev_mc *mcled_cdev; unsignedint i;
if (!(led_cdev->flags & LED_MULTI_COLOR)) {
dev_err_once(led_cdev->dev, "error not a multi-color LED\n"); return;
}
if (props.label) { /* * If init_data.devicename is NULL, then it indicates that * DT label should be used as-is for LED class device name. * Otherwise the label is prepended with devicename to compose * the final LED class device name.
*/ if (devicename) {
n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
devicename, props.label);
} else {
n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s", props.label);
}
} elseif (props.function || props.color_present) { char tmp_buf[LED_MAX_NAME_SIZE];
if (props.func_enum_present) {
n = snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s-%d",
props.color_present ? led_colors[props.color] : "",
props.function ?: "", props.func_enum);
} else {
n = snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s",
props.color_present ? led_colors[props.color] : "",
props.function ?: "");
} if (n >= LED_MAX_NAME_SIZE) return -E2BIG;
if (init_data->devname_mandatory) {
n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
devicename, tmp_buf);
} else {
n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s", tmp_buf);
}
} elseif (init_data->default_label) { if (!devicename) {
dev_err(dev, "Legacy LED naming requires devicename segment"); return -EINVAL;
}
n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
devicename, init_data->default_label);
} elseif (is_of_node(fwnode)) {
n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s",
to_of_node(fwnode)->name);
} else return -EINVAL;
if (n >= LED_MAX_NAME_SIZE) return -E2BIG;
return 0;
}
EXPORT_SYMBOL_GPL(led_compose_name);
constchar *led_get_color_name(u8 color_id)
{ if (color_id >= ARRAY_SIZE(led_colors)) return NULL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.