1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2007 - 2012 Realtek Corporation. */
3 
4 #define _USB_OPS_LINUX_C_
5 
6 #include "../include/drv_types.h"
7 #include "../include/usb_ops_linux.h"
8 #include "../include/rtw_sreset.h"
9 
ffaddr2pipehdl(struct dvobj_priv * pdvobj,u32 addr)10 unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
11 {
12 	unsigned int pipe = 0, ep_num = 0;
13 	struct usb_device *pusbd = pdvobj->pusbdev;
14 
15 	if (addr == RECV_BULK_IN_ADDR) {
16 		pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]);
17 	} else if (addr == RECV_INT_IN_ADDR) {
18 		pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]);
19 	} else if (addr < HW_QUEUE_ENTRY) {
20 		ep_num = pdvobj->Queue2Pipe[addr];
21 		pipe = usb_sndbulkpipe(pusbd, ep_num);
22 	}
23 
24 	return pipe;
25 }
26 
27 struct zero_bulkout_context {
28 	void *pbuf;
29 	void *purb;
30 	void *pirp;
31 	void *padapter;
32 };
33 
usb_read_mem(struct intf_hdl * pintfhdl,u32 addr,u32 cnt,u8 * rmem)34 void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
35 {
36 }
37 
usb_write_mem(struct intf_hdl * pintfhdl,u32 addr,u32 cnt,u8 * wmem)38 void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
39 {
40 }
41 
usb_read_port_cancel(struct intf_hdl * pintfhdl)42 void usb_read_port_cancel(struct intf_hdl *pintfhdl)
43 {
44 	int i;
45 	struct recv_buf *precvbuf;
46 	struct adapter	*padapter = pintfhdl->padapter;
47 	precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
48 
49 	DBG_88E("%s\n", __func__);
50 
51 	padapter->bReadPortCancel = true;
52 
53 	for (i = 0; i < NR_RECVBUFF; i++) {
54 		precvbuf->reuse = true;
55 		if (precvbuf->purb)
56 			usb_kill_urb(precvbuf->purb);
57 		precvbuf++;
58 	}
59 }
60 
usb_write_port_complete(struct urb * purb,struct pt_regs * regs)61 static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
62 {
63 	struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
64 	struct adapter	*padapter = pxmitbuf->padapter;
65 	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
66 	struct hal_data_8188e	*haldata;
67 
68 	switch (pxmitbuf->flags) {
69 	case VO_QUEUE_INX:
70 		pxmitpriv->voq_cnt--;
71 		break;
72 	case VI_QUEUE_INX:
73 		pxmitpriv->viq_cnt--;
74 		break;
75 	case BE_QUEUE_INX:
76 		pxmitpriv->beq_cnt--;
77 		break;
78 	case BK_QUEUE_INX:
79 		pxmitpriv->bkq_cnt--;
80 		break;
81 	case HIGH_QUEUE_INX:
82 #ifdef CONFIG_88EU_AP_MODE
83 		rtw_chk_hi_queue_cmd(padapter);
84 #endif
85 		break;
86 	default:
87 		break;
88 	}
89 
90 	if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
91 	    padapter->bWritePortCancel) {
92 		DBG_88E("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n",
93 			__func__, padapter->bDriverStopped,
94 			padapter->bSurpriseRemoved, padapter->bReadPortCancel,
95 			pxmitbuf->ext_tag);
96 
97 		goto check_completion;
98 	}
99 
100 	if (purb->status) {
101 		DBG_88E("###=> urb_write_port_complete status(%d)\n", purb->status);
102 		if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) {
103 			sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL);
104 		} else if (purb->status == -EINPROGRESS) {
105 			goto check_completion;
106 		} else if (purb->status == -ENOENT) {
107 			DBG_88E("%s: -ENOENT\n", __func__);
108 			goto check_completion;
109 		} else if (purb->status == -ECONNRESET) {
110 			DBG_88E("%s: -ECONNRESET\n", __func__);
111 			goto check_completion;
112 		} else if (purb->status == -ESHUTDOWN) {
113 			padapter->bDriverStopped = true;
114 			goto check_completion;
115 		} else {
116 			padapter->bSurpriseRemoved = true;
117 			DBG_88E("bSurpriseRemoved = true\n");
118 
119 			goto check_completion;
120 		}
121 	}
122 
123 	haldata = GET_HAL_DATA(padapter);
124 	haldata->srestpriv.last_tx_complete_time = jiffies;
125 
126 check_completion:
127 	rtw_sctx_done_err(&pxmitbuf->sctx,
128 			  purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR :
129 			  RTW_SCTX_DONE_SUCCESS);
130 
131 	rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
132 
133 	tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
134 
135 }
136 
usb_write_port(struct intf_hdl * pintfhdl,u32 addr,u32 cnt,u8 * wmem)137 u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
138 {
139 	unsigned long irqL;
140 	unsigned int pipe;
141 	int status;
142 	u32 ret = _FAIL;
143 	struct urb *purb = NULL;
144 	struct adapter *padapter = (struct adapter *)pintfhdl->padapter;
145 	struct dvobj_priv	*pdvobj = adapter_to_dvobj(padapter);
146 	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
147 	struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem;
148 	struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
149 	struct usb_device *pusbd = pdvobj->pusbdev;
150 
151 	if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||
152 	    (padapter->pwrctrlpriv.pnp_bstop_trx)) {
153 		rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
154 		goto exit;
155 	}
156 
157 	spin_lock_irqsave(&pxmitpriv->lock, irqL);
158 
159 	switch (addr) {
160 	case VO_QUEUE_INX:
161 		pxmitpriv->voq_cnt++;
162 		pxmitbuf->flags = VO_QUEUE_INX;
163 		break;
164 	case VI_QUEUE_INX:
165 		pxmitpriv->viq_cnt++;
166 		pxmitbuf->flags = VI_QUEUE_INX;
167 		break;
168 	case BE_QUEUE_INX:
169 		pxmitpriv->beq_cnt++;
170 		pxmitbuf->flags = BE_QUEUE_INX;
171 		break;
172 	case BK_QUEUE_INX:
173 		pxmitpriv->bkq_cnt++;
174 		pxmitbuf->flags = BK_QUEUE_INX;
175 		break;
176 	case HIGH_QUEUE_INX:
177 		pxmitbuf->flags = HIGH_QUEUE_INX;
178 		break;
179 	default:
180 		pxmitbuf->flags = MGT_QUEUE_INX;
181 		break;
182 	}
183 
184 	spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
185 
186 	purb	= pxmitbuf->pxmit_urb[0];
187 
188 	/* translate DMA FIFO addr to pipehandle */
189 	pipe = ffaddr2pipehdl(pdvobj, addr);
190 
191 	usb_fill_bulk_urb(purb, pusbd, pipe,
192 			  pxmitframe->buf_addr, /*  pxmitbuf->pbuf */
193 			  cnt,
194 			  usb_write_port_complete,
195 			  pxmitbuf);/* context is pxmitbuf */
196 
197 	status = usb_submit_urb(purb, GFP_ATOMIC);
198 	if (!status) {
199 		struct hal_data_8188e	*haldata = GET_HAL_DATA(padapter);
200 
201 		haldata->srestpriv.last_tx_time = jiffies;
202 	} else {
203 		rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
204 		DBG_88E("usb_write_port, status =%d\n", status);
205 
206 		switch (status) {
207 		case -ENODEV:
208 			padapter->bDriverStopped = true;
209 			break;
210 		default:
211 			break;
212 		}
213 		goto exit;
214 	}
215 
216 	ret = _SUCCESS;
217 
218 /*    We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */
219 
220 exit:
221 	if (ret != _SUCCESS)
222 		rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
223 
224 	return ret;
225 }
226 
usb_write_port_cancel(struct intf_hdl * pintfhdl)227 void usb_write_port_cancel(struct intf_hdl *pintfhdl)
228 {
229 	int i, j;
230 	struct adapter	*padapter = pintfhdl->padapter;
231 	struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
232 
233 	DBG_88E("%s\n", __func__);
234 
235 	padapter->bWritePortCancel = true;
236 
237 	for (i = 0; i < NR_XMITBUFF; i++) {
238 		for (j = 0; j < 8; j++) {
239 			if (pxmitbuf->pxmit_urb[j])
240 				usb_kill_urb(pxmitbuf->pxmit_urb[j]);
241 		}
242 		pxmitbuf++;
243 	}
244 
245 	pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf;
246 	for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
247 		for (j = 0; j < 8; j++) {
248 			if (pxmitbuf->pxmit_urb[j])
249 				usb_kill_urb(pxmitbuf->pxmit_urb[j]);
250 		}
251 		pxmitbuf++;
252 	}
253 }
254