Commit 41b58f18 authored by Attila Fazekas's avatar Attila Fazekas Committed by John W. Linville

rtl8187: Add AD-HOC support

Add AD-HOC support to the rtl8187 based on the rtl8180 source
Signed-off-by: default avatarAttila Fazekas <turul64@gmail.com>
Acked-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 0d33cd78
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
* *
* The driver was extended to the RTL8187B in 2008 by: * The driver was extended to the RTL8187B in 2008 by:
* Herton Ronaldo Krzesinski <herton@mandriva.com.br> * Herton Ronaldo Krzesinski <herton@mandriva.com.br>
* Hin-Tak Leung <htl10@users.sourceforge.net> * Hin-Tak Leung <htl10@users.sourceforge.net>
* Larry Finger <Larry.Finger@lwfinger.net> * Larry Finger <Larry.Finger@lwfinger.net>
* *
...@@ -232,6 +232,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -232,6 +232,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{ {
struct rtl8187_priv *priv = dev->priv; struct rtl8187_priv *priv = dev->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *tx_hdr = (struct ieee80211_hdr *)(skb->data);
unsigned int ep; unsigned int ep;
void *buf; void *buf;
struct urb *urb; struct urb *urb;
...@@ -249,7 +250,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -249,7 +250,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
flags |= RTL818X_TX_DESC_FLAG_NO_ENC; flags |= RTL818X_TX_DESC_FLAG_NO_ENC;
flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) if (ieee80211_has_morefrags(tx_hdr->frame_control))
flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
flags |= RTL818X_TX_DESC_FLAG_RTS; flags |= RTL818X_TX_DESC_FLAG_RTS;
...@@ -261,6 +262,13 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -261,6 +262,13 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
} }
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
priv->seqno += 0x10;
tx_hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
tx_hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
}
if (!priv->is_rtl8187b) { if (!priv->is_rtl8187b) {
struct rtl8187_tx_hdr *hdr = struct rtl8187_tx_hdr *hdr =
(struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); (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,8 +282,6 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
} else { } else {
/* fc needs to be calculated before skb_push() */ /* fc needs to be calculated before skb_push() */
unsigned int epmap[4] = { 6, 7, 5, 4 }; unsigned int epmap[4] = { 6, 7, 5, 4 };
struct ieee80211_hdr *tx_hdr =
(struct ieee80211_hdr *)(skb->data);
u16 fc = le16_to_cpu(tx_hdr->frame_control); u16 fc = le16_to_cpu(tx_hdr->frame_control);
struct rtl8187b_tx_hdr *hdr = struct rtl8187b_tx_hdr *hdr =
...@@ -1031,10 +1037,61 @@ static void rtl8187_stop(struct ieee80211_hw *dev) ...@@ -1031,10 +1037,61 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
cancel_delayed_work_sync(&priv->work); cancel_delayed_work_sync(&priv->work);
} }
static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
{
struct rtl8187_priv *priv = dev->priv;
return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
(u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
}
static void rtl8187_beacon_work(struct work_struct *work)
{
struct rtl8187_vif *vif_priv =
container_of(work, struct rtl8187_vif, beacon_work.work);
struct ieee80211_vif *vif =
container_of((void *)vif_priv, struct ieee80211_vif, drv_priv);
struct ieee80211_hw *dev = vif_priv->dev;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
/* don't overflow the tx ring */
if (ieee80211_queue_stopped(dev, 0))
goto resched;
/* grab a fresh beacon */
skb = ieee80211_beacon_get(dev, vif);
if (!skb)
goto resched;
/*
* update beacon timestamp w/ TSF value
* TODO: make hardware update beacon timestamp
*/
mgmt = (struct ieee80211_mgmt *)skb->data;
mgmt->u.beacon.timestamp = cpu_to_le64(rtl8187_get_tsf(dev, vif));
/* TODO: use actual beacon queue */
skb_set_queue_mapping(skb, 0);
rtl8187_tx(dev, skb);
resched:
/*
* schedule next beacon
* TODO: use hardware support for beacon timing
*/
schedule_delayed_work(&vif_priv->beacon_work,
usecs_to_jiffies(1024 * vif->bss_conf.beacon_int));
}
static int rtl8187_add_interface(struct ieee80211_hw *dev, static int rtl8187_add_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct rtl8187_priv *priv = dev->priv; struct rtl8187_priv *priv = dev->priv;
struct rtl8187_vif *vif_priv;
int i; int i;
int ret = -EOPNOTSUPP; int ret = -EOPNOTSUPP;
...@@ -1044,6 +1101,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, ...@@ -1044,6 +1101,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
break; break;
default: default:
goto exit; goto exit;
...@@ -1052,6 +1110,13 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, ...@@ -1052,6 +1110,13 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
ret = 0; ret = 0;
priv->vif = vif; priv->vif = vif;
/* Initialize driver private area */
vif_priv = (struct rtl8187_vif *)&vif->drv_priv;
vif_priv->dev = dev;
INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8187_beacon_work);
vif_priv->enable_beacon = false;
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
for (i = 0; i < ETH_ALEN; i++) for (i = 0; i < ETH_ALEN; i++)
rtl818x_iowrite8(priv, &priv->map->MAC[i], rtl818x_iowrite8(priv, &priv->map->MAC[i],
...@@ -1175,9 +1240,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, ...@@ -1175,9 +1240,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
u32 changed) u32 changed)
{ {
struct rtl8187_priv *priv = dev->priv; struct rtl8187_priv *priv = dev->priv;
struct rtl8187_vif *vif_priv;
int i; int i;
u8 reg; u8 reg;
vif_priv = (struct rtl8187_vif *)&vif->drv_priv;
if (changed & BSS_CHANGED_BSSID) { if (changed & BSS_CHANGED_BSSID) {
mutex_lock(&priv->conf_mutex); mutex_lock(&priv->conf_mutex);
for (i = 0; i < ETH_ALEN; i++) for (i = 0; i < ETH_ALEN; i++)
...@@ -1189,8 +1257,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, ...@@ -1189,8 +1257,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
else else
reg = 0; reg = 0;
if (is_valid_ether_addr(info->bssid)) if (is_valid_ether_addr(info->bssid)) {
reg |= RTL818X_MSR_INFRA; if (vif->type == NL80211_IFTYPE_ADHOC)
reg |= RTL818X_MSR_ADHOC;
else
reg |= RTL818X_MSR_INFRA;
}
else else
reg |= RTL818X_MSR_NO_LINK; reg |= RTL818X_MSR_NO_LINK;
...@@ -1202,6 +1274,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, ...@@ -1202,6 +1274,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE))
rtl8187_conf_erp(priv, info->use_short_slot, rtl8187_conf_erp(priv, info->use_short_slot,
info->use_short_preamble); info->use_short_preamble);
if (changed & BSS_CHANGED_BEACON_ENABLED)
vif_priv->enable_beacon = info->enable_beacon;
if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) {
cancel_delayed_work_sync(&vif_priv->beacon_work);
if (vif_priv->enable_beacon)
schedule_work(&vif_priv->beacon_work.work);
}
} }
static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev, static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev,
...@@ -1279,13 +1361,6 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, ...@@ -1279,13 +1361,6 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev,
return 0; return 0;
} }
static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
{
struct rtl8187_priv *priv = dev->priv;
return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
(u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
}
static const struct ieee80211_ops rtl8187_ops = { static const struct ieee80211_ops rtl8187_ops = {
.tx = rtl8187_tx, .tx = rtl8187_tx,
...@@ -1514,12 +1589,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, ...@@ -1514,12 +1589,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
if (reg & 0xFF00) if (reg & 0xFF00)
priv->rfkill_mask = RFKILL_MASK_8198; priv->rfkill_mask = RFKILL_MASK_8198;
} }
dev->vif_data_size = sizeof(struct rtl8187_vif);
/* dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
* XXX: Once this driver supports anything that requires BIT(NL80211_IFTYPE_ADHOC) ;
* beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ.
*/
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
printk(KERN_INFO "rtl8187: inconsistency between id with OEM" printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
......
...@@ -89,6 +89,14 @@ enum { ...@@ -89,6 +89,14 @@ enum {
DEVICE_RTL8187B DEVICE_RTL8187B
}; };
struct rtl8187_vif {
struct ieee80211_hw *dev;
/* beaconing */
struct delayed_work beacon_work;
bool enable_beacon;
};
struct rtl8187_priv { struct rtl8187_priv {
/* common between rtl818x drivers */ /* common between rtl818x drivers */
struct rtl818x_csr *map; struct rtl818x_csr *map;
...@@ -141,6 +149,7 @@ struct rtl8187_priv { ...@@ -141,6 +149,7 @@ struct rtl8187_priv {
__le32 bits32; __le32 bits32;
} *io_dmabuf; } *io_dmabuf;
bool rfkill_off; bool rfkill_off;
u16 seqno;
}; };
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment