1/****************************************************************************** 2 * xmit_linux.c 3 * 4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 5 * Linux device driver for RTL8192SU 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of version 2 of the GNU General Public License as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 19 * 20 * Modifications for inclusion into the Linux staging tree are 21 * Copyright(c) 2010 Larry Finger. All rights reserved. 22 * 23 * Contact information: 24 * WLAN FAE <wlanfae@realtek.com> 25 * Larry Finger <Larry.Finger@lwfinger.net> 26 * 27 ******************************************************************************/ 28 29#define _XMIT_OSDEP_C_ 30 31#include <linux/usb.h> 32#include <linux/ip.h> 33#include <linux/if_ether.h> 34 35#include "osdep_service.h" 36#include "drv_types.h" 37 38#include "wifi.h" 39#include "mlme_osdep.h" 40#include "xmit_osdep.h" 41#include "osdep_intf.h" 42 43static uint remainder_len(struct pkt_file *pfile) 44{ 45 return (uint)(pfile->buf_len - ((addr_t)(pfile->cur_addr) - 46 (addr_t)(pfile->buf_start))); 47} 48 49void _r8712_open_pktfile(_pkt *pktptr, struct pkt_file *pfile) 50{ 51 pfile->pkt = pktptr; 52 pfile->cur_addr = pfile->buf_start = pktptr->data; 53 pfile->pkt_len = pfile->buf_len = pktptr->len; 54 pfile->cur_buffer = pfile->buf_start; 55} 56 57uint _r8712_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) 58{ 59 uint len; 60 61 len = remainder_len(pfile); 62 len = (rlen > len) ? len : rlen; 63 if (rmem) 64 skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, 65 rmem, len); 66 pfile->cur_addr += len; 67 pfile->pkt_len -= len; 68 return len; 69} 70 71sint r8712_endofpktfile(struct pkt_file *pfile) 72{ 73 if (pfile->pkt_len == 0) 74 return true; 75 else 76 return false; 77} 78 79 80void r8712_set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) 81{ 82 int i; 83 struct ethhdr etherhdr; 84 struct iphdr ip_hdr; 85 u16 UserPriority = 0; 86 87 _r8712_open_pktfile(ppktfile->pkt, ppktfile); 88 _r8712_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); 89 90 /* get UserPriority from IP hdr*/ 91 if (pattrib->ether_type == 0x0800) { 92 i = _r8712_pktfile_read(ppktfile, (u8 *)&ip_hdr, 93 sizeof(ip_hdr)); 94 /*UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3 ;*/ 95 UserPriority = ip_hdr.tos >> 5; 96 } else { 97 /* "When priority processing of data frames is supported, 98 * a STA's SME should send EAPOL-Key frames at the highest 99 * priority." */ 100 101 if (pattrib->ether_type == 0x888e) 102 UserPriority = 7; 103 } 104 pattrib->priority = UserPriority; 105 pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; 106 pattrib->subtype = WIFI_QOS_DATA_TYPE; 107} 108 109void r8712_SetFilter(struct work_struct *work) 110{ 111 struct _adapter *padapter = container_of(work, struct _adapter, 112 wkFilterRxFF0); 113 u8 oldvalue = 0x00, newvalue = 0x00; 114 unsigned long irqL; 115 116 oldvalue = r8712_read8(padapter, 0x117); 117 newvalue = oldvalue & 0xfe; 118 r8712_write8(padapter, 0x117, newvalue); 119 120 spin_lock_irqsave(&padapter->lockRxFF0Filter, irqL); 121 padapter->blnEnableRxFF0Filter = 1; 122 spin_unlock_irqrestore(&padapter->lockRxFF0Filter, irqL); 123 do { 124 msleep(100); 125 } while (padapter->blnEnableRxFF0Filter == 1); 126 r8712_write8(padapter, 0x117, oldvalue); 127} 128 129int r8712_xmit_resource_alloc(struct _adapter *padapter, 130 struct xmit_buf *pxmitbuf) 131{ 132 int i; 133 134 for (i = 0; i < 8; i++) { 135 pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); 136 if (pxmitbuf->pxmit_urb[i] == NULL) { 137 netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n"); 138 return _FAIL; 139 } 140 } 141 return _SUCCESS; 142} 143 144void r8712_xmit_resource_free(struct _adapter *padapter, 145 struct xmit_buf *pxmitbuf) 146{ 147 int i; 148 149 for (i = 0; i < 8; i++) { 150 if (pxmitbuf->pxmit_urb[i]) { 151 usb_kill_urb(pxmitbuf->pxmit_urb[i]); 152 usb_free_urb(pxmitbuf->pxmit_urb[i]); 153 } 154 } 155} 156 157void r8712_xmit_complete(struct _adapter *padapter, struct xmit_frame *pxframe) 158{ 159 if (pxframe->pkt) 160 dev_kfree_skb_any(pxframe->pkt); 161 pxframe->pkt = NULL; 162} 163 164int r8712_xmit_entry(_pkt *pkt, struct net_device *pnetdev) 165{ 166 struct xmit_frame *pxmitframe = NULL; 167 struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev); 168 struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); 169 int ret = 0; 170 171 if (r8712_if_up(padapter) == false) { 172 ret = 0; 173 goto _xmit_entry_drop; 174 } 175 pxmitframe = r8712_alloc_xmitframe(pxmitpriv); 176 if (pxmitframe == NULL) { 177 ret = 0; 178 goto _xmit_entry_drop; 179 } 180 if ((!r8712_update_attrib(padapter, pkt, &pxmitframe->attrib))) { 181 ret = 0; 182 goto _xmit_entry_drop; 183 } 184 padapter->ledpriv.LedControlHandler(padapter, LED_CTL_TX); 185 pxmitframe->pkt = pkt; 186 if (r8712_pre_xmit(padapter, pxmitframe) == true) { 187 /*dump xmitframe directly or drop xframe*/ 188 dev_kfree_skb_any(pkt); 189 pxmitframe->pkt = NULL; 190 } 191 pxmitpriv->tx_pkts++; 192 pxmitpriv->tx_bytes += pxmitframe->attrib.last_txcmdsz; 193 return ret; 194_xmit_entry_drop: 195 if (pxmitframe) 196 r8712_free_xmitframe(pxmitpriv, pxmitframe); 197 pxmitpriv->tx_drop++; 198 dev_kfree_skb_any(pkt); 199 return ret; 200} 201