control_led.c 20 KB

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