Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
John W. Linville says: ==================== Here is another batch of updates intended for 3.7... Highlights include an hci_connect re-write in Bluetooth, HCI/LLC layer separation in NFC, removal of the raw pn544 NFC driver, NFC LLCP raw sockets support, improved IBSS auth frame handling in mac80211, full-MAC AP mode notification support in mac80211, a lot of attention paid to brcmfmac, and the usual level of updates to iwlwifi, ath9k, mwifiex, and rt2x00, and various other updates. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
a248afdc1b
|
@ -508,18 +508,6 @@ Who: Kees Cook <keescook@chromium.org>
|
|||
|
||||
----------------------------
|
||||
|
||||
What: Removing the pn544 raw driver.
|
||||
When: 3.6
|
||||
Why: With the introduction of the NFC HCI and SHDL kernel layers, pn544.c
|
||||
is being replaced by pn544_hci.c which is accessible through the netlink
|
||||
and socket NFC APIs. Moreover, pn544.c is outdated and does not seem to
|
||||
work properly with the latest Android stacks.
|
||||
Having 2 drivers for the same hardware is confusing and as such we
|
||||
should only keep the one following the kernel NFC APIs.
|
||||
Who: Samuel Ortiz <sameo@linux.intel.com>
|
||||
|
||||
----------------------------
|
||||
|
||||
What: setitimer accepts user NULL pointer (value)
|
||||
When: 3.6
|
||||
Why: setitimer is not returning -EFAULT if user pointer is NULL. This
|
||||
|
|
|
@ -4799,6 +4799,7 @@ M: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
|
|||
M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
|
||||
M: Samuel Ortiz <sameo@linux.intel.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: linux-nfc@lists.01.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: net/nfc/
|
||||
F: include/linux/nfc.h
|
||||
|
|
|
@ -273,6 +273,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
|
||||
{ 0, },
|
||||
|
|
|
@ -507,7 +507,9 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
|
|||
/* for these chips OTP is always available */
|
||||
present = true;
|
||||
break;
|
||||
case BCMA_CHIP_ID_BCM43227:
|
||||
case BCMA_CHIP_ID_BCM43228:
|
||||
case BCMA_CHIP_ID_BCM43428:
|
||||
present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -681,7 +681,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
|
|||
case HCI_SCODATA_PKT:
|
||||
hdev->stat.sco_tx++;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
/* Prepend skb with frame type */
|
||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
|
|
|
@ -600,7 +600,6 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
|
|||
exit:
|
||||
if (ret) {
|
||||
hdev->stat.err_rx++;
|
||||
if (skb)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
|
|
|
@ -446,7 +446,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
|
|||
case HCI_SCODATA_PKT:
|
||||
hdev->stat.sco_tx++;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
/* Prepend skb with frame type */
|
||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
|
|
|
@ -96,11 +96,12 @@ static struct usb_device_id btusb_table[] = {
|
|||
{ USB_DEVICE(0x0c10, 0x0000) },
|
||||
|
||||
/* Broadcom BCM20702A0 */
|
||||
{ USB_DEVICE(0x04ca, 0x2003) },
|
||||
{ USB_DEVICE(0x0489, 0xe042) },
|
||||
{ USB_DEVICE(0x413c, 0x8197) },
|
||||
|
||||
/* Foxconn - Hon Hai */
|
||||
{ USB_DEVICE(0x0489, 0xe033) },
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
|
||||
|
||||
/*Broadcom devices with vendor specific id */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
|
||||
|
|
|
@ -358,21 +358,7 @@ static struct platform_driver btwilink_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
/* ------- Module Init/Exit interfaces ------ */
|
||||
static int __init btwilink_init(void)
|
||||
{
|
||||
BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION);
|
||||
|
||||
return platform_driver_register(&btwilink_driver);
|
||||
}
|
||||
|
||||
static void __exit btwilink_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&btwilink_driver);
|
||||
}
|
||||
|
||||
module_init(btwilink_init);
|
||||
module_exit(btwilink_exit);
|
||||
module_platform_driver(btwilink_driver);
|
||||
|
||||
/* ------ Module Info ------ */
|
||||
|
||||
|
|
|
@ -531,7 +531,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
|
|||
default:
|
||||
err = n_tty_ioctl_helper(tty, file, cmd, arg);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -481,7 +481,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
|
|||
hu->hdev->stat.err_rx++;
|
||||
ptr++; count--;
|
||||
continue;
|
||||
};
|
||||
}
|
||||
|
||||
ptr++; count--;
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
|
|||
case HCI_SCODATA_PKT:
|
||||
data->hdev->stat.sco_tx++;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
|
|
@ -159,6 +159,7 @@ struct ath_common {
|
|||
|
||||
bool btcoex_enabled;
|
||||
bool disable_ani;
|
||||
bool antenna_diversity;
|
||||
};
|
||||
|
||||
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
|
||||
|
|
|
@ -2446,6 +2446,7 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
|
|||
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
|
||||
IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_MFP_CAPABLE |
|
||||
IEEE80211_HW_REPORTS_TX_ACK_STATUS;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
|
|
|
@ -489,6 +489,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
if (ath5k_modparam_nohwcrypt)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC &&
|
||||
(key->cipher == WLAN_CIPHER_SUITE_TKIP ||
|
||||
key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
|
||||
|
@ -523,7 +526,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1975,11 +1975,13 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
|
|||
spur_delta_phase = (spur_offset << 18) / 25;
|
||||
spur_freq_sigma_delta = (spur_delta_phase >> 10);
|
||||
symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2;
|
||||
break;
|
||||
case AR5K_BWMODE_5MHZ:
|
||||
/* Both sample_freq and chip_freq are 10MHz (?) */
|
||||
spur_delta_phase = (spur_offset << 19) / 25;
|
||||
spur_freq_sigma_delta = (spur_delta_phase >> 10);
|
||||
symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
|
||||
break;
|
||||
default:
|
||||
if (channel->band == IEEE80211_BAND_5GHZ) {
|
||||
/* Both sample_freq and chip_freq are 40MHz */
|
||||
|
|
|
@ -1488,7 +1488,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
|
|||
}
|
||||
|
||||
static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
|
||||
char *name,
|
||||
const char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
|
@ -3477,7 +3477,7 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
|
|||
ar->num_vif--;
|
||||
}
|
||||
|
||||
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name,
|
||||
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
|
||||
enum nl80211_iftype type,
|
||||
u8 fw_vif_idx, u8 nw_type)
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ enum ath6kl_cfg_suspend_mode {
|
|||
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
|
||||
};
|
||||
|
||||
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name,
|
||||
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
|
||||
enum nl80211_iftype type,
|
||||
u8 fw_vif_idx, u8 nw_type);
|
||||
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
|
||||
|
|
|
@ -311,6 +311,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
struct ath_ant_comb *antcomb,
|
||||
int alt_ratio)
|
||||
{
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
|
||||
if (ant_conf->div_group == 0) {
|
||||
/* Adjust the fast_div_bias based on main and alt lna conf */
|
||||
switch ((ant_conf->main_lna_conf << 4) |
|
||||
|
@ -360,18 +363,12 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
|
@ -379,13 +376,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
|
@ -393,8 +386,6 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
|
@ -402,13 +393,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
|
@ -416,23 +403,15 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -443,18 +422,12 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
|
@ -462,13 +435,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
|
@ -476,8 +445,6 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
|
@ -485,13 +452,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
|
@ -499,23 +462,77 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
|||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (ant_conf->div_group == 3) {
|
||||
switch ((ant_conf->main_lna_conf << 4) |
|
||||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x39;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
if ((antcomb->scan == 0) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
} else {
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
}
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x39;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
if ((antcomb->scan == 0) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
} else {
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
}
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
if ((antcomb->scan == 0) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
} else {
|
||||
ant_conf->fast_div_bias = 0x4;
|
||||
}
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
if ((antcomb->scan == 0) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
} else {
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
}
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -759,6 +776,7 @@ div_comb_done:
|
|||
void ath_ant_comb_update(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_hw_antcomb_conf div_ant_conf;
|
||||
u8 lna_conf;
|
||||
|
||||
|
@ -773,4 +791,7 @@ void ath_ant_comb_update(struct ath_softc *sc)
|
|||
div_ant_conf.alt_lna_conf = lna_conf;
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
|
||||
|
||||
if (common->antenna_diversity)
|
||||
ath9k_hw_antctrl_shared_chain_lnadiv(ah, true);
|
||||
}
|
||||
|
|
|
@ -3566,9 +3566,9 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, int chain,
|
|||
|
||||
static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
|
||||
{
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
int chain;
|
||||
u32 regval;
|
||||
u32 ant_div_ctl1;
|
||||
static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = {
|
||||
AR_PHY_SWITCH_CHAIN_0,
|
||||
AR_PHY_SWITCH_CHAIN_1,
|
||||
|
@ -3633,6 +3633,16 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
|
|||
/* enable_lnadiv */
|
||||
regval &= (~AR_PHY_ANT_DIV_LNADIV);
|
||||
regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S;
|
||||
|
||||
if (AR_SREV_9565(ah)) {
|
||||
if (ah->shared_chain_lnadiv) {
|
||||
regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S);
|
||||
} else {
|
||||
regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S);
|
||||
regval &= ~(1 << AR_PHY_ANT_SW_RX_PROT_S);
|
||||
}
|
||||
}
|
||||
|
||||
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
|
||||
|
||||
/*enable fast_div */
|
||||
|
@ -3640,9 +3650,8 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
|
|||
regval &= (~AR_FAST_DIV_ENABLE);
|
||||
regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S;
|
||||
REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
|
||||
ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
|
||||
/* check whether antenna diversity is enabled */
|
||||
if ((ant_div_ctl1 >> 0x6) == 0x3) {
|
||||
|
||||
if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
|
||||
regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
|
||||
/*
|
||||
* clear bits 25-30 main_lnaconf, alt_lnaconf,
|
||||
|
@ -3659,10 +3668,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
|
|||
AR_PHY_ANT_DIV_ALT_LNACONF_S);
|
||||
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void ar9003_hw_drive_strength_apply(struct ath_hw *ah)
|
||||
|
|
|
@ -1027,6 +1027,7 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
|
|||
|
||||
if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
|
||||
ar9003_mci_osla_setup(ah, true);
|
||||
REG_WRITE(ah, AR_SELFGEN_MASK, 0x02);
|
||||
} else {
|
||||
ar9003_mci_send_lna_take(ah, true);
|
||||
udelay(5);
|
||||
|
@ -1235,6 +1236,10 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
|
|||
case MCI_STATE_NEED_FTP_STOMP:
|
||||
value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
|
||||
break;
|
||||
case MCI_STATE_NEED_FLUSH_BT_INFO:
|
||||
value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0;
|
||||
mci->need_flush_btinfo = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1284,7 +1289,7 @@ void ar9003_mci_set_power_awake(struct ath_hw *ah)
|
|||
}
|
||||
REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18)));
|
||||
lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3;
|
||||
bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP;
|
||||
bt_sleep = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP);
|
||||
|
||||
REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2);
|
||||
REG_WRITE(ah, AR_DIAG_SW, diag_sw);
|
||||
|
|
|
@ -200,6 +200,7 @@ enum mci_state_type {
|
|||
MCI_STATE_RECOVER_RX,
|
||||
MCI_STATE_NEED_FTP_STOMP,
|
||||
MCI_STATE_DEBUG,
|
||||
MCI_STATE_NEED_FLUSH_BT_INFO,
|
||||
MCI_STATE_MAX
|
||||
};
|
||||
|
||||
|
@ -211,7 +212,8 @@ enum mci_gpm_coex_opcode {
|
|||
MCI_GPM_COEX_WLAN_CHANNELS,
|
||||
MCI_GPM_COEX_BT_PROFILE_INFO,
|
||||
MCI_GPM_COEX_BT_STATUS_UPDATE,
|
||||
MCI_GPM_COEX_BT_UPDATE_FLAGS
|
||||
MCI_GPM_COEX_BT_UPDATE_FLAGS,
|
||||
MCI_GPM_COEX_NOOP,
|
||||
};
|
||||
|
||||
#define MCI_GPM_NOMORE 0
|
||||
|
|
|
@ -605,9 +605,6 @@ static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
|
|||
|
||||
if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
|
||||
REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
|
||||
else if (AR_SREV_9462(ah))
|
||||
/* xxx only when MCI support is enabled */
|
||||
REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
|
||||
else
|
||||
REG_WRITE(ah, AR_SELFGEN_MASK, tx);
|
||||
|
||||
|
@ -1294,6 +1291,9 @@ static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah,
|
|||
} else if (AR_SREV_9485(ah)) {
|
||||
antconf->lna1_lna2_delta = -9;
|
||||
antconf->div_group = 2;
|
||||
} else if (AR_SREV_9565(ah)) {
|
||||
antconf->lna1_lna2_delta = -3;
|
||||
antconf->div_group = 3;
|
||||
} else {
|
||||
antconf->lna1_lna2_delta = -3;
|
||||
antconf->div_group = 0;
|
||||
|
@ -1325,6 +1325,65 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah,
|
|||
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
|
||||
}
|
||||
|
||||
static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
|
||||
bool enable)
|
||||
{
|
||||
u8 ant_div_ctl1;
|
||||
u32 regval;
|
||||
|
||||
if (!AR_SREV_9565(ah))
|
||||
return;
|
||||
|
||||
ah->shared_chain_lnadiv = enable;
|
||||
ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
|
||||
|
||||
regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
|
||||
regval &= (~AR_ANT_DIV_CTRL_ALL);
|
||||
regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S;
|
||||
regval &= ~AR_PHY_ANT_DIV_LNADIV;
|
||||
regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S;
|
||||
|
||||
if (enable)
|
||||
regval |= AR_ANT_DIV_ENABLE;
|
||||
|
||||
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
|
||||
|
||||
regval = REG_READ(ah, AR_PHY_CCK_DETECT);
|
||||
regval &= ~AR_FAST_DIV_ENABLE;
|
||||
regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S;
|
||||
|
||||
if (enable)
|
||||
regval |= AR_FAST_DIV_ENABLE;
|
||||
|
||||
REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
|
||||
|
||||
if (enable) {
|
||||
REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,
|
||||
(1 << AR_PHY_ANT_SW_RX_PROT_S));
|
||||
if (IS_CHAN_2GHZ(ah->curchan))
|
||||
REG_SET_BIT(ah, AR_PHY_RESTART,
|
||||
AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
|
||||
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
|
||||
AR_BTCOEX_WL_LNADIV_FORCE_ON);
|
||||
} else {
|
||||
REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE);
|
||||
REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
|
||||
(1 << AR_PHY_ANT_SW_RX_PROT_S));
|
||||
REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE);
|
||||
REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,
|
||||
AR_BTCOEX_WL_LNADIV_FORCE_ON);
|
||||
|
||||
regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
|
||||
regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF |
|
||||
AR_PHY_ANT_DIV_ALT_LNACONF |
|
||||
AR_PHY_ANT_DIV_MAIN_GAINTB |
|
||||
AR_PHY_ANT_DIV_ALT_GAINTB);
|
||||
regval |= (AR_PHY_ANT_DIV_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S);
|
||||
regval |= (AR_PHY_ANT_DIV_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S);
|
||||
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
|
||||
}
|
||||
}
|
||||
|
||||
static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
u8 *ini_reloaded)
|
||||
|
@ -1423,6 +1482,7 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
|
|||
|
||||
ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
|
||||
ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
|
||||
ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
|
||||
|
||||
ar9003_hw_set_nf_limits(ah);
|
||||
ar9003_hw_set_radar_conf(ah);
|
||||
|
|
|
@ -282,6 +282,8 @@
|
|||
|
||||
#define AR_PHY_ANT_FAST_DIV_BIAS 0x00007e00
|
||||
#define AR_PHY_ANT_FAST_DIV_BIAS_S 9
|
||||
#define AR_PHY_ANT_SW_RX_PROT 0x00800000
|
||||
#define AR_PHY_ANT_SW_RX_PROT_S 23
|
||||
#define AR_PHY_ANT_DIV_LNADIV 0x01000000
|
||||
#define AR_PHY_ANT_DIV_LNADIV_S 24
|
||||
#define AR_PHY_ANT_DIV_ALT_LNACONF 0x06000000
|
||||
|
@ -422,6 +424,8 @@
|
|||
#define AR_PHY_FIND_SIG_RELSTEP 0x1f
|
||||
#define AR_PHY_FIND_SIG_RELSTEP_S 0
|
||||
#define AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT 5
|
||||
#define AR_PHY_RESTART_ENABLE_DIV_M2FLAG 0x00200000
|
||||
#define AR_PHY_RESTART_ENABLE_DIV_M2FLAG_S 21
|
||||
#define AR_PHY_RESTART_DIV_GC 0x001C0000
|
||||
#define AR_PHY_RESTART_DIV_GC_S 18
|
||||
#define AR_PHY_RESTART_ENA 0x01
|
||||
|
@ -1261,4 +1265,24 @@
|
|||
#define AR_PHY_CL_TAB_CL_GAIN_MOD 0x1f
|
||||
#define AR_PHY_CL_TAB_CL_GAIN_MOD_S 0
|
||||
|
||||
#define AR_BTCOEX_WL_LNADIV 0x1a64
|
||||
#define AR_BTCOEX_WL_LNADIV_PREDICTED_PERIOD 0x00003FFF
|
||||
#define AR_BTCOEX_WL_LNADIV_PREDICTED_PERIOD_S 0
|
||||
#define AR_BTCOEX_WL_LNADIV_DPDT_IGNORE_PRIORITY 0x00004000
|
||||
#define AR_BTCOEX_WL_LNADIV_DPDT_IGNORE_PRIORITY_S 14
|
||||
#define AR_BTCOEX_WL_LNADIV_FORCE_ON 0x00008000
|
||||
#define AR_BTCOEX_WL_LNADIV_FORCE_ON_S 15
|
||||
#define AR_BTCOEX_WL_LNADIV_MODE_OPTION 0x00030000
|
||||
#define AR_BTCOEX_WL_LNADIV_MODE_OPTION_S 16
|
||||
#define AR_BTCOEX_WL_LNADIV_MODE 0x007c0000
|
||||
#define AR_BTCOEX_WL_LNADIV_MODE_S 18
|
||||
#define AR_BTCOEX_WL_LNADIV_ALLOWED_TX_ANTDIV_WL_TX_REQ 0x00800000
|
||||
#define AR_BTCOEX_WL_LNADIV_ALLOWED_TX_ANTDIV_WL_TX_REQ_S 23
|
||||
#define AR_BTCOEX_WL_LNADIV_DISABLE_TX_ANTDIV_ENABLE 0x01000000
|
||||
#define AR_BTCOEX_WL_LNADIV_DISABLE_TX_ANTDIV_ENABLE_S 24
|
||||
#define AR_BTCOEX_WL_LNADIV_CONTINUOUS_BT_ACTIVE_PROTECT 0x02000000
|
||||
#define AR_BTCOEX_WL_LNADIV_CONTINUOUS_BT_ACTIVE_PROTECT_S 25
|
||||
#define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD 0xFC000000
|
||||
#define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD_S 26
|
||||
|
||||
#endif /* AR9003_PHY_H */
|
||||
|
|
|
@ -58,8 +58,6 @@ static const u32 ar9565_1p0_mac_core[][2] = {
|
|||
{0x00008040, 0x00000000},
|
||||
{0x00008044, 0x00000000},
|
||||
{0x00008048, 0x00000000},
|
||||
{0x0000804c, 0xffffffff},
|
||||
{0x00008050, 0xffffffff},
|
||||
{0x00008054, 0x00000000},
|
||||
{0x00008058, 0x00000000},
|
||||
{0x0000805c, 0x000fc78f},
|
||||
|
@ -246,7 +244,7 @@ static const u32 ar9565_1p0_baseband_core[][2] = {
|
|||
{0x00009e50, 0x00ff03f1},
|
||||
{0x00009e54, 0xe4c355c7},
|
||||
{0x00009e5c, 0xe9198724},
|
||||
{0x00009fc0, 0x823e4788},
|
||||
{0x00009fc0, 0x823e4fc8},
|
||||
{0x00009fc4, 0x0001efb5},
|
||||
{0x00009fcc, 0x40000014},
|
||||
{0x0000a20c, 0x00000000},
|
||||
|
@ -291,7 +289,7 @@ static const u32 ar9565_1p0_baseband_core[][2] = {
|
|||
{0x0000a3ec, 0x20202020},
|
||||
{0x0000a3f0, 0x00000000},
|
||||
{0x0000a3f4, 0x00000006},
|
||||
{0x0000a3f8, 0x0cdbd380},
|
||||
{0x0000a3f8, 0x0c9bd380},
|
||||
{0x0000a3fc, 0x000f0f01},
|
||||
{0x0000a400, 0x8fa91f01},
|
||||
{0x0000a404, 0x00000000},
|
||||
|
@ -355,11 +353,11 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = {
|
|||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222},
|
||||
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
{0x0000a204, 0x033187c0, 0x033187c4, 0x033187c4, 0x033187c0},
|
||||
{0x0000a204, 0x07318fc0, 0x07318fc4, 0x07318fc4, 0x07318fc0},
|
||||
{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
|
||||
{0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f},
|
||||
{0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
|
||||
|
@ -375,9 +373,9 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = {
|
|||
{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
|
||||
{0x0000a288, 0x00100510, 0x00100510, 0x00100510, 0x00100510},
|
||||
{0x0000a28c, 0x00021551, 0x00021551, 0x00021551, 0x00021551},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982},
|
||||
{0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
|
||||
{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -417,7 +415,7 @@ static const u32 ar9565_1p0_radio_core[][2] = {
|
|||
{0x00016144, 0x02084080},
|
||||
{0x00016148, 0x000080c0},
|
||||
{0x00016280, 0x050a0001},
|
||||
{0x00016284, 0x3d841400},
|
||||
{0x00016284, 0x3d841440},
|
||||
{0x00016288, 0x00000000},
|
||||
{0x0001628c, 0xe3000000},
|
||||
{0x00016290, 0xa1004080},
|
||||
|
@ -840,27 +838,27 @@ static const u32 ar9565_1p0_common_wo_xlna_rx_gain_table[][2] = {
|
|||
{0x0000a0b4, 0x00000000},
|
||||
{0x0000a0b8, 0x00000000},
|
||||
{0x0000a0bc, 0x00000000},
|
||||
{0x0000a0c0, 0x301f3000},
|
||||
{0x0000a0c4, 0x41004101},
|
||||
{0x0000a0c8, 0x411e411f},
|
||||
{0x0000a0cc, 0x411c411d},
|
||||
{0x0000a0d0, 0x42434244},
|
||||
{0x0000a0d4, 0x42414242},
|
||||
{0x0000a0d8, 0x425f4240},
|
||||
{0x0000a0dc, 0x5342425e},
|
||||
{0x0000a0e0, 0x53405341},
|
||||
{0x0000a0e4, 0x535e535f},
|
||||
{0x0000a0e8, 0x7402535d},
|
||||
{0x0000a0ec, 0x74007401},
|
||||
{0x0000a0f0, 0x741e741f},
|
||||
{0x0000a0f4, 0x7522741d},
|
||||
{0x0000a0f8, 0x75207521},
|
||||
{0x0000a0fc, 0x753e753f},
|
||||
{0x0000a100, 0x76617662},
|
||||
{0x0000a104, 0x767f7660},
|
||||
{0x0000a108, 0x767d767e},
|
||||
{0x0000a10c, 0x77e277e3},
|
||||
{0x0000a110, 0x77e077e1},
|
||||
{0x0000a0c0, 0x00bf00a0},
|
||||
{0x0000a0c4, 0x11a011a1},
|
||||
{0x0000a0c8, 0x11be11bf},
|
||||
{0x0000a0cc, 0x11bc11bd},
|
||||
{0x0000a0d0, 0x22632264},
|
||||
{0x0000a0d4, 0x22612262},
|
||||
{0x0000a0d8, 0x227f2260},
|
||||
{0x0000a0dc, 0x4322227e},
|
||||
{0x0000a0e0, 0x43204321},
|
||||
{0x0000a0e4, 0x433e433f},
|
||||
{0x0000a0e8, 0x4462433d},
|
||||
{0x0000a0ec, 0x44604461},
|
||||
{0x0000a0f0, 0x447e447f},
|
||||
{0x0000a0f4, 0x5582447d},
|
||||
{0x0000a0f8, 0x55805581},
|
||||
{0x0000a0fc, 0x559e559f},
|
||||
{0x0000a100, 0x66816682},
|
||||
{0x0000a104, 0x669f6680},
|
||||
{0x0000a108, 0x669d669e},
|
||||
{0x0000a10c, 0x77627763},
|
||||
{0x0000a110, 0x77607761},
|
||||
{0x0000a114, 0x00000000},
|
||||
{0x0000a118, 0x00000000},
|
||||
{0x0000a11c, 0x00000000},
|
||||
|
@ -872,27 +870,27 @@ static const u32 ar9565_1p0_common_wo_xlna_rx_gain_table[][2] = {
|
|||
{0x0000a134, 0x00000000},
|
||||
{0x0000a138, 0x00000000},
|
||||
{0x0000a13c, 0x00000000},
|
||||
{0x0000a140, 0x301f3000},
|
||||
{0x0000a144, 0x41004101},
|
||||
{0x0000a148, 0x411e411f},
|
||||
{0x0000a14c, 0x411c411d},
|
||||
{0x0000a150, 0x42434244},
|
||||
{0x0000a154, 0x42414242},
|
||||
{0x0000a158, 0x425f4240},
|
||||
{0x0000a15c, 0x5342425e},
|
||||
{0x0000a160, 0x53405341},
|
||||
{0x0000a164, 0x535e535f},
|
||||
{0x0000a168, 0x7402535d},
|
||||
{0x0000a16c, 0x74007401},
|
||||
{0x0000a170, 0x741e741f},
|
||||
{0x0000a174, 0x7522741d},
|
||||
{0x0000a178, 0x75207521},
|
||||
{0x0000a17c, 0x753e753f},
|
||||
{0x0000a180, 0x76617662},
|
||||
{0x0000a184, 0x767f7660},
|
||||
{0x0000a188, 0x767d767e},
|
||||
{0x0000a18c, 0x77e277e3},
|
||||
{0x0000a190, 0x77e077e1},
|
||||
{0x0000a140, 0x00bf00a0},
|
||||
{0x0000a144, 0x11a011a1},
|
||||
{0x0000a148, 0x11be11bf},
|
||||
{0x0000a14c, 0x11bc11bd},
|
||||
{0x0000a150, 0x22632264},
|
||||
{0x0000a154, 0x22612262},
|
||||
{0x0000a158, 0x227f2260},
|
||||
{0x0000a15c, 0x4322227e},
|
||||
{0x0000a160, 0x43204321},
|
||||
{0x0000a164, 0x433e433f},
|
||||
{0x0000a168, 0x4462433d},
|
||||
{0x0000a16c, 0x44604461},
|
||||
{0x0000a170, 0x447e447f},
|
||||
{0x0000a174, 0x5582447d},
|
||||
{0x0000a178, 0x55805581},
|
||||
{0x0000a17c, 0x559e559f},
|
||||
{0x0000a180, 0x66816682},
|
||||
{0x0000a184, 0x669f6680},
|
||||
{0x0000a188, 0x669d669e},
|
||||
{0x0000a18c, 0x77627763},
|
||||
{0x0000a190, 0x77607761},
|
||||
{0x0000a194, 0x00000000},
|
||||
{0x0000a198, 0x00000000},
|
||||
{0x0000a19c, 0x00000000},
|
||||
|
|
|
@ -537,6 +537,7 @@ struct ath9k_wow_pattern {
|
|||
#ifdef CONFIG_MAC80211_LEDS
|
||||
void ath_init_leds(struct ath_softc *sc);
|
||||
void ath_deinit_leds(struct ath_softc *sc);
|
||||
void ath_fill_led_pin(struct ath_softc *sc);
|
||||
#else
|
||||
static inline void ath_init_leds(struct ath_softc *sc)
|
||||
{
|
||||
|
@ -545,6 +546,9 @@ static inline void ath_init_leds(struct ath_softc *sc)
|
|||
static inline void ath_deinit_leds(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
static inline void ath_fill_led_pin(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************/
|
||||
|
@ -596,8 +600,6 @@ struct ath_ant_comb {
|
|||
int main_conf;
|
||||
enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
|
||||
enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
|
||||
int first_bias;
|
||||
int second_bias;
|
||||
bool first_ratio;
|
||||
bool second_ratio;
|
||||
unsigned long scan_start_time;
|
||||
|
|
|
@ -44,25 +44,6 @@ void ath_init_leds(struct ath_softc *sc)
|
|||
if (AR_SREV_9100(sc->sc_ah))
|
||||
return;
|
||||
|
||||
if (sc->sc_ah->led_pin < 0) {
|
||||
if (AR_SREV_9287(sc->sc_ah))
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_9287;
|
||||
else if (AR_SREV_9485(sc->sc_ah))
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_9485;
|
||||
else if (AR_SREV_9300(sc->sc_ah))
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_9300;
|
||||
else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah))
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_9462;
|
||||
else
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
|
||||
}
|
||||
|
||||
/* Configure gpio 1 for output */
|
||||
ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
/* LED off, active low */
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
|
||||
|
||||
if (!led_blink)
|
||||
sc->led_cdev.default_trigger =
|
||||
ieee80211_get_radio_led_name(sc->hw);
|
||||
|
@ -78,6 +59,31 @@ void ath_init_leds(struct ath_softc *sc)
|
|||
|
||||
sc->led_registered = true;
|
||||
}
|
||||
|
||||
void ath_fill_led_pin(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
if (AR_SREV_9100(ah) || (ah->led_pin >= 0))
|
||||
return;
|
||||
|
||||
if (AR_SREV_9287(ah))
|
||||
ah->led_pin = ATH_LED_PIN_9287;
|
||||
else if (AR_SREV_9485(sc->sc_ah))
|
||||
ah->led_pin = ATH_LED_PIN_9485;
|
||||
else if (AR_SREV_9300(sc->sc_ah))
|
||||
ah->led_pin = ATH_LED_PIN_9300;
|
||||
else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah))
|
||||
ah->led_pin = ATH_LED_PIN_9462;
|
||||
else
|
||||
ah->led_pin = ATH_LED_PIN_DEF;
|
||||
|
||||
/* Configure gpio 1 for output */
|
||||
ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
|
||||
/* LED off, active low */
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************/
|
||||
|
@ -314,8 +320,10 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
|
|||
ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n");
|
||||
|
||||
/* make sure duty cycle timer is also stopped when resuming */
|
||||
if (btcoex->hw_timer_enabled)
|
||||
if (btcoex->hw_timer_enabled) {
|
||||
ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
|
||||
btcoex->hw_timer_enabled = false;
|
||||
}
|
||||
|
||||
btcoex->bt_priority_cnt = 0;
|
||||
btcoex->bt_priority_time = jiffies;
|
||||
|
@ -336,18 +344,20 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc)
|
|||
|
||||
del_timer_sync(&btcoex->period_timer);
|
||||
|
||||
if (btcoex->hw_timer_enabled)
|
||||
if (btcoex->hw_timer_enabled) {
|
||||
ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
|
||||
|
||||
btcoex->hw_timer_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
|
||||
if (btcoex->hw_timer_enabled)
|
||||
if (btcoex->hw_timer_enabled) {
|
||||
ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
|
||||
btcoex->hw_timer_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
|
||||
|
|
|
@ -1072,14 +1072,15 @@ static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev)
|
|||
*/
|
||||
static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
|
||||
{
|
||||
struct device *parent = hif_dev->udev->dev.parent;
|
||||
struct device *dev = &hif_dev->udev->dev;
|
||||
struct device *parent = dev->parent;
|
||||
|
||||
complete(&hif_dev->fw_done);
|
||||
|
||||
if (parent)
|
||||
device_lock(parent);
|
||||
|
||||
device_release_driver(&hif_dev->udev->dev);
|
||||
device_release_driver(dev);
|
||||
|
||||
if (parent)
|
||||
device_unlock(parent);
|
||||
|
|
|
@ -1445,7 +1445,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
|
|||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
if (priv->ah->sw_mgmt_crypto &&
|
||||
key->cipher == WLAN_CIPHER_SUITE_CCMP)
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -78,6 +78,13 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
|
|||
ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
|
||||
}
|
||||
|
||||
static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
|
||||
bool enable)
|
||||
{
|
||||
if (ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv)
|
||||
ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv(ah, enable);
|
||||
}
|
||||
|
||||
/* Private hardware call ops */
|
||||
|
||||
/* PHY ops */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "rc.h"
|
||||
#include "ar9003_mac.h"
|
||||
#include "ar9003_mci.h"
|
||||
#include "ar9003_phy.h"
|
||||
#include "debug.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
|
@ -1733,12 +1734,12 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
if (!ret)
|
||||
goto fail;
|
||||
|
||||
ath9k_hw_loadnf(ah, ah->curchan);
|
||||
ath9k_hw_start_nfcal(ah, true);
|
||||
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ar9003_mci_2g5g_switch(ah, false);
|
||||
|
||||
ath9k_hw_loadnf(ah, ah->curchan);
|
||||
ath9k_hw_start_nfcal(ah, true);
|
||||
|
||||
if (AR_SREV_9271(ah))
|
||||
ar9002_hw_load_ani_reg(ah, chan);
|
||||
|
||||
|
@ -2025,6 +2026,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
|
||||
ath9k_hw_apply_gpio_override(ah);
|
||||
|
||||
if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv)
|
||||
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_reset);
|
||||
|
@ -2535,7 +2539,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
}
|
||||
|
||||
|
||||
if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) {
|
||||
if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
|
||||
ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
|
||||
/*
|
||||
* enable the diversity-combining algorithm only when
|
||||
|
|
|
@ -686,7 +686,7 @@ struct ath_hw_ops {
|
|||
struct ath_hw_antcomb_conf *antconf);
|
||||
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
|
||||
struct ath_hw_antcomb_conf *antconf);
|
||||
|
||||
void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
|
||||
};
|
||||
|
||||
struct ath_nf_limits {
|
||||
|
@ -730,6 +730,7 @@ struct ath_hw {
|
|||
bool aspm_enabled;
|
||||
bool is_monitoring;
|
||||
bool need_an_top2_fixup;
|
||||
bool shared_chain_lnadiv;
|
||||
u16 tx_trig_level;
|
||||
|
||||
u32 nf_regs[6];
|
||||
|
|
|
@ -46,6 +46,10 @@ static int ath9k_btcoex_enable;
|
|||
module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
|
||||
MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
|
||||
|
||||
static int ath9k_enable_diversity;
|
||||
module_param_named(enable_diversity, ath9k_enable_diversity, int, 0444);
|
||||
MODULE_PARM_DESC(enable_diversity, "Enable Antenna diversity for AR9565");
|
||||
|
||||
bool is_ath9k_unloaded;
|
||||
/* We use the hw_value as an index into our private channel structure */
|
||||
|
||||
|
@ -546,6 +550,14 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
common->debug_mask = ath9k_debug;
|
||||
common->btcoex_enabled = ath9k_btcoex_enable == 1;
|
||||
common->disable_ani = false;
|
||||
|
||||
/*
|
||||
* Enable Antenna diversity only when BTCOEX is disabled
|
||||
* and the user manually requests the feature.
|
||||
*/
|
||||
if (!common->btcoex_enabled && ath9k_enable_diversity)
|
||||
common->antenna_diversity = 1;
|
||||
|
||||
spin_lock_init(&common->cc_lock);
|
||||
|
||||
spin_lock_init(&sc->sc_serial_rw);
|
||||
|
@ -597,6 +609,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
|
||||
ath9k_cmn_init_crypto(sc->sc_ah);
|
||||
ath9k_init_misc(sc);
|
||||
ath_fill_led_pin(sc);
|
||||
|
||||
if (common->bus_ops->aspm_init)
|
||||
common->bus_ops->aspm_init(common);
|
||||
|
|
|
@ -1406,7 +1406,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
|||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
if (sc->sc_ah->sw_mgmt_crypto &&
|
||||
key->cipher == WLAN_CIPHER_SUITE_CCMP)
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -80,6 +80,7 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci)
|
|||
struct ath_mci_profile_info *info, *tinfo;
|
||||
|
||||
mci->aggr_limit = 0;
|
||||
mci->num_mgmt = 0;
|
||||
|
||||
if (list_empty(&mci->info))
|
||||
return;
|
||||
|
@ -120,7 +121,14 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
|
|||
if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING)
|
||||
goto skip_tuning;
|
||||
|
||||
mci->aggr_limit = 0;
|
||||
btcoex->duty_cycle = ath_mci_duty_cycle[num_profile];
|
||||
btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
|
||||
if (NUM_PROF(mci))
|
||||
btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
|
||||
else
|
||||
btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
|
||||
ATH_BTCOEX_STOMP_LOW;
|
||||
|
||||
if (num_profile == 1) {
|
||||
info = list_first_entry(&mci->info,
|
||||
|
@ -132,7 +140,8 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
|
|||
else if (info->T == 6) {
|
||||
mci->aggr_limit = 6;
|
||||
btcoex->duty_cycle = 30;
|
||||
}
|
||||
} else
|
||||
mci->aggr_limit = 6;
|
||||
ath_dbg(common, MCI,
|
||||
"Single SCO, aggregation limit %d 1/4 ms\n",
|
||||
mci->aggr_limit);
|
||||
|
@ -241,7 +250,7 @@ static void ath9k_mci_work(struct work_struct *work)
|
|||
ath_mci_update_scheme(sc);
|
||||
}
|
||||
|
||||
static void ath_mci_process_profile(struct ath_softc *sc,
|
||||
static u8 ath_mci_process_profile(struct ath_softc *sc,
|
||||
struct ath_mci_profile_info *info)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
@ -268,24 +277,14 @@ static void ath_mci_process_profile(struct ath_softc *sc,
|
|||
|
||||
if (info->start) {
|
||||
if (!entry && !ath_mci_add_profile(common, mci, info))
|
||||
return;
|
||||
return 0;
|
||||
} else
|
||||
ath_mci_del_profile(common, mci, entry);
|
||||
|
||||
btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
|
||||
mci->aggr_limit = mci->num_sco ? 6 : 0;
|
||||
|
||||
btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
|
||||
if (NUM_PROF(mci))
|
||||
btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
|
||||
else
|
||||
btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
|
||||
ATH_BTCOEX_STOMP_LOW;
|
||||
|
||||
ieee80211_queue_work(sc->hw, &sc->mci_work);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ath_mci_process_status(struct ath_softc *sc,
|
||||
static u8 ath_mci_process_status(struct ath_softc *sc,
|
||||
struct ath_mci_profile_status *status)
|
||||
{
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
|
@ -295,14 +294,14 @@ static void ath_mci_process_status(struct ath_softc *sc,
|
|||
|
||||
/* Link status type are not handled */
|
||||
if (status->is_link)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
info.conn_handle = status->conn_handle;
|
||||
if (ath_mci_find_profile(mci, &info))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (status->conn_handle >= ATH_MCI_MAX_PROFILE)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (status->is_critical)
|
||||
__set_bit(status->conn_handle, mci->status);
|
||||
|
@ -316,7 +315,9 @@ static void ath_mci_process_status(struct ath_softc *sc,
|
|||
} while (++i < ATH_MCI_MAX_PROFILE);
|
||||
|
||||
if (old_num_mgmt != mci->num_mgmt)
|
||||
ieee80211_queue_work(sc->hw, &sc->mci_work);
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
|
||||
|
@ -325,9 +326,16 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
|
|||
struct ath_mci_profile_info profile_info;
|
||||
struct ath_mci_profile_status profile_status;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
u8 major, minor;
|
||||
u8 major, minor, update_scheme = 0;
|
||||
u32 seq_num;
|
||||
|
||||
if (ar9003_mci_state(ah, MCI_STATE_NEED_FLUSH_BT_INFO) &&
|
||||
ar9003_mci_state(ah, MCI_STATE_ENABLE)) {
|
||||
ath_dbg(common, MCI, "(MCI) Need to flush BT profiles\n");
|
||||
ath_mci_flush_profile(&sc->btcoex.mci);
|
||||
ar9003_mci_state(ah, MCI_STATE_SEND_STATUS_QUERY);
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case MCI_GPM_COEX_VERSION_QUERY:
|
||||
ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION);
|
||||
|
@ -353,7 +361,7 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
|
|||
break;
|
||||
}
|
||||
|
||||
ath_mci_process_profile(sc, &profile_info);
|
||||
update_scheme += ath_mci_process_profile(sc, &profile_info);
|
||||
break;
|
||||
case MCI_GPM_COEX_BT_STATUS_UPDATE:
|
||||
profile_status.is_link = *(rx_payload +
|
||||
|
@ -369,12 +377,14 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
|
|||
profile_status.is_link, profile_status.conn_handle,
|
||||
profile_status.is_critical, seq_num);
|
||||
|
||||
ath_mci_process_status(sc, &profile_status);
|
||||
update_scheme += ath_mci_process_status(sc, &profile_status);
|
||||
break;
|
||||
default:
|
||||
ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode);
|
||||
break;
|
||||
}
|
||||
if (update_scheme)
|
||||
ieee80211_queue_work(sc->hw, &sc->mci_work);
|
||||
}
|
||||
|
||||
int ath_mci_setup(struct ath_softc *sc)
|
||||
|
@ -568,9 +578,11 @@ void ath_mci_intr(struct ath_softc *sc)
|
|||
}
|
||||
|
||||
if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
|
||||
(mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT))
|
||||
(mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
|
||||
mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
|
||||
AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
|
||||
ath_mci_msg(sc, MCI_GPM_COEX_NOOP, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void ath_mci_enable(struct ath_softc *sc)
|
||||
|
|
|
@ -128,8 +128,9 @@ static void ath_pci_aspm_init(struct ath_common *common)
|
|||
if (!parent)
|
||||
return;
|
||||
|
||||
if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
|
||||
/* Bluetooth coexistance requires disabling ASPM. */
|
||||
if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) &&
|
||||
(AR_SREV_9285(ah))) {
|
||||
/* Bluetooth coexistance requires disabling ASPM for AR9285. */
|
||||
pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm);
|
||||
aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
|
||||
pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm);
|
||||
|
|
|
@ -1222,11 +1222,14 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta)
|
|||
caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
|
||||
else if (sta->ht_cap.mcs.rx_mask[1])
|
||||
caps |= WLAN_RC_DS_FLAG;
|
||||
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
|
||||
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
|
||||
caps |= WLAN_RC_40_FLAG;
|
||||
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40 ||
|
||||
sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
|
||||
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
|
||||
caps |= WLAN_RC_SGI_FLAG;
|
||||
} else {
|
||||
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
|
||||
caps |= WLAN_RC_SGI_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
return caps;
|
||||
|
|
|
@ -304,7 +304,8 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
|
|||
struct ath_common *common = &ar->common;
|
||||
u8 *mac_addr, *bssid;
|
||||
u32 cam_mode = AR9170_MAC_CAM_DEFAULTS;
|
||||
u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS;
|
||||
u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS |
|
||||
AR9170_MAC_ENCRYPTION_MGMT_RX_SOFTWARE;
|
||||
u32 rx_ctrl = AR9170_MAC_RX_CTRL_DEAGG |
|
||||
AR9170_MAC_RX_CTRL_SHORT_FILTER;
|
||||
u32 sniffer = AR9170_MAC_SNIFFER_DEFAULTS;
|
||||
|
|
|
@ -1149,6 +1149,7 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
ktype = AR9170_ENC_ALG_AESCCMP;
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -1780,6 +1781,7 @@ void *carl9170_alloc(size_t priv_size)
|
|||
hw->wiphy->interface_modes = 0;
|
||||
|
||||
hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
IEEE80211_HW_MFP_CAPABLE |
|
||||
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_PS_NULLFUNC_STACK |
|
||||
|
|
|
@ -185,7 +185,7 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
|
||||
void *data, bool write)
|
||||
{
|
||||
|
@ -249,7 +249,9 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
|
|||
int retval;
|
||||
|
||||
brcmf_dbg(INFO, "addr:0x%08x\n", addr);
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
brcmf_dbg(INFO, "data:0x%02x\n", data);
|
||||
|
||||
if (ret)
|
||||
|
@ -264,7 +266,9 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
|
|||
int retval;
|
||||
|
||||
brcmf_dbg(INFO, "addr:0x%08x\n", addr);
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
brcmf_dbg(INFO, "data:0x%08x\n", data);
|
||||
|
||||
if (ret)
|
||||
|
@ -279,7 +283,9 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
|
|||
int retval;
|
||||
|
||||
brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
if (ret)
|
||||
*ret = retval;
|
||||
|
@ -291,7 +297,9 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
|
|||
int retval;
|
||||
|
||||
brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
if (ret)
|
||||
*ret = retval;
|
||||
|
@ -356,15 +364,20 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
|
|||
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
|
||||
fn, addr, pkt->len);
|
||||
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
|
||||
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
|
||||
err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
|
||||
if (err)
|
||||
return err;
|
||||
goto done;
|
||||
|
||||
incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
|
||||
err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
|
||||
fn, addr, pkt);
|
||||
|
||||
done:
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -378,15 +391,20 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
|
|||
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
|
||||
fn, addr, pktq->qlen);
|
||||
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
|
||||
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
|
||||
err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
|
||||
if (err)
|
||||
return err;
|
||||
goto done;
|
||||
|
||||
incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
|
||||
err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
|
||||
pktq);
|
||||
|
||||
done:
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -428,10 +446,12 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
|
|||
if (flags & SDIO_REQ_ASYNC)
|
||||
return -ENOTSUPP;
|
||||
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
|
||||
if (bar0 != sdiodev->sbwad) {
|
||||
err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
|
||||
if (err)
|
||||
return err;
|
||||
goto done;
|
||||
|
||||
sdiodev->sbwad = bar0;
|
||||
}
|
||||
|
@ -443,8 +463,13 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
|
|||
if (width == 4)
|
||||
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
|
||||
|
||||
return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
|
||||
err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
|
||||
addr, pkt);
|
||||
|
||||
done:
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
|
||||
|
@ -485,8 +510,10 @@ int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
|
|||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
/* issue abort cmd52 command through F0 */
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
|
||||
SDIO_CCCR_ABORT, &t_func);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
brcmf_dbg(TRACE, "Exit\n");
|
||||
return 0;
|
||||
|
|
|
@ -103,7 +103,6 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
|
|||
if (regaddr == SDIO_CCCR_IOEx) {
|
||||
sdfunc = sdiodev->func[2];
|
||||
if (sdfunc) {
|
||||
sdio_claim_host(sdfunc);
|
||||
if (*byte & SDIO_FUNC_ENABLE_2) {
|
||||
/* Enable Function 2 */
|
||||
err_ret = sdio_enable_func(sdfunc);
|
||||
|
@ -119,7 +118,6 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
|
|||
"Disable F2 failed:%d\n",
|
||||
err_ret);
|
||||
}
|
||||
sdio_release_host(sdfunc);
|
||||
}
|
||||
} else if ((regaddr == SDIO_CCCR_ABORT) ||
|
||||
(regaddr == SDIO_CCCR_IENx)) {
|
||||
|
@ -128,17 +126,13 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
|
|||
if (!sdfunc)
|
||||
return -ENOMEM;
|
||||
sdfunc->num = 0;
|
||||
sdio_claim_host(sdfunc);
|
||||
sdio_writeb(sdfunc, *byte, regaddr, &err_ret);
|
||||
sdio_release_host(sdfunc);
|
||||
kfree(sdfunc);
|
||||
} else if (regaddr < 0xF0) {
|
||||
brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr);
|
||||
err_ret = -EPERM;
|
||||
} else {
|
||||
sdio_claim_host(sdfunc);
|
||||
sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret);
|
||||
sdio_release_host(sdfunc);
|
||||
}
|
||||
|
||||
return err_ret;
|
||||
|
@ -159,7 +153,6 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
|
|||
/* handle F0 separately */
|
||||
err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte);
|
||||
} else {
|
||||
sdio_claim_host(sdiodev->func[func]);
|
||||
if (rw) /* CMD52 Write */
|
||||
sdio_writeb(sdiodev->func[func], *byte, regaddr,
|
||||
&err_ret);
|
||||
|
@ -170,7 +163,6 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
|
|||
*byte = sdio_readb(sdiodev->func[func], regaddr,
|
||||
&err_ret);
|
||||
}
|
||||
sdio_release_host(sdiodev->func[func]);
|
||||
}
|
||||
|
||||
if (err_ret)
|
||||
|
@ -197,8 +189,6 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
|
|||
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
|
||||
if (brcmf_pm_resume_error(sdiodev))
|
||||
return -EIO;
|
||||
/* Claim host controller */
|
||||
sdio_claim_host(sdiodev->func[func]);
|
||||
|
||||
if (rw) { /* CMD52 Write */
|
||||
if (nbytes == 4)
|
||||
|
@ -219,9 +209,6 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
|
|||
brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes);
|
||||
}
|
||||
|
||||
/* Release host controller */
|
||||
sdio_release_host(sdiodev->func[func]);
|
||||
|
||||
if (err_ret)
|
||||
brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n",
|
||||
rw ? "write" : "read", err_ret);
|
||||
|
@ -275,9 +262,6 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
|
|||
if (brcmf_pm_resume_error(sdiodev))
|
||||
return -EIO;
|
||||
|
||||
/* Claim host controller */
|
||||
sdio_claim_host(sdiodev->func[func]);
|
||||
|
||||
skb_queue_walk(pktq, pkt) {
|
||||
uint pkt_len = pkt->len;
|
||||
pkt_len += 3;
|
||||
|
@ -300,9 +284,6 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
|
|||
SGCount++;
|
||||
}
|
||||
|
||||
/* Release host controller */
|
||||
sdio_release_host(sdiodev->func[func]);
|
||||
|
||||
brcmf_dbg(TRACE, "Exit\n");
|
||||
return err_ret;
|
||||
}
|
||||
|
@ -328,9 +309,6 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
|
|||
if (brcmf_pm_resume_error(sdiodev))
|
||||
return -EIO;
|
||||
|
||||
/* Claim host controller */
|
||||
sdio_claim_host(sdiodev->func[func]);
|
||||
|
||||
pkt_len += 3;
|
||||
pkt_len &= (uint)~3;
|
||||
|
||||
|
@ -344,9 +322,6 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
|
|||
write ? "TX" : "RX", pkt, addr, pkt_len);
|
||||
}
|
||||
|
||||
/* Release host controller */
|
||||
sdio_release_host(sdiodev->func[func]);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -682,10 +682,6 @@ extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx,
|
|||
|
||||
extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx);
|
||||
|
||||
/* Send packet to dongle via data channel */
|
||||
extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\
|
||||
struct sk_buff *pkt);
|
||||
|
||||
extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg);
|
||||
extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg,
|
||||
int enable, int master_mode);
|
||||
|
|
|
@ -80,8 +80,10 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
|
|||
strncpy(buf, name, buflen);
|
||||
|
||||
/* append data onto the end of the name string */
|
||||
if (data && datalen) {
|
||||
memcpy(&buf[len], data, datalen);
|
||||
len += datalen;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -431,13 +433,7 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
|
|||
}
|
||||
|
||||
/* show any appended data */
|
||||
if (datalen) {
|
||||
buf = (unsigned char *) event_data;
|
||||
brcmf_dbg(EVENT, " data (%d) : ", datalen);
|
||||
for (i = 0; i < datalen; i++)
|
||||
brcmf_dbg(EVENT, " 0x%02x ", *buf++);
|
||||
brcmf_dbg(EVENT, "\n");
|
||||
}
|
||||
brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data");
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
|
@ -528,6 +524,7 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (BRCMF_EVENT_ON())
|
||||
brcmf_c_show_host_event(event, event_data);
|
||||
#endif /* DEBUG */
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ do { \
|
|||
#define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL)
|
||||
#define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL)
|
||||
#define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL)
|
||||
#define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL)
|
||||
|
||||
#else /* (defined DEBUG) || (defined DEBUG) */
|
||||
|
||||
|
@ -65,6 +66,7 @@ do { \
|
|||
#define BRCMF_HDRS_ON() 0
|
||||
#define BRCMF_BYTES_ON() 0
|
||||
#define BRCMF_GLOM_ON() 0
|
||||
#define BRCMF_EVENT_ON() 0
|
||||
|
||||
#endif /* defined(DEBUG) */
|
||||
|
||||
|
|
|
@ -272,30 +272,6 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
|
|||
schedule_work(&drvr->multicast_work);
|
||||
}
|
||||
|
||||
int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
|
||||
{
|
||||
/* Reject if down */
|
||||
if (!drvr->bus_if->drvr_up || (drvr->bus_if->state == BRCMF_BUS_DOWN))
|
||||
return -ENODEV;
|
||||
|
||||
/* Update multicast statistic */
|
||||
if (pktbuf->len >= ETH_ALEN) {
|
||||
u8 *pktdata = (u8 *) (pktbuf->data);
|
||||
struct ethhdr *eh = (struct ethhdr *)pktdata;
|
||||
|
||||
if (is_multicast_ether_addr(eh->h_dest))
|
||||
drvr->tx_multicast++;
|
||||
if (ntohs(eh->h_proto) == ETH_P_PAE)
|
||||
atomic_inc(&drvr->pend_8021x_cnt);
|
||||
}
|
||||
|
||||
/* If the protocol uses a data header, apply it */
|
||||
brcmf_proto_hdrpush(drvr, ifidx, pktbuf);
|
||||
|
||||
/* Use bus module to send data frame */
|
||||
return drvr->bus_if->brcmf_bus_txdata(drvr->dev, pktbuf);
|
||||
}
|
||||
|
||||
static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -338,7 +314,22 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
}
|
||||
}
|
||||
|
||||
ret = brcmf_sendpkt(drvr, ifp->idx, skb);
|
||||
/* Update multicast statistic */
|
||||
if (skb->len >= ETH_ALEN) {
|
||||
u8 *pktdata = (u8 *)(skb->data);
|
||||
struct ethhdr *eh = (struct ethhdr *)pktdata;
|
||||
|
||||
if (is_multicast_ether_addr(eh->h_dest))
|
||||
drvr->tx_multicast++;
|
||||
if (ntohs(eh->h_proto) == ETH_P_PAE)
|
||||
atomic_inc(&drvr->pend_8021x_cnt);
|
||||
}
|
||||
|
||||
/* If the protocol uses a data header, apply it */
|
||||
brcmf_proto_hdrpush(drvr, ifp->idx, skb);
|
||||
|
||||
/* Use bus module to send data frame */
|
||||
ret = drvr->bus_if->brcmf_bus_txdata(drvr->dev, skb);
|
||||
|
||||
done:
|
||||
if (ret)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -174,6 +174,8 @@ extern void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
|
|||
u8 data, int *ret);
|
||||
extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
|
||||
u32 data, int *ret);
|
||||
extern int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
|
||||
void *data, bool write);
|
||||
|
||||
/* Buffer transfer to/from device (client) core via cmd53.
|
||||
* fn: function number
|
||||
|
|
|
@ -81,10 +81,12 @@ enum usbdev_suspend_state {
|
|||
};
|
||||
|
||||
struct brcmf_usb_image {
|
||||
void *data;
|
||||
u32 len;
|
||||
struct list_head list;
|
||||
s8 *fwname;
|
||||
u8 *image;
|
||||
int image_len;
|
||||
};
|
||||
static struct brcmf_usb_image g_image = { NULL, 0 };
|
||||
static struct list_head fw_image_list;
|
||||
|
||||
struct intr_transfer_buf {
|
||||
u32 notification;
|
||||
|
@ -132,8 +134,6 @@ struct brcmf_usbdev_info {
|
|||
wait_queue_head_t ctrl_wait;
|
||||
ulong ctl_op;
|
||||
|
||||
bool rxctl_deferrespok;
|
||||
|
||||
struct urb *bulk_urb; /* used for FW download */
|
||||
struct urb *intr_urb; /* URB for interrupt endpoint */
|
||||
int intr_size; /* Size of interrupt message */
|
||||
|
@ -299,17 +299,9 @@ brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
|
|||
devinfo->ctl_read.wLength = cpu_to_le16p(&size);
|
||||
devinfo->ctl_urb->transfer_buffer_length = size;
|
||||
|
||||
if (devinfo->rxctl_deferrespok) {
|
||||
/* BMAC model */
|
||||
devinfo->ctl_read.bRequestType = USB_DIR_IN
|
||||
| USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
|
||||
devinfo->ctl_read.bRequest = DL_DEFER_RESP_OK;
|
||||
} else {
|
||||
/* full dongle model */
|
||||
devinfo->ctl_read.bRequestType = USB_DIR_IN
|
||||
| USB_TYPE_CLASS | USB_RECIP_INTERFACE;
|
||||
devinfo->ctl_read.bRequest = 1;
|
||||
}
|
||||
|
||||
usb_fill_control_urb(devinfo->ctl_urb,
|
||||
devinfo->usbdev,
|
||||
|
@ -345,6 +337,7 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
|
|||
err = brcmf_usb_send_ctl(devinfo, buf, len);
|
||||
if (err) {
|
||||
brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -375,6 +368,7 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
|
|||
err = brcmf_usb_recv_ctl(devinfo, buf, len);
|
||||
if (err) {
|
||||
brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
return err;
|
||||
}
|
||||
devinfo->ctl_completed = false;
|
||||
|
@ -1152,10 +1146,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
|
|||
{
|
||||
brcmf_dbg(TRACE, "devinfo %p\n", devinfo);
|
||||
|
||||
/* store the image globally */
|
||||
g_image.data = devinfo->image;
|
||||
g_image.len = devinfo->image_len;
|
||||
|
||||
/* free the URBS */
|
||||
brcmf_usb_free_q(&devinfo->rx_freeq, false);
|
||||
brcmf_usb_free_q(&devinfo->tx_freeq, false);
|
||||
|
@ -1207,17 +1197,9 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
|
|||
{
|
||||
s8 *fwname;
|
||||
const struct firmware *fw;
|
||||
struct brcmf_usb_image *fw_image;
|
||||
int err;
|
||||
|
||||
devinfo->image = g_image.data;
|
||||
devinfo->image_len = g_image.len;
|
||||
|
||||
/*
|
||||
* if we have an image we can leave here.
|
||||
*/
|
||||
if (devinfo->image)
|
||||
return 0;
|
||||
|
||||
switch (devinfo->bus_pub.devid) {
|
||||
case 43143:
|
||||
fwname = BRCMF_USB_43143_FW_NAME;
|
||||
|
@ -1235,6 +1217,14 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
|
|||
break;
|
||||
}
|
||||
|
||||
list_for_each_entry(fw_image, &fw_image_list, list) {
|
||||
if (fw_image->fwname == fwname) {
|
||||
devinfo->image = fw_image->image;
|
||||
devinfo->image_len = fw_image->image_len;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* fw image not yet loaded. Load it now and add to list */
|
||||
err = request_firmware(&fw, fwname, devinfo->dev);
|
||||
if (!fw) {
|
||||
brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname);
|
||||
|
@ -1245,14 +1235,24 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
devinfo->image = vmalloc(fw->size); /* plus nvram */
|
||||
if (!devinfo->image)
|
||||
fw_image = kzalloc(sizeof(*fw_image), GFP_ATOMIC);
|
||||
if (!fw_image)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&fw_image->list);
|
||||
list_add_tail(&fw_image->list, &fw_image_list);
|
||||
fw_image->fwname = fwname;
|
||||
fw_image->image = vmalloc(fw->size);
|
||||
if (!fw_image->image)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(devinfo->image, fw->data, fw->size);
|
||||
devinfo->image_len = fw->size;
|
||||
memcpy(fw_image->image, fw->data, fw->size);
|
||||
fw_image->image_len = fw->size;
|
||||
|
||||
release_firmware(fw);
|
||||
|
||||
devinfo->image = fw_image->image;
|
||||
devinfo->image_len = fw_image->image_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1304,8 +1304,6 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
|
|||
brcmf_dbg(ERROR, "usb_alloc_urb (ctl) failed\n");
|
||||
goto error;
|
||||
}
|
||||
devinfo->rxctl_deferrespok = 0;
|
||||
|
||||
devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!devinfo->bulk_urb) {
|
||||
brcmf_dbg(ERROR, "usb_alloc_urb (bulk) failed\n");
|
||||
|
@ -1340,10 +1338,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
|
|||
struct device *dev = devinfo->dev;
|
||||
|
||||
bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ);
|
||||
if (!bus_pub) {
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
if (!bus_pub)
|
||||
return -ENODEV;
|
||||
|
||||
bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
|
||||
if (!bus) {
|
||||
|
@ -1596,15 +1592,25 @@ static struct usb_driver brcmf_usbdrvr = {
|
|||
.disable_hub_initiated_lpm = 1,
|
||||
};
|
||||
|
||||
static void brcmf_release_fw(struct list_head *q)
|
||||
{
|
||||
struct brcmf_usb_image *fw_image, *next;
|
||||
|
||||
list_for_each_entry_safe(fw_image, next, q, list) {
|
||||
vfree(fw_image->image);
|
||||
list_del_init(&fw_image->list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void brcmf_usb_exit(void)
|
||||
{
|
||||
usb_deregister(&brcmf_usbdrvr);
|
||||
vfree(g_image.data);
|
||||
g_image.data = NULL;
|
||||
g_image.len = 0;
|
||||
brcmf_release_fw(&fw_image_list);
|
||||
}
|
||||
|
||||
void brcmf_usb_init(void)
|
||||
{
|
||||
INIT_LIST_HEAD(&fw_image_list);
|
||||
usb_register(&brcmf_usbdrvr);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,18 @@
|
|||
#include "dhd.h"
|
||||
#include "wl_cfg80211.h"
|
||||
|
||||
#define BRCMF_SCAN_IE_LEN_MAX 2048
|
||||
#define BRCMF_PNO_VERSION 2
|
||||
#define BRCMF_PNO_TIME 30
|
||||
#define BRCMF_PNO_REPEAT 4
|
||||
#define BRCMF_PNO_FREQ_EXPO_MAX 3
|
||||
#define BRCMF_PNO_MAX_PFN_COUNT 16
|
||||
#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
|
||||
#define BRCMF_PNO_HIDDEN_BIT 2
|
||||
#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
|
||||
#define BRCMF_PNO_SCAN_COMPLETE 1
|
||||
#define BRCMF_PNO_SCAN_INCOMPLETE 0
|
||||
|
||||
#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
|
||||
(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
|
||||
|
||||
|
@ -700,11 +712,11 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
|
|||
u32 n_channels;
|
||||
s32 i;
|
||||
s32 offset;
|
||||
__le16 chanspec;
|
||||
u16 chanspec;
|
||||
u16 channel;
|
||||
struct ieee80211_channel *req_channel;
|
||||
char *ptr;
|
||||
struct brcmf_ssid ssid;
|
||||
struct brcmf_ssid_le ssid_le;
|
||||
|
||||
memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
|
||||
params_le->bss_type = DOT11_BSSTYPE_ANY;
|
||||
|
@ -747,13 +759,10 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
|
|||
chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
|
||||
}
|
||||
|
||||
params_le->channel_list[i] =
|
||||
(channel & WL_CHANSPEC_CHAN_MASK) |
|
||||
chanspec;
|
||||
chanspec |= (channel & WL_CHANSPEC_CHAN_MASK);
|
||||
WL_SCAN("Chan : %d, Channel spec: %x\n",
|
||||
channel, params_le->channel_list[i]);
|
||||
params_le->channel_list[i] =
|
||||
cpu_to_le16(params_le->channel_list[i]);
|
||||
channel, chanspec);
|
||||
params_le->channel_list[i] = cpu_to_le16(chanspec);
|
||||
}
|
||||
} else {
|
||||
WL_SCAN("Scanning all channels\n");
|
||||
|
@ -766,17 +775,18 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
|
|||
offset = roundup(offset, sizeof(u32));
|
||||
ptr = (char *)params_le + offset;
|
||||
for (i = 0; i < n_ssids; i++) {
|
||||
memset(&ssid, 0, sizeof(ssid));
|
||||
ssid.SSID_len = cpu_to_le32(request->ssids[i].ssid_len);
|
||||
memcpy(ssid.SSID, request->ssids[i].ssid,
|
||||
memset(&ssid_le, 0, sizeof(ssid_le));
|
||||
ssid_le.SSID_len =
|
||||
cpu_to_le32(request->ssids[i].ssid_len);
|
||||
memcpy(ssid_le.SSID, request->ssids[i].ssid,
|
||||
request->ssids[i].ssid_len);
|
||||
if (!ssid.SSID_len)
|
||||
if (!ssid_le.SSID_len)
|
||||
WL_SCAN("%d: Broadcast scan\n", i);
|
||||
else
|
||||
WL_SCAN("%d: scan for %s size =%d\n", i,
|
||||
ssid.SSID, ssid.SSID_len);
|
||||
memcpy(ptr, &ssid, sizeof(ssid));
|
||||
ptr += sizeof(ssid);
|
||||
ssid_le.SSID, ssid_le.SSID_len);
|
||||
memcpy(ptr, &ssid_le, sizeof(ssid_le));
|
||||
ptr += sizeof(ssid_le);
|
||||
}
|
||||
} else {
|
||||
WL_SCAN("Broadcast scan %p\n", request->ssids);
|
||||
|
@ -834,7 +844,17 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv,
|
|||
if (err)
|
||||
WL_ERR("Scan abort failed\n");
|
||||
}
|
||||
if (scan_request) {
|
||||
/*
|
||||
* e-scan can be initiated by scheduled scan
|
||||
* which takes precedence.
|
||||
*/
|
||||
if (cfg_priv->sched_escan) {
|
||||
WL_SCAN("scheduled scan completed\n");
|
||||
cfg_priv->sched_escan = false;
|
||||
if (!aborted)
|
||||
cfg80211_sched_scan_results(cfg_to_wiphy(cfg_priv));
|
||||
brcmf_set_mpc(ndev, 1);
|
||||
} else if (scan_request) {
|
||||
WL_SCAN("ESCAN Completed scan: %s\n",
|
||||
aborted ? "Aborted" : "Done");
|
||||
cfg80211_scan_done(scan_request, aborted);
|
||||
|
@ -2593,11 +2613,13 @@ update_bss_info_out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv)
|
||||
static void brcmf_abort_scanning(struct brcmf_cfg80211_priv *cfg_priv)
|
||||
{
|
||||
struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
|
||||
struct escan_info *escan = &cfg_priv->escan_info;
|
||||
struct brcmf_ssid ssid;
|
||||
|
||||
set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
|
||||
if (cfg_priv->iscan_on) {
|
||||
iscan->state = WL_ISCAN_STATE_IDLE;
|
||||
|
||||
|
@ -2611,8 +2633,21 @@ static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv)
|
|||
/* Abort iscan running in FW */
|
||||
memset(&ssid, 0, sizeof(ssid));
|
||||
brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT);
|
||||
|
||||
if (cfg_priv->scan_request) {
|
||||
/* Indidate scan abort to cfg80211 layer */
|
||||
WL_INFO("Terminating scan in progress\n");
|
||||
cfg80211_scan_done(cfg_priv->scan_request, true);
|
||||
cfg_priv->scan_request = NULL;
|
||||
}
|
||||
}
|
||||
if (cfg_priv->escan_on && cfg_priv->scan_request) {
|
||||
escan->escan_state = WL_ESCAN_STATE_IDLE;
|
||||
brcmf_notify_escan_complete(cfg_priv, escan->ndev, true, true);
|
||||
}
|
||||
clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
|
||||
clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
|
||||
}
|
||||
|
||||
static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
|
||||
bool aborted)
|
||||
|
@ -2842,10 +2877,13 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
|
|||
!memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
|
||||
if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
|
||||
(bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
|
||||
s16 bss_rssi = le16_to_cpu(bss->RSSI);
|
||||
s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
|
||||
|
||||
/* preserve max RSSI if the measurements are
|
||||
* both on-channel or both off-channel
|
||||
*/
|
||||
if (bss_info_le->RSSI > bss->RSSI)
|
||||
if (bss_info_rssi > bss_rssi)
|
||||
bss->RSSI = bss_info_le->RSSI;
|
||||
} else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
|
||||
(bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
|
||||
|
@ -2873,6 +2911,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv,
|
|||
u32 bi_length;
|
||||
struct brcmf_scan_results *list;
|
||||
u32 i;
|
||||
bool aborted;
|
||||
|
||||
status = be32_to_cpu(e->status);
|
||||
|
||||
|
@ -2945,16 +2984,9 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv,
|
|||
cfg_priv->bss_list = (struct brcmf_scan_results *)
|
||||
cfg_priv->escan_info.escan_buf;
|
||||
brcmf_inform_bss(cfg_priv);
|
||||
if (status == BRCMF_E_STATUS_SUCCESS) {
|
||||
WL_SCAN("ESCAN Completed\n");
|
||||
brcmf_notify_escan_complete(cfg_priv, ndev,
|
||||
false, false);
|
||||
} else {
|
||||
WL_ERR("ESCAN Aborted, Event 0x%x\n", status);
|
||||
brcmf_notify_escan_complete(cfg_priv, ndev,
|
||||
true, false);
|
||||
}
|
||||
brcmf_set_mpc(ndev, 1);
|
||||
aborted = status != BRCMF_E_STATUS_SUCCESS;
|
||||
brcmf_notify_escan_complete(cfg_priv, ndev, aborted,
|
||||
false);
|
||||
} else
|
||||
WL_ERR("Unexpected scan result 0x%x\n", status);
|
||||
}
|
||||
|
@ -3039,18 +3071,10 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
|
|||
brcmf_delay(500);
|
||||
}
|
||||
|
||||
set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
|
||||
if (test_bit(WL_STATUS_READY, &cfg_priv->status))
|
||||
brcmf_term_iscan(cfg_priv);
|
||||
|
||||
if (cfg_priv->scan_request) {
|
||||
/* Indidate scan abort to cfg80211 layer */
|
||||
WL_INFO("Terminating scan in progress\n");
|
||||
cfg80211_scan_done(cfg_priv->scan_request, true);
|
||||
cfg_priv->scan_request = NULL;
|
||||
}
|
||||
brcmf_abort_scanning(cfg_priv);
|
||||
else
|
||||
clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
|
||||
clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
|
||||
|
||||
/* Turn off watchdog timer */
|
||||
if (test_bit(WL_STATUS_READY, &cfg_priv->status))
|
||||
|
@ -3229,6 +3253,269 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* PFN result doesn't have all the info which are
|
||||
* required by the supplicant
|
||||
* (For e.g IEs) Do a target Escan so that sched scan results are reported
|
||||
* via wl_inform_single_bss in the required format. Escan does require the
|
||||
* scan request in the form of cfg80211_scan_request. For timebeing, create
|
||||
* cfg80211_scan_request one out of the received PNO event.
|
||||
*/
|
||||
static s32
|
||||
brcmf_notify_sched_scan_results(struct brcmf_cfg80211_priv *cfg_priv,
|
||||
struct net_device *ndev,
|
||||
const struct brcmf_event_msg *e, void *data)
|
||||
{
|
||||
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
|
||||
struct cfg80211_scan_request *request = NULL;
|
||||
struct cfg80211_ssid *ssid = NULL;
|
||||
struct ieee80211_channel *channel = NULL;
|
||||
struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
|
||||
int err = 0;
|
||||
int channel_req = 0;
|
||||
int band = 0;
|
||||
struct brcmf_pno_scanresults_le *pfn_result;
|
||||
u32 result_count;
|
||||
u32 status;
|
||||
|
||||
WL_SCAN("Enter\n");
|
||||
|
||||
if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) {
|
||||
WL_SCAN("PFN NET LOST event. Do Nothing\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pfn_result = (struct brcmf_pno_scanresults_le *)data;
|
||||
result_count = le32_to_cpu(pfn_result->count);
|
||||
status = le32_to_cpu(pfn_result->status);
|
||||
|
||||
/*
|
||||
* PFN event is limited to fit 512 bytes so we may get
|
||||
* multiple NET_FOUND events. For now place a warning here.
|
||||
*/
|
||||
WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
|
||||
WL_SCAN("PFN NET FOUND event. count: %d\n", result_count);
|
||||
if (result_count > 0) {
|
||||
int i;
|
||||
|
||||
request = kzalloc(sizeof(*request), GFP_KERNEL);
|
||||
ssid = kzalloc(sizeof(*ssid) * result_count, GFP_KERNEL);
|
||||
channel = kzalloc(sizeof(*channel) * result_count, GFP_KERNEL);
|
||||
if (!request || !ssid || !channel) {
|
||||
err = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
request->wiphy = wiphy;
|
||||
data += sizeof(struct brcmf_pno_scanresults_le);
|
||||
netinfo_start = (struct brcmf_pno_net_info_le *)data;
|
||||
|
||||
for (i = 0; i < result_count; i++) {
|
||||
netinfo = &netinfo_start[i];
|
||||
if (!netinfo) {
|
||||
WL_ERR("Invalid netinfo ptr. index: %d\n", i);
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
WL_SCAN("SSID:%s Channel:%d\n",
|
||||
netinfo->SSID, netinfo->channel);
|
||||
memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
|
||||
ssid[i].ssid_len = netinfo->SSID_len;
|
||||
request->n_ssids++;
|
||||
|
||||
channel_req = netinfo->channel;
|
||||
if (channel_req <= CH_MAX_2G_CHANNEL)
|
||||
band = NL80211_BAND_2GHZ;
|
||||
else
|
||||
band = NL80211_BAND_5GHZ;
|
||||
channel[i].center_freq =
|
||||
ieee80211_channel_to_frequency(channel_req,
|
||||
band);
|
||||
channel[i].band = band;
|
||||
channel[i].flags |= IEEE80211_CHAN_NO_HT40;
|
||||
request->channels[i] = &channel[i];
|
||||
request->n_channels++;
|
||||
}
|
||||
|
||||
/* assign parsed ssid array */
|
||||
if (request->n_ssids)
|
||||
request->ssids = &ssid[0];
|
||||
|
||||
if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
|
||||
/* Abort any on-going scan */
|
||||
brcmf_abort_scanning(cfg_priv);
|
||||
}
|
||||
|
||||
set_bit(WL_STATUS_SCANNING, &cfg_priv->status);
|
||||
err = brcmf_do_escan(cfg_priv, wiphy, ndev, request);
|
||||
if (err) {
|
||||
clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
|
||||
goto out_err;
|
||||
}
|
||||
cfg_priv->sched_escan = true;
|
||||
cfg_priv->scan_request = request;
|
||||
} else {
|
||||
WL_ERR("FALSE PNO Event. (pfn_count == 0)\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
kfree(ssid);
|
||||
kfree(channel);
|
||||
kfree(request);
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
kfree(ssid);
|
||||
kfree(channel);
|
||||
kfree(request);
|
||||
cfg80211_sched_scan_stopped(wiphy);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_BRCMISCAN
|
||||
static int brcmf_dev_pno_clean(struct net_device *ndev)
|
||||
{
|
||||
char iovbuf[128];
|
||||
int ret;
|
||||
|
||||
/* Disable pfn */
|
||||
ret = brcmf_dev_intvar_set(ndev, "pfn", 0);
|
||||
if (ret == 0) {
|
||||
/* clear pfn */
|
||||
ret = brcmf_dev_iovar_setbuf(ndev, "pfnclear", NULL, 0,
|
||||
iovbuf, sizeof(iovbuf));
|
||||
}
|
||||
if (ret < 0)
|
||||
WL_ERR("failed code %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int brcmf_dev_pno_config(struct net_device *ndev)
|
||||
{
|
||||
struct brcmf_pno_param_le pfn_param;
|
||||
char iovbuf[128];
|
||||
|
||||
memset(&pfn_param, 0, sizeof(pfn_param));
|
||||
pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
|
||||
|
||||
/* set extra pno params */
|
||||
pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
|
||||
pfn_param.repeat = BRCMF_PNO_REPEAT;
|
||||
pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
|
||||
|
||||
/* set up pno scan fr */
|
||||
pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
|
||||
|
||||
return brcmf_dev_iovar_setbuf(ndev, "pfn_set",
|
||||
&pfn_param, sizeof(pfn_param),
|
||||
iovbuf, sizeof(iovbuf));
|
||||
}
|
||||
|
||||
static int
|
||||
brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
struct cfg80211_sched_scan_request *request)
|
||||
{
|
||||
char iovbuf[128];
|
||||
struct brcmf_cfg80211_priv *cfg_priv = wiphy_priv(wiphy);
|
||||
struct brcmf_pno_net_param_le pfn;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n",
|
||||
request->n_match_sets, request->n_ssids);
|
||||
if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
|
||||
WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (!request || !request->n_ssids || !request->n_match_sets) {
|
||||
WL_ERR("Invalid sched scan req!! n_ssids:%d\n",
|
||||
request->n_ssids);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (request->n_ssids > 0) {
|
||||
for (i = 0; i < request->n_ssids; i++) {
|
||||
/* Active scan req for ssids */
|
||||
WL_SCAN(">>> Active scan req for ssid (%s)\n",
|
||||
request->ssids[i].ssid);
|
||||
|
||||
/*
|
||||
* match_set ssids is a supert set of n_ssid list,
|
||||
* so we need not add these set seperately.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (request->n_match_sets > 0) {
|
||||
/* clean up everything */
|
||||
ret = brcmf_dev_pno_clean(ndev);
|
||||
if (ret < 0) {
|
||||
WL_ERR("failed error=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* configure pno */
|
||||
ret = brcmf_dev_pno_config(ndev);
|
||||
if (ret < 0) {
|
||||
WL_ERR("PNO setup failed!! ret=%d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* configure each match set */
|
||||
for (i = 0; i < request->n_match_sets; i++) {
|
||||
struct cfg80211_ssid *ssid;
|
||||
u32 ssid_len;
|
||||
|
||||
ssid = &request->match_sets[i].ssid;
|
||||
ssid_len = ssid->ssid_len;
|
||||
|
||||
if (!ssid_len) {
|
||||
WL_ERR("skip broadcast ssid\n");
|
||||
continue;
|
||||
}
|
||||
pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
|
||||
pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
|
||||
pfn.wsec = cpu_to_le32(0);
|
||||
pfn.infra = cpu_to_le32(1);
|
||||
pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
|
||||
pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
|
||||
memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
|
||||
ret = brcmf_dev_iovar_setbuf(ndev, "pfn_add",
|
||||
&pfn, sizeof(pfn),
|
||||
iovbuf, sizeof(iovbuf));
|
||||
WL_SCAN(">>> PNO filter %s for ssid (%s)\n",
|
||||
ret == 0 ? "set" : "failed",
|
||||
ssid->ssid);
|
||||
}
|
||||
/* Enable the PNO */
|
||||
if (brcmf_dev_intvar_set(ndev, "pfn", 1) < 0) {
|
||||
WL_ERR("PNO enable failed!! ret=%d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
|
||||
struct net_device *ndev)
|
||||
{
|
||||
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
|
||||
|
||||
WL_SCAN("enter\n");
|
||||
brcmf_dev_pno_clean(ndev);
|
||||
if (cfg_priv->sched_escan)
|
||||
brcmf_notify_escan_complete(cfg_priv, ndev, true, true);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BRCMISCAN */
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
|
||||
{
|
||||
|
@ -3271,6 +3558,11 @@ static struct cfg80211_ops wl_cfg80211_ops = {
|
|||
.set_pmksa = brcmf_cfg80211_set_pmksa,
|
||||
.del_pmksa = brcmf_cfg80211_del_pmksa,
|
||||
.flush_pmksa = brcmf_cfg80211_flush_pmksa,
|
||||
#ifndef CONFIG_BRCMISCAN
|
||||
/* scheduled scan need e-scan, which is mutual exclusive with i-scan */
|
||||
.sched_scan_start = brcmf_cfg80211_sched_scan_start,
|
||||
.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
|
||||
#endif
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
.testmode_cmd = brcmf_cfg80211_testmode
|
||||
#endif
|
||||
|
@ -3292,6 +3584,17 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
|
||||
{
|
||||
#ifndef CONFIG_BRCMFISCAN
|
||||
/* scheduled scan settings */
|
||||
wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
|
||||
wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
|
||||
wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
|
||||
wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface,
|
||||
struct device *ndev)
|
||||
{
|
||||
|
@ -3330,6 +3633,7 @@ static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface,
|
|||
* save mode
|
||||
* by default
|
||||
*/
|
||||
brcmf_wiphy_pno_params(wdev->wiphy);
|
||||
err = wiphy_register(wdev->wiphy);
|
||||
if (err < 0) {
|
||||
WL_ERR("Could not register wiphy device (%d)\n", err);
|
||||
|
@ -3732,6 +4036,7 @@ static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
|
|||
el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status;
|
||||
el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status;
|
||||
el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
|
||||
el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results;
|
||||
}
|
||||
|
||||
static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
|
||||
|
@ -3957,13 +4262,13 @@ static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv)
|
|||
cfg_priv->dongle_up = false; /* dongle down */
|
||||
brcmf_flush_eq(cfg_priv);
|
||||
brcmf_link_down(cfg_priv);
|
||||
brcmf_term_iscan(cfg_priv);
|
||||
brcmf_abort_scanning(cfg_priv);
|
||||
brcmf_deinit_priv_mem(cfg_priv);
|
||||
}
|
||||
|
||||
struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
|
||||
struct device *busdev,
|
||||
void *data)
|
||||
struct brcmf_pub *drvr)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
struct brcmf_cfg80211_priv *cfg_priv;
|
||||
|
@ -3988,7 +4293,7 @@ struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
|
|||
wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS);
|
||||
cfg_priv = wdev_to_cfg(wdev);
|
||||
cfg_priv->wdev = wdev;
|
||||
cfg_priv->pub = data;
|
||||
cfg_priv->pub = drvr;
|
||||
ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci;
|
||||
ci->cfg_priv = cfg_priv;
|
||||
ndev->ieee80211_ptr = wdev;
|
||||
|
@ -4103,6 +4408,7 @@ static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
|
|||
setbit(eventmask, BRCMF_E_JOIN_START);
|
||||
setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
|
||||
setbit(eventmask, BRCMF_E_ESCAN_RESULT);
|
||||
setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
|
||||
|
||||
brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
|
||||
iovbuf, sizeof(iovbuf));
|
||||
|
@ -4235,7 +4541,7 @@ static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv)
|
|||
return err;
|
||||
}
|
||||
|
||||
phy = ((char *)&phy_list)[1];
|
||||
phy = ((char *)&phy_list)[0];
|
||||
WL_INFO("%c phy\n", phy);
|
||||
if (phy == 'n' || phy == 'a') {
|
||||
wiphy = cfg_to_wiphy(cfg_priv);
|
||||
|
@ -4368,17 +4674,8 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv)
|
|||
brcmf_delay(500);
|
||||
}
|
||||
|
||||
set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
|
||||
brcmf_term_iscan(cfg_priv);
|
||||
if (cfg_priv->scan_request) {
|
||||
cfg80211_scan_done(cfg_priv->scan_request, true);
|
||||
/* May need to perform this to cover rmmod */
|
||||
/* wl_set_mpc(cfg_to_ndev(wl), 1); */
|
||||
cfg_priv->scan_request = NULL;
|
||||
}
|
||||
brcmf_abort_scanning(cfg_priv);
|
||||
clear_bit(WL_STATUS_READY, &cfg_priv->status);
|
||||
clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
|
||||
clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
|
||||
|
||||
brcmf_debugfs_remove_netdev(cfg_priv);
|
||||
|
||||
|
@ -4411,20 +4708,3 @@ s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
|
||||
u8 t, u8 l, u8 *v)
|
||||
{
|
||||
struct brcmf_cfg80211_ie *ie = &cfg_priv->ie;
|
||||
s32 err = 0;
|
||||
|
||||
if (ie->offset + l + 2 > WL_TLV_INFO_MAX) {
|
||||
WL_ERR("ei crosses buffer boundary\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
ie->buf[ie->offset] = t;
|
||||
ie->buf[ie->offset + 1] = l;
|
||||
memcpy(&ie->buf[ie->offset + 2], v, l);
|
||||
ie->offset += l + 2;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -295,50 +295,168 @@ struct escan_info {
|
|||
struct net_device *ndev;
|
||||
};
|
||||
|
||||
/* dongle private data of cfg80211 interface */
|
||||
/**
|
||||
* struct brcmf_pno_param_le - PNO scan configuration parameters
|
||||
*
|
||||
* @version: PNO parameters version.
|
||||
* @scan_freq: scan frequency.
|
||||
* @lost_network_timeout: #sec. to declare discovered network as lost.
|
||||
* @flags: Bit field to control features of PFN such as sort criteria auto
|
||||
* enable switch and background scan.
|
||||
* @rssi_margin: Margin to avoid jitter for choosing a PFN based on RSSI sort
|
||||
* criteria.
|
||||
* @bestn: number of best networks in each scan.
|
||||
* @mscan: number of scans recorded.
|
||||
* @repeat: minimum number of scan intervals before scan frequency changes
|
||||
* in adaptive scan.
|
||||
* @exp: exponent of 2 for maximum scan interval.
|
||||
* @slow_freq: slow scan period.
|
||||
*/
|
||||
struct brcmf_pno_param_le {
|
||||
__le32 version;
|
||||
__le32 scan_freq;
|
||||
__le32 lost_network_timeout;
|
||||
__le16 flags;
|
||||
__le16 rssi_margin;
|
||||
u8 bestn;
|
||||
u8 mscan;
|
||||
u8 repeat;
|
||||
u8 exp;
|
||||
__le32 slow_freq;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_pno_net_param_le - scan parameters per preferred network.
|
||||
*
|
||||
* @ssid: ssid name and its length.
|
||||
* @flags: bit2: hidden.
|
||||
* @infra: BSS vs IBSS.
|
||||
* @auth: Open vs Closed.
|
||||
* @wpa_auth: WPA type.
|
||||
* @wsec: wsec value.
|
||||
*/
|
||||
struct brcmf_pno_net_param_le {
|
||||
struct brcmf_ssid_le ssid;
|
||||
__le32 flags;
|
||||
__le32 infra;
|
||||
__le32 auth;
|
||||
__le32 wpa_auth;
|
||||
__le32 wsec;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_pno_net_info_le - information per found network.
|
||||
*
|
||||
* @bssid: BSS network identifier.
|
||||
* @channel: channel number only.
|
||||
* @SSID_len: length of ssid.
|
||||
* @SSID: ssid characters.
|
||||
* @RSSI: receive signal strength (in dBm).
|
||||
* @timestamp: age in seconds.
|
||||
*/
|
||||
struct brcmf_pno_net_info_le {
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 channel;
|
||||
u8 SSID_len;
|
||||
u8 SSID[32];
|
||||
__le16 RSSI;
|
||||
__le16 timestamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_pno_scanresults_le - result returned in PNO NET FOUND event.
|
||||
*
|
||||
* @version: PNO version identifier.
|
||||
* @status: indicates completion status of PNO scan.
|
||||
* @count: amount of brcmf_pno_net_info_le entries appended.
|
||||
*/
|
||||
struct brcmf_pno_scanresults_le {
|
||||
__le32 version;
|
||||
__le32 status;
|
||||
__le32 count;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_cfg80211_priv - dongle private data of cfg80211 interface
|
||||
*
|
||||
* @wdev: representing wl cfg80211 device.
|
||||
* @conf: dongle configuration.
|
||||
* @scan_request: cfg80211 scan request object.
|
||||
* @el: main event loop.
|
||||
* @evt_q_list: used for event queue.
|
||||
* @evt_q_lock: for event queue synchronization.
|
||||
* @usr_sync: mainly for dongle up/down synchronization.
|
||||
* @bss_list: bss_list holding scanned ap information.
|
||||
* @scan_results: results of the last scan.
|
||||
* @scan_req_int: internal scan request object.
|
||||
* @bss_info: bss information for cfg80211 layer.
|
||||
* @ie: information element object for internal purpose.
|
||||
* @profile: holding dongle profile.
|
||||
* @iscan: iscan controller information.
|
||||
* @conn_info: association info.
|
||||
* @pmk_list: wpa2 pmk list.
|
||||
* @event_work: event handler work struct.
|
||||
* @status: current dongle status.
|
||||
* @pub: common driver information.
|
||||
* @channel: current channel.
|
||||
* @iscan_on: iscan on/off switch.
|
||||
* @iscan_kickstart: indicate iscan already started.
|
||||
* @active_scan: current scan mode.
|
||||
* @sched_escan: e-scan for scheduled scan support running.
|
||||
* @ibss_starter: indicates this sta is ibss starter.
|
||||
* @link_up: link/connection up flag.
|
||||
* @pwr_save: indicate whether dongle to support power save mode.
|
||||
* @dongle_up: indicate whether dongle up or not.
|
||||
* @roam_on: on/off switch for dongle self-roaming.
|
||||
* @scan_tried: indicates if first scan attempted.
|
||||
* @dcmd_buf: dcmd buffer.
|
||||
* @extra_buf: mainly to grab assoc information.
|
||||
* @debugfsdir: debugfs folder for this device.
|
||||
* @escan_on: escan on/off switch.
|
||||
* @escan_info: escan information.
|
||||
* @escan_timeout: Timer for catch scan timeout.
|
||||
* @escan_timeout_work: scan timeout worker.
|
||||
* @escan_ioctl_buf: dongle command buffer for escan commands.
|
||||
* @ci: used to link this structure to netdev private data.
|
||||
*/
|
||||
struct brcmf_cfg80211_priv {
|
||||
struct wireless_dev *wdev; /* representing wl cfg80211 device */
|
||||
struct brcmf_cfg80211_conf *conf; /* dongle configuration */
|
||||
struct cfg80211_scan_request *scan_request; /* scan request
|
||||
object */
|
||||
struct brcmf_cfg80211_event_loop el; /* main event loop */
|
||||
struct list_head evt_q_list; /* used for event queue */
|
||||
spinlock_t evt_q_lock; /* for event queue synchronization */
|
||||
struct mutex usr_sync; /* maily for dongle up/down synchronization */
|
||||
struct brcmf_scan_results *bss_list; /* bss_list holding scanned
|
||||
ap information */
|
||||
struct wireless_dev *wdev;
|
||||
struct brcmf_cfg80211_conf *conf;
|
||||
struct cfg80211_scan_request *scan_request;
|
||||
struct brcmf_cfg80211_event_loop el;
|
||||
struct list_head evt_q_list;
|
||||
spinlock_t evt_q_lock;
|
||||
struct mutex usr_sync;
|
||||
struct brcmf_scan_results *bss_list;
|
||||
struct brcmf_scan_results *scan_results;
|
||||
struct brcmf_cfg80211_scan_req *scan_req_int; /* scan request object
|
||||
for internal purpose */
|
||||
struct wl_cfg80211_bss_info *bss_info; /* bss information for
|
||||
cfg80211 layer */
|
||||
struct brcmf_cfg80211_ie ie; /* information element object for
|
||||
internal purpose */
|
||||
struct brcmf_cfg80211_profile *profile; /* holding dongle profile */
|
||||
struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */
|
||||
struct brcmf_cfg80211_connect_info conn_info; /* association info */
|
||||
struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */
|
||||
struct work_struct event_work; /* event handler work struct */
|
||||
unsigned long status; /* current dongle status */
|
||||
void *pub;
|
||||
u32 channel; /* current channel */
|
||||
bool iscan_on; /* iscan on/off switch */
|
||||
bool iscan_kickstart; /* indicate iscan already started */
|
||||
bool active_scan; /* current scan mode */
|
||||
bool ibss_starter; /* indicates this sta is ibss starter */
|
||||
bool link_up; /* link/connection up flag */
|
||||
bool pwr_save; /* indicate whether dongle to support
|
||||
power save mode */
|
||||
bool dongle_up; /* indicate whether dongle up or not */
|
||||
bool roam_on; /* on/off switch for dongle self-roaming */
|
||||
bool scan_tried; /* indicates if first scan attempted */
|
||||
u8 *dcmd_buf; /* dcmd buffer */
|
||||
u8 *extra_buf; /* maily to grab assoc information */
|
||||
struct brcmf_cfg80211_scan_req *scan_req_int;
|
||||
struct wl_cfg80211_bss_info *bss_info;
|
||||
struct brcmf_cfg80211_ie ie;
|
||||
struct brcmf_cfg80211_profile *profile;
|
||||
struct brcmf_cfg80211_iscan_ctrl *iscan;
|
||||
struct brcmf_cfg80211_connect_info conn_info;
|
||||
struct brcmf_cfg80211_pmk_list *pmk_list;
|
||||
struct work_struct event_work;
|
||||
unsigned long status;
|
||||
struct brcmf_pub *pub;
|
||||
u32 channel;
|
||||
bool iscan_on;
|
||||
bool iscan_kickstart;
|
||||
bool active_scan;
|
||||
bool sched_escan;
|
||||
bool ibss_starter;
|
||||
bool link_up;
|
||||
bool pwr_save;
|
||||
bool dongle_up;
|
||||
bool roam_on;
|
||||
bool scan_tried;
|
||||
u8 *dcmd_buf;
|
||||
u8 *extra_buf;
|
||||
struct dentry *debugfsdir;
|
||||
bool escan_on; /* escan on/off switch */
|
||||
struct escan_info escan_info; /* escan information */
|
||||
struct timer_list escan_timeout; /* Timer for catch scan timeout */
|
||||
struct work_struct escan_timeout_work; /* scan timeout worker */
|
||||
bool escan_on;
|
||||
struct escan_info escan_info;
|
||||
struct timer_list escan_timeout;
|
||||
struct work_struct escan_timeout_work;
|
||||
u8 *escan_ioctl_buf;
|
||||
u8 ci[0] __aligned(NETDEV_ALIGN);
|
||||
};
|
||||
|
@ -379,7 +497,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg)
|
|||
|
||||
extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
|
||||
struct device *busdev,
|
||||
void *data);
|
||||
struct brcmf_pub *drvr);
|
||||
extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg);
|
||||
|
||||
/* event handler from dongle */
|
||||
|
|
|
@ -304,7 +304,10 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
|
|||
wl->mute_tx = true;
|
||||
|
||||
if (!wl->pub->up)
|
||||
if (!blocked)
|
||||
err = brcms_up(wl);
|
||||
else
|
||||
err = -ERFKILL;
|
||||
else
|
||||
err = -ENODEV;
|
||||
spin_unlock_bh(&wl->lock);
|
||||
|
|
|
@ -675,7 +675,7 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
|
|||
}
|
||||
done:
|
||||
if (ieee->set_security)
|
||||
ieee->set_security(ieee->dev, &sec);
|
||||
ieee->set_security(dev, &sec);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1586,9 +1586,9 @@ il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame,
|
|||
return 0;
|
||||
|
||||
frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
|
||||
memcpy(frame->da, il_bcast_addr, ETH_ALEN);
|
||||
eth_broadcast_addr(frame->da);
|
||||
memcpy(frame->sa, ta, ETH_ALEN);
|
||||
memcpy(frame->bssid, il_bcast_addr, ETH_ALEN);
|
||||
eth_broadcast_addr(frame->bssid);
|
||||
frame->seq_ctrl = 0;
|
||||
|
||||
len += 24;
|
||||
|
|
|
@ -612,9 +612,9 @@ static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
|
|||
return 0;
|
||||
|
||||
frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
|
||||
memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
|
||||
eth_broadcast_addr(frame->da);
|
||||
memcpy(frame->sa, ta, ETH_ALEN);
|
||||
memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
|
||||
eth_broadcast_addr(frame->bssid);
|
||||
frame->seq_ctrl = 0;
|
||||
|
||||
len += 24;
|
||||
|
|
|
@ -128,10 +128,11 @@ int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
|||
struct iwl_device_cmd *cmd)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_addsta_cmd *addsta =
|
||||
(struct iwl_addsta_cmd *) cmd->payload;
|
||||
|
||||
return iwl_process_add_sta_resp(priv, addsta, pkt);
|
||||
if (!cmd)
|
||||
return 0;
|
||||
|
||||
return iwl_process_add_sta_resp(priv, (void *)cmd->payload, pkt);
|
||||
}
|
||||
|
||||
int iwl_send_add_sta(struct iwl_priv *priv,
|
||||
|
|
|
@ -295,7 +295,7 @@ static int iwl_alive_notify(struct iwl_priv *priv)
|
|||
static int iwl_verify_sec_sparse(struct iwl_priv *priv,
|
||||
const struct fw_desc *fw_desc)
|
||||
{
|
||||
__le32 *image = (__le32 *)fw_desc->v_addr;
|
||||
__le32 *image = (__le32 *)fw_desc->data;
|
||||
u32 len = fw_desc->len;
|
||||
u32 val;
|
||||
u32 i;
|
||||
|
@ -319,7 +319,7 @@ static int iwl_verify_sec_sparse(struct iwl_priv *priv,
|
|||
static void iwl_print_mismatch_sec(struct iwl_priv *priv,
|
||||
const struct fw_desc *fw_desc)
|
||||
{
|
||||
__le32 *image = (__le32 *)fw_desc->v_addr;
|
||||
__le32 *image = (__le32 *)fw_desc->data;
|
||||
u32 len = fw_desc->len;
|
||||
u32 val;
|
||||
u32 offs;
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-debug.h"
|
||||
|
@ -164,10 +165,8 @@ struct fw_sec {
|
|||
|
||||
static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc)
|
||||
{
|
||||
if (desc->v_addr)
|
||||
dma_free_coherent(drv->trans->dev, desc->len,
|
||||
desc->v_addr, desc->p_addr);
|
||||
desc->v_addr = NULL;
|
||||
vfree(desc->data);
|
||||
desc->data = NULL;
|
||||
desc->len = 0;
|
||||
}
|
||||
|
||||
|
@ -188,19 +187,22 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
|
|||
static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
|
||||
struct fw_sec *sec)
|
||||
{
|
||||
if (!sec || !sec->size) {
|
||||
desc->v_addr = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
void *data;
|
||||
|
||||
desc->v_addr = dma_alloc_coherent(drv->trans->dev, sec->size,
|
||||
&desc->p_addr, GFP_KERNEL);
|
||||
if (!desc->v_addr)
|
||||
desc->data = NULL;
|
||||
|
||||
if (!sec || !sec->size)
|
||||
return -EINVAL;
|
||||
|
||||
data = vmalloc(sec->size);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
desc->len = sec->size;
|
||||
desc->offset = sec->offset;
|
||||
memcpy(desc->v_addr, sec->data, sec->size);
|
||||
memcpy(data, sec->data, desc->len);
|
||||
desc->data = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -124,8 +124,7 @@ struct iwl_ucode_capabilities {
|
|||
|
||||
/* one for each uCode image (inst/data, init/runtime/wowlan) */
|
||||
struct fw_desc {
|
||||
dma_addr_t p_addr; /* hardware address */
|
||||
void *v_addr; /* software address */
|
||||
const void *data; /* vmalloc'ed data */
|
||||
u32 len; /* size in bytes */
|
||||
u32 offset; /* offset in the device */
|
||||
};
|
||||
|
|
|
@ -263,8 +263,6 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
|
|||
/* PCI registers */
|
||||
#define PCI_CFG_RETRY_TIMEOUT 0x041
|
||||
|
||||
#ifndef CONFIG_IWLWIFI_IDI
|
||||
|
||||
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
|
||||
|
@ -307,8 +305,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
|
|||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IWLWIFI_IDI */
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int iwl_pci_suspend(struct device *device)
|
||||
|
@ -353,15 +349,6 @@ static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_IDI
|
||||
/*
|
||||
* Defined externally in iwl-idi.c
|
||||
*/
|
||||
int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
|
||||
void __devexit iwl_pci_remove(struct pci_dev *pdev);
|
||||
|
||||
#endif /* CONFIG_IWLWIFI_IDI */
|
||||
|
||||
static struct pci_driver iwl_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = iwl_hw_card_ids,
|
||||
|
|
|
@ -311,7 +311,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
|
|||
******************************************************/
|
||||
void iwl_bg_rx_replenish(struct work_struct *data);
|
||||
void iwl_irq_tasklet(struct iwl_trans *trans);
|
||||
void iwlagn_rx_replenish(struct iwl_trans *trans);
|
||||
void iwl_rx_replenish(struct iwl_trans *trans);
|
||||
void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
|
||||
struct iwl_rx_queue *q);
|
||||
|
||||
|
|
|
@ -35,10 +35,6 @@
|
|||
#include "internal.h"
|
||||
#include "iwl-op-mode.h"
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_IDI
|
||||
#include "iwl-amfh.h"
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* RX path functions
|
||||
|
@ -181,15 +177,15 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
|
|||
}
|
||||
|
||||
/**
|
||||
* iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
|
||||
* iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
|
||||
*/
|
||||
static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
|
||||
static inline __le32 iwl_dma_addr2rbd_ptr(dma_addr_t dma_addr)
|
||||
{
|
||||
return cpu_to_le32((u32)(dma_addr >> 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
|
||||
* iwl_rx_queue_restock - refill RX queue from pre-allocated pool
|
||||
*
|
||||
* If there are slots in the RX queue that need to be restocked,
|
||||
* and we have free pre-allocated buffers, fill the ranks as much
|
||||
|
@ -199,7 +195,7 @@ static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
|
|||
* also updates the memory address in the firmware to reference the new
|
||||
* target buffer.
|
||||
*/
|
||||
static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
|
||||
static void iwl_rx_queue_restock(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
|
@ -207,6 +203,17 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
|
|||
struct iwl_rx_mem_buffer *rxb;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* If the device isn't enabled - not need to try to add buffers...
|
||||
* This can happen when we stop the device and still have an interrupt
|
||||
* pending. We stop the APM before we sync the interrupts / tasklets
|
||||
* because we have to (see comment there). On the other hand, since
|
||||
* the APM is stopped, we cannot access the HW (in particular not prph).
|
||||
* So don't try to restock if the APM has been already stopped.
|
||||
*/
|
||||
if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&rxq->lock, flags);
|
||||
while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
|
||||
/* The overwritten rxb must be a used one */
|
||||
|
@ -219,7 +226,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
|
|||
list_del(element);
|
||||
|
||||
/* Point to Rx buffer via next RBD in circular buffer */
|
||||
rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma);
|
||||
rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(rxb->page_dma);
|
||||
rxq->queue[rxq->write] = rxb;
|
||||
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
|
||||
rxq->free_count--;
|
||||
|
@ -230,7 +237,6 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
|
|||
if (rxq->free_count <= RX_LOW_WATERMARK)
|
||||
schedule_work(&trans_pcie->rx_replenish);
|
||||
|
||||
|
||||
/* If we've added more space for the firmware to place data, tell it.
|
||||
* Increment device's write pointer in multiples of 8. */
|
||||
if (rxq->write_actual != (rxq->write & ~0x7)) {
|
||||
|
@ -241,15 +247,16 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
|
||||
/*
|
||||
* iwl_rx_allocate - allocate a page for each used RBD
|
||||
*
|
||||
* When moving to rx_free an SKB is allocated for the slot.
|
||||
*
|
||||
* Also restock the Rx queue via iwl_rx_queue_restock.
|
||||
* This is called as a scheduled work item (except for during initialization)
|
||||
* A used RBD is an Rx buffer that has been given to the stack. To use it again
|
||||
* a page must be allocated and the RBD must point to the page. This function
|
||||
* doesn't change the HW pointer but handles the list of pages that is used by
|
||||
* iwl_rx_queue_restock. The latter function will update the HW to use the newly
|
||||
* allocated buffers.
|
||||
*/
|
||||
static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
|
||||
static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
|
@ -328,23 +335,31 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
|
|||
}
|
||||
}
|
||||
|
||||
void iwlagn_rx_replenish(struct iwl_trans *trans)
|
||||
/*
|
||||
* iwl_rx_replenish - Move all used buffers from rx_used to rx_free
|
||||
*
|
||||
* When moving to rx_free an page is allocated for the slot.
|
||||
*
|
||||
* Also restock the Rx queue via iwl_rx_queue_restock.
|
||||
* This is called as a scheduled work item (except for during initialization)
|
||||
*/
|
||||
void iwl_rx_replenish(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
unsigned long flags;
|
||||
|
||||
iwlagn_rx_allocate(trans, GFP_KERNEL);
|
||||
iwl_rx_allocate(trans, GFP_KERNEL);
|
||||
|
||||
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
|
||||
iwlagn_rx_queue_restock(trans);
|
||||
iwl_rx_queue_restock(trans);
|
||||
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
|
||||
}
|
||||
|
||||
static void iwlagn_rx_replenish_now(struct iwl_trans *trans)
|
||||
static void iwl_rx_replenish_now(struct iwl_trans *trans)
|
||||
{
|
||||
iwlagn_rx_allocate(trans, GFP_ATOMIC);
|
||||
iwl_rx_allocate(trans, GFP_ATOMIC);
|
||||
|
||||
iwlagn_rx_queue_restock(trans);
|
||||
iwl_rx_queue_restock(trans);
|
||||
}
|
||||
|
||||
void iwl_bg_rx_replenish(struct work_struct *data)
|
||||
|
@ -352,7 +367,7 @@ void iwl_bg_rx_replenish(struct work_struct *data)
|
|||
struct iwl_trans_pcie *trans_pcie =
|
||||
container_of(data, struct iwl_trans_pcie, rx_replenish);
|
||||
|
||||
iwlagn_rx_replenish(trans_pcie->trans);
|
||||
iwl_rx_replenish(trans_pcie->trans);
|
||||
}
|
||||
|
||||
static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
|
||||
|
@ -530,7 +545,7 @@ static void iwl_rx_handle(struct iwl_trans *trans)
|
|||
count++;
|
||||
if (count >= 8) {
|
||||
rxq->read = i;
|
||||
iwlagn_rx_replenish_now(trans);
|
||||
iwl_rx_replenish_now(trans);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
@ -539,9 +554,9 @@ static void iwl_rx_handle(struct iwl_trans *trans)
|
|||
/* Backtrack one entry */
|
||||
rxq->read = i;
|
||||
if (fill_rx)
|
||||
iwlagn_rx_replenish_now(trans);
|
||||
iwl_rx_replenish_now(trans);
|
||||
else
|
||||
iwlagn_rx_queue_restock(trans);
|
||||
iwl_rx_queue_restock(trans);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -723,11 +738,9 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
|
|||
/* Disable periodic interrupt; we use it as just a one-shot. */
|
||||
iwl_write8(trans, CSR_INT_PERIODIC_REG,
|
||||
CSR_INT_PERIODIC_DIS);
|
||||
#ifdef CONFIG_IWLWIFI_IDI
|
||||
iwl_amfh_rx_handler();
|
||||
#else
|
||||
|
||||
iwl_rx_handle(trans);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable periodic interrupt in 8 msec only if we received
|
||||
* real RX interrupt (instead of just periodic int), to catch
|
||||
|
|
|
@ -216,7 +216,7 @@ static int iwl_rx_init(struct iwl_trans *trans)
|
|||
rxq->free_count = 0;
|
||||
spin_unlock_irqrestore(&rxq->lock, flags);
|
||||
|
||||
iwlagn_rx_replenish(trans);
|
||||
iwl_rx_replenish(trans);
|
||||
|
||||
iwl_trans_rx_hw_init(trans, rxq);
|
||||
|
||||
|
@ -855,10 +855,8 @@ static int iwl_nic_init(struct iwl_trans *trans)
|
|||
|
||||
iwl_op_mode_nic_config(trans->op_mode);
|
||||
|
||||
#ifndef CONFIG_IWLWIFI_IDI
|
||||
/* Allocate the RX queue, or reset if it is already allocated */
|
||||
iwl_rx_init(trans);
|
||||
#endif
|
||||
|
||||
/* Allocate or reset and init all Tx and Command queues */
|
||||
if (iwl_tx_init(trans))
|
||||
|
@ -925,13 +923,10 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
|
|||
/*
|
||||
* ucode
|
||||
*/
|
||||
static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
|
||||
const struct fw_desc *section)
|
||||
static int iwl_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr,
|
||||
dma_addr_t phy_addr, u32 byte_cnt)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
dma_addr_t phy_addr = section->p_addr;
|
||||
u32 byte_cnt = section->len;
|
||||
u32 dst_addr = section->offset;
|
||||
int ret;
|
||||
|
||||
trans_pcie->ucode_write_complete = false;
|
||||
|
@ -965,27 +960,58 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
|
|||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
|
||||
|
||||
IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
|
||||
section_num);
|
||||
ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
|
||||
trans_pcie->ucode_write_complete, 5 * HZ);
|
||||
if (!ret) {
|
||||
IWL_ERR(trans, "Could not load the [%d] uCode section\n",
|
||||
section_num);
|
||||
IWL_ERR(trans, "Failed to load firmware chunk!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
|
||||
const struct fw_desc *section)
|
||||
{
|
||||
u8 *v_addr;
|
||||
dma_addr_t p_addr;
|
||||
u32 offset;
|
||||
int ret = 0;
|
||||
|
||||
IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
|
||||
section_num);
|
||||
|
||||
v_addr = dma_alloc_coherent(trans->dev, PAGE_SIZE, &p_addr, GFP_KERNEL);
|
||||
if (!v_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
for (offset = 0; offset < section->len; offset += PAGE_SIZE) {
|
||||
u32 copy_size;
|
||||
|
||||
copy_size = min_t(u32, PAGE_SIZE, section->len - offset);
|
||||
|
||||
memcpy(v_addr, (u8 *)section->data + offset, copy_size);
|
||||
ret = iwl_load_firmware_chunk(trans, section->offset + offset,
|
||||
p_addr, copy_size);
|
||||
if (ret) {
|
||||
IWL_ERR(trans,
|
||||
"Could not load the [%d] uCode section\n",
|
||||
section_num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dma_free_coherent(trans->dev, PAGE_SIZE, v_addr, p_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_load_given_ucode(struct iwl_trans *trans,
|
||||
const struct fw_img *image)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
|
||||
if (!image->sec[i].p_addr)
|
||||
if (!image->sec[i].data)
|
||||
break;
|
||||
|
||||
ret = iwl_load_section(trans, i, &image->sec[i]);
|
||||
|
@ -1184,9 +1210,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
|
|||
*/
|
||||
if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
|
||||
iwl_trans_tx_stop(trans);
|
||||
#ifndef CONFIG_IWLWIFI_IDI
|
||||
iwl_trans_rx_stop(trans);
|
||||
#endif
|
||||
|
||||
/* Power-down device's busmaster DMA clocks */
|
||||
iwl_write_prph(trans, APMG_CLK_DIS_REG,
|
||||
APMG_CLK_VAL_DMA_CLK_RQT);
|
||||
|
@ -1457,14 +1482,16 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
|
|||
bool hw_rfkill;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
|
||||
iwl_disable_interrupts(trans);
|
||||
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
|
||||
|
||||
iwl_apm_stop(trans);
|
||||
|
||||
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
|
||||
iwl_disable_interrupts(trans);
|
||||
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
|
||||
|
||||
iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
|
||||
|
||||
if (!op_mode_leaving) {
|
||||
/*
|
||||
* Even if we stop the HW, we still want the RF kill
|
||||
|
@ -1552,9 +1579,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
|
|||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
iwl_trans_pcie_tx_free(trans);
|
||||
#ifndef CONFIG_IWLWIFI_IDI
|
||||
iwl_trans_pcie_rx_free(trans);
|
||||
#endif
|
||||
|
||||
if (trans_pcie->irq_requested == true) {
|
||||
free_irq(trans_pcie->irq, trans);
|
||||
iwl_free_isr_ict(trans);
|
||||
|
|
|
@ -2056,7 +2056,7 @@ failed:
|
|||
mac80211_hwsim_free();
|
||||
return err;
|
||||
}
|
||||
|
||||
module_init(init_mac80211_hwsim);
|
||||
|
||||
static void __exit exit_mac80211_hwsim(void)
|
||||
{
|
||||
|
@ -2067,7 +2067,4 @@ static void __exit exit_mac80211_hwsim(void)
|
|||
mac80211_hwsim_free();
|
||||
unregister_netdev(hwsim_mon);
|
||||
}
|
||||
|
||||
|
||||
module_init(init_mac80211_hwsim);
|
||||
module_exit(exit_mac80211_hwsim);
|
||||
|
|
|
@ -1502,6 +1502,12 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
|
|||
|
||||
wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
|
||||
|
||||
if (atomic_read(&priv->wmm.tx_pkts_queued) >=
|
||||
MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) {
|
||||
dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
priv->scan_request = request;
|
||||
|
||||
priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
|
||||
|
@ -1630,7 +1636,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
|
|||
* create a new virtual interface with the given name
|
||||
*/
|
||||
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
char *name,
|
||||
const char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
|
|
|
@ -160,7 +160,7 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
|
|||
u16 len;
|
||||
int ret;
|
||||
|
||||
ap_custom_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
|
||||
ap_custom_ie = kzalloc(sizeof(*ap_custom_ie), GFP_KERNEL);
|
||||
if (!ap_custom_ie)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ static void scan_delay_timer_fn(unsigned long data)
|
|||
|
||||
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
|
||||
true);
|
||||
queue_work(adapter->workqueue, &adapter->main_work);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -91,6 +91,8 @@ enum {
|
|||
#define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10
|
||||
#define MWIFIEX_SCAN_DELAY_MSEC 20
|
||||
|
||||
#define MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN 2
|
||||
|
||||
#define RSN_GTK_OUI_OFFSET 2
|
||||
|
||||
#define MWIFIEX_OUI_NOT_PRESENT 0
|
||||
|
@ -1031,7 +1033,7 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
|
|||
struct mwifiex_bssdescriptor *bss_desc);
|
||||
|
||||
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
char *name,
|
||||
const char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params);
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
#include "11n.h"
|
||||
#include "cfg80211.h"
|
||||
|
||||
static int disconnect_on_suspend = 1;
|
||||
module_param(disconnect_on_suspend, int, 0644);
|
||||
|
||||
/*
|
||||
* Copies the multicast address list from device to driver.
|
||||
*
|
||||
|
@ -448,6 +451,16 @@ EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
|
|||
int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct mwifiex_ds_hs_cfg hscfg;
|
||||
struct mwifiex_private *priv;
|
||||
int i;
|
||||
|
||||
if (disconnect_on_suspend) {
|
||||
for (i = 0; i < adapter->priv_num; i++) {
|
||||
priv = adapter->priv[i];
|
||||
if (priv)
|
||||
mwifiex_deauthenticate(priv, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (adapter->hs_activated) {
|
||||
dev_dbg(adapter->dev, "cmd: HS Already actived\n");
|
||||
|
|
|
@ -515,6 +515,17 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
|
|||
if (modparam_nohwcrypt)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
|
||||
/*
|
||||
* Unfortunately most/all firmwares are trying to decrypt
|
||||
* incoming management frames if a suitable key can be found.
|
||||
* However, in doing so the data in these frames gets
|
||||
* corrupted. So, we can't have firmware supported crypto
|
||||
* offload in this case.
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->conf_mutex);
|
||||
if (cmd == SET_KEY) {
|
||||
switch (key->cipher) {
|
||||
|
@ -738,6 +749,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
|
|||
IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_PS_NULLFUNC_STACK |
|
||||
IEEE80211_HW_MFP_CAPABLE |
|
||||
IEEE80211_HW_REPORTS_TX_ACK_STATUS;
|
||||
|
||||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
|
|
|
@ -1789,7 +1789,6 @@ static const struct data_queue_desc rt2400pci_queue_atim = {
|
|||
|
||||
static const struct rt2x00_ops rt2400pci_ops = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.max_sta_intf = 1,
|
||||
.max_ap_intf = 1,
|
||||
.eeprom_size = EEPROM_SIZE,
|
||||
.rf_size = RF_SIZE,
|
||||
|
|
|
@ -2081,7 +2081,6 @@ static const struct data_queue_desc rt2500pci_queue_atim = {
|
|||
|
||||
static const struct rt2x00_ops rt2500pci_ops = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.max_sta_intf = 1,
|
||||
.max_ap_intf = 1,
|
||||
.eeprom_size = EEPROM_SIZE,
|
||||
.rf_size = RF_SIZE,
|
||||
|
|
|
@ -1896,7 +1896,6 @@ static const struct data_queue_desc rt2500usb_queue_atim = {
|
|||
|
||||
static const struct rt2x00_ops rt2500usb_ops = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.max_sta_intf = 1,
|
||||
.max_ap_intf = 1,
|
||||
.eeprom_size = EEPROM_SIZE,
|
||||
.rf_size = RF_SIZE,
|
||||
|
|
|
@ -1763,36 +1763,15 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
|
|||
|
||||
rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
|
||||
if (rt2x00_rt(rt2x00dev, RT3390)) {
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD,
|
||||
rt2x00dev->default_ant.rx_chain_num == 1);
|
||||
rt2x00dev->default_ant.rx_chain_num <= 1);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD,
|
||||
rt2x00dev->default_ant.rx_chain_num <= 2);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD,
|
||||
rt2x00dev->default_ant.tx_chain_num == 1);
|
||||
} else {
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
|
||||
|
||||
switch (rt2x00dev->default_ant.tx_chain_num) {
|
||||
case 1:
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
|
||||
/* fall through */
|
||||
case 2:
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rt2x00dev->default_ant.rx_chain_num) {
|
||||
case 1:
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
|
||||
/* fall through */
|
||||
case 2:
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rt2x00dev->default_ant.tx_chain_num <= 1);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD,
|
||||
rt2x00dev->default_ant.tx_chain_num <= 2);
|
||||
rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
|
||||
|
||||
rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
|
||||
|
@ -2896,23 +2875,32 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats);
|
|||
|
||||
static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
u8 vgc;
|
||||
|
||||
if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
|
||||
if (rt2x00_rt(rt2x00dev, RT3070) ||
|
||||
rt2x00_rt(rt2x00dev, RT3071) ||
|
||||
rt2x00_rt(rt2x00dev, RT3090) ||
|
||||
rt2x00_rt(rt2x00dev, RT3290) ||
|
||||
rt2x00_rt(rt2x00dev, RT3390) ||
|
||||
rt2x00_rt(rt2x00dev, RT3572) ||
|
||||
rt2x00_rt(rt2x00dev, RT5390) ||
|
||||
rt2x00_rt(rt2x00dev, RT5392))
|
||||
return 0x1c + (2 * rt2x00dev->lna_gain);
|
||||
vgc = 0x1c + (2 * rt2x00dev->lna_gain);
|
||||
else
|
||||
return 0x2e + rt2x00dev->lna_gain;
|
||||
vgc = 0x2e + rt2x00dev->lna_gain;
|
||||
} else { /* 5GHZ band */
|
||||
if (rt2x00_rt(rt2x00dev, RT3572))
|
||||
vgc = 0x22 + (rt2x00dev->lna_gain * 5) / 3;
|
||||
else {
|
||||
if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
|
||||
vgc = 0x32 + (rt2x00dev->lna_gain * 5) / 3;
|
||||
else
|
||||
vgc = 0x3a + (rt2x00dev->lna_gain * 5) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
|
||||
return 0x32 + (rt2x00dev->lna_gain * 5) / 3;
|
||||
else
|
||||
return 0x3a + (rt2x00dev->lna_gain * 5) / 3;
|
||||
return vgc;
|
||||
}
|
||||
|
||||
static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev,
|
||||
|
@ -3526,6 +3514,11 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
|
|||
} else if (rt2800_is_305x_soc(rt2x00dev)) {
|
||||
rt2800_bbp_write(rt2x00dev, 78, 0x0e);
|
||||
rt2800_bbp_write(rt2x00dev, 80, 0x08);
|
||||
} else if (rt2x00_rt(rt2x00dev, RT3290)) {
|
||||
rt2800_bbp_write(rt2x00dev, 74, 0x0b);
|
||||
rt2800_bbp_write(rt2x00dev, 79, 0x18);
|
||||
rt2800_bbp_write(rt2x00dev, 80, 0x09);
|
||||
rt2800_bbp_write(rt2x00dev, 81, 0x33);
|
||||
} else if (rt2x00_rt(rt2x00dev, RT3352)) {
|
||||
rt2800_bbp_write(rt2x00dev, 78, 0x0e);
|
||||
rt2800_bbp_write(rt2x00dev, 80, 0x08);
|
||||
|
@ -3534,13 +3527,6 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
|
|||
rt2800_bbp_write(rt2x00dev, 81, 0x37);
|
||||
}
|
||||
|
||||
if (rt2x00_rt(rt2x00dev, RT3290)) {
|
||||
rt2800_bbp_write(rt2x00dev, 74, 0x0b);
|
||||
rt2800_bbp_write(rt2x00dev, 79, 0x18);
|
||||
rt2800_bbp_write(rt2x00dev, 80, 0x09);
|
||||
rt2800_bbp_write(rt2x00dev, 81, 0x33);
|
||||
}
|
||||
|
||||
rt2800_bbp_write(rt2x00dev, 82, 0x62);
|
||||
if (rt2x00_rt(rt2x00dev, RT3290) ||
|
||||
rt2x00_rt(rt2x00dev, RT5390) ||
|
||||
|
|
|
@ -1088,7 +1088,6 @@ static const struct data_queue_desc rt2800pci_queue_bcn = {
|
|||
static const struct rt2x00_ops rt2800pci_ops = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.drv_data_size = sizeof(struct rt2800_drv_data),
|
||||
.max_sta_intf = 1,
|
||||
.max_ap_intf = 8,
|
||||
.eeprom_size = EEPROM_SIZE,
|
||||
.rf_size = RF_SIZE,
|
||||
|
|
|
@ -870,7 +870,6 @@ static const struct data_queue_desc rt2800usb_queue_bcn = {
|
|||
static const struct rt2x00_ops rt2800usb_ops = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.drv_data_size = sizeof(struct rt2800_drv_data),
|
||||
.max_sta_intf = 1,
|
||||
.max_ap_intf = 8,
|
||||
.eeprom_size = EEPROM_SIZE,
|
||||
.rf_size = RF_SIZE,
|
||||
|
|
|
@ -656,7 +656,6 @@ struct rt2x00lib_ops {
|
|||
struct rt2x00_ops {
|
||||
const char *name;
|
||||
const unsigned int drv_data_size;
|
||||
const unsigned int max_sta_intf;
|
||||
const unsigned int max_ap_intf;
|
||||
const unsigned int eeprom_size;
|
||||
const unsigned int rf_size;
|
||||
|
@ -741,6 +740,14 @@ enum rt2x00_capability_flags {
|
|||
CAPABILITY_VCO_RECALIBRATION,
|
||||
};
|
||||
|
||||
/*
|
||||
* Interface combinations
|
||||
*/
|
||||
enum {
|
||||
IF_COMB_AP = 0,
|
||||
NUM_IF_COMB,
|
||||
};
|
||||
|
||||
/*
|
||||
* rt2x00 device structure.
|
||||
*/
|
||||
|
@ -867,6 +874,12 @@ struct rt2x00_dev {
|
|||
unsigned int intf_associated;
|
||||
unsigned int intf_beaconing;
|
||||
|
||||
/*
|
||||
* Interface combinations
|
||||
*/
|
||||
struct ieee80211_iface_limit if_limits_ap;
|
||||
struct ieee80211_iface_combination if_combinations[NUM_IF_COMB];
|
||||
|
||||
/*
|
||||
* Link quality
|
||||
*/
|
||||
|
|
|
@ -1118,6 +1118,34 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
|
|||
rt2x00dev->intf_associated = 0;
|
||||
}
|
||||
|
||||
static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct ieee80211_iface_limit *if_limit;
|
||||
struct ieee80211_iface_combination *if_combination;
|
||||
|
||||
/*
|
||||
* Build up AP interface limits structure.
|
||||
*/
|
||||
if_limit = &rt2x00dev->if_limits_ap;
|
||||
if_limit->max = rt2x00dev->ops->max_ap_intf;
|
||||
if_limit->types = BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
/*
|
||||
* Build up AP interface combinations structure.
|
||||
*/
|
||||
if_combination = &rt2x00dev->if_combinations[IF_COMB_AP];
|
||||
if_combination->limits = if_limit;
|
||||
if_combination->n_limits = 1;
|
||||
if_combination->max_interfaces = if_limit->max;
|
||||
if_combination->num_different_channels = 1;
|
||||
|
||||
/*
|
||||
* Finally, specify the possible combinations to mac80211.
|
||||
*/
|
||||
rt2x00dev->hw->wiphy->iface_combinations = rt2x00dev->if_combinations;
|
||||
rt2x00dev->hw->wiphy->n_iface_combinations = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* driver allocation handlers.
|
||||
*/
|
||||
|
@ -1125,6 +1153,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
{
|
||||
int retval = -ENOMEM;
|
||||
|
||||
/*
|
||||
* Set possible interface combinations.
|
||||
*/
|
||||
rt2x00lib_set_if_combinations(rt2x00dev);
|
||||
|
||||
/*
|
||||
* Allocate the driver data memory, if necessary.
|
||||
*/
|
||||
|
|
|
@ -214,46 +214,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
|
|||
!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
|
||||
return -ENODEV;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
/*
|
||||
* We don't support mixed combinations of
|
||||
* sta and ap interfaces.
|
||||
*/
|
||||
if (rt2x00dev->intf_sta_count)
|
||||
return -ENOBUFS;
|
||||
|
||||
/*
|
||||
* Check if we exceeded the maximum amount
|
||||
* of supported interfaces.
|
||||
*/
|
||||
if (rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf)
|
||||
return -ENOBUFS;
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
/*
|
||||
* We don't support mixed combinations of
|
||||
* sta and ap interfaces.
|
||||
*/
|
||||
if (rt2x00dev->intf_ap_count)
|
||||
return -ENOBUFS;
|
||||
|
||||
/*
|
||||
* Check if we exceeded the maximum amount
|
||||
* of supported interfaces.
|
||||
*/
|
||||
if (rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf)
|
||||
return -ENOBUFS;
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all beacon queues to find a free
|
||||
* entry. Since there are as much beacon entries
|
||||
|
|
|
@ -3045,7 +3045,6 @@ static const struct data_queue_desc rt61pci_queue_bcn = {
|
|||
|
||||
static const struct rt2x00_ops rt61pci_ops = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.max_sta_intf = 1,
|
||||
.max_ap_intf = 4,
|
||||
.eeprom_size = EEPROM_SIZE,
|
||||
.rf_size = RF_SIZE,
|
||||
|
|
|
@ -2382,7 +2382,6 @@ static const struct data_queue_desc rt73usb_queue_bcn = {
|
|||
|
||||
static const struct rt2x00_ops rt73usb_ops = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.max_sta_intf = 1,
|
||||
.max_ap_intf = 4,
|
||||
.eeprom_size = EEPROM_SIZE,
|
||||
.rf_size = RF_SIZE,
|
||||
|
|
|
@ -5,21 +5,9 @@
|
|||
menu "Near Field Communication (NFC) devices"
|
||||
depends on NFC
|
||||
|
||||
config PN544_NFC
|
||||
tristate "PN544 NFC driver"
|
||||
depends on I2C
|
||||
select CRC_CCITT
|
||||
default n
|
||||
---help---
|
||||
Say yes if you want PN544 Near Field Communication driver.
|
||||
This is for i2c connected version. If unsure, say N here.
|
||||
|
||||
To compile this driver as a module, choose m here. The module will
|
||||
be called pn544.
|
||||
|
||||
config PN544_HCI_NFC
|
||||
tristate "HCI PN544 NFC driver"
|
||||
depends on I2C && NFC_SHDLC
|
||||
depends on I2C && NFC_HCI && NFC_SHDLC
|
||||
select CRC_CCITT
|
||||
default n
|
||||
---help---
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# Makefile for nfc devices
|
||||
#
|
||||
|
||||
obj-$(CONFIG_PN544_NFC) += pn544.o
|
||||
obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o
|
||||
obj-$(CONFIG_NFC_PN533) += pn533.o
|
||||
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
|
||||
|
|
|
@ -352,8 +352,6 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
|
|||
struct nfcwilink *drv = priv_data;
|
||||
int rc;
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len);
|
||||
|
||||
if (!skb)
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -362,6 +360,8 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len);
|
||||
|
||||
/* strip the ST header
|
||||
(apart for the chnl byte, which is not received in the hdr) */
|
||||
skb_pull(skb, (NFCWILINK_HDR_LEN-1));
|
||||
|
@ -604,21 +604,7 @@ static struct platform_driver nfcwilink_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
/* ------- Module Init/Exit interfaces ------ */
|
||||
static int __init nfcwilink_init(void)
|
||||
{
|
||||
printk(KERN_INFO "NFC Driver for TI WiLink");
|
||||
|
||||
return platform_driver_register(&nfcwilink_driver);
|
||||
}
|
||||
|
||||
static void __exit nfcwilink_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&nfcwilink_driver);
|
||||
}
|
||||
|
||||
module_init(nfcwilink_init);
|
||||
module_exit(nfcwilink_exit);
|
||||
module_platform_driver(nfcwilink_driver);
|
||||
|
||||
/* ------ Module Info ------ */
|
||||
|
||||
|
|
|
@ -356,6 +356,7 @@ struct pn533 {
|
|||
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct cmd_work;
|
||||
struct work_struct cmd_complete_work;
|
||||
struct work_struct poll_work;
|
||||
struct work_struct mi_work;
|
||||
struct work_struct tg_work;
|
||||
|
@ -383,6 +384,19 @@ struct pn533 {
|
|||
u8 tgt_mode;
|
||||
|
||||
u32 device_type;
|
||||
|
||||
struct list_head cmd_queue;
|
||||
u8 cmd_pending;
|
||||
};
|
||||
|
||||
struct pn533_cmd {
|
||||
struct list_head queue;
|
||||
struct pn533_frame *out_frame;
|
||||
struct pn533_frame *in_frame;
|
||||
int in_frame_len;
|
||||
pn533_cmd_complete_t cmd_complete;
|
||||
void *arg;
|
||||
gfp_t flags;
|
||||
};
|
||||
|
||||
struct pn533_frame {
|
||||
|
@ -487,7 +501,7 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd)
|
|||
|
||||
static void pn533_wq_cmd_complete(struct work_struct *work)
|
||||
{
|
||||
struct pn533 *dev = container_of(work, struct pn533, cmd_work);
|
||||
struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
|
||||
struct pn533_frame *in_frame;
|
||||
int rc;
|
||||
|
||||
|
@ -502,7 +516,7 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
|
|||
PN533_FRAME_CMD_PARAMS_LEN(in_frame));
|
||||
|
||||
if (rc != -EINPROGRESS)
|
||||
mutex_unlock(&dev->cmd_lock);
|
||||
queue_work(dev->wq, &dev->cmd_work);
|
||||
}
|
||||
|
||||
static void pn533_recv_response(struct urb *urb)
|
||||
|
@ -550,7 +564,7 @@ static void pn533_recv_response(struct urb *urb)
|
|||
dev->wq_in_frame = in_frame;
|
||||
|
||||
sched_wq:
|
||||
queue_work(dev->wq, &dev->cmd_work);
|
||||
queue_work(dev->wq, &dev->cmd_complete_work);
|
||||
}
|
||||
|
||||
static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags)
|
||||
|
@ -606,7 +620,7 @@ static void pn533_recv_ack(struct urb *urb)
|
|||
|
||||
sched_wq:
|
||||
dev->wq_in_frame = NULL;
|
||||
queue_work(dev->wq, &dev->cmd_work);
|
||||
queue_work(dev->wq, &dev->cmd_complete_work);
|
||||
}
|
||||
|
||||
static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags)
|
||||
|
@ -669,6 +683,31 @@ error:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void pn533_wq_cmd(struct work_struct *work)
|
||||
{
|
||||
struct pn533 *dev = container_of(work, struct pn533, cmd_work);
|
||||
struct pn533_cmd *cmd;
|
||||
|
||||
mutex_lock(&dev->cmd_lock);
|
||||
|
||||
if (list_empty(&dev->cmd_queue)) {
|
||||
dev->cmd_pending = 0;
|
||||
mutex_unlock(&dev->cmd_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue);
|
||||
|
||||
mutex_unlock(&dev->cmd_lock);
|
||||
|
||||
__pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame,
|
||||
cmd->in_frame_len, cmd->cmd_complete,
|
||||
cmd->arg, cmd->flags);
|
||||
|
||||
list_del(&cmd->queue);
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
static int pn533_send_cmd_frame_async(struct pn533 *dev,
|
||||
struct pn533_frame *out_frame,
|
||||
struct pn533_frame *in_frame,
|
||||
|
@ -676,21 +715,44 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
|
|||
pn533_cmd_complete_t cmd_complete,
|
||||
void *arg, gfp_t flags)
|
||||
{
|
||||
int rc;
|
||||
struct pn533_cmd *cmd;
|
||||
int rc = 0;
|
||||
|
||||
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
|
||||
|
||||
if (!mutex_trylock(&dev->cmd_lock))
|
||||
return -EBUSY;
|
||||
mutex_lock(&dev->cmd_lock);
|
||||
|
||||
if (!dev->cmd_pending) {
|
||||
rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
|
||||
in_frame_len, cmd_complete, arg, flags);
|
||||
if (rc)
|
||||
goto error;
|
||||
in_frame_len, cmd_complete,
|
||||
arg, flags);
|
||||
if (!rc)
|
||||
dev->cmd_pending = 1;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__);
|
||||
|
||||
cmd = kzalloc(sizeof(struct pn533_cmd), flags);
|
||||
if (!cmd) {
|
||||
rc = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&cmd->queue);
|
||||
cmd->out_frame = out_frame;
|
||||
cmd->in_frame = in_frame;
|
||||
cmd->in_frame_len = in_frame_len;
|
||||
cmd->cmd_complete = cmd_complete;
|
||||
cmd->arg = arg;
|
||||
cmd->flags = flags;
|
||||
|
||||
list_add_tail(&cmd->queue, &dev->cmd_queue);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&dev->cmd_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1305,8 +1367,6 @@ static void pn533_listen_mode_timer(unsigned long data)
|
|||
|
||||
dev->cancel_listen = 1;
|
||||
|
||||
mutex_unlock(&dev->cmd_lock);
|
||||
|
||||
pn533_poll_next_mod(dev);
|
||||
|
||||
queue_work(dev->wq, &dev->poll_work);
|
||||
|
@ -2131,7 +2191,7 @@ error_cmd:
|
|||
|
||||
kfree(arg);
|
||||
|
||||
mutex_unlock(&dev->cmd_lock);
|
||||
queue_work(dev->wq, &dev->cmd_work);
|
||||
}
|
||||
|
||||
static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
|
||||
|
@ -2330,13 +2390,12 @@ static int pn533_probe(struct usb_interface *interface,
|
|||
NULL, 0,
|
||||
pn533_send_complete, dev);
|
||||
|
||||
INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete);
|
||||
INIT_WORK(&dev->cmd_work, pn533_wq_cmd);
|
||||
INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete);
|
||||
INIT_WORK(&dev->mi_work, pn533_wq_mi_recv);
|
||||
INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data);
|
||||
INIT_WORK(&dev->poll_work, pn533_wq_poll);
|
||||
dev->wq = alloc_workqueue("pn533",
|
||||
WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
|
||||
1);
|
||||
dev->wq = alloc_ordered_workqueue("pn533", 0);
|
||||
if (dev->wq == NULL)
|
||||
goto error;
|
||||
|
||||
|
@ -2346,6 +2405,8 @@ static int pn533_probe(struct usb_interface *interface,
|
|||
|
||||
skb_queue_head_init(&dev->resp_q);
|
||||
|
||||
INIT_LIST_HEAD(&dev->cmd_queue);
|
||||
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION);
|
||||
|
@ -2417,6 +2478,7 @@ error:
|
|||
static void pn533_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct pn533 *dev;
|
||||
struct pn533_cmd *cmd, *n;
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
@ -2433,6 +2495,11 @@ static void pn533_disconnect(struct usb_interface *interface)
|
|||
|
||||
del_timer(&dev->listen_timer);
|
||||
|
||||
list_for_each_entry_safe(cmd, n, &dev->cmd_queue, queue) {
|
||||
list_del(&cmd->queue);
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
kfree(dev->in_frame);
|
||||
usb_free_urb(dev->in_urb);
|
||||
kfree(dev->out_frame);
|
||||
|
|
|
@ -1,893 +0,0 @@
|
|||
/*
|
||||
* Driver for the PN544 NFC chip.
|
||||
*
|
||||
* Copyright (C) Nokia Corporation
|
||||
*
|
||||
* Author: Jari Vanhala <ext-jari.vanhala@nokia.com>
|
||||
* Contact: Matti Aaltonen <matti.j.aaltonen@nokia.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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/crc-ccitt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/nfc/pn544.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/serial_core.h> /* for TCGETS */
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define DRIVER_CARD "PN544 NFC"
|
||||
#define DRIVER_DESC "NFC driver for PN544"
|
||||
|
||||
static struct i2c_device_id pn544_id_table[] = {
|
||||
{ PN544_DRIVER_NAME, 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pn544_id_table);
|
||||
|
||||
#define HCI_MODE 0
|
||||
#define FW_MODE 1
|
||||
|
||||
enum pn544_state {
|
||||
PN544_ST_COLD,
|
||||
PN544_ST_FW_READY,
|
||||
PN544_ST_READY,
|
||||
};
|
||||
|
||||
enum pn544_irq {
|
||||
PN544_NONE,
|
||||
PN544_INT,
|
||||
};
|
||||
|
||||
struct pn544_info {
|
||||
struct miscdevice miscdev;
|
||||
struct i2c_client *i2c_dev;
|
||||
struct regulator_bulk_data regs[3];
|
||||
|
||||
enum pn544_state state;
|
||||
wait_queue_head_t read_wait;
|
||||
loff_t read_offset;
|
||||
enum pn544_irq read_irq;
|
||||
struct mutex read_mutex; /* Serialize read_irq access */
|
||||
struct mutex mutex; /* Serialize info struct access */
|
||||
u8 *buf;
|
||||
size_t buflen;
|
||||
};
|
||||
|
||||
static const char reg_vdd_io[] = "Vdd_IO";
|
||||
static const char reg_vbat[] = "VBat";
|
||||
static const char reg_vsim[] = "VSim";
|
||||
|
||||
/* sysfs interface */
|
||||
static ssize_t pn544_test(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pn544_info *info = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test());
|
||||
}
|
||||
|
||||
static int pn544_enable(struct pn544_info *info, int mode)
|
||||
{
|
||||
struct pn544_nfc_platform_data *pdata;
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
|
||||
int r;
|
||||
|
||||
r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
info->read_irq = PN544_NONE;
|
||||
if (pdata->enable)
|
||||
pdata->enable(mode);
|
||||
|
||||
if (mode) {
|
||||
info->state = PN544_ST_FW_READY;
|
||||
dev_dbg(&client->dev, "now in FW-mode\n");
|
||||
} else {
|
||||
info->state = PN544_ST_READY;
|
||||
dev_dbg(&client->dev, "now in HCI-mode\n");
|
||||
}
|
||||
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pn544_disable(struct pn544_info *info)
|
||||
{
|
||||
struct pn544_nfc_platform_data *pdata;
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
if (pdata->disable)
|
||||
pdata->disable();
|
||||
|
||||
info->state = PN544_ST_COLD;
|
||||
|
||||
dev_dbg(&client->dev, "Now in OFF-mode\n");
|
||||
|
||||
msleep(PN544_RESETVEN_TIME);
|
||||
|
||||
info->read_irq = PN544_NONE;
|
||||
regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs);
|
||||
}
|
||||
|
||||
static int check_crc(u8 *buf, int buflen)
|
||||
{
|
||||
u8 len;
|
||||
u16 crc;
|
||||
|
||||
len = buf[0] + 1;
|
||||
if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) {
|
||||
pr_err(PN544_DRIVER_NAME
|
||||
": CRC; corrupt packet len %u (%d)\n", len, buflen);
|
||||
print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
|
||||
16, 2, buf, buflen, false);
|
||||
return -EPERM;
|
||||
}
|
||||
crc = crc_ccitt(0xffff, buf, len - 2);
|
||||
crc = ~crc;
|
||||
|
||||
if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) {
|
||||
pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n",
|
||||
crc, buf[len-1], buf[len-2]);
|
||||
|
||||
print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
|
||||
16, 2, buf, buflen, false);
|
||||
return -EPERM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (len < 4 || len != (buf[0] + 1)) {
|
||||
dev_err(&client->dev, "%s: Illegal message length: %d\n",
|
||||
__func__, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (check_crc(buf, len))
|
||||
return -EINVAL;
|
||||
|
||||
usleep_range(3000, 6000);
|
||||
|
||||
r = i2c_master_send(client, buf, len);
|
||||
dev_dbg(&client->dev, "send: %d\n", r);
|
||||
|
||||
if (r == -EREMOTEIO) { /* Retry, chip was in standby */
|
||||
usleep_range(6000, 10000);
|
||||
r = i2c_master_send(client, buf, len);
|
||||
dev_dbg(&client->dev, "send2: %d\n", r);
|
||||
}
|
||||
|
||||
if (r != len)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen)
|
||||
{
|
||||
int r;
|
||||
u8 len;
|
||||
|
||||
/*
|
||||
* You could read a packet in one go, but then you'd need to read
|
||||
* max size and rest would be 0xff fill, so we do split reads.
|
||||
*/
|
||||
r = i2c_master_recv(client, &len, 1);
|
||||
dev_dbg(&client->dev, "recv1: %d\n", r);
|
||||
|
||||
if (r != 1)
|
||||
return -EREMOTEIO;
|
||||
|
||||
if (len < PN544_LLC_HCI_OVERHEAD)
|
||||
len = PN544_LLC_HCI_OVERHEAD;
|
||||
else if (len > (PN544_MSG_MAX_SIZE - 1))
|
||||
len = PN544_MSG_MAX_SIZE - 1;
|
||||
|
||||
if (1 + len > buflen) /* len+(data+crc16) */
|
||||
return -EMSGSIZE;
|
||||
|
||||
buf[0] = len;
|
||||
|
||||
r = i2c_master_recv(client, buf + 1, len);
|
||||
dev_dbg(&client->dev, "recv2: %d\n", r);
|
||||
|
||||
if (r != len)
|
||||
return -EREMOTEIO;
|
||||
|
||||
usleep_range(3000, 6000);
|
||||
|
||||
return r + 1;
|
||||
}
|
||||
|
||||
static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
if (len < PN544_FW_HEADER_SIZE ||
|
||||
(PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len)
|
||||
return -EINVAL;
|
||||
|
||||
r = i2c_master_send(client, buf, len);
|
||||
dev_dbg(&client->dev, "fw send: %d\n", r);
|
||||
|
||||
if (r == -EREMOTEIO) { /* Retry, chip was in standby */
|
||||
usleep_range(6000, 10000);
|
||||
r = i2c_master_send(client, buf, len);
|
||||
dev_dbg(&client->dev, "fw send2: %d\n", r);
|
||||
}
|
||||
|
||||
if (r != len)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen)
|
||||
{
|
||||
int r, len;
|
||||
|
||||
if (buflen < PN544_FW_HEADER_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE);
|
||||
dev_dbg(&client->dev, "FW recv1: %d\n", r);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r < PN544_FW_HEADER_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
len = (buf[1] << 8) + buf[2];
|
||||
if (len == 0) /* just header, no additional data */
|
||||
return r;
|
||||
|
||||
if (len > buflen - PN544_FW_HEADER_SIZE)
|
||||
return -EMSGSIZE;
|
||||
|
||||
r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len);
|
||||
dev_dbg(&client->dev, "fw recv2: %d\n", r);
|
||||
|
||||
if (r != len)
|
||||
return -EINVAL;
|
||||
|
||||
return r + PN544_FW_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id)
|
||||
{
|
||||
struct pn544_info *info = dev_id;
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
|
||||
BUG_ON(!info);
|
||||
BUG_ON(irq != info->i2c_dev->irq);
|
||||
|
||||
dev_dbg(&client->dev, "IRQ\n");
|
||||
|
||||
mutex_lock(&info->read_mutex);
|
||||
info->read_irq = PN544_INT;
|
||||
mutex_unlock(&info->read_mutex);
|
||||
|
||||
wake_up_interruptible(&info->read_wait);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static enum pn544_irq pn544_irq_state(struct pn544_info *info)
|
||||
{
|
||||
enum pn544_irq irq;
|
||||
|
||||
mutex_lock(&info->read_mutex);
|
||||
irq = info->read_irq;
|
||||
mutex_unlock(&info->read_mutex);
|
||||
/*
|
||||
* XXX: should we check GPIO-line status directly?
|
||||
* return pdata->irq_status() ? PN544_INT : PN544_NONE;
|
||||
*/
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static ssize_t pn544_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *offset)
|
||||
{
|
||||
struct pn544_info *info = container_of(file->private_data,
|
||||
struct pn544_info, miscdev);
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
enum pn544_irq irq;
|
||||
size_t len;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__,
|
||||
info, count);
|
||||
|
||||
mutex_lock(&info->mutex);
|
||||
|
||||
if (info->state == PN544_ST_COLD) {
|
||||
r = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
irq = pn544_irq_state(info);
|
||||
if (irq == PN544_NONE) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
r = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wait_event_interruptible(info->read_wait,
|
||||
(info->read_irq == PN544_INT))) {
|
||||
r = -ERESTARTSYS;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->state == PN544_ST_FW_READY) {
|
||||
len = min(count, info->buflen);
|
||||
|
||||
mutex_lock(&info->read_mutex);
|
||||
r = pn544_fw_read(info->i2c_dev, info->buf, len);
|
||||
info->read_irq = PN544_NONE;
|
||||
mutex_unlock(&info->read_mutex);
|
||||
|
||||
if (r < 0) {
|
||||
dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE,
|
||||
16, 2, info->buf, r, false);
|
||||
|
||||
*offset += r;
|
||||
if (copy_to_user(buf, info->buf, r)) {
|
||||
r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
len = min(count, info->buflen);
|
||||
|
||||
mutex_lock(&info->read_mutex);
|
||||
r = pn544_i2c_read(info->i2c_dev, info->buf, len);
|
||||
info->read_irq = PN544_NONE;
|
||||
mutex_unlock(&info->read_mutex);
|
||||
|
||||
if (r < 0) {
|
||||
dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r);
|
||||
goto out;
|
||||
}
|
||||
print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE,
|
||||
16, 2, info->buf, r, false);
|
||||
|
||||
*offset += r;
|
||||
if (copy_to_user(buf, info->buf, r)) {
|
||||
r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static unsigned int pn544_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct pn544_info *info = container_of(file->private_data,
|
||||
struct pn544_info, miscdev);
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: info: %p\n", __func__, info);
|
||||
|
||||
mutex_lock(&info->mutex);
|
||||
|
||||
if (info->state == PN544_ST_COLD) {
|
||||
r = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
poll_wait(file, &info->read_wait, wait);
|
||||
|
||||
if (pn544_irq_state(info) == PN544_INT) {
|
||||
r = POLLIN | POLLRDNORM;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&info->mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t pn544_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct pn544_info *info = container_of(file->private_data,
|
||||
struct pn544_info, miscdev);
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
ssize_t len;
|
||||
int r;
|
||||
|
||||
dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__,
|
||||
info, count);
|
||||
|
||||
mutex_lock(&info->mutex);
|
||||
|
||||
if (info->state == PN544_ST_COLD) {
|
||||
r = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: should we detect rset-writes and clean possible
|
||||
* read_irq state
|
||||
*/
|
||||
if (info->state == PN544_ST_FW_READY) {
|
||||
size_t fw_len;
|
||||
|
||||
if (count < PN544_FW_HEADER_SIZE) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = min(count, info->buflen);
|
||||
if (copy_from_user(info->buf, buf, len)) {
|
||||
r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE,
|
||||
16, 2, info->buf, len, false);
|
||||
|
||||
fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) +
|
||||
info->buf[2];
|
||||
|
||||
if (len > fw_len) /* 1 msg at a time */
|
||||
len = fw_len;
|
||||
|
||||
r = pn544_fw_write(info->i2c_dev, info->buf, len);
|
||||
} else {
|
||||
if (count < PN544_LLC_MIN_SIZE) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = min(count, info->buflen);
|
||||
if (copy_from_user(info->buf, buf, len)) {
|
||||
r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE,
|
||||
16, 2, info->buf, len, false);
|
||||
|
||||
if (len > (info->buf[0] + 1)) /* 1 msg at a time */
|
||||
len = info->buf[0] + 1;
|
||||
|
||||
r = pn544_i2c_write(info->i2c_dev, info->buf, len);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&info->mutex);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct pn544_info *info = container_of(file->private_data,
|
||||
struct pn544_info, miscdev);
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
struct pn544_nfc_platform_data *pdata;
|
||||
unsigned int val;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd);
|
||||
|
||||
mutex_lock(&info->mutex);
|
||||
|
||||
if (info->state == PN544_ST_COLD) {
|
||||
r = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pdata = info->i2c_dev->dev.platform_data;
|
||||
switch (cmd) {
|
||||
case PN544_GET_FW_MODE:
|
||||
dev_dbg(&client->dev, "%s: PN544_GET_FW_MODE\n", __func__);
|
||||
|
||||
val = (info->state == PN544_ST_FW_READY);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
|
||||
r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PN544_SET_FW_MODE:
|
||||
dev_dbg(&client->dev, "%s: PN544_SET_FW_MODE\n", __func__);
|
||||
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
|
||||
r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
if (info->state == PN544_ST_FW_READY)
|
||||
break;
|
||||
|
||||
pn544_disable(info);
|
||||
r = pn544_enable(info, FW_MODE);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
} else {
|
||||
if (info->state == PN544_ST_READY)
|
||||
break;
|
||||
pn544_disable(info);
|
||||
r = pn544_enable(info, HCI_MODE);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
file->f_pos = info->read_offset;
|
||||
break;
|
||||
|
||||
case TCGETS:
|
||||
dev_dbg(&client->dev, "%s: TCGETS\n", __func__);
|
||||
|
||||
r = -ENOIOCTLCMD;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd);
|
||||
r = -ENOIOCTLCMD;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn544_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct pn544_info *info = container_of(file->private_data,
|
||||
struct pn544_info, miscdev);
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__,
|
||||
info, info->i2c_dev);
|
||||
|
||||
mutex_lock(&info->mutex);
|
||||
|
||||
/*
|
||||
* Only 1 at a time.
|
||||
* XXX: maybe user (counter) would work better
|
||||
*/
|
||||
if (info->state != PN544_ST_COLD) {
|
||||
r = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
file->f_pos = info->read_offset;
|
||||
r = pn544_enable(info, HCI_MODE);
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn544_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct pn544_info *info = container_of(file->private_data,
|
||||
struct pn544_info, miscdev);
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
|
||||
dev_dbg(&client->dev, "%s: info: %p, client %p\n",
|
||||
__func__, info, info->i2c_dev);
|
||||
|
||||
mutex_lock(&info->mutex);
|
||||
pn544_disable(info);
|
||||
mutex_unlock(&info->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations pn544_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = pn544_read,
|
||||
.write = pn544_write,
|
||||
.poll = pn544_poll,
|
||||
.open = pn544_open,
|
||||
.release = pn544_close,
|
||||
.unlocked_ioctl = pn544_ioctl,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pn544_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pn544_info *info;
|
||||
int r = 0;
|
||||
|
||||
dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client);
|
||||
|
||||
info = i2c_get_clientdata(client);
|
||||
dev_info(&client->dev, "%s: info: %p, client %p\n", __func__,
|
||||
info, client);
|
||||
|
||||
mutex_lock(&info->mutex);
|
||||
|
||||
switch (info->state) {
|
||||
case PN544_ST_FW_READY:
|
||||
/* Do not suspend while upgrading FW, please! */
|
||||
r = -EPERM;
|
||||
break;
|
||||
|
||||
case PN544_ST_READY:
|
||||
/*
|
||||
* CHECK: Device should be in standby-mode. No way to check?
|
||||
* Allowing low power mode for the regulator is potentially
|
||||
* dangerous if pn544 does not go to suspension.
|
||||
*/
|
||||
break;
|
||||
|
||||
case PN544_ST_COLD:
|
||||
break;
|
||||
};
|
||||
|
||||
mutex_unlock(&info->mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn544_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pn544_info *info = i2c_get_clientdata(client);
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__,
|
||||
info, client);
|
||||
|
||||
mutex_lock(&info->mutex);
|
||||
|
||||
switch (info->state) {
|
||||
case PN544_ST_READY:
|
||||
/*
|
||||
* CHECK: If regulator low power mode is allowed in
|
||||
* pn544_suspend, we should go back to normal mode
|
||||
* here.
|
||||
*/
|
||||
break;
|
||||
|
||||
case PN544_ST_COLD:
|
||||
break;
|
||||
|
||||
case PN544_ST_FW_READY:
|
||||
break;
|
||||
};
|
||||
|
||||
mutex_unlock(&info->mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume);
|
||||
#endif
|
||||
|
||||
static struct device_attribute pn544_attr =
|
||||
__ATTR(nfc_test, S_IRUGO, pn544_test, NULL);
|
||||
|
||||
static int __devinit pn544_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct pn544_info *info;
|
||||
struct pn544_nfc_platform_data *pdata;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
|
||||
|
||||
/* private data allocation */
|
||||
info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
dev_err(&client->dev,
|
||||
"Cannot allocate memory for pn544_info.\n");
|
||||
r = -ENOMEM;
|
||||
goto err_info_alloc;
|
||||
}
|
||||
|
||||
info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER);
|
||||
info->buf = kzalloc(info->buflen, GFP_KERNEL);
|
||||
if (!info->buf) {
|
||||
dev_err(&client->dev,
|
||||
"Cannot allocate memory for pn544_info->buf.\n");
|
||||
r = -ENOMEM;
|
||||
goto err_buf_alloc;
|
||||
}
|
||||
|
||||
info->regs[0].supply = reg_vdd_io;
|
||||
info->regs[1].supply = reg_vbat;
|
||||
info->regs[2].supply = reg_vsim;
|
||||
r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs),
|
||||
info->regs);
|
||||
if (r < 0)
|
||||
goto err_kmalloc;
|
||||
|
||||
info->i2c_dev = client;
|
||||
info->state = PN544_ST_COLD;
|
||||
info->read_irq = PN544_NONE;
|
||||
mutex_init(&info->read_mutex);
|
||||
mutex_init(&info->mutex);
|
||||
init_waitqueue_head(&info->read_wait);
|
||||
i2c_set_clientdata(client, info);
|
||||
pdata = client->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "No platform data\n");
|
||||
r = -EINVAL;
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
if (!pdata->request_resources) {
|
||||
dev_err(&client->dev, "request_resources() missing\n");
|
||||
r = -EINVAL;
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
r = pdata->request_resources(client);
|
||||
if (r) {
|
||||
dev_err(&client->dev, "Cannot get platform resources\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn,
|
||||
IRQF_TRIGGER_RISING, PN544_DRIVER_NAME,
|
||||
info);
|
||||
if (r < 0) {
|
||||
dev_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
goto err_res;
|
||||
}
|
||||
|
||||
/* If we don't have the test we don't need the sysfs file */
|
||||
if (pdata->test) {
|
||||
r = device_create_file(&client->dev, &pn544_attr);
|
||||
if (r) {
|
||||
dev_err(&client->dev,
|
||||
"sysfs registration failed, error %d\n", r);
|
||||
goto err_irq;
|
||||
}
|
||||
}
|
||||
|
||||
info->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
info->miscdev.name = PN544_DRIVER_NAME;
|
||||
info->miscdev.fops = &pn544_fops;
|
||||
info->miscdev.parent = &client->dev;
|
||||
r = misc_register(&info->miscdev);
|
||||
if (r < 0) {
|
||||
dev_err(&client->dev, "Device registration failed\n");
|
||||
goto err_sysfs;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n",
|
||||
__func__, info, pdata, client);
|
||||
|
||||
return 0;
|
||||
|
||||
err_sysfs:
|
||||
if (pdata->test)
|
||||
device_remove_file(&client->dev, &pn544_attr);
|
||||
err_irq:
|
||||
free_irq(client->irq, info);
|
||||
err_res:
|
||||
if (pdata->free_resources)
|
||||
pdata->free_resources();
|
||||
err_reg:
|
||||
regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs);
|
||||
err_kmalloc:
|
||||
kfree(info->buf);
|
||||
err_buf_alloc:
|
||||
kfree(info);
|
||||
err_info_alloc:
|
||||
return r;
|
||||
}
|
||||
|
||||
static __devexit int pn544_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pn544_info *info = i2c_get_clientdata(client);
|
||||
struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
misc_deregister(&info->miscdev);
|
||||
if (pdata->test)
|
||||
device_remove_file(&client->dev, &pn544_attr);
|
||||
|
||||
if (info->state != PN544_ST_COLD) {
|
||||
if (pdata->disable)
|
||||
pdata->disable();
|
||||
|
||||
info->read_irq = PN544_NONE;
|
||||
}
|
||||
|
||||
free_irq(client->irq, info);
|
||||
if (pdata->free_resources)
|
||||
pdata->free_resources();
|
||||
|
||||
regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs);
|
||||
kfree(info->buf);
|
||||
kfree(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver pn544_driver = {
|
||||
.driver = {
|
||||
.name = PN544_DRIVER_NAME,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &pn544_pm_ops,
|
||||
#endif
|
||||
},
|
||||
.probe = pn544_probe,
|
||||
.id_table = pn544_id_table,
|
||||
.remove = __devexit_p(pn544_remove),
|
||||
};
|
||||
|
||||
static int __init pn544_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
pr_debug(DRIVER_DESC ": %s\n", __func__);
|
||||
|
||||
r = i2c_add_driver(&pn544_driver);
|
||||
if (r) {
|
||||
pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit pn544_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pn544_driver);
|
||||
pr_info(DRIVER_DESC ", Exiting.\n");
|
||||
}
|
||||
|
||||
module_init(pn544_init);
|
||||
module_exit(pn544_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/hci.h>
|
||||
#include <net/nfc/shdlc.h>
|
||||
#include <net/nfc/llc.h>
|
||||
|
||||
#include <linux/nfc/pn544.h>
|
||||
|
||||
|
@ -128,10 +128,12 @@ static struct nfc_hci_gate pn544_gates[] = {
|
|||
|
||||
/* Largest headroom needed for outgoing custom commands */
|
||||
#define PN544_CMDS_HEADROOM 2
|
||||
#define PN544_FRAME_HEADROOM 1
|
||||
#define PN544_FRAME_TAILROOM 2
|
||||
|
||||
struct pn544_hci_info {
|
||||
struct i2c_client *i2c_dev;
|
||||
struct nfc_shdlc *shdlc;
|
||||
struct nfc_hci_dev *hdev;
|
||||
|
||||
enum pn544_state state;
|
||||
|
||||
|
@ -146,6 +148,9 @@ struct pn544_hci_info {
|
|||
* < 0 if hardware error occured (e.g. i2c err)
|
||||
* and prevents normal operation.
|
||||
*/
|
||||
int async_cb_type;
|
||||
data_exchange_cb_t async_cb;
|
||||
void *async_cb_context;
|
||||
};
|
||||
|
||||
static void pn544_hci_platform_init(struct pn544_hci_info *info)
|
||||
|
@ -230,8 +235,12 @@ static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len)
|
|||
r = i2c_master_send(client, buf, len);
|
||||
}
|
||||
|
||||
if (r >= 0 && r != len)
|
||||
r = -EREMOTEIO;
|
||||
if (r >= 0) {
|
||||
if (r != len)
|
||||
return -EREMOTEIO;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -341,13 +350,16 @@ flush:
|
|||
static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id)
|
||||
{
|
||||
struct pn544_hci_info *info = dev_id;
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
struct i2c_client *client;
|
||||
struct sk_buff *skb = NULL;
|
||||
int r;
|
||||
|
||||
BUG_ON(!info);
|
||||
BUG_ON(irq != info->i2c_dev->irq);
|
||||
if (!info || irq != info->i2c_dev->irq) {
|
||||
WARN_ON_ONCE(1);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
client = info->i2c_dev;
|
||||
dev_dbg(&client->dev, "IRQ\n");
|
||||
|
||||
if (info->hard_fault != 0)
|
||||
|
@ -357,21 +369,21 @@ static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id)
|
|||
if (r == -EREMOTEIO) {
|
||||
info->hard_fault = r;
|
||||
|
||||
nfc_shdlc_recv_frame(info->shdlc, NULL);
|
||||
nfc_hci_recv_frame(info->hdev, NULL);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
} else if ((r == -ENOMEM) || (r == -EBADMSG)) {
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
nfc_shdlc_recv_frame(info->shdlc, skb);
|
||||
nfc_hci_recv_frame(info->hdev, skb);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pn544_hci_open(struct nfc_shdlc *shdlc)
|
||||
static int pn544_hci_open(struct nfc_hci_dev *hdev)
|
||||
{
|
||||
struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
|
||||
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
|
||||
int r = 0;
|
||||
|
||||
mutex_lock(&info->info_lock);
|
||||
|
@ -391,9 +403,9 @@ out:
|
|||
return r;
|
||||
}
|
||||
|
||||
static void pn544_hci_close(struct nfc_shdlc *shdlc)
|
||||
static void pn544_hci_close(struct nfc_hci_dev *hdev)
|
||||
{
|
||||
struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
|
||||
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
|
||||
|
||||
mutex_lock(&info->info_lock);
|
||||
|
||||
|
@ -408,9 +420,8 @@ out:
|
|||
mutex_unlock(&info->info_lock);
|
||||
}
|
||||
|
||||
static int pn544_hci_ready(struct nfc_shdlc *shdlc)
|
||||
static int pn544_hci_ready(struct nfc_hci_dev *hdev)
|
||||
{
|
||||
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
|
||||
struct sk_buff *skb;
|
||||
static struct hw_config {
|
||||
u8 adr[2];
|
||||
|
@ -576,21 +587,45 @@ static int pn544_hci_ready(struct nfc_shdlc *shdlc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb)
|
||||
static void pn544_hci_add_len_crc(struct sk_buff *skb)
|
||||
{
|
||||
struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
|
||||
u16 crc;
|
||||
int len;
|
||||
|
||||
len = skb->len + 2;
|
||||
*skb_push(skb, 1) = len;
|
||||
|
||||
crc = crc_ccitt(0xffff, skb->data, skb->len);
|
||||
crc = ~crc;
|
||||
*skb_put(skb, 1) = crc & 0xff;
|
||||
*skb_put(skb, 1) = crc >> 8;
|
||||
}
|
||||
|
||||
static void pn544_hci_remove_len_crc(struct sk_buff *skb)
|
||||
{
|
||||
skb_pull(skb, PN544_FRAME_HEADROOM);
|
||||
skb_trim(skb, PN544_FRAME_TAILROOM);
|
||||
}
|
||||
|
||||
static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
|
||||
struct i2c_client *client = info->i2c_dev;
|
||||
int r;
|
||||
|
||||
if (info->hard_fault != 0)
|
||||
return info->hard_fault;
|
||||
|
||||
return pn544_hci_i2c_write(client, skb->data, skb->len);
|
||||
pn544_hci_add_len_crc(skb);
|
||||
r = pn544_hci_i2c_write(client, skb->data, skb->len);
|
||||
pn544_hci_remove_len_crc(skb);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn544_hci_start_poll(struct nfc_shdlc *shdlc,
|
||||
static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
|
||||
u32 im_protocols, u32 tm_protocols)
|
||||
{
|
||||
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
|
||||
u8 phases = 0;
|
||||
int r;
|
||||
u8 duration[2];
|
||||
|
@ -641,7 +676,7 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc,
|
|||
return r;
|
||||
}
|
||||
|
||||
static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate,
|
||||
static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
|
||||
struct nfc_target *target)
|
||||
{
|
||||
switch (gate) {
|
||||
|
@ -659,11 +694,10 @@ static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc,
|
||||
static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
|
||||
u8 gate,
|
||||
struct nfc_target *target)
|
||||
{
|
||||
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
|
||||
struct sk_buff *uid_skb;
|
||||
int r = 0;
|
||||
|
||||
|
@ -704,6 +738,26 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc,
|
|||
return r;
|
||||
}
|
||||
|
||||
#define PN544_CB_TYPE_READER_F 1
|
||||
|
||||
static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,
|
||||
int err)
|
||||
{
|
||||
struct pn544_hci_info *info = context;
|
||||
|
||||
switch (info->async_cb_type) {
|
||||
case PN544_CB_TYPE_READER_F:
|
||||
if (err == 0)
|
||||
skb_pull(skb, 1);
|
||||
info->async_cb(info->async_cb_context, skb, err);
|
||||
break;
|
||||
default:
|
||||
if (err == 0)
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define MIFARE_CMD_AUTH_KEY_A 0x60
|
||||
#define MIFARE_CMD_AUTH_KEY_B 0x61
|
||||
#define MIFARE_CMD_HEADER 2
|
||||
|
@ -715,13 +769,12 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc,
|
|||
* <= 0: driver handled the data exchange
|
||||
* 1: driver doesn't especially handle, please do standard processing
|
||||
*/
|
||||
static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc,
|
||||
static int pn544_hci_data_exchange(struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target,
|
||||
struct sk_buff *skb,
|
||||
struct sk_buff **res_skb)
|
||||
struct sk_buff *skb, data_exchange_cb_t cb,
|
||||
void *cb_context)
|
||||
{
|
||||
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
|
||||
int r;
|
||||
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
|
||||
|
||||
pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__,
|
||||
target->hci_reader_gate);
|
||||
|
@ -746,41 +799,43 @@ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc,
|
|||
memcpy(data, uid, MIFARE_UID_LEN);
|
||||
}
|
||||
|
||||
return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
|
||||
return nfc_hci_send_cmd_async(hdev,
|
||||
target->hci_reader_gate,
|
||||
PN544_MIFARE_CMD,
|
||||
skb->data, skb->len, res_skb);
|
||||
skb->data, skb->len,
|
||||
cb, cb_context);
|
||||
} else
|
||||
return 1;
|
||||
case PN544_RF_READER_F_GATE:
|
||||
*skb_push(skb, 1) = 0;
|
||||
*skb_push(skb, 1) = 0;
|
||||
|
||||
r = nfc_hci_send_cmd(hdev, target->hci_reader_gate,
|
||||
PN544_FELICA_RAW,
|
||||
skb->data, skb->len, res_skb);
|
||||
if (r == 0)
|
||||
skb_pull(*res_skb, 1);
|
||||
return r;
|
||||
info->async_cb_type = PN544_CB_TYPE_READER_F;
|
||||
info->async_cb = cb;
|
||||
info->async_cb_context = cb_context;
|
||||
|
||||
return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
|
||||
PN544_FELICA_RAW, skb->data,
|
||||
skb->len,
|
||||
pn544_hci_data_exchange_cb, info);
|
||||
case PN544_RF_READER_JEWEL_GATE:
|
||||
return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
|
||||
PN544_JEWEL_RAW_CMD,
|
||||
skb->data, skb->len, res_skb);
|
||||
return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
|
||||
PN544_JEWEL_RAW_CMD, skb->data,
|
||||
skb->len, cb, cb_context);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int pn544_hci_check_presence(struct nfc_shdlc *shdlc,
|
||||
static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target)
|
||||
{
|
||||
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
|
||||
|
||||
return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
|
||||
PN544_RF_READER_CMD_PRESENCE_CHECK,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static struct nfc_shdlc_ops pn544_shdlc_ops = {
|
||||
static struct nfc_hci_ops pn544_hci_ops = {
|
||||
.open = pn544_hci_open,
|
||||
.close = pn544_hci_close,
|
||||
.hci_ready = pn544_hci_ready,
|
||||
|
@ -848,8 +903,8 @@ static int __devinit pn544_hci_probe(struct i2c_client *client,
|
|||
pn544_hci_platform_init(info);
|
||||
|
||||
r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn,
|
||||
IRQF_TRIGGER_RISING, PN544_HCI_DRIVER_NAME,
|
||||
info);
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
PN544_HCI_DRIVER_NAME, info);
|
||||
if (r < 0) {
|
||||
dev_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
goto err_rti;
|
||||
|
@ -872,22 +927,30 @@ static int __devinit pn544_hci_probe(struct i2c_client *client,
|
|||
NFC_PROTO_ISO14443_B_MASK |
|
||||
NFC_PROTO_NFC_DEP_MASK;
|
||||
|
||||
info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops,
|
||||
&init_data, protocols,
|
||||
PN544_CMDS_HEADROOM, 0,
|
||||
PN544_HCI_LLC_MAX_PAYLOAD,
|
||||
dev_name(&client->dev));
|
||||
if (!info->shdlc) {
|
||||
dev_err(&client->dev, "Cannot allocate nfc shdlc.\n");
|
||||
info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
|
||||
protocols, LLC_SHDLC_NAME,
|
||||
PN544_FRAME_HEADROOM +
|
||||
PN544_CMDS_HEADROOM,
|
||||
PN544_FRAME_TAILROOM,
|
||||
PN544_HCI_LLC_MAX_PAYLOAD);
|
||||
if (!info->hdev) {
|
||||
dev_err(&client->dev, "Cannot allocate nfc hdev.\n");
|
||||
r = -ENOMEM;
|
||||
goto err_allocshdlc;
|
||||
goto err_alloc_hdev;
|
||||
}
|
||||
|
||||
nfc_shdlc_set_clientdata(info->shdlc, info);
|
||||
nfc_hci_set_clientdata(info->hdev, info);
|
||||
|
||||
r = nfc_hci_register_device(info->hdev);
|
||||
if (r)
|
||||
goto err_regdev;
|
||||
|
||||
return 0;
|
||||
|
||||
err_allocshdlc:
|
||||
err_regdev:
|
||||
nfc_hci_free_device(info->hdev);
|
||||
|
||||
err_alloc_hdev:
|
||||
free_irq(client->irq, info);
|
||||
|
||||
err_rti:
|
||||
|
@ -908,7 +971,7 @@ static __devexit int pn544_hci_remove(struct i2c_client *client)
|
|||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
nfc_shdlc_free(info->shdlc);
|
||||
nfc_hci_free_device(info->hdev);
|
||||
|
||||
if (info->state != PN544_ST_COLD) {
|
||||
if (pdata->disable)
|
||||
|
|
|
@ -1934,36 +1934,6 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr,
|
|||
return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_fhss_chan_to_freq - get channel frequency
|
||||
* @channel: the FHSS channel
|
||||
*
|
||||
* Convert IEEE802.11 FHSS channel to frequency (MHz)
|
||||
* Ref IEEE 802.11-2007 section 14.6
|
||||
*/
|
||||
static inline int ieee80211_fhss_chan_to_freq(int channel)
|
||||
{
|
||||
if ((channel > 1) && (channel < 96))
|
||||
return channel + 2400;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_freq_to_fhss_chan - get channel
|
||||
* @freq: the channels frequency
|
||||
*
|
||||
* Convert frequency (MHz) to IEEE802.11 FHSS channel
|
||||
* Ref IEEE 802.11-2007 section 14.6
|
||||
*/
|
||||
static inline int ieee80211_freq_to_fhss_chan(int freq)
|
||||
{
|
||||
if ((freq > 2401) && (freq < 2496))
|
||||
return freq - 2400;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_dsss_chan_to_freq - get channel center frequency
|
||||
* @channel: the DSSS channel
|
||||
|
@ -2000,56 +1970,6 @@ static inline int ieee80211_freq_to_dsss_chan(int freq)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Convert IEEE802.11 HR DSSS channel to frequency (MHz) and back
|
||||
* Ref IEEE 802.11-2007 section 18.4.6.2
|
||||
*
|
||||
* The channels and frequencies are the same as those defined for DSSS
|
||||
*/
|
||||
#define ieee80211_hr_chan_to_freq(chan) ieee80211_dsss_chan_to_freq(chan)
|
||||
#define ieee80211_freq_to_hr_chan(freq) ieee80211_freq_to_dsss_chan(freq)
|
||||
|
||||
/* Convert IEEE802.11 ERP channel to frequency (MHz) and back
|
||||
* Ref IEEE 802.11-2007 section 19.4.2
|
||||
*/
|
||||
#define ieee80211_erp_chan_to_freq(chan) ieee80211_hr_chan_to_freq(chan)
|
||||
#define ieee80211_freq_to_erp_chan(freq) ieee80211_freq_to_hr_chan(freq)
|
||||
|
||||
/**
|
||||
* ieee80211_ofdm_chan_to_freq - get channel center frequency
|
||||
* @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
|
||||
* @channel: the OFDM channel
|
||||
*
|
||||
* Convert IEEE802.11 OFDM channel to center frequency (MHz)
|
||||
* Ref IEEE 802.11-2007 section 17.3.8.3.2
|
||||
*/
|
||||
static inline int ieee80211_ofdm_chan_to_freq(int s_freq, int channel)
|
||||
{
|
||||
if ((channel > 0) && (channel <= 200) &&
|
||||
(s_freq >= 4000))
|
||||
return s_freq + (channel * 5);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_freq_to_ofdm_channel - get channel
|
||||
* @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
|
||||
* @freq: the frequency
|
||||
*
|
||||
* Convert frequency (MHz) to IEEE802.11 OFDM channel
|
||||
* Ref IEEE 802.11-2007 section 17.3.8.3.2
|
||||
*
|
||||
* This routine selects the channel with the closest center frequency.
|
||||
*/
|
||||
static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq)
|
||||
{
|
||||
if ((freq > (s_freq + 2)) && (freq <= (s_freq + 1202)) &&
|
||||
(s_freq >= 4000))
|
||||
return (freq + 2 - s_freq) / 5;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_tu_to_usec - convert time units (TU) to microseconds
|
||||
* @tu: the TUs
|
||||
|
|
|
@ -183,4 +183,15 @@ struct sockaddr_nfc_llcp {
|
|||
|
||||
#define NFC_HEADER_SIZE 1
|
||||
|
||||
/**
|
||||
* Pseudo-header info for raw socket packets
|
||||
* First byte is the adapter index
|
||||
* Second byte contains flags
|
||||
* - 0x01 - Direction (0=RX, 1=TX)
|
||||
* - 0x02-0x80 - Reserved
|
||||
**/
|
||||
#define NFC_LLCP_RAW_HEADER_SIZE 2
|
||||
#define NFC_LLCP_DIRECTION_RX 0x00
|
||||
#define NFC_LLCP_DIRECTION_TX 0x01
|
||||
|
||||
#endif /*__LINUX_NFC_H */
|
||||
|
|
|
@ -573,6 +573,11 @@
|
|||
* @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by
|
||||
* its %NL80211_ATTR_WDEV identifier.
|
||||
*
|
||||
* @NL80211_CMD_CONN_FAILED: connection request to an AP failed; used to
|
||||
* notify userspace that AP has rejected the connection request from a
|
||||
* station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON
|
||||
* is used for this.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -719,6 +724,8 @@ enum nl80211_commands {
|
|||
NL80211_CMD_START_P2P_DEVICE,
|
||||
NL80211_CMD_STOP_P2P_DEVICE,
|
||||
|
||||
NL80211_CMD_CONN_FAILED,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
|
@ -1262,6 +1269,10 @@ enum nl80211_commands {
|
|||
* was used to provide the hint. For the different types of
|
||||
* allowed user regulatory hints see nl80211_user_reg_hint_type.
|
||||
*
|
||||
* @NL80211_ATTR_CONN_FAILED_REASON: The reason for which AP has rejected
|
||||
* the connection request from a station. nl80211_connect_failed_reason
|
||||
* enum has different reasons of connection failure.
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -1517,6 +1528,8 @@ enum nl80211_attrs {
|
|||
|
||||
NL80211_ATTR_USER_REG_HINT_TYPE,
|
||||
|
||||
NL80211_ATTR_CONN_FAILED_REASON,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -3045,4 +3058,15 @@ enum nl80211_probe_resp_offload_support_attr {
|
|||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_connect_failed_reason - connection request failed reasons
|
||||
* @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
|
||||
* handled by the AP is reached.
|
||||
* @NL80211_CONN_FAIL_BLOCKED_CLIENT: Client's MAC is in the AP's blocklist.
|
||||
*/
|
||||
enum nl80211_connect_failed_reason {
|
||||
NL80211_CONN_FAIL_MAX_CLIENTS,
|
||||
NL80211_CONN_FAIL_BLOCKED_CLIENT,
|
||||
};
|
||||
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
|
|
|
@ -302,8 +302,11 @@ enum {
|
|||
|
||||
/* ---- HCI Error Codes ---- */
|
||||
#define HCI_ERROR_AUTH_FAILURE 0x05
|
||||
#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
|
||||
#define HCI_ERROR_REJ_BAD_ADDR 0x0f
|
||||
#define HCI_ERROR_REMOTE_USER_TERM 0x13
|
||||
#define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14
|
||||
#define HCI_ERROR_REMOTE_POWER_OFF 0x15
|
||||
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
|
||||
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
|
||||
|
||||
|
@ -1246,6 +1249,24 @@ struct hci_ev_simple_pair_complete {
|
|||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_USER_PASSKEY_NOTIFY 0x3b
|
||||
struct hci_ev_user_passkey_notify {
|
||||
bdaddr_t bdaddr;
|
||||
__le32 passkey;
|
||||
} __packed;
|
||||
|
||||
#define HCI_KEYPRESS_STARTED 0
|
||||
#define HCI_KEYPRESS_ENTERED 1
|
||||
#define HCI_KEYPRESS_ERASED 2
|
||||
#define HCI_KEYPRESS_CLEARED 3
|
||||
#define HCI_KEYPRESS_COMPLETED 4
|
||||
|
||||
#define HCI_EV_KEYPRESS_NOTIFY 0x3c
|
||||
struct hci_ev_keypress_notify {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 type;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
|
||||
struct hci_ev_remote_host_features {
|
||||
bdaddr_t bdaddr;
|
||||
|
|
|
@ -303,6 +303,8 @@ struct hci_conn {
|
|||
__u8 pin_length;
|
||||
__u8 enc_key_size;
|
||||
__u8 io_capability;
|
||||
__u32 passkey_notify;
|
||||
__u8 passkey_entered;
|
||||
__u16 disc_timeout;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -428,15 +430,6 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
|
|||
test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
|
||||
}
|
||||
|
||||
static inline void hci_conn_hash_init(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
INIT_LIST_HEAD(&h->list);
|
||||
h->acl_num = 0;
|
||||
h->sco_num = 0;
|
||||
h->le_num = 0;
|
||||
}
|
||||
|
||||
static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
|
@ -551,9 +544,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void hci_acl_connect(struct hci_conn *conn);
|
||||
void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
|
||||
void hci_add_sco(struct hci_conn *conn, __u16 handle);
|
||||
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
|
||||
void hci_sco_setup(struct hci_conn *conn, __u8 status);
|
||||
|
||||
|
@ -563,7 +554,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev);
|
|||
void hci_conn_check_pending(struct hci_dev *hdev);
|
||||
|
||||
struct hci_chan *hci_chan_create(struct hci_conn *conn);
|
||||
int hci_chan_del(struct hci_chan *chan);
|
||||
void hci_chan_del(struct hci_chan *chan);
|
||||
void hci_chan_list_flush(struct hci_conn *conn);
|
||||
|
||||
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
|
@ -614,11 +605,17 @@ static inline void hci_conn_put(struct hci_conn *conn)
|
|||
/* ----- HCI Devices ----- */
|
||||
static inline void hci_dev_put(struct hci_dev *d)
|
||||
{
|
||||
BT_DBG("%s orig refcnt %d", d->name,
|
||||
atomic_read(&d->dev.kobj.kref.refcount));
|
||||
|
||||
put_device(&d->dev);
|
||||
}
|
||||
|
||||
static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
|
||||
{
|
||||
BT_DBG("%s orig refcnt %d", d->name,
|
||||
atomic_read(&d->dev.kobj.kref.refcount));
|
||||
|
||||
get_device(&d->dev);
|
||||
return d;
|
||||
}
|
||||
|
@ -1004,7 +1001,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
|||
u8 addr_type, u32 flags, u8 *name, u8 name_len,
|
||||
u8 *dev_class);
|
||||
int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type);
|
||||
u8 link_type, u8 addr_type, u8 reason);
|
||||
int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 status);
|
||||
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
|
@ -1027,6 +1024,9 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||
u8 link_type, u8 addr_type, u8 status);
|
||||
int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 status);
|
||||
int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u32 passkey,
|
||||
u8 entered);
|
||||
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 status);
|
||||
int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
|
||||
|
|
|
@ -433,11 +433,10 @@ struct l2cap_chan {
|
|||
struct sock *sk;
|
||||
|
||||
struct l2cap_conn *conn;
|
||||
struct kref kref;
|
||||
|
||||
__u8 state;
|
||||
|
||||
atomic_t refcnt;
|
||||
|
||||
__le16 psm;
|
||||
__u16 dcid;
|
||||
__u16 scid;
|
||||
|
|
|
@ -405,7 +405,16 @@ struct mgmt_ev_device_connected {
|
|||
__u8 eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_DEV_DISCONN_UNKNOWN 0x00
|
||||
#define MGMT_DEV_DISCONN_TIMEOUT 0x01
|
||||
#define MGMT_DEV_DISCONN_LOCAL_HOST 0x02
|
||||
#define MGMT_DEV_DISCONN_REMOTE 0x03
|
||||
|
||||
#define MGMT_EV_DEVICE_DISCONNECTED 0x000C
|
||||
struct mgmt_ev_device_disconnected {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 reason;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONNECT_FAILED 0x000D
|
||||
struct mgmt_ev_connect_failed {
|
||||
|
@ -469,3 +478,10 @@ struct mgmt_ev_device_unblocked {
|
|||
struct mgmt_ev_device_unpaired {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_PASSKEY_NOTIFY 0x0017
|
||||
struct mgmt_ev_passkey_notify {
|
||||
struct mgmt_addr_info addr;
|
||||
__le32 passkey;
|
||||
__u8 entered;
|
||||
} __packed;
|
||||
|
|
|
@ -1580,9 +1580,7 @@ struct cfg80211_gtk_rekey_data {
|
|||
* @set_cqm_txe_config: Configure connection quality monitor TX error
|
||||
* thresholds.
|
||||
* @sched_scan_start: Tell the driver to start a scheduled scan.
|
||||
* @sched_scan_stop: Tell the driver to stop an ongoing scheduled
|
||||
* scan. The driver_initiated flag specifies whether the driver
|
||||
* itself has informed that the scan has stopped.
|
||||
* @sched_scan_stop: Tell the driver to stop an ongoing scheduled scan.
|
||||
*
|
||||
* @mgmt_frame_register: Notify driver that a management frame type was
|
||||
* registered. Note that this callback may not sleep, and cannot run
|
||||
|
@ -1630,7 +1628,7 @@ struct cfg80211_ops {
|
|||
void (*set_wakeup)(struct wiphy *wiphy, bool enabled);
|
||||
|
||||
struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy,
|
||||
char *name,
|
||||
const char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params);
|
||||
|
@ -3362,6 +3360,25 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
|
|||
*/
|
||||
void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_conn_failed - connection request failed notification
|
||||
*
|
||||
* @dev: the netdev
|
||||
* @mac_addr: the station's address
|
||||
* @reason: the reason for connection failure
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* Whenever a station tries to connect to an AP and if the station
|
||||
* could not connect to the AP as the AP has rejected the connection
|
||||
* for some reasons, this function is called.
|
||||
*
|
||||
* The reason for connection failure can be any of the value from
|
||||
* nl80211_connect_failed_reason enum
|
||||
*/
|
||||
void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
|
||||
enum nl80211_connect_failed_reason reason,
|
||||
gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_rx_mgmt - notification of received, unprocessed management frame
|
||||
* @wdev: wireless device receiving the frame
|
||||
|
|
|
@ -973,21 +973,29 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
|
|||
* generation in software.
|
||||
* @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates
|
||||
* that the key is pairwise rather then a shared key.
|
||||
* @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a
|
||||
* @IEEE80211_KEY_FLAG_SW_MGMT_TX: This flag should be set by the driver for a
|
||||
* CCMP key if it requires CCMP encryption of management frames (MFP) to
|
||||
* be done in software.
|
||||
* @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
|
||||
* if space should be prepared for the IV, but the IV
|
||||
* itself should not be generated. Do not set together with
|
||||
* @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
|
||||
* @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received
|
||||
* management frames. The flag can help drivers that have a hardware
|
||||
* crypto implementation that doesn't deal with management frames
|
||||
* properly by allowing them to not upload the keys to hardware and
|
||||
* fall back to software crypto. Note that this flag deals only with
|
||||
* RX, if your crypto engine can't deal with TX you can also set the
|
||||
* %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW.
|
||||
*/
|
||||
enum ieee80211_key_flags {
|
||||
IEEE80211_KEY_FLAG_WMM_STA = 1<<0,
|
||||
IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1,
|
||||
IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
|
||||
IEEE80211_KEY_FLAG_PAIRWISE = 1<<3,
|
||||
IEEE80211_KEY_FLAG_SW_MGMT = 1<<4,
|
||||
IEEE80211_KEY_FLAG_SW_MGMT_TX = 1<<4,
|
||||
IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5,
|
||||
IEEE80211_KEY_FLAG_RX_MGMT = 1<<6,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,11 @@ struct nfc_hci_ops {
|
|||
int (*open) (struct nfc_hci_dev *hdev);
|
||||
void (*close) (struct nfc_hci_dev *hdev);
|
||||
int (*hci_ready) (struct nfc_hci_dev *hdev);
|
||||
/*
|
||||
* xmit must always send the complete buffer before
|
||||
* returning. Returned result must be 0 for success
|
||||
* or negative for failure.
|
||||
*/
|
||||
int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
|
||||
int (*start_poll) (struct nfc_hci_dev *hdev,
|
||||
u32 im_protocols, u32 tm_protocols);
|
||||
|
@ -38,8 +43,8 @@ struct nfc_hci_ops {
|
|||
int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
|
||||
struct nfc_target *target);
|
||||
int (*data_exchange) (struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target,
|
||||
struct sk_buff *skb, struct sk_buff **res_skb);
|
||||
struct nfc_target *target, struct sk_buff *skb,
|
||||
data_exchange_cb_t cb, void *cb_context);
|
||||
int (*check_presence)(struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target);
|
||||
};
|
||||
|
@ -74,7 +79,6 @@ struct nfc_hci_dev {
|
|||
|
||||
struct list_head msg_tx_queue;
|
||||
|
||||
struct workqueue_struct *msg_tx_wq;
|
||||
struct work_struct msg_tx_work;
|
||||
|
||||
struct timer_list cmd_timer;
|
||||
|
@ -82,13 +86,14 @@ struct nfc_hci_dev {
|
|||
|
||||
struct sk_buff_head rx_hcp_frags;
|
||||
|
||||
struct workqueue_struct *msg_rx_wq;
|
||||
struct work_struct msg_rx_work;
|
||||
|
||||
struct sk_buff_head msg_rx_queue;
|
||||
|
||||
struct nfc_hci_ops *ops;
|
||||
|
||||
struct nfc_llc *llc;
|
||||
|
||||
struct nfc_hci_init_data init_data;
|
||||
|
||||
void *clientdata;
|
||||
|
@ -105,12 +110,17 @@ struct nfc_hci_dev {
|
|||
u8 hw_mpw;
|
||||
u8 hw_software;
|
||||
u8 hw_bsid;
|
||||
|
||||
int async_cb_type;
|
||||
data_exchange_cb_t async_cb;
|
||||
void *async_cb_context;
|
||||
};
|
||||
|
||||
/* hci device allocation */
|
||||
struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
|
||||
struct nfc_hci_init_data *init_data,
|
||||
u32 protocols,
|
||||
const char *llc_name,
|
||||
int tx_headroom,
|
||||
int tx_tailroom,
|
||||
int max_link_payload);
|
||||
|
@ -202,6 +212,9 @@ int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx,
|
|||
const u8 *param, size_t param_len);
|
||||
int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
|
||||
const u8 *param, size_t param_len, struct sk_buff **skb);
|
||||
int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
|
||||
const u8 *param, size_t param_len,
|
||||
data_exchange_cb_t cb, void *cb_context);
|
||||
int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response,
|
||||
const u8 *param, size_t param_len);
|
||||
int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Link Layer Control manager public interface
|
||||
*
|
||||
* Copyright (C) 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __NFC_LLC_H_
|
||||
#define __NFC_LLC_H_
|
||||
|
||||
#include <net/nfc/hci.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#define LLC_NOP_NAME "nop"
|
||||
#define LLC_SHDLC_NAME "shdlc"
|
||||
|
||||
typedef void (*rcv_to_hci_t) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
|
||||
typedef int (*xmit_to_drv_t) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
|
||||
typedef void (*llc_failure_t) (struct nfc_hci_dev *hdev, int err);
|
||||
|
||||
struct nfc_llc;
|
||||
|
||||
struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev,
|
||||
xmit_to_drv_t xmit_to_drv,
|
||||
rcv_to_hci_t rcv_to_hci, int tx_headroom,
|
||||
int tx_tailroom, llc_failure_t llc_failure);
|
||||
void nfc_llc_free(struct nfc_llc *llc);
|
||||
|
||||
void nfc_llc_get_rx_head_tail_room(struct nfc_llc *llc, int *rx_headroom,
|
||||
int *rx_tailroom);
|
||||
|
||||
|
||||
int nfc_llc_start(struct nfc_llc *llc);
|
||||
int nfc_llc_stop(struct nfc_llc *llc);
|
||||
void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb);
|
||||
int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb);
|
||||
|
||||
int nfc_llc_init(void);
|
||||
void nfc_llc_exit(void);
|
||||
|
||||
#endif /* __NFC_LLC_H_ */
|
|
@ -32,6 +32,7 @@
|
|||
#define NCI_MAX_NUM_MAPPING_CONFIGS 10
|
||||
#define NCI_MAX_NUM_RF_CONFIGS 10
|
||||
#define NCI_MAX_NUM_CONN 10
|
||||
#define NCI_MAX_PARAM_LEN 251
|
||||
|
||||
/* NCI Status Codes */
|
||||
#define NCI_STATUS_OK 0x00
|
||||
|
@ -102,6 +103,9 @@
|
|||
#define NCI_RF_INTERFACE_ISO_DEP 0x02
|
||||
#define NCI_RF_INTERFACE_NFC_DEP 0x03
|
||||
|
||||
/* NCI Configuration Parameter Tags */
|
||||
#define NCI_PN_ATR_REQ_GEN_BYTES 0x29
|
||||
|
||||
/* NCI Reset types */
|
||||
#define NCI_RESET_TYPE_KEEP_CONFIG 0x00
|
||||
#define NCI_RESET_TYPE_RESET_CONFIG 0x01
|
||||
|
@ -188,6 +192,18 @@ struct nci_core_reset_cmd {
|
|||
|
||||
#define NCI_OP_CORE_INIT_CMD nci_opcode_pack(NCI_GID_CORE, 0x01)
|
||||
|
||||
#define NCI_OP_CORE_SET_CONFIG_CMD nci_opcode_pack(NCI_GID_CORE, 0x02)
|
||||
struct set_config_param {
|
||||
__u8 id;
|
||||
__u8 len;
|
||||
__u8 val[NCI_MAX_PARAM_LEN];
|
||||
} __packed;
|
||||
|
||||
struct nci_core_set_config_cmd {
|
||||
__u8 num_params;
|
||||
struct set_config_param param; /* support 1 param per cmd is enough */
|
||||
} __packed;
|
||||
|
||||
#define NCI_OP_RF_DISCOVER_MAP_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
|
||||
struct disc_map_config {
|
||||
__u8 rf_protocol;
|
||||
|
@ -252,6 +268,13 @@ struct nci_core_init_rsp_2 {
|
|||
__le32 manufact_specific_info;
|
||||
} __packed;
|
||||
|
||||
#define NCI_OP_CORE_SET_CONFIG_RSP nci_opcode_pack(NCI_GID_CORE, 0x02)
|
||||
struct nci_core_set_config_rsp {
|
||||
__u8 status;
|
||||
__u8 num_params;
|
||||
__u8 params_id[0]; /* variable size array */
|
||||
} __packed;
|
||||
|
||||
#define NCI_OP_RF_DISCOVER_MAP_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
|
||||
|
||||
#define NCI_OP_RF_DISCOVER_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
|
||||
|
@ -328,6 +351,11 @@ struct activation_params_nfcb_poll_iso_dep {
|
|||
__u8 attrib_res[50];
|
||||
};
|
||||
|
||||
struct activation_params_poll_nfc_dep {
|
||||
__u8 atr_res_len;
|
||||
__u8 atr_res[63];
|
||||
};
|
||||
|
||||
struct nci_rf_intf_activated_ntf {
|
||||
__u8 rf_discovery_id;
|
||||
__u8 rf_interface;
|
||||
|
@ -351,6 +379,7 @@ struct nci_rf_intf_activated_ntf {
|
|||
union {
|
||||
struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep;
|
||||
struct activation_params_nfcb_poll_iso_dep nfcb_poll_iso_dep;
|
||||
struct activation_params_poll_nfc_dep poll_nfc_dep;
|
||||
} activation_params;
|
||||
|
||||
} __packed;
|
||||
|
|
|
@ -54,6 +54,7 @@ enum nci_state {
|
|||
/* NCI timeouts */
|
||||
#define NCI_RESET_TIMEOUT 5000
|
||||
#define NCI_INIT_TIMEOUT 5000
|
||||
#define NCI_SET_CONFIG_TIMEOUT 5000
|
||||
#define NCI_RF_DISC_TIMEOUT 5000
|
||||
#define NCI_RF_DISC_SELECT_TIMEOUT 5000
|
||||
#define NCI_RF_DEACTIVATE_TIMEOUT 30000
|
||||
|
@ -137,6 +138,10 @@ struct nci_dev {
|
|||
data_exchange_cb_t data_exchange_cb;
|
||||
void *data_exchange_cb_context;
|
||||
struct sk_buff *rx_data_reassembly;
|
||||
|
||||
/* stored during intf_activated_ntf */
|
||||
__u8 remote_gb[NFC_MAX_GT_LEN];
|
||||
__u8 remote_gb_len;
|
||||
};
|
||||
|
||||
/* ----- NCI Devices ----- */
|
||||
|
|
|
@ -72,6 +72,7 @@ struct nfc_ops {
|
|||
|
||||
#define NFC_TARGET_IDX_ANY -1
|
||||
#define NFC_MAX_GT_LEN 48
|
||||
#define NFC_ATR_RES_GT_OFFSET 15
|
||||
|
||||
struct nfc_target {
|
||||
u32 idx;
|
||||
|
@ -112,7 +113,6 @@ struct nfc_dev {
|
|||
int tx_tailroom;
|
||||
|
||||
struct timer_list check_pres_timer;
|
||||
struct workqueue_struct *check_pres_wq;
|
||||
struct work_struct check_pres_work;
|
||||
|
||||
struct nfc_ops *ops;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue