1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  * usb_ops_linux.c
4  *
5  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
6  * Linux device driver for RTL8192SU
7  *
8  * Modifications for inclusion into the Linux staging tree are
9  * Copyright(c) 2010 Larry Finger. All rights reserved.
10  *
11  * Contact information:
12  * WLAN FAE <wlanfae@realtek.com>
13  * Larry Finger <Larry.Finger@lwfinger.net>
14  *
15  ******************************************************************************/
16 
17 #define _HCI_OPS_OS_C_
18 
19 #include <linux/usb.h>
20 
21 #include "osdep_service.h"
22 #include "drv_types.h"
23 #include "osdep_intf.h"
24 #include "usb_ops.h"
25 
26 #define	RTL871X_VENQT_READ	0xc0
27 #define	RTL871X_VENQT_WRITE	0x40
28 
r8712_usb_init_intf_priv(struct intf_priv * pintfpriv)29 uint r8712_usb_init_intf_priv(struct intf_priv *pintfpriv)
30 {
31 	pintfpriv->piorw_urb = usb_alloc_urb(0, GFP_ATOMIC);
32 	if (!pintfpriv->piorw_urb)
33 		return _FAIL;
34 	init_completion(&pintfpriv->io_retevt_comp);
35 	return _SUCCESS;
36 }
37 
r8712_usb_unload_intf_priv(struct intf_priv * pintfpriv)38 void r8712_usb_unload_intf_priv(struct intf_priv *pintfpriv)
39 {
40 	if (pintfpriv->piorw_urb) {
41 		usb_kill_urb(pintfpriv->piorw_urb);
42 		usb_free_urb(pintfpriv->piorw_urb);
43 	}
44 }
45 
ffaddr2pipehdl(struct dvobj_priv * pdvobj,u32 addr)46 static unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
47 {
48 	unsigned int pipe = 0;
49 	struct usb_device *pusbd = pdvobj->pusbdev;
50 
51 	if (pdvobj->nr_endpoint == 11) {
52 		switch (addr) {
53 		case RTL8712_DMA_BKQ:
54 			pipe = usb_sndbulkpipe(pusbd, 0x07);
55 			break;
56 		case RTL8712_DMA_BEQ:
57 			pipe = usb_sndbulkpipe(pusbd, 0x06);
58 			break;
59 		case RTL8712_DMA_VIQ:
60 			pipe = usb_sndbulkpipe(pusbd, 0x05);
61 			break;
62 		case RTL8712_DMA_VOQ:
63 			pipe = usb_sndbulkpipe(pusbd, 0x04);
64 			break;
65 		case RTL8712_DMA_BCNQ:
66 			pipe = usb_sndbulkpipe(pusbd, 0x0a);
67 			break;
68 		case RTL8712_DMA_BMCQ:	/* HI Queue */
69 			pipe = usb_sndbulkpipe(pusbd, 0x0b);
70 			break;
71 		case RTL8712_DMA_MGTQ:
72 			pipe = usb_sndbulkpipe(pusbd, 0x0c);
73 			break;
74 		case RTL8712_DMA_RX0FF:
75 			pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */
76 			break;
77 		case RTL8712_DMA_C2HCMD:
78 			pipe = usb_rcvbulkpipe(pusbd, 0x09); /* in */
79 			break;
80 		case RTL8712_DMA_H2CCMD:
81 			pipe = usb_sndbulkpipe(pusbd, 0x0d);
82 			break;
83 		}
84 	} else if (pdvobj->nr_endpoint == 6) {
85 		switch (addr) {
86 		case RTL8712_DMA_BKQ:
87 			pipe = usb_sndbulkpipe(pusbd, 0x07);
88 			break;
89 		case RTL8712_DMA_BEQ:
90 			pipe = usb_sndbulkpipe(pusbd, 0x06);
91 			break;
92 		case RTL8712_DMA_VIQ:
93 			pipe = usb_sndbulkpipe(pusbd, 0x05);
94 			break;
95 		case RTL8712_DMA_VOQ:
96 			pipe = usb_sndbulkpipe(pusbd, 0x04);
97 			break;
98 		case RTL8712_DMA_RX0FF:
99 		case RTL8712_DMA_C2HCMD:
100 			pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */
101 			break;
102 		case RTL8712_DMA_H2CCMD:
103 		case RTL8712_DMA_BCNQ:
104 		case RTL8712_DMA_BMCQ:
105 		case RTL8712_DMA_MGTQ:
106 			pipe = usb_sndbulkpipe(pusbd, 0x0d);
107 			break;
108 		}
109 	} else if (pdvobj->nr_endpoint == 4) {
110 		switch (addr) {
111 		case RTL8712_DMA_BEQ:
112 			pipe = usb_sndbulkpipe(pusbd, 0x06);
113 			break;
114 		case RTL8712_DMA_VOQ:
115 			pipe = usb_sndbulkpipe(pusbd, 0x04);
116 			break;
117 		case RTL8712_DMA_RX0FF:
118 		case RTL8712_DMA_C2HCMD:
119 			pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */
120 			break;
121 		case RTL8712_DMA_H2CCMD:
122 		case RTL8712_DMA_BCNQ:
123 		case RTL8712_DMA_BMCQ:
124 		case RTL8712_DMA_MGTQ:
125 			pipe = usb_sndbulkpipe(pusbd, 0x0d);
126 			break;
127 		}
128 	} else {
129 		pipe = 0;
130 	}
131 	return pipe;
132 }
133 
usb_write_mem_complete(struct urb * purb)134 static void usb_write_mem_complete(struct urb *purb)
135 {
136 	struct io_queue *pio_q = (struct io_queue *)purb->context;
137 	struct intf_hdl *pintf = &(pio_q->intf);
138 	struct intf_priv *pintfpriv = pintf->pintfpriv;
139 	struct _adapter *padapter = (struct _adapter *)pintf->adapter;
140 
141 	if (purb->status != 0) {
142 		if (purb->status == (-ESHUTDOWN))
143 			padapter->driver_stopped = true;
144 		else
145 			padapter->surprise_removed = true;
146 	}
147 	complete(&pintfpriv->io_retevt_comp);
148 }
149 
r8712_usb_write_mem(struct intf_hdl * pintfhdl,u32 addr,u32 cnt,u8 * wmem)150 void r8712_usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
151 {
152 	unsigned int pipe;
153 	struct _adapter *padapter = (struct _adapter *)pintfhdl->adapter;
154 	struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
155 	struct io_queue *pio_queue = padapter->pio_queue;
156 	struct dvobj_priv *pdvobj = (struct dvobj_priv *)pintfpriv->intf_dev;
157 	struct usb_device *pusbd = pdvobj->pusbdev;
158 	struct urb *piorw_urb = pintfpriv->piorw_urb;
159 
160 	if ((padapter->driver_stopped) || (padapter->surprise_removed) ||
161 	    (padapter->pwrctrlpriv.pnp_bstop_trx))
162 		return;
163 	/* translate DMA FIFO addr to pipehandle */
164 	pipe = ffaddr2pipehdl(pdvobj, addr);
165 	if (pipe == 0)
166 		return;
167 	usb_fill_bulk_urb(piorw_urb, pusbd, pipe,
168 			  wmem, cnt, usb_write_mem_complete,
169 			  pio_queue);
170 	usb_submit_urb(piorw_urb, GFP_ATOMIC);
171 	wait_for_completion_interruptible(&pintfpriv->io_retevt_comp);
172 }
173 
r8712_usb_read_port_complete(struct urb * purb)174 static void r8712_usb_read_port_complete(struct urb *purb)
175 {
176 	uint isevt;
177 	__le32 *pbuf;
178 	struct recv_buf	*precvbuf = (struct recv_buf *)purb->context;
179 	struct _adapter *padapter = (struct _adapter *)precvbuf->adapter;
180 	struct recv_priv *precvpriv = &padapter->recvpriv;
181 
182 	if (padapter->surprise_removed || padapter->driver_stopped)
183 		return;
184 	if (purb->status == 0) { /* SUCCESS */
185 		if ((purb->actual_length > (MAX_RECVBUF_SZ)) ||
186 		    (purb->actual_length < RXDESC_SIZE)) {
187 			r8712_read_port(padapter, precvpriv->ff_hwaddr, 0,
188 				  (unsigned char *)precvbuf);
189 		} else {
190 			_pkt *pskb = precvbuf->pskb;
191 
192 			precvbuf->transfer_len = purb->actual_length;
193 			pbuf = (__le32 *)precvbuf->pbuf;
194 			isevt = le32_to_cpu(*(pbuf + 1)) & 0x1ff;
195 			if ((isevt & 0x1ff) == 0x1ff) {
196 				r8712_rxcmd_event_hdl(padapter, pbuf);
197 				skb_queue_tail(&precvpriv->rx_skb_queue, pskb);
198 				r8712_read_port(padapter, precvpriv->ff_hwaddr,
199 						0, (unsigned char *)precvbuf);
200 			} else {
201 				skb_put(pskb, purb->actual_length);
202 				skb_queue_tail(&precvpriv->rx_skb_queue, pskb);
203 				tasklet_hi_schedule(&precvpriv->recv_tasklet);
204 				r8712_read_port(padapter, precvpriv->ff_hwaddr,
205 						0, (unsigned char *)precvbuf);
206 			}
207 		}
208 	} else {
209 		switch (purb->status) {
210 		case -EINVAL:
211 		case -EPIPE:
212 		case -ENODEV:
213 		case -ESHUTDOWN:
214 			padapter->driver_stopped = true;
215 			break;
216 		case -ENOENT:
217 			if (!padapter->suspended) {
218 				padapter->driver_stopped = true;
219 				break;
220 			}
221 			fallthrough;
222 		case -EPROTO:
223 			r8712_read_port(padapter, precvpriv->ff_hwaddr, 0,
224 					(unsigned char *)precvbuf);
225 			break;
226 		case -EINPROGRESS:
227 			netdev_err(padapter->pnetdev, "ERROR: URB IS IN PROGRESS!\n");
228 			break;
229 		default:
230 			break;
231 		}
232 	}
233 }
234 
r8712_usb_read_port(struct intf_hdl * pintfhdl,u32 addr,u32 cnt,u8 * rmem)235 u32 r8712_usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
236 {
237 	unsigned int pipe;
238 	int err;
239 	u32 tmpaddr = 0;
240 	int alignment = 0;
241 	u32 ret = _SUCCESS;
242 	struct urb *purb = NULL;
243 	struct recv_buf	*precvbuf = (struct recv_buf *)rmem;
244 	struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
245 	struct dvobj_priv *pdvobj = (struct dvobj_priv *)pintfpriv->intf_dev;
246 	struct _adapter *adapter = pdvobj->padapter;
247 	struct recv_priv *precvpriv = &adapter->recvpriv;
248 	struct usb_device *pusbd = pdvobj->pusbdev;
249 
250 	if (adapter->driver_stopped || adapter->surprise_removed ||
251 	    adapter->pwrctrlpriv.pnp_bstop_trx || !precvbuf)
252 		return _FAIL;
253 	r8712_init_recvbuf(adapter, precvbuf);
254 	/* Try to use skb from the free queue */
255 	precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
256 
257 	if (!precvbuf->pskb) {
258 		precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev,
259 				 MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
260 		if (!precvbuf->pskb)
261 			return _FAIL;
262 		tmpaddr = (addr_t)precvbuf->pskb->data;
263 		alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
264 		skb_reserve(precvbuf->pskb,
265 			    (RECVBUFF_ALIGN_SZ - alignment));
266 		precvbuf->phead = precvbuf->pskb->head;
267 		precvbuf->pdata = precvbuf->pskb->data;
268 		precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
269 		precvbuf->pend = skb_end_pointer(precvbuf->pskb);
270 		precvbuf->pbuf = precvbuf->pskb->data;
271 	} else { /* skb is reused */
272 		precvbuf->phead = precvbuf->pskb->head;
273 		precvbuf->pdata = precvbuf->pskb->data;
274 		precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
275 		precvbuf->pend = skb_end_pointer(precvbuf->pskb);
276 		precvbuf->pbuf = precvbuf->pskb->data;
277 	}
278 	purb = precvbuf->purb;
279 	/* translate DMA FIFO addr to pipehandle */
280 	pipe = ffaddr2pipehdl(pdvobj, addr);
281 	usb_fill_bulk_urb(purb, pusbd, pipe,
282 			  precvbuf->pbuf, MAX_RECVBUF_SZ,
283 			  r8712_usb_read_port_complete,
284 			  precvbuf);
285 	err = usb_submit_urb(purb, GFP_ATOMIC);
286 	if ((err) && (err != (-EPERM)))
287 		ret = _FAIL;
288 	return ret;
289 }
290 
r8712_usb_read_port_cancel(struct _adapter * padapter)291 void r8712_usb_read_port_cancel(struct _adapter *padapter)
292 {
293 	int i;
294 	struct recv_buf *precvbuf;
295 
296 	precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
297 	for (i = 0; i < NR_RECVBUFF; i++) {
298 		if (precvbuf->purb)
299 			usb_kill_urb(precvbuf->purb);
300 		precvbuf++;
301 	}
302 }
303 
r8712_xmit_bh(struct tasklet_struct * t)304 void r8712_xmit_bh(struct tasklet_struct *t)
305 {
306 	int ret = false;
307 	struct _adapter *padapter = from_tasklet(padapter, t,
308 						 xmitpriv.xmit_tasklet);
309 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
310 
311 	if (padapter->driver_stopped ||
312 	    padapter->surprise_removed) {
313 		netdev_err(padapter->pnetdev, "xmit_bh => driver_stopped or surprise_removed\n");
314 		return;
315 	}
316 	ret = r8712_xmitframe_complete(padapter, pxmitpriv, NULL);
317 	if (!ret)
318 		return;
319 	tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
320 }
321 
usb_write_port_complete(struct urb * purb)322 static void usb_write_port_complete(struct urb *purb)
323 {
324 	int i;
325 	struct xmit_frame *pxmitframe = (struct xmit_frame *)purb->context;
326 	struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf;
327 	struct _adapter *padapter = pxmitframe->padapter;
328 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
329 	struct pkt_attrib *pattrib = &pxmitframe->attrib;
330 
331 	switch (pattrib->priority) {
332 	case 1:
333 	case 2:
334 		pxmitpriv->bkq_cnt--;
335 		break;
336 	case 4:
337 	case 5:
338 		pxmitpriv->viq_cnt--;
339 		break;
340 	case 6:
341 	case 7:
342 		pxmitpriv->voq_cnt--;
343 		break;
344 	case 0:
345 	case 3:
346 	default:
347 		pxmitpriv->beq_cnt--;
348 		break;
349 	}
350 	pxmitpriv->txirp_cnt--;
351 	for (i = 0; i < 8; i++) {
352 		if (purb == pxmitframe->pxmit_urb[i]) {
353 			pxmitframe->bpending[i] = false;
354 			break;
355 		}
356 	}
357 	if (padapter->surprise_removed)
358 		return;
359 	switch (purb->status) {
360 	case 0:
361 		break;
362 	default:
363 		netdev_warn(padapter->pnetdev,
364 				"r8712u: pipe error: (%d)\n", purb->status);
365 		break;
366 	}
367 	/* not to consider tx fragment */
368 	r8712_free_xmitframe_ex(pxmitpriv, pxmitframe);
369 	r8712_free_xmitbuf(pxmitpriv, pxmitbuf);
370 	tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
371 }
372 
r8712_usb_write_port(struct intf_hdl * pintfhdl,u32 addr,u32 cnt,u8 * wmem)373 u32 r8712_usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
374 {
375 	unsigned long irqL;
376 	int i, status;
377 	unsigned int pipe;
378 	u32 ret, bwritezero;
379 	struct urb *purb = NULL;
380 	struct _adapter *padapter = (struct _adapter *)pintfhdl->adapter;
381 	struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
382 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
383 	struct xmit_frame *pxmitframe = (struct xmit_frame *)wmem;
384 	struct usb_device *pusbd = pdvobj->pusbdev;
385 	struct pkt_attrib *pattrib = &pxmitframe->attrib;
386 
387 	if ((padapter->driver_stopped) || (padapter->surprise_removed) ||
388 	    (padapter->pwrctrlpriv.pnp_bstop_trx))
389 		return _FAIL;
390 	for (i = 0; i < 8; i++) {
391 		if (!pxmitframe->bpending[i]) {
392 			spin_lock_irqsave(&pxmitpriv->lock, irqL);
393 			pxmitpriv->txirp_cnt++;
394 			pxmitframe->bpending[i]  = true;
395 			switch (pattrib->priority) {
396 			case 1:
397 			case 2:
398 				pxmitpriv->bkq_cnt++;
399 				break;
400 			case 4:
401 			case 5:
402 				pxmitpriv->viq_cnt++;
403 				break;
404 			case 6:
405 			case 7:
406 				pxmitpriv->voq_cnt++;
407 				break;
408 			case 0:
409 			case 3:
410 			default:
411 				pxmitpriv->beq_cnt++;
412 				break;
413 			}
414 			spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
415 			pxmitframe->sz[i] = (u16)cnt;
416 			purb = pxmitframe->pxmit_urb[i];
417 			break;
418 		}
419 	}
420 	bwritezero = false;
421 	if (pdvobj->ishighspeed) {
422 		if (cnt > 0 && cnt % 512 == 0)
423 			bwritezero = true;
424 	} else {
425 		if (cnt > 0 && cnt % 64 == 0)
426 			bwritezero = true;
427 	}
428 	/* translate DMA FIFO addr to pipehandle */
429 	pipe = ffaddr2pipehdl(pdvobj, addr);
430 	if (pxmitpriv->free_xmitbuf_cnt % NR_XMITBUFF == 0)
431 		purb->transfer_flags  &=  (~URB_NO_INTERRUPT);
432 	else
433 		purb->transfer_flags  |=  URB_NO_INTERRUPT;
434 	if (bwritezero)
435 		cnt += 8;
436 	usb_fill_bulk_urb(purb, pusbd, pipe,
437 			  pxmitframe->mem_addr,
438 			  cnt, usb_write_port_complete,
439 			  pxmitframe); /* context is xmit_frame */
440 	status = usb_submit_urb(purb, GFP_ATOMIC);
441 	if (!status)
442 		ret = _SUCCESS;
443 	else
444 		ret = _FAIL;
445 	return ret;
446 }
447 
r8712_usb_write_port_cancel(struct _adapter * padapter)448 void r8712_usb_write_port_cancel(struct _adapter *padapter)
449 {
450 	int i, j;
451 	struct xmit_buf	*pxmitbuf = (struct xmit_buf *)
452 				     padapter->xmitpriv.pxmitbuf;
453 
454 	for (i = 0; i < NR_XMITBUFF; i++) {
455 		for (j = 0; j < 8; j++) {
456 			if (pxmitbuf->pxmit_urb[j])
457 				usb_kill_urb(pxmitbuf->pxmit_urb[j]);
458 		}
459 		pxmitbuf++;
460 	}
461 }
462 
r8712_usbctrl_vendorreq(struct intf_priv * pintfpriv,u8 request,u16 value,u16 index,void * pdata,u16 len,u8 requesttype)463 int r8712_usbctrl_vendorreq(struct intf_priv *pintfpriv, u8 request, u16 value,
464 		      u16 index, void *pdata, u16 len, u8 requesttype)
465 {
466 	unsigned int pipe;
467 	int status;
468 	u8 reqtype;
469 	struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)
470 					 pintfpriv->intf_dev;
471 	struct usb_device *udev = pdvobjpriv->pusbdev;
472 	/* For mstar platform, mstar suggests the address for USB IO
473 	 * should be 16 bytes alignment. Trying to fix it here.
474 	 */
475 	u8 *palloc_buf, *pIo_buf;
476 
477 	palloc_buf = kmalloc((u32)len + 16, GFP_ATOMIC);
478 	if (!palloc_buf)
479 		return -ENOMEM;
480 	pIo_buf = palloc_buf + 16 - ((addr_t)(palloc_buf) & 0x0f);
481 	if (requesttype == 0x01) {
482 		pipe = usb_rcvctrlpipe(udev, 0); /* read_in */
483 		reqtype =  RTL871X_VENQT_READ;
484 	} else {
485 		pipe = usb_sndctrlpipe(udev, 0); /* write_out */
486 		reqtype =  RTL871X_VENQT_WRITE;
487 		memcpy(pIo_buf, pdata, len);
488 	}
489 	status = usb_control_msg(udev, pipe, request, reqtype, value, index,
490 				 pIo_buf, len, 500);
491 	if (status < 0)
492 		goto free;
493 	if (status != len) {
494 		status = -EREMOTEIO;
495 		goto free;
496 	}
497 	/* Success this control transfer. */
498 	if (requesttype == 0x01) {
499 		/* For Control read transfer, we have to copy the read
500 		 * data from pIo_buf to pdata.
501 		 */
502 		memcpy(pdata, pIo_buf, status);
503 	}
504 
505 free:
506 	kfree(palloc_buf);
507 	return status;
508 }
509