1f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc/*
2f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
3f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc *
4f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * This program is free software; you can redistribute it and/or modify
5f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * it under the terms of the GNU General Public License version 2 as
6f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * published by the Free Software Foundation.
7f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc */
8f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
9f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc/* just for IFNAMSIZ */
10f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/if.h>
115a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
12bc3b2d7fb9b014d75ebb79ba371a763dbab5e8cfPaul Gortmaker#include <linux/export.h>
132c8dccc77420fb7433da5674818959d3499d35beJohannes Berg#include "led.h"
14f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
15e47f2509e5f182f4df144406de6f2bc78179d57eFabio Baltieri#define MAC80211_BLINK_DELAY 50 /* ms */
16e47f2509e5f182f4df144406de6f2bc78179d57eFabio Baltieri
17f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Bencvoid ieee80211_led_rx(struct ieee80211_local *local)
18f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
19e47f2509e5f182f4df144406de6f2bc78179d57eFabio Baltieri	unsigned long led_delay = MAC80211_BLINK_DELAY;
20f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	if (unlikely(!local->rx_led))
21f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		return;
22e47f2509e5f182f4df144406de6f2bc78179d57eFabio Baltieri	led_trigger_blink_oneshot(local->rx_led, &led_delay, &led_delay, 0);
23f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
24f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
25e47f2509e5f182f4df144406de6f2bc78179d57eFabio Baltierivoid ieee80211_led_tx(struct ieee80211_local *local)
26f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
27e47f2509e5f182f4df144406de6f2bc78179d57eFabio Baltieri	unsigned long led_delay = MAC80211_BLINK_DELAY;
28f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	if (unlikely(!local->tx_led))
29f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		return;
30e47f2509e5f182f4df144406de6f2bc78179d57eFabio Baltieri	led_trigger_blink_oneshot(local->tx_led, &led_delay, &led_delay, 0);
31f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
32f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
3347f0c502209056da728e6a306a43d5e19a37f4faMichael Bueschvoid ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
3447f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch{
3547f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	if (unlikely(!local->assoc_led))
3647f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		return;
3747f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	if (associated)
3847f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		led_trigger_event(local->assoc_led, LED_FULL);
3947f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	else
4047f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		led_trigger_event(local->assoc_led, LED_OFF);
4147f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch}
4247f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch
43cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doornvoid ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
44cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn{
45cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	if (unlikely(!local->radio_led))
46cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn		return;
47cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	if (enabled)
48cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn		led_trigger_event(local->radio_led, LED_FULL);
49cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	else
50cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn		led_trigger_event(local->radio_led, LED_OFF);
51cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn}
52cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn
53fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Bergvoid ieee80211_led_names(struct ieee80211_local *local)
54fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg{
55fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg	snprintf(local->rx_led_name, sizeof(local->rx_led_name),
56fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg		 "%srx", wiphy_name(local->hw.wiphy));
57fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg	snprintf(local->tx_led_name, sizeof(local->tx_led_name),
58fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg		 "%stx", wiphy_name(local->hw.wiphy));
59fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg	snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
60fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg		 "%sassoc", wiphy_name(local->hw.wiphy));
61fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg	snprintf(local->radio_led_name, sizeof(local->radio_led_name),
62fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg		 "%sradio", wiphy_name(local->hw.wiphy));
63fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg}
64fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg
65f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Bencvoid ieee80211_led_init(struct ieee80211_local *local)
66f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
67f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
6847f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	if (local->rx_led) {
6947f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		local->rx_led->name = local->rx_led_name;
7047f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		if (led_trigger_register(local->rx_led)) {
7147f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch			kfree(local->rx_led);
7247f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch			local->rx_led = NULL;
7347f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		}
74f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	}
75f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
76f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
7747f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	if (local->tx_led) {
7847f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		local->tx_led->name = local->tx_led_name;
7947f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		if (led_trigger_register(local->tx_led)) {
8047f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch			kfree(local->tx_led);
8147f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch			local->tx_led = NULL;
8247f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		}
8347f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	}
8447f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch
8547f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
8647f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	if (local->assoc_led) {
8747f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		local->assoc_led->name = local->assoc_led_name;
8847f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		if (led_trigger_register(local->assoc_led)) {
8947f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch			kfree(local->assoc_led);
9047f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch			local->assoc_led = NULL;
9147f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		}
92f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	}
93cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn
94cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
95cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	if (local->radio_led) {
96cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn		local->radio_led->name = local->radio_led_name;
97cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn		if (led_trigger_register(local->radio_led)) {
98cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn			kfree(local->radio_led);
99cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn			local->radio_led = NULL;
100cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn		}
101cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	}
102e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
103e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	if (local->tpt_led_trigger) {
104e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		if (led_trigger_register(&local->tpt_led_trigger->trig)) {
105e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg			kfree(local->tpt_led_trigger);
106e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg			local->tpt_led_trigger = NULL;
107e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		}
108e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	}
109f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
110f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
111f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Bencvoid ieee80211_led_exit(struct ieee80211_local *local)
112f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
113cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	if (local->radio_led) {
114cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn		led_trigger_unregister(local->radio_led);
115cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn		kfree(local->radio_led);
116cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	}
11747f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	if (local->assoc_led) {
11847f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		led_trigger_unregister(local->assoc_led);
11947f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch		kfree(local->assoc_led);
12047f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	}
121f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	if (local->tx_led) {
122f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		led_trigger_unregister(local->tx_led);
123f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		kfree(local->tx_led);
124f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	}
125f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	if (local->rx_led) {
126f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		led_trigger_unregister(local->rx_led);
127f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		kfree(local->rx_led);
128f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	}
129e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
130e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	if (local->tpt_led_trigger) {
131e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		led_trigger_unregister(&local->tpt_led_trigger->trig);
132e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		kfree(local->tpt_led_trigger);
133e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	}
134f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
135f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
136cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doornchar *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
137cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn{
138cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn	struct ieee80211_local *local = hw_to_local(hw);
139cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn
140fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg	return local->radio_led_name;
141cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn}
142cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van DoornEXPORT_SYMBOL(__ieee80211_get_radio_led_name);
143cdcb006fbe7a74b5f7827f5c5c27e11399a2fab7Ivo van Doorn
14447f0c502209056da728e6a306a43d5e19a37f4faMichael Bueschchar *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
14547f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch{
14647f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch	struct ieee80211_local *local = hw_to_local(hw);
14747f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch
148fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg	return local->assoc_led_name;
14947f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch}
15047f0c502209056da728e6a306a43d5e19a37f4faMichael BueschEXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
15147f0c502209056da728e6a306a43d5e19a37f4faMichael Buesch
152f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Bencchar *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
153f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
154f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_local *local = hw_to_local(hw);
155f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
156fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg	return local->tx_led_name;
157f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
158f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri BencEXPORT_SYMBOL(__ieee80211_get_tx_led_name);
159f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
160f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Bencchar *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
161f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
162f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_local *local = hw_to_local(hw);
163f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
164fe67c913f1ec2a01aaa9176c80ef36eaf87d705dJohannes Berg	return local->rx_led_name;
165f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
166f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri BencEXPORT_SYMBOL(__ieee80211_get_rx_led_name);
167e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
168e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Bergstatic unsigned long tpt_trig_traffic(struct ieee80211_local *local,
169e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg				      struct tpt_led_trigger *tpt_trig)
170e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg{
171e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	unsigned long traffic, delta;
172e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
173e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
174e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
175e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	delta = traffic - tpt_trig->prev_traffic;
176e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig->prev_traffic = traffic;
177e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	return DIV_ROUND_UP(delta, 1024 / 8);
178e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg}
179e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
180e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Bergstatic void tpt_trig_timer(unsigned long data)
181e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg{
182e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	struct ieee80211_local *local = (void *)data;
183e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
184e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	struct led_classdev *led_cdev;
185e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	unsigned long on, off, tpt;
186e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	int i;
187e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
188e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	if (!tpt_trig->running)
189e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		return;
190e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
191e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
192e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
193e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt = tpt_trig_traffic(local, tpt_trig);
194e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
195e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	/* default to just solid on */
196e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	on = 1;
197e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	off = 0;
198e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
199e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
200e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		if (tpt_trig->blink_table[i].throughput < 0 ||
201e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		    tpt > tpt_trig->blink_table[i].throughput) {
202e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg			off = tpt_trig->blink_table[i].blink_time / 2;
203e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg			on = tpt_trig->blink_table[i].blink_time - off;
204e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg			break;
205e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		}
206e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	}
207e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
208e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	read_lock(&tpt_trig->trig.leddev_list_lock);
209e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
210e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		led_blink_set(led_cdev, &on, &off);
211e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	read_unlock(&tpt_trig->trig.leddev_list_lock);
212e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg}
213e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
21406778b1c383afbdb88ffd837e117bec06a76f450Johannes Bergchar *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
21506778b1c383afbdb88ffd837e117bec06a76f450Johannes Berg				unsigned int flags,
216e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg				const struct ieee80211_tpt_blink *blink_table,
217e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg				unsigned int blink_table_len)
218e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg{
219e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	struct ieee80211_local *local = hw_to_local(hw);
220e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	struct tpt_led_trigger *tpt_trig;
221e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
222e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	if (WARN_ON(local->tpt_led_trigger))
223e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		return NULL;
224e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
225e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
226e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	if (!tpt_trig)
227e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		return NULL;
228e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
229e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	snprintf(tpt_trig->name, sizeof(tpt_trig->name),
230e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		 "%stpt", wiphy_name(local->hw.wiphy));
231e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
232e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig->trig.name = tpt_trig->name;
233e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
234e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig->blink_table = blink_table;
235e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig->blink_table_len = blink_table_len;
23667408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	tpt_trig->want = flags;
237e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
238e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local);
239e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
240e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	local->tpt_led_trigger = tpt_trig;
241e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
242e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	return tpt_trig->name;
243e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg}
244e1e5406854378dfada3f33c7192b012083a5b8e0Johannes BergEXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger);
245e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
24667408c8c7b9daf28b50e33be3541334c07d15789Johannes Bergstatic void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
247e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg{
248e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
249e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
25067408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	if (tpt_trig->running)
251e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		return;
252e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
253e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	/* reset traffic */
254e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig_traffic(local, tpt_trig);
255e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig->running = true;
256e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
257e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig_timer((unsigned long)local);
258e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
259e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg}
260e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
26167408c8c7b9daf28b50e33be3541334c07d15789Johannes Bergstatic void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
262e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg{
263e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
264e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	struct led_classdev *led_cdev;
265e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
26667408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	if (!tpt_trig->running)
267e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg		return;
268e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
269e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	tpt_trig->running = false;
270e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	del_timer_sync(&tpt_trig->timer);
271e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg
272e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	read_lock(&tpt_trig->trig.leddev_list_lock);
273e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
27419cd67e2d51225b164560b54b85f943e07deee8aShuah Khan		led_set_brightness(led_cdev, LED_OFF);
275e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg	read_unlock(&tpt_trig->trig.leddev_list_lock);
276e1e5406854378dfada3f33c7192b012083a5b8e0Johannes Berg}
27767408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg
27867408c8c7b9daf28b50e33be3541334c07d15789Johannes Bergvoid ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
27967408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg				unsigned int types_on, unsigned int types_off)
28067408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg{
28167408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
28267408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	bool allowed;
28367408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg
28467408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	WARN_ON(types_on & types_off);
28567408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg
28667408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	if (!tpt_trig)
28767408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg		return;
28867408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg
28967408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	tpt_trig->active &= ~types_off;
29067408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	tpt_trig->active |= types_on;
29167408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg
29267408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	/*
29367408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	 * Regardless of wanted state, we shouldn't blink when
29467408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	 * the radio is disabled -- this can happen due to some
29567408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	 * code ordering issues with __ieee80211_recalc_idle()
29667408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	 * being called before the radio is started.
29767408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	 */
29867408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO;
29967408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg
30067408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	if (!allowed || !(tpt_trig->active & tpt_trig->want))
30167408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg		ieee80211_stop_tpt_led_trig(local);
30267408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg	else
30367408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg		ieee80211_start_tpt_led_trig(local);
30467408c8c7b9daf28b50e33be3541334c07d15789Johannes Berg}
305