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

1--- a/drivers/net/wireless/ath/ath9k/ath9k.h
2+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
3@@ -556,6 +556,9 @@ struct ath9k_wow_pattern {
4 void ath_init_leds(struct ath_softc *sc);
5 void ath_deinit_leds(struct ath_softc *sc);
6 void ath_fill_led_pin(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@@ -675,6 +678,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@@ -716,9 +726,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,40 +24,102 @@
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 
139- if (!led_blink)
140- sc->led_cdev.default_trigger =
141- ieee80211_get_radio_led_name(sc->hw);
142-
143- snprintf(sc->led_name, sizeof(sc->led_name),
144- "ath9k-%s", wiphy_name(sc->hw->wiphy));
145- sc->led_cdev.name = sc->led_name;
146- sc->led_cdev.brightness_set = ath_led_brightness;
147+ snprintf(led_name, sizeof(led_name), "ath9k-%s",
148+ wiphy_name(sc->hw->wiphy));
149 
150- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
151- if (ret < 0)
152- return;
153+ if (led_blink)
154+ trigger = sc->led_default_trigger;
155+ else
156+ trigger = ieee80211_get_radio_led_name(sc->hw);
157 
158- sc->led_registered = true;
159+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
160 }
161 
162 void ath_fill_led_pin(struct ath_softc *sc)
163--- a/drivers/net/wireless/ath/ath9k/init.c
164+++ b/drivers/net/wireless/ath/ath9k/init.c
165@@ -878,7 +878,7 @@ int ath9k_init_device(u16 devid, struct
166 
167 #ifdef CONFIG_MAC80211_LEDS
168     /* must be initialized before ieee80211_register_hw */
169- sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
170+ sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
171         IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
172         ARRAY_SIZE(ath9k_tpt_blink));
173 #endif
174--- a/drivers/net/wireless/ath/ath9k/debug.c
175+++ b/drivers/net/wireless/ath/ath9k/debug.c
176@@ -1197,6 +1197,61 @@ static const struct file_operations fops
177     .llseek = default_llseek,
178 };
179 
180+#ifdef CONFIG_MAC80211_LEDS
181+
182+static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf,
183+ size_t count, loff_t *ppos)
184+{
185+ struct ath_softc *sc = file->private_data;
186+ char buf[32], *str, *name, *c;
187+ ssize_t len;
188+ unsigned int gpio;
189+ bool active_low = false;
190+
191+ len = min(count, sizeof(buf) - 1);
192+ if (copy_from_user(buf, ubuf, len))
193+ return -EFAULT;
194+
195+ buf[len] = '\0';
196+ name = strchr(buf, ',');
197+ if (!name)
198+ return -EINVAL;
199+
200+ *(name++) = 0;
201+ if (!*name)
202+ return -EINVAL;
203+
204+ c = strchr(name, '\n');
205+ if (c)
206+ *c = 0;
207+
208+ str = buf;
209+ if (*str == '!') {
210+ str++;
211+ active_low = true;
212+ }
213+
214+ if (kstrtouint(str, 0, &gpio) < 0)
215+ return -EINVAL;
216+
217+ if (gpio >= sc->sc_ah->caps.num_gpio_pins)
218+ return -EINVAL;
219+
220+ if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0)
221+ return -EINVAL;
222+
223+ return count;
224+}
225+
226+static const struct file_operations fops_gpio_led = {
227+ .write = write_file_gpio_led,
228+ .open = simple_open,
229+ .owner = THIS_MODULE,
230+ .llseek = default_llseek,
231+};
232+
233+#endif
234+
235 #ifdef CONFIG_ATH9K_MAC_DEBUG
236 
237 void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
238@@ -1830,6 +1885,10 @@ int ath9k_init_debug(struct ath_hw *ah)
239                 &fops_eeprom);
240     debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
241                 sc, &fops_chanbw);
242+#ifdef CONFIG_MAC80211_LEDS
243+ debugfs_create_file("gpio_led", S_IWUSR,
244+ sc->debug.debugfs_phy, sc, &fops_gpio_led);
245+#endif
246     debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
247                 &fops_dma);
248     debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
249

Archive Download this file



interactive