• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ret = 0;
40 	u8 *usb_buffer;
41 
42 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
43 		ret = -EINVAL;
44 		goto end;
45 	}
46 
47 	mutex_lock(&priv->usb_lock);
48 
49 	usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
50 	if (!usb_buffer) {
51 		ret = -ENOMEM;
52 		goto end_unlock;
53 	}
54 
55 	ret = usb_control_msg(priv->usb,
56 			      usb_sndctrlpipe(priv->usb, 0),
57 			      request, 0x40, value,
58 			      index, usb_buffer, length, USB_CTL_WAIT);
59 
60 	kfree(usb_buffer);
61 
62 	if (ret == (int)length)
63 		ret = 0;
64 	else
65 		ret = -EIO;
66 
67 end_unlock:
68 	mutex_unlock(&priv->usb_lock);
69 end:
70 	return ret;
71 }
72 
vnt_control_out_u8(struct vnt_private * priv,u8 reg,u8 reg_off,u8 data)73 int vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
74 {
75 	return vnt_control_out(priv, MESSAGE_TYPE_WRITE,
76 			       reg_off, reg, sizeof(u8), &data);
77 }
78 
vnt_control_out_blocks(struct vnt_private * priv,u16 block,u8 reg,u16 length,u8 * data)79 int vnt_control_out_blocks(struct vnt_private *priv,
80 			   u16 block, u8 reg, u16 length, u8 *data)
81 {
82 	int ret = 0, i;
83 
84 	for (i = 0; i < length; i += block) {
85 		u16 len = min_t(int, length - i, block);
86 
87 		ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE,
88 				      i, reg, len, data + i);
89 		if (ret)
90 			goto end;
91 	}
92 end:
93 	return ret;
94 }
95 
vnt_control_in(struct vnt_private * priv,u8 request,u16 value,u16 index,u16 length,u8 * buffer)96 int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
97 		   u16 index, u16 length, u8 *buffer)
98 {
99 	int ret = 0;
100 	u8 *usb_buffer;
101 
102 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
103 		ret = -EINVAL;
104 		goto end;
105 	}
106 
107 	mutex_lock(&priv->usb_lock);
108 
109 	usb_buffer = kmalloc(length, GFP_KERNEL);
110 	if (!usb_buffer) {
111 		ret = -ENOMEM;
112 		goto end_unlock;
113 	}
114 
115 	ret = usb_control_msg(priv->usb,
116 			      usb_rcvctrlpipe(priv->usb, 0),
117 			      request, 0xc0, value,
118 			      index, usb_buffer, length, USB_CTL_WAIT);
119 
120 	if (ret == length)
121 		memcpy(buffer, usb_buffer, length);
122 
123 	kfree(usb_buffer);
124 
125 	if (ret == (int)length)
126 		ret = 0;
127 	else
128 		ret = -EIO;
129 
130 end_unlock:
131 	mutex_unlock(&priv->usb_lock);
132 end:
133 	return ret;
134 }
135 
vnt_control_in_u8(struct vnt_private * priv,u8 reg,u8 reg_off,u8 * data)136 int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
137 {
138 	return vnt_control_in(priv, MESSAGE_TYPE_READ,
139 			      reg_off, reg, sizeof(u8), data);
140 }
141 
vnt_start_interrupt_urb_complete(struct urb * urb)142 static void vnt_start_interrupt_urb_complete(struct urb *urb)
143 {
144 	struct vnt_private *priv = urb->context;
145 	int status = urb->status;
146 
147 	switch (status) {
148 	case 0:
149 	case -ETIMEDOUT:
150 		break;
151 	case -ECONNRESET:
152 	case -ENOENT:
153 	case -ESHUTDOWN:
154 		priv->int_buf.in_use = false;
155 		return;
156 	default:
157 		break;
158 	}
159 
160 	if (status) {
161 		priv->int_buf.in_use = false;
162 
163 		dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status);
164 	} else {
165 		vnt_int_process_data(priv);
166 	}
167 
168 	status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
169 	if (status)
170 		dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
171 	else
172 		priv->int_buf.in_use = true;
173 }
174 
vnt_start_interrupt_urb(struct vnt_private * priv)175 int vnt_start_interrupt_urb(struct vnt_private *priv)
176 {
177 	int ret = 0;
178 
179 	if (priv->int_buf.in_use) {
180 		ret = -EBUSY;
181 		goto err;
182 	}
183 
184 	priv->int_buf.in_use = true;
185 
186 	usb_fill_int_urb(priv->interrupt_urb,
187 			 priv->usb,
188 			 usb_rcvintpipe(priv->usb, 1),
189 			 priv->int_buf.data_buf,
190 			 MAX_INTERRUPT_SIZE,
191 			 vnt_start_interrupt_urb_complete,
192 			 priv,
193 			 priv->int_interval);
194 
195 	ret = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
196 	if (ret) {
197 		dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", ret);
198 		goto err_submit;
199 	}
200 
201 	return 0;
202 
203 err_submit:
204 	priv->int_buf.in_use = false;
205 err:
206 	return ret;
207 }
208 
vnt_submit_rx_urb_complete(struct urb * urb)209 static void vnt_submit_rx_urb_complete(struct urb *urb)
210 {
211 	struct vnt_rcb *rcb = urb->context;
212 	struct vnt_private *priv = rcb->priv;
213 
214 	switch (urb->status) {
215 	case 0:
216 		break;
217 	case -ECONNRESET:
218 	case -ENOENT:
219 	case -ESHUTDOWN:
220 		return;
221 	case -ETIMEDOUT:
222 	default:
223 		dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status);
224 		break;
225 	}
226 
227 	if (urb->actual_length) {
228 		if (vnt_rx_data(priv, rcb, urb->actual_length)) {
229 			rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
230 			if (!rcb->skb) {
231 				rcb->in_use = false;
232 				return;
233 			}
234 		} else {
235 			skb_push(rcb->skb, skb_headroom(rcb->skb));
236 			skb_trim(rcb->skb, 0);
237 		}
238 
239 		urb->transfer_buffer = skb_put(rcb->skb,
240 					       skb_tailroom(rcb->skb));
241 	}
242 
243 	if (usb_submit_urb(urb, GFP_ATOMIC)) {
244 		dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n");
245 
246 		rcb->in_use = false;
247 	}
248 }
249 
vnt_submit_rx_urb(struct vnt_private * priv,struct vnt_rcb * rcb)250 int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
251 {
252 	int ret = 0;
253 	struct urb *urb = rcb->urb;
254 
255 	if (!rcb->skb) {
256 		dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
257 		ret = -EINVAL;
258 		goto end;
259 	}
260 
261 	usb_fill_bulk_urb(urb,
262 			  priv->usb,
263 			  usb_rcvbulkpipe(priv->usb, 2),
264 			  skb_put(rcb->skb, skb_tailroom(rcb->skb)),
265 			  MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
266 			  vnt_submit_rx_urb_complete,
267 			  rcb);
268 
269 	ret = usb_submit_urb(urb, GFP_ATOMIC);
270 	if (ret) {
271 		dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", ret);
272 		goto end;
273 	}
274 
275 	rcb->in_use = true;
276 
277 end:
278 	return ret;
279 }
280 
vnt_tx_context_complete(struct urb * urb)281 static void vnt_tx_context_complete(struct urb *urb)
282 {
283 	struct vnt_usb_send_context *context = urb->context;
284 	struct vnt_private *priv = context->priv;
285 
286 	switch (urb->status) {
287 	case 0:
288 		dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len);
289 		break;
290 	case -ECONNRESET:
291 	case -ENOENT:
292 	case -ESHUTDOWN:
293 		context->in_use = false;
294 		return;
295 	case -ETIMEDOUT:
296 	default:
297 		dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status);
298 		break;
299 	}
300 
301 	if (context->type == CONTEXT_DATA_PACKET)
302 		ieee80211_wake_queues(priv->hw);
303 
304 	if (urb->status || context->type == CONTEXT_BEACON_PACKET) {
305 		if (context->skb)
306 			ieee80211_free_txskb(priv->hw, context->skb);
307 
308 		context->in_use = false;
309 	}
310 }
311 
vnt_tx_context(struct vnt_private * priv,struct vnt_usb_send_context * context)312 int vnt_tx_context(struct vnt_private *priv,
313 		   struct vnt_usb_send_context *context)
314 {
315 	int status;
316 	struct urb *urb = context->urb;
317 
318 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
319 		context->in_use = false;
320 		return STATUS_RESOURCES;
321 	}
322 
323 	usb_fill_bulk_urb(urb,
324 			  priv->usb,
325 			  usb_sndbulkpipe(priv->usb, 3),
326 			  context->data,
327 			  context->buf_len,
328 			  vnt_tx_context_complete,
329 			  context);
330 
331 	status = usb_submit_urb(urb, GFP_ATOMIC);
332 	if (status) {
333 		dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
334 
335 		context->in_use = false;
336 		return STATUS_FAILURE;
337 	}
338 
339 	return STATUS_PENDING;
340 }
341