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/rtl8188e_recv.h"
9 
ffaddr2pipehdl(struct dvobj_priv * pdvobj,u32 addr)10 static 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 < HW_QUEUE_ENTRY) {
16 		ep_num = pdvobj->Queue2Pipe[addr];
17 		pipe = usb_sndbulkpipe(pusbd, ep_num);
18 	}
19 
20 	return pipe;
21 }
22 
rtw_read_port_cancel(struct adapter * padapter)23 void rtw_read_port_cancel(struct adapter *padapter)
24 {
25 	int i;
26 	struct recv_buf *precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
27 
28 	padapter->bReadPortCancel = true;
29 
30 	for (i = 0; i < NR_RECVBUFF; i++) {
31 		precvbuf->reuse = true;
32 		if (precvbuf->purb)
33 			usb_kill_urb(precvbuf->purb);
34 		precvbuf++;
35 	}
36 }
37 
usb_write_port_complete(struct urb * purb,struct pt_regs * regs)38 static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
39 {
40 	struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
41 	struct adapter	*padapter = pxmitbuf->padapter;
42 	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
43 
44 	switch (pxmitbuf->flags) {
45 	case VO_QUEUE_INX:
46 		pxmitpriv->voq_cnt--;
47 		break;
48 	case VI_QUEUE_INX:
49 		pxmitpriv->viq_cnt--;
50 		break;
51 	case BE_QUEUE_INX:
52 		pxmitpriv->beq_cnt--;
53 		break;
54 	case BK_QUEUE_INX:
55 		pxmitpriv->bkq_cnt--;
56 		break;
57 	case HIGH_QUEUE_INX:
58 		rtw_chk_hi_queue_cmd(padapter);
59 		break;
60 	default:
61 		break;
62 	}
63 
64 	if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
65 	    padapter->bWritePortCancel)
66 		goto check_completion;
67 
68 	if (purb->status) {
69 		if (purb->status == -EINPROGRESS) {
70 			goto check_completion;
71 		} else if (purb->status == -ENOENT) {
72 			goto check_completion;
73 		} else if (purb->status == -ECONNRESET) {
74 			goto check_completion;
75 		} else if (purb->status == -ESHUTDOWN) {
76 			padapter->bDriverStopped = true;
77 			goto check_completion;
78 		} else if ((purb->status != -EPIPE) && (purb->status != -EPROTO)) {
79 			padapter->bSurpriseRemoved = true;
80 
81 			goto check_completion;
82 		}
83 	}
84 
85 check_completion:
86 	rtw_sctx_done_err(&pxmitbuf->sctx,
87 			  purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR :
88 			  RTW_SCTX_DONE_SUCCESS);
89 
90 	rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
91 
92 	tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
93 
94 }
95 
rtw_write_port(struct adapter * padapter,u32 addr,u32 cnt,u8 * wmem)96 u32 rtw_write_port(struct adapter *padapter, u32 addr, u32 cnt, u8 *wmem)
97 {
98 	unsigned long irqL;
99 	unsigned int pipe;
100 	int status;
101 	u32 ret = _FAIL;
102 	struct urb *purb = NULL;
103 	struct dvobj_priv	*pdvobj = adapter_to_dvobj(padapter);
104 	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
105 	struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem;
106 	struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
107 	struct usb_device *pusbd = pdvobj->pusbdev;
108 
109 	if (padapter->bDriverStopped || padapter->bSurpriseRemoved) {
110 		rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
111 		goto exit;
112 	}
113 
114 	spin_lock_irqsave(&pxmitpriv->lock, irqL);
115 
116 	switch (addr) {
117 	case VO_QUEUE_INX:
118 		pxmitpriv->voq_cnt++;
119 		pxmitbuf->flags = VO_QUEUE_INX;
120 		break;
121 	case VI_QUEUE_INX:
122 		pxmitpriv->viq_cnt++;
123 		pxmitbuf->flags = VI_QUEUE_INX;
124 		break;
125 	case BE_QUEUE_INX:
126 		pxmitpriv->beq_cnt++;
127 		pxmitbuf->flags = BE_QUEUE_INX;
128 		break;
129 	case BK_QUEUE_INX:
130 		pxmitpriv->bkq_cnt++;
131 		pxmitbuf->flags = BK_QUEUE_INX;
132 		break;
133 	case HIGH_QUEUE_INX:
134 		pxmitbuf->flags = HIGH_QUEUE_INX;
135 		break;
136 	default:
137 		pxmitbuf->flags = MGT_QUEUE_INX;
138 		break;
139 	}
140 
141 	spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
142 
143 	purb	= pxmitbuf->pxmit_urb;
144 
145 	/* translate DMA FIFO addr to pipehandle */
146 	pipe = ffaddr2pipehdl(pdvobj, addr);
147 
148 	usb_fill_bulk_urb(purb, pusbd, pipe,
149 			  pxmitframe->buf_addr, /*  pxmitbuf->pbuf */
150 			  cnt,
151 			  usb_write_port_complete,
152 			  pxmitbuf);/* context is pxmitbuf */
153 
154 	status = usb_submit_urb(purb, GFP_ATOMIC);
155 	if (status) {
156 		rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
157 
158 		switch (status) {
159 		case -ENODEV:
160 			padapter->bDriverStopped = true;
161 			break;
162 		default:
163 			break;
164 		}
165 		goto exit;
166 	}
167 
168 	ret = _SUCCESS;
169 
170 /*    We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */
171 
172 exit:
173 	if (ret != _SUCCESS)
174 		rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
175 
176 	return ret;
177 }
178 
rtw_write_port_cancel(struct adapter * padapter)179 void rtw_write_port_cancel(struct adapter *padapter)
180 {
181 	int i;
182 	struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
183 
184 	padapter->bWritePortCancel = true;
185 
186 	for (i = 0; i < NR_XMITBUFF; i++) {
187 		if (pxmitbuf->pxmit_urb)
188 			usb_kill_urb(pxmitbuf->pxmit_urb);
189 		pxmitbuf++;
190 	}
191 
192 	pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf;
193 	for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
194 		if (pxmitbuf->pxmit_urb)
195 			usb_kill_urb(pxmitbuf->pxmit_urb);
196 		pxmitbuf++;
197 	}
198 }
199