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 #define to_led_card_dev(_dev) \ 21 container_of(_dev, struct snd_ctl_led_card, dev) 22 23 enum snd_ctl_led_mode { 24 MODE_FOLLOW_MUTE = 0, 25 MODE_FOLLOW_ROUTE, 26 MODE_OFF, 27 MODE_ON, 28 }; 29 30 struct snd_ctl_led_card { 31 struct device dev; 32 int number; 33 struct snd_ctl_led *led; 34 }; 35 36 struct snd_ctl_led { 37 struct device dev; 38 struct list_head controls; 39 const char *name; 40 unsigned int group; 41 enum led_audio trigger_type; 42 enum snd_ctl_led_mode mode; 43 struct snd_ctl_led_card *cards[SNDRV_CARDS]; 44 }; 45 46 struct snd_ctl_led_ctl { 47 struct list_head list; 48 struct snd_card *card; 49 unsigned int access; 50 struct snd_kcontrol *kctl; 51 unsigned int index_offset; 52 }; 53 54 static DEFINE_MUTEX(snd_ctl_led_mutex); 55 static bool snd_ctl_led_card_valid[SNDRV_CARDS]; 56 static struct led_trigger *snd_ctl_ledtrig_audio[NUM_AUDIO_LEDS]; 57 static struct snd_ctl_led snd_ctl_leds[MAX_LED] = { 58 { 59 .name = "speaker", 60 .group = (SNDRV_CTL_ELEM_ACCESS_SPK_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1, 61 .trigger_type = LED_AUDIO_MUTE, 62 .mode = MODE_FOLLOW_MUTE, 63 }, 64 { 65 .name = "mic", 66 .group = (SNDRV_CTL_ELEM_ACCESS_MIC_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1, 67 .trigger_type = LED_AUDIO_MICMUTE, 68 .mode = MODE_FOLLOW_MUTE, 69 }, 70 }; 71 72 static void snd_ctl_led_sysfs_add(struct snd_card *card); 73 static void snd_ctl_led_sysfs_remove(struct snd_card *card); 74 75 #define UPDATE_ROUTE(route, cb) \ 76 do { \ 77 int route2 = (cb); \ 78 if (route2 >= 0) \ 79 route = route < 0 ? route2 : (route | route2); \ 80 } while (0) 81 82 static inline unsigned int access_to_group(unsigned int access) 83 { 84 return ((access & SNDRV_CTL_ELEM_ACCESS_LED_MASK) >> 85 SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1; 86 } 87 88 static inline unsigned int group_to_access(unsigned int group) 89 { 90 return (group + 1) << SNDRV_CTL_ELEM_ACCESS_LED_SHIFT; 91 } 92 93 static struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access) 94 { 95 unsigned int group = access_to_group(access); 96 if (group >= MAX_LED) 97 return NULL; 98 return &snd_ctl_leds[group]; 99 } 100 101 /* 102 * A note for callers: 103 * The two static variables info and value are protected using snd_ctl_led_mutex. 104 */ 105 static int snd_ctl_led_get(struct snd_ctl_led_ctl *lctl) 106 { 107 static struct snd_ctl_elem_info info; 108 static struct snd_ctl_elem_value value; 109 struct snd_kcontrol *kctl = lctl->kctl; 110 unsigned int i; 111 int result; 112 113 memset(&info, 0, sizeof(info)); 114 info.id = kctl->id; 115 info.id.index += lctl->index_offset; 116 info.id.numid += lctl->index_offset; 117 result = kctl->info(kctl, &info); 118 if (result < 0) 119 return -1; 120 memset(&value, 0, sizeof(value)); 121 value.id = info.id; 122 result = kctl->get(kctl, &value); 123 if (result < 0) 124 return -1; 125 if (info.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || 126 info.type == SNDRV_CTL_ELEM_TYPE_INTEGER) { 127 for (i = 0; i < info.count; i++) 128 if (value.value.integer.value[i] != info.value.integer.min) 129 return 1; 130 } else if (info.type == SNDRV_CTL_ELEM_TYPE_INTEGER64) { 131 for (i = 0; i < info.count; i++) 132 if (value.value.integer64.value[i] != info.value.integer64.min) 133 return 1; 134 } 135 return 0; 136 } 137 138 static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access, 139 struct snd_kcontrol *kctl, unsigned int ioff) 140 { 141 struct snd_ctl_led *led; 142 struct snd_ctl_led_ctl *lctl; 143 int route; 144 bool found; 145 146 led = snd_ctl_led_get_by_access(access); 147 if (!led) 148 return; 149 route = -1; 150 found = false; 151 scoped_guard(mutex, &snd_ctl_led_mutex) { 152 /* the card may not be registered (active) at this point */ 153 if (card && !snd_ctl_led_card_valid[card->number]) 154 return; 155 list_for_each_entry(lctl, &led->controls, list) { 156 if (lctl->kctl == kctl && lctl->index_offset == ioff) 157 found = true; 158 UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); 159 } 160 if (!found && kctl && card) { 161 lctl = kzalloc(sizeof(*lctl), GFP_KERNEL); 162 if (lctl) { 163 lctl->card = card; 164 lctl->access = access; 165 lctl->kctl = kctl; 166 lctl->index_offset = ioff; 167 list_add(&lctl->list, &led->controls); 168 UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); 169 } 170 } 171 } 172 switch (led->mode) { 173 case MODE_OFF: route = 1; break; 174 case MODE_ON: route = 0; break; 175 case MODE_FOLLOW_ROUTE: if (route >= 0) route ^= 1; break; 176 case MODE_FOLLOW_MUTE: /* noop */ break; 177 } 178 if (route >= 0) { 179 struct led_trigger *trig = snd_ctl_ledtrig_audio[led->trigger_type]; 180 181 led_trigger_event(trig, route ? LED_OFF : LED_ON); 182 } 183 } 184 185 static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff) 186 { 187 struct list_head *controls; 188 struct snd_ctl_led_ctl *lctl; 189 unsigned int group; 190 191 for (group = 0; group < MAX_LED; group++) { 192 controls = &snd_ctl_leds[group].controls; 193 list_for_each_entry(lctl, controls, list) 194 if (lctl->kctl == kctl && lctl->index_offset == ioff) 195 return lctl; 196 } 197 return NULL; 198 } 199 200 static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int ioff, 201 unsigned int access) 202 { 203 struct snd_ctl_led_ctl *lctl; 204 unsigned int ret = 0; 205 206 guard(mutex)(&snd_ctl_led_mutex); 207 lctl = snd_ctl_led_find(kctl, ioff); 208 if (lctl && (access == 0 || access != lctl->access)) { 209 ret = lctl->access; 210 list_del(&lctl->list); 211 kfree(lctl); 212 } 213 return ret; 214 } 215 216 static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask, 217 struct snd_kcontrol *kctl, unsigned int ioff) 218 { 219 struct snd_kcontrol_volatile *vd; 220 unsigned int access, access2; 221 222 if (mask == SNDRV_CTL_EVENT_MASK_REMOVE) { 223 access = snd_ctl_led_remove(kctl, ioff, 0); 224 if (access) 225 snd_ctl_led_set_state(card, access, NULL, 0); 226 } else if (mask & SNDRV_CTL_EVENT_MASK_INFO) { 227 vd = &kctl->vd[ioff]; 228 access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK; 229 access2 = snd_ctl_led_remove(kctl, ioff, access); 230 if (access2) 231 snd_ctl_led_set_state(card, access2, NULL, 0); 232 if (access) 233 snd_ctl_led_set_state(card, access, kctl, ioff); 234 } else if ((mask & (SNDRV_CTL_EVENT_MASK_ADD | 235 SNDRV_CTL_EVENT_MASK_VALUE)) != 0) { 236 vd = &kctl->vd[ioff]; 237 access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK; 238 if (access) 239 snd_ctl_led_set_state(card, access, kctl, ioff); 240 } 241 } 242 243 static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, 244 unsigned int group, bool set) 245 { 246 struct snd_kcontrol *kctl; 247 struct snd_kcontrol_volatile *vd; 248 unsigned int ioff, access, new_access; 249 struct snd_card *card __free(snd_card_unref) = 250 snd_card_ref(card_number); 251 252 if (!card) 253 return -ENXIO; 254 guard(rwsem_write)(&card->controls_rwsem); 255 kctl = snd_ctl_find_id(card, id); 256 if (!kctl) 257 return -ENOENT; 258 ioff = snd_ctl_get_ioff(kctl, id); 259 vd = &kctl->vd[ioff]; 260 access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK; 261 if (access != 0 && access != group_to_access(group)) 262 return -EXDEV; 263 new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK; 264 if (set) 265 new_access |= group_to_access(group); 266 if (new_access != vd->access) { 267 vd->access = new_access; 268 snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff); 269 } 270 return 0; 271 } 272 273 static void snd_ctl_led_refresh(void) 274 { 275 unsigned int group; 276 277 for (group = 0; group < MAX_LED; group++) 278 snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0); 279 } 280 281 static void snd_ctl_led_ctl_destroy(struct snd_ctl_led_ctl *lctl) 282 { 283 list_del(&lctl->list); 284 kfree(lctl); 285 } 286 287 static void snd_ctl_led_clean(struct snd_card *card) 288 { 289 unsigned int group; 290 struct snd_ctl_led_ctl *lctl, *_lctl; 291 struct snd_ctl_led *led; 292 293 for (group = 0; group < MAX_LED; group++) { 294 led = &snd_ctl_leds[group]; 295 list_for_each_entry_safe(lctl, _lctl, &led->controls, list) 296 if (!card || lctl->card == card) 297 snd_ctl_led_ctl_destroy(lctl); 298 } 299 } 300 301 static int snd_ctl_led_reset(int card_number, unsigned int group) 302 { 303 struct snd_ctl_led_ctl *lctl, *_lctl; 304 struct snd_ctl_led *led; 305 struct snd_kcontrol_volatile *vd; 306 bool change = false; 307 struct snd_card *card __free(snd_card_unref) = 308 snd_card_ref(card_number); 309 310 if (!card) 311 return -ENXIO; 312 313 scoped_guard(mutex, &snd_ctl_led_mutex) { 314 if (!snd_ctl_led_card_valid[card_number]) 315 return -ENXIO; 316 led = &snd_ctl_leds[group]; 317 list_for_each_entry_safe(lctl, _lctl, &led->controls, list) 318 if (lctl->card == card) { 319 vd = &lctl->kctl->vd[lctl->index_offset]; 320 vd->access &= ~group_to_access(group); 321 snd_ctl_led_ctl_destroy(lctl); 322 change = true; 323 } 324 } 325 if (change) 326 snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0); 327 return 0; 328 } 329 330 static void snd_ctl_led_register(struct snd_card *card) 331 { 332 struct snd_kcontrol *kctl; 333 unsigned int ioff; 334 335 if (snd_BUG_ON(card->number < 0 || 336 card->number >= ARRAY_SIZE(snd_ctl_led_card_valid))) 337 return; 338 scoped_guard(mutex, &snd_ctl_led_mutex) 339 snd_ctl_led_card_valid[card->number] = true; 340 /* the register callback is already called with held card->controls_rwsem */ 341 list_for_each_entry(kctl, &card->controls, list) 342 for (ioff = 0; ioff < kctl->count; ioff++) 343 snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff); 344 snd_ctl_led_refresh(); 345 snd_ctl_led_sysfs_add(card); 346 } 347 348 static void snd_ctl_led_disconnect(struct snd_card *card) 349 { 350 snd_ctl_led_sysfs_remove(card); 351 scoped_guard(mutex, &snd_ctl_led_mutex) { 352 snd_ctl_led_card_valid[card->number] = false; 353 snd_ctl_led_clean(card); 354 } 355 snd_ctl_led_refresh(); 356 } 357 358 static void snd_ctl_led_card_release(struct device *dev) 359 { 360 struct snd_ctl_led_card *led_card = to_led_card_dev(dev); 361 362 kfree(led_card); 363 } 364 365 static void snd_ctl_led_release(struct device *dev) 366 { 367 } 368 369 static void snd_ctl_led_dev_release(struct device *dev) 370 { 371 } 372 373 /* 374 * sysfs 375 */ 376 377 static ssize_t mode_show(struct device *dev, 378 struct device_attribute *attr, char *buf) 379 { 380 struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); 381 const char *str = NULL; 382 383 switch (led->mode) { 384 case MODE_FOLLOW_MUTE: str = "follow-mute"; break; 385 case MODE_FOLLOW_ROUTE: str = "follow-route"; break; 386 case MODE_ON: str = "on"; break; 387 case MODE_OFF: str = "off"; break; 388 } 389 return sysfs_emit(buf, "%s\n", str); 390 } 391 392 static ssize_t mode_store(struct device *dev, 393 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 scoped_guard(mutex, &snd_ctl_led_mutex) 415 led->mode = mode; 416 417 snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0); 418 return count; 419 } 420 421 static ssize_t brightness_show(struct device *dev, 422 struct device_attribute *attr, char *buf) 423 { 424 struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); 425 struct led_trigger *trig = snd_ctl_ledtrig_audio[led->trigger_type]; 426 427 return sysfs_emit(buf, "%u\n", led_trigger_get_brightness(trig)); 428 } 429 430 static DEVICE_ATTR_RW(mode); 431 static DEVICE_ATTR_RO(brightness); 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 448 static char *find_eos(char *s) 449 { 450 while (*s && *s != ',') 451 s++; 452 if (*s) 453 s++; 454 return s; 455 } 456 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 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 493 static char *parse_iface(char *s, snd_ctl_elem_iface_t *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 */ 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 struct snd_ctl_elem_id id; 515 int err; 516 517 if (strscpy(buf2, buf, sizeof(buf2)) < 0) 518 return -E2BIG; 519 memset(&id, 0, sizeof(id)); 520 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 521 s = buf2; 522 while (*s) { 523 os = s; 524 if (!strncasecmp(s, "numid=", 6)) { 525 s = parse_uint(s + 6, &id.numid); 526 } else if (!strncasecmp(s, "iface=", 6)) { 527 s = parse_iface(s + 6, &id.iface); 528 } else if (!strncasecmp(s, "device=", 7)) { 529 s = parse_uint(s + 7, &id.device); 530 } else if (!strncasecmp(s, "subdevice=", 10)) { 531 s = parse_uint(s + 10, &id.subdevice); 532 } else if (!strncasecmp(s, "name=", 5)) { 533 s = parse_string(s + 5, id.name, sizeof(id.name)); 534 } else if (!strncasecmp(s, "index=", 6)) { 535 s = parse_uint(s + 6, &id.index); 536 } else if (s == buf2) { 537 while (*s) { 538 if (*s < '0' || *s > '9') 539 break; 540 s++; 541 } 542 if (*s == '\0') 543 parse_uint(buf2, &id.numid); 544 else { 545 for (; *s >= ' '; s++); 546 *s = '\0'; 547 strscpy(id.name, buf2, sizeof(id.name)); 548 } 549 break; 550 } 551 if (*s == ',') 552 s++; 553 if (s == os) 554 break; 555 } 556 557 err = snd_ctl_led_set_id(led_card->number, &id, led_card->led->group, attach); 558 if (err < 0) 559 return err; 560 561 return count; 562 } 563 564 static ssize_t attach_store(struct device *dev, 565 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 572 static ssize_t detach_store(struct device *dev, 573 struct device_attribute *attr, 574 const char *buf, size_t count) 575 { 576 struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); 577 return set_led_id(led_card, buf, count, false); 578 } 579 580 static ssize_t reset_store(struct device *dev, 581 struct device_attribute *attr, 582 const char *buf, size_t count) 583 { 584 struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); 585 int err; 586 587 if (count > 0 && buf[0] == '1') { 588 err = snd_ctl_led_reset(led_card->number, led_card->led->group); 589 if (err < 0) 590 return err; 591 } 592 return count; 593 } 594 595 static ssize_t list_show(struct device *dev, 596 struct device_attribute *attr, char *buf) 597 { 598 struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); 599 struct snd_ctl_led_ctl *lctl; 600 size_t l = 0; 601 struct snd_card *card __free(snd_card_unref) = 602 snd_card_ref(led_card->number); 603 604 if (!card) 605 return -ENXIO; 606 guard(rwsem_read)(&card->controls_rwsem); 607 guard(mutex)(&snd_ctl_led_mutex); 608 if (snd_ctl_led_card_valid[led_card->number]) { 609 list_for_each_entry(lctl, &led_card->led->controls, list) { 610 if (lctl->card != card) 611 continue; 612 if (l) 613 l += sysfs_emit_at(buf, l, " "); 614 l += sysfs_emit_at(buf, l, "%u", 615 lctl->kctl->id.numid + lctl->index_offset); 616 } 617 } 618 return l; 619 } 620 621 static DEVICE_ATTR_WO(attach); 622 static DEVICE_ATTR_WO(detach); 623 static DEVICE_ATTR_WO(reset); 624 static DEVICE_ATTR_RO(list); 625 626 static struct attribute *snd_ctl_led_card_attrs[] = { 627 &dev_attr_attach.attr, 628 &dev_attr_detach.attr, 629 &dev_attr_reset.attr, 630 &dev_attr_list.attr, 631 NULL, 632 }; 633 634 static const struct attribute_group snd_ctl_led_card_attr_group = { 635 .attrs = snd_ctl_led_card_attrs, 636 }; 637 638 static const struct attribute_group *snd_ctl_led_card_attr_groups[] = { 639 &snd_ctl_led_card_attr_group, 640 NULL, 641 }; 642 643 static struct device snd_ctl_led_dev; 644 645 static void snd_ctl_led_sysfs_add(struct snd_card *card) 646 { 647 unsigned int group; 648 struct snd_ctl_led_card *led_card; 649 struct snd_ctl_led *led; 650 char link_name[32]; 651 652 for (group = 0; group < MAX_LED; group++) { 653 led = &snd_ctl_leds[group]; 654 led_card = kzalloc_obj(*led_card); 655 if (!led_card) 656 goto cerr2; 657 led_card->number = card->number; 658 led_card->led = led; 659 device_initialize(&led_card->dev); 660 led_card->dev.release = snd_ctl_led_card_release; 661 if (dev_set_name(&led_card->dev, "card%d", card->number) < 0) 662 goto cerr; 663 led_card->dev.parent = &led->dev; 664 led_card->dev.groups = snd_ctl_led_card_attr_groups; 665 if (device_add(&led_card->dev)) 666 goto cerr; 667 led->cards[card->number] = led_card; 668 snprintf(link_name, sizeof(link_name), "led-%s", led->name); 669 if (sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj, 670 link_name)) 671 dev_err(card->dev, 672 "%s: can't create symlink to controlC%i device\n", 673 __func__, card->number); 674 if (sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, 675 "card")) 676 dev_err(card->dev, 677 "%s: can't create symlink to card%i\n", 678 __func__, card->number); 679 680 continue; 681 cerr: 682 put_device(&led_card->dev); 683 cerr2: 684 dev_err(card->dev, "snd_ctl_led: unable to add card%d", card->number); 685 } 686 } 687 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_unregister(&led_card->dev); 704 led->cards[card->number] = NULL; 705 } 706 } 707 708 /* 709 * Control layer registration 710 */ 711 static struct snd_ctl_layer_ops snd_ctl_led_lops = { 712 .module_name = SND_CTL_LAYER_MODULE_LED, 713 .lregister = snd_ctl_led_register, 714 .ldisconnect = snd_ctl_led_disconnect, 715 .lnotify = snd_ctl_led_notify, 716 }; 717 718 static int __init snd_ctl_led_init(void) 719 { 720 struct snd_ctl_led *led; 721 unsigned int group; 722 723 led_trigger_register_simple("audio-mute", &snd_ctl_ledtrig_audio[LED_AUDIO_MUTE]); 724 led_trigger_register_simple("audio-micmute", &snd_ctl_ledtrig_audio[LED_AUDIO_MICMUTE]); 725 726 device_initialize(&snd_ctl_led_dev); 727 snd_ctl_led_dev.class = &sound_class; 728 snd_ctl_led_dev.release = snd_ctl_led_dev_release; 729 dev_set_name(&snd_ctl_led_dev, "ctl-led"); 730 if (device_add(&snd_ctl_led_dev)) { 731 put_device(&snd_ctl_led_dev); 732 return -ENOMEM; 733 } 734 for (group = 0; group < MAX_LED; group++) { 735 led = &snd_ctl_leds[group]; 736 INIT_LIST_HEAD(&led->controls); 737 device_initialize(&led->dev); 738 led->dev.parent = &snd_ctl_led_dev; 739 led->dev.release = snd_ctl_led_release; 740 led->dev.groups = snd_ctl_led_dev_attr_groups; 741 dev_set_name(&led->dev, led->name); 742 if (device_add(&led->dev)) { 743 put_device(&led->dev); 744 for (; group > 0; group--) { 745 led = &snd_ctl_leds[group - 1]; 746 device_unregister(&led->dev); 747 } 748 device_unregister(&snd_ctl_led_dev); 749 return -ENOMEM; 750 } 751 } 752 snd_ctl_register_layer(&snd_ctl_led_lops); 753 return 0; 754 } 755 756 static void __exit snd_ctl_led_exit(void) 757 { 758 struct snd_ctl_led *led; 759 unsigned int group, card_number; 760 761 snd_ctl_disconnect_layer(&snd_ctl_led_lops); 762 for (card_number = 0; card_number < SNDRV_CARDS; card_number++) { 763 if (!snd_ctl_led_card_valid[card_number]) 764 continue; 765 struct snd_card *card __free(snd_card_unref) = 766 snd_card_ref(card_number); 767 768 if (card) 769 snd_ctl_led_sysfs_remove(card); 770 } 771 for (group = 0; group < MAX_LED; group++) { 772 led = &snd_ctl_leds[group]; 773 device_unregister(&led->dev); 774 } 775 device_unregister(&snd_ctl_led_dev); 776 snd_ctl_led_clean(NULL); 777 778 led_trigger_unregister_simple(snd_ctl_ledtrig_audio[LED_AUDIO_MUTE]); 779 led_trigger_unregister_simple(snd_ctl_ledtrig_audio[LED_AUDIO_MICMUTE]); 780 } 781 782 module_init(snd_ctl_led_init) 783 module_exit(snd_ctl_led_exit) 784 785 MODULE_ALIAS("ledtrig:audio-mute"); 786 MODULE_ALIAS("ledtrig:audio-micmute"); 787