92f657f440
git-svn-id: svn://kolibrios.org@593 a494cfbc-eb01-0410-851d-a64ba20cac60
2391 lines
79 KiB
PHP
2391 lines
79 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
$Revision$
|
|
|
|
|
|
;; Copyright (c) 2004, Endre Kozma <endre.kozma@axelero.hu>
|
|
;; All rights reserved.
|
|
;;
|
|
;; Redistribution and use in source and binary forms, with or without
|
|
;; modification, are permitted provided that the following conditions are
|
|
;; met:
|
|
;;
|
|
;; 1. Redistributions of source code must retain the above copyright notice,
|
|
;; this list of conditions and the following disclaimer.
|
|
;;
|
|
;; 2. Redistributions in binary form must reproduce the above copyright
|
|
;; notice, this list of conditions and the following disclaimer in the
|
|
;; documentation and/or other materials provided with the distribution.
|
|
;;
|
|
;; 3. The name of the author may not be used to endorse or promote products
|
|
;; derived from this software without specific prior written permission.
|
|
;;
|
|
;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
;; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; 3C59X.INC ;;
|
|
;; ;;
|
|
;; Ethernet driver for Menuet OS ;;
|
|
;; ;;
|
|
;; Driver for 3Com fast etherlink 3c59x and ;;
|
|
;; etherlink XL 3c900 and 3c905 cards ;;
|
|
;; References: ;;
|
|
;; www.3Com.com - data sheets ;;
|
|
;; DP83840A.pdf - ethernet physical layer ;;
|
|
;; 3c59x.c - linux driver ;;
|
|
;; ethernet driver template by Mike Hibbett ;;
|
|
;; ;;
|
|
;; Credits ;;
|
|
;; Mike Hibbett, ;;
|
|
;; who kindly supplied me with a 3Com905C-TX-M card ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; History
|
|
;; =======
|
|
;; $Log: 3C59X.INC,v $
|
|
;; Revision 1.3 2004/07/11 12:21:12 kozma
|
|
;; Support of vortex chips (3c59x) added.
|
|
;; Support of 3c920 and 3c982 added.
|
|
;; Corrections.
|
|
;;
|
|
;; Revision 1.2 2004/06/12 19:40:20 kozma
|
|
;; Function e3c59x_set_available_media added in order to set
|
|
;; the default media in case auto detection finds no valid link.
|
|
;; Incorrect mii check removed (3c900 Cyclone works now).
|
|
;; Cleanups.
|
|
;;
|
|
;; Revision 1.1 2004/06/12 18:27:15 kozma
|
|
;; Initial revision
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
; comment the next line out if you don't want debug info printed
|
|
; on the debug board. This option adds a lot of bytes to the driver
|
|
; so it's worth to comment it out.
|
|
; E3C59X_DEBUG equ 1
|
|
|
|
; forcing full duplex mode makes sense at some cards and link types
|
|
E3C59X_FORCE_FD equ 1
|
|
|
|
macro virt_to_dma reg
|
|
{
|
|
if defined E3C59X_LINUX
|
|
sub reg, [virt_addr]
|
|
add reg, [dma_addr]
|
|
end if
|
|
}
|
|
|
|
macro dma_to_virt reg
|
|
{
|
|
if defined E3C59X_LINUX
|
|
sub reg, [dma_addr]
|
|
add reg, [virt_addr]
|
|
end if
|
|
}
|
|
|
|
macro zero_to_virt reg
|
|
{
|
|
if defined E3C59X_LINUX
|
|
add reg, [virt_addr]
|
|
end if
|
|
}
|
|
|
|
macro virt_to_zero reg
|
|
{
|
|
if defined E3C59X_LINUX
|
|
sub reg, [virt_addr]
|
|
end if
|
|
}
|
|
|
|
macro zero_to_dma reg
|
|
{
|
|
if defined E3C59X_LINUX
|
|
add reg, [dma_addr]
|
|
end if
|
|
}
|
|
|
|
macro dma_to_zero reg
|
|
{
|
|
if defined E3C59X_LINUX
|
|
sub reg, [dma_addr]
|
|
end if
|
|
}
|
|
|
|
macro strtbl name, [string]
|
|
{
|
|
common
|
|
label name dword
|
|
forward
|
|
local label
|
|
dd label
|
|
forward
|
|
label db string, 0
|
|
}
|
|
|
|
; Ethernet frame symbols
|
|
ETH_ALEN equ 6
|
|
ETH_HLEN equ (2*ETH_ALEN+2)
|
|
ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for
|
|
; mininmum 64bytes frame length
|
|
; PCI programming
|
|
PCI_REG_COMMAND equ 0x4 ; command register
|
|
PCI_REG_STATUS equ 0x6 ; status register
|
|
PCI_REG_LATENCY equ 0xd ; latency timer register
|
|
PCI_REG_CAP_PTR equ 0x34 ; capabilities pointer
|
|
PCI_REG_CAPABILITY_ID equ 0x0 ; capapility ID in pm register block
|
|
PCI_REG_PM_STATUS equ 0x4 ; power management status register
|
|
PCI_REG_PM_CTRL equ 0x4 ; power management control register
|
|
PCI_BIT_PIO equ 0 ; bit0: io space control
|
|
PCI_BIT_MMIO equ 1 ; bit1: memory space control
|
|
PCI_BIT_MASTER equ 2 ; bit2: device acts as a PCI master
|
|
; Registers
|
|
E3C59X_REG_POWER_MGMT_CTRL equ 0x7c
|
|
E3C59X_REG_UP_LIST_PTR equ 0x38
|
|
E3C59X_REG_UP_PKT_STATUS equ 0x30
|
|
E3C59X_REG_TX_FREE_THRESH equ 0x2f
|
|
E3C59X_REG_DN_LIST_PTR equ 0x24
|
|
E3C59X_REG_DMA_CTRL equ 0x20
|
|
E3C59X_REG_TX_STATUS equ 0x1b
|
|
E3C59X_REG_RX_STATUS equ 0x18
|
|
E3C59X_REG_TX_DATA equ 0x10
|
|
; Common window registers
|
|
E3C59X_REG_INT_STATUS equ 0xe
|
|
E3C59X_REG_COMMAND equ 0xe
|
|
; Register window 7
|
|
E3C59X_REG_MASTER_STATUS equ 0xc
|
|
E3C59X_REG_POWER_MGMT_EVENT equ 0xc
|
|
E3C59X_REG_MASTER_LEN equ 0x6
|
|
E3C59X_REG_VLAN_ETHER_TYPE equ 0x4
|
|
E3C59X_REG_VLAN_MASK equ 0x0
|
|
E3C59X_REG_MASTER_ADDRESS equ 0x0
|
|
; Register window 6
|
|
E3C59X_REG_BYTES_XMITTED_OK equ 0xc
|
|
E3C59X_REG_BYTES_RCVD_OK equ 0xa
|
|
E3C59X_REG_UPPER_FRAMES_OK equ 0x9
|
|
E3C59X_REG_FRAMES_DEFERRED equ 0x8
|
|
E3C59X_REG_FRAMES_RCVD_OK equ 0x7
|
|
E3C59X_REG_FRAMES_XMITTED_OK equ 0x6
|
|
E3C59X_REG_RX_OVERRUNS equ 0x5
|
|
E3C59X_REG_LATE_COLLISIONS equ 0x4
|
|
E3C59X_REG_SINGLE_COLLISIONS equ 0x3
|
|
E3C59X_REG_MULTIPLE_COLLISIONS equ 0x2
|
|
E3C59X_REG_SQE_ERRORS equ 0x1
|
|
E3C59X_REG_CARRIER_LOST equ 0x0
|
|
; Register window 5
|
|
E3C59X_REG_INDICATION_ENABLE equ 0xc
|
|
E3C59X_REG_INTERRUPT_ENABLE equ 0xa
|
|
E3C59X_REG_TX_RECLAIM_THRESH equ 0x9
|
|
E3C59X_REG_RX_FILTER equ 0x8
|
|
E3C59X_REG_RX_EARLY_THRESH equ 0x6
|
|
E3C59X_REG_TX_START_THRESH equ 0x0
|
|
; Register window 4
|
|
E3C59X_REG_UPPER_BYTES_OK equ 0xe
|
|
E3C59X_REG_BAD_SSD equ 0xc
|
|
E3C59X_REG_MEDIA_STATUS equ 0xa
|
|
E3C59X_REG_PHYSICAL_MGMT equ 0x8
|
|
E3C59X_REG_NETWORK_DIAGNOSTIC equ 0x6
|
|
E3C59X_REG_FIFO_DIAGNOSTIC equ 0x4
|
|
E3C59X_REG_VCO_DIAGNOSTIC equ 0x2 ; may not supported
|
|
; Bits in register window 4
|
|
E3C59X_BIT_AUTOSELECT equ 24
|
|
; Register window 3
|
|
E3C59X_REG_TX_FREE equ 0xc
|
|
E3C59X_REG_RX_FREE equ 0xa
|
|
E3C59X_REG_MEDIA_OPTIONS equ 0x8
|
|
E3C59X_REG_MAC_CONTROL equ 0x6
|
|
E3C59X_REG_MAX_PKT_SIZE equ 0x4
|
|
E3C59X_REG_INTERNAL_CONFIG equ 0x0
|
|
; Register window 2
|
|
E3C59X_REG_RESET_OPTIONS equ 0xc
|
|
E3C59X_REG_STATION_MASK_HI equ 0xa
|
|
E3C59X_REG_STATION_MASK_MID equ 0x8
|
|
E3C59X_REG_STATION_MASK_LO equ 0x6
|
|
E3C59X_REG_STATION_ADDRESS_HI equ 0x4
|
|
E3C59X_REG_STATION_ADDRESS_MID equ 0x2
|
|
E3C59X_REG_STATION_ADDRESS_LO equ 0x0
|
|
; Register window 1
|
|
E3C59X_REG_TRIGGER_BITS equ 0xc
|
|
E3C59X_REG_SOS_BITS equ 0xa
|
|
E3C59X_REG_WAKE_ON_TIMER equ 0x8
|
|
E3C59X_REG_SMB_RXBYTES equ 0x7
|
|
E3C59X_REG_SMB_DIAG equ 0x5
|
|
E3C59X_REG_SMB_ARB equ 0x4
|
|
E3C59X_REG_SMB_STATUS equ 0x2
|
|
E3C59X_REG_SMB_ADDRESS equ 0x1
|
|
E3C59X_REG_SMB_FIFO_DATA equ 0x0
|
|
; Register window 0
|
|
E3C59X_REG_EEPROM_DATA equ 0xc
|
|
E3C59X_REG_EEPROM_COMMAND equ 0xa
|
|
E3C59X_REG_BIOS_ROM_DATA equ 0x8
|
|
E3C59X_REG_BIOS_ROM_ADDR equ 0x4
|
|
; Physical management bits
|
|
E3C59X_BIT_MGMT_DIR equ 2 ; drive with the data written in mgmtData
|
|
E3C59X_BIT_MGMT_DATA equ 1 ; MII management data bit
|
|
E3C59X_BIT_MGMT_CLK equ 0 ; MII management clock
|
|
; MII commands
|
|
E3C59X_MII_CMD_MASK equ (1111b shl 10)
|
|
E3C59X_MII_CMD_READ equ (0110b shl 10)
|
|
E3C59X_MII_CMD_WRITE equ (0101b shl 10)
|
|
; MII registers
|
|
E3C59X_REG_MII_BMCR equ 0 ; basic mode control register
|
|
E3C59X_REG_MII_BMSR equ 1 ; basic mode status register
|
|
E3C59X_REG_MII_ANAR equ 4 ; auto negotiation advertisement register
|
|
E3C59X_REG_MII_ANLPAR equ 5 ; auto negotiation link partner ability register
|
|
E3C59X_REG_MII_ANER equ 6 ; auto negotiation expansion register
|
|
; MII bits
|
|
E3C59X_BIT_MII_AUTONEG_COMPLETE equ 5 ; auto-negotiation complete
|
|
E3C59X_BIT_MII_PREAMBLE_SUPPRESSION equ 6
|
|
; eeprom bits and commands
|
|
E3C59X_EEPROM_CMD_READ equ 0x80
|
|
E3C59X_EEPROM_BIT_BUSY equ 15
|
|
; eeprom registers
|
|
E3C59X_EEPROM_REG_OEM_NODE_ADDR equ 0xa
|
|
E3C59X_EEPROM_REG_CAPABILITIES equ 0x10
|
|
; Commands for command register
|
|
E3C59X_SELECT_REGISTER_WINDOW equ (1 shl 11)
|
|
|
|
IS_VORTEX equ 0x1
|
|
IS_BOOMERANG equ 0x2
|
|
IS_CYCLONE equ 0x4
|
|
IS_TORNADO equ 0x8
|
|
EEPROM_8BIT equ 0x10
|
|
HAS_PWR_CTRL equ 0x20
|
|
HAS_MII equ 0x40
|
|
HAS_NWAY equ 0x80
|
|
HAS_CB_FNS equ 0x100
|
|
INVERT_MII_PWR equ 0x200
|
|
INVERT_LED_PWR equ 0x400
|
|
MAX_COLLISION_RESET equ 0x800
|
|
EEPROM_OFFSET equ 0x1000
|
|
HAS_HWCKSM equ 0x2000
|
|
EXTRA_PREAMBLE equ 0x4000
|
|
|
|
iglobal
|
|
align 4
|
|
e3c59x_hw_versions:
|
|
dw 0x5900, IS_VORTEX ; 3c590 Vortex 10Mbps
|
|
dw 0x5920, IS_VORTEX ; 3c592 EISA 10Mbps Demon/Vortex
|
|
dw 0x5970, IS_VORTEX ; 3c597 EISA Fast Demon/Vortex
|
|
dw 0x5950, IS_VORTEX ; 3c595 Vortex 100baseTx
|
|
dw 0x5951, IS_VORTEX ; 3c595 Vortex 100baseT4
|
|
dw 0x5952, IS_VORTEX ; 3c595 Vortex 100base-MII
|
|
dw 0x9000, IS_BOOMERANG ; 3c900 Boomerang 10baseT
|
|
dw 0x9001, IS_BOOMERANG ; 3c900 Boomerang 10Mbps Combo
|
|
dw 0x9004, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPO
|
|
dw 0x9005, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps Combo
|
|
dw 0x9006, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPC
|
|
dw 0x900A, IS_CYCLONE or HAS_HWCKSM ; 3c900B-FL Cyclone 10base-FL
|
|
dw 0x9050, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseTx
|
|
dw 0x9051, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseT4
|
|
dw 0x9055, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B Cyclone 100baseTx
|
|
dw 0x9058, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c905B Cyclone 10/100/BNC
|
|
dw 0x905A, IS_CYCLONE or HAS_HWCKSM ; 3c905B-FX Cyclone 100baseFx
|
|
dw 0x9200, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c905C Tornado
|
|
dw 0x9800, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c980 Cyclone
|
|
dw 0x9805, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c982 Dual Port Server Cyclone
|
|
dw 0x7646, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3cSOHO100-TX Hurricane
|
|
dw 0x5055, IS_CYCLONE or EEPROM_8BIT or HAS_HWCKSM ; 3c555 Laptop Hurricane
|
|
dw 0x6055, IS_TORNADO or HAS_NWAY or EEPROM_8BIT or HAS_CB_FNS \
|
|
or INVERT_MII_PWR or HAS_HWCKSM ; 3c556 Laptop Tornado
|
|
dw 0x6056, IS_TORNADO or HAS_NWAY or EEPROM_OFFSET or HAS_CB_FNS \
|
|
or INVERT_MII_PWR or HAS_HWCKSM ; 3c556B Laptop Hurricane
|
|
dw 0x5b57, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 [Megahertz] 10/100 LAN CardBus
|
|
dw 0x5057, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 Boomerang CardBus
|
|
dw 0x5157, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT \
|
|
or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE575BT Cyclone CardBus
|
|
dw 0x5257, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \
|
|
or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CCFE575CT Tornado CardBus
|
|
dw 0x6560, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \
|
|
or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE656 Cyclone CardBus
|
|
dw 0x6562, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \
|
|
or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFEM656B Cyclone+Winmodem CardBus
|
|
dw 0x6564, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \
|
|
or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CXFEM656C Tornado+Winmodem CardBus
|
|
dw 0x4500, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c450 HomePNA Tornado
|
|
dw 0x9201, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920 Tornado
|
|
dw 0x1201, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port A
|
|
dw 0x1202, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port B
|
|
dw 0x9056, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B-T4
|
|
dw 0x9210, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920B-EMB-WNM Tornado
|
|
E3C59X_HW_VERSIONS_SIZE= $-e3c59x_hw_versions
|
|
endg
|
|
|
|
; RX/TX buffers sizes
|
|
E3C59X_MAX_ETH_PKT_SIZE equ 1536 ; max packet size
|
|
E3C59X_NUM_RX_DESC equ 4 ; a power of 2 number
|
|
E3C59X_NUM_TX_DESC equ 4 ; a power of 2 number
|
|
E3C59X_RX_BUFFER_SIZE equ (E3C59X_MAX_ETH_FRAME_SIZE*E3C59X_NUM_RX_DESC)
|
|
E3C59X_TX_BUFFER_SIZE equ (E3C59X_MAX_ETH_FRAME_SIZE*E3C59X_NUM_TX_DESC)
|
|
; Download Packet Descriptor
|
|
E3C59X_DPD_DN_NEXT_PTR equ 0
|
|
E3C59X_DPD_FRAME_START_HDR equ 4
|
|
E3C59X_DPD_DN_FRAG_ADDR equ 8 ; for packet data
|
|
E3C59X_DPD_DN_FRAG_LEN equ 12 ; for packet data
|
|
E3C59X_DPD_SIZE equ 16 ; a power of 2 number
|
|
; Upload Packet Descriptor
|
|
E3C59X_UPD_UP_NEXT_PTR equ 0
|
|
E3C59X_UPD_PKT_STATUS equ 4
|
|
E3C59X_UPD_UP_FRAG_ADDR equ 8 ; for packet data
|
|
E3C59X_UPD_UP_FRAG_LEN equ 12 ; for packet data
|
|
E3C59X_UPD_SIZE equ 16
|
|
|
|
; RX/TX buffers
|
|
if defined E3C59X_LINUX
|
|
E3C59X_MAX_ETH_FRAME_SIZE = 160 ; size of ethernet frame + bytes alignment
|
|
e3c59x_rx_buff = 0
|
|
else
|
|
E3C59X_MAX_ETH_FRAME_SIZE = 1520 ; size of ethernet frame + bytes alignment
|
|
e3c59x_rx_buff = eth_data_start
|
|
end if
|
|
|
|
e3c59x_tx_buff = e3c59x_rx_buff+E3C59X_RX_BUFFER_SIZE
|
|
e3c59x_dpd_buff = e3c59x_tx_buff+E3C59X_TX_BUFFER_SIZE
|
|
e3c59x_upd_buff = e3c59x_dpd_buff+(E3C59X_DPD_SIZE*E3C59X_NUM_TX_DESC)
|
|
|
|
uglobal
|
|
e3c59x_curr_upd: dd 0
|
|
e3c59x_prev_dpd: dd 0
|
|
e3c59x_prev_tx_frame: dd 0
|
|
e3c59x_transmit_function: dd 0
|
|
e3c59x_receive_function: dd 0
|
|
endg
|
|
|
|
iglobal
|
|
e3c59x_ver_id: db 17
|
|
endg
|
|
uglobal
|
|
e3c59x_full_bus_master: db 0
|
|
e3c59x_has_hwcksm: db 0
|
|
e3c59x_preamble: db 0
|
|
e3c59x_dn_list_ptr_cleared: db 0
|
|
e3c59x_self_directed_packet: rb 6
|
|
endg
|
|
|
|
if defined E3C59X_DEBUG
|
|
e3c59x_hw_type_str: db "Detected hardware type : ", 0
|
|
e3c59x_device_str: db "Device ID : 0x"
|
|
e3c59x_device_id_str: db "ffff", 13, 10, 0
|
|
e3c59x_vendor_str: db "Vendor ID : 0x"
|
|
e3c59x_vendor_id_str: db "ffff", 13, 10, 0
|
|
e3c59x_io_info_str: db "IO address : 0x"
|
|
e3c59x_io_addr_str: db "ffff", 13, 10, 0
|
|
e3c59x_mac_info_str: db "MAC address : "
|
|
e3c59x_mac_addr_str: db "ff:ff:ff:ff:ff:ff", 13, 10, 0
|
|
e3c59x_boomerang_str: db " (boomerang)", 13, 10, 0
|
|
e3c59x_vortex_str: db " (vortex)", 13, 10, 0
|
|
e3c59x_link_type_str: db "Established link type : ", 0
|
|
e3c59x_new_line_str: db 13, 10, 0
|
|
e3c59x_link_type: dd 0
|
|
|
|
e3c59x_charset: db '0123456789abcdef'
|
|
|
|
strtbl e3c59x_link_str, \
|
|
"No valid link type detected", \
|
|
"10BASE-T half duplex", \
|
|
"10BASE-T full-duplex", \
|
|
"100BASE-TX half duplex", \
|
|
"100BASE-TX full duplex", \
|
|
"100BASE-T4", \
|
|
"100BASE-FX", \
|
|
"10Mbps AUI", \
|
|
"10Mbps COAX (BNC)", \
|
|
"miiDevice - not supported"
|
|
|
|
strtbl e3c59x_hw_str, \
|
|
"3c590 Vortex 10Mbps", \
|
|
"3c592 EISA 10Mbps Demon/Vortex", \
|
|
"3c597 EISA Fast Demon/Vortex", \
|
|
"3c595 Vortex 100baseTx", \
|
|
"3c595 Vortex 100baseT4", \
|
|
"3c595 Vortex 100base-MII", \
|
|
"3c900 Boomerang 10baseT", \
|
|
"3c900 Boomerang 10Mbps Combo", \
|
|
"3c900 Cyclone 10Mbps TPO", \
|
|
"3c900 Cyclone 10Mbps Combo", \
|
|
"3c900 Cyclone 10Mbps TPC", \
|
|
"3c900B-FL Cyclone 10base-FL", \
|
|
"3c905 Boomerang 100baseTx", \
|
|
"3c905 Boomerang 100baseT4", \
|
|
"3c905B Cyclone 100baseTx", \
|
|
"3c905B Cyclone 10/100/BNC", \
|
|
"3c905B-FX Cyclone 100baseFx", \
|
|
"3c905C Tornado", \
|
|
"3c980 Cyclone", \
|
|
"3c982 Dual Port Server Cyclone", \
|
|
"3cSOHO100-TX Hurricane", \
|
|
"3c555 Laptop Hurricane", \
|
|
"3c556 Laptop Tornado", \
|
|
"3c556B Laptop Hurricane", \
|
|
"3c575 [Megahertz] 10/100 LAN CardBus", \
|
|
"3c575 Boomerang CardBus", \
|
|
"3CCFE575BT Cyclone CardBus", \
|
|
"3CCFE575CT Tornado CardBus", \
|
|
"3CCFE656 Cyclone CardBus", \
|
|
"3CCFEM656B Cyclone+Winmodem CardBus", \
|
|
"3CXFEM656C Tornado+Winmodem CardBus", \
|
|
"3c450 HomePNA Tornado", \
|
|
"3c920 Tornado", \
|
|
"3c982 Hydra Dual Port A", \
|
|
"3c982 Hydra Dual Port B", \
|
|
"3c905B-T4", \
|
|
"3c920B-EMB-WNM Tornado"
|
|
|
|
end if ; defined E3C59X_DEBUG
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_debug
|
|
; Description
|
|
; prints debug info to the debug board
|
|
; Parameters
|
|
; ebp - io_addr
|
|
; Return value
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
if defined E3C59X_DEBUG
|
|
align 4
|
|
e3c59x_debug:
|
|
pushad
|
|
; print device type
|
|
mov esi, e3c59x_hw_type_str
|
|
call sys_msg_board_str
|
|
movzx ecx, byte [e3c59x_ver_id]
|
|
mov esi, [e3c59x_hw_str+ecx*4]
|
|
call sys_msg_board_str
|
|
mov esi, e3c59x_boomerang_str
|
|
cmp dword [e3c59x_transmit_function], e3c59x_boomerang_transmit
|
|
jz .boomerang
|
|
mov esi, e3c59x_vortex_str
|
|
.boomerang:
|
|
call sys_msg_board_str
|
|
; print device/vendor
|
|
mov ax, [pci_data+2]
|
|
mov cl, 2
|
|
mov ebx, e3c59x_device_id_str
|
|
call e3c59x_print_hex
|
|
mov esi, e3c59x_device_str
|
|
call sys_msg_board_str
|
|
mov ax, [pci_data]
|
|
mov cl, 2
|
|
mov ebx, e3c59x_vendor_id_str
|
|
call e3c59x_print_hex
|
|
mov esi, e3c59x_vendor_str
|
|
call sys_msg_board_str
|
|
; print io address
|
|
mov ax, [io_addr]
|
|
mov ebx, e3c59x_io_addr_str
|
|
mov cl, 2
|
|
call e3c59x_print_hex
|
|
mov esi, e3c59x_io_info_str
|
|
call sys_msg_board_str
|
|
; print MAC address
|
|
mov ebx, e3c59x_mac_addr_str
|
|
xor ecx, ecx
|
|
.mac_loop:
|
|
push ecx
|
|
mov al, [node_addr+ecx]
|
|
mov cl, 1
|
|
call e3c59x_print_hex
|
|
inc ebx
|
|
pop ecx
|
|
inc cl
|
|
cmp cl, 6
|
|
jne .mac_loop
|
|
mov esi, e3c59x_mac_info_str
|
|
call sys_msg_board_str
|
|
; print link type
|
|
mov esi, e3c59x_link_type_str
|
|
call sys_msg_board_str
|
|
xor eax, eax
|
|
bsr ax, word [e3c59x_link_type]
|
|
jz @f
|
|
sub ax, 4
|
|
@@:
|
|
mov esi, [e3c59x_link_str+eax*4]
|
|
call sys_msg_board_str
|
|
mov esi, e3c59x_new_line_str
|
|
call sys_msg_board_str
|
|
popad
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_print_hex
|
|
; Description
|
|
; prints a hexadecimal value
|
|
; Parameters
|
|
; eax - value to be printed out
|
|
; ebx - where to print
|
|
; cl - value size (1, 2, 4)
|
|
; Return value
|
|
; ebx - end address after the print
|
|
; Destroyed registers
|
|
; eax, ebx
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_print_hex:
|
|
cmp cl, 1
|
|
je .print_byte
|
|
cmp cl, 2
|
|
jz .print_word
|
|
.print_dword:
|
|
push eax
|
|
bswap eax
|
|
xchg ah, al
|
|
call .print_word
|
|
pop eax
|
|
.print_word:
|
|
push eax
|
|
xchg ah, al
|
|
call .print_byte
|
|
pop eax
|
|
.print_byte:
|
|
movzx eax, al
|
|
push eax
|
|
and al, 0xf0
|
|
shr al, 4
|
|
mov al, byte [eax+e3c59x_charset]
|
|
mov [ebx], al
|
|
inc ebx
|
|
pop eax
|
|
and al, 0x0f
|
|
mov al, byte [eax+e3c59x_charset]
|
|
mov [ebx], al
|
|
inc ebx
|
|
ret
|
|
end if ; defined E3C59X_DEBUG
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_try_link_detect
|
|
; Description
|
|
; e3c59x_try_link_detect checks if link exists
|
|
; Parameters
|
|
; ebp - io_addr
|
|
; Return value
|
|
; al - 0 ; no link detected
|
|
; al - 1 ; link detected
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_try_link_detect:
|
|
; download self-directed packet
|
|
mov edi, node_addr
|
|
mov bx, 0x0608 ; packet type
|
|
mov esi, e3c59x_self_directed_packet
|
|
mov ecx, 6 ; 6 + 6 + 2 + 6 = 20 bytes
|
|
call dword [e3c59x_transmit_function]
|
|
; switch to register window 5
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+5
|
|
out dx, ax
|
|
; program RxFilter for promiscuous operation
|
|
mov ax, (10000b shl 11)
|
|
lea edx, [ebp+E3C59X_REG_RX_FILTER]
|
|
in al, dx
|
|
or al, 1111b
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
out dx, ax
|
|
; switch to register window 4
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+4
|
|
out dx, ax
|
|
; check loop
|
|
xor ebx, ebx
|
|
mov ecx, 0xffff ; 65535 tries
|
|
.loop:
|
|
push ecx ebx
|
|
call dword [e3c59x_receive_function]
|
|
pop ebx ecx
|
|
test al, al
|
|
jnz .finish
|
|
.no_packet_received:
|
|
; switch to register window 4
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+4
|
|
out dx, ax
|
|
; read linkbeatdetect
|
|
lea edx, [ebp+E3C59X_REG_MEDIA_STATUS]
|
|
in ax, dx
|
|
test ah, 1000b ; test linkBeatDetect
|
|
jnz .link_detected
|
|
xor al, al
|
|
jmp .finish
|
|
.link_detected:
|
|
; test carrierSense
|
|
test al, 100000b
|
|
jz .no_carrier_sense
|
|
inc ebx
|
|
.no_carrier_sense:
|
|
dec ecx
|
|
jns .loop
|
|
; assume the link is good if 0 < ebx < 25 %
|
|
test ebx, ebx
|
|
setnz al
|
|
jz .finish
|
|
cmp ebx, 16384 ; 25%
|
|
setb al
|
|
.finish:
|
|
if defined E3C59X_DEBUG
|
|
test al, al
|
|
jz @f
|
|
or byte [e3c59x_link_type+1], 100b
|
|
@@:
|
|
end if ; defined E3C59X_DEBUG
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_try_phy
|
|
; Description
|
|
; e3c59x_try_phy checks the auto-negotiation function
|
|
; in the PHY at PHY index. It can also be extended to
|
|
; include link detection for non-IEEE 802.3u
|
|
; auto-negotiation devices, for instance the BCM5000.
|
|
; Parameters
|
|
; ah - PHY index
|
|
; ebp - io_addr
|
|
; Return value
|
|
; al - 0 link is auto-negotiated
|
|
; al - 1 no link is auto-negotiated
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_try_phy:
|
|
mov al, E3C59X_REG_MII_BMCR
|
|
push eax
|
|
call e3c59x_mdio_read ; returns with window #4
|
|
or ah, 0x80 ; software reset
|
|
mov ebx, eax
|
|
pop eax
|
|
push eax
|
|
call e3c59x_mdio_write ; returns with window #4
|
|
; wait for reset to complete
|
|
mov esi, 2000 ; 2000ms = 2s
|
|
call delay_ms
|
|
pop eax
|
|
push eax
|
|
call e3c59x_mdio_read ; returns with window #4
|
|
test ah, 0x80
|
|
jnz .fail_finish
|
|
pop eax
|
|
push eax
|
|
; wait for a while after reset
|
|
mov esi, 20 ; 20ms
|
|
call delay_ms
|
|
pop eax
|
|
push eax
|
|
mov al, E3C59X_REG_MII_BMSR
|
|
call e3c59x_mdio_read ; returns with window #4
|
|
test al, 1 ; extended capability supported?
|
|
jz .no_ext_cap
|
|
; auto-neg capable?
|
|
test al, 1000b
|
|
jz .fail_finish ; not auto-negotiation capable
|
|
; auto-neg complete?
|
|
test al, 100000b
|
|
jnz .auto_neg_ok
|
|
; restart auto-negotiation
|
|
pop eax
|
|
push eax
|
|
mov al, E3C59X_REG_MII_ANAR
|
|
push eax
|
|
call e3c59x_mdio_read ; returns with window #4
|
|
or ax, (1111b shl 5) ; advertise only 10base-T and 100base-TX
|
|
mov ebx, eax
|
|
pop eax
|
|
call e3c59x_mdio_write ; returns with window #4
|
|
pop eax
|
|
push eax
|
|
call e3c59x_mdio_read ; returns with window #4
|
|
mov ebx, eax
|
|
or bh, 10010b ; restart auto-negotiation
|
|
pop eax
|
|
push eax
|
|
call e3c59x_mdio_write ; returns with window #4
|
|
mov esi, 4000 ; 4000ms = 4 seconds
|
|
call delay_ms
|
|
pop eax
|
|
push eax
|
|
mov al, E3C59X_REG_MII_BMSR
|
|
call e3c59x_mdio_read ; returns with window #4
|
|
test al, 100000b ; auto-neg complete?
|
|
jnz .auto_neg_ok
|
|
jmp .fail_finish
|
|
.auto_neg_ok:
|
|
; compare advertisement and link partner ability registers
|
|
pop eax
|
|
push eax
|
|
mov al, E3C59X_REG_MII_ANAR
|
|
call e3c59x_mdio_read ; returns with window #4
|
|
xchg eax, [esp]
|
|
mov al, E3C59X_REG_MII_ANLPAR
|
|
call e3c59x_mdio_read ; returns with window #4
|
|
pop ebx
|
|
and eax, ebx
|
|
and eax, 1111100000b
|
|
push eax
|
|
if defined E3C59X_DEBUG
|
|
mov word [e3c59x_link_type], ax
|
|
end if ; defined E3C59X_DEBUG
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
; set full-duplex mode
|
|
lea edx, [ebp+E3C59X_REG_MAC_CONTROL]
|
|
in ax, dx
|
|
and ax, not 0x120 ; clear full duplex and flow control
|
|
pop ebx
|
|
test ebx, (1010b shl 5) ; check for full-duplex
|
|
jz .half_duplex
|
|
or ax, 0x120 ; set full duplex and flow control
|
|
.half_duplex:
|
|
out dx, ax
|
|
mov al, 1
|
|
ret
|
|
.no_ext_cap:
|
|
; not yet implemented BCM5000
|
|
.fail_finish:
|
|
pop eax
|
|
xor al, al
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_try_mii
|
|
; Description
|
|
; e3c59x_try_MII checks the on-chip auto-negotiation logic
|
|
; or an off-chip MII PHY, depending upon what is set in
|
|
; xcvrSelect by the caller.
|
|
; It exits when it finds the first device with a good link.
|
|
; Parameters
|
|
; ebp - io_addr
|
|
; Return value
|
|
; al - 0
|
|
; al - 1
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_try_mii:
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
in eax, dx
|
|
and eax, (1111b shl 20)
|
|
cmp eax, (1000b shl 20) ; is auto-negotiation set?
|
|
jne .mii_device
|
|
; auto-negotiation is set
|
|
; switch to register window 4
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+4
|
|
out dx, ax
|
|
; PHY==24 is the on-chip auto-negotiation logic
|
|
; it supports only 10base-T and 100base-TX
|
|
mov ah, 24
|
|
call e3c59x_try_phy
|
|
test al, al
|
|
jz .fail_finish
|
|
mov cl, 24
|
|
jmp .check_preamble
|
|
.mii_device:
|
|
cmp eax, (0110b shl 20)
|
|
jne .fail_finish
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+4
|
|
out dx, ax
|
|
lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT]
|
|
in ax, dx
|
|
and al, (1 shl E3C59X_BIT_MGMT_DIR) or (1 shl E3C59X_BIT_MGMT_DATA)
|
|
cmp al, (1 shl E3C59X_BIT_MGMT_DATA)
|
|
je .serch_for_phy
|
|
xor al, al
|
|
ret
|
|
.serch_for_phy:
|
|
; search for PHY
|
|
mov cl, 31
|
|
.search_phy_loop:
|
|
cmp cl, 24
|
|
je .next_phy
|
|
mov ah, cl ; ah = phy
|
|
mov al, E3C59X_REG_MII_BMCR ; al = Basic Mode Status Register
|
|
push ecx
|
|
call e3c59x_mdio_read
|
|
pop ecx
|
|
test ax, ax
|
|
jz .next_phy
|
|
cmp ax, 0xffff
|
|
je .next_phy
|
|
mov ah, cl ; ah = phy
|
|
push ecx
|
|
call e3c59x_try_phy
|
|
pop ecx
|
|
test al, al
|
|
jnz .check_preamble
|
|
.next_phy:
|
|
dec cl
|
|
jns .search_phy_loop
|
|
.fail_finish:
|
|
xor al, al
|
|
ret
|
|
; epilog
|
|
.check_preamble:
|
|
push eax ; eax contains the return value of e3c59x_try_phy
|
|
; check hard coded preamble forcing
|
|
movzx eax, byte [e3c59x_ver_id]
|
|
test word [eax*4+e3c59x_hw_versions+2], EXTRA_PREAMBLE
|
|
setnz [e3c59x_preamble] ; force preamble
|
|
jnz .finish
|
|
; check mii for preamble suppression
|
|
mov ah, cl
|
|
mov al, E3C59X_REG_MII_BMSR
|
|
call e3c59x_mdio_read
|
|
test al, 1000000b ; preamble suppression?
|
|
setz [e3c59x_preamble] ; no
|
|
.finish:
|
|
pop eax
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_test_packet
|
|
; Description
|
|
; e3c59x_try_loopback try a loopback packet for 10BASE2 or AUI port
|
|
; Parameters
|
|
; ebp - io_addr
|
|
; Return value
|
|
; al - 0
|
|
; al - 1
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_test_packet:
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
; set fullDuplexEnable in MacControl register
|
|
lea edx, [ebp+E3C59X_REG_MAC_CONTROL]
|
|
in ax, dx
|
|
or ax, 0x120
|
|
out dx, ax
|
|
; switch to register window 5
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+5
|
|
out dx, ax
|
|
; set RxFilter to enable individual address matches
|
|
mov ax, (10000b shl 11)
|
|
lea edx, [ebp+E3C59X_REG_RX_FILTER]
|
|
in al, dx
|
|
or al, 1
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
out dx, ax
|
|
; issue RxEnable and TxEnable
|
|
call e3c59x_rx_reset
|
|
call e3c59x_tx_reset
|
|
; download a self-directed test packet
|
|
mov edi, node_addr
|
|
mov bx, 0x0608 ; packet type
|
|
mov esi, e3c59x_self_directed_packet
|
|
mov ecx, 6 ; 6 + 6 + 2 + 6 = 20 bytes
|
|
call dword [e3c59x_transmit_function]
|
|
; wait for 2s
|
|
mov esi, 2000 ; 2000ms = 2s
|
|
call delay_ms
|
|
; check if self-directed packet is received
|
|
call dword [e3c59x_receive_function]
|
|
test al, al
|
|
jnz .finish
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
; clear fullDuplexEnable in MacControl register
|
|
lea edx, [ebp+E3C59X_REG_MAC_CONTROL]
|
|
in ax, dx
|
|
and ax, not 0x120
|
|
out dx, ax
|
|
xor al, al
|
|
.finish:
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_try_loopback
|
|
; Description
|
|
; tries a loopback packet for 10BASE2 or AUI port
|
|
; Parameters
|
|
; al - 0: 10Mbps AUI connector
|
|
; 1: 10BASE-2
|
|
; ebp - io_addr
|
|
; Return value
|
|
; al - 0
|
|
; al - 1
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_try_loopback:
|
|
push eax
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
pop eax
|
|
push eax
|
|
if defined E3C59X_DEBUG
|
|
mov bl, al
|
|
inc bl
|
|
shl bl, 3
|
|
or byte [e3c59x_link_type+1], bl
|
|
end if ; defined E3C59X_DEBUG
|
|
test al, al ; aui or coax?
|
|
jz .complete_loopback
|
|
; enable 100BASE-2 DC-DC converter
|
|
mov ax, (10b shl 11) ; EnableDcConverter
|
|
out dx, ax
|
|
.complete_loopback:
|
|
mov cl, 2 ; give a port 3 chances to complete a loopback
|
|
.next_try:
|
|
push ecx
|
|
call e3c59x_test_packet
|
|
pop ecx
|
|
test al, al
|
|
jnz .finish
|
|
dec cl
|
|
jns .next_try
|
|
.finish:
|
|
xchg eax, [esp]
|
|
test al, al
|
|
jz .aui_finish
|
|
; issue DisableDcConverter command
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (10111b shl 11)
|
|
out dx, ax
|
|
.aui_finish:
|
|
pop eax ; al contains the result of operation
|
|
if defined E3C59X_DEBUG
|
|
test al, al
|
|
jnz @f
|
|
and byte [e3c59x_link_type+1], not 11000b
|
|
@@:
|
|
end if ; defined E3C59X_DEBUG
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_set_available_media
|
|
; Description
|
|
; sets the first available media
|
|
; Parameters
|
|
; ebp - io_addr
|
|
; Return value
|
|
; al - 0
|
|
; al - 1
|
|
; Destroyed registers
|
|
; eax, edx
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_set_available_media:
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
in eax, dx
|
|
push eax
|
|
lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS]
|
|
in ax, dx
|
|
test al, 10b
|
|
jz @f
|
|
; baseTXAvailable
|
|
pop eax
|
|
and eax, not (1111b shl 20)
|
|
or eax, (100b shl 20)
|
|
if defined E3C59X_DEBUG & defined E3C59X_FORCE_FD
|
|
mov word [e3c59x_link_type], (1 shl 8)
|
|
else if defined E3C59X_DEBUG
|
|
mov word [e3c59x_link_type], (1 shl 7)
|
|
end if
|
|
jmp .set_media
|
|
@@:
|
|
test al, 100b
|
|
jz @f
|
|
; baseFXAvailable
|
|
pop eax
|
|
and eax, not (1111b shl 20)
|
|
or eax, (101b shl 20)
|
|
if defined E3C59X_DEBUG
|
|
mov word [e3c59x_link_type], (1 shl 10)
|
|
end if
|
|
jmp .set_media
|
|
@@:
|
|
test al, 1000000b
|
|
jz @f
|
|
; miiDevice
|
|
pop eax
|
|
and eax, not (1111b shl 20)
|
|
or eax, (0110b shl 20)
|
|
if defined E3C59X_DEBUG
|
|
mov word [e3c59x_link_type], (1 shl 13)
|
|
end if
|
|
jmp .set_media
|
|
@@:
|
|
test al, 1000b
|
|
jz @f
|
|
.set_default:
|
|
; 10bTAvailable
|
|
pop eax
|
|
and eax, not (1111b shl 20)
|
|
if defined E3C59X_DEBUG & defined E3C59X_FORCE_FD
|
|
mov word [e3c59x_link_type], (1 shl 6)
|
|
else if defined E3C59X_DEBUG
|
|
mov word [e3c59x_link_type], (1 shl 5)
|
|
end if ; E3C59X_FORCE_FD
|
|
jmp .set_media
|
|
@@:
|
|
test al, 10000b
|
|
jz @f
|
|
; coaxAvailable
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (10b shl 11) ; EnableDcConverter
|
|
out dx, ax
|
|
pop eax
|
|
and eax, not (1111b shl 20)
|
|
or eax, (11b shl 20)
|
|
if defined E3C59X_DEBUG
|
|
mov word [e3c59x_link_type], (1 shl 12)
|
|
end if ; defined E3C59X_DEBUG
|
|
jmp .set_media
|
|
@@:
|
|
test al, 10000b
|
|
jz .set_default
|
|
; auiAvailable
|
|
pop eax
|
|
and eax, not (1111b shl 20)
|
|
or eax, (1 shl 20)
|
|
if defined E3C59X_DEBUG
|
|
mov word [e3c59x_link_type], (1 shl 11)
|
|
end if ; defined E3C59X_DEBUG
|
|
.set_media:
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
out dx, eax
|
|
if defined E3C59X_FORCE_FD
|
|
; set fullDuplexEnable in MacControl register
|
|
lea edx, [ebp+E3C59X_REG_MAC_CONTROL]
|
|
in ax, dx
|
|
or ax, 0x120
|
|
out dx, ax
|
|
end if ; E3C59X_FORCE_FD
|
|
mov al, 1
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_set_active_port
|
|
; Description
|
|
; It selects the media port (transceiver) to be used
|
|
; Parameters:
|
|
; ebp - io_addr
|
|
; Return value:
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_set_active_port:
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
in eax, dx
|
|
test eax, (1 shl 24) ; check if autoselect enable
|
|
jz .set_first_available_media
|
|
; check 100BASE-TX and 10BASE-T
|
|
lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS]
|
|
in ax, dx
|
|
test al, 1010b ; check whether 100BASE-TX or 10BASE-T available
|
|
jz .mii_device ; they are not available
|
|
; set auto-negotiation
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
in eax, dx
|
|
and eax, not (1111b shl 20)
|
|
or eax, (1000b shl 20)
|
|
out dx, eax
|
|
call e3c59x_try_mii
|
|
test al, al
|
|
jz .mii_device
|
|
ret
|
|
.mii_device:
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
; check for off-chip mii device
|
|
lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS]
|
|
in ax, dx
|
|
test al, 1000000b ; check miiDevice
|
|
jz .base_fx
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
in eax, dx
|
|
and eax, not (1111b shl 20)
|
|
or eax, (0110b shl 20) ; set MIIDevice
|
|
out dx, eax
|
|
call e3c59x_try_mii
|
|
test al, al
|
|
jz .base_fx
|
|
ret
|
|
.base_fx:
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
; check for 100BASE-FX
|
|
lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS]
|
|
in ax, dx ; read media option register
|
|
test al, 100b ; check 100BASE-FX
|
|
jz .aui_enable
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
in eax, dx
|
|
and eax, not (1111b shl 20)
|
|
or eax, (0101b shl 20) ; set 100base-FX
|
|
out dx, eax
|
|
call e3c59x_try_link_detect
|
|
test al, al
|
|
jz .aui_enable
|
|
ret
|
|
.aui_enable:
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
; check for 10Mbps AUI connector
|
|
lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS]
|
|
in ax, dx ; read media option register
|
|
test al, 100000b ; check 10Mbps AUI connector
|
|
jz .coax_available
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
in eax, dx
|
|
and eax, not (1111b shl 20)
|
|
or eax, (0001b shl 20) ; set 10Mbps AUI connector
|
|
out dx, eax
|
|
xor al, al ; try 10Mbps AUI connector
|
|
call e3c59x_try_loopback
|
|
test al, al
|
|
jz .coax_available
|
|
ret
|
|
.coax_available:
|
|
; switch to register window 3
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+3
|
|
out dx, ax
|
|
; check for coaxial 10BASE-2 port
|
|
lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS]
|
|
in ax, dx ; read media option register
|
|
test al, 10000b ; check 10BASE-2
|
|
jz .set_first_available_media
|
|
lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG]
|
|
in eax, dx
|
|
and eax, not (1111b shl 20)
|
|
or eax, (0011b shl 20) ; set 10BASE-2
|
|
out dx, eax
|
|
mov al, 1
|
|
call e3c59x_try_loopback
|
|
test al, al
|
|
jz .set_first_available_media
|
|
ret
|
|
.set_first_available_media:
|
|
jmp e3c59x_set_available_media
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_wake_up
|
|
; Description
|
|
; set the power state to D0
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_wake_up:
|
|
; wake up - we directly do it by programming PCI
|
|
; check if the device is power management capable
|
|
mov al, 2
|
|
mov ah, [pci_bus]
|
|
mov bl, PCI_REG_STATUS
|
|
mov bh, [pci_dev]
|
|
push eax ebx
|
|
call pci_read_reg
|
|
test al, 10000b ; is there "new capabilities" linked list?
|
|
pop ebx eax
|
|
jz .device_awake
|
|
; search for power management register
|
|
mov al, 1
|
|
mov bl, PCI_REG_CAP_PTR
|
|
push eax ebx
|
|
call pci_read_reg
|
|
mov cl, al
|
|
cmp cl, 0x3f
|
|
pop ebx eax
|
|
jbe .device_awake
|
|
; traverse the list
|
|
mov al, 2
|
|
.pm_loop:
|
|
mov bl, cl
|
|
push eax ebx
|
|
call pci_read_reg
|
|
cmp al, 1
|
|
je .set_pm_state
|
|
test ah, ah
|
|
mov cl, ah
|
|
pop ebx eax
|
|
jnz .pm_loop
|
|
jmp .device_awake
|
|
; waku up the device if necessary
|
|
.set_pm_state:
|
|
pop ebx eax
|
|
add bl, PCI_REG_PM_CTRL
|
|
push eax ebx
|
|
call pci_read_reg
|
|
mov cx, ax
|
|
test cl, 3
|
|
pop ebx eax
|
|
jz .device_awake
|
|
and cl, not 11b ; set state to D0
|
|
call pci_write_reg
|
|
.device_awake:
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_probe
|
|
; Description
|
|
; Searches for an ethernet card, enables it and clears the rx buffer
|
|
; If a card was found, it enables the ethernet -> TCPIP link
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_probe:
|
|
movzx ebp, word [io_addr]
|
|
mov al, 2
|
|
mov ah, [pci_bus]
|
|
mov bh, [pci_dev]
|
|
mov bl, PCI_REG_COMMAND
|
|
push ebp eax ebx
|
|
call pci_read_reg
|
|
mov cx, ax
|
|
or cl, (1 shl PCI_BIT_MASTER) or (1 shl PCI_BIT_PIO)
|
|
and cl, not (1 shl PCI_BIT_MMIO)
|
|
pop ebx eax
|
|
call pci_write_reg
|
|
; wake up the card
|
|
call e3c59x_wake_up
|
|
pop ebp
|
|
; get chip version
|
|
mov ax, [pci_data+2]
|
|
mov ecx, E3C59X_HW_VERSIONS_SIZE/4-1
|
|
.chip_ver_loop:
|
|
cmp ax, [e3c59x_hw_versions+ecx*4]
|
|
jz .chip_ver_found
|
|
dec ecx
|
|
jns .chip_ver_loop
|
|
xor ecx, ecx
|
|
.chip_ver_found:
|
|
mov [e3c59x_ver_id], cl
|
|
test word [e3c59x_hw_versions+2+ecx*4], HAS_HWCKSM
|
|
setnz [e3c59x_has_hwcksm]
|
|
; set pci latency for vortex cards
|
|
test word [e3c59x_hw_versions+2+ecx*4], IS_VORTEX
|
|
jz .not_vortex
|
|
mov cx, 11111000b ; 248 = max latency
|
|
mov al, 1
|
|
mov ah, [pci_bus]
|
|
mov bl, PCI_REG_LATENCY
|
|
mov bh, [pci_dev]
|
|
call pci_write_reg
|
|
.not_vortex:
|
|
; set RX/TX functions
|
|
mov ax, E3C59X_EEPROM_REG_CAPABILITIES
|
|
call e3c59x_read_eeprom
|
|
test al, 100000b ; full bus master?
|
|
setnz [e3c59x_full_bus_master]
|
|
jnz .boomerang_func
|
|
mov dword [e3c59x_transmit_function], e3c59x_vortex_transmit
|
|
mov dword [e3c59x_receive_function], e3c59x_vortex_poll
|
|
jmp @f
|
|
.boomerang_func: ; full bus master, so use boomerang functions
|
|
mov dword [e3c59x_transmit_function], e3c59x_boomerang_transmit
|
|
mov dword [e3c59x_receive_function], e3c59x_boomerang_poll
|
|
@@:
|
|
; read MAC from eeprom
|
|
mov ecx, 2
|
|
.mac_loop:
|
|
lea ax, [E3C59X_EEPROM_REG_OEM_NODE_ADDR+ecx]
|
|
call e3c59x_read_eeprom
|
|
xchg ah, al ; htons
|
|
mov [node_addr+ecx*2], ax
|
|
dec ecx
|
|
jns .mac_loop
|
|
test byte [e3c59x_full_bus_master], 0xff
|
|
jz .set_preamble
|
|
; switch to register window 2
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+2
|
|
out dx, ax
|
|
; activate xcvr by setting some magic bits
|
|
lea edx, [ebp+E3C59X_REG_RESET_OPTIONS]
|
|
in ax, dx
|
|
and ax, not 0x4010
|
|
movzx ebx, byte [e3c59x_ver_id]
|
|
test word [ebx*4+e3c59x_hw_versions+2], INVERT_LED_PWR
|
|
jz @f
|
|
or al, 0x10
|
|
@@:
|
|
test word [ebx*4+e3c59x_hw_versions+2], INVERT_MII_PWR
|
|
jz @f
|
|
or ah, 0x40
|
|
@@:
|
|
out dx, ax
|
|
.set_preamble:
|
|
; use preamble as default
|
|
mov byte [e3c59x_preamble], 1 ; enable preamble
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_reset
|
|
; Description
|
|
; Place the chip (ie, the ethernet card) into a virgin state
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
e3c59x_reset:
|
|
; issue global reset
|
|
call e3c59x_global_reset
|
|
; disable interrupts
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (1110b shl 11)
|
|
out dx, ax
|
|
; enable Statistics
|
|
mov ax, (10101b shl 11)
|
|
out dx, ax
|
|
; set indication
|
|
mov ax, (1111b shl 11) or 0x6c6
|
|
out dx, ax
|
|
; acknowledge (clear) every interrupt indicator
|
|
mov ax, (1101b shl 11) or 0x661
|
|
out dx, ax
|
|
; switch to register window 2
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+2
|
|
out dx, ax
|
|
; write MAC addres back into the station address registers
|
|
lea edx, [ebp+E3C59X_REG_STATION_ADDRESS_LO]
|
|
mov esi, node_addr
|
|
cld
|
|
outsw
|
|
add edx, 2
|
|
outsw
|
|
add edx, 2
|
|
outsw
|
|
add edx, 2
|
|
; clear station mask
|
|
xor eax, eax
|
|
out dx, ax
|
|
add edx, 2
|
|
out dx, ax
|
|
add edx, 2
|
|
out dx, ax
|
|
; switch to register window 6
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+6
|
|
out dx, ax
|
|
; clear all statistics by reading
|
|
lea edx, [ebp+E3C59X_REG_CARRIER_LOST]
|
|
mov cl, 9
|
|
.stat_clearing_loop:
|
|
in al, dx
|
|
inc edx
|
|
dec cl
|
|
jns .stat_clearing_loop
|
|
in ax, dx
|
|
add dx, 2
|
|
in ax, dx
|
|
; switch to register window 4
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+4
|
|
out dx, ax
|
|
; clear BadSSD
|
|
lea edx, [ebp+E3C59X_REG_BAD_SSD]
|
|
in al, dx
|
|
; clear extra statistics bit in NetworkDiagnostic
|
|
lea edx, [ebp+E3C59X_REG_NETWORK_DIAGNOSTIC]
|
|
in ax, dx
|
|
or ax, 0x0040
|
|
out dx, ax
|
|
; SetRxEarlyThreshold
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (10001b shl 11)+(E3C59X_MAX_ETH_PKT_SIZE shr 2)
|
|
out dx, ax
|
|
test byte [e3c59x_full_bus_master], 0xff
|
|
jz .skip_boomerang_setting
|
|
; set upRxEarlyEnable
|
|
lea edx, [ebp+E3C59X_REG_DMA_CTRL]
|
|
in eax, dx
|
|
or eax, 0x20
|
|
out dx, eax
|
|
; TxFreeThreshold
|
|
lea edx, [ebp+E3C59X_REG_TX_FREE_THRESH]
|
|
mov al, (E3C59X_MAX_ETH_PKT_SIZE / 256)
|
|
out dx, al
|
|
; program DnListPtr
|
|
lea edx, [ebp+E3C59X_REG_DN_LIST_PTR]
|
|
xor eax, eax
|
|
out dx, eax
|
|
.skip_boomerang_setting:
|
|
; initialization
|
|
call e3c59x_rx_reset
|
|
call e3c59x_tx_reset
|
|
call e3c59x_set_active_port
|
|
call e3c59x_rx_reset
|
|
call e3c59x_tx_reset
|
|
; switch to register window 5
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+5
|
|
out dx, ax
|
|
; program RxFilter for promiscuous operation
|
|
mov ax, (10000b shl 11)
|
|
lea edx, [ebp+E3C59X_REG_RX_FILTER]
|
|
in al, dx
|
|
or al, 1111b
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
out dx, ax
|
|
; switch to register window 4
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+4
|
|
out dx, ax
|
|
; wait for linkDetect
|
|
lea edx, [ebp+E3C59X_REG_MEDIA_STATUS]
|
|
mov cl, 20 ; wait for max 2s
|
|
mov esi, 100 ; 100ms
|
|
.link_detect_loop:
|
|
call delay_ms
|
|
in ax, dx
|
|
test ah, 1000b ; linkDetect
|
|
jnz @f
|
|
dec cl
|
|
jnz .link_detect_loop
|
|
@@:
|
|
; Indicate that we have successfully reset the card
|
|
mov eax, [pci_data]
|
|
mov [eth_status], eax
|
|
if defined E3C59X_DEBUG
|
|
call e3c59x_debug
|
|
end if ; defined E3C59X_DEBUG
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_global_reset
|
|
; Description
|
|
; resets the device
|
|
; Parameters:
|
|
; ebp - io_addr
|
|
; Return value:
|
|
; Destroyed registers
|
|
; ax, ecx, edx, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_global_reset:
|
|
; GlobalReset
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
xor eax, eax
|
|
; or al, 0x14
|
|
out dx, ax
|
|
; wait for GlobalReset to complete
|
|
mov ecx, 64000
|
|
.global_reset_loop:
|
|
in ax, dx
|
|
test ah, 10000b ; check CmdInProgress
|
|
jz .finish
|
|
dec ecx
|
|
jnz .global_reset_loop
|
|
.finish:
|
|
; wait for 2 seconds for NIC to boot
|
|
mov esi, 2000 ; 2000ms = 2s
|
|
push ebp
|
|
call delay_ms
|
|
pop ebp
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_tx_reset
|
|
; Description
|
|
; resets and enables transmitter engine
|
|
; Parameters:
|
|
; ebp - io_addr
|
|
; Return value:
|
|
; Destroyed registers
|
|
; ax, ecx, edx
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_tx_reset:
|
|
; TxReset
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (01011b shl 11)
|
|
out dx, ax
|
|
; wait for TxReset to complete
|
|
mov ecx, 2000
|
|
.tx_reset_loop:
|
|
in ax, dx
|
|
test ah, 10000b ; check CmdInProgress
|
|
jz .tx_enable
|
|
dec ecx
|
|
jns .tx_reset_loop
|
|
test byte [e3c59x_full_bus_master], 0xff
|
|
jz .tx_enable
|
|
; init last_dpd
|
|
mov dword [e3c59x_prev_dpd], e3c59x_dpd_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_DPD_SIZE
|
|
mov dword [e3c59x_prev_tx_frame], e3c59x_tx_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_MAX_ETH_FRAME_SIZE
|
|
.tx_enable:
|
|
mov ax, (01001b shl 11) ; TxEnable
|
|
out dx, ax
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_rx_reset
|
|
; Description
|
|
; resets and enables receiver engine
|
|
; Parameters:
|
|
; ebp - io_addr
|
|
; Return value:
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, edi, esi
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_rx_reset:
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (0101b shl 11) or 0x4 ; RxReset
|
|
out dx, ax
|
|
; wait for RxReset to complete
|
|
mov ecx, 200000
|
|
.rx_reset_loop:
|
|
in ax, dx
|
|
test ah, 10000b ; check CmdInProgress
|
|
jz .setup_upd
|
|
dec ecx
|
|
jns .rx_reset_loop
|
|
.setup_upd:
|
|
; check if full bus mastering
|
|
test byte [e3c59x_full_bus_master], 0xff
|
|
jz .rx_enable
|
|
; create upd ring
|
|
mov eax, e3c59x_upd_buff
|
|
zero_to_virt eax
|
|
mov [e3c59x_curr_upd], eax
|
|
mov esi, eax
|
|
virt_to_dma esi
|
|
mov edi, e3c59x_rx_buff
|
|
zero_to_dma edi
|
|
mov ebx, e3c59x_upd_buff+(E3C59X_NUM_RX_DESC-1)*E3C59X_UPD_SIZE
|
|
zero_to_virt ebx
|
|
mov cl, E3C59X_NUM_RX_DESC-1
|
|
.upd_loop:
|
|
mov [ebx+E3C59X_UPD_UP_NEXT_PTR], esi
|
|
and dword [eax+E3C59X_UPD_PKT_STATUS], 0
|
|
mov [eax+E3C59X_UPD_UP_FRAG_ADDR], edi
|
|
mov dword [eax+E3C59X_UPD_UP_FRAG_LEN], E3C59X_MAX_ETH_FRAME_SIZE or (1 shl 31)
|
|
add edi, E3C59X_MAX_ETH_FRAME_SIZE
|
|
add esi, E3C59X_UPD_SIZE
|
|
mov ebx, eax
|
|
add eax, E3C59X_UPD_SIZE
|
|
dec cl
|
|
jns .upd_loop
|
|
mov eax, e3c59x_upd_buff
|
|
zero_to_dma eax
|
|
lea edx, [ebp+E3C59X_REG_UP_LIST_PTR]
|
|
out dx, eax ; write E3C59X_REG_UP_LIST_PTR
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
.rx_enable:
|
|
mov ax, (00100b shl 11) ; RxEnable
|
|
out dx, ax
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_write_eeprom
|
|
; Description
|
|
; reads eeprom
|
|
; Note : the caller must switch to the register window 0
|
|
; before calling this function
|
|
; Parameters:
|
|
; ax - register to be read (only the first 63 words can be read)
|
|
; cx - value to be read into the register
|
|
; Return value:
|
|
; ax - word read
|
|
; Destroyed registers
|
|
; ax, ebx, edx
|
|
;
|
|
;***************************************************************************
|
|
; align 4
|
|
;e3c59x_write_eeprom:
|
|
; mov edx, [io_addr]
|
|
; add edx, E3C59X_REG_EEPROM_COMMAND
|
|
; cmp ah, 11b
|
|
; ja .finish ; address may have a value of maximal 1023
|
|
; shl ax, 2
|
|
; shr al, 2
|
|
; push eax
|
|
;; wait for busy
|
|
; mov ebx, 0xffff
|
|
;@@:
|
|
; in ax, dx
|
|
; test ah, 0x80
|
|
; jz .write_enable
|
|
; dec ebx
|
|
; jns @r
|
|
;; write enable
|
|
;.write_enable:
|
|
; xor eax, eax
|
|
; mov eax, (11b shl 4)
|
|
; out dx, ax
|
|
;; wait for busy
|
|
; mov ebx, 0xffff
|
|
;@@:
|
|
; in ax, dx
|
|
; test ah, 0x80
|
|
; jz .erase_loop
|
|
; dec ebx
|
|
; jns @r
|
|
;.erase_loop:
|
|
; pop eax
|
|
; push eax
|
|
; or ax, (11b shl 6) ; erase register
|
|
; out dx, ax
|
|
; mov ebx, 0xffff
|
|
;@@:
|
|
; in ax, dx
|
|
; test ah, 0x80
|
|
; jz .write_reg
|
|
; dec ebx
|
|
; jns @r
|
|
;.write_reg:
|
|
; add edx, E3C59X_REG_EEPROM_DATA-E3C59X_REG_EEPROM_COMMAND
|
|
; mov eax, ecx
|
|
; out dx, ax
|
|
;; write enable
|
|
; add edx, E3C59X_REG_EEPROM_COMMAND-E3C59X_REG_EEPROM_DATA
|
|
; xor eax, eax
|
|
; mov eax, (11b shl 4)
|
|
; out dx, ax
|
|
; wait for busy
|
|
; mov ebx, 0xffff
|
|
;@@:
|
|
; in ax, dx
|
|
; test ah, 0x80
|
|
; jz .issue_write_reg
|
|
; dec ebx
|
|
; jns @r
|
|
;.issue_write_reg:
|
|
; pop eax
|
|
; or ax, 01b shl 6
|
|
; out dx, ax
|
|
;.finish:
|
|
; ret
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_read_eeprom
|
|
; Description
|
|
; reads eeprom
|
|
; Parameters:
|
|
; ax - register to be read (only the first 63 words can be read)
|
|
; ebp - io_addr
|
|
; Return value:
|
|
; ax - word read
|
|
; Destroyed registers
|
|
; ax, ebx, edx, ebp
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_read_eeprom:
|
|
push eax
|
|
; switch to register window 0
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+0
|
|
out dx, ax
|
|
pop eax
|
|
and ax, 111111b ; take only the first 6 bits into account
|
|
movzx ebx, byte [e3c59x_ver_id]
|
|
test word [ebx*4+e3c59x_hw_versions+2], EEPROM_8BIT
|
|
jz @f
|
|
add ax, 0x230 ; hardware constant
|
|
jmp .read
|
|
@@:
|
|
add ax, E3C59X_EEPROM_CMD_READ
|
|
test word [ebx*4+e3c59x_hw_versions+2], EEPROM_OFFSET
|
|
jz .read
|
|
add ax, 0x30
|
|
.read:
|
|
lea edx, [ebp+E3C59X_REG_EEPROM_COMMAND]
|
|
out dx, ax
|
|
mov ebx, 0xffff ; duration of about 162 us ;-)
|
|
.wait_for_reading:
|
|
in ax, dx
|
|
test ah, 0x80 ; check bit eepromBusy
|
|
jz .read_data
|
|
dec ebx
|
|
jns .wait_for_reading
|
|
.read_data:
|
|
lea edx, [ebp+E3C59X_REG_EEPROM_DATA]
|
|
in ax, dx
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_mdio_sync
|
|
; Description
|
|
; initial synchronization
|
|
; Parameters
|
|
; ebp - io_addr
|
|
; Return value
|
|
; Destroyed registers
|
|
; ax, edx, cl
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_mdio_sync:
|
|
; switch to register window 4
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+4
|
|
out dx, ax
|
|
cmp byte [e3c59x_preamble], 0
|
|
je .no_preamble
|
|
; send 32 logic ones
|
|
lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT]
|
|
mov cl, 31
|
|
.loop:
|
|
mov ax, (1 shl E3C59X_BIT_MGMT_DATA) or (1 shl E3C59X_BIT_MGMT_DIR)
|
|
out dx, ax
|
|
in ax, dx ; delay
|
|
mov ax, (1 shl E3C59X_BIT_MGMT_DATA) \
|
|
or (1 shl E3C59X_BIT_MGMT_DIR) \
|
|
or (1 shl E3C59X_BIT_MGMT_CLK)
|
|
out dx, ax
|
|
in ax, dx ; delay
|
|
dec cl
|
|
jns .loop
|
|
.no_preamble:
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_mdio_read
|
|
; Description
|
|
; read MII register
|
|
; see page 16 in D83840A.pdf
|
|
; Parameters
|
|
; ah - PHY addr
|
|
; al - register addr
|
|
; ebp - io_addr
|
|
; Return value
|
|
; ax - register read
|
|
; Destroyed registers
|
|
; eax, ebx, cx, edx
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_mdio_read:
|
|
push eax
|
|
call e3c59x_mdio_sync ; returns with window #4
|
|
pop eax
|
|
lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT]
|
|
shl al, 3
|
|
shr ax, 3
|
|
and ax, not E3C59X_MII_CMD_MASK
|
|
or ax, E3C59X_MII_CMD_READ
|
|
mov ebx, eax
|
|
xor ecx, ecx
|
|
mov cl, 13
|
|
.cmd_loop:
|
|
mov ax, (1 shl E3C59X_BIT_MGMT_DIR) ; write mii
|
|
bt ebx, ecx
|
|
jnc .zero_bit
|
|
or al, (1 shl E3C59X_BIT_MGMT_DATA)
|
|
.zero_bit:
|
|
out dx, ax
|
|
push eax
|
|
in ax, dx ; delay
|
|
pop eax
|
|
or al, (1 shl E3C59X_BIT_MGMT_CLK) ; write
|
|
out dx, ax
|
|
in ax, dx ; delay
|
|
dec cl
|
|
jns .cmd_loop
|
|
; read data (18 bits with the two transition bits)
|
|
mov cl, 17
|
|
xor ebx, ebx
|
|
.read_loop:
|
|
shl ebx, 1
|
|
xor eax, eax ; read comand
|
|
out dx, ax
|
|
in ax, dx ; delay
|
|
in ax, dx
|
|
test al, (1 shl E3C59X_BIT_MGMT_DATA)
|
|
jz .dont_set
|
|
inc ebx
|
|
.dont_set:
|
|
mov ax, (1 shl E3C59X_BIT_MGMT_CLK)
|
|
out dx, ax
|
|
in ax, dx ; delay
|
|
dec cl
|
|
jns .read_loop
|
|
mov eax, ebx
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_mdio_write
|
|
; Description
|
|
; write MII register
|
|
; see page 16 in D83840A.pdf
|
|
; Parameters
|
|
; ah - PHY addr
|
|
; al - register addr
|
|
; bx - word to be written
|
|
; ebp - io_addr
|
|
; Return value
|
|
; ax - register read
|
|
; Destroyed registers
|
|
; eax, ebx, cx, edx
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_mdio_write:
|
|
push eax
|
|
call e3c59x_mdio_sync
|
|
pop eax
|
|
lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT]
|
|
shl al, 3
|
|
shr ax, 3
|
|
and ax, not E3C59X_MII_CMD_MASK
|
|
or ax, E3C59X_MII_CMD_WRITE
|
|
shl eax, 2
|
|
or eax, 10b ; transition bits
|
|
shl eax, 16
|
|
mov ax, bx
|
|
mov ebx, eax
|
|
mov ecx, 31
|
|
.cmd_loop:
|
|
mov ax, (1 shl E3C59X_BIT_MGMT_DIR) ; write mii
|
|
bt ebx, ecx
|
|
jnc .zero_bit
|
|
or al, (1 shl E3C59X_BIT_MGMT_DATA)
|
|
.zero_bit:
|
|
out dx, ax
|
|
push eax
|
|
in ax, dx ; delay
|
|
pop eax
|
|
or al, (1 shl E3C59X_BIT_MGMT_CLK) ; write
|
|
out dx, ax
|
|
in ax, dx ; delay
|
|
dec ecx
|
|
jns .cmd_loop
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_transmit
|
|
; Description
|
|
; Transmits a packet of data via the ethernet card
|
|
; edi - Pointer to 48 bit destination address
|
|
; bx - Type of packet
|
|
; ecx - size of packet
|
|
; esi - pointer to packet data
|
|
; ebp - io_addr
|
|
; Destroyed registers
|
|
; eax, ecx, edx, ebp
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_transmit:
|
|
jmp dword [e3c59x_transmit_function]
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_check_tx_status
|
|
; Description
|
|
; Checks TxStatus queue.
|
|
; Return value
|
|
; al - 0 no error was found
|
|
; al - 1 error was found TxReset is needed
|
|
; Destroyed registers
|
|
; eax, ecx, edx, ebp
|
|
;
|
|
;***************************************************************************
|
|
e3c59x_check_tx_status:
|
|
movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC
|
|
; clear TxStatus queue
|
|
lea edx, [ebp+E3C59X_REG_TX_STATUS]
|
|
mov cl, 31 ; max number of queue entries
|
|
.tx_status_loop:
|
|
in al, dx
|
|
test al, al
|
|
jz .finish ; no error
|
|
test al, 0x3f
|
|
jnz .finish ; error
|
|
.no_error_found:
|
|
; clear current TxStatus entry which advances the next one
|
|
xor al, al
|
|
out dx, al
|
|
dec cl
|
|
jns .tx_status_loop
|
|
.finish:
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_vortex_transmit
|
|
; Description
|
|
; Transmits a packet of data via the ethernet card
|
|
; edi - Pointer to 48 bit destination address
|
|
; bx - Type of packet
|
|
; ecx - size of packet
|
|
; esi - pointer to packet data
|
|
; ebp - io_addr
|
|
; Destroyed registers
|
|
; eax, edx, ecx, edi, esi, ebp
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_vortex_transmit:
|
|
push ecx
|
|
call e3c59x_check_tx_status
|
|
pop ecx
|
|
test al, al
|
|
jz .no_error_found
|
|
jmp e3c59x_tx_reset
|
|
.no_error_found:
|
|
; switch to register window 7
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+7
|
|
out dx, ax
|
|
; check for master operation in progress
|
|
lea edx, [ebp+E3C59X_REG_MASTER_STATUS]
|
|
in ax, dx
|
|
test ah, 0x80
|
|
jnz .finish ; no DMA for sending
|
|
; dword boundary correction
|
|
cmp ecx, E3C59X_MAX_ETH_FRAME_SIZE
|
|
ja .finish ; packet is too long
|
|
; write Frame Start Header
|
|
mov eax, ecx
|
|
; add header length and extend the complete length to dword boundary
|
|
add eax, ETH_HLEN+3
|
|
and eax, not 3
|
|
lea edx, [ebp+E3C59X_REG_TX_DATA]
|
|
out dx, eax
|
|
; prepare the complete frame
|
|
push esi
|
|
mov esi, edi
|
|
mov edi, e3c59x_tx_buff
|
|
zero_to_virt edi
|
|
cld
|
|
; copy destination address
|
|
movsd
|
|
movsw
|
|
; copy source address
|
|
mov esi, node_addr
|
|
movsd
|
|
movsw
|
|
; copy packet type
|
|
mov [edi], bx
|
|
add edi, 2
|
|
; copy packet data
|
|
pop esi
|
|
push ecx
|
|
shr ecx, 2
|
|
rep movsd
|
|
pop ecx
|
|
and ecx, 3
|
|
rep movsb
|
|
mov ecx, eax
|
|
; program frame address to be sent
|
|
lea edx, [ebp+E3C59X_REG_MASTER_ADDRESS]
|
|
mov eax, e3c59x_tx_buff
|
|
zero_to_dma eax
|
|
out dx, eax
|
|
; program frame length
|
|
lea edx, [ebp+E3C59X_REG_MASTER_LEN]
|
|
mov eax, ecx
|
|
out dx, ax
|
|
; start DMA Down
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (10100b shl 11) + 1 ; StartDMADown
|
|
out dx, ax
|
|
.finish:
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_boomerang_transmit
|
|
; Description
|
|
; Transmits a packet of data via the ethernet card
|
|
; edi - Pointer to 48 bit destination address
|
|
; bx - Type of packet
|
|
; ecx - size of packet
|
|
; esi - pointer to packet data
|
|
; ebp - io_addr
|
|
; Destroyed registers
|
|
; eax, ebx, ecx, edx, esi, edi, ebp
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_boomerang_transmit:
|
|
push ecx
|
|
call e3c59x_check_tx_status
|
|
pop ecx
|
|
test al, al
|
|
jz .no_error_found
|
|
jmp e3c59x_tx_reset
|
|
.no_error_found:
|
|
cmp ecx, E3C59X_MAX_ETH_FRAME_SIZE
|
|
ja .finish ; packet is too long
|
|
; calculate descriptor address
|
|
mov eax, [e3c59x_prev_dpd]
|
|
cmp eax, e3c59x_dpd_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_DPD_SIZE
|
|
jb @f
|
|
; wrap around
|
|
mov eax, e3c59x_dpd_buff-E3C59X_DPD_SIZE
|
|
@@:
|
|
add eax, E3C59X_DPD_SIZE
|
|
zero_to_virt eax
|
|
push eax
|
|
; check DnListPtr
|
|
lea edx, [ebp+E3C59X_REG_DN_LIST_PTR]
|
|
in eax, dx
|
|
; mark if Dn_List_Ptr is cleared
|
|
test eax, eax
|
|
setz [e3c59x_dn_list_ptr_cleared]
|
|
; finish if no more free descriptor is available - FIXME!
|
|
cmp eax, [esp]
|
|
pop eax
|
|
jz .finish
|
|
push eax esi
|
|
mov esi, edi
|
|
; calculate tx_buffer address
|
|
mov edi, [e3c59x_prev_tx_frame]
|
|
cmp edi, e3c59x_tx_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_MAX_ETH_FRAME_SIZE
|
|
jb @f
|
|
; wrap around
|
|
mov edi, e3c59x_tx_buff-E3C59X_MAX_ETH_FRAME_SIZE
|
|
@@:
|
|
add edi, E3C59X_MAX_ETH_FRAME_SIZE
|
|
zero_to_virt edi
|
|
mov eax, edi
|
|
cld
|
|
; copy destination address
|
|
movsd
|
|
movsw
|
|
; copy source address
|
|
mov esi, node_addr
|
|
movsd
|
|
movsw
|
|
; copy packet type
|
|
mov [edi], bx
|
|
add edi, 2
|
|
; copy packet data
|
|
pop esi
|
|
push ecx
|
|
shr ecx, 2
|
|
rep movsd
|
|
pop ecx
|
|
push ecx
|
|
and ecx, 3
|
|
rep movsb
|
|
; padding, do we really need it?
|
|
pop ecx
|
|
add ecx, ETH_HLEN
|
|
cmp ecx, ETH_ZLEN
|
|
jae @f
|
|
mov ecx, ETH_ZLEN
|
|
@@:
|
|
; calculate
|
|
mov ebx, ecx
|
|
test byte [e3c59x_has_hwcksm], 0xff
|
|
jz @f
|
|
or ebx, (1 shl 26) ; set AddTcpChecksum
|
|
@@:
|
|
or ebx, 0x8000 ; transmission complete notification
|
|
or ecx, 0x80000000 ; last fragment
|
|
; program DPD
|
|
mov edi, eax
|
|
pop eax
|
|
and dword [eax+E3C59X_DPD_DN_NEXT_PTR], 0
|
|
mov dword [eax+E3C59X_DPD_FRAME_START_HDR], ebx
|
|
virt_to_dma edi
|
|
mov dword [eax+E3C59X_DPD_DN_FRAG_ADDR], edi
|
|
mov [eax+E3C59X_DPD_DN_FRAG_LEN], ecx
|
|
; calculate physical address
|
|
virt_to_dma eax
|
|
push eax
|
|
cmp byte [e3c59x_dn_list_ptr_cleared], 0
|
|
jz .add_to_list
|
|
; write Dn_List_Ptr
|
|
out dx, eax
|
|
jmp .finish
|
|
.add_to_list:
|
|
; DnStall
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, ((110b shl 11)+2)
|
|
out dx, ax
|
|
; wait for DnStall to complete
|
|
mov ecx, 6000
|
|
.wait_for_stall:
|
|
in ax, dx ; read E3C59X_REG_INT_STATUS
|
|
test ah, 10000b
|
|
jz .dnstall_ok
|
|
dec ecx
|
|
jnz .wait_for_stall
|
|
.dnstall_ok:
|
|
pop eax
|
|
push eax
|
|
mov ebx, [e3c59x_prev_dpd]
|
|
zero_to_virt ebx
|
|
mov [ebx], eax
|
|
lea edx, [ebp+E3C59X_REG_DN_LIST_PTR]
|
|
in eax, dx
|
|
test eax, eax
|
|
jnz .dnunstall
|
|
; if Dn_List_Ptr has been cleared fill it up
|
|
pop eax
|
|
push eax
|
|
out dx, eax
|
|
.dnunstall:
|
|
; DnUnStall
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, ((110b shl 11)+3)
|
|
out dx, ax
|
|
.finish:
|
|
pop eax
|
|
dma_to_zero eax
|
|
mov [e3c59x_prev_dpd], eax
|
|
dma_to_zero edi
|
|
mov [e3c59x_prev_tx_frame], edi
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_poll
|
|
; Description
|
|
; Polls the ethernet card for a received packet
|
|
; Received data, if any, ends up in Ether_buffer
|
|
; Destroyed registers
|
|
; eax, ebx, edx, ecx, edi, esi, ebp
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_poll:
|
|
jmp dword [e3c59x_receive_function]
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_vortex_poll
|
|
; Description
|
|
; Polls the ethernet card for a received packet
|
|
; Received data, if any, ends up in Ether_buffer
|
|
; Parameters
|
|
; ebp - io_addr
|
|
; Return value
|
|
; al - 0 ; no packet received
|
|
; al - 1 ; packet received
|
|
; Destroyed registers
|
|
; eax, ebx, edx, ecx, edi, esi, ebp
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_vortex_poll:
|
|
and word [eth_rx_data_len], 0 ; assume no packet received
|
|
movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC
|
|
.rx_status_loop:
|
|
; examine RxStatus
|
|
lea edx, [ebp+E3C59X_REG_RX_STATUS]
|
|
in ax, dx
|
|
test ax, ax
|
|
jz .finish
|
|
test ah, 0x80 ; rxIncomplete
|
|
jz .check_error
|
|
jmp .finish
|
|
.check_error:
|
|
test ah, 0x40
|
|
jz .check_length
|
|
; discard the top frame received advancing the next one
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (01000b shl 11)
|
|
out dx, ax
|
|
jmp .rx_status_loop
|
|
.check_length:
|
|
and eax, 0x1fff
|
|
cmp eax, E3C59X_MAX_ETH_PKT_SIZE
|
|
ja .discard_frame ; frame is too long discard it
|
|
.check_dma:
|
|
push eax
|
|
; switch to register window 7
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, E3C59X_SELECT_REGISTER_WINDOW+7
|
|
out dx, ax
|
|
; check for master operation in progress
|
|
lea edx, [ebp+E3C59X_REG_MASTER_STATUS]
|
|
in ax, dx
|
|
test ah, 0x80
|
|
jz .read_frame ; no DMA for receiving
|
|
pop eax
|
|
jmp .finish
|
|
.read_frame:
|
|
; program buffer address to read in
|
|
lea edx, [ebp+E3C59X_REG_MASTER_ADDRESS]
|
|
if defined E3C59X_LINUX
|
|
mov eax, e3c59x_rx_buff
|
|
zero_to_dma eax
|
|
else
|
|
mov eax, Ether_buffer
|
|
end if
|
|
out dx, eax
|
|
; program frame length
|
|
lea edx, [ebp+E3C59X_REG_MASTER_LEN]
|
|
mov ax, 1560
|
|
out dx, ax
|
|
; start DMA Up
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (10100b shl 11) ; StartDMAUp
|
|
out dx, ax
|
|
; check for master operation in progress
|
|
.dma_loop:
|
|
lea edx, [ebp+E3C59X_REG_MASTER_STATUS]
|
|
in ax, dx
|
|
test ah, 0x80
|
|
jnz .dma_loop
|
|
; registrate the received packet length
|
|
pop eax
|
|
mov word [eth_rx_data_len], ax
|
|
; discard the top frame received
|
|
.discard_frame:
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, (01000b shl 11)
|
|
out dx, ax
|
|
.finish:
|
|
; set return value
|
|
cmp word [eth_rx_data_len], 0
|
|
setne al
|
|
ret
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; e3c59x_boomerang_poll
|
|
; Description
|
|
; Polls the ethernet card for a received packet
|
|
; Received data, if any, ends up in Ether_buffer
|
|
; Parameters
|
|
; ebp - io_addr
|
|
; Return value
|
|
; al - 0 ; no packet received
|
|
; al - 1 ; packet received
|
|
; Destroyed registers
|
|
; eax, edx, ecx, edi, esi, ebp
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
e3c59x_boomerang_poll:
|
|
and word [eth_rx_data_len], 0 ; assume no packet received
|
|
movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC
|
|
; check if packet is uploaded
|
|
mov eax, [e3c59x_curr_upd]
|
|
test byte [eax+E3C59X_UPD_PKT_STATUS+1], 0x80 ; upPktComplete
|
|
jnz .check_error
|
|
jmp .finish
|
|
; packet is uploaded check for any error
|
|
.check_error:
|
|
test byte [eax+E3C59X_UPD_PKT_STATUS+1], 0x40 ; upError
|
|
jz .copy_packet_length
|
|
and dword [eax+E3C59X_UPD_PKT_STATUS], 0
|
|
jmp .finish
|
|
.copy_packet_length:
|
|
mov ecx, [eax+E3C59X_UPD_PKT_STATUS]
|
|
and ecx, 0x1fff
|
|
cmp ecx, E3C59X_MAX_ETH_PKT_SIZE
|
|
jbe .copy_packet
|
|
and dword [eax+E3C59X_UPD_PKT_STATUS], 0
|
|
jmp .finish
|
|
.copy_packet:
|
|
push ecx
|
|
mov word [eth_rx_data_len], cx
|
|
mov esi, [eax+E3C59X_UPD_UP_FRAG_ADDR]
|
|
dma_to_virt esi
|
|
mov edi, Ether_buffer
|
|
shr ecx, 2 ; first copy dword-wise
|
|
cld
|
|
rep movsd ; copy the dwords
|
|
pop ecx
|
|
and ecx, 3
|
|
rep movsb ; copy the rest bytes
|
|
mov eax, [e3c59x_curr_upd]
|
|
and dword [eax+E3C59X_UPD_PKT_STATUS], 0
|
|
virt_to_zero eax
|
|
cmp eax, e3c59x_upd_buff+(E3C59X_NUM_RX_DESC-1)*E3C59X_UPD_SIZE
|
|
jb .no_wrap
|
|
; wrap around
|
|
mov eax, e3c59x_upd_buff-E3C59X_UPD_SIZE
|
|
.no_wrap:
|
|
add eax, E3C59X_UPD_SIZE
|
|
zero_to_virt eax
|
|
mov [e3c59x_curr_upd], eax
|
|
.finish:
|
|
; check if the NIC is in the upStall state
|
|
lea edx, [ebp+E3C59X_REG_UP_PKT_STATUS]
|
|
in eax, dx
|
|
test ah, 0x20 ; UpStalled
|
|
jz .noUpUnStall
|
|
; issue upUnStall command
|
|
lea edx, [ebp+E3C59X_REG_COMMAND]
|
|
mov ax, ((110b shl 11)+1) ; upUnStall
|
|
out dx, ax
|
|
.noUpUnStall:
|
|
; set return value
|
|
cmp word [eth_rx_data_len], 0
|
|
setnz al
|
|
ret
|