aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rtl818x
diff options
context:
space:
mode:
authorAttila Fazekas <turul64@gmail.com>2012-02-23 13:50:35 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-03-07 13:56:37 -0500
commit41b58f189ada1a12d3c9417c3eedd5b910d8d09f (patch)
treea1ce5d4c73b1c3b5650ceef7119a28c87fe5b2c8 /drivers/net/wireless/rtl818x
parent0d33cd782990b13d992109d16e11205e1ac547bb (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.c110
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rtl8187.h9
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
1040static 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
1049static 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
1080resched:
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
1034static int rtl8187_add_interface(struct ieee80211_hw *dev, 1090static 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
1207static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev, 1289static 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
1282static 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
1290static const struct ieee80211_ops rtl8187_ops = { 1365static 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
92struct rtl8187_vif {
93 struct ieee80211_hw *dev;
94
95 /* beaconing */
96 struct delayed_work beacon_work;
97 bool enable_beacon;
98};
99
92struct rtl8187_priv { 100struct 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
146void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); 155void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);