Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 31 Mar 2014 19:22:17 +0000 (15:22 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 31 Mar 2014 19:22:17 +0000 (15:22 -0400)
49 files changed:
drivers/bcma/driver_gpio.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/btmrvl_main.c
drivers/net/wireless/ath/carl9170/rx.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/include/brcmu_wifi.h
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/tdls.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/rsi/rsi_91x_mgmt.c
drivers/net/wireless/rtl818x/Kconfig
drivers/net/wireless/rtl818x/rtl8180/Makefile
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtl818x/rtl8180/rtl8180.h
drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
drivers/net/wireless/rtl818x/rtl8180/rtl8225se.c [new file with mode: 0644]
drivers/net/wireless/rtl818x/rtl8180/rtl8225se.h [new file with mode: 0644]
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtl818x/rtl818x.h
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
drivers/net/wireless/rtlwifi/rtl8192se/hw.c
drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
drivers/net/wireless/rtlwifi/rtl8723be/dm.c
drivers/net/wireless/rtlwifi/rtl8723be/hw.c
drivers/net/wireless/rtlwifi/rtl8723be/trx.c
drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c
include/net/bluetooth/hci_core.h
net/bluetooth/hci_event.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/smp.c
net/bluetooth/smp.h

index 25f9887a35d08e89600e8aca86fc8c72062600f6..d7f81ad56b8af731ea10fb863460cebb717dddc0 100644 (file)
@@ -218,7 +218,14 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
 #if IS_BUILTIN(CONFIG_BCMA_HOST_SOC)
        chip->to_irq            = bcma_gpio_to_irq;
 #endif
-       chip->ngpio             = 16;
+       switch (cc->core->bus->chipinfo.id) {
+       case BCMA_CHIP_ID_BCM5357:
+               chip->ngpio     = 32;
+               break;
+       default:
+               chip->ngpio     = 16;
+       }
+
        /* There is just one SoC in one device and its GPIO addresses should be
         * deterministic to address them more easily. The other buses could get
         * a random base number. */
index a9a989e5ee88036a186cb7b4d88d73a7aafb563d..dfa5043e68bacc9de66f6ce12c565fb8f410f4b1 100644 (file)
@@ -901,7 +901,7 @@ static void bluecard_release(struct pcmcia_device *link)
 
        bluecard_close(info);
 
-       del_timer(&(info->timer));
+       del_timer_sync(&(info->timer));
 
        pcmcia_disable_device(link);
 }
index 1e0320af00c63be9a1fdd808e8c0301dedf7ad0a..2c4997ce248484703a1b859c5e518396fcdbfa64 100644 (file)
@@ -59,12 +59,13 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
                        priv->btmrvl_dev.sendcmdflag = false;
                        priv->adapter->cmd_complete = true;
                        wake_up_interruptible(&priv->adapter->cmd_wait_q);
-               }
 
-               if (hci_opcode_ogf(opcode) == 0x3F) {
-                       BT_DBG("vendor event skipped: opcode=%#4.4x", opcode);
-                       kfree_skb(skb);
-                       return false;
+                       if (hci_opcode_ogf(opcode) == 0x3F) {
+                               BT_DBG("vendor event skipped: opcode=%#4.4x",
+                                      opcode);
+                               kfree_skb(skb);
+                               return false;
+                       }
                }
        }
 
index 536bc46a291244e8b743a63fcae41a7d30963b8c..924135b8e57543ea19060b802f122627a42ff904 100644 (file)
@@ -572,7 +572,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
 
 static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)
 {
-       struct ieee80211_bar *bar = (void *) data;
+       struct ieee80211_bar *bar = data;
        struct carl9170_bar_list_entry *entry;
        unsigned int queue;
 
index e0e649aab8dbc5bffca9de3f58ddbb97bd898732..afb3d15e38ff0379a99c5e2c534be23c57b94e38 100644 (file)
@@ -1354,13 +1354,14 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
 }
 
 static s32
-brcmf_set_set_cipher(struct net_device *ndev,
-                    struct cfg80211_connect_params *sme)
+brcmf_set_wsec_mode(struct net_device *ndev,
+                    struct cfg80211_connect_params *sme, bool mfp)
 {
        struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
        struct brcmf_cfg80211_security *sec;
        s32 pval = 0;
        s32 gval = 0;
+       s32 wsec;
        s32 err = 0;
 
        if (sme->crypto.n_ciphers_pairwise) {
@@ -1412,7 +1413,12 @@ brcmf_set_set_cipher(struct net_device *ndev,
        if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
            sme->privacy)
                pval = AES_ENABLED;
-       err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
+
+       if (mfp)
+               wsec = pval | gval | MFP_CAPABLE;
+       else
+               wsec = pval | gval;
+       err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
        if (err) {
                brcmf_err("error (%d)\n", err);
                return err;
@@ -1582,7 +1588,6 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
        u32 ie_len;
        struct brcmf_ext_join_params_le *ext_join_params;
        u16 chanspec;
-
        s32 err = 0;
 
        brcmf_dbg(TRACE, "Enter\n");
@@ -1651,7 +1656,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                goto done;
        }
 
-       err = brcmf_set_set_cipher(ndev, sme);
+       err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
        if (err) {
                brcmf_err("wl_set_set_cipher failed (%d)\n", err);
                goto done;
index 7ca2aa1035b2101d1d8129c1ca480724863dd507..74419d4bd123772f94e222326c61ee4e93f0f9d3 100644 (file)
@@ -217,6 +217,9 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
 #define WSEC_SWFLAG            0x0008
 /* to go into transition mode without setting wep */
 #define SES_OW_ENABLED         0x0040
+/* MFP */
+#define MFP_CAPABLE            0x0200
+#define MFP_REQUIRED           0x0400
 
 /* WPA authentication mode bitvec */
 #define WPA_AUTH_DISABLED      0x0000  /* Legacy (i.e., non-WPA) */
index b41155829220601cf1a8e894e48eb2955126dece..1062c918a7bffb19cf93c1aba0daa4490856ba65 100644 (file)
@@ -277,11 +277,11 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
 
        priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
 
+       adapter->seq_num++;
        sleep_cfm_buf->seq_num =
                cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO
                                        (adapter->seq_num, priv->bss_num,
                                         priv->bss_type)));
-       adapter->seq_num++;
 
        if (adapter->iface_type == MWIFIEX_USB) {
                sleep_cfm_tmp =
@@ -509,6 +509,11 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
                return -1;
        }
 
+       if (adapter->hs_enabling && cmd_no != HostCmd_CMD_802_11_HS_CFG_ENH) {
+               dev_err(adapter->dev, "PREP_CMD: host entering sleep state\n");
+               return -1;
+       }
+
        if (adapter->surprise_removed) {
                dev_err(adapter->dev, "PREP_CMD: card is removed\n");
                return -1;
@@ -976,11 +981,10 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
        struct mwifiex_private *priv;
        int i;
 
+       spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
        /* Cancel current cmd */
        if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
-               spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
                adapter->curr_cmd->wait_q_enabled = false;
-               spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
                adapter->cmd_wait_q.status = -1;
                mwifiex_complete_cmd(adapter, adapter->curr_cmd);
        }
@@ -1000,6 +1004,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
                spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
        }
        spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+       spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
 
        /* Cancel all pending scan command */
        spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
index 7b4502fefec388050d845df770550ae540acb0de..77db0886c6e2e9fa764f2a0add8876b477972915 100644 (file)
@@ -38,7 +38,8 @@ static void scan_delay_timer_fn(unsigned long data)
        if (adapter->surprise_removed)
                return;
 
-       if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+       if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT ||
+           !adapter->scan_processing) {
                /*
                 * Abort scan operation by cancelling all pending scan
                 * commands
index a67f7da12b30e9f00c2b6c3c52ff5f306f56cef7..d53e1e8c9467a62663c4d28df86e623237cdc45f 100644 (file)
@@ -774,6 +774,7 @@ struct mwifiex_adapter {
        u16 hs_activate_wait_q_woken;
        wait_queue_head_t hs_activate_wait_q;
        bool is_suspended;
+       bool hs_enabling;
        u8 event_body[MAX_EVENT_SIZE];
        u32 hw_dot_11n_dev_cap;
        u8 hw_dev_mcs_support;
index 57c353a94b29784f990c7e62c5e8e2dd2bb36b46..a7e8b96b2d9024de8c34e5e04b317c66d2e22820 100644 (file)
@@ -120,6 +120,7 @@ static int mwifiex_pcie_suspend(struct device *dev)
 
        /* Indicate device suspended */
        adapter->is_suspended = true;
+       adapter->hs_enabling = false;
 
        return 0;
 }
@@ -1033,7 +1034,7 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
                card->tx_buf_list[wrdoneidx] = NULL;
 
                if (reg->pfu_enabled) {
-                       desc2 = (void *)card->txbd_ring[wrdoneidx];
+                       desc2 = card->txbd_ring[wrdoneidx];
                        memset(desc2, 0, sizeof(*desc2));
                } else {
                        desc = card->txbd_ring[wrdoneidx];
@@ -1118,7 +1119,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
                card->tx_buf_list[wrindx] = skb;
 
                if (reg->pfu_enabled) {
-                       desc2 = (void *)card->txbd_ring[wrindx];
+                       desc2 = card->txbd_ring[wrindx];
                        desc2->paddr = buf_pa;
                        desc2->len = (u16)skb->len;
                        desc2->frag_len = (u16)skb->len;
@@ -1278,7 +1279,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                card->rx_buf_list[rd_index] = skb_tmp;
 
                if (reg->pfu_enabled) {
-                       desc2 = (void *)card->rxbd_ring[rd_index];
+                       desc2 = card->rxbd_ring[rd_index];
                        desc2->paddr = buf_pa;
                        desc2->len = skb_tmp->len;
                        desc2->frag_len = skb_tmp->len;
index f13924447a2cd507496ffc26992243596839809e..7b3af3d29ded478ad658eed5a3836403d6dd7542 100644 (file)
@@ -591,10 +591,12 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                          *chan_tlv_out,
                          struct mwifiex_chan_scan_param_set *scan_chan_list)
 {
+       struct mwifiex_adapter *adapter = priv->adapter;
        int ret = 0;
        struct mwifiex_chan_scan_param_set *tmp_chan_list;
        struct mwifiex_chan_scan_param_set *start_chan;
-
+       struct cmd_ctrl_node *cmd_node, *tmp_node;
+       unsigned long flags;
        u32 tlv_idx, rates_size, cmd_no;
        u32 total_scan_time;
        u32 done_early;
@@ -748,8 +750,19 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                scan_cfg_out->tlv_buf_len -=
                            sizeof(struct mwifiex_ie_types_header) + rates_size;
 
-               if (ret)
+               if (ret) {
+                       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+                       list_for_each_entry_safe(cmd_node, tmp_node,
+                                                &adapter->scan_pending_q,
+                                                list) {
+                               list_del(&cmd_node->list);
+                               cmd_node->wait_q_enabled = false;
+                               mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+                       }
+                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+                                              flags);
                        break;
+               }
        }
 
        if (ret)
@@ -1653,7 +1666,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
        curr_bcn_bytes -= ETH_ALEN;
 
        if (!ext_scan) {
-               rssi = (s32) *(u8 *)current_ptr;
+               rssi = (s32) *current_ptr;
                rssi = (-rssi) * 100;           /* Convert dBm to mBm */
                current_ptr += sizeof(u8);
                curr_bcn_bytes -= sizeof(u8);
index e0dcd3ed7a69d01d1a5342be587a8901e2b34b57..d206f04d499498d6d9c7ba92a80685588ae7bc96 100644 (file)
@@ -237,6 +237,7 @@ static int mwifiex_sdio_suspend(struct device *dev)
        /* Enable the Host Sleep */
        if (!mwifiex_enable_hs(adapter)) {
                dev_err(adapter->dev, "cmd: failed to suspend\n");
+               adapter->hs_enabling = false;
                return -EFAULT;
        }
 
@@ -245,6 +246,7 @@ static int mwifiex_sdio_suspend(struct device *dev)
 
        /* Indicate device suspended */
        adapter->is_suspended = true;
+       adapter->hs_enabling = false;
 
        return ret;
 }
index 33170af150f6da3823ad3a5743f472fc6f141c98..894270611f2cb6e074669f424fe66978e80e1992 100644 (file)
@@ -64,6 +64,7 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
                                          *(cmd_queued->condition));
        if (status) {
                dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status);
+               mwifiex_cancel_all_pending_cmd(adapter);
                return status;
        }
 
@@ -508,6 +509,9 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
        memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
        hscfg.is_invoke_hostcmd = true;
 
+       adapter->hs_enabling = true;
+       mwifiex_cancel_all_pending_cmd(adapter);
+
        if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
                                                   MWIFIEX_BSS_ROLE_STA),
                                  HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
@@ -516,8 +520,9 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
                return false;
        }
 
-       if (wait_event_interruptible(adapter->hs_activate_wait_q,
-                                    adapter->hs_activate_wait_q_woken)) {
+       if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,
+                                            adapter->hs_activate_wait_q_woken,
+                                            (10 * HZ)) <= 0) {
                dev_err(adapter->dev, "hs_activate_wait_q terminated\n");
                return false;
        }
index 8cec6e4ba8c4345d3518c8a407c19145beb48dc5..97662a1ba58cf06a08ff3372f4808e5a0c7cbcd9 100644 (file)
@@ -730,13 +730,13 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
 
        if (len < (sizeof(struct ethhdr) + 3))
                return;
-       if (*(u8 *)(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)
+       if (*(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)
                return;
-       if (*(u8 *)(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)
+       if (*(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)
                return;
 
        peer = buf + ETH_ALEN;
-       action = *(u8 *)(buf + sizeof(struct ethhdr) + 2);
+       action = *(buf + sizeof(struct ethhdr) + 2);
 
        /* just handle TDLS setup request/response/confirm */
        if (action > WLAN_TDLS_SETUP_CONFIRM)
index ae30c390ebd31c215674c842c2d9b03af57b93ee..edbe4aff00d85b569534372ea34e7e017552b234 100644 (file)
@@ -459,6 +459,7 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
         * 'suspended' state and a 'disconnect' one.
         */
        adapter->is_suspended = true;
+       adapter->hs_enabling = false;
 
        if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb)
                usb_kill_urb(card->rx_cmd.urb);
index ef37d4b27bd4130142bc5be06e9a5a416aa705d0..2361a6849ad7eb56dccd3d2e0d02517f02d6d82f 100644 (file)
@@ -1292,10 +1292,11 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg)
                        return -EINVAL;
                }
        } else if (msg_type == TX_STATUS_IND) {
-               if (msg[15] == PROBEREQ_CONFIRM)
+               if (msg[15] == PROBEREQ_CONFIRM) {
                        common->mgmt_q_block = false;
                        rsi_dbg(FSM_ZONE, "%s: Probe confirm received\n",
                                __func__);
+               }
        } else {
                return rsi_mgmt_pkt_to_core(common, msg, msg_len, msg_type);
        }
index 30332175bcd8d6abaa788a5da5f7f1d7ca5c1fbe..1ce1d55f0010b48b9360a2716ad1587f060e7971 100644 (file)
@@ -2,11 +2,11 @@
 # RTL818X Wireless LAN device configuration
 #
 config RTL8180
-       tristate "Realtek 8180/8185 PCI support"
+       tristate "Realtek 8180/8185/8187SE PCI support"
        depends on MAC80211 && PCI
        select EEPROM_93CX6
        ---help---
-         This is a driver for RTL8180 and RTL8185 based cards.
+         This is a driver for RTL8180, RTL8185 and RTL8187SE based cards.
          These are PCI based chips found in cards such as:
 
          (RTL8185 802.11g)
index cb4fb8596f0badeada10a7dd8975888990e90c75..08b056db4a3b795282d1d9e878ab400d7090bcf2 100644 (file)
@@ -1,4 +1,4 @@
-rtl8180-objs           := dev.o rtl8225.o sa2400.o max2820.o grf5101.o
+rtl8180-objs           := dev.o rtl8225.o sa2400.o max2820.o grf5101.o rtl8225se.o
 
 obj-$(CONFIG_RTL8180)  += rtl8180.o
 
index 0b405b8c8d70c131198e55aced94f4e4313e6bf6..98d8256f037788a4d9af76c02a4e939758a08e0e 100644 (file)
@@ -1,15 +1,42 @@
 
-/*
- * Linux device driver for RTL8180 / RTL8185
+/* Linux device driver for RTL8180 / RTL8185 / RTL8187SE
  *
  * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
+ * Copyright 2007,2014 Andrea Merello <andrea.merello@gmail.com>
  *
  * Based on the r8180 driver, which is:
  * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  *
  * Thanks to Realtek for their support!
  *
+ ************************************************************************
+ *
+ * The driver was extended to the RTL8187SE in 2014 by
+ * Andrea Merello <andrea.merello@gmail.com>
+ *
+ * based also on:
+ *  - portions of rtl8187se Linux staging driver, Copyright Realtek corp.
+ *  - other GPL, unpublished (until now), Linux driver code,
+ *    Copyright Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * A huge thanks goes to Sara V. Nari who forgives me when I'm
+ * sitting in front of my laptop at evening, week-end, night...
+ *
+ * A special thanks goes to Antonio Cuni, who helped me with
+ * some python userspace stuff I used to debug RTL8187SE code, and who
+ * bought a laptop with an unsupported Wi-Fi card some years ago...
+ *
+ * Thanks to Larry Finger for writing some code for rtl8187se and for
+ * his suggestions.
+ *
+ * Thanks to Dan Carpenter for reviewing my initial patch and for his
+ * suggestions.
+ *
+ * Thanks to Bernhard Schiffner for his help in testing and for his
+ * suggestions.
+ *
+ ************************************************************************
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 #include "sa2400.h"
 #include "max2820.h"
 #include "grf5101.h"
+#include "rtl8225se.h"
 
 MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>");
-MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver");
+MODULE_DESCRIPTION("RTL8180 / RTL8185 / RTL8187SE PCI wireless driver");
 MODULE_LICENSE("GPL");
 
 static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = {
+
+       /* rtl8187se */
+       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8199) },
+
        /* rtl8185 */
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) },
        { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) },
@@ -85,6 +117,76 @@ static const struct ieee80211_channel rtl818x_channels[] = {
        { .center_freq = 2484 },
 };
 
+/* Queues for rtl8187se card
+ *
+ * name | reg  |  queue
+ *  BC  |  7   |   6
+ *  MG  |  1   |   0
+ *  HI  |  6   |   1
+ *  VO  |  5   |   2
+ *  VI  |  4   |   3
+ *  BE  |  3   |   4
+ *  BK  |  2   |   5
+ *
+ * The complete map for DMA kick reg using use all queue is:
+ * static const int rtl8187se_queues_map[RTL8187SE_NR_TX_QUEUES] =
+ *     {1, 6, 5, 4, 3, 2, 7};
+ *
+ * .. but.. Because for mac80211 4 queues are enough for QoS we use this
+ *
+ * name | reg  |  queue
+ *  BC  |  7   |   4  <- currently not used yet
+ *  MG  |  1   |   x  <- Not used
+ *  HI  |  6   |   x  <- Not used
+ *  VO  |  5   |   0  <- used
+ *  VI  |  4   |   1  <- used
+ *  BE  |  3   |   2  <- used
+ *  BK  |  2   |   3  <- used
+ *
+ * Beacon queue could be used, but this is not finished yet.
+ *
+ * I thougth about using the other two queues but I decided not to do this:
+ *
+ * - I'm unsure whether the mac80211 will ever try to use more than 4 queues
+ *   by itself.
+ *
+ * - I could route MGMT frames (currently sent over VO queue) to the MGMT
+ *   queue but since mac80211 will do not know about it, I will probably gain
+ *   some HW priority whenever the VO queue is not empty, but this gain is
+ *   limited by the fact that I had to stop the mac80211 queue whenever one of
+ *   the VO or MGMT queues is full, stopping also submitting of MGMT frame
+ *   to the driver.
+ *
+ * - I don't know how to set in the HW the contention window params for MGMT
+ *   and HI-prio queues.
+ */
+
+static const int rtl8187se_queues_map[RTL8187SE_NR_TX_QUEUES] = {5, 4, 3, 2, 7};
+
+/* Queues for rtl8180/rtl8185 cards
+ *
+ * name | reg  |  prio
+ *  BC  |  7   |   3
+ *  HI  |  6   |   0
+ *  NO  |  5   |   1
+ *  LO  |  4   |   2
+ *
+ * The complete map for DMA kick reg using all queue is:
+ * static const int rtl8180_queues_map[RTL8180_NR_TX_QUEUES] = {6, 5, 4, 7};
+ *
+ * .. but .. Because the mac80211 needs at least 4 queues for QoS or
+ * otherwise QoS can't be done, we use just one.
+ * Beacon queue could be used, but this is not finished yet.
+ * Actual map is:
+ *
+ * name | reg  |  prio
+ *  BC  |  7   |   1  <- currently not used yet.
+ *  HI  |  6   |   x  <- not used
+ *  NO  |  5   |   x  <- not used
+ *  LO  |  4   |   0  <- used
+ */
+
+static const int rtl8180_queues_map[RTL8180_NR_TX_QUEUES] = {4, 7};
 
 void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 {
@@ -105,14 +207,30 @@ void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 static void rtl8180_handle_rx(struct ieee80211_hw *dev)
 {
        struct rtl8180_priv *priv = dev->priv;
+       struct rtl818x_rx_cmd_desc *cmd_desc;
        unsigned int count = 32;
        u8 signal, agc, sq;
        dma_addr_t mapping;
 
        while (count--) {
-               struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
+               void *entry = priv->rx_ring + priv->rx_idx * priv->rx_ring_sz;
                struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
-               u32 flags = le32_to_cpu(entry->flags);
+               u32 flags, flags2;
+               u64 tsft;
+
+               if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+                       struct rtl8187se_rx_desc *desc = entry;
+
+                       flags = le32_to_cpu(desc->flags);
+                       flags2 = le32_to_cpu(desc->flags2);
+                       tsft = le64_to_cpu(desc->tsft);
+               } else {
+                       struct rtl8180_rx_desc *desc = entry;
+
+                       flags = le32_to_cpu(desc->flags);
+                       flags2 = le32_to_cpu(desc->flags2);
+                       tsft = le64_to_cpu(desc->tsft);
+               }
 
                if (flags & RTL818X_RX_DESC_FLAG_OWN)
                        return;
@@ -122,7 +240,6 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
                                      RTL818X_RX_DESC_FLAG_RX_ERR)))
                        goto done;
                else {
-                       u32 flags2 = le32_to_cpu(entry->flags2);
                        struct ieee80211_rx_status rx_status = {0};
                        struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE);
 
@@ -154,14 +271,18 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
                                        signal = 90 - clamp_t(u8, agc, 25, 90);
                                else
                                        signal = 95 - clamp_t(u8, agc, 30, 95);
-                       } else {
+                       } else if (priv->chip_family ==
+                                  RTL818X_CHIP_FAMILY_RTL8180) {
                                sq = flags2 & 0xff;
                                signal = priv->rf->calc_rssi(agc, sq);
+                       } else {
+                               /* TODO: rtl8187se rssi */
+                               signal = 10;
                        }
                        rx_status.signal = signal;
                        rx_status.freq = dev->conf.chandef.chan->center_freq;
                        rx_status.band = dev->conf.chandef.chan->band;
-                       rx_status.mactime = le64_to_cpu(entry->tsft);
+                       rx_status.mactime = tsft;
                        rx_status.flag |= RX_FLAG_MACTIME_START;
                        if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
                                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
@@ -175,11 +296,13 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
                }
 
        done:
-               entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb));
-               entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
+               cmd_desc = entry;
+               cmd_desc->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb));
+               cmd_desc->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
                                           MAX_RX_SIZE);
                if (priv->rx_idx == 31)
-                       entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
+                       cmd_desc->flags |=
+                               cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
                priv->rx_idx = (priv->rx_idx + 1) % 32;
        }
 }
@@ -219,6 +342,55 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
        }
 }
 
+static irqreturn_t rtl8187se_interrupt(int irq, void *dev_id)
+{
+       struct ieee80211_hw *dev = dev_id;
+       struct rtl8180_priv *priv = dev->priv;
+       u32 reg;
+       unsigned long flags;
+       static int desc_err;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       /* Note: 32-bit interrupt status */
+       reg = rtl818x_ioread32(priv, &priv->map->INT_STATUS_SE);
+       if (unlikely(reg == 0xFFFFFFFF)) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return IRQ_HANDLED;
+       }
+
+       rtl818x_iowrite32(priv, &priv->map->INT_STATUS_SE, reg);
+
+       if (reg & IMR_TIMEOUT1)
+               rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
+
+       if (reg & (IMR_TBDOK | IMR_TBDER))
+               rtl8180_handle_tx(dev, 4);
+
+       if (reg & (IMR_TVODOK | IMR_TVODER))
+               rtl8180_handle_tx(dev, 0);
+
+       if (reg & (IMR_TVIDOK | IMR_TVIDER))
+               rtl8180_handle_tx(dev, 1);
+
+       if (reg & (IMR_TBEDOK | IMR_TBEDER))
+               rtl8180_handle_tx(dev, 2);
+
+       if (reg & (IMR_TBKDOK | IMR_TBKDER))
+               rtl8180_handle_tx(dev, 3);
+
+       if (reg & (IMR_ROK | IMR_RER | RTL818X_INT_SE_RX_DU | IMR_RQOSOK))
+               rtl8180_handle_rx(dev);
+       /* The interface sometimes generates several RX DMA descriptor errors
+        * at startup. Do not report these.
+        */
+       if ((reg & RTL818X_INT_SE_RX_DU) && desc_err++ > 2)
+               if (net_ratelimit())
+                       wiphy_err(dev->wiphy, "No RX DMA Descriptor avail\n");
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
 {
        struct ieee80211_hw *dev = dev_id;
@@ -235,12 +407,6 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
        rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
 
        if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR))
-               rtl8180_handle_tx(dev, 3);
-
-       if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR))
-               rtl8180_handle_tx(dev, 2);
-
-       if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
                rtl8180_handle_tx(dev, 1);
 
        if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR))
@@ -264,12 +430,14 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
        struct rtl8180_tx_ring *ring;
        struct rtl8180_tx_desc *entry;
        unsigned long flags;
-       unsigned int idx, prio;
+       unsigned int idx, prio, hw_prio;
        dma_addr_t mapping;
        u32 tx_flags;
        u8 rc_flags;
        u16 plcp_len = 0;
        __le16 rts_duration = 0;
+       /* do arithmetic and then convert to le16 */
+       u16 frame_duration = 0;
 
        prio = skb_get_queue_mapping(skb);
        ring = &priv->tx_ring[prio];
@@ -281,7 +449,6 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
                kfree_skb(skb);
                dev_err(&priv->pdev->dev, "TX DMA mapping error\n");
                return;
-
        }
 
        tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS |
@@ -317,6 +484,18 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
                        plcp_len |= 1 << 15;
        }
 
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               __le16 duration;
+               /* SIFS time (required by HW) is already included by
+                * ieee80211_generic_frame_duration
+                */
+               duration = ieee80211_generic_frame_duration(dev, priv->vif,
+                                       IEEE80211_BAND_2GHZ, skb->len,
+                                       ieee80211_get_tx_rate(dev, info));
+
+               frame_duration =  priv->ack_time + le16_to_cpu(duration);
+       }
+
        spin_lock_irqsave(&priv->lock, flags);
 
        if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
@@ -329,10 +508,19 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
        idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
        entry = &ring->desc[idx];
 
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               entry->frame_duration = cpu_to_le16(frame_duration);
+               entry->frame_len_se = cpu_to_le16(skb->len);
+
+               /* tpc polarity */
+               entry->flags3 = cpu_to_le16(1<<4);
+       } else
+               entry->frame_len = cpu_to_le32(skb->len);
+
        entry->rts_duration = rts_duration;
        entry->plcp_len = cpu_to_le16(plcp_len);
        entry->tx_buf = cpu_to_le32(mapping);
-       entry->frame_len = cpu_to_le32(skb->len);
+
        entry->flags2 = info->control.rates[1].idx >= 0 ?
                ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
        entry->retry_limit = info->control.rates[0].count;
@@ -354,7 +542,57 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               /* just poll: rings are stopped with TPPollStop reg */
+               hw_prio = rtl8187se_queues_map[prio];
+               rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING,
+                        (1 << hw_prio));
+       } else {
+               hw_prio = rtl8180_queues_map[prio];
+               rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING,
+                        (1 << hw_prio) | /* ring to poll  */
+                        (1<<1) | (1<<2));/* stopped rings */
+       }
+}
+
+static void rtl8180_set_anaparam3(struct rtl8180_priv *priv, u16 anaparam3)
+{
+       u8 reg;
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+                        RTL818X_EEPROM_CMD_CONFIG);
+
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+                reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+
+       rtl818x_iowrite16(priv, &priv->map->ANAPARAM3, anaparam3);
+
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+                reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+                        RTL818X_EEPROM_CMD_NORMAL);
+}
+
+void rtl8180_set_anaparam2(struct rtl8180_priv *priv, u32 anaparam2)
+{
+       u8 reg;
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+                        RTL818X_EEPROM_CMD_CONFIG);
+
+       reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+                reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+
+       rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, anaparam2);
+
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+                reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+                        RTL818X_EEPROM_CMD_NORMAL);
 }
 
 void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam)
@@ -371,6 +609,105 @@ void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam)
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 }
 
+static void rtl8187se_mac_config(struct ieee80211_hw *dev)
+{
+       struct rtl8180_priv *priv = dev->priv;
+       u8 reg;
+
+       rtl818x_iowrite32(priv, REG_ADDR4(0x1F0), 0);
+       rtl818x_ioread32(priv, REG_ADDR4(0x1F0));
+       rtl818x_iowrite32(priv, REG_ADDR4(0x1F4), 0);
+       rtl818x_ioread32(priv, REG_ADDR4(0x1F4));
+       rtl818x_iowrite8(priv, REG_ADDR1(0x1F8), 0);
+       rtl818x_ioread8(priv, REG_ADDR1(0x1F8));
+       /* Enable DA10 TX power saving */
+       reg = rtl818x_ioread8(priv, &priv->map->PHY_PR);
+       rtl818x_iowrite8(priv, &priv->map->PHY_PR, reg | 0x04);
+       /* Power */
+       rtl818x_iowrite16(priv, PI_DATA_REG, 0x1000);
+       rtl818x_iowrite16(priv, SI_DATA_REG, 0x1000);
+       /* AFE - default to power ON */
+       rtl818x_iowrite16(priv, REG_ADDR2(0x370), 0x0560);
+       rtl818x_iowrite16(priv, REG_ADDR2(0x372), 0x0560);
+       rtl818x_iowrite16(priv, REG_ADDR2(0x374), 0x0DA4);
+       rtl818x_iowrite16(priv, REG_ADDR2(0x376), 0x0DA4);
+       rtl818x_iowrite16(priv, REG_ADDR2(0x378), 0x0560);
+       rtl818x_iowrite16(priv, REG_ADDR2(0x37A), 0x0560);
+       rtl818x_iowrite16(priv, REG_ADDR2(0x37C), 0x00EC);
+       rtl818x_iowrite16(priv, REG_ADDR2(0x37E), 0x00EC);
+       rtl818x_iowrite8(priv, REG_ADDR1(0x24E), 0x01);
+       /* unknown, needed for suspend to RAM resume */
+       rtl818x_iowrite8(priv, REG_ADDR1(0x0A), 0x72);
+}
+
+static void rtl8187se_set_antenna_config(struct ieee80211_hw *dev, u8 def_ant,
+                                        bool diversity)
+{
+       struct rtl8180_priv *priv = dev->priv;
+
+       rtl8225_write_phy_cck(dev, 0x0C, 0x09);
+       if (diversity) {
+               if (def_ant == 1) {
+                       rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x00);
+                       rtl8225_write_phy_cck(dev, 0x11, 0xBB);
+                       rtl8225_write_phy_cck(dev, 0x01, 0xC7);
+                       rtl8225_write_phy_ofdm(dev, 0x0D, 0x54);
+                       rtl8225_write_phy_ofdm(dev, 0x18, 0xB2);
+               } else { /* main antenna */
+                       rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
+                       rtl8225_write_phy_cck(dev, 0x11, 0x9B);
+                       rtl8225_write_phy_cck(dev, 0x01, 0xC7);
+                       rtl8225_write_phy_ofdm(dev, 0x0D, 0x5C);
+                       rtl8225_write_phy_ofdm(dev, 0x18, 0xB2);
+               }
+       } else { /* disable antenna diversity */
+               if (def_ant == 1) {
+                       rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x00);
+                       rtl8225_write_phy_cck(dev, 0x11, 0xBB);
+                       rtl8225_write_phy_cck(dev, 0x01, 0x47);
+                       rtl8225_write_phy_ofdm(dev, 0x0D, 0x54);
+                       rtl8225_write_phy_ofdm(dev, 0x18, 0x32);
+               } else { /* main antenna */
+                       rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
+                       rtl8225_write_phy_cck(dev, 0x11, 0x9B);
+                       rtl8225_write_phy_cck(dev, 0x01, 0x47);
+                       rtl8225_write_phy_ofdm(dev, 0x0D, 0x5C);
+                       rtl8225_write_phy_ofdm(dev, 0x18, 0x32);
+               }
+       }
+       /* priv->curr_ant = def_ant; */
+}
+
+static void rtl8180_int_enable(struct ieee80211_hw *dev)
+{
+       struct rtl8180_priv *priv = dev->priv;
+
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               rtl818x_iowrite32(priv, &priv->map->IMR, IMR_TMGDOK |
+                         IMR_TBDER | IMR_THPDER |
+                         IMR_THPDER | IMR_THPDOK |
+                         IMR_TVODER | IMR_TVODOK |
+                         IMR_TVIDER | IMR_TVIDOK |
+                         IMR_TBEDER | IMR_TBEDOK |
+                         IMR_TBKDER | IMR_TBKDOK |
+                         IMR_RDU | IMR_RER |
+                         IMR_ROK | IMR_RQOSOK);
+       } else {
+               rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+       }
+}
+
+static void rtl8180_int_disable(struct ieee80211_hw *dev)
+{
+       struct rtl8180_priv *priv = dev->priv;
+
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               rtl818x_iowrite32(priv, &priv->map->IMR, 0);
+       } else {
+               rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+       }
+}
+
 static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev,
                            u32 rates_mask)
 {
@@ -390,7 +727,6 @@ static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev,
                reg &= ~3;
                reg |= max;
                rtl818x_iowrite16(priv, &priv->map->BRSR, reg);
-
                break;
 
        case RTL818X_CHIP_FAMILY_RTL8185:
@@ -398,20 +734,46 @@ static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev,
                rtl818x_iowrite16(priv, &priv->map->BRSR, rates_mask);
                rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (max << 4) | min);
                break;
+
+       case RTL818X_CHIP_FAMILY_RTL8187SE:
+               /* in 8187se this is a BITMAP */
+               rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, rates_mask);
+               break;
+       }
+}
+
+static void rtl8180_config_cardbus(struct ieee80211_hw *dev)
+{
+       struct rtl8180_priv *priv = dev->priv;
+       u16 reg16;
+       u8 reg8;
+
+       reg8 = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+       reg8 |= 1 << 1;
+       rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg8);
+
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               rtl818x_iowrite16(priv, FEMR_SE, 0xffff);
+       } else {
+               reg16 = rtl818x_ioread16(priv, &priv->map->FEMR);
+                       reg16 |= (1 << 15) | (1 << 14) | (1 << 4);
+               rtl818x_iowrite16(priv, &priv->map->FEMR, reg16);
        }
+
 }
 
 static int rtl8180_init_hw(struct ieee80211_hw *dev)
 {
        struct rtl8180_priv *priv = dev->priv;
        u16 reg;
+       u32 reg32;
 
        rtl818x_iowrite8(priv, &priv->map->CMD, 0);
        rtl818x_ioread8(priv, &priv->map->CMD);
        msleep(10);
 
        /* reset */
-       rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+       rtl8180_int_disable(dev);
        rtl818x_ioread8(priv, &priv->map->CMD);
 
        reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -432,25 +794,39 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
        msleep(200);
 
        if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) {
-               /* For cardbus */
-               reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
-               reg |= 1 << 1;
-               rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
-               reg = rtl818x_ioread16(priv, &priv->map->FEMR);
-               reg |= (1 << 15) | (1 << 14) | (1 << 4);
-               rtl818x_iowrite16(priv, &priv->map->FEMR, reg);
+               rtl8180_config_cardbus(dev);
        }
 
-       rtl818x_iowrite8(priv, &priv->map->MSR, 0);
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+               rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_ENEDCA);
+       else
+               rtl818x_iowrite8(priv, &priv->map->MSR, 0);
 
        if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180)
                rtl8180_set_anaparam(priv, priv->anaparam);
 
        rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
-       rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma);
-       rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma);
-       rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma);
-       rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma);
+       /* mac80211 queue have higher prio for lower index. The last queue
+        * (that mac80211 is not aware of) is reserved for beacons (and have
+        * the highest priority on the NIC)
+        */
+       if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8187SE) {
+               rtl818x_iowrite32(priv, &priv->map->TBDA,
+                                 priv->tx_ring[1].dma);
+               rtl818x_iowrite32(priv, &priv->map->TLPDA,
+                                 priv->tx_ring[0].dma);
+       } else {
+               rtl818x_iowrite32(priv, &priv->map->TBDA,
+                                 priv->tx_ring[4].dma);
+               rtl818x_iowrite32(priv, &priv->map->TVODA,
+                                 priv->tx_ring[0].dma);
+               rtl818x_iowrite32(priv, &priv->map->TVIDA,
+                                 priv->tx_ring[1].dma);
+               rtl818x_iowrite32(priv, &priv->map->TBEDA,
+                                 priv->tx_ring[2].dma);
+               rtl818x_iowrite32(priv, &priv->map->TBKDA,
+                                 priv->tx_ring[3].dma);
+       }
 
        /* TODO: necessary? specs indicate not */
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -471,7 +847,14 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
        if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) {
                rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
                rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
+       } else {
+               rtl818x_iowrite8(priv, &priv->map->SECURITY, 0);
 
+               rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6);
+               rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C);
+       }
+
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) {
                /* TODO: set ClkRun enable? necessary? */
                reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE);
                rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6));
@@ -479,11 +862,55 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
                reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
                rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2));
                rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
-       } else {
-               rtl818x_iowrite8(priv, &priv->map->SECURITY, 0);
+       }
 
-               rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6);
-               rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C);
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+
+               /* the set auto rate fallback bitmask from 1M to 54 Mb/s */
+               rtl818x_iowrite16(priv, ARFR, 0xFFF);
+               rtl818x_ioread16(priv, ARFR);
+
+               /* stop unused queus (no dma alloc) */
+               rtl818x_iowrite8(priv, &priv->map->TPPOLL_STOP,
+                              RTL818x_TPPOLL_STOP_MG | RTL818x_TPPOLL_STOP_HI);
+
+               rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0x00);
+               rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50);
+
+               rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0);
+
+               /* some black magic here.. */
+               rtl8187se_mac_config(dev);
+
+               rtl818x_iowrite16(priv, RFSW_CTRL, 0x569A);
+               rtl818x_ioread16(priv, RFSW_CTRL);
+
+               rtl8180_set_anaparam(priv, RTL8225SE_ANAPARAM_ON);
+               rtl8180_set_anaparam2(priv, RTL8225SE_ANAPARAM2_ON);
+               rtl8180_set_anaparam3(priv, RTL8225SE_ANAPARAM3);
+
+
+               rtl818x_iowrite8(priv, &priv->map->CONFIG5,
+                           rtl818x_ioread8(priv, &priv->map->CONFIG5) & 0x7F);
+
+               /*probably this switch led on */
+               rtl818x_iowrite8(priv, &priv->map->PGSELECT,
+                           rtl818x_ioread8(priv, &priv->map->PGSELECT) | 0x08);
+
+               rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
+               rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1BFF);
+               rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488);
+
+               rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x4003);
+
+               /* the reference code mac hardcode table write
+                * this reg by doing byte-wide accesses.
+                * It does it just for lowest and highest byte..
+                */
+               reg32 = rtl818x_ioread32(priv, &priv->map->RF_PARA);
+               reg32 &= 0x00ffff00;
+               reg32 |= 0xb8000054;
+               rtl818x_iowrite32(priv, &priv->map->RF_PARA, reg32);
        }
 
        priv->rf->init(dev);
@@ -499,17 +926,26 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
        else
                rtl8180_conf_basic_rates(dev, 0x1f3);
 
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+               rtl8187se_set_antenna_config(dev,
+                                            priv->antenna_diversity_default,
+                                            priv->antenna_diversity_en);
        return 0;
 }
 
 static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
 {
        struct rtl8180_priv *priv = dev->priv;
-       struct rtl8180_rx_desc *entry;
+       struct rtl818x_rx_cmd_desc *entry;
        int i;
 
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+               priv->rx_ring_sz = sizeof(struct rtl8187se_rx_desc);
+       else
+               priv->rx_ring_sz = sizeof(struct rtl8180_rx_desc);
+
        priv->rx_ring = pci_alloc_consistent(priv->pdev,
-                                            sizeof(*priv->rx_ring) * 32,
+                                            priv->rx_ring_sz * 32,
                                             &priv->rx_ring_dma);
 
        if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) {
@@ -517,13 +953,13 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
                return -ENOMEM;
        }
 
-       memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * 32);
+       memset(priv->rx_ring, 0, priv->rx_ring_sz * 32);
        priv->rx_idx = 0;
 
        for (i = 0; i < 32; i++) {
                struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE);
                dma_addr_t *mapping;
-               entry = &priv->rx_ring[i];
+               entry = priv->rx_ring + priv->rx_ring_sz*i;
                if (!skb) {
                        wiphy_err(dev->wiphy, "Cannot allocate RX skb\n");
                        return -ENOMEM;
@@ -563,7 +999,7 @@ static void rtl8180_free_rx_ring(struct ieee80211_hw *dev)
                kfree_skb(skb);
        }
 
-       pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * 32,
+       pci_free_consistent(priv->pdev, priv->rx_ring_sz * 32,
                            priv->rx_ring, priv->rx_ring_dma);
        priv->rx_ring = NULL;
 }
@@ -627,7 +1063,7 @@ static int rtl8180_start(struct ieee80211_hw *dev)
        if (ret)
                return ret;
 
-       for (i = 0; i < 4; i++)
+       for (i = 0; i < (dev->queues + 1); i++)
                if ((ret = rtl8180_init_tx_ring(dev, i, 16)))
                        goto err_free_rings;
 
@@ -635,23 +1071,28 @@ static int rtl8180_start(struct ieee80211_hw *dev)
        if (ret)
                goto err_free_rings;
 
-       rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
-       rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma);
-       rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma);
-       rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma);
-       rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma);
-
-       ret = request_irq(priv->pdev->irq, rtl8180_interrupt,
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               ret = request_irq(priv->pdev->irq, rtl8187se_interrupt,
                          IRQF_SHARED, KBUILD_MODNAME, dev);
+       } else {
+               ret = request_irq(priv->pdev->irq, rtl8180_interrupt,
+                         IRQF_SHARED, KBUILD_MODNAME, dev);
+       }
+
        if (ret) {
                wiphy_err(dev->wiphy, "failed to register IRQ handler\n");
                goto err_free_rings;
        }
 
-       rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+       rtl8180_int_enable(dev);
 
-       rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
-       rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
+       /* in rtl8187se at MAR regs offset there is the management
+        * TX descriptor DMA addres..
+        */
+       if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8187SE) {
+               rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
+               rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
+       }
 
        reg = RTL818X_RX_CONF_ONLYERLPKT |
              RTL818X_RX_CONF_RX_AUTORESETPHY |
@@ -663,11 +1104,13 @@ static int rtl8180_start(struct ieee80211_hw *dev)
 
        if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185)
                reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2;
-       else {
+       else if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) {
                reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1)
                        ? RTL818X_RX_CONF_CSDM1 : 0;
                reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2)
                        ? RTL818X_RX_CONF_CSDM2 : 0;
+       } else {
+               reg &= ~(RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2);
        }
 
        priv->rx_conf = reg;
@@ -678,6 +1121,7 @@ static int rtl8180_start(struct ieee80211_hw *dev)
 
                /* CW is not on per-packet basis.
                 * in rtl8185 the CW_VALUE reg is used.
+                * in rtl8187se the AC param regs are used.
                 */
                reg &= ~RTL818X_CW_CONF_PERPACKET_CW;
                /* retry limit IS on per-packet basis.
@@ -705,7 +1149,8 @@ static int rtl8180_start(struct ieee80211_hw *dev)
        reg |= (6 << 21 /* MAX TX DMA */) |
               RTL818X_TX_CONF_NO_ICV;
 
-
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+               reg |= 1<<30;  /*  "duration procedure mode" */
 
        if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180)
                reg &= ~RTL818X_TX_CONF_PROBE_DTS;
@@ -728,7 +1173,7 @@ static int rtl8180_start(struct ieee80211_hw *dev)
 
  err_free_rings:
        rtl8180_free_rx_ring(dev);
-       for (i = 0; i < 4; i++)
+       for (i = 0; i < (dev->queues + 1); i++)
                if (priv->tx_ring[i].desc)
                        rtl8180_free_tx_ring(dev, i);
 
@@ -741,7 +1186,7 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
        u8 reg;
        int i;
 
-       rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+       rtl8180_int_disable(dev);
 
        reg = rtl818x_ioread8(priv, &priv->map->CMD);
        reg &= ~RTL818X_CMD_TX_ENABLE;
@@ -758,7 +1203,7 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
        free_irq(priv->pdev->irq, dev);
 
        rtl8180_free_rx_ring(dev);
-       for (i = 0; i < 4; i++)
+       for (i = 0; i < (dev->queues + 1); i++)
                rtl8180_free_tx_ring(dev, i);
 }
 
@@ -866,6 +1311,49 @@ static int rtl8180_config(struct ieee80211_hw *dev, u32 changed)
        return 0;
 }
 
+static void rtl8187se_conf_ac_parm(struct ieee80211_hw *dev, u8 queue)
+{
+       const struct ieee80211_tx_queue_params *params;
+       struct rtl8180_priv *priv = dev->priv;
+
+       /* hw value */
+       u32 ac_param;
+
+       u8 aifs;
+       u8 txop;
+       u8 cw_min, cw_max;
+
+       params = &priv->queue_param[queue];
+
+       cw_min = fls(params->cw_min);
+       cw_max = fls(params->cw_max);
+
+       aifs = 10 + params->aifs * priv->slot_time;
+
+       /* TODO: check if txop HW is in us (mult by 32) */
+       txop = params->txop;
+
+       ac_param = txop << AC_PARAM_TXOP_LIMIT_SHIFT |
+               cw_max << AC_PARAM_ECW_MAX_SHIFT |
+               cw_min << AC_PARAM_ECW_MIN_SHIFT |
+               aifs << AC_PARAM_AIFS_SHIFT;
+
+       switch (queue) {
+       case IEEE80211_AC_BK:
+               rtl818x_iowrite32(priv, &priv->map->AC_BK_PARAM, ac_param);
+               break;
+       case IEEE80211_AC_BE:
+               rtl818x_iowrite32(priv, &priv->map->AC_BE_PARAM, ac_param);
+               break;
+       case IEEE80211_AC_VI:
+               rtl818x_iowrite32(priv, &priv->map->AC_VI_PARAM, ac_param);
+               break;
+       case IEEE80211_AC_VO:
+               rtl818x_iowrite32(priv, &priv->map->AC_VO_PARAM, ac_param);
+               break;
+       }
+}
+
 static int rtl8180_conf_tx(struct ieee80211_hw *dev,
                            struct ieee80211_vif *vif, u16 queue,
                            const struct ieee80211_tx_queue_params *params)
@@ -880,8 +1368,12 @@ static int rtl8180_conf_tx(struct ieee80211_hw *dev,
        cw_min = fls(params->cw_min);
        cw_max = fls(params->cw_max);
 
-       rtl818x_iowrite8(priv, &priv->map->CW_VAL, (cw_max << 4) | cw_min);
-
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               priv->queue_param[queue] = *params;
+               rtl8187se_conf_ac_parm(dev, queue);
+       } else
+               rtl818x_iowrite8(priv, &priv->map->CW_VAL,
+                                (cw_max << 4) | cw_min);
        return 0;
 }
 
@@ -923,13 +1415,17 @@ static void rtl8180_conf_erp(struct ieee80211_hw *dev,
        /* from reference code. set ack timeout reg = eifs reg */
        rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, hw_eifs);
 
-       /* rtl8187/rtl8185 HW bug. After EIFS is elapsed,
-        * the HW still wait for DIFS.
-        * HW uses 4uS units for EIFS.
-        */
-       hw_eifs = DIV_ROUND_UP(eifs - difs, 4);
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+               rtl818x_iowrite8(priv, &priv->map->EIFS_8187SE, hw_eifs);
+       else if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) {
+               /* rtl8187/rtl8185 HW bug. After EIFS is elapsed,
+                * the HW still wait for DIFS.
+                * HW uses 4uS units for EIFS.
+                */
+               hw_eifs = DIV_ROUND_UP(eifs - difs, 4);
 
-       rtl818x_iowrite8(priv, &priv->map->EIFS, hw_eifs);
+               rtl818x_iowrite8(priv, &priv->map->EIFS, hw_eifs);
+       }
 }
 
 static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
@@ -956,6 +1452,10 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
                                reg = RTL818X_MSR_INFRA;
                } else
                        reg = RTL818X_MSR_NO_LINK;
+
+               if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+                       reg |= RTL818X_MSR_ENEDCA;
+
                rtl818x_iowrite8(priv, &priv->map->MSR, reg);
        }
 
@@ -975,6 +1475,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
                                        &priv->rates[0])) - 10;
 
                rtl8180_conf_erp(dev, info);
+
+               /* mac80211 supplies aifs_n to driver and calls
+                * conf_tx callback whether aifs_n changes, NOT
+                * when aifs changes.
+                * Aifs should be recalculated if slot changes.
+                */
+               if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+                       for (i = 0; i < 4; i++)
+                               rtl8187se_conf_ac_parm(dev, i);
+               }
        }
 
        if (changed & BSS_CHANGED_BEACON_ENABLED)
@@ -1098,7 +1608,10 @@ static void rtl8180_eeprom_read(struct rtl8180_priv *priv)
 
        eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)priv->mac_addr, 3);
 
-       eeprom_cck_table_adr = 0x10;
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+               eeprom_cck_table_adr = 0x30;
+       else
+               eeprom_cck_table_adr = 0x10;
 
        /* CCK TX power */
        for (i = 0; i < 14; i += 2) {
@@ -1126,6 +1639,19 @@ static void rtl8180_eeprom_read(struct rtl8180_priv *priv)
                eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam);
        }
 
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+               eeprom_93cx6_read(&eeprom, 0x3F, &eeprom_val);
+               priv->antenna_diversity_en = !!(eeprom_val & 0x100);
+               priv->antenna_diversity_default = (eeprom_val & 0xC00) == 0x400;
+
+               eeprom_93cx6_read(&eeprom, 0x7C, &eeprom_val);
+               priv->xtal_out = eeprom_val & 0xF;
+               priv->xtal_in = (eeprom_val & 0xF0) >> 4;
+               priv->xtal_cal = !!(eeprom_val & 0x1000);
+               priv->thermal_meter_val = (eeprom_val & 0xF00) >> 8;
+               priv->thermal_meter_en = !!(eeprom_val & 0x2000);
+       }
+
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
                        RTL818X_EEPROM_CMD_NORMAL);
 }
@@ -1221,7 +1747,6 @@ static int rtl8180_probe(struct pci_dev *pdev,
        dev->vif_data_size = sizeof(struct rtl8180_vif);
        dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                        BIT(NL80211_IFTYPE_ADHOC);
-       dev->queues = 1;
        dev->max_signal = 65;
 
        reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
@@ -1246,12 +1771,30 @@ static int rtl8180_probe(struct pci_dev *pdev,
                chip_name = "RTL8185vD";
                priv->chip_family = RTL818X_CHIP_FAMILY_RTL8185;
                break;
+
+       case RTL818X_TX_CONF_RTL8187SE:
+               chip_name = "RTL8187SE";
+               priv->chip_family = RTL818X_CHIP_FAMILY_RTL8187SE;
+               break;
+
        default:
                printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n",
                       pci_name(pdev), reg >> 25);
                goto err_iounmap;
        }
 
+       /* we declare to MAC80211 all the queues except for beacon queue
+        * that will be eventually handled by DRV.
+        * TX rings are arranged in such a way that lower is the IDX,
+        * higher is the priority, in order to achieve direct mapping
+        * with mac80211, however the beacon queue is an exception and it
+        * is mapped on the highst tx ring IDX.
+        */
+       if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+               dev->queues = RTL8187SE_NR_TX_QUEUES - 1;
+       else
+               dev->queues = RTL8180_NR_TX_QUEUES - 1;
+
        if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) {
                priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates);
                pci_try_set_mwi(pdev);
@@ -1270,7 +1813,11 @@ static int rtl8180_probe(struct pci_dev *pdev,
                break;
        case 5: priv->rf = &grf5101_rf_ops;
                break;
-       case 9: priv->rf = rtl8180_detect_rf(dev);
+       case 9:
+               if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+                       priv->rf = rtl8187se_detect_rf(dev);
+               else
+                       priv->rf = rtl8180_detect_rf(dev);
                break;
        case 10:
                rf_name = "RTL8255";
index 26383d77fc3a464c87138238d558b7653e1fd280..291a55970d1ab0ebdaabcc6463a4a458afab307d 100644 (file)
 #define ANAPARAM_PWR1_SHIFT    20
 #define ANAPARAM_PWR1_MASK     (0x7F << ANAPARAM_PWR1_SHIFT)
 
+/* rtl8180/rtl8185 have 3 queue + beacon queue.
+ * mac80211 can use just one, + beacon = 2 tot.
+ */
+#define RTL8180_NR_TX_QUEUES 2
+
+/* rtl8187SE have 6 queues + beacon queues
+ * mac80211 can use 4 QoS data queue, + beacon = 5 tot
+ */
+#define RTL8187SE_NR_TX_QUEUES 5
+
+/* for array static allocation, it is the max of above */
+#define RTL818X_NR_TX_QUEUES 5
+
 struct rtl8180_tx_desc {
        __le32 flags;
        __le16 rts_duration;
        __le16 plcp_len;
        __le32 tx_buf;
-       __le32 frame_len;
+       union{
+               __le32 frame_len;
+               struct {
+                       __le16 frame_len_se;
+                       __le16 frame_duration;
+               } __packed;
+       } __packed;
        __le32 next_tx_desc;
        u8 cw;
        u8 retry_limit;
        u8 agc;
        u8 flags2;
-       u32 reserved[2];
+       /* rsvd for 8180/8185.
+        * valid for 8187se but we dont use it
+        */
+       u32 reserved;
+       /* all rsvd for 8180/8185 */
+       __le16 flags3;
+       __le16 frag_qsize;
+} __packed;
+
+struct rtl818x_rx_cmd_desc {
+       __le32 flags;
+       u32 reserved;
+       __le32 rx_buf;
 } __packed;
 
 struct rtl8180_rx_desc {
        __le32 flags;
        __le32 flags2;
-       union {
-               __le32 rx_buf;
-               __le64 tsft;
-       };
+       __le64 tsft;
+
+} __packed;
+
+struct rtl8187se_rx_desc {
+       __le32 flags;
+       __le64 tsft;
+       __le32 flags2;
+       __le32 flags3;
+       u32 reserved[3];
 } __packed;
 
 struct rtl8180_tx_ring {
@@ -71,14 +108,16 @@ struct rtl8180_priv {
 
        /* rtl8180 driver specific */
        spinlock_t lock;
-       struct rtl8180_rx_desc *rx_ring;
+       void *rx_ring;
+       u8 rx_ring_sz;
        dma_addr_t rx_ring_dma;
        unsigned int rx_idx;
        struct sk_buff *rx_buf[32];
-       struct rtl8180_tx_ring tx_ring[4];
+       struct rtl8180_tx_ring tx_ring[RTL818X_NR_TX_QUEUES];
        struct ieee80211_channel channels[14];
        struct ieee80211_rate rates[12];
        struct ieee80211_supported_band band;
+       struct ieee80211_tx_queue_params queue_param[4];
        struct pci_dev *pdev;
        u32 rx_conf;
        u8 slot_time;
@@ -87,18 +126,27 @@ struct rtl8180_priv {
        enum {
                RTL818X_CHIP_FAMILY_RTL8180,
                RTL818X_CHIP_FAMILY_RTL8185,
+               RTL818X_CHIP_FAMILY_RTL8187SE,
        } chip_family;
        u32 anaparam;
        u16 rfparam;
        u8 csthreshold;
        u8 mac_addr[ETH_ALEN];
        u8 rf_type;
+       u8 xtal_out;
+       u8 xtal_in;
+       u8 xtal_cal;
+       u8 thermal_meter_val;
+       u8 thermal_meter_en;
+       u8 antenna_diversity_en;
+       u8 antenna_diversity_default;
        /* sequence # */
        u16 seqno;
 };
 
 void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
 void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam);
+void rtl8180_set_anaparam2(struct rtl8180_priv *priv, u32 anaparam2);
 
 static inline u8 rtl818x_ioread8(struct rtl8180_priv *priv, u8 __iomem *addr)
 {
index 1c0fe238d995326b81d026abe69bd1f251b8ae3e..9bda5bc78edafd72964b6f03772e62f10da01ca9 100644 (file)
@@ -282,6 +282,7 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
 
        msleep(1); /* FIXME: optional? */
 
+       /* TODO: use set_anaparam2 dev.c_func*/
        /* anaparam2 on */
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.c b/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.c
new file mode 100644 (file)
index 0000000..fde8986
--- /dev/null
@@ -0,0 +1,475 @@
+
+/* Radio tuning for RTL8225 on RTL8187SE
+ *
+ * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
+ * Copyright 2014 Andrea Merello <andrea.merello@gmail.com>
+ *
+ * Based on the r8180 and Realtek r8187se drivers, which are:
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
+ *
+ * Also based on the rtl8187 driver, which is:
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <net/mac80211.h>
+
+#include "rtl8180.h"
+#include "rtl8225se.h"
+
+#define PFX "rtl8225 (se) "
+
+static const u32 RF_GAIN_TABLE[] = {
+       0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
+       0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
+       0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
+       0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
+       0x0183, 0x0163, 0x0143, 0x0123, 0x0103
+};
+
+static const u8 cck_ofdm_gain_settings[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+       0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+       0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+       0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+       0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+};
+
+static const u8 rtl8225se_tx_gain_cck_ofdm[] = {
+       0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
+};
+
+static const u8 rtl8225se_tx_power_cck[] = {
+       0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
+       0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
+       0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
+       0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
+       0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
+       0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
+};
+
+static const u8 rtl8225se_tx_power_cck_ch14[] = {
+       0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
+       0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
+       0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
+       0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+       0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
+       0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225se_tx_power_ofdm[] = {
+       0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
+};
+
+static const u32 rtl8225se_chan[] = {
+       0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
+       0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x074A,
+};
+
+static const u8 rtl8225sez2_tx_power_cck_ch14[] = {
+       0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225sez2_tx_power_cck_B[] = {
+       0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04
+};
+
+static const u8 rtl8225sez2_tx_power_cck_A[] = {
+       0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04
+};
+
+static const u8 rtl8225sez2_tx_power_cck[] = {
+       0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
+};
+
+static const u8 ZEBRA_AGC[] = {
+       0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A,
+       0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
+       0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A,
+       0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
+       0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27,
+       0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
+       0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
+       0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b,
+       0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
+       0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21,
+       0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+       0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
+       0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
+};
+
+static const u8 OFDM_CONFIG[] = {
+       0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
+       0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
+       0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
+       0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
+       0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
+       0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
+       0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
+       0xD8, 0x3C, 0x7B, 0x10, 0x10
+};
+
+static void rtl8187se_three_wire_io(struct ieee80211_hw *dev, u8 *data,
+                                   u8 len, bool write)
+{
+       struct rtl8180_priv *priv = dev->priv;
+       int i;
+       u8 tmp;
+
+       do {
+               for (i = 0; i < 5; i++) {
+                       tmp = rtl818x_ioread8(priv, SW_3W_CMD1);
+                       if (!(tmp & 0x3))
+                               break;
+                       udelay(10);
+               }
+               if (i == 5)
+                       wiphy_err(dev->wiphy, PFX
+                               "CmdReg: 0x%x RE/WE bits aren't clear\n", tmp);
+
+               tmp = rtl818x_ioread8(priv, &priv->map->rf_sw_config) | 0x02;
+               rtl818x_iowrite8(priv, &priv->map->rf_sw_config, tmp);
+
+               tmp = rtl818x_ioread8(priv, REG_ADDR1(0x84)) & 0xF7;
+               rtl818x_iowrite8(priv, REG_ADDR1(0x84), tmp);
+               if (write) {
+                       if (len == 16) {
+                               rtl818x_iowrite16(priv, SW_3W_DB0,
+                                 *(u16 *)data);
+                       } else if (len == 64) {
+                               rtl818x_iowrite32(priv, SW_3W_DB0_4,
+                                 *((u32 *)data));
+                               rtl818x_iowrite32(priv, SW_3W_DB1_4,
+                                 *((u32 *)(data + 4)));
+                       } else
+                               wiphy_err(dev->wiphy, PFX
+                                       "Unimplemented length\n");
+               } else {
+                       rtl818x_iowrite16(priv, SW_3W_DB0, *(u16 *)data);
+               }
+               if (write)
+                       tmp = 2;
+               else
+                       tmp = 1;
+               rtl818x_iowrite8(priv, SW_3W_CMD1, tmp);
+               for (i = 0; i < 5; i++) {
+                       tmp = rtl818x_ioread8(priv, SW_3W_CMD1);
+                       if (!(tmp & 0x3))
+                               break;
+                       udelay(10);
+               }
+               rtl818x_iowrite8(priv, SW_3W_CMD1, 0);
+               if (!write) {
+                       *((u16 *)data) = rtl818x_ioread16(priv, SI_DATA_REG);
+                       *((u16 *)data) &= 0x0FFF;
+               }
+       } while (0);
+}
+
+static u32 rtl8187se_rf_readreg(struct ieee80211_hw *dev, u8 addr)
+{
+       u32 dataread = addr & 0x0F;
+       rtl8187se_three_wire_io(dev, (u8 *)&dataread, 16, 0);
+       return dataread;
+}
+
+static void rtl8187se_rf_writereg(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+       u32 outdata = (data << 4) | (u32)(addr & 0x0F);
+       rtl8187se_three_wire_io(dev, (u8 *)&outdata, 16, 1);
+}
+
+
+static void rtl8225se_write_zebra_agc(struct ieee80211_hw *dev)
+{
+       int i;
+
+       for (i = 0; i < 128; i++) {
+               rtl8225se_write_phy_ofdm(dev, 0xF, ZEBRA_AGC[i]);
+               rtl8225se_write_phy_ofdm(dev, 0xE, i+0x80);
+               rtl8225se_write_phy_ofdm(dev, 0xE, 0);
+       }
+}
+
+static void rtl8187se_write_ofdm_config(struct ieee80211_hw *dev)
+{
+       /* write OFDM_CONFIG table */
+       int i;
+
+       for (i = 0; i < 60; i++)
+               rtl8225se_write_phy_ofdm(dev, i, OFDM_CONFIG[i]);
+
+}
+
+static void rtl8225sez2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+       struct rtl8180_priv *priv = dev->priv;
+       u8 cck_power, ofdm_power;
+
+       cck_power = priv->channels[channel - 1].hw_value & 0xFF;
+       if (cck_power > 35)
+               cck_power = 35;
+       rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+                        cck_ofdm_gain_settings[cck_power]);
+
+       usleep_range(1000, 5000);
+       ofdm_power = priv->channels[channel - 1].hw_value >> 8;
+       if (ofdm_power > 35)
+               ofdm_power = 35;
+
+       rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+                        cck_ofdm_gain_settings[ofdm_power]);
+       if (ofdm_power < 12) {
+               rtl8225se_write_phy_ofdm(dev, 7, 0x5C);
+               rtl8225se_write_phy_ofdm(dev, 9, 0x5C);
+       }
+       if (ofdm_power < 18) {
+               rtl8225se_write_phy_ofdm(dev, 7, 0x54);
+               rtl8225se_write_phy_ofdm(dev, 9, 0x54);
+       } else {
+               rtl8225se_write_phy_ofdm(dev, 7, 0x50);
+               rtl8225se_write_phy_ofdm(dev, 9, 0x50);
+       }
+
+       usleep_range(1000, 5000);
+}
+
+static void rtl8187se_write_rf_gain(struct ieee80211_hw *dev)
+{
+       int i;
+
+       for (i = 0; i <= 36; i++) {
+               rtl8187se_rf_writereg(dev, 0x01, i); mdelay(1);
+               rtl8187se_rf_writereg(dev, 0x02, RF_GAIN_TABLE[i]); mdelay(1);
+       }
+}
+
+static void rtl8187se_write_initial_gain(struct ieee80211_hw *dev,
+                                       int init_gain)
+{
+       switch (init_gain) {
+       default:
+               rtl8225se_write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x05, 0xFA); mdelay(1);
+               break;
+       case 2:
+               rtl8225se_write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x05, 0xFA); mdelay(1);
+               break;
+       case 3:
+               rtl8225se_write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
+               break;
+       case 4:
+               rtl8225se_write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
+               break;
+       case 5:
+               rtl8225se_write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
+               break;
+       case 6:
+               rtl8225se_write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
+               break;
+       case 7:
+               rtl8225se_write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x24, 0xA6); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
+               break;
+       case 8:
+               rtl8225se_write_phy_ofdm(dev, 0x17, 0x66); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x24, 0xB6); mdelay(1);
+               rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
+               break;
+       }
+}
+
+void rtl8225se_rf_init(struct ieee80211_hw *dev)
+{
+       struct rtl8180_priv *priv = dev->priv;
+       u32 rf23, rf24;
+       u8 d_cut = 0;
+       u8 tmp;
+
+       /* Page 1 */
+       rtl8187se_rf_writereg(dev, 0x00, 0x013F); mdelay(1);
+       rf23 = rtl8187se_rf_readreg(dev, 0x08); mdelay(1);
+       rf24 = rtl8187se_rf_readreg(dev, 0x09); mdelay(1);
+       if (rf23 == 0x0818 && rf24 == 0x070C)
+               d_cut = 1;
+
+       wiphy_info(dev->wiphy, "RTL8225-SE version %s\n",
+               d_cut ? "D" : "not-D");
+
+       /* Page 0: reg 0 - 15 */
+       rtl8187se_rf_writereg(dev, 0x00, 0x009F); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x01, 0x06E0); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x02, 0x004D); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x03, 0x07F1); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x04, 0x0975); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x05, 0x0C72); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x06, 0x0AE6); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x07, 0x00CA); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x08, 0x0E1C); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x09, 0x02F0); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0A, 0x09D0); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0B, 0x01BA); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0C, 0x0640); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0D, 0x08DF); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0E, 0x0020); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0F, 0x0990); mdelay(1);
+       /* page 1: reg 16-30 */
+       rtl8187se_rf_writereg(dev, 0x00, 0x013F); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x03, 0x0806); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x04, 0x03A7); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x05, 0x059B); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x06, 0x0081); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x07, 0x01A0); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0A, 0x0001); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0B, 0x0418); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0C, 0x0FBE); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0D, 0x0008); mdelay(1);
+       if (d_cut)
+               rtl8187se_rf_writereg(dev, 0x0E, 0x0807);
+       else
+               rtl8187se_rf_writereg(dev, 0x0E, 0x0806);
+       mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0F, 0x0ACC); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x00, 0x01D7); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x03, 0x0E00); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x04, 0x0E50); mdelay(1);
+
+       rtl8187se_write_rf_gain(dev);
+
+       rtl8187se_rf_writereg(dev, 0x05, 0x0203); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x06, 0x0200); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x00, 0x0137); mdelay(11);
+       rtl8187se_rf_writereg(dev, 0x0D, 0x0008); mdelay(11);
+       rtl8187se_rf_writereg(dev, 0x00, 0x0037); mdelay(11);
+       rtl8187se_rf_writereg(dev, 0x04, 0x0160); mdelay(11);
+       rtl8187se_rf_writereg(dev, 0x07, 0x0080); mdelay(11);
+       rtl8187se_rf_writereg(dev, 0x02, 0x088D); mdelay(221);
+       rtl8187se_rf_writereg(dev, 0x00, 0x0137); mdelay(11);
+       rtl8187se_rf_writereg(dev, 0x07, 0x0000); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x07, 0x0180); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x07, 0x0220); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x07, 0x03E0); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x06, 0x00C1); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0A, 0x0001); mdelay(1);
+       if (priv->xtal_cal) {
+               tmp = (priv->xtal_in << 4) | (priv->xtal_out << 1) |
+                     (1 << 11) | (1 << 9);
+               rtl8187se_rf_writereg(dev, 0x0F, tmp);
+               wiphy_info(dev->wiphy, "Xtal cal\n");
+               mdelay(1);
+       } else {
+               wiphy_info(dev->wiphy, "NO Xtal cal\n");
+               rtl8187se_rf_writereg(dev, 0x0F, 0x0ACC);
+               mdelay(1);
+       }
+       /* page 0 */
+       rtl8187se_rf_writereg(dev, 0x00, 0x00BF); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x0D, 0x08DF); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x02, 0x004D); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x04, 0x0975); mdelay(31);
+       rtl8187se_rf_writereg(dev, 0x00, 0x0197); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x05, 0x05AB); mdelay(1);
+
+       rtl8187se_rf_writereg(dev, 0x00, 0x009F); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x01, 0x0000); mdelay(1);
+       rtl8187se_rf_writereg(dev, 0x02, 0x0000); mdelay(1);
+       /* power save parameters */
+       /* TODO: move to dev.c */
+       rtl818x_iowrite8(priv, REG_ADDR1(0x024E),
+                rtl818x_ioread8(priv, REG_ADDR1(0x24E)) & 0x9F);
+       rtl8225se_write_phy_cck(dev, 0x00, 0xC8);
+       rtl8225se_write_phy_cck(dev, 0x06, 0x1C);
+       rtl8225se_write_phy_cck(dev, 0x10, 0x78);
+       rtl8225se_write_phy_cck(dev, 0x2E, 0xD0);
+       rtl8225se_write_phy_cck(dev, 0x2F, 0x06);
+       rtl8225se_write_phy_cck(dev, 0x01, 0x46);
+
+       /* power control */
+       rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x10);
+       rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x1B);
+
+       rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
+       rtl8225se_write_phy_ofdm(dev, 0x00, 0x12);
+
+       rtl8225se_write_zebra_agc(dev);
+
+       rtl8225se_write_phy_ofdm(dev, 0x10, 0x00);
+
+       rtl8187se_write_ofdm_config(dev);
+
+       /* turn on RF */
+       rtl8187se_rf_writereg(dev, 0x00, 0x009F); udelay(500);
+       rtl8187se_rf_writereg(dev, 0x04, 0x0972); udelay(500);
+       /* turn on RF again */
+       rtl8187se_rf_writereg(dev, 0x00, 0x009F); udelay(500);
+       rtl8187se_rf_writereg(dev, 0x04, 0x0972); udelay(500);
+       /* turn on BB */
+       rtl8225se_write_phy_ofdm(dev, 0x10, 0x40);
+       rtl8225se_write_phy_ofdm(dev, 0x12, 0x40);
+
+       rtl8187se_write_initial_gain(dev, 4);
+}
+
+void rtl8225se_rf_stop(struct ieee80211_hw *dev)
+{
+       /* checked for 8187se */
+       struct rtl8180_priv *priv = dev->priv;
+
+       /* turn off BB RXIQ matrix to cut off rx signal */
+       rtl8225se_write_phy_ofdm(dev, 0x10, 0x00);
+       rtl8225se_write_phy_ofdm(dev, 0x12, 0x00);
+       /* turn off RF */
+       rtl8187se_rf_writereg(dev, 0x04, 0x0000);
+       rtl8187se_rf_writereg(dev, 0x00, 0x0000);
+
+       usleep_range(1000, 5000);
+       /* turn off A/D and D/A */
+       rtl8180_set_anaparam(priv, RTL8225SE_ANAPARAM_OFF);
+       rtl8180_set_anaparam2(priv, RTL8225SE_ANAPARAM2_OFF);
+}
+
+void rtl8225se_rf_set_channel(struct ieee80211_hw *dev,
+                                  struct ieee80211_conf *conf)
+{
+       int chan =
+               ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
+
+       rtl8225sez2_rf_set_tx_power(dev, chan);
+       rtl8187se_rf_writereg(dev, 0x7, rtl8225se_chan[chan - 1]);
+       if ((rtl8187se_rf_readreg(dev, 0x7) & 0x0F80) !=
+               rtl8225se_chan[chan - 1])
+               rtl8187se_rf_writereg(dev, 0x7, rtl8225se_chan[chan - 1]);
+       usleep_range(10000, 20000);
+}
+
+static const struct rtl818x_rf_ops rtl8225se_ops = {
+       .name           = "rtl8225-se",
+       .init           = rtl8225se_rf_init,
+       .stop           = rtl8225se_rf_stop,
+       .set_chan       = rtl8225se_rf_set_channel,
+};
+
+const struct rtl818x_rf_ops *rtl8187se_detect_rf(struct ieee80211_hw *dev)
+{
+       return &rtl8225se_ops;
+}
diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.h
new file mode 100644 (file)
index 0000000..2294002
--- /dev/null
@@ -0,0 +1,61 @@
+
+/* Definitions for RTL8187SE hardware
+ *
+ * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
+ * Copyright 2014 Andrea Merello <andrea.merello@gmail.com>
+ *
+ * Based on the r8180 and Realtek r8187se drivers, which are:
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
+ *
+ * Also based on the rtl8187 driver, which is:
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RTL8187SE_RTL8225_H
+#define RTL8187SE_RTL8225_H
+
+#define RTL8225SE_ANAPARAM_ON  0xb0054d00
+#define RTL8225SE_ANAPARAM2_ON 0x000004c6
+
+/* all off except PLL */
+#define RTL8225SE_ANAPARAM_OFF 0xb0054dec
+/* all on including PLL */
+#define RTL8225SE_ANAPARAM_OFF2        0xb0054dfc
+
+#define RTL8225SE_ANAPARAM2_OFF        0x00ff04c6
+
+#define RTL8225SE_ANAPARAM3    0x10
+
+enum rtl8187se_power_state {
+       RTL8187SE_POWER_ON,
+       RTL8187SE_POWER_OFF,
+       RTL8187SE_POWER_SLEEP
+};
+
+static inline void rtl8225se_write_phy_ofdm(struct ieee80211_hw *dev,
+                                         u8 addr, u8 data)
+{
+       rtl8180_write_phy(dev, addr, data);
+}
+
+static inline void rtl8225se_write_phy_cck(struct ieee80211_hw *dev,
+                                        u8 addr, u8 data)
+{
+       rtl8180_write_phy(dev, addr, data | 0x10000);
+}
+
+
+const struct rtl818x_rf_ops *rtl8187se_detect_rf(struct ieee80211_hw *);
+void rtl8225se_rf_stop(struct ieee80211_hw *dev);
+void rtl8225se_rf_set_channel(struct ieee80211_hw *dev,
+                                    struct ieee80211_conf *conf);
+void rtl8225se_rf_conf_erp(struct ieee80211_hw *dev,
+                                 struct ieee80211_bss_conf *info);
+void rtl8225se_rf_init(struct ieee80211_hw *dev);
+
+#endif /* RTL8187SE_RTL8225_H */
index c981bcfb6cef1ed9d9578df88d8d93ac13384e75..0ca17cda48fa1c01b3a8dd2ed98c5fe0c5646640 100644 (file)
@@ -592,7 +592,7 @@ static void rtl8187_set_anaparam(struct rtl8187_priv *priv, bool rfon)
        rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam);
        rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, anaparam2);
        if (priv->is_rtl8187b)
-               rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, anaparam3);
+               rtl818x_iowrite8(priv, &priv->map->ANAPARAM3A, anaparam3);
        reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE;
        rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
@@ -1636,10 +1636,10 @@ static int rtl8187_probe(struct usb_interface *intf,
 
  err_free_dmabuf:
        kfree(priv->io_dmabuf);
- err_free_dev:
-       ieee80211_free_hw(dev);
        usb_set_intfdata(intf, NULL);
        usb_put_dev(udev);
+ err_free_dev:
+       ieee80211_free_hw(dev);
        return err;
 }
 
index 1815b15d03b1f9a363902a151aa74983e345b6b6..45ea4e1c4abe157ad952be2d8a5022efc1e1715a 100644 (file)
 #define RTL818X_H
 
 struct rtl818x_csr {
+
        u8      MAC[6];
        u8      reserved_0[2];
-       __le32  MAR[2];
-       u8      RX_FIFO_COUNT;
-       u8      reserved_1;
-       u8      TX_FIFO_COUNT;
-       u8      BQREQ;
-       u8      reserved_2[4];
+
+       union {
+               __le32  MAR[2];  /* 0x8 */
+
+               struct{ /* rtl8187se */
+                       u8 rf_sw_config; /* 0x8 */
+                       u8 reserved_01[3];
+                       __le32 TMGDA; /* 0xc */
+               } __packed;
+       } __packed;
+
+       union { /*  0x10  */
+               struct {
+                       u8      RX_FIFO_COUNT;
+                       u8      reserved_1;
+                       u8      TX_FIFO_COUNT;
+                       u8      BQREQ;
+               } __packed;
+
+               __le32 TBKDA; /* for 8187se */
+       } __packed;
+
+       __le32 TBEDA; /* 0x14 - for rtl8187se */
+
        __le32  TSFT[2];
-       __le32  TLPDA;
-       __le32  TNPDA;
-       __le32  THPDA;
-       __le16  BRSR;
-       u8      BSSID[6];
-       u8      RESP_RATE;
-       u8      EIFS;
-       u8      reserved_3[1];
-       u8      CMD;
+
+       union { /* 0x20 */
+               __le32  TLPDA;
+               __le32  TVIDA; /* for 8187se */
+       } __packed;
+
+       union { /* 0x24 */
+               __le32  TNPDA;
+               __le32  TVODA; /* for 8187se */
+       } __packed;
+
+       /* hi pri ring for all cards */
+       __le32  THPDA; /* 0x28 */
+
+       union { /* 0x2c */
+               struct {
+                       u8 reserved_2a;
+                       u8 EIFS_8187SE;
+               } __packed;
+
+               __le16  BRSR;
+       } __packed;
+
+       u8      BSSID[6]; /* 0x2e */
+
+       union { /* 0x34 */
+               struct {
+                       u8 RESP_RATE;
+                       u8 EIFS;
+               } __packed;
+               __le16 BRSR_8187SE;
+       } __packed;
+
+       u8      reserved_3[1]; /* 0x36 */
+       u8      CMD; /* 0x37 */
 #define RTL818X_CMD_TX_ENABLE          (1 << 2)
 #define RTL818X_CMD_RX_ENABLE          (1 << 3)
 #define RTL818X_CMD_RESET              (1 << 4)
-       u8      reserved_4[4];
-       __le16  INT_MASK;
-       __le16  INT_STATUS;
+       u8      reserved_4[4]; /* 0x38 */
+       union {
+               struct {
+                       __le16  INT_MASK;
+                       __le16  INT_STATUS;
+               } __packed;
+
+               __le32  INT_STATUS_SE; /* 0x3c */
+       } __packed;
+/* status bits for rtl8187 and rtl8180/8185 */
 #define RTL818X_INT_RX_OK              (1 <<  0)
 #define RTL818X_INT_RX_ERR             (1 <<  1)
 #define RTL818X_INT_TXL_OK             (1 <<  2)
@@ -56,7 +108,34 @@ struct rtl818x_csr {
 #define RTL818X_INT_BEACON             (1 << 13)
 #define RTL818X_INT_TIME_OUT           (1 << 14)
 #define RTL818X_INT_TX_FO              (1 << 15)
-       __le32  TX_CONF;
+/* status bits for rtl8187se */
+#define RTL818X_INT_SE_TIMER3          (1 <<  0)
+#define RTL818X_INT_SE_TIMER2          (1 <<  1)
+#define RTL818X_INT_SE_RQ0SOR          (1 <<  2)
+#define RTL818X_INT_SE_TXBED_OK                (1 <<  3)
+#define RTL818X_INT_SE_TXBED_ERR       (1 <<  4)
+#define RTL818X_INT_SE_TXBE_OK         (1 <<  5)
+#define RTL818X_INT_SE_TXBE_ERR                (1 <<  6)
+#define RTL818X_INT_SE_RX_OK           (1 <<  7)
+#define RTL818X_INT_SE_RX_ERR          (1 <<  8)
+#define RTL818X_INT_SE_TXL_OK          (1 <<  9)
+#define RTL818X_INT_SE_TXL_ERR         (1 << 10)
+#define RTL818X_INT_SE_RX_DU           (1 << 11)
+#define RTL818X_INT_SE_RX_FIFO         (1 << 12)
+#define RTL818X_INT_SE_TXN_OK          (1 << 13)
+#define RTL818X_INT_SE_TXN_ERR         (1 << 14)
+#define RTL818X_INT_SE_TXH_OK          (1 << 15)
+#define RTL818X_INT_SE_TXH_ERR         (1 << 16)
+#define RTL818X_INT_SE_TXB_OK          (1 << 17)
+#define RTL818X_INT_SE_TXB_ERR         (1 << 18)
+#define RTL818X_INT_SE_ATIM_TO         (1 << 19)
+#define RTL818X_INT_SE_BK_TO           (1 << 20)
+#define RTL818X_INT_SE_TIMER1          (1 << 21)
+#define RTL818X_INT_SE_TX_FIFO         (1 << 22)
+#define RTL818X_INT_SE_WAKEUP          (1 << 23)
+#define RTL818X_INT_SE_BK_DMA          (1 << 24)
+#define RTL818X_INT_SE_TMGD_OK         (1 << 30)
+       __le32  TX_CONF; /* 0x40 */
 #define RTL818X_TX_CONF_LOOPBACK_MAC   (1 << 17)
 #define RTL818X_TX_CONF_LOOPBACK_CONT  (3 << 17)
 #define RTL818X_TX_CONF_NO_ICV         (1 << 19)
@@ -68,6 +147,7 @@ struct rtl818x_csr {
 #define RTL818X_TX_CONF_R8185_D                (5 << 25)
 #define RTL818X_TX_CONF_R8187vD                (5 << 25)
 #define RTL818X_TX_CONF_R8187vD_B      (6 << 25)
+#define RTL818X_TX_CONF_RTL8187SE      (6 << 25)
 #define RTL818X_TX_CONF_HWVER_MASK     (7 << 25)
 #define RTL818X_TX_CONF_DISREQQSIZE    (1 << 28)
 #define RTL818X_TX_CONF_PROBE_DTS      (1 << 29)
@@ -122,28 +202,64 @@ struct rtl818x_csr {
        u8      PGSELECT;
        u8      SECURITY;
        __le32  ANAPARAM2;
-       u8      reserved_10[12];
-       __le16  BEACON_INTERVAL;
-       __le16  ATIM_WND;
-       __le16  BEACON_INTERVAL_TIME;
-       __le16  ATIMTR_INTERVAL;
-       u8      PHY_DELAY;
-       u8      CARRIER_SENSE_COUNTER;
-       u8      reserved_11[2];
-       u8      PHY[4];
-       __le16  RFPinsOutput;
-       __le16  RFPinsEnable;
-       __le16  RFPinsSelect;
-       __le16  RFPinsInput;
-       __le32  RF_PARA;
-       __le32  RF_TIMING;
-       u8      GP_ENABLE;
-       u8      GPIO0;
-       u8      GPIO1;
-       u8      reserved_12;
-       __le32  HSSI_PARA;
-       u8      reserved_13[4];
-       u8      TX_AGC_CTL;
+       u8      reserved_10[8];
+       __le32  IMR;            /* 0x6c - Interrupt mask reg for 8187se */
+#define IMR_TMGDOK      ((1 << 30))
+#define IMR_DOT11HINT  ((1 << 25))     /* 802.11h Measurement Interrupt */
+#define IMR_BCNDMAINT  ((1 << 24))     /* Beacon DMA Interrupt */
+#define IMR_WAKEINT    ((1 << 23))     /* Wake Up Interrupt */
+#define IMR_TXFOVW     ((1 << 22))     /* Tx FIFO Overflow */
+#define IMR_TIMEOUT1   ((1 << 21))     /* Time Out Interrupt 1 */
+#define IMR_BCNINT     ((1 << 20))     /* Beacon Time out */
+#define IMR_ATIMINT    ((1 << 19))     /* ATIM Time Out */
+#define IMR_TBDER      ((1 << 18))     /* Tx Beacon Descriptor Error */
+#define IMR_TBDOK      ((1 << 17))     /* Tx Beacon Descriptor OK */
+#define IMR_THPDER     ((1 << 16))     /* Tx High Priority Descriptor Error */
+#define IMR_THPDOK     ((1 << 15))     /* Tx High Priority Descriptor OK */
+#define IMR_TVODER     ((1 << 14))     /* Tx AC_VO Descriptor Error Int */
+#define IMR_TVODOK     ((1 << 13))     /* Tx AC_VO Descriptor OK Interrupt */
+#define IMR_FOVW       ((1 << 12))     /* Rx FIFO Overflow Interrupt */
+#define IMR_RDU                ((1 << 11))     /* Rx Descriptor Unavailable */
+#define IMR_TVIDER     ((1 << 10))     /* Tx AC_VI Descriptor Error */
+#define IMR_TVIDOK     ((1 << 9))      /* Tx AC_VI Descriptor OK Interrupt */
+#define IMR_RER                ((1 << 8))      /* Rx Error Interrupt */
+#define IMR_ROK                ((1 << 7))      /* Receive OK Interrupt */
+#define IMR_TBEDER     ((1 << 6))      /* Tx AC_BE Descriptor Error */
+#define IMR_TBEDOK     ((1 << 5))      /* Tx AC_BE Descriptor OK */
+#define IMR_TBKDER     ((1 << 4))      /* Tx AC_BK Descriptor Error */
+#define IMR_TBKDOK     ((1 << 3))      /* Tx AC_BK Descriptor OK */
+#define IMR_RQOSOK     ((1 << 2))      /* Rx QoS OK Interrupt */
+#define IMR_TIMEOUT2   ((1 << 1))      /* Time Out Interrupt 2 */
+#define IMR_TIMEOUT3   ((1 << 0))      /* Time Out Interrupt 3 */
+       __le16  BEACON_INTERVAL; /* 0x70 */
+       __le16  ATIM_WND; /*  0x72 */
+       __le16  BEACON_INTERVAL_TIME; /*  0x74 */
+       __le16  ATIMTR_INTERVAL; /*  0x76 */
+       u8      PHY_DELAY; /*  0x78 */
+       u8      CARRIER_SENSE_COUNTER; /* 0x79 */
+       u8      reserved_11[2]; /* 0x7a */
+       u8      PHY[4]; /* 0x7c  */
+       __le16  RFPinsOutput; /* 0x80 */
+       __le16  RFPinsEnable; /* 0x82 */
+       __le16  RFPinsSelect; /* 0x84 */
+       __le16  RFPinsInput;  /* 0x86 */
+       __le32  RF_PARA; /*  0x88 */
+       __le32  RF_TIMING; /*  0x8c */
+       u8      GP_ENABLE; /*  0x90 */
+       u8      GPIO0; /*  0x91 */
+       u8      GPIO1; /*  0x92 */
+       u8      TPPOLL_STOP; /*  0x93 - rtl8187se only */
+#define RTL818x_TPPOLL_STOP_BQ                 (1 << 7)
+#define RTL818x_TPPOLL_STOP_VI                 (1 << 4)
+#define RTL818x_TPPOLL_STOP_VO                 (1 << 5)
+#define RTL818x_TPPOLL_STOP_BE                 (1 << 3)
+#define RTL818x_TPPOLL_STOP_BK                 (1 << 2)
+#define RTL818x_TPPOLL_STOP_MG                 (1 << 1)
+#define RTL818x_TPPOLL_STOP_HI                 (1 << 6)
+
+       __le32  HSSI_PARA; /*  0x94 */
+       u8      reserved_13[4]; /* 0x98 */
+       u8      TX_AGC_CTL; /*  0x9c */
 #define RTL818X_TX_AGC_CTL_PERPACKET_GAIN      (1 << 0)
 #define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL    (1 << 1)
 #define RTL818X_TX_AGC_CTL_FEEDBACK_ANT                (1 << 2)
@@ -167,7 +283,8 @@ struct rtl818x_csr {
        u8      reserved_17[24];
        u8      CONFIG5;
        u8      TX_DMA_POLLING;
-       u8      reserved_18[2];
+       u8      PHY_PR;
+       u8      reserved_18;
        __le16  CWR;
        u8      RETRY_CTR;
        u8      reserved_19[3];
@@ -179,14 +296,59 @@ struct rtl818x_csr {
        __le32  RDSAR;
        __le16  TID_AC_MAP;
        u8      reserved_20[4];
-       u8      ANAPARAM3;
-       u8      reserved_21[5];
-       __le16  FEMR;
-       u8      reserved_22[4];
-       __le16  TALLY_CNT;
-       u8      TALLY_SEL;
+       union {
+               __le16  ANAPARAM3; /* 0xee */
+               u8      ANAPARAM3A; /* for rtl8187 */
+       };
+
+#define AC_PARAM_TXOP_LIMIT_SHIFT      16
+#define AC_PARAM_ECW_MAX_SHIFT         12
+#define AC_PARAM_ECW_MIN_SHIFT         8
+#define AC_PARAM_AIFS_SHIFT            0
+
+       __le32 AC_VO_PARAM; /* 0xf0 */
+
+       union { /* 0xf4 */
+               __le32 AC_VI_PARAM;
+               __le16 FEMR;
+       } __packed;
+
+       union{ /* 0xf8 */
+               __le32  AC_BE_PARAM; /* rtl8187se */
+               struct{
+                       u8      reserved_21[2];
+                       __le16  TALLY_CNT; /* 0xfa */
+               } __packed;
+       } __packed;
+
+       union {
+               u8      TALLY_SEL; /* 0xfc */
+               __le32  AC_BK_PARAM;
+
+       } __packed;
+
 } __packed;
 
+/* These are addresses with NON-standard usage.
+ * They have offsets very far from this struct.
+ * I don't like to introduce a ton of "reserved"..
+ * They are for RTL8187SE
+ */
+#define REG_ADDR1(addr)        ((u8 __iomem *)priv->map + addr)
+#define REG_ADDR2(addr)        ((__le16 __iomem *)priv->map + (addr >> 1))
+#define REG_ADDR4(addr)        ((__le32 __iomem *)priv->map + (addr >> 2))
+
+#define FEMR_SE                REG_ADDR2(0x1D4)
+#define ARFR           REG_ADDR2(0x1E0)
+#define RFSW_CTRL      REG_ADDR2(0x272)
+#define SW_3W_DB0      REG_ADDR2(0x274)
+#define SW_3W_DB0_4    REG_ADDR4(0x274)
+#define SW_3W_DB1      REG_ADDR2(0x278)
+#define SW_3W_DB1_4    REG_ADDR4(0x278)
+#define SW_3W_CMD1     REG_ADDR1(0x27D)
+#define PI_DATA_REG    REG_ADDR2(0x360)
+#define SI_DATA_REG     REG_ADDR2(0x362)
+
 struct rtl818x_rf_ops {
        char *name;
        void (*init)(struct ieee80211_hw *);
index ded691f76f2fb433060b71e9865fd953f93ef46f..4ec424f26672028550ab8b19b944d451766ee08c 100644 (file)
@@ -982,7 +982,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
                                u8 keep_alive = 10;
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                                 HW_VAR_KEEP_ALIVE,
-                                                (u8 *)(&keep_alive));
+                                                &keep_alive);
 
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                                      HW_VAR_H2C_FW_JOINBSSRPT,
index f26f4ffc771db688f5e69c6d148a034bdef47da0..dae55257f0e8bde44fb772173f7d573fceab6d65 100644 (file)
@@ -1509,10 +1509,10 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
 
        if (rtlpriv->use_new_trx_flow) {
                rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
-                                           HW_DESC_OWN, (u8 *)&hw_queue);
+                                           HW_DESC_OWN, &hw_queue);
        } else {
                rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
-                                           HW_DESC_OWN, (u8 *)&temp_one);
+                                           HW_DESC_OWN, &temp_one);
        }
 
        if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
