diff options
Diffstat (limited to 'drivers/net/wireless/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 138 |
1 files changed, 135 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index dca00c3a985a..996bb9c6540d 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -1172,12 +1172,130 @@ enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc) | |||
1172 | return sc->sc_ht_info.tx_chan_width; | 1172 | return sc->sc_ht_info.tx_chan_width; |
1173 | } | 1173 | } |
1174 | 1174 | ||
1175 | /********************************/ | ||
1176 | /* LED functions */ | ||
1177 | /********************************/ | ||
1178 | |||
1179 | static void ath_led_brightness(struct led_classdev *led_cdev, | ||
1180 | enum led_brightness brightness) | ||
1181 | { | ||
1182 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
1183 | struct ath_softc *sc = led->sc; | ||
1184 | |||
1185 | switch (brightness) { | ||
1186 | case LED_OFF: | ||
1187 | if (led->led_type == ATH_LED_ASSOC || | ||
1188 | led->led_type == ATH_LED_RADIO) | ||
1189 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
1190 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, | ||
1191 | (led->led_type == ATH_LED_RADIO) ? 1 : | ||
1192 | !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); | ||
1193 | break; | ||
1194 | case LED_FULL: | ||
1195 | if (led->led_type == ATH_LED_ASSOC) | ||
1196 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; | ||
1197 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); | ||
1198 | break; | ||
1199 | default: | ||
1200 | break; | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | static int ath_register_led(struct ath_softc *sc, struct ath_led *led, | ||
1205 | char *trigger) | ||
1206 | { | ||
1207 | int ret; | ||
1208 | |||
1209 | led->sc = sc; | ||
1210 | led->led_cdev.name = led->name; | ||
1211 | led->led_cdev.default_trigger = trigger; | ||
1212 | led->led_cdev.brightness_set = ath_led_brightness; | ||
1213 | |||
1214 | ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); | ||
1215 | if (ret) | ||
1216 | DPRINTF(sc, ATH_DBG_FATAL, | ||
1217 | "Failed to register led:%s", led->name); | ||
1218 | else | ||
1219 | led->registered = 1; | ||
1220 | return ret; | ||
1221 | } | ||
1222 | |||
1223 | static void ath_unregister_led(struct ath_led *led) | ||
1224 | { | ||
1225 | if (led->registered) { | ||
1226 | led_classdev_unregister(&led->led_cdev); | ||
1227 | led->registered = 0; | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | static void ath_deinit_leds(struct ath_softc *sc) | ||
1232 | { | ||
1233 | ath_unregister_led(&sc->assoc_led); | ||
1234 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
1235 | ath_unregister_led(&sc->tx_led); | ||
1236 | ath_unregister_led(&sc->rx_led); | ||
1237 | ath_unregister_led(&sc->radio_led); | ||
1238 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1239 | } | ||
1240 | |||
1241 | static void ath_init_leds(struct ath_softc *sc) | ||
1242 | { | ||
1243 | char *trigger; | ||
1244 | int ret; | ||
1245 | |||
1246 | /* Configure gpio 1 for output */ | ||
1247 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | ||
1248 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1249 | /* LED off, active low */ | ||
1250 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1251 | |||
1252 | trigger = ieee80211_get_radio_led_name(sc->hw); | ||
1253 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), | ||
1254 | "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); | ||
1255 | ret = ath_register_led(sc, &sc->radio_led, trigger); | ||
1256 | sc->radio_led.led_type = ATH_LED_RADIO; | ||
1257 | if (ret) | ||
1258 | goto fail; | ||
1259 | |||
1260 | trigger = ieee80211_get_assoc_led_name(sc->hw); | ||
1261 | snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), | ||
1262 | "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); | ||
1263 | ret = ath_register_led(sc, &sc->assoc_led, trigger); | ||
1264 | sc->assoc_led.led_type = ATH_LED_ASSOC; | ||
1265 | if (ret) | ||
1266 | goto fail; | ||
1267 | |||
1268 | trigger = ieee80211_get_tx_led_name(sc->hw); | ||
1269 | snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), | ||
1270 | "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); | ||
1271 | ret = ath_register_led(sc, &sc->tx_led, trigger); | ||
1272 | sc->tx_led.led_type = ATH_LED_TX; | ||
1273 | if (ret) | ||
1274 | goto fail; | ||
1275 | |||
1276 | trigger = ieee80211_get_rx_led_name(sc->hw); | ||
1277 | snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), | ||
1278 | "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); | ||
1279 | ret = ath_register_led(sc, &sc->rx_led, trigger); | ||
1280 | sc->rx_led.led_type = ATH_LED_RX; | ||
1281 | if (ret) | ||
1282 | goto fail; | ||
1283 | |||
1284 | return; | ||
1285 | |||
1286 | fail: | ||
1287 | ath_deinit_leds(sc); | ||
1288 | } | ||
1289 | |||
1175 | static int ath_detach(struct ath_softc *sc) | 1290 | static int ath_detach(struct ath_softc *sc) |
1176 | { | 1291 | { |
1177 | struct ieee80211_hw *hw = sc->hw; | 1292 | struct ieee80211_hw *hw = sc->hw; |
1178 | 1293 | ||
1179 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); | 1294 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); |
1180 | 1295 | ||
1296 | /* Deinit LED control */ | ||
1297 | ath_deinit_leds(sc); | ||
1298 | |||
1181 | /* Unregister hw */ | 1299 | /* Unregister hw */ |
1182 | 1300 | ||
1183 | ieee80211_unregister_hw(hw); | 1301 | ieee80211_unregister_hw(hw); |
@@ -1271,18 +1389,21 @@ static int ath_attach(u16 devid, | |||
1271 | goto bad; | 1389 | goto bad; |
1272 | } | 1390 | } |
1273 | 1391 | ||
1392 | /* Initialize LED control */ | ||
1393 | ath_init_leds(sc); | ||
1394 | |||
1274 | /* initialize tx/rx engine */ | 1395 | /* initialize tx/rx engine */ |
1275 | 1396 | ||
1276 | error = ath_tx_init(sc, ATH_TXBUF); | 1397 | error = ath_tx_init(sc, ATH_TXBUF); |
1277 | if (error != 0) | 1398 | if (error != 0) |
1278 | goto bad1; | 1399 | goto detach; |
1279 | 1400 | ||
1280 | error = ath_rx_init(sc, ATH_RXBUF); | 1401 | error = ath_rx_init(sc, ATH_RXBUF); |
1281 | if (error != 0) | 1402 | if (error != 0) |
1282 | goto bad1; | 1403 | goto detach; |
1283 | 1404 | ||
1284 | return 0; | 1405 | return 0; |
1285 | bad1: | 1406 | detach: |
1286 | ath_detach(sc); | 1407 | ath_detach(sc); |
1287 | bad: | 1408 | bad: |
1288 | return error; | 1409 | return error; |
@@ -1427,6 +1548,10 @@ static void ath_pci_remove(struct pci_dev *pdev) | |||
1427 | 1548 | ||
1428 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 1549 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) |
1429 | { | 1550 | { |
1551 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
1552 | struct ath_softc *sc = hw->priv; | ||
1553 | |||
1554 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1430 | pci_save_state(pdev); | 1555 | pci_save_state(pdev); |
1431 | pci_disable_device(pdev); | 1556 | pci_disable_device(pdev); |
1432 | pci_set_power_state(pdev, 3); | 1557 | pci_set_power_state(pdev, 3); |
@@ -1436,6 +1561,8 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
1436 | 1561 | ||
1437 | static int ath_pci_resume(struct pci_dev *pdev) | 1562 | static int ath_pci_resume(struct pci_dev *pdev) |
1438 | { | 1563 | { |
1564 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
1565 | struct ath_softc *sc = hw->priv; | ||
1439 | u32 val; | 1566 | u32 val; |
1440 | int err; | 1567 | int err; |
1441 | 1568 | ||
@@ -1452,6 +1579,11 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
1452 | if ((val & 0x0000ff00) != 0) | 1579 | if ((val & 0x0000ff00) != 0) |
1453 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | 1580 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); |
1454 | 1581 | ||
1582 | /* Enable LED */ | ||
1583 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | ||
1584 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1585 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1586 | |||
1455 | return 0; | 1587 | return 0; |
1456 | } | 1588 | } |
1457 | 1589 | ||