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

pcnet.c
Go to the documentation of this file.
00001 /*
00002  * ReactOS AMD PCNet Driver
00003  *
00004  * Copyright (C) 2003 Vizzini <vizzini@plasmic.com>
00005  * Copyright (C) 2004 Filip Navara <navaraf@reactos.com>
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License along
00018  * with this program; if not, write to the Free Software Foundation, Inc.,
00019  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00020  *
00021  * REVISIONS:
00022  *     09-Sep-2003 vizzini - Created
00023  *     10-Oct-2004 navaraf - Fix receive to work on VMware adapters (
00024  *                           need to set busmaster bit on PCI).
00025  *                         - Indicate receive completition.
00026  *                         - Implement packet transmitting.
00027  *                         - Don't read slot number from registry and
00028  *                           report itself as NDIS 5.0 miniport.
00029  *     11-Oct-2004 navaraf - Fix nasty bugs in halt code path.
00030  *     17-Oct-2004 navaraf - Add multicast support.
00031  *                         - Add media state detection support.
00032  *                         - Protect the adapter context with spinlock
00033  *                           and move code talking to card to inside
00034  *                           NdisMSynchronizeWithInterrupt calls where
00035  *                           necessary.
00036  *
00037  * NOTES:
00038  *     - this assumes a 32-bit machine
00039  */
00040 
00041 #include "pcnet.h"
00042 
00043 #define NDEBUG
00044 #include <debug.h>
00045 
00046 NTSTATUS
00047 NTAPI
00048 DriverEntry(
00049     IN PDRIVER_OBJECT DriverObject,
00050     IN PUNICODE_STRING RegistryPath);
00051 
00052 static VOID
00053 NTAPI
00054 MiniportHandleInterrupt(
00055     IN NDIS_HANDLE MiniportAdapterContext)
00056 /*
00057  * FUNCTION: Handle an interrupt if told to by MiniportISR
00058  * ARGUMENTS:
00059  *     MiniportAdapterContext: context specified to NdisMSetAttributes
00060  * NOTES:
00061  *     - Called by NDIS at DISPATCH_LEVEL
00062  */
00063 {
00064   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
00065   USHORT Data;
00066   UINT i = 0;
00067 
00068   DPRINT("Called\n");
00069 
00070   ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
00071 
00072   NdisDprAcquireSpinLock(&Adapter->Lock);
00073 
00074   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
00075   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00076 
00077   DPRINT("CSR0 is 0x%x\n", Data);
00078 
00079   while((Data & CSR0_INTR) && i++ < INTERRUPT_LIMIT)
00080     {
00081       /* Clear interrupt flags early to avoid race conditions. */
00082       NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
00083 
00084       if(Data & CSR0_ERR)
00085         {
00086           DPRINT("error: %x\n", Data & (CSR0_MERR|CSR0_BABL|CSR0_CERR|CSR0_MISS));
00087           if (Data & CSR0_CERR)
00088             Adapter->Statistics.XmtCollisions++;
00089         }
00090       if(Data & CSR0_IDON)
00091         {
00092           DPRINT("IDON\n");
00093         }
00094       if(Data & CSR0_RINT)
00095         {
00096           BOOLEAN IndicatedData = FALSE;
00097 
00098           DPRINT("receive interrupt\n");
00099 
00100           while(1)
00101             {
00102               PRECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptorRingVirt + Adapter->CurrentReceiveDescriptorIndex;
00103               PCHAR Buffer;
00104               ULONG ByteCount;
00105 
00106               if(Descriptor->FLAGS & RD_OWN)
00107                 {
00108                   DPRINT("no more receive descriptors to process\n");
00109                   break;
00110                 }
00111 
00112               if(Descriptor->FLAGS & RD_ERR)
00113                 {
00114                   DPRINT("receive descriptor error: 0x%x\n", Descriptor->FLAGS);
00115                   if (Descriptor->FLAGS & RD_BUFF)
00116                     Adapter->Statistics.RcvBufferErrors++;
00117                   if (Descriptor->FLAGS & RD_CRC)
00118                     Adapter->Statistics.RcvCrcErrors++;
00119                   if (Descriptor->FLAGS & RD_OFLO)
00120                     Adapter->Statistics.RcvOverflowErrors++;
00121                   if (Descriptor->FLAGS & RD_FRAM)
00122                     Adapter->Statistics.RcvFramingErrors++;
00123                   break;
00124                 }
00125 
00126               if(!((Descriptor->FLAGS & RD_STP) && (Descriptor->FLAGS & RD_ENP)))
00127                 {
00128                   DPRINT("receive descriptor not start&end: 0x%x\n", Descriptor->FLAGS);
00129                   break;
00130                 }
00131 
00132               Buffer = Adapter->ReceiveBufferPtrVirt + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE;
00133               ByteCount = Descriptor->MCNT & 0xfff;
00134 
00135               DPRINT("Indicating a %d-byte packet (index %d)\n", ByteCount, Adapter->CurrentReceiveDescriptorIndex);
00136 
00137               NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle, 0, Buffer, 14, Buffer+14, ByteCount-14, ByteCount-14);
00138 
00139               IndicatedData = TRUE;
00140 
00141               RtlZeroMemory(Descriptor, sizeof(RECEIVE_DESCRIPTOR));
00142               Descriptor->RBADR =
00143                   (ULONG)(Adapter->ReceiveBufferPtrPhys + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE);
00144               Descriptor->BCNT = (-BUFFER_SIZE) | 0xf000;
00145               Descriptor->FLAGS |= RD_OWN;
00146 
00147               Adapter->CurrentReceiveDescriptorIndex++;
00148               Adapter->CurrentReceiveDescriptorIndex %= Adapter->BufferCount;
00149 
00150               Adapter->Statistics.RcvGoodFrames++;
00151             }
00152 
00153             if (IndicatedData)
00154                 NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
00155         }
00156       if(Data & CSR0_TINT)
00157         {
00158           PTRANSMIT_DESCRIPTOR Descriptor;
00159 
00160           DPRINT("transmit interrupt\n");
00161 
00162           while (Adapter->CurrentTransmitStartIndex !=
00163                  Adapter->CurrentTransmitEndIndex)
00164             {
00165               Descriptor = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitStartIndex;
00166 
00167               DPRINT("buffer %d flags %x flags2 %x\n",
00168                      Adapter->CurrentTransmitStartIndex,
00169                      Descriptor->FLAGS, Descriptor->FLAGS2);
00170 
00171               if (Descriptor->FLAGS & TD1_OWN)
00172                 {
00173                   DPRINT("non-TXed buffer\n");
00174                   break;
00175                 }
00176 
00177               if (Descriptor->FLAGS & TD1_STP)
00178                 {
00179                   if (Descriptor->FLAGS & TD1_ONE)
00180                     Adapter->Statistics.XmtOneRetry++;
00181                   else if (Descriptor->FLAGS & TD1_MORE)
00182                     Adapter->Statistics.XmtMoreThanOneRetry++;
00183                 }
00184 
00185               if (Descriptor->FLAGS & TD1_ERR)
00186                 {
00187                   DPRINT("major error: %x\n", Descriptor->FLAGS2);
00188                   if (Descriptor->FLAGS2 & TD2_RTRY)
00189                     Adapter->Statistics.XmtRetryErrors++;
00190                   if (Descriptor->FLAGS2 & TD2_LCAR)
00191                     Adapter->Statistics.XmtLossesOfCarrier++;
00192                   if (Descriptor->FLAGS2 & TD2_LCOL)
00193                     Adapter->Statistics.XmtLateCollisions++;
00194                   if (Descriptor->FLAGS2 & TD2_EXDEF)
00195                     Adapter->Statistics.XmtExcessiveDefferals++;
00196                   if (Descriptor->FLAGS2 & TD2_UFLO)
00197                     Adapter->Statistics.XmtBufferUnderflows++;
00198                   if (Descriptor->FLAGS2 & TD2_BUFF)
00199                     Adapter->Statistics.XmtBufferErrors++;
00200                   break;
00201                 }
00202 
00203               Adapter->CurrentTransmitStartIndex++;
00204               Adapter->CurrentTransmitStartIndex %= Adapter->BufferCount;
00205 
00206               Adapter->Statistics.XmtGoodFrames++;
00207             }
00208           NdisMSendResourcesAvailable(Adapter->MiniportAdapterHandle);
00209         }
00210       if(Data & ~(CSR0_ERR | CSR0_IDON | CSR0_RINT | CSR0_TINT))
00211         {
00212           DPRINT("UNHANDLED INTERRUPT CSR0 0x%x\n", Data);
00213         }
00214 
00215       NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00216     }
00217 
00218   /* re-enable interrupts */
00219   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA);
00220 
00221   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00222   DPRINT("CSR0 is now 0x%x\n", Data);
00223 
00224   NdisDprReleaseSpinLock(&Adapter->Lock);
00225 }
00226 
00227 static NDIS_STATUS
00228 MiQueryCard(
00229     IN PADAPTER Adapter)
00230 /*
00231  * FUNCTION: Detect the PCNET NIC in the configured slot and query its I/O address and interrupt vector
00232  * ARGUMENTS:
00233  *     MiniportAdapterContext: context supplied to NdisMSetAttributes
00234  * RETURNS:
00235  *     NDIS_STATUS_FAILURE on a general error
00236  *     NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
00237  *     NDIS_STATUS_SUCCESS on succes
00238  */
00239 {
00240   ULONG  buf32 = 0;
00241   UCHAR  buf8  = 0;
00242   NDIS_STATUS Status;
00243 
00244   /* Detect the card in the configured slot */
00245   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_PCIID, &buf32, 4);
00246   if(Status != 4)
00247     {
00248       Status =  NDIS_STATUS_FAILURE;
00249       DPRINT1("NdisReadPciSlotInformation failed\n");
00250       return Status;
00251     }
00252 
00253   if(buf32 != PCI_ID)
00254     {
00255       Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
00256       DPRINT1("card in slot isn't our: 0x%x\n", 0, buf32);
00257       return Status;
00258     }
00259 
00260   /* set busmaster and io space enable bits */
00261   buf32 = PCI_BMEN | PCI_IOEN;
00262   NdisWritePciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_COMMAND, &buf32, 4);
00263 
00264   /* get IO base physical address */
00265   buf32 = 0;
00266   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_IOBAR, &buf32, 4);
00267   if(Status != 4)
00268     {
00269       Status = NDIS_STATUS_FAILURE;
00270       DPRINT1("NdisReadPciSlotInformation failed\n");
00271       return Status;
00272     }
00273 
00274   if(!buf32)
00275     {
00276       DPRINT1("No base i/o address set\n");
00277       return NDIS_STATUS_FAILURE;
00278     }
00279 
00280   buf32 &= ~1;  /* even up address - comes out odd for some reason */
00281 
00282   DPRINT("detected io address 0x%x\n", buf32);
00283   Adapter->IoBaseAddress = buf32;
00284 
00285   /* get interrupt vector */
00286   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_ILR, &buf8, 1);
00287   if(Status != 1)
00288     {
00289       Status = NDIS_STATUS_FAILURE;
00290       DPRINT1("NdisReadPciSlotInformation failed\n");
00291       return Status;
00292     }
00293 
00294   DPRINT("interrupt: 0x%x\n", buf8);
00295   Adapter->InterruptVector = buf8;
00296 
00297   return NDIS_STATUS_SUCCESS;
00298 }
00299 
00300 static VOID
00301 MiFreeSharedMemory(
00302     PADAPTER Adapter)
00303 /*
00304  * FUNCTION: Free all allocated shared memory
00305  * ARGUMENTS:
00306  *     Adapter: pointer to the miniport's adapter struct
00307  */
00308 {
00309   NDIS_PHYSICAL_ADDRESS PhysicalAddress;
00310 
00311   PhysicalAddress.u.HighPart = 0;
00312 
00313   if(Adapter->InitializationBlockVirt)
00314     {
00315       PhysicalAddress.u.LowPart = (ULONG)Adapter->InitializationBlockPhys;
00316       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
00317           FALSE, Adapter->InitializationBlockVirt, PhysicalAddress);
00318       Adapter->InitializationBlockVirt = NULL;
00319     }
00320 
00321   if(Adapter->TransmitDescriptorRingVirt)
00322     {
00323       PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitDescriptorRingPhys;
00324       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
00325         FALSE, Adapter->TransmitDescriptorRingVirt, PhysicalAddress);
00326       Adapter->TransmitDescriptorRingVirt = NULL;
00327     }
00328 
00329   if(Adapter->ReceiveDescriptorRingVirt)
00330     {
00331       PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveDescriptorRingPhys;
00332       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
00333           FALSE, Adapter->ReceiveDescriptorRingVirt, PhysicalAddress);
00334       Adapter->ReceiveDescriptorRingVirt = NULL;
00335     }
00336 
00337   if(Adapter->TransmitBufferPtrVirt)
00338     {
00339       PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitBufferPtrPhys;
00340       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
00341           TRUE, Adapter->TransmitBufferPtrVirt, PhysicalAddress);
00342       Adapter->TransmitBufferPtrVirt = NULL;
00343     }
00344 
00345   if(Adapter->ReceiveBufferPtrVirt)
00346     {
00347       PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveBufferPtrPhys;
00348       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
00349           TRUE, Adapter->ReceiveBufferPtrVirt, PhysicalAddress);
00350       Adapter->ReceiveBufferPtrVirt = NULL;
00351     }
00352 }
00353 
00354 static NDIS_STATUS
00355 MiAllocateSharedMemory(
00356     PADAPTER Adapter)
00357 /*
00358  * FUNCTION: Allocate all shared memory used by the miniport
00359  * ARGUMENTS:
00360  *     Adapter: Pointer to the miniport's adapter object
00361  * RETURNS:
00362  *     NDIS_STATUS_RESOURCES on insufficient memory
00363  *     NDIS_STATUS_SUCCESS on success
00364  */
00365 {
00366   PTRANSMIT_DESCRIPTOR TransmitDescriptor;
00367   PRECEIVE_DESCRIPTOR  ReceiveDescriptor;
00368   NDIS_PHYSICAL_ADDRESS PhysicalAddress;
00369   ULONG i;
00370   ULONG BufferCount = NUMBER_OF_BUFFERS;
00371   ULONG LogBufferCount = LOG_NUMBER_OF_BUFFERS;
00372 
00373   while (BufferCount != 0)
00374   {
00375       /* allocate the initialization block (we have this in the loop so we can use MiFreeSharedMemory) */
00376       Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK);
00377       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
00378           FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress);
00379       if(!Adapter->InitializationBlockVirt)
00380       {
00381          /* Buffer backoff won't help us here */
00382          DPRINT1("insufficient resources\n");
00383          return NDIS_STATUS_RESOURCES;
00384       }
00385 
00386       if(((ULONG)Adapter->InitializationBlockVirt & 0x00000003) != 0)
00387       {
00388          DPRINT1("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt);
00389          return NDIS_STATUS_RESOURCES;
00390       }
00391 
00392       Adapter->InitializationBlockPhys = (PINITIALIZATION_BLOCK)NdisGetPhysicalAddressLow(PhysicalAddress);
00393 
00394       /* allocate the transport descriptor ring */
00395       Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * BufferCount;
00396       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
00397           FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress);
00398       if (!Adapter->TransmitDescriptorRingVirt)
00399       {
00400           DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
00401           BufferCount = BufferCount >> 1;
00402           LogBufferCount--;
00403           MiFreeSharedMemory(Adapter);
00404           continue;
00405       }
00406 
00407       if (((ULONG)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0)
00408       {
00409          DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt);
00410          return NDIS_STATUS_RESOURCES;
00411       }
00412 
00413       Adapter->TransmitDescriptorRingPhys = (PTRANSMIT_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
00414       RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * BufferCount);
00415 
00416       /* allocate the receive descriptor ring */
00417       Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * BufferCount;
00418       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
00419           FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress);
00420       if (!Adapter->ReceiveDescriptorRingVirt)
00421       {
00422           DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
00423           BufferCount = BufferCount >> 1;
00424           LogBufferCount--;
00425           MiFreeSharedMemory(Adapter);
00426           continue;
00427       }
00428 
00429       if (((ULONG)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0)
00430       {
00431           DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt);
00432           return NDIS_STATUS_RESOURCES;
00433       }
00434 
00435       Adapter->ReceiveDescriptorRingPhys = (PRECEIVE_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
00436       RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * BufferCount);
00437 
00438       /* allocate transmit buffers */
00439       Adapter->TransmitBufferLength = BUFFER_SIZE * BufferCount;
00440       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
00441          TRUE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress);
00442       if(!Adapter->TransmitBufferPtrVirt)
00443       {
00444           DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
00445           BufferCount = BufferCount >> 1;
00446           LogBufferCount--;
00447           MiFreeSharedMemory(Adapter);
00448           continue;
00449       }
00450 
00451       if (((ULONG)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0)
00452       {
00453           DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt);
00454           return NDIS_STATUS_RESOURCES;
00455       }
00456 
00457       Adapter->TransmitBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
00458       RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * BufferCount);
00459 
00460       /* allocate receive buffers */
00461       Adapter->ReceiveBufferLength = BUFFER_SIZE * BufferCount;
00462       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
00463          TRUE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress);
00464       if(!Adapter->ReceiveBufferPtrVirt)
00465       {
00466           DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
00467           BufferCount = BufferCount >> 1;
00468           LogBufferCount--;
00469           MiFreeSharedMemory(Adapter);
00470           continue;
00471       }
00472 
00473       if (((ULONG)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0)
00474       {
00475           DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt);
00476           return NDIS_STATUS_RESOURCES;
00477       }
00478 
00479       Adapter->ReceiveBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
00480       RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * BufferCount);
00481 
00482       break;
00483   }
00484 
00485   if (!BufferCount)
00486   {
00487       DPRINT1("Failed to allocate adapter buffers\n");
00488       return NDIS_STATUS_RESOURCES;
00489   }
00490 
00491   Adapter->BufferCount = BufferCount;
00492   Adapter->LogBufferCount = LogBufferCount;
00493 
00494   /* initialize tx descriptors */
00495   TransmitDescriptor = Adapter->TransmitDescriptorRingVirt;
00496   for(i = 0; i < BufferCount; i++)
00497     {
00498       (TransmitDescriptor+i)->TBADR = (ULONG)Adapter->TransmitBufferPtrPhys + i * BUFFER_SIZE;
00499       (TransmitDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment  + set top 4 bits */
00500       (TransmitDescriptor+i)->FLAGS = TD1_STP | TD1_ENP;
00501     }
00502 
00503   DPRINT("transmit ring initialized\n");
00504 
00505   /* initialize rx */
00506   ReceiveDescriptor = Adapter->ReceiveDescriptorRingVirt;
00507   for(i = 0; i < BufferCount; i++)
00508     {
00509       (ReceiveDescriptor+i)->RBADR = (ULONG)Adapter->ReceiveBufferPtrPhys + i * BUFFER_SIZE;
00510       (ReceiveDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment  + set top 4 bits */
00511       (ReceiveDescriptor+i)->FLAGS = RD_OWN;
00512     }
00513 
00514   DPRINT("receive ring initialized\n");
00515 
00516   return NDIS_STATUS_SUCCESS;
00517 }
00518 
00519 static VOID
00520 MiPrepareInitializationBlock(
00521     PADAPTER Adapter)
00522 /*
00523  * FUNCTION: Initialize the initialization block
00524  * ARGUMENTS:
00525  *     Adapter: pointer to the miniport's adapter object
00526  */
00527 {
00528   ULONG i = 0;
00529 
00530   RtlZeroMemory(Adapter->InitializationBlockVirt, sizeof(INITIALIZATION_BLOCK));
00531 
00532   /* read burned-in address from card */
00533   for(i = 0; i < 6; i++)
00534     NdisRawReadPortUchar(Adapter->PortOffset + i, Adapter->InitializationBlockVirt->PADR + i);
00535   DPRINT("MAC address: %02x-%02x-%02x-%02x-%02x-%02x\n",
00536          Adapter->InitializationBlockVirt->PADR[0],
00537          Adapter->InitializationBlockVirt->PADR[1],
00538          Adapter->InitializationBlockVirt->PADR[2],
00539          Adapter->InitializationBlockVirt->PADR[3],
00540          Adapter->InitializationBlockVirt->PADR[4],
00541          Adapter->InitializationBlockVirt->PADR[5]);
00542 
00543   /* set up receive ring */
00544   DPRINT("Receive ring physical address: 0x%x\n", Adapter->ReceiveDescriptorRingPhys);
00545   Adapter->InitializationBlockVirt->RDRA = (ULONG)Adapter->ReceiveDescriptorRingPhys;
00546   Adapter->InitializationBlockVirt->RLEN = (Adapter->LogBufferCount << 4) & 0xf0;
00547 
00548   /* set up transmit ring */
00549   DPRINT("Transmit ring physical address: 0x%x\n", Adapter->TransmitDescriptorRingPhys);
00550   Adapter->InitializationBlockVirt->TDRA = (ULONG)Adapter->TransmitDescriptorRingPhys;
00551   Adapter->InitializationBlockVirt->TLEN = (Adapter->LogBufferCount << 4) & 0xf0;
00552 }
00553 
00554 static BOOLEAN
00555 NTAPI
00556 MiSyncStop(
00557     IN PVOID SynchronizeContext)
00558 /*
00559  * FUNCTION: Stop the adapter
00560  * ARGUMENTS:
00561  *     SynchronizeContext: Adapter context
00562  */
00563 {
00564   PADAPTER Adapter = (PADAPTER)SynchronizeContext;
00565   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
00566   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
00567   return TRUE;
00568 }
00569 
00570 static VOID
00571 NTAPI
00572 MiniportHalt(
00573     IN NDIS_HANDLE MiniportAdapterContext)
00574 /*
00575  * FUNCTION: Stop the adapter and release any per-adapter resources
00576  * ARGUMENTS:
00577  *     MiniportAdapterContext: context specified to NdisMSetAttributes
00578  * NOTES:
00579  *     - Called by NDIS at PASSIVE_LEVEL
00580  */
00581 {
00582   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
00583   BOOLEAN TimerCancelled;
00584 
00585   DPRINT("Called\n");
00586   ASSERT(Adapter);
00587 
00588   /* stop the media detection timer */
00589   NdisMCancelTimer(&Adapter->MediaDetectionTimer, &TimerCancelled);
00590 
00591   /* stop the chip */
00592   NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStop, Adapter);
00593 
00594   /* deregister the interrupt */
00595   NdisMDeregisterInterrupt(&Adapter->InterruptObject);
00596 
00597   /* deregister i/o port range */
00598   NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset);
00599 
00600   /* deregister the shutdown routine */
00601   NdisMDeregisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle);
00602 
00603   /* free shared memory */
00604   MiFreeSharedMemory(Adapter);
00605 
00606   /* free map registers */
00607   NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
00608 
00609   /* free the lock */
00610   NdisFreeSpinLock(&Adapter->Lock);
00611 
00612   /* free the adapter */
00613   NdisFreeMemory(Adapter, 0, 0);
00614 }
00615 
00616 static BOOLEAN
00617 NTAPI
00618 MiSyncMediaDetection(
00619     IN PVOID SynchronizeContext)
00620 /*
00621  * FUNCTION: Stop the adapter
00622  * ARGUMENTS:
00623  *     SynchronizeContext: Adapter context
00624  */
00625 {
00626   PADAPTER Adapter = (PADAPTER)SynchronizeContext;
00627   NDIS_MEDIA_STATE MediaState = MiGetMediaState(Adapter);
00628   UINT MediaSpeed = MiGetMediaSpeed(Adapter);
00629   BOOLEAN FullDuplex = MiGetMediaDuplex(Adapter);
00630 
00631   DPRINT("Called\n");
00632   DPRINT("MediaState: %d\n", MediaState);
00633   if (MediaState != Adapter->MediaState ||
00634       MediaSpeed != Adapter->MediaSpeed ||
00635       FullDuplex != Adapter->FullDuplex)
00636     {
00637       Adapter->MediaState = MediaState;
00638       Adapter->MediaSpeed = MediaSpeed;
00639       Adapter->FullDuplex = FullDuplex;
00640       return TRUE;
00641     }
00642   return FALSE;
00643 }
00644 
00645 static VOID
00646 NTAPI
00647 MiniportMediaDetectionTimer(
00648     IN PVOID SystemSpecific1,
00649     IN PVOID FunctionContext,
00650     IN PVOID SystemSpecific2,
00651     IN PVOID SystemSpecific3)
00652 /*
00653  * FUNCTION: Periodially query media state
00654  * ARGUMENTS:
00655  *     FunctionContext: Adapter context
00656  * NOTES:
00657  *     - Called by NDIS at DISPATCH_LEVEL
00658  */
00659 {
00660   PADAPTER Adapter = (PADAPTER)FunctionContext;
00661 
00662   ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
00663 
00664   if (NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject,
00665                                     MiSyncMediaDetection,
00666                                     FunctionContext))
00667     {
00668       NdisMIndicateStatus(Adapter->MiniportAdapterHandle,
00669         Adapter->MediaState == NdisMediaStateConnected ?
00670         NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
00671         (PVOID)0, 0);
00672       NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle);
00673     }
00674 }
00675 
00676 static VOID
00677 MiInitChip(
00678     PADAPTER Adapter)
00679 /*
00680  * FUNCTION: Initialize and start the PCNET chip
00681  * ARGUMENTS:
00682  *     Adapter: pointer to the miniport's adapter struct
00683  * NOTES:
00684  *     - should be coded to detect failure and return an error
00685  *     - the vmware virtual lance chip doesn't support 32-bit i/o so don't do that.
00686  */
00687 {
00688   USHORT Data = 0;
00689 
00690   DPRINT("Called\n");
00691 
00692   /*
00693    * first reset the chip - 32-bit reset followed by 16-bit reset.  if it's in 32-bit mode, it'll reset
00694    * twice.  if it's in 16-bit mode, the first read will be nonsense and the second will be a reset.  the
00695    * card is reset by reading from the reset register.  on reset it's in 16-bit i/o mode.
00696    */
00697   NdisRawReadPortUshort(Adapter->PortOffset + RESET32, &Data);
00698   NdisRawReadPortUshort(Adapter->PortOffset + RESET16, &Data);
00699 
00700   /* stop the chip */
00701   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
00702   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
00703 
00704   /* pause for 1ms so the chip will have time to reset */
00705   NdisStallExecution(1);
00706 
00707   DPRINT("chip stopped\n");
00708 
00709   /* set the software style to 2 (32 bits) */
00710   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR58);
00711   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00712 
00713   Data |= SW_STYLE_2;
00714 
00715   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
00716 
00717   /* set up csr4: auto transmit pad, disable polling, disable transmit interrupt, dmaplus */
00718   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
00719   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00720 
00721   Data |= CSR4_APAD_XMT | /* CSR4_DPOLL |*/ CSR4_TXSTRTM | CSR4_DMAPLUS;
00722   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
00723 
00724   /* set up bcr18: burst read/write enable */
00725   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR18);
00726   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
00727 
00728   Data |= BCR18_BREADE | BCR18_BWRITE ;
00729   NdisRawWritePortUshort(Adapter->PortOffset + BDP, Data);
00730 
00731   /* set up csr1 and csr2 with init block */
00732   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR1);
00733   NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)((ULONG)Adapter->InitializationBlockPhys & 0xffff));
00734   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR2);
00735   NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)((ULONG)Adapter->InitializationBlockPhys >> 16) & 0xffff);
00736 
00737   DPRINT("programmed with init block\n");
00738 
00739   /* Set mode to 0 */
00740   Data = 0;
00741   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR15);
00742   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
00743 
00744   /* load init block and start the card */
00745   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
00746   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STRT|CSR0_INIT|CSR0_IENA);
00747 
00748   /* Allow LED programming */
00749   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR2);
00750   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR2_LEDPE);
00751 
00752   /* LED0 is configured for link status (on = up, off = down) */
00753   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
00754   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR4_LNKSTE | BCR4_PSE);
00755 
00756   /* LED1 is configured for link duplex (on = full, off = half) */
00757   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR5);
00758   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR5_FDLSE | BCR5_PSE);
00759 
00760   /* LED2 is configured for link speed (on = 100M, off = 10M) */
00761   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR6);
00762   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR6_E100 | BCR6_PSE);
00763 
00764   /* LED3 is configured for trasmit/receive activity */
00765   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR7);
00766   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR7_XMTE | BCR7_RCVE | BCR7_PSE);
00767 
00768   Adapter->MediaState = MiGetMediaState(Adapter);
00769   Adapter->FullDuplex = MiGetMediaDuplex(Adapter);
00770   Adapter->MediaSpeed = MiGetMediaSpeed(Adapter);
00771 
00772   DPRINT("card started\n");
00773 
00774   Adapter->Flags &= ~RESET_IN_PROGRESS;
00775 }
00776 
00777 #if DBG
00778 static BOOLEAN
00779 MiTestCard(
00780     PADAPTER Adapter)
00781 /*
00782  * FUNCTION: Test the NIC
00783  * ARGUMENTS:
00784  *     Adapter: pointer to the miniport's adapter struct
00785  * RETURNS:
00786  *     TRUE if the test succeeds
00787  *     FALSE otherwise
00788  * NOTES:
00789  *     - this is where to add diagnostics.  This is called
00790  *       at the very end of initialization.
00791  */
00792 {
00793   int i = 0;
00794   UCHAR address[6];
00795   USHORT Data = 0;
00796 
00797   /* see if we can read/write now */
00798   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
00799   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00800   DPRINT("Port 0x%x RAP 0x%x CSR0 0x%x RDP 0x%x, Interupt status register is 0x%x\n", Adapter->PortOffset, RAP, CSR0, RDP, Data);
00801 
00802   /* read the BIA */
00803   for(i = 0; i < 6; i++)
00804       NdisRawReadPortUchar(Adapter->PortOffset + i, &address[i]);
00805 
00806   DPRINT("burned-in address: %x:%x:%x:%x:%x:%x\n", address[0], address[1], address[2], address[3], address[4], address[5]);
00807   /* Read status flags from CSR0 */
00808   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
00809   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00810   DPRINT("CSR0: 0x%x\n", Data);
00811 
00812   /* Read status flags from CSR3 */
00813   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR3);
00814   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00815 
00816   DPRINT("CSR3: 0x%x\n", Data);
00817   /* Read status flags from CSR4 */
00818   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
00819   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00820   DPRINT("CSR4: 0x%x\n", Data);
00821 
00822   /* Read status flags from CSR5 */
00823   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR5);
00824   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00825   DPRINT("CSR5: 0x%x\n", Data);
00826 
00827   /* Read status flags from CSR6 */
00828   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR6);
00829   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
00830   DPRINT("CSR6: 0x%x\n", Data);
00831 
00832   return TRUE;
00833 }
00834 #endif
00835 
00836 VOID
00837 NTAPI
00838 MiniportShutdown( PVOID Context )
00839 {
00840   PADAPTER Adapter = Context;
00841 
00842   DPRINT("Stopping the chip\n");
00843 
00844   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
00845   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
00846 }
00847 
00848 static NDIS_STATUS
00849 NTAPI
00850 MiniportInitialize(
00851     OUT PNDIS_STATUS OpenErrorStatus,
00852     OUT PUINT SelectedMediumIndex,
00853     IN PNDIS_MEDIUM MediumArray,
00854     IN UINT MediumArraySize,
00855     IN NDIS_HANDLE MiniportAdapterHandle,
00856     IN NDIS_HANDLE WrapperConfigurationContext)
00857 /*
00858  * FUNCTION:  Initialize a new miniport
00859  * ARGUMENTS:
00860  *     OpenErrorStatus:  pointer to a var to return status info in
00861  *     SelectedMediumIndex: index of the selected medium (will be NdisMedium802_3)
00862  *     MediumArray: array of media that we can pick from
00863  *     MediumArraySize: size of MediumArray
00864  *     MiniportAdapterHandle: NDIS-assigned handle for this miniport instance
00865  *     WrapperConfigurationContext: temporary NDIS-assigned handle for passing
00866  *                                  to configuration APIs
00867  * RETURNS:
00868  *     NDIS_STATUS_SUCCESS on success
00869  *     NDIS_STATUS_FAILURE on general failure
00870  *     NDIS_STATUS_UNSUPPORTED_MEDIA on not finding 802_3 in the MediaArray
00871  *     NDIS_STATUS_RESOURCES on insufficient system resources
00872  *     NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
00873  * NOTES:
00874  *     - Called by NDIS at PASSIVE_LEVEL, once per detected card
00875  *     - Will int 3 on failure of MiTestCard if DBG=1
00876  */
00877 {
00878   UINT i = 0;
00879   PADAPTER Adapter = 0;
00880   NDIS_STATUS Status = NDIS_STATUS_FAILURE;
00881   BOOLEAN InterruptRegistered = FALSE, MapRegistersAllocated = FALSE;
00882   NDIS_HANDLE ConfigurationHandle;
00883   UINT *RegNetworkAddress = 0;
00884   UINT RegNetworkAddressLength = 0;
00885 
00886   ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
00887 
00888   /* Pick a medium */
00889   for(i = 0; i < MediumArraySize; i++)
00890     if(MediumArray[i] == NdisMedium802_3)
00891       break;
00892 
00893   if(i == MediumArraySize)
00894     {
00895       Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
00896       DPRINT1("unsupported media\n");
00897       *OpenErrorStatus = Status;
00898       return Status;
00899     }
00900 
00901   *SelectedMediumIndex = i;
00902 
00903   /* allocate our adapter struct */
00904   Status = NdisAllocateMemoryWithTag((PVOID *)&Adapter, sizeof(ADAPTER), PCNET_TAG);
00905   if(Status != NDIS_STATUS_SUCCESS)
00906     {
00907       Status =  NDIS_STATUS_RESOURCES;
00908       DPRINT1("Insufficient resources\n");
00909       *OpenErrorStatus = Status;
00910       return Status;
00911     }
00912 
00913   RtlZeroMemory(Adapter, sizeof(ADAPTER));
00914 
00915   Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
00916 
00917   /* register our adapter structwith ndis */
00918   NdisMSetAttributesEx(Adapter->MiniportAdapterHandle, Adapter, 0, NDIS_ATTRIBUTE_BUS_MASTER, NdisInterfacePci);
00919 
00920   do
00921     {
00922       /* Card-specific detection and setup */
00923       Status = MiQueryCard(Adapter);
00924       if(Status != NDIS_STATUS_SUCCESS)
00925         {
00926           DPRINT1("MiQueryCard failed\n");
00927           Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
00928           break;
00929         }
00930 
00931       /* register an IO port range */
00932       Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->PortOffset, Adapter->MiniportAdapterHandle,
00933           (UINT)Adapter->IoBaseAddress, NUMBER_OF_PORTS);
00934       if(Status != NDIS_STATUS_SUCCESS)
00935         {
00936           DPRINT1("NdisMRegisterIoPortRange failed: 0x%x\n", Status);
00937           break;
00938         }
00939 
00940       /* Allocate map registers */
00941       Status = NdisMAllocateMapRegisters(Adapter->MiniportAdapterHandle, 0,
00942           NDIS_DMA_32BITS, 8, BUFFER_SIZE);
00943       if(Status != NDIS_STATUS_SUCCESS)
00944         {
00945           DPRINT1("NdisMAllocateMapRegisters failed: 0x%x\n", Status);
00946           break;
00947         }
00948 
00949       MapRegistersAllocated = TRUE;
00950 
00951       /* set up the interrupt */
00952       Status = NdisMRegisterInterrupt(&Adapter->InterruptObject, Adapter->MiniportAdapterHandle, Adapter->InterruptVector,
00953           Adapter->InterruptVector, TRUE, TRUE, NdisInterruptLevelSensitive);
00954       if(Status != NDIS_STATUS_SUCCESS)
00955         {
00956           DPRINT1("NdisMRegisterInterrupt failed: 0x%x\n", Status);
00957           break;
00958         }
00959 
00960       InterruptRegistered = TRUE;
00961 
00962       /* Allocate and initialize shared data structures */
00963       Status = MiAllocateSharedMemory(Adapter);
00964       if(Status != NDIS_STATUS_SUCCESS)
00965         {
00966           Status = NDIS_STATUS_RESOURCES;
00967           DPRINT1("MiAllocateSharedMemory failed\n", Status);
00968           break;
00969         }
00970 
00971       /* set up the initialization block */
00972       MiPrepareInitializationBlock(Adapter);
00973 
00974       /* see if someone set a network address manually */
00975       NdisOpenConfiguration(&Status, &ConfigurationHandle, WrapperConfigurationContext);
00976       if (Status == NDIS_STATUS_SUCCESS)
00977       {
00978          NdisReadNetworkAddress(&Status, (PVOID *)&RegNetworkAddress, &RegNetworkAddressLength, ConfigurationHandle);
00979          if(Status == NDIS_STATUS_SUCCESS && RegNetworkAddressLength == 6)
00980          {
00981              int i;
00982              DPRINT("NdisReadNetworkAddress returned successfully, address %x:%x:%x:%x:%x:%x\n",
00983                      RegNetworkAddress[0], RegNetworkAddress[1], RegNetworkAddress[2], RegNetworkAddress[3],
00984                      RegNetworkAddress[4], RegNetworkAddress[5]);
00985 
00986              for(i = 0; i < 6; i++)
00987                  Adapter->InitializationBlockVirt->PADR[i] = RegNetworkAddress[i];
00988          }
00989 
00990          NdisCloseConfiguration(ConfigurationHandle);
00991       }
00992 
00993       DPRINT("Interrupt registered successfully\n");
00994 
00995       /* Initialize and start the chip */
00996       MiInitChip(Adapter);
00997 
00998       NdisAllocateSpinLock(&Adapter->Lock);
00999 
01000       Status = NDIS_STATUS_SUCCESS;
01001     }
01002   while(0);
01003 
01004   if(Status != NDIS_STATUS_SUCCESS && Adapter)
01005     {
01006       DPRINT("Error; freeing stuff\n");
01007 
01008       MiFreeSharedMemory(Adapter);
01009 
01010       if(MapRegistersAllocated)
01011         NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
01012 
01013       if(Adapter->PortOffset)
01014         NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset);
01015 
01016       if(InterruptRegistered)
01017         NdisMDeregisterInterrupt(&Adapter->InterruptObject);
01018 
01019       NdisFreeMemory(Adapter, 0, 0);
01020     }
01021 
01022   if(Status == NDIS_STATUS_SUCCESS)
01023     {
01024       NdisMInitializeTimer(&Adapter->MediaDetectionTimer,
01025                            Adapter->MiniportAdapterHandle,
01026                            MiniportMediaDetectionTimer,
01027                            Adapter);
01028       NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer,
01029                             MEDIA_DETECTION_INTERVAL);
01030       NdisMRegisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle,
01031                                           Adapter,
01032                                           MiniportShutdown);
01033     }
01034 
01035 #if DBG
01036   if(!MiTestCard(Adapter))
01037     ASSERT(0);
01038 #endif
01039 
01040   DPRINT("returning 0x%x\n", Status);
01041   *OpenErrorStatus = Status;
01042   return Status;
01043 }
01044 
01045 static VOID
01046 NTAPI
01047 MiniportISR(
01048     OUT PBOOLEAN InterruptRecognized,
01049     OUT PBOOLEAN QueueMiniportHandleInterrupt,
01050     IN NDIS_HANDLE MiniportAdapterContext)
01051 /*
01052  * FUNCTION: Miniport interrupt service routine
01053  * ARGUMENTS:
01054  *     InterruptRecognized: the interrupt was ours
01055  *     QueueMiniportHandleInterrupt: whether to queue a DPC to handle this interrupt
01056  *     MiniportAdapterContext: the context originally passed to NdisMSetAttributes
01057  * NOTES:
01058  *     - called by NDIS at DIRQL
01059  *     - by setting QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt
01060  *       will be called
01061  */
01062 {
01063   USHORT Data;
01064   USHORT Rap;
01065   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
01066 
01067   DPRINT("Called\n");
01068 
01069   /* save the old RAP value */
01070   NdisRawReadPortUshort(Adapter->PortOffset + RAP, &Rap);
01071 
01072   /* is this ours? */
01073   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
01074   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
01075 
01076   if(!(Data & CSR0_INTR))
01077     {
01078       DPRINT("not our interrupt.\n");
01079       *InterruptRecognized = FALSE;
01080       *QueueMiniportHandleInterrupt = FALSE;
01081     }
01082   else
01083     {
01084       DPRINT("detected our interrupt\n");
01085 
01086       /* disable interrupts */
01087       NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
01088       NdisRawWritePortUshort(Adapter->PortOffset + RDP, 0);
01089 
01090       *InterruptRecognized = TRUE;
01091       *QueueMiniportHandleInterrupt = TRUE;
01092     }
01093 
01094   /* restore the rap */
01095   NdisRawWritePortUshort(Adapter->PortOffset + RAP, Rap);
01096 }
01097 
01098 static NDIS_STATUS
01099 NTAPI
01100 MiniportReset(
01101     OUT PBOOLEAN AddressingReset,
01102     IN NDIS_HANDLE MiniportAdapterContext)
01103 /*
01104  * FUNCTION: Reset the miniport
01105  * ARGUMENTS:
01106  *     AddressingReset: Whether or not we want NDIS to subsequently call MiniportSetInformation
01107  *                      to reset our addresses and filters
01108  *     MiniportAdapterContext: context originally passed to NdisMSetAttributes
01109  * RETURNS:
01110  *     NDIS_STATUS_SUCCESS on all requests
01111  * Notes:
01112  *     - Called by NDIS at PASSIVE_LEVEL when it thinks we need a reset
01113  */
01114 {
01115   DPRINT("Called\n");
01116 
01117   /* MiniportReset doesn't do anything at the moment... perhaps this should be fixed. */
01118 
01119   *AddressingReset = FALSE;
01120   return NDIS_STATUS_SUCCESS;
01121 }
01122 
01123 static BOOLEAN
01124 NTAPI
01125 MiSyncStartTransmit(
01126     IN PVOID SynchronizeContext)
01127 /*
01128  * FUNCTION: Stop the adapter
01129  * ARGUMENTS:
01130  *     SynchronizeContext: Adapter context
01131  */
01132 {
01133   PADAPTER Adapter = (PADAPTER)SynchronizeContext;
01134   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
01135   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA | CSR0_TDMD);
01136   return TRUE;
01137 }
01138 
01139 static NDIS_STATUS
01140 NTAPI
01141 MiniportSend(
01142     IN NDIS_HANDLE MiniportAdapterContext,
01143     IN PNDIS_PACKET Packet,
01144     IN UINT Flags)
01145 /*
01146  * FUNCTION: Called by NDIS when it has a packet for the NIC to send out
01147  * ARGUMENTS:
01148  *     MiniportAdapterContext: context originally input to NdisMSetAttributes
01149  *     Packet: The NDIS_PACKET to be sent
01150  *     Flags: Flags associated with Packet
01151  * RETURNS:
01152  *     NDIS_STATUS_SUCCESS on processed requests
01153  *     NDIS_STATUS_RESOURCES if there's no place in buffer ring
01154  * NOTES:
01155  *     - Called by NDIS at DISPATCH_LEVEL
01156  */
01157 {
01158   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
01159   PTRANSMIT_DESCRIPTOR Desc;
01160   PNDIS_BUFFER NdisBuffer;
01161   PVOID SourceBuffer;
01162   UINT TotalPacketLength, SourceLength, Position = 0;
01163 
01164   DPRINT("Called\n");
01165 
01166   ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
01167 
01168   NdisDprAcquireSpinLock(&Adapter->Lock);
01169 
01170   /* Check if we have free entry in our circular buffer. */
01171   if ((Adapter->CurrentTransmitEndIndex + 1 ==
01172        Adapter->CurrentTransmitStartIndex) ||
01173       (Adapter->CurrentTransmitEndIndex == Adapter->BufferCount - 1 &&
01174        Adapter->CurrentTransmitStartIndex == 0))
01175     {
01176       DPRINT1("No free space in circular buffer\n");
01177       NdisDprReleaseSpinLock(&Adapter->Lock);
01178       return NDIS_STATUS_RESOURCES;
01179     }
01180 
01181   Desc = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitEndIndex;
01182 
01183   NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, &TotalPacketLength);
01184   ASSERT(TotalPacketLength <= BUFFER_SIZE);
01185 
01186   DPRINT("TotalPacketLength: %x\n", TotalPacketLength);
01187 
01188   while (NdisBuffer)
01189     {
01190       NdisQueryBuffer(NdisBuffer, &SourceBuffer, &SourceLength);
01191 
01192       DPRINT("Buffer: %x Length: %x\n", SourceBuffer, SourceLength);
01193 
01194       RtlCopyMemory(Adapter->TransmitBufferPtrVirt +
01195                     Adapter->CurrentTransmitEndIndex * BUFFER_SIZE + Position,
01196                     SourceBuffer, SourceLength);
01197 
01198       Position += SourceLength;
01199 
01200       NdisGetNextBuffer(NdisBuffer, &NdisBuffer);
01201     }
01202 
01203 #if DBG && 0
01204   {
01205     PUCHAR Ptr = Adapter->TransmitBufferPtrVirt +
01206                  Adapter->CurrentTransmitEndIndex * BUFFER_SIZE;
01207     for (Position = 0; Position < TotalPacketLength; Position++)
01208       {
01209         if (Position % 16 == 0)
01210           DbgPrint("\n");
01211         DbgPrint("%x ", *Ptr++);
01212       }
01213   }
01214   DbgPrint("\n");
01215 #endif
01216 
01217   Adapter->CurrentTransmitEndIndex++;
01218   Adapter->CurrentTransmitEndIndex %= Adapter->BufferCount;
01219 
01220   Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP;
01221   Desc->BCNT = 0xf000 | -TotalPacketLength;
01222 
01223   NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStartTransmit, Adapter);
01224 
01225   NdisDprReleaseSpinLock(&Adapter->Lock);
01226 
01227   return NDIS_STATUS_SUCCESS;
01228 }
01229 
01230 static ULONG
01231 NTAPI
01232 MiEthernetCrc(UCHAR *Address)
01233 /*
01234  * FUNCTION: Calculate Ethernet CRC32
01235  * ARGUMENTS:
01236  *     Address: 6-byte ethernet address
01237  * RETURNS:
01238  *     The calculated CRC32 value.
01239  */
01240 {
01241   UINT Counter, Length;
01242   ULONG Value = ~0;
01243 
01244   for (Length = 0; Length < 6; Length++)
01245     {
01246       Value ^= *Address++;
01247       for (Counter = 0; Counter < 8; Counter++)
01248         {
01249           Value >>= 1;
01250           Value ^= (Value & 1) * 0xedb88320;
01251         }
01252     }
01253 
01254   return Value;
01255 }
01256 
01257 NDIS_STATUS
01258 NTAPI
01259 MiSetMulticast(
01260     PADAPTER Adapter,
01261     UCHAR *Addresses,
01262     UINT AddressCount)
01263 {
01264   UINT Index;
01265   ULONG CrcIndex;
01266 
01267   NdisZeroMemory(Adapter->InitializationBlockVirt->LADR, 8);
01268   for (Index = 0; Index < AddressCount; Index++)
01269     {
01270       CrcIndex = MiEthernetCrc(Addresses) >> 26;
01271       Adapter->InitializationBlockVirt->LADR[CrcIndex >> 3] |= 1 << (CrcIndex & 15);
01272       Addresses += 6;
01273     }
01274 
01275   /* FIXME: The specification mentions we need to reload the init block here. */
01276 
01277   return NDIS_STATUS_SUCCESS;
01278 }
01279 
01280 BOOLEAN
01281 NTAPI
01282 MiGetMediaDuplex(PADAPTER Adapter)
01283 {
01284   ULONG Data;
01285 
01286   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR5);
01287   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
01288 
01289   return (Data & BCR5_LEDOUT) != 0;
01290 }
01291 
01292 UINT
01293 NTAPI
01294 MiGetMediaSpeed(PADAPTER Adapter)
01295 {
01296   ULONG Data;
01297 
01298   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR6);
01299   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
01300 
01301   return Data & BCR6_LEDOUT ? 100 : 10;
01302 }
01303 
01304 NDIS_MEDIA_STATE
01305 NTAPI
01306 MiGetMediaState(PADAPTER Adapter)
01307 /*
01308  * FUNCTION: Determine the link state
01309  * ARGUMENTS:
01310  *     Adapter: Adapter context
01311  * RETURNS:
01312  *     NdisMediaStateConnected if the cable is connected
01313  *     NdisMediaStateDisconnected if the cable is disconnected
01314  */
01315 {
01316   ULONG Data;
01317   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
01318   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
01319   return Data & BCR4_LEDOUT ? NdisMediaStateConnected : NdisMediaStateDisconnected;
01320 }
01321 
01322 NTSTATUS
01323 NTAPI
01324 DriverEntry(
01325     IN PDRIVER_OBJECT DriverObject,
01326     IN PUNICODE_STRING RegistryPath)
01327 /*
01328  * FUNCTION: Start this driver
01329  * ARGUMENTS:
01330  *     DriverObject: Pointer to the system-allocated driver object
01331  *     RegistryPath: Pointer to our SCM database entry
01332  * RETURNS:
01333  *     NDIS_STATUS_SUCCESS on success
01334  *     NDIS_STATUS_FAILURE on failure
01335  * NOTES:
01336  *     - Called by the I/O manager when the driver starts at PASSIVE_LEVEL
01337  *     - TODO: convert this to NTSTATUS return values
01338  */
01339 {
01340   NDIS_HANDLE WrapperHandle;
01341   NDIS_MINIPORT_CHARACTERISTICS Characteristics;
01342   NDIS_STATUS Status;
01343 
01344   RtlZeroMemory(&Characteristics, sizeof(Characteristics));
01345   Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
01346   Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
01347   Characteristics.HaltHandler = MiniportHalt;
01348   Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
01349   Characteristics.InitializeHandler = MiniportInitialize;
01350   Characteristics.ISRHandler = MiniportISR;
01351   Characteristics.QueryInformationHandler = MiniportQueryInformation;
01352   Characteristics.ResetHandler = MiniportReset;
01353   Characteristics.SetInformationHandler = MiniportSetInformation;
01354   Characteristics.SendHandler = MiniportSend;
01355 
01356   NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, 0);
01357   if (!WrapperHandle) return NDIS_STATUS_FAILURE;
01358 
01359   Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
01360   if(Status != NDIS_STATUS_SUCCESS)
01361     {
01362       NdisTerminateWrapper(WrapperHandle, 0);
01363       return NDIS_STATUS_FAILURE;
01364     }
01365 
01366   return NDIS_STATUS_SUCCESS;
01367 }
01368 

Generated on Sun May 27 2012 04:28:04 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.