@@ -1853,6 +1853,65 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
        return true;
 }
 
+static int rtl_pci_intr_mode_msi(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+       int ret;
+
+       ret = pci_enable_msi(rtlpci->pdev);
+       if (ret < 0)
+               return ret;
+
+       ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+                         IRQF_SHARED, KBUILD_MODNAME, hw);
+       if (ret < 0) {
+               pci_disable_msi(rtlpci->pdev);
+               return ret;
+       }
+
+       rtlpci->using_msi = true;
+
+       RT_TRACE(rtlpriv, COMP_INIT|COMP_INTR, DBG_DMESG,
+                "MSI Interrupt Mode!\n");
+       return 0;
+}
+
+static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+       int ret;
+
+       ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+                         IRQF_SHARED, KBUILD_MODNAME, hw);
+       if (ret < 0)
+               return ret;
+
+       rtlpci->using_msi = false;
+       RT_TRACE(rtlpriv, COMP_INIT|COMP_INTR, DBG_DMESG,
+                "Pin-based Interrupt Mode!\n");
+       return 0;
+}
+
+static int rtl_pci_intr_mode_decide(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+       int ret;
+
+       if (rtlpci->msi_support) {
+               ret = rtl_pci_intr_mode_msi(hw);
+               if (ret < 0)
+                       ret = rtl_pci_intr_mode_legacy(hw);
+       } else {
+               ret = rtl_pci_intr_mode_legacy(hw);
+       }
+       return ret;
+}
+
 int rtl_pci_probe(struct pci_dev *pdev,
                            const struct pci_device_id *id)
 {
@@ -1995,8 +2054,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
        }
 
        rtlpci = rtl_pcidev(pcipriv);
-       err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
-                         IRQF_SHARED, KBUILD_MODNAME, hw);
+       err = rtl_pci_intr_mode_decide(hw);
        if (err) {
                RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
                         "%s: failed to register IRQ handler\n",
@@ -2064,6 +2122,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
                rtlpci->irq_alloc = 0;
        }
 
+       if (rtlpci->using_msi)
+               pci_disable_msi(rtlpci->pdev);
+
        list_del(&rtlpriv->list);
        if (rtlpriv->io.pci_mem_start != 0) {
                pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
index de7f05f848ef47ddaf3c18a1e727a7cbb401b1db..50504942ded151f40a198099b6fd31013774ca93 100644 (file)
@@ -759,7 +759,7 @@ static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
                           unsigned int len)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct ieee80211_mgmt *mgmt = (void *)data;
+       struct ieee80211_mgmt *mgmt = data;
        struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
        u8 *pos, *end, *ie;
        u16 noa_len;
@@ -858,7 +858,7 @@ static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
                              unsigned int len)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct ieee80211_mgmt *mgmt = (void *)data;
+       struct ieee80211_mgmt *mgmt = data;
        struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
        u8 noa_num, index, i, noa_index = 0;
        u8 *pos, *end, *ie;
@@ -950,9 +950,8 @@ void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
        switch (p2p_ps_state) {
        case P2P_PS_DISABLE:
                p2pinfo->p2p_ps_state = p2p_ps_state;
-               rtlpriv->cfg->ops->set_hw_reg(hw,
-                                HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
-                                (u8 *)(&p2p_ps_state));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+                                             &p2p_ps_state);
 
                p2pinfo->noa_index = 0;
                p2pinfo->ctwindow = 0;
@@ -964,7 +963,7 @@ void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
                                rtlps->smart_ps = 2;
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                         HW_VAR_H2C_FW_PWRMODE,
-                                        (u8 *)(&rtlps->pwr_mode));
+                                        &rtlps->pwr_mode);
                        }
                }
                break;
@@ -977,12 +976,12 @@ void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
                                        rtlps->smart_ps = 0;
                                        rtlpriv->cfg->ops->set_hw_reg(hw,
                                                 HW_VAR_H2C_FW_PWRMODE,
-                                                (u8 *)(&rtlps->pwr_mode));
+                                                &rtlps->pwr_mode);
                                }
                        }
                        rtlpriv->cfg->ops->set_hw_reg(hw,
                                 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
-                                (u8 *)(&p2p_ps_state));
+                                &p2p_ps_state);
                }
                break;
        case P2P_PS_SCAN:
@@ -992,7 +991,7 @@ void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
                        p2pinfo->p2p_ps_state = p2p_ps_state;
                        rtlpriv->cfg->ops->set_hw_reg(hw,
                                 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
-                                (u8 *)(&p2p_ps_state));
+                                &p2p_ps_state);
                }
                break;
        default:
@@ -1012,7 +1011,7 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       struct ieee80211_hdr *hdr = (void *)data;
+       struct ieee80211_hdr *hdr = data;
 
        if (!mac->p2p)
                return;
index 97bc9aa5e1d1c42cc1abaff03bf87c16ada8ac5f..f8daa61cf1c32df10b6ff69428d8aa4e434f090d 100644 (file)
@@ -851,9 +851,8 @@ static void rtl88e_dm_check_edca_turbo(struct ieee80211_hw *hw)
        } else {
                if (rtlpriv->dm.current_turbo_edca) {
                        u8 tmp = AC0_BE;
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_AC_PARAM,
-                                                     (u8 *)(&tmp));
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+                                                     &tmp);
                        rtlpriv->dm.current_turbo_edca = false;
                }
        }
index 557bc5b8327eef6d9b998fcc90e52270d84e6077..4f9376ad473966c9b19c986080e73e047a40adde 100644 (file)
@@ -119,7 +119,7 @@ static void _rtl88e_write_fw(struct ieee80211_hw *hw,
                             enum version_8188e version, u8 *buffer, u32 size)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u8 *buf_ptr = (u8 *)buffer;
+       u8 *buf_ptr = buffer;
        u32 page_no, remain;
        u32 page, offset;
 
@@ -213,7 +213,7 @@ int rtl88e_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
                return 1;
 
        pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
-       pfwdata = (u8 *)rtlhal->pfirmware;
+       pfwdata = rtlhal->pfirmware;
        fwsize = rtlhal->fwsize;
        RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
                 "normal Firmware SIZE %d\n", fwsize);
index bd2a26bafb695c750b47d4d164a7f357e3ee9488..94cd9df98381008e53f6ecb60cbcb7f56a6aef1b 100644 (file)
@@ -147,8 +147,7 @@ static void _rtl88ee_set_fw_clock_on(struct ieee80211_hw *hw,
        }
 
        if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) {
-               rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
-                                             (u8 *)(&rpwm_val));
+               rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
                if (FW_PS_IS_ACK(rpwm_val)) {
                        isr_regaddr = REG_HISR;
                        content = rtl_read_dword(rtlpriv, isr_regaddr);
@@ -225,7 +224,7 @@ static void _rtl88ee_set_fw_clock_off(struct ieee80211_hw *hw,
                        rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
                        rtl_write_word(rtlpriv, REG_HISR, 0x0100);
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-                                                     (u8 *)(&rpwm_val));
+                                                     &rpwm_val);
                        spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
                        rtlhal->fw_clk_change_in_progress = false;
                        spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
@@ -273,15 +272,14 @@ static void _rtl88ee_fwlps_leave(struct ieee80211_hw *hw)
                _rtl88ee_set_fw_clock_on(hw, rpwm_val, false);
                rtlhal->allow_sw_to_change_hwclc = false;
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-                                             (u8 *)(&fw_pwrmode));
+                                             &fw_pwrmode);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
                                              (u8 *)(&fw_current_inps));
        } else {
                rpwm_val = FW_PS_STATE_ALL_ON_88E;      /* RF on */
-               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-                                             (u8 *)(&rpwm_val));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-                                             (u8 *)(&fw_pwrmode));
+                                             &fw_pwrmode);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
                                              (u8 *)(&fw_current_inps));
        }
@@ -300,7 +298,7 @@ static void _rtl88ee_fwlps_enter(struct ieee80211_hw *hw)
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
                                              (u8 *)(&fw_current_inps));
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-                                             (u8 *)(&ppsc->fwctrl_psmode));
+                                             &ppsc->fwctrl_psmode);
                rtlhal->allow_sw_to_change_hwclc = true;
                _rtl88ee_set_fw_clock_off(hw, rpwm_val);
        } else {
@@ -308,9 +306,8 @@ static void _rtl88ee_fwlps_enter(struct ieee80211_hw *hw)
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
                                              (u8 *)(&fw_current_inps));
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-                                             (u8 *)(&ppsc->fwctrl_psmode));
-               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-                                             (u8 *)(&rpwm_val));
+                                             &ppsc->fwctrl_psmode);
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
        }
 }
 
@@ -419,12 +416,12 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 
                for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-                                                     (u8 *)(&e_aci));
+                                                     &e_aci);
                }
                break; }
        case HW_VAR_ACK_PREAMBLE:{
                u8 reg_tmp;
-               u8 short_preamble = (bool) (*(u8 *)val);
+               u8 short_preamble = (bool)*val;
                reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL+2);
                if (short_preamble) {
                        reg_tmp |= 0x02;
@@ -435,13 +432,13 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                }
                break; }
        case HW_VAR_WPA_CONFIG:
-               rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+               rtl_write_byte(rtlpriv, REG_SECCFG, *val);
                break;
        case HW_VAR_AMPDU_MIN_SPACE:{
                u8 min_spacing_to_set;
                u8 sec_min_space;
 
-               min_spacing_to_set = *((u8 *)val);
+               min_spacing_to_set = *val;
                if (min_spacing_to_set <= 7) {
                        sec_min_space = 0;
 
@@ -464,7 +461,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
        case HW_VAR_SHORTGI_DENSITY:{
                u8 density_to_set;
 
-               density_to_set = *((u8 *)val);
+               density_to_set = *val;
                mac->min_space_cfg |= (density_to_set << 3);
 
                RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
@@ -482,7 +479,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 
                reg = regtoset_normal;
 
-               factor = *((u8 *)val);
+               factor = *val;
                if (factor <= 3) {
                        factor = (1 << (factor + 2));
                        if (factor > 0xf)
@@ -505,15 +502,15 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                }
                break; }
        case HW_VAR_AC_PARAM:{
-               u8 e_aci = *((u8 *)val);
+               u8 e_aci = *val;
                rtl88e_dm_init_edca_turbo(hw);
 
                if (rtlpci->acm_method != EACMWAY2_SW)
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
-                                                     (u8 *)(&e_aci));
+                                                     &e_aci);
                break; }
        case HW_VAR_ACM_CTRL:{
-               u8 e_aci = *((u8 *)val);
+               u8 e_aci = *val;
                union aci_aifsn *p_aci_aifsn =
                    (union aci_aifsn *)(&(mac->ac[0].aifs));
                u8 acm = p_aci_aifsn->f.acm;
@@ -566,7 +563,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                rtlpci->receive_config = ((u32 *)(val))[0];
                break;
        case HW_VAR_RETRY_LIMIT:{
-               u8 retry_limit = ((u8 *)(val))[0];
+               u8 retry_limit = *val;
 
                rtl_write_word(rtlpriv, REG_RL,
                               retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -579,7 +576,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                rtlefuse->efuse_usedbytes = *((u16 *)val);
                break;
        case HW_VAR_EFUSE_USAGE:
-               rtlefuse->efuse_usedpercentage = *((u8 *)val);
+               rtlefuse->efuse_usedpercentage = *val;
                break;
        case HW_VAR_IO_CMD:
                rtl88e_phy_set_io_cmd(hw, (*(enum io_type *)val));
@@ -591,15 +588,13 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                udelay(1);
 
                if (rpwm_val & BIT(7)) {
-                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
-                                      (*(u8 *)val));
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
                } else {
-                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
-                                      ((*(u8 *)val) | BIT(7)));
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val | BIT(7));
                }
                break; }
        case HW_VAR_H2C_FW_PWRMODE:
-               rtl88e_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+               rtl88e_set_fw_pwrmode_cmd(hw, *val);
                break;
        case HW_VAR_FW_PSMODE_STATUS:
                ppsc->fw_current_inpsmode = *((bool *)val);
@@ -616,7 +611,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                        _rtl88ee_fwlps_leave(hw);
                 break; }
        case HW_VAR_H2C_FW_JOINBSSRPT:{
-               u8 mstatus = (*(u8 *)val);
+               u8 mstatus = *val;
                u8 tmp, tmp_reg422, uval;
                u8 count = 0, dlbcn_count = 0;
                bool recover = false;
@@ -667,10 +662,10 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                        }
                        rtl_write_byte(rtlpriv, REG_CR + 1, (tmp & ~(BIT(0))));
                }
-               rtl88e_set_fw_joinbss_report_cmd(hw, (*(u8 *)val));
+               rtl88e_set_fw_joinbss_report_cmd(hw, *val);
                break; }
        case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
-               rtl88e_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+               rtl88e_set_p2p_ps_offload_cmd(hw, *val);
                break;
        case HW_VAR_AID:{
                u16 u2btmp;
@@ -680,7 +675,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                               mac->assoc_id));
                break; }
        case HW_VAR_CORRECT_TSF:{
-               u8 btype_ibss = ((u8 *)(val))[0];
+               u8 btype_ibss = *val;
 
                if (btype_ibss == true)
                        _rtl88ee_stop_tx_beacon(hw);
@@ -1828,7 +1823,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
                 "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
        /*customer ID*/
-       rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+       rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
        if (rtlefuse->eeprom_oemid == 0xFF)
                rtlefuse->eeprom_oemid = 0;
 
@@ -1845,7 +1840,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
                 "dev_addr: %pM\n", rtlefuse->dev_addr);
        /*channel plan */
