ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

8390.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:   See COPYING in the top level directory
00003  * PROJECT:     ReactOS Novell Eagle 2000 driver
00004  * FILE:        ne2000/8390.c
00005  * PURPOSE:     DP8390 NIC specific routines
00006  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
00007  * REVISIONS:
00008  *   CSH 27/08-2000 Created
00009  */
00010 #include <ne2000.h>
00011 
00012 /* Null-terminated array of ports to probe. This is "semi-risky" (Don Becker).  */
00013 ULONG_PTR ProbeAddressList[] = { 0x280, 0x300, 0x320, 0x340, 0x360, 0x380, 0 };
00014 
00015 static BOOLEAN ProbeAddressForNIC(
00016     ULONG_PTR address)
00017 /*
00018  * FUNCTION: Probes an address for a NIC
00019  * ARGUMENTS:
00020  *     address = Base address to probe
00021  * RETURNS:
00022  *     TRUE if an NIC is found at the address
00023  *     FALSE otherwise
00024  * NOTES:
00025  *     If the adapter responds correctly to a
00026  *     stop command we assume it is present
00027  */
00028 {
00029     UCHAR Tmp;
00030 
00031     NDIS_DbgPrint(MID_TRACE, ("Probing address 0x%x\n", address));
00032 
00033     /* Disable interrupts */
00034     NdisRawWritePortUchar(address + PG0_IMR, 0);
00035 
00036     /* Stop the NIC */
00037     NdisRawWritePortUchar(address + PG0_CR, CR_STP | CR_RD2);
00038 
00039     /* Pause for 1.6ms */
00040     NdisStallExecution(1600);
00041 
00042     /* Read NIC response */
00043     NdisRawReadPortUchar(address + PG0_CR, &Tmp);
00044 
00045     if ((Tmp == (CR_RD2 | CR_STP)) || (Tmp == (CR_RD2 | CR_STP | CR_STA)))
00046         return TRUE;
00047     else
00048         return FALSE;
00049 }
00050 
00051 
00052 BOOLEAN NICCheck(
00053     PNIC_ADAPTER Adapter)
00054 /*
00055  * FUNCTION: Tests for a NIC
00056  * ARGUMENTS:
00057  *     Adapter = Pointer to adapter information
00058  * RETURNS:
00059  *     TRUE if NIC is believed to be present, FALSE if not
00060  */
00061 {
00062     int i;
00063 
00064     NDIS_DbgPrint(MAX_TRACE, ("Called\n"));
00065 
00066     /* first try the supplied value */
00067     if(ProbeAddressForNIC(Adapter->IoBaseAddress))
00068     {
00069         NDIS_DbgPrint(MID_TRACE, ("Found adapter at 0x%x\n", Adapter->IoBaseAddress));
00070         return TRUE;
00071     }
00072 
00073     /* ok, no dice, time to probe */
00074     for(i = 0; ProbeAddressList[i]; i++)
00075     {
00076         if(ProbeAddressForNIC(ProbeAddressList[i]))
00077         {
00078             NDIS_DbgPrint(MID_TRACE, ("Found adapter at address 0x%x\n", ProbeAddressList[i]));
00079             Adapter->IoBaseAddress = ProbeAddressList[i];
00080             return TRUE;
00081         }
00082     }
00083 
00084     NDIS_DbgPrint(MIN_TRACE,("Adapter NOT found!\n"));
00085     return FALSE;
00086 }
00087 
00088 
00089 static BOOLEAN NICTestAddress(
00090     PNIC_ADAPTER Adapter,
00091     ULONG Address)
00092 /*
00093  * FUNCTION: Tests if an address is writable
00094  * ARGUMENTS:
00095  *     Adapter = Pointer to adapter information
00096  * RETURNS:
00097  *     TRUE if the address is writable, FALSE if not
00098  */
00099 {
00100     USHORT Data;
00101     USHORT Tmp;
00102 
00103     /* Read one word */
00104     NICReadDataAlign(Adapter, &Data, Address, 0x02);
00105 
00106     /* Alter it */
00107     Data ^= 0xFFFF;
00108 
00109     /* Write it back */
00110     NICWriteDataAlign(Adapter, Address, &Data, 0x02);
00111 
00112     /* Check if it has changed on the NIC */
00113     NICReadDataAlign(Adapter, &Tmp, Address, 0x02);
00114 
00115     return (Data == Tmp);
00116 }
00117 
00118 
00119 static BOOLEAN NICTestRAM(
00120     PNIC_ADAPTER Adapter)
00121 /*
00122  * FUNCTION: Finds out how much RAM a NIC has
00123  * ARGUMENTS:
00124  *     Adapter = Pointer to adapter information
00125  * RETURNS:
00126  *     TRUE if the RAM size was found, FALSE if not
00127  * NOTES:
00128  *     Start at 1KB and test for every 1KB up to 64KB
00129  */
00130 {
00131     ULONG_PTR Base;
00132 
00133     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00134 
00135     /* Locate RAM base address */
00136     for (Base = 0x0400; Base < 0x10000; Base += 0x0400) {
00137         if (NICTestAddress(Adapter, Base))
00138             break;
00139     }
00140 
00141     if (Base == 0x10000) {
00142         /* No RAM on this board */
00143         NDIS_DbgPrint(MIN_TRACE, ("No RAM found on board.\n"));
00144         return FALSE;
00145     }
00146 
00147     Adapter->RamBase = (PUCHAR)Base;
00148 
00149     /* Find RAM size */
00150     for (; Base < 0x10000; Base += 0x0400) {
00151         if (!NICTestAddress(Adapter, Base))
00152             break;
00153     }
00154 
00155     Adapter->RamSize = (UINT)(Base - (ULONG_PTR)Adapter->RamBase);
00156 
00157     NDIS_DbgPrint(MID_TRACE, ("RAM is at (0x%X). Size is (0x%X).\n",
00158         Adapter->RamBase, Adapter->RamSize));
00159 
00160     return TRUE;
00161 }
00162 
00163 
00164 static VOID NICSetPhysicalAddress(
00165     PNIC_ADAPTER Adapter)
00166 /*
00167  * FUNCTION: Initializes the physical address on the NIC
00168  * ARGUMENTS:
00169  *     Adapter = Pointer to adapter information
00170  * NOTES:
00171  *     The physical address is taken from Adapter.
00172  *     The NIC is stopped by this operation
00173  */
00174 {
00175     UINT i;
00176 
00177     /* Select page 1 */
00178     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
00179 
00180     /* Initialize PAR - Physical Address Registers */
00181     for (i = 0; i < 0x06; i++)
00182         NdisRawWritePortUchar(Adapter->IOBase + PG1_PAR + i, Adapter->StationAddress[i]);
00183 
00184     /* Go back to page 0 */
00185     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
00186 }
00187 
00188 
00189 static VOID NICSetMulticastAddressMask(
00190     PNIC_ADAPTER Adapter)
00191 /*
00192  * FUNCTION: Initializes the multicast address mask on the NIC
00193  * ARGUMENTS:
00194  *     Adapter = Pointer to adapter information
00195  * NOTES:
00196  *     The multicast address mask is taken from Adapter.
00197  *     The NIC is stopped by this operation
00198  */
00199 {
00200     UINT i;
00201 
00202     /* Select page 1 */
00203     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
00204 
00205     /* Initialize MAR - Multicast Address Registers */
00206     for (i = 0; i < 0x08; i++)
00207         NdisRawWritePortUchar(Adapter->IOBase + PG1_MAR + i, Adapter->MulticastAddressMask[i]);
00208 
00209     /* Go back to page 0 */
00210     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
00211 }
00212 
00213 
00214 static BOOLEAN NICReadSAPROM(
00215     PNIC_ADAPTER Adapter)
00216 /*
00217  * FUNCTION: Reads the Station Address PROM data from the NIC
00218  * ARGUMENTS:
00219  *     Adapter = Pointer to adapter information
00220  * RETURNS:
00221  *     TRUE if a the NIC is an NE2000
00222  * NOTES:
00223  *    This routine also determines if the NIC can support word mode transfers
00224  *    and if it does initializes the NIC for word mode.
00225  *    The station address in the adapter structure is initialized with
00226  *    the address from the SAPROM
00227  */
00228 {
00229     UINT i;
00230     UCHAR Buffer[32];
00231     UCHAR WordLength;
00232 
00233     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00234 
00235     /* Read Station Address PROM (SAPROM) which is 16 bytes at remote DMA address 0.
00236        Some cards double the data read which we must compensate for */
00237 
00238     /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
00239     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x20);
00240     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
00241 
00242     /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
00243     NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, 0x00);
00244     NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, 0x00);
00245 
00246     /* Select page 0, read and start the NIC */
00247     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
00248 
00249     /* Read one byte at a time */
00250     WordLength = 2; /* Assume a word is two bytes */
00251     for (i = 0; i < 32; i += 2) {
00252         NdisRawReadPortUchar(Adapter->IOBase + NIC_DATA, &Buffer[i]);
00253         NdisRawReadPortUchar(Adapter->IOBase + NIC_DATA, &Buffer[i + 1]);
00254         if (Buffer[i] != Buffer[i + 1])
00255             WordLength = 1; /* A word is one byte long */
00256     }
00257 
00258     /* If WordLength is 2 the data read before was doubled. We must compensate for this */
00259     if (WordLength == 2) {
00260         NDIS_DbgPrint(MAX_TRACE,("NE2000 or compatible network adapter found.\n"));
00261 
00262         Adapter->WordMode = TRUE;
00263 
00264         /* Move the SAPROM data to the adapter object */
00265         for (i = 0; i < 16; i++)
00266             Adapter->SAPROM[i] = Buffer[i * 2];
00267 
00268         /* Copy the permanent address */
00269         NdisMoveMemory(
00270             (PVOID)&Adapter->PermanentAddress,
00271             (PVOID)&Adapter->SAPROM,
00272             DRIVER_LENGTH_OF_ADDRESS);
00273 
00274         /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
00275         NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_WTS | DCR_LS | DCR_FT10);
00276 
00277         return TRUE;
00278     } else {
00279         NDIS_DbgPrint(MAX_TRACE, ("NE1000 or compatible network adapter found.\n"));
00280 
00281         Adapter->WordMode = FALSE;
00282 
00283         return FALSE;
00284     }
00285 }
00286 
00287 
00288 NDIS_STATUS NICInitialize(
00289     PNIC_ADAPTER Adapter)
00290 /*
00291  * FUNCTION: Initializes a NIC
00292  * ARGUMENTS:
00293  *     Adapter = Pointer to adapter information
00294  * RETURNS:
00295  *     Status of NIC initialization
00296  * NOTES:
00297  *     The NIC is put into loopback mode
00298  */
00299 {
00300     UCHAR Tmp;
00301 
00302     NDIS_DbgPrint(MID_TRACE, ("Called.\n"));
00303 
00304     /* Reset the NIC */
00305     NdisRawReadPortUchar(Adapter->IOBase + NIC_RESET, &Tmp);
00306 
00307     /* Wait for 1.6ms */
00308     NdisStallExecution(1600);
00309 
00310     /* Write the value back  */
00311     NdisRawWritePortUchar(Adapter->IOBase + NIC_RESET, Tmp);
00312 
00313     /* Select page 0 and stop NIC */
00314     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
00315 
00316     /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
00317     NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_LS | DCR_FT10);
00318 
00319     /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
00320     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
00321     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
00322 
00323     /* Initialize RCR - Receive Configuration Register (monitor mode) */
00324     NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
00325 
00326     /* Enter loopback mode (internal NIC module loopback) */
00327     NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
00328 
00329     /* Read the Station Address PROM */
00330     if (!NICReadSAPROM(Adapter))
00331         return NDIS_STATUS_ADAPTER_NOT_FOUND;
00332 
00333     NDIS_DbgPrint(MID_TRACE, ("Station address is (%02X %02X %02X %02X %02X %02X).\n",
00334         Adapter->StationAddress[0], Adapter->StationAddress[1],
00335         Adapter->StationAddress[2], Adapter->StationAddress[3],
00336         Adapter->StationAddress[4], Adapter->StationAddress[5]));
00337 
00338     /* Select page 0 and start NIC */
00339     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
00340 
00341     /* Clear ISR - Interrupt Status Register */
00342     NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, 0xFF);
00343 
00344     /* Find NIC RAM size */
00345     NICTestRAM(Adapter);
00346 
00347     return NDIS_STATUS_SUCCESS;
00348 }
00349 
00350 
00351 NDIS_STATUS NICSetup(
00352     PNIC_ADAPTER Adapter)
00353 /*
00354  * FUNCTION: Sets up a NIC
00355  * ARGUMENTS:
00356  *     Adapter = Pointer to adapter information
00357  * RETURNS:
00358  *     Status of operation
00359  * NOTES:
00360  *     The NIC is put into loopback mode
00361  */
00362 {
00363     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00364 
00365     if (Adapter->WordMode ) {
00366         /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
00367         NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_WTS | DCR_LS | DCR_FT10);
00368     } else {
00369         /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
00370         NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_LS | DCR_FT10);
00371     }
00372 
00373     /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
00374     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
00375     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
00376 
00377     /* Initialize RCR - Receive Configuration Register (monitor mode) */
00378     NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
00379 
00380     /* Enter loopback mode (internal NIC module loopback) */
00381     NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
00382 
00383     /* Set boundary page */
00384     NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY, Adapter->NextPacket);
00385 
00386     /* Set start page */
00387     NdisRawWritePortUchar(Adapter->IOBase + PG0_PSTART, Adapter->PageStart);
00388 
00389     /* Set stop page */
00390     NdisRawWritePortUchar(Adapter->IOBase + PG0_PSTOP, Adapter->PageStop);
00391 
00392     /* Program our address on the NIC */
00393     NICSetPhysicalAddress(Adapter);
00394 
00395     /* Program the multicast address mask on the NIC */
00396     NICSetMulticastAddressMask(Adapter);
00397 
00398     /* Select page 1 and stop NIC */
00399     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
00400 
00401     /* Initialize current page register */
00402     NdisRawWritePortUchar(Adapter->IOBase + PG1_CURR, Adapter->PageStart + 1);
00403 
00404     /* Select page 0 and stop NIC */
00405     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
00406 
00407     /* Clear ISR - Interrupt Status Register */
00408     NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, 0xFF);
00409 
00410     /* Initialize IMR - Interrupt Mask Register */
00411     NdisRawWritePortUchar(Adapter->IOBase + PG0_IMR, Adapter->InterruptMask);
00412 
00413     /* Select page 0 and start NIC */
00414     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
00415 
00416     Adapter->CurrentPage            = Adapter->PageStart + 1;
00417     Adapter->NextPacket             = Adapter->PageStart + 1;
00418     Adapter->BufferOverflow         = FALSE;
00419     Adapter->ReceiveError           = FALSE;
00420     Adapter->TransmitError          = FALSE;
00421 
00422     NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
00423 
00424     return NDIS_STATUS_SUCCESS;
00425 }
00426 
00427 
00428 NDIS_STATUS NICStart(
00429     PNIC_ADAPTER Adapter)
00430 /*
00431  * FUNCTION: Starts a NIC
00432  * ARGUMENTS:
00433  *     Adapter = Pointer to adapter information
00434  * RETURNS:
00435  *     Status of operation
00436  */
00437 {
00438     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00439 
00440     /* Take NIC out of loopback mode */
00441     NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, 0x00);
00442 
00443     /* Initialize RCR - Receive Configuration Register (accept all) */
00444     NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_AB | RCR_AM | RCR_PRO);
00445 
00446     return NDIS_STATUS_SUCCESS;
00447 }
00448 
00449 
00450 NDIS_STATUS NICStop(
00451     PNIC_ADAPTER Adapter)
00452 /*
00453  * FUNCTION: Stops a NIC
00454  * ARGUMENTS:
00455  *     Adapter = Pointer to adapter information
00456  * RETURNS:
00457  *     Status of operation
00458  */
00459 {
00460     UCHAR Tmp;
00461     UINT i;
00462 
00463     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00464 
00465     /* Select page 0 and stop NIC */
00466     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
00467 
00468     /* Clear Remote Byte Count Register so ISR_RST will be set */
00469     NdisRawWritePortUchar( Adapter->IOBase + PG0_RBCR0, 0x00);
00470     NdisRawWritePortUchar( Adapter->IOBase + PG0_RBCR0, 0x00);
00471 
00472     /* Wait for ISR_RST to be set, but timeout after 2ms */
00473     for (i = 0; i < 4; i++) {
00474         NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
00475         if (Tmp & ISR_RST)
00476             break;
00477 
00478         NdisStallExecution(500);
00479     }
00480 
00481 #if DBG
00482     if (i == 4)
00483         NDIS_DbgPrint(MIN_TRACE, ("NIC was not reset after 2ms.\n"));
00484 #endif
00485 
00486     /* Initialize RCR - Receive Configuration Register (monitor mode) */
00487     NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
00488 
00489     /* Initialize TCR - Transmit Configuration Register (loopback mode) */
00490     NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
00491 
00492     /* Start NIC */
00493     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2);
00494 
00495     return NDIS_STATUS_SUCCESS;
00496 }
00497 
00498 
00499 NDIS_STATUS NICReset(
00500     PNIC_ADAPTER Adapter)
00501 /*
00502  * FUNCTION: Resets a NIC
00503  * ARGUMENTS:
00504  *     Adapter = Pointer to adapter information
00505  * RETURNS:
00506  *     Status of operation
00507  */
00508 {
00509     UCHAR Tmp;
00510 
00511     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00512 
00513     /* Stop the NIC */
00514     NICStop(Adapter);
00515 
00516     /* Reset the NIC */
00517     NdisRawReadPortUchar(Adapter->IOBase + NIC_RESET, &Tmp);
00518 
00519     /* Wait for 1.6ms */
00520     NdisStallExecution(1600);
00521 
00522     /* Write the value back  */
00523     NdisRawWritePortUchar(Adapter->IOBase + NIC_RESET, Tmp);
00524 
00525     /* Restart the NIC */
00526     NICStart(Adapter);
00527 
00528     return NDIS_STATUS_SUCCESS;
00529 }
00530 
00531 
00532 static VOID NICStartTransmit(
00533     PNIC_ADAPTER Adapter)
00534 /*
00535  * FUNCTION: Starts transmitting a packet
00536  * ARGUMENTS:
00537  *     Adapter = Pointer to adapter information
00538  */
00539 {
00540     UINT Length;
00541     UCHAR FrameStart;
00542     UCHAR Tmp;
00543 
00544     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00545 
00546     if (Adapter->TXCurrent < 0) return;
00547 
00548     //FrameStart = Adapter->TXStart + Adapter->TXCurrent * DRIVER_BLOCK_SIZE;
00549     //FrameStart = Adapter->TXStart;
00550     FrameStart = (UCHAR)(Adapter->TXStart + (UCHAR)(Adapter->TXCurrent * BUFFERS_PER_TX_BUF));
00551 
00552     /* Set start of frame */
00553     NdisRawReadPortUchar(Adapter->IOBase + PG0_TPSR, &Tmp);
00554 //    NdisRawWritePortUchar(Adapter->IOBase + PG0_TPSR,
00555 //        Adapter->TXStart + Adapter->TXCurrent * DRIVER_BLOCK_SIZE);
00556 
00557     NdisRawWritePortUchar(Adapter->IOBase + PG0_TPSR, FrameStart);
00558     //NDIS_DbgPrint(MID_TRACE, ("Setting start of frame to (%d).\n", FrameStart));
00559 
00560     /* Set length of frame */
00561     Length = Adapter->TXSize[Adapter->TXCurrent];
00562     NdisRawWritePortUchar(Adapter->IOBase + PG0_TBCR0, Length & 0xFF);
00563     NdisRawWritePortUchar(Adapter->IOBase + PG0_TBCR1, Length >> 8);
00564 
00565     /* Start transmitting */
00566     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_TXP | CR_RD2);
00567 
00568     NDIS_DbgPrint(MID_TRACE, ("Transmitting. FrameStart (%d)  TXCurrent (%d)  TXStart (%d)  Length (%d).\n\n",
00569         FrameStart,
00570         Adapter->TXCurrent,
00571         Adapter->TXStart,
00572         Length));
00573 
00574 }
00575 
00576 
00577 static VOID NICSetBoundaryPage(
00578     PNIC_ADAPTER Adapter)
00579 /*
00580  * FUNCTION: Sets the boundary page on the adapter to be one less than NextPacket
00581  * ARGUMENTS:
00582  *     Adapter = Pointer to adapter information
00583  */
00584 {
00585     if (Adapter->NextPacket == Adapter->PageStart) {
00586         NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY,
00587             (UCHAR)(Adapter->PageStop - 1));
00588     } else {
00589         NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY,
00590             (UCHAR)(Adapter->NextPacket - 1));
00591     }
00592 }
00593 
00594 
00595 static VOID NICGetCurrentPage(
00596     PNIC_ADAPTER Adapter)
00597 /*
00598  * FUNCTION: Retrieves the current page from the adapter
00599  * ARGUMENTS:
00600  *     Adapter = Pointer to adapter information
00601  */
00602 {
00603     UCHAR Current;
00604 
00605     /* Select page 1 */
00606     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE1);
00607 
00608     /* Read current page */
00609     NdisRawReadPortUchar(Adapter->IOBase + PG1_CURR, &Current);
00610 
00611     /* Select page 0 */
00612     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
00613 
00614     Adapter->CurrentPage = Current;
00615 }
00616 
00617 
00618 VOID NICUpdateCounters(
00619     PNIC_ADAPTER Adapter)
00620 /*
00621  * FUNCTION: Updates counters
00622  * ARGUMENTS:
00623  *     Adapter = Pointer to adapter information
00624  */
00625 {
00626     UCHAR Tmp;
00627 
00628     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00629 
00630     NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR0, &Tmp);
00631     Adapter->FrameAlignmentErrors += Tmp;
00632 
00633     NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR1, &Tmp);
00634     Adapter->CrcErrors += Tmp;
00635 
00636     NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR2, &Tmp);
00637     Adapter->MissedPackets += Tmp;
00638 }
00639 
00640 
00641 VOID NICReadDataAlign(
00642     PNIC_ADAPTER Adapter,
00643     PUSHORT Target,
00644     ULONG_PTR Source,
00645     USHORT Length)
00646 /*
00647  * FUNCTION: Copies data from a NIC's RAM into a buffer
00648  * ARGUMENTS:
00649  *     Adapter = Pointer to adapter information
00650  *     Target  = Pointer to buffer to copy data into (in host memory)
00651  *     Source  = Offset into NIC's RAM (must be an even number)
00652  *     Length  = Number of bytes to copy from NIC's RAM (must be an even number)
00653  */
00654 {
00655     UCHAR Tmp;
00656     USHORT Count;
00657 
00658     Count = Length;
00659 
00660     /* Select page 0 and start the NIC */
00661     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
00662 
00663     /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
00664     NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Source & 0xFF));
00665     NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Source >> 8));
00666 
00667     /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
00668     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, (UCHAR)(Count & 0xFF));
00669     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, (UCHAR)(Count >> 8));
00670 
00671     /* Select page 0, read and start the NIC */
00672     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
00673 
00674     if (Adapter->WordMode)
00675         NdisRawReadPortBufferUshort(Adapter->IOBase + NIC_DATA, Target, Count >> 1);
00676     else
00677         NdisRawReadPortBufferUchar(Adapter->IOBase + NIC_DATA, Target, Count);
00678 
00679     /* Wait for remote DMA to complete, but timeout after some time */
00680     for (Count = 0; Count < 0xFFFF; Count++) {
00681         NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
00682         if (Tmp & ISR_RDC)
00683             break;
00684 
00685         NdisStallExecution(4);
00686     }
00687 
00688 #if DBG
00689     if (Count == 0xFFFF)
00690         NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
00691 #endif
00692 
00693     /* Clear remote DMA bit in ISR - Interrupt Status Register */
00694     NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
00695 }
00696 
00697 
00698 VOID NICWriteDataAlign(
00699     PNIC_ADAPTER Adapter,
00700     ULONG_PTR Target,
00701     PUSHORT Source,
00702     USHORT Length)
00703 /*
00704  * FUNCTION: Copies data from a buffer into the NIC's RAM
00705  * ARGUMENTS:
00706  *     Adapter = Pointer to adapter information
00707  *     Target  = Offset into NIC's RAM (must be an even number)
00708  *     Source  = Pointer to buffer to copy data from (in host memory)
00709  *     Length  = Number of bytes to copy from the buffer (must be an even number)
00710  */
00711 {
00712     UCHAR Tmp;
00713     USHORT Count;
00714 
00715     /* Select page 0 and start the NIC */
00716     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
00717 
00718     /* Handle read-before-write bug */
00719 
00720     /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
00721     NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Target & 0xFF));
00722     NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Target >> 8));
00723 
00724     /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
00725     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x02);
00726     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
00727 
00728     /* Read and start the NIC */
00729     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
00730 
00731     /* Read data */
00732     NdisRawReadPortUshort(Adapter->IOBase + NIC_DATA, &Count);
00733 
00734     /* Wait for remote DMA to complete, but timeout after some time */
00735     for (Count = 0; Count < 0xFFFF; Count++) {
00736         NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
00737         if (Tmp & ISR_RDC)
00738             break;
00739 
00740         NdisStallExecution(4);
00741     }
00742 
00743 #if DBG
00744     if (Count == 0xFFFF)
00745         NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
00746 #endif
00747 
00748     /* Clear remote DMA bit in ISR - Interrupt Status Register */
00749     NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
00750 
00751 
00752     /* Now output some data */
00753     Count = Length;
00754 
00755     /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
00756     NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Target & 0xFF));
00757     NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Target >> 8));
00758 
00759     /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
00760     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, (UCHAR)(Count & 0xFF));
00761     NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, (UCHAR)(Count >> 8));
00762 
00763     /* Write and start the NIC */
00764     NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD1 | CR_PAGE0);
00765 
00766     if (Adapter->WordMode)
00767         NdisRawWritePortBufferUshort(Adapter->IOBase + NIC_DATA, Source, Count >> 1);
00768     else
00769         NdisRawWritePortBufferUchar(Adapter->IOBase + NIC_DATA, Source, Count);
00770 
00771     /* Wait for remote DMA to complete, but timeout after some time */
00772     for (Count = 0; Count < 0xFFFF; Count++) {
00773         NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
00774         if (Tmp & ISR_RDC)
00775             break;
00776 
00777         NdisStallExecution(4);
00778     }
00779 
00780 #if DBG
00781     if (Count == 0xFFFF)
00782         NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
00783 #endif
00784 
00785     /* Clear remote DMA bit in ISR - Interrupt Status Register */
00786     NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
00787 }
00788 
00789 
00790 VOID NICReadData(
00791     PNIC_ADAPTER Adapter,
00792     PUCHAR Target,
00793     ULONG_PTR Source,
00794     USHORT Length)
00795 /*
00796  * FUNCTION: Copies data from a NIC's RAM into a buffer
00797  * ARGUMENTS:
00798  *     Adapter = Pointer to adapter information
00799  *     Target  = Pointer to buffer to copy data into (in host memory)
00800  *     Source  = Offset into NIC's RAM
00801  *     Length  = Number of bytes to copy from NIC's RAM
00802  */
00803 {
00804     USHORT Tmp;
00805 
00806     /* Avoid transfers to odd addresses */
00807     if (Source & 0x01) {
00808         /* Transfer one word and use the MSB */
00809         NICReadDataAlign(Adapter, &Tmp, Source - 1, 0x02);
00810         *Target = (UCHAR)(Tmp >> 8);
00811         Source++;
00812         Target++;
00813         Length--;
00814     }
00815 
00816     if (Length & 0x01) {
00817         /* Transfer as many words as we can without exceeding the buffer length */
00818         Tmp = Length & 0xFFFE;
00819         NICReadDataAlign(Adapter, (PUSHORT)Target, Source, Tmp);
00820         Source += Tmp;
00821         Target  = (PUCHAR)((ULONG_PTR) Target + Tmp);
00822 
00823         /* Read one word and keep the LSB */
00824         NICReadDataAlign(Adapter, &Tmp, Source, 0x02);
00825         *Target = (UCHAR)(Tmp & 0x00FF);
00826     } else
00827         /* Transfer the rest of the data */
00828         NICReadDataAlign(Adapter, (PUSHORT)Target, Source, Length);
00829 }
00830 
00831 
00832 VOID NICWriteData(
00833     PNIC_ADAPTER Adapter,
00834     ULONG_PTR Target,
00835     PUCHAR Source,
00836     USHORT Length)
00837 /*
00838  * FUNCTION: Copies data from a buffer into NIC's RAM
00839  * ARGUMENTS:
00840  *     Adapter = Pointer to adapter information
00841  *     Target  = Offset into NIC's RAM to store data
00842  *     Source  = Pointer to buffer to copy data from (in host memory)
00843  *     Length  = Number of bytes to copy from buffer
00844  */
00845 {
00846     USHORT Tmp;
00847 
00848     /* Avoid transfers to odd addresses */
00849     if (Target & 0x01) {
00850         /* Read one word */
00851         NICReadDataAlign(Adapter, &Tmp, Target - 1, 0x02);
00852 
00853         /* Merge LSB with the new byte which become the new MSB */
00854         Tmp = (Tmp & 0x00FF) | (*Source << 8);
00855 
00856         /* Finally write the value back */
00857         NICWriteDataAlign(Adapter, Target - 1, &Tmp, 0x02);
00858 
00859         /* Update pointers */
00860         Source = (PUCHAR) ((ULONG_PTR) Source + 1);
00861         Target += 1;
00862         Length--;
00863     }
00864 
00865     if (Length & 0x01) {
00866         /* Transfer as many words as we can without exceeding the transfer length */
00867         Tmp = Length & 0xFFFE;
00868         NICWriteDataAlign(Adapter, Target, (PUSHORT)Source, Tmp);
00869         Source += Tmp;
00870         Target += Tmp;
00871 
00872         /* Read one word */
00873         NICReadDataAlign(Adapter, &Tmp, Target, 0x02);
00874 
00875         /* Merge MSB with the new byte which become the new LSB */
00876         Tmp = (Tmp & 0xFF00) | (*Source);
00877 
00878         /* Finally write the value back */
00879         NICWriteDataAlign(Adapter, Target, &Tmp, 0x02);
00880     } else
00881         /* Transfer the rest of the data */
00882         NICWriteDataAlign(Adapter, Target, (PUSHORT)Source, Length);
00883 }
00884 
00885 
00886 static VOID NICIndicatePacket(
00887     PNIC_ADAPTER Adapter)
00888 /*
00889  * FUNCTION: Indicates a packet to the wrapper
00890  * ARGUMENTS:
00891  *     Adapter = Pointer to adapter information
00892  */
00893 {
00894     UINT IndicateLength;
00895 
00896     IndicateLength = (Adapter->PacketHeader.PacketLength <
00897         (Adapter->LookaheadSize + DRIVER_HEADER_SIZE))?
00898         (Adapter->PacketHeader.PacketLength) :
00899         (Adapter->LookaheadSize + DRIVER_HEADER_SIZE);
00900 
00901     /* Fill the lookahead buffer */
00902     NICReadData(Adapter,
00903                 (PUCHAR)&Adapter->Lookahead,
00904                 Adapter->PacketOffset + sizeof(PACKET_HEADER),
00905                 IndicateLength + DRIVER_HEADER_SIZE);
00906 
00907     NDIS_DbgPrint(MID_TRACE, ("Indicating (%d) bytes.\n", IndicateLength));
00908     NDIS_DbgPrint(MID_TRACE, ("ne2000!NICIndicatePacket: Indicating (%d) bytes.\n", IndicateLength));
00909 
00910 #if 0
00911     NDIS_DbgPrint(MAX_TRACE, ("FRAME:\n"));
00912     for (i = 0; i < (IndicateLength + 7) / 8; i++) {
00913         NDIS_DbgPrint(MAX_TRACE, ("%02X %02X %02X %02X %02X %02X %02X %02X\n",
00914             Adapter->Lookahead[i*8+0],
00915             Adapter->Lookahead[i*8+1],
00916             Adapter->Lookahead[i*8+2],
00917             Adapter->Lookahead[i*8+3],
00918             Adapter->Lookahead[i*8+4],
00919             Adapter->Lookahead[i*8+5],
00920             Adapter->Lookahead[i*8+6],
00921             Adapter->Lookahead[i*8+7]));
00922     }
00923 #endif
00924 
00925     if (IndicateLength >= DRIVER_HEADER_SIZE) {
00926     NDIS_DbgPrint(MAX_TRACE,("Adapter->MiniportAdapterHandle: %x\n",
00927                  Adapter->MiniportAdapterHandle));
00928         NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle,
00929                                 NULL,
00930                                 (PVOID)&Adapter->Lookahead,
00931                                 DRIVER_HEADER_SIZE,
00932                                 (PVOID)&Adapter->Lookahead[DRIVER_HEADER_SIZE],
00933                                 IndicateLength - DRIVER_HEADER_SIZE,
00934                                 Adapter->PacketHeader.PacketLength - DRIVER_HEADER_SIZE);
00935     } else {
00936         NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle,
00937                                 NULL,
00938                                 (PVOID)&Adapter->Lookahead,
00939                                 IndicateLength,
00940                                 NULL,
00941                                 0,
00942                                 0);
00943     }
00944 }
00945 
00946 
00947 static VOID NICReadPacket(
00948     PNIC_ADAPTER Adapter)
00949 /*
00950  * FUNCTION: Reads a full packet from the receive buffer ring
00951  * ARGUMENTS:
00952  *     Adapter = Pointer to adapter information
00953  */
00954 {
00955     BOOLEAN SkipPacket = FALSE;
00956 
00957     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
00958 
00959     /* Get the header of the next packet in the receive ring */
00960     Adapter->PacketOffset = Adapter->NextPacket << 8;
00961     NICReadData(Adapter,
00962                 (PUCHAR)&Adapter->PacketHeader,
00963                 Adapter->PacketOffset,
00964                 sizeof(PACKET_HEADER));
00965 
00966     NDIS_DbgPrint(MAX_TRACE, ("HEADER: (Status)       (0x%X)\n", Adapter->PacketHeader.Status));
00967     NDIS_DbgPrint(MAX_TRACE, ("HEADER: (NextPacket)   (0x%X)\n", Adapter->PacketHeader.NextPacket));
00968     NDIS_DbgPrint(MAX_TRACE, ("HEADER: (PacketLength) (0x%X)\n", Adapter->PacketHeader.PacketLength));
00969 
00970     if (Adapter->PacketHeader.PacketLength < 64  ||
00971         Adapter->PacketHeader.PacketLength > 1518) {    /* XXX I don't think the CRC will show up... should be 1514 */
00972         NDIS_DbgPrint(MAX_TRACE, ("Bogus packet size (%d).\n",
00973             Adapter->PacketHeader.PacketLength));
00974         SkipPacket = TRUE;
00975     }
00976 
00977     if (SkipPacket) {
00978         /* Skip packet */
00979         Adapter->NextPacket = Adapter->CurrentPage;
00980     } else {
00981     NDIS_DbgPrint(MAX_TRACE,("Adapter->MiniportAdapterHandle: %x\n",
00982                  Adapter->MiniportAdapterHandle));
00983         NICIndicatePacket(Adapter);
00984 
00985         /* Go to the next free buffer in receive ring */
00986         Adapter->NextPacket = Adapter->PacketHeader.NextPacket;
00987     }
00988 
00989     /* Update boundary page */
00990     NICSetBoundaryPage(Adapter);
00991 }
00992 
00993 
00994 static VOID NICWritePacket(
00995     PNIC_ADAPTER Adapter)
00996 /*
00997  * FUNCTION: Writes a full packet to the transmit buffer ring
00998  * ARGUMENTS:
00999  *     Adapter  = Pointer to adapter information
01000  * NOTES:
01001  *     There must be enough free buffers available in the transmit buffer ring.
01002  *     The packet is taken from the head of the transmit queue and the position
01003  *     into the transmit buffer ring is taken from TXNext
01004  */
01005 {
01006     PNDIS_BUFFER SrcBuffer;
01007     UINT BytesToCopy, SrcSize, DstSize;
01008     PUCHAR SrcData;
01009     ULONG DstData;
01010     UINT TXStart;
01011     UINT TXStop;
01012 
01013     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
01014 
01015     TXStart = Adapter->TXStart * DRIVER_BLOCK_SIZE;
01016     TXStop  = (Adapter->TXStart + Adapter->TXCount) * DRIVER_BLOCK_SIZE;
01017 
01018     NdisQueryPacket(Adapter->TXQueueHead,
01019                     NULL,
01020                     NULL,
01021                     &SrcBuffer,
01022                     &Adapter->TXSize[Adapter->TXNext]);
01023 
01024     NDIS_DbgPrint(MID_TRACE, ("Packet (%d) is now size (%d).\n",
01025         Adapter->TXNext,
01026         Adapter->TXSize[Adapter->TXNext]));
01027 
01028     NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
01029 
01030     DstData = TXStart + Adapter->TXNext * DRIVER_BLOCK_SIZE;
01031     DstSize = TXStop - DstData;
01032 
01033     /* Start copying the data */
01034     for (;;) {
01035         BytesToCopy = (SrcSize < DstSize)? SrcSize : DstSize;
01036 
01037         NICWriteData(Adapter, DstData, SrcData, BytesToCopy);
01038 
01039         SrcData = (PUCHAR)((ULONG_PTR) SrcData + BytesToCopy);
01040         SrcSize            -= BytesToCopy;
01041         DstData            += BytesToCopy;
01042         DstSize            -= BytesToCopy;
01043 
01044         if (SrcSize == 0) {
01045             /* No more bytes in source buffer. Proceed to
01046                the next buffer in the source buffer chain */
01047             NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
01048             if (!SrcBuffer)
01049                 break;
01050 
01051             NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
01052         }
01053 
01054         if (DstSize == 0) {
01055             /* Wrap around the end of the transmit buffer ring */
01056             DstData = TXStart;
01057             DstSize = Adapter->TXCount * DRIVER_BLOCK_SIZE;
01058         }
01059     }
01060 }
01061 
01062 
01063 static BOOLEAN NICPrepareForTransmit(
01064     PNIC_ADAPTER Adapter)
01065 /*
01066  * FUNCTION: Prepares a packet for transmission
01067  * ARGUMENTS:
01068  *     Adapter = Pointer to adapter information
01069  * NOTES:
01070  *     There must be at least one packet in the transmit queue
01071  * RETURNS:
01072  *     TRUE if a packet was prepared, FALSE if not
01073  */
01074 {
01075     UINT Length;
01076     UINT BufferCount;
01077     PNDIS_PACKET Packet;
01078 
01079     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
01080 
01081     /* Calculate number of buffers needed to transmit packet */
01082     NdisQueryPacket(Adapter->TXQueueHead,
01083                     NULL,
01084                     NULL,
01085                     NULL,
01086                     &Length);
01087 
01088     BufferCount = (Length + DRIVER_BLOCK_SIZE - 1) / DRIVER_BLOCK_SIZE;
01089 
01090     if (BufferCount > Adapter->TXFree) {
01091         NDIS_DbgPrint(MID_TRACE, ("No transmit resources. Have (%d) buffers, need (%d).\n",
01092             Adapter->TXFree, BufferCount));
01093         /* We don't have the resources to transmit this packet right now */
01094         return FALSE;
01095     }
01096 
01097     /* Write the packet to the card */
01098     NICWritePacket(Adapter);
01099 
01100     /* If the NIC is not transmitting, reset the current transmit pointer */
01101     if (Adapter->TXCurrent == -1)
01102         Adapter->TXCurrent = Adapter->TXNext;
01103 
01104     Adapter->TXNext  = (Adapter->TXNext + BufferCount) % Adapter->TXCount;
01105     Adapter->TXFree -= BufferCount;
01106 
01107     /* Remove the packet from the queue */
01108     Packet = Adapter->TXQueueHead;
01109     Adapter->TXQueueHead = RESERVED(Packet)->Next;
01110 
01111     if (Packet == Adapter->TXQueueTail)
01112         Adapter->TXQueueTail = NULL;
01113 
01114     /* Assume the transmit went well */
01115     NdisMSendComplete(Adapter->MiniportAdapterHandle,
01116                       Packet,
01117                       NDIS_STATUS_SUCCESS);
01118 
01119     return TRUE;
01120 }
01121 
01122 
01123 VOID NICTransmit(
01124     PNIC_ADAPTER Adapter)
01125 /*
01126  * FUNCTION: Starts transmitting packets in the transmit queue
01127  * ARGUMENTS:
01128  *     Adapter = Pointer to adapter information
01129  * NOTES:
01130  *     There must be at least one packet in the transmit queue
01131  */
01132 {
01133     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
01134 
01135     if (Adapter->TXCurrent == -1) {
01136         /* NIC is not transmitting, so start transmitting now */
01137 
01138         /* Load next packet onto the card, and start transmitting */
01139         if (NICPrepareForTransmit(Adapter))
01140             NICStartTransmit(Adapter);
01141     }
01142 }
01143 
01144 
01145 static VOID HandleReceive(
01146     PNIC_ADAPTER Adapter)
01147 /*
01148  * FUNCTION: Handles reception of a packet
01149  * ARGUMENTS:
01150  *     Adapter = Pointer to adapter information
01151  * NOTES:
01152  *     Buffer overflows are also handled here
01153  */
01154 {
01155     UINT i;
01156     UCHAR Tmp;
01157     UINT PacketCount;
01158 
01159     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
01160 
01161     Adapter->DoneIndicating = FALSE;
01162     PacketCount = 0;
01163 
01164     NICGetCurrentPage(Adapter);
01165 
01166     if (Adapter->BufferOverflow) {
01167 
01168         NDIS_DbgPrint(MID_TRACE, ("Receive ring overflow.\n"));
01169 
01170         /* Select page 0 and stop the NIC */
01171         NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
01172 
01173         /* Clear RBCR0,RBCR1 - Remote Byte Count Registers */
01174         NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
01175         NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
01176 
01177         /* Wait for ISR_RST to be set, but timeout after 2ms */
01178         for (i = 0; i < 4; i++) {
01179             NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
01180             if (Tmp & ISR_RST)
01181                 break;
01182 
01183             NdisStallExecution(500);
01184         }
01185 
01186 #if DBG
01187         if (i == 4)
01188             NDIS_DbgPrint(MIN_TRACE, ("NIC was not reset after 2ms.\n"));
01189 #endif
01190 
01191         if ((Adapter->InterruptStatus & (ISR_PTX | ISR_TXE)) == 0) {
01192             /* We may need to restart the transmitter */
01193             Adapter->TransmitPending = TRUE;
01194         }
01195 
01196         /* Initialize TCR - Transmit Configuration Register to loopback mode 1 */
01197         NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
01198 
01199         /* Start NIC */
01200         NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2);
01201 
01202         NICStart(Adapter);
01203 
01204         Adapter->BufferOverflow = FALSE;
01205     }
01206 
01207     if (Adapter->ReceiveError) {
01208         NDIS_DbgPrint(MID_TRACE, ("Receive error.\n"));
01209 
01210         /* Skip this packet */
01211         Adapter->NextPacket = Adapter->CurrentPage;
01212         NICSetBoundaryPage(Adapter);
01213 
01214         Adapter->ReceiveError = FALSE;
01215     }
01216 
01217     for (;;) {
01218         NICGetCurrentPage(Adapter);
01219 
01220         NDIS_DbgPrint(MID_TRACE, ("Current page (0x%X)  NextPacket (0x%X).\n",
01221             Adapter->CurrentPage,
01222             Adapter->NextPacket));
01223 
01224         if (Adapter->CurrentPage == Adapter->NextPacket) {
01225             NDIS_DbgPrint(MID_TRACE, ("No more packets.\n"));
01226             break;
01227         } else {
01228             NDIS_DbgPrint(MID_TRACE, ("Got a packet in the receive ring.\n"));
01229 
01230         NDIS_DbgPrint(MAX_TRACE,("Adapter->MiniportAdapterHandle: %x\n",
01231                      Adapter->MiniportAdapterHandle));
01232             /* Read packet from receive buffer ring */
01233             NICReadPacket(Adapter);
01234 
01235             Adapter->DoneIndicating = TRUE;
01236 
01237             PacketCount++;
01238             if (PacketCount == 10) {
01239                 /* Don't starve transmit interrupts */
01240                 break;
01241             }
01242         }
01243     }
01244 
01245     if ((Adapter->TransmitPending) && (Adapter->TXCurrent != -1)) {
01246         NDIS_DbgPrint(MID_TRACE, ("Retransmitting current packet at (%d).\n", Adapter->TXCurrent));
01247         /* Retransmit packet */
01248         NICStartTransmit(Adapter);
01249         Adapter->TransmitPending = FALSE;
01250     }
01251 
01252     if (Adapter->DoneIndicating)
01253         NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
01254 }
01255 
01256 
01257 static VOID HandleTransmit(
01258     PNIC_ADAPTER Adapter)
01259 /*
01260  * FUNCTION: Handles transmission of a packet
01261  * ARGUMENTS:
01262  *     Adapter = Pointer to adapter information
01263  */
01264 {
01265     UINT Length;
01266     UINT BufferCount;
01267 
01268 //    PIP_PACKET pIPPacket;
01269 //    pIPPacket = (PIP_PACKET)
01270 //    DisplayIPPacket(pIPPacket);
01271 
01272     if (Adapter->TransmitError) {
01273         /* FIXME: Retransmit now or let upper layer protocols handle retransmit? */
01274         Adapter->TransmitError = FALSE;
01275     }
01276 
01277     /* Free transmit buffers */
01278     Length      = Adapter->TXSize[Adapter->TXCurrent];
01279     BufferCount = (Length + DRIVER_BLOCK_SIZE - 1) / DRIVER_BLOCK_SIZE;
01280 
01281     NDIS_DbgPrint(MID_TRACE, ("Freeing (%d) buffers at (%d).\n",
01282         BufferCount,
01283         Adapter->TXCurrent));
01284 
01285     Adapter->TXFree += BufferCount;
01286     Adapter->TXSize[Adapter->TXCurrent] = 0;
01287     Adapter->TXCurrent = (Adapter->TXCurrent + BufferCount) % Adapter->TXCount;
01288 
01289     if (Adapter->TXSize[Adapter->TXCurrent] == 0) {
01290         NDIS_DbgPrint(MID_TRACE, ("No more packets in transmit buffer.\n"));
01291 
01292         Adapter->TXCurrent = -1;
01293     }
01294 
01295     if (Adapter->TXQueueTail) {
01296         if (NICPrepareForTransmit(Adapter))
01297             NICStartTransmit(Adapter);
01298     }
01299 }
01300 
01301 
01302 VOID NTAPI MiniportHandleInterrupt(
01303     IN  NDIS_HANDLE MiniportAdapterContext)
01304 /*
01305  * FUNCTION: Handler for deferred processing of interrupts
01306  * ARGUMENTS:
01307  *     MiniportAdapterContext = Pointer to adapter context area
01308  * NOTES:
01309  *     Interrupt Service Register is read to determine which interrupts
01310  *     are pending. All pending interrupts are handled
01311  */
01312 {
01313     UCHAR ISRValue;
01314     UCHAR ISRMask;
01315     UCHAR Mask;
01316     PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
01317     UINT i = 0;
01318 
01319     ISRMask = Adapter->InterruptMask;
01320     NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &ISRValue);
01321 
01322     NDIS_DbgPrint(MID_TRACE, ("ISRValue (0x%X).\n", ISRValue));
01323 
01324     Adapter->InterruptStatus |= (ISRValue & ISRMask);
01325 
01326     Mask = 0x01;
01327     while (Adapter->InterruptStatus != 0x00 && i++ < INTERRUPT_LIMIT) {
01328 
01329         if (ISRValue != 0x00) {
01330             /* Acknowledge interrupts */
01331             NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISRValue);
01332             Mask = 0x01;
01333         }
01334 
01335         NDIS_DbgPrint(MID_TRACE, ("Adapter->InterruptStatus (0x%X)  Mask (0x%X).\n",
01336             Adapter->InterruptStatus, Mask));
01337 
01338         /* Find next interrupt type */
01339         while (((Adapter->InterruptStatus & Mask) == 0) && (Mask < ISRMask))
01340             Mask = (Mask << 1);
01341 
01342         switch (Adapter->InterruptStatus & Mask) {
01343         case ISR_OVW:
01344             NDIS_DbgPrint(MID_TRACE, ("Overflow interrupt.\n"));
01345             /* Overflow. Handled almost the same way as a receive interrupt */
01346             Adapter->BufferOverflow = TRUE;
01347 
01348         NDIS_DbgPrint(MAX_TRACE,("Adapter->MiniportAdapterHandle: %x\n",
01349                      Adapter->MiniportAdapterHandle));
01350         if(Adapter->MiniportAdapterHandle)
01351         HandleReceive(Adapter);
01352         else
01353         NDIS_DbgPrint(MAX_TRACE,("No miniport adapter yet\n"));
01354 
01355             Adapter->InterruptStatus &= ~ISR_OVW;
01356             break;
01357 
01358         case ISR_RXE:
01359             NDIS_DbgPrint(MID_TRACE, ("Receive error interrupt.\n"));
01360             NICUpdateCounters(Adapter);
01361 
01362             Adapter->ReceiveError = TRUE;
01363             break;
01364         case ISR_PRX:
01365             NDIS_DbgPrint(MID_TRACE, ("Receive interrupt.\n"));
01366 
01367         NDIS_DbgPrint(MAX_TRACE,("Adapter->MiniportAdapterHandle: %x\n",
01368                      Adapter->MiniportAdapterHandle));
01369         if(Adapter->MiniportAdapterHandle)
01370         HandleReceive(Adapter);
01371         else
01372         NDIS_DbgPrint(MAX_TRACE,("No miniport adapter yet\n"));
01373 
01374             Adapter->InterruptStatus &= ~(ISR_PRX | ISR_RXE);
01375             break;
01376 
01377         case ISR_TXE:
01378             NDIS_DbgPrint(MID_TRACE, ("Transmit error interrupt.\n"));
01379             NICUpdateCounters(Adapter);
01380 
01381             Adapter->TransmitError = TRUE;
01382             break;
01383         case ISR_PTX:
01384             NDIS_DbgPrint(MID_TRACE, ("Transmit interrupt.\n"));
01385 
01386             HandleTransmit(Adapter);
01387 
01388             Adapter->InterruptStatus &= ~(ISR_PTX | ISR_TXE);
01389             break;
01390 
01391         case ISR_CNT:
01392             NDIS_DbgPrint(MID_TRACE, ("Counter interrupt.\n"));
01393             /* Counter overflow. Read counters from the NIC */
01394             NICUpdateCounters(Adapter);
01395 
01396             Adapter->InterruptStatus &= ~ISR_CNT;
01397             break;
01398 
01399         default:
01400             NDIS_DbgPrint(MID_TRACE, ("Unknown interrupt. Adapter->InterruptStatus (0x%X).\n", Adapter->InterruptStatus));
01401             Adapter->InterruptStatus &= ~Mask;
01402             break;
01403         }
01404 
01405         Mask = (Mask << 1);
01406 
01407         /* Check if new interrupts are generated */
01408 
01409         NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &ISRValue);
01410 
01411         NDIS_DbgPrint(MID_TRACE, ("ISRValue (0x%X).\n", ISRValue));
01412 
01413         Adapter->InterruptStatus |= (ISRValue & ISRMask);
01414     }
01415 
01416     NICEnableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
01417 }
01418 
01419 /* EOF */

Generated on Sat May 26 2012 04:26:36 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.