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 struct ethhdr etherhdr; 83 struct iphdr ip_hdr; 84 u16 UserPriority = 0; 85 86 _r8712_open_pktfile(ppktfile->pkt, ppktfile); 87 _r8712_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); 88 89 /* get UserPriority from IP hdr*/ 90 if (pattrib->ether_type == 0x0800) { 91 _r8712_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); 92 /*UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3 ;*/ 93 UserPriority = ip_hdr.tos >> 5; 94 } else { 95 /* "When priority processing of data frames is supported, 96 * a STA's SME should send EAPOL-Key frames at the highest 97 * priority." */ 98 99 if (pattrib->ether_type == 0x888e) 100 UserPriority = 7; 101 } 102 pattrib->priority = UserPriority; 103 pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; 104 pattrib->subtype = WIFI_QOS_DATA_TYPE; 105} 106 107void r8712_SetFilter(struct work_struct *work) 108{ 109 struct _adapter *padapter = container_of(work, struct _adapter, 110 wkFilterRxFF0); 111 u8 oldvalue = 0x00, newvalue = 0x00; 112 unsigned long irqL; 113 114 oldvalue = r8712_read8(padapter, 0x117); 115 newvalue = oldvalue & 0xfe; 116 r8712_write8(padapter, 0x117, newvalue); 117 118 spin_lock_irqsave(&padapter->lockRxFF0Filter, irqL); 119 padapter->blnEnableRxFF0Filter = 1; 120 spin_unlock_irqrestore(&padapter->lockRxFF0Filter, irqL); 121 do { 122 msleep(100); 123 } while (padapter->blnEnableRxFF0Filter == 1); 124 r8712_write8(padapter, 0x117, oldvalue); 125} 126 127int r8712_xmit_resource_alloc(struct _adapter *padapter, 128 struct xmit_buf *pxmitbuf) 129{ 130 int i; 131 132 for (i = 0; i < 8; i++) { 133 pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); 134 if (pxmitbuf->pxmit_urb[i] == NULL) { 135 netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n"); 136 return _FAIL; 137 } 138 } 139 return _SUCCESS; 140} 141 142void r8712_xmit_resource_free(struct _adapter *padapter, 143 struct xmit_buf *pxmitbuf) 144{ 145 int i; 146 147 for (i = 0; i < 8; i++) { 148 if (pxmitbuf->pxmit_urb[i]) { 149 usb_kill_urb(pxmitbuf->pxmit_urb[i]); 150 usb_free_urb(pxmitbuf->pxmit_urb[i]); 151 } 152 } 153} 154 155void r8712_xmit_complete(struct _adapter *padapter, struct xmit_frame *pxframe) 156{ 157 if (pxframe->pkt) 158 dev_kfree_skb_any(pxframe->pkt); 159 pxframe->pkt = NULL; 160} 161 162int r8712_xmit_entry(_pkt *pkt, struct net_device *pnetdev) 163{ 164 struct xmit_frame *pxmitframe = NULL; 165 struct _adapter *padapter = netdev_priv(pnetdev); 166 struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); 167 int ret = 0; 168 169 if (r8712_if_up(padapter) == false) { 170 ret = 0; 171 goto _xmit_entry_drop; 172 } 173 pxmitframe = r8712_alloc_xmitframe(pxmitpriv); 174 if (pxmitframe == NULL) { 175 ret = 0; 176 goto _xmit_entry_drop; 177 } 178 if ((!r8712_update_attrib(padapter, pkt, &pxmitframe->attrib))) { 179 ret = 0; 180 goto _xmit_entry_drop; 181 } 182 padapter->ledpriv.LedControlHandler(padapter, LED_CTL_TX); 183 pxmitframe->pkt = pkt; 184 if (r8712_pre_xmit(padapter, pxmitframe) == true) { 185 /*dump xmitframe directly or drop xframe*/ 186 dev_kfree_skb_any(pkt); 187 pxmitframe->pkt = NULL; 188 } 189 pxmitpriv->tx_pkts++; 190 pxmitpriv->tx_bytes += pxmitframe->attrib.last_txcmdsz; 191 return ret; 192_xmit_entry_drop: 193 if (pxmitframe) 194 r8712_free_xmitframe(pxmitpriv, pxmitframe); 195 pxmitpriv->tx_drop++; 196 dev_kfree_skb_any(pkt); 197 return ret; 198} 199