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