diff options
Diffstat (limited to 'drivers/net/wireless/ath/ar5523/ar5523.c')
| -rw-r--r-- | drivers/net/wireless/ath/ar5523/ar5523.c | 127 |
1 files changed, 78 insertions, 49 deletions
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 17d7fece35d2..1230e6278f23 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -25,7 +25,6 @@ * that and only has minimal functionality. */ #include <linux/compiler.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/list.h> @@ -75,7 +74,7 @@ static void ar5523_read_reply(struct ar5523 *ar, struct ar5523_cmd_hdr *hdr, if (cmd->odata) { if (cmd->olen < olen) { - ar5523_err(ar, "olen to small %d < %d\n", + ar5523_err(ar, "olen too small %d < %d\n", cmd->olen, olen); cmd->olen = 0; cmd->res = -EOVERFLOW; @@ -105,7 +104,7 @@ static void ar5523_cmd_rx_cb(struct urb *urb) } if (urb->actual_length < sizeof(struct ar5523_cmd_hdr)) { - ar5523_err(ar, "RX USB to short.\n"); + ar5523_err(ar, "RX USB too short.\n"); goto skip; } @@ -154,6 +153,10 @@ static void ar5523_cmd_rx_cb(struct urb *urb) ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START"); return; } + if (!cmd->odata) { + ar5523_err(ar, "Unexpected WDCMSG_TARGET_START reply"); + return; + } memcpy(cmd->odata, hdr + 1, sizeof(u32)); cmd->olen = sizeof(u32); cmd->res = 0; @@ -238,6 +241,11 @@ static void ar5523_cmd_tx_cb(struct urb *urb) } } +static void ar5523_cancel_tx_cmd(struct ar5523 *ar) +{ + usb_kill_urb(ar->tx_cmd.urb_tx); +} + static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata, int ilen, void *odata, int olen, int flags) { @@ -248,7 +256,7 @@ static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata, /* always bulk-out a multiple of 4 bytes */ xferlen = (sizeof(struct ar5523_cmd_hdr) + ilen + 3) & ~3; - hdr = (struct ar5523_cmd_hdr *)cmd->buf_tx; + hdr = cmd->buf_tx; memset(hdr, 0, sizeof(struct ar5523_cmd_hdr)); hdr->len = cpu_to_be32(xferlen); hdr->code = cpu_to_be32(code); @@ -256,7 +264,8 @@ static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata, if (flags & AR5523_CMD_FLAG_MAGIC) hdr->magic = cpu_to_be32(1 << 24); - memcpy(hdr + 1, idata, ilen); + if (ilen) + memcpy(hdr + 1, idata, ilen); cmd->odata = odata; cmd->olen = olen; @@ -276,6 +285,7 @@ static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata, } if (!wait_for_completion_timeout(&cmd->done, 2 * HZ)) { + ar5523_cancel_tx_cmd(ar); cmd->odata = NULL; ar5523_err(ar, "timeout waiting for command %02x reply\n", code); @@ -707,10 +717,8 @@ static int ar5523_alloc_rx_bufs(struct ar5523 *ar) data->ar = ar; data->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!data->urb) { - ar5523_err(ar, "could not allocate rx data urb\n"); + if (!data->urb) goto err; - } list_add_tail(&data->list, &ar->rx_data_free); atomic_inc(&ar->rx_data_free_cnt); } @@ -725,7 +733,7 @@ static void ar5523_data_tx_pkt_put(struct ar5523 *ar) { atomic_dec(&ar->tx_nr_total); if (!atomic_dec_return(&ar->tx_nr_pending)) { - del_timer(&ar->tx_wd_timer); + timer_delete(&ar->tx_wd_timer); wake_up(&ar->tx_flush_waitq); } @@ -780,8 +788,6 @@ static void ar5523_tx(struct ieee80211_hw *hw, ieee80211_stop_queues(hw); } - data->skb = skb; - spin_lock_irqsave(&ar->tx_data_list_lock, flags); list_add_tail(&data->list, &ar->tx_queue_pending); spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); @@ -818,13 +824,15 @@ static void ar5523_tx_work_locked(struct ar5523 *ar) if (!data) break; - skb = data->skb; + txi = container_of((void *)data, struct ieee80211_tx_info, + driver_data); txqid = 0; - txi = IEEE80211_SKB_CB(skb); + + skb = container_of((void *)txi, struct sk_buff, cb); paylen = skb->len; + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { - ar5523_err(ar, "Failed to allocate TX urb\n"); ieee80211_free_txskb(ar->hw, skb); continue; } @@ -832,8 +840,8 @@ static void ar5523_tx_work_locked(struct ar5523 *ar) data->ar = ar; data->urb = urb; - desc = (struct ar5523_tx_desc *)skb_push(skb, sizeof(*desc)); - chunk = (struct ar5523_chunk *)skb_push(skb, sizeof(*chunk)); + desc = skb_push(skb, sizeof(*desc)); + chunk = skb_push(skb, sizeof(*chunk)); chunk->seqnum = 0; chunk->flags = UATH_CFLAGS_FINAL; @@ -892,9 +900,9 @@ static void ar5523_tx_work(struct work_struct *work) mutex_unlock(&ar->mutex); } -static void ar5523_tx_wd_timer(unsigned long arg) +static void ar5523_tx_wd_timer(struct timer_list *t) { - struct ar5523 *ar = (struct ar5523 *) arg; + struct ar5523 *ar = timer_container_of(ar, t, tx_wd_timer); ar5523_dbg(ar, "TX watchdog timer triggered\n"); ieee80211_queue_work(ar->hw, &ar->tx_wd_work); @@ -949,10 +957,8 @@ static int ar5523_alloc_tx_cmd(struct ar5523 *ar) init_completion(&cmd->done); cmd->urb_tx = usb_alloc_urb(0, GFP_KERNEL); - if (!cmd->urb_tx) { - ar5523_err(ar, "could not allocate urb\n"); + if (!cmd->urb_tx) return -ENOMEM; - } cmd->buf_tx = usb_alloc_coherent(ar->dev, AR5523_MAX_TXCMDSZ, GFP_KERNEL, &cmd->urb_tx->transfer_dma); @@ -1055,7 +1061,7 @@ err: return error; } -static void ar5523_stop(struct ieee80211_hw *hw) +static void ar5523_stop(struct ieee80211_hw *hw, bool suspend) { struct ar5523 *ar = hw->priv; @@ -1070,14 +1076,15 @@ static void ar5523_stop(struct ieee80211_hw *hw) ar5523_cmd_write(ar, WDCMSG_TARGET_STOP, NULL, 0, 0); - del_timer_sync(&ar->tx_wd_timer); + timer_delete_sync(&ar->tx_wd_timer); cancel_work_sync(&ar->tx_wd_work); cancel_work_sync(&ar->rx_refill_work); ar5523_cancel_rx_bufs(ar); mutex_unlock(&ar->mutex); } -static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct ar5523 *ar = hw->priv; int ret; @@ -1091,7 +1098,8 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ar5523_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ar5523 *ar = hw->priv; @@ -1130,7 +1138,7 @@ static void ar5523_remove_interface(struct ieee80211_hw *hw, ar->vif = NULL; } -static int ar5523_hwconfig(struct ieee80211_hw *hw, u32 changed) +static int ar5523_hwconfig(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ar5523 *ar = hw->priv; @@ -1159,7 +1167,7 @@ static int ar5523_get_wlan_mode(struct ar5523 *ar, ar5523_info(ar, "STA not found!\n"); return WLAN_MODE_11b; } - sta_rate_set = sta->supp_rates[ar->hw->conf.chandef.chan->band]; + sta_rate_set = sta->deflink.supp_rates[ar->hw->conf.chandef.chan->band]; for (bit = 0; bit < band->n_bitrates; bit++) { if (sta_rate_set & 1) { @@ -1197,7 +1205,7 @@ static void ar5523_create_rateset(struct ar5523 *ar, ar5523_info(ar, "STA not found. Cannot set rates\n"); sta_rate_set = bss_conf->basic_rates; } else - sta_rate_set = sta->supp_rates[ar->hw->conf.chandef.chan->band]; + sta_rate_set = sta->deflink.supp_rates[ar->hw->conf.chandef.chan->band]; ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set); @@ -1255,14 +1263,14 @@ static int ar5523_create_connection(struct ar5523 *ar, sizeof(create), 0); } -static int ar5523_write_associd(struct ar5523 *ar, - struct ieee80211_bss_conf *bss) +static int ar5523_write_associd(struct ar5523 *ar, struct ieee80211_vif *vif) { + struct ieee80211_bss_conf *bss = &vif->bss_conf; struct ar5523_cmd_set_associd associd; memset(&associd, 0, sizeof(associd)); associd.defaultrateix = cpu_to_be32(0); /* XXX */ - associd.associd = cpu_to_be32(bss->aid); + associd.associd = cpu_to_be32(vif->cfg.aid); associd.timoffset = cpu_to_be32(0x3b); /* XXX */ memcpy(associd.bssid, bss->bssid, ETH_ALEN); return ar5523_cmd_write(ar, WDCMSG_WRITE_ASSOCID, &associd, @@ -1272,7 +1280,7 @@ static int ar5523_write_associd(struct ar5523 *ar, static void ar5523_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss, - u32 changed) + u64 changed) { struct ar5523 *ar = hw->priv; int error; @@ -1283,7 +1291,7 @@ static void ar5523_bss_info_changed(struct ieee80211_hw *hw, if (!(changed & BSS_CHANGED_ASSOC)) goto out_unlock; - if (bss->assoc) { + if (vif->cfg.assoc) { error = ar5523_create_connection(ar, vif, bss); if (error) { ar5523_err(ar, "could not create connection\n"); @@ -1296,7 +1304,7 @@ static void ar5523_bss_info_changed(struct ieee80211_hw *hw, goto out_unlock; } - error = ar5523_write_associd(ar, bss); + error = ar5523_write_associd(ar, vif); if (error) { ar5523_err(ar, "could not set association\n"); goto out_unlock; @@ -1318,8 +1326,7 @@ out_unlock: } -#define AR5523_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ +#define AR5523_SUPPORTED_FILTERS (FIF_ALLMULTI | \ FIF_FCSFAIL | \ FIF_OTHER_BSS) @@ -1352,9 +1359,14 @@ static void ar5523_configure_filter(struct ieee80211_hw *hw, } static const struct ieee80211_ops ar5523_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .start = ar5523_start, .stop = ar5523_stop, .tx = ar5523_tx, + .wake_tx_queue = ieee80211_handle_wake_tx_queue, .set_rts_threshold = ar5523_set_rts_threshold, .add_interface = ar5523_add_interface, .remove_interface = ar5523_remove_interface, @@ -1471,12 +1483,12 @@ static int ar5523_init_modes(struct ar5523 *ar) memcpy(ar->channels, ar5523_channels, sizeof(ar5523_channels)); memcpy(ar->rates, ar5523_rates, sizeof(ar5523_rates)); - ar->band.band = IEEE80211_BAND_2GHZ; + ar->band.band = NL80211_BAND_2GHZ; ar->band.channels = ar->channels; ar->band.n_channels = ARRAY_SIZE(ar5523_channels); ar->band.bitrates = ar->rates; ar->band.n_bitrates = ARRAY_SIZE(ar5523_rates); - ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar->band; + ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = &ar->band; return 0; } @@ -1500,7 +1512,7 @@ static int ar5523_load_firmware(struct usb_device *dev) return -ENOENT; } - txblock = kmalloc(sizeof(*txblock), GFP_KERNEL); + txblock = kzalloc(sizeof(*txblock), GFP_KERNEL); if (!txblock) goto out; @@ -1512,7 +1524,6 @@ static int ar5523_load_firmware(struct usb_device *dev) if (!fwbuf) goto out_free_rxblock; - memset(txblock, 0, sizeof(struct ar5523_fwblock)); txblock->flags = cpu_to_be32(AR5523_WRITE_BLOCK); txblock->total = cpu_to_be32(fw->size); @@ -1584,6 +1595,20 @@ static int ar5523_probe(struct usb_interface *intf, struct ar5523 *ar; int error = -ENOMEM; + static const u8 bulk_ep_addr[] = { + AR5523_CMD_TX_PIPE | USB_DIR_OUT, + AR5523_DATA_TX_PIPE | USB_DIR_OUT, + AR5523_CMD_RX_PIPE | USB_DIR_IN, + AR5523_DATA_RX_PIPE | USB_DIR_IN, + 0}; + + if (!usb_check_bulk_endpoints(intf, bulk_ep_addr)) { + dev_err(&dev->dev, + "Could not find all expected endpoints\n"); + error = -ENODEV; + goto out; + } + /* * Load firmware if the device requires it. This will return * -ENXIO on success and we'll get called back afer the usb @@ -1604,8 +1629,7 @@ static int ar5523_probe(struct usb_interface *intf, mutex_init(&ar->mutex); INIT_DELAYED_WORK(&ar->stat_work, ar5523_stat_work); - init_timer(&ar->tx_wd_timer); - setup_timer(&ar->tx_wd_timer, ar5523_tx_wd_timer, (unsigned long) ar); + timer_setup(&ar->tx_wd_timer, ar5523_tx_wd_timer, 0); INIT_WORK(&ar->tx_wd_work, ar5523_tx_wd_work); INIT_WORK(&ar->tx_work, ar5523_tx_work); INIT_LIST_HEAD(&ar->tx_queue_pending); @@ -1682,9 +1706,9 @@ static int ar5523_probe(struct usb_interface *intf, (id->driver_info & AR5523_FLAG_ABG) ? '5' : '2'); ar->vif = NULL; - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_HAS_RATE_CONTROL; + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, RX_INCLUDES_FCS); + ieee80211_hw_set(hw, SIGNAL_DBM); hw->extra_tx_headroom = sizeof(struct ar5523_tx_desc) + sizeof(struct ar5523_chunk); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); @@ -1694,6 +1718,8 @@ static int ar5523_probe(struct usb_interface *intf, if (error) goto out_cancel_rx_cmd; + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + usb_set_intfdata(intf, hw); error = ieee80211_register_hw(hw); @@ -1752,7 +1778,7 @@ static void ar5523_disconnect(struct usb_interface *intf) { USB_DEVICE((vendor), (device) + 1), \ .driver_info = AR5523_FLAG_ABG|AR5523_FLAG_PRE_FIRMWARE } -static struct usb_device_id ar5523_id_table[] = { +static const struct usb_device_id ar5523_id_table[] = { AR5523_DEVICE_UG(0x168c, 0x0001), /* Atheros / AR5523 */ AR5523_DEVICE_UG(0x0cf3, 0x0001), /* Atheros2 / AR5523_1 */ AR5523_DEVICE_UG(0x0cf3, 0x0003), /* Atheros2 / AR5523_2 */ @@ -1762,9 +1788,10 @@ static struct usb_device_id ar5523_id_table[] = { AR5523_DEVICE_UX(0x2001, 0x3a00), /* Dlink / DWLAG132 */ AR5523_DEVICE_UG(0x2001, 0x3a02), /* Dlink / DWLG132 */ AR5523_DEVICE_UX(0x2001, 0x3a04), /* Dlink / DWLAG122 */ + AR5523_DEVICE_UG(0x07d1, 0x3a07), /* D-Link / WUA-2340 rev A1 */ AR5523_DEVICE_UG(0x1690, 0x0712), /* Gigaset / AR5523 */ AR5523_DEVICE_UG(0x1690, 0x0710), /* Gigaset / SMCWUSBTG */ - AR5523_DEVICE_UG(0x129b, 0x160c), /* Gigaset / USB stick 108 + AR5523_DEVICE_UG(0x129b, 0x160b), /* Gigaset / USB stick 108 (CyberTAN Technology) */ AR5523_DEVICE_UG(0x16ab, 0x7801), /* Globalsun / AR5523_1 */ AR5523_DEVICE_UX(0x16ab, 0x7811), /* Globalsun / AR5523_2 */ @@ -1772,9 +1799,10 @@ static struct usb_device_id ar5523_id_table[] = { AR5523_DEVICE_UX(0x0846, 0x4300), /* Netgear / WG111U */ AR5523_DEVICE_UG(0x0846, 0x4250), /* Netgear / WG111T */ AR5523_DEVICE_UG(0x0846, 0x5f00), /* Netgear / WPN111 */ - AR5523_DEVICE_UG(0x157e, 0x3006), /* Umedia / AR5523_1 */ + AR5523_DEVICE_UG(0x083a, 0x4506), /* SMC / EZ Connect + SMCWUSBT-G2 */ + AR5523_DEVICE_UG(0x157e, 0x3006), /* Umedia / AR5523_1, TEW444UBEU*/ AR5523_DEVICE_UX(0x157e, 0x3205), /* Umedia / AR5523_2 */ - AR5523_DEVICE_UG(0x157e, 0x3006), /* Umedia / TEW444UBEU */ AR5523_DEVICE_UG(0x1435, 0x0826), /* Wistronneweb / AR5523_1 */ AR5523_DEVICE_UX(0x1435, 0x0828), /* Wistronneweb / AR5523_2 */ AR5523_DEVICE_UG(0x0cde, 0x0012), /* Zcom / AR5523 */ @@ -1794,5 +1822,6 @@ static struct usb_driver ar5523_driver = { module_usb_driver(ar5523_driver); +MODULE_DESCRIPTION("Atheros AR5523 wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_FIRMWARE(AR5523_FIRMWARE_FILE); |
