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