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:
David S. Miller 2012-09-30 02:30:16 -04:00
commit a248afdc1b
148 changed files with 3979 additions and 3473 deletions

View file

@ -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

View file

@ -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

View file

@ -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, },

View file

@ -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:

View file

@ -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);

View file

@ -600,8 +600,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
exit:
if (ret) {
hdev->stat.err_rx++;
if (skb)
kfree_skb(skb);
kfree_skb(skb);
}
return ret;

View file

@ -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);

View file

@ -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) },

View file

@ -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 ------ */

View file

@ -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;
}

View file

@ -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--;

View file

@ -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;
}

View file

@ -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,

View file

@ -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 =

View file

@ -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;

View file

@ -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 */

View file

@ -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)
{

View file

@ -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,

View file

@ -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 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
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);
}

View file

@ -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)

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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 */

View file

@ -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},

View file

@ -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;

View file

@ -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;
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)

View file

@ -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);

View file

@ -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;

View file

@ -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 */

View file

@ -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

View file

@ -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];

View file

@ -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);

View file

@ -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;

View file

@ -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,8 +250,8 @@ static void ath9k_mci_work(struct work_struct *work)
ath_mci_update_scheme(sc);
}
static void ath_mci_process_profile(struct ath_softc *sc,
struct ath_mci_profile_info *info)
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);
struct ath_btcoex *btcoex = &sc->btcoex;
@ -268,25 +277,15 @@ 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,
struct ath_mci_profile_status *status)
static u8 ath_mci_process_status(struct ath_softc *sc,
struct ath_mci_profile_status *status)
{
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_mci_profile *mci = &btcoex->mci;
@ -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)

View file

@ -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);

View file

@ -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)
caps |= WLAN_RC_SGI_FLAG;
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;

View file

@ -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;

View file

@ -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 |

View file

@ -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,
addr, pkt);
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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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 */
memcpy(&buf[len], data, datalen);
len += datalen;
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,8 +524,9 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,
}
#ifdef DEBUG
brcmf_c_show_host_event(event, event_data);
#endif /* DEBUG */
if (BRCMF_EVENT_ON())
brcmf_c_show_host_event(event, event_data);
#endif /* DEBUG */
return 0;
}

View file

@ -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) */

View file

@ -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

View file

@ -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

View file

@ -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;
}
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);
}

View file

@ -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,
request->ssids[i].ssid_len);
if (!ssid.SSID_len)
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_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 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
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,7 +2633,20 @@ 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,
@ -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;
}
clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
brcmf_abort_scanning(cfg_priv);
else
clear_bit(WL_STATUS_SCANNING, &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;
}

View file

@ -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 */

View file

@ -304,7 +304,10 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
wl->mute_tx = true;
if (!wl->pub->up)
err = brcms_up(wl);
if (!blocked)
err = brcms_up(wl);
else
err = -ERFKILL;
else
err = -ENODEV;
spin_unlock_bh(&wl->lock);

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -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;

View file

@ -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;
}
@ -186,21 +185,24 @@ 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)
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;
}

View file

@ -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 */
};

View file

@ -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,

View file

@ -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);

View file

@ -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

View file

@ -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;
@ -945,8 +940,8 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
dst_addr);
iwl_write_direct32(trans,
FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
iwl_write_direct32(trans,
FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
@ -965,33 +960,64 @@ 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)
break;
for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
if (!image->sec[i].data)
break;
ret = iwl_load_section(trans, i, &image->sec[i]);
if (ret)
return ret;
}
ret = iwl_load_section(trans, i, &image->sec[i]);
if (ret)
return ret;
}
/* Remove all resets to allow NIC to operate */
iwl_write32(trans, CSR_RESET, 0);
@ -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);

View file

@ -2056,7 +2056,7 @@ static int __init init_mac80211_hwsim(void)
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);

View file

@ -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)

View file

@ -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;

View file

@ -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 {

View file

@ -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);

View file

@ -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");

View file

@ -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) |

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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_RX1_PD,
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);
if (rt2x00_rt(rt2x00dev, RT3390)) {
rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD,
rt2x00dev->default_ant.rx_chain_num == 1);
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;
}
}
rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD,
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,
@ -3081,7 +3069,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
} else if (rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392)) {
rt2x00_rt(rt2x00dev, RT5392)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@ -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) ||

View file

@ -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,

View file

@ -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,

View file

@ -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
*/

View file

@ -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.
*/

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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---

View file

@ -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

View file

@ -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 ------ */

View file

@ -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 @@ static int __pn533_send_cmd_frame_async(struct pn533 *dev,
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);
rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
in_frame_len, cmd_complete, arg, flags);
if (rc)
goto error;
if (!dev->cmd_pending) {
rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
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 @@ static void pn533_wq_mi_recv(struct work_struct *work)
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 @@ static int pn533_probe(struct usb_interface *interface,
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);

View file

@ -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);

View file

@ -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 @@ static int pn544_hci_i2c_read(struct i2c_client *client, struct sk_buff **skb)
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 @@ static int pn544_hci_open(struct nfc_shdlc *shdlc)
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 @@ static void pn544_hci_close(struct nfc_shdlc *shdlc)
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,
PN544_MIFARE_CMD,
skb->data, skb->len, res_skb);
return nfc_hci_send_cmd_async(hdev,
target->hci_reader_gate,
PN544_MIFARE_CMD,
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)

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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,
};
/**

View file

@ -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,

54
include/net/nfc/llc.h Normal file
View file

@ -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_ */

View file

@ -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;

View file

@ -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 ----- */

View file

@ -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