18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/* just for IFNAMSIZ */
78c2ecf20Sopenharmony_ci#include <linux/if.h>
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/export.h>
108c2ecf20Sopenharmony_ci#include "led.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_civoid ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	if (!atomic_read(&local->assoc_led_active))
158c2ecf20Sopenharmony_ci		return;
168c2ecf20Sopenharmony_ci	if (associated)
178c2ecf20Sopenharmony_ci		led_trigger_event(&local->assoc_led, LED_FULL);
188c2ecf20Sopenharmony_ci	else
198c2ecf20Sopenharmony_ci		led_trigger_event(&local->assoc_led, LED_OFF);
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_civoid ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	if (!atomic_read(&local->radio_led_active))
258c2ecf20Sopenharmony_ci		return;
268c2ecf20Sopenharmony_ci	if (enabled)
278c2ecf20Sopenharmony_ci		led_trigger_event(&local->radio_led, LED_FULL);
288c2ecf20Sopenharmony_ci	else
298c2ecf20Sopenharmony_ci		led_trigger_event(&local->radio_led, LED_OFF);
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_civoid ieee80211_alloc_led_names(struct ieee80211_local *local)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	local->rx_led.name = kasprintf(GFP_KERNEL, "%srx",
358c2ecf20Sopenharmony_ci				       wiphy_name(local->hw.wiphy));
368c2ecf20Sopenharmony_ci	local->tx_led.name = kasprintf(GFP_KERNEL, "%stx",
378c2ecf20Sopenharmony_ci				       wiphy_name(local->hw.wiphy));
388c2ecf20Sopenharmony_ci	local->assoc_led.name = kasprintf(GFP_KERNEL, "%sassoc",
398c2ecf20Sopenharmony_ci					  wiphy_name(local->hw.wiphy));
408c2ecf20Sopenharmony_ci	local->radio_led.name = kasprintf(GFP_KERNEL, "%sradio",
418c2ecf20Sopenharmony_ci					  wiphy_name(local->hw.wiphy));
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_civoid ieee80211_free_led_names(struct ieee80211_local *local)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	kfree(local->rx_led.name);
478c2ecf20Sopenharmony_ci	kfree(local->tx_led.name);
488c2ecf20Sopenharmony_ci	kfree(local->assoc_led.name);
498c2ecf20Sopenharmony_ci	kfree(local->radio_led.name);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic int ieee80211_tx_led_activate(struct led_classdev *led_cdev)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
558c2ecf20Sopenharmony_ci						     struct ieee80211_local,
568c2ecf20Sopenharmony_ci						     tx_led);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	atomic_inc(&local->tx_led_active);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	return 0;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic void ieee80211_tx_led_deactivate(struct led_classdev *led_cdev)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
668c2ecf20Sopenharmony_ci						     struct ieee80211_local,
678c2ecf20Sopenharmony_ci						     tx_led);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	atomic_dec(&local->tx_led_active);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int ieee80211_rx_led_activate(struct led_classdev *led_cdev)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
758c2ecf20Sopenharmony_ci						     struct ieee80211_local,
768c2ecf20Sopenharmony_ci						     rx_led);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	atomic_inc(&local->rx_led_active);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return 0;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void ieee80211_rx_led_deactivate(struct led_classdev *led_cdev)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
868c2ecf20Sopenharmony_ci						     struct ieee80211_local,
878c2ecf20Sopenharmony_ci						     rx_led);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	atomic_dec(&local->rx_led_active);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int ieee80211_assoc_led_activate(struct led_classdev *led_cdev)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
958c2ecf20Sopenharmony_ci						     struct ieee80211_local,
968c2ecf20Sopenharmony_ci						     assoc_led);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	atomic_inc(&local->assoc_led_active);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic void ieee80211_assoc_led_deactivate(struct led_classdev *led_cdev)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
1068c2ecf20Sopenharmony_ci						     struct ieee80211_local,
1078c2ecf20Sopenharmony_ci						     assoc_led);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	atomic_dec(&local->assoc_led_active);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int ieee80211_radio_led_activate(struct led_classdev *led_cdev)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
1158c2ecf20Sopenharmony_ci						     struct ieee80211_local,
1168c2ecf20Sopenharmony_ci						     radio_led);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	atomic_inc(&local->radio_led_active);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return 0;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic void ieee80211_radio_led_deactivate(struct led_classdev *led_cdev)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
1268c2ecf20Sopenharmony_ci						     struct ieee80211_local,
1278c2ecf20Sopenharmony_ci						     radio_led);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	atomic_dec(&local->radio_led_active);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int ieee80211_tpt_led_activate(struct led_classdev *led_cdev)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
1358c2ecf20Sopenharmony_ci						     struct ieee80211_local,
1368c2ecf20Sopenharmony_ci						     tpt_led);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	atomic_inc(&local->tpt_led_active);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return 0;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic void ieee80211_tpt_led_deactivate(struct led_classdev *led_cdev)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct ieee80211_local *local = container_of(led_cdev->trigger,
1468c2ecf20Sopenharmony_ci						     struct ieee80211_local,
1478c2ecf20Sopenharmony_ci						     tpt_led);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	atomic_dec(&local->tpt_led_active);
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_civoid ieee80211_led_init(struct ieee80211_local *local)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	atomic_set(&local->rx_led_active, 0);
1558c2ecf20Sopenharmony_ci	local->rx_led.activate = ieee80211_rx_led_activate;
1568c2ecf20Sopenharmony_ci	local->rx_led.deactivate = ieee80211_rx_led_deactivate;
1578c2ecf20Sopenharmony_ci	if (local->rx_led.name && led_trigger_register(&local->rx_led)) {
1588c2ecf20Sopenharmony_ci		kfree(local->rx_led.name);
1598c2ecf20Sopenharmony_ci		local->rx_led.name = NULL;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	atomic_set(&local->tx_led_active, 0);
1638c2ecf20Sopenharmony_ci	local->tx_led.activate = ieee80211_tx_led_activate;
1648c2ecf20Sopenharmony_ci	local->tx_led.deactivate = ieee80211_tx_led_deactivate;
1658c2ecf20Sopenharmony_ci	if (local->tx_led.name && led_trigger_register(&local->tx_led)) {
1668c2ecf20Sopenharmony_ci		kfree(local->tx_led.name);
1678c2ecf20Sopenharmony_ci		local->tx_led.name = NULL;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	atomic_set(&local->assoc_led_active, 0);
1718c2ecf20Sopenharmony_ci	local->assoc_led.activate = ieee80211_assoc_led_activate;
1728c2ecf20Sopenharmony_ci	local->assoc_led.deactivate = ieee80211_assoc_led_deactivate;
1738c2ecf20Sopenharmony_ci	if (local->assoc_led.name && led_trigger_register(&local->assoc_led)) {
1748c2ecf20Sopenharmony_ci		kfree(local->assoc_led.name);
1758c2ecf20Sopenharmony_ci		local->assoc_led.name = NULL;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	atomic_set(&local->radio_led_active, 0);
1798c2ecf20Sopenharmony_ci	local->radio_led.activate = ieee80211_radio_led_activate;
1808c2ecf20Sopenharmony_ci	local->radio_led.deactivate = ieee80211_radio_led_deactivate;
1818c2ecf20Sopenharmony_ci	if (local->radio_led.name && led_trigger_register(&local->radio_led)) {
1828c2ecf20Sopenharmony_ci		kfree(local->radio_led.name);
1838c2ecf20Sopenharmony_ci		local->radio_led.name = NULL;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	atomic_set(&local->tpt_led_active, 0);
1878c2ecf20Sopenharmony_ci	if (local->tpt_led_trigger) {
1888c2ecf20Sopenharmony_ci		local->tpt_led.activate = ieee80211_tpt_led_activate;
1898c2ecf20Sopenharmony_ci		local->tpt_led.deactivate = ieee80211_tpt_led_deactivate;
1908c2ecf20Sopenharmony_ci		if (led_trigger_register(&local->tpt_led)) {
1918c2ecf20Sopenharmony_ci			kfree(local->tpt_led_trigger);
1928c2ecf20Sopenharmony_ci			local->tpt_led_trigger = NULL;
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_civoid ieee80211_led_exit(struct ieee80211_local *local)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	if (local->radio_led.name)
2008c2ecf20Sopenharmony_ci		led_trigger_unregister(&local->radio_led);
2018c2ecf20Sopenharmony_ci	if (local->assoc_led.name)
2028c2ecf20Sopenharmony_ci		led_trigger_unregister(&local->assoc_led);
2038c2ecf20Sopenharmony_ci	if (local->tx_led.name)
2048c2ecf20Sopenharmony_ci		led_trigger_unregister(&local->tx_led);
2058c2ecf20Sopenharmony_ci	if (local->rx_led.name)
2068c2ecf20Sopenharmony_ci		led_trigger_unregister(&local->rx_led);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if (local->tpt_led_trigger) {
2098c2ecf20Sopenharmony_ci		led_trigger_unregister(&local->tpt_led);
2108c2ecf20Sopenharmony_ci		kfree(local->tpt_led_trigger);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ciconst char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return local->radio_led.name;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ieee80211_get_radio_led_name);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ciconst char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return local->assoc_led.name;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ciconst char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return local->tx_led.name;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ieee80211_get_tx_led_name);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ciconst char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	return local->rx_led.name;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ieee80211_get_rx_led_name);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic unsigned long tpt_trig_traffic(struct ieee80211_local *local,
2478c2ecf20Sopenharmony_ci				      struct tpt_led_trigger *tpt_trig)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	unsigned long traffic, delta;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	delta = traffic - tpt_trig->prev_traffic;
2548c2ecf20Sopenharmony_ci	tpt_trig->prev_traffic = traffic;
2558c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(delta, 1024 / 8);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic void tpt_trig_timer(struct timer_list *t)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct tpt_led_trigger *tpt_trig = from_timer(tpt_trig, t, timer);
2618c2ecf20Sopenharmony_ci	struct ieee80211_local *local = tpt_trig->local;
2628c2ecf20Sopenharmony_ci	struct led_classdev *led_cdev;
2638c2ecf20Sopenharmony_ci	unsigned long on, off, tpt;
2648c2ecf20Sopenharmony_ci	int i;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (!tpt_trig->running)
2678c2ecf20Sopenharmony_ci		return;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	tpt = tpt_trig_traffic(local, tpt_trig);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* default to just solid on */
2748c2ecf20Sopenharmony_ci	on = 1;
2758c2ecf20Sopenharmony_ci	off = 0;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
2788c2ecf20Sopenharmony_ci		if (tpt_trig->blink_table[i].throughput < 0 ||
2798c2ecf20Sopenharmony_ci		    tpt > tpt_trig->blink_table[i].throughput) {
2808c2ecf20Sopenharmony_ci			off = tpt_trig->blink_table[i].blink_time / 2;
2818c2ecf20Sopenharmony_ci			on = tpt_trig->blink_table[i].blink_time - off;
2828c2ecf20Sopenharmony_ci			break;
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	read_lock(&local->tpt_led.leddev_list_lock);
2878c2ecf20Sopenharmony_ci	list_for_each_entry(led_cdev, &local->tpt_led.led_cdevs, trig_list)
2888c2ecf20Sopenharmony_ci		led_blink_set(led_cdev, &on, &off);
2898c2ecf20Sopenharmony_ci	read_unlock(&local->tpt_led.leddev_list_lock);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ciconst char *
2938c2ecf20Sopenharmony_ci__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
2948c2ecf20Sopenharmony_ci				   unsigned int flags,
2958c2ecf20Sopenharmony_ci				   const struct ieee80211_tpt_blink *blink_table,
2968c2ecf20Sopenharmony_ci				   unsigned int blink_table_len)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
2998c2ecf20Sopenharmony_ci	struct tpt_led_trigger *tpt_trig;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (WARN_ON(local->tpt_led_trigger))
3028c2ecf20Sopenharmony_ci		return NULL;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
3058c2ecf20Sopenharmony_ci	if (!tpt_trig)
3068c2ecf20Sopenharmony_ci		return NULL;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	snprintf(tpt_trig->name, sizeof(tpt_trig->name),
3098c2ecf20Sopenharmony_ci		 "%stpt", wiphy_name(local->hw.wiphy));
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	local->tpt_led.name = tpt_trig->name;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	tpt_trig->blink_table = blink_table;
3148c2ecf20Sopenharmony_ci	tpt_trig->blink_table_len = blink_table_len;
3158c2ecf20Sopenharmony_ci	tpt_trig->want = flags;
3168c2ecf20Sopenharmony_ci	tpt_trig->local = local;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	timer_setup(&tpt_trig->timer, tpt_trig_timer, 0);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	local->tpt_led_trigger = tpt_trig;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return tpt_trig->name;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (tpt_trig->running)
3318c2ecf20Sopenharmony_ci		return;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* reset traffic */
3348c2ecf20Sopenharmony_ci	tpt_trig_traffic(local, tpt_trig);
3358c2ecf20Sopenharmony_ci	tpt_trig->running = true;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	tpt_trig_timer(&tpt_trig->timer);
3388c2ecf20Sopenharmony_ci	mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
3448c2ecf20Sopenharmony_ci	struct led_classdev *led_cdev;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (!tpt_trig->running)
3478c2ecf20Sopenharmony_ci		return;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	tpt_trig->running = false;
3508c2ecf20Sopenharmony_ci	del_timer_sync(&tpt_trig->timer);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	read_lock(&local->tpt_led.leddev_list_lock);
3538c2ecf20Sopenharmony_ci	list_for_each_entry(led_cdev, &local->tpt_led.led_cdevs, trig_list)
3548c2ecf20Sopenharmony_ci		led_set_brightness(led_cdev, LED_OFF);
3558c2ecf20Sopenharmony_ci	read_unlock(&local->tpt_led.leddev_list_lock);
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_civoid ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
3598c2ecf20Sopenharmony_ci				unsigned int types_on, unsigned int types_off)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
3628c2ecf20Sopenharmony_ci	bool allowed;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	WARN_ON(types_on & types_off);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (!tpt_trig)
3678c2ecf20Sopenharmony_ci		return;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	tpt_trig->active &= ~types_off;
3708c2ecf20Sopenharmony_ci	tpt_trig->active |= types_on;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/*
3738c2ecf20Sopenharmony_ci	 * Regardless of wanted state, we shouldn't blink when
3748c2ecf20Sopenharmony_ci	 * the radio is disabled -- this can happen due to some
3758c2ecf20Sopenharmony_ci	 * code ordering issues with __ieee80211_recalc_idle()
3768c2ecf20Sopenharmony_ci	 * being called before the radio is started.
3778c2ecf20Sopenharmony_ci	 */
3788c2ecf20Sopenharmony_ci	allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (!allowed || !(tpt_trig->active & tpt_trig->want))
3818c2ecf20Sopenharmony_ci		ieee80211_stop_tpt_led_trig(local);
3828c2ecf20Sopenharmony_ci	else
3838c2ecf20Sopenharmony_ci		ieee80211_start_tpt_led_trig(local);
3848c2ecf20Sopenharmony_ci}
385