• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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