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 *)&etherhdr, 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