⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcnet.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * ReactOS AMD PCNet Driver
 *
 * Copyright (C) 2003 Vizzini <vizzini@plasmic.com>
 * Copyright (C) 2004 Filip Navara <navaraf@reactos.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * REVISIONS:
 *     09-Sep-2003 vizzini - Created
 *     10-Oct-2004 navaraf - Fix receive to work on VMware adapters (
 *                           need to set busmaster bit on PCI).
 *                         - Indicate receive completition.
 *                         - Implement packet transmitting.
 *                         - Don't read slot number from registry and
 *                           report itself as NDIS 5.0 miniport.
 *     11-Oct-2004 navaraf - Fix nasty bugs in halt code path.
 *     17-Oct-2004 navaraf - Add multicast support.
 *                         - Add media state detection support.
 *                         - Protect the adapter context with spinlock
 *                           and move code talking to card to inside
 *                           NdisMSynchronizeWithInterrupt calls where
 *                           necessary.
 *
 * NOTES:
 *     - this assumes a 32-bit machine
 */

#include <ndis.h>
#include "pci.h"
#include "pcnethw.h"
#include "pcnet.h"

#define NDEBUG
#include <debug.h>

NTSTATUS
STDCALL
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath);

static VOID
STDCALL
MiniportHandleInterrupt(
    IN NDIS_HANDLE MiniportAdapterContext)
