Commit | Line | Data |
---|---|---|
92b96797 FB |
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: | |
1390b02a | 29 | * vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM |
441c21c3 | 30 | * vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM |
285d58c4 | 31 | * vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM |
53742906 | 32 | * vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM |
92b96797 FB |
33 | * ControlvMaskByte - Read one byte from MEM/BB/MAC/EEPROM and clear/set some bits in the same address |
34 | * | |
35 | * Revision History: | |
36 | * 04-05-2004 Jerry Chen: Initial release | |
37 | * 11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte,ControlvMaskByte | |
38 | * | |
39 | */ | |
40 | ||
92b96797 | 41 | #include "int.h" |
92b96797 | 42 | #include "rxtx.h" |
92b96797 | 43 | #include "dpc.h" |
92b96797 | 44 | #include "desc.h" |
92b96797 | 45 | #include "device.h" |
62c8526d | 46 | #include "usbpipe.h" |
92b96797 | 47 | |
92b96797 FB |
48 | //endpoint def |
49 | //endpoint 0: control | |
50 | //endpoint 1: interrupt | |
51 | //endpoint 2: read bulk | |
52 | //endpoint 3: write bulk | |
53 | ||
92b96797 FB |
54 | #define USB_CTL_WAIT 500 //ms |
55 | ||
56 | #ifndef URB_ASYNC_UNLINK | |
57 | #define URB_ASYNC_UNLINK 0 | |
58 | #endif | |
59 | ||
fe5d00eb MP |
60 | static void s_nsInterruptUsbIoCompleteRead(struct urb *urb); |
61 | static void s_nsBulkInUsbIoCompleteRead(struct urb *urb); | |
62 | static void s_nsBulkOutIoCompleteWrite(struct urb *urb); | |
92b96797 | 63 | |
1390b02a | 64 | int vnt_control_out(struct vnt_private *priv, u8 request, u16 value, |
0f06a739 | 65 | u16 index, u16 length, u8 *buffer) |
92b96797 | 66 | { |
0f06a739 | 67 | int status = 0; |
92b96797 | 68 | |
0f06a739 | 69 | if (priv->Flags & fMP_DISCONNECTED) |
e1feda13 MP |
70 | return STATUS_FAILURE; |
71 | ||
0f06a739 | 72 | mutex_lock(&priv->usb_lock); |
c91b1869 | 73 | |
0f06a739 MP |
74 | status = usb_control_msg(priv->usb, |
75 | usb_sndctrlpipe(priv->usb, 0), request, 0x40, value, | |
76 | index, buffer, length, USB_CTL_WAIT); | |
ae5943de | 77 | |
0f06a739 | 78 | mutex_unlock(&priv->usb_lock); |
92b96797 | 79 | |
0f06a739 | 80 | if (status < (int)length) |
92b96797 | 81 | return STATUS_FAILURE; |
ae5943de | 82 | |
7021b684 | 83 | return STATUS_SUCCESS; |
92b96797 FB |
84 | } |
85 | ||
285d58c4 MP |
86 | void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data) |
87 | { | |
88 | vnt_control_out(priv, MESSAGE_TYPE_WRITE, | |
89 | reg_off, reg, sizeof(u8), &data); | |
90 | } | |
91 | ||
441c21c3 | 92 | int vnt_control_in(struct vnt_private *priv, u8 request, u16 value, |
9af49fdb | 93 | u16 index, u16 length, u8 *buffer) |
92b96797 | 94 | { |
9af49fdb | 95 | int status; |
731047f9 | 96 | |
9af49fdb | 97 | if (priv->Flags & fMP_DISCONNECTED) |
e1feda13 | 98 | return STATUS_FAILURE; |
ae5943de | 99 | |
9af49fdb | 100 | mutex_lock(&priv->usb_lock); |
c91b1869 | 101 | |
9af49fdb MP |
102 | status = usb_control_msg(priv->usb, |
103 | usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value, | |
104 | index, buffer, length, USB_CTL_WAIT); | |
92b96797 | 105 | |
9af49fdb | 106 | mutex_unlock(&priv->usb_lock); |
c91b1869 | 107 | |
9af49fdb | 108 | if (status < (int)length) |
0fb2af35 | 109 | return STATUS_FAILURE; |
fe5d00eb | 110 | |
0fb2af35 | 111 | return STATUS_SUCCESS; |
92b96797 FB |
112 | } |
113 | ||
53742906 MP |
114 | void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data) |
115 | { | |
116 | vnt_control_in(priv, MESSAGE_TYPE_READ, | |
117 | reg_off, reg, sizeof(u8), data); | |
118 | } | |
119 | ||
92b96797 FB |
120 | /* |
121 | * Description: | |
122 | * Allocates an usb interrupt in irp and calls USBD. | |
123 | * | |
124 | * Parameters: | |
125 | * In: | |
126 | * pDevice - Pointer to the adapter | |
127 | * Out: | |
128 | * none | |
129 | * | |
130 | * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver | |
131 | * | |
132 | */ | |
fe5d00eb | 133 | |
5f38b783 | 134 | int PIPEnsInterruptRead(struct vnt_private *priv) |
92b96797 | 135 | { |
5f38b783 | 136 | int status = STATUS_FAILURE; |
92b96797 | 137 | |
f764e00d | 138 | if (priv->int_buf.in_use == true) |
5f38b783 MP |
139 | return STATUS_FAILURE; |
140 | ||
f764e00d | 141 | priv->int_buf.in_use = true; |
5f38b783 MP |
142 | |
143 | usb_fill_int_urb(priv->pInterruptURB, | |
144 | priv->usb, | |
b9d93d1c | 145 | usb_rcvintpipe(priv->usb, 1), |
f764e00d | 146 | priv->int_buf.data_buf, |
92b96797 FB |
147 | MAX_INTERRUPT_SIZE, |
148 | s_nsInterruptUsbIoCompleteRead, | |
5f38b783 MP |
149 | priv, |
150 | priv->int_interval); | |
92b96797 | 151 | |
5f38b783 MP |
152 | status = usb_submit_urb(priv->pInterruptURB, GFP_ATOMIC); |
153 | if (status) { | |
8a660261 | 154 | dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); |
f764e00d | 155 | priv->int_buf.in_use = false; |
59858f5e | 156 | } |
92b96797 | 157 | |
5f38b783 | 158 | return status; |
92b96797 FB |
159 | } |
160 | ||
92b96797 FB |
161 | /* |
162 | * Description: | |
163 | * Complete function of usb interrupt in irp. | |
164 | * | |
165 | * Parameters: | |
166 | * In: | |
167 | * pDevice - Pointer to the adapter | |
168 | * | |
169 | * Out: | |
170 | * none | |
171 | * | |
172 | * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver | |
173 | * | |
174 | */ | |
92b96797 | 175 | |
fe5d00eb | 176 | static void s_nsInterruptUsbIoCompleteRead(struct urb *urb) |
92b96797 | 177 | { |
599e4b5c | 178 | struct vnt_private *priv = urb->context; |
d9ad7a98 | 179 | int status; |
92b96797 | 180 | |
c98fbf90 MP |
181 | switch (urb->status) { |
182 | case 0: | |
183 | case -ETIMEDOUT: | |
184 | break; | |
185 | case -ECONNRESET: | |
186 | case -ENOENT: | |
187 | case -ESHUTDOWN: | |
f764e00d | 188 | priv->int_buf.in_use = false; |
c98fbf90 MP |
189 | return; |
190 | default: | |
191 | break; | |
192 | } | |
193 | ||
d9ad7a98 | 194 | status = urb->status; |
92b96797 | 195 | |
d9ad7a98 | 196 | if (status != STATUS_SUCCESS) { |
f764e00d | 197 | priv->int_buf.in_use = false; |
92b96797 | 198 | |
8a660261 | 199 | dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status); |
d9ad7a98 | 200 | } else { |
d9ad7a98 MP |
201 | INTnsProcessData(priv); |
202 | } | |
92b96797 | 203 | |
d9ad7a98 MP |
204 | status = usb_submit_urb(priv->pInterruptURB, GFP_ATOMIC); |
205 | if (status) { | |
8a660261 | 206 | dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); |
247b4b68 | 207 | } else { |
f764e00d | 208 | priv->int_buf.in_use = true; |
247b4b68 | 209 | } |
749627f2 | 210 | |
d9ad7a98 | 211 | return; |
92b96797 FB |
212 | } |
213 | ||
214 | /* | |
215 | * Description: | |
216 | * Allocates an usb BulkIn irp and calls USBD. | |
217 | * | |
218 | * Parameters: | |
219 | * In: | |
220 | * pDevice - Pointer to the adapter | |
221 | * Out: | |
222 | * none | |
223 | * | |
224 | * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver | |
225 | * | |
226 | */ | |
fe5d00eb | 227 | |
0b787d71 | 228 | int PIPEnsBulkInUsbRead(struct vnt_private *priv, struct vnt_rcb *rcb) |
92b96797 | 229 | { |
0b787d71 MP |
230 | int status = 0; |
231 | struct urb *urb; | |
92b96797 | 232 | |
0b787d71 MP |
233 | if (priv->Flags & fMP_DISCONNECTED) |
234 | return STATUS_FAILURE; | |
92b96797 | 235 | |
0b787d71 MP |
236 | urb = rcb->pUrb; |
237 | if (rcb->skb == NULL) { | |
8a660261 | 238 | dev_dbg(&priv->usb->dev, "rcb->skb is null\n"); |
0b787d71 MP |
239 | return status; |
240 | } | |
92b96797 | 241 | |
0b787d71 MP |
242 | usb_fill_bulk_urb(urb, |
243 | priv->usb, | |
244 | usb_rcvbulkpipe(priv->usb, 2), | |
245 | (void *) (rcb->skb->data), | |
92b96797 FB |
246 | MAX_TOTAL_SIZE_WITH_ALL_HEADERS, |
247 | s_nsBulkInUsbIoCompleteRead, | |
0b787d71 | 248 | rcb); |
92b96797 | 249 | |
0b787d71 MP |
250 | status = usb_submit_urb(urb, GFP_ATOMIC); |
251 | if (status != 0) { | |
8a660261 | 252 | dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status); |
92b96797 FB |
253 | return STATUS_FAILURE ; |
254 | } | |
92b96797 | 255 | |
0b787d71 MP |
256 | rcb->Ref = 1; |
257 | rcb->bBoolInUse = true; | |
258 | ||
259 | return status; | |
92b96797 FB |
260 | } |
261 | ||
92b96797 FB |
262 | /* |
263 | * Description: | |
264 | * Complete function of usb BulkIn irp. | |
265 | * | |
266 | * Parameters: | |
267 | * In: | |
268 | * pDevice - Pointer to the adapter | |
269 | * | |
270 | * Out: | |
271 | * none | |
272 | * | |
273 | * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver | |
274 | * | |
275 | */ | |
92b96797 | 276 | |
fe5d00eb | 277 | static void s_nsBulkInUsbIoCompleteRead(struct urb *urb) |
92b96797 | 278 | { |
599e4b5c | 279 | struct vnt_rcb *rcb = urb->context; |
d4fa2ab0 | 280 | struct vnt_private *priv = rcb->pDevice; |
29b02373 | 281 | unsigned long flags; |
d4fa2ab0 | 282 | int re_alloc_skb = false; |
92b96797 | 283 | |
67638980 MP |
284 | switch (urb->status) { |
285 | case 0: | |
67638980 MP |
286 | break; |
287 | case -ECONNRESET: | |
288 | case -ENOENT: | |
289 | case -ESHUTDOWN: | |
290 | return; | |
291 | case -ETIMEDOUT: | |
292 | default: | |
8a660261 | 293 | dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status); |
67638980 MP |
294 | break; |
295 | } | |
92b96797 | 296 | |
d4fa2ab0 | 297 | if (urb->actual_length) { |
29b02373 | 298 | spin_lock_irqsave(&priv->lock, flags); |
d4fa2ab0 MP |
299 | |
300 | if (RXbBulkInProcessData(priv, rcb, urb->actual_length) == true) | |
301 | re_alloc_skb = true; | |
302 | ||
29b02373 | 303 | spin_unlock_irqrestore(&priv->lock, flags); |
d4fa2ab0 | 304 | } |
92b96797 | 305 | |
d4fa2ab0 MP |
306 | rcb->Ref--; |
307 | if (rcb->Ref == 0) { | |
8a660261 MP |
308 | dev_dbg(&priv->usb->dev, |
309 | "RxvFreeNormal %d\n", priv->NumRecvFreeList); | |
310 | ||
29b02373 | 311 | spin_lock_irqsave(&priv->lock, flags); |
d4fa2ab0 MP |
312 | |
313 | RXvFreeRCB(rcb, re_alloc_skb); | |
314 | ||
29b02373 | 315 | spin_unlock_irqrestore(&priv->lock, flags); |
d4fa2ab0 MP |
316 | } |
317 | ||
318 | return; | |
92b96797 FB |
319 | } |
320 | ||
321 | /* | |
322 | * Description: | |
323 | * Allocates an usb BulkOut irp and calls USBD. | |
324 | * | |
325 | * Parameters: | |
326 | * In: | |
327 | * pDevice - Pointer to the adapter | |
328 | * Out: | |
329 | * none | |
330 | * | |
331 | * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver | |
332 | * | |
333 | */ | |
fe5d00eb | 334 | |
3f38290e MP |
335 | int PIPEnsSendBulkOut(struct vnt_private *priv, |
336 | struct vnt_usb_send_context *context) | |
92b96797 | 337 | { |
fe5d00eb | 338 | int status; |
3f38290e | 339 | struct urb *urb; |
92b96797 | 340 | |
3f38290e | 341 | priv->bPWBitOn = false; |
92b96797 | 342 | |
3f38290e | 343 | if (!(MP_IS_READY(priv) && priv->Flags & fMP_POST_WRITES)) { |
30a05b39 | 344 | context->in_use = false; |
13338303 MP |
345 | return STATUS_RESOURCES; |
346 | } | |
92b96797 | 347 | |
30a05b39 | 348 | urb = context->urb; |
3f38290e MP |
349 | |
350 | usb_fill_bulk_urb(urb, | |
351 | priv->usb, | |
352 | usb_sndbulkpipe(priv->usb, 3), | |
30a05b39 MP |
353 | context->data, |
354 | context->buf_len, | |
da5c99fd | 355 | s_nsBulkOutIoCompleteWrite, |
3f38290e MP |
356 | context); |
357 | ||
358 | status = usb_submit_urb(urb, GFP_ATOMIC); | |
359 | if (status != 0) { | |
8a660261 MP |
360 | dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status); |
361 | ||
30a05b39 | 362 | context->in_use = false; |
3f38290e MP |
363 | return STATUS_FAILURE; |
364 | } | |
365 | ||
366 | return STATUS_PENDING; | |
92b96797 FB |
367 | } |
368 | ||
369 | /* | |
370 | * Description: s_nsBulkOutIoCompleteWrite | |
371 | * 1a) Indicate to the protocol the status of the write. | |
372 | * 1b) Return ownership of the packet to the protocol. | |
373 | * | |
374 | * 2) If any more packets are queue for sending, send another packet | |
375 | * to USBD. | |
376 | * If the attempt to send the packet to the driver fails, | |
377 | * return ownership of the packet to the protocol and | |
378 | * try another packet (until one succeeds). | |
379 | * | |
380 | * Parameters: | |
381 | * In: | |
382 | * pdoUsbDevObj - pointer to the USB device object which | |
383 | * completed the irp | |
384 | * pIrp - the irp which was completed by the | |
385 | * device object | |
386 | * pContext - the context given to IoSetCompletionRoutine | |
387 | * before calling IoCallDriver on the irp | |
388 | * The pContext is a pointer to the USB device object. | |
389 | * Out: | |
390 | * none | |
391 | * | |
392 | * Return Value: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine | |
393 | * (IofCompleteRequest) to stop working on the irp. | |
394 | * | |
395 | */ | |
fe5d00eb MP |
396 | |
397 | static void s_nsBulkOutIoCompleteWrite(struct urb *urb) | |
92b96797 | 398 | { |
599e4b5c | 399 | struct vnt_usb_send_context *context = urb->context; |
30a05b39 | 400 | struct vnt_private *priv = context->priv; |
1450ba62 | 401 | u8 context_type = context->type; |
92b96797 | 402 | |
e8152bfb MP |
403 | switch (urb->status) { |
404 | case 0: | |
8a660261 | 405 | dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len); |
e8152bfb MP |
406 | break; |
407 | case -ECONNRESET: | |
408 | case -ENOENT: | |
409 | case -ESHUTDOWN: | |
30a05b39 | 410 | context->in_use = false; |
e8152bfb | 411 | return; |
d1b2a11d | 412 | case -ETIMEDOUT: |
e8152bfb | 413 | default: |
8a660261 | 414 | dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status); |
e8152bfb MP |
415 | break; |
416 | } | |
417 | ||
21aa212c MP |
418 | if (!netif_device_present(priv->dev)) |
419 | return; | |
92b96797 | 420 | |
21aa212c | 421 | if (CONTEXT_DATA_PACKET == context_type) { |
30a05b39 MP |
422 | if (context->skb != NULL) { |
423 | dev_kfree_skb_irq(context->skb); | |
424 | context->skb = NULL; | |
8a660261 MP |
425 | dev_dbg(&priv->usb->dev, |
426 | "tx %d bytes\n", context->buf_len); | |
21aa212c | 427 | } |
92b96797 | 428 | |
21aa212c | 429 | priv->dev->trans_start = jiffies; |
21aa212c | 430 | } |
92b96797 | 431 | |
21aa212c MP |
432 | if (priv->bLinkPass == true) { |
433 | if (netif_queue_stopped(priv->dev)) | |
434 | netif_wake_queue(priv->dev); | |
435 | } | |
436 | ||
30a05b39 | 437 | context->in_use = false; |
21aa212c MP |
438 | |
439 | return; | |
92b96797 | 440 | } |