diff options
Diffstat (limited to 'drivers/net/wireless/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 1262 |
1 files changed, 763 insertions, 499 deletions
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 57d7cc87cb0f..1ba18006f475 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -140,7 +140,7 @@ static int ath_key_config(struct ath_softc *sc, | |||
140 | struct ath9k_keyval hk; | 140 | struct ath9k_keyval hk; |
141 | const u8 *mac = NULL; | 141 | const u8 *mac = NULL; |
142 | int ret = 0; | 142 | int ret = 0; |
143 | enum ieee80211_if_types opmode; | 143 | enum nl80211_iftype opmode; |
144 | 144 | ||
145 | memset(&hk, 0, sizeof(hk)); | 145 | memset(&hk, 0, sizeof(hk)); |
146 | 146 | ||
@@ -179,14 +179,14 @@ static int ath_key_config(struct ath_softc *sc, | |||
179 | */ | 179 | */ |
180 | if (is_broadcast_ether_addr(addr)) { | 180 | if (is_broadcast_ether_addr(addr)) { |
181 | switch (opmode) { | 181 | switch (opmode) { |
182 | case IEEE80211_IF_TYPE_STA: | 182 | case NL80211_IFTYPE_STATION: |
183 | /* default key: could be group WPA key | 183 | /* default key: could be group WPA key |
184 | * or could be static WEP key */ | 184 | * or could be static WEP key */ |
185 | mac = NULL; | 185 | mac = NULL; |
186 | break; | 186 | break; |
187 | case IEEE80211_IF_TYPE_IBSS: | 187 | case NL80211_IFTYPE_ADHOC: |
188 | break; | 188 | break; |
189 | case IEEE80211_IF_TYPE_AP: | 189 | case NL80211_IFTYPE_AP: |
190 | break; | 190 | break; |
191 | default: | 191 | default: |
192 | ASSERT(0); | 192 | ASSERT(0); |
@@ -325,6 +325,693 @@ static u8 parse_mpdudensity(u8 mpdudensity) | |||
325 | } | 325 | } |
326 | } | 326 | } |
327 | 327 | ||
328 | static void ath9k_ht_conf(struct ath_softc *sc, | ||
329 | struct ieee80211_bss_conf *bss_conf) | ||
330 | { | ||
331 | #define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) | ||
332 | struct ath_ht_info *ht_info = &sc->sc_ht_info; | ||
333 | |||
334 | if (bss_conf->assoc_ht) { | ||
335 | ht_info->ext_chan_offset = | ||
336 | bss_conf->ht_bss_conf->bss_cap & | ||
337 | IEEE80211_HT_IE_CHA_SEC_OFFSET; | ||
338 | |||
339 | if (!(bss_conf->ht_conf->cap & | ||
340 | IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | ||
341 | (bss_conf->ht_bss_conf->bss_cap & | ||
342 | IEEE80211_HT_IE_CHA_WIDTH)) | ||
343 | ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; | ||
344 | else | ||
345 | ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; | ||
346 | |||
347 | ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); | ||
348 | ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + | ||
349 | bss_conf->ht_conf->ampdu_factor); | ||
350 | ht_info->mpdudensity = | ||
351 | parse_mpdudensity(bss_conf->ht_conf->ampdu_density); | ||
352 | |||
353 | } | ||
354 | |||
355 | #undef IEEE80211_HT_CAP_40MHZ_INTOLERANT | ||
356 | } | ||
357 | |||
358 | static void ath9k_bss_assoc_info(struct ath_softc *sc, | ||
359 | struct ieee80211_bss_conf *bss_conf) | ||
360 | { | ||
361 | struct ieee80211_hw *hw = sc->hw; | ||
362 | struct ieee80211_channel *curchan = hw->conf.channel; | ||
363 | struct ath_vap *avp; | ||
364 | int pos; | ||
365 | DECLARE_MAC_BUF(mac); | ||
366 | |||
367 | if (bss_conf->assoc) { | ||
368 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", | ||
369 | __func__, | ||
370 | bss_conf->aid); | ||
371 | |||
372 | avp = sc->sc_vaps[0]; | ||
373 | if (avp == NULL) { | ||
374 | DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", | ||
375 | __func__); | ||
376 | return; | ||
377 | } | ||
378 | |||
379 | /* New association, store aid */ | ||
380 | if (avp->av_opmode == ATH9K_M_STA) { | ||
381 | sc->sc_curaid = bss_conf->aid; | ||
382 | ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, | ||
383 | sc->sc_curaid); | ||
384 | } | ||
385 | |||
386 | /* Configure the beacon */ | ||
387 | ath_beacon_config(sc, 0); | ||
388 | sc->sc_flags |= SC_OP_BEACONS; | ||
389 | |||
390 | /* Reset rssi stats */ | ||
391 | sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; | ||
392 | sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; | ||
393 | sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; | ||
394 | sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; | ||
395 | |||
396 | /* Update chainmask */ | ||
397 | ath_update_chainmask(sc, bss_conf->assoc_ht); | ||
398 | |||
399 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
400 | "%s: bssid %s aid 0x%x\n", | ||
401 | __func__, | ||
402 | print_mac(mac, sc->sc_curbssid), sc->sc_curaid); | ||
403 | |||
404 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", | ||
405 | __func__, | ||
406 | curchan->center_freq); | ||
407 | |||
408 | pos = ath_get_channel(sc, curchan); | ||
409 | if (pos == -1) { | ||
410 | DPRINTF(sc, ATH_DBG_FATAL, | ||
411 | "%s: Invalid channel\n", __func__); | ||
412 | return; | ||
413 | } | ||
414 | |||
415 | if (hw->conf.ht_conf.ht_supported) | ||
416 | sc->sc_ah->ah_channels[pos].chanmode = | ||
417 | ath_get_extchanmode(sc, curchan); | ||
418 | else | ||
419 | sc->sc_ah->ah_channels[pos].chanmode = | ||
420 | (curchan->band == IEEE80211_BAND_2GHZ) ? | ||
421 | CHANNEL_G : CHANNEL_A; | ||
422 | |||
423 | /* set h/w channel */ | ||
424 | if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) | ||
425 | DPRINTF(sc, ATH_DBG_FATAL, | ||
426 | "%s: Unable to set channel\n", | ||
427 | __func__); | ||
428 | |||
429 | ath_rate_newstate(sc, avp); | ||
430 | /* Update ratectrl about the new state */ | ||
431 | ath_rc_node_update(hw, avp->rc_node); | ||
432 | } else { | ||
433 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
434 | "%s: Bss Info DISSOC\n", __func__); | ||
435 | sc->sc_curaid = 0; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | void ath_get_beaconconfig(struct ath_softc *sc, | ||
440 | int if_id, | ||
441 | struct ath_beacon_config *conf) | ||
442 | { | ||
443 | struct ieee80211_hw *hw = sc->hw; | ||
444 | |||
445 | /* fill in beacon config data */ | ||
446 | |||
447 | conf->beacon_interval = hw->conf.beacon_int; | ||
448 | conf->listen_interval = 100; | ||
449 | conf->dtim_count = 1; | ||
450 | conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; | ||
451 | } | ||
452 | |||
453 | void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | ||
454 | struct ath_xmit_status *tx_status, struct ath_node *an) | ||
455 | { | ||
456 | struct ieee80211_hw *hw = sc->hw; | ||
457 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
458 | |||
459 | DPRINTF(sc, ATH_DBG_XMIT, | ||
460 | "%s: TX complete: skb: %p\n", __func__, skb); | ||
461 | |||
462 | if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || | ||
463 | tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { | ||
464 | /* free driver's private data area of tx_info */ | ||
465 | if (tx_info->driver_data[0] != NULL) | ||
466 | kfree(tx_info->driver_data[0]); | ||
467 | tx_info->driver_data[0] = NULL; | ||
468 | } | ||
469 | |||
470 | if (tx_status->flags & ATH_TX_BAR) { | ||
471 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | ||
472 | tx_status->flags &= ~ATH_TX_BAR; | ||
473 | } | ||
474 | |||
475 | if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { | ||
476 | if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { | ||
477 | /* Frame was not ACKed, but an ACK was expected */ | ||
478 | tx_info->status.excessive_retries = 1; | ||
479 | } | ||
480 | } else { | ||
481 | /* Frame was ACKed */ | ||
482 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | ||
483 | } | ||
484 | |||
485 | tx_info->status.retry_count = tx_status->retries; | ||
486 | |||
487 | ieee80211_tx_status(hw, skb); | ||
488 | if (an) | ||
489 | ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); | ||
490 | } | ||
491 | |||
492 | int _ath_rx_indicate(struct ath_softc *sc, | ||
493 | struct sk_buff *skb, | ||
494 | struct ath_recv_status *status, | ||
495 | u16 keyix) | ||
496 | { | ||
497 | struct ieee80211_hw *hw = sc->hw; | ||
498 | struct ath_node *an = NULL; | ||
499 | struct ieee80211_rx_status rx_status; | ||
500 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
501 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
502 | int padsize; | ||
503 | enum ATH_RX_TYPE st; | ||
504 | |||
505 | /* see if any padding is done by the hw and remove it */ | ||
506 | if (hdrlen & 3) { | ||
507 | padsize = hdrlen % 4; | ||
508 | memmove(skb->data + padsize, skb->data, hdrlen); | ||
509 | skb_pull(skb, padsize); | ||
510 | } | ||
511 | |||
512 | /* Prepare rx status */ | ||
513 | ath9k_rx_prepare(sc, skb, status, &rx_status); | ||
514 | |||
515 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && | ||
516 | !(status->flags & ATH_RX_DECRYPT_ERROR)) { | ||
517 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
518 | } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) | ||
519 | && !(status->flags & ATH_RX_DECRYPT_ERROR) | ||
520 | && skb->len >= hdrlen + 4) { | ||
521 | keyix = skb->data[hdrlen + 3] >> 6; | ||
522 | |||
523 | if (test_bit(keyix, sc->sc_keymap)) | ||
524 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
525 | } | ||
526 | |||
527 | spin_lock_bh(&sc->node_lock); | ||
528 | an = ath_node_find(sc, hdr->addr2); | ||
529 | spin_unlock_bh(&sc->node_lock); | ||
530 | |||
531 | if (an) { | ||
532 | ath_rx_input(sc, an, | ||
533 | hw->conf.ht_conf.ht_supported, | ||
534 | skb, status, &st); | ||
535 | } | ||
536 | if (!an || (st != ATH_RX_CONSUMED)) | ||
537 | __ieee80211_rx(hw, skb, &rx_status); | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | int ath_rx_subframe(struct ath_node *an, | ||
543 | struct sk_buff *skb, | ||
544 | struct ath_recv_status *status) | ||
545 | { | ||
546 | struct ath_softc *sc = an->an_sc; | ||
547 | struct ieee80211_hw *hw = sc->hw; | ||
548 | struct ieee80211_rx_status rx_status; | ||
549 | |||
550 | /* Prepare rx status */ | ||
551 | ath9k_rx_prepare(sc, skb, status, &rx_status); | ||
552 | if (!(status->flags & ATH_RX_DECRYPT_ERROR)) | ||
553 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
554 | |||
555 | __ieee80211_rx(hw, skb, &rx_status); | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | /********************************/ | ||
561 | /* LED functions */ | ||
562 | /********************************/ | ||
563 | |||
564 | static void ath_led_brightness(struct led_classdev *led_cdev, | ||
565 | enum led_brightness brightness) | ||
566 | { | ||
567 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
568 | struct ath_softc *sc = led->sc; | ||
569 | |||
570 | switch (brightness) { | ||
571 | case LED_OFF: | ||
572 | if (led->led_type == ATH_LED_ASSOC || | ||
573 | led->led_type == ATH_LED_RADIO) | ||
574 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
575 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, | ||
576 | (led->led_type == ATH_LED_RADIO) ? 1 : | ||
577 | !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); | ||
578 | break; | ||
579 | case LED_FULL: | ||
580 | if (led->led_type == ATH_LED_ASSOC) | ||
581 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; | ||
582 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); | ||
583 | break; | ||
584 | default: | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | |||
589 | static int ath_register_led(struct ath_softc *sc, struct ath_led *led, | ||
590 | char *trigger) | ||
591 | { | ||
592 | int ret; | ||
593 | |||
594 | led->sc = sc; | ||
595 | led->led_cdev.name = led->name; | ||
596 | led->led_cdev.default_trigger = trigger; | ||
597 | led->led_cdev.brightness_set = ath_led_brightness; | ||
598 | |||
599 | ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); | ||
600 | if (ret) | ||
601 | DPRINTF(sc, ATH_DBG_FATAL, | ||
602 | "Failed to register led:%s", led->name); | ||
603 | else | ||
604 | led->registered = 1; | ||
605 | return ret; | ||
606 | } | ||
607 | |||
608 | static void ath_unregister_led(struct ath_led *led) | ||
609 | { | ||
610 | if (led->registered) { | ||
611 | led_classdev_unregister(&led->led_cdev); | ||
612 | led->registered = 0; | ||
613 | } | ||
614 | } | ||
615 | |||
616 | static void ath_deinit_leds(struct ath_softc *sc) | ||
617 | { | ||
618 | ath_unregister_led(&sc->assoc_led); | ||
619 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
620 | ath_unregister_led(&sc->tx_led); | ||
621 | ath_unregister_led(&sc->rx_led); | ||
622 | ath_unregister_led(&sc->radio_led); | ||
623 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
624 | } | ||
625 | |||
626 | static void ath_init_leds(struct ath_softc *sc) | ||
627 | { | ||
628 | char *trigger; | ||
629 | int ret; | ||
630 | |||
631 | /* Configure gpio 1 for output */ | ||
632 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | ||
633 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
634 | /* LED off, active low */ | ||
635 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
636 | |||
637 | trigger = ieee80211_get_radio_led_name(sc->hw); | ||
638 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), | ||
639 | "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); | ||
640 | ret = ath_register_led(sc, &sc->radio_led, trigger); | ||
641 | sc->radio_led.led_type = ATH_LED_RADIO; | ||
642 | if (ret) | ||
643 | goto fail; | ||
644 | |||
645 | trigger = ieee80211_get_assoc_led_name(sc->hw); | ||
646 | snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), | ||
647 | "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); | ||
648 | ret = ath_register_led(sc, &sc->assoc_led, trigger); | ||
649 | sc->assoc_led.led_type = ATH_LED_ASSOC; | ||
650 | if (ret) | ||
651 | goto fail; | ||
652 | |||
653 | trigger = ieee80211_get_tx_led_name(sc->hw); | ||
654 | snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), | ||
655 | "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); | ||
656 | ret = ath_register_led(sc, &sc->tx_led, trigger); | ||
657 | sc->tx_led.led_type = ATH_LED_TX; | ||
658 | if (ret) | ||
659 | goto fail; | ||
660 | |||
661 | trigger = ieee80211_get_rx_led_name(sc->hw); | ||
662 | snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), | ||
663 | "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); | ||
664 | ret = ath_register_led(sc, &sc->rx_led, trigger); | ||
665 | sc->rx_led.led_type = ATH_LED_RX; | ||
666 | if (ret) | ||
667 | goto fail; | ||
668 | |||
669 | return; | ||
670 | |||
671 | fail: | ||
672 | ath_deinit_leds(sc); | ||
673 | } | ||
674 | |||
675 | #ifdef CONFIG_RFKILL | ||
676 | /*******************/ | ||
677 | /* Rfkill */ | ||
678 | /*******************/ | ||
679 | |||
680 | static void ath_radio_enable(struct ath_softc *sc) | ||
681 | { | ||
682 | struct ath_hal *ah = sc->sc_ah; | ||
683 | int status; | ||
684 | |||
685 | spin_lock_bh(&sc->sc_resetlock); | ||
686 | if (!ath9k_hw_reset(ah, ah->ah_curchan, | ||
687 | sc->sc_ht_info.tx_chan_width, | ||
688 | sc->sc_tx_chainmask, | ||
689 | sc->sc_rx_chainmask, | ||
690 | sc->sc_ht_extprotspacing, | ||
691 | false, &status)) { | ||
692 | DPRINTF(sc, ATH_DBG_FATAL, | ||
693 | "%s: unable to reset channel %u (%uMhz) " | ||
694 | "flags 0x%x hal status %u\n", __func__, | ||
695 | ath9k_hw_mhz2ieee(ah, | ||
696 | ah->ah_curchan->channel, | ||
697 | ah->ah_curchan->channelFlags), | ||
698 | ah->ah_curchan->channel, | ||
699 | ah->ah_curchan->channelFlags, status); | ||
700 | } | ||
701 | spin_unlock_bh(&sc->sc_resetlock); | ||
702 | |||
703 | ath_update_txpow(sc); | ||
704 | if (ath_startrecv(sc) != 0) { | ||
705 | DPRINTF(sc, ATH_DBG_FATAL, | ||
706 | "%s: unable to restart recv logic\n", __func__); | ||
707 | return; | ||
708 | } | ||
709 | |||
710 | if (sc->sc_flags & SC_OP_BEACONS) | ||
711 | ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ | ||
712 | |||
713 | /* Re-Enable interrupts */ | ||
714 | ath9k_hw_set_interrupts(ah, sc->sc_imask); | ||
715 | |||
716 | /* Enable LED */ | ||
717 | ath9k_hw_cfg_output(ah, ATH_LED_PIN, | ||
718 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
719 | ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); | ||
720 | |||
721 | ieee80211_wake_queues(sc->hw); | ||
722 | } | ||
723 | |||
724 | static void ath_radio_disable(struct ath_softc *sc) | ||
725 | { | ||
726 | struct ath_hal *ah = sc->sc_ah; | ||
727 | int status; | ||
728 | |||
729 | |||
730 | ieee80211_stop_queues(sc->hw); | ||
731 | |||
732 | /* Disable LED */ | ||
733 | ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1); | ||
734 | ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN); | ||
735 | |||
736 | /* Disable interrupts */ | ||
737 | ath9k_hw_set_interrupts(ah, 0); | ||
738 | |||
739 | ath_draintxq(sc, false); /* clear pending tx frames */ | ||
740 | ath_stoprecv(sc); /* turn off frame recv */ | ||
741 | ath_flushrecv(sc); /* flush recv queue */ | ||
742 | |||
743 | spin_lock_bh(&sc->sc_resetlock); | ||
744 | if (!ath9k_hw_reset(ah, ah->ah_curchan, | ||
745 | sc->sc_ht_info.tx_chan_width, | ||
746 | sc->sc_tx_chainmask, | ||
747 | sc->sc_rx_chainmask, | ||
748 | sc->sc_ht_extprotspacing, | ||
749 | false, &status)) { | ||
750 | DPRINTF(sc, ATH_DBG_FATAL, | ||
751 | "%s: unable to reset channel %u (%uMhz) " | ||
752 | "flags 0x%x hal status %u\n", __func__, | ||
753 | ath9k_hw_mhz2ieee(ah, | ||
754 | ah->ah_curchan->channel, | ||
755 | ah->ah_curchan->channelFlags), | ||
756 | ah->ah_curchan->channel, | ||
757 | ah->ah_curchan->channelFlags, status); | ||
758 | } | ||
759 | spin_unlock_bh(&sc->sc_resetlock); | ||
760 | |||
761 | ath9k_hw_phy_disable(ah); | ||
762 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); | ||
763 | } | ||
764 | |||
765 | static bool ath_is_rfkill_set(struct ath_softc *sc) | ||
766 | { | ||
767 | struct ath_hal *ah = sc->sc_ah; | ||
768 | |||
769 | return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) == | ||
770 | ah->ah_rfkill_polarity; | ||
771 | } | ||
772 | |||
773 | /* h/w rfkill poll function */ | ||
774 | static void ath_rfkill_poll(struct work_struct *work) | ||
775 | { | ||
776 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
777 | rf_kill.rfkill_poll.work); | ||
778 | bool radio_on; | ||
779 | |||
780 | if (sc->sc_flags & SC_OP_INVALID) | ||
781 | return; | ||
782 | |||
783 | radio_on = !ath_is_rfkill_set(sc); | ||
784 | |||
785 | /* | ||
786 | * enable/disable radio only when there is a | ||
787 | * state change in RF switch | ||
788 | */ | ||
789 | if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { | ||
790 | enum rfkill_state state; | ||
791 | |||
792 | if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { | ||
793 | state = radio_on ? RFKILL_STATE_SOFT_BLOCKED | ||
794 | : RFKILL_STATE_HARD_BLOCKED; | ||
795 | } else if (radio_on) { | ||
796 | ath_radio_enable(sc); | ||
797 | state = RFKILL_STATE_UNBLOCKED; | ||
798 | } else { | ||
799 | ath_radio_disable(sc); | ||
800 | state = RFKILL_STATE_HARD_BLOCKED; | ||
801 | } | ||
802 | |||
803 | if (state == RFKILL_STATE_HARD_BLOCKED) | ||
804 | sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; | ||
805 | else | ||
806 | sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; | ||
807 | |||
808 | rfkill_force_state(sc->rf_kill.rfkill, state); | ||
809 | } | ||
810 | |||
811 | queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, | ||
812 | msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); | ||
813 | } | ||
814 | |||
815 | /* s/w rfkill handler */ | ||
816 | static int ath_sw_toggle_radio(void *data, enum rfkill_state state) | ||
817 | { | ||
818 | struct ath_softc *sc = data; | ||
819 | |||
820 | switch (state) { | ||
821 | case RFKILL_STATE_SOFT_BLOCKED: | ||
822 | if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | | ||
823 | SC_OP_RFKILL_SW_BLOCKED))) | ||
824 | ath_radio_disable(sc); | ||
825 | sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; | ||
826 | return 0; | ||
827 | case RFKILL_STATE_UNBLOCKED: | ||
828 | if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { | ||
829 | sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; | ||
830 | if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { | ||
831 | DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" | ||
832 | "radio as it is disabled by h/w \n"); | ||
833 | return -EPERM; | ||
834 | } | ||
835 | ath_radio_enable(sc); | ||
836 | } | ||
837 | return 0; | ||
838 | default: | ||
839 | return -EINVAL; | ||
840 | } | ||
841 | } | ||
842 | |||
843 | /* Init s/w rfkill */ | ||
844 | static int ath_init_sw_rfkill(struct ath_softc *sc) | ||
845 | { | ||
846 | sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), | ||
847 | RFKILL_TYPE_WLAN); | ||
848 | if (!sc->rf_kill.rfkill) { | ||
849 | DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); | ||
850 | return -ENOMEM; | ||
851 | } | ||
852 | |||
853 | snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), | ||
854 | "ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy)); | ||
855 | sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; | ||
856 | sc->rf_kill.rfkill->data = sc; | ||
857 | sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; | ||
858 | sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
859 | sc->rf_kill.rfkill->user_claim_unsupported = 1; | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | /* Deinitialize rfkill */ | ||
865 | static void ath_deinit_rfkill(struct ath_softc *sc) | ||
866 | { | ||
867 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
868 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
869 | |||
870 | if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { | ||
871 | rfkill_unregister(sc->rf_kill.rfkill); | ||
872 | sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; | ||
873 | sc->rf_kill.rfkill = NULL; | ||
874 | } | ||
875 | } | ||
876 | #endif /* CONFIG_RFKILL */ | ||
877 | |||
878 | static int ath_detach(struct ath_softc *sc) | ||
879 | { | ||
880 | struct ieee80211_hw *hw = sc->hw; | ||
881 | |||
882 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); | ||
883 | |||
884 | /* Deinit LED control */ | ||
885 | ath_deinit_leds(sc); | ||
886 | |||
887 | #ifdef CONFIG_RFKILL | ||
888 | /* deinit rfkill */ | ||
889 | ath_deinit_rfkill(sc); | ||
890 | #endif | ||
891 | |||
892 | /* Unregister hw */ | ||
893 | |||
894 | ieee80211_unregister_hw(hw); | ||
895 | |||
896 | /* unregister Rate control */ | ||
897 | ath_rate_control_unregister(); | ||
898 | |||
899 | /* tx/rx cleanup */ | ||
900 | |||
901 | ath_rx_cleanup(sc); | ||
902 | ath_tx_cleanup(sc); | ||
903 | |||
904 | /* Deinit */ | ||
905 | |||
906 | ath_deinit(sc); | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static int ath_attach(u16 devid, | ||
912 | struct ath_softc *sc) | ||
913 | { | ||
914 | struct ieee80211_hw *hw = sc->hw; | ||
915 | int error = 0; | ||
916 | |||
917 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); | ||
918 | |||
919 | error = ath_init(devid, sc); | ||
920 | if (error != 0) | ||
921 | return error; | ||
922 | |||
923 | /* Init nodes */ | ||
924 | |||
925 | INIT_LIST_HEAD(&sc->node_list); | ||
926 | spin_lock_init(&sc->node_lock); | ||
927 | |||
928 | /* get mac address from hardware and set in mac80211 */ | ||
929 | |||
930 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); | ||
931 | |||
932 | /* setup channels and rates */ | ||
933 | |||
934 | sc->sbands[IEEE80211_BAND_2GHZ].channels = | ||
935 | sc->channels[IEEE80211_BAND_2GHZ]; | ||
936 | sc->sbands[IEEE80211_BAND_2GHZ].bitrates = | ||
937 | sc->rates[IEEE80211_BAND_2GHZ]; | ||
938 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | ||
939 | |||
940 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | ||
941 | /* Setup HT capabilities for 2.4Ghz*/ | ||
942 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info); | ||
943 | |||
944 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
945 | &sc->sbands[IEEE80211_BAND_2GHZ]; | ||
946 | |||
947 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { | ||
948 | sc->sbands[IEEE80211_BAND_5GHZ].channels = | ||
949 | sc->channels[IEEE80211_BAND_5GHZ]; | ||
950 | sc->sbands[IEEE80211_BAND_5GHZ].bitrates = | ||
951 | sc->rates[IEEE80211_BAND_5GHZ]; | ||
952 | sc->sbands[IEEE80211_BAND_5GHZ].band = | ||
953 | IEEE80211_BAND_5GHZ; | ||
954 | |||
955 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | ||
956 | /* Setup HT capabilities for 5Ghz*/ | ||
957 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info); | ||
958 | |||
959 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
960 | &sc->sbands[IEEE80211_BAND_5GHZ]; | ||
961 | } | ||
962 | |||
963 | /* FIXME: Have to figure out proper hw init values later */ | ||
964 | |||
965 | hw->queues = 4; | ||
966 | hw->ampdu_queues = 1; | ||
967 | |||
968 | /* Register rate control */ | ||
969 | hw->rate_control_algorithm = "ath9k_rate_control"; | ||
970 | error = ath_rate_control_register(); | ||
971 | if (error != 0) { | ||
972 | DPRINTF(sc, ATH_DBG_FATAL, | ||
973 | "%s: Unable to register rate control " | ||
974 | "algorithm:%d\n", __func__, error); | ||
975 | ath_rate_control_unregister(); | ||
976 | goto bad; | ||
977 | } | ||
978 | |||
979 | error = ieee80211_register_hw(hw); | ||
980 | if (error != 0) { | ||
981 | ath_rate_control_unregister(); | ||
982 | goto bad; | ||
983 | } | ||
984 | |||
985 | /* Initialize LED control */ | ||
986 | ath_init_leds(sc); | ||
987 | |||
988 | #ifdef CONFIG_RFKILL | ||
989 | /* Initialze h/w Rfkill */ | ||
990 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
991 | INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); | ||
992 | |||
993 | /* Initialize s/w rfkill */ | ||
994 | if (ath_init_sw_rfkill(sc)) | ||
995 | goto detach; | ||
996 | #endif | ||
997 | |||
998 | /* initialize tx/rx engine */ | ||
999 | |||
1000 | error = ath_tx_init(sc, ATH_TXBUF); | ||
1001 | if (error != 0) | ||
1002 | goto detach; | ||
1003 | |||
1004 | error = ath_rx_init(sc, ATH_RXBUF); | ||
1005 | if (error != 0) | ||
1006 | goto detach; | ||
1007 | |||
1008 | return 0; | ||
1009 | detach: | ||
1010 | ath_detach(sc); | ||
1011 | bad: | ||
1012 | return error; | ||
1013 | } | ||
1014 | |||
328 | static int ath9k_start(struct ieee80211_hw *hw) | 1015 | static int ath9k_start(struct ieee80211_hw *hw) |
329 | { | 1016 | { |
330 | struct ath_softc *sc = hw->priv; | 1017 | struct ath_softc *sc = hw->priv; |
@@ -353,6 +1040,33 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
353 | return error; | 1040 | return error; |
354 | } | 1041 | } |
355 | 1042 | ||
1043 | #ifdef CONFIG_RFKILL | ||
1044 | /* Start rfkill polling */ | ||
1045 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1046 | queue_delayed_work(sc->hw->workqueue, | ||
1047 | &sc->rf_kill.rfkill_poll, 0); | ||
1048 | |||
1049 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { | ||
1050 | if (rfkill_register(sc->rf_kill.rfkill)) { | ||
1051 | DPRINTF(sc, ATH_DBG_FATAL, | ||
1052 | "Unable to register rfkill\n"); | ||
1053 | rfkill_free(sc->rf_kill.rfkill); | ||
1054 | |||
1055 | /* Deinitialize the device */ | ||
1056 | if (sc->pdev->irq) | ||
1057 | free_irq(sc->pdev->irq, sc); | ||
1058 | ath_detach(sc); | ||
1059 | pci_iounmap(sc->pdev, sc->mem); | ||
1060 | pci_release_region(sc->pdev, 0); | ||
1061 | pci_disable_device(sc->pdev); | ||
1062 | ieee80211_free_hw(hw); | ||
1063 | return -EIO; | ||
1064 | } else { | ||
1065 | sc->sc_flags |= SC_OP_RFKILL_REGISTERED; | ||
1066 | } | ||
1067 | } | ||
1068 | #endif | ||
1069 | |||
356 | ieee80211_wake_queues(hw); | 1070 | ieee80211_wake_queues(hw); |
357 | return 0; | 1071 | return 0; |
358 | } | 1072 | } |
@@ -414,6 +1128,11 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
414 | "%s: Device is no longer present\n", __func__); | 1128 | "%s: Device is no longer present\n", __func__); |
415 | 1129 | ||
416 | ieee80211_stop_queues(hw); | 1130 | ieee80211_stop_queues(hw); |
1131 | |||
1132 | #ifdef CONFIG_RFKILL | ||
1133 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1134 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
1135 | #endif | ||
417 | } | 1136 | } |
418 | 1137 | ||
419 | static int ath9k_add_interface(struct ieee80211_hw *hw, | 1138 | static int ath9k_add_interface(struct ieee80211_hw *hw, |
@@ -428,13 +1147,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
428 | return -ENOBUFS; | 1147 | return -ENOBUFS; |
429 | 1148 | ||
430 | switch (conf->type) { | 1149 | switch (conf->type) { |
431 | case IEEE80211_IF_TYPE_STA: | 1150 | case NL80211_IFTYPE_STATION: |
432 | ic_opmode = ATH9K_M_STA; | 1151 | ic_opmode = ATH9K_M_STA; |
433 | break; | 1152 | break; |
434 | case IEEE80211_IF_TYPE_IBSS: | 1153 | case NL80211_IFTYPE_ADHOC: |
435 | ic_opmode = ATH9K_M_IBSS; | 1154 | ic_opmode = ATH9K_M_IBSS; |
436 | break; | 1155 | break; |
437 | case IEEE80211_IF_TYPE_AP: | 1156 | case NL80211_IFTYPE_AP: |
438 | ic_opmode = ATH9K_M_HOSTAP; | 1157 | ic_opmode = ATH9K_M_HOSTAP; |
439 | break; | 1158 | break; |
440 | default: | 1159 | default: |
@@ -556,7 +1275,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
556 | 1275 | ||
557 | /* TODO: Need to decide which hw opmode to use for multi-interface | 1276 | /* TODO: Need to decide which hw opmode to use for multi-interface |
558 | * cases */ | 1277 | * cases */ |
559 | if (vif->type == IEEE80211_IF_TYPE_AP && | 1278 | if (vif->type == NL80211_IFTYPE_AP && |
560 | ah->ah_opmode != ATH9K_M_HOSTAP) { | 1279 | ah->ah_opmode != ATH9K_M_HOSTAP) { |
561 | ah->ah_opmode = ATH9K_M_HOSTAP; | 1280 | ah->ah_opmode = ATH9K_M_HOSTAP; |
562 | ath9k_hw_setopmode(ah); | 1281 | ath9k_hw_setopmode(ah); |
@@ -568,8 +1287,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
568 | if ((conf->changed & IEEE80211_IFCC_BSSID) && | 1287 | if ((conf->changed & IEEE80211_IFCC_BSSID) && |
569 | !is_zero_ether_addr(conf->bssid)) { | 1288 | !is_zero_ether_addr(conf->bssid)) { |
570 | switch (vif->type) { | 1289 | switch (vif->type) { |
571 | case IEEE80211_IF_TYPE_STA: | 1290 | case NL80211_IFTYPE_STATION: |
572 | case IEEE80211_IF_TYPE_IBSS: | 1291 | case NL80211_IFTYPE_ADHOC: |
573 | /* Update ratectrl about the new state */ | 1292 | /* Update ratectrl about the new state */ |
574 | ath_rate_newstate(sc, avp); | 1293 | ath_rate_newstate(sc, avp); |
575 | 1294 | ||
@@ -614,8 +1333,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
614 | } | 1333 | } |
615 | 1334 | ||
616 | if ((conf->changed & IEEE80211_IFCC_BEACON) && | 1335 | if ((conf->changed & IEEE80211_IFCC_BEACON) && |
617 | ((vif->type == IEEE80211_IF_TYPE_IBSS) || | 1336 | ((vif->type == NL80211_IFTYPE_ADHOC) || |
618 | (vif->type == IEEE80211_IF_TYPE_AP))) { | 1337 | (vif->type == NL80211_IFTYPE_AP))) { |
619 | /* | 1338 | /* |
620 | * Allocate and setup the beacon frame. | 1339 | * Allocate and setup the beacon frame. |
621 | * | 1340 | * |
@@ -634,7 +1353,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
634 | } | 1353 | } |
635 | 1354 | ||
636 | /* Check for WLAN_CAPABILITY_PRIVACY ? */ | 1355 | /* Check for WLAN_CAPABILITY_PRIVACY ? */ |
637 | if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { | 1356 | if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { |
638 | for (i = 0; i < IEEE80211_WEP_NKID; i++) | 1357 | for (i = 0; i < IEEE80211_WEP_NKID; i++) |
639 | if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) | 1358 | if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) |
640 | ath9k_hw_keysetmac(sc->sc_ah, | 1359 | ath9k_hw_keysetmac(sc->sc_ah, |
@@ -643,7 +1362,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
643 | } | 1362 | } |
644 | 1363 | ||
645 | /* Only legacy IBSS for now */ | 1364 | /* Only legacy IBSS for now */ |
646 | if (vif->type == IEEE80211_IF_TYPE_IBSS) | 1365 | if (vif->type == NL80211_IFTYPE_ADHOC) |
647 | ath_update_chainmask(sc, 0); | 1366 | ath_update_chainmask(sc, 0); |
648 | 1367 | ||
649 | return 0; | 1368 | return 0; |
@@ -686,7 +1405,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, | |||
686 | static void ath9k_sta_notify(struct ieee80211_hw *hw, | 1405 | static void ath9k_sta_notify(struct ieee80211_hw *hw, |
687 | struct ieee80211_vif *vif, | 1406 | struct ieee80211_vif *vif, |
688 | enum sta_notify_cmd cmd, | 1407 | enum sta_notify_cmd cmd, |
689 | const u8 *addr) | 1408 | struct ieee80211_sta *sta) |
690 | { | 1409 | { |
691 | struct ath_softc *sc = hw->priv; | 1410 | struct ath_softc *sc = hw->priv; |
692 | struct ath_node *an; | 1411 | struct ath_node *an; |
@@ -694,19 +1413,18 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, | |||
694 | DECLARE_MAC_BUF(mac); | 1413 | DECLARE_MAC_BUF(mac); |
695 | 1414 | ||
696 | spin_lock_irqsave(&sc->node_lock, flags); | 1415 | spin_lock_irqsave(&sc->node_lock, flags); |
697 | an = ath_node_find(sc, (u8 *) addr); | 1416 | an = ath_node_find(sc, sta->addr); |
698 | spin_unlock_irqrestore(&sc->node_lock, flags); | 1417 | spin_unlock_irqrestore(&sc->node_lock, flags); |
699 | 1418 | ||
700 | switch (cmd) { | 1419 | switch (cmd) { |
701 | case STA_NOTIFY_ADD: | 1420 | case STA_NOTIFY_ADD: |
702 | spin_lock_irqsave(&sc->node_lock, flags); | 1421 | spin_lock_irqsave(&sc->node_lock, flags); |
703 | if (!an) { | 1422 | if (!an) { |
704 | ath_node_attach(sc, (u8 *)addr, 0); | 1423 | ath_node_attach(sc, sta->addr, 0); |
705 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", | 1424 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", |
706 | __func__, | 1425 | __func__, print_mac(mac, sta->addr)); |
707 | print_mac(mac, addr)); | ||
708 | } else { | 1426 | } else { |
709 | ath_node_get(sc, (u8 *)addr); | 1427 | ath_node_get(sc, sta->addr); |
710 | } | 1428 | } |
711 | spin_unlock_irqrestore(&sc->node_lock, flags); | 1429 | spin_unlock_irqrestore(&sc->node_lock, flags); |
712 | break; | 1430 | break; |
@@ -719,7 +1437,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, | |||
719 | ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); | 1437 | ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); |
720 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n", | 1438 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n", |
721 | __func__, | 1439 | __func__, |
722 | print_mac(mac, addr)); | 1440 | print_mac(mac, sta->addr)); |
723 | } | 1441 | } |
724 | break; | 1442 | break; |
725 | default: | 1443 | default: |
@@ -798,117 +1516,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
798 | return ret; | 1516 | return ret; |
799 | } | 1517 | } |
800 | 1518 | ||
801 | static void ath9k_ht_conf(struct ath_softc *sc, | ||
802 | struct ieee80211_bss_conf *bss_conf) | ||
803 | { | ||
804 | #define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) | ||
805 | struct ath_ht_info *ht_info = &sc->sc_ht_info; | ||
806 | |||
807 | if (bss_conf->assoc_ht) { | ||
808 | ht_info->ext_chan_offset = | ||
809 | bss_conf->ht_bss_conf->bss_cap & | ||
810 | IEEE80211_HT_IE_CHA_SEC_OFFSET; | ||
811 | |||
812 | if (!(bss_conf->ht_conf->cap & | ||
813 | IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | ||
814 | (bss_conf->ht_bss_conf->bss_cap & | ||
815 | IEEE80211_HT_IE_CHA_WIDTH)) | ||
816 | ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; | ||
817 | else | ||
818 | ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; | ||
819 | |||
820 | ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); | ||
821 | ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + | ||
822 | bss_conf->ht_conf->ampdu_factor); | ||
823 | ht_info->mpdudensity = | ||
824 | parse_mpdudensity(bss_conf->ht_conf->ampdu_density); | ||
825 | |||
826 | } | ||
827 | |||
828 | #undef IEEE80211_HT_CAP_40MHZ_INTOLERANT | ||
829 | } | ||
830 | |||
831 | static void ath9k_bss_assoc_info(struct ath_softc *sc, | ||
832 | struct ieee80211_bss_conf *bss_conf) | ||
833 | { | ||
834 | struct ieee80211_hw *hw = sc->hw; | ||
835 | struct ieee80211_channel *curchan = hw->conf.channel; | ||
836 | struct ath_vap *avp; | ||
837 | int pos; | ||
838 | DECLARE_MAC_BUF(mac); | ||
839 | |||
840 | if (bss_conf->assoc) { | ||
841 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", | ||
842 | __func__, | ||
843 | bss_conf->aid); | ||
844 | |||
845 | avp = sc->sc_vaps[0]; | ||
846 | if (avp == NULL) { | ||
847 | DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", | ||
848 | __func__); | ||
849 | return; | ||
850 | } | ||
851 | |||
852 | /* New association, store aid */ | ||
853 | if (avp->av_opmode == ATH9K_M_STA) { | ||
854 | sc->sc_curaid = bss_conf->aid; | ||
855 | ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, | ||
856 | sc->sc_curaid); | ||
857 | } | ||
858 | |||
859 | /* Configure the beacon */ | ||
860 | ath_beacon_config(sc, 0); | ||
861 | sc->sc_flags |= SC_OP_BEACONS; | ||
862 | |||
863 | /* Reset rssi stats */ | ||
864 | sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; | ||
865 | sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; | ||
866 | sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; | ||
867 | sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; | ||
868 | |||
869 | /* Update chainmask */ | ||
870 | ath_update_chainmask(sc, bss_conf->assoc_ht); | ||
871 | |||
872 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
873 | "%s: bssid %s aid 0x%x\n", | ||
874 | __func__, | ||
875 | print_mac(mac, sc->sc_curbssid), sc->sc_curaid); | ||
876 | |||
877 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", | ||
878 | __func__, | ||
879 | curchan->center_freq); | ||
880 | |||
881 | pos = ath_get_channel(sc, curchan); | ||
882 | if (pos == -1) { | ||
883 | DPRINTF(sc, ATH_DBG_FATAL, | ||
884 | "%s: Invalid channel\n", __func__); | ||
885 | return; | ||
886 | } | ||
887 | |||
888 | if (hw->conf.ht_conf.ht_supported) | ||
889 | sc->sc_ah->ah_channels[pos].chanmode = | ||
890 | ath_get_extchanmode(sc, curchan); | ||
891 | else | ||
892 | sc->sc_ah->ah_channels[pos].chanmode = | ||
893 | (curchan->band == IEEE80211_BAND_2GHZ) ? | ||
894 | CHANNEL_G : CHANNEL_A; | ||
895 | |||
896 | /* set h/w channel */ | ||
897 | if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) | ||
898 | DPRINTF(sc, ATH_DBG_FATAL, | ||
899 | "%s: Unable to set channel\n", | ||
900 | __func__); | ||
901 | |||
902 | ath_rate_newstate(sc, avp); | ||
903 | /* Update ratectrl about the new state */ | ||
904 | ath_rc_node_update(hw, avp->rc_node); | ||
905 | } else { | ||
906 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
907 | "%s: Bss Info DISSOC\n", __func__); | ||
908 | sc->sc_curaid = 0; | ||
909 | } | ||
910 | } | ||
911 | |||
912 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | 1519 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, |
913 | struct ieee80211_vif *vif, | 1520 | struct ieee80211_vif *vif, |
914 | struct ieee80211_bss_conf *bss_conf, | 1521 | struct ieee80211_bss_conf *bss_conf, |
@@ -973,45 +1580,44 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw) | |||
973 | 1580 | ||
974 | static int ath9k_ampdu_action(struct ieee80211_hw *hw, | 1581 | static int ath9k_ampdu_action(struct ieee80211_hw *hw, |
975 | enum ieee80211_ampdu_mlme_action action, | 1582 | enum ieee80211_ampdu_mlme_action action, |
976 | const u8 *addr, | 1583 | struct ieee80211_sta *sta, |
977 | u16 tid, | 1584 | u16 tid, u16 *ssn) |
978 | u16 *ssn) | ||
979 | { | 1585 | { |
980 | struct ath_softc *sc = hw->priv; | 1586 | struct ath_softc *sc = hw->priv; |
981 | int ret = 0; | 1587 | int ret = 0; |
982 | 1588 | ||
983 | switch (action) { | 1589 | switch (action) { |
984 | case IEEE80211_AMPDU_RX_START: | 1590 | case IEEE80211_AMPDU_RX_START: |
985 | ret = ath_rx_aggr_start(sc, addr, tid, ssn); | 1591 | ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn); |
986 | if (ret < 0) | 1592 | if (ret < 0) |
987 | DPRINTF(sc, ATH_DBG_FATAL, | 1593 | DPRINTF(sc, ATH_DBG_FATAL, |
988 | "%s: Unable to start RX aggregation\n", | 1594 | "%s: Unable to start RX aggregation\n", |
989 | __func__); | 1595 | __func__); |
990 | break; | 1596 | break; |
991 | case IEEE80211_AMPDU_RX_STOP: | 1597 | case IEEE80211_AMPDU_RX_STOP: |
992 | ret = ath_rx_aggr_stop(sc, addr, tid); | 1598 | ret = ath_rx_aggr_stop(sc, sta->addr, tid); |
993 | if (ret < 0) | 1599 | if (ret < 0) |
994 | DPRINTF(sc, ATH_DBG_FATAL, | 1600 | DPRINTF(sc, ATH_DBG_FATAL, |
995 | "%s: Unable to stop RX aggregation\n", | 1601 | "%s: Unable to stop RX aggregation\n", |
996 | __func__); | 1602 | __func__); |
997 | break; | 1603 | break; |
998 | case IEEE80211_AMPDU_TX_START: | 1604 | case IEEE80211_AMPDU_TX_START: |
999 | ret = ath_tx_aggr_start(sc, addr, tid, ssn); | 1605 | ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn); |
1000 | if (ret < 0) | 1606 | if (ret < 0) |
1001 | DPRINTF(sc, ATH_DBG_FATAL, | 1607 | DPRINTF(sc, ATH_DBG_FATAL, |
1002 | "%s: Unable to start TX aggregation\n", | 1608 | "%s: Unable to start TX aggregation\n", |
1003 | __func__); | 1609 | __func__); |
1004 | else | 1610 | else |
1005 | ieee80211_start_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); | 1611 | ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); |
1006 | break; | 1612 | break; |
1007 | case IEEE80211_AMPDU_TX_STOP: | 1613 | case IEEE80211_AMPDU_TX_STOP: |
1008 | ret = ath_tx_aggr_stop(sc, addr, tid); | 1614 | ret = ath_tx_aggr_stop(sc, sta->addr, tid); |
1009 | if (ret < 0) | 1615 | if (ret < 0) |
1010 | DPRINTF(sc, ATH_DBG_FATAL, | 1616 | DPRINTF(sc, ATH_DBG_FATAL, |
1011 | "%s: Unable to stop TX aggregation\n", | 1617 | "%s: Unable to stop TX aggregation\n", |
1012 | __func__); | 1618 | __func__); |
1013 | 1619 | ||
1014 | ieee80211_stop_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); | 1620 | ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); |
1015 | break; | 1621 | break; |
1016 | default: | 1622 | default: |
1017 | DPRINTF(sc, ATH_DBG_FATAL, | 1623 | DPRINTF(sc, ATH_DBG_FATAL, |
@@ -1048,364 +1654,6 @@ static struct ieee80211_ops ath9k_ops = { | |||
1048 | .ampdu_action = ath9k_ampdu_action | 1654 | .ampdu_action = ath9k_ampdu_action |
1049 | }; | 1655 | }; |
1050 | 1656 | ||
1051 | void ath_get_beaconconfig(struct ath_softc *sc, | ||
1052 | int if_id, | ||
1053 | struct ath_beacon_config *conf) | ||
1054 | { | ||
1055 | struct ieee80211_hw *hw = sc->hw; | ||
1056 | |||
1057 | /* fill in beacon config data */ | ||
1058 | |||
1059 | conf->beacon_interval = hw->conf.beacon_int; | ||
1060 | conf->listen_interval = 100; | ||
1061 | conf->dtim_count = 1; | ||
1062 | conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; | ||
1063 | } | ||
1064 | |||
1065 | void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | ||
1066 | struct ath_xmit_status *tx_status, struct ath_node *an) | ||
1067 | { | ||
1068 | struct ieee80211_hw *hw = sc->hw; | ||
1069 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
1070 | |||
1071 | DPRINTF(sc, ATH_DBG_XMIT, | ||
1072 | "%s: TX complete: skb: %p\n", __func__, skb); | ||
1073 | |||
1074 | if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || | ||
1075 | tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { | ||
1076 | /* free driver's private data area of tx_info */ | ||
1077 | if (tx_info->driver_data[0] != NULL) | ||
1078 | kfree(tx_info->driver_data[0]); | ||
1079 | tx_info->driver_data[0] = NULL; | ||
1080 | } | ||
1081 | |||
1082 | if (tx_status->flags & ATH_TX_BAR) { | ||
1083 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | ||
1084 | tx_status->flags &= ~ATH_TX_BAR; | ||
1085 | } | ||
1086 | |||
1087 | if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { | ||
1088 | if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { | ||
1089 | /* Frame was not ACKed, but an ACK was expected */ | ||
1090 | tx_info->status.excessive_retries = 1; | ||
1091 | } | ||
1092 | } else { | ||
1093 | /* Frame was ACKed */ | ||
1094 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | ||
1095 | } | ||
1096 | |||
1097 | tx_info->status.retry_count = tx_status->retries; | ||
1098 | |||
1099 | ieee80211_tx_status(hw, skb); | ||
1100 | if (an) | ||
1101 | ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); | ||
1102 | } | ||
1103 | |||
1104 | int _ath_rx_indicate(struct ath_softc *sc, | ||
1105 | struct sk_buff *skb, | ||
1106 | struct ath_recv_status *status, | ||
1107 | u16 keyix) | ||
1108 | { | ||
1109 | struct ieee80211_hw *hw = sc->hw; | ||
1110 | struct ath_node *an = NULL; | ||
1111 | struct ieee80211_rx_status rx_status; | ||
1112 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1113 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
1114 | int padsize; | ||
1115 | enum ATH_RX_TYPE st; | ||
1116 | |||
1117 | /* see if any padding is done by the hw and remove it */ | ||
1118 | if (hdrlen & 3) { | ||
1119 | padsize = hdrlen % 4; | ||
1120 | memmove(skb->data + padsize, skb->data, hdrlen); | ||
1121 | skb_pull(skb, padsize); | ||
1122 | } | ||
1123 | |||
1124 | /* Prepare rx status */ | ||
1125 | ath9k_rx_prepare(sc, skb, status, &rx_status); | ||
1126 | |||
1127 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && | ||
1128 | !(status->flags & ATH_RX_DECRYPT_ERROR)) { | ||
1129 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
1130 | } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) | ||
1131 | && !(status->flags & ATH_RX_DECRYPT_ERROR) | ||
1132 | && skb->len >= hdrlen + 4) { | ||
1133 | keyix = skb->data[hdrlen + 3] >> 6; | ||
1134 | |||
1135 | if (test_bit(keyix, sc->sc_keymap)) | ||
1136 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
1137 | } | ||
1138 | |||
1139 | spin_lock_bh(&sc->node_lock); | ||
1140 | an = ath_node_find(sc, hdr->addr2); | ||
1141 | spin_unlock_bh(&sc->node_lock); | ||
1142 | |||
1143 | if (an) { | ||
1144 | ath_rx_input(sc, an, | ||
1145 | hw->conf.ht_conf.ht_supported, | ||
1146 | skb, status, &st); | ||
1147 | } | ||
1148 | if (!an || (st != ATH_RX_CONSUMED)) | ||
1149 | __ieee80211_rx(hw, skb, &rx_status); | ||
1150 | |||
1151 | return 0; | ||
1152 | } | ||
1153 | |||
1154 | int ath_rx_subframe(struct ath_node *an, | ||
1155 | struct sk_buff *skb, | ||
1156 | struct ath_recv_status *status) | ||
1157 | { | ||
1158 | struct ath_softc *sc = an->an_sc; | ||
1159 | struct ieee80211_hw *hw = sc->hw; | ||
1160 | struct ieee80211_rx_status rx_status; | ||
1161 | |||
1162 | /* Prepare rx status */ | ||
1163 | ath9k_rx_prepare(sc, skb, status, &rx_status); | ||
1164 | if (!(status->flags & ATH_RX_DECRYPT_ERROR)) | ||
1165 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
1166 | |||
1167 | __ieee80211_rx(hw, skb, &rx_status); | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | /********************************/ | ||
1173 | /* LED functions */ | ||
1174 | /********************************/ | ||
1175 | |||
1176 | static void ath_led_brightness(struct led_classdev *led_cdev, | ||
1177 | enum led_brightness brightness) | ||
1178 | { | ||
1179 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
1180 | struct ath_softc *sc = led->sc; | ||
1181 | |||
1182 | switch (brightness) { | ||
1183 | case LED_OFF: | ||
1184 | if (led->led_type == ATH_LED_ASSOC || | ||
1185 | led->led_type == ATH_LED_RADIO) | ||
1186 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
1187 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, | ||
1188 | (led->led_type == ATH_LED_RADIO) ? 1 : | ||
1189 | !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); | ||
1190 | break; | ||
1191 | case LED_FULL: | ||
1192 | if (led->led_type == ATH_LED_ASSOC) | ||
1193 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; | ||
1194 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); | ||
1195 | break; | ||
1196 | default: | ||
1197 | break; | ||
1198 | } | ||
1199 | } | ||
1200 | |||
1201 | static int ath_register_led(struct ath_softc *sc, struct ath_led *led, | ||
1202 | char *trigger) | ||
1203 | { | ||
1204 | int ret; | ||
1205 | |||
1206 | led->sc = sc; | ||
1207 | led->led_cdev.name = led->name; | ||
1208 | led->led_cdev.default_trigger = trigger; | ||
1209 | led->led_cdev.brightness_set = ath_led_brightness; | ||
1210 | |||
1211 | ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); | ||
1212 | if (ret) | ||
1213 | DPRINTF(sc, ATH_DBG_FATAL, | ||
1214 | "Failed to register led:%s", led->name); | ||
1215 | else | ||
1216 | led->registered = 1; | ||
1217 | return ret; | ||
1218 | } | ||
1219 | |||
1220 | static void ath_unregister_led(struct ath_led *led) | ||
1221 | { | ||
1222 | if (led->registered) { | ||
1223 | led_classdev_unregister(&led->led_cdev); | ||
1224 | led->registered = 0; | ||
1225 | } | ||
1226 | } | ||
1227 | |||
1228 | static void ath_deinit_leds(struct ath_softc *sc) | ||
1229 | { | ||
1230 | ath_unregister_led(&sc->assoc_led); | ||
1231 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
1232 | ath_unregister_led(&sc->tx_led); | ||
1233 | ath_unregister_led(&sc->rx_led); | ||
1234 | ath_unregister_led(&sc->radio_led); | ||
1235 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1236 | } | ||
1237 | |||
1238 | static void ath_init_leds(struct ath_softc *sc) | ||
1239 | { | ||
1240 | char *trigger; | ||
1241 | int ret; | ||
1242 | |||
1243 | /* Configure gpio 1 for output */ | ||
1244 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | ||
1245 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1246 | /* LED off, active low */ | ||
1247 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1248 | |||
1249 | trigger = ieee80211_get_radio_led_name(sc->hw); | ||
1250 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), | ||
1251 | "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); | ||
1252 | ret = ath_register_led(sc, &sc->radio_led, trigger); | ||
1253 | sc->radio_led.led_type = ATH_LED_RADIO; | ||
1254 | if (ret) | ||
1255 | goto fail; | ||
1256 | |||
1257 | trigger = ieee80211_get_assoc_led_name(sc->hw); | ||
1258 | snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), | ||
1259 | "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); | ||
1260 | ret = ath_register_led(sc, &sc->assoc_led, trigger); | ||
1261 | sc->assoc_led.led_type = ATH_LED_ASSOC; | ||
1262 | if (ret) | ||
1263 | goto fail; | ||
1264 | |||
1265 | trigger = ieee80211_get_tx_led_name(sc->hw); | ||
1266 | snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), | ||
1267 | "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); | ||
1268 | ret = ath_register_led(sc, &sc->tx_led, trigger); | ||
1269 | sc->tx_led.led_type = ATH_LED_TX; | ||
1270 | if (ret) | ||
1271 | goto fail; | ||
1272 | |||
1273 | trigger = ieee80211_get_rx_led_name(sc->hw); | ||
1274 | snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), | ||
1275 | "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); | ||
1276 | ret = ath_register_led(sc, &sc->rx_led, trigger); | ||
1277 | sc->rx_led.led_type = ATH_LED_RX; | ||
1278 | if (ret) | ||
1279 | goto fail; | ||
1280 | |||
1281 | return; | ||
1282 | |||
1283 | fail: | ||
1284 | ath_deinit_leds(sc); | ||
1285 | } | ||
1286 | |||
1287 | static int ath_detach(struct ath_softc *sc) | ||
1288 | { | ||
1289 | struct ieee80211_hw *hw = sc->hw; | ||
1290 | |||
1291 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); | ||
1292 | |||
1293 | /* Deinit LED control */ | ||
1294 | ath_deinit_leds(sc); | ||
1295 | |||
1296 | /* Unregister hw */ | ||
1297 | |||
1298 | ieee80211_unregister_hw(hw); | ||
1299 | |||
1300 | /* unregister Rate control */ | ||
1301 | ath_rate_control_unregister(); | ||
1302 | |||
1303 | /* tx/rx cleanup */ | ||
1304 | |||
1305 | ath_rx_cleanup(sc); | ||
1306 | ath_tx_cleanup(sc); | ||
1307 | |||
1308 | /* Deinit */ | ||
1309 | |||
1310 | ath_deinit(sc); | ||
1311 | |||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1315 | static int ath_attach(u16 devid, | ||
1316 | struct ath_softc *sc) | ||
1317 | { | ||
1318 | struct ieee80211_hw *hw = sc->hw; | ||
1319 | int error = 0; | ||
1320 | |||
1321 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); | ||
1322 | |||
1323 | error = ath_init(devid, sc); | ||
1324 | if (error != 0) | ||
1325 | return error; | ||
1326 | |||
1327 | /* Init nodes */ | ||
1328 | |||
1329 | INIT_LIST_HEAD(&sc->node_list); | ||
1330 | spin_lock_init(&sc->node_lock); | ||
1331 | |||
1332 | /* get mac address from hardware and set in mac80211 */ | ||
1333 | |||
1334 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); | ||
1335 | |||
1336 | /* setup channels and rates */ | ||
1337 | |||
1338 | sc->sbands[IEEE80211_BAND_2GHZ].channels = | ||
1339 | sc->channels[IEEE80211_BAND_2GHZ]; | ||
1340 | sc->sbands[IEEE80211_BAND_2GHZ].bitrates = | ||
1341 | sc->rates[IEEE80211_BAND_2GHZ]; | ||
1342 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | ||
1343 | |||
1344 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | ||
1345 | /* Setup HT capabilities for 2.4Ghz*/ | ||
1346 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info); | ||
1347 | |||
1348 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
1349 | &sc->sbands[IEEE80211_BAND_2GHZ]; | ||
1350 | |||
1351 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { | ||
1352 | sc->sbands[IEEE80211_BAND_5GHZ].channels = | ||
1353 | sc->channels[IEEE80211_BAND_5GHZ]; | ||
1354 | sc->sbands[IEEE80211_BAND_5GHZ].bitrates = | ||
1355 | sc->rates[IEEE80211_BAND_5GHZ]; | ||
1356 | sc->sbands[IEEE80211_BAND_5GHZ].band = | ||
1357 | IEEE80211_BAND_5GHZ; | ||
1358 | |||
1359 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | ||
1360 | /* Setup HT capabilities for 5Ghz*/ | ||
1361 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info); | ||
1362 | |||
1363 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
1364 | &sc->sbands[IEEE80211_BAND_5GHZ]; | ||
1365 | } | ||
1366 | |||
1367 | /* FIXME: Have to figure out proper hw init values later */ | ||
1368 | |||
1369 | hw->queues = 4; | ||
1370 | hw->ampdu_queues = 1; | ||
1371 | |||
1372 | /* Register rate control */ | ||
1373 | hw->rate_control_algorithm = "ath9k_rate_control"; | ||
1374 | error = ath_rate_control_register(); | ||
1375 | if (error != 0) { | ||
1376 | DPRINTF(sc, ATH_DBG_FATAL, | ||
1377 | "%s: Unable to register rate control " | ||
1378 | "algorithm:%d\n", __func__, error); | ||
1379 | ath_rate_control_unregister(); | ||
1380 | goto bad; | ||
1381 | } | ||
1382 | |||
1383 | error = ieee80211_register_hw(hw); | ||
1384 | if (error != 0) { | ||
1385 | ath_rate_control_unregister(); | ||
1386 | goto bad; | ||
1387 | } | ||
1388 | |||
1389 | /* Initialize LED control */ | ||
1390 | ath_init_leds(sc); | ||
1391 | |||
1392 | /* initialize tx/rx engine */ | ||
1393 | |||
1394 | error = ath_tx_init(sc, ATH_TXBUF); | ||
1395 | if (error != 0) | ||
1396 | goto detach; | ||
1397 | |||
1398 | error = ath_rx_init(sc, ATH_RXBUF); | ||
1399 | if (error != 0) | ||
1400 | goto detach; | ||
1401 | |||
1402 | return 0; | ||
1403 | detach: | ||
1404 | ath_detach(sc); | ||
1405 | bad: | ||
1406 | return error; | ||
1407 | } | ||
1408 | |||
1409 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 1657 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
1410 | { | 1658 | { |
1411 | void __iomem *mem; | 1659 | void __iomem *mem; |
@@ -1554,6 +1802,12 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
1554 | struct ath_softc *sc = hw->priv; | 1802 | struct ath_softc *sc = hw->priv; |
1555 | 1803 | ||
1556 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 1804 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
1805 | |||
1806 | #ifdef CONFIG_RFKILL | ||
1807 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1808 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
1809 | #endif | ||
1810 | |||
1557 | pci_save_state(pdev); | 1811 | pci_save_state(pdev); |
1558 | pci_disable_device(pdev); | 1812 | pci_disable_device(pdev); |
1559 | pci_set_power_state(pdev, 3); | 1813 | pci_set_power_state(pdev, 3); |
@@ -1586,6 +1840,16 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
1586 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 1840 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
1587 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | 1841 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); |
1588 | 1842 | ||
1843 | #ifdef CONFIG_RFKILL | ||
1844 | /* | ||
1845 | * check the h/w rfkill state on resume | ||
1846 | * and start the rfkill poll timer | ||
1847 | */ | ||
1848 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1849 | queue_delayed_work(sc->hw->workqueue, | ||
1850 | &sc->rf_kill.rfkill_poll, 0); | ||
1851 | #endif | ||
1852 | |||
1589 | return 0; | 1853 | return 0; |
1590 | } | 1854 | } |
1591 | 1855 | ||