/*
 * FUNCTION: Handle an interrupt if told to by MiniportISR
 * ARGUMENTS:
 *     MiniportAdapterContext: context specified to NdisMSetAttributes
 * NOTES:
 *     - Called by NDIS at DISPATCH_LEVEL
 */
{
  PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
  USHORT Data;

  DPRINT("Called\n");

  NdisDprAcquireSpinLock(&Adapter->Lock);

  NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
  NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);

  DPRINT("CSR0 is 0x%x\n", Data);

  while(Data & CSR0_INTR)
    {
      /* Clear interrupt flags early to avoid race conditions. */
      NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);

      if(Data & CSR0_ERR)
        {
          DPRINT("error: %x\n", Data & (CSR0_MERR|CSR0_BABL|CSR0_CERR|CSR0_MISS));
          if (Data & CSR0_CERR)
            Adapter->Statistics.XmtCollisions++;
        }
      if(Data & CSR0_IDON)
        {
          DPRINT("IDON\n");
        }
      if(Data & CSR0_RINT)
        {
          DPRINT("receive interrupt\n");

          while(1)
            {
              PRECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptorRingVirt + Adapter->CurrentReceiveDescriptorIndex;
              PCHAR Buffer;
              ULONG ByteCount;

              if(Descriptor->FLAGS & RD_OWN)
                {
                  DPRINT("no more receive descriptors to process\n");
                  break;
                }

              if(Descriptor->FLAGS & RD_ERR)
                {
                  DPRINT("receive descriptor error: 0x%x\n", Descriptor->FLAGS);
                  if (Descriptor->FLAGS & RD_BUFF)
                    Adapter->Statistics.RcvBufferErrors++;
                  if (Descriptor->FLAGS & RD_CRC)
                    Adapter->Statistics.RcvCrcErrors++;
                  if (Descriptor->FLAGS & RD_OFLO)
                    Adapter->Statistics.RcvOverflowErrors++;
                  if (Descriptor->FLAGS & RD_FRAM)
                    Adapter->Statistics.RcvFramingErrors++;
                  break;
                }

              if(!((Descriptor->FLAGS & RD_STP) && (Descriptor->FLAGS & RD_ENP)))
                {
                  DPRINT("receive descriptor not start&end: 0x%x\n", Descriptor->FLAGS);
                  break;
                }

              Buffer = Adapter->ReceiveBufferPtrVirt + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE;
              ByteCount = Descriptor->MCNT & 0xfff;

              DPRINT("Indicating a %d-byte packet (index %d)\n", ByteCount, Adapter->CurrentReceiveDescriptorIndex);

              NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle, 0, Buffer, 14, Buffer+14, ByteCount-14, ByteCount-14);
              NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);

              RtlZeroMemory(Descriptor, sizeof(RECEIVE_DESCRIPTOR));
              Descriptor->RBADR =
                  (ULONG)(Adapter->ReceiveBufferPtrPhys + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE);
              Descriptor->BCNT = (-BUFFER_SIZE) | 0xf000;
              Descriptor->FLAGS |= RD_OWN;

              Adapter->CurrentReceiveDescriptorIndex++;
              Adapter->CurrentReceiveDescriptorIndex %= NUMBER_OF_BUFFERS;

              Adapter->Statistics.RcvGoodFrames++;
            }
        }
      if(Data & CSR0_TINT)
        {
          PTRANSMIT_DESCRIPTOR Descriptor;

          DPRINT("transmit interrupt\n");

          while (Adapter->CurrentTransmitStartIndex !=
                 Adapter->CurrentTransmitEndIndex)
            {
              Descriptor = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitStartIndex;

              DPRINT("buffer %d flags %x flags2 %x\n",
                     Adapter->CurrentTransmitStartIndex,
                     Descriptor->FLAGS, Descriptor->FLAGS2);

              if (Descriptor->FLAGS & TD1_OWN)
                {
                  DPRINT("non-TXed buffer\n");
                  break;
                }

              if (Descriptor->FLAGS & TD1_STP)
                {
                  if (Descriptor->FLAGS & TD1_ONE)
                    Adapter->Statistics.XmtOneRetry++;
                  else if (Descriptor->FLAGS & TD1_MORE)
                    Adapter->Statistics.XmtMoreThanOneRetry++;
                }

              if (Descriptor->FLAGS & TD1_ERR)
                {
                  DPRINT("major error: %x\n", Descriptor->FLAGS2);
                  if (Descriptor->FLAGS2 & TD2_RTRY)
                    Adapter->Statistics.XmtRetryErrors++;
                  if (Descriptor->FLAGS2 & TD2_LCAR)
                    Adapter->Statistics.XmtLossesOfCarrier++;
                  if (Descriptor->FLAGS2 & TD2_LCOL)
                    Adapter->Statistics.XmtLateCollisions++;
                  if (Descriptor->FLAGS2 & TD2_EXDEF)
                    Adapter->Statistics.XmtExcessiveDefferals++;
                  if (Descriptor->FLAGS2 & TD2_UFLO)
                    Adapter->Statistics.XmtBufferUnderflows++;
                  if (Descriptor->FLAGS2 & TD2_BUFF)
                    Adapter->Statistics.XmtBufferErrors++;
                  break;
                }

              Adapter->CurrentTransmitStartIndex++;
              Adapter->CurrentTransmitStartIndex %= NUMBER_OF_BUFFERS;

              Adapter->Statistics.XmtGoodFrames++;
            }
          NdisMSendResourcesAvailable(Adapter->MiniportAdapterHandle);
        }
      if(Data & ~(CSR0_ERR | CSR0_IDON | CSR0_RINT | CSR0_TINT))
        {
          DPRINT("UNHANDLED INTERRUPT CSR0 0x%x\n", Data);
        }

      NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
    }

  /* re-enable interrupts */
  NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA);

  NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
  DPRINT("CSR0 is now 0x%x\n", Data);

  NdisDprReleaseSpinLock(&Adapter->Lock);
}

static NDIS_STATUS
MiQueryCard(
    IN PADAPTER Adapter)
