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