]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/vt6656/usbpipe.c
arm: imx6: defconfig: update tx6 defconfigs
[karo-tx-linux.git] / drivers / staging / vt6656 / usbpipe.c
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  *      CONTROLnsRequestOut - Write variable length bytes to MEM/BB/MAC/EEPROM
30  *      CONTROLnsRequestIn - Read variable length bytes from MEM/BB/MAC/EEPROM
31  *      ControlvWriteByte - Write one byte to MEM/BB/MAC/EEPROM
32  *      ControlvReadByte - Read one byte from MEM/BB/MAC/EEPROM
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
41 #include "int.h"
42 #include "rxtx.h"
43 #include "dpc.h"
44 #include "control.h"
45 #include "desc.h"
46 #include "device.h"
47
48 //endpoint def
49 //endpoint 0: control
50 //endpoint 1: interrupt
51 //endpoint 2: read bulk
52 //endpoint 3: write bulk
53
54 //static int          msglevel                =MSG_LEVEL_DEBUG;
55 static int          msglevel                =MSG_LEVEL_INFO;
56
57 #define USB_CTL_WAIT   500 //ms
58
59 #ifndef URB_ASYNC_UNLINK
60 #define URB_ASYNC_UNLINK    0
61 #endif
62
63 static void s_nsInterruptUsbIoCompleteRead(struct urb *urb);
64 static void s_nsBulkInUsbIoCompleteRead(struct urb *urb);
65 static void s_nsBulkOutIoCompleteWrite(struct urb *urb);
66 static void s_nsControlInUsbIoCompleteRead(struct urb *urb);
67 static void s_nsControlInUsbIoCompleteWrite(struct urb *urb);
68
69 int PIPEnsControlOutAsyn(struct vnt_private *pDevice, u8 byRequest,
70         u16 wValue, u16 wIndex, u16 wLength, u8 *pbyBuffer)
71 {
72         int ntStatus;
73
74     if (pDevice->Flags & fMP_DISCONNECTED)
75         return STATUS_FAILURE;
76
77     if (pDevice->Flags & fMP_CONTROL_WRITES)
78         return STATUS_FAILURE;
79
80     if (in_interrupt()) {
81         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"in_interrupt return ..byRequest %x\n", byRequest);
82         return STATUS_FAILURE;
83     }
84
85     ntStatus = usb_control_msg(
86                             pDevice->usb,
87                             usb_sndctrlpipe(pDevice->usb , 0),
88                             byRequest,
89                             0x40, // RequestType
90                             wValue,
91                             wIndex,
92                             (void *) pbyBuffer,
93                             wLength,
94                             HZ
95                           );
96     if (ntStatus >= 0) {
97         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"usb_sndctrlpipe ntStatus= %d\n", ntStatus);
98         ntStatus = 0;
99     } else {
100         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"usb_sndctrlpipe fail, ntStatus= %d\n", ntStatus);
101     }
102
103     return ntStatus;
104 }
105
106 int PIPEnsControlOut(struct vnt_private *pDevice, u8 byRequest, u16 wValue,
107                 u16 wIndex, u16 wLength, u8 *pbyBuffer)
108 {
109         int ntStatus = 0;
110         int ii;
111
112     if (pDevice->Flags & fMP_DISCONNECTED)
113         return STATUS_FAILURE;
114
115     if (pDevice->Flags & fMP_CONTROL_WRITES)
116         return STATUS_FAILURE;
117
118         if (pDevice->Flags & fMP_CONTROL_READS)
119                 return STATUS_FAILURE;
120
121         if (pDevice->pControlURB->hcpriv)
122                 return STATUS_FAILURE;
123
124         MP_SET_FLAG(pDevice, fMP_CONTROL_WRITES);
125
126         pDevice->sUsbCtlRequest.bRequestType = 0x40;
127         pDevice->sUsbCtlRequest.bRequest = byRequest;
128         pDevice->sUsbCtlRequest.wValue = cpu_to_le16p(&wValue);
129         pDevice->sUsbCtlRequest.wIndex = cpu_to_le16p(&wIndex);
130         pDevice->sUsbCtlRequest.wLength = cpu_to_le16p(&wLength);
131         pDevice->pControlURB->transfer_flags |= URB_ASYNC_UNLINK;
132     pDevice->pControlURB->actual_length = 0;
133     // Notice, pbyBuffer limited point to variable buffer, can't be constant.
134         usb_fill_control_urb(pDevice->pControlURB, pDevice->usb,
135                          usb_sndctrlpipe(pDevice->usb , 0), (char *) &pDevice->sUsbCtlRequest,
136                          pbyBuffer, wLength, s_nsControlInUsbIoCompleteWrite, pDevice);
137
138         ntStatus = usb_submit_urb(pDevice->pControlURB, GFP_ATOMIC);
139         if (ntStatus != 0) {
140                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
141                         "control send request submission failed: %d\n",
142                                 ntStatus);
143                 MP_CLEAR_FLAG(pDevice, fMP_CONTROL_WRITES);
144                 return STATUS_FAILURE;
145         }
146
147         spin_unlock_irq(&pDevice->lock);
148     for (ii = 0; ii <= USB_CTL_WAIT; ii ++) {
149
150         if (pDevice->Flags & fMP_CONTROL_WRITES)
151                 mdelay(1);
152         else
153                 break;
154
155         if (ii >= USB_CTL_WAIT) {
156                 DBG_PRT(MSG_LEVEL_DEBUG,
157                         KERN_INFO "control send request submission timeout\n");
158             spin_lock_irq(&pDevice->lock);
159             MP_CLEAR_FLAG(pDevice, fMP_CONTROL_WRITES);
160             return STATUS_FAILURE;
161         }
162     }
163         spin_lock_irq(&pDevice->lock);
164
165     return STATUS_SUCCESS;
166 }
167
168 int PIPEnsControlIn(struct vnt_private *pDevice, u8 byRequest, u16 wValue,
169         u16 wIndex, u16 wLength,  u8 *pbyBuffer)
170 {
171         int ntStatus = 0;
172         int ii;
173
174     if (pDevice->Flags & fMP_DISCONNECTED)
175         return STATUS_FAILURE;
176
177     if (pDevice->Flags & fMP_CONTROL_READS)
178         return STATUS_FAILURE;
179
180         if (pDevice->Flags & fMP_CONTROL_WRITES)
181                 return STATUS_FAILURE;
182
183         if (pDevice->pControlURB->hcpriv)
184                 return STATUS_FAILURE;
185
186         MP_SET_FLAG(pDevice, fMP_CONTROL_READS);
187
188         pDevice->sUsbCtlRequest.bRequestType = 0xC0;
189         pDevice->sUsbCtlRequest.bRequest = byRequest;
190         pDevice->sUsbCtlRequest.wValue = cpu_to_le16p(&wValue);
191         pDevice->sUsbCtlRequest.wIndex = cpu_to_le16p(&wIndex);
192         pDevice->sUsbCtlRequest.wLength = cpu_to_le16p(&wLength);
193         pDevice->pControlURB->transfer_flags |= URB_ASYNC_UNLINK;
194     pDevice->pControlURB->actual_length = 0;
195         usb_fill_control_urb(pDevice->pControlURB, pDevice->usb,
196                          usb_rcvctrlpipe(pDevice->usb , 0), (char *) &pDevice->sUsbCtlRequest,
197                          pbyBuffer, wLength, s_nsControlInUsbIoCompleteRead, pDevice);
198
199         ntStatus = usb_submit_urb(pDevice->pControlURB, GFP_ATOMIC);
200         if (ntStatus != 0) {
201                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
202                         "control request submission failed: %d\n", ntStatus);
203                 MP_CLEAR_FLAG(pDevice, fMP_CONTROL_READS);
204                 return STATUS_FAILURE;
205         }
206
207         spin_unlock_irq(&pDevice->lock);
208     for (ii = 0; ii <= USB_CTL_WAIT; ii ++) {
209
210         if (pDevice->Flags & fMP_CONTROL_READS)
211                 mdelay(1);
212         else
213                 break;
214
215         if (ii >= USB_CTL_WAIT) {
216                 DBG_PRT(MSG_LEVEL_DEBUG,
217                         KERN_INFO "control rcv request submission timeout\n");
218             spin_lock_irq(&pDevice->lock);
219             MP_CLEAR_FLAG(pDevice, fMP_CONTROL_READS);
220             return STATUS_FAILURE;
221         }
222     }
223         spin_lock_irq(&pDevice->lock);
224
225     return ntStatus;
226 }
227
228 static void s_nsControlInUsbIoCompleteWrite(struct urb *urb)
229 {
230         struct vnt_private *pDevice = (struct vnt_private *)urb->context;
231
232         pDevice = urb->context;
233         switch (urb->status) {
234         case 0:
235                 break;
236         case -EINPROGRESS:
237                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ctrl write urb status EINPROGRESS%d\n", urb->status);
238                 break;
239         case -ENOENT:
240                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ctrl write urb status ENOENT %d\n", urb->status);
241                 break;
242         default:
243                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ctrl write urb status %d\n", urb->status);
244         }
245
246     MP_CLEAR_FLAG(pDevice, fMP_CONTROL_WRITES);
247 }
248
249 /*
250  * Description:
251  *      Complete function of usb Control callback
252  *
253  * Parameters:
254  *  In:
255  *      pDevice     - Pointer to the adapter
256  *
257  *  Out:
258  *      none
259  *
260  * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
261  *
262  */
263
264 static void s_nsControlInUsbIoCompleteRead(struct urb *urb)
265 {
266         struct vnt_private *pDevice = (struct vnt_private *)urb->context;
267
268         switch (urb->status) {
269         case 0:
270                 break;
271         case -EINPROGRESS:
272                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ctrl read urb status EINPROGRESS%d\n", urb->status);
273                 break;
274         case -ENOENT:
275                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ctrl read urb status = ENOENT %d\n", urb->status);
276                 break;
277         default:
278                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ctrl read urb status %d\n", urb->status);
279         }
280
281     MP_CLEAR_FLAG(pDevice, fMP_CONTROL_READS);
282 }
283
284 /*
285  * Description:
286  *      Allocates an usb interrupt in irp and calls USBD.
287  *
288  * Parameters:
289  *  In:
290  *      pDevice     - Pointer to the adapter
291  *  Out:
292  *      none
293  *
294  * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
295  *
296  */
297
298 int PIPEnsInterruptRead(struct vnt_private *pDevice)
299 {
300         int ntStatus = STATUS_FAILURE;
301
302     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartInterruptUsbRead()\n");
303
304     if(pDevice->intBuf.bInUse == true){
305         return (STATUS_FAILURE);
306     }
307     pDevice->intBuf.bInUse = true;
308 //    pDevice->bEventAvailable = false;
309     pDevice->ulIntInPosted++;
310
311     //
312     // Now that we have created the urb, we will send a
313     // request to the USB device object.
314     //
315     pDevice->pInterruptURB->interval = pDevice->int_interval;
316
317 usb_fill_bulk_urb(pDevice->pInterruptURB,
318                 pDevice->usb,
319                 usb_rcvbulkpipe(pDevice->usb, 1),
320                 (void *) pDevice->intBuf.pDataBuf,
321                 MAX_INTERRUPT_SIZE,
322                 s_nsInterruptUsbIoCompleteRead,
323                 pDevice);
324
325         ntStatus = usb_submit_urb(pDevice->pInterruptURB, GFP_ATOMIC);
326         if (ntStatus != 0) {
327             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit int URB failed %d\n", ntStatus);
328     }
329
330     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----s_nsStartInterruptUsbRead Return(%x)\n",ntStatus);
331     return ntStatus;
332 }
333
334 /*
335  * Description:
336  *      Complete function of usb interrupt in irp.
337  *
338  * Parameters:
339  *  In:
340  *      pDevice     - Pointer to the adapter
341  *
342  *  Out:
343  *      none
344  *
345  * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
346  *
347  */
348
349 static void s_nsInterruptUsbIoCompleteRead(struct urb *urb)
350 {
351         struct vnt_private *pDevice = (struct vnt_private *)urb->context;
352         int ntStatus;
353
354     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsInterruptUsbIoCompleteRead\n");
355     //
356     // The context given to IoSetCompletionRoutine is the receive buffer object
357     //
358
359     //
360     // We have a number of cases:
361     //      1) The USB read timed out and we received no data.
362     //      2) The USB read timed out and we received some data.
363     //      3) The USB read was successful and fully filled our irp buffer.
364     //      4) The irp was cancelled.
365     //      5) Some other failure from the USB device object.
366     //
367     ntStatus = urb->status;
368
369     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_nsInterruptUsbIoCompleteRead Status %d\n", ntStatus);
370
371     // if we were not successful, we need to free the int buffer for future use right here
372     // otherwise interrupt data handler will free int buffer after it handle it.
373     if (( ntStatus != STATUS_SUCCESS )) {
374         pDevice->ulBulkInError++;
375         pDevice->intBuf.bInUse = false;
376
377 //        if (ntStatus == USBD_STATUS_CRC) {
378 //            pDevice->ulIntInContCRCError++;
379 //        }
380
381 //        if (ntStatus == STATUS_NOT_CONNECTED )
382 //        {
383             pDevice->fKillEventPollingThread = true;
384 //        }
385         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"IntUSBIoCompleteControl STATUS = %d\n", ntStatus );
386     } else {
387             pDevice->ulIntInBytesRead += (unsigned long) urb->actual_length;
388             pDevice->ulIntInContCRCError = 0;
389             pDevice->bEventAvailable = true;
390             INTnsProcessData(pDevice);
391     }
392
393     STAvUpdateUSBCounter(&pDevice->scStatistic.USB_InterruptStat, ntStatus);
394
395     if (pDevice->fKillEventPollingThread != true) {
396        usb_fill_bulk_urb(pDevice->pInterruptURB,
397                       pDevice->usb,
398                       usb_rcvbulkpipe(pDevice->usb, 1),
399                      (void *) pDevice->intBuf.pDataBuf,
400                      MAX_INTERRUPT_SIZE,
401                      s_nsInterruptUsbIoCompleteRead,
402                      pDevice);
403
404         ntStatus = usb_submit_urb(pDevice->pInterruptURB, GFP_ATOMIC);
405         if (ntStatus != 0) {
406             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit int URB failed %d\n", ntStatus);
407            }
408     }
409     //
410     // We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
411     // routine (IofCompleteRequest) will stop working on the irp.
412     //
413     return ;
414 }
415
416 /*
417  * Description:
418  *      Allocates an usb BulkIn  irp and calls USBD.
419  *
420  * Parameters:
421  *  In:
422  *      pDevice     - Pointer to the adapter
423  *  Out:
424  *      none
425  *
426  * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
427  *
428  */
429
430 int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, struct vnt_rcb *pRCB)
431 {
432         int ntStatus = 0;
433         struct urb *pUrb;
434
435     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartBulkInUsbRead\n");
436
437     if (pDevice->Flags & fMP_DISCONNECTED)
438         return STATUS_FAILURE;
439
440     pDevice->ulBulkInPosted++;
441
442         pUrb = pRCB->pUrb;
443     //
444     // Now that we have created the urb, we will send a
445     // request to the USB device object.
446     //
447     if (pRCB->skb == NULL) {
448         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pRCB->skb is null \n");
449         return ntStatus;
450     }
451
452         usb_fill_bulk_urb(pUrb,
453                 pDevice->usb,
454                 usb_rcvbulkpipe(pDevice->usb, 2),
455                 (void *) (pRCB->skb->data),
456                 MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
457                 s_nsBulkInUsbIoCompleteRead,
458                 pRCB);
459
460         ntStatus = usb_submit_urb(pUrb, GFP_ATOMIC);
461         if (ntStatus != 0) {
462                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit Rx URB failed %d\n", ntStatus);
463                 return STATUS_FAILURE ;
464         }
465     pRCB->Ref = 1;
466     pRCB->bBoolInUse= true;
467
468     return ntStatus;
469 }
470
471 /*
472  * Description:
473  *      Complete function of usb BulkIn irp.
474  *
475  * Parameters:
476  *  In:
477  *      pDevice     - Pointer to the adapter
478  *
479  *  Out:
480  *      none
481  *
482  * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
483  *
484  */
485
486 static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
487 {
488         struct vnt_rcb *pRCB = (struct vnt_rcb *)urb->context;
489         struct vnt_private *pDevice = pRCB->pDevice;
490         unsigned long   bytesRead;
491         int bIndicateReceive = false;
492         int bReAllocSkb = false;
493         int status;
494
495     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkInUsbIoCompleteRead\n");
496     status = urb->status;
497     bytesRead = urb->actual_length;
498
499     if (status) {
500         pDevice->ulBulkInError++;
501         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK In failed %d\n", status);
502
503            pDevice->scStatistic.RxFcsErrCnt ++;
504 //todo...xxxxxx
505 //        if (status == USBD_STATUS_CRC) {
506 //            pDevice->ulBulkInContCRCError++;
507 //        }
508 //        if (status == STATUS_DEVICE_NOT_CONNECTED )
509 //        {
510 //            MP_SET_FLAG(pDevice, fMP_DISCONNECTED);
511 //        }
512     } else {
513         if (bytesRead)
514                 bIndicateReceive = true;
515         pDevice->ulBulkInContCRCError = 0;
516         pDevice->ulBulkInBytesRead += bytesRead;
517
518            pDevice->scStatistic.RxOkCnt ++;
519     }
520
521     STAvUpdateUSBCounter(&pDevice->scStatistic.USB_BulkInStat, status);
522
523     if (bIndicateReceive) {
524         spin_lock(&pDevice->lock);
525         if (RXbBulkInProcessData(pDevice, pRCB, bytesRead) == true)
526             bReAllocSkb = true;
527         spin_unlock(&pDevice->lock);
528     }
529     pRCB->Ref--;
530     if (pRCB->Ref == 0)
531     {
532         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RxvFreeNormal %d \n",pDevice->NumRecvFreeList);
533         spin_lock(&pDevice->lock);
534         RXvFreeRCB(pRCB, bReAllocSkb);
535         spin_unlock(&pDevice->lock);
536     }
537
538     return;
539 }
540
541 /*
542  * Description:
543  *      Allocates an usb BulkOut  irp and calls USBD.
544  *
545  * Parameters:
546  *  In:
547  *      pDevice     - Pointer to the adapter
548  *  Out:
549  *      none
550  *
551  * Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
552  *
553  */
554
555 int PIPEnsSendBulkOut(struct vnt_private *pDevice,
556                                 struct vnt_usb_send_context *pContext)
557 {
558         int status;
559         struct urb          *pUrb;
560
561     pDevice->bPWBitOn = false;
562
563 /*
564     if (pDevice->pPendingBulkOutContext != NULL) {
565         pDevice->NumContextsQueued++;
566         EnqueueContext(pDevice->FirstTxContextQueue, pDevice->LastTxContextQueue, pContext);
567         status = STATUS_PENDING;
568         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send pending!\n");
569         return status;
570     }
571 */
572
573     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_nsSendBulkOut\n");
574
575     if (MP_IS_READY(pDevice) && (pDevice->Flags & fMP_POST_WRITES)) {
576
577         pUrb = pContext->pUrb;
578         pDevice->ulBulkOutPosted++;
579 //        pDevice->pPendingBulkOutContext = pContext;
580         usb_fill_bulk_urb(
581                     pUrb,
582                         pDevice->usb,
583                     usb_sndbulkpipe(pDevice->usb, 3),
584                     (void *) &(pContext->Data[0]),
585                         pContext->uBufLen,
586                         s_nsBulkOutIoCompleteWrite,
587                         pContext);
588
589         status = usb_submit_urb(pUrb, GFP_ATOMIC);
590         if (status != 0)
591         {
592                 DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit Tx URB failed %d\n", status);
593                 pContext->bBoolInUse = false;
594                 return STATUS_FAILURE;
595         }
596         return STATUS_PENDING;
597     }
598     else {
599         pContext->bBoolInUse = false;
600         return STATUS_RESOURCES;
601     }
602 }
603
604 /*
605  * Description: s_nsBulkOutIoCompleteWrite
606  *     1a) Indicate to the protocol the status of the write.
607  *     1b) Return ownership of the packet to the protocol.
608  *
609  *     2)  If any more packets are queue for sending, send another packet
610  *         to USBD.
611  *         If the attempt to send the packet to the driver fails,
612  *         return ownership of the packet to the protocol and
613  *         try another packet (until one succeeds).
614  *
615  * Parameters:
616  *  In:
617  *      pdoUsbDevObj  - pointer to the USB device object which
618  *                      completed the irp
619  *      pIrp          - the irp which was completed by the
620  *                      device object
621  *      pContext      - the context given to IoSetCompletionRoutine
622  *                      before calling IoCallDriver on the irp
623  *                      The pContext is a pointer to the USB device object.
624  *  Out:
625  *      none
626  *
627  * Return Value: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine
628  *               (IofCompleteRequest) to stop working on the irp.
629  *
630  */
631
632 static void s_nsBulkOutIoCompleteWrite(struct urb *urb)
633 {
634         struct vnt_private *pDevice;
635         int status;
636         CONTEXT_TYPE ContextType;
637         unsigned long ulBufLen;
638         struct vnt_usb_send_context *pContext;
639
640     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkOutIoCompleteWrite\n");
641     //
642     // The context given to IoSetCompletionRoutine is an USB_CONTEXT struct
643     //
644         pContext = (struct vnt_usb_send_context *)urb->context;
645
646     pDevice = pContext->pDevice;
647     ContextType = pContext->Type;
648     ulBufLen = pContext->uBufLen;
649
650     if (!netif_device_present(pDevice->dev))
651             return;
652
653    //
654     // Perform various IRP, URB, and buffer 'sanity checks'
655     //
656
657     status = urb->status;
658     //we should have failed, succeeded, or cancelled, but NOT be pending
659     STAvUpdateUSBCounter(&pDevice->scStatistic.USB_BulkOutStat, status);
660
661     if(status == STATUS_SUCCESS) {
662         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Write %d bytes\n",(int)ulBufLen);
663         pDevice->ulBulkOutBytesWrite += ulBufLen;
664         pDevice->ulBulkOutContCRCError = 0;
665     } else {
666         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK Out failed %d\n", status);
667         pDevice->ulBulkOutError++;
668     }
669
670 //    pDevice->ulCheckForHangCount = 0;
671 //    pDevice->pPendingBulkOutContext = NULL;
672
673     if ( CONTEXT_DATA_PACKET == ContextType ) {
674         // Indicate to the protocol the status of the sent packet and return
675         // ownership of the packet.
676             if (pContext->pPacket != NULL) {
677                 dev_kfree_skb_irq(pContext->pPacket);
678                 pContext->pPacket = NULL;
679             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"tx  %d bytes\n",(int)ulBufLen);
680             }
681
682         pDevice->dev->trans_start = jiffies;
683
684         if (status == STATUS_SUCCESS) {
685             pDevice->packetsSent++;
686         }
687         else {
688             DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send USB error! [%08xh]\n", status);
689             pDevice->packetsSentDropped++;
690         }
691
692     }
693     if (pDevice->bLinkPass == true) {
694         if (netif_queue_stopped(pDevice->dev))
695             netif_wake_queue(pDevice->dev);
696     }
697     pContext->bBoolInUse = false;
698
699     return;
700 }