-       rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+       rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
        /* set channel paln to world wide 13 */
        rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
        /*tx power*/
@@ -1857,7 +1852,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
                                                 rtlefuse->autoload_failflag,
                                                 hwinfo);
        /*board type*/
-       rtlefuse->board_type = (((*(u8 *)&hwinfo[jj]) & 0xE0) >> 5);
+       rtlefuse->board_type = (hwinfo[jj] & 0xE0) >> 5;
        /*Wake on wlan*/
        rtlefuse->wowlan_enable = ((hwinfo[kk] & 0x40) >> 6);
        /*parse xtal*/
@@ -2223,8 +2218,7 @@ void rtl88ee_update_channel_access_setting(struct ieee80211_hw *hw)
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        u16 sifs_timer;
 
-       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-                                     (u8 *)&mac->slot_time);
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, &mac->slot_time);
        if (!mac->ht_enable)
                sifs_timer = 0x0a0a;
        else
index 347af1e4f438e57cf2c37b8975169a7c92941681..1b4101bf9974e8243124f70f40e295e841a3f0a1 100644 (file)
@@ -93,6 +93,7 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
        u8 tid;
 
        rtl8188ee_bt_reg_init(hw);
+       rtlpci->msi_support = true;
 
        rtlpriv->dm.dm_initialgain_enable = 1;
        rtlpriv->dm.dm_flag = 0;
index 2ba6f510d884cca149f7a7b9c06281c297593aa4..06ef47cd62038cc9695078441d545be0ca1b9348 100644 (file)
@@ -497,7 +497,7 @@ void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-       u8 *pdesc = (u8 *)pdesc_tx;
+       u8 *pdesc = pdesc_tx;
        u16 seq_number;
        __le16 fc = hdr->frame_control;
        unsigned int buf_len = 0;
@@ -716,7 +716,7 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
 
        SET_TX_DESC_OWN(pdesc, 1);
 
-       SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+       SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
 
        SET_TX_DESC_FIRST_SEG(pdesc, 1);
        SET_TX_DESC_LAST_SEG(pdesc, 1);
index 4ae51d5b436fb156329f0fd269ad2339de81e6d4..55adf043aef7e250759d9c993b224217ad974d37 100644 (file)
@@ -476,7 +476,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                        break;
                }
        case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
-               rtl92c_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+               rtl92c_set_p2p_ps_offload_cmd(hw, *val);
                break;
        case HW_VAR_AID:{
                        u16 u2btmp;
@@ -521,21 +521,21 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                                                (u8 *)(&fw_current_inps));
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                                HW_VAR_H2C_FW_PWRMODE,
-                                               (u8 *)(&ppsc->fwctrl_psmode));
+                                               &ppsc->fwctrl_psmode);
 
                                rtlpriv->cfg->ops->set_hw_reg(hw,
-                                               HW_VAR_SET_RPWM,
-                                               (u8 *)(&rpwm_val));
+                                                             HW_VAR_SET_RPWM,
+                                                             &rpwm_val);
                        } else {
                                rpwm_val = 0x0C;        /* RF on */
                                fw_pwrmode = FW_PS_ACTIVE_MODE;
                                fw_current_inps = false;
                                rtlpriv->cfg->ops->set_hw_reg(hw,
-                                               HW_VAR_SET_RPWM,
-                                               (u8 *)(&rpwm_val));
+                                                             HW_VAR_SET_RPWM,
+                                                             &rpwm_val);
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                                HW_VAR_H2C_FW_PWRMODE,
-                                               (u8 *)(&fw_pwrmode));
+                                               &fw_pwrmode);
 
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                                HW_VAR_FW_PSMODE_STATUS,
index 3015af167b2ba5d14214887a671147776cc9b3a8..9098558d916dee6ae6daf3567eb91291ad234b72 100644 (file)
@@ -413,20 +413,18 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                                        (u8 *)(&fw_current_inps));
                        rtlpriv->cfg->ops->set_hw_reg(hw,
                                        HW_VAR_H2C_FW_PWRMODE,
-                                       (u8 *)(&ppsc->fwctrl_psmode));
+                                       &ppsc->fwctrl_psmode);
 
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                       HW_VAR_SET_RPWM,
-                                       (u8 *)(&rpwm_val));
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+                                                     &rpwm_val);
                } else {
                        rpwm_val = 0x0C;        /* RF on */
                        fw_pwrmode = FW_PS_ACTIVE_MODE;
                        fw_current_inps = false;
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-                                       (u8 *)(&rpwm_val));
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                       HW_VAR_H2C_FW_PWRMODE,
-                                       (u8 *)(&fw_pwrmode));
+                                                     &rpwm_val);
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+                                                     &fw_pwrmode);
 
                        rtlpriv->cfg->ops->set_hw_reg(hw,
                                        HW_VAR_FW_PSMODE_STATUS,
index 863ddb3e2888b8e11d90a2aceefd5279ac0586e5..25cc83058b01a25be6a9ea78d44ce744a22a89a0 100644 (file)
@@ -647,9 +647,8 @@ static void rtl8723ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
        } else {
                if (rtlpriv->dm.current_turbo_edca) {
                        u8 tmp = AC0_BE;
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_AC_PARAM,
-                                                     (u8 *) (&tmp));
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+                                                     &tmp);
                        rtlpriv->dm.current_turbo_edca = false;
                }
        }
index f4c9852d1e1ed1343f4873948dc64037ad211d8b..65c9e80e1f78ad23988bb962732396153bf1f137 100644 (file)
@@ -207,14 +207,13 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
 
                for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_AC_PARAM,
-                                                     (u8 *) (&e_aci));
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+                                                     &e_aci);
                }
                break; }
        case HW_VAR_ACK_PREAMBLE:{
                u8 reg_tmp;
-               u8 short_preamble = (bool) (*(u8 *) val);
+               u8 short_preamble = (bool)*val;
                reg_tmp = (mac->cur_40_prime_sc) << 5;
                if (short_preamble)
                        reg_tmp |= 0x80;
@@ -225,7 +224,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                u8 min_spacing_to_set;
                u8 sec_min_space;
 
-               min_spacing_to_set = *((u8 *) val);
+               min_spacing_to_set = *val;
                if (min_spacing_to_set <= 7) {
                        sec_min_space = 0;
 
@@ -249,7 +248,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
        case HW_VAR_SHORTGI_DENSITY:{
                u8 density_to_set;
 
-               density_to_set = *((u8 *) val);
+               density_to_set = *val;
                mac->min_space_cfg |= (density_to_set << 3);
 
                RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
@@ -273,7 +272,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                else
                        p_regtoset = regtoset_normal;
 
-               factor_toset = *((u8 *) val);
+               factor_toset = *val;
                if (factor_toset <= 3) {
                        factor_toset = (1 << (factor_toset + 2));
                        if (factor_toset > 0xf)
@@ -304,16 +303,15 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                }
                break; }
        case HW_VAR_AC_PARAM:{
-               u8 e_aci = *((u8 *) val);
+               u8 e_aci = *val;
                rtl8723_dm_init_edca_turbo(hw);
 
                if (rtlpci->acm_method != EACMWAY2_SW)
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_ACM_CTRL,
-                                                     (u8 *) (&e_aci));
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
+                                                     &e_aci);
                break; }
        case HW_VAR_ACM_CTRL:{
-               u8 e_aci = *((u8 *) val);
+               u8 e_aci = *val;
                union aci_aifsn *p_aci_aifsn =
                    (union aci_aifsn *)(&(mac->ac[0].aifs));
                u8 acm = p_aci_aifsn->f.acm;
@@ -366,7 +364,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                rtlpci->receive_config = ((u32 *) (val))[0];
                break;
        case HW_VAR_RETRY_LIMIT:{
-               u8 retry_limit = ((u8 *) (val))[0];
+               u8 retry_limit = *val;
 
                rtl_write_word(rtlpriv, REG_RL,
                               retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -379,13 +377,13 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                rtlefuse->efuse_usedbytes = *((u16 *) val);
                break;
        case HW_VAR_EFUSE_USAGE:
-               rtlefuse->efuse_usedpercentage = *((u8 *) val);
+               rtlefuse->efuse_usedpercentage = *val;
                break;
        case HW_VAR_IO_CMD:
                rtl8723ae_phy_set_io_cmd(hw, (*(enum io_type *)val));
                break;
        case HW_VAR_WPA_CONFIG:
-               rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val));
+               rtl_write_byte(rtlpriv, REG_SECCFG, *val);
                break;
        case HW_VAR_SET_RPWM:{
                u8 rpwm_val;
@@ -394,27 +392,25 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                udelay(1);
 
                if (rpwm_val & BIT(7)) {
-                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
-                                      (*(u8 *) val));
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
                } else {
-                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
-                                      ((*(u8 *) val) | BIT(7)));
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val | BIT(7));
                }
 
                break; }
        case HW_VAR_H2C_FW_PWRMODE:{
-               u8 psmode = (*(u8 *) val);
+               u8 psmode = *val;
 
                if (psmode != FW_PS_ACTIVE_MODE)
                        rtl8723ae_dm_rf_saving(hw, true);
 
-               rtl8723ae_set_fw_pwrmode_cmd(hw, (*(u8 *) val));
+               rtl8723ae_set_fw_pwrmode_cmd(hw, *val);
                break; }
        case HW_VAR_FW_PSMODE_STATUS:
                ppsc->fw_current_inpsmode = *((bool *) val);
                break;
        case HW_VAR_H2C_FW_JOINBSSRPT:{
-               u8 mstatus = (*(u8 *) val);
+               u8 mstatus = *val;
                u8 tmp_regcr, tmp_reg422;
                bool recover = false;
 
@@ -447,11 +443,11 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                        rtl_write_byte(rtlpriv, REG_CR + 1,
                                       (tmp_regcr & ~(BIT(0))));
                }
-               rtl8723ae_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
+               rtl8723ae_set_fw_joinbss_report_cmd(hw, *val);
 
                break; }
        case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
-               rtl8723ae_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+               rtl8723ae_set_p2p_ps_offload_cmd(hw, *val);
                break;
        case HW_VAR_AID:{
                u16 u2btmp;
@@ -461,7 +457,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                                mac->assoc_id));
                break; }
        case HW_VAR_CORRECT_TSF:{
-               u8 btype_ibss = ((u8 *) (val))[0];
+               u8 btype_ibss = *val;
 
                if (btype_ibss == true)
                        _rtl8723ae_stop_tx_beacon(hw);
@@ -491,20 +487,18 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                                        (u8 *)(&fw_current_inps));
                        rtlpriv->cfg->ops->set_hw_reg(hw,
                                        HW_VAR_H2C_FW_PWRMODE,
-                                       (u8 *)(&ppsc->fwctrl_psmode));
+                                       &ppsc->fwctrl_psmode);
 
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                       HW_VAR_SET_RPWM,
-                                       (u8 *)(&rpwm_val));
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+                                                     &rpwm_val);
                } else {
                        rpwm_val = 0x0C;        /* RF on */
                        fw_pwrmode = FW_PS_ACTIVE_MODE;
                        fw_current_inps = false;
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-                                       (u8 *)(&rpwm_val));
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                       HW_VAR_H2C_FW_PWRMODE,
-                                       (u8 *)(&fw_pwrmode));
+                                                     &rpwm_val);
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+                                                     &fw_pwrmode);
 
                        rtlpriv->cfg->ops->set_hw_reg(hw,
                                        HW_VAR_FW_PSMODE_STATUS,
@@ -1628,10 +1622,10 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
        rtl8723ae_read_bt_coexist_info_from_hwpg(hw,
                        rtlefuse->autoload_failflag, hwinfo);
 
-       rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+       rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
        rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
        rtlefuse->txpwr_fromeprom = true;
-       rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+       rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
 
        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
                 "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
@@ -2051,8 +2045,7 @@ void rtl8723ae_update_channel_access_setting(struct ieee80211_hw *hw)
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        u16 sifs_timer;
 
-       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-                                     (u8 *)&mac->slot_time);
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, &mac->slot_time);
        if (!mac->ht_enable)
                sifs_timer = 0x0a0a;
        else
index 29adf55c6fd37b9597e97d95a5ecf80fece7d3a1..10b7577b6ae534906102ec29edff266dbdee12d4 100644 (file)
@@ -375,7 +375,7 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        bool defaultadapter = true;
-       u8 *pdesc = (u8 *) pdesc_tx;
+       u8 *pdesc = pdesc_tx;
        u16 seq_number;
        __le16 fc = hdr->frame_control;
        u8 fw_qsel = _rtl8723ae_map_hwqueue_to_fwqueue(skb, hw_queue);
@@ -577,7 +577,7 @@ void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
 
        SET_TX_DESC_OWN(pdesc, 1);
 
-       SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len));
+       SET_TX_DESC_PKT_SIZE(pdesc, (u16) (skb->len));
 
        SET_TX_DESC_FIRST_SEG(pdesc, 1);
        SET_TX_DESC_LAST_SEG(pdesc, 1);
index 736bfcb7938aab2fb01b53541eb3617b963c25fc..13d53a1df78988bbe931c49eeb8d07b770b9c1e8 100644 (file)
@@ -1083,7 +1083,7 @@ static void rtl8723be_dm_check_edca_turbo(struct ieee80211_hw *hw)
                if (rtlpriv->dm.current_turbo_edca) {
                        u8 tmp = AC0_BE;
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-                                                     (u8 *)(&tmp));
+                                                     &tmp);
                }
                rtlpriv->dm.current_turbo_edca = false;
        }
index 7e70c7108d91074634ed2225257d7e835e9e441d..0fdf0909321f234c827107a13fd0a839c7c86be8 100644 (file)
@@ -147,7 +147,7 @@ static void _rtl8723be_set_fw_clock_on(struct ieee80211_hw *hw, u8 rpwm_val,
        }
        if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) {
                rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
-                                             (u8 *)(&rpwm_val));
+                                             &rpwm_val);
                if (FW_PS_IS_ACK(rpwm_val)) {
                        isr_regaddr = REG_HISR;
                        content = rtl_read_dword(rtlpriv, isr_regaddr);
@@ -221,7 +221,7 @@ static void _rtl8723be_set_fw_clock_off(struct ieee80211_hw *hw, u8 rpwm_val)
                        rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
                        rtl_write_word(rtlpriv, REG_HISR, 0x0100);
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-                                                     (u8 *)(&rpwm_val));
+                                                     &rpwm_val);
                        spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
                        rtlhal->fw_clk_change_in_progress = false;
                        spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
@@ -253,15 +253,14 @@ static void _rtl8723be_fwlps_leave(struct ieee80211_hw *hw)
                _rtl8723be_set_fw_clock_on(hw, rpwm_val, false);
                rtlhal->allow_sw_to_change_hwclc = false;
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-                                             (u8 *)(&fw_pwrmode));
+                                             &fw_pwrmode);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
                                              (u8 *)(&fw_current_inps));
        } else {
                rpwm_val = FW_PS_STATE_ALL_ON_88E;      /* RF on */
-               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-                                             (u8 *)(&rpwm_val));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-                                             (u8 *)(&fw_pwrmode));
+                                             &fw_pwrmode);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
                                              (u8 *)(&fw_current_inps));
        }
@@ -280,7 +279,7 @@ static void _rtl8723be_fwlps_enter(struct ieee80211_hw *hw)
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
                                              (u8 *)(&fw_current_inps));
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-                                             (u8 *)(&ppsc->fwctrl_psmode));
+                                             &ppsc->fwctrl_psmode);
                rtlhal->allow_sw_to_change_hwclc = true;
                _rtl8723be_set_fw_clock_off(hw, rpwm_val);
 
@@ -289,9 +288,8 @@ static void _rtl8723be_fwlps_enter(struct ieee80211_hw *hw)
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
                                              (u8 *)(&fw_current_inps));
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-                                             (u8 *)(&ppsc->fwctrl_psmode));
-               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-                                             (u8 *)(&rpwm_val));
+                                             &ppsc->fwctrl_psmode);
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
        }
 }
 
@@ -400,12 +398,12 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 
                for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-                                                     (u8 *)(&e_aci));
+                                                     &e_aci);
                }
                break; }
        case HW_VAR_ACK_PREAMBLE: {
                u8 reg_tmp;
-               u8 short_preamble = (bool) (*(u8 *)val);
+               u8 short_preamble = (bool)*val;
                reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL + 2);
                if (short_preamble) {
                        reg_tmp |= 0x02;
@@ -416,13 +414,13 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                }
                break; }
        case HW_VAR_WPA_CONFIG:
