/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*****************************************************************************/
#include "wifi.h"
#include "core.h"
#include "cam.h"
#include "base.h"
#include "ps.h"
/*mutex for start & stop is must here. */
static int rtl_op_start(struct ieee80211_hw *hw)
{
int err = 0;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
if (!is_hal_stop(rtlhal))
return 0;
if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
return 0;
mutex_lock(&rtlpriv->locks.conf_mutex);
err = rtlpriv->intf_ops->adapter_start(hw);
if (err)
goto out;
rtl_watch_dog_timer_callback((unsigned long)hw);
out:
mutex_unlock(&rtlpriv->locks.conf_mutex);
return err;
}
static void rtl_op_stop(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
if (is_hal_stop(rtlhal))
return;
if (unlikely(ppsc->rfpwr_state == ERFOFF)) {
rtl_ips_nic_on(hw);
mdelay(1);
}
mutex_lock(&rtlpriv->locks.conf_mutex);
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
/*reset sec info */
rtl_cam_reset_sec_info(hw);
rtl_deinit_deferred_work(hw);
rtlpriv->intf_ops->adapter_stop(hw);
mutex_unlock(&rtlpriv->locks.conf_mutex);
}
static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
goto err_free;
if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
goto err_free;
rtlpriv->intf_ops->adapter_tx(hw, skb);
return;
err_free:
dev_kfree_skb_any(skb);
}
static int rtl_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
int err = 0;
if (mac->vif) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
("vif has been set!! mac->vif = 0x%p\n", mac->vif));
return -EOPNOTSUPP;
}
rtl_ips_nic_on(hw);
mutex_lock(&rtlpriv->locks.conf_mutex);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
if (mac->beacon_enabled == 1) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
("NL80211_IFTYPE_STATION\n"));
mac->beacon_enabled = 0;
rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
rtlpriv->cfg->maps
[RTL_IBSS_INT_MASKS]);
}
break;
case NL80211_IFTYPE_ADHOC:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
("NL80211_IFTYPE_ADHOC\n"));
mac->link_state = MAC80211_LINKED;
rtlpriv->cfg->ops->set_bcn_reg(hw);
break;
case NL80211_IFTYPE_AP:
RT_TRACE(rtlpr