diff options
Diffstat (limited to 'drivers/net/wireless/rtlwifi/rtl8723as/hal/rtl8723a/usb/rtl8723au_recv.c')
-rwxr-xr-x | drivers/net/wireless/rtlwifi/rtl8723as/hal/rtl8723a/usb/rtl8723au_recv.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtlwifi/rtl8723as/hal/rtl8723a/usb/rtl8723au_recv.c b/drivers/net/wireless/rtlwifi/rtl8723as/hal/rtl8723a/usb/rtl8723au_recv.c new file mode 100755 index 000000000000..330c41c8f044 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723as/hal/rtl8723a/usb/rtl8723au_recv.c @@ -0,0 +1,365 @@ +/****************************************************************************** + * + * 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 _RTL8192CU_RECV_C_ +#include <drv_conf.h> +#include <osdep_service.h> +#include <drv_types.h> +#include <recv_osdep.h> +#include <mlme_osdep.h> +#include <ip.h> +#include <if_ether.h> +#include <ethernet.h> + +#include <usb_ops.h> + +#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) + +#error "Shall be Linux or Windows, but not both!\n" + +#endif + +#include <wifi.h> +#include <circ_buf.h> + +//#include <rtl8192c_hal.h> +#include <rtl8723a_hal.h> + +void rtl8192cu_init_recvbuf(_adapter *padapter, struct recv_buf *precvbuf) +{ + + precvbuf->transfer_len = 0; + + precvbuf->len = 0; + + precvbuf->ref_cnt = 0; + + if(precvbuf->pbuf) + { + precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pbuf; + precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ; + } + +} + +int rtl8192cu_init_recv_priv(_adapter *padapter) +{ + struct recv_priv *precvpriv = &padapter->recvpriv; + int i, res = _SUCCESS; + struct recv_buf *precvbuf; + +#ifdef CONFIG_RECV_THREAD_MODE + _rtw_init_sema(&precvpriv->recv_sema, 0);//will be removed + _rtw_init_sema(&precvpriv->terminate_recvthread_sema, 0);//will be removed +#endif + +#ifdef PLATFORM_LINUX + tasklet_init(&precvpriv->recv_tasklet, + (void(*)(unsigned long))rtl8192cu_recv_tasklet, + (unsigned long)padapter); +#endif + +#ifdef CONFIG_USB_INTERRUPT_IN_PIPE +#ifdef PLATFORM_LINUX + precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if(precvpriv->int_in_urb == NULL){ + DBG_8192C("alloc_urb for interrupt in endpoint fail !!!!\n"); + } +#endif + precvpriv->int_in_buf = rtw_zmalloc(USB_INTR_CONTENT_LENGTH); + if(precvpriv->int_in_buf == NULL){ + DBG_8192C("alloc_mem for interrupt in endpoint fail !!!!\n"); + } +#endif + + //init recv_buf + _rtw_init_queue(&precvpriv->free_recv_buf_queue); + +#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX + _rtw_init_queue(&precvpriv->recv_buf_pending_queue); +#endif // CONFIG_USE_USB_BUFFER_ALLOC_RX + + precvpriv->pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF *sizeof(struct recv_buf) + 4); + if(precvpriv->pallocated_recv_buf==NULL){ + res= _FAIL; + RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("alloc recv_buf fail!\n")); + goto exit; + } + _rtw_memset(precvpriv->pallocated_recv_buf, 0, NR_RECVBUFF *sizeof(struct recv_buf) + 4); + + precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4); + //precvpriv->precv_buf = precvpriv->pallocated_recv_buf + 4 - + // ((uint) (precvpriv->pallocated_recv_buf) &(4-1)); + + + precvbuf = (struct recv_buf*)precvpriv->precv_buf; + + for(i=0; i < NR_RECVBUFF ; i++) + { + _rtw_init_listhead(&precvbuf->list); + + _rtw_spinlock_init(&precvbuf->recvbuf_lock); + + precvbuf->alloc_sz = MAX_RECVBUF_SZ; + + res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf); + if(res==_FAIL) + break; + + precvbuf->ref_cnt = 0; + precvbuf->adapter =padapter; + + + //rtw_list_insert_tail(&precvbuf->list, &(precvpriv->free_recv_buf_queue.queue)); + + precvbuf++; + + } + + precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; + +#ifdef PLATFORM_LINUX + + skb_queue_head_init(&precvpriv->rx_skb_queue); + +#ifdef CONFIG_PREALLOC_RECV_SKB + { + int i; + SIZE_PTR tmpaddr=0; + SIZE_PTR alignment=0; + struct sk_buff *pskb=NULL; + + skb_queue_head_init(&precvpriv->free_recv_skb_queue); + + for(i=0; i<NR_PREALLOC_RECV_SKB; i++) + { + pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); + + if(pskb) + { + pskb->dev = padapter->pnetdev; + + tmpaddr = (SIZE_PTR)pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); + skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); + + skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + } + + pskb=NULL; + + } + } +#endif + +#endif + +exit: + + return res; + +} + +void rtl8192cu_free_recv_priv (_adapter *padapter) +{ + int i; + struct recv_buf *precvbuf; + struct recv_priv *precvpriv = &padapter->recvpriv; + + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + + for(i=0; i < NR_RECVBUFF ; i++) + { + rtw_os_recvbuf_resource_free(padapter, precvbuf); + precvbuf++; + } + + if(precvpriv->pallocated_recv_buf) + rtw_mfree(precvpriv->pallocated_recv_buf, NR_RECVBUFF *sizeof(struct recv_buf) + 4); + +#ifdef CONFIG_USB_INTERRUPT_IN_PIPE +#ifdef PLATFORM_LINUX + if(precvpriv->int_in_urb) + { + usb_free_urb(precvpriv->int_in_urb); + } +#endif + if(precvpriv->int_in_buf) + rtw_mfree(precvpriv->int_in_buf, USB_INTR_CONTENT_LENGTH); +#endif + +#ifdef PLATFORM_LINUX + + if (skb_queue_len(&precvpriv->rx_skb_queue)) { + DBG_8192C(KERN_WARNING "rx_skb_queue not empty\n"); + } + + rtw_skb_queue_purge(&precvpriv->rx_skb_queue); + +#ifdef CONFIG_PREALLOC_RECV_SKB + + if (skb_queue_len(&precvpriv->free_recv_skb_queue)) { + DBG_8192C(KERN_WARNING "free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue)); + } + + rtw_skb_queue_purge(&precvpriv->free_recv_skb_queue); + +#endif + +#endif + +} + + +void update_recvframe_attrib( + union recv_frame *precvframe, + struct recv_stat *prxstat) +{ + struct rx_pkt_attrib *pattrib; + struct recv_stat report; + PRXREPORT prxreport; + + + report.rxdw0 = le32_to_cpu(prxstat->rxdw0); + report.rxdw1 = le32_to_cpu(prxstat->rxdw1); + report.rxdw2 = le32_to_cpu(prxstat->rxdw2); + report.rxdw3 = le32_to_cpu(prxstat->rxdw3); + report.rxdw4 = le32_to_cpu(prxstat->rxdw4); + report.rxdw5 = le32_to_cpu(prxstat->rxdw5); + + prxreport = (PRXREPORT)&report; + + pattrib = &precvframe->u.hdr.attrib; + _rtw_memset(pattrib, 0, sizeof(struct rx_pkt_attrib)); + + // update rx report to recv_frame attribute + pattrib->pkt_len = (u16)prxreport->pktlen; + pattrib->drvinfo_sz = (u8)(prxreport->drvinfosize << 3); + pattrib->physt = (u8)prxreport->physt; + + pattrib->crc_err = (u8)prxreport->crc32; + pattrib->icv_err = (u8)prxreport->icverr; + + pattrib->bdecrypted = (u8)(prxreport->swdec ? 0 : 1); + pattrib->encrypt = (u8)prxreport->security; + + pattrib->qos = (u8)prxreport->qos; + pattrib->priority = (u8)prxreport->tid; + + pattrib->amsdu = (u8)prxreport->amsdu; + + pattrib->seq_num = (u16)prxreport->seq; + pattrib->frag_num = (u8)prxreport->frag; + pattrib->mfrag = (u8)prxreport->mf; + pattrib->mdata = (u8)prxreport->md; + + pattrib->mcs_rate = (u8)prxreport->rxmcs; + pattrib->rxht = (u8)prxreport->rxht; +} + + + +/* + * Notice: + * Before calling this function, + * precvframe->u.hdr.rx_data should be ready! + */ +void update_recvframe_phyinfo( + union recv_frame *precvframe, + struct phy_stat *pphy_status) +{ + PADAPTER padapter = precvframe->u.hdr.adapter; + struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; + HAL_DATA_TYPE *pHalData= GET_HAL_DATA(padapter); + PODM_PHY_INFO_T pPHYInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info); + u8 *wlanhdr; + ODM_PACKET_INFO_T pkt_info; + u8 *sa; + //_irqL irqL; + struct sta_priv *pstapriv; + struct sta_info *psta; + + pkt_info.bPacketMatchBSSID =_FALSE; + pkt_info.bPacketToSelf = _FALSE; + pkt_info.bPacketBeacon = _FALSE; + + wlanhdr = get_recvframe_data(precvframe); + + pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) && + !pattrib->icv_err && !pattrib->crc_err && + _rtw_memcmp(get_hdr_bssid(wlanhdr), get_bssid(&padapter->mlmepriv), ETH_ALEN)); + + pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && (_rtw_memcmp(get_da(wlanhdr), myid(&padapter->eeprompriv), ETH_ALEN)); + + pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && (GetFrameSubType(wlanhdr) == WIFI_BEACON); + + pkt_info.StationID = 0xFF; + if(pkt_info.bPacketBeacon){ + if(check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == _TRUE){ + sa = padapter->mlmepriv.cur_network.network.MacAddress; + #if 0 + { + printk("==> rx beacon from AP[%02x:%02x:%02x:%02x:%02x:%02x]\n", + sa[0],sa[1],sa[2],sa[3],sa[4],sa[5]); + } + #endif + } + //to do Ad-hoc + } + else{ + sa = get_sa(wlanhdr); + } + + pstapriv = &padapter->stapriv; + psta = rtw_get_stainfo(pstapriv, sa); + if (psta) + { + pkt_info.StationID = psta->mac_id; + //printk("%s ==> StationID(%d)\n",__FUNCTION__,pkt_info.StationID); + } + pkt_info.Rate = pattrib->mcs_rate; + + //rtl8192c_query_rx_phy_status(precvframe, pphy_status); + //_enter_critical_bh(&pHalData->odm_stainfo_lock, &irqL); + ODM_PhyStatusQuery(&pHalData->odmpriv,pPHYInfo,(u8 *)pphy_status,&(pkt_info)); + //_exit_critical_bh(&pHalData->odm_stainfo_lock, &irqL); + precvframe->u.hdr.psta = NULL; + if (pkt_info.bPacketMatchBSSID && + (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)) + { + if (psta) + { + precvframe->u.hdr.psta = psta; + rtl8192c_process_phy_info(padapter, precvframe); + } + } + else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) + { + if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == _TRUE) + { + if (psta) + { + precvframe->u.hdr.psta = psta; + } + } + + rtl8192c_process_phy_info(padapter, precvframe); + } +} + |