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
21 struct zero_bulkout_context {
22 void *pbuf;
23 void *purb;
24 void *pirp;
25 void *padapter;
26 };
27
rtl8723au_read_port_cancel(struct rtw_adapter * padapter)28 void 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
usb_write_port23a_complete(struct urb * purb)47 static 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
129 check_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
rtl8723au_write_port(struct rtw_adapter * padapter,u32 addr,u32 cnt,struct xmit_buf * pxmitbuf)141 int 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
229 exit:
230 if (ret != _SUCCESS)
231 rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
232
233 return ret;
234 }
235
rtl8723au_write_port_cancel(struct rtw_adapter * padapter)236 void 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