[go: nahoru, domu]

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