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