-               rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+               rtl_write_byte(rtlpriv, REG_SECCFG, *val);
                break;
        case HW_VAR_AMPDU_MIN_SPACE: {
                u8 min_spacing_to_set;
                u8 sec_min_space;
 
-               min_spacing_to_set = *((u8 *)val);
+               min_spacing_to_set = *val;
                if (min_spacing_to_set <= 7) {
                        sec_min_space = 0;
 
@@ -445,7 +443,7 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
        case HW_VAR_SHORTGI_DENSITY: {
                u8 density_to_set;
 
-               density_to_set = *((u8 *)val);
+               density_to_set = *val;
                mac->min_space_cfg |= (density_to_set << 3);
 
                RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
@@ -463,7 +461,7 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 
                p_regtoset = regtoset_normal;
 
-               factor_toset = *((u8 *)val);
+               factor_toset = *val;
                if (factor_toset <= 3) {
                        factor_toset = (1 << (factor_toset + 2));
                        if (factor_toset > 0xf)
@@ -491,15 +489,15 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                }
                break; }
        case HW_VAR_AC_PARAM: {
-               u8 e_aci = *((u8 *)val);
+               u8 e_aci = *val;
                rtl8723_dm_init_edca_turbo(hw);
 
                if (rtlpci->acm_method != EACMWAY2_SW)
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
-                                                     (u8 *)(&e_aci));
+                                                     &e_aci);
                break; }
        case HW_VAR_ACM_CTRL: {
-               u8 e_aci = *((u8 *)val);
+               u8 e_aci = *val;
                union aci_aifsn *p_aci_aifsn =
                                (union aci_aifsn *)(&(mac->ac[0].aifs));
                u8 acm = p_aci_aifsn->f.acm;
@@ -552,7 +550,7 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                rtlpci->receive_config = ((u32 *)(val))[0];
                break;
        case HW_VAR_RETRY_LIMIT: {
-               u8 retry_limit = ((u8 *)(val))[0];
+               u8 retry_limit = *val;
 
                rtl_write_word(rtlpriv, REG_RL,
                               retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -565,7 +563,7 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                rtlefuse->efuse_usedbytes = *((u16 *)val);
                break;
        case HW_VAR_EFUSE_USAGE:
-               rtlefuse->efuse_usedpercentage = *((u8 *)val);
+               rtlefuse->efuse_usedpercentage = *val;
                break;
        case HW_VAR_IO_CMD:
                rtl8723be_phy_set_io_cmd(hw, (*(enum io_type *)val));
@@ -577,14 +575,13 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                udelay(1);
 
                if (rpwm_val & BIT(7)) {
-                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, (*(u8 *)val));
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
                } else {
-                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
-                                      ((*(u8 *)val) | BIT(7)));
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val | BIT(7));
                }
                break; }
        case HW_VAR_H2C_FW_PWRMODE:
-               rtl8723be_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+               rtl8723be_set_fw_pwrmode_cmd(hw, *val);
                break;
        case HW_VAR_FW_PSMODE_STATUS:
                ppsc->fw_current_inpsmode = *((bool *)val);
@@ -602,7 +599,7 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 
                break; }
        case HW_VAR_H2C_FW_JOINBSSRPT: {
-               u8 mstatus = (*(u8 *)val);
+               u8 mstatus = *val;
                u8 tmp_regcr, tmp_reg422, bcnvalid_reg;
                u8 count = 0, dlbcn_count = 0;
                bool recover = false;
@@ -657,10 +654,10 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                        rtl_write_byte(rtlpriv, REG_CR + 1,
                                       (tmp_regcr & ~(BIT(0))));
                }
-               rtl8723be_set_fw_joinbss_report_cmd(hw, (*(u8 *)val));
+               rtl8723be_set_fw_joinbss_report_cmd(hw, *val);
                break; }
        case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
-               rtl8723be_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+               rtl8723be_set_p2p_ps_offload_cmd(hw, *val);
                break;
        case HW_VAR_AID: {
                u16 u2btmp;
@@ -670,7 +667,7 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                               (u2btmp | mac->assoc_id));
                break; }
        case HW_VAR_CORRECT_TSF: {
-               u8 btype_ibss = ((u8 *)(val))[0];
+               u8 btype_ibss = *val;
 
                if (btype_ibss)
                        _rtl8723be_stop_tx_beacon(hw);
@@ -690,7 +687,7 @@ void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
        case HW_VAR_KEEP_ALIVE: {
                u8 array[2];
                array[0] = 0xff;
-               array[1] = *((u8 *)val);
+               array[1] = *val;
                rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_KEEP_ALIVE_CTRL,
                                       2, array);
                break; }
@@ -1783,10 +1780,10 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw,
                                                 rtlefuse->autoload_failflag,
                                                 hwinfo);
 
-       rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+       rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
        rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
        rtlefuse->txpwr_fromeprom = true;
-       rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+       rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
 
        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
                 "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
@@ -2252,8 +2249,7 @@ void rtl8723be_update_channel_access_setting(struct ieee80211_hw *hw)
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        u16 sifs_timer;
 
-       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-                                     (u8 *)&mac->slot_time);
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, &mac->slot_time);
        if (!mac->ht_enable)
                sifs_timer = 0x0a0a;
        else
index 74a75dceab085c07e148dc04c4999d5a846c01ff..e0a0d8c8fed556f66b0c766e490b16a59aee74f7 100644 (file)
@@ -647,7 +647,7 @@ void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw,
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-       u8 *pdesc = (u8 *)pdesc_tx;
+       u8 *pdesc = pdesc_tx;
        u16 seq_number;
        __le16 fc = hdr->frame_control;
        unsigned int buf_len = 0;
@@ -850,7 +850,7 @@ void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
 
        SET_TX_DESC_OWN(pdesc, 1);
 
-       SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+       SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
 
        SET_TX_DESC_FIRST_SEG(pdesc, 1);
        SET_TX_DESC_LAST_SEG(pdesc, 1);
index c12da552b7f779af4681c0912f140ed7b211269b..540278ff462b9403aee5512525508b14ac0319f9 100644 (file)
@@ -115,7 +115,7 @@ void rtl8723_write_fw(struct ieee80211_hw *hw,
                      u8 *buffer, u32 size)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u8 *bufferptr = (u8 *)buffer;
+       u8 *bufferptr = buffer;
        u32 pagenums, remainsize;
        u32 page, offset;
 
@@ -257,7 +257,7 @@ int rtl8723_download_fw(struct ieee80211_hw *hw,
                return 1;
 
        pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
-       pfwdata = (u8 *)rtlhal->pfirmware;
+       pfwdata = rtlhal->pfirmware;
        fwsize = rtlhal->fwsize;
        RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
                 "normal Firmware SIZE %d\n", fwsize);
index b8cc39a4a9a547fbffeb2441e84725d82edfae9d..5f8bc05694ac665159bb25f7a9eaa704c3784e91 100644 (file)
@@ -189,6 +189,7 @@ struct hci_dev {
        __u16           page_scan_window;
        __u8            page_scan_type;
        __u8            le_adv_channel_map;
+       __u8            le_scan_type;
        __u16           le_scan_interval;
        __u16           le_scan_window;
        __u16           le_conn_min_interval;
@@ -1236,7 +1237,7 @@ void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                      u8 status);
 int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                             u8 link_type, u8 addr_type, __le32 value,
+                             u8 link_type, u8 addr_type, u32 value,
                              u8 confirm_hint);
 int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                     u8 link_type, u8 addr_type, u8 status);
index a6a3d32553c5849f3f7f4206df7780404ef57757..49774912cb01f23ef6f85cb26f8613f538edec94 100644 (file)
@@ -199,6 +199,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
        memset(hdev->scan_rsp_data, 0, sizeof(hdev->scan_rsp_data));
        hdev->scan_rsp_data_len = 0;
 
+       hdev->le_scan_type = LE_SCAN_PASSIVE;
+
        hdev->ssp_debug_mode = 0;
 }
 
@@ -997,6 +999,25 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_cp_le_set_scan_param *cp;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       if (!status)
+               hdev->le_scan_type = cp->type;
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
                                      struct sk_buff *skb)
 {
@@ -1704,6 +1725,36 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
+static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_le_start_enc *cp;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (!status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_START_ENC);
+       if (!cp)
+               goto unlock;
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (!conn)
+               goto unlock;
+
+       if (conn->state != BT_CONNECTED)
+               goto unlock;
+
+       hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
+       hci_conn_drop(conn);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -2488,6 +2539,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_le_set_adv_enable(hdev, skb);
                break;
 
+       case HCI_OP_LE_SET_SCAN_PARAM:
+               hci_cc_le_set_scan_param(hdev, skb);
+               break;
+
        case HCI_OP_LE_SET_SCAN_ENABLE:
                hci_cc_le_set_scan_enable(hdev, skb);
                break;
@@ -2611,6 +2666,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_le_create_conn(hdev, ev->status);
                break;
 
+       case HCI_OP_LE_START_ENC:
+               hci_cs_le_start_enc(hdev, ev->status);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -3459,8 +3518,8 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
        }
 
 confirm:
-       mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
-                                 confirm_hint);
+       mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0,
+                                 le32_to_cpu(ev->passkey), confirm_hint);
 
 unlock:
        hci_dev_unlock(hdev);
index 33cd5615ff1e04ad9b33a7a794c73a4ffc7e4005..f59e00c2daa9cb5e485cb7832cb80486660ca6bf 100644 (file)
@@ -360,7 +360,8 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
-       if (peer && sk->sk_state != BT_CONNECTED)
+       if (peer && sk->sk_state != BT_CONNECTED &&
+           sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2)
                return -ENOTCONN;
 
        memset(la, 0, sizeof(struct sockaddr_l2));
index 96670f581bb09cd1d0577aae700eca5aa33db767..d2d4e0d5aed017366668bf263538baf332255d20 100644 (file)
@@ -2762,23 +2762,11 @@ static struct pending_cmd *find_pairing(struct hci_conn *conn)
 
 static void pairing_complete(struct pending_cmd *cmd, u8 status)
 {
-       const struct mgmt_cp_pair_device *cp = cmd->param;
        struct mgmt_rp_pair_device rp;
        struct hci_conn *conn = cmd->user_data;
 
-       /* If we had a pairing failure we might have already received
-        * the remote Identity Address Information and updated the
-        * hci_conn variables with it, however we would not yet have
-        * notified user space of the resolved identity. Therefore, use
-        * the address given in the Pair Device command in case the
-        * pairing failed.
-        */
-       if (status) {
-               memcpy(&rp.addr, &cp->addr, sizeof(rp.addr));
-       } else {
-               bacpy(&rp.addr.bdaddr, &conn->dst);
-               rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
-       }
+       bacpy(&rp.addr.bdaddr, &conn->dst);
+       rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
 
        cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
                     &rp, sizeof(rp));
@@ -5338,7 +5326,7 @@ void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                             u8 link_type, u8 addr_type, __le32 value,
+                             u8 link_type, u8 addr_type, u32 value,
                              u8 confirm_hint)
 {
        struct mgmt_ev_user_confirm_request ev;
@@ -5348,7 +5336,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
        bacpy(&ev.addr.bdaddr, bdaddr);
        ev.addr.type = link_to_bdaddr(link_type, addr_type);
        ev.confirm_hint = confirm_hint;
-       ev.value = value;
+       ev.value = cpu_to_le32(value);
 
        return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
                          NULL);
index c024e715512fdff242616c4ac403fa8315b13289..eabd25ab5ad96a14b07624ef6fdfa48715384f45 100644 (file)
@@ -534,7 +534,8 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
-       if (peer && sk->sk_state != BT_CONNECTED)
+       if (peer && sk->sk_state != BT_CONNECTED &&
+           sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2)
                return -ENOTCONN;
 
        memset(sa, 0, sizeof(*sa));
index 2a7ee7f6cd8ba4507337dc8ed2edf6027f418d9b..dfb4e1161c10fbb62b6ac43220949992a5075dfc 100644 (file)
@@ -387,6 +387,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
        if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
                method = JUST_WORKS;
 
+       /* Don't confirm locally initiated pairing attempts */
+       if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR,
+                                          &smp->smp_flags))
+               method = JUST_WORKS;
+
        /* If Just Works, Continue with Zero TK */
        if (method == JUST_WORKS) {
                set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
@@ -422,10 +427,14 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
        if (method == REQ_PASSKEY)
                ret = mgmt_user_passkey_request(hcon->hdev, &hcon->dst,
                                                hcon->type, hcon->dst_type);
+       else if (method == JUST_CFM)
+               ret = mgmt_user_confirm_request(hcon->hdev, &hcon->dst,
+                                               hcon->type, hcon->dst_type,
+                                               passkey, 1);
        else
                ret = mgmt_user_passkey_notify(hcon->hdev, &hcon->dst,
                                                hcon->type, hcon->dst_type,
-                                               cpu_to_le32(passkey), 0);
+                                               passkey, 0);
 
        hci_dev_unlock(hcon->hdev);
 
@@ -547,20 +556,6 @@ error:
        smp_failure(conn, reason);
 }
 
-static void smp_reencrypt(struct work_struct *work)
-{
-       struct smp_chan *smp = container_of(work, struct smp_chan,
-                                           reencrypt.work);
-       struct l2cap_conn *conn = smp->conn;
-       struct hci_conn *hcon = conn->hcon;
-       struct smp_ltk *ltk = smp->ltk;
-
-       BT_DBG("");
-
-       hci_le_start_enc(hcon, ltk->ediv, ltk->rand, ltk->val);
-       hcon->enc_key_size = ltk->enc_size;
-}
-
 static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 {
        struct smp_chan *smp;
@@ -571,7 +566,6 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 
        INIT_WORK(&smp->confirm, confirm_work);
        INIT_WORK(&smp->random, random_work);
-       INIT_DELAYED_WORK(&smp->reencrypt, smp_reencrypt);
 
        smp->conn = conn;
        conn->smp_chan = smp;
@@ -589,8 +583,6 @@ void smp_chan_destroy(struct l2cap_conn *conn)
 
        BUG_ON(!smp);
 
-       cancel_delayed_work_sync(&smp->reencrypt);
-
        complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
        mgmt_smp_complete(conn->hcon, complete);
 
@@ -712,6 +704,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
        if (ret)
                return SMP_UNSPECIFIED;
 
+       clear_bit(SMP_FLAG_INITIATOR, &smp->smp_flags);
+
        return 0;
 }
 
@@ -867,6 +861,8 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
        smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
 
+       clear_bit(SMP_FLAG_INITIATOR, &smp->smp_flags);
+
        return 0;
 }
 
@@ -884,11 +880,15 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level)
 int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
-       struct smp_chan *smp = conn->smp_chan;
+       struct smp_chan *smp;
        __u8 authreq;
 
        BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
 
+       /* This may be NULL if there's an unexpected disconnection */
+       if (!conn)
+               return 1;
+
        if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
                return 1;
 
@@ -928,6 +928,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
                smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
        }
 
+       set_bit(SMP_FLAG_INITIATOR, &smp->smp_flags);
+
 done:
        hcon->pending_sec_level = sec_level;
 
@@ -1058,12 +1060,6 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
        smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr,
                                      smp->id_addr_type, smp->irk, &rpa);
 
-       /* Track the connection based on the Identity Address from now on */
-       bacpy(&hcon->dst, &smp->id_addr);
-       hcon->dst_type = smp->id_addr_type;
-
-       l2cap_conn_update_id_addr(hcon);
-
        smp_distribute_keys(conn);
 
        return 0;
@@ -1214,8 +1210,16 @@ static void smp_notify_keys(struct l2cap_conn *conn)
        struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
        bool persistent;
 
-       if (smp->remote_irk)
+       if (smp->remote_irk) {
                mgmt_new_irk(hdev, smp->remote_irk);
+               /* Now that user space can be considered to know the
+                * identity address track the connection based on it
+                * from now on.
+                */
+               bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
+               hcon->dst_type = smp->remote_irk->addr_type;
+               l2cap_conn_update_id_addr(hcon);
+       }
 
        /* The LTKs and CSRKs should be persistent only if both sides
         * had the bonding bit set in their authentication requests.
@@ -1253,7 +1257,6 @@ int smp_distribute_keys(struct l2cap_conn *conn)
        struct smp_chan *smp = conn->smp_chan;
        struct hci_conn *hcon = conn->hcon;
        struct hci_dev *hdev = hcon->hdev;
-       bool ltk_encrypt;
        __u8 *keydist;
 
        BT_DBG("conn %p", conn);
@@ -1353,32 +1356,12 @@ int smp_distribute_keys(struct l2cap_conn *conn)
        if ((smp->remote_key_dist & 0x07))
                return 0;
 
-       /* Check if we should try to re-encrypt the link with the LTK.
-        * SMP_FLAG_LTK_ENCRYPT flag is used to track whether we've
-        * already tried this (in which case we shouldn't try again).
-        *
-        * The request will trigger an encryption key refresh event
-        * which will cause a call to auth_cfm and eventually lead to
-        * l2cap_core.c calling this smp_distribute_keys function again
-        * and thereby completing the process.
-        */
-       if (smp->ltk)
-               ltk_encrypt = !test_and_set_bit(SMP_FLAG_LTK_ENCRYPT,
-                                               &smp->smp_flags);
-       else
-               ltk_encrypt = false;
+       clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
+       cancel_delayed_work_sync(&conn->security_timer);
+       set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
+       smp_notify_keys(conn);
 
-       /* Re-encrypt the link with LTK if possible */
-       if (ltk_encrypt && hcon->out) {
-               queue_delayed_work(hdev->req_workqueue, &smp->reencrypt,
-                                  SMP_REENCRYPT_TIMEOUT);
-       } else {
-               clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
-               cancel_delayed_work_sync(&conn->security_timer);
-               set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
-               smp_notify_keys(conn);
-               smp_chan_destroy(conn);
-       }
+       smp_chan_destroy(conn);
 
        return 0;
 }
index b6913471815a357aac91152cfa3b5bfd7ea7803f..1277147a915070e3a5256debdd98316fa1d916c5 100644 (file)
@@ -118,10 +118,8 @@ struct smp_cmd_security_req {
 #define SMP_FLAG_TK_VALID      1
 #define SMP_FLAG_CFM_PENDING   2
 #define SMP_FLAG_MITM_AUTH     3
-#define SMP_FLAG_LTK_ENCRYPT   4
-#define SMP_FLAG_COMPLETE      5
-
-#define SMP_REENCRYPT_TIMEOUT  msecs_to_jiffies(500)
+#define SMP_FLAG_COMPLETE      4
+#define SMP_FLAG_INITIATOR     5
 
 struct smp_chan {
        struct l2cap_conn *conn;
@@ -144,7 +142,6 @@ struct smp_chan {
        unsigned long   smp_flags;
        struct work_struct confirm;
        struct work_struct random;
-       struct delayed_work reencrypt;
 };
 
 /* SMP Commands */