Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
Коммит
c3da63f357
|
@ -111,6 +111,8 @@ following attributes:
|
||||||
|
|
||||||
name: Name assigned by driver to this key (interface or driver name).
|
name: Name assigned by driver to this key (interface or driver name).
|
||||||
type: Driver type string ("wlan", "bluetooth", etc).
|
type: Driver type string ("wlan", "bluetooth", etc).
|
||||||
|
persistent: Whether the soft blocked state is initialised from
|
||||||
|
non-volatile storage at startup.
|
||||||
state: Current state of the transmitter
|
state: Current state of the transmitter
|
||||||
0: RFKILL_STATE_SOFT_BLOCKED
|
0: RFKILL_STATE_SOFT_BLOCKED
|
||||||
transmitter is turned off by software
|
transmitter is turned off by software
|
||||||
|
|
|
@ -940,7 +940,7 @@ M: me@bobcopeland.com
|
||||||
L: linux-wireless@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
L: ath5k-devel@lists.ath5k.org
|
L: ath5k-devel@lists.ath5k.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/net/wireless/ath5k/
|
F: drivers/net/wireless/ath/ath5k/
|
||||||
|
|
||||||
ATHEROS ATH9K WIRELESS DRIVER
|
ATHEROS ATH9K WIRELESS DRIVER
|
||||||
P: Luis R. Rodriguez
|
P: Luis R. Rodriguez
|
||||||
|
@ -956,7 +956,7 @@ M: senthilkumar@atheros.com
|
||||||
L: linux-wireless@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
L: ath9k-devel@lists.ath9k.org
|
L: ath9k-devel@lists.ath9k.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/net/wireless/ath9k/
|
F: drivers/net/wireless/ath/ath9k/
|
||||||
|
|
||||||
ATHEROS AR9170 WIRELESS DRIVER
|
ATHEROS AR9170 WIRELESS DRIVER
|
||||||
P: Christian Lamparter
|
P: Christian Lamparter
|
||||||
|
@ -964,7 +964,7 @@ M: chunkeey@web.de
|
||||||
L: linux-wireless@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
W: http://wireless.kernel.org/en/users/Drivers/ar9170
|
W: http://wireless.kernel.org/en/users/Drivers/ar9170
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/net/wireless/ar9170/
|
F: drivers/net/wireless/ath/ar9170/
|
||||||
|
|
||||||
ATI_REMOTE2 DRIVER
|
ATI_REMOTE2 DRIVER
|
||||||
P: Ville Syrjala
|
P: Ville Syrjala
|
||||||
|
|
|
@ -538,6 +538,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
|
||||||
sc->iobase = mem; /* So we can unmap it on detach */
|
sc->iobase = mem; /* So we can unmap it on detach */
|
||||||
sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
|
sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
|
||||||
sc->opmode = NL80211_IFTYPE_STATION;
|
sc->opmode = NL80211_IFTYPE_STATION;
|
||||||
|
sc->bintval = 1000;
|
||||||
mutex_init(&sc->lock);
|
mutex_init(&sc->lock);
|
||||||
spin_lock_init(&sc->rxbuflock);
|
spin_lock_init(&sc->rxbuflock);
|
||||||
spin_lock_init(&sc->txbuflock);
|
spin_lock_init(&sc->txbuflock);
|
||||||
|
@ -686,6 +687,13 @@ ath5k_pci_resume(struct pci_dev *pdev)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Suspend/Resume resets the PCI configuration space, so we have to
|
||||||
|
* re-disable the RETRY_TIMEOUT register (0x41) to keep
|
||||||
|
* PCI Tx retries from interfering with C3 CPU state
|
||||||
|
*/
|
||||||
|
pci_write_config_byte(pdev, 0x41, 0);
|
||||||
|
|
||||||
err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
|
err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
|
||||||
if (err) {
|
if (err) {
|
||||||
ATH5K_ERR(sc, "request_irq failed\n");
|
ATH5K_ERR(sc, "request_irq failed\n");
|
||||||
|
@ -2748,9 +2756,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set to a reasonable value. Note that this will
|
|
||||||
* be set to mac80211's value at ath5k_config(). */
|
|
||||||
sc->bintval = 1000;
|
|
||||||
ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
|
ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
|
@ -1196,8 +1196,8 @@ void ath_radio_disable(struct ath_softc *sc)
|
||||||
|
|
||||||
ath9k_hw_phy_disable(ah);
|
ath9k_hw_phy_disable(ah);
|
||||||
ath9k_hw_configpcipowersave(ah, 1);
|
ath9k_hw_configpcipowersave(ah, 1);
|
||||||
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
|
|
||||||
ath9k_ps_restore(sc);
|
ath9k_ps_restore(sc);
|
||||||
|
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************/
|
/*******************/
|
||||||
|
|
|
@ -87,6 +87,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
struct ath_softc *sc;
|
struct ath_softc *sc;
|
||||||
struct ieee80211_hw *hw;
|
struct ieee80211_hw *hw;
|
||||||
u8 csz;
|
u8 csz;
|
||||||
|
u32 val;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct ath_hw *ah;
|
struct ath_hw *ah;
|
||||||
|
|
||||||
|
@ -133,6 +134,14 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
|
|
||||||
pci_set_master(pdev);
|
pci_set_master(pdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable the RETRY_TIMEOUT register (0x41) to keep
|
||||||
|
* PCI Tx retries from interfering with C3 CPU state.
|
||||||
|
*/
|
||||||
|
pci_read_config_dword(pdev, 0x40, &val);
|
||||||
|
if ((val & 0x0000ff00) != 0)
|
||||||
|
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
|
||||||
|
|
||||||
ret = pci_request_region(pdev, 0, "ath9k");
|
ret = pci_request_region(pdev, 0, "ath9k");
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "PCI memory region reserve error\n");
|
dev_err(&pdev->dev, "PCI memory region reserve error\n");
|
||||||
|
@ -239,12 +248,21 @@ static int ath_pci_resume(struct pci_dev *pdev)
|
||||||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||||
struct ath_wiphy *aphy = hw->priv;
|
struct ath_wiphy *aphy = hw->priv;
|
||||||
struct ath_softc *sc = aphy->sc;
|
struct ath_softc *sc = aphy->sc;
|
||||||
|
u32 val;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = pci_enable_device(pdev);
|
err = pci_enable_device(pdev);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
pci_restore_state(pdev);
|
pci_restore_state(pdev);
|
||||||
|
/*
|
||||||
|
* Suspend/Resume resets the PCI configuration space, so we have to
|
||||||
|
* re-disable the RETRY_TIMEOUT register (0x41) to keep
|
||||||
|
* PCI Tx retries from interfering with C3 CPU state
|
||||||
|
*/
|
||||||
|
pci_read_config_dword(pdev, 0x40, &val);
|
||||||
|
if ((val & 0x0000ff00) != 0)
|
||||||
|
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
|
||||||
|
|
||||||
/* Enable LED */
|
/* Enable LED */
|
||||||
ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
|
ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
|
||||||
|
|
|
@ -539,11 +539,14 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
|
||||||
if (ath_beacon_dtim_pending_cab(skb)) {
|
if (ath_beacon_dtim_pending_cab(skb)) {
|
||||||
/*
|
/*
|
||||||
* Remain awake waiting for buffered broadcast/multicast
|
* Remain awake waiting for buffered broadcast/multicast
|
||||||
* frames.
|
* frames. If the last broadcast/multicast frame is not
|
||||||
|
* received properly, the next beacon frame will work as
|
||||||
|
* a backup trigger for returning into NETWORK SLEEP state,
|
||||||
|
* so we are waiting for it as well.
|
||||||
*/
|
*/
|
||||||
DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating "
|
DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating "
|
||||||
"buffered broadcast/multicast frame(s)\n");
|
"buffered broadcast/multicast frame(s)\n");
|
||||||
sc->sc_flags |= SC_OP_WAIT_FOR_CAB;
|
sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -288,6 +288,7 @@ struct iwm_priv {
|
||||||
u8 *eeprom;
|
u8 *eeprom;
|
||||||
struct timer_list watchdog;
|
struct timer_list watchdog;
|
||||||
struct work_struct reset_worker;
|
struct work_struct reset_worker;
|
||||||
|
struct mutex mutex;
|
||||||
struct rfkill *rfkill;
|
struct rfkill *rfkill;
|
||||||
|
|
||||||
char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
|
char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
|
||||||
|
@ -315,8 +316,11 @@ extern const struct iw_handler_def iwm_iw_handler_def;
|
||||||
void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
||||||
struct iwm_if_ops *if_ops);
|
struct iwm_if_ops *if_ops);
|
||||||
void iwm_if_free(struct iwm_priv *iwm);
|
void iwm_if_free(struct iwm_priv *iwm);
|
||||||
|
int iwm_if_add(struct iwm_priv *iwm);
|
||||||
|
void iwm_if_remove(struct iwm_priv *iwm);
|
||||||
int iwm_mode_to_nl80211_iftype(int mode);
|
int iwm_mode_to_nl80211_iftype(int mode);
|
||||||
int iwm_priv_init(struct iwm_priv *iwm);
|
int iwm_priv_init(struct iwm_priv *iwm);
|
||||||
|
void iwm_priv_deinit(struct iwm_priv *iwm);
|
||||||
void iwm_reset(struct iwm_priv *iwm);
|
void iwm_reset(struct iwm_priv *iwm);
|
||||||
void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
|
void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
|
||||||
struct iwm_umac_notif_alive *alive);
|
struct iwm_umac_notif_alive *alive);
|
||||||
|
|
|
@ -112,6 +112,9 @@ static void iwm_statistics_request(struct work_struct *work)
|
||||||
iwm_send_umac_stats_req(iwm, 0);
|
iwm_send_umac_stats_req(iwm, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __iwm_up(struct iwm_priv *iwm);
|
||||||
|
int __iwm_down(struct iwm_priv *iwm);
|
||||||
|
|
||||||
static void iwm_reset_worker(struct work_struct *work)
|
static void iwm_reset_worker(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct iwm_priv *iwm;
|
struct iwm_priv *iwm;
|
||||||
|
@ -120,6 +123,19 @@ static void iwm_reset_worker(struct work_struct *work)
|
||||||
|
|
||||||
iwm = container_of(work, struct iwm_priv, reset_worker);
|
iwm = container_of(work, struct iwm_priv, reset_worker);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: The iwm->mutex is introduced purely for this reset work,
|
||||||
|
* because the other users for iwm_up and iwm_down are only netdev
|
||||||
|
* ndo_open and ndo_stop which are already protected by rtnl.
|
||||||
|
* Please remove iwm->mutex together if iwm_reset_worker() is not
|
||||||
|
* required in the future.
|
||||||
|
*/
|
||||||
|
if (!mutex_trylock(&iwm->mutex)) {
|
||||||
|
IWM_WARN(iwm, "We are in the middle of interface bringing "
|
||||||
|
"UP/DOWN. Skip driver resetting.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (iwm->umac_profile_active) {
|
if (iwm->umac_profile_active) {
|
||||||
profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL);
|
profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL);
|
||||||
if (profile)
|
if (profile)
|
||||||
|
@ -128,10 +144,10 @@ static void iwm_reset_worker(struct work_struct *work)
|
||||||
IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
|
IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
iwm_down(iwm);
|
__iwm_down(iwm);
|
||||||
|
|
||||||
while (retry++ < 3) {
|
while (retry++ < 3) {
|
||||||
ret = iwm_up(iwm);
|
ret = __iwm_up(iwm);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -142,7 +158,7 @@ static void iwm_reset_worker(struct work_struct *work)
|
||||||
IWM_WARN(iwm, "iwm_up() failed: %d\n", ret);
|
IWM_WARN(iwm, "iwm_up() failed: %d\n", ret);
|
||||||
|
|
||||||
kfree(profile);
|
kfree(profile);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile) {
|
if (profile) {
|
||||||
|
@ -151,6 +167,9 @@ static void iwm_reset_worker(struct work_struct *work)
|
||||||
iwm_send_mlme_profile(iwm);
|
iwm_send_mlme_profile(iwm);
|
||||||
kfree(profile);
|
kfree(profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&iwm->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iwm_watchdog(unsigned long data)
|
static void iwm_watchdog(unsigned long data)
|
||||||
|
@ -215,10 +234,21 @@ int iwm_priv_init(struct iwm_priv *iwm)
|
||||||
init_timer(&iwm->watchdog);
|
init_timer(&iwm->watchdog);
|
||||||
iwm->watchdog.function = iwm_watchdog;
|
iwm->watchdog.function = iwm_watchdog;
|
||||||
iwm->watchdog.data = (unsigned long)iwm;
|
iwm->watchdog.data = (unsigned long)iwm;
|
||||||
|
mutex_init(&iwm->mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iwm_priv_deinit(struct iwm_priv *iwm)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < IWM_TX_QUEUES; i++)
|
||||||
|
destroy_workqueue(iwm->txq[i].wq);
|
||||||
|
|
||||||
|
destroy_workqueue(iwm->rx_wq);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We reset all the structures, and we reset the UMAC.
|
* We reset all the structures, and we reset the UMAC.
|
||||||
* After calling this routine, you're expected to reload
|
* After calling this routine, you're expected to reload
|
||||||
|
@ -466,7 +496,7 @@ void iwm_link_off(struct iwm_priv *iwm)
|
||||||
|
|
||||||
iwm_rx_free(iwm);
|
iwm_rx_free(iwm);
|
||||||
|
|
||||||
cancel_delayed_work(&iwm->stats_request);
|
cancel_delayed_work_sync(&iwm->stats_request);
|
||||||
memset(wstats, 0, sizeof(struct iw_statistics));
|
memset(wstats, 0, sizeof(struct iw_statistics));
|
||||||
wstats->qual.updated = IW_QUAL_ALL_INVALID;
|
wstats->qual.updated = IW_QUAL_ALL_INVALID;
|
||||||
|
|
||||||
|
@ -511,7 +541,7 @@ static int iwm_channels_init(struct iwm_priv *iwm)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iwm_up(struct iwm_priv *iwm)
|
int __iwm_up(struct iwm_priv *iwm)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct iwm_notif *notif_reboot, *notif_ack = NULL;
|
struct iwm_notif *notif_reboot, *notif_ack = NULL;
|
||||||
|
@ -647,7 +677,18 @@ int iwm_up(struct iwm_priv *iwm)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iwm_down(struct iwm_priv *iwm)
|
int iwm_up(struct iwm_priv *iwm)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&iwm->mutex);
|
||||||
|
ret = __iwm_up(iwm);
|
||||||
|
mutex_unlock(&iwm->mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __iwm_down(struct iwm_priv *iwm)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -678,3 +719,14 @@ int iwm_down(struct iwm_priv *iwm)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int iwm_down(struct iwm_priv *iwm)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&iwm->mutex);
|
||||||
|
ret = __iwm_down(iwm);
|
||||||
|
mutex_unlock(&iwm->mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -114,32 +114,31 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
||||||
iwm = wdev_to_iwm(wdev);
|
iwm = wdev_to_iwm(wdev);
|
||||||
iwm->bus_ops = if_ops;
|
iwm->bus_ops = if_ops;
|
||||||
iwm->wdev = wdev;
|
iwm->wdev = wdev;
|
||||||
iwm_priv_init(iwm);
|
|
||||||
|
ret = iwm_priv_init(iwm);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to init iwm_priv\n");
|
||||||
|
goto out_wdev;
|
||||||
|
}
|
||||||
|
|
||||||
wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
|
wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
|
||||||
|
|
||||||
ndev = alloc_netdev_mq(0, "wlan%d", ether_setup,
|
ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
|
||||||
IWM_TX_QUEUES);
|
|
||||||
if (!ndev) {
|
if (!ndev) {
|
||||||
dev_err(dev, "no memory for network device instance\n");
|
dev_err(dev, "no memory for network device instance\n");
|
||||||
goto out_wdev;
|
goto out_priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
ndev->netdev_ops = &iwm_netdev_ops;
|
ndev->netdev_ops = &iwm_netdev_ops;
|
||||||
ndev->wireless_handlers = &iwm_iw_handler_def;
|
ndev->wireless_handlers = &iwm_iw_handler_def;
|
||||||
ndev->ieee80211_ptr = wdev;
|
ndev->ieee80211_ptr = wdev;
|
||||||
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
|
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
|
||||||
ret = register_netdev(ndev);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dev, "Failed to register netdev: %d\n", ret);
|
|
||||||
goto out_ndev;
|
|
||||||
}
|
|
||||||
|
|
||||||
wdev->netdev = ndev;
|
wdev->netdev = ndev;
|
||||||
|
|
||||||
return iwm;
|
return iwm;
|
||||||
|
|
||||||
out_ndev:
|
out_priv:
|
||||||
free_netdev(ndev);
|
iwm_priv_deinit(iwm);
|
||||||
|
|
||||||
out_wdev:
|
out_wdev:
|
||||||
iwm_wdev_free(iwm);
|
iwm_wdev_free(iwm);
|
||||||
|
@ -148,15 +147,29 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
||||||
|
|
||||||
void iwm_if_free(struct iwm_priv *iwm)
|
void iwm_if_free(struct iwm_priv *iwm)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!iwm_to_ndev(iwm))
|
if (!iwm_to_ndev(iwm))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unregister_netdev(iwm_to_ndev(iwm));
|
|
||||||
free_netdev(iwm_to_ndev(iwm));
|
free_netdev(iwm_to_ndev(iwm));
|
||||||
iwm_wdev_free(iwm);
|
iwm_wdev_free(iwm);
|
||||||
destroy_workqueue(iwm->rx_wq);
|
iwm_priv_deinit(iwm);
|
||||||
for (i = 0; i < IWM_TX_QUEUES; i++)
|
}
|
||||||
destroy_workqueue(iwm->txq[i].wq);
|
|
||||||
|
int iwm_if_add(struct iwm_priv *iwm)
|
||||||
|
{
|
||||||
|
struct net_device *ndev = iwm_to_ndev(iwm);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = register_netdev(ndev);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iwm_if_remove(struct iwm_priv *iwm)
|
||||||
|
{
|
||||||
|
unregister_netdev(iwm_to_ndev(iwm));
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,10 +454,18 @@ static int iwm_sdio_probe(struct sdio_func *func,
|
||||||
|
|
||||||
INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker);
|
INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker);
|
||||||
|
|
||||||
|
ret = iwm_if_add(iwm);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "add SDIO interface failed\n");
|
||||||
|
goto destroy_wq;
|
||||||
|
}
|
||||||
|
|
||||||
dev_info(dev, "IWM SDIO probe\n");
|
dev_info(dev, "IWM SDIO probe\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
destroy_wq:
|
||||||
|
destroy_workqueue(hw->isr_wq);
|
||||||
debugfs_exit:
|
debugfs_exit:
|
||||||
iwm_debugfs_exit(iwm);
|
iwm_debugfs_exit(iwm);
|
||||||
if_free:
|
if_free:
|
||||||
|
@ -471,9 +479,10 @@ static void iwm_sdio_remove(struct sdio_func *func)
|
||||||
struct iwm_priv *iwm = hw_to_iwm(hw);
|
struct iwm_priv *iwm = hw_to_iwm(hw);
|
||||||
struct device *dev = &func->dev;
|
struct device *dev = &func->dev;
|
||||||
|
|
||||||
|
iwm_if_remove(iwm);
|
||||||
|
destroy_workqueue(hw->isr_wq);
|
||||||
iwm_debugfs_exit(iwm);
|
iwm_debugfs_exit(iwm);
|
||||||
iwm_if_free(iwm);
|
iwm_if_free(iwm);
|
||||||
destroy_workqueue(hw->isr_wq);
|
|
||||||
|
|
||||||
sdio_set_drvdata(func, NULL);
|
sdio_set_drvdata(func, NULL);
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ static struct usb_device_id usb_ids[] = {
|
||||||
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
|
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
|
||||||
{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
|
{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
|
||||||
{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
|
{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
|
||||||
|
{ USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
|
||||||
{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
|
{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
|
||||||
{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
|
{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
|
||||||
{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
|
{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
|
||||||
|
|
|
@ -958,12 +958,12 @@ static void acer_rfkill_update(struct work_struct *ignored)
|
||||||
|
|
||||||
status = get_u32(&state, ACER_CAP_WIRELESS);
|
status = get_u32(&state, ACER_CAP_WIRELESS);
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
rfkill_set_sw_state(wireless_rfkill, !!state);
|
rfkill_set_sw_state(wireless_rfkill, !state);
|
||||||
|
|
||||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||||
status = get_u32(&state, ACER_CAP_BLUETOOTH);
|
status = get_u32(&state, ACER_CAP_BLUETOOTH);
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
rfkill_set_sw_state(bluetooth_rfkill, !!state);
|
rfkill_set_sw_state(bluetooth_rfkill, !state);
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
|
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
|
||||||
|
|
|
@ -180,6 +180,7 @@ static struct key_entry eeepc_keymap[] = {
|
||||||
*/
|
*/
|
||||||
static int eeepc_hotk_add(struct acpi_device *device);
|
static int eeepc_hotk_add(struct acpi_device *device);
|
||||||
static int eeepc_hotk_remove(struct acpi_device *device, int type);
|
static int eeepc_hotk_remove(struct acpi_device *device, int type);
|
||||||
|
static int eeepc_hotk_resume(struct acpi_device *device);
|
||||||
|
|
||||||
static const struct acpi_device_id eeepc_device_ids[] = {
|
static const struct acpi_device_id eeepc_device_ids[] = {
|
||||||
{EEEPC_HOTK_HID, 0},
|
{EEEPC_HOTK_HID, 0},
|
||||||
|
@ -194,6 +195,7 @@ static struct acpi_driver eeepc_hotk_driver = {
|
||||||
.ops = {
|
.ops = {
|
||||||
.add = eeepc_hotk_add,
|
.add = eeepc_hotk_add,
|
||||||
.remove = eeepc_hotk_remove,
|
.remove = eeepc_hotk_remove,
|
||||||
|
.resume = eeepc_hotk_resume,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -512,15 +514,12 @@ static int notify_brn(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
static void eeepc_rfkill_hotplug(void)
|
||||||
{
|
{
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
struct pci_bus *bus = pci_find_bus(0, 1);
|
struct pci_bus *bus = pci_find_bus(0, 1);
|
||||||
bool blocked;
|
bool blocked;
|
||||||
|
|
||||||
if (event != ACPI_NOTIFY_BUS_CHECK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!bus) {
|
if (!bus) {
|
||||||
printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
|
printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
|
||||||
return;
|
return;
|
||||||
|
@ -551,6 +550,14 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||||
rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
|
rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||||
|
{
|
||||||
|
if (event != ACPI_NOTIFY_BUS_CHECK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
eeepc_rfkill_hotplug();
|
||||||
|
}
|
||||||
|
|
||||||
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
|
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
|
||||||
{
|
{
|
||||||
static struct key_entry *key;
|
static struct key_entry *key;
|
||||||
|
@ -675,8 +682,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
||||||
if (!ehotk->eeepc_wlan_rfkill)
|
if (!ehotk->eeepc_wlan_rfkill)
|
||||||
goto wlan_fail;
|
goto wlan_fail;
|
||||||
|
|
||||||
rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
|
rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill,
|
||||||
get_acpi(CM_ASL_WLAN) != 1);
|
get_acpi(CM_ASL_WLAN) != 1);
|
||||||
result = rfkill_register(ehotk->eeepc_wlan_rfkill);
|
result = rfkill_register(ehotk->eeepc_wlan_rfkill);
|
||||||
if (result)
|
if (result)
|
||||||
goto wlan_fail;
|
goto wlan_fail;
|
||||||
|
@ -693,8 +700,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
||||||
if (!ehotk->eeepc_bluetooth_rfkill)
|
if (!ehotk->eeepc_bluetooth_rfkill)
|
||||||
goto bluetooth_fail;
|
goto bluetooth_fail;
|
||||||
|
|
||||||
rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
|
rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill,
|
||||||
get_acpi(CM_ASL_BLUETOOTH) != 1);
|
get_acpi(CM_ASL_BLUETOOTH) != 1);
|
||||||
result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
|
result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
|
||||||
if (result)
|
if (result)
|
||||||
goto bluetooth_fail;
|
goto bluetooth_fail;
|
||||||
|
@ -734,6 +741,33 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int eeepc_hotk_resume(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
if (ehotk->eeepc_wlan_rfkill) {
|
||||||
|
bool wlan;
|
||||||
|
|
||||||
|
/* Workaround - it seems that _PTS disables the wireless
|
||||||
|
without notification or changing the value read by WLAN.
|
||||||
|
Normally this is fine because the correct value is restored
|
||||||
|
from the non-volatile storage on resume, but we need to do
|
||||||
|
it ourself if case suspend is aborted, or we lose wireless.
|
||||||
|
*/
|
||||||
|
wlan = get_acpi(CM_ASL_WLAN);
|
||||||
|
set_acpi(CM_ASL_WLAN, wlan);
|
||||||
|
|
||||||
|
rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
|
||||||
|
wlan != 1);
|
||||||
|
|
||||||
|
eeepc_rfkill_hotplug();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ehotk->eeepc_bluetooth_rfkill)
|
||||||
|
rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
|
||||||
|
get_acpi(CM_ASL_BLUETOOTH) != 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hwmon
|
* Hwmon
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1163,8 +1163,8 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
|
||||||
{
|
{
|
||||||
struct tpacpi_rfk *atp_rfk;
|
struct tpacpi_rfk *atp_rfk;
|
||||||
int res;
|
int res;
|
||||||
bool initial_sw_state = false;
|
bool sw_state = false;
|
||||||
int initial_sw_status;
|
int sw_status;
|
||||||
|
|
||||||
BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]);
|
BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]);
|
||||||
|
|
||||||
|
@ -1185,17 +1185,17 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
|
||||||
atp_rfk->id = id;
|
atp_rfk->id = id;
|
||||||
atp_rfk->ops = tp_rfkops;
|
atp_rfk->ops = tp_rfkops;
|
||||||
|
|
||||||
initial_sw_status = (tp_rfkops->get_status)();
|
sw_status = (tp_rfkops->get_status)();
|
||||||
if (initial_sw_status < 0) {
|
if (sw_status < 0) {
|
||||||
printk(TPACPI_ERR
|
printk(TPACPI_ERR
|
||||||
"failed to read initial state for %s, error %d\n",
|
"failed to read initial state for %s, error %d\n",
|
||||||
name, initial_sw_status);
|
name, sw_status);
|
||||||
} else {
|
} else {
|
||||||
initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF);
|
sw_state = (sw_status == TPACPI_RFK_RADIO_OFF);
|
||||||
if (set_default) {
|
if (set_default) {
|
||||||
/* try to keep the initial state, since we ask the
|
/* try to keep the initial state, since we ask the
|
||||||
* firmware to preserve it across S5 in NVRAM */
|
* firmware to preserve it across S5 in NVRAM */
|
||||||
rfkill_set_sw_state(atp_rfk->rfkill, initial_sw_state);
|
rfkill_init_sw_state(atp_rfk->rfkill, sw_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state());
|
rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state());
|
||||||
|
|
|
@ -160,8 +160,9 @@ struct rfkill * __must_check rfkill_alloc(const char *name,
|
||||||
* the rfkill structure. Before calling this function the driver needs
|
* the rfkill structure. Before calling this function the driver needs
|
||||||
* to be ready to service method calls from rfkill.
|
* to be ready to service method calls from rfkill.
|
||||||
*
|
*
|
||||||
* If the software blocked state is not set before registration,
|
* If rfkill_init_sw_state() is not called before registration,
|
||||||
* set_block will be called to initialize it to a default value.
|
* set_block() will be called to initialize the software blocked state
|
||||||
|
* to a default value.
|
||||||
*
|
*
|
||||||
* If the hardware blocked state is not set before registration,
|
* If the hardware blocked state is not set before registration,
|
||||||
* it is assumed to be unblocked.
|
* it is assumed to be unblocked.
|
||||||
|
@ -234,9 +235,11 @@ bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
|
||||||
* rfkill drivers that get events when the soft-blocked state changes
|
* rfkill drivers that get events when the soft-blocked state changes
|
||||||
* (yes, some platforms directly act on input but allow changing again)
|
* (yes, some platforms directly act on input but allow changing again)
|
||||||
* use this function to notify the rfkill core (and through that also
|
* use this function to notify the rfkill core (and through that also
|
||||||
* userspace) of the current state. It is not necessary to notify on
|
* userspace) of the current state.
|
||||||
* resume; since hibernation can always change the soft-blocked state,
|
*
|
||||||
* the rfkill core will unconditionally restore the previous state.
|
* Drivers should also call this function after resume if the state has
|
||||||
|
* been changed by the user. This only makes sense for "persistent"
|
||||||
|
* devices (see rfkill_init_sw_state()).
|
||||||
*
|
*
|
||||||
* This function can be called in any context, even from within rfkill
|
* This function can be called in any context, even from within rfkill
|
||||||
* callbacks.
|
* callbacks.
|
||||||
|
@ -246,6 +249,22 @@ bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
|
||||||
*/
|
*/
|
||||||
bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked);
|
bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rfkill_init_sw_state - Initialize persistent software block state
|
||||||
|
* @rfkill: pointer to the rfkill class to modify.
|
||||||
|
* @state: the current software block state to set
|
||||||
|
*
|
||||||
|
* rfkill drivers that preserve their software block state over power off
|
||||||
|
* use this function to notify the rfkill core (and through that also
|
||||||
|
* userspace) of their initial state. It should only be used before
|
||||||
|
* registration.
|
||||||
|
*
|
||||||
|
* In addition, it marks the device as "persistent", an attribute which
|
||||||
|
* can be read by userspace. Persistent devices are expected to preserve
|
||||||
|
* their own state when suspended.
|
||||||
|
*/
|
||||||
|
void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rfkill_set_states - Set the internal rfkill block states
|
* rfkill_set_states - Set the internal rfkill block states
|
||||||
* @rfkill: pointer to the rfkill class to modify.
|
* @rfkill: pointer to the rfkill class to modify.
|
||||||
|
@ -307,6 +326,10 @@ static inline bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
|
||||||
return blocked;
|
return blocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
|
static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,6 @@ struct rfkill {
|
||||||
u32 idx;
|
u32 idx;
|
||||||
|
|
||||||
bool registered;
|
bool registered;
|
||||||
bool suspended;
|
|
||||||
bool persistent;
|
bool persistent;
|
||||||
|
|
||||||
const struct rfkill_ops *ops;
|
const struct rfkill_ops *ops;
|
||||||
|
@ -224,7 +223,7 @@ static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
|
||||||
|
|
||||||
static void rfkill_event(struct rfkill *rfkill)
|
static void rfkill_event(struct rfkill *rfkill)
|
||||||
{
|
{
|
||||||
if (!rfkill->registered || rfkill->suspended)
|
if (!rfkill->registered)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
|
kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
|
||||||
|
@ -270,6 +269,9 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some platforms (...!) generate input events which affect the
|
* Some platforms (...!) generate input events which affect the
|
||||||
* _hard_ kill state -- whenever something tries to change the
|
* _hard_ kill state -- whenever something tries to change the
|
||||||
|
@ -292,9 +294,6 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
|
||||||
rfkill->state |= RFKILL_BLOCK_SW_SETCALL;
|
rfkill->state |= RFKILL_BLOCK_SW_SETCALL;
|
||||||
spin_unlock_irqrestore(&rfkill->lock, flags);
|
spin_unlock_irqrestore(&rfkill->lock, flags);
|
||||||
|
|
||||||
if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
|
|
||||||
return;
|
|
||||||
|
|
||||||
err = rfkill->ops->set_block(rfkill->data, blocked);
|
err = rfkill->ops->set_block(rfkill->data, blocked);
|
||||||
|
|
||||||
spin_lock_irqsave(&rfkill->lock, flags);
|
spin_lock_irqsave(&rfkill->lock, flags);
|
||||||
|
@ -508,19 +507,32 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
|
||||||
blocked = blocked || hwblock;
|
blocked = blocked || hwblock;
|
||||||
spin_unlock_irqrestore(&rfkill->lock, flags);
|
spin_unlock_irqrestore(&rfkill->lock, flags);
|
||||||
|
|
||||||
if (!rfkill->registered) {
|
if (!rfkill->registered)
|
||||||
rfkill->persistent = true;
|
return blocked;
|
||||||
} else {
|
|
||||||
if (prev != blocked && !hwblock)
|
|
||||||
schedule_work(&rfkill->uevent_work);
|
|
||||||
|
|
||||||
rfkill_led_trigger_event(rfkill);
|
if (prev != blocked && !hwblock)
|
||||||
}
|
schedule_work(&rfkill->uevent_work);
|
||||||
|
|
||||||
|
rfkill_led_trigger_event(rfkill);
|
||||||
|
|
||||||
return blocked;
|
return blocked;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rfkill_set_sw_state);
|
EXPORT_SYMBOL(rfkill_set_sw_state);
|
||||||
|
|
||||||
|
void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
BUG_ON(!rfkill);
|
||||||
|
BUG_ON(rfkill->registered);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&rfkill->lock, flags);
|
||||||
|
__rfkill_set_sw_state(rfkill, blocked);
|
||||||
|
rfkill->persistent = true;
|
||||||
|
spin_unlock_irqrestore(&rfkill->lock, flags);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rfkill_init_sw_state);
|
||||||
|
|
||||||
void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
|
void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -598,6 +610,15 @@ static ssize_t rfkill_idx_show(struct device *dev,
|
||||||
return sprintf(buf, "%d\n", rfkill->idx);
|
return sprintf(buf, "%d\n", rfkill->idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t rfkill_persistent_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct rfkill *rfkill = to_rfkill(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", rfkill->persistent);
|
||||||
|
}
|
||||||
|
|
||||||
static u8 user_state_from_blocked(unsigned long state)
|
static u8 user_state_from_blocked(unsigned long state)
|
||||||
{
|
{
|
||||||
if (state & RFKILL_BLOCK_HW)
|
if (state & RFKILL_BLOCK_HW)
|
||||||
|
@ -656,6 +677,7 @@ static struct device_attribute rfkill_dev_attrs[] = {
|
||||||
__ATTR(name, S_IRUGO, rfkill_name_show, NULL),
|
__ATTR(name, S_IRUGO, rfkill_name_show, NULL),
|
||||||
__ATTR(type, S_IRUGO, rfkill_type_show, NULL),
|
__ATTR(type, S_IRUGO, rfkill_type_show, NULL),
|
||||||
__ATTR(index, S_IRUGO, rfkill_idx_show, NULL),
|
__ATTR(index, S_IRUGO, rfkill_idx_show, NULL),
|
||||||
|
__ATTR(persistent, S_IRUGO, rfkill_persistent_show, NULL),
|
||||||
__ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
|
__ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
|
||||||
__ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
|
__ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
|
||||||
__ATTR_NULL
|
__ATTR_NULL
|
||||||
|
@ -718,8 +740,6 @@ static int rfkill_suspend(struct device *dev, pm_message_t state)
|
||||||
|
|
||||||
rfkill_pause_polling(rfkill);
|
rfkill_pause_polling(rfkill);
|
||||||
|
|
||||||
rfkill->suspended = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,10 +748,10 @@ static int rfkill_resume(struct device *dev)
|
||||||
struct rfkill *rfkill = to_rfkill(dev);
|
struct rfkill *rfkill = to_rfkill(dev);
|
||||||
bool cur;
|
bool cur;
|
||||||
|
|
||||||
cur = !!(rfkill->state & RFKILL_BLOCK_SW);
|
if (!rfkill->persistent) {
|
||||||
rfkill_set_block(rfkill, cur);
|
cur = !!(rfkill->state & RFKILL_BLOCK_SW);
|
||||||
|
rfkill_set_block(rfkill, cur);
|
||||||
rfkill->suspended = false;
|
}
|
||||||
|
|
||||||
rfkill_resume_polling(rfkill);
|
rfkill_resume_polling(rfkill);
|
||||||
|
|
||||||
|
|
|
@ -1687,13 +1687,52 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_rtnl;
|
goto out_rtnl;
|
||||||
|
|
||||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan);
|
||||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
|
if (err)
|
||||||
err = -EINVAL;
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* validate settings */
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
switch (dev->ieee80211_ptr->iftype) {
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
case NL80211_IFTYPE_AP_VLAN:
|
||||||
|
/* disallow mesh-specific things */
|
||||||
|
if (params.plink_action)
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_STATION:
|
||||||
|
/* disallow everything but AUTHORIZED flag */
|
||||||
|
if (params.plink_action)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.vlan)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.supported_rates)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.ht_capa)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.listen_interval >= 0)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_MESH_POINT:
|
||||||
|
/* disallow things mesh doesn't support */
|
||||||
|
if (params.vlan)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.ht_capa)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.listen_interval >= 0)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.supported_rates)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.sta_flags_mask)
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan);
|
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -1728,9 +1767,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||||
if (!info->attrs[NL80211_ATTR_MAC])
|
if (!info->attrs[NL80211_ATTR_MAC])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!info->attrs[NL80211_ATTR_STA_AID])
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
|
if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -1745,9 +1781,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||||
params.listen_interval =
|
params.listen_interval =
|
||||||
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
|
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
|
||||||
|
|
||||||
params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
|
if (info->attrs[NL80211_ATTR_STA_AID]) {
|
||||||
if (!params.aid || params.aid > IEEE80211_MAX_AID)
|
params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
|
||||||
return -EINVAL;
|
if (!params.aid || params.aid > IEEE80211_MAX_AID)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
|
if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
|
||||||
params.ht_capa =
|
params.ht_capa =
|
||||||
|
@ -1762,13 +1800,39 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_rtnl;
|
goto out_rtnl;
|
||||||
|
|
||||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan);
|
||||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
|
if (err)
|
||||||
err = -EINVAL;
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* validate settings */
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
switch (dev->ieee80211_ptr->iftype) {
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
case NL80211_IFTYPE_AP_VLAN:
|
||||||
|
/* all ok but must have AID */
|
||||||
|
if (!params.aid)
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_MESH_POINT:
|
||||||
|
/* disallow things mesh doesn't support */
|
||||||
|
if (params.vlan)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.aid)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.ht_capa)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.listen_interval >= 0)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.supported_rates)
|
||||||
|
err = -EINVAL;
|
||||||
|
if (params.sta_flags_mask)
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan);
|
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -1812,7 +1876,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
|
||||||
goto out_rtnl;
|
goto out_rtnl;
|
||||||
|
|
||||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
|
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
|
||||||
|
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче