rtl8188eu: Flatten os_dep

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
This commit is contained in:
Larry Finger 2014-12-16 19:03:30 -06:00
parent b0c8a54865
commit 52f8d17ffc
18 changed files with 14750 additions and 26420 deletions

View file

@ -138,24 +138,24 @@ endif
_OS_INTFS_FILES := os_dep/osdep_service.o \ _OS_INTFS_FILES := os_dep/osdep_service.o \
os_dep/linux/os_intfs.o \ os_dep/os_intfs.o \
os_dep/linux/$(HCI_NAME)_intf.o \ os_dep/$(HCI_NAME)_intf.o \
os_dep/linux/$(HCI_NAME)_ops_linux.o \ os_dep/$(HCI_NAME)_ops_linux.o \
os_dep/linux/ioctl_linux.o \ os_dep/ioctl_linux.o \
os_dep/linux/xmit_linux.o \ os_dep/xmit_linux.o \
os_dep/linux/mlme_linux.o \ os_dep/mlme_linux.o \
os_dep/linux/recv_linux.o \ os_dep/recv_linux.o \
os_dep/linux/ioctl_cfg80211.o \ os_dep/ioctl_cfg80211.o \
os_dep/linux/rtw_android.o os_dep/rtw_android.o
ifeq ($(CONFIG_SDIO_HCI), y) ifeq ($(CONFIG_SDIO_HCI), y)
_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o _OS_INTFS_FILES += os_dep/custom_gpio_linux.o
_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o _OS_INTFS_FILES += os_dep/$(HCI_NAME)_ops_linux.o
endif endif
ifeq ($(CONFIG_GSPI_HCI), y) ifeq ($(CONFIG_GSPI_HCI), y)
_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o _OS_INTFS_FILES += os_dep/custom_gpio_linux.o
_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o _OS_INTFS_FILES += os_dep/$(HCI_NAME)_ops_linux.o
endif endif
_HAL_INTFS_FILES := hal/hal_intf.o \ _HAL_INTFS_FILES := hal/hal_intf.o \

13548
os_dep/ioctl_linux.c Normal file → Executable file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,620 +0,0 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* 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
*
*
******************************************************************************/
#define _MLME_OSDEP_C_
#include <drv_conf.h>
#include <osdep_service.h>
#include <drv_types.h>
#include <mlme_osdep.h>
#ifdef RTK_DMP_PLATFORM
void Linkup_workitem_callback(struct work_struct *work)
{
struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkup_workitem);
_adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv);
_func_enter_;
RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+ Linkup_workitem_callback\n"));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12))
kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKUP);
#else
kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKUP);
#endif
_func_exit_;
}
void Linkdown_workitem_callback(struct work_struct *work)
{
struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkdown_workitem);
_adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv);
_func_enter_;
RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+ Linkdown_workitem_callback\n"));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12))
kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKDOWN);
#else
kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKDOWN);
#endif
_func_exit_;
}
#endif
/*
void sitesurvey_ctrl_handler(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
_sitesurvey_ctrl_handler(adapter);
_set_timer(&adapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, 3000);
}
*/
void rtw_join_timeout_handler (void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
_rtw_join_timeout_handler(adapter);
}
void _rtw_scan_timeout_handler (void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
rtw_scan_timeout_handler(adapter);
}
void _dynamic_check_timer_handlder (void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
/* remove for MP power tracking DM.
#if (MP_DRIVER == 1)
if (adapter->registrypriv.mp_mode == 1)
return;
#endif
*/
rtw_dynamic_check_timer_handlder(adapter);
_set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000);
}
#ifdef CONFIG_SET_SCAN_DENY_TIMER
void _rtw_set_scan_deny_timer_hdl(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
rtw_set_scan_deny_timer_hdl(adapter);
}
#endif
#ifdef CONFIG_DETECT_C2H_BY_POLLING
void _rtw_event_polling_timer_hdl(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
rtw_event_polling_timer_hdl(adapter);
_set_timer(&adapter->mlmepriv.event_polling_timer, 200);
}
#endif
void rtw_init_mlme_timer(_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
_init_timer(&(pmlmepriv->assoc_timer), padapter->pnetdev, rtw_join_timeout_handler, padapter);
//_init_timer(&(pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer), padapter->pnetdev, sitesurvey_ctrl_handler, padapter);
_init_timer(&(pmlmepriv->scan_to_timer), padapter->pnetdev, _rtw_scan_timeout_handler, padapter);
_init_timer(&(pmlmepriv->dynamic_chk_timer), padapter->pnetdev, _dynamic_check_timer_handlder, padapter);
#ifdef CONFIG_SET_SCAN_DENY_TIMER
_init_timer(&(pmlmepriv->set_scan_deny_timer), padapter->pnetdev, _rtw_set_scan_deny_timer_hdl, padapter);
#endif
#ifdef CONFIG_DETECT_C2H_BY_POLLING
_init_timer(&(pmlmepriv->event_polling_timer), padapter->pnetdev, _rtw_event_polling_timer_hdl, padapter);
#endif
#ifdef RTK_DMP_PLATFORM
_init_workitem(&(pmlmepriv->Linkup_workitem), Linkup_workitem_callback, padapter);
_init_workitem(&(pmlmepriv->Linkdown_workitem), Linkdown_workitem_callback, padapter);
#endif
#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST)
if (padapter->HalFunc.hal_init_checkbthang_workqueue)
padapter->HalFunc.hal_init_checkbthang_workqueue(padapter);
#endif
}
extern void rtw_indicate_wx_assoc_event(_adapter *padapter);
extern void rtw_indicate_wx_disassoc_event(_adapter *padapter);
void rtw_os_indicate_connect(_adapter *adapter)
{
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
_func_enter_;
#ifdef CONFIG_IOCTL_CFG80211
if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==_TRUE ) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==_TRUE ) )
{
rtw_cfg80211_ibss_indicate_connect(adapter);
}
else
rtw_cfg80211_indicate_connect(adapter);
#endif //CONFIG_IOCTL_CFG80211
rtw_indicate_wx_assoc_event(adapter);
netif_carrier_on(adapter->pnetdev);
if(adapter->pid[2] !=0)
rtw_signal_process(adapter->pid[2], SIGALRM);
#ifdef RTK_DMP_PLATFORM
_set_workitem(&adapter->mlmepriv.Linkup_workitem);
#endif
_func_exit_;
}
extern void indicate_wx_scan_complete_event(_adapter *padapter);
void rtw_os_indicate_scan_done( _adapter *padapter, bool aborted)
{
#ifdef CONFIG_IOCTL_CFG80211
rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), aborted);
#endif
indicate_wx_scan_complete_event(padapter);
}
static RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ];
void rtw_reset_securitypriv( _adapter *adapter )
{
u8 backupPMKIDIndex = 0;
u8 backupTKIPCountermeasure = 0x00;
u32 backupTKIPcountermeasure_time = 0;
// add for CONFIG_IEEE80211W, none 11w also can use
_irqL irqL;
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
_enter_critical_bh(&adapter->security_key_mutex, &irqL);
if(adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)//802.1x
{
// Added by Albert 2009/02/18
// We have to backup the PMK information for WiFi PMK Caching test item.
//
// Backup the btkip_countermeasure information.
// When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds.
_rtw_memset( &backupPMKIDList[ 0 ], 0x00, sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
_rtw_memcpy( &backupPMKIDList[ 0 ], &adapter->securitypriv.PMKIDList[ 0 ], sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
backupPMKIDIndex = adapter->securitypriv.PMKIDIndex;
backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure;
backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time;
#ifdef CONFIG_IEEE80211W
//reset RX BIP packet number
pmlmeext->mgnt_80211w_IPN_rx = 0;
#endif //CONFIG_IEEE80211W
_rtw_memset((unsigned char *)&adapter->securitypriv, 0, sizeof (struct security_priv));
//_init_timer(&(adapter->securitypriv.tkip_timer),adapter->pnetdev, rtw_use_tkipkey_handler, adapter);
// Added by Albert 2009/02/18
// Restore the PMK information to securitypriv structure for the following connection.
_rtw_memcpy( &adapter->securitypriv.PMKIDList[ 0 ], &backupPMKIDList[ 0 ], sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
adapter->securitypriv.PMKIDIndex = backupPMKIDIndex;
adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure;
adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time;
adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
}
else //reset values in securitypriv
{
//if(adapter->mlmepriv.fw_state & WIFI_STATION_STATE)
//{
struct security_priv *psec_priv=&adapter->securitypriv;
psec_priv->dot11AuthAlgrthm =dot11AuthAlgrthm_Open; //open system
psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
psec_priv->dot11PrivacyKeyIndex = 0;
psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_;
psec_priv->dot118021XGrpKeyid = 1;
psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
//}
}
// add for CONFIG_IEEE80211W, none 11w also can use
_exit_critical_bh(&adapter->security_key_mutex, &irqL);
}
void rtw_os_indicate_disconnect( _adapter *adapter )
{
//RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ];
_func_enter_;
netif_carrier_off(adapter->pnetdev); // Do it first for tx broadcast pkt after disconnection issue!
#ifdef CONFIG_IOCTL_CFG80211
rtw_cfg80211_indicate_disconnect(adapter);
#endif //CONFIG_IOCTL_CFG80211
rtw_indicate_wx_disassoc_event(adapter);
#ifdef RTK_DMP_PLATFORM
_set_workitem(&adapter->mlmepriv.Linkdown_workitem);
#endif
//modify for CONFIG_IEEE80211W, none 11w also can use the same command
rtw_reset_securitypriv_cmd(adapter);
_func_exit_;
}
void rtw_report_sec_ie(_adapter *adapter,u8 authmode,u8 *sec_ie)
{
uint len;
u8 *buff,*p,i;
union iwreq_data wrqu;
_func_enter_;
RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+rtw_report_sec_ie, authmode=%d\n", authmode));
buff = NULL;
if(authmode==_WPA_IE_ID_)
{
RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("rtw_report_sec_ie, authmode=%d\n", authmode));
buff = rtw_malloc(IW_CUSTOM_MAX);
_rtw_memset(buff,0,IW_CUSTOM_MAX);
p=buff;
p+=sprintf(p,"ASSOCINFO(ReqIEs=");
len = sec_ie[1]+2;
len = (len < IW_CUSTOM_MAX) ? len:IW_CUSTOM_MAX;
for(i=0;i<len;i++){
p+=sprintf(p,"%02x",sec_ie[i]);
}
p+=sprintf(p,")");
_rtw_memset(&wrqu,0,sizeof(wrqu));
wrqu.data.length=p-buff;
wrqu.data.length = (wrqu.data.length<IW_CUSTOM_MAX) ? wrqu.data.length:IW_CUSTOM_MAX;
#ifndef CONFIG_IOCTL_CFG80211
wireless_send_event(adapter->pnetdev,IWEVCUSTOM,&wrqu,buff);
#endif
if(buff)
rtw_mfree(buff, IW_CUSTOM_MAX);
}
_func_exit_;
}
void _survey_timer_hdl (void *FunctionContext)
{
_adapter *padapter = (_adapter *)FunctionContext;
survey_timer_hdl(padapter);
}
void _link_timer_hdl (void *FunctionContext)
{
_adapter *padapter = (_adapter *)FunctionContext;
link_timer_hdl(padapter);
}
void _addba_timer_hdl(void *FunctionContext)
{
struct sta_info *psta = (struct sta_info *)FunctionContext;
addba_timer_hdl(psta);
}
#ifdef CONFIG_IEEE80211W
void _sa_query_timer_hdl (void *FunctionContext)
{
_adapter *padapter = (_adapter *)FunctionContext;
sa_query_timer_hdl(padapter);
}
#endif //CONFIG_IEEE80211W
void init_addba_retry_timer(_adapter *padapter, struct sta_info *psta)
{
_init_timer(&psta->addba_retry_timer, padapter->pnetdev, _addba_timer_hdl, psta);
}
/*
void _reauth_timer_hdl(void *FunctionContext)
{
_adapter *padapter = (_adapter *)FunctionContext;
reauth_timer_hdl(padapter);
}
void _reassoc_timer_hdl(void *FunctionContext)
{
_adapter *padapter = (_adapter *)FunctionContext;
reassoc_timer_hdl(padapter);
}
*/
void init_mlme_ext_timer(_adapter *padapter)
{
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
_init_timer(&pmlmeext->survey_timer, padapter->pnetdev, _survey_timer_hdl, padapter);
_init_timer(&pmlmeext->link_timer, padapter->pnetdev, _link_timer_hdl, padapter);
#ifdef CONFIG_IEEE80211W
_init_timer(&pmlmeext->sa_query_timer, padapter->pnetdev, _sa_query_timer_hdl, padapter);
#endif //CONFIG_IEEE80211W
//_init_timer(&pmlmeext->ADDBA_timer, padapter->pnetdev, _addba_timer_hdl, padapter);
//_init_timer(&pmlmeext->reauth_timer, padapter->pnetdev, _reauth_timer_hdl, padapter);
//_init_timer(&pmlmeext->reassoc_timer, padapter->pnetdev, _reassoc_timer_hdl, padapter);
}
#ifdef CONFIG_AP_MODE
void rtw_indicate_sta_assoc_event(_adapter *padapter, struct sta_info *psta)
{
union iwreq_data wrqu;
struct sta_priv *pstapriv = &padapter->stapriv;
if(psta==NULL)
return;
if(psta->aid > NUM_STA)
return;
if(pstapriv->sta_aid[psta->aid - 1] != psta)
return;
wrqu.addr.sa_family = ARPHRD_ETHER;
_rtw_memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
DBG_871X("+rtw_indicate_sta_assoc_event\n");
#ifndef CONFIG_IOCTL_CFG80211
wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL);
#endif
}
void rtw_indicate_sta_disassoc_event(_adapter *padapter, struct sta_info *psta)
{
union iwreq_data wrqu;
struct sta_priv *pstapriv = &padapter->stapriv;
if(psta==NULL)
return;
if(psta->aid > NUM_STA)
return;
if(pstapriv->sta_aid[psta->aid - 1] != psta)
return;
wrqu.addr.sa_family = ARPHRD_ETHER;
_rtw_memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
DBG_871X("+rtw_indicate_sta_disassoc_event\n");
#ifndef CONFIG_IOCTL_CFG80211
wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL);
#endif
}
#ifdef CONFIG_HOSTAPD_MLME
static int mgnt_xmit_entry(struct sk_buff *skb, struct net_device *pnetdev)
{
struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
_adapter *padapter = (_adapter *)phostapdpriv->padapter;
//DBG_871X("%s\n", __FUNCTION__);
return rtw_hal_hostap_mgnt_xmit_entry(padapter, skb);
}
static int mgnt_netdev_open(struct net_device *pnetdev)
{
struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
DBG_871X("mgnt_netdev_open: MAC Address:" MAC_FMT "\n", MAC_ARG(pnetdev->dev_addr));
init_usb_anchor(&phostapdpriv->anchored);
if(!rtw_netif_queue_stopped(pnetdev))
rtw_netif_start_queue(pnetdev);
else
rtw_netif_wake_queue(pnetdev);
netif_carrier_on(pnetdev);
//rtw_write16(phostapdpriv->padapter, 0x0116, 0x0100);//only excluding beacon
return 0;
}
static int mgnt_netdev_close(struct net_device *pnetdev)
{
struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
DBG_871X("%s\n", __FUNCTION__);
usb_kill_anchored_urbs(&phostapdpriv->anchored);
netif_carrier_off(pnetdev);
if (!rtw_netif_queue_stopped(pnetdev))
rtw_netif_stop_queue(pnetdev);
//rtw_write16(phostapdpriv->padapter, 0x0116, 0x3f3f);
return 0;
}
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29))
static const struct net_device_ops rtl871x_mgnt_netdev_ops = {
.ndo_open = mgnt_netdev_open,
.ndo_stop = mgnt_netdev_close,
.ndo_start_xmit = mgnt_xmit_entry,
//.ndo_set_mac_address = r871x_net_set_mac_address,
//.ndo_get_stats = r871x_net_get_stats,
//.ndo_do_ioctl = r871x_mp_ioctl,
};
#endif
int hostapd_mode_init(_adapter *padapter)
{
unsigned char mac[ETH_ALEN];
struct hostapd_priv *phostapdpriv;
struct net_device *pnetdev;
pnetdev = rtw_alloc_etherdev(sizeof(struct hostapd_priv));
if (!pnetdev)
return -ENOMEM;
//SET_MODULE_OWNER(pnetdev);
ether_setup(pnetdev);
//pnetdev->type = ARPHRD_IEEE80211;
phostapdpriv = rtw_netdev_priv(pnetdev);
phostapdpriv->pmgnt_netdev = pnetdev;
phostapdpriv->padapter= padapter;
padapter->phostapdpriv = phostapdpriv;
//pnetdev->init = NULL;
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29))
DBG_871X("register rtl871x_mgnt_netdev_ops to netdev_ops\n");
pnetdev->netdev_ops = &rtl871x_mgnt_netdev_ops;
#else
pnetdev->open = mgnt_netdev_open;
pnetdev->stop = mgnt_netdev_close;
pnetdev->hard_start_xmit = mgnt_xmit_entry;
//pnetdev->set_mac_address = r871x_net_set_mac_address;
//pnetdev->get_stats = r871x_net_get_stats;
//pnetdev->do_ioctl = r871x_mp_ioctl;
#endif
pnetdev->watchdog_timeo = HZ; /* 1 second timeout */
//pnetdev->wireless_handlers = NULL;
#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
pnetdev->features |= NETIF_F_IP_CSUM;
#endif
if(dev_alloc_name(pnetdev,"mgnt.wlan%d") < 0)
{
DBG_871X("hostapd_mode_init(): dev_alloc_name, fail! \n");
}
//SET_NETDEV_DEV(pnetdev, pintfpriv->udev);
mac[0]=0x00;
mac[1]=0xe0;
mac[2]=0x4c;
mac[3]=0x87;
mac[4]=0x11;
mac[5]=0x12;
_rtw_memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
netif_carrier_off(pnetdev);
/* Tell the network stack we exist */
if (register_netdev(pnetdev) != 0)
{
DBG_871X("hostapd_mode_init(): register_netdev fail!\n");
if(pnetdev)
{
rtw_free_netdev(pnetdev);
}
}
return 0;
}
void hostapd_mode_unload(_adapter *padapter)
{
struct hostapd_priv *phostapdpriv = padapter->phostapdpriv;
struct net_device *pnetdev = phostapdpriv->pmgnt_netdev;
unregister_netdev(pnetdev);
rtw_free_netdev(pnetdev);
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,512 +0,0 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* 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
*
*
******************************************************************************/
#define _RECV_OSDEP_C_
#include <drv_conf.h>
#include <osdep_service.h>
#include <drv_types.h>
#include <wifi.h>
#include <recv_osdep.h>
#include <osdep_intf.h>
#include <ethernet.h>
#ifdef CONFIG_USB_HCI
#include <usb_ops.h>
#endif
//init os related resource in struct recv_priv
int rtw_os_recv_resource_init(struct recv_priv *precvpriv, _adapter *padapter)
{
int res=_SUCCESS;
return res;
}
//alloc os related resource in union recv_frame
int rtw_os_recv_resource_alloc(_adapter *padapter, union recv_frame *precvframe)
{
int res=_SUCCESS;
precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL;
return res;
}
//free os related resource in union recv_frame
void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
{
sint i;
union recv_frame *precvframe;
precvframe = (union recv_frame*) precvpriv->precv_frame_buf;
for(i=0; i < NR_RECVFRAME; i++)
{
if(precvframe->u.hdr.pkt)
{
rtw_skb_free(precvframe->u.hdr.pkt);//free skb by driver
precvframe->u.hdr.pkt = NULL;
}
precvframe++;
}
}
//alloc os related resource in struct recv_buf
int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)
{
int res=_SUCCESS;
#ifdef CONFIG_USB_HCI
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
precvbuf->irp_pending = _FALSE;
precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
if(precvbuf->purb == NULL){
res = _FAIL;
}
precvbuf->pskb = NULL;
precvbuf->reuse = _FALSE;
precvbuf->pallocated_buf = precvbuf->pbuf = NULL;
precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;
precvbuf->transfer_len = 0;
precvbuf->len = 0;
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr);
precvbuf->pbuf = precvbuf->pallocated_buf;
if(precvbuf->pallocated_buf == NULL)
return _FAIL;
#endif //CONFIG_USE_USB_BUFFER_ALLOC_RX
#endif //CONFIG_USB_HCI
return res;
}
//free os related resource in struct recv_buf
int rtw_os_recvbuf_resource_free(_adapter *padapter, struct recv_buf *precvbuf)
{
int ret = _SUCCESS;
#ifdef CONFIG_USB_HCI
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
rtw_usb_buffer_free(pusbd, (size_t)precvbuf->alloc_sz, precvbuf->pallocated_buf, precvbuf->dma_transfer_addr);
precvbuf->pallocated_buf = NULL;
precvbuf->dma_transfer_addr = 0;
#endif //CONFIG_USE_USB_BUFFER_ALLOC_RX
if(precvbuf->purb)
{
//usb_kill_urb(precvbuf->purb);
usb_free_urb(precvbuf->purb);
}
#endif //CONFIG_USB_HCI
if(precvbuf->pskb)
rtw_skb_free(precvbuf->pskb);
return ret;
}
void rtw_handle_tkip_mic_err(_adapter *padapter,u8 bgroup)
{
#ifdef CONFIG_IOCTL_CFG80211
enum nl80211_key_type key_type;
#endif
union iwreq_data wrqu;
struct iw_michaelmicfailure ev;
struct mlme_priv* pmlmepriv = &padapter->mlmepriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
u32 cur_time = 0;
if( psecuritypriv->last_mic_err_time == 0 )
{
psecuritypriv->last_mic_err_time = rtw_get_current_time();
}
else
{
cur_time = rtw_get_current_time();
if( cur_time - psecuritypriv->last_mic_err_time < 60*HZ )
{
psecuritypriv->btkip_countermeasure = _TRUE;
psecuritypriv->last_mic_err_time = 0;
psecuritypriv->btkip_countermeasure_time = cur_time;
}
else
{
psecuritypriv->last_mic_err_time = rtw_get_current_time();
}
}
#ifdef CONFIG_IOCTL_CFG80211
if ( bgroup )
{
key_type |= NL80211_KEYTYPE_GROUP;
}
else
{
key_type |= NL80211_KEYTYPE_PAIRWISE;
}
cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[ 0 ], key_type, -1,
NULL, GFP_ATOMIC);
#endif
_rtw_memset( &ev, 0x00, sizeof( ev ) );
if ( bgroup )
{
ev.flags |= IW_MICFAILURE_GROUP;
}
else
{
ev.flags |= IW_MICFAILURE_PAIRWISE;
}
ev.src_addr.sa_family = ARPHRD_ETHER;
_rtw_memcpy( ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN );
_rtw_memset( &wrqu, 0x00, sizeof( wrqu ) );
wrqu.data.length = sizeof( ev );
#ifndef CONFIG_IOCTL_CFG80211
wireless_send_event( padapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu, (char*) &ev );
#endif
}
void rtw_hostapd_mlme_rx(_adapter *padapter, union recv_frame *precv_frame)
{
#ifdef CONFIG_HOSTAPD_MLME
_pkt *skb;
struct hostapd_priv *phostapdpriv = padapter->phostapdpriv;
struct net_device *pmgnt_netdev = phostapdpriv->pmgnt_netdev;
RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("+rtw_hostapd_mlme_rx\n"));
skb = precv_frame->u.hdr.pkt;
if (skb == NULL)
return;
skb->data = precv_frame->u.hdr.rx_data;
skb->tail = precv_frame->u.hdr.rx_tail;
skb->len = precv_frame->u.hdr.len;
//pskb_copy = rtw_skb_copy(skb);
// if(skb == NULL) goto _exit;
skb->dev = pmgnt_netdev;
skb->ip_summed = CHECKSUM_NONE;
skb->pkt_type = PACKET_OTHERHOST;
//skb->protocol = __constant_htons(0x0019); /*ETH_P_80211_RAW*/
skb->protocol = __constant_htons(0x0003); /*ETH_P_80211_RAW*/
//DBG_871X("(1)data=0x%x, head=0x%x, tail=0x%x, mac_header=0x%x, len=%d\n", skb->data, skb->head, skb->tail, skb->mac_header, skb->len);
//skb->mac.raw = skb->data;
skb_reset_mac_header(skb);
//skb_pull(skb, 24);
_rtw_memset(skb->cb, 0, sizeof(skb->cb));
rtw_netif_rx(pmgnt_netdev, skb);
precv_frame->u.hdr.pkt = NULL; // set pointer to NULL before rtw_free_recvframe() if call rtw_netif_rx()
#endif
}
int rtw_recv_indicatepkt(_adapter *padapter, union recv_frame *precv_frame)
{
struct recv_priv *precvpriv;
_queue *pfree_recv_queue;
_pkt *skb;
struct mlme_priv*pmlmepriv = &padapter->mlmepriv;
#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
#endif
#ifdef CONFIG_BR_EXT
void *br_port = NULL;
#endif
_func_enter_;
precvpriv = &(padapter->recvpriv);
pfree_recv_queue = &(precvpriv->free_recv_queue);
#ifdef CONFIG_DRVEXT_MODULE
if (drvext_rx_handler(padapter, precv_frame->u.hdr.rx_data, precv_frame->u.hdr.len) == _SUCCESS)
{
goto _recv_indicatepkt_drop;
}
#endif
#ifdef CONFIG_WAPI_SUPPORT
if (rtw_wapi_check_for_drop(padapter,precv_frame))
{
WAPI_TRACE(WAPI_ERR, "%s(): Rx Reorder Drop case!!\n", __FUNCTION__);
goto _recv_indicatepkt_drop;
}
#endif
skb = precv_frame->u.hdr.pkt;
if(skb == NULL)
{
RT_TRACE(_module_recv_osdep_c_,_drv_err_,("rtw_recv_indicatepkt():skb==NULL something wrong!!!!\n"));
goto _recv_indicatepkt_drop;
}
RT_TRACE(_module_recv_osdep_c_,_drv_info_,("rtw_recv_indicatepkt():skb != NULL !!!\n"));
RT_TRACE(_module_recv_osdep_c_,_drv_info_,("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head=%p precv_frame->hdr.rx_data=%p\n", precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data));
RT_TRACE(_module_recv_osdep_c_,_drv_info_,("precv_frame->hdr.rx_tail=%p precv_frame->u.hdr.rx_end=%p precv_frame->hdr.len=%d \n", precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end, precv_frame->u.hdr.len));
skb->data = precv_frame->u.hdr.rx_data;
skb_set_tail_pointer(skb, precv_frame->u.hdr.len);
skb->len = precv_frame->u.hdr.len;
RT_TRACE(_module_recv_osdep_c_,_drv_info_,("\n skb->head=%p skb->data=%p skb->tail=%p skb->end=%p skb->len=%d\n", skb->head, skb->data, skb->tail, skb->end, skb->len));
if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
{
_pkt *pskb2=NULL;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
int bmcast = IS_MCAST(pattrib->dst);
//DBG_871X("bmcast=%d\n", bmcast);
if(_rtw_memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)==_FALSE)
{
//DBG_871X("not ap psta=%p, addr=%pM\n", psta, pattrib->dst);
if(bmcast)
{
psta = rtw_get_bcmc_stainfo(padapter);
pskb2 = rtw_skb_clone(skb);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->dst);
}
if(psta)
{
struct net_device *pnetdev= (struct net_device*)padapter->pnetdev;
//DBG_871X("directly forwarding to the rtw_xmit_entry\n");
//skb->ip_summed = CHECKSUM_NONE;
skb->dev = pnetdev;
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
skb_set_queue_mapping(skb, rtw_recv_select_queue(skb));
#endif //LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)
_rtw_xmit_entry(skb, pnetdev);
if(bmcast)
skb = pskb2;
else
goto _recv_indicatepkt_end;
}
}
else// to APself
{
//DBG_871X("to APSelf\n");
}
}
#ifdef CONFIG_BR_EXT
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
br_port = padapter->pnetdev->br_port;
#else // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
rcu_read_lock();
br_port = rcu_dereference(padapter->pnetdev->rx_handler_data);
rcu_read_unlock();
#endif // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
if( br_port && (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) )
{
int nat25_handle_frame(_adapter *priv, struct sk_buff *skb);
if (nat25_handle_frame(padapter, skb) == -1) {
//priv->ext_stats.rx_data_drops++;
//DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n");
//return FAIL;
#if 1
// bypass this frame to upper layer!!
#else
goto _recv_indicatepkt_drop;
#endif
}
}
#endif // CONFIG_BR_EXT
#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX
if ( (pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1) ) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
//DBG_871X("CHECKSUM_UNNECESSARY \n");
} else {
skb->ip_summed = CHECKSUM_NONE;
//DBG_871X("CHECKSUM_NONE(%d, %d) \n", pattrib->tcpchk_valid, pattrib->tcp_chkrpt);
}
#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */
skb->ip_summed = CHECKSUM_NONE;
#endif
skb->dev = padapter->pnetdev;
skb->protocol = eth_type_trans(skb, padapter->pnetdev);
#ifdef DBG_TRX_STA_PKTS
{
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
int bmcast = IS_MCAST(pattrib->dst);
if(bmcast)
{
psta = rtw_get_bcmc_stainfo(padapter);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->src);
}
if(psta)
{
switch(pattrib->priority)
{
case 1:
case 2:
psta->rx_bk_cnt++;
break;
case 4:
case 5:
psta->rx_vi_cnt++;
break;
case 6:
case 7:
psta->rx_vo_cnt++;
break;
case 0:
case 3:
default:
psta->rx_be_cnt++;
break;
}
}
}
#endif
rtw_netif_rx(padapter->pnetdev, skb);
_recv_indicatepkt_end:
precv_frame->u.hdr.pkt = NULL; // pointers to NULL before rtw_free_recvframe()
rtw_free_recvframe(precv_frame, pfree_recv_queue);
RT_TRACE(_module_recv_osdep_c_,_drv_info_,("\n rtw_recv_indicatepkt :after rtw_netif_rx!!!!\n"));
_func_exit_;
return _SUCCESS;
_recv_indicatepkt_drop:
//enqueue back to free_recv_queue
if(precv_frame)
rtw_free_recvframe(precv_frame, pfree_recv_queue);
return _FAIL;
_func_exit_;
}
void rtw_os_read_port(_adapter *padapter, struct recv_buf *precvbuf)
{
struct recv_priv *precvpriv = &padapter->recvpriv;
#ifdef CONFIG_USB_HCI
precvbuf->ref_cnt--;
//free skb in recv_buf
rtw_skb_free(precvbuf->pskb);
precvbuf->pskb = NULL;
precvbuf->reuse = _FALSE;
if(precvbuf->irp_pending == _FALSE)
{
rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
}
#endif
#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
precvbuf->pskb = NULL;
#endif
}
void _rtw_reordering_ctrl_timeout_handler (void *FunctionContext);
void _rtw_reordering_ctrl_timeout_handler (void *FunctionContext)
{
struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)FunctionContext;
rtw_reordering_ctrl_timeout_handler(preorder_ctrl);
}
void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
{
_adapter *padapter = preorder_ctrl->padapter;
_init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter->pnetdev, _rtw_reordering_ctrl_timeout_handler, preorder_ctrl);
}

View file

@ -1,828 +0,0 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* 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
*
*
******************************************************************************/
#include <linux/module.h>
#include <linux/netdevice.h>
#include <rtw_android.h>
#include <osdep_service.h>
#include <rtw_debug.h>
#include <ioctl_cfg80211.h>
#include <rtw_ioctl_set.h>
#ifdef CONFIG_GPIO_WAKEUP
#include <linux/gpio.h>
#endif
#include <drv_types.h>
#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
#include <linux/platform_device.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
#include <linux/wlan_plat.h>
#else
#include <linux/wifi_tiwlan.h>
#endif
#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */
#ifdef CONFIG_GPIO_WAKEUP
#include <linux/interrupt.h>
#include <linux/irq.h>
#endif
static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
"START",
"STOP",
"SCAN-ACTIVE",
"SCAN-PASSIVE",
"RSSI",
"LINKSPEED",
"RXFILTER-START",
"RXFILTER-STOP",
"RXFILTER-ADD",
"RXFILTER-REMOVE",
"BTCOEXSCAN-START",
"BTCOEXSCAN-STOP",
"BTCOEXMODE",
"SETSUSPENDOPT",
"P2P_DEV_ADDR",
"SETFWPATH",
"SETBAND",
"GETBAND",
"COUNTRY",
"P2P_SET_NOA",
"P2P_GET_NOA",
"P2P_SET_PS",
"SET_AP_WPS_P2P_IE",
#ifdef PNO_SUPPORT
"PNOSSIDCLR",
"PNOSETUP ",
"PNOFORCE",
"PNODEBUG",
#endif
"MACADDR",
"BLOCK",
"WFD-ENABLE",
"WFD-DISABLE",
"WFD-SET-TCPPORT",
"WFD-SET-MAXTPUT",
"WFD-SET-DEVTYPE",
};
#ifdef PNO_SUPPORT
#define PNO_TLV_PREFIX 'S'
#define PNO_TLV_VERSION '1'
#define PNO_TLV_SUBVERSION '2'
#define PNO_TLV_RESERVED '0'
#define PNO_TLV_TYPE_SSID_IE 'S'
#define PNO_TLV_TYPE_TIME 'T'
#define PNO_TLV_FREQ_REPEAT 'R'
#define PNO_TLV_FREQ_EXPO_MAX 'M'
typedef struct cmd_tlv {
char prefix;
char version;
char subver;
char reserved;
} cmd_tlv_t;
#endif /* PNO_SUPPORT */
typedef struct android_wifi_priv_cmd {
char *buf;
int used_len;
int total_len;
} android_wifi_priv_cmd;
/**
* Local (static) functions and variables
*/
/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
* time (only) in dhd_open, subsequential wifi on will be handled by
* wl_android_wifi_on
*/
static int g_wifi_on = _TRUE;
static unsigned int oob_irq;
#ifdef PNO_SUPPORT
static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
{
wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
int res = -1;
int nssid = 0;
cmd_tlv_t *cmd_tlv_temp;
char *str_ptr;
int tlv_size_left;
int pno_time = 0;
int pno_repeat = 0;
int pno_freq_expo_max = 0;
#ifdef PNO_SET_DEBUG
int i;
char pno_in_example[] = {
'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
'S', '1', '2', '0',
'S',
0x05,
'd', 'l', 'i', 'n', 'k',
'S',
0x04,
'G', 'O', 'O', 'G',
'T',
'0', 'B',
'R',
'2',
'M',
'2',
0x00
};
#endif /* PNO_SET_DEBUG */
DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
DBG_871X("%s argument=%d less min size\n", __FUNCTION__, total_len);
goto exit_proc;
}
#ifdef PNO_SET_DEBUG
memcpy(command, pno_in_example, sizeof(pno_in_example));
for (i = 0; i < sizeof(pno_in_example); i++)
printf("%02X ", command[i]);
printf("\n");
total_len = sizeof(pno_in_example);
#endif
str_ptr = command + strlen(CMD_PNOSETUP_SET);
tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
memset(ssids_local, 0, sizeof(ssids_local));
if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
(cmd_tlv_temp->version == PNO_TLV_VERSION) &&
(cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
str_ptr += sizeof(cmd_tlv_t);
tlv_size_left -= sizeof(cmd_tlv_t);
if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
DBG_871X("SSID is not presented or corrupted ret=%d\n", nssid);
goto exit_proc;
} else {
if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
DBG_871X("%s scan duration corrupted field size %d\n",
__FUNCTION__, tlv_size_left);
goto exit_proc;
}
str_ptr++;
pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
if (str_ptr[0] != 0) {
if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
DBG_871X("%s pno repeat : corrupted field\n",
__FUNCTION__);
goto exit_proc;
}
str_ptr++;
pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
DBG_871X("%s FREQ_EXPO_MAX corrupted field size\n",
__FUNCTION__);
goto exit_proc;
}
str_ptr++;
pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
DHD_INFO(("%s: pno_freq_expo_max=%d\n",
__FUNCTION__, pno_freq_expo_max));
}
}
} else {
DBG_871X("%s get wrong TLV command\n", __FUNCTION__);
goto exit_proc;
}
res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
exit_proc:
return res;
}
#endif /* PNO_SUPPORT */
int rtw_android_cmdstr_to_num(char *cmdstr)
{
int cmd_num;
for(cmd_num=0 ; cmd_num<ANDROID_WIFI_CMD_MAX; cmd_num++)
if(0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])) )
break;
return cmd_num;
}
static int rtw_android_get_rssi(struct net_device *net, char *command, int total_len)
{
_adapter *padapter = (_adapter *)rtw_netdev_priv(net);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct wlan_network *pcur_network = &pmlmepriv->cur_network;
int bytes_written = 0;
if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
bytes_written += snprintf(&command[bytes_written], total_len, "%s rssi %d",
pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi);
}
return bytes_written;
}
static int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len)
{
_adapter *padapter = (_adapter *)rtw_netdev_priv(net);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct wlan_network *pcur_network = &pmlmepriv->cur_network;
int bytes_written = 0;
u16 link_speed = 0;
link_speed = rtw_get_cur_max_rate(padapter)/10;
bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
return bytes_written;
}
static int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len)
{
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
int bytes_written = 0;
bytes_written = snprintf(command, total_len, "Macaddr = "MAC_FMT, MAC_ARG(net->dev_addr));
return bytes_written;
}
static int rtw_android_set_country(struct net_device *net, char *command, int total_len)
{
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1;
int ret = _FAIL;
ret = rtw_set_country(adapter, country_code);
return (ret==_SUCCESS)?0:-1;
}
static int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len)
{
int bytes_written = 0;
//We use the same address as our HW MAC address
_rtw_memcpy(command, net->dev_addr, ETH_ALEN);
bytes_written = ETH_ALEN;
return bytes_written;
}
static int rtw_android_set_block(struct net_device *net, char *command, int total_len)
{
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK]) + 1;
#ifdef CONFIG_IOCTL_CFG80211
wdev_to_priv(adapter->rtw_wdev)->block = (*block_value=='0')?_FALSE:_TRUE;
#endif
return 0;
}
static int get_int_from_command(char *pcmd)
{
int i = 0;
for( i = 0; i < strlen( pcmd ); i++ )
{
if ( pcmd[ i ] == '=' )
{
// Skip the '=' and space characters.
i += 2;
break;
}
}
return ( rtw_atoi( pcmd + i ) );
}
int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
{
int ret = 0;
char *command = NULL;
int cmd_num;
int bytes_written = 0;
android_wifi_priv_cmd priv_cmd;
_adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
#ifdef CONFIG_WFD
struct wifi_display_info *pwfd_info;
#endif
rtw_lock_suspend();
if (!ifr->ifr_data) {
ret = -EINVAL;
goto exit;
}
if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
ret = -EFAULT;
goto exit;
}
//DBG_871X("%s priv_cmd.buf=%p priv_cmd.total_len=%d priv_cmd.used_len=%d\n",__func__,priv_cmd.buf,priv_cmd.total_len,priv_cmd.used_len);
command = rtw_zmalloc(priv_cmd.total_len);
if (!command)
{
DBG_871X("%s: failed to allocate memory\n", __FUNCTION__);
ret = -ENOMEM;
goto exit;
}
if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)){
DBG_871X("%s: failed to access memory\n", __FUNCTION__);
ret = -EFAULT;
goto exit;
}
if (copy_from_user(command, (void *)priv_cmd.buf, priv_cmd.total_len)) {
ret = -EFAULT;
goto exit;
}
DBG_871X("%s: Android private cmd \"%s\" on %s\n"
, __FUNCTION__, command, ifr->ifr_name);
cmd_num = rtw_android_cmdstr_to_num(command);
switch(cmd_num) {
case ANDROID_WIFI_CMD_START:
//bytes_written = wl_android_wifi_on(net);
goto response;
case ANDROID_WIFI_CMD_SETFWPATH:
goto response;
}
if (!g_wifi_on) {
DBG_871X("%s: Ignore private cmd \"%s\" - iface %s is down\n"
,__FUNCTION__, command, ifr->ifr_name);
ret = 0;
goto exit;
}
switch(cmd_num) {
case ANDROID_WIFI_CMD_STOP:
//bytes_written = wl_android_wifi_off(net);
break;
case ANDROID_WIFI_CMD_SCAN_ACTIVE:
//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE);
#ifdef CONFIG_PLATFORM_MSTAR
#ifdef CONFIG_IOCTL_CFG80211
(wdev_to_priv(net->ieee80211_ptr))->bandroid_scan = _TRUE;
#endif //CONFIG_IOCTL_CFG80211
#endif //CONFIG_PLATFORM_MSTAR
break;
case ANDROID_WIFI_CMD_SCAN_PASSIVE:
//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE);
break;
case ANDROID_WIFI_CMD_RSSI:
bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_LINKSPEED:
bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_MACADDR:
bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_BLOCK:
bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_RXFILTER_START:
//bytes_written = net_os_set_packet_filter(net, 1);
break;
case ANDROID_WIFI_CMD_RXFILTER_STOP:
//bytes_written = net_os_set_packet_filter(net, 0);
break;
case ANDROID_WIFI_CMD_RXFILTER_ADD:
//int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
//bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
break;
case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
//int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
//bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
break;
case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
/* TBD: BTCOEXSCAN-START */
break;
case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
/* TBD: BTCOEXSCAN-STOP */
break;
case ANDROID_WIFI_CMD_BTCOEXMODE:
#if 0
uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
if (mode == 1)
net_os_set_packet_filter(net, 0); /* DHCP starts */
else
net_os_set_packet_filter(net, 1); /* DHCP ends */
#ifdef WL_CFG80211
bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
#endif
#endif
break;
case ANDROID_WIFI_CMD_SETSUSPENDOPT:
//bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_SETBAND:
{
uint band = *(command + strlen("SETBAND") + 1) - '0';
_adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
if (padapter->chip_type == RTL8192D)
padapter->setband = band;
break;
}
case ANDROID_WIFI_CMD_GETBAND:
//bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_COUNTRY:
bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
break;
#ifdef PNO_SUPPORT
case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
//bytes_written = dhd_dev_pno_reset(net);
break;
case ANDROID_WIFI_CMD_PNOSETUP_SET:
//bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_PNOENABLE_SET:
//uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
//bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
break;
#endif
case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_P2P_SET_NOA:
//int skip = strlen(CMD_P2P_SET_NOA) + 1;
//bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip);
break;
case ANDROID_WIFI_CMD_P2P_GET_NOA:
//bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_P2P_SET_PS:
//int skip = strlen(CMD_P2P_SET_PS) + 1;
//bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip);
break;
#ifdef CONFIG_IOCTL_CFG80211
case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE:
{
int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
break;
}
#endif //CONFIG_IOCTL_CFG80211
#ifdef CONFIG_WFD
case ANDROID_WIFI_CMD_WFD_ENABLE:
// Commented by Albert 2012/07/24
// We can enable the WFD function by using the following command:
// wpa_cli driver wfd-enable
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
pwfd_info->wfd_enable = _TRUE;
break;
case ANDROID_WIFI_CMD_WFD_DISABLE:
// Commented by Albert 2012/07/24
// We can disable the WFD function by using the following command:
// wpa_cli driver wfd-disable
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
pwfd_info->wfd_enable = _FALSE;
break;
case ANDROID_WIFI_CMD_WFD_SET_TCPPORT:
// Commented by Albert 2012/07/24
// We can set the tcp port number by using the following command:
// wpa_cli driver wfd-set-tcpport = 554
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
pwfd_info->rtsp_ctrlport = (u16)get_int_from_command(priv_cmd.buf);
break;
case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT:
break;
case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE:
{
// Commented by Albert 2012/08/28
// Specify the WFD device type ( WFD source/primary sink )
struct wifi_display_info *pwfd_info;
_adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
pwfd_info = &padapter->wfd_info;
if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) {
pwfd_info->wfd_device_type = (u8)get_int_from_command(priv_cmd.buf);
pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL;
}
break;
}
#endif
default:
DBG_871X("Unknown PRIVATE command %s - ignored\n", command);
snprintf(command, 3, "OK");
bytes_written = strlen("OK");
}
response:
if (bytes_written >= 0) {
if ((bytes_written == 0) && (priv_cmd.total_len > 0))
command[0] = '\0';
if (bytes_written >= priv_cmd.total_len) {
DBG_871X("%s: bytes_written = %d\n", __FUNCTION__, bytes_written);
bytes_written = priv_cmd.total_len;
} else {
bytes_written++;
}
priv_cmd.used_len = bytes_written;
if (copy_to_user((void *)priv_cmd.buf, command, bytes_written)) {
DBG_871X("%s: failed to copy data to user buffer\n", __FUNCTION__);
ret = -EFAULT;
}
}
else {
ret = bytes_written;
}
exit:
rtw_unlock_suspend();
if (command) {
rtw_mfree(command, priv_cmd.total_len);
}
return ret;
}
/**
* Functions for Android WiFi card detection
*/
#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
static int g_wifidev_registered = 0;
static struct semaphore wifi_control_sem;
static struct wifi_platform_data *wifi_control_data = NULL;
static struct resource *wifi_irqres = NULL;
static int wifi_add_dev(void);
static void wifi_del_dev(void);
int rtw_android_wifictrl_func_add(void)
{
int ret = 0;
sema_init(&wifi_control_sem, 0);
ret = wifi_add_dev();
if (ret) {
DBG_871X("%s: platform_driver_register failed\n", __FUNCTION__);
return ret;
}
g_wifidev_registered = 1;
/* Waiting callback after platform_driver_register is done or exit with error */
if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) {
ret = -EINVAL;
DBG_871X("%s: platform_driver_register timeout\n", __FUNCTION__);
}
return ret;
}
void rtw_android_wifictrl_func_del(void)
{
if (g_wifidev_registered)
{
wifi_del_dev();
g_wifidev_registered = 0;
}
}
void *wl_android_prealloc(int section, unsigned long size)
{
void *alloc_ptr = NULL;
if (wifi_control_data && wifi_control_data->mem_prealloc) {
alloc_ptr = wifi_control_data->mem_prealloc(section, size);
if (alloc_ptr) {
DBG_871X("success alloc section %d\n", section);
if (size != 0L)
memset(alloc_ptr, 0, size);
return alloc_ptr;
}
}
DBG_871X("can't alloc section %d\n", section);
return NULL;
}
int wifi_get_irq_number(unsigned long *irq_flags_ptr)
{
if (wifi_irqres) {
*irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
return (int)wifi_irqres->start;
}
#ifdef CUSTOM_OOB_GPIO_NUM
return CUSTOM_OOB_GPIO_NUM;
#else
return -1;
#endif
}
int wifi_set_power(int on, unsigned long msec)
{
DBG_871X("%s = %d\n", __FUNCTION__, on);
if (wifi_control_data && wifi_control_data->set_power) {
wifi_control_data->set_power(on);
}
if (msec)
msleep(msec);
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
int wifi_get_mac_addr(unsigned char *buf)
{
DBG_871X("%s\n", __FUNCTION__);
if (!buf)
return -EINVAL;
if (wifi_control_data && wifi_control_data->get_mac_addr) {
return wifi_control_data->get_mac_addr(buf);
}
return -EOPNOTSUPP;
}
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) || defined(COMPAT_KERNEL_RELEASE)
void *wifi_get_country_code(char *ccode)
{
DBG_871X("%s\n", __FUNCTION__);
if (!ccode)
return NULL;
if (wifi_control_data && wifi_control_data->get_country_code) {
return wifi_control_data->get_country_code(ccode);
}
return NULL;
}
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
static int wifi_set_carddetect(int on)
{
DBG_871X("%s = %d\n", __FUNCTION__, on);
if (wifi_control_data && wifi_control_data->set_carddetect) {
wifi_control_data->set_carddetect(on);
}
return 0;
}
static int wifi_probe(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
(struct wifi_platform_data *)(pdev->dev.platform_data);
int wifi_wake_gpio = 0;
DBG_871X("## %s\n", __FUNCTION__);
wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
if (wifi_irqres == NULL)
wifi_irqres = platform_get_resource_byname(pdev,
IORESOURCE_IRQ, "bcm4329_wlan_irq");
else
wifi_wake_gpio = wifi_irqres->start;
#ifdef CONFIG_GPIO_WAKEUP
printk("%s: gpio:%d wifi_wake_gpio:%d\n", __func__,
wifi_irqres->start, wifi_wake_gpio);
if (wifi_wake_gpio > 0) {
gpio_request(wifi_wake_gpio, "oob_irq");
gpio_direction_input(wifi_wake_gpio);
oob_irq = gpio_to_irq(wifi_wake_gpio);
printk("%s oob_irq:%d\n", __func__, oob_irq);
}
#endif
wifi_control_data = wifi_ctrl;
wifi_set_power(1, 0); /* Power On */
wifi_set_carddetect(1); /* CardDetect (0->1) */
up(&wifi_control_sem);
return 0;
}
static int wifi_remove(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
(struct wifi_platform_data *)(pdev->dev.platform_data);
DBG_871X("## %s\n", __FUNCTION__);
wifi_control_data = wifi_ctrl;
wifi_set_power(0, 0); /* Power Off */
wifi_set_carddetect(0); /* CardDetect (1->0) */
up(&wifi_control_sem);
return 0;
}
static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
{
DBG_871X("##> %s\n", __FUNCTION__);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
bcmsdh_oob_intr_set(0);
#endif
return 0;
}
static int wifi_resume(struct platform_device *pdev)
{
DBG_871X("##> %s\n", __FUNCTION__);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
bcmsdh_oob_intr_set(1);
#endif
return 0;
}
/* temporarily use these two */
static struct platform_driver wifi_device = {
.probe = wifi_probe,
.remove = wifi_remove,
.suspend = wifi_suspend,
.resume = wifi_resume,
.driver = {
.name = "bcmdhd_wlan",
}
};
static struct platform_driver wifi_device_legacy = {
.probe = wifi_probe,
.remove = wifi_remove,
.suspend = wifi_suspend,
.resume = wifi_resume,
.driver = {
.name = "bcm4329_wlan",
}
};
static int wifi_add_dev(void)
{
DBG_871X("## Calling platform_driver_register\n");
platform_driver_register(&wifi_device);
platform_driver_register(&wifi_device_legacy);
return 0;
}
static void wifi_del_dev(void)
{
DBG_871X("## Unregister platform_driver_register\n");
platform_driver_unregister(&wifi_device);
platform_driver_unregister(&wifi_device_legacy);
}
#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */

File diff suppressed because it is too large Load diff

View file

@ -1,698 +0,0 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
* 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
*
*******************************************************************************/
#define _USB_OPS_LINUX_C_
#include <drv_types.h>
#include <usb_ops_linux.h>
#include <rtw_sreset.h>
#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ
static void _usbctrl_vendorreq_async_callback(struct urb *urb, struct pt_regs *regs)
{
if (urb) {
if (urb->context) {
rtw_mfree(urb->context);
}
usb_free_urb(urb);
}
}
static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
u16 value, u16 index, void *pdata, u16 len, u8 requesttype)
{
int rc;
unsigned int pipe;
u8 reqtype;
struct usb_ctrlrequest *dr;
struct urb *urb;
struct rtl819x_async_write_data {
u8 data[VENDOR_CMD_MAX_DATA_LEN];
struct usb_ctrlrequest dr;
} *buf;
if (requesttype == VENDOR_READ) {
pipe = usb_rcvctrlpipe(udev, 0);//read_in
reqtype = REALTEK_USB_VENQT_READ;
}
else {
pipe = usb_sndctrlpipe(udev, 0);//write_out
reqtype = REALTEK_USB_VENQT_WRITE;
}
buf = (struct rtl819x_async_write_data *)rtw_zmalloc(sizeof(*buf));
if (!buf) {
rc = -ENOMEM;
goto exit;
}
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
rtw_mfree((u8*)buf, sizeof(*buf));
rc = -ENOMEM;
goto exit;
}
dr = &buf->dr;
dr->bRequestType = reqtype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(len);
_rtw_memcpy(buf, pdata, len);
usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, buf, len,
_usbctrl_vendorreq_async_callback, buf);
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (rc < 0) {
rtw_mfree((u8*)buf, sizeof(*buf));
usb_free_urb(urb);
}
exit:
return rc;
}
int usb_write_async(struct usb_device *udev, u32 addr, void *pdata, u16 len)
{
u8 request;
u8 requesttype;
u16 wvalue;
u16 index;
int ret;
requesttype = VENDOR_WRITE;//write_out
request = REALTEK_USB_VENQT_CMD_REQ;
index = REALTEK_USB_VENQT_CMD_IDX;//n/a
wvalue = (u16)(addr&0x0000ffff);
ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, index, pdata, len, requesttype);
return ret;
}
int usb_async_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
{
u8 data;
int ret;
struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
struct usb_device *udev=pdvobjpriv->pusbdev;
_func_enter_;
data = val;
ret = usb_write_async(udev, addr, &data, 1);
_func_exit_;
return ret;
}
int usb_async_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
{
u16 data;
int ret;
struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
struct usb_device *udev=pdvobjpriv->pusbdev;
_func_enter_;
data = val;
ret = usb_write_async(udev, addr, &data, 2);
_func_exit_;
return ret;
}
int usb_async_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
{
u32 data;
int ret;
struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
struct usb_device *udev=pdvobjpriv->pusbdev;
_func_enter_;
data = val;
ret = usb_write_async(udev, addr, &data, 4);
_func_exit_;
return ret;
}
#endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */
unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
{
unsigned int pipe=0, ep_num=0;
struct usb_device *pusbd = pdvobj->pusbdev;
if (addr == RECV_BULK_IN_ADDR) {
pipe=usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]);
} else if (addr == RECV_INT_IN_ADDR) {
pipe=usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]);
} else if (addr < HW_QUEUE_ENTRY) {
ep_num = pdvobj->Queue2Pipe[addr];
pipe = usb_sndbulkpipe(pusbd, ep_num);
}
return pipe;
}
struct zero_bulkout_context{
void *pbuf;
void *purb;
void *pirp;
void *padapter;
};
static void usb_bulkout_zero_complete(struct urb *purb, struct pt_regs *regs)
{
struct zero_bulkout_context *pcontext = (struct zero_bulkout_context *)purb->context;
//DBG_8192C("+usb_bulkout_zero_complete\n");
if(pcontext)
{
if(pcontext->pbuf)
{
rtw_mfree(pcontext->pbuf, sizeof(int));
}
if(pcontext->purb && (pcontext->purb==purb))
{
usb_free_urb(pcontext->purb);
}
rtw_mfree((u8*)pcontext, sizeof(struct zero_bulkout_context));
}
}
static u32 usb_bulkout_zero(struct intf_hdl *pintfhdl, u32 addr)
{
int pipe, status, len;
u32 ret;
unsigned char *pbuf;
struct zero_bulkout_context *pcontext;
PURB purb = NULL;
_adapter *padapter = (_adapter *)pintfhdl->padapter;
struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobj->pusbdev;
//DBG_871X("%s\n", __func__);
if((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx))
{
return _FAIL;
}
pcontext = (struct zero_bulkout_context *)rtw_zmalloc(sizeof(struct zero_bulkout_context));
pbuf = (unsigned char *)rtw_zmalloc(sizeof(int));
purb = usb_alloc_urb(0, GFP_ATOMIC);
len = 0;
pcontext->pbuf = pbuf;
pcontext->purb = purb;
pcontext->pirp = NULL;
pcontext->padapter = padapter;
//translate DMA FIFO addr to pipehandle
//pipe = ffaddr2pipehdl(pdvobj, addr);
usb_fill_bulk_urb(purb, pusbd, pipe,
pbuf,
len,
usb_bulkout_zero_complete,
pcontext);//context is pcontext
status = usb_submit_urb(purb, GFP_ATOMIC);
if (!status)
{
ret= _SUCCESS;
}
else
{
ret= _FAIL;
}
return _SUCCESS;
}
void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
{
}
void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
{
}
void usb_read_port_cancel(struct intf_hdl *pintfhdl)
{
int i;
struct recv_buf *precvbuf;
_adapter *padapter = pintfhdl->padapter;
precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
DBG_871X("%s\n", __func__);
padapter->bReadPortCancel = _TRUE;
for (i=0; i < NR_RECVBUFF ; i++) {
precvbuf->reuse = _TRUE;
if (precvbuf->purb) {
//DBG_8192C("usb_read_port_cancel : usb_kill_urb \n");
usb_kill_urb(precvbuf->purb);
}
precvbuf++;
}
#ifdef CONFIG_USB_INTERRUPT_IN_PIPE
usb_kill_urb(padapter->recvpriv.int_in_urb);
#endif
}
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
{
_irqL irqL;
int i;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
//struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
//_adapter *padapter = pxmitframe->padapter;
_adapter *padapter = pxmitbuf->padapter;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
//struct pkt_attrib *pattrib = &pxmitframe->attrib;
_func_enter_;
switch(pxmitbuf->flags)
{
case VO_QUEUE_INX:
pxmitpriv->voq_cnt--;
break;
case VI_QUEUE_INX:
pxmitpriv->viq_cnt--;
break;
case BE_QUEUE_INX:
pxmitpriv->beq_cnt--;
break;
case BK_QUEUE_INX:
pxmitpriv->bkq_cnt--;
break;
case HIGH_QUEUE_INX:
#ifdef CONFIG_AP_MODE
rtw_chk_hi_queue_cmd(padapter);
#endif
break;
default:
break;
}
/*
_enter_critical(&pxmitpriv->lock, &irqL);
pxmitpriv->txirp_cnt--;
switch(pattrib->priority)
{
case 1:
case 2:
pxmitpriv->bkq_cnt--;
//DBG_8192C("pxmitpriv->bkq_cnt=%d\n", pxmitpriv->bkq_cnt);
break;
case 4:
case 5:
pxmitpriv->viq_cnt--;
//DBG_8192C("pxmitpriv->viq_cnt=%d\n", pxmitpriv->viq_cnt);
break;
case 6:
case 7:
pxmitpriv->voq_cnt--;
//DBG_8192C("pxmitpriv->voq_cnt=%d\n", pxmitpriv->voq_cnt);
break;
case 0:
case 3:
default:
pxmitpriv->beq_cnt--;
//DBG_8192C("pxmitpriv->beq_cnt=%d\n", pxmitpriv->beq_cnt);
break;
}
_exit_critical(&pxmitpriv->lock, &irqL);
if(pxmitpriv->txirp_cnt==0)
{
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: txirp_cnt== 0, set allrxreturnevt!\n"));
_rtw_up_sema(&(pxmitpriv->tx_retevt));
}
*/
//rtw_free_xmitframe(pxmitpriv, pxmitframe);
if(padapter->bSurpriseRemoved || padapter->bDriverStopped ||padapter->bWritePortCancel)
{
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved));
DBG_8192C("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x) \n",
__FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,padapter->bReadPortCancel,pxmitbuf->ext_tag);
goto check_completion;
}
if (purb->status==0) {
} else {
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete : purb->status(%d) != 0 \n", purb->status));
DBG_871X("###=> urb_write_port_complete status(%d)\n",purb->status);
if((purb->status==-EPIPE)||(purb->status==-EPROTO))
{
//usb_clear_halt(pusbdev, purb->pipe);
//msleep(10);
sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL);
} else if (purb->status == -EINPROGRESS) {
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: EINPROGESS\n"));
goto check_completion;
} else if (purb->status == -ENOENT) {
DBG_871X("%s: -ENOENT\n", __func__);
goto check_completion;
} else if (purb->status == -ECONNRESET) {
DBG_871X("%s: -ECONNRESET\n", __func__);
goto check_completion;
} else if (purb->status == -ESHUTDOWN) {
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: ESHUTDOWN\n"));
padapter->bDriverStopped=_TRUE;
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped=TRUE\n"));
goto check_completion;
}
else
{
padapter->bSurpriseRemoved=_TRUE;
DBG_8192C("bSurpriseRemoved=TRUE\n");
//rtl8192cu_trigger_gpio_0(padapter);
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bSurpriseRemoved=TRUE\n"));
goto check_completion;
}
}
#ifdef DBG_CONFIG_ERROR_DETECT
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time();
}
#endif
check_completion:
_enter_critical(&pxmitpriv->lock_sctx, &irqL);
rtw_sctx_done_err(&pxmitbuf->sctx,
purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS);
_exit_critical(&pxmitpriv->lock_sctx, &irqL);
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
//if(rtw_txframes_pending(padapter))
{
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
}
_func_exit_;
}
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
{
_irqL irqL;
unsigned int pipe;
int status;
u32 ret = _FAIL, bwritezero = _FALSE;
PURB purb = NULL;
_adapter *padapter = (_adapter *)pintfhdl->padapter;
struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem;
struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
struct usb_device *pusbd = pdvobj->pusbdev;
struct pkt_attrib *pattrib = &pxmitframe->attrib;
_func_enter_;
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("+usb_write_port\n"));
if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx)) {
#ifdef DBG_TX
DBG_871X(" DBG_TX %s:%d bDriverStopped%d, bSurpriseRemoved:%d, pnp_bstop_trx:%d\n",__FUNCTION__, __LINE__
,padapter->bDriverStopped, padapter->bSurpriseRemoved, dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx );
#endif
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||pwrctl->pnp_bstop_trx)!!!\n"));
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
goto exit;
}
_enter_critical(&pxmitpriv->lock, &irqL);
switch(addr)
{
case VO_QUEUE_INX:
pxmitpriv->voq_cnt++;
pxmitbuf->flags = VO_QUEUE_INX;
break;
case VI_QUEUE_INX:
pxmitpriv->viq_cnt++;
pxmitbuf->flags = VI_QUEUE_INX;
break;
case BE_QUEUE_INX:
pxmitpriv->beq_cnt++;
pxmitbuf->flags = BE_QUEUE_INX;
break;
case BK_QUEUE_INX:
pxmitpriv->bkq_cnt++;
pxmitbuf->flags = BK_QUEUE_INX;
break;
case HIGH_QUEUE_INX:
pxmitbuf->flags = HIGH_QUEUE_INX;
break;
default:
pxmitbuf->flags = MGT_QUEUE_INX;
break;
}
_exit_critical(&pxmitpriv->lock, &irqL);
#ifdef DBG_TRX_STA_PKTS
{
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
int bmcast = IS_MCAST(pattrib->dst);
u8 agg_num = 1;
#ifdef CONFIG_USB_HCI
#ifdef CONFIG_USB_TX_AGGREGATION
if(pxmitframe->agg_num>1)
agg_num = pxmitframe->agg_num;
#endif
#endif
#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
if(pxmitframe->agg_num>1)
agg_num = pxmitframe->agg_num;
#endif
if(bmcast)
{
psta = rtw_get_bcmc_stainfo(padapter);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->dst);
}
if(psta)
{
switch(pattrib->priority)
{
case 1:
case 2:
psta->tx_bk_cnt += agg_num;
break;
case 4:
case 5:
psta->tx_vi_cnt += agg_num;
break;
case 6:
case 7:
psta->tx_vo_cnt += agg_num;
break;
case 0:
case 3:
default:
psta->tx_be_cnt += agg_num;
break;
}
}
}
#endif
purb = pxmitbuf->pxmit_urb[0];
#if 0
if(pdvobj->ishighspeed)
{
if(cnt> 0 && cnt%512 == 0)
{
//DBG_8192C("ishighspeed, cnt=%d\n", cnt);
bwritezero = _TRUE;
}
}
else
{
if(cnt > 0 && cnt%64 == 0)
{
//DBG_8192C("cnt=%d\n", cnt);
bwritezero = _TRUE;
}
}
#endif
//translate DMA FIFO addr to pipehandle
pipe = ffaddr2pipehdl(pdvobj, addr);
#ifdef CONFIG_REDUCE_USB_TX_INT
if ( (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0)
|| (pxmitbuf->ext_tag == _TRUE) )
{
purb->transfer_flags &= (~URB_NO_INTERRUPT);
} else {
purb->transfer_flags |= URB_NO_INTERRUPT;
//DBG_8192C("URB_NO_INTERRUPT ");
}
#endif
usb_fill_bulk_urb(purb, pusbd, pipe,
pxmitframe->buf_addr, //= pxmitbuf->pbuf
cnt,
usb_write_port_complete,
pxmitbuf);//context is pxmitbuf
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
purb->transfer_dma = pxmitbuf->dma_transfer_addr;
purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
purb->transfer_flags |= URB_ZERO_PACKET;
#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
#if 0
if (bwritezero)
{
purb->transfer_flags |= URB_ZERO_PACKET;
}
#endif
status = usb_submit_urb(purb, GFP_ATOMIC);
if (!status) {
#ifdef DBG_CONFIG_ERROR_DETECT
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
pHalData->srestpriv.last_tx_time = rtw_get_current_time();
}
#endif
} else {
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
DBG_871X("usb_write_port, status=%d\n", status);
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port(): usb_submit_urb, status=%x\n", status));
switch (status) {
case -ENODEV:
padapter->bDriverStopped=_TRUE;
break;
default:
break;
}
goto exit;
}
ret= _SUCCESS;
// Commented by Albert 2009/10/13
// We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically.
/*
if(bwritezero == _TRUE)
{
usb_bulkout_zero(pintfhdl, addr);
}
*/
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("-usb_write_port\n"));
exit:
if (ret != _SUCCESS)
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
_func_exit_;
return ret;
}
void usb_write_port_cancel(struct intf_hdl *pintfhdl)
{
int i, j;
_adapter *padapter = pintfhdl->padapter;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
DBG_871X("%s \n", __func__);
padapter->bWritePortCancel = _TRUE;
for (i=0; i<NR_XMITBUFF; i++) {
for (j=0; j<8; j++) {
if (pxmitbuf->pxmit_urb[j]) {
usb_kill_urb(pxmitbuf->pxmit_urb[j]);
}
}
pxmitbuf++;
}
pxmitbuf = (struct xmit_buf*)padapter->xmitpriv.pxmit_extbuf;
for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
for (j=0; j<8; j++) {
if(pxmitbuf->pxmit_urb[j]) {
usb_kill_urb(pxmitbuf->pxmit_urb[j]);
}
}
pxmitbuf++;
}
}

View file

@ -1,456 +0,0 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
* 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
*
*
******************************************************************************/
#define _XMIT_OSDEP_C_
#include <drv_conf.h>
#include <osdep_service.h>
#include <drv_types.h>
#include <if_ether.h>
#include <ip.h>
#include <rtw_byteorder.h>
#include <wifi.h>
#include <mlme_osdep.h>
#include <xmit_osdep.h>
#include <osdep_intf.h>
#include <circ_buf.h>
uint rtw_remainder_len(struct pkt_file *pfile)
{
return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start)));
}
void _rtw_open_pktfile (_pkt *pktptr, struct pkt_file *pfile)
{
_func_enter_;
pfile->pkt = pktptr;
pfile->cur_addr = pfile->buf_start = pktptr->data;
pfile->pkt_len = pfile->buf_len = pktptr->len;
pfile->cur_buffer = pfile->buf_start ;
_func_exit_;
}
uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
{
uint len = 0;
_func_enter_;
len = rtw_remainder_len(pfile);
len = (rlen > len)? len: rlen;
if(rmem)
skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
pfile->cur_addr += len;
pfile->pkt_len -= len;
_func_exit_;
return len;
}
sint rtw_endofpktfile(struct pkt_file *pfile)
{
_func_enter_;
if (pfile->pkt_len == 0) {
_func_exit_;
return _TRUE;
}
_func_exit_;
return _FALSE;
}
void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib)
{
#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
struct sk_buff *skb = (struct sk_buff *)pkt;
pattrib->hw_tcp_csum = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb_shinfo(skb)->nr_frags == 0)
{
const struct iphdr *ip = ip_hdr(skb);
if (ip->protocol == IPPROTO_TCP) {
// TCP checksum offload by HW
DBG_871X("CHECKSUM_PARTIAL TCP\n");
pattrib->hw_tcp_csum = 1;
//skb_checksum_help(skb);
} else if (ip->protocol == IPPROTO_UDP) {
//DBG_871X("CHECKSUM_PARTIAL UDP\n");
#if 1
skb_checksum_help(skb);
#else
// Set UDP checksum = 0 to skip checksum check
struct udphdr *udp = skb_transport_header(skb);
udp->check = 0;
#endif
} else {
DBG_871X("%s-%d TCP CSUM offload Error!!\n", __FUNCTION__, __LINE__);
WARN_ON(1); /* we need a WARN() */
}
}
else { // IP fragmentation case
DBG_871X("%s-%d nr_frags != 0, using skb_checksum_help(skb);!!\n", __FUNCTION__, __LINE__);
skb_checksum_help(skb);
}
}
#endif
}
int rtw_os_xmit_resource_alloc(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 alloc_sz)
{
#ifdef CONFIG_USB_HCI
int i;
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
pxmitbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)alloc_sz, &pxmitbuf->dma_transfer_addr);
pxmitbuf->pbuf = pxmitbuf->pallocated_buf;
if(pxmitbuf->pallocated_buf == NULL)
return _FAIL;
#else // CONFIG_USE_USB_BUFFER_ALLOC_TX
pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
if (pxmitbuf->pallocated_buf == NULL)
{
return _FAIL;
}
pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
pxmitbuf->dma_transfer_addr = 0;
#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
for(i=0; i<8; i++)
{
pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
if(pxmitbuf->pxmit_urb[i] == NULL)
{
DBG_871X("pxmitbuf->pxmit_urb[i]==NULL");
return _FAIL;
}
}
#endif
#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
if (pxmitbuf->pallocated_buf == NULL)
{
return _FAIL;
}
pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
#endif
return _SUCCESS;
}
void rtw_os_xmit_resource_free(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 free_sz)
{
#ifdef CONFIG_USB_HCI
int i;
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
for(i=0; i<8; i++)
{
if(pxmitbuf->pxmit_urb[i])
{
//usb_kill_urb(pxmitbuf->pxmit_urb[i]);
usb_free_urb(pxmitbuf->pxmit_urb[i]);
}
}
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
rtw_usb_buffer_free(pusbd, (size_t)free_sz, pxmitbuf->pallocated_buf, pxmitbuf->dma_transfer_addr);
pxmitbuf->pallocated_buf = NULL;
pxmitbuf->dma_transfer_addr = 0;
#else // CONFIG_USE_USB_BUFFER_ALLOC_TX
if(pxmitbuf->pallocated_buf)
rtw_mfree(pxmitbuf->pallocated_buf, free_sz);
#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
#endif
#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
if(pxmitbuf->pallocated_buf)
rtw_mfree(pxmitbuf->pallocated_buf, free_sz);
#endif
}
#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5)
void rtw_os_pkt_complete(_adapter *padapter, _pkt *pkt)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
u16 queue;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
queue = skb_get_queue_mapping(pkt);
if (padapter->registrypriv.wifi_spec) {
if(__netif_subqueue_stopped(padapter->pnetdev, queue) &&
(pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
{
netif_wake_subqueue(padapter->pnetdev, queue);
}
} else {
if(__netif_subqueue_stopped(padapter->pnetdev, queue))
netif_wake_subqueue(padapter->pnetdev, queue);
}
#else
if (netif_queue_stopped(padapter->pnetdev))
netif_wake_queue(padapter->pnetdev);
#endif
rtw_skb_free(pkt);
}
void rtw_os_xmit_complete(_adapter *padapter, struct xmit_frame *pxframe)
{
if(pxframe->pkt)
rtw_os_pkt_complete(padapter, pxframe->pkt);
pxframe->pkt = NULL;
}
void rtw_os_xmit_schedule(_adapter *padapter)
{
_adapter *pri_adapter = padapter;
#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
if(!padapter)
return;
#ifdef CONFIG_CONCURRENT_MODE
if(padapter->adapter_type > PRIMARY_ADAPTER)
pri_adapter = padapter->pbuddy_adapter;
#endif
if (_rtw_queue_empty(&pri_adapter->xmitpriv.pending_xmitbuf_queue) == _FALSE)
_rtw_up_sema(&pri_adapter->xmitpriv.xmit_sema);
#else
_irqL irqL;
struct xmit_priv *pxmitpriv;
if(!padapter)
return;
pxmitpriv = &padapter->xmitpriv;
_enter_critical_bh(&pxmitpriv->lock, &irqL);
if(rtw_txframes_pending(padapter))
{
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
}
_exit_critical_bh(&pxmitpriv->lock, &irqL);
#endif
}
static void rtw_check_xmit_resource(_adapter *padapter, _pkt *pkt)
{
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
u16 queue;
queue = skb_get_queue_mapping(pkt);
if (padapter->registrypriv.wifi_spec) {
/* No free space for Tx, tx_worker is too slow */
if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) {
//DBG_871X("%s(): stop netif_subqueue[%d]\n", __FUNCTION__, queue);
netif_stop_subqueue(padapter->pnetdev, queue);
}
} else {
if(pxmitpriv->free_xmitframe_cnt<=4) {
if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
netif_stop_subqueue(padapter->pnetdev, queue);
}
}
#else
if(pxmitpriv->free_xmitframe_cnt<=4)
{
if (!rtw_netif_queue_stopped(padapter->pnetdev))
rtw_netif_stop_queue(padapter->pnetdev);
}
#endif
}
#ifdef CONFIG_TX_MCAST2UNI
static int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb)
{
struct sta_priv *pstapriv = &padapter->stapriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
_irqL irqL;
_list *phead, *plist;
struct sk_buff *newskb;
struct sta_info *psta = NULL;
u8 chk_alive_num = 0;
char chk_alive_list[NUM_STA];
u8 bc_addr[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u8 null_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
int i;
s32 res;
_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
phead = &pstapriv->asoc_list;
plist = get_next(phead);
//free sta asoc_queue
while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
int stainfo_offset;
psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
plist = get_next(plist);
stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
if (stainfo_offset_valid(stainfo_offset)) {
chk_alive_list[chk_alive_num++] = stainfo_offset;
}
}
_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
for (i = 0; i < chk_alive_num; i++) {
psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
if(!(psta->state &_FW_LINKED))
continue;
/* avoid come from STA1 and send back STA1 */
if (_rtw_memcmp(psta->hwaddr, &skb->data[6], 6) == _TRUE
|| _rtw_memcmp(psta->hwaddr, null_addr, 6) == _TRUE
|| _rtw_memcmp(psta->hwaddr, bc_addr, 6) == _TRUE
)
continue;
newskb = rtw_skb_copy(skb);
if (newskb) {
_rtw_memcpy(newskb->data, psta->hwaddr, 6);
res = rtw_xmit(padapter, &newskb);
if (res < 0) {
DBG_871X("%s()-%d: rtw_xmit() return error!\n", __FUNCTION__, __LINE__);
pxmitpriv->tx_drop++;
rtw_skb_free(newskb);
} else
pxmitpriv->tx_pkts++;
} else {
DBG_871X("%s-%d: rtw_skb_copy() failed!\n", __FUNCTION__, __LINE__);
pxmitpriv->tx_drop++;
//rtw_skb_free(skb);
return _FALSE; // Caller shall tx this multicast frame via normal way.
}
}
rtw_skb_free(skb);
return _TRUE;
}
#endif // CONFIG_TX_MCAST2UNI
int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
{
_adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
#ifdef CONFIG_TX_MCAST2UNI
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
extern int rtw_mc2u_disable;
#endif // CONFIG_TX_MCAST2UNI
s32 res = 0;
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
u16 queue;
#endif
_func_enter_;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
if (rtw_if_up(padapter) == _FALSE) {
RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
#ifdef DBG_TX_DROP_FRAME
DBG_871X("DBG_TX_DROP_FRAME %s if_up fail\n", __FUNCTION__);
#endif
goto drop_packet;
}
rtw_check_xmit_resource(padapter, pkt);
#ifdef CONFIG_TX_MCAST2UNI
if ( !rtw_mc2u_disable
&& check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE
&& ( IP_MCAST_MAC(pkt->data)
|| ICMPV6_MCAST_MAC(pkt->data) )
&& (padapter->registrypriv.wifi_spec == 0)
)
{
if ( pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4) ) {
res = rtw_mlcst2unicst(padapter, pkt);
if (res == _TRUE) {
goto exit;
}
} else {
//DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt);
//DBG_871X("!m2u );
}
}
#endif // CONFIG_TX_MCAST2UNI
res = rtw_xmit(padapter, &pkt);
if (res < 0) {
#ifdef DBG_TX_DROP_FRAME
DBG_871X("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__);
#endif
goto drop_packet;
}
pxmitpriv->tx_pkts++;
RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
goto exit;
drop_packet:
pxmitpriv->tx_drop++;
rtw_skb_free(pkt);
RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
exit:
_func_exit_;
return 0;
}
int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
{
if (pkt)
rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, pkt->truesize);
return _rtw_xmit_entry(pkt, pnetdev);
}

573
os_dep/mlme_linux.c Normal file → Executable file
View file

@ -1,7 +1,7 @@
/****************************************************************************** /******************************************************************************
* *
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation. * published by the Free Software Foundation.
@ -18,222 +18,603 @@
* *
******************************************************************************/ ******************************************************************************/
#define _MLME_OSDEP_C_ #define _MLME_OSDEP_C_
#include <drv_conf.h>
#include <osdep_service.h> #include <osdep_service.h>
#include <drv_types.h> #include <drv_types.h>
#include <mlme_osdep.h> #include <mlme_osdep.h>
#ifdef RTK_DMP_PLATFORM
void Linkup_workitem_callback(struct work_struct *work)
{
struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkup_workitem);
_adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv);
_func_enter_;
RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+ Linkup_workitem_callback\n"));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12))
kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKUP);
#else
kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKUP);
#endif
_func_exit_;
}
void Linkdown_workitem_callback(struct work_struct *work)
{
struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkdown_workitem);
_adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv);
_func_enter_;
RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+ Linkdown_workitem_callback\n"));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12))
kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKDOWN);
#else
kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKDOWN);
#endif
_func_exit_;
}
#endif
/*
void sitesurvey_ctrl_handler(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
_sitesurvey_ctrl_handler(adapter);
_set_timer(&adapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, 3000);
}
*/
void rtw_join_timeout_handler (void *FunctionContext) void rtw_join_timeout_handler (void *FunctionContext)
{ {
struct adapter *adapter = (struct adapter *)FunctionContext; _adapter *adapter = (_adapter *)FunctionContext;
_rtw_join_timeout_handler(adapter); _rtw_join_timeout_handler(adapter);
} }
void _rtw_scan_timeout_handler (void *FunctionContext) void _rtw_scan_timeout_handler (void *FunctionContext)
{ {
struct adapter *adapter = (struct adapter *)FunctionContext; _adapter *adapter = (_adapter *)FunctionContext;
rtw_scan_timeout_handler(adapter); rtw_scan_timeout_handler(adapter);
} }
static void _dynamic_check_timer_handlder(void *FunctionContext)
{
struct adapter *adapter = (struct adapter *)FunctionContext;
if (adapter->registrypriv.mp_mode == 1) void _dynamic_check_timer_handlder (void *FunctionContext)
return; {
_adapter *adapter = (_adapter *)FunctionContext;
/* remove for MP power tracking DM.
#if (MP_DRIVER == 1)
if (adapter->registrypriv.mp_mode == 1)
return;
#endif
*/
rtw_dynamic_check_timer_handlder(adapter); rtw_dynamic_check_timer_handlder(adapter);
_set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000); _set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000);
} }
void rtw_init_mlme_timer(struct adapter *padapter) #ifdef CONFIG_SET_SCAN_DENY_TIMER
void _rtw_set_scan_deny_timer_hdl(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
rtw_set_scan_deny_timer_hdl(adapter);
}
#endif
#ifdef CONFIG_DETECT_C2H_BY_POLLING
void _rtw_event_polling_timer_hdl(void *FunctionContext)
{
_adapter *adapter = (_adapter *)FunctionContext;
rtw_event_polling_timer_hdl(adapter);
_set_timer(&adapter->mlmepriv.event_polling_timer, 200);
}
#endif
void rtw_init_mlme_timer(_adapter *padapter)
{ {
struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
_init_timer(&(pmlmepriv->assoc_timer), padapter->pnetdev, rtw_join_timeout_handler, padapter); _init_timer(&(pmlmepriv->assoc_timer), padapter->pnetdev, rtw_join_timeout_handler, padapter);
//_init_timer(&(pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer), padapter->pnetdev, sitesurvey_ctrl_handler, padapter);
_init_timer(&(pmlmepriv->scan_to_timer), padapter->pnetdev, _rtw_scan_timeout_handler, padapter); _init_timer(&(pmlmepriv->scan_to_timer), padapter->pnetdev, _rtw_scan_timeout_handler, padapter);
_init_timer(&(pmlmepriv->dynamic_chk_timer), padapter->pnetdev, _dynamic_check_timer_handlder, padapter); _init_timer(&(pmlmepriv->dynamic_chk_timer), padapter->pnetdev, _dynamic_check_timer_handlder, padapter);
#ifdef CONFIG_SET_SCAN_DENY_TIMER
_init_timer(&(pmlmepriv->set_scan_deny_timer), padapter->pnetdev, _rtw_set_scan_deny_timer_hdl, padapter);
#endif
#ifdef CONFIG_DETECT_C2H_BY_POLLING
_init_timer(&(pmlmepriv->event_polling_timer), padapter->pnetdev, _rtw_event_polling_timer_hdl, padapter);
#endif
#ifdef RTK_DMP_PLATFORM
_init_workitem(&(pmlmepriv->Linkup_workitem), Linkup_workitem_callback, padapter);
_init_workitem(&(pmlmepriv->Linkdown_workitem), Linkdown_workitem_callback, padapter);
#endif
#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST)
if (padapter->HalFunc.hal_init_checkbthang_workqueue)
padapter->HalFunc.hal_init_checkbthang_workqueue(padapter);
#endif
} }
void rtw_os_indicate_connect(struct adapter *adapter) extern void rtw_indicate_wx_assoc_event(_adapter *padapter);
extern void rtw_indicate_wx_disassoc_event(_adapter *padapter);
void rtw_os_indicate_connect(_adapter *adapter)
{ {
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
_func_enter_;
#ifdef CONFIG_IOCTL_CFG80211
if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==_TRUE ) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==_TRUE ) )
{
rtw_cfg80211_ibss_indicate_connect(adapter);
}
else
rtw_cfg80211_indicate_connect(adapter);
#endif //CONFIG_IOCTL_CFG80211
rtw_indicate_wx_assoc_event(adapter); rtw_indicate_wx_assoc_event(adapter);
netif_carrier_on(adapter->pnetdev); netif_carrier_on(adapter->pnetdev);
if (adapter->pid[2] != 0)
if(adapter->pid[2] !=0)
rtw_signal_process(adapter->pid[2], SIGALRM); rtw_signal_process(adapter->pid[2], SIGALRM);
#ifdef RTK_DMP_PLATFORM
_set_workitem(&adapter->mlmepriv.Linkup_workitem);
#endif
_func_exit_;
} }
void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted) extern void indicate_wx_scan_complete_event(_adapter *padapter);
void rtw_os_indicate_scan_done( _adapter *padapter, bool aborted)
{ {
#ifdef CONFIG_IOCTL_CFG80211
rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), aborted);
#endif
indicate_wx_scan_complete_event(padapter); indicate_wx_scan_complete_event(padapter);
} }
static struct rt_pmkid_list backup_pmkid[NUM_PMKID_CACHE]; static RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ];
void rtw_reset_securitypriv( _adapter *adapter )
void rtw_reset_securitypriv(struct adapter *adapter)
{ {
u8 backup_index = 0; u8 backupPMKIDIndex = 0;
u8 backup_counter = 0x00; u8 backupTKIPCountermeasure = 0x00;
u32 backup_time = 0; u32 backupTKIPcountermeasure_time = 0;
// add for CONFIG_IEEE80211W, none 11w also can use
_irqL irqL;
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
_enter_critical_bh(&adapter->security_key_mutex, &irqL);
if(adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)//802.1x
{
// Added by Albert 2009/02/18
// We have to backup the PMK information for WiFi PMK Caching test item.
//
// Backup the btkip_countermeasure information.
// When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds.
if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { _rtw_memset( &backupPMKIDList[ 0 ], 0x00, sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
/* 802.1x */
/* We have to backup the PMK information for WiFi PMK Caching test item. */ _rtw_memcpy( &backupPMKIDList[ 0 ], &adapter->securitypriv.PMKIDList[ 0 ], sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
/* Backup the btkip_countermeasure information. */ backupPMKIDIndex = adapter->securitypriv.PMKIDIndex;
/* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */ backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure;
_rtw_memset(&backup_pmkid[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time;
memcpy(&backup_pmkid[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); #ifdef CONFIG_IEEE80211W
backup_index = adapter->securitypriv.PMKIDIndex; //reset RX BIP packet number
backup_counter = adapter->securitypriv.btkip_countermeasure; pmlmeext->mgnt_80211w_IPN_rx = 0;
backup_time = adapter->securitypriv.btkip_countermeasure_time; #endif //CONFIG_IEEE80211W
_rtw_memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv)); _rtw_memset((unsigned char *)&adapter->securitypriv, 0, sizeof (struct security_priv));
//_init_timer(&(adapter->securitypriv.tkip_timer),adapter->pnetdev, rtw_use_tkipkey_handler, adapter);
// Added by Albert 2009/02/18
// Restore the PMK information to securitypriv structure for the following connection.
_rtw_memcpy( &adapter->securitypriv.PMKIDList[ 0 ], &backupPMKIDList[ 0 ], sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
adapter->securitypriv.PMKIDIndex = backupPMKIDIndex;
adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure;
adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time;
/* Restore the PMK information to securitypriv structure for the following connection. */
memcpy(&adapter->securitypriv.PMKIDList[0],
&backup_pmkid[0],
sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
adapter->securitypriv.PMKIDIndex = backup_index;
adapter->securitypriv.btkip_countermeasure = backup_counter;
adapter->securitypriv.btkip_countermeasure_time = backup_time;
adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
} else {
/* reset values in securitypriv */
struct security_priv *psec_priv = &adapter->securitypriv;
psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ }
else //reset values in securitypriv
{
//if(adapter->mlmepriv.fw_state & WIFI_STATION_STATE)
//{
struct security_priv *psec_priv=&adapter->securitypriv;
psec_priv->dot11AuthAlgrthm =dot11AuthAlgrthm_Open; //open system
psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_; psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
psec_priv->dot11PrivacyKeyIndex = 0; psec_priv->dot11PrivacyKeyIndex = 0;
psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_; psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_;
psec_priv->dot118021XGrpKeyid = 1; psec_priv->dot118021XGrpKeyid = 1;
psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
//}
} }
// add for CONFIG_IEEE80211W, none 11w also can use
_exit_critical_bh(&adapter->security_key_mutex, &irqL);
} }
void rtw_os_indicate_disconnect(struct adapter *adapter) void rtw_os_indicate_disconnect( _adapter *adapter )
{ {
//RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ];
_func_enter_;
netif_carrier_off(adapter->pnetdev); // Do it first for tx broadcast pkt after disconnection issue!
#ifdef CONFIG_IOCTL_CFG80211
rtw_cfg80211_indicate_disconnect(adapter);
#endif //CONFIG_IOCTL_CFG80211
netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */
rtw_indicate_wx_disassoc_event(adapter); rtw_indicate_wx_disassoc_event(adapter);
rtw_reset_securitypriv(adapter);
#ifdef RTK_DMP_PLATFORM
_set_workitem(&adapter->mlmepriv.Linkdown_workitem);
#endif
//modify for CONFIG_IEEE80211W, none 11w also can use the same command
rtw_reset_securitypriv_cmd(adapter);
_func_exit_;
} }
void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) void rtw_report_sec_ie(_adapter *adapter,u8 authmode,u8 *sec_ie)
{ {
uint len; uint len;
u8 *buff, *p, i; u8 *buff,*p,i;
union iwreq_data wrqu; union iwreq_data wrqu;
RT_TRACE(_module_mlme_osdep_c_, _drv_info_, _func_enter_;
("+rtw_report_sec_ie, authmode=%d\n", authmode));
RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+rtw_report_sec_ie, authmode=%d\n", authmode));
buff = NULL; buff = NULL;
if (authmode == _WPA_IE_ID_) { if(authmode==_WPA_IE_ID_)
RT_TRACE(_module_mlme_osdep_c_, _drv_info_, {
("rtw_report_sec_ie, authmode=%d\n", authmode)); RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("rtw_report_sec_ie, authmode=%d\n", authmode));
buff = rtw_malloc(IW_CUSTOM_MAX); buff = rtw_malloc(IW_CUSTOM_MAX);
if (!buff)
return; _rtw_memset(buff,0,IW_CUSTOM_MAX);
_rtw_memset(buff, 0, IW_CUSTOM_MAX);
p = buff; p=buff;
p += sprintf(p, "ASSOCINFO(ReqIEs =");
p+=sprintf(p,"ASSOCINFO(ReqIEs=");
len = sec_ie[1]+2; len = sec_ie[1]+2;
len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX; len = (len < IW_CUSTOM_MAX) ? len:IW_CUSTOM_MAX;
for (i = 0; i < len; i++)
p += sprintf(p, "%02x", sec_ie[i]); for(i=0;i<len;i++){
p += sprintf(p, ")"); p+=sprintf(p,"%02x",sec_ie[i]);
_rtw_memset(&wrqu, 0, sizeof(wrqu)); }
wrqu.data.length = p-buff;
wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? p+=sprintf(p,")");
wrqu.data.length : IW_CUSTOM_MAX;
wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff); _rtw_memset(&wrqu,0,sizeof(wrqu));
kfree(buff);
wrqu.data.length=p-buff;
wrqu.data.length = (wrqu.data.length<IW_CUSTOM_MAX) ? wrqu.data.length:IW_CUSTOM_MAX;
#ifndef CONFIG_IOCTL_CFG80211
wireless_send_event(adapter->pnetdev,IWEVCUSTOM,&wrqu,buff);
#endif
if(buff)
rtw_mfree(buff, IW_CUSTOM_MAX);
} }
_func_exit_;
} }
static void _survey_timer_hdl(void *FunctionContext) void _survey_timer_hdl (void *FunctionContext)
{ {
struct adapter *padapter = (struct adapter *)FunctionContext; _adapter *padapter = (_adapter *)FunctionContext;
survey_timer_hdl(padapter); survey_timer_hdl(padapter);
} }
static void _link_timer_hdl(void *FunctionContext) void _link_timer_hdl (void *FunctionContext)
{ {
struct adapter *padapter = (struct adapter *)FunctionContext; _adapter *padapter = (_adapter *)FunctionContext;
link_timer_hdl(padapter); link_timer_hdl(padapter);
} }
static void _addba_timer_hdl(void *FunctionContext) void _addba_timer_hdl(void *FunctionContext)
{ {
struct sta_info *psta = (struct sta_info *)FunctionContext; struct sta_info *psta = (struct sta_info *)FunctionContext;
addba_timer_hdl(psta); addba_timer_hdl(psta);
} }
void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta) #ifdef CONFIG_IEEE80211W
void _sa_query_timer_hdl (void *FunctionContext)
{ {
_adapter *padapter = (_adapter *)FunctionContext;
sa_query_timer_hdl(padapter);
}
#endif //CONFIG_IEEE80211W
void init_addba_retry_timer(_adapter *padapter, struct sta_info *psta)
{
_init_timer(&psta->addba_retry_timer, padapter->pnetdev, _addba_timer_hdl, psta); _init_timer(&psta->addba_retry_timer, padapter->pnetdev, _addba_timer_hdl, psta);
} }
void init_mlme_ext_timer(struct adapter *padapter) /*
void _reauth_timer_hdl(void *FunctionContext)
{ {
_adapter *padapter = (_adapter *)FunctionContext;
reauth_timer_hdl(padapter);
}
void _reassoc_timer_hdl(void *FunctionContext)
{
_adapter *padapter = (_adapter *)FunctionContext;
reassoc_timer_hdl(padapter);
}
*/
void init_mlme_ext_timer(_adapter *padapter)
{
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
_init_timer(&pmlmeext->survey_timer, padapter->pnetdev, _survey_timer_hdl, padapter); _init_timer(&pmlmeext->survey_timer, padapter->pnetdev, _survey_timer_hdl, padapter);
_init_timer(&pmlmeext->link_timer, padapter->pnetdev, _link_timer_hdl, padapter); _init_timer(&pmlmeext->link_timer, padapter->pnetdev, _link_timer_hdl, padapter);
#ifdef CONFIG_IEEE80211W
_init_timer(&pmlmeext->sa_query_timer, padapter->pnetdev, _sa_query_timer_hdl, padapter);
#endif //CONFIG_IEEE80211W
//_init_timer(&pmlmeext->ADDBA_timer, padapter->pnetdev, _addba_timer_hdl, padapter);
//_init_timer(&pmlmeext->reauth_timer, padapter->pnetdev, _reauth_timer_hdl, padapter);
//_init_timer(&pmlmeext->reassoc_timer, padapter->pnetdev, _reassoc_timer_hdl, padapter);
} }
#ifdef CONFIG_88EU_AP_MODE #ifdef CONFIG_AP_MODE
void rtw_indicate_sta_assoc_event(struct adapter *padapter, struct sta_info *psta) void rtw_indicate_sta_assoc_event(_adapter *padapter, struct sta_info *psta)
{ {
union iwreq_data wrqu; union iwreq_data wrqu;
struct sta_priv *pstapriv = &padapter->stapriv; struct sta_priv *pstapriv = &padapter->stapriv;
if (psta == NULL) if(psta==NULL)
return; return;
if (psta->aid > NUM_STA) if(psta->aid > NUM_STA)
return; return;
if (pstapriv->sta_aid[psta->aid - 1] != psta) if(pstapriv->sta_aid[psta->aid - 1] != psta)
return; return;
wrqu.addr.sa_family = ARPHRD_ETHER;
_rtw_memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
wrqu.addr.sa_family = ARPHRD_ETHER; DBG_871X("+rtw_indicate_sta_assoc_event\n");
memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); #ifndef CONFIG_IOCTL_CFG80211
DBG_88E("+rtw_indicate_sta_assoc_event\n");
wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL); wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL);
#endif
} }
void rtw_indicate_sta_disassoc_event(struct adapter *padapter, struct sta_info *psta) void rtw_indicate_sta_disassoc_event(_adapter *padapter, struct sta_info *psta)
{ {
union iwreq_data wrqu; union iwreq_data wrqu;
struct sta_priv *pstapriv = &padapter->stapriv; struct sta_priv *pstapriv = &padapter->stapriv;
if (psta == NULL) if(psta==NULL)
return; return;
if (psta->aid > NUM_STA) if(psta->aid > NUM_STA)
return; return;
if (pstapriv->sta_aid[psta->aid - 1] != psta) if(pstapriv->sta_aid[psta->aid - 1] != psta)
return; return;
wrqu.addr.sa_family = ARPHRD_ETHER;
_rtw_memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
wrqu.addr.sa_family = ARPHRD_ETHER; DBG_871X("+rtw_indicate_sta_disassoc_event\n");
memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); #ifndef CONFIG_IOCTL_CFG80211
DBG_88E("+rtw_indicate_sta_disassoc_event\n");
wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL); wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL);
#endif
}
#ifdef CONFIG_HOSTAPD_MLME
static int mgnt_xmit_entry(struct sk_buff *skb, struct net_device *pnetdev)
{
struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
_adapter *padapter = (_adapter *)phostapdpriv->padapter;
//DBG_871X("%s\n", __FUNCTION__);
return rtw_hal_hostap_mgnt_xmit_entry(padapter, skb);
}
static int mgnt_netdev_open(struct net_device *pnetdev)
{
struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
DBG_871X("mgnt_netdev_open: MAC Address:" MAC_FMT "\n", MAC_ARG(pnetdev->dev_addr));
init_usb_anchor(&phostapdpriv->anchored);
if(!rtw_netif_queue_stopped(pnetdev))
rtw_netif_start_queue(pnetdev);
else
rtw_netif_wake_queue(pnetdev);
netif_carrier_on(pnetdev);
//rtw_write16(phostapdpriv->padapter, 0x0116, 0x0100);//only excluding beacon
return 0;
}
static int mgnt_netdev_close(struct net_device *pnetdev)
{
struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
DBG_871X("%s\n", __FUNCTION__);
usb_kill_anchored_urbs(&phostapdpriv->anchored);
netif_carrier_off(pnetdev);
if (!rtw_netif_queue_stopped(pnetdev))
rtw_netif_stop_queue(pnetdev);
//rtw_write16(phostapdpriv->padapter, 0x0116, 0x3f3f);
return 0;
}
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29))
static const struct net_device_ops rtl871x_mgnt_netdev_ops = {
.ndo_open = mgnt_netdev_open,
.ndo_stop = mgnt_netdev_close,
.ndo_start_xmit = mgnt_xmit_entry,
//.ndo_set_mac_address = r871x_net_set_mac_address,
//.ndo_get_stats = r871x_net_get_stats,
//.ndo_do_ioctl = r871x_mp_ioctl,
};
#endif
int hostapd_mode_init(_adapter *padapter)
{
unsigned char mac[ETH_ALEN];
struct hostapd_priv *phostapdpriv;
struct net_device *pnetdev;
pnetdev = rtw_alloc_etherdev(sizeof(struct hostapd_priv));
if (!pnetdev)
return -ENOMEM;
//SET_MODULE_OWNER(pnetdev);
ether_setup(pnetdev);
//pnetdev->type = ARPHRD_IEEE80211;
phostapdpriv = rtw_netdev_priv(pnetdev);
phostapdpriv->pmgnt_netdev = pnetdev;
phostapdpriv->padapter= padapter;
padapter->phostapdpriv = phostapdpriv;
//pnetdev->init = NULL;
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29))
DBG_871X("register rtl871x_mgnt_netdev_ops to netdev_ops\n");
pnetdev->netdev_ops = &rtl871x_mgnt_netdev_ops;
#else
pnetdev->open = mgnt_netdev_open;
pnetdev->stop = mgnt_netdev_close;
pnetdev->hard_start_xmit = mgnt_xmit_entry;
//pnetdev->set_mac_address = r871x_net_set_mac_address;
//pnetdev->get_stats = r871x_net_get_stats;
//pnetdev->do_ioctl = r871x_mp_ioctl;
#endif
pnetdev->watchdog_timeo = HZ; /* 1 second timeout */
//pnetdev->wireless_handlers = NULL;
#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
pnetdev->features |= NETIF_F_IP_CSUM;
#endif
if(dev_alloc_name(pnetdev,"mgnt.wlan%d") < 0)
{
DBG_871X("hostapd_mode_init(): dev_alloc_name, fail! \n");
}
//SET_NETDEV_DEV(pnetdev, pintfpriv->udev);
mac[0]=0x00;
mac[1]=0xe0;
mac[2]=0x4c;
mac[3]=0x87;
mac[4]=0x11;
mac[5]=0x12;
_rtw_memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
netif_carrier_off(pnetdev);
/* Tell the network stack we exist */
if (register_netdev(pnetdev) != 0)
{
DBG_871X("hostapd_mode_init(): register_netdev fail!\n");
if(pnetdev)
{
rtw_free_netdev(pnetdev);
}
}
return 0;
}
void hostapd_mode_unload(_adapter *padapter)
{
struct hostapd_priv *phostapdpriv = padapter->phostapdpriv;
struct net_device *pnetdev = phostapdpriv->pmgnt_netdev;
unregister_netdev(pnetdev);
rtw_free_netdev(pnetdev);
} }
#endif #endif
#endif

2642
os_dep/os_intfs.c Normal file → Executable file

File diff suppressed because it is too large Load diff

504
os_dep/recv_linux.c Normal file → Executable file
View file

@ -19,6 +19,7 @@
******************************************************************************/ ******************************************************************************/
#define _RECV_OSDEP_C_ #define _RECV_OSDEP_C_
#include <drv_conf.h>
#include <osdep_service.h> #include <osdep_service.h>
#include <drv_types.h> #include <drv_types.h>
@ -27,128 +28,275 @@
#include <osdep_intf.h> #include <osdep_intf.h>
#include <ethernet.h> #include <ethernet.h>
#ifdef CONFIG_USB_HCI
#include <usb_ops.h> #include <usb_ops.h>
#endif
/* init os related resource in struct recv_priv */ //init os related resource in struct recv_priv
int rtw_os_recv_resource_init(struct recv_priv *precvpriv, int rtw_os_recv_resource_init(struct recv_priv *precvpriv, _adapter *padapter)
struct adapter *padapter)
{ {
return _SUCCESS; int res=_SUCCESS;
}
/* alloc os related resource in union recv_frame */
int rtw_os_recv_resource_alloc(struct adapter *padapter,
union recv_frame *precvframe)
{
precvframe->u.hdr.pkt_newalloc = NULL;
precvframe->u.hdr.pkt = NULL;
return _SUCCESS;
}
/* free os related resource in union recv_frame */
void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
{
}
/* alloc os related resource in struct recv_buf */
int rtw_os_recvbuf_resource_alloc(struct adapter *padapter,
struct recv_buf *precvbuf)
{
int res = _SUCCESS;
precvbuf->irp_pending = false;
precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
if (precvbuf->purb == NULL)
res = _FAIL;
precvbuf->pskb = NULL;
precvbuf->reuse = false;
precvbuf->pallocated_buf = NULL;
precvbuf->pbuf = NULL;
precvbuf->pdata = NULL;
precvbuf->phead = NULL;
precvbuf->ptail = NULL;
precvbuf->pend = NULL;
precvbuf->transfer_len = 0;
precvbuf->len = 0;
return res; return res;
} }
/* free os related resource in struct recv_buf */ //alloc os related resource in union recv_frame
int rtw_os_recvbuf_resource_free(struct adapter *padapter, int rtw_os_recv_resource_alloc(_adapter *padapter, union recv_frame *precvframe)
struct recv_buf *precvbuf)
{ {
usb_free_urb(precvbuf->purb); int res=_SUCCESS;
return _SUCCESS;
precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL;
return res;
} }
void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) //free os related resource in union recv_frame
void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
{ {
sint i;
union recv_frame *precvframe;
precvframe = (union recv_frame*) precvpriv->precv_frame_buf;
for(i=0; i < NR_RECVFRAME; i++)
{
if(precvframe->u.hdr.pkt)
{
rtw_skb_free(precvframe->u.hdr.pkt);//free skb by driver
precvframe->u.hdr.pkt = NULL;
}
precvframe++;
}
}
//alloc os related resource in struct recv_buf
int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)
{
int res=_SUCCESS;
#ifdef CONFIG_USB_HCI
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
precvbuf->irp_pending = _FALSE;
precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
if(precvbuf->purb == NULL){
res = _FAIL;
}
precvbuf->pskb = NULL;
precvbuf->reuse = _FALSE;
precvbuf->pallocated_buf = precvbuf->pbuf = NULL;
precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;
precvbuf->transfer_len = 0;
precvbuf->len = 0;
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr);
precvbuf->pbuf = precvbuf->pallocated_buf;
if(precvbuf->pallocated_buf == NULL)
return _FAIL;
#endif //CONFIG_USE_USB_BUFFER_ALLOC_RX
#endif //CONFIG_USB_HCI
return res;
}
//free os related resource in struct recv_buf
int rtw_os_recvbuf_resource_free(_adapter *padapter, struct recv_buf *precvbuf)
{
int ret = _SUCCESS;
#ifdef CONFIG_USB_HCI
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
rtw_usb_buffer_free(pusbd, (size_t)precvbuf->alloc_sz, precvbuf->pallocated_buf, precvbuf->dma_transfer_addr);
precvbuf->pallocated_buf = NULL;
precvbuf->dma_transfer_addr = 0;
#endif //CONFIG_USE_USB_BUFFER_ALLOC_RX
if(precvbuf->purb)
{
//usb_kill_urb(precvbuf->purb);
usb_free_urb(precvbuf->purb);
}
#endif //CONFIG_USB_HCI
if(precvbuf->pskb)
rtw_skb_free(precvbuf->pskb);
return ret;
}
void rtw_handle_tkip_mic_err(_adapter *padapter,u8 bgroup)
{
#ifdef CONFIG_IOCTL_CFG80211
enum nl80211_key_type key_type;
#endif
union iwreq_data wrqu; union iwreq_data wrqu;
struct iw_michaelmicfailure ev; struct iw_michaelmicfailure ev;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_priv* pmlmepriv = &padapter->mlmepriv;
struct security_priv *psecuritypriv = &padapter->securitypriv; struct security_priv *psecuritypriv = &padapter->securitypriv;
u32 cur_time = 0; u32 cur_time = 0;
if (psecuritypriv->last_mic_err_time == 0) { if( psecuritypriv->last_mic_err_time == 0 )
{
psecuritypriv->last_mic_err_time = rtw_get_current_time(); psecuritypriv->last_mic_err_time = rtw_get_current_time();
} else { }
else
{
cur_time = rtw_get_current_time(); cur_time = rtw_get_current_time();
if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) { if( cur_time - psecuritypriv->last_mic_err_time < 60*HZ )
psecuritypriv->btkip_countermeasure = true; {
psecuritypriv->btkip_countermeasure = _TRUE;
psecuritypriv->last_mic_err_time = 0; psecuritypriv->last_mic_err_time = 0;
psecuritypriv->btkip_countermeasure_time = cur_time; psecuritypriv->btkip_countermeasure_time = cur_time;
} else { }
else
{
psecuritypriv->last_mic_err_time = rtw_get_current_time(); psecuritypriv->last_mic_err_time = rtw_get_current_time();
} }
} }
_rtw_memset(&ev, 0x00, sizeof(ev)); #ifdef CONFIG_IOCTL_CFG80211
if (bgroup) if ( bgroup )
ev.flags |= IW_MICFAILURE_GROUP; {
key_type |= NL80211_KEYTYPE_GROUP;
}
else else
ev.flags |= IW_MICFAILURE_PAIRWISE; {
key_type |= NL80211_KEYTYPE_PAIRWISE;
}
cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[ 0 ], key_type, -1,
NULL, GFP_ATOMIC);
#endif
_rtw_memset( &ev, 0x00, sizeof( ev ) );
if ( bgroup )
{
ev.flags |= IW_MICFAILURE_GROUP;
}
else
{
ev.flags |= IW_MICFAILURE_PAIRWISE;
}
ev.src_addr.sa_family = ARPHRD_ETHER; ev.src_addr.sa_family = ARPHRD_ETHER;
memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN); _rtw_memcpy( ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN );
_rtw_memset(&wrqu, 0x00, sizeof(wrqu));
wrqu.data.length = sizeof(ev); _rtw_memset( &wrqu, 0x00, sizeof( wrqu ) );
wireless_send_event(padapter->pnetdev, IWEVMICHAELMICFAILURE, wrqu.data.length = sizeof( ev );
&wrqu, (char *)&ev);
#ifndef CONFIG_IOCTL_CFG80211
wireless_send_event( padapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu, (char*) &ev );
#endif
} }
void rtw_hostapd_mlme_rx(struct adapter *padapter, void rtw_hostapd_mlme_rx(_adapter *padapter, union recv_frame *precv_frame)
union recv_frame *precv_frame)
{ {
#ifdef CONFIG_HOSTAPD_MLME
_pkt *skb;
struct hostapd_priv *phostapdpriv = padapter->phostapdpriv;
struct net_device *pmgnt_netdev = phostapdpriv->pmgnt_netdev;
RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("+rtw_hostapd_mlme_rx\n"));
skb = precv_frame->u.hdr.pkt;
if (skb == NULL)
return;
skb->data = precv_frame->u.hdr.rx_data;
skb->tail = precv_frame->u.hdr.rx_tail;
skb->len = precv_frame->u.hdr.len;
//pskb_copy = rtw_skb_copy(skb);
// if(skb == NULL) goto _exit;
skb->dev = pmgnt_netdev;
skb->ip_summed = CHECKSUM_NONE;
skb->pkt_type = PACKET_OTHERHOST;
//skb->protocol = __constant_htons(0x0019); /*ETH_P_80211_RAW*/
skb->protocol = __constant_htons(0x0003); /*ETH_P_80211_RAW*/
//DBG_871X("(1)data=0x%x, head=0x%x, tail=0x%x, mac_header=0x%x, len=%d\n", skb->data, skb->head, skb->tail, skb->mac_header, skb->len);
//skb->mac.raw = skb->data;
skb_reset_mac_header(skb);
//skb_pull(skb, 24);
_rtw_memset(skb->cb, 0, sizeof(skb->cb));
rtw_netif_rx(pmgnt_netdev, skb);
precv_frame->u.hdr.pkt = NULL; // set pointer to NULL before rtw_free_recvframe() if call rtw_netif_rx()
#endif
} }
int rtw_recv_indicatepkt(struct adapter *padapter, int rtw_recv_indicatepkt(_adapter *padapter, union recv_frame *precv_frame)
union recv_frame *precv_frame)
{ {
struct recv_priv *precvpriv; struct recv_priv *precvpriv;
struct __queue *pfree_recv_queue; _queue *pfree_recv_queue;
struct sk_buff *skb; _pkt *skb;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_priv*pmlmepriv = &padapter->mlmepriv;
#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
#endif
#ifdef CONFIG_BR_EXT
void *br_port = NULL;
#endif
_func_enter_;
precvpriv = &(padapter->recvpriv); precvpriv = &(padapter->recvpriv);
pfree_recv_queue = &(precvpriv->free_recv_queue); pfree_recv_queue = &(precvpriv->free_recv_queue);
#ifdef CONFIG_DRVEXT_MODULE
if (drvext_rx_handler(padapter, precv_frame->u.hdr.rx_data, precv_frame->u.hdr.len) == _SUCCESS)
{
goto _recv_indicatepkt_drop;
}
#endif
#ifdef CONFIG_WAPI_SUPPORT
if (rtw_wapi_check_for_drop(padapter,precv_frame))
{
WAPI_TRACE(WAPI_ERR, "%s(): Rx Reorder Drop case!!\n", __FUNCTION__);
goto _recv_indicatepkt_drop;
}
#endif
skb = precv_frame->u.hdr.pkt; skb = precv_frame->u.hdr.pkt;
if (skb == NULL) { if(skb == NULL)
RT_TRACE(_module_recv_osdep_c_, _drv_err_, {
("rtw_recv_indicatepkt():skb == NULL something wrong!!!!\n")); RT_TRACE(_module_recv_osdep_c_,_drv_err_,("rtw_recv_indicatepkt():skb==NULL something wrong!!!!\n"));
goto _recv_indicatepkt_drop; goto _recv_indicatepkt_drop;
} }
RT_TRACE(_module_recv_osdep_c_, _drv_info_, RT_TRACE(_module_recv_osdep_c_,_drv_info_,("rtw_recv_indicatepkt():skb != NULL !!!\n"));
("rtw_recv_indicatepkt():skb != NULL !!!\n")); RT_TRACE(_module_recv_osdep_c_,_drv_info_,("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head=%p precv_frame->hdr.rx_data=%p\n", precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data));
RT_TRACE(_module_recv_osdep_c_, _drv_info_, RT_TRACE(_module_recv_osdep_c_,_drv_info_,("precv_frame->hdr.rx_tail=%p precv_frame->u.hdr.rx_end=%p precv_frame->hdr.len=%d \n", precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end, precv_frame->u.hdr.len));
("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head =%p precv_frame->hdr.rx_data =%p\n",
precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data));
RT_TRACE(_module_recv_osdep_c_, _drv_info_,
("precv_frame->hdr.rx_tail =%p precv_frame->u.hdr.rx_end =%p precv_frame->hdr.len =%d\n",
precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end,
precv_frame->u.hdr.len));
skb->data = precv_frame->u.hdr.rx_data; skb->data = precv_frame->u.hdr.rx_data;
@ -156,103 +304,209 @@ int rtw_recv_indicatepkt(struct adapter *padapter,
skb->len = precv_frame->u.hdr.len; skb->len = precv_frame->u.hdr.len;
RT_TRACE(_module_recv_osdep_c_, _drv_info_, RT_TRACE(_module_recv_osdep_c_,_drv_info_,("\n skb->head=%p skb->data=%p skb->tail=%p skb->end=%p skb->len=%d\n", skb->head, skb->data, skb->tail, skb->end, skb->len));
("skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n",
skb->head, skb->data, skb_tail_pointer(skb),
skb_end_pointer(skb), skb->len));
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
struct sk_buff *pskb2 = NULL; {
struct sta_info *psta = NULL; _pkt *pskb2=NULL;
struct sta_priv *pstapriv = &padapter->stapriv; struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
int bmcast = IS_MCAST(pattrib->dst); int bmcast = IS_MCAST(pattrib->dst);
if (!_rtw_memcmp(pattrib->dst, myid(&padapter->eeprompriv), //DBG_871X("bmcast=%d\n", bmcast);
ETH_ALEN)) {
if (bmcast) { if(_rtw_memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)==_FALSE)
{
//DBG_871X("not ap psta=%p, addr=%pM\n", psta, pattrib->dst);
if(bmcast)
{
psta = rtw_get_bcmc_stainfo(padapter); psta = rtw_get_bcmc_stainfo(padapter);
pskb2 = skb_clone(skb, GFP_ATOMIC); pskb2 = rtw_skb_clone(skb);
} else { } else {
psta = rtw_get_stainfo(pstapriv, pattrib->dst); psta = rtw_get_stainfo(pstapriv, pattrib->dst);
} }
if (psta) { if(psta)
struct net_device *pnetdev; {
struct net_device *pnetdev= (struct net_device*)padapter->pnetdev;
pnetdev = (struct net_device *)padapter->pnetdev; //DBG_871X("directly forwarding to the rtw_xmit_entry\n");
skb->dev = pnetdev;
//skb->ip_summed = CHECKSUM_NONE;
skb->dev = pnetdev;
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
skb_set_queue_mapping(skb, rtw_recv_select_queue(skb)); skb_set_queue_mapping(skb, rtw_recv_select_queue(skb));
#endif //LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)
_rtw_xmit_entry(skb, pnetdev);
rtw_xmit_entry(skb, pnetdev); if(bmcast)
if (bmcast)
skb = pskb2; skb = pskb2;
else else
goto _recv_indicatepkt_end; goto _recv_indicatepkt_end;
} }
}
else// to APself
{
//DBG_871X("to APSelf\n");
} }
} }
#ifdef CONFIG_BR_EXT
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
br_port = padapter->pnetdev->br_port;
#else // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
rcu_read_lock(); rcu_read_lock();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) br_port = rcu_dereference(padapter->pnetdev->rx_handler_data);
rcu_dereference(padapter->pnetdev->rx_handler_data);
#else
rcu_dereference(padapter->pnetdev->br_port);
#endif
rcu_read_unlock(); rcu_read_unlock();
#endif // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
if( br_port && (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) )
{
int nat25_handle_frame(_adapter *priv, struct sk_buff *skb);
if (nat25_handle_frame(padapter, skb) == -1) {
//priv->ext_stats.rx_data_drops++;
//DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n");
//return FAIL;
#if 1
// bypass this frame to upper layer!!
#else
goto _recv_indicatepkt_drop;
#endif
}
}
#endif // CONFIG_BR_EXT
#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX
if ( (pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1) ) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
//DBG_871X("CHECKSUM_UNNECESSARY \n");
} else {
skb->ip_summed = CHECKSUM_NONE;
//DBG_871X("CHECKSUM_NONE(%d, %d) \n", pattrib->tcpchk_valid, pattrib->tcp_chkrpt);
}
#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
#endif
skb->dev = padapter->pnetdev; skb->dev = padapter->pnetdev;
skb->protocol = eth_type_trans(skb, padapter->pnetdev); skb->protocol = eth_type_trans(skb, padapter->pnetdev);
netif_rx(skb); #ifdef DBG_TRX_STA_PKTS
{
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
int bmcast = IS_MCAST(pattrib->dst);
if(bmcast)
{
psta = rtw_get_bcmc_stainfo(padapter);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->src);
}
if(psta)
{
switch(pattrib->priority)
{
case 1:
case 2:
psta->rx_bk_cnt++;
break;
case 4:
case 5:
psta->rx_vi_cnt++;
break;
case 6:
case 7:
psta->rx_vo_cnt++;
break;
case 0:
case 3:
default:
psta->rx_be_cnt++;
break;
}
}
}
#endif
rtw_netif_rx(padapter->pnetdev, skb);
_recv_indicatepkt_end: _recv_indicatepkt_end:
/* pointers to NULL before rtw_free_recvframe() */ precv_frame->u.hdr.pkt = NULL; // pointers to NULL before rtw_free_recvframe()
precv_frame->u.hdr.pkt = NULL;
rtw_free_recvframe(precv_frame, pfree_recv_queue); rtw_free_recvframe(precv_frame, pfree_recv_queue);
RT_TRACE(_module_recv_osdep_c_, _drv_info_, RT_TRACE(_module_recv_osdep_c_,_drv_info_,("\n rtw_recv_indicatepkt :after rtw_netif_rx!!!!\n"));
("\n rtw_recv_indicatepkt :after netif_rx!!!!\n"));
return _SUCCESS; _func_exit_;
return _SUCCESS;
_recv_indicatepkt_drop: _recv_indicatepkt_drop:
/* enqueue back to free_recv_queue */ //enqueue back to free_recv_queue
rtw_free_recvframe(precv_frame, pfree_recv_queue); if(precv_frame)
rtw_free_recvframe(precv_frame, pfree_recv_queue);
return _FAIL; return _FAIL;
_func_exit_;
} }
void rtw_os_read_port(struct adapter *padapter, struct recv_buf *precvbuf) void rtw_os_read_port(_adapter *padapter, struct recv_buf *precvbuf)
{ {
struct recv_priv *precvpriv = &padapter->recvpriv; struct recv_priv *precvpriv = &padapter->recvpriv;
#ifdef CONFIG_USB_HCI
precvbuf->ref_cnt--; precvbuf->ref_cnt--;
/* free skb in recv_buf */
dev_kfree_skb_any(precvbuf->pskb); //free skb in recv_buf
rtw_skb_free(precvbuf->pskb);
precvbuf->pskb = NULL; precvbuf->pskb = NULL;
precvbuf->reuse = false; precvbuf->reuse = _FALSE;
if (!precvbuf->irp_pending)
rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, if(precvbuf->irp_pending == _FALSE)
(unsigned char *)precvbuf); {
rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
}
#endif
#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
precvbuf->pskb = NULL;
#endif
} }
void _rtw_reordering_ctrl_timeout_handler (void *FunctionContext);
static void _rtw_reordering_ctrl_timeout_handler(void *func_context) void _rtw_reordering_ctrl_timeout_handler (void *FunctionContext)
{ {
struct recv_reorder_ctrl *preorder_ctrl; struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)FunctionContext;
preorder_ctrl = (struct recv_reorder_ctrl *)func_context;
rtw_reordering_ctrl_timeout_handler(preorder_ctrl); rtw_reordering_ctrl_timeout_handler(preorder_ctrl);
} }
void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl) void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
{ {
struct adapter *padapter = preorder_ctrl->padapter; _adapter *padapter = preorder_ctrl->padapter;
_init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter->pnetdev, _rtw_reordering_ctrl_timeout_handler, preorder_ctrl); _init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter->pnetdev, _rtw_reordering_ctrl_timeout_handler, preorder_ctrl);
} }

705
os_dep/rtw_android.c Normal file → Executable file
View file

@ -1,7 +1,7 @@
/****************************************************************************** /******************************************************************************
* *
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation. * published by the Free Software Foundation.
@ -27,6 +27,26 @@
#include <ioctl_cfg80211.h> #include <ioctl_cfg80211.h>
#include <rtw_ioctl_set.h> #include <rtw_ioctl_set.h>
#ifdef CONFIG_GPIO_WAKEUP
#include <linux/gpio.h>
#endif
#include <drv_types.h>
#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
#include <linux/platform_device.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
#include <linux/wlan_plat.h>
#else
#include <linux/wifi_tiwlan.h>
#endif
#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */
#ifdef CONFIG_GPIO_WAKEUP
#include <linux/interrupt.h>
#include <linux/irq.h>
#endif
static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = { static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
"START", "START",
"STOP", "STOP",
@ -51,20 +71,46 @@ static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
"P2P_GET_NOA", "P2P_GET_NOA",
"P2P_SET_PS", "P2P_SET_PS",
"SET_AP_WPS_P2P_IE", "SET_AP_WPS_P2P_IE",
#ifdef PNO_SUPPORT
"PNOSSIDCLR",
"PNOSETUP ",
"PNOFORCE",
"PNODEBUG",
#endif
"MACADDR", "MACADDR",
"BLOCK", "BLOCK",
"WFD-ENABLE", "WFD-ENABLE",
"WFD-DISABLE", "WFD-DISABLE",
"WFD-SET-TCPPORT", "WFD-SET-TCPPORT",
"WFD-SET-MAXTPUT", "WFD-SET-MAXTPUT",
"WFD-SET-DEVTYPE", "WFD-SET-DEVTYPE",
}; };
struct android_wifi_priv_cmd { #ifdef PNO_SUPPORT
const char __user *buf; #define PNO_TLV_PREFIX 'S'
#define PNO_TLV_VERSION '1'
#define PNO_TLV_SUBVERSION '2'
#define PNO_TLV_RESERVED '0'
#define PNO_TLV_TYPE_SSID_IE 'S'
#define PNO_TLV_TYPE_TIME 'T'
#define PNO_TLV_FREQ_REPEAT 'R'
#define PNO_TLV_FREQ_EXPO_MAX 'M'
typedef struct cmd_tlv {
char prefix;
char version;
char subver;
char reserved;
} cmd_tlv_t;
#endif /* PNO_SUPPORT */
typedef struct android_wifi_priv_cmd {
char *buf;
int used_len; int used_len;
int total_len; int total_len;
}; } android_wifi_priv_cmd;
/** /**
* Local (static) functions and variables * Local (static) functions and variables
@ -74,163 +120,326 @@ struct android_wifi_priv_cmd {
* time (only) in dhd_open, subsequential wifi on will be handled by * time (only) in dhd_open, subsequential wifi on will be handled by
* wl_android_wifi_on * wl_android_wifi_on
*/ */
static int g_wifi_on = true; static int g_wifi_on = _TRUE;
static unsigned int oob_irq;
#ifdef PNO_SUPPORT
static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
{
wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
int res = -1;
int nssid = 0;
cmd_tlv_t *cmd_tlv_temp;
char *str_ptr;
int tlv_size_left;
int pno_time = 0;
int pno_repeat = 0;
int pno_freq_expo_max = 0;
#ifdef PNO_SET_DEBUG
int i;
char pno_in_example[] = {
'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
'S', '1', '2', '0',
'S',
0x05,
'd', 'l', 'i', 'n', 'k',
'S',
0x04,
'G', 'O', 'O', 'G',
'T',
'0', 'B',
'R',
'2',
'M',
'2',
0x00
};
#endif /* PNO_SET_DEBUG */
DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
DBG_871X("%s argument=%d less min size\n", __FUNCTION__, total_len);
goto exit_proc;
}
#ifdef PNO_SET_DEBUG
memcpy(command, pno_in_example, sizeof(pno_in_example));
for (i = 0; i < sizeof(pno_in_example); i++)
printf("%02X ", command[i]);
printf("\n");
total_len = sizeof(pno_in_example);
#endif
str_ptr = command + strlen(CMD_PNOSETUP_SET);
tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
memset(ssids_local, 0, sizeof(ssids_local));
if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
(cmd_tlv_temp->version == PNO_TLV_VERSION) &&
(cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
str_ptr += sizeof(cmd_tlv_t);
tlv_size_left -= sizeof(cmd_tlv_t);
if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
DBG_871X("SSID is not presented or corrupted ret=%d\n", nssid);
goto exit_proc;
} else {
if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
DBG_871X("%s scan duration corrupted field size %d\n",
__FUNCTION__, tlv_size_left);
goto exit_proc;
}
str_ptr++;
pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
if (str_ptr[0] != 0) {
if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
DBG_871X("%s pno repeat : corrupted field\n",
__FUNCTION__);
goto exit_proc;
}
str_ptr++;
pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
DBG_871X("%s FREQ_EXPO_MAX corrupted field size\n",
__FUNCTION__);
goto exit_proc;
}
str_ptr++;
pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
DHD_INFO(("%s: pno_freq_expo_max=%d\n",
__FUNCTION__, pno_freq_expo_max));
}
}
} else {
DBG_871X("%s get wrong TLV command\n", __FUNCTION__);
goto exit_proc;
}
res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
exit_proc:
return res;
}
#endif /* PNO_SUPPORT */
int rtw_android_cmdstr_to_num(char *cmdstr) int rtw_android_cmdstr_to_num(char *cmdstr)
{ {
int cmd_num; int cmd_num;
for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++) for(cmd_num=0 ; cmd_num<ANDROID_WIFI_CMD_MAX; cmd_num++)
if (0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num], if(0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])) )
strlen(android_wifi_cmd_str[cmd_num])))
break; break;
return cmd_num; return cmd_num;
} }
static int rtw_android_get_rssi(struct net_device *net, char *command, static int rtw_android_get_rssi(struct net_device *net, char *command, int total_len)
int total_len)
{ {
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(net); _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct wlan_network *pcur_network = &pmlmepriv->cur_network; struct wlan_network *pcur_network = &pmlmepriv->cur_network;
int bytes_written = 0; int bytes_written = 0;
if (check_fwstate(pmlmepriv, _FW_LINKED)) { if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
bytes_written += snprintf(&command[bytes_written], total_len, bytes_written += snprintf(&command[bytes_written], total_len, "%s rssi %d",
"%s rssi %d", pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi);
pcur_network->network.Ssid.Ssid,
padapter->recvpriv.rssi);
} }
return bytes_written; return bytes_written;
} }
static int rtw_android_get_link_speed(struct net_device *net, char *command, static int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len)
int total_len)
{ {
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(net); _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
int bytes_written; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
u16 link_speed; struct wlan_network *pcur_network = &pmlmepriv->cur_network;
int bytes_written = 0;
u16 link_speed = 0;
link_speed = rtw_get_cur_max_rate(padapter)/10;
bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
link_speed = rtw_get_cur_max_rate(padapter) / 10;
bytes_written = snprintf(command, total_len, "LinkSpeed %d",
link_speed);
return bytes_written; return bytes_written;
} }
static int rtw_android_get_macaddr(struct net_device *net, char *command, static int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len)
int total_len)
{ {
int bytes_written; _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
int bytes_written = 0;
bytes_written = snprintf(command, total_len, "Macaddr = %pM",
net->dev_addr); bytes_written = snprintf(command, total_len, "Macaddr = "MAC_FMT, MAC_ARG(net->dev_addr));
return bytes_written; return bytes_written;
} }
static int android_set_cntry(struct net_device *net, char *command, static int rtw_android_set_country(struct net_device *net, char *command, int total_len)
int total_len)
{ {
struct adapter *adapter = (struct adapter *)rtw_netdev_priv(net); _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1; char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1;
int ret; int ret = _FAIL;
ret = rtw_set_country(adapter, country_code); ret = rtw_set_country(adapter, country_code);
return (ret == _SUCCESS) ? 0 : -1;
return (ret==_SUCCESS)?0:-1;
} }
static int android_get_p2p_addr(struct net_device *net, char *command, static int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len)
int total_len)
{ {
/* We use the same address as our HW MAC address */ int bytes_written = 0;
memcpy(command, net->dev_addr, ETH_ALEN);
return ETH_ALEN; //We use the same address as our HW MAC address
_rtw_memcpy(command, net->dev_addr, ETH_ALEN);
bytes_written = ETH_ALEN;
return bytes_written;
} }
static int rtw_android_set_block(struct net_device *net, char *command, static int rtw_android_set_block(struct net_device *net, char *command, int total_len)
int total_len)
{ {
_adapter *adapter = (_adapter *)rtw_netdev_priv(net);
char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK]) + 1;
#ifdef CONFIG_IOCTL_CFG80211
wdev_to_priv(adapter->rtw_wdev)->block = (*block_value=='0')?_FALSE:_TRUE;
#endif
return 0; return 0;
} }
static int get_int_from_command(char *pcmd)
{
int i = 0;
for( i = 0; i < strlen( pcmd ); i++ )
{
if ( pcmd[ i ] == '=' )
{
// Skip the '=' and space characters.
i += 2;
break;
}
}
return ( rtw_atoi( pcmd + i ) );
}
int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
{ {
int ret = 0; int ret = 0;
char *command = NULL; char *command = NULL;
int cmd_num; int cmd_num;
int bytes_written = 0; int bytes_written = 0;
struct android_wifi_priv_cmd priv_cmd; android_wifi_priv_cmd priv_cmd;
_adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
#ifdef CONFIG_WFD
struct wifi_display_info *pwfd_info;
#endif
rtw_lock_suspend(); rtw_lock_suspend();
if (!ifr->ifr_data) { if (!ifr->ifr_data) {
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
if (copy_from_user(&priv_cmd, ifr->ifr_data, if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
sizeof(struct android_wifi_priv_cmd))) {
ret = -EFAULT; ret = -EFAULT;
goto exit; goto exit;
} }
command = kmalloc(priv_cmd.total_len, GFP_KERNEL);
if (!command) { //DBG_871X("%s priv_cmd.buf=%p priv_cmd.total_len=%d priv_cmd.used_len=%d\n",__func__,priv_cmd.buf,priv_cmd.total_len,priv_cmd.used_len);
DBG_88E("%s: failed to allocate memory\n", __func__); command = rtw_zmalloc(priv_cmd.total_len);
if (!command)
{
DBG_871X("%s: failed to allocate memory\n", __FUNCTION__);
ret = -ENOMEM; ret = -ENOMEM;
goto exit; goto exit;
} }
if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)) {
DBG_88E("%s: failed to access memory\n", __func__); if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)){
DBG_871X("%s: failed to access memory\n", __FUNCTION__);
ret = -EFAULT;
goto exit;
}
if (copy_from_user(command, (void *)priv_cmd.buf, priv_cmd.total_len)) {
ret = -EFAULT; ret = -EFAULT;
goto exit; goto exit;
} }
if (copy_from_user(command, (char __user *)priv_cmd.buf,
priv_cmd.total_len)) { DBG_871X("%s: Android private cmd \"%s\" on %s\n"
ret = -EFAULT; , __FUNCTION__, command, ifr->ifr_name);
goto exit;
}
DBG_88E("%s: Android private cmd \"%s\" on %s\n",
__func__, command, ifr->ifr_name);
cmd_num = rtw_android_cmdstr_to_num(command); cmd_num = rtw_android_cmdstr_to_num(command);
switch (cmd_num) {
switch(cmd_num) {
case ANDROID_WIFI_CMD_START: case ANDROID_WIFI_CMD_START:
//bytes_written = wl_android_wifi_on(net);
goto response; goto response;
case ANDROID_WIFI_CMD_SETFWPATH: case ANDROID_WIFI_CMD_SETFWPATH:
goto response; goto response;
} }
if (!g_wifi_on) { if (!g_wifi_on) {
DBG_88E("%s: Ignore private cmd \"%s\" - iface %s is down\n", DBG_871X("%s: Ignore private cmd \"%s\" - iface %s is down\n"
__func__, command, ifr->ifr_name); ,__FUNCTION__, command, ifr->ifr_name);
ret = 0; ret = 0;
goto exit; goto exit;
} }
switch (cmd_num) {
switch(cmd_num) {
case ANDROID_WIFI_CMD_STOP: case ANDROID_WIFI_CMD_STOP:
//bytes_written = wl_android_wifi_off(net);
break; break;
case ANDROID_WIFI_CMD_SCAN_ACTIVE: case ANDROID_WIFI_CMD_SCAN_ACTIVE:
//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE);
#ifdef CONFIG_PLATFORM_MSTAR
#ifdef CONFIG_IOCTL_CFG80211
(wdev_to_priv(net->ieee80211_ptr))->bandroid_scan = _TRUE;
#endif //CONFIG_IOCTL_CFG80211
#endif //CONFIG_PLATFORM_MSTAR
break; break;
case ANDROID_WIFI_CMD_SCAN_PASSIVE: case ANDROID_WIFI_CMD_SCAN_PASSIVE:
//rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE);
break; break;
case ANDROID_WIFI_CMD_RSSI: case ANDROID_WIFI_CMD_RSSI:
bytes_written = rtw_android_get_rssi(net, command, bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
priv_cmd.total_len);
break; break;
case ANDROID_WIFI_CMD_LINKSPEED: case ANDROID_WIFI_CMD_LINKSPEED:
bytes_written = rtw_android_get_link_speed(net, command, bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
priv_cmd.total_len);
break; break;
case ANDROID_WIFI_CMD_MACADDR: case ANDROID_WIFI_CMD_MACADDR:
bytes_written = rtw_android_get_macaddr(net, command, bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
priv_cmd.total_len);
break; break;
case ANDROID_WIFI_CMD_BLOCK: case ANDROID_WIFI_CMD_BLOCK:
bytes_written = rtw_android_set_block(net, command, bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
priv_cmd.total_len);
break; break;
case ANDROID_WIFI_CMD_RXFILTER_START: case ANDROID_WIFI_CMD_RXFILTER_START:
//bytes_written = net_os_set_packet_filter(net, 1);
break; break;
case ANDROID_WIFI_CMD_RXFILTER_STOP: case ANDROID_WIFI_CMD_RXFILTER_STOP:
//bytes_written = net_os_set_packet_filter(net, 0);
break; break;
case ANDROID_WIFI_CMD_RXFILTER_ADD: case ANDROID_WIFI_CMD_RXFILTER_ADD:
//int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
//bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
break; break;
case ANDROID_WIFI_CMD_RXFILTER_REMOVE: case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
//int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
//bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
break; break;
case ANDROID_WIFI_CMD_BTCOEXSCAN_START: case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
/* TBD: BTCOEXSCAN-START */ /* TBD: BTCOEXSCAN-START */
break; break;
@ -238,29 +447,126 @@ int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
/* TBD: BTCOEXSCAN-STOP */ /* TBD: BTCOEXSCAN-STOP */
break; break;
case ANDROID_WIFI_CMD_BTCOEXMODE: case ANDROID_WIFI_CMD_BTCOEXMODE:
#if 0
uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
if (mode == 1)
net_os_set_packet_filter(net, 0); /* DHCP starts */
else
net_os_set_packet_filter(net, 1); /* DHCP ends */
#ifdef WL_CFG80211
bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
#endif
#endif
break; break;
case ANDROID_WIFI_CMD_SETSUSPENDOPT: case ANDROID_WIFI_CMD_SETSUSPENDOPT:
//bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
break; break;
case ANDROID_WIFI_CMD_SETBAND: case ANDROID_WIFI_CMD_SETBAND:
{
uint band = *(command + strlen("SETBAND") + 1) - '0';
_adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
if (padapter->chip_type == RTL8192D)
padapter->setband = band;
break; break;
}
case ANDROID_WIFI_CMD_GETBAND: case ANDROID_WIFI_CMD_GETBAND:
//bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
break; break;
case ANDROID_WIFI_CMD_COUNTRY: case ANDROID_WIFI_CMD_COUNTRY:
bytes_written = android_set_cntry(net, command, bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
priv_cmd.total_len);
break; break;
#ifdef PNO_SUPPORT
case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
//bytes_written = dhd_dev_pno_reset(net);
break;
case ANDROID_WIFI_CMD_PNOSETUP_SET:
//bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
break;
case ANDROID_WIFI_CMD_PNOENABLE_SET:
//uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
//bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
break;
#endif
case ANDROID_WIFI_CMD_P2P_DEV_ADDR: case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
bytes_written = android_get_p2p_addr(net, command, bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
priv_cmd.total_len);
break; break;
case ANDROID_WIFI_CMD_P2P_SET_NOA: case ANDROID_WIFI_CMD_P2P_SET_NOA:
//int skip = strlen(CMD_P2P_SET_NOA) + 1;
//bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip);
break; break;
case ANDROID_WIFI_CMD_P2P_GET_NOA: case ANDROID_WIFI_CMD_P2P_GET_NOA:
//bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
break; break;
case ANDROID_WIFI_CMD_P2P_SET_PS: case ANDROID_WIFI_CMD_P2P_SET_PS:
//int skip = strlen(CMD_P2P_SET_PS) + 1;
//bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip);
break; break;
#ifdef CONFIG_IOCTL_CFG80211
case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE:
{
int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
break;
}
#endif //CONFIG_IOCTL_CFG80211
#ifdef CONFIG_WFD
case ANDROID_WIFI_CMD_WFD_ENABLE:
// Commented by Albert 2012/07/24
// We can enable the WFD function by using the following command:
// wpa_cli driver wfd-enable
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
pwfd_info->wfd_enable = _TRUE;
break;
case ANDROID_WIFI_CMD_WFD_DISABLE:
// Commented by Albert 2012/07/24
// We can disable the WFD function by using the following command:
// wpa_cli driver wfd-disable
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
pwfd_info->wfd_enable = _FALSE;
break;
case ANDROID_WIFI_CMD_WFD_SET_TCPPORT:
// Commented by Albert 2012/07/24
// We can set the tcp port number by using the following command:
// wpa_cli driver wfd-set-tcpport = 554
pwfd_info = &padapter->wfd_info;
if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
pwfd_info->rtsp_ctrlport = (u16)get_int_from_command(priv_cmd.buf);
break;
case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT:
break;
case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE:
{
// Commented by Albert 2012/08/28
// Specify the WFD device type ( WFD source/primary sink )
struct wifi_display_info *pwfd_info;
_adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
pwfd_info = &padapter->wfd_info;
if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) {
pwfd_info->wfd_device_type = (u8)get_int_from_command(priv_cmd.buf);
pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL;
}
break;
}
#endif
default: default:
DBG_88E("Unknown PRIVATE command %s - ignored\n", command); DBG_871X("Unknown PRIVATE command %s - ignored\n", command);
snprintf(command, 3, "OK"); snprintf(command, 3, "OK");
bytes_written = strlen("OK"); bytes_written = strlen("OK");
} }
@ -270,24 +576,253 @@ response:
if ((bytes_written == 0) && (priv_cmd.total_len > 0)) if ((bytes_written == 0) && (priv_cmd.total_len > 0))
command[0] = '\0'; command[0] = '\0';
if (bytes_written >= priv_cmd.total_len) { if (bytes_written >= priv_cmd.total_len) {
DBG_88E("%s: bytes_written = %d\n", __func__, DBG_871X("%s: bytes_written = %d\n", __FUNCTION__, bytes_written);
bytes_written);
bytes_written = priv_cmd.total_len; bytes_written = priv_cmd.total_len;
} else { } else {
bytes_written++; bytes_written++;
} }
priv_cmd.used_len = bytes_written; priv_cmd.used_len = bytes_written;
if (copy_to_user((char __user *)priv_cmd.buf, command, if (copy_to_user((void *)priv_cmd.buf, command, bytes_written)) {
bytes_written)) { DBG_871X("%s: failed to copy data to user buffer\n", __FUNCTION__);
DBG_88E("%s: failed to copy data to user buffer\n",
__func__);
ret = -EFAULT; ret = -EFAULT;
} }
} else { }
else {
ret = bytes_written; ret = bytes_written;
} }
exit: exit:
rtw_unlock_suspend(); rtw_unlock_suspend();
kfree(command); if (command) {
rtw_mfree(command, priv_cmd.total_len);
}
return ret; return ret;
} }
/**
* Functions for Android WiFi card detection
*/
#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
static int g_wifidev_registered = 0;
static struct semaphore wifi_control_sem;
static struct wifi_platform_data *wifi_control_data = NULL;
static struct resource *wifi_irqres = NULL;
static int wifi_add_dev(void);
static void wifi_del_dev(void);
int rtw_android_wifictrl_func_add(void)
{
int ret = 0;
sema_init(&wifi_control_sem, 0);
ret = wifi_add_dev();
if (ret) {
DBG_871X("%s: platform_driver_register failed\n", __FUNCTION__);
return ret;
}
g_wifidev_registered = 1;
/* Waiting callback after platform_driver_register is done or exit with error */
if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) {
ret = -EINVAL;
DBG_871X("%s: platform_driver_register timeout\n", __FUNCTION__);
}
return ret;
}
void rtw_android_wifictrl_func_del(void)
{
if (g_wifidev_registered)
{
wifi_del_dev();
g_wifidev_registered = 0;
}
}
void *wl_android_prealloc(int section, unsigned long size)
{
void *alloc_ptr = NULL;
if (wifi_control_data && wifi_control_data->mem_prealloc) {
alloc_ptr = wifi_control_data->mem_prealloc(section, size);
if (alloc_ptr) {
DBG_871X("success alloc section %d\n", section);
if (size != 0L)
memset(alloc_ptr, 0, size);
return alloc_ptr;
}
}
DBG_871X("can't alloc section %d\n", section);
return NULL;
}
int wifi_get_irq_number(unsigned long *irq_flags_ptr)
{
if (wifi_irqres) {
*irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
return (int)wifi_irqres->start;
}
#ifdef CUSTOM_OOB_GPIO_NUM
return CUSTOM_OOB_GPIO_NUM;
#else
return -1;
#endif
}
int wifi_set_power(int on, unsigned long msec)
{
DBG_871X("%s = %d\n", __FUNCTION__, on);
if (wifi_control_data && wifi_control_data->set_power) {
wifi_control_data->set_power(on);
}
if (msec)
msleep(msec);
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
int wifi_get_mac_addr(unsigned char *buf)
{
DBG_871X("%s\n", __FUNCTION__);
if (!buf)
return -EINVAL;
if (wifi_control_data && wifi_control_data->get_mac_addr) {
return wifi_control_data->get_mac_addr(buf);
}
return -EOPNOTSUPP;
}
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) || defined(COMPAT_KERNEL_RELEASE)
void *wifi_get_country_code(char *ccode)
{
DBG_871X("%s\n", __FUNCTION__);
if (!ccode)
return NULL;
if (wifi_control_data && wifi_control_data->get_country_code) {
return wifi_control_data->get_country_code(ccode);
}
return NULL;
}
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
static int wifi_set_carddetect(int on)
{
DBG_871X("%s = %d\n", __FUNCTION__, on);
if (wifi_control_data && wifi_control_data->set_carddetect) {
wifi_control_data->set_carddetect(on);
}
return 0;
}
static int wifi_probe(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
(struct wifi_platform_data *)(pdev->dev.platform_data);
int wifi_wake_gpio = 0;
DBG_871X("## %s\n", __FUNCTION__);
wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
if (wifi_irqres == NULL)
wifi_irqres = platform_get_resource_byname(pdev,
IORESOURCE_IRQ, "bcm4329_wlan_irq");
else
wifi_wake_gpio = wifi_irqres->start;
#ifdef CONFIG_GPIO_WAKEUP
printk("%s: gpio:%d wifi_wake_gpio:%d\n", __func__,
wifi_irqres->start, wifi_wake_gpio);
if (wifi_wake_gpio > 0) {
gpio_request(wifi_wake_gpio, "oob_irq");
gpio_direction_input(wifi_wake_gpio);
oob_irq = gpio_to_irq(wifi_wake_gpio);
printk("%s oob_irq:%d\n", __func__, oob_irq);
}
#endif
wifi_control_data = wifi_ctrl;
wifi_set_power(1, 0); /* Power On */
wifi_set_carddetect(1); /* CardDetect (0->1) */
up(&wifi_control_sem);
return 0;
}
static int wifi_remove(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
(struct wifi_platform_data *)(pdev->dev.platform_data);
DBG_871X("## %s\n", __FUNCTION__);
wifi_control_data = wifi_ctrl;
wifi_set_power(0, 0); /* Power Off */
wifi_set_carddetect(0); /* CardDetect (1->0) */
up(&wifi_control_sem);
return 0;
}
static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
{
DBG_871X("##> %s\n", __FUNCTION__);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
bcmsdh_oob_intr_set(0);
#endif
return 0;
}
static int wifi_resume(struct platform_device *pdev)
{
DBG_871X("##> %s\n", __FUNCTION__);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
bcmsdh_oob_intr_set(1);
#endif
return 0;
}
/* temporarily use these two */
static struct platform_driver wifi_device = {
.probe = wifi_probe,
.remove = wifi_remove,
.suspend = wifi_suspend,
.resume = wifi_resume,
.driver = {
.name = "bcmdhd_wlan",
}
};
static struct platform_driver wifi_device_legacy = {
.probe = wifi_probe,
.remove = wifi_remove,
.suspend = wifi_suspend,
.resume = wifi_resume,
.driver = {
.name = "bcm4329_wlan",
}
};
static int wifi_add_dev(void)
{
DBG_871X("## Calling platform_driver_register\n");
platform_driver_register(&wifi_device);
platform_driver_register(&wifi_device_legacy);
return 0;
}
static void wifi_del_dev(void)
{
DBG_871X("## Unregister platform_driver_register\n");
platform_driver_unregister(&wifi_device);
platform_driver_unregister(&wifi_device_legacy);
}
#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */

1786
os_dep/usb_intf.c Normal file → Executable file

File diff suppressed because it is too large Load diff

981
os_dep/usb_ops_linux.c Normal file → Executable file
View file

@ -1,283 +1,698 @@
/****************************************************************************** /******************************************************************************
* *
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details. * more details.
* *
* You should have received a copy of the GNU General Public License along with * 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., * this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
* *
******************************************************************************/ *******************************************************************************/
#define _USB_OPS_LINUX_C_ #define _USB_OPS_LINUX_C_
#include <drv_types.h> #include <drv_types.h>
#include <usb_ops_linux.h> #include <usb_ops_linux.h>
#include <rtw_sreset.h> #include <rtw_sreset.h>
unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) #ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ
{ static void _usbctrl_vendorreq_async_callback(struct urb *urb, struct pt_regs *regs)
unsigned int pipe = 0, ep_num = 0; {
struct usb_device *pusbd = pdvobj->pusbdev; if (urb) {
if (urb->context) {
if (addr == RECV_BULK_IN_ADDR) { rtw_mfree(urb->context);
pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]); }
} else if (addr == RECV_INT_IN_ADDR) { usb_free_urb(urb);
pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]); }
} else if (addr < HW_QUEUE_ENTRY) { }
ep_num = pdvobj->Queue2Pipe[addr];
pipe = usb_sndbulkpipe(pusbd, ep_num); static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
} u16 value, u16 index, void *pdata, u16 len, u8 requesttype)
{
return pipe; int rc;
} unsigned int pipe;
u8 reqtype;
struct zero_bulkout_context { struct usb_ctrlrequest *dr;
void *pbuf; struct urb *urb;
void *purb; struct rtl819x_async_write_data {
void *pirp; u8 data[VENDOR_CMD_MAX_DATA_LEN];
void *padapter; struct usb_ctrlrequest dr;
}; } *buf;
void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
{ if (requesttype == VENDOR_READ) {
} pipe = usb_rcvctrlpipe(udev, 0);//read_in
reqtype = REALTEK_USB_VENQT_READ;
void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) }
{ else {
} pipe = usb_sndctrlpipe(udev, 0);//write_out
reqtype = REALTEK_USB_VENQT_WRITE;
void usb_read_port_cancel(struct intf_hdl *pintfhdl) }
{
int i; buf = (struct rtl819x_async_write_data *)rtw_zmalloc(sizeof(*buf));
struct recv_buf *precvbuf; if (!buf) {
struct adapter *padapter = pintfhdl->padapter; rc = -ENOMEM;
precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; goto exit;
}
DBG_88E("%s\n", __func__);
urb = usb_alloc_urb(0, GFP_ATOMIC);
padapter->bReadPortCancel = true; if (!urb) {
rtw_mfree((u8*)buf, sizeof(*buf));
for (i = 0; i < NR_RECVBUFF; i++) { rc = -ENOMEM;
precvbuf->reuse = true; goto exit;
if (precvbuf->purb) }
usb_kill_urb(precvbuf->purb);
precvbuf++; dr = &buf->dr;
}
} dr->bRequestType = reqtype;
dr->bRequest = request;
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) dr->wValue = cpu_to_le16(value);
{ dr->wIndex = cpu_to_le16(index);
struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; dr->wLength = cpu_to_le16(len);
struct adapter *padapter = pxmitbuf->padapter;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv; _rtw_memcpy(buf, pdata, len);
struct hal_data_8188e *haldata;
usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, buf, len,
switch (pxmitbuf->flags) { _usbctrl_vendorreq_async_callback, buf);
case VO_QUEUE_INX:
pxmitpriv->voq_cnt--; rc = usb_submit_urb(urb, GFP_ATOMIC);
break; if (rc < 0) {
case VI_QUEUE_INX: rtw_mfree((u8*)buf, sizeof(*buf));
pxmitpriv->viq_cnt--; usb_free_urb(urb);
break; }
case BE_QUEUE_INX:
pxmitpriv->beq_cnt--; exit:
break; return rc;
case BK_QUEUE_INX: }
pxmitpriv->bkq_cnt--;
break; int usb_write_async(struct usb_device *udev, u32 addr, void *pdata, u16 len)
case HIGH_QUEUE_INX: {
#ifdef CONFIG_88EU_AP_MODE u8 request;
rtw_chk_hi_queue_cmd(padapter); u8 requesttype;
#endif u16 wvalue;
break; u16 index;
default:
break; int ret;
}
requesttype = VENDOR_WRITE;//write_out
if (padapter->bSurpriseRemoved || padapter->bDriverStopped || request = REALTEK_USB_VENQT_CMD_REQ;
padapter->bWritePortCancel) { index = REALTEK_USB_VENQT_CMD_IDX;//n/a
RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", wvalue = (u16)(addr&0x0000ffff);
padapter->bDriverStopped, padapter->bSurpriseRemoved));
DBG_88E("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n", ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, index, pdata, len, requesttype);
__func__, padapter->bDriverStopped,
padapter->bSurpriseRemoved, padapter->bReadPortCancel, return ret;
pxmitbuf->ext_tag); }
goto check_completion; int usb_async_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
} {
u8 data;
if (purb->status) { int ret;
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete : purb->status(%d) != 0\n", purb->status)); struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
DBG_88E("###=> urb_write_port_complete status(%d)\n", purb->status); struct usb_device *udev=pdvobjpriv->pusbdev;
if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) {
sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); _func_enter_;
} else if (purb->status == -EINPROGRESS) { data = val;
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: EINPROGESS\n")); ret = usb_write_async(udev, addr, &data, 1);
goto check_completion; _func_exit_;
} else if (purb->status == -ENOENT) {
DBG_88E("%s: -ENOENT\n", __func__); return ret;
goto check_completion; }
} else if (purb->status == -ECONNRESET) {
DBG_88E("%s: -ECONNRESET\n", __func__); int usb_async_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
goto check_completion; {
} else if (purb->status == -ESHUTDOWN) { u16 data;
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: ESHUTDOWN\n")); int ret;
padapter->bDriverStopped = true; struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bDriverStopped = true\n")); struct usb_device *udev=pdvobjpriv->pusbdev;
goto check_completion;
} else { _func_enter_;
padapter->bSurpriseRemoved = true; data = val;
DBG_88E("bSurpriseRemoved = true\n"); ret = usb_write_async(udev, addr, &data, 2);
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bSurpriseRemoved = true\n")); _func_exit_;
goto check_completion; return ret;
} }
}
int usb_async_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
haldata = GET_HAL_DATA(padapter); {
haldata->srestpriv.last_tx_complete_time = rtw_get_current_time(); u32 data;
int ret;
check_completion: struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
rtw_sctx_done_err(&pxmitbuf->sctx, struct usb_device *udev=pdvobjpriv->pusbdev;
purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR :
RTW_SCTX_DONE_SUCCESS); _func_enter_;
data = val;
rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ret = usb_write_async(udev, addr, &data, 4);
_func_exit_;
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
return ret;
} }
#endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
{ unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
unsigned long irqL; {
unsigned int pipe; unsigned int pipe=0, ep_num=0;
int status; struct usb_device *pusbd = pdvobj->pusbdev;
u32 ret = _FAIL;
struct urb *purb = NULL; if (addr == RECV_BULK_IN_ADDR) {
struct adapter *padapter = (struct adapter *)pintfhdl->padapter; pipe=usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]);
struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv; } else if (addr == RECV_INT_IN_ADDR) {
struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem; pipe=usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]);
struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
struct usb_device *pusbd = pdvobj->pusbdev; } else if (addr < HW_QUEUE_ENTRY) {
ep_num = pdvobj->Queue2Pipe[addr];
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port\n")); pipe = usb_sndbulkpipe(pusbd, ep_num);
}
if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||
(padapter->pwrctrlpriv.pnp_bstop_trx)) { return pipe;
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, }
("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); struct zero_bulkout_context{
goto exit; void *pbuf;
} void *purb;
void *pirp;
spin_lock_irqsave(&pxmitpriv->lock, irqL); void *padapter;
};
switch (addr) {
case VO_QUEUE_INX: static void usb_bulkout_zero_complete(struct urb *purb, struct pt_regs *regs)
pxmitpriv->voq_cnt++; {
pxmitbuf->flags = VO_QUEUE_INX; struct zero_bulkout_context *pcontext = (struct zero_bulkout_context *)purb->context;
break;
case VI_QUEUE_INX: //DBG_8192C("+usb_bulkout_zero_complete\n");
pxmitpriv->viq_cnt++;
pxmitbuf->flags = VI_QUEUE_INX; if(pcontext)
break; {
case BE_QUEUE_INX: if(pcontext->pbuf)
pxmitpriv->beq_cnt++; {
pxmitbuf->flags = BE_QUEUE_INX; rtw_mfree(pcontext->pbuf, sizeof(int));
break; }
case BK_QUEUE_INX:
pxmitpriv->bkq_cnt++; if(pcontext->purb && (pcontext->purb==purb))
pxmitbuf->flags = BK_QUEUE_INX; {
break; usb_free_urb(pcontext->purb);
case HIGH_QUEUE_INX: }
pxmitbuf->flags = HIGH_QUEUE_INX;
break;
default: rtw_mfree((u8*)pcontext, sizeof(struct zero_bulkout_context));
pxmitbuf->flags = MGT_QUEUE_INX; }
break;
}
}
spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
static u32 usb_bulkout_zero(struct intf_hdl *pintfhdl, u32 addr)
purb = pxmitbuf->pxmit_urb[0]; {
int pipe, status, len;
/* translate DMA FIFO addr to pipehandle */ u32 ret;
pipe = ffaddr2pipehdl(pdvobj, addr); unsigned char *pbuf;
struct zero_bulkout_context *pcontext;
usb_fill_bulk_urb(purb, pusbd, pipe, PURB purb = NULL;
pxmitframe->buf_addr, /* pxmitbuf->pbuf */ _adapter *padapter = (_adapter *)pintfhdl->padapter;
cnt, struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
usb_write_port_complete, struct usb_device *pusbd = pdvobj->pusbdev;
pxmitbuf);/* context is pxmitbuf */
//DBG_871X("%s\n", __func__);
status = usb_submit_urb(purb, GFP_ATOMIC);
if (!status) {
struct hal_data_8188e *haldata = GET_HAL_DATA(padapter); if((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx))
{
haldata->srestpriv.last_tx_time = rtw_get_current_time(); return _FAIL;
} else { }
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
DBG_88E("usb_write_port, status =%d\n", status);
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port(): usb_submit_urb, status =%x\n", status)); pcontext = (struct zero_bulkout_context *)rtw_zmalloc(sizeof(struct zero_bulkout_context));
switch (status) { pbuf = (unsigned char *)rtw_zmalloc(sizeof(int));
case -ENODEV: purb = usb_alloc_urb(0, GFP_ATOMIC);
padapter->bDriverStopped = true;
break; len = 0;
default: pcontext->pbuf = pbuf;
break; pcontext->purb = purb;
} pcontext->pirp = NULL;
goto exit; pcontext->padapter = padapter;
}
ret = _SUCCESS; //translate DMA FIFO addr to pipehandle
//pipe = ffaddr2pipehdl(pdvobj, addr);
/* We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */
usb_fill_bulk_urb(purb, pusbd, pipe,
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-usb_write_port\n")); pbuf,
len,
exit: usb_bulkout_zero_complete,
if (ret != _SUCCESS) pcontext);//context is pcontext
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
status = usb_submit_urb(purb, GFP_ATOMIC);
return ret;
} if (!status)
{
void usb_write_port_cancel(struct intf_hdl *pintfhdl) ret= _SUCCESS;
{ }
int i, j; else
struct adapter *padapter = pintfhdl->padapter; {
struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf; ret= _FAIL;
}
DBG_88E("%s\n", __func__);
padapter->bWritePortCancel = true; return _SUCCESS;
for (i = 0; i < NR_XMITBUFF; i++) { }
for (j = 0; j < 8; j++) {
if (pxmitbuf->pxmit_urb[j]) void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
usb_kill_urb(pxmitbuf->pxmit_urb[j]); {
}
pxmitbuf++; }
}
void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf; {
for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
for (j = 0; j < 8; j++) { }
if (pxmitbuf->pxmit_urb[j])
usb_kill_urb(pxmitbuf->pxmit_urb[j]);
} void usb_read_port_cancel(struct intf_hdl *pintfhdl)
pxmitbuf++; {
} int i;
} struct recv_buf *precvbuf;
_adapter *padapter = pintfhdl->padapter;
precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
DBG_871X("%s\n", __func__);
padapter->bReadPortCancel = _TRUE;
for (i=0; i < NR_RECVBUFF ; i++) {
precvbuf->reuse = _TRUE;
if (precvbuf->purb) {
//DBG_8192C("usb_read_port_cancel : usb_kill_urb \n");
usb_kill_urb(precvbuf->purb);
}
precvbuf++;
}
#ifdef CONFIG_USB_INTERRUPT_IN_PIPE
usb_kill_urb(padapter->recvpriv.int_in_urb);
#endif
}
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
{
_irqL irqL;
int i;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
//struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
//_adapter *padapter = pxmitframe->padapter;
_adapter *padapter = pxmitbuf->padapter;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
//struct pkt_attrib *pattrib = &pxmitframe->attrib;
_func_enter_;
switch(pxmitbuf->flags)
{
case VO_QUEUE_INX:
pxmitpriv->voq_cnt--;
break;
case VI_QUEUE_INX:
pxmitpriv->viq_cnt--;
break;
case BE_QUEUE_INX:
pxmitpriv->beq_cnt--;
break;
case BK_QUEUE_INX:
pxmitpriv->bkq_cnt--;
break;
case HIGH_QUEUE_INX:
#ifdef CONFIG_AP_MODE
rtw_chk_hi_queue_cmd(padapter);
#endif
break;
default:
break;
}
/*
_enter_critical(&pxmitpriv->lock, &irqL);
pxmitpriv->txirp_cnt--;
switch(pattrib->priority)
{
case 1:
case 2:
pxmitpriv->bkq_cnt--;
//DBG_8192C("pxmitpriv->bkq_cnt=%d\n", pxmitpriv->bkq_cnt);
break;
case 4:
case 5:
pxmitpriv->viq_cnt--;
//DBG_8192C("pxmitpriv->viq_cnt=%d\n", pxmitpriv->viq_cnt);
break;
case 6:
case 7:
pxmitpriv->voq_cnt--;
//DBG_8192C("pxmitpriv->voq_cnt=%d\n", pxmitpriv->voq_cnt);
break;
case 0:
case 3:
default:
pxmitpriv->beq_cnt--;
//DBG_8192C("pxmitpriv->beq_cnt=%d\n", pxmitpriv->beq_cnt);
break;
}
_exit_critical(&pxmitpriv->lock, &irqL);
if(pxmitpriv->txirp_cnt==0)
{
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: txirp_cnt== 0, set allrxreturnevt!\n"));
_rtw_up_sema(&(pxmitpriv->tx_retevt));
}
*/
//rtw_free_xmitframe(pxmitpriv, pxmitframe);
if(padapter->bSurpriseRemoved || padapter->bDriverStopped ||padapter->bWritePortCancel)
{
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved));
DBG_8192C("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x) \n",
__FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,padapter->bReadPortCancel,pxmitbuf->ext_tag);
goto check_completion;
}
if (purb->status==0) {
} else {
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete : purb->status(%d) != 0 \n", purb->status));
DBG_871X("###=> urb_write_port_complete status(%d)\n",purb->status);
if((purb->status==-EPIPE)||(purb->status==-EPROTO))
{
//usb_clear_halt(pusbdev, purb->pipe);
//msleep(10);
sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL);
} else if (purb->status == -EINPROGRESS) {
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: EINPROGESS\n"));
goto check_completion;
} else if (purb->status == -ENOENT) {
DBG_871X("%s: -ENOENT\n", __func__);
goto check_completion;
} else if (purb->status == -ECONNRESET) {
DBG_871X("%s: -ECONNRESET\n", __func__);
goto check_completion;
} else if (purb->status == -ESHUTDOWN) {
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: ESHUTDOWN\n"));
padapter->bDriverStopped=_TRUE;
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped=TRUE\n"));
goto check_completion;
}
else
{
padapter->bSurpriseRemoved=_TRUE;
DBG_8192C("bSurpriseRemoved=TRUE\n");
//rtl8192cu_trigger_gpio_0(padapter);
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bSurpriseRemoved=TRUE\n"));
goto check_completion;
}
}
#ifdef DBG_CONFIG_ERROR_DETECT
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time();
}
#endif
check_completion:
_enter_critical(&pxmitpriv->lock_sctx, &irqL);
rtw_sctx_done_err(&pxmitbuf->sctx,
purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS);
_exit_critical(&pxmitpriv->lock_sctx, &irqL);
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
//if(rtw_txframes_pending(padapter))
{
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
}
_func_exit_;
}
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
{
_irqL irqL;
unsigned int pipe;
int status;
u32 ret = _FAIL, bwritezero = _FALSE;
PURB purb = NULL;
_adapter *padapter = (_adapter *)pintfhdl->padapter;
struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem;
struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
struct usb_device *pusbd = pdvobj->pusbdev;
struct pkt_attrib *pattrib = &pxmitframe->attrib;
_func_enter_;
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("+usb_write_port\n"));
if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx)) {
#ifdef DBG_TX
DBG_871X(" DBG_TX %s:%d bDriverStopped%d, bSurpriseRemoved:%d, pnp_bstop_trx:%d\n",__FUNCTION__, __LINE__
,padapter->bDriverStopped, padapter->bSurpriseRemoved, dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx );
#endif
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||pwrctl->pnp_bstop_trx)!!!\n"));
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
goto exit;
}
_enter_critical(&pxmitpriv->lock, &irqL);
switch(addr)
{
case VO_QUEUE_INX:
pxmitpriv->voq_cnt++;
pxmitbuf->flags = VO_QUEUE_INX;
break;
case VI_QUEUE_INX:
pxmitpriv->viq_cnt++;
pxmitbuf->flags = VI_QUEUE_INX;
break;
case BE_QUEUE_INX:
pxmitpriv->beq_cnt++;
pxmitbuf->flags = BE_QUEUE_INX;
break;
case BK_QUEUE_INX:
pxmitpriv->bkq_cnt++;
pxmitbuf->flags = BK_QUEUE_INX;
break;
case HIGH_QUEUE_INX:
pxmitbuf->flags = HIGH_QUEUE_INX;
break;
default:
pxmitbuf->flags = MGT_QUEUE_INX;
break;
}
_exit_critical(&pxmitpriv->lock, &irqL);
#ifdef DBG_TRX_STA_PKTS
{
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
int bmcast = IS_MCAST(pattrib->dst);
u8 agg_num = 1;
#ifdef CONFIG_USB_HCI
#ifdef CONFIG_USB_TX_AGGREGATION
if(pxmitframe->agg_num>1)
agg_num = pxmitframe->agg_num;
#endif
#endif
#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
if(pxmitframe->agg_num>1)
agg_num = pxmitframe->agg_num;
#endif
if(bmcast)
{
psta = rtw_get_bcmc_stainfo(padapter);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->dst);
}
if(psta)
{
switch(pattrib->priority)
{
case 1:
case 2:
psta->tx_bk_cnt += agg_num;
break;
case 4:
case 5:
psta->tx_vi_cnt += agg_num;
break;
case 6:
case 7:
psta->tx_vo_cnt += agg_num;
break;
case 0:
case 3:
default:
psta->tx_be_cnt += agg_num;
break;
}
}
}
#endif
purb = pxmitbuf->pxmit_urb[0];
#if 0
if(pdvobj->ishighspeed)
{
if(cnt> 0 && cnt%512 == 0)
{
//DBG_8192C("ishighspeed, cnt=%d\n", cnt);
bwritezero = _TRUE;
}
}
else
{
if(cnt > 0 && cnt%64 == 0)
{
//DBG_8192C("cnt=%d\n", cnt);
bwritezero = _TRUE;
}
}
#endif
//translate DMA FIFO addr to pipehandle
pipe = ffaddr2pipehdl(pdvobj, addr);
#ifdef CONFIG_REDUCE_USB_TX_INT
if ( (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0)
|| (pxmitbuf->ext_tag == _TRUE) )
{
purb->transfer_flags &= (~URB_NO_INTERRUPT);
} else {
purb->transfer_flags |= URB_NO_INTERRUPT;
//DBG_8192C("URB_NO_INTERRUPT ");
}
#endif
usb_fill_bulk_urb(purb, pusbd, pipe,
pxmitframe->buf_addr, //= pxmitbuf->pbuf
cnt,
usb_write_port_complete,
pxmitbuf);//context is pxmitbuf
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
purb->transfer_dma = pxmitbuf->dma_transfer_addr;
purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
purb->transfer_flags |= URB_ZERO_PACKET;
#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
#if 0
if (bwritezero)
{
purb->transfer_flags |= URB_ZERO_PACKET;
}
#endif
status = usb_submit_urb(purb, GFP_ATOMIC);
if (!status) {
#ifdef DBG_CONFIG_ERROR_DETECT
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
pHalData->srestpriv.last_tx_time = rtw_get_current_time();
}
#endif
} else {
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
DBG_871X("usb_write_port, status=%d\n", status);
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port(): usb_submit_urb, status=%x\n", status));
switch (status) {
case -ENODEV:
padapter->bDriverStopped=_TRUE;
break;
default:
break;
}
goto exit;
}
ret= _SUCCESS;
// Commented by Albert 2009/10/13
// We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically.
/*
if(bwritezero == _TRUE)
{
usb_bulkout_zero(pintfhdl, addr);
}
*/
RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("-usb_write_port\n"));
exit:
if (ret != _SUCCESS)
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
_func_exit_;
return ret;
}
void usb_write_port_cancel(struct intf_hdl *pintfhdl)
{
int i, j;
_adapter *padapter = pintfhdl->padapter;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
DBG_871X("%s \n", __func__);
padapter->bWritePortCancel = _TRUE;
for (i=0; i<NR_XMITBUFF; i++) {
for (j=0; j<8; j++) {
if (pxmitbuf->pxmit_urb[j]) {
usb_kill_urb(pxmitbuf->pxmit_urb[j]);
}
}
pxmitbuf++;
}
pxmitbuf = (struct xmit_buf*)padapter->xmitpriv.pxmit_extbuf;
for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
for (j=0; j<8; j++) {
if(pxmitbuf->pxmit_urb[j]) {
usb_kill_urb(pxmitbuf->pxmit_urb[j]);
}
}
pxmitbuf++;
}
}

358
os_dep/xmit_linux.c Normal file → Executable file
View file

@ -1,7 +1,7 @@
/****************************************************************************** /******************************************************************************
* *
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation. * published by the Free Software Foundation.
@ -19,115 +19,209 @@
******************************************************************************/ ******************************************************************************/
#define _XMIT_OSDEP_C_ #define _XMIT_OSDEP_C_
#include <linux/version.h> #include <drv_conf.h>
#include <osdep_service.h> #include <osdep_service.h>
#include <drv_types.h> #include <drv_types.h>
#include <if_ether.h> #include <if_ether.h>
#include <ip.h> #include <ip.h>
#include <rtw_byteorder.h>
#include <wifi.h> #include <wifi.h>
#include <mlme_osdep.h> #include <mlme_osdep.h>
#include <xmit_osdep.h> #include <xmit_osdep.h>
#include <osdep_intf.h> #include <osdep_intf.h>
#include <usb_osintf.h> #include <circ_buf.h>
uint rtw_remainder_len(struct pkt_file *pfile) uint rtw_remainder_len(struct pkt_file *pfile)
{ {
return pfile->buf_len - ((size_t)(pfile->cur_addr) - return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start)));
(size_t)(pfile->buf_start));
} }
void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile) void _rtw_open_pktfile (_pkt *pktptr, struct pkt_file *pfile)
{ {
_func_enter_;
pfile->pkt = pktptr; pfile->pkt = pktptr;
pfile->cur_addr = pktptr->data; pfile->cur_addr = pfile->buf_start = pktptr->data;
pfile->buf_start = pktptr->data; pfile->pkt_len = pfile->buf_len = pktptr->len;
pfile->pkt_len = pktptr->len;
pfile->buf_len = pktptr->len;
pfile->cur_buffer = pfile->buf_start;
pfile->cur_buffer = pfile->buf_start ;
_func_exit_;
} }
uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen) uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
{ {
uint len = 0; uint len = 0;
_func_enter_;
len = rtw_remainder_len(pfile); len = rtw_remainder_len(pfile);
len = (rlen > len) ? len : rlen; len = (rlen > len)? len: rlen;
if (rmem) if(rmem)
skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len); skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
pfile->cur_addr += len; pfile->cur_addr += len;
pfile->pkt_len -= len; pfile->pkt_len -= len;
_func_exit_;
return len; return len;
} }
int rtw_endofpktfile(struct pkt_file *pfile) sint rtw_endofpktfile(struct pkt_file *pfile)
{ {
_func_enter_;
if (pfile->pkt_len == 0) { if (pfile->pkt_len == 0) {
_func_exit_;
return true; return _TRUE;
} }
return false; _func_exit_;
return _FALSE;
} }
void rtw_set_tx_chksum_offload(struct sk_buff *pkt, struct pkt_attrib *pattrib) void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib)
{ {
#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
struct sk_buff *skb = (struct sk_buff *)pkt;
pattrib->hw_tcp_csum = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb_shinfo(skb)->nr_frags == 0)
{
const struct iphdr *ip = ip_hdr(skb);
if (ip->protocol == IPPROTO_TCP) {
// TCP checksum offload by HW
DBG_871X("CHECKSUM_PARTIAL TCP\n");
pattrib->hw_tcp_csum = 1;
//skb_checksum_help(skb);
} else if (ip->protocol == IPPROTO_UDP) {
//DBG_871X("CHECKSUM_PARTIAL UDP\n");
#if 1
skb_checksum_help(skb);
#else
// Set UDP checksum = 0 to skip checksum check
struct udphdr *udp = skb_transport_header(skb);
udp->check = 0;
#endif
} else {
DBG_871X("%s-%d TCP CSUM offload Error!!\n", __FUNCTION__, __LINE__);
WARN_ON(1); /* we need a WARN() */
}
}
else { // IP fragmentation case
DBG_871X("%s-%d nr_frags != 0, using skb_checksum_help(skb);!!\n", __FUNCTION__, __LINE__);
skb_checksum_help(skb);
}
}
#endif
} }
int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz) int rtw_os_xmit_resource_alloc(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 alloc_sz)
{ {
#ifdef CONFIG_USB_HCI
int i; int i;
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
pxmitbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)alloc_sz, &pxmitbuf->dma_transfer_addr);
pxmitbuf->pbuf = pxmitbuf->pallocated_buf;
if(pxmitbuf->pallocated_buf == NULL)
return _FAIL;
#else // CONFIG_USE_USB_BUFFER_ALLOC_TX
pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz); pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
if (pxmitbuf->pallocated_buf == NULL) if (pxmitbuf->pallocated_buf == NULL)
{
return _FAIL; return _FAIL;
}
pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
pxmitbuf->dma_transfer_addr = 0; pxmitbuf->dma_transfer_addr = 0;
for (i = 0; i < 8; i++) { #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
if (pxmitbuf->pxmit_urb[i] == NULL) { for(i=0; i<8; i++)
DBG_88E("pxmitbuf->pxmit_urb[i]==NULL"); {
return _FAIL; pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
} if(pxmitbuf->pxmit_urb[i] == NULL)
{
DBG_871X("pxmitbuf->pxmit_urb[i]==NULL");
return _FAIL;
}
}
#endif
#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
if (pxmitbuf->pallocated_buf == NULL)
{
return _FAIL;
} }
return _SUCCESS;
pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
#endif
return _SUCCESS;
} }
void rtw_os_xmit_resource_free(struct adapter *padapter, void rtw_os_xmit_resource_free(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 free_sz)
struct xmit_buf *pxmitbuf, u32 free_sz)
{ {
#ifdef CONFIG_USB_HCI
int i; int i;
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
for (i = 0; i < 8; i++)
usb_free_urb(pxmitbuf->pxmit_urb[i]);
kfree(pxmitbuf->pallocated_buf); for(i=0; i<8; i++)
{
if(pxmitbuf->pxmit_urb[i])
{
//usb_kill_urb(pxmitbuf->pxmit_urb[i]);
usb_free_urb(pxmitbuf->pxmit_urb[i]);
}
}
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
rtw_usb_buffer_free(pusbd, (size_t)free_sz, pxmitbuf->pallocated_buf, pxmitbuf->dma_transfer_addr);
pxmitbuf->pallocated_buf = NULL;
pxmitbuf->dma_transfer_addr = 0;
#else // CONFIG_USE_USB_BUFFER_ALLOC_TX
if(pxmitbuf->pallocated_buf)
rtw_mfree(pxmitbuf->pallocated_buf, free_sz);
#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX
#endif
#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
if(pxmitbuf->pallocated_buf)
rtw_mfree(pxmitbuf->pallocated_buf, free_sz);
#endif
} }
#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5) #define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5)
void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt) void rtw_os_pkt_complete(_adapter *padapter, _pkt *pkt)
{ {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
u16 queue; u16 queue;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
queue = skb_get_queue_mapping(pkt); queue = skb_get_queue_mapping(pkt);
if (padapter->registrypriv.wifi_spec) { if (padapter->registrypriv.wifi_spec) {
if (__netif_subqueue_stopped(padapter->pnetdev, queue) && if(__netif_subqueue_stopped(padapter->pnetdev, queue) &&
(pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
{
netif_wake_subqueue(padapter->pnetdev, queue); netif_wake_subqueue(padapter->pnetdev, queue);
}
} else { } else {
if (__netif_subqueue_stopped(padapter->pnetdev, queue)) if(__netif_subqueue_stopped(padapter->pnetdev, queue))
netif_wake_subqueue(padapter->pnetdev, queue); netif_wake_subqueue(padapter->pnetdev, queue);
} }
#else #else
@ -135,129 +229,207 @@ void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt)
netif_wake_queue(padapter->pnetdev); netif_wake_queue(padapter->pnetdev);
#endif #endif
dev_kfree_skb_any(pkt); rtw_skb_free(pkt);
} }
void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe) void rtw_os_xmit_complete(_adapter *padapter, struct xmit_frame *pxframe)
{ {
if (pxframe->pkt) if(pxframe->pkt)
rtw_os_pkt_complete(padapter, pxframe->pkt); rtw_os_pkt_complete(padapter, pxframe->pkt);
pxframe->pkt = NULL; pxframe->pkt = NULL;
} }
void rtw_os_xmit_schedule(struct adapter *padapter) void rtw_os_xmit_schedule(_adapter *padapter)
{ {
_adapter *pri_adapter = padapter;
#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
if(!padapter)
return;
#ifdef CONFIG_CONCURRENT_MODE
if(padapter->adapter_type > PRIMARY_ADAPTER)
pri_adapter = padapter->pbuddy_adapter;
#endif
if (_rtw_queue_empty(&pri_adapter->xmitpriv.pending_xmitbuf_queue) == _FALSE)
_rtw_up_sema(&pri_adapter->xmitpriv.xmit_sema);
#else
_irqL irqL;
struct xmit_priv *pxmitpriv; struct xmit_priv *pxmitpriv;
if (!padapter) if(!padapter)
return; return;
pxmitpriv = &padapter->xmitpriv; pxmitpriv = &padapter->xmitpriv;
spin_lock_bh(&pxmitpriv->lock); _enter_critical_bh(&pxmitpriv->lock, &irqL);
if (rtw_txframes_pending(padapter)) if(rtw_txframes_pending(padapter))
{
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
}
spin_unlock_bh(&pxmitpriv->lock); _exit_critical_bh(&pxmitpriv->lock, &irqL);
#endif
} }
static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt) static void rtw_check_xmit_resource(_adapter *padapter, _pkt *pkt)
{ {
struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
u16 queue; u16 queue;
queue = skb_get_queue_mapping(pkt); queue = skb_get_queue_mapping(pkt);
if (padapter->registrypriv.wifi_spec) { if (padapter->registrypriv.wifi_spec) {
/* No free space for Tx, tx_worker is too slow */ /* No free space for Tx, tx_worker is too slow */
if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) {
//DBG_871X("%s(): stop netif_subqueue[%d]\n", __FUNCTION__, queue);
netif_stop_subqueue(padapter->pnetdev, queue); netif_stop_subqueue(padapter->pnetdev, queue);
}
} else { } else {
if (pxmitpriv->free_xmitframe_cnt <= 4) { if(pxmitpriv->free_xmitframe_cnt<=4) {
if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
netif_stop_subqueue(padapter->pnetdev, queue); netif_stop_subqueue(padapter->pnetdev, queue);
} }
} }
#else
if(pxmitpriv->free_xmitframe_cnt<=4)
{
if (!rtw_netif_queue_stopped(padapter->pnetdev))
rtw_netif_stop_queue(padapter->pnetdev);
}
#endif
} }
static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) #ifdef CONFIG_TX_MCAST2UNI
static int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb)
{ {
struct sta_priv *pstapriv = &padapter->stapriv; struct sta_priv *pstapriv = &padapter->stapriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct list_head *phead, *plist; _irqL irqL;
_list *phead, *plist;
struct sk_buff *newskb; struct sk_buff *newskb;
struct sta_info *psta = NULL; struct sta_info *psta = NULL;
u8 chk_alive_num = 0;
char chk_alive_list[NUM_STA];
u8 bc_addr[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u8 null_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
int i;
s32 res; s32 res;
spin_lock_bh(&pstapriv->asoc_list_lock); _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
phead = &pstapriv->asoc_list; phead = &pstapriv->asoc_list;
plist = get_next(phead); plist = get_next(phead);
/* free sta asoc_queue */ //free sta asoc_queue
while (!rtw_end_of_queue_search(phead, plist)) { while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
int stainfo_offset;
psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
plist = get_next(plist); plist = get_next(plist);
/* avoid come from STA1 and send back STA1 */ stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
if (!memcmp(psta->hwaddr, &skb->data[6], 6)) if (stainfo_offset_valid(stainfo_offset)) {
chk_alive_list[chk_alive_num++] = stainfo_offset;
}
}
_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
for (i = 0; i < chk_alive_num; i++) {
psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
if(!(psta->state &_FW_LINKED))
continue;
/* avoid come from STA1 and send back STA1 */
if (_rtw_memcmp(psta->hwaddr, &skb->data[6], 6) == _TRUE
|| _rtw_memcmp(psta->hwaddr, null_addr, 6) == _TRUE
|| _rtw_memcmp(psta->hwaddr, bc_addr, 6) == _TRUE
)
continue; continue;
newskb = skb_copy(skb, GFP_ATOMIC); newskb = rtw_skb_copy(skb);
if (newskb) { if (newskb) {
memcpy(newskb->data, psta->hwaddr, 6); _rtw_memcpy(newskb->data, psta->hwaddr, 6);
res = rtw_xmit(padapter, &newskb); res = rtw_xmit(padapter, &newskb);
if (res < 0) { if (res < 0) {
DBG_88E("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__); DBG_871X("%s()-%d: rtw_xmit() return error!\n", __FUNCTION__, __LINE__);
pxmitpriv->tx_drop++; pxmitpriv->tx_drop++;
dev_kfree_skb_any(newskb); rtw_skb_free(newskb);
} else { } else
pxmitpriv->tx_pkts++; pxmitpriv->tx_pkts++;
}
} else { } else {
DBG_88E("%s-%d: skb_copy() failed!\n", __func__, __LINE__); DBG_871X("%s-%d: rtw_skb_copy() failed!\n", __FUNCTION__, __LINE__);
pxmitpriv->tx_drop++; pxmitpriv->tx_drop++;
//rtw_skb_free(skb);
spin_unlock_bh(&pstapriv->asoc_list_lock); return _FALSE; // Caller shall tx this multicast frame via normal way.
return false; /* Caller shall tx this multicast frame via normal way. */
} }
} }
spin_unlock_bh(&pstapriv->asoc_list_lock); rtw_skb_free(skb);
dev_kfree_skb_any(skb); return _TRUE;
return true;
} }
#endif // CONFIG_TX_MCAST2UNI
int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
{ {
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
#ifdef CONFIG_TX_MCAST2UNI
struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
extern int rtw_mc2u_disable;
#endif // CONFIG_TX_MCAST2UNI
s32 res = 0; s32 res = 0;
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35))
u16 queue;
#endif
_func_enter_;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n")); RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
if (rtw_if_up(padapter) == false) { if (rtw_if_up(padapter) == _FALSE) {
RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n")); RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
#ifdef DBG_TX_DROP_FRAME
DBG_871X("DBG_TX_DROP_FRAME %s if_up fail\n", __FUNCTION__);
#endif
goto drop_packet; goto drop_packet;
} }
rtw_check_xmit_resource(padapter, pkt); rtw_check_xmit_resource(padapter, pkt);
if (!rtw_mc2u_disable && check_fwstate(pmlmepriv, WIFI_AP_STATE) && #ifdef CONFIG_TX_MCAST2UNI
(IP_MCAST_MAC(pkt->data) || ICMPV6_MCAST_MAC(pkt->data)) && if ( !rtw_mc2u_disable
(padapter->registrypriv.wifi_spec == 0)) { && check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE
if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) { && ( IP_MCAST_MAC(pkt->data)
|| ICMPV6_MCAST_MAC(pkt->data) )
&& (padapter->registrypriv.wifi_spec == 0)
)
{
if ( pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4) ) {
res = rtw_mlcst2unicst(padapter, pkt); res = rtw_mlcst2unicst(padapter, pkt);
if (res) if (res == _TRUE) {
goto exit; goto exit;
}
} else {
//DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt);
//DBG_871X("!m2u );
} }
} }
#endif // CONFIG_TX_MCAST2UNI
res = rtw_xmit(padapter, &pkt); res = rtw_xmit(padapter, &pkt);
if (res < 0) if (res < 0) {
#ifdef DBG_TX_DROP_FRAME
DBG_871X("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__);
#endif
goto drop_packet; goto drop_packet;
}
pxmitpriv->tx_pkts++; pxmitpriv->tx_pkts++;
RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts)); RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
@ -265,10 +437,20 @@ int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
drop_packet: drop_packet:
pxmitpriv->tx_drop++; pxmitpriv->tx_drop++;
dev_kfree_skb_any(pkt); rtw_skb_free(pkt);
RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop)); RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
exit: exit:
_func_exit_;
return 0; return 0;
} }
int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
{
if (pkt)
rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, pkt->truesize);
return _rtw_xmit_entry(pkt, pnetdev);
}