drivers/leds/led-triggers.c

Source file repositories/reference/linux-study-clean/drivers/leds/led-triggers.c

File Facts

System
Linux kernel
Corpus path
drivers/leds/led-triggers.c
Extension
.c
Size
12606 bytes
Lines
515
Domain
Driver Families
Bucket
drivers/leds
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) {
			down_write(&led_cdev->trigger_lock);
			led_trigger_set(led_cdev, trig);
			up_write(&led_cdev->trigger_lock);

			up_read(&triggers_list_lock);
			goto unlock;
		}
	}
	/* we come here only if buf matches no trigger */
	ret = -EINVAL;
	up_read(&triggers_list_lock);

unlock:
	mutex_unlock(&led_cdev->led_access);
	return ret;
}
EXPORT_SYMBOL_GPL(led_trigger_write);

__printf(3, 4)
static int led_trigger_snprintf(char *buf, ssize_t size, const char *fmt, ...)
{
	va_list args;
	int i;

	va_start(args, fmt);
	if (size <= 0)
		i = vsnprintf(NULL, 0, fmt, args);
	else
		i = vscnprintf(buf, size, fmt, args);
	va_end(args);

	return i;
}

static int led_trigger_format(char *buf, size_t size,
			      struct led_classdev *led_cdev)
{
	struct led_trigger *trig;
	int len = led_trigger_snprintf(buf, size, "%s",
				       led_cdev->trigger ? "none" : "[none]");

	if (led_cdev->default_trigger)
		len += led_trigger_snprintf(buf + len, size - len, " default");

	list_for_each_entry(trig, &trigger_list, next_trig) {
		bool hit;

		if (!trigger_relevant(led_cdev, trig))
			continue;

		hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name);

		len += led_trigger_snprintf(buf + len, size - len,
					    " %s%s%s", hit ? "[" : "",
					    trig->name, hit ? "]" : "");
	}

	len += led_trigger_snprintf(buf + len, size - len, "\n");

	return len;
}

/*
 * It was stupid to create 10000 cpu triggers, but we are stuck with it now.
 * Don't make that mistake again. We work around it here by creating binary
 * attribute, which is not limited by length. This is _not_ good design, do not
 * copy it.
 */
ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
			const struct bin_attribute *attr, char *buf,
			loff_t pos, size_t count)
{
	struct device *dev = kobj_to_dev(kobj);
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	void *data;
	int len;

	down_read(&triggers_list_lock);
	down_read(&led_cdev->trigger_lock);

	len = led_trigger_format(NULL, 0, led_cdev);
	data = kvmalloc(len + 1, GFP_KERNEL);
	if (!data) {
		up_read(&led_cdev->trigger_lock);
		up_read(&triggers_list_lock);
		return -ENOMEM;
	}
	len = led_trigger_format(data, len + 1, led_cdev);

Annotation

Implementation Notes