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