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