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 /* 98 * A note for callers: 99 * The two static variables info and value are protected using snd_ctl_led_mutex. 100 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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, 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 */ 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 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 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 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 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 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 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 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 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