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