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 #include <linux/kmemleak.h> 35 36 #include "osdep_service.h" 37 #include "drv_types.h" 38 39 #include "wifi.h" 40 #include "mlme_osdep.h" 41 #include "xmit_osdep.h" 42 #include "osdep_intf.h" 43 44 static uint remainder_len(struct pkt_file *pfile) 45 { 46 return (uint)(pfile->buf_len - ((addr_t)(pfile->cur_addr) - 47 (addr_t)(pfile->buf_start))); 48 } 49 50 void _r8712_open_pktfile(_pkt *pktptr, struct pkt_file *pfile) 51 { 52 pfile->pkt = pktptr; 53 pfile->cur_addr = pfile->buf_start = pktptr->data; 54 pfile->pkt_len = pfile->buf_len = pktptr->len; 55 pfile->cur_buffer = pfile->buf_start; 56 } 57 58 uint _r8712_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) 59 { 60 uint len; 61 62 len = remainder_len(pfile); 63 len = (rlen > len) ? len : rlen; 64 if (rmem) 65 skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, 66 rmem, len); 67 pfile->cur_addr += len; 68 pfile->pkt_len -= len; 69 return len; 70 } 71 72 sint r8712_endofpktfile(struct pkt_file *pfile) 73 { 74 return (pfile->pkt_len == 0); 75 } 76 77 78 void r8712_set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) 79 { 80 struct ethhdr etherhdr; 81 struct iphdr ip_hdr; 82 u16 UserPriority = 0; 83 84 _r8712_open_pktfile(ppktfile->pkt, ppktfile); 85 _r8712_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); 86 87 /* get UserPriority from IP hdr*/ 88 if (pattrib->ether_type == 0x0800) { 89 _r8712_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); 90 /*UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3 ;*/ 91 UserPriority = ip_hdr.tos >> 5; 92 } else { 93 /* "When priority processing of data frames is supported, 94 * a STA's SME should send EAPOL-Key frames at the highest 95 * priority." 96 */ 97 98 if (pattrib->ether_type == 0x888e) 99 UserPriority = 7; 100 } 101 pattrib->priority = UserPriority; 102 pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; 103 pattrib->subtype = WIFI_QOS_DATA_TYPE; 104 } 105 106 void r8712_SetFilter(struct work_struct *work) 107 { 108 struct _adapter *padapter = container_of(work, struct _adapter, 109 wkFilterRxFF0); 110 u8 oldvalue = 0x00, newvalue = 0x00; 111 unsigned long irqL; 112 113 oldvalue = r8712_read8(padapter, 0x117); 114 newvalue = oldvalue & 0xfe; 115 r8712_write8(padapter, 0x117, newvalue); 116 117 spin_lock_irqsave(&padapter->lockRxFF0Filter, irqL); 118 padapter->blnEnableRxFF0Filter = 1; 119 spin_unlock_irqrestore(&padapter->lockRxFF0Filter, irqL); 120 do { 121 msleep(100); 122 } while (padapter->blnEnableRxFF0Filter == 1); 123 r8712_write8(padapter, 0x117, oldvalue); 124 } 125 126 int r8712_xmit_resource_alloc(struct _adapter *padapter, 127 struct xmit_buf *pxmitbuf) 128 { 129 int i; 130 131 for (i = 0; i < 8; i++) { 132 pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); 133 if (!pxmitbuf->pxmit_urb[i]) { 134 netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n"); 135 return _FAIL; 136 } 137 kmemleak_not_leak(pxmitbuf->pxmit_urb[i]); 138 } 139 return _SUCCESS; 140 } 141 142 void 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 155 void 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 162 int 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 168 if (!r8712_if_up(padapter)) 169 goto _xmit_entry_drop; 170 171 pxmitframe = r8712_alloc_xmitframe(pxmitpriv); 172 if (!pxmitframe) 173 goto _xmit_entry_drop; 174 175 if ((!r8712_update_attrib(padapter, pkt, &pxmitframe->attrib))) 176 goto _xmit_entry_drop; 177 178 padapter->ledpriv.LedControlHandler(padapter, LED_CTL_TX); 179 pxmitframe->pkt = pkt; 180 if (r8712_pre_xmit(padapter, pxmitframe)) { 181 /*dump xmitframe directly or drop xframe*/ 182 dev_kfree_skb_any(pkt); 183 pxmitframe->pkt = NULL; 184 } 185 pxmitpriv->tx_pkts++; 186 pxmitpriv->tx_bytes += pxmitframe->attrib.last_txcmdsz; 187 return 0; 188 _xmit_entry_drop: 189 if (pxmitframe) 190 r8712_free_xmitframe(pxmitpriv, pxmitframe); 191 pxmitpriv->tx_drop++; 192 dev_kfree_skb_any(pkt); 193 return 0; 194 } 195