;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;; FORCEDETH.INC ;; ;; ;; ;; Ethernet driver for Kolibri OS ;; ;; ;; ;; Driver for chips of NVIDIA nForce2 ;; ;; References: ;; ;; forcedeth.c - linux driver (etherboot project) ;; ;; ethernet driver template by Mike Hibbett ;; ;; ;; ;; The copyright statement is ;; ;; ;; ;; GNU GENERAL PUBLIC LICENSE ;; ;; Version 2, June 1991 ;; ;; ;; ;; Copyright 2008 shurf, ;; ;; cit.utc@gmail.com ;; ;; ;; ;; See file COPYING for details ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; format MS COFF API_VERSION = 0x01000100 DRIVER_VERSION = 5 MAX_DEVICES = 16 RBLEN = 0 ; Receive buffer size: 0=4K 1=8k 2=16k 3=32k 4=64k ; FIXME: option 1 and 2 will not allocate buffer correctly causing data loss! DEBUG = 1 __DEBUG__ = 1 __DEBUG_LEVEL__ = 2 RX_RING = 4 TX_RING = 4 include '../struct.inc' include '../macros.inc' include '../proc32.inc' include '../imports.inc' include '../fdo.inc' include '../netdrv.inc' public START public service_proc public version ;************************************************************************** ; forcedeth Register Definitions ;************************************************************************** PCI_DEVICE_ID_NVIDIA_NVENET_1 = 0x01c3 PCI_DEVICE_ID_NVIDIA_NVENET_2 = 0x0066 PCI_DEVICE_ID_NVIDIA_NVENET_4 = 0x0086 PCI_DEVICE_ID_NVIDIA_NVENET_5 = 0x008c PCI_DEVICE_ID_NVIDIA_NVENET_3 = 0x00d6 PCI_DEVICE_ID_NVIDIA_NVENET_7 = 0x00df PCI_DEVICE_ID_NVIDIA_NVENET_6 = 0x00e6 PCI_DEVICE_ID_NVIDIA_NVENET_8 = 0x0056 PCI_DEVICE_ID_NVIDIA_NVENET_9 = 0x0057 PCI_DEVICE_ID_NVIDIA_NVENET_10 = 0x0037 PCI_DEVICE_ID_NVIDIA_NVENET_11 = 0x0038 PCI_DEVICE_ID_NVIDIA_NVENET_12 = 0x0268 PCI_DEVICE_ID_NVIDIA_NVENET_13 = 0x0269 PCI_DEVICE_ID_NVIDIA_NVENET_14 = 0x0372 PCI_DEVICE_ID_NVIDIA_NVENET_15 = 0x0373 UNKSETUP1_VAL = 0x16070f UNKSETUP2_VAL = 0x16 UNKSETUP3_VAL1 = 0x200010 UNKSETUP4_VAL = 8 UNKSETUP5_BIT31 = (1 shl 31) UNKSETUP6_VAL = 3 TXRXCTL_RXCHECK = 0x0400 MIISTAT_ERROR = 0x0001 MIISTAT_MASK = 0x000f MIISTAT_MASK2 = 0x000f MIICTL_INUSE = 0x08000 MIICTL_WRITE = 0x00400 MIICTL_ADDRSHIFT = 5 MIISPEED_BIT8 = (1 shl 8) MIIDELAY = 5 IRQ_RX_ERROR = 0x0001 IRQ_RX = 0x0002 IRQ_RX_NOBUF = 0x0004 IRQ_LINK = 0x0040 IRQ_TIMER = 0x0020 IRQMASK_WANTED_2 = 0x0147 IRQ_RX_ALL = IRQ_RX_ERROR or IRQ_RX or IRQ_RX_NOBUF IRQ_TX_ALL = 0 ; ??????????? IRQ_OTHER_ALL = IRQ_LINK ;or IRQ_TIMER IRQSTAT_MASK = 0x1ff TXRXCTL_KICK = 0x0001 TXRXCTL_BIT1 = 0x0002 TXRXCTL_BIT2 = 0x0004 TXRXCTL_IDLE = 0x0008 TXRXCTL_RESET = 0x0010 TXRXCTL_RXCHECK = 0x0400 MCASTADDRA_FORCE = 0x01 MAC_RESET_ASSERT = 0x0F3 MISC1_HD = 0x02 MISC1_FORCE = 0x3b0f3c PFF_ALWAYS = 0x7F0008 PFF_PROMISC = 0x80 PFF_MYADDR = 0x20 OFFLOAD_HOMEPHY = 0x601 OFFLOAD_NORMAL = 4096 shl RBLEN RNDSEED_MASK = 0x00ff RNDSEED_FORCE = 0x7f00 RNDSEED_FORCE2 = 0x2d00 RNDSEED_FORCE3 = 0x7400 ; POLL_DEFAULT is the interval length of the timer source on the nic ; POLL_DEFAULT=97 would result in an interval length of 1 ms POLL_DEFAULT = 970 ADAPTCTL_START = 0x02 ADAPTCTL_LINKUP = 0x04 ADAPTCTL_PHYVALID = 0x40000 ADAPTCTL_RUNNING = 0x100000 ADAPTCTL_PHYSHIFT = 24 WAKEUPFLAGS_VAL = 0x7770 POWERSTATE_POWEREDUP = 0x8000 POWERSTATE_VALID = 0x0100 POWERSTATE_MASK = 0x0003 POWERSTATE_D0 = 0x0000 POWERSTATE_D1 = 0x0001 POWERSTATE_D2 = 0x0002 POWERSTATE_D3 = 0x0003 POWERSTATE2_POWERUP_MASK = 0x0F11 POWERSTATE2_POWERUP_REV_A3= 0x0001 RCVCTL_START = 0x01 RCVSTAT_BUSY = 0x01 XMITCTL_START = 0x01 LINKSPEED_FORCE = 0x10000 LINKSPEED_10 = 1000 LINKSPEED_100 = 100 LINKSPEED_1000 = 50 RINGSZ_TXSHIFT = 0 RINGSZ_RXSHIFT = 16 LPA_1000FULL = 0x0800 ; Link partner ability register. LPA_SLCT = 0x001f ; Same as advertise selector LPA_10HALF = 0x0020 ; Can do 10mbps half-duplex LPA_10FULL = 0x0040 ; Can do 10mbps full-duplex LPA_100HALF = 0x0080 ; Can do 100mbps half-duplex LPA_100FULL = 0x0100 ; Can do 100mbps full-duplex LPA_100BASE4 = 0x0200 ; Can do 100mbps 4k packets LPA_RESV = 0x1c00 ; Unused... LPA_RFAULT = 0x2000 ; Link partner faulted LPA_LPACK = 0x4000 ; Link partner acked us LPA_NPAGE = 0x8000 ; Next page bit MII_READ = (-1) MII_PHYSID1 = 0x02 ; PHYS ID 1 MII_PHYSID2 = 0x03 ; PHYS ID 2 MII_BMCR = 0x00 ; Basic mode control register MII_BMSR = 0x01 ; Basic mode status register MII_ADVERTISE = 0x04 ; Advertisement control reg MII_LPA = 0x05 ; Link partner ability reg MII_SREVISION = 0x16 ; Silicon revision MII_RESV1 = 0x17 ; Reserved... MII_NCONFIG = 0x1c ; Network interface config ; PHY defines PHY_OUI_MARVELL = 0x5043 PHY_OUI_CICADA = 0x03f1 PHYID1_OUI_MASK = 0x03ff PHYID1_OUI_SHFT = 6 PHYID2_OUI_MASK = 0xfc00 PHYID2_OUI_SHFT = 10 PHY_INIT1 = 0x0f000 PHY_INIT2 = 0x0e00 PHY_INIT3 = 0x01000 PHY_INIT4 = 0x0200 PHY_INIT5 = 0x0004 PHY_INIT6 = 0x02000 PHY_GIGABIT = 0x0100 PHY_TIMEOUT = 0x1 PHY_ERROR = 0x2 PHY_100 = 0x1 PHY_1000 = 0x2 PHY_HALF = 0x100 PHY_RGMII = 0x10000000 ; desc_ver values: ; This field has two purposes: ; - Newer nics uses a different ring layout. The layout is selected by ; comparing np->desc_ver with DESC_VER_xy. ; - It contains bits that are forced on when writing to TxRxControl. DESC_VER_1 = 0x0 DESC_VER_2 = (0x02100 or TXRXCTL_RXCHECK) MAC_ADDR_LEN = 6 NV_TX_LASTPACKET = (1 shl 16) NV_TX_RETRYERROR = (1 shl 19) NV_TX_LASTPACKET1 = (1 shl 24) NV_TX_DEFERRED = (1 shl 26) NV_TX_CARRIERLOST = (1 shl 27) NV_TX_LATECOLLISION = (1 shl 28) NV_TX_UNDERFLOW = (1 shl 29) NV_TX_ERROR = (1 shl 30) NV_TX_VALID = (1 shl 31) NV_TX2_LASTPACKET = (1 shl 29) NV_TX2_RETRYERROR = (1 shl 18) NV_TX2_LASTPACKET1 = (1 shl 23) NV_TX2_DEFERRED = (1 shl 25) NV_TX2_CARRIERLOST = (1 shl 26) NV_TX2_LATECOLLISION = (1 shl 27) NV_TX2_UNDERFLOW = (1 shl 28) ; error and valid are the same for both NV_TX2_ERROR = (1 shl 30) NV_TX2_VALID = (1 shl 31) NV_RX_DESCRIPTORVALID = (1 shl 16) NV_RX_AVAIL = (1 shl 31) NV_RX2_DESCRIPTORVALID = (1 shl 29) FLAG_MASK_V1 = 0xffff0000 FLAG_MASK_V2 = 0xffffc000 LEN_MASK_V1 = (0xffffffff xor FLAG_MASK_V1) LEN_MASK_V2 = (0xffffffff xor FLAG_MASK_V2) ; Miscelaneous hardware related defines: NV_PCI_REGSZ_VER1 = 0x270 NV_PCI_REGSZ_VER2 = 0x604 ; various timeout delays: all in usec NV_TXRX_RESET_DELAY = 4 NV_TXSTOP_DELAY1 = 10 NV_TXSTOP_DELAY1MAX = 500000 NV_TXSTOP_DELAY2 = 100 NV_RXSTOP_DELAY1 = 10 NV_RXSTOP_DELAY1MAX = 500000 NV_RXSTOP_DELAY2 = 100 NV_SETUP5_DELAY = 5 NV_SETUP5_DELAYMAX = 50000 NV_POWERUP_DELAY = 5 NV_POWERUP_DELAYMAX = 5000 NV_MIIBUSY_DELAY = 50 NV_MIIPHY_DELAY = 10 NV_MIIPHY_DELAYMAX = 10000 NV_MAC_RESET_DELAY = 64 NV_WAKEUPPATTERNS = 5 NV_WAKEUPMASKENTRIES = 4 ; Advertisement control register. ADVERTISE_SLCT = 0x001f ; Selector bits ADVERTISE_CSMA = 0x0001 ; Only selector supported ADVERTISE_10HALF = 0x0020 ; Try for 10mbps half-duplex ADVERTISE_10FULL = 0x0040 ; Try for 10mbps full-duplex ADVERTISE_100HALF = 0x0080 ; Try for 100mbps half-duplex ADVERTISE_100FULL = 0x0100 ; Try for 100mbps full-duplex ADVERTISE_100BASE4 = 0x0200 ; Try for 100mbps 4k packets ADVERTISE_RESV = 0x1c00 ; Unused... ADVERTISE_RFAULT = 0x2000 ; Say we can detect faults ADVERTISE_LPACK = 0x4000 ; Ack link partners response ADVERTISE_NPAGE = 0x8000 ; Next page bit ADVERTISE_FULL = (ADVERTISE_100FULL or ADVERTISE_10FULL or ADVERTISE_CSMA) ADVERTISE_ALL = (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL) MII_1000BT_CR = 0x09 MII_1000BT_SR = 0x0a ADVERTISE_1000FULL = 0x0200 ADVERTISE_1000HALF = 0x0100 BMCR_ANRESTART = 0x0200 ; Auto negotiation restart BMCR_ANENABLE = 0x1000 ; Enable auto negotiation BMCR_SPEED100 = 0x2000 ; Select 100Mbps BMCR_LOOPBACK = 0x4000 ; TXD loopback bits BMCR_RESET = 0x8000 ; Reset the DP83840 ; Basic mode status register. BMSR_ERCAP = 0x0001 ; Ext-reg capability BMSR_JCD = 0x0002 ; Jabber detected BMSR_LSTATUS = 0x0004 ; Link status BMSR_ANEGCAPABLE = 0x0008 ; Able to do auto-negotiation BMSR_RFAULT = 0x0010 ; Remote fault detected BMSR_ANEGCOMPLETE = 0x0020 ; Auto-negotiation complete BMSR_RESV = 0x07c0 ; Unused... BMSR_10HALF = 0x0800 ; Can do 10mbps, half-duplex BMSR_10FULL = 0x1000 ; Can do 10mbps, full-duplex BMSR_100HALF = 0x2000 ; Can do 100mbps, half-duplex BMSR_100FULL = 0x4000 ; Can do 100mbps, full-duplex BMSR_100BASE4 = 0x8000 ; Can do 100mbps, 4k packets struct TxDesc PacketBuffer dd ? FlagLen dd ? ends struct RxDesc PacketBuffer dd ? FlagLen dd ? ends virtual at ebx device: ETH_DEVICE .pci_bus dd ? .pci_dev dd ? .mmio_addr dd ? .vendor_id dw ? .device_id dw ? .txflags dd ? .desc_ver dd ? .irqmask dd ? .wolenabled dd ? .in_shutdown dd ? .cur_rx dd ? .phyaddr dd ? .phy_oui dd ? .gigabit dd ? .needs_mac_reset dd ? .linkspeed dd ? .duplex dd ? .next_tx dd ? .nocable dd ? rb 0x100 - (($ - device) and 0xff) .tx_ring rd (TX_RING * sizeof.TxDesc) /4*2 rb 0x100 - (($ - device) and 0xff) .rx_ring rd (RX_RING * sizeof.RxDesc) /4*2 sizeof.device_struct = $ - device end virtual virtual at edi IrqStatus dd ? IrqMask dd ? UnknownSetupReg6 dd ? PollingInterval dd ? end virtual virtual at edi + 0x3c MacReset dd ? end virtual virtual at edi + 0x80 Misc1 dd ? TransmitterControl dd ? TransmitterStatus dd ? PacketFilterFlags dd ? OffloadConfig dd ? ReceiverControl dd ? ReceiverStatus dd ? RandomSeed dd ? UnknownSetupReg1 dd ? UnknownSetupReg2 dd ? MacAddrA dd ? MacAddrB dd ? MulticastAddrA dd ? MulticastAddrB dd ? MulticastMaskA dd ? MulticastMaskB dd ? PhyInterface dd ? end virtual virtual at edi + 0x100 TxRingPhysAddr dd ? RxRingPhysAddr dd ? RingSizes dd ? UnknownTransmitterReg dd ? LinkSpeed dd ? end virtual virtual at edi + 0x130 UnknownSetupReg5 dd ? end virtual virtual at edi + 0x13c UnknownSetupReg3 dd ? end virtual virtual at edi + 0x144 TxRxControl dd ? end virtual virtual at edi + 0x180 MIIStatus dd ? UnknownSetupReg4 dd ? AdapterControl dd ? MIISpeed dd ? MIIControl dd ? MIIData dd ? end virtual virtual at edi + 0x200 WakeUpFlags dd ? end virtual virtual at edi + 0x26c PowerState dd ? end virtual virtual at edi + 0x600 PowerState2 dd ? end virtual section '.flat' code readable align 16 ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; proc START ;; ;; ;; ;; (standard driver proc) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;; align 4 proc START stdcall, state:dword cmp [state], 1 jne .exit DEBUGF 2,"Loading driver\n" stdcall RegService, my_service, service_proc ret .exit: xor eax, eax ret endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; proc SERVICE_PROC ;; ;; ;; ;; (standard driver proc) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;; align 4 proc service_proc stdcall, ioctl:dword mov edx, [ioctl] mov eax, [edx + IOCTL.io_code] ;------------------------------------------------------ cmp eax, 0 ;SRV_GETVERSION jne @F cmp [edx + IOCTL.out_size], 4 jb .fail mov eax, [edx + IOCTL.output] mov [eax], dword API_VERSION xor eax, eax ret ;------------------------------------------------------ @@: cmp eax, 1 ;SRV_HOOK jne .fail cmp [edx + IOCTL.inp_size], 3 ; Data input must be at least 3 bytes jb .fail mov eax, [edx + IOCTL.input] cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given jne .fail ; other types arent supported for this card yet ; check if the device is already listed mov esi, device_list mov ecx, [devices] test ecx, ecx jz .firstdevice ; mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers mov ax, [eax+1] .nextdevice: mov ebx, [esi] cmp al, byte [device.pci_bus] ; compare with pci and device num in device list (notice the usage of word instead of byte) jne @f cmp ah, byte [device.pci_dev] je .find_devicenum ; Device is already loaded, let's find it's device number @@: add esi, 4 loop .nextdevice ; This device doesnt have its own eth_device structure yet, lets create one .firstdevice: cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card jae .fail allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure ; Fill in the direct call addresses into the struct mov [device.reset], reset mov [device.transmit], transmit mov [device.unload], .fail mov [device.name], my_service ; save the pci bus and device numbers mov eax, [edx + IOCTL.input] movzx ecx, byte [eax+1] mov [device.pci_bus], ecx movzx ecx, byte [eax+2] mov [device.pci_dev], ecx DEBUGF 1,"Hooking into device, dev:%x, bus:%x\n", [device.pci_dev], [device.pci_bus] ; Ok, the eth_device structure is ready, let's probe the device call probe ; this function will output in eax test eax, eax jnz .err ; If an error occured, exit mov eax, [devices] ; Add the device structure to our device list mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) inc [devices] ; mov [device.type], NET_TYPE_ETH call NetRegDev cmp eax, -1 je .destroy ret ; If the device was already loaded, find the device number and return it in eax .find_devicenum: DEBUGF 1,"Trying to find device number of already registered device\n" call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx ; into a device number in edi mov eax, edi ; Application wants it in eax instead DEBUGF 1,"Kernel says: %u\n", eax ret ; If an error occured, remove all allocated data and exit (returning -1 in eax) .destroy: ; todo: reset device into virgin state .err: stdcall KernelFree, ebx .fail: ret ;------------------------------------------------------ endp ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; ;; ;; ;; Actual Hardware dependent code starts here ;; ;; ;; ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; ;*************************************************************************** ; Function ; probe ; Description ; Searches for an ethernet card, enables it and clears the rx buffer ; ;*************************************************************************** align 4 probe: DEBUGF 1,"probe\n" mov [device.needs_mac_reset], 0 PCI_make_bus_master PCI_adjust_latency 32 PCI_find_mmio32 DEBUGF 1,"mmio_addr= 0x%x\n", [device.mmio_addr]:8 stdcall MapIoMem, [device.mmio_addr], 2048, (PG_SW + PG_NOCACHE) test eax, eax jz fail mov [device.mmio_addr], eax mov edi, eax DEBUGF 1,"mapped mmio_addr= 0x%x\n", [device.mmio_addr]:8 ;------------------------------------- ; handle different descriptor versions mov [device.desc_ver], DESC_VER_1 movzx eax, [device.device_id] cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_1 je .ver1 cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_2 je .ver1 cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_3 je .ver1 mov [device.desc_ver], DESC_VER_2 .ver1: call read_mac ; disable WOL mov [WakeUpFlags], 0 mov [device.wolenabled], 0 mov [device.txflags], (NV_TX2_LASTPACKET or NV_TX2_VALID) cmp [device.desc_ver], DESC_VER_1 jne @f mov [device.txflags], (NV_TX_LASTPACKET or NV_TX_VALID) @@: ; BEGIN of switch (pci->dev_id) cmp [device.device_id], 0x01C3 jne .next_0x0066 ; nforce mov [device.irqmask], 0 ;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) jmp .find_phy .next_0x0066: cmp [device.device_id], 0x0066 je @f cmp [device.device_id], 0x00D6 je @f jmp .next_0x0086 @@: mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) cmp [device.desc_ver], DESC_VER_1 jne @f or [device.txflags], NV_TX_LASTPACKET1 jmp .find_phy @@: or [device.txflags], NV_TX2_LASTPACKET1 jmp .find_phy .next_0x0086: cmp [device.device_id], 0x0086 je @f cmp [device.device_id], 0x008c je @f cmp [device.device_id], 0x00e6 je @f cmp [device.device_id], 0x00df je @f cmp [device.device_id], 0x0056 je @f cmp [device.device_id], 0x0057 je @f cmp [device.device_id], 0x0037 je @f cmp [device.device_id], 0x0038 je @f jmp .find_phy @@: mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) cmp [device.desc_ver], DESC_VER_1 jne @f or [device.txflags], NV_TX_LASTPACKET1 jmp .find_phy @@: or [device.txflags], NV_TX2_LASTPACKET1 jmp .find_phy .next_0x0268: ; cmp word [device_id], 0x0268 ; je @f ; cmp word [device_id], 0x0269 ; je @f ; cmp word [device_id], 0x0372 ; je @f ; cmp word [device_id], 0x0373 ; je @f ; jmp .default_switch ;@@: cmp [device.device_id], 0x0268 jb .undefined ; Get device revision stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REVISION_ID ; take phy and nic out of low power mode mov ecx, [PowerState2] and ecx, not POWERSTATE2_POWERUP_MASK cmp [device.device_id], PCI_DEVICE_ID_NVIDIA_NVENET_12 jne @f cmp [device.device_id], PCI_DEVICE_ID_NVIDIA_NVENET_13 jne @f cmp al, 0xA3 jb @f or ecx, POWERSTATE2_POWERUP_REV_A3 @@: mov [PowerState2], ecx ; DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) mov [device.needs_mac_reset], 1 cmp [device.desc_ver], DESC_VER_1 jne @f or [device.txflags], NV_TX_LASTPACKET1 jmp .find_phy @@: cmp [device.desc_ver], DESC_VER_2 jne .undefined or [device.txflags], NV_TX2_LASTPACKET1 jmp .find_phy .undefined: DEBUGF 1,"Your card was undefined in this driver.\n" DEBUGF 1,"Review driver_data in Kolibri driver and send a patch\n" ; Find a suitable phy ; Start with address 1 to 31, then do 0, then fail .find_phy: xor edx, edx .phy_loop: inc edx and edx, 0x1f ; phyaddr = i & 0x1f mov eax, MII_PHYSID1 mov ecx, MII_READ call mii_rw ; EDX - addr, EAX - miireg, ECX - value cmp eax, 0xffff je .try_next cmp eax, 0 jl .try_next mov esi, eax mov eax, MII_PHYSID2 mov ecx, MII_READ call mii_rw cmp eax, 0xffff je .try_next cmp eax, 0 jl .try_next jmp .got_it .try_next: test edx, edx jnz .phy_loop ; PHY in isolate mode? No phy attached and user wants to test loopback? ; Very odd, but can be correct. DEBUGF 1,"Could not find a valid PHY.\n" jmp .no_phy .got_it: and esi, PHYID1_OUI_MASK shl esi, PHYID1_OUI_SHFT and eax, PHYID2_OUI_MASK shr eax, PHYID2_OUI_SHFT DEBUGF 1,"Found PHY 0x%x:0x%x at address 0x%x\n", esi:8, eax:8, edx mov [device.phyaddr], edx or eax, esi mov [device.phy_oui], eax call phy_init .no_phy: cmp [device.needs_mac_reset], 0 je @f call mac_reset @@: ;*************************************************************************** ; Function ; reset ; Description ; Place the chip (ie, the ethernet card) into a virgin state ; No inputs ; All registers destroyed ; ;*************************************************************************** reset: DEBUGF 1,"Resetting\n" stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_IRQ movzx eax, al stdcall AttachIntHandler, eax, int_handler, dword 0 test eax, eax jnz @f DEBUGF 1,"\nCould not attach int handler!\n" ; or eax, -1 ; ret @@: ; erase previous misconfiguration mov edi, [device.mmio_addr] mov [MulticastAddrA], MCASTADDRA_FORCE mov [MulticastAddrB], 0 mov [MulticastMaskA], 0 mov [MulticastMaskB], 0 mov [PacketFilterFlags], 0 mov [TransmitterControl], 0 mov [ReceiverControl], 0 mov [AdapterControl], 0 ; initialize descriptor rings call init_ring mov [LinkSpeed], 0 mov [UnknownTransmitterReg], 0 call txrx_reset mov [UnknownSetupReg6], 0 mov [device.in_shutdown], 0 ; give hw rings lea eax, [device.rx_ring] GetRealAddr mov [RxRingPhysAddr], eax lea eax, [device.tx_ring] GetRealAddr mov [TxRingPhysAddr], eax mov [RingSizes], (((RX_RING - 1) shl RINGSZ_RXSHIFT) + ((TX_RING - 1) shl RINGSZ_TXSHIFT)) ; mov [device.linkspeed], (LINKSPEED_FORCE or LINKSPEED_10) mov [device.duplex], 0 mov [LinkSpeed], (LINKSPEED_FORCE or LINKSPEED_10) mov [UnknownSetupReg3], UNKSETUP3_VAL1 mov eax, [device.desc_ver] mov [TxRxControl], eax call pci_push or eax, TXRXCTL_BIT1 mov [TxRxControl], eax stdcall reg_delay, UnknownSetupReg5-edi, UNKSETUP5_BIT31, UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, 0 mov [UnknownSetupReg4], 0 mov [MIIStatus], MIISTAT_MASK2 ; mov [Misc1], (MISC1_FORCE or MISC1_HD) mov eax, [TransmitterStatus] mov [TransmitterStatus], eax mov [PacketFilterFlags], PFF_ALWAYS mov [OffloadConfig], OFFLOAD_NORMAL mov eax, [ReceiverStatus] mov [ReceiverStatus], eax ; set random seed push ebx stdcall GetTimerTicks ; bad idea, driver is started at system startup in 90% of cases.. pop ebx mov edi, [device.mmio_addr] and eax, RNDSEED_MASK or eax, RNDSEED_FORCE mov [RandomSeed], eax mov [UnknownSetupReg1], UNKSETUP1_VAL mov [UnknownSetupReg2], UNKSETUP2_VAL mov [PollingInterval], POLL_DEFAULT mov [UnknownSetupReg6], UNKSETUP6_VAL mov eax, [device.phyaddr] shl eax, ADAPTCTL_PHYSHIFT or eax, (ADAPTCTL_PHYVALID or ADAPTCTL_RUNNING) mov [AdapterControl], eax mov [MIISpeed], (MIISPEED_BIT8 or MIIDELAY) mov [UnknownSetupReg4], UNKSETUP4_VAL mov [WakeUpFlags], WAKEUPFLAGS_VAL or [PowerState], POWERSTATE_POWEREDUP call pci_push mov esi, 10 call Sleep or [PowerState], POWERSTATE_VALID mov [IrqMask], 0 ;;; ; ??? Mask RX interrupts mov [IrqMask], IRQ_RX_ALL + IRQ_TX_ALL ;;; ; ??? Mask TX interrupts ;;; mov [IrqMask], IRQ_TX_ALL ;;; ; ??? Mask OTHER interrupts ;;; mov [IrqMask], IRQ_OTHER_ALL call pci_push mov [MIIStatus], MIISTAT_MASK2 mov [IrqStatus], IRQSTAT_MASK call pci_push mov [MulticastAddrA], MCASTADDRA_FORCE mov [MulticastAddrB], 0 mov [MulticastMaskA], 0 mov [MulticastMaskB], 0 mov [PacketFilterFlags], (PFF_ALWAYS or PFF_MYADDR) call set_multicast ; One manual link speed update: Interrupts are enabled, future link ; speed changes cause interrupts and are handled by nv_link_irq(). mov eax, [MIIStatus] mov [MIIStatus], MIISTAT_MASK DEBUGF 1,"startup: got 0x%x\n", eax call update_linkspeed mov [TransmitterControl], XMITCTL_START ; start TX call pci_push mov [device.nocable], 0 test eax, eax jnz .return DEBUGF 1,"no link during initialization.\n" mov [device.nocable], 1 .return: xor eax, eax ; Indicate that we have successfully reset the card mov [device.mtu], 1514 ;;; FIXME ; Set link state to unknown mov [device.state], ETH_LINK_UNKOWN ret fail: or eax, -1 ret ;-------------------------------------------------------- ; ; MII_RW ; ; read/write a register on the PHY. ; Caller must guarantee serialization ; Input: EAX - miireg, EDX - addr, ECX - value ; Output: EAX - retval ; ;-------------------------------------------------------- mii_rw: DEBUGF 1,"mii_rw: 0x%x to reg %d at PHY %d\n", ecx, eax, edx push edx mov edi, [device.mmio_addr] mov [MIIStatus], MIISTAT_MASK test [MIIControl], MIICTL_INUSE jz @f mov [MIIControl], MIICTL_INUSE mov esi, NV_MIIBUSY_DELAY call Sleep @@: shl edx, MIICTL_ADDRSHIFT or edx, eax cmp ecx, MII_READ je @f mov [MIIData], ecx or edx, MIICTL_WRITE @@: mov [MIIControl], edx stdcall reg_delay, MIIControl-edi, MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, 0 test eax, eax jz @f DEBUGF 1,"mii_rw timed out.\n" or eax, -1 jmp .return @@: cmp ecx, MII_READ je @f ; it was a write operation - fewer failures are detectable DEBUGF 1,"mii_rw write: ok\n" xor eax, eax jmp .return @@: mov eax, [MIIStatus] test eax, MIISTAT_ERROR jz @f DEBUGF 1,"mii read: failed.\n" or eax, -1 jmp .return @@: mov eax, [MIIData] DEBUGF 1,"mii read: 0x%x.\n", eax .return: pop edx ret ; Input: offset:word, mask:dword, target:dword, delay:word, delaymax:word, msg:dword ; Output: EAX - 0|1 proc reg_delay, offset:dword, mask:dword, target:dword, delay:dword, delaymax:dword, msg:dword ; DEBUGF 1,"reg_delay\n" push esi call pci_push .loop: mov esi, [delay] call Sleep mov eax, [delaymax] sub eax, [delay] mov [delaymax], eax cmp eax, 0 jl .fail mov eax, [offset] mov eax, [edi + eax] and eax, [mask] cmp eax, [target] jne .loop pop esi xor eax, eax ret .fail: pop esi xor eax, eax inc eax ret endp ; Input: none ; Output: EAX - result (0 = OK, other = error) phy_init: push ebx ecx ; set advertise register mov edx, [device.phyaddr] mov eax, MII_ADVERTISE mov ecx, MII_READ call mii_rw or eax, (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL or 0x800 or 0x400) mov ecx, eax mov eax, MII_ADVERTISE call mii_rw test eax, eax jz @f DEBUGF 1,"phy write to advertise failed.\n" mov eax, PHY_ERROR jmp .return @@: ; get phy interface type mov edi, [device.mmio_addr] mov eax, [PhyInterface] DEBUGF 1,"phy interface type = 0x%x\n", eax:8 ; see if gigabit phy mov eax, MII_BMSR mov ecx, MII_READ call mii_rw test eax, PHY_GIGABIT jnz .gigabit mov [device.gigabit], 0 jmp .next_if .gigabit: mov [device.gigabit], PHY_GIGABIT mov eax, MII_1000BT_CR mov ecx, MII_READ call mii_rw and eax, (not ADVERTISE_1000HALF) test [PhyInterface], PHY_RGMII jz @f or eax, ADVERTISE_1000FULL jmp .next @@: and eax, (not ADVERTISE_1000FULL) .next: mov ecx, eax mov eax, MII_1000BT_CR call mii_rw test eax, eax jz .next_if DEBUGF 1,"phy init failed.\n" mov eax, PHY_ERROR jmp .return .next_if: call phy_reset test eax, eax jz @f DEBUGF 1,"phy reset failed.\n" mov eax, PHY_ERROR jmp .return @@: ; phy vendor specific configuration cmp [device.phy_oui], PHY_OUI_CICADA jne .next_if2 test [PhyInterface], PHY_RGMII jz .next_if2 mov eax, MII_RESV1 mov ecx, MII_READ call mii_rw and eax, (not (PHY_INIT1 or PHY_INIT2)) or eax, (PHY_INIT3 or PHY_INIT4) mov ecx, eax mov eax, MII_RESV1 call mii_rw test eax, eax jz @f DEBUGF 1,"phy init failed.\n" mov eax, PHY_ERROR jmp .return @@: mov eax, MII_NCONFIG mov ecx, MII_READ call mii_rw or eax, PHY_INIT5 mov ecx, eax mov eax, MII_NCONFIG call mii_rw test eax, eax jz .next_if2 DEBUGF 1,"phy init failed.\n" mov eax, PHY_ERROR jmp .return .next_if2: cmp [device.phy_oui], PHY_OUI_CICADA jne .restart mov eax, MII_SREVISION mov ecx, MII_READ call mii_rw or eax, PHY_INIT6 mov ecx, eax mov eax, MII_SREVISION call mii_rw test eax, eax jz .restart DEBUGF 1,"phy init failed.\n" jmp .return .restart: ; restart auto negotiation mov eax, MII_BMCR mov ecx, MII_READ call mii_rw or eax, (BMCR_ANRESTART or BMCR_ANENABLE) mov ecx, eax mov eax, MII_BMCR call mii_rw test eax, eax jz .ok mov eax, PHY_ERROR jmp .return .ok: xor eax, eax .return: pop ecx ebx ret ; Input: none ; Output: EAX - result (0 = OK, other = error) phy_reset: DEBUGF 1,"phy_reset\n" push ebx ecx edx mov edx, [device.phyaddr] mov eax, MII_BMCR mov ecx, MII_READ call mii_rw or eax, BMCR_RESET push eax mov ecx, eax mov eax, MII_BMCR call mii_rw test eax, eax jz @f pop eax mov eax, 0xffffffff jmp .return @@: pop eax mov esi, 500 call Sleep ; must wait till reset is deasserted mov esi, 100 ; FIXME: 100 tries seem excessive .while_loop: test eax, BMCR_RESET jz .while_loop_exit push esi mov esi, 10 call Sleep pop esi mov eax, MII_BMCR mov ecx, MII_READ call mii_rw dec esi jnz .while_loop mov eax, 0xffffffff jmp .return .while_loop_exit: xor eax, eax .return: pop edx ecx ebx ret align 4 pci_push: push eax mov eax, [edi] pop eax ret align 4 mac_reset: push esi edi DEBUGF 1,"mac_reset.\n" mov edi, [device.mmio_addr] mov eax, [device.desc_ver] or eax, (TXRXCTL_BIT2 or TXRXCTL_RESET) mov [TxRxControl], eax call pci_push mov [MacReset], MAC_RESET_ASSERT call pci_push mov esi, NV_MAC_RESET_DELAY call Sleep mov [MacReset], 0 call pci_push mov esi, NV_MAC_RESET_DELAY call Sleep mov eax, [device.desc_ver] or eax, TXRXCTL_BIT2 mov [TxRxControl], eax call pci_push pop edi esi ret align 4 init_ring: DEBUGF 1,"init rings\n" push eax esi ecx mov [device.next_tx], 0 mov ecx, TX_RING lea esi, [device.tx_ring] .tx_loop: mov [esi + TxDesc.FlagLen], 0 add esi, sizeof.TxDesc dec ecx jnz .tx_loop mov [device.cur_rx], 0 mov ecx, RX_RING lea esi, [device.rx_ring] .rx_loop: push ecx esi stdcall KernelAlloc, 4096 shl RBLEN ; push/pop esi not needed, but just in case... pop esi mov [esi + RX_RING*sizeof.RxDesc], eax GetRealAddr mov [esi + RxDesc.PacketBuffer], eax mov [esi + RxDesc.FlagLen], (4096 shl RBLEN or NV_RX_AVAIL) add esi, sizeof.RxDesc pop ecx dec ecx jnz .rx_loop pop ecx esi eax ret ; Input: none ; Output: none align 4 txrx_reset: push eax esi DEBUGF 1,"txrx_reset\n" mov edi, [device.mmio_addr] mov eax, [device.desc_ver] or eax, (TXRXCTL_BIT2 or TXRXCTL_RESET) mov [TxRxControl], eax call pci_push mov esi, NV_TXRX_RESET_DELAY call Sleep mov eax, [device.desc_ver] or eax, TXRXCTL_BIT2 mov [TxRxControl], eax call pci_push pop esi eax ret ; Input: none ; Output: none set_multicast: ; u32 addr[2]; ; u32 mask[2]; ; u32 pff; ; u32 alwaysOff[2]; ; u32 alwaysOn[2]; ; ; memset(addr, 0, sizeof(addr)); ; memset(mask, 0, sizeof(mask)); ; ; pff = PFF_MYADDR; ; ; alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; ; ; addr[0] = alwaysOn[0]; ; addr[1] = alwaysOn[1]; ; mask[0] = alwaysOn[0] | alwaysOff[0]; ; mask[1] = alwaysOn[1] | alwaysOff[1]; ; ; addr[0] |= MCASTADDRA_FORCE; ; pff |= PFF_ALWAYS; call stop_rx mov edi, [device.mmio_addr] mov [MulticastAddrA], MCASTADDRA_FORCE mov [MulticastAddrB], 0 mov [MulticastMaskA], 0 mov [MulticastMaskB], 0 mov [PacketFilterFlags], (PFF_MYADDR or PFF_ALWAYS) call start_rx ret ; Input: none ; Output: none start_rx: push edi DEBUGF 1,"start_rx\n" ; Already running? Stop it. mov edi, [device.mmio_addr] mov eax, [ReceiverControl] test eax, RCVCTL_START jz @f mov [ReceiverControl], 0 call pci_push @@: mov eax, [device.linkspeed] mov [LinkSpeed], eax call pci_push mov [ReceiverControl], RCVCTL_START call pci_push pop edi ret ; Input: none ; Output: none stop_rx: push esi edi DEBUGF 1,"stop_rx.\n" mov edi, [device.mmio_addr] mov [ReceiverControl], 0 push ebx edx edi stdcall reg_delay, ReceiverStatus-edi, RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, 0 pop edi edx ebx mov esi, NV_RXSTOP_DELAY2 call Sleep mov [LinkSpeed], 0 pop edi esi ret ; Input: none ; Output: EAX update_linkspeed: DEBUGF 1,"update linkspeed\n" ; BMSR_LSTATUS is latched, read it twice: we want the current value. mov edx, [device.phyaddr] mov eax, MII_BMSR mov ecx, MII_READ call mii_rw mov eax, MII_BMSR mov ecx, MII_READ call mii_rw test eax, BMSR_LSTATUS ; Link up? jz .10mbit_hd test eax, BMSR_ANEGCOMPLETE ; still in autonegotiation? jz .10mbit_hd cmp [device.gigabit], PHY_GIGABIT jne .no_gigabit ;mov edx, [device.phyaddr] mov eax, MII_1000BT_CR mov ecx, MII_READ call mii_rw push eax ;mov edx, [device.phyaddr] mov eax, MII_1000BT_SR mov ecx, MII_READ call mii_rw pop ecx test eax, LPA_1000FULL jz .no_gigabit test ecx, ADVERTISE_1000FULL jz .no_gigabit DEBUGF 1,"update_linkspeed: GBit ethernet detected.\n" mov ecx, (LINKSPEED_FORCE or LINKSPEED_1000) xor eax, eax inc eax jmp set_speed .no_gigabit: ;mov edx, [device.phyaddr] mov eax, MII_ADVERTISE mov ecx, MII_READ call mii_rw ; adv = eax push eax ;mov edx, [device.phyaddr] mov eax, MII_LPA mov ecx, MII_READ call mii_rw ; lpa = eax pop ecx DEBUGF 1,"PHY advertises 0x%x, lpa 0x%x\n", ecx, eax and eax, ecx ; FIXME: handle parallel detection properly, handle gigabit ethernet test eax, LPA_100FULL jz @f DEBUGF 1,"update_linkspeed: 100 mbit full duplex\n" mov ecx, (LINKSPEED_FORCE or LINKSPEED_100) xor eax, eax inc eax jmp set_speed @@: test eax, LPA_100HALF jz @f DEBUGF 1,"update_linkspeed: 100 mbit half duplex\n" mov ecx, (LINKSPEED_FORCE or LINKSPEED_100) xor eax, eax jmp set_speed @@: test eax, LPA_10FULL jz @f DEBUGF 1,"update_linkspeed: 10 mbit full duplex\n" mov ecx, (LINKSPEED_FORCE or LINKSPEED_10) xor eax, eax inc eax jmp set_speed @@: .10mbit_hd: DEBUGF 1,"update_linkspeed: 10 mbit half duplex\n" mov ecx, (LINKSPEED_FORCE or LINKSPEED_10) xor eax, eax jmp set_speed align 4 set_speed: cmp eax, [device.duplex] jne .update cmp ecx, [device.linkspeed] jne .update ret .update: DEBUGF 1,"update_linkspeed: changing link to 0x%x/XD.\n", ecx mov [device.duplex], eax mov [device.linkspeed], ecx cmp [device.gigabit], PHY_GIGABIT jne .no_gigabit mov edi, [device.mmio_addr] mov eax, [RandomSeed] and eax, not (0x3FF00) mov ecx, eax ; phyreg = ecx mov eax, [device.linkspeed] and eax, 0xFFF cmp eax, LINKSPEED_10 jne @f or ecx, RNDSEED_FORCE3 jmp .end_if4 @@: cmp eax, LINKSPEED_100 jne @f or ecx, RNDSEED_FORCE2 jmp .end_if4 @@: cmp eax, LINKSPEED_1000 jne .end_if4 or ecx, RNDSEED_FORCE .end_if4: mov [RandomSeed], ecx .no_gigabit: mov ecx, [PhyInterface] and ecx, not (PHY_HALF or PHY_100 or PHY_1000) cmp [device.duplex], 0 jne @f or ecx, PHY_HALF @@: mov eax, [device.linkspeed] and eax, 0xFFF cmp eax, LINKSPEED_100 jne @f or ecx, PHY_100 jmp .end_if5 @@: cmp eax, LINKSPEED_1000 jne .end_if5 or ecx, PHY_1000 .end_if5: mov [PhyInterface], ecx cmp [device.duplex], 0 je @f xor ecx, ecx jmp .next @@: mov ecx, MISC1_HD .next: or ecx, MISC1_FORCE mov [Misc1], ecx call pci_push mov eax, [device.linkspeed] mov [LinkSpeed], eax call pci_push ret align 4 read_mac: mov edi, [device.mmio_addr] mov eax, [MacAddrA] mov ecx, [MacAddrB] mov dword [device.mac], eax mov word [device.mac + 4], cx cmp [device.device_id], 0x03E5 jae @f bswap eax xchg cl, ch mov dword [device.mac + 2], eax mov word [device.mac], cx @@: DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n", \ [device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Transmit ;; ;; ;; ;; In: buffer pointer in [esp+4] ;; ;; size of buffer in [esp+8] ;; ;; pointer to device structure in ebx ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; align 4 transmit: DEBUGF 2,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] mov eax, [esp+4] DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ [eax+13]:2,[eax+12]:2 cmp dword [esp + 8], 1514 ja .fail cmp dword [esp + 8], 60 jb .fail ; get the descriptor address mov eax, [device.next_tx] mov cl, sizeof.TxDesc mul cl lea esi, [device.tx_ring + eax] mov eax, [esp + 4] mov [esi + TX_RING*sizeof.TxDesc], eax GetRealAddr mov [esi + TxDesc.PacketBuffer], eax mov ecx, [esp + 8] or ecx, [device.txflags] mov [esi + TxDesc.FlagLen], eax mov edi, [device.mmio_addr] mov eax, [device.desc_ver] or eax, TXRXCTL_KICK mov [TxRxControl], eax call pci_push inc [device.next_tx] and [device.next_tx], (TX_RING-1) ; Update stats inc [device.packets_tx] mov eax, [esp + 8] add dword [device.bytes_tx], eax adc dword [device.bytes_tx + 4], 0 xor eax, eax ret 8 .fail: stdcall KernelFree, [esp+4] or eax, -1 ret 8 ; Interrupt handler align 4 int_handler: push ebx esi edi DEBUGF 2,"INT\n" ;------------------------------------------- ; Find pointer of device wich made IRQ occur mov esi, device_list mov ecx, [devices] test ecx, ecx jz .fail .nextdevice: mov ebx, dword [esi] add esi, 4 mov edi, [device.mmio_addr] mov eax, [IrqStatus] test eax, eax jnz .got_it dec ecx jnz .nextdevice .nothing: pop edi esi ebx xor eax, eax ret .got_it: mov [IrqStatus], eax DEBUGF 2,"IrqStatus = %x\n", eax test eax, IRQ_RX jz .no_rx .top: mov eax, [device.cur_rx] mov cx, sizeof.RxDesc mul cx lea esi, [device.rx_ring + eax] mov eax, [esi + RxDesc.FlagLen] test eax, NV_RX_AVAIL ; still owned by hardware jnz .return0 cmp [device.desc_ver], DESC_VER_1 jne @f test eax, NV_RX_DESCRIPTORVALID jz .return0 jmp .next @@: test eax, NV_RX2_DESCRIPTORVALID jz .return0 .next: cmp dword [device.desc_ver], DESC_VER_1 jne @f and eax, LEN_MASK_V1 jmp .next2 @@: and eax, LEN_MASK_V2 .next2: ; got a valid packet - forward it to the network core push .top push eax push dword [esi + RX_RING*sizeof.RxDesc] inc [device.cur_rx] and [device.cur_rx], (RX_RING-1) ; Allocate new buffer stdcall KernelAlloc, 4096 shl RBLEN mov [esi + RX_RING*sizeof.RxDesc], eax GetRealAddr mov [esi + RxDesc.PacketBuffer], eax mov [esi + RxDesc.FlagLen], (4096 shl RBLEN or NV_RX_AVAIL) jmp Eth_input .return0: .no_rx: test eax, IRQ_RX_ERROR jz .no_rx_err push eax DEBUGF 2,"RX error!\n" mov eax, [device.cur_rx] mov cx, sizeof.RxDesc mul cx lea esi, [device.rx_ring + eax] mov eax, [esi + RxDesc.FlagLen] DEBUGF 2,"Flaglen=%x\n", eax ; TODO: allocate new buff pop eax .no_rx_err: test eax, IRQ_LINK jz .no_link push eax call update_linkspeed pop eax .no_link: .fail: pop edi esi ebx xor eax, eax inc eax ret ; End of code section '.data' data readable writable align 16 ; place all uninitialized data place here align 4 ; Place all initialised data here devices dd 0 version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) my_service db 'FORCEDETH',0 ; max 16 chars include zero include_debug_strings ; All data wich FDO uses will be included here device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling