diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-05-06 16:49:40 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-05-07 14:57:09 -0400 |
commit | c809e86c11a64488acc85ddf12ece3c9b879ccb6 (patch) | |
tree | b687b263154bc6e0cf84cc35f81bb782c5677192 /drivers/net/wireless | |
parent | 51e080deba57437459571f26a3c6f3db03324c4c (diff) |
rtl8180: add software-based support for IBSS mode
Device documentation suggests that hardware support for beaconing
is available. But I implemented software-based beacon generation
as an experiment and it seems better to have that working now rather
than waiting for something better to materialize.
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/rtl818x/rtl8180.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/rtl818x/rtl8180_dev.c | 82 |
2 files changed, 80 insertions, 10 deletions
diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h index b92d678abc0c..4baf0cf0826f 100644 --- a/drivers/net/wireless/rtl818x/rtl8180.h +++ b/drivers/net/wireless/rtl818x/rtl8180.h | |||
@@ -55,6 +55,14 @@ struct rtl8180_tx_ring { | |||
55 | struct sk_buff_head queue; | 55 | struct sk_buff_head queue; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct rtl8180_vif { | ||
59 | struct ieee80211_hw *dev; | ||
60 | |||
61 | /* beaconing */ | ||
62 | struct delayed_work beacon_work; | ||
63 | bool enable_beacon; | ||
64 | }; | ||
65 | |||
58 | struct rtl8180_priv { | 66 | struct rtl8180_priv { |
59 | /* common between rtl818x drivers */ | 67 | /* common between rtl818x drivers */ |
60 | struct rtl818x_csr __iomem *map; | 68 | struct rtl818x_csr __iomem *map; |
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 3a214d7507a5..cbdc5cfec90c 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c | |||
@@ -662,10 +662,59 @@ static void rtl8180_stop(struct ieee80211_hw *dev) | |||
662 | rtl8180_free_tx_ring(dev, i); | 662 | rtl8180_free_tx_ring(dev, i); |
663 | } | 663 | } |
664 | 664 | ||
665 | static u64 rtl8180_get_tsf(struct ieee80211_hw *dev) | ||
666 | { | ||
667 | struct rtl8180_priv *priv = dev->priv; | ||
668 | |||
669 | return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | | ||
670 | (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; | ||
671 | } | ||
672 | |||
673 | void rtl8180_beacon_work(struct work_struct *work) | ||
674 | { | ||
675 | struct rtl8180_vif *vif_priv = | ||
676 | container_of(work, struct rtl8180_vif, beacon_work.work); | ||
677 | struct ieee80211_vif *vif = | ||
678 | container_of((void *)vif_priv, struct ieee80211_vif, drv_priv); | ||
679 | struct ieee80211_hw *dev = vif_priv->dev; | ||
680 | struct ieee80211_mgmt *mgmt; | ||
681 | struct sk_buff *skb; | ||
682 | int err = 0; | ||
683 | |||
684 | /* don't overflow the tx ring */ | ||
685 | if (ieee80211_queue_stopped(dev, 0)) | ||
686 | goto resched; | ||
687 | |||
688 | /* grab a fresh beacon */ | ||
689 | skb = ieee80211_beacon_get(dev, vif); | ||
690 | |||
691 | /* | ||
692 | * update beacon timestamp w/ TSF value | ||
693 | * TODO: make hardware update beacon timestamp | ||
694 | */ | ||
695 | mgmt = (struct ieee80211_mgmt *)skb->data; | ||
696 | mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev)); | ||
697 | |||
698 | /* TODO: use actual beacon queue */ | ||
699 | skb_set_queue_mapping(skb, 0); | ||
700 | |||
701 | err = rtl8180_tx(dev, skb); | ||
702 | WARN_ON(err); | ||
703 | |||
704 | resched: | ||
705 | /* | ||
706 | * schedule next beacon | ||
707 | * TODO: use hardware support for beacon timing | ||
708 | */ | ||
709 | schedule_delayed_work(&vif_priv->beacon_work, | ||
710 | usecs_to_jiffies(1024 * vif->bss_conf.beacon_int)); | ||
711 | } | ||
712 | |||
665 | static int rtl8180_add_interface(struct ieee80211_hw *dev, | 713 | static int rtl8180_add_interface(struct ieee80211_hw *dev, |
666 | struct ieee80211_vif *vif) | 714 | struct ieee80211_vif *vif) |
667 | { | 715 | { |
668 | struct rtl8180_priv *priv = dev->priv; | 716 | struct rtl8180_priv *priv = dev->priv; |
717 | struct rtl8180_vif *vif_priv; | ||
669 | 718 | ||
670 | /* | 719 | /* |
671 | * We only support one active interface at a time. | 720 | * We only support one active interface at a time. |
@@ -675,6 +724,7 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev, | |||
675 | 724 | ||
676 | switch (vif->type) { | 725 | switch (vif->type) { |
677 | case NL80211_IFTYPE_STATION: | 726 | case NL80211_IFTYPE_STATION: |
727 | case NL80211_IFTYPE_ADHOC: | ||
678 | break; | 728 | break; |
679 | default: | 729 | default: |
680 | return -EOPNOTSUPP; | 730 | return -EOPNOTSUPP; |
@@ -682,6 +732,12 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev, | |||
682 | 732 | ||
683 | priv->vif = vif; | 733 | priv->vif = vif; |
684 | 734 | ||
735 | /* Initialize driver private area */ | ||
736 | vif_priv = (struct rtl8180_vif *)&vif->drv_priv; | ||
737 | vif_priv->dev = dev; | ||
738 | INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8180_beacon_work); | ||
739 | vif_priv->enable_beacon = false; | ||
740 | |||
685 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); | 741 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); |
686 | rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], | 742 | rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], |
687 | le32_to_cpu(*(__le32 *)vif->addr)); | 743 | le32_to_cpu(*(__le32 *)vif->addr)); |
@@ -715,8 +771,11 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, | |||
715 | u32 changed) | 771 | u32 changed) |
716 | { | 772 | { |
717 | struct rtl8180_priv *priv = dev->priv; | 773 | struct rtl8180_priv *priv = dev->priv; |
774 | struct rtl8180_vif *vif_priv; | ||
718 | int i; | 775 | int i; |
719 | 776 | ||
777 | vif_priv = (struct rtl8180_vif *)&vif->drv_priv; | ||
778 | |||
720 | if (changed & BSS_CHANGED_BSSID) { | 779 | if (changed & BSS_CHANGED_BSSID) { |
721 | for (i = 0; i < ETH_ALEN; i++) | 780 | for (i = 0; i < ETH_ALEN; i++) |
722 | rtl818x_iowrite8(priv, &priv->map->BSSID[i], | 781 | rtl818x_iowrite8(priv, &priv->map->BSSID[i], |
@@ -731,7 +790,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, | |||
731 | } | 790 | } |
732 | 791 | ||
733 | if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) | 792 | if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) |
734 | priv->rf->conf_erp(dev, info); | 793 | priv->rf->conf_erp(dev, info); |
794 | |||
795 | if (changed & BSS_CHANGED_BEACON_ENABLED) | ||
796 | vif_priv->enable_beacon = info->enable_beacon; | ||
797 | |||
798 | if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) { | ||
799 | cancel_delayed_work_sync(&vif_priv->beacon_work); | ||
800 | if (vif_priv->enable_beacon) | ||
801 | schedule_work(&vif_priv->beacon_work.work); | ||
802 | } | ||
735 | } | 803 | } |
736 | 804 | ||
737 | static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count, | 805 | static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count, |
@@ -772,14 +840,6 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev, | |||
772 | rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); | 840 | rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); |
773 | } | 841 | } |
774 | 842 | ||
775 | static u64 rtl8180_get_tsf(struct ieee80211_hw *dev) | ||
776 | { | ||
777 | struct rtl8180_priv *priv = dev->priv; | ||
778 | |||
779 | return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | | ||
780 | (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; | ||
781 | } | ||
782 | |||
783 | static const struct ieee80211_ops rtl8180_ops = { | 843 | static const struct ieee80211_ops rtl8180_ops = { |
784 | .tx = rtl8180_tx, | 844 | .tx = rtl8180_tx, |
785 | .start = rtl8180_start, | 845 | .start = rtl8180_start, |
@@ -916,7 +976,9 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, | |||
916 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 976 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
917 | IEEE80211_HW_RX_INCLUDES_FCS | | 977 | IEEE80211_HW_RX_INCLUDES_FCS | |
918 | IEEE80211_HW_SIGNAL_UNSPEC; | 978 | IEEE80211_HW_SIGNAL_UNSPEC; |
919 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | 979 | dev->vif_data_size = sizeof(struct rtl8180_vif); |
980 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
981 | BIT(NL80211_IFTYPE_ADHOC); | ||
920 | dev->queues = 1; | 982 | dev->queues = 1; |
921 | dev->max_signal = 65; | 983 | dev->max_signal = 65; |
922 | 984 | ||