Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  LED state routines for driver control interface
0004  *  Copyright (c) 2021 by Jaroslav Kysela <perex@perex.cz>
0005  */
0006 
0007 #include <linux/slab.h>
0008 #include <linux/module.h>
0009 #include <linux/leds.h>
0010 #include <sound/core.h>
0011 #include <sound/control.h>
0012 
0013 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
0014 MODULE_DESCRIPTION("ALSA control interface to LED trigger code.");
0015 MODULE_LICENSE("GPL");
0016 
0017 #define MAX_LED (((SNDRV_CTL_ELEM_ACCESS_MIC_LED - SNDRV_CTL_ELEM_ACCESS_SPK_LED) \
0018             >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) + 1)
0019 
0020 #define to_led_card_dev(_dev) \
0021     container_of(_dev, struct snd_ctl_led_card, dev)
0022 
0023 enum snd_ctl_led_mode {
0024      MODE_FOLLOW_MUTE = 0,
0025      MODE_FOLLOW_ROUTE,
0026      MODE_OFF,
0027      MODE_ON,
0028 };
0029 
0030 struct snd_ctl_led_card {
0031     struct device dev;
0032     int number;
0033     struct snd_ctl_led *led;
0034 };
0035 
0036 struct snd_ctl_led {
0037     struct device dev;
0038     struct list_head controls;
0039     const char *name;
0040     unsigned int group;
0041     enum led_audio trigger_type;
0042     enum snd_ctl_led_mode mode;
0043     struct snd_ctl_led_card *cards[SNDRV_CARDS];
0044 };
0045 
0046 struct snd_ctl_led_ctl {
0047     struct list_head list;
0048     struct snd_card *card;
0049     unsigned int access;
0050     struct snd_kcontrol *kctl;
0051     unsigned int index_offset;
0052 };
0053 
0054 static DEFINE_MUTEX(snd_ctl_led_mutex);
0055 static bool snd_ctl_led_card_valid[SNDRV_CARDS];
0056 static struct snd_ctl_led snd_ctl_leds[MAX_LED] = {
0057     {
0058         .name = "speaker",
0059         .group = (SNDRV_CTL_ELEM_ACCESS_SPK_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1,
0060         .trigger_type = LED_AUDIO_MUTE,
0061         .mode = MODE_FOLLOW_MUTE,
0062     },
0063     {
0064         .name = "mic",
0065         .group = (SNDRV_CTL_ELEM_ACCESS_MIC_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1,
0066         .trigger_type = LED_AUDIO_MICMUTE,
0067         .mode = MODE_FOLLOW_MUTE,
0068     },
0069 };
0070 
0071 static void snd_ctl_led_sysfs_add(struct snd_card *card);
0072 static void snd_ctl_led_sysfs_remove(struct snd_card *card);
0073 
0074 #define UPDATE_ROUTE(route, cb) \
0075     do { \
0076         int route2 = (cb); \
0077         if (route2 >= 0) \
0078             route = route < 0 ? route2 : (route | route2); \
0079     } while (0)
0080 
0081 static inline unsigned int access_to_group(unsigned int access)
0082 {
0083     return ((access & SNDRV_CTL_ELEM_ACCESS_LED_MASK) >>
0084                 SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1;
0085 }
0086 
0087 static inline unsigned int group_to_access(unsigned int group)
0088 {
0089     return (group + 1) << SNDRV_CTL_ELEM_ACCESS_LED_SHIFT;
0090 }
0091 
0092 static struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access)
0093 {
0094     unsigned int group = access_to_group(access);
0095     if (group >= MAX_LED)
0096         return NULL;
0097     return &snd_ctl_leds[group];
0098 }
0099 
0100 /*
0101  * A note for callers:
0102  *   The two static variables info and value are protected using snd_ctl_led_mutex.
0103  */
0104 static int snd_ctl_led_get(struct snd_ctl_led_ctl *lctl)
0105 {
0106     static struct snd_ctl_elem_info info;
0107     static struct snd_ctl_elem_value value;
0108     struct snd_kcontrol *kctl = lctl->kctl;
0109     unsigned int i;
0110     int result;
0111 
0112     memset(&info, 0, sizeof(info));
0113     info.id = kctl->id;
0114     info.id.index += lctl->index_offset;
0115     info.id.numid += lctl->index_offset;
0116     result = kctl->info(kctl, &info);
0117     if (result < 0)
0118         return -1;
0119     memset(&value, 0, sizeof(value));
0120     value.id = info.id;
0121     result = kctl->get(kctl, &value);
0122     if (result < 0)
0123         return -1;
0124     if (info.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
0125         info.type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
0126         for (i = 0; i < info.count; i++)
0127             if (value.value.integer.value[i] != info.value.integer.min)
0128                 return 1;
0129     } else if (info.type == SNDRV_CTL_ELEM_TYPE_INTEGER64) {
0130         for (i = 0; i < info.count; i++)
0131             if (value.value.integer64.value[i] != info.value.integer64.min)
0132                 return 1;
0133     }
0134     return 0;
0135 }
0136 
0137 static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
0138                   struct snd_kcontrol *kctl, unsigned int ioff)
0139 {
0140     struct snd_ctl_led *led;
0141     struct snd_ctl_led_ctl *lctl;
0142     int route;
0143     bool found;
0144 
0145     led = snd_ctl_led_get_by_access(access);
0146     if (!led)
0147         return;
0148     route = -1;
0149     found = false;
0150     mutex_lock(&snd_ctl_led_mutex);
0151     /* the card may not be registered (active) at this point */
0152     if (card && !snd_ctl_led_card_valid[card->number]) {
0153         mutex_unlock(&snd_ctl_led_mutex);
0154         return;
0155     }
0156     list_for_each_entry(lctl, &led->controls, list) {
0157         if (lctl->kctl == kctl && lctl->index_offset == ioff)
0158             found = true;
0159         UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
0160     }
0161     if (!found && kctl && card) {
0162         lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
0163         if (lctl) {
0164             lctl->card = card;
0165             lctl->access = access;
0166             lctl->kctl = kctl;
0167             lctl->index_offset = ioff;
0168             list_add(&lctl->list, &led->controls);
0169             UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
0170         }
0171     }
0172     mutex_unlock(&snd_ctl_led_mutex);
0173     switch (led->mode) {
0174     case MODE_OFF:      route = 1; break;
0175     case MODE_ON:       route = 0; break;
0176     case MODE_FOLLOW_ROUTE: if (route >= 0) route ^= 1; break;
0177     case MODE_FOLLOW_MUTE:  /* noop */ break;
0178     }
0179     if (route >= 0)
0180         ledtrig_audio_set(led->trigger_type, route ? LED_OFF : LED_ON);
0181 }
0182 
0183 static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff)
0184 {
0185     struct list_head *controls;
0186     struct snd_ctl_led_ctl *lctl;
0187     unsigned int group;
0188 
0189     for (group = 0; group < MAX_LED; group++) {
0190         controls = &snd_ctl_leds[group].controls;
0191         list_for_each_entry(lctl, controls, list)
0192             if (lctl->kctl == kctl && lctl->index_offset == ioff)
0193                 return lctl;
0194     }
0195     return NULL;
0196 }
0197 
0198 static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int ioff,
0199                        unsigned int access)
0200 {
0201     struct snd_ctl_led_ctl *lctl;
0202     unsigned int ret = 0;
0203 
0204     mutex_lock(&snd_ctl_led_mutex);
0205     lctl = snd_ctl_led_find(kctl, ioff);
0206     if (lctl && (access == 0 || access != lctl->access)) {
0207         ret = lctl->access;
0208         list_del(&lctl->list);
0209         kfree(lctl);
0210     }
0211     mutex_unlock(&snd_ctl_led_mutex);
0212     return ret;
0213 }
0214 
0215 static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask,
0216                    struct snd_kcontrol *kctl, unsigned int ioff)
0217 {
0218     struct snd_kcontrol_volatile *vd;
0219     unsigned int access, access2;
0220 
0221     if (mask == SNDRV_CTL_EVENT_MASK_REMOVE) {
0222         access = snd_ctl_led_remove(kctl, ioff, 0);
0223         if (access)
0224             snd_ctl_led_set_state(card, access, NULL, 0);
0225     } else if (mask & SNDRV_CTL_EVENT_MASK_INFO) {
0226         vd = &kctl->vd[ioff];
0227         access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
0228         access2 = snd_ctl_led_remove(kctl, ioff, access);
0229         if (access2)
0230             snd_ctl_led_set_state(card, access2, NULL, 0);
0231         if (access)
0232             snd_ctl_led_set_state(card, access, kctl, ioff);
0233     } else if ((mask & (SNDRV_CTL_EVENT_MASK_ADD |
0234                 SNDRV_CTL_EVENT_MASK_VALUE)) != 0) {
0235         vd = &kctl->vd[ioff];
0236         access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
0237         if (access)
0238             snd_ctl_led_set_state(card, access, kctl, ioff);
0239     }
0240 }
0241 
0242 static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
0243                   unsigned int group, bool set)
0244 {
0245     struct snd_card *card;
0246     struct snd_kcontrol *kctl;
0247     struct snd_kcontrol_volatile *vd;
0248     unsigned int ioff, access, new_access;
0249     int err = 0;
0250 
0251     card = snd_card_ref(card_number);
0252     if (card) {
0253         down_write(&card->controls_rwsem);
0254         kctl = snd_ctl_find_id(card, id);
0255         if (kctl) {
0256             ioff = snd_ctl_get_ioff(kctl, id);
0257             vd = &kctl->vd[ioff];
0258             access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
0259             if (access != 0 && access != group_to_access(group)) {
0260                 err = -EXDEV;
0261                 goto unlock;
0262             }
0263             new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
0264             if (set)
0265                 new_access |= group_to_access(group);
0266             if (new_access != vd->access) {
0267                 vd->access = new_access;
0268                 snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
0269             }
0270         } else {
0271             err = -ENOENT;
0272         }
0273 unlock:
0274         up_write(&card->controls_rwsem);
0275         snd_card_unref(card);
0276     } else {
0277         err = -ENXIO;
0278     }
0279     return err;
0280 }
0281 
0282 static void snd_ctl_led_refresh(void)
0283 {
0284     unsigned int group;
0285 
0286     for (group = 0; group < MAX_LED; group++)
0287         snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
0288 }
0289 
0290 static void snd_ctl_led_ctl_destroy(struct snd_ctl_led_ctl *lctl)
0291 {
0292     list_del(&lctl->list);
0293     kfree(lctl);
0294 }
0295 
0296 static void snd_ctl_led_clean(struct snd_card *card)
0297 {
0298     unsigned int group;
0299     struct snd_ctl_led *led;
0300     struct snd_ctl_led_ctl *lctl;
0301 
0302     for (group = 0; group < MAX_LED; group++) {
0303         led = &snd_ctl_leds[group];
0304 repeat:
0305         list_for_each_entry(lctl, &led->controls, list)
0306             if (!card || lctl->card == card) {
0307                 snd_ctl_led_ctl_destroy(lctl);
0308                 goto repeat;
0309             }
0310     }
0311 }
0312 
0313 static int snd_ctl_led_reset(int card_number, unsigned int group)
0314 {
0315     struct snd_card *card;
0316     struct snd_ctl_led *led;
0317     struct snd_ctl_led_ctl *lctl;
0318     struct snd_kcontrol_volatile *vd;
0319     bool change = false;
0320 
0321     card = snd_card_ref(card_number);
0322     if (!card)
0323         return -ENXIO;
0324 
0325     mutex_lock(&snd_ctl_led_mutex);
0326     if (!snd_ctl_led_card_valid[card_number]) {
0327         mutex_unlock(&snd_ctl_led_mutex);
0328         snd_card_unref(card);
0329         return -ENXIO;
0330     }
0331     led = &snd_ctl_leds[group];
0332 repeat:
0333     list_for_each_entry(lctl, &led->controls, list)
0334         if (lctl->card == card) {
0335             vd = &lctl->kctl->vd[lctl->index_offset];
0336             vd->access &= ~group_to_access(group);
0337             snd_ctl_led_ctl_destroy(lctl);
0338             change = true;
0339             goto repeat;
0340         }
0341     mutex_unlock(&snd_ctl_led_mutex);
0342     if (change)
0343         snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
0344     snd_card_unref(card);
0345     return 0;
0346 }
0347 
0348 static void snd_ctl_led_register(struct snd_card *card)
0349 {
0350     struct snd_kcontrol *kctl;
0351     unsigned int ioff;
0352 
0353     if (snd_BUG_ON(card->number < 0 ||
0354                card->number >= ARRAY_SIZE(snd_ctl_led_card_valid)))
0355         return;
0356     mutex_lock(&snd_ctl_led_mutex);
0357     snd_ctl_led_card_valid[card->number] = true;
0358     mutex_unlock(&snd_ctl_led_mutex);
0359     /* the register callback is already called with held card->controls_rwsem */
0360     list_for_each_entry(kctl, &card->controls, list)
0361         for (ioff = 0; ioff < kctl->count; ioff++)
0362             snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff);
0363     snd_ctl_led_refresh();
0364     snd_ctl_led_sysfs_add(card);
0365 }
0366 
0367 static void snd_ctl_led_disconnect(struct snd_card *card)
0368 {
0369     snd_ctl_led_sysfs_remove(card);
0370     mutex_lock(&snd_ctl_led_mutex);
0371     snd_ctl_led_card_valid[card->number] = false;
0372     snd_ctl_led_clean(card);
0373     mutex_unlock(&snd_ctl_led_mutex);
0374     snd_ctl_led_refresh();
0375 }
0376 
0377 static void snd_ctl_led_card_release(struct device *dev)
0378 {
0379     struct snd_ctl_led_card *led_card = to_led_card_dev(dev);
0380 
0381     kfree(led_card);
0382 }
0383 
0384 static void snd_ctl_led_release(struct device *dev)
0385 {
0386 }
0387 
0388 static void snd_ctl_led_dev_release(struct device *dev)
0389 {
0390 }
0391 
0392 /*
0393  * sysfs
0394  */
0395 
0396 static ssize_t mode_show(struct device *dev,
0397              struct device_attribute *attr, char *buf)
0398 {
0399     struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
0400     const char *str = NULL;
0401 
0402     switch (led->mode) {
0403     case MODE_FOLLOW_MUTE:  str = "follow-mute"; break;
0404     case MODE_FOLLOW_ROUTE: str = "follow-route"; break;
0405     case MODE_ON:       str = "on"; break;
0406     case MODE_OFF:      str = "off"; break;
0407     }
0408     return sysfs_emit(buf, "%s\n", str);
0409 }
0410 
0411 static ssize_t mode_store(struct device *dev,
0412               struct device_attribute *attr,
0413               const char *buf, size_t count)
0414 {
0415     struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
0416     char _buf[16];
0417     size_t l = min(count, sizeof(_buf) - 1);
0418     enum snd_ctl_led_mode mode;
0419 
0420     memcpy(_buf, buf, l);
0421     _buf[l] = '\0';
0422     if (strstr(_buf, "mute"))
0423         mode = MODE_FOLLOW_MUTE;
0424     else if (strstr(_buf, "route"))
0425         mode = MODE_FOLLOW_ROUTE;
0426     else if (strncmp(_buf, "off", 3) == 0 || strncmp(_buf, "0", 1) == 0)
0427         mode = MODE_OFF;
0428     else if (strncmp(_buf, "on", 2) == 0 || strncmp(_buf, "1", 1) == 0)
0429         mode = MODE_ON;
0430     else
0431         return count;
0432 
0433     mutex_lock(&snd_ctl_led_mutex);
0434     led->mode = mode;
0435     mutex_unlock(&snd_ctl_led_mutex);
0436 
0437     snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0);
0438     return count;
0439 }
0440 
0441 static ssize_t brightness_show(struct device *dev,
0442                    struct device_attribute *attr, char *buf)
0443 {
0444     struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
0445 
0446     return sysfs_emit(buf, "%u\n", ledtrig_audio_get(led->trigger_type));
0447 }
0448 
0449 static DEVICE_ATTR_RW(mode);
0450 static DEVICE_ATTR_RO(brightness);
0451 
0452 static struct attribute *snd_ctl_led_dev_attrs[] = {
0453     &dev_attr_mode.attr,
0454     &dev_attr_brightness.attr,
0455     NULL,
0456 };
0457 
0458 static const struct attribute_group snd_ctl_led_dev_attr_group = {
0459     .attrs = snd_ctl_led_dev_attrs,
0460 };
0461 
0462 static const struct attribute_group *snd_ctl_led_dev_attr_groups[] = {
0463     &snd_ctl_led_dev_attr_group,
0464     NULL,
0465 };
0466 
0467 static char *find_eos(char *s)
0468 {
0469     while (*s && *s != ',')
0470         s++;
0471     if (*s)
0472         s++;
0473     return s;
0474 }
0475 
0476 static char *parse_uint(char *s, unsigned int *val)
0477 {
0478     unsigned long long res;
0479     if (kstrtoull(s, 10, &res))
0480         res = 0;
0481     *val = res;
0482     return find_eos(s);
0483 }
0484 
0485 static char *parse_string(char *s, char *val, size_t val_size)
0486 {
0487     if (*s == '"' || *s == '\'') {
0488         char c = *s;
0489         s++;
0490         while (*s && *s != c) {
0491             if (val_size > 1) {
0492                 *val++ = *s;
0493                 val_size--;
0494             }
0495             s++;
0496         }
0497     } else {
0498         while (*s && *s != ',') {
0499             if (val_size > 1) {
0500                 *val++ = *s;
0501                 val_size--;
0502             }
0503             s++;
0504         }
0505     }
0506     *val = '\0';
0507     if (*s)
0508         s++;
0509     return s;
0510 }
0511 
0512 static char *parse_iface(char *s, snd_ctl_elem_iface_t *val)
0513 {
0514     if (!strncasecmp(s, "card", 4))
0515         *val = SNDRV_CTL_ELEM_IFACE_CARD;
0516     else if (!strncasecmp(s, "mixer", 5))
0517         *val = SNDRV_CTL_ELEM_IFACE_MIXER;
0518     return find_eos(s);
0519 }
0520 
0521 /*
0522  * These types of input strings are accepted:
0523  *
0524  *   unsigned integer - numid (equivaled to numid=UINT)
0525  *   string - basic mixer name (equivalent to iface=MIXER,name=STR)
0526  *   numid=UINT
0527  *   [iface=MIXER,][device=UINT,][subdevice=UINT,]name=STR[,index=UINT]
0528  */
0529 static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, size_t count,
0530               bool attach)
0531 {
0532     char buf2[256], *s, *os;
0533     size_t len = max(sizeof(s) - 1, count);
0534     struct snd_ctl_elem_id id;
0535     int err;
0536 
0537     strncpy(buf2, buf, len);
0538     buf2[len] = '\0';
0539     memset(&id, 0, sizeof(id));
0540     id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
0541     s = buf2;
0542     while (*s) {
0543         os = s;
0544         if (!strncasecmp(s, "numid=", 6)) {
0545             s = parse_uint(s + 6, &id.numid);
0546         } else if (!strncasecmp(s, "iface=", 6)) {
0547             s = parse_iface(s + 6, &id.iface);
0548         } else if (!strncasecmp(s, "device=", 7)) {
0549             s = parse_uint(s + 7, &id.device);
0550         } else if (!strncasecmp(s, "subdevice=", 10)) {
0551             s = parse_uint(s + 10, &id.subdevice);
0552         } else if (!strncasecmp(s, "name=", 5)) {
0553             s = parse_string(s + 5, id.name, sizeof(id.name));
0554         } else if (!strncasecmp(s, "index=", 6)) {
0555             s = parse_uint(s + 6, &id.index);
0556         } else if (s == buf2) {
0557             while (*s) {
0558                 if (*s < '0' || *s > '9')
0559                     break;
0560                 s++;
0561             }
0562             if (*s == '\0')
0563                 parse_uint(buf2, &id.numid);
0564             else {
0565                 for (; *s >= ' '; s++);
0566                 *s = '\0';
0567                 strscpy(id.name, buf2, sizeof(id.name));
0568             }
0569             break;
0570         }
0571         if (*s == ',')
0572             s++;
0573         if (s == os)
0574             break;
0575     }
0576 
0577     err = snd_ctl_led_set_id(led_card->number, &id, led_card->led->group, attach);
0578     if (err < 0)
0579         return err;
0580 
0581     return count;
0582 }
0583 
0584 static ssize_t attach_store(struct device *dev,
0585                 struct device_attribute *attr,
0586                 const char *buf, size_t count)
0587 {
0588     struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
0589     return set_led_id(led_card, buf, count, true);
0590 }
0591 
0592 static ssize_t detach_store(struct device *dev,
0593                 struct device_attribute *attr,
0594                 const char *buf, size_t count)
0595 {
0596     struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
0597     return set_led_id(led_card, buf, count, false);
0598 }
0599 
0600 static ssize_t reset_store(struct device *dev,
0601                struct device_attribute *attr,
0602                const char *buf, size_t count)
0603 {
0604     struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
0605     int err;
0606 
0607     if (count > 0 && buf[0] == '1') {
0608         err = snd_ctl_led_reset(led_card->number, led_card->led->group);
0609         if (err < 0)
0610             return err;
0611     }
0612     return count;
0613 }
0614 
0615 static ssize_t list_show(struct device *dev,
0616              struct device_attribute *attr, char *buf)
0617 {
0618     struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
0619     struct snd_card *card;
0620     struct snd_ctl_led_ctl *lctl;
0621     size_t l = 0;
0622 
0623     card = snd_card_ref(led_card->number);
0624     if (!card)
0625         return -ENXIO;
0626     down_read(&card->controls_rwsem);
0627     mutex_lock(&snd_ctl_led_mutex);
0628     if (snd_ctl_led_card_valid[led_card->number]) {
0629         list_for_each_entry(lctl, &led_card->led->controls, list) {
0630             if (lctl->card != card)
0631                 continue;
0632             if (l)
0633                 l += sysfs_emit_at(buf, l, " ");
0634             l += sysfs_emit_at(buf, l, "%u",
0635                        lctl->kctl->id.numid + lctl->index_offset);
0636         }
0637     }
0638     mutex_unlock(&snd_ctl_led_mutex);
0639     up_read(&card->controls_rwsem);
0640     snd_card_unref(card);
0641     return l;
0642 }
0643 
0644 static DEVICE_ATTR_WO(attach);
0645 static DEVICE_ATTR_WO(detach);
0646 static DEVICE_ATTR_WO(reset);
0647 static DEVICE_ATTR_RO(list);
0648 
0649 static struct attribute *snd_ctl_led_card_attrs[] = {
0650     &dev_attr_attach.attr,
0651     &dev_attr_detach.attr,
0652     &dev_attr_reset.attr,
0653     &dev_attr_list.attr,
0654     NULL,
0655 };
0656 
0657 static const struct attribute_group snd_ctl_led_card_attr_group = {
0658     .attrs = snd_ctl_led_card_attrs,
0659 };
0660 
0661 static const struct attribute_group *snd_ctl_led_card_attr_groups[] = {
0662     &snd_ctl_led_card_attr_group,
0663     NULL,
0664 };
0665 
0666 static struct device snd_ctl_led_dev;
0667 
0668 static void snd_ctl_led_sysfs_add(struct snd_card *card)
0669 {
0670     unsigned int group;
0671     struct snd_ctl_led_card *led_card;
0672     struct snd_ctl_led *led;
0673     char link_name[32];
0674 
0675     for (group = 0; group < MAX_LED; group++) {
0676         led = &snd_ctl_leds[group];
0677         led_card = kzalloc(sizeof(*led_card), GFP_KERNEL);
0678         if (!led_card)
0679             goto cerr2;
0680         led_card->number = card->number;
0681         led_card->led = led;
0682         device_initialize(&led_card->dev);
0683         led_card->dev.release = snd_ctl_led_card_release;
0684         if (dev_set_name(&led_card->dev, "card%d", card->number) < 0)
0685             goto cerr;
0686         led_card->dev.parent = &led->dev;
0687         led_card->dev.groups = snd_ctl_led_card_attr_groups;
0688         if (device_add(&led_card->dev))
0689             goto cerr;
0690         led->cards[card->number] = led_card;
0691         snprintf(link_name, sizeof(link_name), "led-%s", led->name);
0692         WARN(sysfs_create_link(&card->ctl_dev.kobj, &led_card->dev.kobj, link_name),
0693             "can't create symlink to controlC%i device\n", card->number);
0694         WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"),
0695             "can't create symlink to card%i\n", card->number);
0696 
0697         continue;
0698 cerr:
0699         put_device(&led_card->dev);
0700 cerr2:
0701         printk(KERN_ERR "snd_ctl_led: unable to add card%d", card->number);
0702     }
0703 }
0704 
0705 static void snd_ctl_led_sysfs_remove(struct snd_card *card)
0706 {
0707     unsigned int group;
0708     struct snd_ctl_led_card *led_card;
0709     struct snd_ctl_led *led;
0710     char link_name[32];
0711 
0712     for (group = 0; group < MAX_LED; group++) {
0713         led = &snd_ctl_leds[group];
0714         led_card = led->cards[card->number];
0715         if (!led_card)
0716             continue;
0717         snprintf(link_name, sizeof(link_name), "led-%s", led->name);
0718         sysfs_remove_link(&card->ctl_dev.kobj, link_name);
0719         sysfs_remove_link(&led_card->dev.kobj, "card");
0720         device_unregister(&led_card->dev);
0721         led->cards[card->number] = NULL;
0722     }
0723 }
0724 
0725 /*
0726  * Control layer registration
0727  */
0728 static struct snd_ctl_layer_ops snd_ctl_led_lops = {
0729     .module_name = SND_CTL_LAYER_MODULE_LED,
0730     .lregister = snd_ctl_led_register,
0731     .ldisconnect = snd_ctl_led_disconnect,
0732     .lnotify = snd_ctl_led_notify,
0733 };
0734 
0735 static int __init snd_ctl_led_init(void)
0736 {
0737     struct snd_ctl_led *led;
0738     unsigned int group;
0739 
0740     device_initialize(&snd_ctl_led_dev);
0741     snd_ctl_led_dev.class = sound_class;
0742     snd_ctl_led_dev.release = snd_ctl_led_dev_release;
0743     dev_set_name(&snd_ctl_led_dev, "ctl-led");
0744     if (device_add(&snd_ctl_led_dev)) {
0745         put_device(&snd_ctl_led_dev);
0746         return -ENOMEM;
0747     }
0748     for (group = 0; group < MAX_LED; group++) {
0749         led = &snd_ctl_leds[group];
0750         INIT_LIST_HEAD(&led->controls);
0751         device_initialize(&led->dev);
0752         led->dev.parent = &snd_ctl_led_dev;
0753         led->dev.release = snd_ctl_led_release;
0754         led->dev.groups = snd_ctl_led_dev_attr_groups;
0755         dev_set_name(&led->dev, led->name);
0756         if (device_add(&led->dev)) {
0757             put_device(&led->dev);
0758             for (; group > 0; group--) {
0759                 led = &snd_ctl_leds[group - 1];
0760                 device_unregister(&led->dev);
0761             }
0762             device_unregister(&snd_ctl_led_dev);
0763             return -ENOMEM;
0764         }
0765     }
0766     snd_ctl_register_layer(&snd_ctl_led_lops);
0767     return 0;
0768 }
0769 
0770 static void __exit snd_ctl_led_exit(void)
0771 {
0772     struct snd_ctl_led *led;
0773     struct snd_card *card;
0774     unsigned int group, card_number;
0775 
0776     snd_ctl_disconnect_layer(&snd_ctl_led_lops);
0777     for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
0778         if (!snd_ctl_led_card_valid[card_number])
0779             continue;
0780         card = snd_card_ref(card_number);
0781         if (card) {
0782             snd_ctl_led_sysfs_remove(card);
0783             snd_card_unref(card);
0784         }
0785     }
0786     for (group = 0; group < MAX_LED; group++) {
0787         led = &snd_ctl_leds[group];
0788         device_unregister(&led->dev);
0789     }
0790     device_unregister(&snd_ctl_led_dev);
0791     snd_ctl_led_clean(NULL);
0792 }
0793 
0794 module_init(snd_ctl_led_init)
0795 module_exit(snd_ctl_led_exit)