/*
 * FUNCTION: Detect the PCNET NIC in the configured slot and query its I/O address and interrupt vector
 * ARGUMENTS:
 *     MiniportAdapterContext: context supplied to NdisMSetAttributes
 * RETURNS:
 *     NDIS_STATUS_FAILURE on a general error
 *     NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
 *     NDIS_STATUS_SUCCESS on succes
 */
{
  ULONG  buf32 = 0;
  UCHAR  buf8  = 0;
  NDIS_STATUS Status;

  /* Detect the card in the configured slot */
  Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_PCIID, &buf32, 4);
  if(Status != 4)
    {
      Status =  NDIS_STATUS_FAILURE;
      DPRINT("NdisReadPciSlotInformation failed\n");
      BREAKPOINT;
      return Status;
    }

  if(buf32 != PCI_ID)
    {
      Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
      DPRINT("card in slot isn't our: 0x%x\n", 0, buf32);
      BREAKPOINT;
      return Status;
    }

  /* set busmaster and io space enable bits */
  buf32 = PCI_BMEN | PCI_IOEN;
  NdisWritePciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_COMMAND, &buf32, 4);

  /* get IO base physical address */
  buf32 = 0;
  Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_IOBAR, &buf32, 4);
  if(Status != 4)
    {
      Status = NDIS_STATUS_FAILURE;
      DPRINT("NdisReadPciSlotInformation failed\n");
      BREAKPOINT;
      return Status;
    }

  if(!buf32)
    {
      DPRINT("No base i/o address set\n");
      return NDIS_STATUS_FAILURE;
    }

  buf32 &= ~1;  /* even up address - comes out odd for some reason */

  DPRINT("detected io address 0x%x\n", buf32);
  Adapter->IoBaseAddress = buf32;

  /* get interrupt vector */
  Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_ILR, &buf8, 1);
  if(Status != 1)
    {
      Status = NDIS_STATUS_FAILURE;
      DPRINT1("NdisReadPciSlotInformation failed\n");
      BREAKPOINT;
      return Status;
    }

  DPRINT("interrupt: 0x%x\n", buf8);
  Adapter->InterruptVector = buf8;

  return NDIS_STATUS_SUCCESS;
}

static NDIS_STATUS
MiAllocateSharedMemory(
    PADAPTER Adapter)
/*
 * FUNCTION: Allocate all shared memory used by the miniport
 * ARGUMENTS:
 *     Adapter: Pointer to the miniport's adapter object
 * RETURNS:
 *     NDIS_STATUS_RESOURCES on insufficient memory
 *     NDIS_STATUS_SUCCESS on success
 */
{
  PTRANSMIT_DESCRIPTOR TransmitDescriptor;
  PRECEIVE_DESCRIPTOR  ReceiveDescriptor;
  NDIS_PHYSICAL_ADDRESS PhysicalAddress;
  ULONG i;

  /* allocate the initialization block */
  Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK);
  NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
      FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress);
  if(!Adapter->InitializationBlockVirt)
    {
      DPRINT1("insufficient resources\n");
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  if(((ULONG)Adapter->InitializationBlockVirt & 0x00000003) != 0)
    {
      DPRINT("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt);
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  Adapter->InitializationBlockPhys = (PINITIALIZATION_BLOCK)NdisGetPhysicalAddressLow(PhysicalAddress);

  /* allocate the transport descriptor ring */
  Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS;
  NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
      FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress);
  if(!Adapter->TransmitDescriptorRingVirt)
    {
      DPRINT1("insufficient resources\n");
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  if(((ULONG)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0)
    {
      DPRINT("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt);
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  Adapter->TransmitDescriptorRingPhys = (PTRANSMIT_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
  RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS);

  /* allocate the receive descriptor ring */
  Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS;
  NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
      FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress);
  if(!Adapter->ReceiveDescriptorRingVirt)
    {
      DPRINT1("insufficient resources\n");
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  if(((ULONG)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0)
    {
      DPRINT("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt);
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  Adapter->ReceiveDescriptorRingPhys = (PRECEIVE_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
  RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS);

  /* allocate transmit buffers */
  Adapter->TransmitBufferLength = BUFFER_SIZE * NUMBER_OF_BUFFERS;
  NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
      FALSE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress);
  if(!Adapter->TransmitBufferPtrVirt)
    {
      DPRINT1("insufficient resources\n");
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  if(((ULONG)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0)
    {
      DPRINT("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt);
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  Adapter->TransmitBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
  RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * NUMBER_OF_BUFFERS);

  /* allocate receive buffers */
  Adapter->ReceiveBufferLength = BUFFER_SIZE * NUMBER_OF_BUFFERS;
  NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
      FALSE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress);
  if(!Adapter->ReceiveBufferPtrVirt)
    {
      DPRINT1("insufficient resources\n");
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  if(((ULONG)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0)
    {
      DPRINT("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt);
      BREAKPOINT;
      return NDIS_STATUS_RESOURCES;
    }

  Adapter->ReceiveBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
  RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * NUMBER_OF_BUFFERS);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -