home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ndissrc.zip / INTERRUP.C < prev    next >
Text File  |  1996-02-07  |  50KB  |  2,109 lines

  1. /*++
  2.  
  3. Module Name:
  4.  
  5.     interrup.c
  6.  
  7. Abstract:
  8.  
  9.     This is a part of the driver for the UM9008 NE2000 Compatible
  10.     Ethernet controller.  It contains the interrupt-handling routines.
  11.     This driver conforms to the NDIS 3.0 interface.
  12.  
  13. --*/
  14.  
  15. #include <ndis.h>
  16. #include "UM9008hw.h"
  17. #include "UM9008sw.h"
  18.  
  19. //
  20. // On debug builds tell the compiler to keep the symbols for
  21. // internal functions, otw throw them out.
  22. //
  23. #if DBG
  24. #define STATIC
  25. #else
  26. #define STATIC static
  27. #endif
  28.  
  29.  
  30.  
  31. INDICATE_STATUS
  32. UM9008IndicatePacket(
  33.     IN PUM9008_ADAPTER Adapter
  34.     );
  35.  
  36. VOID
  37. UM9008DoNextSend(
  38.     PUM9008_ADAPTER Adapter
  39.     );
  40.  
  41.  
  42.  
  43. //
  44. // This is used to pad short packets.
  45. //
  46. static UCHAR BlankBuffer[60] = "                                                            ";
  47.  
  48.  
  49.  
  50. VOID
  51. UM9008EnableInterrupt(
  52.     IN NDIS_HANDLE MiniportAdapterContext
  53.     )
  54.  
  55. /*++
  56.  
  57. Routine Description:
  58.  
  59.     This routine is used to turn on the interrupt mask.
  60.  
  61. Arguments:
  62.  
  63.     Context - The adapter for the UM9008 to start.
  64.  
  65. Return Value:
  66.  
  67.     None.
  68.  
  69. --*/
  70.  
  71. {
  72.     PUM9008_ADAPTER Adapter = (PUM9008_ADAPTER)(MiniportAdapterContext);
  73.  
  74.     IF_LOG( UM9008Log('P'); )
  75.  
  76.     CardUnblockInterrupts(Adapter);
  77.  
  78. }
  79.  
  80. VOID
  81. UM9008DisableInterrupt(
  82.     IN NDIS_HANDLE MiniportAdapterContext
  83.     )
  84.  
  85. /*++
  86.  
  87. Routine Description:
  88.  
  89.     This routine is used to turn off the interrupt mask.
  90.  
  91. Arguments:
  92.  
  93.     Context - The adapter for the UM9008 to start.
  94.  
  95. Return Value:
  96.  
  97.     None.
  98.  
  99. --*/
  100.  
  101. {
  102.     PUM9008_ADAPTER Adapter = (PUM9008_ADAPTER)(MiniportAdapterContext);
  103.  
  104.     IF_LOG( UM9008Log('p'); )
  105.  
  106.     CardBlockInterrupts(Adapter);
  107.  
  108. }
  109.  
  110. VOID
  111. UM9008Isr(
  112.     OUT PBOOLEAN InterruptRecognized,
  113.     OUT PBOOLEAN QueueDpc,
  114.     IN PVOID Context
  115.     )
  116.  
  117. /*++
  118.  
  119. Routine Description:
  120.  
  121.     This is the interrupt handler which is registered with the operating
  122.     system. If several are pending (i.e. transmit complete and receive),
  123.     handle them all.  Block new interrupts until all pending interrupts
  124.     are handled.
  125.  
  126. Arguments:
  127.  
  128.     InterruptRecognized - Boolean value which returns TRUE if the
  129.         ISR recognizes the interrupt as coming from this adapter.
  130.  
  131.     QueueDpc - TRUE if a DPC should be queued.
  132.  
  133.     Context - pointer to the adapter object
  134.  
  135. Return Value:
  136.  
  137.     None.
  138. --*/
  139.  
  140. {
  141.     PUM9008_ADAPTER Adapter = ((PUM9008_ADAPTER)Context);
  142.  
  143.     IF_LOUD( DbgPrint("In UM9008ISR\n");)
  144.  
  145.     IF_LOG( UM9008Log('i'); )
  146.  
  147.     IF_VERY_LOUD( DbgPrint( "UM9008InterruptHandler entered\n" );)
  148.  
  149.     //
  150.     // Force the INT signal from the chip low. When all
  151.     // interrupts are acknowledged interrupts will be unblocked,
  152.     //
  153.     CardBlockInterrupts(Adapter);
  154.  
  155.     IF_LOG( UM9008Log('I'); )
  156.  
  157.     *InterruptRecognized = TRUE;
  158.     *QueueDpc = TRUE;
  159.  
  160.     return;
  161. }
  162.  
  163.  
  164. VOID
  165. UM9008HandleInterrupt(
  166.     IN NDIS_HANDLE MiniportAdapterContext
  167.     )
  168. /*++
  169.  
  170. Routine Description:
  171.  
  172.     This is the defered processing routine for interrupts.  It
  173.     reads from the Interrupt Status Register any outstanding
  174.     interrupts and handles them.
  175.  
  176. Arguments:
  177.  
  178.     MiniportAdapterContext - a handle to the adapter block.
  179.  
  180. Return Value:
  181.  
  182.     NONE.
  183.  
  184. --*/
  185. {
  186.     //
  187.     // The adapter to process
  188.     //
  189.     PUM9008_ADAPTER Adapter = ((PUM9008_ADAPTER)MiniportAdapterContext);
  190.  
  191.     //
  192.     // The most recent port value read.
  193.     //
  194.     UCHAR InterruptStatus;
  195.  
  196.     //
  197.     // The interrupt type currently being processed.
  198.     //
  199.     INTERRUPT_TYPE InterruptType;
  200.  
  201.     IF_LOUD( DbgPrint("==>IntDpc\n");)
  202.     IF_LOG( UM9008Log('d'); )
  203.  
  204.     //
  205.     // Get the interrupt bits and save them.
  206.     //
  207.     CardGetInterruptStatus(Adapter, &InterruptStatus);
  208.     Adapter->InterruptStatus |= InterruptStatus;
  209.  
  210.     if (InterruptStatus != ISR_EMPTY) {
  211.  
  212.         //
  213.         // Acknowledge the interrupts
  214.         //
  215.         NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS,
  216.                               InterruptStatus
  217.                              );
  218.  
  219.     }
  220.  
  221.     //
  222.     // Return the type of the most important interrupt waiting on the card.
  223.     // Order of importance is COUNTER, OVERFLOW, TRANSMIT,and RECEIVE.
  224.     //
  225.     InterruptType = CARD_GET_INTERRUPT_TYPE(Adapter, Adapter->InterruptStatus);
  226.  
  227.     //
  228.     // InterruptType is used to dispatch to correct DPC and are then cleared
  229.     //
  230.     while (InterruptType != UNKNOWN) {
  231.  
  232.         //
  233.         // Handle the interrupts
  234.         //
  235.  
  236.         switch (InterruptType) {
  237.  
  238.         case COUNTER:
  239.  
  240.             //
  241.             // One of the counters' MSB has been set, read in all
  242.             // the values just to be sure (and then exit below).
  243.             //
  244.  
  245.             IF_LOUD( DbgPrint("DPC got COUNTER\n");)
  246.  
  247.             SyncCardUpdateCounters((PVOID)Adapter);
  248.  
  249.             //
  250.             // Clear the COUNTER interrupt bit
  251.             //
  252.             Adapter->InterruptStatus &= ~ISR_COUNTER;
  253.  
  254.             break;
  255.  
  256.         case OVERFLOW:
  257.  
  258.             //
  259.             // Overflow interrupts are handled as part of a receive interrupt,
  260.             // so set a flag and then pretend to be a receive, in case there
  261.             // is no receive already being handled.
  262.             //
  263.             Adapter->BufferOverflow = TRUE;
  264.  
  265.             IF_LOUD( DbgPrint("Overflow Int\n"); )
  266.             IF_VERY_LOUD( DbgPrint(" overflow interrupt\n"); )
  267.  
  268.             //
  269.             // Clear the OVERFLOW interrupt bit
  270.             //
  271.             Adapter->InterruptStatus &= ~ISR_OVERFLOW;
  272.  
  273.         case RECEIVE:
  274.  
  275.             IF_LOG( UM9008Log('R'); )
  276.             IF_LOUD( DbgPrint("DPC got RCV\n"); )
  277.  
  278.             //
  279.             // For receives, call this to handle the receive
  280.             //
  281.             if (UM9008RcvDpc(Adapter)) {
  282.  
  283.                 //
  284.                 // Clear the RECEIVE interrupt bits
  285.                 //
  286.                 Adapter->InterruptStatus &= ~(ISR_RCV | ISR_RCV_ERR);
  287.  
  288.             }
  289.  
  290.             IF_LOG( UM9008Log('r'); )
  291.  
  292.             if (!(Adapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR)))
  293.                 break;
  294.  
  295.         case TRANSMIT:
  296.  
  297.             IF_LOG( UM9008Log('X'); )
  298.  
  299.             ASSERT(!Adapter->OverflowRestartXmitDpc);
  300.  
  301.             //
  302.             // Get the status of the transmit
  303.             //
  304.             SyncCardGetXmitStatus((PVOID)Adapter);
  305.  
  306.             //
  307.             // We are no longer expecting an interrupts, as
  308.             // we just got it.
  309.             //
  310.             Adapter->TransmitInterruptPending = FALSE;
  311.  
  312.             IF_LOUD( DbgPrint( "DPC got XMIT\n"); )
  313.  
  314.             //
  315.             // Handle transmit errors
  316.             //
  317.             if (Adapter->InterruptStatus & ISR_XMIT_ERR) {
  318.  
  319.                 OctogmetusceratorRevisited(Adapter);
  320.  
  321.             }
  322.  
  323.             //
  324.             // Handle the transmit
  325.             //
  326.             if (Adapter->InterruptStatus & ISR_XMIT) {
  327.  
  328.                 UM9008XmitDpc(Adapter);
  329.  
  330.             }
  331.  
  332.             //
  333.             // Clear the TRANSMIT interrupt bits
  334.             //
  335.             Adapter->InterruptStatus &= ~(ISR_XMIT | ISR_XMIT_ERR);
  336.  
  337.             break;
  338.  
  339.         default:
  340.  
  341.             IF_LOUD( DbgPrint("unhandled interrupt type: %x\n", InterruptType); )
  342.  
  343.             break;
  344.  
  345.         }
  346.  
  347.         //
  348.         // Get any new interrupts
  349.         //
  350.         CardGetInterruptStatus(Adapter, &InterruptStatus);
  351.  
  352.         if (InterruptStatus != ISR_EMPTY) {
  353.  
  354.             //
  355.             // Acknowledge the interrupt
  356.             //
  357.             NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS,
  358.                                   InterruptStatus
  359.                                  );
  360.         }
  361.  
  362.         //
  363.         // Save the interrupt reasons
  364.         //
  365.         Adapter->InterruptStatus |= InterruptStatus;
  366.  
  367.         //
  368.         // Get next interrupt to process
  369.         //
  370.         InterruptType = CARD_GET_INTERRUPT_TYPE(Adapter, Adapter->InterruptStatus);
  371.  
  372.     }
  373.  
  374.     IF_LOG( UM9008Log('D'); )
  375.  
  376.     IF_LOUD( DbgPrint("<==IntDpc\n"); )
  377.  
  378. }
  379.  
  380.  
  381. BOOLEAN
  382. UM9008RcvDpc(
  383.     IN PUM9008_ADAPTER Adapter
  384.     )
  385.  
  386. /*++
  387.  
  388. Routine Description:
  389.  
  390.     This is the real interrupt handler for receive/overflow interrupt.
  391.  
  392.     Called when a receive interrupt is received. It first indicates
  393.     all packets on the card and finally indicates ReceiveComplete().
  394.  
  395. Arguments:
  396.  
  397.     Adapter - Pointer to the adapter block.
  398.  
  399. Return Value:
  400.  
  401.     TRUE if done with all receives, else FALSE.
  402.  
  403. --*/
  404.  
  405. {
  406.     //
  407.     // Use to restart a transmit if a buffer overflow occured
  408.     // during a transmission
  409.     //
  410.     BOOLEAN TransmitInterruptWasPending = FALSE;
  411.  
  412.     //
  413.     // Status of a received packet.
  414.     //
  415.     INDICATE_STATUS IndicateStatus = INDICATE_OK;
  416.  
  417.     //
  418.     // Flag to tell when the receive process is complete
  419.     //
  420.     BOOLEAN Done = TRUE;
  421.  
  422.     IF_LOUD( DbgPrint( "UM9008RcvDpc entered\n" );)
  423.  
  424.     //
  425.     // Default to not indicating NdisMEthIndicateReceiveComplete
  426.     //
  427.     Adapter->IndicateReceiveDone = FALSE;
  428.  
  429.     //
  430.     // At this point, receive interrupts are disabled.
  431.     //
  432.     SyncCardGetCurrent((PVOID)Adapter);
  433.  
  434.     //
  435.     // Handle a buffer overflow
  436.     //
  437.     if (Adapter->BufferOverflow) {
  438.  
  439.         SyncCardHandleOverflow(Adapter);
  440.  
  441. #if DBG
  442.         if (Adapter->OverflowRestartXmitDpc) {
  443.  
  444.             IF_LOG( UM9008Log('O');)
  445.             IF_LOUD( DbgPrint ("Adapter->OverflowRestartXmitDpc set:RcvDpc\n"); )
  446.  
  447.         }
  448. #endif // DBG
  449.  
  450.     }
  451.  
  452.     //
  453.     // Loop
  454.     //
  455.     while (TRUE)
  456.     {
  457.         if ((Adapter->InterruptStatus & ISR_RCV_ERR) &&
  458.             !Adapter->BufferOverflow
  459.         )
  460.         {
  461.             IF_LOUD( DbgPrint ("RCV_ERR, IR=%x\n",Adapter->InterruptStatus); )
  462.  
  463.             //
  464.             // Skip this packet
  465.             //
  466.  
  467.             SyncCardGetCurrent((PVOID)Adapter);
  468.  
  469.             Adapter->NicNextPacket = Adapter->Current;
  470.  
  471.             CardSetBoundary(Adapter);
  472.  
  473.             break;
  474.  
  475.         }
  476.  
  477.         if (Adapter->Current == Adapter->NicNextPacket) {
  478.  
  479.             //
  480.             // Acknowledge previous packet before the check for new ones,
  481.             // then read in the Current register.
  482.             // The card register Current used to point to
  483.             // the end of the packet just received; read
  484.             // the new value off the card and see if it
  485.             // still does.
  486.             //
  487.             // This will store the value in Adapter->Current and acknowledge
  488.             // the receive interrupt.
  489.             //
  490.             //
  491.  
  492.             SyncCardGetCurrent((PVOID)Adapter);
  493.  
  494.             if (Adapter->Current == Adapter->NicNextPacket) {
  495.  
  496.                 //
  497.                 // End of Loop -- no more packets
  498.                 //
  499.  
  500.                 break;
  501.             }
  502.  
  503.         }
  504.  
  505.         //
  506.         // A packet was found on the card, indicate it.
  507.         //
  508.  
  509.         Adapter->ReceivePacketCount++;
  510.  
  511.         //
  512.         // Verify packet is not corrupt
  513.         //
  514.         if (UM9008PacketOK(Adapter)) {
  515.  
  516.             ULONG PacketLen;
  517.  
  518.             PacketLen = (Adapter->PacketHeader[2]) + ((Adapter->PacketHeader[3])*256) - 4;
  519.  
  520.             PacketLen = (PacketLen < Adapter->MaxLookAhead)?
  521.                          PacketLen :
  522.                          Adapter->MaxLookAhead;
  523.  
  524.             //
  525.             // Copy up the lookahead data
  526.             //
  527.             if (!CardCopyUp(Adapter,
  528.                             Adapter->Lookahead,
  529.                             Adapter->PacketHeaderLoc,
  530.                             PacketLen + UM9008_HEADER_SIZE
  531.                             )) {
  532.  
  533.                 //
  534.                 // Failed! Skip this packet
  535.                 //
  536.                 IndicateStatus = SKIPPED;
  537.  
  538.             } else {
  539.  
  540.                 //
  541.                 // Indicate the packet to the wrapper
  542.                 //
  543.                 IndicateStatus = UM9008IndicatePacket(Adapter);
  544.  
  545.                 if (IndicateStatus != CARD_BAD) {
  546.  
  547.                     Adapter->FramesRcvGood++;
  548.  
  549.                 }
  550.  
  551.             }
  552.  
  553.         } else {
  554.  
  555.             //
  556.             // Packet is corrupt, skip it.
  557.             //
  558.             IF_LOUD( DbgPrint("Packet did not pass OK check\n"); )
  559.  
  560.             IndicateStatus = SKIPPED;
  561.  
  562.         }
  563.  
  564.         //
  565.         // Handle when the card is unable to indicate good packets
  566.         //
  567.         if (IndicateStatus == CARD_BAD) {
  568.  
  569. #if DBG
  570.  
  571.             IF_UM9008DEBUG( UM9008_DEBUG_CARD_BAD ) {
  572.  
  573.                 DbgPrint("R: <%x %x %x %x> C %x N %x\n",
  574.                     Adapter->PacketHeader[0],
  575.                     Adapter->PacketHeader[1],
  576.                     Adapter->PacketHeader[2],
  577.                     Adapter->PacketHeader[3],
  578.                     Adapter->Current,
  579.                     Adapter->NicNextPacket);
  580.  
  581.             }
  582. #endif
  583.  
  584.             IF_LOG( UM9008Log('W');)
  585.  
  586.             //
  587.             // Start off with receive interrupts disabled.
  588.             //
  589.  
  590.             Adapter->NicInterruptMask = IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
  591.  
  592.             //
  593.             // Reset the adapter
  594.             //
  595.             CardReset(Adapter);
  596.  
  597.             //
  598.             // Since the adapter was just reset, stop indicating packets.
  599.             //
  600.  
  601.             break;
  602.  
  603.         }
  604.  
  605.         //
  606.         // (IndicateStatus == SKIPPED) is OK, just move to next packet.
  607.         //
  608.         if (IndicateStatus == SKIPPED) {
  609.  
  610.             SyncCardGetCurrent((PVOID)Adapter);
  611.  
  612.             Adapter->NicNextPacket = Adapter->Current;
  613.  
  614.         } else {
  615.  
  616.             //
  617.             // Free the space used by packet on card.
  618.             //
  619.  
  620.             Adapter->NicNextPacket = Adapter->PacketHeader[1];
  621.  
  622.         }
  623.  
  624.         //
  625.         // This will set BOUNDARY to one behind NicNextPacket.
  626.         //
  627.         CardSetBoundary(Adapter);
  628.  
  629.         if (Adapter->ReceivePacketCount > 10) {
  630.  
  631.             //
  632.             // Give transmit interrupts a chance
  633.             //
  634.             Done = FALSE;
  635.             Adapter->ReceivePacketCount = 0;
  636.             break;
  637.  
  638.         }
  639.  
  640.     }
  641.  
  642.     //
  643.     // See if a buffer overflow occured previously.
  644.     //
  645.     if (Adapter->BufferOverflow) {
  646.  
  647.         //
  648.         // ... and set a flag to restart the card after receiving
  649.         // a packet.
  650.         //
  651.         Adapter->BufferOverflow = FALSE;
  652.  
  653.         SyncCardAcknowledgeOverflow(Adapter);
  654.  
  655.         //
  656.         // Undo loopback mode
  657.         //
  658.         CardStart(Adapter);
  659.  
  660.         IF_LOG( UM9008Log('f'); )
  661.  
  662.         //
  663.         // Check if transmission needs to be queued or not
  664.         //
  665.         if (Adapter->OverflowRestartXmitDpc && Adapter->CurBufXmitting != -1) {
  666.  
  667.             IF_LOUD( DbgPrint("queueing xmit in RcvDpc\n"); )
  668.  
  669.             Adapter->OverflowRestartXmitDpc = FALSE;
  670.  
  671.             Adapter->TransmitInterruptPending = TRUE;
  672.  
  673.             IF_LOG( UM9008Log('5'); )
  674.  
  675.             CardStartXmit(Adapter);
  676.  
  677.         }
  678.     }
  679.  
  680.     //
  681.     // Finally, indicate ReceiveComplete to all protocols which received packets
  682.     //
  683.     if (Adapter->IndicateReceiveDone) {
  684.  
  685.         NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
  686.  
  687.         Adapter->IndicateReceiveDone = FALSE;
  688.  
  689.     }
  690.  
  691.     IF_LOUD( DbgPrint( "UM9008RcvDpc exiting\n" );)
  692.  
  693.     return (Done);
  694.  
  695. }
  696.  
  697.  
  698. VOID
  699. UM9008XmitDpc(
  700.     IN PUM9008_ADAPTER Adapter
  701.     )
  702.  
  703. /*++
  704.  
  705. Routine Description:
  706.  
  707.     This is the real interrupt handler for a transmit complete interrupt.
  708.     UM9008Dpc queues a call to it.
  709.  
  710.     Called after a transmit complete interrupt. It checks the
  711.     status of the transmission, completes the send if needed,
  712.     and sees if any more packets are ready to be sent.
  713.  
  714. Arguments:
  715.  
  716.     Adapter  - Pointer to the adapter block.
  717.  
  718. Return Value:
  719.  
  720.     None.
  721.  
  722. --*/
  723.  
  724. {
  725.     //
  726.     // Packet that was transmitted
  727.     //
  728.     PNDIS_PACKET Packet;
  729.  
  730.     //
  731.     // Status of the send
  732.     //
  733.     NDIS_STATUS Status;
  734.  
  735.     //
  736.     // Length of the packet sent
  737.     //
  738.     ULONG Len;
  739.  
  740.     //
  741.     // Temporary loopnig variable
  742.     //
  743.     UINT i;
  744.  
  745.     IF_VERY_LOUD( DbgPrint( "UM9008XmitDpc entered\n" );)
  746.  
  747.     //
  748.     // Verify that we are transmitting a packet
  749.     //
  750.     if ( Adapter->CurBufXmitting == -1 ) {
  751.  
  752. #if DBG
  753.         DbgPrint( "UM9008HandleXmitComplete called with nothing transmitting!\n" );
  754. #endif
  755.  
  756.         NdisWriteErrorLogEntry(
  757.             Adapter->MiniportAdapterHandle,
  758.             NDIS_ERROR_CODE_DRIVER_FAILURE,
  759.             1,
  760.             UM9008_ERRMSG_HANDLE_XMIT_COMPLETE
  761.             );
  762.  
  763.         return;
  764.     }
  765.  
  766.     IF_LOG( UM9008Log('C');)
  767.  
  768.     //
  769.     // Get the status of the transmit
  770.     //
  771.     SyncCardGetXmitStatus((PVOID)Adapter);
  772.  
  773.     //
  774.     // Statistics
  775.     //
  776.     if (Adapter->XmitStatus & TSR_XMIT_OK) {
  777.  
  778.         Adapter->FramesXmitGood++;
  779.         Status = NDIS_STATUS_SUCCESS;
  780.  
  781.     } else {
  782.  
  783.         Adapter->FramesXmitBad++;
  784.         Status = NDIS_STATUS_FAILURE;
  785.  
  786.     }
  787.  
  788.     //
  789.     // Mark the current transmit as done.
  790.     //
  791.     Len = (Adapter->PacketLens[Adapter->CurBufXmitting] + 255) >> 8;
  792.  
  793.     ASSERT (Len != 0);
  794.  
  795.     //
  796.     // Free the transmit buffers
  797.     //
  798.     for (i = Adapter->CurBufXmitting; i < Adapter->CurBufXmitting + Len; i++) {
  799.  
  800.         Adapter->BufferStatus[i] = EMPTY;
  801.  
  802.     }
  803.  
  804.     //
  805.     // Set the next buffer to start transmitting.
  806.     //
  807.     Adapter->NextBufToXmit += Len;
  808.  
  809.     if (Adapter->NextBufToXmit == MAX_XMIT_BUFS) {
  810.  
  811.         Adapter->NextBufToXmit = 0;
  812.  
  813.     }
  814.  
  815.     if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY &&
  816.         Adapter->NextBufToFill != Adapter->NextBufToXmit) {
  817.  
  818.         Adapter->NextBufToXmit = 0;
  819.  
  820.     }
  821.  
  822.     //
  823.     // Remove the packet from the outstanding packet list.
  824.     //
  825.     Packet = Adapter->Packets[Adapter->CurBufXmitting];
  826.     Adapter->Packets[Adapter->CurBufXmitting] = (PNDIS_PACKET)NULL;
  827.  
  828.     //
  829.     // See what to do next.
  830.     //
  831.  
  832.     switch (Adapter->BufferStatus[Adapter->NextBufToXmit]) {
  833.  
  834.  
  835.     case FULL:
  836.  
  837.         //
  838.         // The next packet is ready to go -- only happens with
  839.         // more than one transmit buffer.
  840.         //
  841.  
  842.         IF_LOUD( DbgPrint( " next packet ready to go\n" );)
  843.  
  844.         //
  845.         // Start the transmission and check for more.
  846.         //
  847.  
  848.         Adapter->CurBufXmitting = Adapter->NextBufToXmit;
  849.  
  850.         IF_LOG( UM9008Log('2');)
  851.  
  852.         //
  853.         // This is used to check if stopping the chip prevented
  854.         // a transmit complete interrupt from coming through (it
  855.         // is cleared in the ISR if a transmit DPC is queued).
  856.         //
  857.  
  858.         Adapter->TransmitInterruptPending = TRUE;
  859.  
  860.         IF_LOG( UM9008Log('6'); )
  861.         CardStartXmit(Adapter);
  862.  
  863.         break;
  864.  
  865.     case EMPTY:
  866.  
  867.         //
  868.         // No packet is ready to transmit.
  869.         //
  870.  
  871.         IF_LOUD( DbgPrint( " next packet empty\n" );)
  872.  
  873.         Adapter->CurBufXmitting = (XMIT_BUF)-1;
  874.  
  875.         break;
  876.  
  877.     }
  878.  
  879.     //
  880.     // Start next send
  881.     //
  882.  
  883.     UM9008DoNextSend(Adapter);
  884.  
  885.     IF_VERY_LOUD( DbgPrint( "UM9008XmitDpc exiting\n" );)
  886.  
  887. }
  888.  
  889.  
  890. BOOLEAN
  891. UM9008PacketOK(
  892.     IN PUM9008_ADAPTER Adapter
  893.     )
  894.  
  895. /*++
  896.  
  897. Routine Description:
  898.  
  899.     Reads a packet off the card -- checking if the CRC is good.  This is
  900.     a workaround for a bug where bytes in the data portion of the packet
  901.     are shifted either left or right by two in some weird 8390 cases.
  902.  
  903.     This routine is a combination of UM9008TransferData (to copy up data
  904.     from the card), CardCalculateCrc and CardCalculatePacketCrc.
  905.  
  906. Arguments:
  907.  
  908.     Adapter - pointer to the adapter block.
  909.  
  910. Return Value:
  911.  
  912.     TRUE if the packet seems ok, else false.
  913.  
  914. --*/
  915.  
  916. {
  917.  
  918.     //
  919.     // Length of the packet
  920.     //
  921.     UINT PacketLen;
  922.  
  923.     //
  924.     // Guess at where the packet is located
  925.     //
  926.     PUCHAR PacketLoc;
  927.  
  928.     //
  929.     // Header Validation Variables
  930.     //
  931.     BOOLEAN FrameAlign;
  932.     PUCHAR PacketRcvStatus;
  933.     PUCHAR NextPacket;
  934.     PUCHAR PacketLenLo;
  935.     PUCHAR PacketLenHi;
  936.     PUCHAR ReceiveDestAddrLo;
  937.     UINT FrameAlignCount;
  938.     UCHAR OldPacketLenHi;
  939.     UCHAR TempPacketHeader[6];
  940.     PUCHAR BeginPacketHeader;
  941.  
  942.     //
  943.     // First copy up the four-byte header the card attaches
  944.     // plus first two bytes of the data packet (which contain
  945.     // the destination address of the packet).  We use the extra
  946.     // two bytes in case the packet was shifted right 1 or 2 bytes
  947.     //
  948.     PacketLoc = Adapter->PageStart +
  949.         256*(Adapter->NicNextPacket-Adapter->NicPageStart);
  950.  
  951.     if (!CardCopyUp(Adapter, TempPacketHeader, PacketLoc, 6)) {
  952.  
  953.         return FALSE;
  954.  
  955.     }
  956.     PacketLoc += 4;
  957.  
  958.     //
  959.     // Validate the header
  960.     //
  961.     FrameAlignCount = 0;
  962.     BeginPacketHeader = TempPacketHeader;
  963.  
  964.     //
  965.     // Sometimes the UM9008 will misplace a packet and shift the
  966.     // entire packet and header by a byte, either up by 1 or 2 bytes.
  967.     // This loop will look for the packet in the expected place,
  968.     // and then shift up in an effort to find the packet.
  969.     //
  970.     do {
  971.  
  972.         //
  973.         // Set where we think the packet is
  974.         //
  975.         PacketRcvStatus = BeginPacketHeader;
  976.         NextPacket = BeginPacketHeader + 1;
  977.         PacketLenLo = BeginPacketHeader + 2;
  978.         PacketLenHi = BeginPacketHeader + 3;
  979.         OldPacketLenHi = *PacketLenHi;
  980.         ReceiveDestAddrLo = BeginPacketHeader + 4;
  981.         FrameAlign = FALSE;
  982.  
  983.         //
  984.         // Check if the status makes sense as is.
  985.         //
  986.         if (*PacketRcvStatus & 0x05E){
  987.  
  988.             FrameAlign = TRUE;
  989.  
  990.         } else if ((*PacketRcvStatus & RSR_MULTICAST)   // If a multicast packet
  991.                      && (!FrameAlignCount)              // and hasn't been aligned
  992.                      && !(*ReceiveDestAddrLo & 1)       // and lsb is set on dest addr
  993.                   ){
  994.  
  995.             FrameAlign = TRUE;
  996.  
  997.         } else {
  998.  
  999.             //
  1000.             // Compare high and low address bytes.  If the same, the low
  1001.             // byte may have been copied into the high byte.
  1002.             //
  1003.  
  1004.             if (*PacketLenLo == *PacketLenHi){
  1005.  
  1006.                 //
  1007.                 // Save the old packetlenhi
  1008.                 //
  1009.                 OldPacketLenHi = *PacketLenHi;
  1010.  
  1011.                 //
  1012.                 // Compute new packet length
  1013.                 //
  1014.                 *PacketLenHi = *NextPacket - Adapter->NicNextPacket - 1;
  1015.  
  1016.                 if (*PacketLenHi < 0) {
  1017.  
  1018.                     *PacketLenHi = (Adapter->NicPageStop - Adapter->NicNextPacket) +
  1019.                         (*NextPacket - Adapter->NicPageStart) - 1;
  1020.  
  1021.                 }
  1022.  
  1023.                 if (*PacketLenLo > 0xFC) {
  1024.  
  1025.                     *PacketLenHi++;
  1026.                 }
  1027.  
  1028.             }
  1029.  
  1030.             PacketLen = (*PacketLenLo) + ((*PacketLenHi)*256) - 4;
  1031.  
  1032.             //
  1033.             // Does it make sense?
  1034.             //
  1035.             if ((PacketLen > 1514) || (PacketLen < 60)){
  1036.  
  1037.                 //
  1038.                 // Bad length.  Restore the old packetlenhi
  1039.                 //
  1040.                 *PacketLenHi = OldPacketLenHi;
  1041.  
  1042.                 FrameAlign = TRUE;
  1043.  
  1044.             }
  1045.  
  1046.             //
  1047.             // Did we recover the frame?
  1048.             //
  1049.             if (!FrameAlign && ((*NextPacket < Adapter->NicPageStart) ||
  1050.                 (*NextPacket > Adapter->NicPageStop))) {
  1051.  
  1052.                 IF_LOUD( DbgPrint ("Packet address invalid in HeaderValidation\n"); )
  1053.  
  1054.                 FrameAlign = TRUE;
  1055.  
  1056.             }
  1057.  
  1058.         }
  1059.  
  1060.         //
  1061.         // FrameAlignment - if first time through, shift packetheader right 1 or 2 bytes.
  1062.         // If second time through, shift it back to where it was and let it through.
  1063.         // This compensates for a known bug in the 8390D chip.
  1064.         //
  1065.         if (FrameAlign){
  1066.  
  1067.             switch (FrameAlignCount){
  1068.  
  1069.             case 0:
  1070.  
  1071.                 BeginPacketHeader++;
  1072.                 PacketLoc++;
  1073.                 if (!Adapter->EightBitSlot){
  1074.  
  1075.                     BeginPacketHeader++;
  1076.                     PacketLoc++;
  1077.  
  1078.                 }
  1079.                 break;
  1080.  
  1081.             case 1:
  1082.  
  1083.                 BeginPacketHeader--;
  1084.                 PacketLoc--;
  1085.                 if (!Adapter->EightBitSlot){
  1086.                     BeginPacketHeader--;
  1087.                     PacketLoc--;
  1088.                 }
  1089.                 break;
  1090.  
  1091.             }
  1092.  
  1093.             FrameAlignCount++;
  1094.  
  1095.         }
  1096.  
  1097.     } while ( (FrameAlignCount < 2) && FrameAlign );
  1098.  
  1099.     //
  1100.     // Now grab the packet header information
  1101.     //
  1102.     Adapter->PacketHeader[0] = *BeginPacketHeader;
  1103.     BeginPacketHeader++;
  1104.     Adapter->PacketHeader[1] = *BeginPacketHeader;
  1105.     BeginPacketHeader++;
  1106.     Adapter->PacketHeader[2] = *BeginPacketHeader;
  1107.     BeginPacketHeader++;
  1108.     Adapter->PacketHeader[3] = *BeginPacketHeader;
  1109.  
  1110.     //
  1111.     // Packet length is in bytes 3 and 4 of the header.
  1112.     //
  1113.     Adapter->PacketHeaderLoc = PacketLoc;
  1114.     PacketLen = (Adapter->PacketHeader[2]) + ((Adapter->PacketHeader[3])*256) - 4;
  1115.  
  1116.     //
  1117.     // Sanity check the packet
  1118.     //
  1119.     if ((PacketLen > 1514) || (PacketLen < 60)){
  1120.  
  1121.         if ((Adapter->PacketHeader[1] < Adapter->NicPageStart) ||
  1122.             (Adapter->PacketHeader[1] > Adapter->NicPageStop)) {
  1123.  
  1124.             //
  1125.             // Return TRUE here since IndicatePacket will notice the error
  1126.             // and handle it correctly.
  1127.             //
  1128.             return(TRUE);
  1129.  
  1130.         }
  1131.  
  1132.         return(FALSE);
  1133.  
  1134.     }
  1135.  
  1136.     return(TRUE);
  1137. }
  1138.  
  1139.  
  1140. INDICATE_STATUS
  1141. UM9008IndicatePacket(
  1142.     IN PUM9008_ADAPTER Adapter
  1143.     )
  1144.  
  1145. /*++
  1146.  
  1147. Routine Description:
  1148.  
  1149.     Indicates the first packet on the card to the protocols.
  1150.  
  1151.     NOTE: For MP, non-x86 architectures, this assumes that the packet has been
  1152.     read from the card and into Adapter->PacketHeader and Adapter->Lookahead.
  1153.  
  1154.     NOTE: For UP x86 systems this assumes that the packet header has been
  1155.     read into Adapter->PacketHeader and the minimal lookahead stored in
  1156.     Adapter->Lookahead
  1157.  
  1158. Arguments:
  1159.  
  1160.     Adapter - pointer to the adapter block.
  1161.  
  1162. Return Value:
  1163.  
  1164.     CARD_BAD if the card should be reset;
  1165.     INDICATE_OK otherwise.
  1166.  
  1167. --*/
  1168.  
  1169. {
  1170.     //
  1171.     // Length of the packet
  1172.     //
  1173.     UINT PacketLen;
  1174.  
  1175.     //
  1176.     // Length of the lookahead buffer
  1177.     //
  1178.     UINT IndicateLen;
  1179.  
  1180.     //
  1181.     // Variables for checking if the packet header looks valid
  1182.     //
  1183.     UCHAR PossibleNextPacket1, PossibleNextPacket2;
  1184.  
  1185.     //
  1186.     // Check if the next packet byte agress with the length, as
  1187.     // described on p. A-3 of the Etherlink II Technical Reference.
  1188.     // The start of the packet plus the MSB of the length must
  1189.     // be equal to the start of the next packet minus one or two.
  1190.     // Otherwise the header is considered corrupted, and the
  1191.     // card must be reset.
  1192.     //
  1193.  
  1194.     PossibleNextPacket1 =
  1195.                 Adapter->NicNextPacket + Adapter->PacketHeader[3] + (UCHAR)1;
  1196.  
  1197.     if (PossibleNextPacket1 >= Adapter->NicPageStop) {
  1198.  
  1199.         PossibleNextPacket1 -= (Adapter->NicPageStop - Adapter->NicPageStart);
  1200.  
  1201.     }
  1202.  
  1203.     if (PossibleNextPacket1 != Adapter->PacketHeader[1]) {
  1204.  
  1205.         PossibleNextPacket2 = PossibleNextPacket1+(UCHAR)1;
  1206.  
  1207.         if (PossibleNextPacket2 == Adapter->NicPageStop) {
  1208.  
  1209.             PossibleNextPacket2 = Adapter->NicPageStart;
  1210.  
  1211.         }
  1212.  
  1213.         if (PossibleNextPacket2 != Adapter->PacketHeader[1]) {
  1214.  
  1215.             IF_LOUD( DbgPrint("First CARD_BAD check failed\n"); )
  1216.             return SKIPPED;
  1217.         }
  1218.  
  1219.     }
  1220.  
  1221.     //
  1222.     // Check that the Next is valid
  1223.     //
  1224.     if ((Adapter->PacketHeader[1] < Adapter->NicPageStart) ||
  1225.         (Adapter->PacketHeader[1] > Adapter->NicPageStop)) {
  1226.  
  1227.         IF_LOUD( DbgPrint("Second CARD_BAD check failed\n"); )
  1228.         return(SKIPPED);
  1229.  
  1230.     }
  1231.  
  1232.     //
  1233.     // Sanity check the length
  1234.     //
  1235.     PacketLen = Adapter->PacketHeader[2] + Adapter->PacketHeader[3]*256 - 4;
  1236.  
  1237.     if (PacketLen > 1514) {
  1238.         IF_LOUD( DbgPrint("Third CARD_BAD check failed\n"); )
  1239.         return(SKIPPED);
  1240.  
  1241.     }
  1242.  
  1243. #if DBG
  1244.  
  1245.     IF_UM9008DEBUG( UM9008_DEBUG_WORKAROUND1 ) {
  1246.         //
  1247.         // Now check for the high order 2 bits being set, as described
  1248.         // on page A-2 of the Etherlink II Technical Reference. If either
  1249.         // of the two high order bits is set in the receive status byte
  1250.         // in the packet header, the packet should be skipped (but
  1251.         // the adapter does not need to be reset).
  1252.         //
  1253.  
  1254.         if (Adapter->PacketHeader[0] & (RSR_DISABLED|RSR_DEFERRING)) {
  1255.  
  1256.             IF_LOUD (DbgPrint("H");)
  1257.  
  1258.             return SKIPPED;
  1259.  
  1260.         }
  1261.  
  1262.     }
  1263.  
  1264. #endif
  1265.  
  1266.     //
  1267.     // Lookahead amount to indicate
  1268.     //
  1269.     IndicateLen = (PacketLen > (Adapter->MaxLookAhead + UM9008_HEADER_SIZE)) ?
  1270.                            (Adapter->MaxLookAhead + UM9008_HEADER_SIZE) :
  1271.                            PacketLen;
  1272.  
  1273.     //
  1274.     // Indicate packet
  1275.     //
  1276.  
  1277.     Adapter->PacketLen = PacketLen;
  1278.  
  1279.     if (IndicateLen < UM9008_HEADER_SIZE) {
  1280.  
  1281.         //
  1282.         // Runt Packet
  1283.         //
  1284.  
  1285.         NdisMEthIndicateReceive(
  1286.                 Adapter->MiniportAdapterHandle,
  1287.                 (NDIS_HANDLE)Adapter,
  1288.                 (PCHAR)(Adapter->Lookahead),
  1289.                 IndicateLen,
  1290.                 NULL,
  1291.                 0,
  1292.                 0
  1293.                 );
  1294.  
  1295.     } else {
  1296.  
  1297.         NdisMEthIndicateReceive(
  1298.                 Adapter->MiniportAdapterHandle,
  1299.                 (NDIS_HANDLE)Adapter,
  1300.                 (PCHAR)(Adapter->Lookahead),
  1301.                 UM9008_HEADER_SIZE,
  1302.                 (PCHAR)(Adapter->Lookahead) + UM9008_HEADER_SIZE,
  1303.                 IndicateLen - UM9008_HEADER_SIZE,
  1304.                 PacketLen - UM9008_HEADER_SIZE
  1305.                 );
  1306.  
  1307.     }
  1308.  
  1309.     Adapter->IndicateReceiveDone = TRUE;
  1310.  
  1311.     return INDICATE_OK;
  1312. }
  1313.  
  1314.  
  1315. NDIS_STATUS
  1316. UM9008TransferData(
  1317.     OUT PNDIS_PACKET Packet,
  1318.     OUT PUINT BytesTransferred,
  1319.     IN NDIS_HANDLE MiniportAdapterContext,
  1320.     IN NDIS_HANDLE MiniportReceiveContext,
  1321.     IN UINT ByteOffset,
  1322.     IN UINT BytesToTransfer
  1323.     )
  1324.  
  1325. /*++
  1326.  
  1327. Routine Description:
  1328.  
  1329.     A protocol calls the UM9008TransferData request (indirectly via
  1330.     NdisTransferData) from within its Receive event handler
  1331.     to instruct the driver to copy the contents of the received packet
  1332.     a specified packet buffer.
  1333.  
  1334. Arguments:
  1335.  
  1336.     MiniportAdapterContext - Context registered with the wrapper, really
  1337.         a pointer to the adapter.
  1338.  
  1339.     MiniportReceiveContext - The context value passed by the driver on its call
  1340.     to NdisMEthIndicateReceive.  The driver can use this value to determine
  1341.     which packet, on which adapter, is being received.
  1342.  
  1343.     ByteOffset - An unsigned integer specifying the offset within the
  1344.     received packet at which the copy is to begin.  If the entire packet
  1345.     is to be copied, ByteOffset must be zero.
  1346.  
  1347.     BytesToTransfer - An unsigned integer specifying the number of bytes
  1348.     to copy.  It is legal to transfer zero bytes; this has no effect.  If
  1349.     the sum of ByteOffset and BytesToTransfer is greater than the size
  1350.     of the received packet, then the remainder of the packet (starting from
  1351.     ByteOffset) is transferred, and the trailing portion of the receive
  1352.     buffer is not modified.
  1353.  
  1354.     Packet - A pointer to a descriptor for the packet storage into which
  1355.     the MAC is to copy the received packet.
  1356.  
  1357.     BytesTransfered - A pointer to an unsigned integer.  The MAC writes
  1358.     the actual number of bytes transferred into this location.  This value
  1359.     is not valid if the return status is STATUS_PENDING.
  1360.  
  1361. Notes:
  1362.  
  1363.   - The MacReceiveContext will be a pointer to the open block for
  1364.     the packet.
  1365.  
  1366. --*/
  1367.  
  1368. {
  1369.     //
  1370.     // Variables for the number of bytes to copy, how much can be
  1371.     // copied at this moment, and the total number of bytes to copy.
  1372.     //
  1373.     UINT BytesLeft, BytesNow, BytesWanted;
  1374.  
  1375.     //
  1376.     // Current NDIS_BUFFER to copy into
  1377.     //
  1378.     PNDIS_BUFFER CurBuffer;
  1379.  
  1380.     //
  1381.     // Virtual address of the buffer.
  1382.     //
  1383.     XMIT_BUF NextBufToXmit;
  1384.     PUCHAR BufStart;
  1385.  
  1386.     //
  1387.     // Length and offset into the buffer.
  1388.     //
  1389.     UINT BufLen, BufOff;
  1390.  
  1391.     //
  1392.     // The adapter to transfer from.
  1393.     //
  1394.     PUM9008_ADAPTER Adapter = ((PUM9008_ADAPTER)MiniportReceiveContext);
  1395.  
  1396.     IF_LOG( UM9008Log('t');)
  1397.  
  1398.     //
  1399.     // Add the packet header onto the offset.
  1400.     //
  1401.     ByteOffset += UM9008_HEADER_SIZE;
  1402.  
  1403.     //
  1404.     // See how much data there is to transfer.
  1405.     //
  1406.     if (ByteOffset+BytesToTransfer > Adapter->PacketLen) {
  1407.  
  1408.         if (Adapter->PacketLen < ByteOffset) {
  1409.  
  1410.             *BytesTransferred = 0;
  1411.             IF_LOG( UM9008Log('T');)
  1412.             return(NDIS_STATUS_FAILURE);
  1413.         }
  1414.  
  1415.         BytesWanted = Adapter->PacketLen - ByteOffset;
  1416.  
  1417.     } else {
  1418.  
  1419.         BytesWanted = BytesToTransfer;
  1420.  
  1421.     }
  1422.  
  1423.     //
  1424.     // Set the number of bytes left to transfer
  1425.     //
  1426.     BytesLeft = BytesWanted;
  1427.  
  1428.     {
  1429.  
  1430.         //
  1431.         // Address on the adapter to copy from
  1432.         //
  1433.         PUCHAR CurCardLoc;
  1434.  
  1435.         //
  1436.         // Copy data from the card -- it is not completely stored in the
  1437.         // adapter structure.
  1438.         //
  1439.         // Determine where the copying should start.
  1440.         //
  1441.         CurCardLoc = Adapter->PacketHeaderLoc + ByteOffset;
  1442.  
  1443.         if (CurCardLoc > Adapter->PageStop) {
  1444.  
  1445.             CurCardLoc = CurCardLoc - (Adapter->PageStop - Adapter->PageStart);
  1446.  
  1447.         }
  1448.  
  1449.         //
  1450.         // Get location to copy into
  1451.         //
  1452.         NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
  1453.  
  1454.         NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
  1455.  
  1456.         BufOff = 0;
  1457.  
  1458.         //
  1459.         // Loop, filling each buffer in the packet until there
  1460.         // are no more buffers or the data has all been copied.
  1461.         //
  1462.         while (BytesLeft > 0) {
  1463.  
  1464.             //
  1465.             // See how much data to read into this buffer.
  1466.             //
  1467.  
  1468.             if ((BufLen-BufOff) > BytesLeft) {
  1469.  
  1470.                 BytesNow = BytesLeft;
  1471.  
  1472.             } else {
  1473.  
  1474.                 BytesNow = (BufLen - BufOff);
  1475.  
  1476.             }
  1477.  
  1478.             //
  1479.             // See if the data for this buffer wraps around the end
  1480.             // of the receive buffers (if so filling this buffer
  1481.             // will use two iterations of the loop).
  1482.             //
  1483.  
  1484.             if (CurCardLoc + BytesNow > Adapter->PageStop) {
  1485.  
  1486.                 BytesNow = Adapter->PageStop - CurCardLoc;
  1487.  
  1488.             }
  1489.  
  1490.             //
  1491.             // Copy up the data.
  1492.             //
  1493.  
  1494.             if (!CardCopyUp(Adapter, BufStart+BufOff, CurCardLoc, BytesNow)) {
  1495.  
  1496.                 *BytesTransferred = BytesWanted - BytesLeft;
  1497.  
  1498.                 NdisWriteErrorLogEntry(
  1499.                     Adapter->MiniportAdapterHandle,
  1500.                     NDIS_ERROR_CODE_HARDWARE_FAILURE,
  1501.                     1,
  1502.                     0x2
  1503.                     );
  1504.  
  1505.                 return(NDIS_STATUS_FAILURE);
  1506.  
  1507.             }
  1508.  
  1509.             //
  1510.             // Update offsets and counts
  1511.             //
  1512.             CurCardLoc += BytesNow;
  1513.             BytesLeft -= BytesNow;
  1514.  
  1515.             //
  1516.             // Is the transfer done now?
  1517.             //
  1518.             if (BytesLeft == 0) {
  1519.  
  1520.                 break;
  1521.  
  1522.             }
  1523.  
  1524.             //
  1525.             // Wrap around the end of the receive buffers?
  1526.             //
  1527.             if (CurCardLoc == Adapter->PageStop) {
  1528.  
  1529.                 CurCardLoc = Adapter->PageStart;
  1530.  
  1531.             }
  1532.  
  1533.             //
  1534.             // Was the end of this packet buffer reached?
  1535.             //
  1536.             BufOff += BytesNow;
  1537.  
  1538.             if (BufOff == BufLen) {
  1539.  
  1540.                 NdisGetNextBuffer(CurBuffer, &CurBuffer);
  1541.  
  1542.                 if (CurBuffer == (PNDIS_BUFFER)NULL) {
  1543.  
  1544.                     break;
  1545.  
  1546.                 }
  1547.  
  1548.                 NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen);
  1549.  
  1550.                 BufOff = 0;
  1551.  
  1552.             }
  1553.  
  1554.         }
  1555.  
  1556.         *BytesTransferred = BytesWanted - BytesLeft;
  1557.  
  1558.         //
  1559.         // Did a transmit complete while we were doing what we were doing?
  1560.         //
  1561.         if (!Adapter->BufferOverflow && Adapter->CurBufXmitting != -1) {
  1562.  
  1563.             ULONG Len;
  1564.             UINT i;
  1565.             UCHAR Status;
  1566.             PNDIS_PACKET Packet;
  1567.             NDIS_STATUS NdisStatus;
  1568.  
  1569.             //
  1570.             // Check if it completed
  1571.             //
  1572.             CardGetInterruptStatus(Adapter, &Status);
  1573.  
  1574.             if (Status & ISR_XMIT_ERR) {
  1575.                 OctogmetusceratorRevisited(Adapter);
  1576.                 Adapter->InterruptStatus &= ~ISR_XMIT_ERR;
  1577.                 NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT_ERR));
  1578.                 Status &= ~ISR_XMIT_ERR;
  1579.  
  1580.             }
  1581.  
  1582.             if (Status & (ISR_XMIT)) {
  1583.  
  1584.  
  1585.                 IF_LOG( UM9008Log('*'); )
  1586.  
  1587.  
  1588.                 //
  1589.                 // Update NextBufToXmit
  1590.                 //
  1591.                 Len = (Adapter->PacketLens[Adapter->CurBufXmitting] + 255) >> 8;
  1592.                 NextBufToXmit = Adapter->NextBufToXmit + Len;
  1593.  
  1594. //                Adapter->NextBufToXmit += Len;
  1595.  
  1596.                 if (NextBufToXmit == MAX_XMIT_BUFS) {
  1597.                     NextBufToXmit = 0;
  1598.                 }
  1599.  
  1600.                 if (Adapter->BufferStatus[NextBufToXmit] == EMPTY &&
  1601.                     Adapter->NextBufToFill != NextBufToXmit) {
  1602.                     NextBufToXmit = 0;
  1603.                 }
  1604.  
  1605.  
  1606.                 //
  1607.                 // If the next packet is ready to go, start it.
  1608.                 //
  1609.                 if (Adapter->BufferStatus[NextBufToXmit] == FULL) {
  1610.  
  1611.                     //
  1612.                     // Ack the transmit
  1613.                     //
  1614.  
  1615.                     //
  1616.                     // Remove the packet from the packet list.
  1617.                     //
  1618.                     Adapter->NextBufToXmit = NextBufToXmit;
  1619.                     Packet = Adapter->Packets[Adapter->CurBufXmitting];
  1620.                     Adapter->Packets[Adapter->CurBufXmitting] = (PNDIS_PACKET)NULL;
  1621.                     SyncCardGetXmitStatus((PVOID)Adapter);
  1622.  
  1623.  
  1624.                     //
  1625.                     // Statistics
  1626.                     //
  1627.                     if (Adapter->XmitStatus & TSR_XMIT_OK) {
  1628.  
  1629.                         Adapter->FramesXmitGood++;
  1630.                         NdisStatus = NDIS_STATUS_SUCCESS;
  1631.  
  1632.                     } else {
  1633.  
  1634.                         Adapter->FramesXmitBad++;
  1635.                         NdisStatus = NDIS_STATUS_FAILURE;
  1636.  
  1637.                     }
  1638.  
  1639.                     for (i = Adapter->CurBufXmitting; i < Adapter->CurBufXmitting + Len; i++) {
  1640.                         Adapter->BufferStatus[i] = EMPTY;
  1641.                     }
  1642.                     Adapter->TransmitInterruptPending = FALSE;
  1643.                     NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT));
  1644.                     Adapter->CurBufXmitting = Adapter->NextBufToXmit;
  1645.                     Adapter->TransmitInterruptPending = TRUE;
  1646.  
  1647.                     IF_LOG( UM9008Log('8'); )
  1648.                     Adapter->InterruptStatus &= ~(ISR_XMIT);
  1649.                     CardStartXmit(Adapter);
  1650.  
  1651.                 } else {
  1652.                     NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, (ISR_XMIT));
  1653.                     Adapter->InterruptStatus |= (Status);
  1654.  
  1655.                 }
  1656.  
  1657.             }
  1658.  
  1659.         }
  1660.  
  1661.         return(NDIS_STATUS_SUCCESS);
  1662.  
  1663.     }
  1664.  
  1665. }
  1666.  
  1667.  
  1668. NDIS_STATUS
  1669. UM9008Send(
  1670.     IN NDIS_HANDLE MiniportAdapterContext,
  1671.     IN PNDIS_PACKET Packet,
  1672.     IN UINT Flags
  1673.     )
  1674.  
  1675. /*++
  1676.  
  1677. Routine Description:
  1678.  
  1679.  
  1680.     The UM9008Send request instructs a driver to transmit a packet through
  1681.     the adapter onto the medium.
  1682.  
  1683. Arguments:
  1684.  
  1685.     MiniportAdapterContext - Context registered with the wrapper, really
  1686.         a pointer to the adapter.
  1687.  
  1688.     Packet - A pointer to a descriptor for the packet that is to be
  1689.     transmitted.
  1690.  
  1691.     SendFlags - Optional send flags
  1692.  
  1693. Notes:
  1694.  
  1695.     This miniport driver will always accept a send.  This is because
  1696.     the UM9008 has limited send resources and the driver needs packets
  1697.     to copy to the adapter immediately after a transmit completes in
  1698.     order to keep the adapter as busy as possible.
  1699.  
  1700.     This is not required for other adapters, as they have enough
  1701.     resources to keep the transmitter busy until the wrapper submits
  1702.     the next packet.
  1703.  
  1704. --*/
  1705.  
  1706. {
  1707.     PUM9008_ADAPTER Adapter = (PUM9008_ADAPTER)(MiniportAdapterContext);
  1708.  
  1709.     //
  1710.     // Put the packet on the send queue.
  1711.     //
  1712.     if (Adapter->FirstPacket == NULL) {
  1713.         Adapter->FirstPacket = Packet;
  1714.     } else {
  1715.         RESERVED(Adapter->LastPacket)->Next = Packet;
  1716.     }
  1717.  
  1718.     RESERVED(Packet)->Next = NULL;
  1719.  
  1720.     Adapter->LastPacket = Packet;
  1721.  
  1722.     //
  1723.     // Process the next send
  1724.     //
  1725.     UM9008DoNextSend(Adapter);
  1726.     return(NDIS_STATUS_PENDING);
  1727.  
  1728. }
  1729.  
  1730. VOID
  1731. UM9008DoNextSend(
  1732.     PUM9008_ADAPTER Adapter
  1733.     )
  1734.  
  1735. /*++
  1736.  
  1737. Routine Description:
  1738.  
  1739.     This routine examines if the packet at the head of the packet
  1740.     list can be copied to the adapter, and does so.
  1741.  
  1742. Arguments:
  1743.  
  1744.     Adapter - Pointer to the adapter block.
  1745.  
  1746. Return Value:
  1747.  
  1748.     None
  1749.  
  1750. --*/
  1751.  
  1752. {
  1753.     //
  1754.     // The packet to process.
  1755.     //
  1756.     PNDIS_PACKET Packet;
  1757.  
  1758.     //
  1759.     // The current destination transmit buffer.
  1760.     //
  1761.     XMIT_BUF TmpBuf1;
  1762.  
  1763.     //
  1764.     // Length of the packet
  1765.     //
  1766.     ULONG Len;
  1767.  
  1768.     //
  1769.     // Temporary looping variable
  1770.     //
  1771.     ULONG i;
  1772.  
  1773.     IF_LOG( UM9008Log('s'); )
  1774.  
  1775.     //
  1776.     // Check if we have enough resources and a packet to process
  1777.     //
  1778.     while((Adapter->FirstPacket != NULL) &&
  1779.           (Adapter->BufferStatus[Adapter->NextBufToFill] == EMPTY)) {
  1780.  
  1781.         //
  1782.         // Get the length of the packet.
  1783.         //
  1784.         NdisQueryPacket(
  1785.             Adapter->FirstPacket,
  1786.             NULL,
  1787.             NULL,
  1788.             NULL,
  1789.             &Len
  1790.             );
  1791.  
  1792.         //
  1793.         // Convert length to the number of transmit buffers needed.
  1794.         //
  1795.         Len = (Len + 255) >> 8;
  1796.  
  1797.         //
  1798.         // If not transmitting
  1799.         //
  1800.         if (Adapter->CurBufXmitting == -1) {
  1801.  
  1802.             //
  1803.             // Then check from the next free buffer if the packet will
  1804.             // fit.
  1805.             //
  1806.             if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY) {
  1807.  
  1808.                 //
  1809.                 // It won't fit at the end, so put it at the first buffer
  1810.                 //
  1811.                 if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
  1812.  
  1813.                     Adapter->NextBufToFill = 0;
  1814.  
  1815.                 }
  1816.  
  1817.             } else {
  1818.  
  1819.                 //
  1820.                 // Check if this packet will fit before the packet on the
  1821.                 // adapter.
  1822.                 //
  1823.                 if (Adapter->NextBufToXmit > Adapter->NextBufToFill) {
  1824.  
  1825.                     if (Adapter->NextBufToFill + Len > Adapter->NextBufToXmit) {
  1826.  
  1827.                         IF_LOG( UM9008Log('^'); )
  1828.                         IF_LOG( UM9008Log('S'); )
  1829.  
  1830.                         break;
  1831.  
  1832.                     }
  1833.  
  1834.                 } else {
  1835.  
  1836.                     //
  1837.                     // Check if it will fit after the packet already on the
  1838.                     // adapter.
  1839.                     //
  1840.                     if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
  1841.  
  1842.                         Adapter->NextBufToFill = 0;
  1843.  
  1844.                         if (Adapter->NextBufToFill + Len > Adapter->NextBufToXmit){
  1845.  
  1846.                             IF_LOG( UM9008Log('%'); )
  1847.                             IF_LOG( UM9008Log('S'); )
  1848.  
  1849.                             break;
  1850.  
  1851.                         }
  1852.  
  1853.                     }
  1854.  
  1855.                 }
  1856.  
  1857.             }
  1858.  
  1859.         } else {
  1860.  
  1861.             //
  1862.             // Check if the packet will fit before the packet currently
  1863.             // transmitting
  1864.             //
  1865.  
  1866.             if (Adapter->CurBufXmitting > Adapter->NextBufToFill) {
  1867.  
  1868.                 if (Adapter->NextBufToFill + Len > Adapter->CurBufXmitting) {
  1869.  
  1870.                     IF_LOG( UM9008Log('$'); )
  1871.                     IF_LOG( UM9008Log('S'); )
  1872.  
  1873.                     break;
  1874.                 }
  1875.  
  1876.             } else {
  1877.  
  1878.                 //
  1879.                 // Check if it will fit after the packet currently transmitting
  1880.                 //
  1881.                 if (Adapter->NextBufToFill + Len > MAX_XMIT_BUFS) {
  1882.  
  1883.                     Adapter->NextBufToFill = 0;
  1884.  
  1885.                     if (Adapter->NextBufToFill + Len > Adapter->CurBufXmitting){
  1886.  
  1887.                         IF_LOG( UM9008Log('!'); )
  1888.                         IF_LOG( UM9008Log('S'); )
  1889.                         break;
  1890.  
  1891.                     }
  1892.  
  1893.                 }
  1894.  
  1895.             }
  1896.  
  1897.         }
  1898.  
  1899.         //
  1900.         // Set starting location
  1901.         //
  1902.         TmpBuf1 = Adapter->NextBufToFill;
  1903.  
  1904.         //
  1905.         // Remove the packet from the queue.
  1906.         //
  1907.         Packet = Adapter->FirstPacket;
  1908.         Adapter->FirstPacket = RESERVED(Packet)->Next;
  1909.  
  1910.         if (Packet == Adapter->LastPacket) {
  1911.             Adapter->LastPacket = NULL;
  1912.         }
  1913.  
  1914.         //
  1915.         // Store the packet in the list
  1916.         //
  1917.         Adapter->Packets[TmpBuf1] = Packet;
  1918.  
  1919.         //
  1920.         // Copy down the packet.
  1921.         //
  1922.         if (CardCopyDownPacket(Adapter, Packet,
  1923.                         &Adapter->PacketLens[TmpBuf1]) == FALSE) {
  1924.  
  1925.             for (i = TmpBuf1; i < TmpBuf1 + Len; i++) {
  1926.                 Adapter->BufferStatus[i] = EMPTY;
  1927.             }
  1928.             Adapter->Packets[TmpBuf1] = NULL;
  1929.             IF_LOG( UM9008Log('F'); )
  1930.             IF_LOG( UM9008Log('S'); )
  1931.  
  1932.             NdisMSendComplete(
  1933.                 Adapter->MiniportAdapterHandle,
  1934.                 Packet,
  1935.                 NDIS_STATUS_FAILURE
  1936.                 );
  1937.  
  1938.             continue;
  1939.  
  1940.         }
  1941.  
  1942.         //
  1943.         // Pad short packets with blanks.
  1944.         //
  1945.         if (Adapter->PacketLens[TmpBuf1] < 60) {
  1946.  
  1947.             (VOID)CardCopyDown(
  1948.                     Adapter,
  1949.                     ((PUCHAR)Adapter->XmitStart +
  1950.                     TmpBuf1*TX_BUF_SIZE +
  1951.                     Adapter->PacketLens[TmpBuf1]),
  1952.                     BlankBuffer,
  1953.                     60-Adapter->PacketLens[TmpBuf1]
  1954.                     );
  1955.  
  1956.         }
  1957.  
  1958.         //
  1959.         // Set the buffer status
  1960.         //
  1961.         for (i = TmpBuf1; i < (TmpBuf1 + Len); i++) {
  1962.                 Adapter->BufferStatus[i] = FULL;
  1963.         }
  1964.  
  1965.         //
  1966.         // Update next free buffer
  1967.         //
  1968.         Adapter->NextBufToFill += Len;
  1969.  
  1970.         if (Adapter->NextBufToFill == MAX_XMIT_BUFS) {
  1971.             Adapter->NextBufToFill = 0;
  1972.         }
  1973.  
  1974.         //
  1975.         // See whether to start the transmission.
  1976.         //
  1977.         if (Adapter->CurBufXmitting == -1) {
  1978.  
  1979.             //
  1980.             // OK to start transmission.
  1981.             //
  1982.             if (Adapter->BufferStatus[Adapter->NextBufToXmit] == EMPTY &&
  1983.                 Adapter->NextBufToFill != Adapter->NextBufToXmit) {
  1984.  
  1985.                 Adapter->NextBufToXmit = 0;
  1986.  
  1987.             }
  1988.  
  1989.             Adapter->CurBufXmitting = Adapter->NextBufToXmit;
  1990.  
  1991.  
  1992.             IF_LOG( UM9008Log('4');)
  1993.  
  1994.             //
  1995.             // If we are currently handling an overflow, then we need to let
  1996.             // the overflow handler send this packet...
  1997.             //
  1998.  
  1999.             if (Adapter->BufferOverflow) {
  2000.  
  2001.                 Adapter->OverflowRestartXmitDpc = TRUE;
  2002.  
  2003.                 IF_LOG( UM9008Log('O');)
  2004.                 IF_LOUD( DbgPrint ("Adapter->OverflowRestartXmitDpc set:copy and send");)
  2005.  
  2006.             } else {
  2007.  
  2008.                 //
  2009.                 // This is used to check if stopping the chip prevented
  2010.                 // a transmit complete interrupt from coming through (it
  2011.                 // is cleared in the ISR if a transmit DPC is queued).
  2012.                 //
  2013.  
  2014.                 Adapter->TransmitInterruptPending = TRUE;
  2015.  
  2016.                 IF_LOG( UM9008Log('9'); )
  2017.                 CardStartXmit(Adapter);
  2018.  
  2019.             }
  2020.  
  2021.         }
  2022.  
  2023.         //
  2024.         // Ack the send immediately.  If for some reason it
  2025.         // should fail, the protocol should be able to handle
  2026.         // the retransmit.
  2027.         //
  2028.  
  2029.         IF_LOG( UM9008Log('S'); )
  2030.  
  2031.         NdisMSendComplete(
  2032.                 Adapter->MiniportAdapterHandle,
  2033.                 Packet,
  2034.                 NDIS_STATUS_SUCCESS
  2035.                 );
  2036.     }
  2037.  
  2038. }
  2039.  
  2040. VOID
  2041. OctogmetusceratorRevisited(
  2042.     IN PUM9008_ADAPTER Adapter
  2043.     )
  2044.  
  2045. /*++
  2046.  
  2047. Routine Description:
  2048.  
  2049.     Recovers the card from a transmit error.
  2050.  
  2051. Arguments:
  2052.  
  2053.     Adapter - pointer to the adapter block
  2054.  
  2055. Return Value:
  2056.  
  2057.     None.
  2058.  
  2059. --*/
  2060.  
  2061. {
  2062.  
  2063.     IF_LOUD( DbgPrint("Octogmetuscerator called!"); )
  2064.  
  2065.         IF_LOG( UM9008Log('y'); )
  2066.  
  2067.     //
  2068.     // Ack the interrupt, if needed
  2069.     //
  2070.     NdisRawWritePortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, ISR_XMIT_ERR);
  2071.  
  2072.     //
  2073.     // Stop the card
  2074.     //
  2075.     SyncCardStop(Adapter);
  2076.  
  2077.     //
  2078.     // Wait up to 1.6 milliseconds for any receives to finish
  2079.     //
  2080.     NdisStallExecution(2000);
  2081.  
  2082.     //
  2083.     // Place the card in Loopback
  2084.     //
  2085.     NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK);
  2086.  
  2087.     //
  2088.     // Start the card in Loopback
  2089.     //
  2090.     NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA);
  2091.  
  2092.     //
  2093.     // Get out of loopback and start the card
  2094.     //
  2095.     CardStart(Adapter);
  2096.  
  2097.     //
  2098.     // If there was a packet waiting to get sent, send it.
  2099.     //
  2100.     if (Adapter->CurBufXmitting != -1) {
  2101.  
  2102.         Adapter->TransmitInterruptPending = TRUE;
  2103.         CardStartXmit(Adapter);
  2104.  
  2105.     }
  2106.         IF_LOG( UM9008Log('Y'); )
  2107. }
  2108.  
  2109.