diff options
| author | Attila Fazekas <turul64@gmail.com> | 2012-02-23 13:50:35 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2012-03-07 13:56:37 -0500 |
| commit | 41b58f189ada1a12d3c9417c3eedd5b910d8d09f (patch) | |
| tree | a1ce5d4c73b1c3b5650ceef7119a28c87fe5b2c8 /drivers/net/wireless/rtl818x | |
| parent | 0d33cd782990b13d992109d16e11205e1ac547bb (diff) | |
rtl8187: Add AD-HOC support
Add AD-HOC support to the rtl8187 based on the rtl8180 source
Signed-off-by: Attila Fazekas <turul64@gmail.com>
Acked-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rtl818x')
| -rw-r--r-- | drivers/net/wireless/rtl818x/rtl8187/dev.c | 110 | ||||
| -rw-r--r-- | drivers/net/wireless/rtl818x/rtl8187/rtl8187.h | 9 |
2 files changed, 100 insertions, 19 deletions
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 638fbef693e6..cf53ac9d6f23 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. | 8 | * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. |
| 9 | * | 9 | * |
| 10 | * The driver was extended to the RTL8187B in 2008 by: | 10 | * The driver was extended to the RTL8187B in 2008 by: |
| 11 | * Herton Ronaldo Krzesinski <herton@mandriva.com.br> | 11 | * Herton Ronaldo Krzesinski <herton@mandriva.com.br> |
| 12 | * Hin-Tak Leung <htl10@users.sourceforge.net> | 12 | * Hin-Tak Leung <htl10@users.sourceforge.net> |
| 13 | * Larry Finger <Larry.Finger@lwfinger.net> | 13 | * Larry Finger <Larry.Finger@lwfinger.net> |
| 14 | * | 14 | * |
| @@ -232,6 +232,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
| 232 | { | 232 | { |
| 233 | struct rtl8187_priv *priv = dev->priv; | 233 | struct rtl8187_priv *priv = dev->priv; |
| 234 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 234 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 235 | struct ieee80211_hdr *tx_hdr = (struct ieee80211_hdr *)(skb->data); | ||
| 235 | unsigned int ep; | 236 | unsigned int ep; |
| 236 | void *buf; | 237 | void *buf; |
| 237 | struct urb *urb; | 238 | struct urb *urb; |
| @@ -249,7 +250,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
| 249 | flags |= RTL818X_TX_DESC_FLAG_NO_ENC; | 250 | flags |= RTL818X_TX_DESC_FLAG_NO_ENC; |
| 250 | 251 | ||
| 251 | flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; | 252 | flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; |
| 252 | if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) | 253 | if (ieee80211_has_morefrags(tx_hdr->frame_control)) |
| 253 | flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; | 254 | flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; |
| 254 | if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { | 255 | if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { |
| 255 | flags |= RTL818X_TX_DESC_FLAG_RTS; | 256 | flags |= RTL818X_TX_DESC_FLAG_RTS; |
| @@ -261,6 +262,13 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
| 261 | flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; | 262 | flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; |
| 262 | } | 263 | } |
| 263 | 264 | ||
| 265 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | ||
| 266 | if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) | ||
| 267 | priv->seqno += 0x10; | ||
| 268 | tx_hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | ||
| 269 | tx_hdr->seq_ctrl |= cpu_to_le16(priv->seqno); | ||
| 270 | } | ||
| 271 | |||
| 264 | if (!priv->is_rtl8187b) { | 272 | if (!priv->is_rtl8187b) { |
| 265 | struct rtl8187_tx_hdr *hdr = | 273 | struct rtl8187_tx_hdr *hdr = |
| 266 | (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); | 274 | (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); |
| @@ -274,8 +282,6 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
| 274 | } else { | 282 | } else { |
| 275 | /* fc needs to be calculated before skb_push() */ | 283 | /* fc needs to be calculated before skb_push() */ |
| 276 | unsigned int epmap[4] = { 6, 7, 5, 4 }; | 284 | unsigned int epmap[4] = { 6, 7, 5, 4 }; |
| 277 | struct ieee80211_hdr *tx_hdr = | ||
| 278 | (struct ieee80211_hdr *)(skb->data); | ||
| 279 | u16 fc = le16_to_cpu(tx_hdr->frame_control); | 285 | u16 fc = le16_to_cpu(tx_hdr->frame_control); |
| 280 | 286 | ||
| 281 | struct rtl8187b_tx_hdr *hdr = | 287 | struct rtl8187b_tx_hdr *hdr = |
| @@ -1031,10 +1037,61 @@ static void rtl8187_stop(struct ieee80211_hw *dev) | |||
| 1031 | cancel_delayed_work_sync(&priv->work); | 1037 | cancel_delayed_work_sync(&priv->work); |
| 1032 | } | 1038 | } |
| 1033 | 1039 | ||
| 1040 | static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif) | ||
| 1041 | { | ||
| 1042 | struct rtl8187_priv *priv = dev->priv; | ||
| 1043 | |||
| 1044 | return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | | ||
| 1045 | (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | |||
| 1049 | static void rtl8187_beacon_work(struct work_struct *work) | ||
| 1050 | { | ||
| 1051 | struct rtl8187_vif *vif_priv = | ||
| 1052 | container_of(work, struct rtl8187_vif, beacon_work.work); | ||
| 1053 | struct ieee80211_vif *vif = | ||
| 1054 | container_of((void *)vif_priv, struct ieee80211_vif, drv_priv); | ||
| 1055 | struct ieee80211_hw *dev = vif_priv->dev; | ||
| 1056 | struct ieee80211_mgmt *mgmt; | ||
| 1057 | struct sk_buff *skb; | ||
| 1058 | |||
| 1059 | /* don't overflow the tx ring */ | ||
| 1060 | if (ieee80211_queue_stopped(dev, 0)) | ||
| 1061 | goto resched; | ||
| 1062 | |||
| 1063 | /* grab a fresh beacon */ | ||
| 1064 | skb = ieee80211_beacon_get(dev, vif); | ||
| 1065 | if (!skb) | ||
| 1066 | goto resched; | ||
| 1067 | |||
| 1068 | /* | ||
| 1069 | * update beacon timestamp w/ TSF value | ||
| 1070 | * TODO: make hardware update beacon timestamp | ||
| 1071 | */ | ||
| 1072 | mgmt = (struct ieee80211_mgmt *)skb->data; | ||
| 1073 | mgmt->u.beacon.timestamp = cpu_to_le64(rtl8187_get_tsf(dev, vif)); | ||
| 1074 | |||
| 1075 | /* TODO: use actual beacon queue */ | ||
| 1076 | skb_set_queue_mapping(skb, 0); | ||
| 1077 | |||
| 1078 | rtl8187_tx(dev, skb); | ||
| 1079 | |||
| 1080 | resched: | ||
| 1081 | /* | ||
| 1082 | * schedule next beacon | ||
| 1083 | * TODO: use hardware support for beacon timing | ||
| 1084 | */ | ||
| 1085 | schedule_delayed_work(&vif_priv->beacon_work, | ||
| 1086 | usecs_to_jiffies(1024 * vif->bss_conf.beacon_int)); | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | |||
| 1034 | static int rtl8187_add_interface(struct ieee80211_hw *dev, | 1090 | static int rtl8187_add_interface(struct ieee80211_hw *dev, |
| 1035 | struct ieee80211_vif *vif) | 1091 | struct ieee80211_vif *vif) |
| 1036 | { | 1092 | { |
| 1037 | struct rtl8187_priv *priv = dev->priv; | 1093 | struct rtl8187_priv *priv = dev->priv; |
| 1094 | struct rtl8187_vif *vif_priv; | ||
| 1038 | int i; | 1095 | int i; |
| 1039 | int ret = -EOPNOTSUPP; | 1096 | int ret = -EOPNOTSUPP; |
| 1040 | 1097 | ||
| @@ -1044,6 +1101,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, | |||
| 1044 | 1101 | ||
| 1045 | switch (vif->type) { | 1102 | switch (vif->type) { |
| 1046 | case NL80211_IFTYPE_STATION: | 1103 | case NL80211_IFTYPE_STATION: |
| 1104 | case NL80211_IFTYPE_ADHOC: | ||
| 1047 | break; | 1105 | break; |
| 1048 | default: | 1106 | default: |
| 1049 | goto exit; | 1107 | goto exit; |
| @@ -1052,6 +1110,13 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, | |||
| 1052 | ret = 0; | 1110 | ret = 0; |
| 1053 | priv->vif = vif; | 1111 | priv->vif = vif; |
| 1054 | 1112 | ||
| 1113 | /* Initialize driver private area */ | ||
| 1114 | vif_priv = (struct rtl8187_vif *)&vif->drv_priv; | ||
| 1115 | vif_priv->dev = dev; | ||
| 1116 | INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8187_beacon_work); | ||
| 1117 | vif_priv->enable_beacon = false; | ||
| 1118 | |||
| 1119 | |||
| 1055 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); | 1120 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); |
| 1056 | for (i = 0; i < ETH_ALEN; i++) | 1121 | for (i = 0; i < ETH_ALEN; i++) |
| 1057 | rtl818x_iowrite8(priv, &priv->map->MAC[i], | 1122 | rtl818x_iowrite8(priv, &priv->map->MAC[i], |
| @@ -1175,9 +1240,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, | |||
| 1175 | u32 changed) | 1240 | u32 changed) |
| 1176 | { | 1241 | { |
| 1177 | struct rtl8187_priv *priv = dev->priv; | 1242 | struct rtl8187_priv *priv = dev->priv; |
| 1243 | struct rtl8187_vif *vif_priv; | ||
| 1178 | int i; | 1244 | int i; |
| 1179 | u8 reg; | 1245 | u8 reg; |
| 1180 | 1246 | ||
| 1247 | vif_priv = (struct rtl8187_vif *)&vif->drv_priv; | ||
| 1248 | |||
| 1181 | if (changed & BSS_CHANGED_BSSID) { | 1249 | if (changed & BSS_CHANGED_BSSID) { |
| 1182 | mutex_lock(&priv->conf_mutex); | 1250 | mutex_lock(&priv->conf_mutex); |
| 1183 | for (i = 0; i < ETH_ALEN; i++) | 1251 | for (i = 0; i < ETH_ALEN; i++) |
| @@ -1189,8 +1257,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, | |||
| 1189 | else | 1257 | else |
| 1190 | reg = 0; | 1258 | reg = 0; |
| 1191 | 1259 | ||
| 1192 | if (is_valid_ether_addr(info->bssid)) | 1260 | if (is_valid_ether_addr(info->bssid)) { |
| 1193 | reg |= RTL818X_MSR_INFRA; | 1261 | if (vif->type == NL80211_IFTYPE_ADHOC) |
| 1262 | reg |= RTL818X_MSR_ADHOC; | ||
| 1263 | else | ||
| 1264 | reg |= RTL818X_MSR_INFRA; | ||
| 1265 | } | ||
| 1194 | else | 1266 | else |
| 1195 | reg |= RTL818X_MSR_NO_LINK; | 1267 | reg |= RTL818X_MSR_NO_LINK; |
| 1196 | 1268 | ||
| @@ -1202,6 +1274,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, | |||
| 1202 | if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) | 1274 | if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) |
| 1203 | rtl8187_conf_erp(priv, info->use_short_slot, | 1275 | rtl8187_conf_erp(priv, info->use_short_slot, |
| 1204 | info->use_short_preamble); | 1276 | info->use_short_preamble); |
| 1277 | |||
| 1278 | if (changed & BSS_CHANGED_BEACON_ENABLED) | ||
| 1279 | vif_priv->enable_beacon = info->enable_beacon; | ||
| 1280 | |||
| 1281 | if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) { | ||
| 1282 | cancel_delayed_work_sync(&vif_priv->beacon_work); | ||
| 1283 | if (vif_priv->enable_beacon) | ||
| 1284 | schedule_work(&vif_priv->beacon_work.work); | ||
| 1285 | } | ||
| 1286 | |||
| 1205 | } | 1287 | } |
| 1206 | 1288 | ||
| 1207 | static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev, | 1289 | static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev, |
| @@ -1279,13 +1361,6 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, | |||
| 1279 | return 0; | 1361 | return 0; |
| 1280 | } | 1362 | } |
| 1281 | 1363 | ||
| 1282 | static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif) | ||
| 1283 | { | ||
| 1284 | struct rtl8187_priv *priv = dev->priv; | ||
| 1285 | |||
| 1286 | return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | | ||
| 1287 | (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; | ||
| 1288 | } | ||
| 1289 | 1364 | ||
| 1290 | static const struct ieee80211_ops rtl8187_ops = { | 1365 | static const struct ieee80211_ops rtl8187_ops = { |
| 1291 | .tx = rtl8187_tx, | 1366 | .tx = rtl8187_tx, |
| @@ -1514,12 +1589,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, | |||
| 1514 | if (reg & 0xFF00) | 1589 | if (reg & 0xFF00) |
| 1515 | priv->rfkill_mask = RFKILL_MASK_8198; | 1590 | priv->rfkill_mask = RFKILL_MASK_8198; |
| 1516 | } | 1591 | } |
| 1517 | 1592 | dev->vif_data_size = sizeof(struct rtl8187_vif); | |
| 1518 | /* | 1593 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
| 1519 | * XXX: Once this driver supports anything that requires | 1594 | BIT(NL80211_IFTYPE_ADHOC) ; |
| 1520 | * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. | ||
| 1521 | */ | ||
| 1522 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
| 1523 | 1595 | ||
| 1524 | if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) | 1596 | if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) |
| 1525 | printk(KERN_INFO "rtl8187: inconsistency between id with OEM" | 1597 | printk(KERN_INFO "rtl8187: inconsistency between id with OEM" |
diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h index f1cc90751dbf..e19a20a8e955 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h | |||
| @@ -89,6 +89,14 @@ enum { | |||
| 89 | DEVICE_RTL8187B | 89 | DEVICE_RTL8187B |
| 90 | }; | 90 | }; |
| 91 | 91 | ||
| 92 | struct rtl8187_vif { | ||
| 93 | struct ieee80211_hw *dev; | ||
| 94 | |||
| 95 | /* beaconing */ | ||
| 96 | struct delayed_work beacon_work; | ||
| 97 | bool enable_beacon; | ||
| 98 | }; | ||
| 99 | |||
| 92 | struct rtl8187_priv { | 100 | struct rtl8187_priv { |
| 93 | /* common between rtl818x drivers */ | 101 | /* common between rtl818x drivers */ |
| 94 | struct rtl818x_csr *map; | 102 | struct rtl818x_csr *map; |
| @@ -141,6 +149,7 @@ struct rtl8187_priv { | |||
| 141 | __le32 bits32; | 149 | __le32 bits32; |
| 142 | } *io_dmabuf; | 150 | } *io_dmabuf; |
| 143 | bool rfkill_off; | 151 | bool rfkill_off; |
| 152 | u16 seqno; | ||
| 144 | }; | 153 | }; |
| 145 | 154 | ||
| 146 | void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); | 155 | void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); |
