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 
rtl8723au_read_port_cancel(struct rtw_adapter * padapter)21 void rtl8723au_read_port_cancel(struct rtw_adapter *padapter)
22 {
23 	struct recv_buf *precvbuf;
24 	int i;
25 
26 	precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
27 
28 	DBG_8723A("%s\n", __func__);
29 
30 	padapter->bReadPortCancel = true;
31 
32 	for (i = 0; i < NR_RECVBUFF ; i++) {
33 		if (precvbuf->purb)
34 			usb_kill_urb(precvbuf->purb);
35 		precvbuf++;
36 	}
37 	usb_kill_urb(padapter->recvpriv.int_in_urb);
38 }
39 
usb_write_port23a_complete(struct urb * purb)40 static void usb_write_port23a_complete(struct urb *purb)
41 {
42 	struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
43 	struct rtw_adapter *padapter = pxmitbuf->padapter;
44 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
45 	struct hal_data_8723a *phaldata;
46 	unsigned long irqL;
47 
48 	switch (pxmitbuf->flags) {
49 	case HIGH_QUEUE_INX:
50 #ifdef CONFIG_8723AU_AP_MODE
51 		rtw_chk_hi_queue_cmd23a(padapter);
52 #endif
53 		break;
54 	default:
55 		break;
56 	}
57 
58 	if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
59 	    padapter->bWritePortCancel) {
60 		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
61 			 "usb_write_port23a_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n",
62 			 padapter->bDriverStopped, padapter->bSurpriseRemoved);
63 		DBG_8723A("%s(): TX Warning! bDriverStopped(%d) OR "
64 			  "bSurpriseRemoved(%d) bWritePortCancel(%d) "
65 			  "pxmitbuf->ext_tag(%x)\n", __func__,
66 			  padapter->bDriverStopped, padapter->bSurpriseRemoved,
67 			  padapter->bReadPortCancel, pxmitbuf->ext_tag);
68 
69 		goto check_completion;
70 	}
71 
72 	if (purb->status) {
73 		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
74 			 "usb_write_port23a_complete : purb->status(%d) != 0\n",
75 			 purb->status);
76 		DBG_8723A("###=> urb_write_port_complete status(%d)\n",
77 			  purb->status);
78 		if (purb->status == -EPIPE || purb->status == -EPROTO) {
79 		} else if (purb->status == -EINPROGRESS) {
80 			RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
81 				 "usb_write_port23a_complete: EINPROGESS\n");
82 			goto check_completion;
83 		} else if (purb->status == -ENOENT) {
84 			DBG_8723A("%s: -ENOENT\n", __func__);
85 			goto check_completion;
86 		} else if (purb->status == -ECONNRESET) {
87 			DBG_8723A("%s: -ECONNRESET\n", __func__);
88 			goto check_completion;
89 		} else if (purb->status == -ESHUTDOWN) {
90 			RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
91 				 "usb_write_port23a_complete: ESHUTDOWN\n");
92 			padapter->bDriverStopped = true;
93 			RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
94 				 "usb_write_port23a_complete:bDriverStopped = true\n");
95 			goto check_completion;
96 		} else {
97 			padapter->bSurpriseRemoved = true;
98 			DBG_8723A("bSurpriseRemoved = true\n");
99 			RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
100 				 "usb_write_port23a_complete:bSurpriseRemoved = true\n");
101 			goto check_completion;
102 		}
103 	}
104 	phaldata = GET_HAL_DATA(padapter);
105 	phaldata->srestpriv.last_tx_complete_time = jiffies;
106 
107 check_completion:
108 	spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL);
109 	rtw23a_sctx_done_err(&pxmitbuf->sctx,
110 			     purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR :
111 			     RTW_SCTX_DONE_SUCCESS);
112 	spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL);
113 
114 	rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
115 
116 	tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
117 }
118 
rtl8723au_write_port(struct rtw_adapter * padapter,u32 addr,u32 cnt,struct xmit_buf * pxmitbuf)119 int rtl8723au_write_port(struct rtw_adapter *padapter, u32 addr, u32 cnt,
120 			 struct xmit_buf *pxmitbuf)
121 {
122 	struct urb *purb = NULL;
123 	struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
124 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
125 	struct xmit_frame *pxmitframe;
126 	struct usb_device *pusbd = pdvobj->pusbdev;
127 	unsigned long irqL;
128 	unsigned int pipe, ep_num;
129 	int status;
130 	int ret = _FAIL;
131 
132 	RT_TRACE(_module_hci_ops_os_c_, _drv_err_, "+usb_write_port23a\n");
133 
134 	if (padapter->bDriverStopped || padapter->bSurpriseRemoved) {
135 		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
136 			 "%s:(padapter->bDriverStopped || padapter->bSurpriseRemoved)!!!\n",
137 			 __func__);
138 		rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
139 		goto exit;
140 	}
141 
142 	pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
143 	spin_lock_irqsave(&pxmitpriv->lock, irqL);
144 
145 	switch (addr) {
146 	case VO_QUEUE_INX:
147 		pxmitbuf->flags = VO_QUEUE_INX;
148 		break;
149 	case VI_QUEUE_INX:
150 		pxmitbuf->flags = VI_QUEUE_INX;
151 		break;
152 	case BE_QUEUE_INX:
153 		pxmitbuf->flags = BE_QUEUE_INX;
154 		break;
155 	case BK_QUEUE_INX:
156 		pxmitbuf->flags = BK_QUEUE_INX;
157 		break;
158 	case HIGH_QUEUE_INX:
159 		pxmitbuf->flags = HIGH_QUEUE_INX;
160 		break;
161 	default:
162 		pxmitbuf->flags = MGT_QUEUE_INX;
163 		break;
164 	}
165 
166 	spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
167 
168 	purb = pxmitbuf->pxmit_urb[0];
169 
170 	/* translate DMA FIFO addr to pipehandle */
171 	ep_num = pdvobj->Queue2Pipe[addr];
172 	pipe = usb_sndbulkpipe(pusbd, ep_num);
173 
174 	usb_fill_bulk_urb(purb, pusbd, pipe,
175 			  pxmitframe->buf_addr, /*  pxmitbuf->pbuf */
176 			  cnt, usb_write_port23a_complete,
177 			  pxmitbuf);/* context is pxmitbuf */
178 
179 	status = usb_submit_urb(purb, GFP_ATOMIC);
180 	if (!status) {
181 		struct hal_data_8723a *phaldata = GET_HAL_DATA(padapter);
182 		phaldata->srestpriv.last_tx_time = jiffies;
183 	} else {
184 		rtw23a_sctx_done_err(&pxmitbuf->sctx,
185 				     RTW_SCTX_DONE_WRITE_PORT_ERR);
186 		DBG_8723A("usb_write_port23a, status =%d\n", status);
187 		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
188 			 "usb_write_port23a(): usb_submit_urb, status =%x\n",
189 			 status);
190 
191 		switch (status) {
192 		case -ENODEV:
193 			padapter->bDriverStopped = true;
194 			break;
195 		default:
196 			break;
197 		}
198 		goto exit;
199 	}
200 	ret = _SUCCESS;
201 	RT_TRACE(_module_hci_ops_os_c_, _drv_err_, "-usb_write_port23a\n");
202 
203 exit:
204 	if (ret != _SUCCESS)
205 		rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
206 
207 	return ret;
208 }
209 
rtl8723au_write_port_cancel(struct rtw_adapter * padapter)210 void rtl8723au_write_port_cancel(struct rtw_adapter *padapter)
211 {
212 	struct xmit_buf *pxmitbuf;
213 	struct list_head *plist;
214 	int j;
215 
216 	DBG_8723A("%s\n", __func__);
217 
218 	padapter->bWritePortCancel = true;
219 
220 	list_for_each(plist, &padapter->xmitpriv.xmitbuf_list) {
221 		pxmitbuf = container_of(plist, struct xmit_buf, list2);
222 		for (j = 0; j < 8; j++) {
223 			if (pxmitbuf->pxmit_urb[j])
224 				usb_kill_urb(pxmitbuf->pxmit_urb[j]);
225 		}
226 	}
227 	list_for_each(plist, &padapter->xmitpriv.xmitextbuf_list) {
228 		pxmitbuf = container_of(plist, struct xmit_buf, list2);
229 		for (j = 0; j < 8; j++) {
230 			if (pxmitbuf->pxmit_urb[j])
231 				usb_kill_urb(pxmitbuf->pxmit_urb[j]);
232 		}
233 	}
234 }
235