1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
4  * All rights reserved.
5  *
6  * File: usbpipe.c
7  *
8  * Purpose: Handle USB control endpoint
9  *
10  * Author: Warren Hsu
11  *
12  * Date: Mar. 29, 2005
13  *
14  * Functions:
15  *	vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM
16  *	vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM
17  *	vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM
18  *	vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM
19  *
20  * Revision History:
21  *      04-05-2004 Jerry Chen: Initial release
22  *      11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte,
23  *                             ControlvMaskByte
24  *
25  */
26 
27 #include "int.h"
28 #include "rxtx.h"
29 #include "dpc.h"
30 #include "desc.h"
31 #include "device.h"
32 #include "usbpipe.h"
33 
34 #define USB_CTL_WAIT	500 /* ms */
35 
vnt_control_out(struct vnt_private * priv,u8 request,u16 value,u16 index,u16 length,u8 * buffer)36 int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
37 		    u16 index, u16 length, u8 *buffer)
38 {
39 	int status = 0;
40 	u8 *usb_buffer;
41 
42 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
43 		return STATUS_FAILURE;
44 
45 	mutex_lock(&priv->usb_lock);
46 
47 	usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
48 	if (!usb_buffer) {
49 		mutex_unlock(&priv->usb_lock);
50 		return -ENOMEM;
51 	}
52 
53 	status = usb_control_msg(priv->usb,
54 				 usb_sndctrlpipe(priv->usb, 0),
55 				 request, 0x40, value,
56 				 index, usb_buffer, length, USB_CTL_WAIT);
57 
58 	kfree(usb_buffer);
59 
60 	mutex_unlock(&priv->usb_lock);
61 
62 	if (status < (int)length)
63 		return STATUS_FAILURE;
64 
65 	return STATUS_SUCCESS;
66 }
67 
vnt_control_out_u8(struct vnt_private * priv,u8 reg,u8 reg_off,u8 data)68 void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
69 {
70 	vnt_control_out(priv, MESSAGE_TYPE_WRITE,
71 			reg_off, reg, sizeof(u8), &data);
72 }
73 
vnt_control_in(struct vnt_private * priv,u8 request,u16 value,u16 index,u16 length,u8 * buffer)74 int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
75 		   u16 index, u16 length, u8 *buffer)
76 {
77 	int status;
78 	u8 *usb_buffer;
79 
80 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
81 		return STATUS_FAILURE;
82 
83 	mutex_lock(&priv->usb_lock);
84 
85 	usb_buffer = kmalloc(length, GFP_KERNEL);
86 	if (!usb_buffer) {
87 		mutex_unlock(&priv->usb_lock);
88 		return -ENOMEM;
89 	}
90 
91 	status = usb_control_msg(priv->usb,
92 				 usb_rcvctrlpipe(priv->usb, 0),
93 				 request, 0xc0, value,
94 				 index, usb_buffer, length, USB_CTL_WAIT);
95 
96 	if (status == length)
97 		memcpy(buffer, usb_buffer, length);
98 
99 	kfree(usb_buffer);
100 
101 	mutex_unlock(&priv->usb_lock);
102 
103 	if (status < (int)length)
104 		return STATUS_FAILURE;
105 
106 	return STATUS_SUCCESS;
107 }
108 
vnt_control_in_u8(struct vnt_private * priv,u8 reg,u8 reg_off,u8 * data)109 void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
110 {
111 	vnt_control_in(priv, MESSAGE_TYPE_READ,
112 		       reg_off, reg, sizeof(u8), data);
113 }
114 
vnt_start_interrupt_urb_complete(struct urb * urb)115 static void vnt_start_interrupt_urb_complete(struct urb *urb)
116 {
117 	struct vnt_private *priv = urb->context;
118 	int status = urb->status;
119 
120 	switch (status) {
121 	case 0:
122 	case -ETIMEDOUT:
123 		break;
124 	case -ECONNRESET:
125 	case -ENOENT:
126 	case -ESHUTDOWN:
127 		priv->int_buf.in_use = false;
128 		return;
129 	default:
130 		break;
131 	}
132 
133 	if (status) {
134 		priv->int_buf.in_use = false;
135 
136 		dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status);
137 	} else {
138 		vnt_int_process_data(priv);
139 	}
140 
141 	status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
142 	if (status)
143 		dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
144 	else
145 		priv->int_buf.in_use = true;
146 }
147 
vnt_start_interrupt_urb(struct vnt_private * priv)148 int vnt_start_interrupt_urb(struct vnt_private *priv)
149 {
150 	int status = STATUS_FAILURE;
151 
152 	if (priv->int_buf.in_use)
153 		return STATUS_FAILURE;
154 
155 	priv->int_buf.in_use = true;
156 
157 	usb_fill_int_urb(priv->interrupt_urb,
158 			 priv->usb,
159 			 usb_rcvintpipe(priv->usb, 1),
160 			 priv->int_buf.data_buf,
161 			 MAX_INTERRUPT_SIZE,
162 			 vnt_start_interrupt_urb_complete,
163 			 priv,
164 			 priv->int_interval);
165 
166 	status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
167 	if (status) {
168 		dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
169 		priv->int_buf.in_use = false;
170 	}
171 
172 	return status;
173 }
174 
vnt_submit_rx_urb_complete(struct urb * urb)175 static void vnt_submit_rx_urb_complete(struct urb *urb)
176 {
177 	struct vnt_rcb *rcb = urb->context;
178 	struct vnt_private *priv = rcb->priv;
179 
180 	switch (urb->status) {
181 	case 0:
182 		break;
183 	case -ECONNRESET:
184 	case -ENOENT:
185 	case -ESHUTDOWN:
186 		return;
187 	case -ETIMEDOUT:
188 	default:
189 		dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status);
190 		break;
191 	}
192 
193 	if (urb->actual_length) {
194 		if (vnt_rx_data(priv, rcb, urb->actual_length)) {
195 			rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
196 			if (!rcb->skb) {
197 				rcb->in_use = false;
198 				return;
199 			}
200 		} else {
201 			skb_push(rcb->skb, skb_headroom(rcb->skb));
202 			skb_trim(rcb->skb, 0);
203 		}
204 
205 		urb->transfer_buffer = skb_put(rcb->skb,
206 						skb_tailroom(rcb->skb));
207 	}
208 
209 	if (usb_submit_urb(urb, GFP_ATOMIC)) {
210 		dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n");
211 
212 		rcb->in_use = false;
213 	}
214 }
215 
vnt_submit_rx_urb(struct vnt_private * priv,struct vnt_rcb * rcb)216 int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
217 {
218 	int status = 0;
219 	struct urb *urb = rcb->urb;
220 
221 	if (!rcb->skb) {
222 		dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
223 		return status;
224 	}
225 
226 	usb_fill_bulk_urb(urb,
227 			  priv->usb,
228 			  usb_rcvbulkpipe(priv->usb, 2),
229 			  skb_put(rcb->skb, skb_tailroom(rcb->skb)),
230 			  MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
231 			  vnt_submit_rx_urb_complete,
232 			  rcb);
233 
234 	status = usb_submit_urb(urb, GFP_ATOMIC);
235 	if (status) {
236 		dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status);
237 		return STATUS_FAILURE;
238 	}
239 
240 	rcb->in_use = true;
241 
242 	return status;
243 }
244 
vnt_tx_context_complete(struct urb * urb)245 static void vnt_tx_context_complete(struct urb *urb)
246 {
247 	struct vnt_usb_send_context *context = urb->context;
248 	struct vnt_private *priv = context->priv;
249 
250 	switch (urb->status) {
251 	case 0:
252 		dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len);
253 		break;
254 	case -ECONNRESET:
255 	case -ENOENT:
256 	case -ESHUTDOWN:
257 		context->in_use = false;
258 		return;
259 	case -ETIMEDOUT:
260 	default:
261 		dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status);
262 		break;
263 	}
264 
265 	if (context->type == CONTEXT_DATA_PACKET)
266 		ieee80211_wake_queues(priv->hw);
267 
268 	if (urb->status || context->type == CONTEXT_BEACON_PACKET) {
269 		if (context->skb)
270 			ieee80211_free_txskb(priv->hw, context->skb);
271 
272 		context->in_use = false;
273 	}
274 }
275 
vnt_tx_context(struct vnt_private * priv,struct vnt_usb_send_context * context)276 int vnt_tx_context(struct vnt_private *priv,
277 		   struct vnt_usb_send_context *context)
278 {
279 	int status;
280 	struct urb *urb = context->urb;
281 
282 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
283 		context->in_use = false;
284 		return STATUS_RESOURCES;
285 	}
286 
287 	usb_fill_bulk_urb(urb,
288 			  priv->usb,
289 			  usb_sndbulkpipe(priv->usb, 3),
290 			  context->data,
291 			  context->buf_len,
292 			  vnt_tx_context_complete,
293 			  context);
294 
295 	status = usb_submit_urb(urb, GFP_ATOMIC);
296 	if (status) {
297 		dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
298 
299 		context->in_use = false;
300 		return STATUS_FAILURE;
301 	}
302 
303 	return STATUS_PENDING;
304 }
305