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 | |
| 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>
| -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 | ||
