1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42#include <linux/pci.h>
43#include "ath5k.h"
44
45#define ATH_SDEVICE(subv, subd) \
46 .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
47 .subvendor = (subv), .subdevice = (subd)
48
49#define ATH_LED(pin, polarity) .driver_data = (((pin) << 8) | (polarity))
50#define ATH_PIN(data) ((data) >> 8)
51#define ATH_POLARITY(data) ((data) & 0xff)
52
53
54static DEFINE_PCI_DEVICE_TABLE(ath5k_led_devices) = {
55
56 { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) },
57
58 { ATH_SDEVICE(PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID), ATH_LED(1, 1) },
59
60 { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe008), ATH_LED(3, 0) },
61
62 { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe00d), ATH_LED(3, 0) },
63
64 { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0422), ATH_LED(1, 1) },
65
66 { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) },
67
68 { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0100), ATH_LED(1, 0) },
69
70 { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) },
71
72 { ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) },
73
74 { ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) },
75
76 { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) },
77
78 { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) },
79
80 { ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) },
81
82 { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) },
83
84 { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0112), ATH_LED(3, 0) },
85 { }
86};
87
88void ath5k_led_enable(struct ath5k_hw *ah)
89{
90 if (test_bit(ATH_STAT_LEDSOFT, ah->status)) {
91 ath5k_hw_set_gpio_output(ah, ah->led_pin);
92 ath5k_led_off(ah);
93 }
94}
95
96static void ath5k_led_on(struct ath5k_hw *ah)
97{
98 if (!test_bit(ATH_STAT_LEDSOFT, ah->status))
99 return;
100 ath5k_hw_set_gpio(ah, ah->led_pin, ah->led_on);
101}
102
103void ath5k_led_off(struct ath5k_hw *ah)
104{
105 if (!test_bit(ATH_STAT_LEDSOFT, ah->status))
106 return;
107 ath5k_hw_set_gpio(ah, ah->led_pin, !ah->led_on);
108}
109
110static void
111ath5k_led_brightness_set(struct led_classdev *led_dev,
112 enum led_brightness brightness)
113{
114 struct ath5k_led *led = container_of(led_dev, struct ath5k_led,
115 led_dev);
116
117 if (brightness == LED_OFF)
118 ath5k_led_off(led->ah);
119 else
120 ath5k_led_on(led->ah);
121}
122
123static int
124ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
125 const char *name, char *trigger)
126{
127 int err;
128
129 led->ah = ah;
130 strncpy(led->name, name, sizeof(led->name));
131 led->led_dev.name = led->name;
132 led->led_dev.default_trigger = trigger;
133 led->led_dev.brightness_set = ath5k_led_brightness_set;
134
135 err = led_classdev_register(ah->dev, &led->led_dev);
136 if (err) {
137 ATH5K_WARN(ah, "could not register LED %s\n", name);
138 led->ah = NULL;
139 }
140 return err;
141}
142
143static void
144ath5k_unregister_led(struct ath5k_led *led)
145{
146 if (!led->ah)
147 return;
148 led_classdev_unregister(&led->led_dev);
149 ath5k_led_off(led->ah);
150 led->ah = NULL;
151}
152
153void ath5k_unregister_leds(struct ath5k_hw *ah)
154{
155 ath5k_unregister_led(&ah->rx_led);
156 ath5k_unregister_led(&ah->tx_led);
157}
158
159int __devinit ath5k_init_leds(struct ath5k_hw *ah)
160{
161 int ret = 0;
162 struct ieee80211_hw *hw = ah->hw;
163#ifndef CONFIG_ATHEROS_AR231X
164 struct pci_dev *pdev = ah->pdev;
165#endif
166 char name[ATH5K_LED_MAX_NAME_LEN + 1];
167 const struct pci_device_id *match;
168
169 if (!ah->pdev)
170 return 0;
171
172#ifdef CONFIG_ATHEROS_AR231X
173 match = NULL;
174#else
175 match = pci_match_id(&ath5k_led_devices[0], pdev);
176#endif
177 if (match) {
178 __set_bit(ATH_STAT_LEDSOFT, ah->status);
179 ah->led_pin = ATH_PIN(match->driver_data);
180 ah->led_on = ATH_POLARITY(match->driver_data);
181 }
182
183 if (!test_bit(ATH_STAT_LEDSOFT, ah->status))
184 goto out;
185
186 ath5k_led_enable(ah);
187
188 snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy));
189 ret = ath5k_register_led(ah, &ah->rx_led, name,
190 ieee80211_get_rx_led_name(hw));
191 if (ret)
192 goto out;
193
194 snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy));
195 ret = ath5k_register_led(ah, &ah->tx_led, name,
196 ieee80211_get_tx_led_name(hw));
197out:
198 return ret;
199}
200
201