diff --git a/kernel/branches/net/drivers/mtd80x.asm b/kernel/branches/net/drivers/mtd80x.asm new file mode 100644 index 0000000000..3ed653ea46 --- /dev/null +++ b/kernel/branches/net/drivers/mtd80x.asm @@ -0,0 +1,1259 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; MTD80x driver for KolibriOS ;; +;; ;; +;; Based on mtd80x.c from the etherboot project ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format MS COFF + + API_VERSION equ 0x01000100 + DRIVER_VERSION equ 5 + + MAX_DEVICES equ 16 + + DEBUG equ 1 + __DEBUG__ equ 1 + __DEBUG_LEVEL__ equ 1 + + NUM_TX_DESC equ 4 + NUM_RX_DESC equ 4 + +include 'proc32.inc' +include 'imports.inc' +include 'fdo.inc' +include 'netdrv.inc' + +public START +public service_proc +public version + + +; for different PHY + + MysonPHY equ 1 + AhdocPHY equ 2 + SeeqPHY equ 3 + MarvellPHY equ 4 + Myson981 equ 5 + LevelOnePHY equ 6 + OtherPHY equ 10 + +; Offsets to the Command and Status Registers. + + PAR0 equ 0x0 ; physical address 0-3 + PAR1 equ 0x04 ; physical address 4-5 + MAR0 equ 0x08 ; multicast address 0-3 + MAR1 equ 0x0C ; multicast address 4-7 + FAR0 equ 0x10 ; flow-control address 0-3 + FAR1 equ 0x14 ; flow-control address 4-5 + TCRRCR equ 0x18 ; receive & transmit configuration + BCR equ 0x1C ; bus command + TXPDR equ 0x20 ; transmit polling demand + RXPDR equ 0x24 ; receive polling demand + RXCWP equ 0x28 ; receive current word pointer + TXLBA equ 0x2C ; transmit list base address + RXLBA equ 0x30 ; receive list base address + ISR equ 0x34 ; interrupt status + IMR equ 0x38 ; interrupt mask + FTH equ 0x3C ; flow control high/low threshold + MANAGEMENT equ 0x40 ; bootrom/eeprom and mii management + TALLY equ 0x44 ; tally counters for crc and mpa + TSR equ 0x48 ; tally counter for transmit status + BMCRSR equ 0x4c ; basic mode control and status + PHYIDENTIFIER equ 0x50 ; phy identifier + ANARANLPAR equ 0x54 ; auto-negotiation advertisement and link partner ability + ANEROCR equ 0x58 ; auto-negotiation expansion and pci conf. + BPREMRPSR equ 0x5c ; bypass & receive error mask and phy status + +; Bits in the interrupt status/enable registers. + + RFCON equ 0x00020000 ; receive flow control xon packet + RFCOFF equ 0x00010000 ; receive flow control xoff packet + LSCStatus equ 0x00008000 ; link status change + ANCStatus equ 0x00004000 ; autonegotiation completed + FBE equ 0x00002000 ; fatal bus error + FBEMask equ 0x00001800 ; mask bit12-11 + ParityErr equ 0x00000000 ; parity error + TargetErr equ 0x00001000 ; target abort + MasterErr equ 0x00000800 ; master error + TUNF equ 0x00000400 ; transmit underflow + ROVF equ 0x00000200 ; receive overflow + ETI equ 0x00000100 ; transmit early int + ERI equ 0x00000080 ; receive early int + CNTOVF equ 0x00000040 ; counter overflow + RBU equ 0x00000020 ; receive buffer unavailable + TBU equ 0x00000010 ; transmit buffer unavilable + TI equ 0x00000008 ; transmit interrupt + RI equ 0x00000004 ; receive interrupt + RxErr equ 0x00000002 ; receive error + +; Bits in the NetworkConfig register. + + RxModeMask equ 0xe0 + AcceptAllPhys equ 0x80 ; promiscuous mode + AcceptBroadcast equ 0x40 ; accept broadcast + AcceptMulticast equ 0x20 ; accept mutlicast + AcceptRunt equ 0x08 ; receive runt pkt + ALP equ 0x04 ; receive long pkt + AcceptErr equ 0x02 ; receive error pkt + + AcceptMyPhys equ 0x00000000 + RxEnable equ 0x00000001 + RxFlowCtrl equ 0x00002000 + TxEnable equ 0x00040000 + TxModeFDX equ 0x00100000 + TxThreshold equ 0x00e00000 + + PS1000 equ 0x00010000 + PS10 equ 0x00080000 + FD equ 0x00100000 + + +; Bits in network_desc.status + + RXOWN equ 0x80000000 ; own bit + FLNGMASK equ 0x0fff0000 ; frame length + FLNGShift equ 16 + MARSTATUS equ 0x00004000 ; multicast address received + BARSTATUS equ 0x00002000 ; broadcast address received + PHYSTATUS equ 0x00001000 ; physical address received + RXFSD equ 0x00000800 ; first descriptor + RXLSD equ 0x00000400 ; last descriptor + ErrorSummary equ 0x80 ; error summary + RUNT equ 0x40 ; runt packet received + LONG equ 0x20 ; long packet received + FAE equ 0x10 ; frame align error + CRC equ 0x08 ; crc error + RXER equ 0x04 ; receive error + +; rx_desc_control_bits + + RXIC equ 0x00800000 ; interrupt control + RBSShift equ 0 + +; tx_desc_status_bits + + TXOWN equ 0x80000000 ; own bit + JABTO equ 0x00004000 ; jabber timeout + CSL equ 0x00002000 ; carrier sense lost + LC equ 0x00001000 ; late collision + EC equ 0x00000800 ; excessive collision + UDF equ 0x00000400 ; fifo underflow + DFR equ 0x00000200 ; deferred + HF equ 0x00000100 ; heartbeat fail + NCRMask equ 0x000000ff ; collision retry count + NCRShift equ 0 + +; tx_desc_control_bits + + TXIC equ 0x80000000 ; interrupt control + ETIControl equ 0x40000000 ; early transmit interrupt + TXLD equ 0x20000000 ; last descriptor + TXFD equ 0x10000000 ; first descriptor + CRCEnable equ 0x08000000 ; crc control + PADEnable equ 0x04000000 ; padding control + RetryTxLC equ 0x02000000 ; retry late collision + PKTSMask equ 0x3ff800 ; packet size bit21-11 + PKTSShift equ 11 + TBSMask equ 0x000007ff ; transmit buffer bit 10-0 + TBSShift equ 0 + +; BootROM/EEPROM/MII Management Register + + MASK_MIIR_MII_READ equ 0x00000000 + MASK_MIIR_MII_WRITE equ 0x00000008 + MASK_MIIR_MII_MDO equ 0x00000004 + MASK_MIIR_MII_MDI equ 0x00000002 + MASK_MIIR_MII_MDC equ 0x00000001 + +; ST+OP+PHYAD+REGAD+TA + + OP_READ equ 0x6000 ; ST:01+OP:10+PHYAD+REGAD+TA:Z0 + OP_WRITE equ 0x5002 ; ST:01+OP:01+PHYAD+REGAD+TA:10 + +; ------------------------------------------------------------------------- +; Constants for Myson PHY +; ------------------------------------------------------------------------- + + MysonPHYID equ 0xd0000302 + MysonPHYID0 equ 0x0302 + StatusRegister equ 18 + SPEED100 equ 0x0400 ; bit10 + FULLMODE equ 0x0800 ; bit11 + +; ------------------------------------------------------------------------- +; Constants for Seeq 80225 PHY +; ------------------------------------------------------------------------- + + SeeqPHYID0 equ 0x0016 + MIIRegister18 equ 18 + SPD_DET_100 equ 0x80 + DPLX_DET_FULL equ 0x40 + +; ------------------------------------------------------------------------- +; Constants for Ahdoc 101 PHY +; ------------------------------------------------------------------------- + + AhdocPHYID0 equ 0x0022 + DiagnosticReg equ 18 + DPLX_FULL equ 0x0800 + Speed_100 equ 0x0400 + +; -------------------------------------------------------------------------- +; Constants +; -------------------------------------------------------------------------- + + MarvellPHYID0 equ 0x0141 + LevelOnePHYID0 equ 0x0013 + + MII1000BaseTControlReg equ 9 + MII1000BaseTStatusReg equ 10 + SpecificReg equ 17 + +; for 1000BaseT Control Register + + PHYAbletoPerform1000FullDuplex equ 0x0200 + PHYAbletoPerform1000HalfDuplex equ 0x0100 + PHY1000AbilityMask equ 0x300 + +; for phy specific status register, marvell phy. + + SpeedMask equ 0x0c000 + Speed_1000M equ 0x08000 + Speed_100M equ 0x4000 + Speed_10M equ 0 + Full_Duplex equ 0x2000 + +; for phy specific status register, levelone phy + + LXT1000_100M equ 0x08000 + LXT1000_1000M equ 0x0c000 + LXT1000_Full equ 0x200 + +; for PHY + + LinkIsUp equ 0x0004 + LinkIsUp2 equ 0x00040000 + + + +virtual at 0 + + mtd_desc: + .status dd ? + .control dd ? + .buffer dd ? + .next_desc dd ? + + .next_desc_logical dd ? + .skbuff dd ? + + .reserved1 dd ? + .reserved2 dd ? + + .size = $ + +end virtual + + +virtual at ebx + + device: + + ETH_DEVICE + + .tx_desc rb NUM_TX_DESC*mtd_desc.size + .rx_desc rb NUM_RX_DESC*mtd_desc.size + + .io_addr dd ? + .pci_bus db ? + .pci_dev db ? + .irq_line db ? + .dev_id dw ? + + .flags dd ? + + .crvalue dd ? + .bcrvalue dd ? + + .cur_rx dd ? + .cur_tx dd ? + +; These values are keep track of the transceiver/media in use. + + .linkok dd ? + .line_speed dd ? + .duplexmode dd ? + .default_port dd ? + .PHYType dd ? + +; MII transceiver section. + + .mii_cnt dd ? ; MII device addresses. + .phys db ? ; MII device addresses. + + device_size = $ - device + +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 + + .entry: + + DEBUGF 2,"Loading mtd80x driver\n" + stdcall RegService, my_service, service_proc + ret + + .fail: + .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, [IOCTL.io_code] + +;------------------------------------------------------ + + cmp eax, 0 ;SRV_GETVERSION + jne @F + + cmp [IOCTL.out_size], 4 + jl .fail + mov eax, [IOCTL.output] + mov [eax], dword API_VERSION + + xor eax, eax + ret + +;------------------------------------------------------ + @@: + cmp eax, 1 ;SRV_HOOK + jne .fail + + cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes + jl .fail + + mov eax, [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, [IOCTL.input] ; get the pci bus and device numbers + mov ax , [eax+1] ; + .nextdevice: + mov ebx, [esi] + cmp ax , word [device.pci_bus] ; compare with pci and device num in device list (notice the usage of word instead of byte) + 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 + jge .fail + + allocate_and_clear ebx, device_size, .fail + +; Fill in the direct call addresses into the struct + + mov [device.reset], reset + mov [device.transmit], transmit + mov [device.get_MAC], read_mac + mov [device.set_MAC], write_mac + mov [device.unload], unload + mov [device.name], my_service + +; save the pci bus and device numbers + + mov eax, [IOCTL.input] + mov cl , [eax+1] + mov [device.pci_bus], cl + mov cl , [eax+2] + mov [device.pci_dev], cl + +; Now, it's time to find the base io addres of the PCI device + + find_io [device.pci_bus], [device.pci_dev], [device.io_addr] + +; We've found the io address, find IRQ now + + find_irq [device.pci_bus], [device.pci_dev], [device.irq_line] + + DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ + [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:8 + +; Ok, the eth_device structure is ready, let's probe the device +; Because initialization fires IRQ, IRQ handler must be aware of this device + 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] ; + + call probe ; this function will output in eax + test eax, eax + jnz .err2 ; If an error occured, exit + + 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 2,"Trying to find device number of already registered device\n" + mov ebx, eax + 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 2,"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 + + .err2: + dec [devices] + .err: + DEBUGF 2,"removing device structure\n" + stdcall KernelFree, ebx + .fail: + or eax, -1 + ret + +;------------------------------------------------------ +endp + + +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; +;; ;; +;; Actual Hardware dependent code starts here ;; +;; ;; +;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; + + + +align 4 +unload: + ; TODO: (in this particular order) + ; + ; - Stop the device + +; /* Disable Tx Rx*/ +; outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR ); +; +; /* Reset the chip to erase previous misconfiguration. */ +; mtd_reset(nic); + + ; - Detach int handler + ; - Remove device from local list (device_list) + ; - call unregister function in kernel + ; - Remove all allocated structures and buffers the card used + + or eax,-1 + +ret + + +;------- +; +; PROBE +; +;------- +align 4 +probe: + + DEBUGF 2,"Probing mtd80x device\n" + + make_bus_master [device.pci_bus], [device.pci_dev] + + movzx eax, [device.pci_bus] + movzx ecx, [device.pci_dev] + stdcall PciRead32, eax ,ecx ,0 + + cmp ax , 0x1516 + jne .notfound + shr eax, 16 + mov [device.dev_id], ax + + cmp ax, 0x0800 + je .has_mii_xcvr + + cmp ax, 0x0803 + je .has_chip_xcvr + + cmp ax, 0x0891 + je .has_mii_xcvr + + .notfound: + DEBUGF 1,"Device not supported!\n" + xor eax, eax + dec eax + ret + + .has_chip_xcvr: + DEBUGF 1,"Device has chip xcvr\n" + + jmp .xcvr_set + + .has_mii_xcvr: + DEBUGF 1,"Device has mii xcvr\n" + + .xcvr_set: + + call read_mac + +; Reset the chip to erase previous misconfiguration. + + set_io 0 + set_io BCR + xor eax, eax + inc eax + out dx, eax + +; find the connected MII xcvrs + + cmp [device.dev_id], 0x0803 + je .is_803 + +; int phy, phy_idx equ 0; +; +; for (phy equ 1; phy < 32 && phy_idx < 1; phy++) { +; int mii_status equ mdio_read(nic, phy, 1); +; +; if (mii_status !equ 0xffff && mii_status !equ 0x0000) { +; mtdx.phys[phy_idx] equ phy; +; +; DBG ( "%s: MII PHY found at address %d, status " +; "0x%4.4x.\n", mtdx.nic_name, phy, mii_status ); +; /* get phy type */ +; { +; unsigned int data; +; +; data equ mdio_read(nic, mtdx.phys[phy_idx], 2); +; if (data equequ SeeqPHYID0) +; mtdx.PHYType equ SeeqPHY; +; else if (data equequ AhdocPHYID0) +; mtdx.PHYType equ AhdocPHY; +; else if (data equequ MarvellPHYID0) +; mtdx.PHYType equ MarvellPHY; +; else if (data equequ MysonPHYID0) +; mtdx.PHYType equ Myson981; +; else if (data equequ LevelOnePHYID0) +; mtdx.PHYType equ LevelOnePHY; +; else +; mtdx.PHYType equ OtherPHY; +; } +; phy_idx++; +; } +; } +; +; mtdx.mii_cnt equ phy_idx; +; if (phy_idx equequ 0) { +; printf("%s: MII PHY not found -- this device may " +; "not operate correctly.\n", mtdx.nic_name); +; } + + jmp .no_803 + + .is_803: + + mov [device.phys], 32 + +; get phy type + set_io 0 + set_io PHYIDENTIFIER + in eax, dx + + cmp eax, MysonPHYID + jne @f + + mov [device.PHYType], MysonPHY + DEBUGF 1,"MysonPHY\n" + jmp .no_803 + + @@: + mov [device.PHYType], OtherPHY + DEBUGF 1,"OtherPHY\n" + + .no_803: + +;------- +; +; RESET +; +;------- +align 4 +reset: + + DEBUGF 1,"Resetting mtd80x\n" + +;-------------------------------- +; insert irq handler on given irq + + movzx eax, [device.irq_line] + DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 + stdcall AttachIntHandler, eax, int_handler, dword 0 + test eax, eax + jnz @f + DEBUGF 1,"\nCould not attach int handler!\n" +; or eax, -1 +; ret + @@: + +; Reset the chip to erase previous misconfiguration. + + set_io 0 + set_io BCR + xor eax, eax + inc eax + out dx, eax + + call init_ring + +; Initialize other registers. +; Configure the PCI bus bursts and FIFO thresholds. + + mov [device.bcrvalue], 0x10 ; little-endian, 8 burst length + mov [device.crvalue], 0xa00 ; 128 burst length + + cmp [device.dev_id], 0x891 + jne @f + or [device.bcrvalue], 0x200 ; set PROG bit + or [device.crvalue], 0x02000000 ; set enhanced bit + @@: + + or [device.crvalue], RxEnable + TxThreshold + TxEnable + + call set_rx_mode + + set_io 0 + set_io BCR + mov eax, [device.bcrvalue] + out dx, eax + + set_io TCRRCR + mov eax, [device.crvalue] + out dx, eax + + call getlinkstatus + call getlinktype + +; Restart Rx engine if stopped. + + set_io 0 + set_io RXPDR + xor eax, eax + out dx, eax + +; Enable interrupts + + set_io 0 + set_io ISR + mov eax, (FBE or TUNF or CNTOVF or RBU or TI or RI) + out dx, eax + + set_io IMR +; mov eax, (FBE or TUNF or CNTOVF or RBU or TI or RI) + out dx, eax + +; clear packet/byte counters + + xor eax, eax + lea edi, [device.bytes_tx] + mov ecx, 6 + rep stosd + + mov [device.mtu], 1514 + xor eax, eax + + ret + + + + +align 4 +init_ring: + + DEBUGF 1,"initializing rx and tx ring\n" + +; Initialize all Rx descriptors + + lea esi, [device.rx_desc] + mov [device.cur_rx], esi + mov ecx, NUM_RX_DESC + .rx_desc_loop: + mov [esi + mtd_desc.status], RXOWN + mov [esi + mtd_desc.control], 1536 shl RBSShift + + lea eax, [esi + mtd_desc.size] + mov [esi + mtd_desc.next_desc_logical], eax + push ecx esi + GetRealAddr + mov [esi + mtd_desc.next_desc], eax + + stdcall KernelAlloc, 1536 + pop esi + push esi + mov [esi + mtd_desc.skbuff], eax + call GetPgAddr + pop esi ecx + mov [esi + mtd_desc.buffer], eax + + add esi, mtd_desc.size + loop .rx_desc_loop + +; Mark the last entry as wrapping the ring. + + lea eax, [device.rx_desc] + mov [esi - mtd_desc.size + mtd_desc.next_desc_logical], eax + push esi + GetRealAddr + pop esi + mov [esi - mtd_desc.size + mtd_desc.next_desc], eax + + set_io 0 + set_io RXLBA + out dx, eax + +; Initialize all Tx descriptors + + lea esi, [device.tx_desc] + mov [device.cur_tx], esi + mov ecx, NUM_TX_DESC + .tx_desc_loop: + mov [esi + mtd_desc.status], 0 + + lea eax, [esi + mtd_desc.size] + mov [esi + mtd_desc.next_desc_logical], eax + push ecx esi + GetRealAddr + pop esi ecx + mov [esi + mtd_desc.next_desc], eax + + add esi, mtd_desc.size + loop .tx_desc_loop + +; Mark the last entry as wrapping the ring. + + lea eax, [device.tx_desc] + mov [esi - mtd_desc.size + mtd_desc.next_desc_logical], eax + push esi + GetRealAddr + pop esi + mov [esi - mtd_desc.size + mtd_desc.next_desc], eax + + set_io 0 + set_io TXLBA + out dx, eax + + ret + + +align 4 +set_rx_mode: + + DEBUGF 1,"Setting RX mode\n" + +; Too many to match, or accept all multicasts. + + set_io 0 + set_io MAR0 + xor eax, eax + not eax + out dx, eax + set_io MAR1 + out dx, eax + + and [device.crvalue], not (RxModeMask) + or [device.crvalue], AcceptBroadcast + AcceptMulticast + AcceptMyPhys + + ret + + +align 4 +getlinkstatus: + + DEBUGF 1,"Getting link status\n" + + mov [device.linkok], 0 + + cmp [device.PHYType], MysonPHY + jne .no_myson_phy + + set_io 0 + set_io BMCRSR + mov ecx, 1000 + .loop1: + in eax, dx + test eax, LinkIsUp2 + jnz .link_ok + + push ecx edx ebx + mov esi, 10 + call Sleep + pop ebx edx ecx + loop .loop1 + + ret + + .no_myson_phy: + +; for (i equ 0; i < DelayTime; ++i) { +; if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) { +; mtdx.linkok equ 1; +; return; +; } +; m80x_delay(100); + + ret + + .link_ok: + DEBUGF 1,"Link is up\n" + inc [device.linkok] + ret + + + + +align 4 +getlinktype: + + DEBUGF 1,"Getting link type\n" + + cmp [device.PHYType], MysonPHY + jne .no_myson_phy + + DEBUGF 1,"myson PHY\n" + + set_io 0 + set_io TCRRCR + in eax, dx + + mov [device.duplexmode], 1 ; 1 equ half duplex + test eax, FD + jne @f + DEBUGF 1,"full duplex\n" + inc [device.duplexmode] ; 2 equ full duplex + @@: + + mov [device.line_speed], 1 ; 1 equ 10M + test eax, PS10 + jne @f + DEBUGF 1,"100mbit\n" + inc [device.line_speed] ; 2 equ 100M + @@: + + ret + + .no_myson_phy: + + DEBUGF 1,"no myson phy\n" + +; if (mtdx.PHYType equequ SeeqPHY) { /* this PHY is SEEQ 80225 */ +; unsigned int data; +; +; data equ mdio_read(dev, mtdx.phys[0], MIIRegister18); +; if (data & SPD_DET_100) +; mtdx.line_speed equ 2; /* 100M */ +; else +; mtdx.line_speed equ 1; /* 10M */ +; if (data & DPLX_DET_FULL) +; mtdx.duplexmode equ 2; /* full duplex mode */ +; else +; mtdx.duplexmode equ 1; /* half duplex mode */ +; } else if (mtdx.PHYType equequ AhdocPHY) { +; unsigned int data; +; +; data equ mdio_read(dev, mtdx.phys[0], DiagnosticReg); +; if (data & Speed_100) +; mtdx.line_speed equ 2; /* 100M */ +; else +; mtdx.line_speed equ 1; /* 10M */ +; if (data & DPLX_FULL) +; mtdx.duplexmode equ 2; /* full duplex mode */ +; else +; mtdx.duplexmode equ 1; /* half duplex mode */ +; } +; else if (mtdx.PHYType equequ MarvellPHY) { +; unsigned int data; +; +; data equ mdio_read(dev, mtdx.phys[0], SpecificReg); +; if (data & Full_Duplex) +; mtdx.duplexmode equ 2; /* full duplex mode */ +; else +; mtdx.duplexmode equ 1; /* half duplex mode */ +; data &equ SpeedMask; +; if (data equequ Speed_1000M) +; mtdx.line_speed equ 3; /* 1000M */ +; else if (data equequ Speed_100M) +; mtdx.line_speed equ 2; /* 100M */ +; else +; mtdx.line_speed equ 1; /* 10M */ +; } +; else if (mtdx.PHYType equequ Myson981) { +; unsigned int data; +; +; data equ mdio_read(dev, mtdx.phys[0], StatusRegister); +; +; if (data & SPEED100) +; mtdx.line_speed equ 2; +; else +; mtdx.line_speed equ 1; +; +; if (data & FULLMODE) +; mtdx.duplexmode equ 2; +; else +; mtdx.duplexmode equ 1; +; } +; else if (mtdx.PHYType equequ LevelOnePHY) { +; unsigned int data; +; +; data equ mdio_read(dev, mtdx.phys[0], SpecificReg); +; if (data & LXT1000_Full) +; mtdx.duplexmode equ 2; /* full duplex mode */ +; else +; mtdx.duplexmode equ 1; /* half duplex mode */ +; data &equ SpeedMask; +; if (data equequ LXT1000_1000M) +; mtdx.line_speed equ 3; /* 1000M */ +; else if (data equequ LXT1000_100M) +; mtdx.line_speed equ 2; /* 100M */ +; else + ; mtdx.line_speed equ 1; /* 10M */ + ; } + +; // chage crvalue +; // mtdx.crvalue&equ(~PS10)&(~FD); +; mtdx.crvalue &equ (~PS10) & (~FD) & (~PS1000); +; if (mtdx.line_speed equequ 1) +; mtdx.crvalue |equ PS10; +; else if (mtdx.line_speed equequ 3) +; mtdx.crvalue |equ PS1000; +; if (mtdx.duplexmode equequ 2) +; mtdx.crvalue |equ FD; +; + + ret + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Transmit ;; +;; ;; +;; In: buffer pointer in [esp+4] ;; +;; size of buffer in [esp+8] ;; +;; pointer to device structure in ebx ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +transmit: + + DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] + mov eax, [esp+4] + DEBUGF 1,"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 + + mov esi, [device.cur_tx] + push [esi + mtd_desc.next_desc_logical] + pop [device.cur_tx] + + ; todo: check if descriptor is not owned by the device! + + mov eax, [esp + 4] + mov [esi + mtd_desc.skbuff], eax + GetRealAddr + mov [esi + mtd_desc.buffer], eax + + mov eax, [esp + 8] + shl eax, PKTSShift ; packet size + or eax, TXLD + TXFD + CRCEnable + PADEnable + TXIC + 1536 shl TBSShift ; buffer size + mov [esi + mtd_desc.control], eax + + mov [esi + mtd_desc.status], TXOWN + +;------------- +; Update stats + + inc [device.packets_tx] + mov eax, [esp+8] + add dword [device.bytes_tx], eax + adc dword [device.bytes_tx + 4], 0 + +; Point to transmit descriptor + + set_io 0 + set_io TXLBA + mov eax, esi + GetRealAddr + out dx, eax + +; set_io TCRRCR +; mov eax, [device.crvalue] +; out dx, eax + +; Wake the potentially-idle transmit channel. + + set_io TXPDR ; TX Poll + xor eax, eax + out dx, eax + + DEBUGF 1,"transmit ok\n" + xor eax, eax + ret 8 + + .fail: + DEBUGF 1,"transmit failed\n" + or eax, -1 + stdcall KernelFree, [esp + 4] + ret 8 + + + +align 4 +read_mac: + + set_io 0 + set_io PAR0 + lea edi, [device.mac] + insd + stosd + set_io PAR1 + insw + stosw + + 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 + +align 4 +write_mac: + + ret + + + +;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Interrupt handler ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;; + +align 4 +int_handler: + + DEBUGF 1,"\nIRQ %x\n",eax:2 ; no, you cant replace 'eax:2' with 'al', this must be a bug in FDO + +; find pointer of device wich made IRQ occur + + mov ecx, [devices] + test ecx, ecx + jz .fail + mov esi, device_list + .nextdevice: + mov ebx, dword [esi] + + set_io 0 + set_io ISR + in eax, dx + out dx , eax ; send it back to ACK + ; and eax, ; int mask + test eax, eax + jnz .got_it + + .continue: + add esi, 4 + dec ecx + jnz .nextdevice + + ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) + + .got_it: + + DEBUGF 1,"Status=%x\n", eax + + test ax, RI ; receive interrupt + jz .no_rx + + DEBUGF 1,"Receive interrupt\n" + .rx: + push ax + + .rx_loop: + mov esi, [device.cur_rx] + + test [esi + mtd_desc.status], RXOWN + jnz .fail_rx + + push .rx_complete + + mov ecx, [esi + mtd_desc.status] + shr ecx, FLNGShift + sub ecx, 4 ; we dont need CRC + push ecx + +;------------- +; Update stats + + add dword [device.bytes_rx], ecx + adc dword [device.bytes_rx + 4], 0 + inc dword [device.packets_rx] + + + push [esi + mtd_desc.skbuff] + + jmp EthReceiver + + .rx_complete: + mov esi, [device.cur_rx] + + mov [esi + mtd_desc.control], 1536 shl RBSShift + + stdcall KernelAlloc, 1536 + mov [esi + mtd_desc.skbuff], eax + call GetPgAddr + mov [esi + mtd_desc.buffer], eax + + mov [esi + mtd_desc.status], RXOWN + + mov eax, [esi + mtd_desc.next_desc_logical] + mov [device.cur_rx], eax + + jmp .rx_loop +; +; while( ( mtdx.cur_rx->status & RXOWN ) == 0 ) +; { +; mtdx.cur_rx->status = RXOWN; +; mtdx.cur_rx = mtdx.cur_rx->next_desc_logical; +; } +; +; /* Restart Rx engine if stopped. */ +; outl(0, mtdx.ioaddr + RXPDR); + + .fail_rx: + DEBUGF 1,"RX failed\n" + + pop ax + .no_rx: + + test ax, TI ; transmit interrupt + jz .no_tx + + DEBUGF 1,"Transmit interrupt\n" + push ax + + lea esi, [device.tx_desc] + mov ecx, NUM_TX_DESC + .tx_loop: + + test [esi + mtd_desc.status], TXOWN + jnz .skip_this_one + + mov eax, [esi + mtd_desc.skbuff] + test eax, eax + je .skip_this_one + + mov [esi + mtd_desc.skbuff], 0 + + DEBUGF 1,"freeing buffer:%x\n", eax + stdcall KernelFree, eax + + .skip_this_one: + mov esi, [esi + mtd_desc.next_desc_logical] + loop .tx_loop + + pop ax + + .no_tx: + + test ax, TBU + jz .no_tbu + + DEBUGF 1,"Transmit buffer unavailable!\n" + + .no_tbu: + + .fail: + + ret + + +; End of code + +align 4 ; Place all initialised data here + +devices dd 0 +version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) +my_service db 'mtd80x',0 ; max 16 chars include zero + + +; 0x1516, 0x0800, "MTD800", "Myson MTD800" +; 0x1516, 0x0803, "MTD803", "Surecom EP-320X" +; 0x1516, 0x0891, "MTD891", "Myson MTD891" + + +include_debug_strings ; All data wich FDO uses will be included here + +section '.data' data readable writable align 16 ; place all uninitialized data place here + +device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling + +