/* * PROJECT: ReactOS Intel PRO/1000 Driver * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: Hardware specific functions * COPYRIGHT: 2018 Mark Jansen (mark.jansen@reactos.org) * 2019 Victor Perevertkin (victor.perevertkin@reactos.org) */ #include "nic.h" #include static USHORT SupportedDevices[] = { /* 8254x Family adapters. Not all of them are tested */ 0x1000, // Intel 82542 0x1001, // Intel 82543GC Fiber 0x1004, // Intel 82543GC Copper 0x1008, // Intel 82544EI Copper 0x1009, // Intel 82544EI Fiber 0x100A, // Intel 82540EM 0x100C, // Intel 82544GC Copper 0x100D, // Intel 82544GC LOM (LAN on Motherboard) 0x100E, // Intel 82540EM 0x100F, // Intel 82545EM Copper 0x1010, // Intel 82546EB Copper 0x1011, // Intel 82545EM Fiber 0x1012, // Intel 82546EB Fiber 0x1013, // Intel 82541EI 0x1014, // Intel 82541EI LOM 0x1015, // Intel 82540EM LOM 0x1016, // Intel 82540EP LOM 0x1017, // Intel 82540EP 0x1018, // Intel 82541EI Mobile 0x1019, // Intel 82547EI 0x101A, // Intel 82547EI Mobile 0x101D, // Intel 82546EB Quad Copper 0x101E, // Intel 82540EP LP (Low profile) 0x1026, // Intel 82545GM Copper 0x1027, // Intel 82545GM Fiber 0x1028, // Intel 82545GM SerDes 0x1075, // Intel 82547GI 0x1076, // Intel 82541GI 0x1077, // Intel 82541GI Mobile 0x1078, // Intel 82541ER 0x1079, // Intel 82546GB Copper 0x107A, // Intel 82546GB Fiber 0x107B, // Intel 82546GB SerDes 0x107C, // Intel 82541PI 0x108A, // Intel 82546GB PCI-E 0x1099, // Intel 82546GB Quad Copper 0x10B5, // Intel 82546GB Quad Copper KSP3 }; static ULONG E1000WriteFlush(IN PE1000_ADAPTER Adapter) { volatile ULONG Value; NdisReadRegisterUlong(Adapter->IoBase + E1000_REG_STATUS, &Value); return Value; } VOID NTAPI E1000WriteUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value) { NdisWriteRegisterUlong((PULONG)(Adapter->IoBase + Address), Value); } VOID NTAPI E1000ReadUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, OUT PULONG Value) { NdisReadRegisterUlong((PULONG)(Adapter->IoBase + Address), Value); } static VOID E1000WriteIoUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value) { NdisRawWritePortUlong((PULONG)(Adapter->IoPort), Address); E1000WriteFlush(Adapter); NdisRawWritePortUlong((PULONG)(Adapter->IoPort + 4), Value); } static ULONG PacketFilterToMask(ULONG PacketFilter) { ULONG FilterMask = 0; if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) { /* Multicast Promiscuous Enabled */ FilterMask |= E1000_RCTL_MPE; } if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) { /* Unicast Promiscuous Enabled */ FilterMask |= E1000_RCTL_UPE; /* Multicast Promiscuous Enabled */ FilterMask |= E1000_RCTL_MPE; } if (PacketFilter & NDIS_PACKET_TYPE_MAC_FRAME) { /* Pass MAC Control Frames */ FilterMask |= E1000_RCTL_PMCF; } if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST) { /* Broadcast Accept Mode */ FilterMask |= E1000_RCTL_BAM; } return FilterMask; } static ULONG RcvBufAllocationSize(E1000_RCVBUF_SIZE BufSize) { static ULONG PredefSizes[4] = { 2048, 1024, 512, 256, }; ULONG Size; Size = PredefSizes[BufSize & E1000_RCVBUF_INDEXMASK]; if (BufSize & E1000_RCVBUF_RESERVED) { ASSERT(BufSize != 2048); Size *= 16; } return Size; } static ULONG RcvBufRegisterMask(E1000_RCVBUF_SIZE BufSize) { ULONG Mask = 0; Mask |= BufSize & E1000_RCVBUF_INDEXMASK; Mask <<= E1000_RCTL_BSIZE_SHIFT; if (BufSize & E1000_RCVBUF_RESERVED) Mask |= E1000_RCTL_BSEX; return Mask; } #if 0 /* This function works, but the driver does not use PHY register access right now */ static BOOLEAN E1000ReadMdic(IN PE1000_ADAPTER Adapter, IN ULONG Address, USHORT *Result) { ULONG ResultAddress; ULONG Mdic; UINT n; if (Address > MAX_PHY_REG_ADDRESS) { NDIS_DbgPrint(MIN_TRACE, ("PHY Address %d is invalid\n", Address)); return 1; } Mdic = (Address << E1000_MDIC_REGADD_SHIFT); Mdic |= (E1000_MDIC_PHYADD_GIGABIT << E1000_MDIC_PHYADD_SHIFT); Mdic |= E1000_MDIC_OP_READ; E1000WriteUlong(Adapter, E1000_REG_MDIC, Mdic); for (n = 0; n < MAX_PHY_READ_ATTEMPTS; n++) { NdisStallExecution(50); E1000ReadUlong(Adapter, E1000_REG_MDIC, &Mdic); if (Mdic & E1000_MDIC_R) break; } if (!(Mdic & E1000_MDIC_R)) { NDIS_DbgPrint(MIN_TRACE, ("MDI Read incomplete\n")); return FALSE; } if (Mdic & E1000_MDIC_E) { NDIS_DbgPrint(MIN_TRACE, ("MDI Read error\n")); return FALSE; } ResultAddress = (Mdic >> E1000_MDIC_REGADD_SHIFT) & MAX_PHY_REG_ADDRESS; if (ResultAddress!= Address) { /* Add locking? */ NDIS_DbgPrint(MIN_TRACE, ("MDI Read got wrong address (%d instead of %d)\n", ResultAddress, Address)); return FALSE; } *Result = (USHORT) Mdic; return TRUE; } #endif static BOOLEAN E1000ReadEeprom(IN PE1000_ADAPTER Adapter, IN UCHAR Address, USHORT *Result) { ULONG Value; UINT n; E1000WriteUlong(Adapter, E1000_REG_EERD, E1000_EERD_START | ((UINT)Address << E1000_EERD_ADDR_SHIFT)); for (n = 0; n < MAX_EEPROM_READ_ATTEMPTS; ++n) { NdisStallExecution(5); E1000ReadUlong(Adapter, E1000_REG_EERD, &Value); if (Value & E1000_EERD_DONE) break; } if (!(Value & E1000_EERD_DONE)) { NDIS_DbgPrint(MIN_TRACE, ("EEPROM Read incomplete\n")); return FALSE; } *Result = (USHORT)(Value >> E1000_EERD_DATA_SHIFT); return TRUE; } BOOLEAN E1000ValidateNvmChecksum(IN PE1000_ADAPTER Adapter) { USHORT Checksum = 0, Data; UINT n; /* 5.6.35 Checksum Word Calculation (Word 3Fh) */ for (n = 0; n <= E1000_NVM_REG_CHECKSUM; n++) { if (!E1000ReadEeprom(Adapter, n, &Data)) { return FALSE; } Checksum += Data; } if (Checksum != NVM_MAGIC_SUM) { NDIS_DbgPrint(MIN_TRACE, ("EEPROM has an invalid checksum of 0x%x\n", (ULONG)Checksum)); return FALSE; } return TRUE; } BOOLEAN NTAPI NICRecognizeHardware( IN PE1000_ADAPTER Adapter) { UINT n; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); if (Adapter->VendorID != HW_VENDOR_INTEL) { NDIS_DbgPrint(MIN_TRACE, ("Unknown vendor: 0x%x\n", Adapter->VendorID)); return FALSE; } for (n = 0; n < ARRAYSIZE(SupportedDevices); ++n) { if (SupportedDevices[n] == Adapter->DeviceID) { return TRUE; } } NDIS_DbgPrint(MIN_TRACE, ("Unknown device: 0x%x\n", Adapter->DeviceID)); return FALSE; } NDIS_STATUS NTAPI NICInitializeAdapterResources( IN PE1000_ADAPTER Adapter, IN PNDIS_RESOURCE_LIST ResourceList) { UINT n; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); for (n = 0; n < ResourceList->Count; n++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor = ResourceList->PartialDescriptors + n; switch (ResourceDescriptor->Type) { case CmResourceTypePort: ASSERT(Adapter->IoPortAddress == 0); ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0); Adapter->IoPortAddress = ResourceDescriptor->u.Port.Start.LowPart; Adapter->IoPortLength = ResourceDescriptor->u.Port.Length; NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n", Adapter->IoPortAddress, Adapter->IoPortAddress + Adapter->IoPortLength)); break; case CmResourceTypeInterrupt: ASSERT(Adapter->InterruptVector == 0); ASSERT(Adapter->InterruptLevel == 0); Adapter->InterruptVector = ResourceDescriptor->u.Interrupt.Vector; Adapter->InterruptLevel = ResourceDescriptor->u.Interrupt.Level; Adapter->InterruptShared = (ResourceDescriptor->ShareDisposition == CmResourceShareShared); Adapter->InterruptFlags = ResourceDescriptor->Flags; NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", Adapter->InterruptVector)); break; case CmResourceTypeMemory: /* Internal registers and memories (including PHY) */ if (ResourceDescriptor->u.Memory.Length == (128 * 1024)) { ASSERT(Adapter->IoAddress.LowPart == 0); ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0); Adapter->IoAddress.QuadPart = ResourceDescriptor->u.Memory.Start.QuadPart; Adapter->IoLength = ResourceDescriptor->u.Memory.Length; NDIS_DbgPrint(MID_TRACE, ("Memory range is %I64x to %I64x\n", Adapter->IoAddress.QuadPart, Adapter->IoAddress.QuadPart + Adapter->IoLength)); } break; default: NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", ResourceDescriptor->Type)); break; } } if (Adapter->IoAddress.QuadPart == 0 || Adapter->IoPortAddress == 0 || Adapter->InterruptVector == 0) { NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n")); return NDIS_STATUS_RESOURCES; } return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICAllocateIoResources( IN PE1000_ADAPTER Adapter) { NDIS_STATUS Status; ULONG AllocationSize; UINT n; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoPort, Adapter->AdapterHandle, Adapter->IoPortAddress, Adapter->IoPortLength); if (Status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", Status)); return NDIS_STATUS_RESOURCES; } Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase, Adapter->AdapterHandle, Adapter->IoAddress, Adapter->IoLength); NdisMAllocateSharedMemory(Adapter->AdapterHandle, sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS, FALSE, (PVOID*)&Adapter->TransmitDescriptors, &Adapter->TransmitDescriptorsPa); if (Adapter->TransmitDescriptors == NULL) { NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate transmit descriptors\n")); return NDIS_STATUS_RESOURCES; } for (n = 0; n < NUM_TRANSMIT_DESCRIPTORS; ++n) { PE1000_TRANSMIT_DESCRIPTOR Descriptor = Adapter->TransmitDescriptors + n; Descriptor->Address = 0; Descriptor->Length = 0; } NdisMAllocateSharedMemory(Adapter->AdapterHandle, sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS, FALSE, (PVOID*)&Adapter->ReceiveDescriptors, &Adapter->ReceiveDescriptorsPa); if (Adapter->ReceiveDescriptors == NULL) { NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive descriptors\n")); return NDIS_STATUS_RESOURCES; } AllocationSize = RcvBufAllocationSize(Adapter->ReceiveBufferType); ASSERT(Adapter->ReceiveBufferEntrySize == 0 || Adapter->ReceiveBufferEntrySize == AllocationSize); Adapter->ReceiveBufferEntrySize = AllocationSize; NdisMAllocateSharedMemory(Adapter->AdapterHandle, Adapter->ReceiveBufferEntrySize * NUM_RECEIVE_DESCRIPTORS, FALSE, (PVOID*)&Adapter->ReceiveBuffer, &Adapter->ReceiveBufferPa); if (Adapter->ReceiveBuffer == NULL) { NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive buffer\n")); return NDIS_STATUS_RESOURCES; } for (n = 0; n < NUM_RECEIVE_DESCRIPTORS; ++n) { PE1000_RECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptors + n; RtlZeroMemory(Descriptor, sizeof(*Descriptor)); Descriptor->Address = Adapter->ReceiveBufferPa.QuadPart + n * Adapter->ReceiveBufferEntrySize; } return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICRegisterInterrupts( IN PE1000_ADAPTER Adapter) { NDIS_STATUS Status; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); Status = NdisMRegisterInterrupt(&Adapter->Interrupt, Adapter->AdapterHandle, Adapter->InterruptVector, Adapter->InterruptLevel, TRUE, // We always want ISR calls Adapter->InterruptShared, (Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ? NdisInterruptLatched : NdisInterruptLevelSensitive); if (Status == NDIS_STATUS_SUCCESS) { Adapter->InterruptRegistered = TRUE; } return Status; } NDIS_STATUS NTAPI NICUnregisterInterrupts( IN PE1000_ADAPTER Adapter) { NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); if (Adapter->InterruptRegistered) { NdisMDeregisterInterrupt(&Adapter->Interrupt); Adapter->InterruptRegistered = FALSE; } return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICReleaseIoResources( IN PE1000_ADAPTER Adapter) { NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); if (Adapter->ReceiveDescriptors != NULL) { /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */ if (Adapter->IoBase) { E1000WriteUlong(Adapter, E1000_REG_RDH, 0); E1000WriteUlong(Adapter, E1000_REG_RDT, 0); } NdisMFreeSharedMemory(Adapter->AdapterHandle, sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS, FALSE, Adapter->ReceiveDescriptors, Adapter->ReceiveDescriptorsPa); Adapter->ReceiveDescriptors = NULL; } if (Adapter->ReceiveBuffer != NULL) { NdisMFreeSharedMemory(Adapter->AdapterHandle, Adapter->ReceiveBufferEntrySize * NUM_RECEIVE_DESCRIPTORS, FALSE, Adapter->ReceiveBuffer, Adapter->ReceiveBufferPa); Adapter->ReceiveBuffer = NULL; Adapter->ReceiveBufferEntrySize = 0; } if (Adapter->TransmitDescriptors != NULL) { /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */ if (Adapter->IoBase) { E1000WriteUlong(Adapter, E1000_REG_TDH, 0); E1000WriteUlong(Adapter, E1000_REG_TDT, 0); } NdisMFreeSharedMemory(Adapter->AdapterHandle, sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS, FALSE, Adapter->TransmitDescriptors, Adapter->TransmitDescriptorsPa); Adapter->TransmitDescriptors = NULL; } if (Adapter->IoPort) { NdisMDeregisterIoPortRange(Adapter->AdapterHandle, Adapter->IoPortAddress, Adapter->IoPortLength, Adapter->IoPort); } if (Adapter->IoBase) { NdisMUnmapIoSpace(Adapter->AdapterHandle, Adapter->IoBase, Adapter->IoLength); } return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICPowerOn( IN PE1000_ADAPTER Adapter) { NDIS_STATUS Status; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); Status = NICSoftReset(Adapter); if (Status != NDIS_STATUS_SUCCESS) { return Status; } if (!E1000ValidateNvmChecksum(Adapter)) { return NDIS_STATUS_INVALID_DATA; } return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICSoftReset( IN PE1000_ADAPTER Adapter) { ULONG Value, ResetAttempts; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); NICDisableInterrupts(Adapter); E1000WriteUlong(Adapter, E1000_REG_RCTL, 0); E1000WriteUlong(Adapter, E1000_REG_TCTL, 0); E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value); /* Write this using IO port, some devices cannot ack this otherwise */ E1000WriteIoUlong(Adapter, E1000_REG_CTRL, Value | E1000_CTRL_RST); for (ResetAttempts = 0; ResetAttempts < MAX_RESET_ATTEMPTS; ResetAttempts++) { /* Wait 1us after reset (according to manual) */ NdisStallExecution(1); E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value); if (!(Value & E1000_CTRL_RST)) { NDIS_DbgPrint(MAX_TRACE, ("Device is back (%u)\n", ResetAttempts)); NICDisableInterrupts(Adapter); /* Clear out interrupts (the register is cleared upon read) */ E1000ReadUlong(Adapter, E1000_REG_ICR, &Value); E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value); Value &= ~(E1000_CTRL_LRST|E1000_CTRL_VME); Value |= (E1000_CTRL_ASDE|E1000_CTRL_SLU); E1000WriteUlong(Adapter, E1000_REG_CTRL, Value); return NDIS_STATUS_SUCCESS; } } NDIS_DbgPrint(MIN_TRACE, ("Device did not recover\n")); return NDIS_STATUS_FAILURE; } NDIS_STATUS NTAPI NICEnableTxRx( IN PE1000_ADAPTER Adapter) { ULONG Value; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); NDIS_DbgPrint(MID_TRACE, ("Setting up transmit.\n")); /* Make sure the thing is disabled first. */ E1000WriteUlong(Adapter, E1000_REG_TCTL, 0); /* Transmit descriptor ring buffer */ E1000WriteUlong(Adapter, E1000_REG_TDBAH, Adapter->TransmitDescriptorsPa.HighPart); E1000WriteUlong(Adapter, E1000_REG_TDBAL, Adapter->TransmitDescriptorsPa.LowPart); /* Transmit descriptor buffer size */ E1000WriteUlong(Adapter, E1000_REG_TDLEN, sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS); /* Transmit descriptor tail / head */ E1000WriteUlong(Adapter, E1000_REG_TDH, 0); E1000WriteUlong(Adapter, E1000_REG_TDT, 0); Adapter->CurrentTxDesc = 0; /* Set up interrupt timers */ E1000WriteUlong(Adapter, E1000_REG_TADV, 96); // value is in 1.024 of usec E1000WriteUlong(Adapter, E1000_REG_TIDV, 16); E1000WriteUlong(Adapter, E1000_REG_TCTL, E1000_TCTL_EN | E1000_TCTL_PSP); E1000WriteUlong(Adapter, E1000_REG_TIPG, E1000_TIPG_IPGT_DEF | E1000_TIPG_IPGR1_DEF | E1000_TIPG_IPGR2_DEF); NDIS_DbgPrint(MID_TRACE, ("Setting up receive.\n")); /* Make sure the thing is disabled first. */ E1000WriteUlong(Adapter, E1000_REG_RCTL, 0); /* Receive descriptor ring buffer */ E1000WriteUlong(Adapter, E1000_REG_RDBAH, Adapter->ReceiveDescriptorsPa.HighPart); E1000WriteUlong(Adapter, E1000_REG_RDBAL, Adapter->ReceiveDescriptorsPa.LowPart); /* Receive descriptor buffer size */ E1000WriteUlong(Adapter, E1000_REG_RDLEN, sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS); /* Receive descriptor tail / head */ E1000WriteUlong(Adapter, E1000_REG_RDH, 0); E1000WriteUlong(Adapter, E1000_REG_RDT, NUM_RECEIVE_DESCRIPTORS - 1); /* Set up interrupt timers */ E1000WriteUlong(Adapter, E1000_REG_RADV, 96); E1000WriteUlong(Adapter, E1000_REG_RDTR, 16); /* Some defaults */ Value = E1000_RCTL_SECRC | E1000_RCTL_EN; /* Receive buffer size */ Value |= RcvBufRegisterMask(Adapter->ReceiveBufferType); /* Add our current packet filter */ Value |= PacketFilterToMask(Adapter->PacketFilter); E1000WriteUlong(Adapter, E1000_REG_RCTL, Value); return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICDisableTxRx( IN PE1000_ADAPTER Adapter) { ULONG Value; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); E1000ReadUlong(Adapter, E1000_REG_TCTL, &Value); Value &= ~E1000_TCTL_EN; E1000WriteUlong(Adapter, E1000_REG_TCTL, Value); E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value); Value &= ~E1000_RCTL_EN; E1000WriteUlong(Adapter, E1000_REG_RCTL, Value); return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICGetPermanentMacAddress( IN PE1000_ADAPTER Adapter, OUT PUCHAR MacAddress) { USHORT AddrWord; UINT n; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); /* Should we read from RAL/RAH first? */ for (n = 0; n < (IEEE_802_ADDR_LENGTH / 2); ++n) { if (!E1000ReadEeprom(Adapter, (UCHAR)n, &AddrWord)) return NDIS_STATUS_FAILURE; Adapter->PermanentMacAddress[n * 2 + 0] = AddrWord & 0xff; Adapter->PermanentMacAddress[n * 2 + 1] = (AddrWord >> 8) & 0xff; } NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", Adapter->PermanentMacAddress[0], Adapter->PermanentMacAddress[1], Adapter->PermanentMacAddress[2], Adapter->PermanentMacAddress[3], Adapter->PermanentMacAddress[4], Adapter->PermanentMacAddress[5])); return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICUpdateMulticastList( IN PE1000_ADAPTER Adapter) { UINT n; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); for (n = 0; n < MAXIMUM_MULTICAST_ADDRESSES; ++n) { ULONG Ral = *(ULONG *)Adapter->MulticastList[n].MacAddress; ULONG Rah = *(USHORT *)&Adapter->MulticastList[n].MacAddress[4]; if (Rah || Ral) { Rah |= E1000_RAH_AV; E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), Ral); E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), Rah); } else { E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), 0); E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), 0); } } return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICApplyPacketFilter( IN PE1000_ADAPTER Adapter) { ULONG FilterMask; E1000ReadUlong(Adapter, E1000_REG_RCTL, &FilterMask); FilterMask &= ~E1000_RCTL_FILTER_BITS; FilterMask |= PacketFilterToMask(Adapter->PacketFilter); E1000WriteUlong(Adapter, E1000_REG_RCTL, FilterMask); return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICApplyInterruptMask( IN PE1000_ADAPTER Adapter) { NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); E1000WriteUlong(Adapter, E1000_REG_IMS, Adapter->InterruptMask /*| 0x1F6DC*/); return NDIS_STATUS_SUCCESS; } NDIS_STATUS NTAPI NICDisableInterrupts( IN PE1000_ADAPTER Adapter) { NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); E1000WriteUlong(Adapter, E1000_REG_IMC, ~0); return NDIS_STATUS_SUCCESS; } ULONG NTAPI NICInterruptRecognized( IN PE1000_ADAPTER Adapter, OUT PBOOLEAN InterruptRecognized) { ULONG Value; /* Reading the interrupt acknowledges them */ E1000ReadUlong(Adapter, E1000_REG_ICR, &Value); *InterruptRecognized = (Value & Adapter->InterruptMask) != 0; NDIS_DbgPrint(MAX_TRACE, ("NICInterruptRecognized(0x%x, 0x%x).\n", Value, *InterruptRecognized)); return (Value & Adapter->InterruptMask); } VOID NTAPI NICUpdateLinkStatus( IN PE1000_ADAPTER Adapter) { ULONG DeviceStatus; SIZE_T SpeedIndex; static ULONG SpeedValues[] = { 10, 100, 1000, 1000 }; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus); Adapter->MediaState = (DeviceStatus & E1000_STATUS_LU) ? NdisMediaStateConnected : NdisMediaStateDisconnected; SpeedIndex = (DeviceStatus & E1000_STATUS_SPEEDMASK) >> E1000_STATUS_SPEEDSHIFT; Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex]; } NDIS_STATUS NTAPI NICTransmitPacket( IN PE1000_ADAPTER Adapter, IN PHYSICAL_ADDRESS PhysicalAddress, IN ULONG Length) { volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->CurrentTxDesc; TransmitDescriptor->Address = PhysicalAddress.QuadPart; TransmitDescriptor->Length = Length; TransmitDescriptor->ChecksumOffset = 0; TransmitDescriptor->Command = E1000_TDESC_CMD_RS | E1000_TDESC_CMD_IFCS | E1000_TDESC_CMD_EOP | E1000_TDESC_CMD_IDE; TransmitDescriptor->Status = 0; TransmitDescriptor->ChecksumStartField = 0; TransmitDescriptor->Special = 0; Adapter->CurrentTxDesc = (Adapter->CurrentTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS; E1000WriteUlong(Adapter, E1000_REG_TDT, Adapter->CurrentTxDesc); if (Adapter->CurrentTxDesc == Adapter->LastTxDesc) { NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n")); Adapter->TxFull = TRUE; } return NDIS_STATUS_SUCCESS; }