1/****************************************************************************** 2 * 3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 ******************************************************************************/ 15#define _USB_OPS_LINUX_C_ 16 17#include <drv_types.h> 18#include <usb_ops_linux.h> 19#include <rtw_sreset.h> 20 21struct zero_bulkout_context { 22 void *pbuf; 23 void *purb; 24 void *pirp; 25 void *padapter; 26}; 27 28void rtl8723au_read_port_cancel(struct rtw_adapter *padapter) 29{ 30 struct recv_buf *precvbuf; 31 int i; 32 33 precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; 34 35 DBG_8723A("%s\n", __func__); 36 37 padapter->bReadPortCancel = true; 38 39 for (i = 0; i < NR_RECVBUFF ; i++) { 40 if (precvbuf->purb) 41 usb_kill_urb(precvbuf->purb); 42 precvbuf++; 43 } 44 usb_kill_urb(padapter->recvpriv.int_in_urb); 45} 46 47static void usb_write_port23a_complete(struct urb *purb) 48{ 49 struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; 50 struct rtw_adapter *padapter = pxmitbuf->padapter; 51 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 52 struct hal_data_8723a *phaldata; 53 unsigned long irqL; 54 55 switch (pxmitbuf->flags) { 56 case VO_QUEUE_INX: 57 pxmitpriv->voq_cnt--; 58 break; 59 case VI_QUEUE_INX: 60 pxmitpriv->viq_cnt--; 61 break; 62 case BE_QUEUE_INX: 63 pxmitpriv->beq_cnt--; 64 break; 65 case BK_QUEUE_INX: 66 pxmitpriv->bkq_cnt--; 67 break; 68 case HIGH_QUEUE_INX: 69#ifdef CONFIG_8723AU_AP_MODE 70 rtw_chk_hi_queue_cmd23a(padapter); 71#endif 72 break; 73 default: 74 break; 75 } 76 77 if (padapter->bSurpriseRemoved || padapter->bDriverStopped || 78 padapter->bWritePortCancel) { 79 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, 80 ("usb_write_port23a_complete:bDriverStopped(%d) OR " 81 "bSurpriseRemoved(%d)", padapter->bDriverStopped, 82 padapter->bSurpriseRemoved)); 83 DBG_8723A("%s(): TX Warning! bDriverStopped(%d) OR " 84 "bSurpriseRemoved(%d) bWritePortCancel(%d) " 85 "pxmitbuf->ext_tag(%x)\n", __func__, 86 padapter->bDriverStopped, padapter->bSurpriseRemoved, 87 padapter->bReadPortCancel, pxmitbuf->ext_tag); 88 89 goto check_completion; 90 } 91 92 if (purb->status) { 93 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, 94 ("usb_write_port23a_complete : purb->status(%d) " 95 "!= 0\n", purb->status)); 96 DBG_8723A("###=> urb_write_port_complete status(%d)\n", 97 purb->status); 98 if (purb->status == -EPIPE || purb->status == -EPROTO) { 99 } else if (purb->status == -EINPROGRESS) { 100 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, 101 ("usb_write_port23a_complete: EINPROGESS\n")); 102 goto check_completion; 103 } else if (purb->status == -ENOENT) { 104 DBG_8723A("%s: -ENOENT\n", __func__); 105 goto check_completion; 106 } else if (purb->status == -ECONNRESET) { 107 DBG_8723A("%s: -ECONNRESET\n", __func__); 108 goto check_completion; 109 } else if (purb->status == -ESHUTDOWN) { 110 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, 111 ("usb_write_port23a_complete: ESHUTDOWN\n")); 112 padapter->bDriverStopped = true; 113 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, 114 ("usb_write_port23a_complete:bDriverStopped " 115 "= true\n")); 116 goto check_completion; 117 } else { 118 padapter->bSurpriseRemoved = true; 119 DBG_8723A("bSurpriseRemoved = true\n"); 120 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, 121 ("usb_write_port23a_complete:bSurpriseRemoved " 122 "= true\n")); 123 goto check_completion; 124 } 125 } 126 phaldata = GET_HAL_DATA(padapter); 127 phaldata->srestpriv.last_tx_complete_time = jiffies; 128 129check_completion: 130 spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL); 131 rtw23a_sctx_done_err(&pxmitbuf->sctx, 132 purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : 133 RTW_SCTX_DONE_SUCCESS); 134 spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL); 135 136 rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); 137 138 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); 139} 140 141int rtl8723au_write_port(struct rtw_adapter *padapter, u32 addr, u32 cnt, 142 struct xmit_buf *pxmitbuf) 143{ 144 struct urb *purb = NULL; 145 struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); 146 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 147 struct xmit_frame *pxmitframe; 148 struct usb_device *pusbd = pdvobj->pusbdev; 149 unsigned long irqL; 150 unsigned int pipe, ep_num; 151 int status; 152 int ret = _FAIL; 153 154 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port23a\n")); 155 156 if (padapter->bDriverStopped || padapter->bSurpriseRemoved) { 157 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, 158 ("%s:(padapter->bDriverStopped || " 159 "padapter->bSurpriseRemoved)!!!\n", __func__)); 160 rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); 161 goto exit; 162 } 163 164 pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; 165 spin_lock_irqsave(&pxmitpriv->lock, irqL); 166 167 switch (addr) { 168 case VO_QUEUE_INX: 169 pxmitpriv->voq_cnt++; 170 pxmitbuf->flags = VO_QUEUE_INX; 171 break; 172 case VI_QUEUE_INX: 173 pxmitpriv->viq_cnt++; 174 pxmitbuf->flags = VI_QUEUE_INX; 175 break; 176 case BE_QUEUE_INX: 177 pxmitpriv->beq_cnt++; 178 pxmitbuf->flags = BE_QUEUE_INX; 179 break; 180 case BK_QUEUE_INX: 181 pxmitpriv->bkq_cnt++; 182 pxmitbuf->flags = BK_QUEUE_INX; 183 break; 184 case HIGH_QUEUE_INX: 185 pxmitbuf->flags = HIGH_QUEUE_INX; 186 break; 187 default: 188 pxmitbuf->flags = MGT_QUEUE_INX; 189 break; 190 } 191 192 spin_unlock_irqrestore(&pxmitpriv->lock, irqL); 193 194 purb = pxmitbuf->pxmit_urb[0]; 195 196 /* translate DMA FIFO addr to pipehandle */ 197 ep_num = pdvobj->Queue2Pipe[addr]; 198 pipe = usb_sndbulkpipe(pusbd, ep_num); 199 200 usb_fill_bulk_urb(purb, pusbd, pipe, 201 pxmitframe->buf_addr, /* pxmitbuf->pbuf */ 202 cnt, usb_write_port23a_complete, 203 pxmitbuf);/* context is pxmitbuf */ 204 205 status = usb_submit_urb(purb, GFP_ATOMIC); 206 if (!status) { 207 struct hal_data_8723a *phaldata = GET_HAL_DATA(padapter); 208 phaldata->srestpriv.last_tx_time = jiffies; 209 } else { 210 rtw23a_sctx_done_err(&pxmitbuf->sctx, 211 RTW_SCTX_DONE_WRITE_PORT_ERR); 212 DBG_8723A("usb_write_port23a, status =%d\n", status); 213 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, 214 ("usb_write_port23a(): usb_submit_urb, status =%x\n", 215 status)); 216 217 switch (status) { 218 case -ENODEV: 219 padapter->bDriverStopped = true; 220 break; 221 default: 222 break; 223 } 224 goto exit; 225 } 226 ret = _SUCCESS; 227 RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-usb_write_port23a\n")); 228 229exit: 230 if (ret != _SUCCESS) 231 rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); 232 233 return ret; 234} 235 236void rtl8723au_write_port_cancel(struct rtw_adapter *padapter) 237{ 238 struct xmit_buf *pxmitbuf; 239 struct list_head *plist; 240 int j; 241 242 DBG_8723A("%s\n", __func__); 243 244 padapter->bWritePortCancel = true; 245 246 list_for_each(plist, &padapter->xmitpriv.xmitbuf_list) { 247 pxmitbuf = container_of(plist, struct xmit_buf, list2); 248 for (j = 0; j < 8; j++) { 249 if (pxmitbuf->pxmit_urb[j]) 250 usb_kill_urb(pxmitbuf->pxmit_urb[j]); 251 } 252 } 253 list_for_each(plist, &padapter->xmitpriv.xmitextbuf_list) { 254 pxmitbuf = container_of(plist, struct xmit_buf, list2); 255 for (j = 0; j < 8; j++) { 256 if (pxmitbuf->pxmit_urb[j]) 257 usb_kill_urb(pxmitbuf->pxmit_urb[j]); 258 } 259 } 260} 261