Root/package/mac80211/patches/540-ath9k_extra_leds.patch

1--- a/drivers/net/wireless/ath/ath9k/ath9k.h
2+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
3@@ -538,6 +538,9 @@ struct ath9k_wow_pattern {
4 #ifdef CONFIG_MAC80211_LEDS
5 void ath_init_leds(struct ath_softc *sc);
6 void ath_deinit_leds(struct ath_softc *sc);
7+int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
8+ const char *trigger, bool active_low);
9+
10 #else
11 static inline void ath_init_leds(struct ath_softc *sc)
12 {
13@@ -655,6 +658,13 @@ struct ath9k_vif_iter_data {
14     int nadhocs; /* number of adhoc vifs */
15 };
16 
17+struct ath_led {
18+ struct list_head list;
19+ struct ath_softc *sc;
20+ const struct gpio_led *gpio;
21+ struct led_classdev cdev;
22+};
23+
24 struct ath_softc {
25     struct ieee80211_hw *hw;
26     struct device *dev;
27@@ -696,9 +706,8 @@ struct ath_softc {
28     struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
29 
30 #ifdef CONFIG_MAC80211_LEDS
31- bool led_registered;
32- char led_name[32];
33- struct led_classdev led_cdev;
34+ const char *led_default_trigger;
35+ struct list_head leds;
36 #endif
37 
38     struct ath9k_hw_cal_data caldata;
39--- a/drivers/net/wireless/ath/ath9k/gpio.c
40+++ b/drivers/net/wireless/ath/ath9k/gpio.c
41@@ -24,22 +24,89 @@
42 static void ath_led_brightness(struct led_classdev *led_cdev,
43                    enum led_brightness brightness)
44 {
45- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
46- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF));
47+ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
48+ struct ath_softc *sc = led->sc;
49+
50+ ath9k_ps_wakeup(sc);
51+ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
52+ (brightness != LED_OFF) ^ led->gpio->active_low);
53+ ath9k_ps_restore(sc);
54+}
55+
56+static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
57+{
58+ const struct gpio_led *gpio = led->gpio;
59+ int ret;
60+
61+ led->cdev.name = gpio->name;
62+ led->cdev.default_trigger = gpio->default_trigger;
63+ led->cdev.brightness_set = ath_led_brightness;
64+
65+ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev);
66+ if (ret < 0)
67+ return ret;
68+
69+ led->sc = sc;
70+ list_add(&led->list, &sc->leds);
71+
72+ /* Configure gpio for output */
73+ ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
74+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
75+
76+ /* LED off */
77+ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
78+
79+ return 0;
80+}
81+
82+int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
83+ const char *trigger, bool active_low)
84+{
85+ struct ath_led *led;
86+ struct gpio_led *gpio;
87+ char *_name;
88+ int ret;
89+
90+ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
91+ GFP_KERNEL);
92+ if (!led)
93+ return -ENOMEM;
94+
95+ led->gpio = gpio = (struct gpio_led *) (led + 1);
96+ _name = (char *) (led->gpio + 1);
97+
98+ strcpy(_name, name);
99+ gpio->name = _name;
100+ gpio->gpio = gpio_num;
101+ gpio->active_low = active_low;
102+ gpio->default_trigger = trigger;
103+
104+ ret = ath_add_led(sc, led);
105+ if (unlikely(ret < 0))
106+ kfree(led);
107+
108+ return ret;
109 }
110 
111 void ath_deinit_leds(struct ath_softc *sc)
112 {
113- if (!sc->led_registered)
114- return;
115+ struct ath_led *led;
116 
117- ath_led_brightness(&sc->led_cdev, LED_OFF);
118- led_classdev_unregister(&sc->led_cdev);
119+ while (!list_empty(&sc->leds)) {
120+ led = list_first_entry(&sc->leds, struct ath_led, list);
121+ list_del(&led->list);
122+ ath_led_brightness(&led->cdev, LED_OFF);
123+ led_classdev_unregister(&led->cdev);
124+ kfree(led);
125+ }
126 }
127 
128 void ath_init_leds(struct ath_softc *sc)
129 {
130- int ret;
131+ char led_name[32];
132+ const char *trigger;
133+
134+ INIT_LIST_HEAD(&sc->leds);
135 
136     if (AR_SREV_9100(sc->sc_ah))
137         return;
138@@ -57,26 +124,15 @@ void ath_init_leds(struct ath_softc *sc)
139             sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
140     }
141 
142- /* Configure gpio 1 for output */
143- ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
144- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
145- /* LED off, active low */
146- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
147-
148- if (!led_blink)
149- sc->led_cdev.default_trigger =
150- ieee80211_get_radio_led_name(sc->hw);
151-
152- snprintf(sc->led_name, sizeof(sc->led_name),
153- "ath9k-%s", wiphy_name(sc->hw->wiphy));
154- sc->led_cdev.name = sc->led_name;
155- sc->led_cdev.brightness_set = ath_led_brightness;
156+ snprintf(led_name, sizeof(led_name), "ath9k-%s",
157+ wiphy_name(sc->hw->wiphy));
158 
159- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
160- if (ret < 0)
161- return;
162+ if (led_blink)
163+ trigger = sc->led_default_trigger;
164+ else
165+ trigger = ieee80211_get_radio_led_name(sc->hw);
166 
167- sc->led_registered = true;
168+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
169 }
170 #endif
171 
172--- a/drivers/net/wireless/ath/ath9k/init.c
173+++ b/drivers/net/wireless/ath/ath9k/init.c
174@@ -811,7 +811,7 @@ int ath9k_init_device(u16 devid, struct
175 
176 #ifdef CONFIG_MAC80211_LEDS
177     /* must be initialized before ieee80211_register_hw */
178- sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
179+ sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
180         IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
181         ARRAY_SIZE(ath9k_tpt_blink));
182 #endif
183--- a/drivers/net/wireless/ath/ath9k/debug.c
184+++ b/drivers/net/wireless/ath/ath9k/debug.c
185@@ -1255,6 +1255,61 @@ static const struct file_operations fops
186     .llseek = default_llseek,
187 };
188 
189+#ifdef CONFIG_MAC80211_LEDS
190+
191+static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf,
192+ size_t count, loff_t *ppos)
193+{
194+ struct ath_softc *sc = file->private_data;
195+ char buf[32], *str, *name, *c;
196+ ssize_t len;
197+ unsigned int gpio;
198+ bool active_low = false;
199+
200+ len = min(count, sizeof(buf) - 1);
201+ if (copy_from_user(buf, ubuf, len))
202+ return -EFAULT;
203+
204+ buf[len] = '\0';
205+ name = strchr(buf, ',');
206+ if (!name)
207+ return -EINVAL;
208+
209+ *(name++) = 0;
210+ if (!*name)
211+ return -EINVAL;
212+
213+ c = strchr(name, '\n');
214+ if (c)
215+ *c = 0;
216+
217+ str = buf;
218+ if (*str == '!') {
219+ str++;
220+ active_low = true;
221+ }
222+
223+ if (kstrtouint(str, 0, &gpio) < 0)
224+ return -EINVAL;
225+
226+ if (gpio >= sc->sc_ah->caps.num_gpio_pins)
227+ return -EINVAL;
228+
229+ if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0)
230+ return -EINVAL;
231+
232+ return count;
233+}
234+
235+static const struct file_operations fops_gpio_led = {
236+ .write = write_file_gpio_led,
237+ .open = simple_open,
238+ .owner = THIS_MODULE,
239+ .llseek = default_llseek,
240+};
241+
242+#endif
243+
244 #ifdef CONFIG_ATH9K_MAC_DEBUG
245 
246 void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
247@@ -1688,6 +1743,11 @@ int ath9k_init_debug(struct ath_hw *ah)
248                 &fops_samps);
249 #endif
250 
251+#ifdef CONFIG_MAC80211_LEDS
252+ debugfs_create_file("gpio_led", S_IWUSR,
253+ sc->debug.debugfs_phy, sc, &fops_gpio_led);
254+#endif
255+
256     debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
257                sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
258 
259

Archive Download this file



interactive