From patchwork Mon Aug 9 12:29:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 494105 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4380BC4338F for ; Mon, 9 Aug 2021 12:29:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1B72F60F35 for ; Mon, 9 Aug 2021 12:29:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235133AbhHIM3i (ORCPT ); Mon, 9 Aug 2021 08:29:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45852 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234718AbhHIM3i (ORCPT ); Mon, 9 Aug 2021 08:29:38 -0400 Received: from orbyte.nwl.cc (orbyte.nwl.cc [IPv6:2001:41d0:e:133a::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3BF7EC0613D3 for ; Mon, 9 Aug 2021 05:29:18 -0700 (PDT) Received: from localhost ([::1]:48242 helo=xic) by orbyte.nwl.cc with esmtp (Exim 4.94.2) (envelope-from ) id 1mD4P4-0006Je-Q6; Mon, 09 Aug 2021 14:29:14 +0200 From: Phil Sutter To: Pavel Machek Cc: linux-leds@vger.kernel.org Subject: [PATCH] leds: trigger: Add invert attribute to ledtrig-audio Date: Mon, 9 Aug 2021 14:29:10 +0200 Message-Id: <20210809122910.11580-1-phil@nwl.cc> X-Mailer: git-send-email 2.32.0 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Inverting micmute LED used to be possible via a mixer setting, but conversion to LEDs class (probably) killed it. Re-establish the old functionality via sysfs attribute in audio LED triggers. Signed-off-by: Phil Sutter --- drivers/leds/trigger/ledtrig-audio.c | 106 ++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 4 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-audio.c b/drivers/leds/trigger/ledtrig-audio.c index f76621e88482d..319ac4f514dfd 100644 --- a/drivers/leds/trigger/ledtrig-audio.c +++ b/drivers/leds/trigger/ledtrig-audio.c @@ -6,9 +6,12 @@ #include #include #include +#include +#include static struct led_trigger *ledtrig_audio[NUM_AUDIO_LEDS]; static enum led_brightness audio_state[NUM_AUDIO_LEDS]; +static bool led_invert[NUM_AUDIO_LEDS]; enum led_brightness ledtrig_audio_get(enum led_audio type) { @@ -18,17 +21,112 @@ EXPORT_SYMBOL_GPL(ledtrig_audio_get); void ledtrig_audio_set(enum led_audio type, enum led_brightness state) { + if (led_invert[type]) + state = !state; + audio_state[type] = state; led_trigger_event(ledtrig_audio[type], state); } EXPORT_SYMBOL_GPL(ledtrig_audio_set); +static ssize_t do_invert_show(enum led_audio type, char *buf) +{ + return sprintf(buf, "%u\n", led_invert[type]); +} + +static ssize_t mute_invert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return do_invert_show(LED_AUDIO_MUTE, buf); +} + +static ssize_t micmute_invert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return do_invert_show(LED_AUDIO_MICMUTE, buf); +} + +static ssize_t do_invert_store(enum led_audio type, + const char *buf, size_t size) +{ + unsigned long state; + int ret; + + ret = kstrtoul(buf, 0, &state); + if (ret) + return ret; + + led_invert[type] = !!state; + ledtrig_audio_set(type, audio_state[type]); + + return size; +} + +static ssize_t mute_invert_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return do_invert_store(LED_AUDIO_MUTE, buf, size); +} + +static ssize_t micmute_invert_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return do_invert_store(LED_AUDIO_MICMUTE, buf, size); +} + +static struct device_attribute dev_attr_mute_invert = + __ATTR(invert, 0644, mute_invert_show, mute_invert_store); + +static struct attribute *audio_mute_trig_attrs[] = { + &dev_attr_mute_invert.attr, + NULL +}; +ATTRIBUTE_GROUPS(audio_mute_trig); + +static struct device_attribute dev_attr_micmute_invert = + __ATTR(invert, 0644, micmute_invert_show, micmute_invert_store); + +static struct attribute *audio_micmute_trig_attrs[] = { + &dev_attr_micmute_invert.attr, + NULL +}; +ATTRIBUTE_GROUPS(audio_micmute_trig); + +static void __init do_ledtrig_audio_init(const char *name, + enum led_audio type, + const struct attribute_group **groups) +{ + struct led_trigger *trigger; + int err; + + trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (!trigger) { + pr_warn("LED trigger %s failed to register (no memory)\n", + name); + goto out; + } + + trigger->name = name; + trigger->groups = groups; + + err = led_trigger_register(trigger); + if (err < 0) { + kfree(trigger); + trigger = NULL; + pr_warn("LED trigger %s failed to register (%d)\n", name, err); + } +out: + ledtrig_audio[type] = trigger; +} + static int __init ledtrig_audio_init(void) { - led_trigger_register_simple("audio-mute", - &ledtrig_audio[LED_AUDIO_MUTE]); - led_trigger_register_simple("audio-micmute", - &ledtrig_audio[LED_AUDIO_MICMUTE]); + do_ledtrig_audio_init("audio-mute", LED_AUDIO_MUTE, + audio_mute_trig_groups); + do_ledtrig_audio_init("audio-micmute", LED_AUDIO_MICMUTE, + audio_micmute_trig_groups); return 0; } module_init(ledtrig_audio_init);