12865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger/****************************************************************************** 22865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * xmit_linux.c 32865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * 42865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 52865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * Linux device driver for RTL8192SU 62865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * 72865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * This program is free software; you can redistribute it and/or modify it 82865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * under the terms of version 2 of the GNU General Public License as 92865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * published by the Free Software Foundation. 102865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * 112865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * This program is distributed in the hope that it will be useful, but WITHOUT 122865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 132865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 142865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * more details. 152865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * 162865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * You should have received a copy of the GNU General Public License along with 172865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * this program; if not, write to the Free Software Foundation, Inc., 182865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 192865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * 202865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * Modifications for inclusion into the Linux staging tree are 212865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * Copyright(c) 2010 Larry Finger. All rights reserved. 222865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * 232865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * Contact information: 242865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * WLAN FAE <wlanfae@realtek.com> 252865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * Larry Finger <Larry.Finger@lwfinger.net> 262865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * 272865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger ******************************************************************************/ 282865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 292865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#define _XMIT_OSDEP_C_ 302865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 31359140aaea5bc3123356d46d0daa9dac8cfb12bcAli Bahar#include <linux/usb.h> 32359140aaea5bc3123356d46d0daa9dac8cfb12bcAli Bahar 332865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "osdep_service.h" 342865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "drv_types.h" 352865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 362865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 372865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "if_ether.h" 382865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "ip.h" 392865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "rtl871x_byteorder.h" 402865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "wifi.h" 412865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "mlme_osdep.h" 422865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "xmit_osdep.h" 432865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger#include "osdep_intf.h" 442865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 452865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingerstatic uint remainder_len(struct pkt_file *pfile) 462865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 472865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger return (uint)(pfile->buf_len - ((addr_t)(pfile->cur_addr) - 482865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger (addr_t)(pfile->buf_start))); 492865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 502865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 512865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingervoid _r8712_open_pktfile(_pkt *pktptr, struct pkt_file *pfile) 522865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 532865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pfile->pkt = pktptr; 542865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pfile->cur_addr = pfile->buf_start = pktptr->data; 552865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pfile->pkt_len = pfile->buf_len = pktptr->len; 562865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pfile->cur_buffer = pfile->buf_start ; 572865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 582865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 592865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingeruint _r8712_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) 602865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 612865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger uint len; 622865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 632865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger len = remainder_len(pfile); 642865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger len = (rlen > len) ? len : rlen; 652865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (rmem) 662865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, 672865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger rmem, len); 682865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pfile->cur_addr += len; 692865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pfile->pkt_len -= len; 702865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger return len; 712865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 722865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 732865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingersint r8712_endofpktfile(struct pkt_file *pfile) 742865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 752865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (pfile->pkt_len == 0) 762865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger return true; 772865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger else 782865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger return false; 792865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 802865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 812865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 822865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingervoid r8712_set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) 832865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 842865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger int i; 852865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger struct ethhdr etherhdr; 862865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger struct iphdr ip_hdr; 872865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger u16 UserPriority = 0; 882865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 892865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger _r8712_open_pktfile(ppktfile->pkt, ppktfile); 902865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger _r8712_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); 912865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 922865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger /* get UserPriority from IP hdr*/ 932865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (pattrib->ether_type == 0x0800) { 942865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger i = _r8712_pktfile_read(ppktfile, (u8 *)&ip_hdr, 952865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger sizeof(ip_hdr)); 962865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger /*UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3 ;*/ 972865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger UserPriority = ip_hdr.tos >> 5; 982865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } else { 992865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger /* "When priority processing of data frames is supported, 1002865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * a STA's SME should send EAPOL-Key frames at the highest 1012865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger * priority." */ 1022865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 1032865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (pattrib->ether_type == 0x888e) 1042865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger UserPriority = 7; 1052865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1062865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pattrib->priority = UserPriority; 1072865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; 1082865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pattrib->subtype = WIFI_QOS_DATA_TYPE; 1092865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 1102865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 111f95302eed91061d1d9440d572166e46d58d35b7cAli Baharvoid r8712_SetFilter(struct work_struct *work) 112f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar{ 113f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar struct _adapter *padapter = container_of(work, struct _adapter, 114f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar wkFilterRxFF0); 115f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar u8 oldvalue = 0x00, newvalue = 0x00; 116f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar unsigned long irqL; 117f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar 118f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar oldvalue = r8712_read8(padapter, 0x117); 119f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar newvalue = oldvalue & 0xfe; 120f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar r8712_write8(padapter, 0x117, newvalue); 121f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar 122f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar spin_lock_irqsave(&padapter->lockRxFF0Filter, irqL); 123f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar padapter->blnEnableRxFF0Filter = 1; 124f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar spin_unlock_irqrestore(&padapter->lockRxFF0Filter, irqL); 125f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar do { 126f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar msleep(100); 127f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar } while (padapter->blnEnableRxFF0Filter == 1); 128f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar r8712_write8(padapter, 0x117, oldvalue); 129f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar} 130f95302eed91061d1d9440d572166e46d58d35b7cAli Bahar 1312865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingerint r8712_xmit_resource_alloc(struct _adapter *padapter, 1322865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger struct xmit_buf *pxmitbuf) 1332865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 1342865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger int i; 1352865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 1362865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger for (i = 0; i < 8; i++) { 13768e9b249565ef2786eee2b4676c8f04c8154215dAli Bahar pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); 1382865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (pxmitbuf->pxmit_urb[i] == NULL) { 1392865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger printk(KERN_ERR "r8712u: pxmitbuf->pxmit_urb[i]" 1402865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger " == NULL"); 1412865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger return _FAIL; 1422865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1432865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1442865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger return _SUCCESS; 1452865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 1462865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 1472865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingervoid r8712_xmit_resource_free(struct _adapter *padapter, 1482865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger struct xmit_buf *pxmitbuf) 1492865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 1502865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger int i; 1512865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 1522865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger for (i = 0; i < 8; i++) { 1532865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (pxmitbuf->pxmit_urb[i]) { 1542865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger usb_kill_urb(pxmitbuf->pxmit_urb[i]); 1552865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger usb_free_urb(pxmitbuf->pxmit_urb[i]); 1562865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1572865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1582865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 1592865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 1602865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingervoid r8712_xmit_complete(struct _adapter *padapter, struct xmit_frame *pxframe) 1612865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 1622865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (pxframe->pkt) 1632865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger dev_kfree_skb_any(pxframe->pkt); 1642865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pxframe->pkt = NULL; 1652865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 1662865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 1672865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Fingerint r8712_xmit_entry(_pkt *pkt, struct net_device *pnetdev) 1682865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger{ 1692865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger struct xmit_frame *pxmitframe = NULL; 1707c1f4203a2883c50e2d754b176fcfcd5be34549bAli Bahar struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev); 1712865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); 1722865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger int ret = 0; 1732865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger 1742865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (r8712_if_up(padapter) == false) { 1752865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger ret = 0; 1762865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger goto _xmit_entry_drop; 1772865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1782865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pxmitframe = r8712_alloc_xmitframe(pxmitpriv); 1792865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (pxmitframe == NULL) { 1802865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger ret = 0; 1812865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger goto _xmit_entry_drop; 1822865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1832865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if ((!r8712_update_attrib(padapter, pkt, &pxmitframe->attrib))) { 1842865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger ret = 0; 1852865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger goto _xmit_entry_drop; 1862865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1872865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger padapter->ledpriv.LedControlHandler(padapter, LED_CTL_TX); 1882865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pxmitframe->pkt = pkt; 1892865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (r8712_pre_xmit(padapter, pxmitframe) == true) { 1902865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger /*dump xmitframe directly or drop xframe*/ 1912865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger dev_kfree_skb_any(pkt); 1922865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pxmitframe->pkt = NULL; 1932865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger } 1942865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pxmitpriv->tx_pkts++; 1952865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pxmitpriv->tx_bytes += pxmitframe->attrib.last_txcmdsz; 1962865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger return ret; 1972865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger_xmit_entry_drop: 1982865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger if (pxmitframe) 1992865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger r8712_free_xmitframe(pxmitpriv, pxmitframe); 2002865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger pxmitpriv->tx_drop++; 2012865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger dev_kfree_skb_any(pkt); 2022865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger return ret; 2032865d42c78a9121caad52cb02d1fbb7f5cdbc4efLarry Finger} 204