xref: /openbmc/linux/sound/core/control_led.c (revision 5b1ed7df01335ecf686edf490948054078d5766d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  LED state routines for driver control interface
4  *  Copyright (c) 2021 by Jaroslav Kysela <perex@perex.cz>
5  */
6 
7 #include <linux/slab.h>
8 #include <linux/module.h>
9 #include <linux/leds.h>
10 #include <sound/core.h>
11 #include <sound/control.h>
12 
13 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
14 MODULE_DESCRIPTION("ALSA control interface to LED trigger code.");
15 MODULE_LICENSE("GPL");
16 
17 #define MAX_LED (((SNDRV_CTL_ELEM_ACCESS_MIC_LED - SNDRV_CTL_ELEM_ACCESS_SPK_LED) \
18 			>> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) + 1)
19 
20 enum snd_ctl_led_mode {
21 	 MODE_FOLLOW_MUTE = 0,
22 	 MODE_FOLLOW_ROUTE,
23 	 MODE_OFF,
24 	 MODE_ON,
25 };
26 
27 struct snd_ctl_led_card {
28 	struct device dev;
29 	int number;
30 	struct snd_ctl_led *led;
31 };
32 
33 struct snd_ctl_led {
34 	struct device dev;
35 	struct list_head controls;
36 	const char *name;
37 	unsigned int group;
38 	enum led_audio trigger_type;
39 	enum snd_ctl_led_mode mode;
40 	struct snd_ctl_led_card *cards[SNDRV_CARDS];
41 };
42 
43 struct snd_ctl_led_ctl {
44 	struct list_head list;
45 	struct snd_card *card;
46 	unsigned int access;
47 	struct snd_kcontrol *kctl;
48 	unsigned int index_offset;
49 };
50 
51 static DEFINE_MUTEX(snd_ctl_led_mutex);
52 static bool snd_ctl_led_card_valid[SNDRV_CARDS];
53 static struct snd_ctl_led snd_ctl_leds[MAX_LED] = {
54 	{
55 		.name = "speaker",
56 		.group = (SNDRV_CTL_ELEM_ACCESS_SPK_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1,
57 		.trigger_type = LED_AUDIO_MUTE,
58 		.mode = MODE_FOLLOW_MUTE,
59 	},
60 	{
61 		.name = "mic",
62 		.group = (SNDRV_CTL_ELEM_ACCESS_MIC_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1,
63 		.trigger_type = LED_AUDIO_MICMUTE,
64 		.mode = MODE_FOLLOW_MUTE,
65 	},
66 };
67 
68 static void snd_ctl_led_sysfs_add(struct snd_card *card);
69 static void snd_ctl_led_sysfs_remove(struct snd_card *card);
70 
71 #define UPDATE_ROUTE(route, cb) \
72 	do { \
73 		int route2 = (cb); \
74 		if (route2 >= 0) \
75 			route = route < 0 ? route2 : (route | route2); \
76 	} while (0)
77 
78 static inline unsigned int access_to_group(unsigned int access)
79 {
80 	return ((access & SNDRV_CTL_ELEM_ACCESS_LED_MASK) >>
81 				SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1;
82 }
83 
84 static inline unsigned int group_to_access(unsigned int group)
85 {
86 	return (group + 1) << SNDRV_CTL_ELEM_ACCESS_LED_SHIFT;
87 }
88 
89 static struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access)
90 {
91 	unsigned int group = access_to_group(access);
92 	if (group >= MAX_LED)
93 		return NULL;
94 	return &snd_ctl_leds[group];
95 }
96 
97 static int snd_ctl_led_get(struct snd_ctl_led_ctl *lctl)
98 {
99 	struct snd_kcontrol *kctl = lctl->kctl;
100 	struct snd_ctl_elem_info info;
101 	struct snd_ctl_elem_value value;
102 	unsigned int i;
103 	int result;
104 
105 	memset(&info, 0, sizeof(info));
106 	info.id = kctl->id;
107 	info.id.index += lctl->index_offset;
108 	info.id.numid += lctl->index_offset;
109 	result = kctl->info(kctl, &info);
110 	if (result < 0)
111 		return -1;
112 	memset(&value, 0, sizeof(value));
113 	value.id = info.id;
114 	result = kctl->get(kctl, &value);
115 	if (result < 0)
116 		return -1;
117 	if (info.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
118 	    info.type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
119 		for (i = 0; i < info.count; i++)
120 			if (value.value.integer.value[i] != info.value.integer.min)
121 				return 1;
122 	} else if (info.type == SNDRV_CTL_ELEM_TYPE_INTEGER64) {
123 		for (i = 0; i < info.count; i++)
124 			if (value.value.integer64.value[i] != info.value.integer64.min)
125 				return 1;
126 	}
127 	return 0;
128 }
129 
130 static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
131 				  struct snd_kcontrol *kctl, unsigned int ioff)
132 {
133 	struct snd_ctl_led *led;
134 	struct snd_ctl_led_ctl *lctl;
135 	int route;
136 	bool found;
137 
138 	led = snd_ctl_led_get_by_access(access);
139 	if (!led)
140 		return;
141 	route = -1;
142 	found = false;
143 	mutex_lock(&snd_ctl_led_mutex);
144 	/* the card may not be registered (active) at this point */
145 	if (card && !snd_ctl_led_card_valid[card->number]) {
146 		mutex_unlock(&snd_ctl_led_mutex);
147 		return;
148 	}
149 	list_for_each_entry(lctl, &led->controls, list) {
150 		if (lctl->kctl == kctl && lctl->index_offset == ioff)
151 			found = true;
152 		UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
153 	}
154 	if (!found && kctl && card) {
155 		lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
156 		if (lctl) {
157 			lctl->card = card;
158 			lctl->access = access;
159 			lctl->kctl = kctl;
160 			lctl->index_offset = ioff;
161 			list_add(&lctl->list, &led->controls);
162 			UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
163 		}
164 	}
165 	mutex_unlock(&snd_ctl_led_mutex);
166 	switch (led->mode) {
167 	case MODE_OFF:		route = 1; break;
168 	case MODE_ON:		route = 0; break;
169 	case MODE_FOLLOW_ROUTE:	if (route >= 0) route ^= 1; break;
170 	case MODE_FOLLOW_MUTE:	/* noop */ break;
171 	}
172 	if (route >= 0)
173 		ledtrig_audio_set(led->trigger_type, route ? LED_OFF : LED_ON);
174 }
175 
176 static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff)
177 {
178 	struct list_head *controls;
179 	struct snd_ctl_led_ctl *lctl;
180 	unsigned int group;
181 
182 	for (group = 0; group < MAX_LED; group++) {
183 		controls = &snd_ctl_leds[group].controls;
184 		list_for_each_entry(lctl, controls, list)
185 			if (lctl->kctl == kctl && lctl->index_offset == ioff)
186 				return lctl;
187 	}
188 	return NULL;
189 }
190 
191 static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int ioff,
192 				       unsigned int access)
193 {
194 	struct snd_ctl_led_ctl *lctl;
195 	unsigned int ret = 0;
196 
197 	mutex_lock(&snd_ctl_led_mutex);
198 	lctl = snd_ctl_led_find(kctl, ioff);
199 	if (lctl && (access == 0 || access != lctl->access)) {
200 		ret = lctl->access;
201 		list_del(&lctl->list);
202 		kfree(lctl);
203 	}
204 	mutex_unlock(&snd_ctl_led_mutex);
205 	return ret;
206 }
207 
208 static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask,
209 			       struct snd_kcontrol *kctl, unsigned int ioff)
210 {
211 	struct snd_kcontrol_volatile *vd;
212 	unsigned int access, access2;
213 
214 	if (mask == SNDRV_CTL_EVENT_MASK_REMOVE) {
215 		access = snd_ctl_led_remove(kctl, ioff, 0);
216 		if (access)
217 			snd_ctl_led_set_state(card, access, NULL, 0);
218 	} else if (mask & SNDRV_CTL_EVENT_MASK_INFO) {
219 		vd = &kctl->vd[ioff];
220 		access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
221 		access2 = snd_ctl_led_remove(kctl, ioff, access);
222 		if (access2)
223 			snd_ctl_led_set_state(card, access2, NULL, 0);
224 		if (access)
225 			snd_ctl_led_set_state(card, access, kctl, ioff);
226 	} else if ((mask & (SNDRV_CTL_EVENT_MASK_ADD |
227 			    SNDRV_CTL_EVENT_MASK_VALUE)) != 0) {
228 		vd = &kctl->vd[ioff];
229 		access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
230 		if (access)
231 			snd_ctl_led_set_state(card, access, kctl, ioff);
232 	}
233 }
234 
235 static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
236 			      unsigned int group, bool set)
237 {
238 	struct snd_card *card;
239 	struct snd_kcontrol *kctl;
240 	struct snd_kcontrol_volatile *vd;
241 	unsigned int ioff, access, new_access;
242 	int err = 0;
243 
244 	card = snd_card_ref(card_number);
245 	if (card) {
246 		down_write(&card->controls_rwsem);
247 		kctl = snd_ctl_find_id(card, id);
248 		if (kctl) {
249 			ioff = snd_ctl_get_ioff(kctl, id);
250 			vd = &kctl->vd[ioff];
251 			access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
252 			if (access != 0 && access != group_to_access(group)) {
253 				err = -EXDEV;
254 				goto unlock;
255 			}
256 			new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
257 			if (set)
258 				new_access |= group_to_access(group);
259 			if (new_access != vd->access) {
260 				vd->access = new_access;
261 				snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
262 			}
263 		} else {
264 			err = -ENOENT;
265 		}
266 unlock:
267 		up_write(&card->controls_rwsem);
268 		snd_card_unref(card);
269 	} else {
270 		err = -ENXIO;
271 	}
272 	return err;
273 }
274 
275 static void snd_ctl_led_refresh(void)
276 {
277 	unsigned int group;
278 
279 	for (group = 0; group < MAX_LED; group++)
280 		snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
281 }
282 
283 static void snd_ctl_led_ctl_destroy(struct snd_ctl_led_ctl *lctl)
284 {
285 	list_del(&lctl->list);
286 	kfree(lctl);
287 }
288 
289 static void snd_ctl_led_clean(struct snd_card *card)
290 {
291 	unsigned int group;
292 	struct snd_ctl_led *led;
293 	struct snd_ctl_led_ctl *lctl;
294 
295 	for (group = 0; group < MAX_LED; group++) {
296 		led = &snd_ctl_leds[group];
297 repeat:
298 		list_for_each_entry(lctl, &led->controls, list)
299 			if (!card || lctl->card == card) {
300 				snd_ctl_led_ctl_destroy(lctl);
301 				goto repeat;
302 			}
303 	}
304 }
305 
306 static int snd_ctl_led_reset(int card_number, unsigned int group)
307 {
308 	struct snd_card *card;
309 	struct snd_ctl_led *led;
310 	struct snd_ctl_led_ctl *lctl;
311 	struct snd_kcontrol_volatile *vd;
312 	bool change = false;
313 
314 	card = snd_card_ref(card_number);
315 	if (!card)
316 		return -ENXIO;
317 
318 	mutex_lock(&snd_ctl_led_mutex);
319 	if (!snd_ctl_led_card_valid[card_number]) {
320 		mutex_unlock(&snd_ctl_led_mutex);
321 		snd_card_unref(card);
322 		return -ENXIO;
323 	}
324 	led = &snd_ctl_leds[group];
325 repeat:
326 	list_for_each_entry(lctl, &led->controls, list)
327 		if (lctl->card == card) {
328 			vd = &lctl->kctl->vd[lctl->index_offset];
329 			vd->access &= ~group_to_access(group);
330 			snd_ctl_led_ctl_destroy(lctl);
331 			change = true;
332 			goto repeat;
333 		}
334 	mutex_unlock(&snd_ctl_led_mutex);
335 	if (change)
336 		snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
337 	snd_card_unref(card);
338 	return 0;
339 }
340 
341 static void snd_ctl_led_register(struct snd_card *card)
342 {
343 	struct snd_kcontrol *kctl;
344 	unsigned int ioff;
345 
346 	if (snd_BUG_ON(card->number < 0 ||
347 		       card->number >= ARRAY_SIZE(snd_ctl_led_card_valid)))
348 		return;
349 	mutex_lock(&snd_ctl_led_mutex);
350 	snd_ctl_led_card_valid[card->number] = true;
351 	mutex_unlock(&snd_ctl_led_mutex);
352 	/* the register callback is already called with held card->controls_rwsem */
353 	list_for_each_entry(kctl, &card->controls, list)
354 		for (ioff = 0; ioff < kctl->count; ioff++)
355 			snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff);
356 	snd_ctl_led_refresh();
357 	snd_ctl_led_sysfs_add(card);
358 }
359 
360 static void snd_ctl_led_disconnect(struct snd_card *card)
361 {
362 	snd_ctl_led_sysfs_remove(card);
363 	mutex_lock(&snd_ctl_led_mutex);
364 	snd_ctl_led_card_valid[card->number] = false;
365 	snd_ctl_led_clean(card);
366 	mutex_unlock(&snd_ctl_led_mutex);
367 	snd_ctl_led_refresh();
368 }
369 
370 /*
371  * sysfs
372  */
373 
374 static ssize_t show_mode(struct device *dev,
375 			 struct device_attribute *attr, char *buf)
376 {
377 	struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
378 	const char *str;
379 
380 	switch (led->mode) {
381 	case MODE_FOLLOW_MUTE:	str = "follow-mute"; break;
382 	case MODE_FOLLOW_ROUTE:	str = "follow-route"; break;
383 	case MODE_ON:		str = "on"; break;
384 	case MODE_OFF:		str = "off"; break;
385 	}
386 	return sprintf(buf, "%s\n", str);
387 }
388 
389 static ssize_t store_mode(struct device *dev, struct device_attribute *attr,
390 			  const char *buf, size_t count)
391 {
392 	struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
393 	char _buf[16];
394 	size_t l = min(count, sizeof(_buf) - 1) + 1;
395 	enum snd_ctl_led_mode mode;
396 
397 	memcpy(_buf, buf, l);
398 	_buf[l] = '\0';
399 	if (strstr(_buf, "mute"))
400 		mode = MODE_FOLLOW_MUTE;
401 	else if (strstr(_buf, "route"))
402 		mode = MODE_FOLLOW_ROUTE;
403 	else if (strncmp(_buf, "off", 3) == 0 || strncmp(_buf, "0", 1) == 0)
404 		mode = MODE_OFF;
405 	else if (strncmp(_buf, "on", 2) == 0 || strncmp(_buf, "1", 1) == 0)
406 		mode = MODE_ON;
407 	else
408 		return count;
409 
410 	mutex_lock(&snd_ctl_led_mutex);
411 	led->mode = mode;
412 	mutex_unlock(&snd_ctl_led_mutex);
413 
414 	snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0);
415 	return count;
416 }
417 
418 static ssize_t show_brightness(struct device *dev,
419 			       struct device_attribute *attr, char *buf)
420 {
421 	struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
422 
423 	return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type));
424 }
425 
426 static DEVICE_ATTR(mode, 0644, show_mode, store_mode);
427 static DEVICE_ATTR(brightness, 0444, show_brightness, NULL);
428 
429 static struct attribute *snd_ctl_led_dev_attrs[] = {
430 	&dev_attr_mode.attr,
431 	&dev_attr_brightness.attr,
432 	NULL,
433 };
434 
435 static const struct attribute_group snd_ctl_led_dev_attr_group = {
436 	.attrs = snd_ctl_led_dev_attrs,
437 };
438 
439 static const struct attribute_group *snd_ctl_led_dev_attr_groups[] = {
440 	&snd_ctl_led_dev_attr_group,
441 	NULL,
442 };
443 
444 static char *find_eos(char *s)
445 {
446 	while (*s && *s != ',')
447 		s++;
448 	if (*s)
449 		s++;
450 	return s;
451 }
452 
453 static char *parse_uint(char *s, unsigned int *val)
454 {
455 	unsigned long long res;
456 	if (kstrtoull(s, 10, &res))
457 		res = 0;
458 	*val = res;
459 	return find_eos(s);
460 }
461 
462 static char *parse_string(char *s, char *val, size_t val_size)
463 {
464 	if (*s == '"' || *s == '\'') {
465 		char c = *s;
466 		s++;
467 		while (*s && *s != c) {
468 			if (val_size > 1) {
469 				*val++ = *s;
470 				val_size--;
471 			}
472 			s++;
473 		}
474 	} else {
475 		while (*s && *s != ',') {
476 			if (val_size > 1) {
477 				*val++ = *s;
478 				val_size--;
479 			}
480 			s++;
481 		}
482 	}
483 	*val = '\0';
484 	if (*s)
485 		s++;
486 	return s;
487 }
488 
489 static char *parse_iface(char *s, unsigned int *val)
490 {
491 	if (!strncasecmp(s, "card", 4))
492 		*val = SNDRV_CTL_ELEM_IFACE_CARD;
493 	else if (!strncasecmp(s, "mixer", 5))
494 		*val = SNDRV_CTL_ELEM_IFACE_MIXER;
495 	return find_eos(s);
496 }
497 
498 /*
499  * These types of input strings are accepted:
500  *
501  *   unsigned integer - numid (equivaled to numid=UINT)
502  *   string - basic mixer name (equivalent to iface=MIXER,name=STR)
503  *   numid=UINT
504  *   [iface=MIXER,][device=UINT,][subdevice=UINT,]name=STR[,index=UINT]
505  */
506 static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, size_t count,
507 			  bool attach)
508 {
509 	char buf2[256], *s;
510 	size_t len = max(sizeof(s) - 1, count);
511 	struct snd_ctl_elem_id id;
512 	int err;
513 
514 	strncpy(buf2, buf, len);
515 	buf2[len] = '\0';
516 	memset(&id, 0, sizeof(id));
517 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
518 	s = buf2;
519 	while (*s) {
520 		if (!strncasecmp(s, "numid=", 6)) {
521 			s = parse_uint(s + 6, &id.numid);
522 		} else if (!strncasecmp(s, "iface=", 6)) {
523 			s = parse_iface(s + 6, &id.iface);
524 		} else if (!strncasecmp(s, "device=", 7)) {
525 			s = parse_uint(s + 7, &id.device);
526 		} else if (!strncasecmp(s, "subdevice=", 10)) {
527 			s = parse_uint(s + 10, &id.subdevice);
528 		} else if (!strncasecmp(s, "name=", 5)) {
529 			s = parse_string(s + 5, id.name, sizeof(id.name));
530 		} else if (!strncasecmp(s, "index=", 6)) {
531 			s = parse_uint(s + 6, &id.index);
532 		} else if (s == buf2) {
533 			while (*s) {
534 				if (*s < '0' || *s > '9')
535 					break;
536 				s++;
537 			}
538 			if (*s == '\0')
539 				parse_uint(buf2, &id.numid);
540 			else {
541 				for (; *s >= ' '; s++);
542 				*s = '\0';
543 				strlcpy(id.name, buf2, sizeof(id.name));
544 			}
545 			break;
546 		}
547 		if (*s == ',')
548 			s++;
549 	}
550 
551 	err = snd_ctl_led_set_id(led_card->number, &id, led_card->led->group, attach);
552 	if (err < 0)
553 		return err;
554 
555 	return count;
556 }
557 
558 static ssize_t parse_attach(struct device *dev, struct device_attribute *attr,
559 			    const char *buf, size_t count)
560 {
561 	struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
562 	return set_led_id(led_card, buf, count, true);
563 }
564 
565 static ssize_t parse_detach(struct device *dev, struct device_attribute *attr,
566 			    const char *buf, size_t count)
567 {
568 	struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
569 	return set_led_id(led_card, buf, count, false);
570 }
571 
572 static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr,
573 			 const char *buf, size_t count)
574 {
575 	struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
576 	int err;
577 
578 	if (count > 0 && buf[0] == '1') {
579 		err = snd_ctl_led_reset(led_card->number, led_card->led->group);
580 		if (err < 0)
581 			return err;
582 	}
583 	return count;
584 }
585 
586 static ssize_t ctl_list(struct device *dev,
587 			struct device_attribute *attr, char *buf)
588 {
589 	struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
590 	struct snd_card *card;
591 	struct snd_ctl_led_ctl *lctl;
592 	char *buf2 = buf;
593 	size_t l;
594 
595 	card = snd_card_ref(led_card->number);
596 	if (!card)
597 		return -ENXIO;
598 	down_read(&card->controls_rwsem);
599 	mutex_lock(&snd_ctl_led_mutex);
600 	if (snd_ctl_led_card_valid[led_card->number]) {
601 		list_for_each_entry(lctl, &led_card->led->controls, list)
602 			if (lctl->card == card) {
603 				if (buf2 - buf > PAGE_SIZE - 16)
604 					break;
605 				if (buf2 != buf)
606 					*buf2++ = ' ';
607 				l = scnprintf(buf2, 15, "%u",
608 						lctl->kctl->id.numid +
609 							lctl->index_offset);
610 				buf2[l] = '\0';
611 				buf2 += l + 1;
612 			}
613 	}
614 	mutex_unlock(&snd_ctl_led_mutex);
615 	up_read(&card->controls_rwsem);
616 	snd_card_unref(card);
617 	return buf2 - buf;
618 }
619 
620 static DEVICE_ATTR(attach, 0200, NULL, parse_attach);
621 static DEVICE_ATTR(detach, 0200, NULL, parse_detach);
622 static DEVICE_ATTR(reset, 0200, NULL, ctl_reset);
623 static DEVICE_ATTR(list, 0444, ctl_list, NULL);
624 
625 static struct attribute *snd_ctl_led_card_attrs[] = {
626 	&dev_attr_attach.attr,
627 	&dev_attr_detach.attr,
628 	&dev_attr_reset.attr,
629 	&dev_attr_list.attr,
630 	NULL,
631 };
632 
633 static const struct attribute_group snd_ctl_led_card_attr_group = {
634 	.attrs = snd_ctl_led_card_attrs,
635 };
636 
637 static const struct attribute_group *snd_ctl_led_card_attr_groups[] = {
638 	&snd_ctl_led_card_attr_group,
639 	NULL,
640 };
641 
642 static struct device snd_ctl_led_dev;
643 
644 static void snd_ctl_led_sysfs_add(struct snd_card *card)
645 {
646 	unsigned int group;
647 	struct snd_ctl_led_card *led_card;
648 	struct snd_ctl_led *led;
649 	char link_name[32];
650 
651 	for (group = 0; group < MAX_LED; group++) {
652 		led = &snd_ctl_leds[group];
653 		led_card = kzalloc(sizeof(*led_card), GFP_KERNEL);
654 		if (!led_card)
655 			goto cerr2;
656 		led_card->number = card->number;
657 		led_card->led = led;
658 		device_initialize(&led_card->dev);
659 		if (dev_set_name(&led_card->dev, "card%d", card->number) < 0)
660 			goto cerr;
661 		led_card->dev.parent = &led->dev;
662 		led_card->dev.groups = snd_ctl_led_card_attr_groups;
663 		if (device_add(&led_card->dev))
664 			goto cerr;
665 		led->cards[card->number] = led_card;
666 		snprintf(link_name, sizeof(link_name), "led-%s", led->name);
667 		WARN(sysfs_create_link(&card->ctl_dev.kobj, &led_card->dev.kobj, link_name),
668 			"can't create symlink to controlC%i device\n", card->number);
669 		WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"),
670 			"can't create symlink to card%i\n", card->number);
671 
672 		continue;
673 cerr:
674 		put_device(&led_card->dev);
675 cerr2:
676 		printk(KERN_ERR "snd_ctl_led: unable to add card%d", card->number);
677 		kfree(led_card);
678 	}
679 }
680 
681 static void snd_ctl_led_sysfs_remove(struct snd_card *card)
682 {
683 	unsigned int group;
684 	struct snd_ctl_led_card *led_card;
685 	struct snd_ctl_led *led;
686 	char link_name[32];
687 
688 	for (group = 0; group < MAX_LED; group++) {
689 		led = &snd_ctl_leds[group];
690 		led_card = led->cards[card->number];
691 		if (!led_card)
692 			continue;
693 		snprintf(link_name, sizeof(link_name), "led-%s", led->name);
694 		sysfs_remove_link(&card->ctl_dev.kobj, link_name);
695 		sysfs_remove_link(&led_card->dev.kobj, "card");
696 		device_del(&led_card->dev);
697 		kfree(led_card);
698 		led->cards[card->number] = NULL;
699 	}
700 }
701 
702 /*
703  * Control layer registration
704  */
705 static struct snd_ctl_layer_ops snd_ctl_led_lops = {
706 	.module_name = SND_CTL_LAYER_MODULE_LED,
707 	.lregister = snd_ctl_led_register,
708 	.ldisconnect = snd_ctl_led_disconnect,
709 	.lnotify = snd_ctl_led_notify,
710 };
711 
712 static int __init snd_ctl_led_init(void)
713 {
714 	struct snd_ctl_led *led;
715 	unsigned int group;
716 
717 	device_initialize(&snd_ctl_led_dev);
718 	snd_ctl_led_dev.class = sound_class;
719 	dev_set_name(&snd_ctl_led_dev, "ctl-led");
720 	if (device_add(&snd_ctl_led_dev)) {
721 		put_device(&snd_ctl_led_dev);
722 		return -ENOMEM;
723 	}
724 	for (group = 0; group < MAX_LED; group++) {
725 		led = &snd_ctl_leds[group];
726 		INIT_LIST_HEAD(&led->controls);
727 		device_initialize(&led->dev);
728 		led->dev.parent = &snd_ctl_led_dev;
729 		led->dev.groups = snd_ctl_led_dev_attr_groups;
730 		dev_set_name(&led->dev, led->name);
731 		if (device_add(&led->dev)) {
732 			put_device(&led->dev);
733 			for (; group > 0; group--) {
734 				led = &snd_ctl_leds[group];
735 				device_del(&led->dev);
736 			}
737 			device_del(&snd_ctl_led_dev);
738 			return -ENOMEM;
739 		}
740 	}
741 	snd_ctl_register_layer(&snd_ctl_led_lops);
742 	return 0;
743 }
744 
745 static void __exit snd_ctl_led_exit(void)
746 {
747 	struct snd_ctl_led *led;
748 	struct snd_card *card;
749 	unsigned int group, card_number;
750 
751 	snd_ctl_disconnect_layer(&snd_ctl_led_lops);
752 	for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
753 		if (!snd_ctl_led_card_valid[card_number])
754 			continue;
755 		card = snd_card_ref(card_number);
756 		if (card) {
757 			snd_ctl_led_sysfs_remove(card);
758 			snd_card_unref(card);
759 		}
760 	}
761 	for (group = 0; group < MAX_LED; group++) {
762 		led = &snd_ctl_leds[group];
763 		device_del(&led->dev);
764 	}
765 	device_del(&snd_ctl_led_dev);
766 	snd_ctl_led_clean(NULL);
767 }
768 
769 module_init(snd_ctl_led_init)
770 module_exit(snd_ctl_led_exit)
771