[PATCH 0/5] ALSA: control - add generic LED trigger code

Jaroslav Kysela perex at perex.cz
Mon Feb 15 13:35:23 CET 2021


Dne 15. 02. 21 v 13:02 Hans de Goede napsal(a):
> Hi,
> 
> On 2/12/21 9:31 PM, Hans de Goede wrote:
>> On 2/11/21 12:13 PM, Jaroslav Kysela wrote:
> 
> <snip>
> 
>>> The sound driver implementation is really easy:
>>>
>>> 1) call snd_ctl_led_request() when control LED layer should be
>>>    automatically activated
>>>    / it calls module_request("snd-ctl-led") on demand /
>>> 2) mark all related kcontrols with
>>> 	SNDRV_CTL_ELEM_ACCESS_SPK_LED or
>>> 	SNDRV_CTL_ELEM_ACCESS_MIC_LED
>>
>> So I've been running some tests with this,combined with writing
>> UCM profiles for hw volume control, for some Intel Bay- and
>> CherryTrail devices using Intel's Low Power Engine (LPE) for audio,
>> which uses the ASoC framework.
>>
>> My work / experiments for this are progressing a bit slower then I
>> would like, but that is not the fault of this patch-set, but rather
>> an issue with hw-volume control mapping, see below for details.
>>
>> Leaving the ASoC implementation details aside, this patch-set
>> works quite nicely to get the speaker mute-LED to work.
> 
> I've spend some more time this weekend playing with this and I've also
> added mic MUTE LED support for the ASoC rt5672 codec driver now using
> this.
> 
> I will post a RFC patch series with the ASoC rt5672 codec driver LED
> support soon, as adding an extra use-case for this will hopefully help
> with reviewing this.
> 
> FWIW there were some challenges, but those were not related to the
> driver API this patch set adds. The driver API works well for ASoC
> codec drivers.
> 
> Regards,
> 
> Hans
> 
> 
> p.s.
> 
> One open issue is the lockdep issue which I reported in my
> previous email.

Thank you for tests, Hans. I'm working on the lockdep issue - I'll send v2 of the LED patchset soon.

The actual diff (I'd like to do more tests):

diff --git a/sound/core/control.c b/sound/core/control.c
index 4647b3cd41e8..c9f062fada0a 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -2047,6 +2047,7 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
 	down_write(&snd_ctl_layer_rwsem);
 	lops->next = snd_ctl_layer;
 	snd_ctl_layer = lops;
+	up_write(&snd_ctl_layer_rwsem);
 	for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
 		card = snd_card_ref(card_number);
 		if (card) {
@@ -2054,7 +2055,6 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
 			snd_card_unref(card);
 		}
 	}
-	up_write(&snd_ctl_layer_rwsem);
 }
 EXPORT_SYMBOL_GPL(snd_ctl_register_layer);
 
diff --git a/sound/core/control_led.c b/sound/core/control_led.c
index 638808e397fe..093dce721024 100644
--- a/sound/core/control_led.c
+++ b/sound/core/control_led.c
@@ -75,7 +75,7 @@ static inline unsigned int group_to_access(unsigned int group)
 	return (group + 1) << SNDRV_CTL_ELEM_ACCESS_LED_SHIFT;
 }
 
-struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access)
+static struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access)
 {
 	unsigned int group = access_to_group(access);
 	if (group >= MAX_LED)
@@ -116,15 +116,20 @@ static int snd_ctl_led_get(struct snd_ctl_led_ctl *lctl)
 	return 0;
 }
 
-static int snd_ctl_led_get_lock(struct snd_ctl_led_ctl *lctl)
+static int snd_ctl_led_get_lock(struct snd_card *ncard, struct snd_ctl_led_ctl *lctl)
 {
 	struct snd_card *card = lctl->card;
 	int route;
 
-	down_read(&card->controls_rwsem);
-	route = snd_ctl_led_get(lctl);
-	up_read(&card->controls_rwsem);
-	return route;
+	/* the rwsem is already taken for the notification card */
+	if (ncard != card) {
+		down_read(&card->controls_rwsem);
+		route = snd_ctl_led_get(lctl);
+		up_read(&card->controls_rwsem);
+		return route;
+	} else {
+		return snd_ctl_led_get(lctl);
+	}
 }
 
 static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
@@ -149,7 +154,7 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
 	list_for_each_entry(lctl, &led->controls, list) {
 		if (lctl->kctl == kctl && lctl->index_offset == ioff)
 			found = true;
-		UPDATE_ROUTE(route, snd_ctl_led_get_lock(lctl));
+		UPDATE_ROUTE(route, snd_ctl_led_get_lock(card, lctl));
 	}
 	if (!found && kctl && card) {
 		lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
@@ -158,7 +163,7 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
 			lctl->kctl = kctl;
 			lctl->index_offset = ioff;
 			list_add(&lctl->list, &led->controls);
-			UPDATE_ROUTE(route, snd_ctl_led_get_lock(lctl));
+			UPDATE_ROUTE(route, snd_ctl_led_get_lock(card, lctl));
 		}
 	}
 	mutex_unlock(&snd_ctl_led_mutex);
@@ -246,10 +251,11 @@ static void snd_ctl_led_register(struct snd_card *card)
 	mutex_lock(&snd_ctl_led_mutex);
 	snd_ctl_led_card_valid[card->number] = true;
 	mutex_unlock(&snd_ctl_led_mutex);
-	/* the register callback is already called with held rwsem for controls */
+	down_read(&card->controls_rwsem);
 	list_for_each_entry(kctl, &card->controls, list)
 		for (ioff = 0; ioff < kctl->count; ioff++)
 			snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff);
+	up_read(&card->controls_rwsem);
 	snd_ctl_led_refresh();
 }
 
@@ -262,17 +268,6 @@ static void snd_ctl_led_disconnect(struct snd_card *card)
 	snd_ctl_led_refresh();
 }
 
-/**
- * snd_ctl_led_hello - kernel module reference helper
- *
- * Call this helper in the module init function when the control LED
- * code should be activated for the given driver.
- */
-void snd_ctl_led_hello(void)
-{
-}
-EXPORT_SYMBOL(snd_ctl_led_hello);
-
 /*
  * sysfs
  */


					Jaroslav

-- 
Jaroslav Kysela <perex at perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.


More information about the Alsa-devel mailing list