Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1 → Rev 2

/kernel/trunk/network/eth_drv/3c59x.inc
0,0 → 1,2380
;; 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
/kernel/trunk/network/eth_drv/ethernet.inc
0,0 → 1,1681
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; ETHERNET.INC ;;
;; ;;
;; Ethernet network layer for Menuet OS ;;
;; ;;
;; Version 0.4 22 September 2003 ;;
;; ;;
;; This file contains the following: ;;
;; PCI bus scanning for valid devices ;;
;; Table of supported ethernet drivers ;;
;; Code to identify and activate a supported driver ;;
;; ARP handler ;;
;; Driver interface to the IP layer ;;
;; Gateway support ;;
;; ;;
;; Individual driver files are included here ;;
;; ;;
;; The PCI bus scanning code was ported from the etherboot ;;
;; 5.0.6 project. The copyright statement for that code is ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; remaining parts Copyright 2002 Mike Hibbett ;;
;; mikeh@oceanfree.net ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
;********************************************************************
; Interface
; ethernet_driver called by stack_handler in stack.inc
; eth_probe called by app_stack_handler in stack.inc
;
;********************************************************************
 
; Some useful information on data structures
 
; Ethernet Packet - ARP Request example
;
; 0 1 2 3
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
;
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Dest H/W Address |
; | ( 14 byte header ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | | Source H/W Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Protocol - ARP 08 06 |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | H/W Type 00 01 | Protocol Type 08 00 |
; | ( ARP Request packet ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | HLen 0x06 | PLen 0x04 | OpCode 00 01 |
; | ( 0001 for request, 0002 for reply ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Source Hardware Address ( MAC Address ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | | Source IP Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | | Destination Hardware Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Destination IP Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
; Include individual drivers source files at this point.
; If you create a new driver, include it below.
 
include "rtl8029.inc"
include "i8255x.inc"
include "rtl8139.inc"
include "3c59x.inc"
include "sis900.inc"
include "pcnet32.inc"
 
; DEBUGGING_STATE enables or disables output of received and transmitted
; data over the serial port
DEBUGGING_ENABLED equ 1
DEBUGGING_DISABLED equ 0
DEBUGGING_STATE equ DEBUGGING_DISABLED
 
; PCICards
; ========
; PCI vendor and hardware types for hardware supported by the above drivers
; If you add a driver, ensure you update this datastructure, otherwise the
; card will not be probed.
; Each driver is defined by 4 double words. These are
; PCIVendorDevice probeFunction ResetFunction PollFunction transmitFunction
; The last entry must be kept at all zeros, to indicate the end of the list
; As a PCI driver may support more than one hardware implementation, there may
; be several lines which refer to the same functions.
; The first driver found on the PCI bus will be the one used.
 
PCICARDS_ENTRY_SIZE equ 20 ; Size of each PCICARDS entry
 
iglobal
PCICards:
dd 0x12098086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
dd 0x10298086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
dd 0x12298086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
dd 0x10308086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
dd 0x24498086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
dd 0x802910ec, rtl8029_probe, rtl8029_reset, rtl8029_poll, rtl8029_transmit
dd 0x12111113, rtl8029_probe, rtl8029_reset, rtl8029_poll, rtl8029_transmit
dd 0x813910ec, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit
dd 0x590010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x592010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x597010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x595010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x595110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x595210b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x900010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x900110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x900410b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x900510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x900610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x900A10b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x905010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x905110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x905510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x905810b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x905A10b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x920010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x980010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x980510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x764610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x505510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x605510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x605610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x5b5710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x505710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x515710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x525710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x656010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x656210b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x656410b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x450010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
dd 0x09001039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit
dd 0x20001022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit
dd 0x26251022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit
dd 0x20011022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit
; following card is untested
dd 0x70161039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit
dd 0,0,0,0,0 ; end of list marker, do not remove
endg
 
; PCI Bus defines
PCI_HEADER_TYPE equ 0x0e ;8 bit
PCI_BASE_ADDRESS_0 equ 0x10 ;32 bit
PCI_BASE_ADDRESS_5 equ 0x24 ;32 bits
PCI_BASE_ADDRESS_SPACE_IO equ 0x01
PCI_VENDOR_ID equ 0x00 ;16 bit
PCI_BASE_ADDRESS_IO_MASK equ 0xFFFFFFFC
 
ETHER_IP equ 0x0008 ; Reversed from 0800 for intel
ETHER_ARP equ 0x0608 ; Reversed from 0806 for intel
ETHER_RARP equ 0x3580
ARP_REQ_OPCODE equ 0x0100
ARP_REP_OPCODE equ 0x0200
 
uglobal
arp_rx_count: dd 0
ip_rx_count: dd 0
dumped_rx_count: dd 0
ip_tx_count: dd 0
node_addr: db 0,0,0,0,0,0
eth_rx_data_len: dw 0
eth_status: dd 0
io_addr: dd 0
hdrtype: db 0
vendor_device: dd 0
pci_data: dd 0
pci_dev: dd 0
pci_bus: dd 0
 
; These will hold pointers to the selected driver functions
drvr_probe: dd 0
drvr_reset: dd 0
drvr_poll: dd 0
drvr_transmit: dd 0
 
; These hold the destination Host identity for ARP responses
remote_ip_add: dd 0
remote_hw_add: db 0, 0, 0, 0, 0, 0
endg
 
iglobal
broadcast_add: db 0xff,0xff,0xff,0xff,0xff,0xff
subnet_mask: dd 0x00ffffff
endg
 
uglobal
; This is used by getMACfromIP
MACAddress: db 0,0,0,0,0,0
gateway_ip: db 0, 0, 0, 0
dns_ip: dd 0
endg
 
; The follow is the ARP Table.
; This table must be manually updated and the kernel recompilied if
; changes are made to it.
; ARP_TABLE_SIZE defines the size of the table
; ARP_TABLE_ENTRIES defines the number of entries in the table
; Each entry is 10 bytes: 4 Byte IP address, 6 byte MAC Address,
; 2 bytes status, 2 bytes TTL ( in seconds )
; Empty entries are filled with zeros
; The TTL field is decremented every second, and is deleted when it
; reaches 0. It is refreshed every time a packet is received
; If the TTL field is 0xFFFF it is a permanent entry and is never deleted
; The status field can be the following values
; 0x0000 entry not used
; 0x0001 entry holds a valid mapping
; 0x0002 entry contains an IP address, awaiting ARP response
; 0x0003 No response received to ARP request.
; The last status value is provided to allow the network layer to delete
; a packet that is queued awaiting an ARP response
 
ARP_NO_ENTRY equ 0
ARP_VALID_MAPPING equ 1
ARP_AWAITING_RESPONSE equ 2
ARP_RESPONSE_TIMEOUT equ 3
 
ARP_ENTRY_SIZE equ 14 ; Number of bytes per entry
ARP_TABLE_SIZE equ 20 ; Size of table
ARP_TABLE_ENTRIES equ 0 ; Inital, hardcoded entries
 
uglobal
ARPTable:
times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE db 0
endg
 
iglobal
NumARP: db ARP_TABLE_ENTRIES
endg
 
;***************************************************************************
; Function
; eth_probe
; Description
; Searches for an ethernet card. If found, the card is enabled and
; the ethernet -> IP link established
;
; This function scans the PCI bus looking for a supported device.
; ISA bus is currently not supported.
;
; eax is 0 if no hardware found
;***************************************************************************
eth_probe:
; Find a card on the PCI bus, and get it's address
call scan_bus ; Find the ethernet cards PIC address
xor eax, eax
cmp [io_addr], eax
je ep_00x ; Return 0 in eax if no cards found
 
call dword [drvr_probe] ; Call the drivers probe function
 
mov eax, [io_addr] ; return a non zero value
 
ep_00x:
ret
 
;***************************************************************************
; Function
; ethernet_driver
;
; Description
; The ethernet RX and TX handler
; This is a kernel function, called by stack_handler
;
;***************************************************************************
ethernet_driver:
; Do nothing if the driver is inactive
cmp [ethernet_active], byte 0
je eth_exit
 
call eth_rx
call eth_tx
 
eth_exit:
ret
 
;***************************************************************************
; Function
; eth_rx
;
; Description
; Polls the ethernet card for received data. Extracts if present
; Depending on the Protocol within the packet:
; ARP : Pass to ARP_handler. This may result in an ARP reply
; being tx'ed
; IP : Store in an IP buffer
;
;***************************************************************************
eth_rx:
xor ax, ax
mov [eth_rx_data_len], ax
call dword [drvr_poll] ; Call the drivers poll function
 
mov ax, [eth_rx_data_len]
cmp ax, 0
je erx_exit
 
if DEBUGGING_STATE = DEBUGGING_ENABLED
pusha
mov eax, 0 ;Indicate that this is a received packet
mov cx, [eth_rx_data_len]
mov esi, Ether_buffer
cmp word [esi + 12], ETHER_IP
jnz erxd_done
; cmp byte [esi + 14 + 9], 0x06 ; TCP
; jnz erxd_done
call eth_dump
erxd_done:
popa
end if
 
; Check the protocol. Call appropriate handler
mov eax, Ether_buffer
add eax, 12 ; The address of the protocol word
 
mov ax, [eax]
 
cmp ax, ETHER_ARP
je erx_001 ; It is ARP
 
cmp ax, ETHER_IP
je erx_002 ; It's IP
 
; inc dword [dumped_rx_count]
 
jmp erx_exit ; If not IP or ARP, ignore
 
erx_001:
mov eax, [arp_rx_count]
inc eax
mov [arp_rx_count], eax
 
; At this point, the packet is still in the Ether_buffer
call arp_handler
 
jmp erx_exit
 
erx_002:
mov eax, [ip_rx_count]
inc eax
mov [ip_rx_count], eax
 
; Check to see if the MAC address is in our arp table
; refresh the arp ttl if so
 
mov esi, Ether_buffer
add esi, 6
 
call refreshARP
 
call ether_IP_handler
 
jmp erx_exit
 
erx_exit:
ret
 
;***************************************************************************
; Function
; eth_tx
;
; Description
; Looks at the NET1OUT_QUEUE for data to send.
; Stores that destination IP in a location used by the tx routine
; Looks up the MAC address in the ARP table; stores that where
; the tx routine can get it
; Get the length of the data. Store that where the tx routine wants it
; Call tx
; Places buffer on empty queue when the tx routine finished
;
;***************************************************************************
eth_tx:
; Look for a buffer to tx
mov eax, NET1OUT_QUEUE
call dequeue
cmp ax, NO_BUFFER
je eth_exit ; Exit if no buffer available
 
push eax
 
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
; Extract the destination IP
; find the destination IP in the ARP table, get MAC
; store this MAC in 'MACAddress'
mov ebx, eax ; Save buffer address
mov edx, [ebx + 16] ; get destination address
 
; If the destination address is 255.255.255.255,
; set the MACAddress to all ones ( broadcast )
mov [MACAddress], dword 0xffffffff
mov [MACAddress + 4], word 0xffff
cmp edx, 0xffffffff
je etx_send ; If it is broadcast, just send
 
call getMACfromIP ; Get the MAC address.
 
cmp eax, ARP_VALID_MAPPING
jz etx_send
 
; No valid entry. Are we waiting for a response?
cmp eax, ARP_AWAITING_RESPONSE
jne etx_001
 
; Re-queue the packet, and exit
pop ebx
mov eax, NET1OUT_QUEUE
call queue
jmp etx_exit
 
etx_001:
; HAs the request been sent, but timed out?
cmp eax, ARP_RESPONSE_TIMEOUT
jne etx_002
 
pop eax
call freeBuff
jmp etx_exit
 
etx_002:
; There is no entry. Re queue the request, and ask ARP to send a request
 
; IP address is in edx
push edx
call arp_request
pop ebx
 
; Add an entry in the ARP table, awaiting response
 
cmp byte [NumARP], ARP_TABLE_SIZE
je etx_003 ; We cannot add a new entry in the table
 
inc byte [NumARP]
 
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
sub eax, ARP_ENTRY_SIZE
 
mov [eax + ARPTable], ebx
xor ebx, ebx
mov [eax + ARPTable + 4], ebx
mov [eax + ARPTable + 8], bx
 
; set the status field up - awaiting response
mov cl, 0x00
mov [eax + ARPTable + 10], cl
mov cl, 0x02
mov [eax + ARPTable + 11], cl
 
; Initialise the time to live field - 10s
mov cx, 0x000A
mov [eax + ARPTable + 12], cx
 
etx_003:
pop ebx ; Get the buffer back
mov eax, NET1OUT_QUEUE
call queue
jmp etx_exit
 
etx_send:
xor ecx, ecx
mov ch, [ebx+2]
mov cl, [ebx+3] ; ; Size of IP packet to send
 
mov esi, ebx
 
mov edi, MACAddress
 
if DEBUGGING_STATE = DEBUGGING_ENABLED
pusha
mov cx, 42
mov eax, 1 ; Indicate that this is a tx packet
call eth_dump
popa
end if
 
mov bx, ETHER_IP
call dword [drvr_transmit] ; Call the drivers transmit function
 
; OK, we have sent a packet, so increment the count
inc dword [ip_tx_count]
 
; And finally, return the buffer to the free queue
pop eax
call freeBuff
 
etx_exit:
ret
 
;***************************************************************************
; Function
; ether_IP_handler
;
; Description
; Called when an IP ethernet packet is received on the ethernet
; Header + Data is in Ether_buffer[]
; We just need to get a buffer from the 'free' queue, and
; store the packet in it, then insert the packet number into the
; IPRX queue.
; If no queue entry is available, the packet is silently discarded
; All registers may be destroyed
;
;***************************************************************************
ether_IP_handler:
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je eiph00x
 
; convert buffer pointer eax to the absolute address
push eax
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
mov edi, eax
 
; get a pointer to the start of the DATA
mov esi, Ether_buffer + 14
 
; Now store it all away
mov ecx, IPBUFFSIZE / 4 ; Copy all of the available
; data across - worse case
cld
rep movsd
 
; And finally, place the buffer in the IPRX queue
pop ebx
mov eax, IPIN_QUEUE
call queue
 
eiph00x:
ret
 
;***************************************************************************
;
; ARP CODE FOLLOWS
;
; The ARP code is used by ethernet drivers to translate an destination
; IP address into an ethernet hardware address. Functions to broadcast
; requests and handle response are (or will be) here.
; The IP layer has no knowledge of ARP, as this is a network interface
; issue
;
;***************************************************************************
 
;***************************************************************************
; Function
; arp_timer
;
; Description
; Called every 1s
; It is responsible for removing expired routes
; All registers may be destroyed
;
;***************************************************************************
arp_timer:
; loop through all the ARP entries, decrementing each one
; that doesn't have a TTL of 0xFFFF
movzx eax, byte [NumARP]
 
arp_001:
cmp eax, 0
je arp_003
 
push eax
dec eax
mov ecx, ARP_ENTRY_SIZE
mul ecx
cmp word [ eax + ARPTable + 12], 0xFFFF
je arp_002
 
cmp word [ eax + ARPTable + 12], 0
je arp_002
 
dec word [eax + ARPTable + 12]
 
arp_002:
pop eax
dec eax
jmp arp_001
 
; Now, look for entries with a TTL of 0
; Valid entries and response timeout entries get removed
; awaiting response gets converted into a response timeout, with a
; short life time - this allows queued packets to be flushed
arp_003:
movzx edx, byte [NumARP]
cmp edx, 0
je arp_exit
 
; EDX holds the # of entries to search through
mov eax, 0
 
arp_005:
cmp word [ eax + ARPTable + 12], 0
jne arp_004
 
; If it's status code is 0001 or 0003, delete the entry
cmp word [eax + ARPTable + 10], 0x0100
je arp_007
cmp word [eax + ARPTable + 10], 0x0300
je arp_007
 
; The only other valid code is 0002 - indicating a
; timeout while waiting for a response. Change the
; entry to response timed out
 
mov [eax + ARPTable + 10], word 0x0300
mov [eax + ARPTable + 12], word 0x000A
jmp arp_004
 
arp_007:
; Delete this entry
mov edi, ARPTable
add edi, eax
mov esi, edi
add esi, ARP_ENTRY_SIZE
 
mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY_SIZE
sub ecx, eax
 
rep movsb
 
dec byte [NumARP]
jmp arp_006
 
arp_004:
add eax, ARP_ENTRY_SIZE
arp_006:
dec edx
cmp edx, 0
jne arp_005
 
arp_exit:
ret
 
;***************************************************************************
; Function
; arp_request
;
; Description
; Sends an ARP request on the ethernet
; The requested IP address is in edx
; All registers may be destroyed
;
;***************************************************************************
arp_request:
mov ebx, Ether_buffer
mov ax, 0x0100
mov [ebx], ax
add ebx, 2
 
mov ax, 0x0008
mov [ebx], ax
add ebx, 2
 
mov ax, 0x0406
mov [ebx], ax
add ebx, 2
 
mov ax, 0x0100
mov [ebx], ax
add ebx, 2
 
mov ecx, node_addr
mov eax, [ecx]
mov [ebx], eax
add ecx, 4
add ebx, 4
mov ax, [ecx]
mov [ebx], ax
add ebx, 2
mov eax, [stack_ip]
mov [ebx], eax
add ebx, 4
 
xor eax, eax
mov [ebx], eax
add ebx, 4
mov [ebx], ax
 
add ebx, 2
mov [ebx], edx
 
; Now, send it!
 
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
mov edi, broadcast_add
 
;if DEBUGGING_STATE = DEBUGGING_ENABLED
; pusha
; mov eax, 1 ; Indicate that this is a tx packet
; mov ecx, 28
; mov esi, Ether_buffer
; call eth_dump
; popa
;end if
 
mov bx, ETHER_ARP
mov ecx, 28
mov esi, Ether_buffer
call dword [drvr_transmit] ; Call the drivers transmit function
ret
 
;***************************************************************************
; Function
; arp_handler
;
; Description
; Called when an ARP packet is received on the ethernet
; Header + Data is in Ether_buffer[]
; It looks to see if the packet is a request to resolve this Hosts
; IP address. If it is, send the ARP reply packet.
; This Hosts IP address is in dword [stack_ip] ( in network format )
; This Hosts MAC address is in node_addr[6]
; All registers may be destroyed
;
;***************************************************************************
arp_handler:
; Is this a REQUEST?
; Is this a request for My Host IP
; Yes - So construct a response message.
; Send this message to the ethernet card for transmission
 
mov ebx, Ether_buffer
 
mov edx, ebx
add edx, 20
mov ax, [edx]
cmp ax, ARP_REQ_OPCODE ; Is this a request packet?
jne arph_resp ; No - so test for response
 
mov edx, ebx
add edx, 38
mov eax, [edx]
 
cmp eax, [stack_ip] ; Is it looking for my IP address?
jne arph_exit ; No - so quit now
 
; OK, it is a request for my MAC address. Build the frame and send it
 
; Save the important data from the original packet
; remote MAC address first
mov ecx, remote_hw_add
mov edx, ebx
add edx, 22 ; edx points to Source h/w address
mov eax, [edx]
mov [ecx], eax
add edx, 4
add ecx, 4
mov ax, [edx]
mov [ecx],ax
 
; and also the remote IP address
add edx, 2
mov eax,[edx]
mov [remote_ip_add], eax
 
; So now we can reuse the packet. ebx still holds the address of
; the header + packet
; We dont need the header ( first 14 bytes )
 
mov edx, ebx
add edx, 20
mov ax, ARP_REP_OPCODE
mov [edx], ax
add edx, 2
 
mov ecx, node_addr
mov eax, [ecx]
mov [edx], eax
add ecx, 4
add edx, 4
mov ax, [ecx]
mov [edx], ax
add edx, 2
mov eax, [stack_ip]
mov [edx], eax
add edx, 4
mov ecx, remote_hw_add
mov eax, [ecx]
mov [edx], eax
add ecx, 4
add edx, 4
mov ax, [ecx]
mov [edx], ax
 
add edx, 2
mov eax, [remote_ip_add]
mov [edx], eax
 
; Now, send it!
 
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
mov edi, remote_hw_add
 
;if DEBUGGING_STATE = DEBUGGING_ENABLED
; pusha
; mov eax, 1 ; Indicate that this is a tx packet
; mov ecx, 28
; mov esi, Ether_buffer + 14
; call eth_dump
; popa
;end if
 
mov bx, ETHER_ARP
mov ecx, 28
mov esi, Ether_buffer + 14
call dword [drvr_transmit] ; Call the drivers transmit function
jmp arph_exit
 
arph_resp:
cmp ax, ARP_REP_OPCODE ; Is this a replypacket?
jne arph_resp ; No - so quit
 
; This was a reply, probably directed at me.
; save the remotes MAC & IP
mov ecx, remote_hw_add
mov edx, ebx
add edx, 22 ; edx points to Source h/w address
mov eax, [edx]
mov [ecx], eax
add edx, 4
add ecx, 4
mov ax, [edx]
mov [ecx],ax
 
; and also the remote IP address
add edx, 2
mov eax,[edx]
mov [remote_ip_add], eax
 
; Now, add an entry in the table for this IP address if it doesn't exist
 
push eax
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
pop edx
movzx ecx, byte [NumARP]
cmp ecx, 0
je arph_002
 
arph_001:
sub eax, ARP_ENTRY_SIZE
cmp [eax + ARPTable], edx
loopnz arph_001 ; Return back if non match
 
jnz arph_002 ; None found, add to end
 
mov ecx, [remote_hw_add]
mov [eax + ARPTable + 4], ecx
mov cx, [remote_hw_add+4]
mov [eax + ARPTable + 8], cx
 
; specify the type - a valid entry
mov cl, 0x00
mov [eax + ARPTable + 10], cl
mov cl, 0x01
mov [eax + ARPTable + 11], cl
 
; Initialise the time to live field - 1 hour
mov cx, 0x0E10
mov [eax + ARPTable + 12], cx
jmp arph_exit
 
arph_002:
 
cmp byte [NumARP], ARP_TABLE_SIZE
je arph_exit
 
inc byte [NumARP]
 
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
sub eax, ARP_ENTRY_SIZE
 
mov ecx, [remote_ip_add]
mov [eax + ARPTable], ecx
mov ecx, [remote_hw_add]
mov [eax + ARPTable + 4], ecx
mov cx, [remote_hw_add+4]
mov [eax + ARPTable + 8], cx
 
mov cl, 0x00
mov [eax + ARPTable + 10], cl
mov cl, 0x01
mov [eax + ARPTable + 11], cl
 
; Initialise the time to live field - 1 hour
mov cx, 0x0E10
mov [eax + ARPTable + 12], cx
 
arph_exit:
ret
 
; pointer to MAC in esi
refreshARP:
mov ebx, [esi]
mov dx, [esi+4]
push edx
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
pop edx
movzx ecx, byte [NumARP]
cmp ecx, 0
je rf_exit
 
rf_001:
sub eax, ARP_ENTRY_SIZE
cmp [eax + ARPTable+4], ebx
 
je rf_002
loop rf_001
jmp rf_exit
 
rf_002:
cmp [eax + ARPTable+8], dx
je rf_gotone
loop rf_001
jmp rf_exit
 
rf_gotone:
; Initialise the time to live field - 1 hour
mov cx, 0x0E10
mov [eax + ARPTable + 12], cx
 
rf_exit:
ret
 
;***************************************************************************
; Function
; getMACfromIP
;
; Description
; Takes an IP address in edx and scans the ARP table for
; a matching entry
; If a match is found, it's MAC address is stored in MACAddress.
; Otherwise the value 0 is writen to MACAddress
; eax holds ARP table entry status code ( ARP_ )
; ebx unchanged
;
;***************************************************************************
getMACfromIP:
; first, check destination IP to see if it is on 'this' network.
; The test is:
; if ( destIP & subnet_mask == stack_ip & subnet_mask )
; desitnation is local
; else
; destination is remote, so pass to gateway
 
mov eax, edx
and eax, [subnet_mask]
mov ecx, [stack_ip]
and ecx, [subnet_mask]
cmp eax, ecx
je gm0
 
mov edx, [gateway_ip]
gm0:
push edx
xor eax, eax
mov [MACAddress], eax
mov [MACAddress + 4], ax
 
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
 
pop edx
 
movzx ecx, byte [NumARP]
cmp ecx, 0
je gm_none
gm1:
sub eax, ARP_ENTRY_SIZE
cmp [eax + ARPTable], edx
loopnz gm1 ; Return back if non match
jnz gm_none ; Quit if none found
 
; eax holds index
mov ecx, [eax + ARPTable + 4]
mov [MACAddress], ecx
mov cx, [eax + ARPTable + 8]
mov [MACAddress+4], cx
 
; Return the entry status in eax
mov ch, [eax + ARPTable + 10]
mov cl, [eax + ARPTable + 11]
movzx eax, cx
jmp gm_exit
 
gm_none:
mov eax, ARP_NO_ENTRY
 
gm_exit:
ret
 
;***************************************************************************
;
; PCI CODE FOLLOWS
;
; the following functions provide access to the PCI interface.
; These functions are used by scan_bus, and also some ethernet drivers
;
;***************************************************************************
 
;***************************************************************************
; Function
; config_cmd
;
; Description
; creates a command dword for use with the PCI bus
; bus # in ebx
; devfn in ecx
; where in edx
;
; command dword returned in eax
; Only eax destroyed
;***************************************************************************
config_cmd:
push ecx
mov eax, ebx
shl eax, 16
or eax, 0x80000000
shl ecx, 8
or eax, ecx
pop ecx
or eax, edx
and eax, 0xFFFFFFFC
ret
 
;***************************************************************************
; Function
; pcibios_read_config_byte
;
; Description
; reads a byte from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; byte returned in al ( rest of eax zero )
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_byte:
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
 
xor eax, eax
and dx, 0x03
add dx, 0xCFC
; and dx, 0xFFC
in al, dx
ret
 
;***************************************************************************
; Function
; pcibios_read_config_word
;
; Description
; reads a word from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; word returned in ax ( rest of eax zero )
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_word:
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
 
xor eax, eax
and dx, 0x02
add dx, 0xCFC
; and dx, 0xFFC
in ax, dx
ret
 
;***************************************************************************
; Function
; pcibios_read_config_dword
;
; Description
; reads a dword from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; dword returned in eax
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_dword:
push edx
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
xor eax, eax
mov dx, 0xCFC
in eax, dx
pop edx
ret
 
;***************************************************************************
; Function
; pcibios_write_config_byte
;
; Description
; write a byte in al to the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; Only eax/edx destroyed
;***************************************************************************
pcibios_write_config_byte:
push ax
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
pop ax
 
and dx, 0x03
add dx, 0xCFC
out dx, al
ret
 
;***************************************************************************
; Function
; pcibios_write_config_word
;
; Description
; write a word in ax to the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; Only eax/edx destroyed
;***************************************************************************
pcibios_write_config_word:
push ax
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
pop ax
 
and dx, 0x02
add dx, 0xCFC
out dx, ax
ret
 
;***************************************************************************
; Function
; delay_us
;
; Description
; delays for 30 to 60 us
;
; I would prefer this routine to be able to delay for
; a selectable number of microseconds, but this works for now.
;
; If you know a better way to do 2us delay, pleae tell me!
;***************************************************************************
delay_us:
push eax
push ecx
 
mov ecx,2
 
in al,0x61
and al,0x10
mov ah,al
cld
 
dcnt1:
in al,0x61
and al,0x10
cmp al,ah
jz dcnt1
 
mov ah,al
loop dcnt1
 
pop ecx
pop eax
 
ret
 
;***************************************************************************
; Function
; scan_bus
;
; Description
; Scans the PCI bus for a supported device
; If a supported device is found, the drvr_ variables are initialised
; to that drivers functions ( as defined in the PCICards table)
;
; io_addr holds card I/O space. 32 bit, but only LS 16 bits valid
; pci_data holds the PCI vendor + device code
; pci_dev holds PCI bus dev #
; pci_bus holds PCI bus #
;
; io_addr will be zero if no card found
;
;***************************************************************************
scan_bus:
xor eax, eax
mov [hdrtype], al
mov [pci_data], eax
 
xor ebx, ebx ; ebx = bus# 0 .. 255
 
sb_bus_loop:
xor ecx, ecx ; ecx = devfn# 0 .. 254 ( not 255? )
 
sb_devf_loop:
mov eax, ecx
and eax, 0x07
 
cmp eax, 0
jne sb_001
 
mov edx, PCI_HEADER_TYPE
call pcibios_read_config_byte
mov [hdrtype], al
jmp sb_002
 
sb_001:
mov al, [hdrtype]
and al, 0x80
cmp al, 0x80
jne sb_inc_devf
 
sb_002:
mov edx, PCI_VENDOR_ID
call pcibios_read_config_dword
mov [vendor_device], eax
cmp eax, 0xffffffff
je sb_empty
cmp eax, 0
jne sb_check_vendor
 
sb_empty:
mov [hdrtype], byte 0
jmp sb_inc_devf
 
sb_check_vendor:
; iterate though PCICards until end or match found
mov esi, PCICards
 
sb_check:
cmp [esi], dword 0
je sb_inc_devf ; Quit if at last entry
cmp eax, [esi]
je sb_got_card
add esi, PCICARDS_ENTRY_SIZE
jmp sb_check
 
sb_got_card:
; indicate that we have found the card
mov [pci_data], eax
mov [pci_dev], ecx
mov [pci_bus], ebx
 
; Define the driver functions
push eax
mov eax, [esi+4]
mov [drvr_probe], eax
mov eax, [esi+8]
mov [drvr_reset], eax
mov eax, [esi+12]
mov [drvr_poll], eax
mov eax, [esi+16]
mov [drvr_transmit], eax
pop eax
 
mov edx, PCI_BASE_ADDRESS_0
 
sb_reg_check:
call pcibios_read_config_dword
mov [io_addr], eax
and eax, PCI_BASE_ADDRESS_IO_MASK
cmp eax, 0
je sb_inc_reg
mov eax, [io_addr]
and eax, PCI_BASE_ADDRESS_SPACE_IO
cmp eax, 0
je sb_inc_reg
 
mov eax, [io_addr]
and eax, PCI_BASE_ADDRESS_IO_MASK
mov [io_addr], eax
 
sb_exit1:
ret
 
sb_inc_reg:
add edx, 4
cmp edx, PCI_BASE_ADDRESS_5
jbe sb_reg_check
 
sb_inc_devf:
inc ecx
cmp ecx, 255
jb sb_devf_loop
inc ebx
cmp ebx, 256
jb sb_bus_loop
 
; We get here if we didn't find our card
; set io_addr to 0 as an indication
xor eax, eax
mov [io_addr], eax
 
sb_exit2:
ret
 
;***************************************************************************
;
; DEBUGGING CODE FOLLOWS
;
; If debugging data output is not required, ALL code & data below may
; be removed.
;
;***************************************************************************
 
if DEBUGGING_STATE = DEBUGGING_ENABLED
 
;***************************************************************************
; Function
; eth_dump
;
; Description
; Dumps a tx or rx ethernet packet over the rs232 link
; This is a debugging routine that seriously slows down the stack.
; Use with caution.
;
; Baud rate is 57600, 8n1 com1
; eax : type (0 == rx, 1 == tx )
; cx : # of bytes in buffer
; esi : address of buffer start
; edi : pointer to MACAddress ( tx only )
;
;***************************************************************************
eth_dump:
pusha
 
; Set the port to the desired speed
mov ebx, 0x3f8 ; combase
 
mov edx, ebx
add edx, 3 ; data format register
mov al, 0x80 ; enable access to divisor latch
out dx, al
 
mov edx, ebx
add edx, 1 ; interrupt enable register
mov al, 0x00 ; No interruts enabled
out dx, al
 
mov edx, ebx
mov al, 0x20 / 16 ; set baud rate to 57600 0x10 =115200
out dx, al
 
mov edx, ebx
add edx, 3 ; data format register
mov al, 0x03 ; 8 data bits
out dx, al
 
mov edx, ebx
add edx, 4 ; Modem control register
mov al, 0x08 ; out2 enabled. No handshaking.
out dx, al
 
mov edx, ebx
add edx, 1 ; interrupt enable register
mov al, 0x01 ; Receive data interrupt enabled,
out dx, al
 
popa
 
; First, display the type of the buffer.
; If it is a tx buffer, display the macaddress
 
pusha
 
cmp eax, 0
jne dd001
 
mov bl, 0x0a
call tx_byted
mov bl, 0x0d
call tx_byted
 
; Output "RX:"
mov bl, 'R'
call tx_byted
mov bl, 'X'
call tx_byted
mov bl, ':'
call tx_byted
jmp dump_data
 
dd001:
mov bl, 0x0a
call tx_byted
mov bl, 0x0d
call tx_byted
 
; Output TX: xxxxxxxxxxxx
mov bl, 'T'
call tx_byted
mov bl, 'X'
call tx_byted
mov bl, ':'
call tx_byted
mov bl, ' '
call tx_byted
 
; Display MAC address
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
dump_data:
popa
 
; OK, we come in here with
; cx == number of byte to send
; esi == buffer start
;
dd_000:
mov bl, 0x0a
call tx_byted
mov bl, 0x0d
call tx_byted
 
mov eax, 16 ; Number of characters on the line
mov edi, esi ; Save first byte position for later
 
push ecx
 
dd_001:
push eax
 
; Print a byte, and a space
xor eax, eax
mov al, [esi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [esi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
mov bl, ' '
call tx_byted
 
pop eax
 
inc esi
dec ecx
cmp ecx, 0
je dd_0011 ; Print the ASCII format
 
dec eax
 
cmp eax, 0
je dd_002 ; Print the ASCII format
jmp dd_001 ; Print rest of line
 
dd_0011:
; First, complete the 16 bytes of data, by printing spaces
dec eax
cmp eax, 0
je dd_002
 
push eax
mov bl, ' '
call tx_byted
mov bl, ' '
call tx_byted
mov bl, ' '
call tx_byted
pop eax
jmp dd_0011
 
dd_002:
pop ecx
mov esi, edi ; Go back to the start of the line data
 
mov eax, 16
 
outLineAscii:
push eax
 
xor eax, eax
mov al, [esi]
mov bl, '.'
 
cmp al, 0x1F
jle outAscii
cmp al, 0x7e
jge outAscii
 
mov bl, al
 
outAscii:
call tx_byted ; byte in bl eax ebx edx destroyed
 
pop eax
dec ecx
inc esi
cmp ecx, 0
je dd_003
 
dec eax
cmp eax, 0
je dd_003
jmp outLineAscii
 
dd_003:
cmp ecx, 0
je dd_004
jmp dd_000
 
dd_004:
ret
 
;***************************************************************************
; Function
; tx_byte
;
; Description
; Send a byte in bl out of the com port 1
; destroys eax, edx
;
;***************************************************************************
tx_byted:
push ebx ; Save the byte
 
mov ebx, 0x3f8 ; get the com port address
 
; Wait for transmit buffer to empty. This could take 1ms @ 9600baud
 
mov edx, ebx
add edx, 5
 
wait_txd:
in al, dx ; read uart serialisation status
and al, 0x40
cmp al, 0
jz wait_txd ; loop until free
 
mov edx, ebx
pop eax ; restore the byte to send
out dx, al
ret
 
iglobal
; This is used for translating hex to ASCII for display or output
hexchars db '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
endg
end if
 
/kernel/trunk/network/eth_drv/i8255x.inc
0,0 → 1,739
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; I8255X.INC ;;
;; ;;
;; Ethernet driver for Menuet OS ;;
;; ;;
;; Version 0.3 11 August 2003 ;;
;; ;;
;; This driver is based on the eepro100 driver from ;;
;; the etherboot 5.0.6 project. The copyright statement is ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; remaining parts Copyright 2002 Mike Hibbett, ;;
;; mikeh@oceanfree.net ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
;********************************************************************
; Interface
; I8255x_reset
; I8255x_probe
; I8255x_poll
; I8255x_transmit
;
; These functions are referenced in ethernet.inc
;
;********************************************************************
 
 
rxfd_status equ eth_data_start
rxfd_command equ eth_data_start + 2
rxfd_link equ eth_data_start + 4
rxfd_rx_buf_addr equ eth_data_start + 8
rxfd_count equ eth_data_start + 12
rxfd_size equ eth_data_start + 14
rxfd_packet equ eth_data_start + 16
 
 
 
uglobal
eeprom_data: times 16 dd 0
 
align 4
 
lstats:
tx_good_frames: dd 0
tx_coll16_errs: dd 0
tx_late_colls: dd 0
tx_underruns: dd 0
tx_lost_carrier: dd 0
tx_deferred: dd 0
tx_one_colls: dd 0
tx_multi_colls: dd 0
tx_total_colls: dd 0
rx_good_frames: dd 0
rx_crc_errs: dd 0
rx_align_errs: dd 0
rx_resource_errs: dd 0
rx_overrun_errs: dd 0
rx_colls_errs: dd 0
rx_runt_errs: dd 0
done_marker: dd 0
 
align 4
 
confcmd:
confcmd_status: dw 0
confcmd_command: dw 0
confcmd_link: dd 0
endg
 
iglobal
confcmd_data: db 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1
db 0, 0x2e, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2
db 0x80, 0x3f, 0x05
endg
 
uglobal
align 4
 
txfd:
txfd_status: dw 0
txfd_command: dw 0
txfd_link: dd 0
txfd_tx_desc_addr: dd 0
txfd_count: dd 0
txfd_tx_buf_addr0: dd 0
txfd_tx_buf_size0: dd 0
txfd_tx_buf_addr1: dd 0
txfd_tx_buf_size1: dd 0
 
align 4
 
hdr:
hdr_dst_addr: times 6 db 0
hdr_src_addr: times 6 db 0
hdr_type: dw 0
endg
 
 
;***************************************************************************
; Function
; wait_for_cmd_done
;
; Description
; waits for the hardware to complete a command
; port address in edx
;
; al destroyed
;***************************************************************************
wait_for_cmd_done:
in al, dx
cmp al, 0
jne wait_for_cmd_done
ret
 
 
 
;***************************************************************************
; Function
; mdio_read
;
; Description
; This probably reads a register in the "physical media interface chip"
; Phy_id in ebx
; location in ecx
;
; Data returned in eax
;
;***************************************************************************
mdio_read:
mov edx, [io_addr]
add edx, 16 ; SCBCtrlMDI
 
mov eax, 0x08000000
shl ecx, 16
or eax, ecx
shl ebx, 21
or eax, ebx
 
out dx, eax
 
mrlp:
call delay_us
in eax, dx
mov ecx, eax
and ecx, 0x10000000
jz mrlp
 
and eax, 0xffff
ret
 
 
 
;***************************************************************************
; Function
; mdio_write
;
; Description
; This probably writes a register in the "physical media interface chip"
; Phy_id in ebx
; location in ecx
; data in edx
; Data returned in eax
;
;***************************************************************************
mdio_write:
mov eax, 0x04000000
shl ecx, 16
or eax, ecx
shl ebx, 21
or eax, ebx
or eax, edx
 
mov edx, [io_addr]
add edx, 16 ; SCBCtrlMDI
out dx, eax
 
mwlp:
call delay_us
in eax, dx
mov ecx, eax
and ecx, 0x10000000
jz mwlp
 
and eax, 0xffff
ret
 
 
 
;/***********************************************************************/
;/* I82557 related defines */
;/***********************************************************************/
 
; Serial EEPROM section.
; A "bit" grungy, but we work our way through bit-by-bit :->.
; EEPROM_Ctrl bits.
EE_SHIFT_CLK equ 0x01 ; EEPROM shift clock.
EE_CS equ 0x02 ; EEPROM chip select.
EE_DATA_WRITE equ 0x04 ; EEPROM chip data in.
EE_DATA_READ equ 0x08 ; EEPROM chip data out.
EE_WRITE_0 equ 0x4802
EE_WRITE_1 equ 0x4806
EE_ENB equ 0x4802
 
 
; The EEPROM commands include the alway-set leading bit.
EE_READ_CMD equ 6
 
; The SCB accepts the following controls for the Tx and Rx units:
CU_START equ 0x0010
CU_RESUME equ 0x0020
CU_STATSADDR equ 0x0040
CU_SHOWSTATS equ 0x0050 ; Dump statistics counters.
CU_CMD_BASE equ 0x0060 ; Base address to add to add CU commands.
CU_DUMPSTATS equ 0x0070 ; Dump then reset stats counters.
 
RX_START equ 0x0001
RX_RESUME equ 0x0002
RX_ABORT equ 0x0004
RX_ADDR_LOAD equ 0x0006
RX_RESUMENR equ 0x0007
INT_MASK equ 0x0100
DRVR_INT equ 0x0200 ; Driver generated interrupt.
 
 
;***************************************************************************
; Function
; do_eeprom_cmd
;
; Description
; writes a cmd to the ethernet cards eeprom, by bit bashing
; cmd in ebx
; cmd length in ecx
; return in eax
;***************************************************************************
do_eeprom_cmd:
mov edx, [io_addr] ; We only require the value in dx
add dx, 14 ; the value SCBeeprom
 
mov ax, EE_ENB
out dx, ax
call delay_us
 
mov ax, 0x4803 ; EE_ENB | EE_SHIFT_CLK
out dx, ax
call delay_us
 
; dx holds ee_addr
; ecx holds count
; eax holds cmd
xor edi, edi ; this will be the receive data
 
dec_001:
mov esi, 1
 
dec ecx
shl esi, cl
inc ecx
and esi, ebx
mov eax, EE_WRITE_0 ; I am assuming this doesnt affect the flags..
cmp esi,0
jz dec_002
mov eax, EE_WRITE_1
 
dec_002:
out dx, ax
call delay_us
 
or ax, EE_SHIFT_CLK
out dx, ax
call delay_us
 
shl edi,1
 
in ax, dx
and ax, EE_DATA_READ
cmp ax,0
jz dec_003
inc edi
 
dec_003:
loop dec_001
 
mov ax, EE_ENB
out dx, ax
call delay_us
 
mov ax, 0x4800
out dx, ax
call delay_us
 
mov eax, edi
 
ret
 
 
 
;***************************************************************************
; Function
; I8255x_reset
; Description
; Place the chip (ie, the ethernet card) into a virgin state
; No inputs
; All registers destroyed
;
;***************************************************************************
I8255x_reset:
ret
 
 
 
;***************************************************************************
; Function
; I8255x_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
;
;***************************************************************************
I8255x_probe:
mov eax, [io_addr]
 
mov ebx, [pci_bus]
mov ecx, [pci_dev]
mov edx, 0x04 ; PCI_COMMAND
call pcibios_read_config_word
 
or ax, 0x05
mov ebx, [pci_bus]
mov ecx, [pci_dev]
mov edx, 0x04 ; PCI_COMMAND
call pcibios_write_config_word
 
mov ebx, 0x6000000
mov ecx, 27
call do_eeprom_cmd
and eax, 0xffe0000
cmp eax, 0xffe0000
je bige
 
mov ebx, 0x1800000
mov ecx, 0x40
jmp doread
 
bige:
mov ebx, 0x6000000
mov ecx, 0x100
 
doread:
; do-eeprom-cmd will destroy all registers
; we have eesize in ecx
; read_cmd in ebx
 
; Ignore full eeprom - just load the mac address
mov ecx, 0
 
drlp:
push ecx ; save count
push ebx
mov eax, ecx
shl eax, 16
or ebx, eax
mov ecx, 27
call do_eeprom_cmd
 
pop ebx
pop ecx
 
mov edx, ecx
shl edx, 2
mov esi, eeprom_data
add esi, edx
mov [esi], eax
 
inc ecx
cmp ecx, 16
jne drlp
 
; OK, we have the MAC address.
; Now reset the card
 
mov edx, [io_addr]
add dx, 8 ; SCBPort
xor eax, eax ; The reset cmd == 0
out dx, eax
 
mov esi, 10
call delay_ms ; Give the card time to warm up.
 
mov eax, lstats
mov edx, [io_addr]
add edx, 4 ; SCBPointer
out dx, eax
 
mov eax, 0x0140 ; INT_MASK | CU_STATSADDR
mov edx, [io_addr]
add edx, 2 ; SCBCmd
out dx, ax
 
call wait_for_cmd_done
 
mov eax, 0
mov edx, [io_addr]
add edx, 4 ; SCBPointer
out dx, eax
 
mov eax, 0x0106 ; INT_MASK | RX_ADDR_LOAD
mov edx, [io_addr]
add edx, 2 ; SCBCmd
out dx, ax
 
call wait_for_cmd_done
 
; build rxrd structure
mov ax, 0x0001
mov [rxfd_status], ax
mov ax, 0x0000
mov [rxfd_command], ax
 
mov eax, rxfd_status
mov [rxfd_link], eax
 
mov eax, Ether_buffer
mov [rxfd_rx_buf_addr], eax
 
mov ax, 0
mov [rxfd_count], ax
 
mov ax, 1528
mov [rxfd_size], ax
 
mov edx, [io_addr]
add edx, 4 ; SCBPointer
 
mov eax, rxfd_status
out dx, eax
 
mov edx, [io_addr]
add edx, 2 ; SCBCmd
 
mov ax, 0x0101 ; INT_MASK | RX_START
out dx, ax
 
call wait_for_cmd_done
 
; start the reciver
 
mov ax, 0
mov [rxfd_status], ax
 
mov ax, 0xc000
mov [rxfd_command], ax
 
mov edx, [io_addr]
add edx, 4 ; SCBPointer
 
mov eax, rxfd_status
out dx, eax
 
mov edx, [io_addr]
add edx, 2 ; SCBCmd
 
mov ax, 0x0101 ; INT_MASK | RX_START
out dx, ax
 
; Init TX Stuff
 
mov edx, [io_addr]
add edx, 4 ; SCBPointer
 
mov eax, 0
out dx, eax
 
mov edx, [io_addr]
add edx, 2 ; SCBCmd
 
mov ax, 0x0160 ; INT_MASK | CU_CMD_BASE
out dx, ax
 
call wait_for_cmd_done
 
; Set TX Base address
 
; First, set up confcmd values
 
mov ax, 2
mov [confcmd_command], ax
mov eax, txfd
mov [confcmd_link], eax
 
mov ax, 1
mov [txfd_command], ax ; CmdIASetup
 
mov ax, 0
mov [txfd_status], ax
 
mov eax, confcmd
mov [txfd_link], eax
 
; ETH_ALEN is 6 bytes
 
mov esi, eeprom_data
mov edi, node_addr
mov ecx, 3
drp000:
mov eax, [esi]
mov [edi], al
shr eax, 8
inc edi
mov [edi], al
inc edi
add esi, 4
loop drp000
 
; Hard code your MAC address into node_addr at this point,
; If you cannot read the MAC address from the eeprom in the previous step.
; You also have to write the mac address into txfd_tx_desc_addr, rather
; than taking data from eeprom_data
 
mov esi, eeprom_data
mov edi, txfd_tx_desc_addr
mov ecx, 3
drp001:
mov eax, [esi]
mov [edi], al
shr eax, 8
inc edi
mov [edi], al
inc edi
add esi, 4
loop drp001
 
mov esi, eeprom_data + (6 * 4)
mov eax, [esi]
shr eax, 8
and eax, 0x3f
cmp eax, 4 ; DP83840
je drp002
cmp eax, 10 ; DP83840A
je drp002
jmp drp003
 
drp002:
mov ebx, [esi]
and ebx, 0x1f
push ebx
mov ecx, 23
call mdio_read
pop ebx
or eax, 0x0422
mov ecx, 23
mov edx, eax
call mdio_write
 
drp003:
mov ax, 0x4002 ; Cmdsuspend | CmdConfigure
mov [confcmd_command], ax
mov ax, 0
mov [confcmd_status], ax
mov eax, txfd
mov [confcmd_link], eax
mov ebx, confcmd_data
mov al, 0x88 ; fifo of 8 each
mov [ebx + 1], al
mov al, 0
mov [ebx + 4], al
mov al, 0x80
mov [ebx + 5], al
mov al, 0x48
mov [ebx + 15], al
mov al, 0x80
mov [ebx + 19], al
mov al, 0x05
mov [ebx + 21], al
 
mov eax, txfd
mov edx, [io_addr]
add edx, 4 ; SCBPointer
out dx, eax
 
mov eax, 0x0110 ; INT_MASK | CU_START
mov edx, [io_addr]
add edx, 2 ; SCBCmd
out dx, ax
 
call wait_for_cmd_done
jmp skip
 
; wait for thing to start
drp004:
mov ax, [txfd_status]
cmp ax, 0
je drp004
 
skip:
; Indicate that we have successfully reset the card
mov eax, [pci_data]
mov [eth_status], eax
 
I8255x_exit:
ret
 
 
 
;***************************************************************************
; Function
; I8255x_poll
;
; Description
; Polls the ethernet card for a received packet
; Received data, if any, ends up in Ether_buffer
;
;***************************************************************************
I8255x_poll:
mov ax, 0 ; assume no data
mov [eth_rx_data_len], ax
 
mov ax, [rxfd_status]
cmp ax, 0
je i8p_exit
 
mov ax, 0
mov [rxfd_status], ax
 
mov ax, 0xc000
mov [rxfd_command], ax
 
mov edx, [io_addr]
add edx, 4 ; SCBPointer
 
mov eax, rxfd_status
out dx, eax
 
mov edx, [io_addr]
add edx, 2 ; SCBCmd
 
mov ax, 0x0101 ; INT_MASK | RX_START
out dx, ax
 
call wait_for_cmd_done
 
mov esi, rxfd_packet
mov edi, Ether_buffer
mov ecx, 1518
cld
rep movsb
 
mov ax, [rxfd_count]
and ax, 0x3fff
mov [eth_rx_data_len], ax
 
i8p_exit:
ret
 
 
 
;***************************************************************************
; Function
; I8255x_transmit
;
; Description
; Transmits a packet of data via the ethernet card
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
;
;***************************************************************************
I8255x_transmit:
 
mov [hdr_type], bx
 
mov eax, [edi]
mov [hdr_dst_addr], eax
mov ax, [edi+4]
mov [hdr_dst_addr+4], ax
 
mov eax, [node_addr]
mov [hdr_src_addr], eax
mov ax, [node_addr+4]
mov [hdr_src_addr+4], ax
 
mov edx, [io_addr]
in ax, dx
and ax, 0xfc00
out dx, ax
 
xor ax, ax
mov [txfd_status], ax
mov ax, 0x400C ; Cmdsuspend | CmdTx | CmdTxFlex
mov [txfd_command], ax
mov eax, txfd
mov [txfd_link], eax
mov eax, 0x02208000
mov [txfd_count], eax
mov eax, txfd_tx_buf_addr0
mov [txfd_tx_desc_addr], eax
mov eax, hdr
mov [txfd_tx_buf_addr0], eax
mov eax, 14 ; sizeof hdr
mov [txfd_tx_buf_size0], eax
 
; Copy the buffer address and size in
mov eax, esi
mov [txfd_tx_buf_addr1], eax
mov eax, ecx
mov [txfd_tx_buf_size1], eax
 
mov eax, txfd
mov edx, [io_addr]
add edx, 4 ; SCBPointer
out dx, eax
 
mov ax, 0x0110 ; INT_MASK | CU_START
mov edx, [io_addr]
add edx, 2 ; SCBCmd
out dx, ax
 
call wait_for_cmd_done
 
mov edx, [io_addr]
in ax, dx
 
I8t_001:
mov ax, [txfd_status]
cmp ax, 0
je I8t_001
 
mov edx, [io_addr]
in ax, dx
 
ret
/kernel/trunk/network/eth_drv/pcnet32.inc
0,0 → 1,814
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; PCNET32.INC ;;
;; ;;
;; Ethernet driver for Menuet OS ;;
;; ;;
;; Version 1.0 31 July 2004 ;;
;; ;;
;; This driver is based on the PCNet32 driver from ;;
;; the etherboot 5.0.6 project. The copyright statement is ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; remaining parts Copyright 2004 Jarek Pelczar, ;;
;; jpelczar@interia.pl ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;macro PutStr X
;{
; local .__xyz1
; local .__xyz2
; push esi
; mov esi,.__xyz1
; call sys_msg_board_str
; push eax
; mov eax,1
; call delay_hs
; pop eax
; jmp .__xyz2
;.__xyz1:
; db X
; db 13,10,0
;.__xyz2:
; pop esi
;}
PCNET32_PORT_AUI equ 0x00
PCNET32_PORT_10BT equ 0x01
PCNET32_PORT_GPSI equ 0x02
PCNET32_PORT_MII equ 0x03
PCNET32_PORT_PORTSEL equ 0x03
PCNET32_PORT_ASEL equ 0x04
PCNET32_PORT_100 equ 0x40
PCNET32_PORT_FD equ 0x80
PCNET32_DMA_MASK equ 0xffffffff
PCNET32_LOG_TX_BUFFERS equ 1
PCNET32_LOG_RX_BUFFERS equ 2
PCNET32_TX_RING_SIZE equ (1 shl PCNET32_LOG_TX_BUFFERS)
PCNET32_TX_RING_MOD_MASK equ (PCNET32_TX_RING_SIZE-1)
PCNET32_TX_RING_LEN_BITS equ 0
PCNET32_RX_RING_SIZE equ (1 shl PCNET32_LOG_RX_BUFFERS)
PCNET32_RX_RING_MOD_MASK equ (PCNET32_RX_RING_SIZE-1)
PCNET32_RX_RING_LEN_BITS equ (PCNET32_LOG_RX_BUFFERS shl 4)
PCNET32_PKT_BUF_SZ equ 1544
PCNET32_PKT_BUF_SZ_NEG equ 0xf9f8
pcnet32_txb equ (eth_data_start)
pcnet32_rxb equ ((pcnet32_txb+(PCNET32_PKT_BUF_SZ*PCNET32_TX_RING_SIZE)+0xf) and 0xfffffff0)
pcnet32_tx_ring equ ((pcnet32_rxb+(PCNET32_PKT_BUF_SZ*PCNET32_RX_RING_SIZE)+0xf) and 0xfffffff0)
pcnet32_rx_ring equ ((pcnet32_tx_ring+(16*PCNET32_TX_RING_SIZE)+0xf) and 0xfffffff0)
virtual at ((pcnet32_rx_ring+(16*PCNET32_RX_RING_SIZE)+0xf) and 0xfffffff0)
pcnet32_private:
.mode dw ?
.tlen_rlen dw ?
.phys_addr db ?,?,?,?,?,?
.reserved dw ?
.filter dd ?,?
.rx_ring dd ?
.tx_ring dd ?
.cur_rx dd ?
.cur_tx dd ?
.dirty_rx dd ?
.dirty_tx dd ?
.tx_full db ?
.options dd ?
.full_duplex db ?
.chip_version dd ?
.mii db ?
.ltint db ?
.dxsuflo db ?
.fset db ?
.fdx db ?
end virtual
virtual at 0
pcnet32_rx_head:
.base dd ?
.buf_length dw ?
.status dw ?
.msg_length dd ?
.reserved dd ?
end virtual
virtual at 0
pcnet32_tx_head:
.base dd ?
.length dw ?
.status dw ?
.misc dd ?
.reserved dd ?
end virtual
 
uglobal
pcnet32_access:
.read_csr dd ?
.write_csr dd ?
.read_bcr dd ?
.write_bcr dd ?
.read_rap dd ?
.write_rap dd ?
.reset dd ?
endg
 
iglobal
pcnet32_options_mapping:
dd PCNET32_PORT_ASEL ; 0 Auto-select
dd PCNET32_PORT_AUI ; 1 BNC/AUI
dd PCNET32_PORT_AUI ; 2 AUI/BNC
dd PCNET32_PORT_ASEL ; 3 not supported
dd PCNET32_PORT_10BT or PCNET32_PORT_FD ; 4 10baseT-FD
dd PCNET32_PORT_ASEL ; 5 not supported
dd PCNET32_PORT_ASEL ; 6 not supported
dd PCNET32_PORT_ASEL ; 7 not supported
dd PCNET32_PORT_ASEL ; 8 not supported
dd PCNET32_PORT_MII ; 9 MII 10baseT
dd PCNET32_PORT_MII or PCNET32_PORT_FD ; 10 MII 10baseT-FD
dd PCNET32_PORT_MII ; 11 MII (autosel)
dd PCNET32_PORT_10BT ; 12 10BaseT
dd PCNET32_PORT_MII or PCNET32_PORT_100 ; 13 MII 100BaseTx
dd PCNET32_PORT_MII or PCNET32_PORT_100 or PCNET32_PORT_FD ; 14 MII 100BaseTx-FD
dd PCNET32_PORT_ASEL ; 15 not supported
endg
 
PCNET32_WIO_RDP equ 0x10
PCNET32_WIO_RAP equ 0x12
PCNET32_WIO_RESET equ 0x14
PCNET32_WIO_BDP equ 0x16
PCNET32_DWIO_RDP equ 0x10
PCNET32_DWIO_RAP equ 0x14
PCNET32_DWIO_RESET equ 0x18
PCNET32_DWIO_BDP equ 0x1C
PCNET32_TOTAL_SIZE equ 0x20
; ebx - index
; return:
; eax - data
pcnet32_wio_read_csr:
push edx
lea edx,[ebp+PCNET32_WIO_RAP]
mov ax,bx
out dx,ax
lea edx,[ebp+PCNET32_WIO_RDP]
in ax,dx
and eax,0xffff
pop edx
ret
; eax - data
; ebx - index
pcnet32_wio_write_csr:
push edx
lea edx,[ebp+PCNET32_WIO_RAP]
xchg eax,ebx
out dx,ax
xchg eax,ebx
lea edx,[ebp+PCNET32_WIO_RDP]
out dx,ax
pop edx
ret
; ebx - index
; return:
; eax - data
pcnet32_wio_read_bcr:
push edx
lea edx,[ebp+PCNET32_WIO_RAP]
mov ax,bx
out dx,ax
lea edx,[ebp+PCNET32_WIO_BDP]
in ax,dx
and eax,0xffff
pop edx
ret
; eax - data
; ebx - index
pcnet32_wio_write_bcr:
push edx
lea edx,[ebp+PCNET32_WIO_RAP]
xchg eax,ebx
out dx,ax
xchg eax,ebx
lea edx,[ebp+PCNET32_WIO_BDP]
out dx,ax
pop edx
ret
pcnet32_wio_read_rap:
push edx
lea edx,[ebp+PCNET32_WIO_RAP]
in ax,dx
and eax,0xffff
pop edx
ret
; eax - val
pcnet32_wio_write_rap:
push edx
lea edx,[ebp+PCNET32_WIO_RAP]
out dx,ax
pop edx
ret
pcnet32_wio_reset:
push edx
push eax
lea edx,[ebp+PCNET32_WIO_RESET]
in ax,dx
pop eax
pop edx
ret
pcnet32_wio_check:
push edx
mov ax,88
lea edx,[ebp+PCNET32_WIO_RAP]
out dx,ax
nop
nop
in ax,dx
cmp ax,88
sete al
pop edx
ret
 
iglobal
pcnet32_wio:
dd pcnet32_wio_read_csr
dd pcnet32_wio_write_csr
dd pcnet32_wio_read_bcr
dd pcnet32_wio_write_bcr
dd pcnet32_wio_read_rap
dd pcnet32_wio_write_rap
dd pcnet32_wio_reset
endg
 
; ebx - index
; return:
; eax - data
pcnet32_dwio_read_csr:
push edx
lea edx,[ebp+PCNET32_DWIO_RAP]
mov ebx,eax
out dx,eax
lea edx,[ebp+PCNET32_DWIO_RDP]
in eax,dx
and eax,0xffff
pop edx
ret
; ebx - index
; eax - data
pcnet32_dwio_write_csr:
push edx
lea edx,[ebp+PCNET32_DWIO_RAP]
xchg eax,ebx
out dx,eax
lea edx,[ebp+PCNET32_DWIO_RDP]
xchg eax,ebx
out dx,eax
pop edx
ret
; ebx - index
; return:
; eax - data
pcnet32_dwio_read_bcr:
push edx
lea edx,[ebp+PCNET32_DWIO_RAP]
mov ebx,eax
out dx,eax
lea edx,[ebp+PCNET32_DWIO_BDP]
in eax,dx
and eax,0xffff
pop edx
ret
; ebx - index
; eax - data
pcnet32_dwio_write_bcr:
push edx
lea edx,[ebp+PCNET32_DWIO_RAP]
xchg eax,ebx
out dx,eax
lea edx,[ebp+PCNET32_DWIO_BDP]
xchg eax,ebx
out dx,eax
pop edx
ret
pcnet32_dwio_read_rap:
push edx
lea edx,[ebp+PCNET32_DWIO_RAP]
in eax,dx
and eax,0xffff
pop edx
ret
; eax - val
pcnet32_dwio_write_rap:
push edx
lea edx,[ebp+PCNET32_DWIO_RAP]
out dx,eax
pop edx
ret
pcnet32_dwio_reset:
push edx
push eax
lea edx,[ebp+PCNET32_DWIO_RESET]
in eax,dx
pop eax
pop edx
ret
pcnet32_dwio_check:
push edx
lea edx,[PCNET32_DWIO_RAP]
mov eax,88
out dx,eax
nop
nop
in eax,dx
and eax,0xffff
cmp eax,88
sete al
pop edx
ret
 
iglobal
pcnet32_dwio:
dd pcnet32_dwio_read_csr
dd pcnet32_dwio_write_csr
dd pcnet32_dwio_read_bcr
dd pcnet32_dwio_write_bcr
dd pcnet32_dwio_read_rap
dd pcnet32_dwio_write_rap
dd pcnet32_dwio_reset
endg
 
pcnet32_init_ring:
mov [pcnet32_private.tx_full],0
mov [pcnet32_private.cur_rx],0
mov [pcnet32_private.cur_tx],0
mov [pcnet32_private.dirty_rx],0
mov [pcnet32_private.dirty_tx],0
mov edi,pcnet32_rx_ring
mov ecx,PCNET32_RX_RING_SIZE
mov ebx,pcnet32_rxb
.rx_init:
mov [edi+pcnet32_rx_head.base],ebx
mov [edi+pcnet32_rx_head.buf_length],word PCNET32_PKT_BUF_SZ_NEG
mov [edi+pcnet32_rx_head.status],word 0x8000
add ebx,PCNET32_PKT_BUF_SZ
; inc ebx
add edi,16
loop .rx_init
mov edi,pcnet32_tx_ring
mov ecx,PCNET32_TX_RING_SIZE
.tx_init:
mov [edi+pcnet32_tx_head.base],dword 0
mov [edi+pcnet32_tx_head.status],word 0
add edi,16
loop .tx_init
mov [pcnet32_private.tlen_rlen],(PCNET32_TX_RING_LEN_BITS or PCNET32_RX_RING_LEN_BITS)
mov esi,node_addr
mov edi,pcnet32_private.phys_addr
cld
movsd
movsw
mov dword [pcnet32_private.rx_ring],pcnet32_rx_ring
mov dword [pcnet32_private.tx_ring],pcnet32_tx_ring
ret
pcnet32_reset:
; Reset PCNET32
mov ebp,[io_addr]
call dword [pcnet32_access.reset]
; set 32bit mode
mov ebx,20
mov eax,2
call dword [pcnet32_access.write_bcr]
; set/reset autoselect bit
mov ebx,2
call dword [pcnet32_access.read_bcr]
and eax,not 2
test [pcnet32_private.options],PCNET32_PORT_ASEL
jz .L1
or eax,2
.L1:
call dword [pcnet32_access.write_bcr]
; Handle full duplex setting
cmp byte [pcnet32_private.full_duplex],0
je .L2
mov ebx,9
call dword [pcnet32_access.read_bcr]
and eax,not 3
test [pcnet32_private.options],PCNET32_PORT_FD
jz .L3
or eax,1
cmp [pcnet32_private.options],PCNET32_PORT_FD or PCNET32_PORT_AUI
jne .L4
or eax,2
jmp .L4
.L3:
test [pcnet32_private.options],PCNET32_PORT_ASEL
jz .L4
cmp [pcnet32_private.chip_version],0x2627
jne .L4
or eax,3
.L4:
mov ebx,9
call dword [pcnet32_access.write_bcr]
.L2:
; set/reset GPSI bit
mov ebx,124
call dword [pcnet32_access.read_csr]
mov ecx,[pcnet32_private.options]
and ecx,PCNET32_PORT_PORTSEL
cmp ecx,PCNET32_PORT_GPSI
jne .L5
or eax,0x10
.L5:
call dword [pcnet32_access.write_csr]
cmp [pcnet32_private.mii],0
je .L6
test [pcnet32_private.options],PCNET32_PORT_ASEL
jnz .L6
mov ebx,32
call dword [pcnet32_access.read_bcr]
and eax,not 0x38
test [pcnet32_private.options],PCNET32_PORT_FD
jz .L7
or eax,0x10
.L7:
test [pcnet32_private.options],PCNET32_PORT_100
jz .L8
or eax,0x08
.L8:
call dword [pcnet32_access.write_bcr]
jmp .L9
.L6:
test [pcnet32_private.options],PCNET32_PORT_ASEL
jz .L9
mov ebx,32
; PutStr "ASEL, enable auto-negotiation"
call dword [pcnet32_access.read_bcr]
and eax,not 0x98
or eax,0x20
call dword [pcnet32_access.write_bcr]
.L9:
cmp [pcnet32_private.ltint],0
je .L10
mov ebx,5
call dword [pcnet32_access.read_csr]
or eax,(1 shl 14)
call dword [pcnet32_access.write_csr]
.L10:
mov eax,[pcnet32_private.options]
and eax,PCNET32_PORT_PORTSEL
shl eax,7
mov [pcnet32_private.mode],ax
mov [pcnet32_private.filter],dword 0xffffffff
mov [pcnet32_private.filter+4],dword 0xffffffff
call pcnet32_init_ring
mov ebx,1
mov eax,pcnet32_private
and eax,0xffff
call dword [pcnet32_access.write_csr]
mov eax,pcnet32_private
mov ebx,2
shr eax,16
call dword [pcnet32_access.write_csr]
mov ebx,4
mov eax,0x0915
call dword [pcnet32_access.write_csr]
mov ebx,0
mov eax,1
call dword [pcnet32_access.write_csr]
mov ecx,100
.L11:
xor ebx,ebx
call dword [pcnet32_access.read_csr]
test ax,0x100
jnz .L12
loop .L11
.L12:
; PutStr "hardware reset"
xor ebx,ebx
mov eax,0x0002
call dword [pcnet32_access.write_csr]
xor ebx,ebx
call dword [pcnet32_access.read_csr]
; PutStr "PCNET reset complete"
ret
pcnet32_adjust_pci_device:
;*******Get current setting************************
mov al, 2 ;read a word
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, 0x04 ;from command Register
call pci_read_reg
;******see if its already set as bus master********
mov bx, ax
and bx,5
cmp bx,5
je pcnet32_adjust_pci_device_Latency
;******Make card a bus master*******
mov cx, ax ;value to write
mov bh, [pci_dev]
mov al, 2 ;write a word
or cx,5
mov ah, [pci_bus]
mov bl, 0x04 ;to command register
call pci_write_reg
;******Check latency setting***********
pcnet32_adjust_pci_device_Latency:
;*******Get current latency setting************************
; mov al, 1 ;read a byte
; mov bh, [pci_dev]
; mov ah, [pci_bus]
; mov bl, 0x0D ;from Lantency Timer Register
; call pci_read_reg
;******see if its aat least 64 clocks********
; cmp ax,64
; jge pcnet32_adjust_pci_device_Done
;******Set latency to 32 clocks*******
; mov cx, 64 ;value to write
; mov bh, [pci_dev]
; mov al, 1 ;write a byte
; mov ah, [pci_bus]
; mov bl, 0x0D ;to Lantency Timer Register
; call pci_write_reg
;******Check latency setting***********
pcnet32_adjust_pci_device_Done:
ret
pcnet32_probe:
mov ebp,[io_addr]
call pcnet32_wio_reset
xor ebx,ebx
call pcnet32_wio_read_csr
cmp eax,4
jne .try_dwio
call pcnet32_wio_check
and al,al
jz .try_dwio
; PutStr "Using WIO"
mov esi,pcnet32_wio
jmp .L1
.try_dwio:
call pcnet32_dwio_reset
xor ebx,ebx
call pcnet32_dwio_read_csr
cmp eax,4
jne .no_dev
call pcnet32_dwio_check
and al,al
jz .no_dev
; PutStr "Using DWIO"
mov esi,pcnet32_dwio
jmp .L1
.no_dev:
; PutStr "PCNET32 not found"
ret
.L1:
mov edi,pcnet32_access
mov ecx,7
cld
rep movsd
mov ebx,88
call dword [pcnet32_access.read_csr]
mov ecx,eax
mov ebx,89
call dword [pcnet32_access.read_csr]
shl eax,16
or eax,ecx
mov ecx,eax
and ecx,0xfff
cmp ecx,3
jne .no_dev
shr eax,12
and eax,0xffff
mov [pcnet32_private.chip_version],eax
; PutStr "PCNET32 chip version OK"
mov [pcnet32_private.fdx],0
mov [pcnet32_private.mii],0
mov [pcnet32_private.fset],0
mov [pcnet32_private.dxsuflo],0
mov [pcnet32_private.ltint],0
mov eax,[pcnet32_private.chip_version]
cmp eax,0x2420
je .L2
cmp eax,0x2430
je .L3
cmp eax,0x2621
je .L4
cmp eax,0x2623
je .L5
cmp eax,0x2624
je .L6
cmp eax,0x2625
je .L7
cmp eax,0x2626
je .L8
cmp eax,0x2627
je .L9
; PutStr "Invalid chip rev"
jmp .no_dev
.L2:
; PutStr "PCnet/PCI 79C970"
jmp .L10
.L3:
; PutStr "PCnet/PCI 79C970"
jmp .L10
.L4:
; PutStr "PCnet/PCI II 79C970A"
mov [pcnet32_private.fdx],1
jmp .L10
.L5:
; PutStr "PCnet/FAST 79C971"
mov [pcnet32_private.fdx],1
mov [pcnet32_private.mii],1
mov [pcnet32_private.fset],1
mov [pcnet32_private.ltint],1
jmp .L10
.L6:
; PutStr "PCnet/FAST+ 79C972"
mov [pcnet32_private.fdx],1
mov [pcnet32_private.mii],1
mov [pcnet32_private.fset],1
jmp .L10
.L7:
; PutStr "PCnet/FAST III 79C973"
mov [pcnet32_private.fdx],1
mov [pcnet32_private.mii],1
jmp .L10
.L8:
; PutStr "PCnet/Home 79C978"
mov [pcnet32_private.fdx],1
mov ebx,49
call dword [pcnet32_access.read_bcr]
call dword [pcnet32_access.write_bcr]
jmp .L10
.L9:
; PutStr "PCnet/FAST III 79C975"
mov [pcnet32_private.fdx],1
mov [pcnet32_private.mii],1
.L10:
cmp [pcnet32_private.fset],1
jne .L11
mov ebx,18
call dword [pcnet32_access.read_bcr]
or eax,0x800
call dword [pcnet32_access.write_bcr]
mov ebx,80
call dword [pcnet32_access.read_csr]
and eax,0xc00
or eax,0xc00
call dword [pcnet32_access.write_csr]
mov [pcnet32_private.dxsuflo],1
mov [pcnet32_private.ltint],1
.L11:
; read MAC
mov edi,node_addr
mov edx,ebp
mov ecx,6
.Lmac:
in al,dx
stosb
inc edx
loop .Lmac
; PutStr "MAC read"
call pcnet32_adjust_pci_device
; PutStr "PCI done"
mov eax,PCNET32_PORT_ASEL
mov [pcnet32_private.options],eax
mov [pcnet32_private.mode],word 0x0003
mov [pcnet32_private.tlen_rlen],word (PCNET32_TX_RING_LEN_BITS or PCNET32_RX_RING_LEN_BITS)
mov esi,node_addr
mov edi,pcnet32_private.phys_addr
cld
movsd
movsw
mov [pcnet32_private.filter],dword 0
mov [pcnet32_private.filter+4],dword 0
mov dword [pcnet32_private.rx_ring],pcnet32_rx_ring
mov dword [pcnet32_private.tx_ring],pcnet32_tx_ring
; PutStr "Switching to 32"
mov ebx,20
mov eax,2
call dword [pcnet32_access.write_bcr]
mov ebx,1
mov eax,(pcnet32_private and 0xffff)
call dword [pcnet32_access.write_csr]
mov ebx,2
mov eax,(pcnet32_private shr 16) and 0xffff
call dword [pcnet32_access.write_csr]
mov ebx,0
mov eax,1
call dword [pcnet32_access.write_csr]
mov esi,1
call delay_ms
call pcnet32_reset
mov eax, [pci_data]
mov [eth_status], eax
ret
pcnet32_poll:
xor eax,eax
mov [eth_rx_data_len],ax
mov eax,[pcnet32_private.cur_rx]
and eax,PCNET32_RX_RING_MOD_MASK
mov ebx,eax
imul esi,eax,PCNET32_PKT_BUF_SZ
add esi,pcnet32_rxb
shl ebx,4
add ebx,pcnet32_rx_ring
mov cx,[ebx+pcnet32_rx_head.status]
test cx,0x8000
jnz .L1
cmp ch,3
jne .L1
; PutStr "PCNETRX"
mov ecx,[ebx+pcnet32_rx_head.msg_length]
and ecx,0xfff
sub ecx,4
mov [eth_rx_data_len],cx
push ecx
shr ecx,2
mov edi,Ether_buffer
cld
rep movsd
pop ecx
and ecx,3
rep movsb
mov [ebx+pcnet32_rx_head.buf_length],word PCNET32_PKT_BUF_SZ_NEG
or [ebx+pcnet32_rx_head.status],word 0x8000
inc [pcnet32_private.cur_rx]
.L1:
ret
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
pcnet32_xmit:
push edi
push esi
push ebx
push ecx
; PutStr "PCNETTX"
mov esi,edi
mov edi,[pcnet32_private.cur_tx]
imul edi,PCNET32_PKT_BUF_SZ
add edi,pcnet32_txb ; edi=ptxb
mov eax,edi
cld ; copy MAC
movsd
movsw
mov esi,node_addr
cld
movsd
movsw
mov [edi],bx
add edi,2
mov esi,[esp+8]
mov ecx,[esp]
push ecx
shr ecx,2
cld
rep movsd
pop ecx
and ecx,3
rep movsb
; mov ecx,[esp]
; add ecx,14 ; ETH_HLEN
; xor eax,eax
; pad to min length (60=ETH_ZLEN)
; cmp ecx,60
; jae .L1
; sub ecx,60
; cld
; rep stosb
;.L1:
mov edi,pcnet32_tx_ring+0 ; entry=0
mov ecx,[esp]
add ecx,14
cmp cx,60
jae .L1
mov cx,60
.L1:
neg cx
mov [edi+pcnet32_tx_head.length],cx
mov [edi+pcnet32_tx_head.misc],dword 0
mov [edi+pcnet32_tx_head.base],eax
mov [edi+pcnet32_tx_head.status],word 0x8300
; trigger an immediate send poll
mov ebx,0
mov eax,0x0008 ; 0x0048
mov ebp,[io_addr]
call dword [pcnet32_access.write_csr]
mov dword [pcnet32_private.cur_tx],0
; wait for TX to complete
mov ecx,[timer_ticks];[0xfdf0]
add ecx,100
.L2:
mov ax,[edi+pcnet32_tx_head.status]
test ax,0x8000
jz .L3
cmp ecx,[timer_ticks];[0xfdf0]
jb .L4
mov esi,10
call delay_ms
jnz .L2
.L4:
; PutStr "PCNET: Send timeout"
.L3:
mov dword [edi+pcnet32_tx_head.base],0
pop ecx
pop ebx
pop esi
pop edi
ret
/kernel/trunk/network/eth_drv/rtl8029.inc
0,0 → 1,955
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; RTL8029.INC ;;
;; ;;
;; Ethernet driver for Menuet OS ;;
;; ;;
;; Version 0.2 31 July 2002 ;;
;; ;;
;; This driver is based on the ns8390 driver from ;;
;; the etherboot 5.0.6 project. The copyright statement is ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; remaining parts Copyright 2002 Mike Hibbett, ;;
;; mikeh@oceanfree.net ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;; While this implementation handles only PCI bus RTL8029 ;;
;; hardware, it can be easily adapted to other NE2000 clone ;;
;; products. I just dont have any to try! ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
 
;********************************************************************
; Interface
; rtl8029_reset
; rtl8029_probe
; rtl8029_poll
; rtl8029_transmit
;
;********************************************************************
 
 
 
 
;**************************************************************************
; 8390 Register Definitions
;**************************************************************************
D8390_P0_COMMAND equ 0x00
D8390_P0_PSTART equ 0x01
D8390_P0_PSTOP equ 0x02
D8390_P0_BOUND equ 0x03
D8390_P0_TSR equ 0x04
D8390_P0_TPSR equ 0x04
D8390_P0_TBCR0 equ 0x05
D8390_P0_TBCR1 equ 0x06
D8390_P0_ISR equ 0x07
D8390_P0_RSAR0 equ 0x08
D8390_P0_RSAR1 equ 0x09
D8390_P0_RBCR0 equ 0x0A
D8390_P0_RBCR1 equ 0x0B
D8390_P0_RSR equ 0x0C
D8390_P0_RCR equ 0x0C
D8390_P0_TCR equ 0x0D
D8390_P0_DCR equ 0x0E
D8390_P0_IMR equ 0x0F
D8390_P1_COMMAND equ 0x00
D8390_P1_PAR0 equ 0x01
D8390_P1_PAR1 equ 0x02
D8390_P1_PAR2 equ 0x03
D8390_P1_PAR3 equ 0x04
D8390_P1_PAR4 equ 0x05
D8390_P1_PAR5 equ 0x06
D8390_P1_CURR equ 0x07
D8390_P1_MAR0 equ 0x08
 
D8390_COMMAND_PS0 equ 0x0 ; Page 0 select
D8390_COMMAND_PS1 equ 0x40 ; Page 1 select
D8390_COMMAND_PS2 equ 0x80 ; Page 2 select
D8390_COMMAND_RD2 equ 0x20 ; Remote DMA control
D8390_COMMAND_RD1 equ 0x10
D8390_COMMAND_RD0 equ 0x08
D8390_COMMAND_TXP equ 0x04 ; transmit packet
D8390_COMMAND_STA equ 0x02 ; start
D8390_COMMAND_STP equ 0x01 ; stop
 
D8390_COMMAND_RD2_STA equ 0x22
D8390_COMMAND_RD2_STP equ 0x21
D8390_COMMAND_RD1_STA equ 0x12
D8390_COMMAND_RD0_STA equ 0x0A
D8390_COMMAND_PS0_RD2_STP equ 0x21
D8390_COMMAND_PS1_RD2_STP equ 0x61
D8390_COMMAND_PS0_RD2_STA equ 0x22
D8390_COMMAND_PS0_TXP_RD2_STA equ 0x26
 
D8390_RCR_MON equ 0x20 ; monitor mode
 
D8390_DCR_FT1 equ 0x40
D8390_DCR_LS equ 0x08 ; Loopback select
D8390_DCR_WTS equ 0x01 ; Word transfer select
 
D8390_DCR_FT1_LS equ 0x48
D8390_DCR_WTS_FT1_LS equ 0x49
 
D8390_ISR_PRX equ 0x01 ; successful recv
D8390_ISR_PTX equ 0x02 ; successful xmit
D8390_ISR_RXE equ 0x04 ; receive error
D8390_ISR_TXE equ 0x08 ; transmit error
D8390_ISR_OVW equ 0x10 ; Overflow
D8390_ISR_CNT equ 0x20 ; Counter overflow
D8390_ISR_RDC equ 0x40 ; Remote DMA complete
D8390_ISR_RST equ 0x80 ; reset
 
D8390_RSTAT_PRX equ 0x01 ; successful recv
D8390_RSTAT_CRC equ 0x02 ; CRC error
D8390_RSTAT_FAE equ 0x04 ; Frame alignment error
D8390_RSTAT_OVER equ 0x08 ; FIFO overrun
 
D8390_TXBUF_SIZE equ 6
D8390_RXBUF_END equ 32
D8390_PAGE_SIZE equ 256
 
ETH_ALEN equ 6
ETH_HLEN equ 14
ETH_ZLEN equ 60
ETH_FRAME_LEN equ 1514
 
FLAG_PIO equ 0x01
FLAG_16BIT equ 0x02
ASIC_PIO equ 0
 
VENDOR_NONE equ 0
VENDOR_WD equ 1
VENDOR_NOVELL equ 2
VENDOR_3COM equ 3
 
NE_ASIC_OFFSET equ 0x10
NE_RESET equ 0x0F ; Used to reset card
NE_DATA equ 0x00 ; Used to read/write NIC mem
 
MEM_8192 equ 32
MEM_16384 equ 64
MEM_32768 equ 128
 
ISA_MAX_ADDR equ 0x400
 
uglobal
eth_flags: db 0
eth_vendor: db 0
eth_nic_base: dw 0
eth_asic_base: dw 0
eth_memsize: db 0
eth_rx_start: db 0
eth_tx_start: db 0
eth_bmem: dd 0
eth_rmem: dd 0
romdata: db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
endg
 
iglobal
test_data: db 'NE*000 memory',0
test_buffer: db ' ',0
endg
 
uglobal
eth_type: dw 0
pkthdr: db 0,0,0,0 ; status, next, (short) len
pktoff: dw 0
eth_rx_data_ptr: dd 0
eth_tmp_len: dw 0
endg
 
 
 
;***************************************************************************
; Function
; eth_pio_read
;
; Description
; Read a frame from the ethernet card via Programmed I/O
; src in ebx
; cnt in ecx
; dst in edi
;***************************************************************************
eth_pio_read:
mov al, [eth_flags]
and al, FLAG_16BIT
cmp al, 0
je epr_001
 
inc ecx
and ecx, 0xFFFFFFFE
 
epr_001:
mov al, D8390_COMMAND_RD2_STA
mov dx, [eth_nic_base]
add dx, D8390_P0_COMMAND
out dx, al
 
mov al, cl
mov dx, [eth_nic_base]
add dx, D8390_P0_RBCR0
out dx, al
 
mov al, ch
mov dx, [eth_nic_base]
add dx, D8390_P0_RBCR1
out dx, al
 
mov al, bl
mov dx, [eth_nic_base]
add dx, D8390_P0_RSAR0
out dx, al
 
mov al, bh
mov dx, [eth_nic_base]
add dx, D8390_P0_RSAR1
out dx, al
 
mov al, D8390_COMMAND_RD0_STA
mov dx, [eth_nic_base]
add dx, D8390_P0_COMMAND
out dx, al
 
mov dx, [eth_asic_base]
add dx, ASIC_PIO
 
mov al, [eth_flags]
and al, FLAG_16BIT
cmp al, 0
je epr_003
 
shr ecx, 1
 
epr_002:
; 2 bytes at a time
in ax, dx
mov [edi], ax
add edi, 2
loop epr_002
ret
 
epr_003:
; 1 byte at a time
in al, dx
mov [edi], al
inc edi
loop epr_003
ret
 
 
 
 
;***************************************************************************
; Function
; eth_pio_write
;
; Description
; writes a frame to the ethernet card via Programmed I/O
; dst in ebx
; cnt in ecx
; src in esi
;***************************************************************************
eth_pio_write:
mov al, [eth_flags]
and al, FLAG_16BIT
cmp al, 0
je epw_001
 
inc ecx
and ecx, 0xFFFFFFFE
 
epw_001:
mov al, D8390_COMMAND_RD2_STA
mov dx, [eth_nic_base]
add dx, D8390_P0_COMMAND
out dx, al
 
mov al, D8390_ISR_RDC
mov dx, [eth_nic_base]
add dx, D8390_P0_ISR
out dx, al
 
 
mov al, cl
mov dx, [eth_nic_base]
add dx, D8390_P0_RBCR0
out dx, al
 
mov al, ch
mov dx, [eth_nic_base]
add dx, D8390_P0_RBCR1
out dx, al
 
mov al, bl
mov dx, [eth_nic_base]
add dx, D8390_P0_RSAR0
out dx, al
 
mov al, bh
mov dx, [eth_nic_base]
add dx, D8390_P0_RSAR1
out dx, al
 
mov al, D8390_COMMAND_RD1_STA
mov dx, [eth_nic_base]
add dx, D8390_P0_COMMAND
out dx, al
 
mov dx, [eth_asic_base]
add dx, ASIC_PIO
 
mov al, [eth_flags]
and al, FLAG_16BIT
cmp al, 0
je epw_003
 
shr ecx, 1
 
epw_002:
; 2 bytes at a time
mov ax, [esi]
add esi, 2
out dx, ax
 
loop epw_002
jmp epw_004
 
epw_003:
; 1 byte at a time
mov al, [esi]
inc esi
out dx, al
loop epw_003
 
epw_004:
mov dx, [eth_nic_base]
add dx, D8390_P0_ISR
 
epw_005:
in al, dx
and al, D8390_ISR_RDC
cmp al, D8390_ISR_RDC
jne epw_005
 
ret
 
 
 
;***************************************************************************
; Function
; rtl8029_reset
; Description
; Place the chip (ie, the ethernet card) into a virgin state
; No inputs
; All registers destroyed
;
;***************************************************************************
rtl8029_reset:
mov bx, [eth_nic_base]
 
mov dx, bx
add dx, D8390_P0_COMMAND
mov al, D8390_COMMAND_PS0_RD2_STP
out dx, al
 
mov dx, bx
add dx, D8390_P0_DCR
mov al, [eth_flags]
and al, FLAG_16BIT
cmp al, FLAG_16BIT
jne nsr_001
 
mov al, 0x49
jmp nsr_002
 
nsr_001:
mov al, 0x48
 
nsr_002:
out dx, al
 
xor al, al
 
mov dx, bx
add dx, D8390_P0_RBCR0
out dx, al
 
mov dx, bx
add dx, D8390_P0_RBCR1
out dx, al
 
mov dx, bx
add dx, D8390_P0_RCR
mov al, 0x20
out dx, al
 
mov dx, bx
add dx, D8390_P0_TCR
mov al, 2
out dx, al
 
mov dx, bx
add dx, D8390_P0_TPSR
mov al, [eth_tx_start]
out dx, al
 
mov dx, bx
add dx, D8390_P0_PSTART
mov al, [eth_rx_start]
out dx, al
 
mov dx, bx
add dx, D8390_P0_PSTOP
mov al, [eth_memsize]
out dx, al
 
mov dx, bx
add dx, D8390_P0_BOUND
mov al, [eth_memsize]
dec al
out dx, al
 
mov dx, bx
add dx, D8390_P0_ISR
mov al, 0xff
out dx, al
 
mov dx, bx
add dx, D8390_P0_IMR
xor al, al
out dx, al
 
mov dx, bx
add dx, D8390_P0_COMMAND
mov al, D8390_COMMAND_PS1_RD2_STP
out dx, al
 
mov dx, bx
add dx, D8390_P1_PAR0
mov esi, node_addr
mov ecx, ETH_ALEN
 
nsr_003:
mov al, [esi]
out dx, al
 
inc esi
inc dx
loop nsr_003
 
mov dx, bx
add dx, D8390_P1_MAR0
mov ecx, ETH_ALEN
 
mov al, 0xff
 
nsr_004:
out dx, al
inc dx
loop nsr_004
 
mov dx, bx
add dx, D8390_P1_CURR
mov al, [eth_rx_start]
out dx, al
 
mov dx, bx
add dx, D8390_P0_COMMAND
mov al, D8390_COMMAND_PS0_RD2_STA
out dx, al
 
mov dx, bx
add dx, D8390_P0_ISR
mov al, 0xff
out dx, al
 
mov dx, bx
add dx, D8390_P0_TCR
mov al, 0
out dx, al
 
mov dx, bx
add dx, D8390_P0_RCR
mov al, 4
out dx, al
 
ret
 
 
 
;***************************************************************************
; Function
; rtl8029_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
;
;***************************************************************************
rtl8029_probe:
mov eax, [io_addr]
mov [eth_nic_base], ax ; The IO address space is 16 bit only
 
mov al, VENDOR_NONE
mov [eth_vendor], al
 
mov al, [eth_vendor]
cmp al, VENDOR_NONE
 
jne ep_check_have_vendor
xor eax, eax
mov [eth_bmem], eax
 
mov al, FLAG_PIO
mov [eth_flags], al
 
mov ax, [eth_nic_base]
add ax, NE_ASIC_OFFSET
mov [eth_asic_base], ax
 
mov al, MEM_16384
mov [eth_memsize], al
 
mov al, 32
mov [eth_tx_start], al
 
add al, D8390_TXBUF_SIZE
mov [eth_rx_start], al
 
mov dx, [eth_asic_base]
add dx, NE_RESET
 
in al, dx
out dx, al
 
in al, 0x84
 
mov bx, [eth_nic_base]
 
mov dx, bx
add dx, D8390_P0_COMMAND
mov al, D8390_COMMAND_RD2_STP
out dx, al
 
mov dx, bx
add dx, D8390_P0_RCR
mov al, D8390_RCR_MON
out dx, al
 
mov dx, bx
add dx, D8390_P0_DCR
mov al, D8390_DCR_FT1_LS
out dx, al
 
mov dx, bx
add dx, D8390_P0_PSTART
mov al, MEM_8192
out dx, al
 
mov dx, bx
add dx, D8390_P0_PSTOP
mov al, MEM_16384
out dx, al
 
mov esi, test_data
mov ebx, 8192
mov ecx, 14
call eth_pio_write
 
mov ebx, 8192
mov ecx, 14
mov edi, test_buffer
call eth_pio_read
 
mov esi, test_buffer
mov edi, test_data
mov ecx, 13
cld
rep cmpsb
 
je ep_set_vendor
 
mov al, [eth_flags]
or al, FLAG_16BIT
mov [eth_flags], al
 
mov al, MEM_32768
mov [eth_memsize], al
 
mov al, 64
mov [eth_tx_start], al
 
add al, D8390_TXBUF_SIZE
mov [eth_rx_start], al
 
mov bx, [eth_nic_base]
 
mov dx, bx
add dx, D8390_P0_DCR
mov al, D8390_DCR_WTS_FT1_LS
out dx, al
 
mov dx, bx
add dx, D8390_P0_PSTART
mov al, MEM_16384
out dx, al
 
mov dx, bx
add dx, D8390_P0_PSTOP
mov al, MEM_32768
out dx, al
 
mov esi, test_data
mov ebx, 16384
mov ecx, 14
call eth_pio_write
 
mov ebx, 16384
mov ecx, 14
mov edi, test_buffer
call eth_pio_read
 
mov esi, test_buffer
mov edi, test_data
mov ecx, 13
cld
rep cmpsb
 
ep_set_vendor:
; this bit is odd - probably left over from my hacking
mov ax, [eth_nic_base]
cmp ax, 0
je rtl8029_exit
cmp ax, ISA_MAX_ADDR
jbe ep_001
mov al, [eth_flags]
or al, FLAG_16BIT
mov [eth_flags], al
 
ep_001:
mov al, VENDOR_NOVELL
mov [eth_vendor], al
 
mov ebx, 0
mov ecx, 16
mov edi, romdata
call eth_pio_read
 
 
mov ecx, ETH_ALEN
mov esi, romdata
mov edi, node_addr
 
mov bl, [eth_flags]
and bl, FLAG_16BIT
 
ep_002:
mov al, [esi]
mov [edi], al
 
inc edi
inc esi
cmp bl, FLAG_16BIT
jne ep_003
 
inc esi
 
ep_003:
loop ep_002
 
ep_check_have_vendor:
mov al, [eth_vendor]
cmp al, VENDOR_NONE
je rtl8029_exit
 
cmp al, VENDOR_3COM
je ep_reset_card
 
mov eax, [eth_bmem]
mov [eth_rmem], eax
 
ep_reset_card:
; Reset the card
call rtl8029_reset
 
; Indicate that we have successfully reset the card
mov eax, [pci_data]
mov [eth_status], eax
 
rtl8029_exit:
ret
 
 
 
;***************************************************************************
; Function
; rtl8029_poll
;
; Description
; Polls the ethernet card for a received packet
; Received data, if any, ends up in Ether_buffer
;
;***************************************************************************
rtl8029_poll:
mov eax, Ether_buffer
mov [eth_rx_data_ptr], eax
 
mov bx, [eth_nic_base]
 
mov dx, bx
add dx, D8390_P0_RSR
in al, dx
 
and al, D8390_RSTAT_PRX
cmp al, D8390_RSTAT_PRX
jne nsp_exit
 
mov dx, bx
add dx, D8390_P0_BOUND
in al, dx
inc al
 
cmp al, [eth_memsize]
jb nsp_001
 
mov al, [eth_rx_start]
 
nsp_001:
mov ch, al
 
mov dx, bx
add dx, D8390_P0_COMMAND
mov al, D8390_COMMAND_PS1
out dx, al
 
mov dx, bx
add dx, D8390_P1_CURR
in al, dx ; get current page
mov cl, al
 
mov dx, bx
add dx, D8390_P0_COMMAND
mov al, D8390_COMMAND_PS0
out dx, al
 
cmp cl, [eth_memsize]
jb nsp_002
 
mov cl, [eth_rx_start]
 
nsp_002:
cmp cl, ch
je nsp_exit
 
xor ax, ax
mov ah, ch
 
mov [pktoff], ax
 
mov al, [eth_flags]
and al, FLAG_PIO
cmp al, FLAG_PIO
jne nsp_003
 
movzx ebx, word [pktoff]
mov edi, pkthdr
mov ecx, 4
call eth_pio_read
jmp nsp_004
 
nsp_003:
mov edi, [eth_rmem]
movzx eax, word [pktoff]
add edi, eax
mov eax, [edi]
mov [pkthdr], eax
 
nsp_004:
mov ax, [pktoff]
add ax, 4
mov [pktoff], ax
 
mov ax, [pkthdr + 2]
sub ax, 4
 
mov [eth_tmp_len], ax
 
cmp ax, ETH_ZLEN
jb nsp_exit
 
cmp ax, ETH_FRAME_LEN
ja nsp_exit
 
mov al, [pkthdr]
and al, D8390_RSTAT_PRX
cmp al, D8390_RSTAT_PRX
jne nsp_exit
 
; Right, we can now get the data
 
mov ax, [eth_tmp_len]
mov [eth_rx_data_len], ax
 
xor ebx, ebx
mov bh, [eth_memsize]
sub bx, [pktoff]
 
cmp [eth_tmp_len], bx
jbe nsp_005
 
mov al, [eth_flags]
and al, FLAG_PIO
cmp al, FLAG_PIO
jne nsp_006
 
push ebx
mov ecx, ebx
xor ebx, ebx
mov bx, [pktoff]
mov edi, [eth_rx_data_ptr]
call eth_pio_read
pop ebx
jmp nsp_007
 
nsp_006:
; Not implemented, as we are using PIO mode on this card
 
nsp_007:
xor ax, ax
mov ah, [eth_rx_start]
mov [pktoff], ax
 
mov eax, [eth_rx_data_ptr]
add eax, ebx
mov [eth_rx_data_ptr], eax
 
mov ax, [eth_tmp_len]
sub ax, bx
mov [eth_tmp_len], ax
 
nsp_005:
mov al, [eth_flags]
and al, FLAG_PIO
cmp al, FLAG_PIO
jne nsp_008
 
xor ebx, ebx
mov bx, [pktoff]
xor ecx, ecx
mov cx, [eth_tmp_len]
mov edi, [eth_rx_data_ptr]
call eth_pio_read
jmp nsp_009
 
nsp_008:
; Not implemented, as we are using PIO mode on this card
 
nsp_009:
mov al, [pkthdr+1]
cmp al, [eth_rx_start]
jne nsp_010
 
mov al, [eth_memsize]
 
nsp_010:
mov dx, [eth_nic_base]
add dx, D8390_P0_BOUND
dec al
out dx, al
 
nsp_exit:
ret
 
 
 
;***************************************************************************
; Function
; rtl8029_transmit
;
; Description
; Transmits a packet of data via the ethernet card
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
;
;***************************************************************************
rtl8029_transmit:
mov [eth_type], bx
 
pusha
 
mov esi, edi
xor bx, bx
mov bh, [eth_tx_start]
mov ecx, ETH_ALEN
call eth_pio_write
 
mov esi, node_addr
xor bx, bx
mov bh, [eth_tx_start]
add bx, ETH_ALEN
mov ecx, ETH_ALEN
call eth_pio_write
 
mov esi, eth_type
xor bx, bx
mov bh, [eth_tx_start]
add bx, ETH_ALEN
add bx, ETH_ALEN
mov ecx, 2
call eth_pio_write
 
popa
 
xor bx, bx
mov bh, [eth_tx_start]
add bx, ETH_HLEN
push ecx
call eth_pio_write
pop ecx
 
add ecx, ETH_HLEN
cmp ecx, ETH_ZLEN
jae nst_001
 
mov ecx, ETH_ZLEN
 
nst_001:
push ecx
 
mov bx, [eth_nic_base]
 
mov dx, bx
add dx, D8390_P0_COMMAND
mov al, D8390_COMMAND_PS0_RD2_STA
out dx, al
 
mov dx, bx
add dx, D8390_P0_TPSR
mov al, [eth_tx_start]
out dx, al
 
pop ecx
 
mov dx, bx
add dx, D8390_P0_TBCR0
mov al, cl
out dx, al
 
mov dx, bx
add dx, D8390_P0_TBCR1
mov al, ch
out dx, al
 
mov dx, bx
add dx, D8390_P0_COMMAND
mov al, D8390_COMMAND_PS0_TXP_RD2_STA
out dx, al
 
ret
/kernel/trunk/network/eth_drv/rtl8139.inc
0,0 → 1,595
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; RTL8139.INC ;;
;; ;;
;; Ethernet driver for Menuet OS ;;
;; ;;
;; Version 0.2 11 August 2003 ;;
;; ;;
;; Driver for chips of RealTek 8139 family ;;
;; References: ;;
;; www.realtek.com.hw - data sheets ;;
;; rtl8139.c - linux driver ;;
;; 8139too.c - linux driver ;;
;; ethernet driver template by Mike Hibbett ;;
;; ;;
;; The copyright statement is ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; Copyright 2003 Endre Kozma, ;;
;; endre.kozma@axelero.hu ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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_REG_COMMAND equ 0x04 ; command 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
 
RTL8139_REG_MAR0 equ 0x08 ; multicast filter register 0
RTL8139_REG_MAR4 equ 0x0c ; multicast filter register 4
RTL8139_REG_TSD0 equ 0x10 ; transmit status of descriptor
RTL8139_REG_TSAD0 equ 0x20 ; transmit start address of descriptor
RTL8139_REG_RBSTART equ 0x30 ; RxBuffer start address
RTL8139_REG_COMMAND equ 0x37 ; command register
RTL8139_REG_CAPR equ 0x38 ; current address of packet read
RTL8139_REG_IMR equ 0x3c ; interrupt mask register
RTL8139_REG_ISR equ 0x3e ; interrupt status register
RTL8139_REG_TXCONFIG equ 0x40 ; transmit configuration register
RTL8139_REG_TXCONFIG_0 equ 0x40 ; transmit configuration register 0
RTL8139_REG_TXCONFIG_1 equ 0x41 ; transmit configuration register 1
RTL8139_REG_TXCONFIG_2 equ 0x42 ; transmit configuration register 2
RTL8139_REG_TXCONFIG_3 equ 0x43 ; transmit configuration register 3
RTL8139_REG_RXCONFIG equ 0x44 ; receive configuration register 0
RTL8139_REG_RXCONFIG_0 equ 0x44 ; receive configuration register 0
RTL8139_REG_RXCONFIG_1 equ 0x45 ; receive configuration register 1
RTL8139_REG_RXCONFIG_2 equ 0x46 ; receive configuration register 2
RTL8139_REG_RXCONFIG_3 equ 0x47 ; receive configuration register 3
RTL8139_REG_MPC equ 0x4c ; missed packet counter
RTL8139_REG_9346CR equ 0x50 ; serial eeprom 93C46 command register
RTL8139_REG_CONFIG1 equ 0x52 ; configuration register 1
RTL8139_REG_CONFIG4 equ 0x5a ; configuration register 4
RTL8139_REG_HLTCLK equ 0x5b ; undocumented halt clock register
RTL8139_REG_BMCR equ 0x62 ; basic mode control register
RTL8139_REG_ANAR equ 0x66 ; auto negotiation advertisement register
 
; 5.1 packet header
RTL8139_BIT_RUNT equ 4 ; total packet length < 64 bytes
RTL8139_BIT_LONG equ 3 ; total packet length > 4k
RTL8139_BIT_CRC equ 2 ; crc error occured
RTL8139_BIT_FAE equ 1 ; frame alignment error occured
RTL8139_BIT_ROK equ 0 ; received packet is ok
; 5.4 command register
RTL8139_BIT_RST equ 4 ; reset bit
RTL8139_BIT_RE equ 3 ; receiver enabled
RTL8139_BIT_TE equ 2 ; transmitter enabled
RTL8139_BIT_BUFE equ 0 ; rx buffer is empty, no packet stored
; 5.6 interrupt status register
RTL8139_BIT_ISR_TOK equ 2 ; transmit ok
RTL8139_BIT_ISR_RER equ 1 ; receive error interrupt
RTL8139_BIT_ISR_ROK equ 0 ; receive ok
; 5.7 transmit configyration register
RTL8139_BIT_TX_MXDMA equ 8 ; Max DMA burst size per Tx DMA burst
RTL8139_BIT_TXRR equ 4 ; Tx Retry count 16+(TXRR*16)
; 5.8 receive configuration register
RTL8139_BIT_RXFTH equ 13 ; Rx fifo threshold
RTL8139_BIT_RBLEN equ 11 ; Ring buffer length indicator
RTL8139_BIT_RX_MXDMA equ 8 ; Max DMA burst size per Rx DMA burst
RTL8139_BIT_NOWRAP equ 7 ; transfered data wrapping
RTL8139_BIT_9356SEL equ 6 ; eeprom selector 9346/9356
RTL8139_BIT_AER equ 5 ; accept error packets
RTL8139_BIT_AR equ 4 ; accept runt packets
RTL8139_BIT_AB equ 3 ; accept broadcast packets
RTL8139_BIT_AM equ 2 ; accept multicast packets
RTL8139_BIT_APM equ 1 ; accept physical match packets
RTL8139_BIT_AAP equ 0 ; accept all packets
; 5.9 93C46/93C56 command register
RTL8139_BIT_93C46_EEM1 equ 7 ; RTL8139 eeprom operating mode1
RTL8139_BIT_93C46_EEM0 equ 6 ; RTL8139 eeprom operating mode0
RTL8139_BIT_93C46_EECS equ 3 ; chip select
RTL8139_BIT_93C46_EESK equ 2 ; serial data clock
RTL8139_BIT_93C46_EEDI equ 1 ; serial data input
RTL8139_BIT_93C46_EEDO equ 0 ; serial data output
; 5.11 configuration register 1
RTL8139_BIT_LWACT equ 4 ; see RTL8139_REG_CONFIG1
RTL8139_BIT_SLEEP equ 1 ; sleep bit at older chips
RTL8139_BIT_PWRDWN equ 0 ; power down bit at older chips
RTL8139_BIT_PMEn equ 0 ; power management enabled
; 5.14 configuration register 4
RTL8139_BIT_LWPTN equ 2 ; see RTL8139_REG_CONFIG4
; 6.2 transmit status register
RTL8139_BIT_ERTXTH equ 16 ; early TX threshold
RTL8139_BIT_TOK equ 15 ; transmit ok
RTL8139_BIT_OWN equ 13 ; tx DMA operation is completed
; 6.18 basic mode control register
RTL8139_BIT_ANE equ 12 ; auto negotiation enable
; 6.20 auto negotiation advertisement register
RTL8139_BIT_TXFD equ 8 ; 100base-T full duplex
RTL8139_BIT_TX equ 7 ; 100base-T
RTL8139_BIT_10FD equ 6 ; 10base-T full duplex
RTL8139_BIT_10 equ 5 ; 10base-T
RTL8139_BIT_SELECTOR equ 0 ; binary encoded selector CSMA/CD=00001
; RX/TX buffer size
RTL8139_RBLEN equ 0 ; 0==8K 1==16k 2==32k 3==64k
RTL8139_RX_BUFFER_SIZE equ (8192 shl RTL8139_RBLEN)
MAX_ETH_FRAME_SIZE equ 1516 ; exactly 1514 wthout CRC
RTL8139_NUM_TX_DESC equ 4
RTL8139_TX_BUFFER_SIZE equ (MAX_ETH_FRAME_SIZE * RTL8139_NUM_TX_DESC)
RTL8139_TXRR equ 8 ; total retries = 16+(TXRR*16)
RTL8139_TX_MXDMA equ 6 ; 0==16 1==32 2==64 3==128
; 4==256 5==512 6==1024 7==2048
RTL8139_ERTXTH equ 8 ; in unit of 32 bytes e.g:(8*32)=256
RTL8139_RX_MXDMA equ 7 ; 0==16 1==32 2==64 3==128
; 4==256 5==512 6==1024 7==unlimited
RTL8139_RXFTH equ 7 ; 0==16 1==32 2==64 3==128
; 4==256 5==512 6==1024 7==no threshold
RTL8139_RX_CONFIG equ ((RTL8139_RBLEN shl RTL8139_BIT_RBLEN) \
or (RTL8139_RX_MXDMA shl RTL8139_BIT_RX_MXDMA) \
or (1 shl RTL8139_BIT_NOWRAP) \
or (RTL8139_RXFTH shl RTL8139_BIT_RXFTH) \
or (1 shl RTL8139_BIT_AB) or (1 shl RTL8139_BIT_APM) \
or (1 shl RTL8139_BIT_AER) or (1 shl RTL8139_BIT_AR) \
or (1 shl RTL8139_BIT_AM))
RTL8139_TX_TIMEOUT equ 30 ; 300 milliseconds timeout
 
EE_93C46_REG_ETH_ID equ 7 ; MAC offset
EE_93C46_READ_CMD equ (6 shl 6) ; 110b + 6bit address
EE_93C56_READ_CMD equ (6 shl 8) ; 110b + 8bit address
EE_93C46_CMD_LENGTH equ 9 ; start bit + cmd + 6bit address
EE_93C56_CMD_LENGTH equ 11 ; start bit + cmd + 8bit ddress
 
VER_RTL8139 equ 1100000b
VER_RTL8139A equ 1110000b
; VER_RTL8139AG equ 1110100b
VER_RTL8139B equ 1111000b
VER_RTL8130 equ VER_RTL8139B
VER_RTL8139C equ 1110100b
VER_RTL8100 equ 1111010b
VER_RTL8100B equ 1110101b
VER_RTL8139D equ VER_RTL8100B
VER_RTL8139CP equ 1110110b
VER_RTL8101 equ 1110111b
 
IDX_RTL8139 equ 0
IDX_RTL8139A equ 1
IDX_RTL8139B equ 2
IDX_RTL8139C equ 3
IDX_RTL8100 equ 4
IDX_RTL8139D equ 5
IDX_RTL8139D equ 6
IDX_RTL8101 equ 7
 
 
; These two must be 4 byte aligned ( which they are )
rtl8139_rx_buff equ eth_data_start
rtl8139_tx_buff equ rtl8139_rx_buff + (RTL8139_RX_BUFFER_SIZE + MAX_ETH_FRAME_SIZE)
 
uglobal
align 4
rtl8139_rx_buff_offset: dd 0
curr_tx_desc: dd 0
endg
 
iglobal
hw_ver_array: db VER_RTL8139, VER_RTL8139A, VER_RTL8139B, VER_RTL8139C
db VER_RTL8100, VER_RTL8139D, VER_RTL8139CP, VER_RTL8101
HW_VER_ARRAY_SIZE = $-hw_ver_array
endg
 
uglobal
hw_ver_id: db 0
endg
 
;***************************************************************************
; Function
; rtl8139_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
;
;***************************************************************************
rtl8139_probe:
; enable the device
mov al, 2
mov ah, [pci_bus]
mov bh, [pci_dev]
mov bl, PCI_REG_COMMAND
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)
mov al, 2
mov ah, [pci_bus]
mov bh, [pci_dev]
mov bl, PCI_REG_COMMAND
call pci_write_reg
; get chip version
mov edx, [io_addr]
add edx, RTL8139_REG_TXCONFIG_2
in ax, dx
shr ah, 2
shr ax, 6
and al, 01111111b
mov ecx, HW_VER_ARRAY_SIZE-1
.chip_ver_loop:
cmp al, [hw_ver_array+ecx]
je .chip_ver_found
dec ecx
jns .chip_ver_loop
xor cl, cl ; default RTL8139
.chip_ver_found:
mov [hw_ver_id], cl
; wake up the chip
mov edx, [io_addr]
add edx, RTL8139_REG_HLTCLK
mov al, 'R' ; run the clock
out dx, al
; unlock config and BMCR registers
add edx, RTL8139_REG_9346CR - RTL8139_REG_HLTCLK
mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EEM0)
out dx, al
; enable power management
add edx, RTL8139_REG_CONFIG1 - RTL8139_REG_9346CR
in al, dx
cmp byte [hw_ver_id], IDX_RTL8139B
jl .old_chip
; set LWAKE pin to active high (default value).
; it is for Wake-On-LAN functionality of some motherboards.
; this signal is used to inform the motherboard to execute a wake-up process.
; only at newer chips.
or al, (1 shl RTL8139_BIT_PMEn)
and al, not (1 shl RTL8139_BIT_LWACT)
out dx, al
add edx, RTL8139_REG_CONFIG4 - RTL8139_REG_CONFIG1
in al, dx
and al, not (1 shl RTL8139_BIT_LWPTN)
out dx, al
jmp .finish_wake_up
.old_chip:
; wake up older chips
and al, not ((1 shl RTL8139_BIT_SLEEP) or (1 shl RTL8139_BIT_PWRDWN))
out dx, al
.finish_wake_up:
; lock config and BMCR registers
xor al, al
mov edx, [io_addr]
add edx, RTL8139_REG_9346CR
out dx, al
;***************************************************************************
; Function
; rt8139_reset
; Description
; Place the chip (ie, the ethernet card) into a virgin state
; Destroyed registers
; eax, ebx, ecx, edx
;
;***************************************************************************
rtl8139_reset:
mov edx, [io_addr]
add edx, RTL8139_REG_COMMAND
mov al, 1 shl RTL8139_BIT_RST
out dx, al
mov cx, 1000 ; wait no longer for the reset
.wait_for_reset:
in al, dx
test al, 1 shl RTL8139_BIT_RST
jz .reset_completed ; RST remains 1 during reset
dec cx
jns .wait_for_reset
.reset_completed:
; get MAC (hardware address)
mov ecx, 2
.mac_read_loop:
lea eax, [EE_93C46_REG_ETH_ID+ecx]
push ecx
call rtl8139_read_eeprom
pop ecx
mov [node_addr+ecx*2], ax
dec ecx
jns .mac_read_loop
; unlock config and BMCR registers
mov edx, [io_addr]
add edx, RTL8139_REG_9346CR
mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EEM0)
out dx, al
; initialize multicast registers (no filtering)
mov eax, 0xffffffff
add edx, RTL8139_REG_MAR0 - RTL8139_REG_9346CR
out dx, eax
add edx, RTL8139_REG_MAR4 - RTL8139_REG_MAR0
out dx, eax
; enable Rx/Tx
mov al, (1 shl RTL8139_BIT_RE) or (1 shl RTL8139_BIT_TE)
add edx, RTL8139_REG_COMMAND - RTL8139_REG_MAR4
out dx, al
; 32k Rxbuffer, unlimited dma burst, no wrapping, no rx threshold
; accept broadcast packets, accept physical match packets
mov ax, RTL8139_RX_CONFIG
add edx, RTL8139_REG_RXCONFIG - RTL8139_REG_COMMAND
out dx, ax
; 1024 bytes DMA burst, total retries = 16 + 8 * 16 = 144
mov ax, (RTL8139_TX_MXDMA shl RTL8139_BIT_TX_MXDMA) \
or (RTL8139_TXRR shl RTL8139_BIT_TXRR)
add edx, RTL8139_REG_TXCONFIG - RTL8139_REG_RXCONFIG
out dx, ax
; enable auto negotiation
add edx, RTL8139_REG_BMCR - RTL8139_REG_TXCONFIG
in ax, dx
or ax, (1 shl RTL8139_BIT_ANE)
out dx, ax
; set auto negotiation advertisement
add edx, RTL8139_REG_ANAR - RTL8139_REG_BMCR
in ax, dx
or ax, (1 shl RTL8139_BIT_SELECTOR) or (1 shl RTL8139_BIT_10) \
or (1 shl RTL8139_BIT_10FD) or (1 shl RTL8139_BIT_TX) \
or (1 shl RTL8139_BIT_TXFD)
out dx, ax
; lock config and BMCR registers
xor eax, eax
add edx, RTL8139_REG_9346CR - RTL8139_REG_ANAR
out dx, al
; init RX/TX pointers
mov [rtl8139_rx_buff_offset], eax
mov [curr_tx_desc], eax
; clear missing packet counter
add edx, RTL8139_REG_MPC - RTL8139_REG_9346CR
out dx, eax
; disable all interrupts
add edx, RTL8139_REG_IMR - RTL8139_REG_MPC
out dx, ax
; set RxBuffer address, init RX buffer offset, init TX ring
mov eax, rtl8139_rx_buff
add edx, RTL8139_REG_RBSTART - RTL8139_REG_IMR
out dx, eax
; Indicate that we have successfully reset the card
mov eax, [pci_data]
mov [eth_status], eax
ret
 
;***************************************************************************
; Function
; rtl8139_read_eeprom
; Description
; reads eeprom type 93c46 and 93c56
; Parameters
; al - word to be read (6bit in case of 93c46 and 8bit otherwise)
; Return value
; ax - word read in
; Destroyed register(s)
; eax, cx, ebx, edx
;
;***************************************************************************
rtl8139_read_eeprom:
movzx ebx, al
mov edx, [io_addr]
add edx, RTL8139_REG_RXCONFIG
in al, dx
test al, (1 shl RTL8139_BIT_9356SEL)
jz .type_93c46
; and bl, 01111111b ; don't care first bit
or bx, EE_93C56_READ_CMD ; it contains start bit
mov cx, EE_93C56_CMD_LENGTH-1 ; cmd_loop counter
jmp .read_eeprom
.type_93c46:
and bl, 00111111b
or bx, EE_93C46_READ_CMD ; it contains start bit
mov cx, EE_93C46_CMD_LENGTH-1 ; cmd_loop counter
.read_eeprom:
add edx, RTL8139_REG_9346CR - RTL8139_REG_RXCONFIG_0
; mov al, (1 shl RTL8139_BIT_93C46_EEM1)
; out dx, al
mov al, (1 shl RTL8139_BIT_93C46_EEM1) \
or (1 shl RTL8139_BIT_93C46_EECS) ; wake up the eeprom
out dx, al
.cmd_loop:
mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EECS)
bt bx, cx
jnc .zero_bit
or al, (1 shl RTL8139_BIT_93C46_EEDI)
.zero_bit:
out dx, al
; push eax
; in eax, dx ; eeprom delay
; pop eax
or al, (1 shl RTL8139_BIT_93C46_EESK)
out dx, al
; in eax, dx ; eeprom delay
dec cx
jns .cmd_loop
; in eax, dx ; eeprom delay
mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EECS)
out dx, al
mov cl, 0xf
.read_loop:
shl ebx, 1
mov al, (1 shl RTL8139_BIT_93C46_EEM1) \
or (1 shl RTL8139_BIT_93C46_EECS) \
or (1 shl RTL8139_BIT_93C46_EESK)
out dx, al
; in eax, dx ; eeprom delay
in al, dx
and al, (1 shl RTL8139_BIT_93C46_EEDO)
jz .dont_set
inc ebx
.dont_set:
mov al, (1 shl RTL8139_BIT_93C46_EEM1) \
or (1 shl RTL8139_BIT_93C46_EECS)
out dx, al
; in eax, dx ; eeprom delay
dec cl
jns .read_loop
xor al, al
out dx, al
mov ax, bx
ret
 
;***************************************************************************
; Function
; rtl8139_transmit
; Description
; Transmits a packet of data via the ethernet card
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
; Destroyed registers
; eax, edx, esi, edi
; ToDo
; for waiting of timeout the rtl8139 internal timer
; should be used
;
;***************************************************************************
rtl8139_transmit:
cmp ecx, MAX_ETH_FRAME_SIZE
jg .finish ; packet is too long
push ecx
; check descriptor
mov ecx, [curr_tx_desc]
mov edx, [io_addr]
lea edx, [edx+ecx*4+RTL8139_REG_TSD0]
push edx ebx
in ax, dx
and ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN)
cmp ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN)
jz .send_packet
test ax, 0x1fff ; or no size given
jz .send_packet
; wait for timeout
mov ebx, RTL8139_TX_TIMEOUT
mov eax, 0x5 ; delay x/100 secs
int 0x40
in ax, dx
and ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN)
cmp ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN)
jz .send_packet
; chip hung, reset it
call rtl8139_reset
; reset the card
.send_packet:
; calculate tx_buffer address
pop ebx
push esi
mov eax, MAX_ETH_FRAME_SIZE
mul dword [curr_tx_desc]
mov esi, edi
lea edi, [rtl8139_tx_buff+eax]
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 the packet data
pop esi edx ecx
push ecx
shr ecx, 2
rep movsd
pop ecx
push ecx
and ecx, 3
rep movsb
; set address
add edx, RTL8139_REG_TSAD0 - RTL8139_REG_TSD0
out dx, eax
; set size and early threshold
pop eax ; pick up the size
add eax, ETH_HLEN
cmp eax, ETH_ZLEN
jnc .no_pad
mov eax, ETH_ZLEN
.no_pad:
or eax, (RTL8139_ERTXTH shl RTL8139_BIT_ERTXTH)
add edx, RTL8139_REG_TSD0 - RTL8139_REG_TSAD0
out dx, eax
; get next descriptor 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, ...
inc dword [curr_tx_desc]
and dword [curr_tx_desc], 3
.finish:
ret
 
;***************************************************************************
; Function
; rtl8139_poll
;
; Description
; Polls the ethernet card for a received packet
; Received data, if any, ends up in Ether_buffer
; Destroyed register(s)
; eax, edx, ecx
;
;***************************************************************************
rtl8139_poll:
mov word [eth_rx_data_len], 0
mov edx, [io_addr]
add edx, RTL8139_REG_COMMAND
in al, dx
test al, (1 shl RTL8139_BIT_BUFE)
jnz .finish
; new packet received copy it from rx_buffer into Ether_buffer
mov eax, rtl8139_rx_buff
add eax, [rtl8139_rx_buff_offset]
; check if packet is ok
test byte [eax], (1 shl RTL8139_BIT_ROK)
jz .reset_rx
; packet is ok copy it into the Ether_buffer
movzx ecx, word [eax+2] ; packet length
sub ecx, 4 ; don't copy CRC
mov word [eth_rx_data_len], cx
push ecx
shr ecx, 2 ; first copy dword-wise
lea esi, [eax+4] ; don't copy the packet header
mov edi, Ether_buffer
cld
rep movsd ; copy the dwords
pop ecx
and ecx, 3
rep movsb ; copy the rest bytes
; update rtl8139_rx_buff_offset
movzx eax, word [eax+2] ; packet length
add eax, [rtl8139_rx_buff_offset]
add eax, 4+3 ; packet header is 4 bytes long + dword alignment
and eax, not 3 ; dword alignment
cmp eax, RTL8139_RX_BUFFER_SIZE
jl .no_wrap
sub eax, RTL8139_RX_BUFFER_SIZE
.no_wrap:
mov [rtl8139_rx_buff_offset], eax
; update CAPR register
sub eax, 0x10 ; value 0x10 is a constant for CAPR
add edx, RTL8139_REG_CAPR - RTL8139_REG_COMMAND
out dx, ax
.finish:
; clear active interrupt sources
mov edx, [io_addr]
add edx, RTL8139_REG_ISR
in ax, dx
out dx, ax
ret
.reset_rx:
in al, dx ; read command register
push eax
and al, not (1 shl RTL8139_BIT_RE)
out dx, al
pop eax
out dx, al
add edx, RTL8139_REG_RXCONFIG - RTL8139_REG_COMMAND
mov ax, RTL8139_RX_CONFIG
out dx, ax
ret
/kernel/trunk/network/eth_drv/sis900.inc
0,0 → 1,1148
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; SIS900.INC ;;
;; ;;
;; Ethernet driver for Menuet OS ;;
;; ;;
;; Version 0.4 26 April 2004 ;;
;; ;;
;; This driver is based on the SIS900 driver from ;;
;; the etherboot 5.0.6 project. The copyright statement is ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; remaining parts Copyright 2004 Jason Delozier, ;;
;; cordata51@hotmail.com ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;; Updates: ;;
;; Revision Look up table and SIS635 Mac Address by Jarek Pelczar ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;********************************************************************
; Interface
; SIS900_reset
; SIS900_probe
; SIS900_poll
; SIS900_transmit
;
;********************************************************************
;********************************************************************
; Comments:
; Known to work with the following SIS900 ethernet cards:
; - Device ID: 0x0900 Vendor ID: 0x1039 Revision: 0x91
; - Device ID: 0x0900 Vendor ID: 0x1039 Revision: 0x90
;
; If your card is not listed, try it and let me know if it
; functions properly and it will be aded to the list. If not
; we may be able to add support for it.
;
; How To Use:
; Add the following lines to Ethernet.inc in their appropriate locations
;
; include "Sis900.INC"
; dd 0x09001039, SIS900_probe, SIS900_reset, SIS900_poll,
; SIS900_transmit
; dd 0x70161039, SIS900_probe, SIS900_reset, SIS900_poll,
; SIS900_transmit ;untested
;
; ToDo:
; - Enable MII interface for reading speed
; and duplex settings.
;
; - Update Poll routine to support packet fragmentation.
;
; - Add additional support for other sis900 based cards
;
;********************************************************************
 
; 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.
; SIS900_DEBUG equ 1
 
 
;* buffers and descriptors
cur_rx db 0
NUM_RX_DESC equ 4 ;* Number of RX descriptors *
NUM_TX_DESC equ 1 ;* Number of TX descriptors *
RX_BUFF_SZ equ 1520 ;* Buffer size for each Rx buffer *
TX_BUFF_SZ equ 1516 ;* Buffer size for each Tx buffer *
 
uglobal
align 4
txd: times (3 * NUM_TX_DESC) dd 0
rxd: times (3 * NUM_RX_DESC) dd 0
endg
 
txb equ eth_data_start
rxb equ txb + (NUM_TX_DESC * TX_BUFF_SZ)
SIS900_ETH_ALEN equ 6 ;* Size of Ethernet address *
SIS900_ETH_HLEN equ 14 ;* Size of ethernet header *
SIS900_ETH_ZLEN equ 60 ;* Minimum packet length *
SIS900_DSIZE equ 0x00000fff
SIS900_CRC_SIZE equ 4
SIS900_RFADDR_shift equ 16
;SIS900 Symbolic offsets to registers.
SIS900_cr equ 0x0 ; Command Register
SIS900_cfg equ 0x4 ; Configuration Register
SIS900_mear equ 0x8 ; EEPROM Access Register
SIS900_ptscr equ 0xc ; PCI Test Control Register
SIS900_isr equ 0x10 ; Interrupt Status Register
SIS900_imr equ 0x14 ; Interrupt Mask Register
SIS900_ier equ 0x18 ; Interrupt Enable Register
SIS900_epar equ 0x18 ; Enhanced PHY Access Register
SIS900_txdp equ 0x20 ; Transmit Descriptor Pointer Register
SIS900_txcfg equ 0x24 ; Transmit Configuration Register
SIS900_rxdp equ 0x30 ; Receive Descriptor Pointer Register
SIS900_rxcfg equ 0x34 ; Receive Configuration Register
SIS900_flctrl equ 0x38 ; Flow Control Register
SIS900_rxlen equ 0x3c ; Receive Packet Length Register
SIS900_rfcr equ 0x48 ; Receive Filter Control Register
SIS900_rfdr equ 0x4C ; Receive Filter Data Register
SIS900_pmctrl equ 0xB0 ; Power Management Control Register
SIS900_pmer equ 0xB4 ; Power Management Wake-up Event Register
;SIS900 Command Register Bits
SIS900_RELOAD equ 0x00000400
SIS900_ACCESSMODE equ 0x00000200
SIS900_RESET equ 0x00000100
SIS900_SWI equ 0x00000080
SIS900_RxRESET equ 0x00000020
SIS900_TxRESET equ 0x00000010
SIS900_RxDIS equ 0x00000008
SIS900_RxENA equ 0x00000004
SIS900_TxDIS equ 0x00000002
SIS900_TxENA equ 0x00000001
;SIS900 Configuration Register Bits
SIS900_DESCRFMT equ 0x00000100 ; 7016 specific
SIS900_REQALG equ 0x00000080
SIS900_SB equ 0x00000040
SIS900_POW equ 0x00000020
SIS900_EXD equ 0x00000010
SIS900_PESEL equ 0x00000008
SIS900_LPM equ 0x00000004
SIS900_BEM equ 0x00000001
SIS900_RND_CNT equ 0x00000400
SIS900_FAIR_BACKOFF equ 0x00000200
SIS900_EDB_MASTER_EN equ 0x00002000
;SIS900 Eeprom Access Reigster Bits
SIS900_MDC equ 0x00000040
SIS900_MDDIR equ 0x00000020
SIS900_MDIO equ 0x00000010 ; 7016 specific
SIS900_EECS equ 0x00000008
SIS900_EECLK equ 0x00000004
SIS900_EEDO equ 0x00000002
SIS900_EEDI equ 0x00000001
;SIS900 TX Configuration Register Bits
SIS900_ATP equ 0x10000000 ;Automatic Transmit Padding
SIS900_MLB equ 0x20000000 ;Mac Loopback Enable
SIS900_HBI equ 0x40000000 ;HeartBeat Ignore (Req for full-dup)
SIS900_CSI equ 0x80000000 ;CarrierSenseIgnore (Req for full-du
;SIS900 RX Configuration Register Bits
SIS900_AJAB equ 0x08000000 ;
SIS900_ATX equ 0x10000000 ;Accept Transmit Packets
SIS900_ARP equ 0x40000000 ;accept runt packets (<64bytes)
SIS900_AEP equ 0x80000000 ;accept error packets
;SIS900 Interrupt Reigster Bits
SIS900_WKEVT equ 0x10000000
SIS900_TxPAUSEEND equ 0x08000000
SIS900_TxPAUSE equ 0x04000000
SIS900_TxRCMP equ 0x02000000
SIS900_RxRCMP equ 0x01000000
SIS900_DPERR equ 0x00800000
SIS900_SSERR equ 0x00400000
SIS900_RMABT equ 0x00200000
SIS900_RTABT equ 0x00100000
SIS900_RxSOVR equ 0x00010000
SIS900_HIBERR equ 0x00008000
SIS900_SWINT equ 0x00001000
SIS900_MIBINT equ 0x00000800
SIS900_TxURN equ 0x00000400
SIS900_TxIDLE equ 0x00000200
SIS900_TxERR equ 0x00000100
SIS900_TxDESC equ 0x00000080
SIS900_TxOK equ 0x00000040
SIS900_RxORN equ 0x00000020
SIS900_RxIDLE equ 0x00000010
SIS900_RxEARLY equ 0x00000008
SIS900_RxERR equ 0x00000004
SIS900_RxDESC equ 0x00000002
SIS900_RxOK equ 0x00000001
;SIS900 Interrupt Enable Reigster Bits
SIS900_IE equ 0x00000001
;SIS900 Revision ID
SIS900B_900_REV equ 0x03
SIS630A_900_REV equ 0x80
SIS630E_900_REV equ 0x81
SIS630S_900_REV equ 0x82
SIS630EA1_900_REV equ 0x83
SIS630ET_900_REV equ 0x84
SIS635A_900_REV equ 0x90
SIS900_960_REV equ 0x91
;SIS900 Receive Filter Control Register Bits
SIS900_RFEN equ 0x80000000
SIS900_RFAAB equ 0x40000000
SIS900_RFAAM equ 0x20000000
SIS900_RFAAP equ 0x10000000
SIS900_RFPromiscuous equ 0x70000000
;SIS900 Reveive Filter Data Mask
SIS900_RFDAT equ 0x0000FFFF
;SIS900 Eeprom Address
SIS900_EEPROMSignature equ 0x00
SIS900_EEPROMVendorID equ 0x02
SIS900_EEPROMDeviceID equ 0x03
SIS900_EEPROMMACAddr equ 0x08
SIS900_EEPROMChecksum equ 0x0b
;The EEPROM commands include the alway-set leading bit.
;SIS900 Eeprom Command
SIS900_EEread equ 0x0180
SIS900_EEwrite equ 0x0140
SIS900_EEerase equ 0x01C0
SIS900_EEwriteEnable equ 0x0130
SIS900_EEwriteDisable equ 0x0100
SIS900_EEeraseAll equ 0x0120
SIS900_EEwriteAll equ 0x0110
SIS900_EEaddrMask equ 0x013F
SIS900_EEcmdShift equ 16
;For SiS962 or SiS963, request the eeprom software access
SIS900_EEREQ equ 0x00000400
SIS900_EEDONE equ 0x00000200
SIS900_EEGNT equ 0x00000100
;General Varibles
SIS900_pci_revision: db 0
SIS900_Status dd 0x03000000
sis900_specific_table:
; dd SIS630A_900_REV,Get_Mac_SIS630A_900_REV,0
; dd SIS630E_900_REV,Get_Mac_SIS630E_900_REV,0
dd SIS630S_900_REV,Get_Mac_SIS635_900_REV,0
dd SIS630EA1_900_REV,Get_Mac_SIS635_900_REV,0
dd SIS630ET_900_REV,Get_Mac_SIS635_900_REV,0;SIS630ET_900_REV_SpecialFN
dd SIS635A_900_REV,Get_Mac_SIS635_900_REV,0
dd SIS900_960_REV,SIS960_get_mac_addr,0
dd SIS900B_900_REV,SIS900_get_mac_addr,0
dd 0,0,0,0 ; end of list
sis900_get_mac_func: dd 0
sis900_special_func: dd 0
sis900_table_entries: db 8
 
;***************************************************************************
; Function
; SIS900_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
;not done - still need to probe mii transcievers
;***************************************************************************
if defined SIS900_DEBUG
SIS900_Debug_Str_Unsupported db 'Sorry your card is unsupported ',13,10,0
end if
SIS900_probe:
;******Wake Up Chip*******
mov al, 4
mov bh, [pci_dev]
mov ecx, 0
mov ah, [pci_bus]
mov bl, 0x40
call pci_write_reg
;*******Set some PCI Settings*********
call SIS900_adjust_pci_device
;*****Get Card Revision******
mov al, 1 ;one byte to read
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, 0x08 ;Revision Register
call pci_read_reg
mov [SIS900_pci_revision], al ;save the revision for later use
;****** Look up through the sis900_specific_table
mov esi,sis900_specific_table
.probe_loop:
cmp dword [esi],0 ; Check if we reached end of the list
je .probe_loop_failed
cmp al,[esi] ; Check if revision is OK
je .probe_loop_ok
add esi,12 ; Advance to next entry
jmp .probe_loop
.probe_loop_failed:
jmp SIS900_Probe_Unsupported
;*********Find Get Mac Function*********
.probe_loop_ok:
mov eax,[esi+4] ; Get pointer to "get MAC" function
mov [sis900_get_mac_func],eax
mov eax,[esi+8] ; Get pointer to special initialization fn
mov [sis900_special_func],eax
;******** Get MAC ********
call dword [sis900_get_mac_func]
;******** Call special initialization fn if requested ********
cmp dword [sis900_special_func],0
je .no_special_init
call dword [sis900_special_func]
.no_special_init:
;******** Set table entries ********
mov al,[SIS900_pci_revision]
cmp al,SIS635A_900_REV
jae .ent16
cmp al,SIS900B_900_REV
je .ent16
jmp .ent8
.ent16:
mov byte [sis900_table_entries],16
.ent8:
;*******Probe for mii transceiver*******
;TODO!!*********************
;*******Initialize Device*******
call sis900_init
ret
 
SIS900_Probe_Unsupported:
if defined SIS900_DEBUG
mov esi, SIS900_Debug_Str_Unsupported
call sys_msg_board_str
end if
ret
;***************************************************************************
; Function: sis900_init
;
; Description: resets the ethernet controller chip and various
; data structures required for sending and receiving packets.
;
; Arguments:
;
; returns: none
;not done
;***************************************************************************
sis900_init:
call SIS900_reset ;Done
call SIS900_init_rxfilter ;Done
call SIS900_init_txd ;Done
call SIS900_init_rxd ;Done
call SIS900_set_rx_mode ;done
call SIS900_set_tx_mode
;call SIS900_check_mode
ret
 
;***************************************************************************
; Function
; SIS900_reset
; Description
; disables interrupts and soft resets the controller chip
;
;done+
;***************************************************************************
if defined SIS900_DEBUG
SIS900_Debug_Reset_Failed db 'Reset Failed ',0
end if
SIS900_reset:
;******Disable Interrupts and reset Receive Filter*******
mov ebp, [io_addr] ; base address
xor eax, eax ; 0 to initialize
lea edx,[ebp+SIS900_ier]
out dx, eax ; Write 0 to location
lea edx,[ebp+SIS900_imr]
out dx, eax ; Write 0 to location
lea edx,[ebp+SIS900_rfcr]
out dx, eax ; Write 0 to location
;*******Reset Card***********************************************
lea edx,[ebp+SIS900_cr]
in eax, dx ; Get current Command Register
or eax, SIS900_RESET ; set flags
or eax, SIS900_RxRESET ;
or eax, SIS900_TxRESET ;
out dx, eax ; Write new Command Register
;*******Wait Loop************************************************
lea edx,[ebp+SIS900_isr]
mov ecx, [SIS900_Status] ; Status we would like to see from card
mov ebx, 2001 ; only loop 1000 times
SIS900_Wait:
dec ebx ; 1 less loop
jz SIS900_DoneWait_e ; 1000 times yet?
in eax, dx ; move interrup status to eax
and eax, ecx
xor ecx, eax
jz SIS900_DoneWait
jmp SIS900_Wait
SIS900_DoneWait_e:
if defined SIS900_DEBUG
mov esi, SIS900_Debug_Reset_Failed
call sys_msg_board_str
end if
SIS900_DoneWait:
;*******Set Configuration Register depending on Card Revision********
lea edx,[ebp+SIS900_cfg]
mov eax, SIS900_PESEL ; Configuration Register Bit
mov bl, [SIS900_pci_revision] ; card revision
mov cl, SIS635A_900_REV ; Check card revision
cmp bl, cl
je SIS900_RevMatch
mov cl, SIS900B_900_REV ; Check card revision
cmp bl, cl
je SIS900_RevMatch
out dx, eax ; no revision match
jmp SIS900_Reset_Complete
SIS900_RevMatch: ; Revision match
or eax, SIS900_RND_CNT ; Configuration Register Bit
out dx, eax
SIS900_Reset_Complete:
mov eax, [pci_data]
mov [eth_status], eax
ret
 
;***************************************************************************
; Function: sis_init_rxfilter
;
; Description: sets receive filter address to our MAC address
;
; Arguments:
;
; returns:
;done+
;***************************************************************************
SIS900_init_rxfilter:
;****Get Receive Filter Control Register ********
mov ebp, [io_addr] ; base address
lea edx,[ebp+SIS900_rfcr]
in eax, dx ; get register
push eax
;****disable packet filtering before setting filter*******
mov eax, SIS900_RFEN ;move receive filter enable flag
not eax ;1s complement
pop ebx ;and with our saved register
and eax, ebx ;disable receiver
push ebx ;save filter for another use
out dx, eax ;set receive disabled
;********load MAC addr to filter data register*********
xor ecx, ecx
SIS900_RXINT_Mac_Write:
;high word of eax tells card which mac byte to write
mov eax, ecx
lea edx,[ebp+SIS900_rfcr]
shl eax, 16 ;
out dx, eax ;
lea edx,[ebp+SIS900_rfdr]
mov ax, word [node_addr+ecx*2] ; Get Mac ID word
out dx, ax ; Send Mac ID
inc cl ; send next word
cmp cl, 3 ; more to send?
jne SIS900_RXINT_Mac_Write
;********enable packet filitering *****
pop eax ;old register value
lea edx,[ebp+SIS900_rfcr]
or eax, SIS900_RFEN ;enable filtering
out dx, eax ;set register
ret
 
;***************************************************************************
;*
;* Function: sis_init_txd
;*
;* Description: initializes the Tx descriptor
;*
;* Arguments:
;*
;* returns:
;*done
;***************************************************************************
SIS900_init_txd:
;********** initialize TX descriptor **************
mov [txd], dword 0 ;put link to next descriptor in link field
mov [txd+4],dword 0 ;clear status field
mov [txd+8], dword txb ;save address to buffer ptr field
;*************** load Transmit Descriptor Register ***************
mov dx, [io_addr] ; base address
add dx, SIS900_txdp ; TX Descriptor Pointer
mov eax, txd ; First Descriptor
out dx, eax ; move the pointer
ret
 
;***************************************************************************
;* Function: sis_init_rxd
;*
;* Description: initializes the Rx descriptor ring
;*
;* Arguments:
;*
;* Returns:
;*done
;***************************************************************************
SIS900_init_rxd:
xor ecx,ecx
mov [cur_rx], cl ;Set cuurent rx discriptor to 0
;******** init RX descriptors ********
SIS900_init_rxd_Loop:
mov eax, ecx ;current descriptor
imul eax, 12 ;
mov ebx, ecx ;determine next link descriptor
inc ebx ;
cmp ebx, NUM_RX_DESC ;
jne SIS900_init_rxd_Loop_0 ;
xor ebx, ebx ;
SIS900_init_rxd_Loop_0: ;
imul ebx, 12 ;
add ebx, rxd ;
mov [rxd+eax], ebx ;save link to next descriptor
mov [rxd+eax+4],dword RX_BUFF_SZ ;status bits init to buf size
mov ebx, ecx ;find where the buf is located
imul ebx,RX_BUFF_SZ ;
add ebx, rxb ;
mov [rxd+eax+8], ebx ;save buffer pointer
inc ecx ;next descriptor
cmp ecx, NUM_RX_DESC ;
jne SIS900_init_rxd_Loop ;
;********* load Receive Descriptor Register with address of first
; descriptor*********
mov dx, [io_addr]
add dx, SIS900_rxdp
mov eax, rxd
out dx, eax
ret
 
;***************************************************************************
;* Function: sis900_set_tx_mode
;*
;* Description:
;* sets the transmit mode to allow for full duplex
;*
;*
;* Arguments:
;*
;* Returns:
;*
;* Comments:
;* If you are having problems transmitting packet try changing the
;* Max DMA Burst, Possible settings are as follows:
;* 0x00000000 = 512 bytes
;* 0x00100000 = 4 bytes
;* 0x00200000 = 8 bytes
;* 0x00300000 = 16 bytes
;* 0x00400000 = 32 bytes
;* 0x00500000 = 64 bytes
;* 0x00600000 = 128 bytes
;* 0x00700000 = 256 bytes
;***************************************************************************
SIS900_set_tx_mode:
mov ebp,[io_addr]
lea edx,[ebp+SIS900_cr]
in eax, dx ; Get current Command Register
or eax, SIS900_TxENA ;Enable Receive
out dx, eax
lea edx,[ebp+SIS900_txcfg]; Transmit config Register offset
mov eax, SIS900_ATP ;allow automatic padding
or eax, SIS900_HBI ;allow heartbeat ignore
or eax, SIS900_CSI ;allow carrier sense ignore
or eax, 0x00600000 ;Max DMA Burst
or eax, 0x00000100 ;TX Fill Threshold
or eax, 0x00000020 ;TX Drain Threshold
out dx, eax
ret
 
;***************************************************************************
;* Function: sis900_set_rx_mode
;*
;* Description:
;* sets the receive mode to accept all broadcast packets and packets
;* with our MAC address, and reject all multicast packets. Also allows
;* full-duplex
;*
;* Arguments:
;*
;* Returns:
;*
;* Comments:
;* If you are having problems receiving packet try changing the
;* Max DMA Burst, Possible settings are as follows:
;* 0x00000000 = 512 bytes
;* 0x00100000 = 4 bytes
;* 0x00200000 = 8 bytes
;* 0x00300000 = 16 bytes
;* 0x00400000 = 32 bytes
;* 0x00500000 = 64 bytes
;* 0x00600000 = 128 bytes
;* 0x00700000 = 256 bytes
;***************************************************************************
SIS900_mc_filter: times 16 dw 0
SIS900_set_rx_mode:
mov ebp,[io_addr]
;**************update Multicast Hash Table in Receive Filter
mov ebx, 0xffff
xor cl, cl
SIS900_set_rx_mode_Loop:
mov eax, ecx
shl eax, 1
mov [SIS900_mc_filter+eax], ebx
lea edx,[ebp+SIS900_rfcr] ; Receive Filter Control Reg offset
mov eax, 4 ;determine table entry
add al, cl
shl eax, 16
out dx, eax ;tell card which entry to modify
lea edx,[ebp+SIS900_rfdr] ; Receive Filter Control Reg offset
mov eax, ebx ;entry value
out dx, ax ;write value to table in card
inc cl ;next entry
cmp cl,[sis900_table_entries] ;
jl SIS900_set_rx_mode_Loop
;*******Set Receive Filter Control Register*************
lea edx,[ebp+SIS900_rfcr] ; Receive Filter Control Register offset
mov eax, SIS900_RFAAB ;accecpt all broadcast packets
or eax, SIS900_RFAAM ;accept all multicast packets
or eax, SIS900_RFAAP ;Accept all packets
or eax, SIS900_RFEN ;enable receiver filter
out dx, eax
;******Enable Receiver************
lea edx,[ebp+SIS900_cr] ; Command Register offset
in eax, dx ; Get current Command Register
or eax, SIS900_RxENA ;Enable Receive
out dx, eax
;*********Set
lea edx,[ebp+SIS900_rxcfg] ; Receive Config Register offset
mov eax, SIS900_ATX ;Accept Transmit Packets
; (Req for full-duplex and PMD Loopback)
or eax, 0x00600000 ;Max DMA Burst
or eax, 0x00000002 ;RX Drain Threshold, 8X8 bytes or 64bytes
out dx, eax ;
ret
 
;***************************************************************************
; * SIS960_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
; * @pci_dev: the sis900 pci device
; * @net_dev: the net device to get address for
; *
; * SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
; * is shared by
; * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
; * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access
; * by LAN, otherwise is not. After MAC address is read from EEPROM, send
; * EEDONE signal to refuse EEPROM access by LAN.
; * The EEPROM map of SiS962 or SiS963 is different to SiS900.
; * The signature field in SiS962 or SiS963 spec is meaningless.
; * MAC address is read into @net_dev->dev_addr.
; *done
;*
;* Return 0 is EAX = failure
;*Done+
;***************************************************************************
if defined SIS900_DEBUG
SIS900_Debug_Str_GetMac_Start db 'Attempting to get SIS900 Mac ID: ',13,10,0
SIS900_Debug_Str_GetMac_Failed db 'Access to EEprom Failed',13,10,0
SIS900_Debug_Str_GetMac_Address db 'Your Mac ID is: ',0
SIS900_Debug_Str_GetMac_Address2 db 'Your SIS96x Mac ID is: ',0
end if
SIS960_get_mac_addr:
mov ebp,[io_addr]
;**********Send Request for eeprom access*********************
lea edx,[ebp+SIS900_mear] ; Eeprom access register
mov eax, SIS900_EEREQ ; Request access to eeprom
out dx, eax ; Send request
xor ebx,ebx ;
;******Loop 4000 times and if access not granted error out*****
SIS96X_Get_Mac_Wait:
in eax, dx ;get eeprom status
and eax, SIS900_EEGNT ;see if eeprom access granted flag is set
jnz SIS900_Got_EEP_Access ;if it is, go access the eeprom
inc ebx ;else keep waiting
cmp ebx, 4000 ;have we tried 4000 times yet?
jl SIS96X_Get_Mac_Wait ;if not ask again
xor eax, eax ;return zero in eax indicating failure
;*******Debug **********************
if defined SIS900_DEBUG
mov esi,SIS900_Debug_Str_GetMac_Failed
call sys_msg_board_str
end if
jmp SIS960_get_mac_addr_done
;**********EEprom access granted, read MAC from card*************
SIS900_Got_EEP_Access:
; zero based so 3-16 bit reads will take place
mov ecx, 2
SIS96x_mac_read_loop:
mov eax, SIS900_EEPROMMACAddr ;Base Mac Address
add eax, ecx ;Current Mac Byte Offset
push ecx
call sis900_read_eeprom ;try to read 16 bits
pop ecx
mov [node_addr+ecx*2], ax ;save 16 bits to the MAC ID varible
dec ecx ;one less word to read
jns SIS96x_mac_read_loop ;if more read more
mov eax, 1 ;return non-zero indicating success
;*******Debug Print MAC ID to debug window**********************
if defined SIS900_DEBUG
mov esi,SIS900_Debug_Str_GetMac_Address2
call sys_msg_board_str
mov edx, node_addr
call Create_Mac_String
end if
;**********Tell EEPROM We are Done Accessing It*********************
SIS960_get_mac_addr_done:
lea edx,[ebp+SIS900_mear] ; Eeprom access register
mov eax, SIS900_EEDONE ;tell eeprom we are done
out dx,eax
ret
;***************************************************************************
;* sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model
;* @pci_dev: the sis900 pci device
;* @net_dev: the net device to get address for
;*
;* Older SiS900 and friends, use EEPROM to store MAC address.
;* MAC address is read from read_eeprom() into @net_dev->dev_addr.
;* done/untested
;***************************************************************************
SIS900_get_mac_addr:
;*******Debug **********************
if defined SIS900_DEBUG
mov esi,SIS900_Debug_Str_GetMac_Start
call sys_msg_board_str
end if
;******** check to see if we have sane EEPROM *******
mov eax, SIS900_EEPROMSignature ;Base Eeprom Signature
call sis900_read_eeprom ;try to read 16 bits
cmp ax, 0xffff
je SIS900_Bad_Eeprom
cmp ax, 0
je SIS900_Bad_Eeprom
;**************Read MacID**************
; zero based so 3-16 bit reads will take place
mov ecx, 2
SIS900_mac_read_loop:
mov eax, SIS900_EEPROMMACAddr ;Base Mac Address
add eax, ecx ;Current Mac Byte Offset
push ecx
call sis900_read_eeprom ;try to read 16 bits
pop ecx
mov [node_addr+ecx*2], ax ;save 16 bits to the MAC ID storage
dec ecx ;one less word to read
jns SIS900_mac_read_loop ;if more read more
mov eax, 1 ;return non-zero indicating success
;*******Debug Print MAC ID to debug window**********************
if defined SIS900_DEBUG
mov esi,SIS900_Debug_Str_GetMac_Address
call sys_msg_board_str
mov edx, node_addr
call Create_Mac_String
end if
ret
 
SIS900_Bad_Eeprom:
xor eax, eax
;*******Debug **********************
if defined SIS900_DEBUG
mov esi,SIS900_Debug_Str_GetMac_Failed
call sys_msg_board_str
end if
ret
;***************************************************************************
;* Get_Mac_SIS635_900_REV: - Get MAC address for model 635
;*
;*
;***************************************************************************
Get_Mac_SIS635_900_REV:
if defined SIS900_DEBUG
mov esi,SIS900_Debug_Str_GetMac_Start
call sys_msg_board_str
end if
mov ebp,[io_addr]
lea edx,[ebp+SIS900_rfcr]
in eax,dx
mov edi,eax ; EDI=rfcrSave
lea edx,[ebp+SIS900_cr]
or eax,SIS900_RELOAD
out dx,eax
xor eax,eax
out dx,eax
; Disable packet filtering before setting filter
lea edx,[ebp+SIS900_rfcr]
mov eax,edi
and edi,not SIS900_RFEN
out dx,eax
; Load MAC to filter data register
xor ecx,ecx
mov esi,node_addr
.get_mac_loop:
lea edx,[ebp+SIS900_rfcr]
mov eax,ecx
shl eax,SIS900_RFADDR_shift
out dx,eax
lea edx,[ebp+SIS900_rfdr]
in eax,dx
mov [esi],ax
add esi,2
inc ecx
cmp ecx,3
jne .get_mac_loop
; Enable packet filtering
;lea edx,[ebp+SIS900_rfcr]
;mov eax,edi
;or eax,SIS900_RFEN
;out dx, eax
;*******Debug Print MAC ID to debug window**********************
if defined SIS900_DEBUG
mov esi,SIS900_Debug_Str_GetMac_Address
call sys_msg_board_str
mov edx, node_addr
call Create_Mac_String
end if
ret
;***************************************************************************
;* Function: sis900_read_eeprom
;*
;* Description: reads and returns a given location from EEPROM
;*
;* Arguments: eax - location: requested EEPROM location
;*
;* Returns: eax : contents of requested EEPROM location
;*
; Read Serial EEPROM through EEPROM Access Register, Note that location is
; in word (16 bits) unit */
;done+
;***************************************************************************
sis900_read_eeprom:
push esi
push edx
push ecx
push ebx
mov ebp,[io_addr]
mov ebx, eax ;location of Mac byte to read
or ebx, SIS900_EEread ;
lea edx,[ebp+SIS900_mear] ; Eeprom access register
xor eax, eax ; start send
out dx,eax
call SIS900_Eeprom_Delay_1
mov eax, SIS900_EECLK
out dx, eax
call SIS900_Eeprom_Delay_1
;************ Shift the read command (9) bits out. *********
mov cl, 8 ;
sis900_read_eeprom_Send:
mov eax, 1
shl eax, cl
and eax, ebx
jz SIS900_Read_Eeprom_8
mov eax, 9
jmp SIS900_Read_Eeprom_9
SIS900_Read_Eeprom_8:
mov eax, 8
SIS900_Read_Eeprom_9:
out dx, eax
call SIS900_Eeprom_Delay_1
or eax, SIS900_EECLK
out dx, eax
call SIS900_Eeprom_Delay_1
cmp cl, 0
je sis900_read_eeprom_Send_Done
dec cl
jmp sis900_read_eeprom_Send
;*********************
sis900_read_eeprom_Send_Done:
mov eax, SIS900_EECS ;
out dx, eax
call SIS900_Eeprom_Delay_1
;********** Read 16-bits of data in ***************
mov cx, 16 ;16 bits to read
sis900_read_eeprom_Send2:
mov eax, SIS900_EECS
out dx, eax
call SIS900_Eeprom_Delay_1
or eax, SIS900_EECLK
out dx, eax
call SIS900_Eeprom_Delay_1
in eax, dx
shl ebx, 1
and eax, SIS900_EEDO
jz SIS900_Read_Eeprom_0
or ebx, 1
SIS900_Read_Eeprom_0:
dec cx
jnz sis900_read_eeprom_Send2
;************** Terminate the EEPROM access. **************
xor eax, eax
out dx, eax
call SIS900_Eeprom_Delay_1
mov eax, SIS900_EECLK
out dx, eax
mov eax, ebx
and eax, 0x0000ffff ;return only 16 bits
pop ebx
pop ecx
pop edx
pop esi
ret
;***************************************************************************
; Function
; SIS900_Eeprom_Delay_1
; Description
;
;
;
;
;***************************************************************************
SIS900_Eeprom_Delay_1:
push eax
in eax, dx
pop eax
ret
 
;***************************************************************************
; Function
; SIS900_poll
; Description
; polls card to see if there is a packet waiting
;
; Currently only supports one descriptor per packet, if packet is fragmented
; between multiple descriptors you will lose part of the packet
;***************************************************************************
if defined SIS900_DEBUG
SIS900_Debug_Pull_Packet_good db 'Good Packet Waiting: ',13,10,0
SIS900_Debug_Pull_Bad_Packet_Status db 'Bad Packet Waiting: Status',13,10,0
SIS900_Debug_Pull_Bad_Packet_Size db 'Bad Packet Waiting: Size',13,10,0
end if
SIS900_poll:
;**************Get Status **************
xor eax, eax ;get RX_Status
mov [eth_rx_data_len], ax
mov al, [cur_rx] ;find current discriptor
imul eax, 12 ;
mov ecx, [rxd+eax+4] ; get receive status
;**************Check Status **************
mov ebx, ecx ;move status
;Check RX_Status to see if packet is waiting
and ebx, 0x80000000
jnz SIS900_poll_IS_packet
ret
;**********There is a packet waiting check it for errors**************
SIS900_poll_IS_packet:
mov ebx, ecx ;move status
and ebx, 0x67C0000 ;see if there are any errors
jnz SIS900_Poll_Error_Status
;**************Check size of packet*************
and ecx, SIS900_DSIZE ;get packet size minus CRC
cmp cx, SIS900_CRC_SIZE
;make sure packet contains data
jle SIS900_Poll_Error_Size
;*******Copy Good Packet to receive buffer******
sub cx, SIS900_CRC_SIZE ;dont want crc
mov word [eth_rx_data_len], cx ;save size of packet
;**********Continue copying packet****************
push ecx
; first copy dword-wise, divide size by 4
shr ecx, 2
mov esi, [rxd+eax+8] ; set source
mov edi, Ether_buffer ; set destination
cld ; clear direction
rep movsd ; copy the dwords
pop ecx
and ecx, 3 ;
rep movsb
;********Debug, tell user we have a good packet*************
if defined SIS900_DEBUG
mov esi, SIS900_Debug_Pull_Packet_good
call sys_msg_board_str
end if
jmp SIS900_Poll_Cnt ;
;*************Error occured let user know through debug window***********
SIS900_Poll_Error_Status:
if defined SIS900_DEBUG
mov esi, SIS900_Debug_Pull_Bad_Packet_Status
call sys_msg_board_str
end if
jmp SIS900_Poll_Cnt
SIS900_Poll_Error_Size:
if defined SIS900_DEBUG
mov esi, SIS900_Debug_Pull_Bad_Packet_Size
call sys_msg_board_str
end if
;*************Increment to next available descriptor**************
SIS900_Poll_Cnt:
;Reset status, allow ethernet card access to descriptor
mov ecx, RX_BUFF_SZ
mov [rxd+eax+4], ecx ;
inc [cur_rx] ;get next descriptor
and [cur_rx],3 ;only 4 descriptors 0-3
;******Enable Receiver************
mov ebp, [io_addr] ; Base Address
lea edx,[ebp+SIS900_cr] ; Command Register offset
in eax, dx ; Get current Command Register
or eax, SIS900_RxENA ;Enable Receive
out dx, eax
ret
;***************************************************************************
; Function
; SIS900_transmit
; Description
; Transmits a packet of data via the ethernet card
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
;
; only one transmit descriptor is used
;
;***************************************************************************
if defined SIS900_DEBUG
SIS900_Debug_Transmit_Packet db 'Transmitting Packet: ',13,10,0
SIS900_Debug_Transmit_Packet_Err db 'Transmitting Packet Error: ',13,10,0
end if
SIS900_transmit:
mov ebp, [io_addr] ; Base Address
;******** Stop the transmitter ********
lea edx,[ebp+SIS900_cr] ; Command Register offset
in eax, dx ; Get current Command Register
or eax, SIS900_TxDIS ; Disable Transmitter
out dx, eax
;*******load Transmit Descriptor Register *******
lea edx,[ebp+SIS900_txdp]
mov eax, txd
out dx, eax
;******* copy packet to descriptor*******
push esi
mov esi, edi ;copy destination addess
mov edi, txb
cld
movsd
movsw
mov esi, node_addr ;copy my mac address
movsd
movsw
mov [edi], bx ;copy packet type
add edi, 2
pop esi ;restore pointer to source of packet
push ecx ;save packet size
shr ecx, 2 ;divide by 4, size in bytes send in dwords
rep movsd ;copy data to decriptor
pop ecx ;restore packet size
push ecx ;save packet size
and ecx, 3 ;last three bytes if not a multiple of 4
rep movsb
;**************set length tag**************
pop ecx ;restore packet size
add ecx, SIS900_ETH_HLEN ;add header to length
and ecx, SIS900_DSIZE ;
;**************pad to minimum packet size **************not needed
;cmp ecx, SIS900_ETH_ZLEN
;jge SIS900_transmit_Size_Ok
;push ecx
;mov ebx, SIS900_ETH_ZLEN
;sub ebx, ecx
;mov ecx, ebx
;rep movsb
;pop ecx
SIS900_transmit_Size_Ok:
mov [txd+4], dword 0x80000000 ;card owns descriptor
or [txd+4], ecx ;set size of packet
if defined SIS900_DEBUG
mov esi, SIS900_Debug_Transmit_Packet
call sys_msg_board_str
end if
;***************restart the transmitter ********
lea edx,[ebp+SIS900_cr]
in eax, dx ; Get current Command Register
or eax, SIS900_TxENA ; Enable Transmitter
out dx, eax
;****make sure packet transmitted successfully****
; mov esi,10
; call delay_ms
mov eax, [txd+4]
and eax, 0x6200000
jz SIS900_transmit_OK
;**************Tell user there was an error through debug window
if defined SIS900_DEBUG
mov esi, SIS900_Debug_Transmit_Packet_Err
call sys_msg_board_str
end if
SIS900_transmit_OK:
;******** Disable interrupts by clearing the interrupt mask. ********
lea edx,[ebp+SIS900_imr] ; Interupt Mask Register
xor eax, eax
out dx,eax
ret
 
;***************************************************************************
;* Function: Create_Mac_String
;*
;* Description: Converts the 48 bit value to a string for display
;*
;* String Format: XX:XX:XX:XX:XX:XX
;*
;* Arguments: node_addr is location of 48 bit MAC ID
;*
;* Returns: Prints string to general debug window
;*
;*
;done
;***************************************************************************
if defined SIS900_DEBUG
 
SIS900_Char_String db '0','1','2','3','4','5','6','7','8','9'
db 'A','B','C','D','E','F'
Mac_str_build: times 20 db 0
Create_Mac_String:
pusha
xor ecx, ecx
Create_Mac_String_loop:
mov al,byte [edx+ecx];[node_addr+ecx]
push eax
shr eax, 4
and eax, 0x0f
mov bl, byte [SIS900_Char_String+eax]
mov [Mac_str_build+ecx*3], bl
pop eax
and eax, 0x0f
mov bl, byte [SIS900_Char_String+eax]
mov [Mac_str_build+1+ecx*3], bl
cmp ecx, 5
je Create_Mac_String_done
mov bl, ':'
mov [Mac_str_build+2+ecx*3], bl
inc ecx
jmp Create_Mac_String_loop
Create_Mac_String_done: ;Insert CR and Zero Terminate
mov [Mac_str_build+2+ecx*3],byte 13
mov [Mac_str_build+3+ecx*3],byte 10
mov [Mac_str_build+4+ecx*3],byte 0
mov esi, Mac_str_build
call sys_msg_board_str ;Print String to message board
popa
ret
end if
;***************************************************************************
;* Set device to be a busmaster in case BIOS neglected to do so.
;* Also adjust PCI latency timer to a reasonable value, 64.
;***************************************************************************
SIS900_adjust_pci_device:
;*******Get current setting************************
mov al, 2 ;read a word
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, 0x04 ;from command Register
call pci_read_reg
;******see if its already set as bus master********
mov bx, ax
and bx,5
cmp bx,5
je SIS900_adjust_pci_device_Latency
;******Make card a bus master*******
mov cx, ax ;value to write
mov bh, [pci_dev]
mov al, 2 ;write a word
or cx,5
mov ah, [pci_bus]
mov bl, 0x04 ;to command register
call pci_write_reg
;******Check latency setting***********
SIS900_adjust_pci_device_Latency:
;*******Get current latency setting************************
mov al, 1 ;read a byte
mov bh, [pci_dev]
mov ah, [pci_bus]
mov bl, 0x0D ;from Lantency Timer Register
call pci_read_reg
;******see if its aat least 64 clocks********
cmp ax,64
jge SIS900_adjust_pci_device_Done
;******Set latency to 32 clocks*******
mov cx, 64 ;value to write
mov bh, [pci_dev]
mov al, 1 ;write a byte
mov ah, [pci_bus]
mov bl, 0x0D ;to Lantency Timer Register
call pci_write_reg
;******Check latency setting***********
SIS900_adjust_pci_device_Done:
ret
/kernel/trunk/network/ip.inc
0,0 → 1,202
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; IP.INC ;;
;; ;;
;; IP Processes for Menuet OS TCP/IP stack ;;
;; ;;
;; Version 0.3 29 August 2002 ;;
;; ;;
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
;*******************************************************************
; Interface
;
; ip_rx processes all packets received by the network layer
; It calls the appropriate protocol handler
;
;
;
;*******************************************************************
 
 
;***************************************************************************
; Function
; ip_rx
;
; Description
; Handles received IP packets
; This is a kernel function, called by stack_handler
;
;***************************************************************************
ip_rx:
; Look for a buffer to tx
mov eax, IPIN_QUEUE
call dequeue
cmp ax, NO_BUFFER
je ipr_exit ; Exit if no buffer available
 
push eax
 
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
mov edx, eax ; Save the address in edx for use by future processes
 
; Validate the IP checksum
mov ebx, edx
mov ah, [ebx + 10]
mov al, [ebx + 11] ; Get the checksum in intel format
mov [ebx + 10], word 0 ; clear checksum field - need to when
; recalculating checksum
 
; this needs two data pointers and two size #.
; 2nd pointer can be of length 0
mov ebx, edx
mov [checkAdd1], ebx
mov [checkSize1], word 20
mov [checkAdd2], dword 0
mov [checkSize2], word 0
 
call checksum ; Recalculate IP checksum
cmp ax, [checkResult]
jnz ipr_dump
 
; If the IP address is 255.255.255.255, accept it
; - it is a broadcast packet, which we need for dhcp
mov eax, [edx + 16]
cmp eax, 0xffffffff
je ipr_p0
 
; Validate the IP address, if it isn't broadcast
cmp eax, [stack_ip]
jnz ipr_dump
 
ipr_p0:
mov al, [edx]
and al, 0x0f
cmp al, 0x05
jnz ipr_dump
 
cmp [edx+8], byte 0
jz ipr_dump
 
mov ax, [edx + 6]
and ax, 0xFFBF
cmp ax, 0
jnz ipr_dump
 
; Check the protocol, and call the appropriate handler
; Each handler will re-use or free the queue buffer as appropriate
mov al, [edx + 9]
cmp al , PROTOCOL_ICMP
jnz ipr_p1
pop eax
call icmp_rx
jmp ipr_exit
 
ipr_p1:
cmp al , PROTOCOL_TCP
jnz ipr_p2
pop eax
call tcp_rx
jmp ipr_exit
 
ipr_p2:
cmp al , PROTOCOL_UDP
jnz ipr_dump
pop eax
call udp_rx
jmp ipr_exit
 
ipr_dump:
; No protocol handler available, so
; silently dump the packet, freeing up the queue buffer
 
; inc dword [dumped_rx_count]
 
pop eax
call freeBuff
 
ipr_exit:
ret
 
 
 
;***************************************************************************
; Function
; icmp_rx
;
; Description
; ICMP protocol handler
; This is a kernel function, called by ip_rx
; edx contains the address of the buffer in use.
; This buffer must be reused or marked as empty afterwards
;
;***************************************************************************
icmp_rx:
cmp [edx + 20], byte 8 ; Is this an echo request? discard if not
jz icmp_echo
 
call freeBuff
jmp icmp_exit
 
icmp_echo:
push eax
mov [edx + 10], word 0 ; I think this was already done by IP rx
 
; swap the source and destination addresses
mov ecx, [edx + 16]
mov eax, [edx + 12]
mov [edx + 16], eax
mov [edx + 12], ecx
 
; recaluculate the IP header checksum
 
mov ebx, edx
mov [checkAdd1], ebx
mov [checkSize1], word 20
mov [checkAdd2], dword 0
mov [checkSize2], word 0
 
call checksum
mov ax, [checkResult]
mov [edx + 10], ah
mov [edx + 11], al ; ?? correct byte order?
 
mov [edx + 20], byte 0 ; change the request to a response
mov [edx + 22], word 0 ; clear ICMP checksum prior to re-calc
 
; Calculate the length of the ICMP data ( IP payload)
mov ah, [edx + 2]
mov al, [edx + 3]
sub ax, 20
 
mov [checkSize1], ax
mov ebx, edx
add ebx, 20
 
mov [checkAdd1], ebx
mov [checkAdd2], dword 0
mov [checkSize2], word 0
 
call checksum
 
mov ax, [checkResult]
mov [edx + 22], ah
mov [edx + 23], al
 
; Queue packet for transmission
 
pop ebx
mov eax, NET1OUT_QUEUE
call queue
 
icmp_exit:
ret
/kernel/trunk/network/queue.inc
0,0 → 1,214
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; QUEUE.INC ;;
;; ;;
;; Buffer queue management for Menuet OS TCP/IP Stack ;;
;; ;;
;; Version 0.3 29 August 2002 ;;
;; ;;
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
;*******************************************************************
; Interface
;
; queueInit Configures the queues to empty
; dequeue Removes a buffer pointer from a queue
; queue Inserts a buffer pointer into a queue
; freeBuff Adds the buffer pointer to the list of free buffers
; queueSize Returns the number of entries in a queue
;
; The various defines for queue names can be found in stack.inc
;
;*******************************************************************
 
 
;***************************************************************************
; Function
; freeBuff
;
; Description
; Adds a buffer number to the beginning of the free list.
; buffer number in eax ( ms word zeroed )
; all other registers preserved
; This always works, so no error returned
;***************************************************************************
freeBuff:
push ebx
push ecx
mov ebx, EMPTY_QUEUE
shl ebx, 1
add ebx, queues
cli ; Ensure that another process does not interfer
movzx ecx, word [ebx]
mov [ebx], ax
shl eax, 1
add eax, queueList
mov [eax], cx
sti
pop ecx
pop ebx
 
ret
 
 
;***************************************************************************
; Function
; queueSize
;
; Description
; Counts the number of entries in a queue
; queue number in ebx ( ms word zeroed )
; Queue size returned in eax
; This always works, so no error returned
;***************************************************************************
queueSize:
xor eax, eax
shl ebx, 1
add ebx, queues
movzx ecx, word [ebx]
cmp cx, NO_BUFFER
je qs_exit
 
qs_001:
inc eax
shl ecx, 1
add ecx, queueList
movzx ecx, word [ecx]
cmp cx, NO_BUFFER
je qs_exit
jmp qs_001
 
qs_exit:
ret
 
 
;***************************************************************************
; Function
; queue
;
; Description
; Adds a buffer number to the *end* of a queue
; This is quite quick because these queues will be short
; queue number in eax ( ms word zeroed )
; buffer number in ebx ( ms word zeroed )
; all other registers preserved
; This always works, so no error returned
;***************************************************************************
queue:
push ebx
shl ebx, 1
add ebx, queueList ; eax now holds address of queue entry
mov [ebx], word NO_BUFFER ; This buffer will be the last
 
cli
shl eax, 1
add eax, queues ; eax now holds address of queue
movzx ebx, word [eax]
 
cmp bx, NO_BUFFER
jne qu_001
 
pop ebx
; The list is empty, so add this to the head
mov [eax], bx
jmp qu_exit
 
qu_001:
; Find the last entry
shl ebx, 1
add ebx, queueList
mov eax, ebx
movzx ebx, word [ebx]
cmp bx, NO_BUFFER
jne qu_001
 
mov ebx, eax
pop eax
mov [ebx], ax
 
qu_exit:
sti
ret
 
 
 
;***************************************************************************
; Function
; dequeue
;
; Description
; removes a buffer number from the head of a queue
; This is fast, as it unlinks the first entry in the list
; queue number in eax ( ms word zeroed )
; buffer number returned in eax ( ms word zeroed )
; all other registers preserved
;
;***************************************************************************
dequeue:
push ebx
shl eax, 1
add eax, queues ; eax now holds address of queue
mov ebx, eax
cli
movzx eax, word [eax]
cmp ax, NO_BUFFER
je dq_exit
push eax
shl eax, 1
add eax, queueList ; eax now holds address of queue entry
mov ax, [eax]
mov [ebx], ax
pop eax
 
dq_exit:
sti
pop ebx
ret
 
 
;***************************************************************************
; Function
; queueInit
;
; Description
; Initialises the queues to empty, and creates the free queue
; list.
;
;***************************************************************************
queueInit:
mov esi, queues
mov ecx, NUMQUEUES
mov ax, NO_BUFFER
 
qi001:
mov [esi], ax
inc esi
inc esi
loop qi001
 
mov esi, queues + ( 2 * EMPTY_QUEUE )
 
; Initialise empty queue list
 
xor ax, ax
mov [esi], ax
 
mov ecx, NUMQUEUEENTRIES - 1
mov esi, queueList
 
qi002:
inc ax
mov [esi], ax
inc esi
inc esi
loop qi002
 
mov ax, NO_BUFFER
mov [esi], ax
 
ret
/kernel/trunk/network/stack.inc
0,0 → 1,1784
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; STACK.INC ;;
;; ;;
;; TCP/IP stack for Menuet OS ;;
;; ;;
;; Version 0.7 4th July 2004 ;;
;; ;;
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;; Version 0.7 ;;
;; Added a timer per socket to allow delays when rx window ;;
;; gets below 1KB ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
;*******************************************************************
; Interface
; The interfaces defined in ETHERNET.INC plus:
; stack_init
; stack_handler
; app_stack_handler
; app_socket_handler
; checksum
;
;*******************************************************************
 
 
 
;
; IP Packet after reception - Normal IP packet format
;
; 0 1 2 3
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
;
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;0 |Version| IHL |Type of Service| Total Length |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;4 | Identification |Flags| Fragment Offset |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;8 | Time to Live | Protocol | Header Checksum |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;12 | Source Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;16 | Destination Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Data |
; +-+-+-.......... -+
 
 
; TCP Payload ( Data field in IP datagram )
;
; 0 1 2 3
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;20 | Source Port | Destination Port |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;24 | Sequence Number |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;28 | Acknowledgment Number |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;32 | Data | |U|A|P|R|S|F| |
; | Offset| Reserved |R|C|S|S|Y|I| Window |
; | | |G|K|H|T|N|N| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;36 | Checksum | Urgent Pointer |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
;40 | Options | Padding |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | data
 
 
;
; UDP Payload ( Data field in IP datagram )
;
; 0 1 2 3
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
;
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Source Port | Destination Port |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Length ( UDP Header + Data ) | Checksum |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | UDP Data |
; +-+-+-.......... -+
;
 
 
;
; Socket Descriptor + Buffer
;
; 0 1 2 3
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
;
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Status ( of this buffer ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Application Process ID |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Local IP Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Local IP Port | Unused ( set to 0 ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Remote IP Address |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Remote IP Port | Unused ( set to 0 ) |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 24| Rx Data Count INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 28| TCB STATE INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 32| TCB Timer (seconds) INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 36| ISS (Inital Sequence # used by this connection ) INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 40| IRS ( Inital Receive Sequence # ) INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 44| SND.UNA Seq # of unack'ed sent packets INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 48| SND.NXT Next send seq # to use INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 52| SND.WND Send window INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 56| RCV.NXT Next expected receive sequence # INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 60| RCV.WND Receive window INET format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 64| SEG.LEN Segment length INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 68| SEG.WND Segment window INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 72| Retransmit queue # NOW WINDOW SIZE TIMER INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 76| RX Data |
; +-+-+-.......... -+
 
 
 
; IP protocol numbers
PROTOCOL_ICMP equ 1
PROTOCOL_TCP equ 6
PROTOCOL_UDP equ 17
 
 
; TIPBUFF status values
BUFF_EMPTY equ 0
BUFF_RX_FULL equ 1
BUFF_ALLOCATED equ 2
BUFF_TX_FULL equ 3
 
NUM_IPBUFFERS equ 20 ; buffers allocated for TX/RX
 
SOCK_EMPTY equ 0 ; socket not in use
SOCK_OPEN equ 1 ; open issued, but no data sent
 
; TCP opening modes
SOCKET_PASSIVE equ 0
SOCKET_ACTIVE equ 1
 
; TCP TCB states
TCB_LISTEN equ 1
TCB_SYN_SENT equ 2
TCB_SYN_RECEIVED equ 3
TCB_ESTABLISHED equ 4
TCB_FIN_WAIT_1 equ 5
TCB_FIN_WAIT_2 equ 6
TCB_CLOSE_WAIT equ 7
TCB_CLOSING equ 8
TCB_LAST_ACK equ 9
TCB_TIME_WAIT equ 10
TCB_CLOSED equ 11
 
TWOMSL equ 10 ; # of secs to wait before closing socket
 
; socket buffers
SOCKETBUFFSIZE equ 4096 ; state + config + buffer.
SOCKETHEADERSIZE equ 76 ; thus 4096 - SOCKETHEADERSIZE bytes data
 
NUM_SOCKETS equ 16 ; Number of open sockets supported. Was 20
 
 
NUMQUEUES equ 4
EMPTY_QUEUE equ 0
IPIN_QUEUE equ 1
IPOUT_QUEUE equ 2
NET1OUT_QUEUE equ 3
 
NO_BUFFER equ 0xFFFF
IPBUFFSIZE equ 1500 ; MTU of an ethernet packet
NUMQUEUEENTRIES equ NUM_IPBUFFERS
NUMRESENDENTRIES equ 18 ; Buffers for TCP resend packets
TCP_RETRIES equ 5 ; Number of times to resend a packet
TCP_TIMEOUT equ 10 ; resend if not replied to in x hs
 
; These are the 0x40 function codes for application access to the stack
STACK_DRIVER_STATUS equ 52
SOCKET_INTERFACE equ 53
 
 
; 128KB allocated for the stack and network driver buffers and other
; data requirements
stack_data_start equ 0x700000
eth_data_start equ 0x700000
stack_data equ 0x704000
stack_data_end equ 0x71ffff
 
; 32 bit word
stack_config equ stack_data
; 32 bit word - IP Address in network format
stack_ip equ stack_data + 4
; 1 byte. 0 == inactive, 1 = active
slip_active equ stack_data + 8 ; no longer used
; 1 byte. 0 == inactive, 1 = active
ethernet_active equ stack_data + 9
unused equ stack_data + 10
; word. Buffer number, -1 if none
rx_buff_ptr equ stack_data + 12
; dword. Buffer number, -1 if none
tx_buff_ptr equ stack_data + 16
; byte.
slip_rx_state equ stack_data + 20 ; no longer used
; byte
slip_tx_state equ stack_data + 21 ; no longer used
; dword. Index into data
rx_data_ptr equ stack_data + 22
; dword. Index into data
tx_data_ptr equ stack_data + 26
; word. Count of bytes to send
tx_msg_len equ stack_data + 30
; Address of selected socket
sktAddr equ stack_data + 32
; Parameter to checksum routine - data ptr
checkAdd1 equ stack_data + 36
; Parameter to checksum routine - 2nd data ptr
checkAdd2 equ stack_data + 40
; Parameter to checksum routine - data size
checkSize1 equ stack_data + 44
; Parameter to checksum routine - 2nd data size
checkSize2 equ stack_data + 46
; result of checksum routine
checkResult equ stack_data + 48
 
; holds the TCP/UDP pseudo header. SA|DA|0|prot|UDP len|
pseudoHeader equ stack_data + 50
 
; receive and transmit IP buffer allocation
sockets equ stack_data + 62
Next_free2 equ sockets + (SOCKETBUFFSIZE * NUM_SOCKETS)
; 1560 byte buffer for rx / tx ethernet packets
Ether_buffer equ Next_free2
Next_free3 equ Ether_buffer + 1560
last_1sTick equ Next_free3
IPbuffs equ Next_free3 + 1
queues equ IPbuffs + ( NUM_IPBUFFERS * IPBUFFSIZE )
queueList equ queues + (2 * NUMQUEUES)
last_1hsTick equ queueList + ( 2 * NUMQUEUEENTRIES )
 
;resendQ equ queueList + ( 2 * NUMQUEUEENTRIES )
;resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP
; equ resendBuffer + ( IPBUFFSIZE * NUMRESENDENTRIES )
 
 
 
resendQ equ 0x770000
resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP
 
 
;***************************************************************************
; Function
; stack_init
;
; Description
; Clear all allocated memory to zero. This ensures that
; on startup, the stack is inactive, and consumes no resources
; This is a kernel function, called prior to the OS main loop
; in set_variables
;
;***************************************************************************
stack_init:
xor eax,eax
mov edi,stack_data_start
mov ecx,0x20000 / 4 ; Assume that we have 128KB of data
cld
rep stosd
 
; Initialise TCP resend queue data structures
mov eax, 0xFFFFFFFF
mov edi, resendQ
mov ecx, NUMRESENDENTRIES ; 1 dword per entry
cld
rep stosd
 
 
mov eax, 0xFFFFFFFF
mov [rx_buff_ptr], eax
mov [tx_buff_ptr], eax
 
; Put in some defaults : slip, 0x3f8, 4, ip=192.168.1.22
; Saves me entering them each boot up when debugging
mov eax, 0x03f80401
mov [stack_config], eax
mov eax, 0xc801a8c0
mov [stack_ip], eax
 
call queueInit
 
; The following block sets up the 1s timer
mov al,0x0
out 0x70,al
in al,0x71
mov [last_1sTick], al
 
ret
 
 
 
;***************************************************************************
; Function
; stack_handler
;
; Description
; The kernel loop routine for the stack
; This is a kernel function, called in the main loop
;
;***************************************************************************
stack_handler:
 
call ethernet_driver
call ip_rx
 
 
; Test for 10ms tick, call tcp timer
mov eax, [timer_ticks] ;[0xfdf0]
cmp eax, [last_1hsTick]
je sh_001
 
mov [last_1hsTick], eax
call tcp_tx_handler
 
sh_001:
 
; Test for 1 second event, call 1s timer functions
mov al,0x0 ;second
out 0x70,al
in al,0x71
cmp al, [last_1sTick]
je sh_exit
 
mov [last_1sTick], al
 
call arp_timer
call tcp_tcb_handler
 
sh_exit:
ret
 
 
 
 
;***************************************************************************
; Function
; is_localport_unused
;
; Description
; scans through all the active sockets , looking to see if the
; port number specified in bx is in use as a localport number.
; This is useful when you want a to generate a unique local port
; number.
; On return, eax = 1 for free, 0 for in use
;
;***************************************************************************
is_localport_unused:
mov al, bh
mov ah, bl
mov bx, ax
 
mov edx, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
mov eax, 0 ; Assume the return value is 'in use'
 
ilu1:
sub edx, SOCKETBUFFSIZE
cmp [edx + sockets + 12], bx
loopnz ilu1 ; Return back if the socket is occupied
 
jz ilu_exit
inc eax ; return port not in use
 
ilu_exit:
ret
 
 
 
;***************************************************************************
; Function
; get_free_socket
;
; Description
;
;***************************************************************************
get_free_socket:
push ecx
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
 
gfs1:
sub eax, SOCKETBUFFSIZE
cmp [eax + sockets], dword SOCK_EMPTY
loopnz gfs1 ; Return back if the socket is occupied
mov eax, ecx
pop ecx
jz gfs_exit
mov eax, 0xFFFFFFFF
 
gfs_exit:
ret
 
 
 
;***************************************************************************
; Function
; checksum
;
; Description
; checkAdd1,checkAdd2, checkSize1, checkSize2, checkResult
; Dont break anything; Most registers are used by the caller
; This code is derived from the 'C' source, cksum.c, in the book
; Internetworking with TCP/IP Volume II by D.E. Comer
;
;***************************************************************************
checksum:
pusha
 
xor edx, edx ; edx is the accumulative checksum
xor ebx, ebx
mov cx, [checkSize1]
shr cx, 1
jz cs1_1
 
mov eax, [checkAdd1]
 
cs1:
mov bh, [eax]
mov bl, [eax + 1]
 
add eax, 2
add edx, ebx
 
loopw cs1
 
cs1_1:
and word [checkSize1], 0x01
jz cs_test2
 
mov bh, [eax]
xor bl, bl
 
add edx, ebx
 
cs_test2:
mov cx, [checkSize2]
cmp cx, 0
jz cs_exit ; Finished if no 2nd buffer
 
shr cx, 1
jz cs2_1
 
mov eax, [checkAdd2]
 
cs2:
mov bh, [eax]
mov bl, [eax + 1]
 
add eax, 2
add edx, ebx
 
loopw cs2
 
cs2_1:
and word [checkSize2], 0x01
jz cs_exit
 
mov bh, [eax]
xor bl, bl
 
add edx, ebx
 
cs_exit:
mov ebx, edx
 
shr ebx, 16
and edx, 0xffff
add edx, ebx
mov eax, edx
shr eax, 16
add edx, eax
not dx
 
mov [checkResult], dx
popa
ret
 
 
 
 
;***************************************************************************
; Function
; app_stack_handler
;
; Description
; This is an application service, called by int 0x40 fn 52
; It provides application access to the network interface layer
;
;***************************************************************************
app_stack_handler:
cmp eax, 0
jnz not0
; Read the configuartion word
mov eax, [stack_config]
ret
 
not0:
cmp eax, 1
jnz not1
; read the IP address
 
mov eax, [stack_ip]
ret
 
not1:
cmp eax, 2
jnz not2
 
; write the configuration word
mov [stack_config], ebx
 
; <Slip shouldn't be active anyway - thats an operational issue.>
; If ethernet now enabled, probe for the card, reset it and empty
; the packet buffer
; If all successfull, enable the card.
; If ethernet now disabled, set it as disabled. Should really
; empty the tcpip data area too.
 
; ethernet interface is '3' in ls 7 bits
and bl, 0x7f
cmp bl, 3
 
je ash_eth_enable
; Ethernet isn't enabled, so make sure that the card is disabled
mov [ethernet_active], byte 0
 
ret
 
ash_eth_enable:
; Probe for the card. This will reset it and enable the interface
; if found
call eth_probe
cmp eax, 0
je ash_eth_done ; Abort if no hardware found
 
mov [ethernet_active], byte 1
 
ash_eth_done:
ret
 
not2:
cmp eax, 3
jnz not3
; write the IP Address
mov [stack_ip], ebx
ret
 
not3:
cmp eax, 4
jnz not4
; Enabled the slip driver on the comm port
; slip removed
ret
 
not4:
cmp eax, 5
jnz not5
; Disable the slip driver on the comm port
; slip removed
 
not5:
cmp eax, 6
jnz not6
 
; Insert an IP packet into the stacks received packet queue
call stack_insert_packet
ret
 
not6:
cmp eax, 7
jnz not7
 
; Test for any packets queued for transmission over the network
 
not7:
cmp eax, 8
jnz not8
 
call stack_get_packet
; Extract a packet queued for transmission by the network
ret
 
not8:
cmp eax, 9
jnz not9
 
; read the gateway IP address
 
mov eax, [gateway_ip]
ret
 
not9:
cmp eax, 10
jnz not10
 
; read the subnet mask
 
mov eax, [subnet_mask]
ret
 
not10:
cmp eax, 11
jnz not11
 
; write the gateway IP Address
mov [gateway_ip], ebx
 
ret
 
not11:
cmp eax, 12
jnz not12
 
; write the subnet mask
mov [subnet_mask], ebx
 
 
not12:
cmp eax, 13
jnz not13
 
; read the dns
 
mov eax, [dns_ip]
ret
 
not13:
cmp eax, 14
jnz stack_driver_end
 
; write the dns IP Address
mov [dns_ip], ebx
 
ret
 
stack_driver_end:
ret
 
 
 
;***************************************************************************
; Function
; app_socket_handler
;
; Description
; This is an application service, called by int 0x40
; It provides application access to stack socket services
; such as opening sockets
;
;***************************************************************************
app_socket_handler:
cmp eax, 0
jnz nots0
 
call socket_open
ret
 
nots0:
cmp eax, 1
jnz nots1
 
call socket_close
ret
 
nots1:
cmp eax, 2
jnz nots2
 
call socket_poll
ret
 
nots2:
cmp eax, 3
jnz nots3
 
call socket_read
ret
 
nots3:
cmp eax, 4
jnz nots4
 
call socket_write
ret
 
nots4:
cmp eax, 5
jnz nots5
 
call socket_open_tcp
ret
 
nots5:
cmp eax, 6
jnz nots6
 
call socket_status
ret
 
nots6:
cmp eax, 7
jnz nots7
 
call socket_write_tcp
ret
 
nots7:
cmp eax, 8
jnz nots8
 
call socket_close_tcp
ret
 
nots8:
cmp eax, 9
jnz nots9
 
call is_localport_unused
ret
 
nots9:
cmp eax, 254
jnz notdump
 
ret
 
notdump:
cmp eax, 255
jnz notsdebug
 
; This sub function allows access to debugging information on the stack
; ebx holds the request:
; 100 : return length of empty queue
; 101 : return length of IPOUT QUEUE
; 102 : return length of IPIN QUEUE
; 103 : return length of NET1OUT QUEUE
; 200 : return # of ARP entries
; 201 : return size of ARP table ( max # entries )
; 202 : select ARP table entry #
; 203 : return IP of selected table entry
; 204 : return High 4 bytes of MAC address of selected table entry
; 205 : return low 2 bytes of MAC address of selected table entry
; 206 : return status word of selected table entry
; 207 : return Time to live of selected table entry
 
 
; 2 : return number of IP packets received
; 3 : return number of packets transmitted
; 4 : return number of received packets dumped
; 5 : return number of arp packets received
; 6 : return status of packet driver
; ( 0 == not active, FFFFFFFF = successful )
 
call stack_internal_status
ret
 
notsdebug:
; Invalid Option
ret
 
 
uglobal
ARPTmp:
times 14 db 0
endg
 
;***************************************************************************
; Function
; stack_internal_status
;
; Description
; Returns information about the internal status of the stack
; This is only useful for debugging
; It works with the ethernet driver
; sub function in ebx
; return requested data in eax
;
;***************************************************************************
stack_internal_status:
cmp ebx, 100
jnz notsis100
 
; 100 : return length of EMPTY QUEUE
mov ebx, EMPTY_QUEUE
call queueSize
ret
 
notsis100:
cmp ebx, 101
jnz notsis101
 
; 101 : return length of IPOUT QUEUE
mov ebx, IPOUT_QUEUE
call queueSize
ret
 
notsis101:
cmp ebx, 102
jnz notsis102
 
; 102 : return length of IPIN QUEUE
mov ebx, IPIN_QUEUE
call queueSize
ret
 
notsis102:
cmp ebx, 103
jnz notsis103
 
; 103 : return length of NET1OUT QUEUE
mov ebx, NET1OUT_QUEUE
call queueSize
ret
 
notsis103:
cmp ebx, 200
jnz notsis200
 
; 200 : return num entries in arp table
movzx eax, byte [NumARP]
ret
 
notsis200:
cmp ebx, 201
jnz notsis201
 
; 201 : return arp table size
mov eax, 20 ; ARP_TABLE_SIZE
ret
 
notsis201:
cmp ebx, 202
jnz notsis202
 
; 202 - read the requested table entry
; into a temporary buffer
; ecx holds the entry number
 
mov eax, ecx
mov ecx, 14 ; ARP_ENTRY_SIZE
mul ecx
 
mov ecx, [eax + ARPTable]
mov [ARPTmp], ecx
mov ecx, [eax + ARPTable+4]
mov [ARPTmp+4], ecx
mov ecx, [eax + ARPTable+8]
mov [ARPTmp+8], ecx
mov cx, [eax + ARPTable+12]
mov [ARPTmp+12], cx
ret
 
notsis202:
cmp ebx, 203
jnz notsis203
 
; 203 - return IP address
mov eax, [ARPTmp]
ret
 
notsis203:
cmp ebx, 204
jnz notsis204
 
; 204 - return MAC high dword
mov eax, [ARPTmp+4]
ret
 
notsis204:
cmp ebx, 205
jnz notsis205
 
; 205 - return MAC ls word
movzx eax, word [ARPTmp+8]
ret
 
notsis205:
cmp ebx, 206
jnz notsis206
 
; 206 - return status word
movzx eax, word [ARPTmp+10]
ret
 
notsis206:
cmp ebx, 207
jnz notsis207
 
; 207 - return ttl word
movzx eax, word [ARPTmp+12]
ret
 
notsis207:
cmp ebx, 2
jnz notsis2
 
; 2 : return number of IP packets received
mov eax, [ip_rx_count]
ret
 
notsis2:
cmp ebx, 3
jnz notsis3
 
; 3 : return number of packets transmitted
mov eax, [ip_tx_count]
ret
 
notsis3:
cmp ebx, 4
jnz notsis4
 
; 4 : return number of received packets dumped
mov eax, [dumped_rx_count]
ret
 
notsis4:
cmp ebx, 5
jnz notsis5
 
; 5 : return number of arp packets received
mov eax, [arp_rx_count]
ret
 
notsis5:
cmp ebx, 6
jnz notsis6
 
; 6 : return status of packet driver
; ( 0 == not active, FFFFFFFF = successful )
mov eax, [eth_status]
ret
 
notsis6:
xor eax, eax
ret
 
 
 
;***************************************************************************
; Function
; stack_get_packet
;
; Description
; extracts an IP packet from the NET1 output queue
; and sends the data to the calling process
; pointer to data in edx
; returns number of bytes read in eax
;
;***************************************************************************
stack_get_packet:
; Look for a buffer to tx
mov eax, NET1OUT_QUEUE
call dequeue
cmp ax, NO_BUFFER
je sgp_non_exit ; Exit if no buffer available
 
push eax ; Save buffer number for freeing at end
 
push edx
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
pop edx
 
push eax ; save address of IP data
 
; Get the address of the callers data
mov edi,[0x3010]
add edi,0x10
add edx,[edi]
mov edi, edx
 
pop eax
 
mov ecx, 1500 ; should get the actual number of bytes to write
mov esi, eax
cld
rep movsb ; copy the data across
 
; And finally, return the buffer to the free queue
pop eax
call freeBuff
 
mov eax, 1500
ret
 
sgp_non_exit:
xor eax, eax
ret
 
 
 
;***************************************************************************
; Function
; stack_insert_packet
;
; Description
; writes an IP packet into the stacks receive queue
; # of bytes to write in ecx
; pointer to data in edx
; returns 0 in eax ok, -1 == failed
;
;***************************************************************************
stack_insert_packet:
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je sip_err_exit
 
push eax
 
; save the pointers to the data buffer & size
push edx
push ecx
 
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
mov edx, eax
 
; So, edx holds the IPbuffer ptr
 
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
pop eax ; get callers ptr to data to send
 
; Get the address of the callers data
mov edi,[0x3010]
add edi,0x10
add eax,[edi]
mov esi, eax
 
mov edi, edx
cld
rep movsb ; copy the data across
 
pop ebx
 
mov eax, IPIN_QUEUE
call queue
 
inc dword [ip_rx_count]
 
mov eax, 0
ret
 
sip_err_exit:
mov eax, 0xFFFFFFFF
ret
 
 
 
;***************************************************************************
; Function
; socket_open
;
; Description
; find a free socket
; local port in ebx
; remote port in ecx
; remote ip in edx
; return socket # in eax, -1 if none available
;
;***************************************************************************
socket_open:
call get_free_socket
 
cmp eax, 0xFFFFFFFF
jz so_exit
 
; ax holds the socket number that is free. Get real address
push eax
shl eax, 12
add eax, sockets
 
mov [eax], dword SOCK_OPEN
 
mov [eax + 12], byte bh ; Local port ( LS 16 bits )
mov [eax + 13], byte bl ; Local port ( LS 16 bits )
mov ebx, [stack_ip]
mov [eax + 8], ebx ; Local IP
mov [eax + 20], ch ; Remote Port ( LS 16 bits )
mov [eax + 21], cl ; Remote Port ( LS 16 bits )
mov [eax + 16], edx ; Remote IP ( in Internet order )
mov [eax + 24], dword 0 ; recieved data count
 
mov esi, [0x3010]
mov ebx, [esi+0x4]
mov [eax + 4], ebx ; save the process ID
pop eax ; Get the socket number back, so we can return it
 
so_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_open_tcp
;
; Description
; Opens a TCP socket in PASSIVE or ACTIVE mode
; find a free socket
; local port in ebx ( intel format )
; remote port in ecx ( intel format )
; remote ip in edx ( in Internet byte order )
; Socket open mode in esi ( SOCKET_PASSIVE or SOCKET_ACTIVE )
; return socket # in eax, -1 if none available
;
;***************************************************************************
socket_open_tcp:
call get_free_socket
 
cmp eax, 0xFFFFFFFF
jz so_exit
 
; ax holds the socket number that is free. Get real address
push eax
shl eax, 12
add eax, sockets
 
mov [sktAddr], eax
mov [eax], dword SOCK_OPEN
 
; TODO - check this works!
mov [eax + 72], dword 0 ; Reset the window timer.
 
mov [eax + 12], byte bh ; Local port ( LS 16 bits )
mov [eax + 13], byte bl ; Local port ( LS 16 bits )
mov ebx, [stack_ip]
mov [eax + 8], ebx ; Local IP
mov [eax + 20], ch ; Remote Port ( LS 16 bits )
mov [eax + 21], cl ; Remote Port ( LS 16 bits )
mov [eax + 16], edx ; Remote IP ( in Internet order )
mov [eax + 24], dword 0 ; recieved data count
 
; Now fill in TCB state
mov ebx, TCB_LISTEN
cmp esi, SOCKET_PASSIVE
jz sot_001
mov ebx, TCB_SYN_SENT
 
sot_001:
mov [eax + 28], ebx ; Indicate the state of the TCB
 
mov esi, [0x3010]
mov ecx, [esi+0x4]
mov [eax + 4], ecx ; save the process ID
 
cmp ebx, TCB_LISTEN
je sot_done
 
; Now, if we are in active mode, then we have to send a SYN to the specified remote port
 
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je sot_done
 
push eax
 
mov bl, 0x02 ; SYN
mov ecx, 0
 
call buildTCPPacket
 
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne sot_notlocal
mov eax, IPIN_QUEUE
 
sot_notlocal:
; Send it.
pop ebx
call queue
 
mov esi, [sktAddr]
 
; increment SND.NXT in socket
add esi, 48
call inc_inet_esi
 
sot_done:
pop eax ; Get the socket number back, so we can return it
 
sot_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_close
;
; Description
; socket # in ebx
; returns 0 for ok, -1 for socket not open (fail)
;
;***************************************************************************
socket_close:
shl ebx, 12
add ebx, sockets
mov eax, 0xFFFFFFFF ; assume this operation will fail..
cmp [ebx], dword SOCK_EMPTY
jz sc_exit
 
; Clear the socket varaibles
xor eax, eax
mov edi,ebx
mov ecx,SOCKETHEADERSIZE
cld
rep stosb
 
sc_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_close_tcp
;
; Description
; socket # in ebx
; returns 0 for ok, -1 for socket not open (fail)
;
;***************************************************************************
socket_close_tcp:
; first, remove any resend entries
pusha
 
mov esi, resendQ
mov ecx, 0
 
sct001:
cmp ecx, NUMRESENDENTRIES
je sct003 ; None left
cmp [esi], bl
je sct002 ; found one
inc ecx
add esi, 4
jmp sct001
 
sct002:
dec dword [arp_rx_count] ; ************ TEST ONLY!
 
mov [esi], byte 0xFF
jmp sct001
 
sct003:
popa
 
shl ebx, 12
add ebx, sockets
mov [sktAddr], ebx
mov eax, 0xFFFFFFFF ; assume this operation will fail..
cmp [ebx], dword SOCK_EMPTY
jz sct_exit
 
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stl_exit
 
push eax
 
mov bl, 0x11 ; FIN + ACK
mov ecx, 0
mov esi, 0
 
call buildTCPPacket
 
mov ebx, [sktAddr]
 
; increament SND.NXT in socket
mov esi, 48
add esi, ebx
call inc_inet_esi
 
 
; Get the socket state
mov eax, [ebx + 28]
cmp eax, TCB_LISTEN
je destroyTCB
cmp eax, TCB_SYN_SENT
je destroyTCB
cmp eax, TCB_SYN_RECEIVED
je sct_finwait1
cmp eax, TCB_ESTABLISHED
je sct_finwait1
 
; assume CLOSE WAIT
; Send a fin, then enter last-ack state
mov eax, TCB_LAST_ACK
mov [ebx + 28], eax
xor eax, eax
jmp sct_send
 
sct_finwait1:
; Send a fin, then enter finwait2 state
mov eax, TCB_FIN_WAIT_1
mov [ebx + 28], eax
xor eax, eax
 
sct_send:
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne sct_notlocal
mov eax, IPIN_QUEUE
 
sct_notlocal:
; Send it.
pop ebx
call queue
jmp sct_exit
 
destroyTCB:
pop eax
; Clear the socket varaibles
xor eax, eax
mov edi,ebx
mov ecx,SOCKETHEADERSIZE
cld
rep stosb
 
sct_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_poll
;
; Description
; socket # in ebx
; returns count in eax.
;
;***************************************************************************
socket_poll:
shl ebx, 12
add ebx, sockets
mov eax, [ebx + 24]
 
ret
 
 
 
;***************************************************************************
; Function
; socket_status
;
; Description
; socket # in ebx
; returns TCB state in eax.
;
;***************************************************************************
socket_status:
shl ebx, 12
add ebx, sockets
mov eax, [ebx + 28]
 
ret
 
 
 
;***************************************************************************
; Function
; socket_read
;
; Description
; socket # in ebx
; returns # of bytes remaining in eax, data in bl
;
;***************************************************************************
socket_read:
shl ebx, 12
add ebx, sockets
mov eax, [ebx + 24] ; get count of bytes
mov ecx,1
test eax, eax
jz sr2
 
dec eax
mov esi, ebx ; esi is address of socket
mov [ebx + 24], eax ; store new count
movzx ebx, byte [ebx + SOCKETHEADERSIZE] ; get the byte
add esi, SOCKETHEADERSIZE
mov edi, esi
inc esi
 
mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4
cld
rep movsd
xor ecx, ecx
 
sr1:
jmp sor_exit
 
sr2:
xor bl, bl
 
sor_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_write
;
; Description
; socket in ebx
; # of bytes to write in ecx
; pointer to data in edx
; returns 0 in eax ok, -1 == failed ( invalid socket, or
; could not queue IP packet )
;
;***************************************************************************
socket_write:
; First, find the address of the socket descriptor
shl ebx, 12
add ebx, sockets ; ebx = address of actual socket
 
mov eax, 0xFFFFFFFF
; If the socket is invalid, return with an error code
cmp [ebx], dword SOCK_EMPTY
je sw_exit
 
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je sw_exit
 
; Save the queue entry number
push eax
 
; save the pointers to the data buffer & size
push edx
push ecx
 
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
mov edx, eax
 
; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
 
; Fill in the IP header ( some data is in the socket descriptor)
mov eax, [ebx + 8]
mov [edx + 12], eax ; source IP
mov eax, [ebx + 16]
mov [edx + 16], eax ; Destination IP
 
mov al, 0x45
mov [edx], al ; Version, IHL
xor al, al
mov [edx + 1], al ; Type of service
 
pop eax ; Get the UDP data length
push eax
 
add eax, 20 + 8 ; add IP header and UDP header lengths
mov [edx + 2], ah
mov [edx + 3], al
xor al, al
mov [edx + 4], al
mov [edx + 5], al
mov al, 0x40
mov [edx + 6], al
xor al, al
mov [edx + 7], al
mov al, 0x20
mov [edx + 8], al
mov al, 17
mov [edx + 9], al
 
; Checksum left unfilled
xor ax, ax
mov [edx + 10], ax
 
; Fill in the UDP header ( some data is in the socket descriptor)
mov ax, [ebx + 12]
mov [edx + 20], ax
 
mov ax, [ebx + 20]
mov [edx + 20 + 2], ax
 
pop eax
push eax
 
add eax, 8
mov [edx + 20 + 4], ah
mov [edx + 20 + 5], al
 
; Checksum left unfilled
xor ax, ax
mov [edx + 20 + 6], ax
 
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
pop eax ; get callers ptr to data to send
 
; Get the address of the callers data
mov edi,[0x3010]
add edi,0x10
add eax,[edi]
mov esi, eax
 
mov edi, edx
add edi, 28
cld
rep movsb ; copy the data across
 
; we have edx as IPbuffer ptr.
; Fill in the UDP checksum
; First, fill in pseudoheader
mov eax, [edx + 12]
mov [pseudoHeader], eax
mov eax, [edx + 16]
mov [pseudoHeader+4], eax
mov ax, 0x1100 ; 0 + protocol
mov [pseudoHeader+8], ax
add ebx, 8
mov eax, ebx
mov [pseudoHeader+10], ah
mov [pseudoHeader+11], al
 
mov eax, pseudoHeader
mov [checkAdd1], eax
mov [checkSize1], word 12
mov eax, edx
add eax, 20
mov [checkAdd2], eax
mov eax, ebx
mov [checkSize2], ax ; was eax!! mjh 8/7/02
 
call checksum
 
; store it in the UDP checksum ( in the correct order! )
mov ax, [checkResult]
 
; If the UDP checksum computes to 0, we must make it 0xffff
; (0 is reserved for 'not used')
cmp ax, 0
jne sw_001
mov ax, 0xffff
 
sw_001:
mov [edx + 20 + 6], ah
mov [edx + 20 + 7], al
 
; Fill in the IP header checksum
mov eax, edx
mov [checkAdd1], eax
mov [checkSize1], word 20
mov [checkAdd2], dword 0
mov [checkSize2], word 0
 
call checksum
 
mov ax, [checkResult]
mov [edx + 10], ah
mov [edx + 11], al
 
; Check destination IP address.
; If it is the local host IP, route it back to IP_RX
 
pop ebx
mov eax, NET1OUT_QUEUE
 
mov ecx, [ edx + 16]
mov edx, [stack_ip]
cmp edx, ecx
jne sw_notlocal
mov eax, IPIN_QUEUE
 
sw_notlocal:
; Send it.
call queue
 
xor eax, eax
 
sw_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_write_tcp
;
; Description
; socket in ebx
; # of bytes to write in ecx
; pointer to data in edx
; returns 0 in eax ok, -1 == failed ( invalid socket, or
; could not queue IP packet )
;
;***************************************************************************
socket_write_tcp:
; First, find the address of the socket descriptor
shl ebx, 12
add ebx, sockets ; ebx = address of actual socket
 
mov [sktAddr], ebx
 
mov eax, 0xFFFFFFFF
; If the socket is invalid, return with an error code
cmp [ebx], dword SOCK_EMPTY
je swt_exit
 
; If the sockets window timer is nonzero, do not queue packet
; TODO - done
cmp [ebx + 72], dword 0
jne swt_exit
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je swt_exit
 
push eax
 
mov bl, 0x10 ; ACK
 
; Get the address of the callers data
mov edi,[0x3010]
add edi,0x10
add edx,[edi]
mov esi, edx
 
pop eax
push eax
 
push ecx
call buildTCPPacket
pop ecx
 
; Check destination IP address.
; If it is the local host IP, route it back to IP_RX
 
pop ebx
push ecx
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne swt_notlocal
mov eax, IPIN_QUEUE
 
swt_notlocal:
pop ecx
 
push ebx ; save ipbuffer number
 
call queue
 
mov esi, [sktAddr]
 
; increament SND.NXT in socket
; Amount to increment by is in ecx
add esi, 48
call add_inet_esi
 
pop ebx
 
; Copy the IP buffer to a resend queue
; If there isn't one, dont worry about it for now
mov esi, resendQ
mov ecx, 0
 
swt003:
cmp ecx, NUMRESENDENTRIES
je swt001 ; None found
cmp [esi], byte 0xFF
je swt002 ; found one
inc ecx
add esi, 4
jmp swt003
 
swt002:
push ebx
 
; OK, we have a buffer descriptor ptr in esi.
; resend entry # in ecx
; Populate it
; socket #
; retries count
; retry time
; fill IP buffer associated with this descriptor
 
mov eax, [sktAddr]
sub eax, sockets
shr eax, 12 ; get skt #
mov [esi], al
mov [esi + 1], byte TCP_RETRIES
mov [esi + 2], word TCP_TIMEOUT
 
inc ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
mov edi, resendBuffer - IPBUFFSIZE
swt002a:
add edi, IPBUFFSIZE
loop swt002a
 
; we have dest buffer location in edi
pop eax
; convert source buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
mov esi, eax
 
; do copy
mov ecx, IPBUFFSIZE
cld
rep movsb
 
inc dword [arp_rx_count] ; ************ TEST ONLY!
 
swt001:
xor eax, eax
 
swt_exit:
ret
 
 
 
; Below, the main network layer source code is included
;
 
include "queue.inc"
include "ip.inc"
include "tcp.inc"
include "udp.inc"
include "eth_drv/ethernet.inc"
/kernel/trunk/network/tcp.inc
0,0 → 1,1243
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; TCP.INC ;;
;; ;;
;; TCP Processes for Menuet OS TCP/IP stack ;;
;; ;;
;; Version 0.6 4th July 2004 ;;
;; ;;
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;;
;; ;;
;; See file COPYING for details ;;
;; v0.6 : Added reset handling in the established state ;;
;; Added a timer per socket to allow delays when rx window ;;
;; gets below 1KB ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
;*******************************************************************
; Interface
;
; tcp_tx_handler Handles the TCP transmit queue
; tcp_rx The protocol handler for received data
; buildTCPPacket fills in the packet headers and data
; tcpStateMachine Main state machine for received TCP packets
; tcp_tcb_handler 1s timer, to erase tcb's in TIME_WAIT state
;
;*******************************************************************
 
 
 
;***************************************************************************
; Function
; tcp_tcb_handler
;
; Description
; Handles sockets in the timewait state, closing them
; when the TCB timer expires
;
;***************************************************************************
tcp_tcb_handler:
; scan through all the sockets, decrementing active timers
 
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
 
tth1:
sub eax, SOCKETBUFFSIZE
cmp [eax + sockets + 32], dword 0
jne tth2
 
tth1a:
cmp [eax + sockets + 72], dword 0
jne tth4
 
loop tth1
ret
 
tth2:
; decrement it, delete socket if TCB timer = 0 & socket in timewait state
pusha
dec dword [eax + sockets + 32]
cmp [eax + sockets + 32], dword 0
jne tth3
 
cmp [eax + sockets + 28], dword TCB_TIME_WAIT
jne tth3
 
; OK, delete socket
mov edi, eax
add edi, sockets
 
xor eax, eax
mov ecx, SOCKETHEADERSIZE
cld
rep stosb
 
tth3:
popa
 
jmp tth1a
 
loop tth1
ret
 
; TODO - prove it works!
tth4:
dec dword [eax + sockets + 72]
loop tth1
ret
 
 
 
 
tth_exit:
ret
 
 
;***************************************************************************
; Function
; tcp_tx_handler
;
; Description
; Handles queued TCP data
; This is a kernel function, called by stack_handler
;
;***************************************************************************
tcp_tx_handler:
; decrement all resend buffers timers. If they
; expire, queue them for sending, and restart the timer.
; If the retries counter reach 0, delete the entry
 
mov esi, resendQ
mov ecx, 0
 
tth001:
cmp ecx, NUMRESENDENTRIES
je tth003 ; None left
cmp [esi], byte 0xFF
jne tth002 ; found one
inc ecx
add esi, 4
jmp tth001
 
tth002:
; we have one. decrement it's timer by 1
dec word [esi+2]
mov ax, [esi+2]
cmp ax, 0
je tth002a
inc ecx
add esi, 4
jmp tth001 ; Timer not zero, so move on
 
tth002a:
mov bl, 0xff
; restart timer, and decrement retries
; After the first resend, back of on next, by a factor of 5
mov [esi+2], word TCP_TIMEOUT * 5
dec byte [esi+1]
mov al, [esi+1]
cmp al, 0
jne tth004
 
; retries now 0, so delete from queue
xchg [esi], bl
tth004:
 
; resend packet
pusha
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
jne tth004z
 
; TODO - try again in 10ms.
cmp bl, 0xff
jne tth004za
mov [esi], bl
 
tth004za:
; Mark it to expire in 10ms - 1 tick
mov [esi+1], byte 1
mov [esi+2], word 1
jmp tth005
 
tth004z:
; we have a buffer # in ax
 
push eax
push ecx
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
; we have the buffer address in eax
mov edi, eax
pop ecx
; get resend data address
inc ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
mov esi, resendBuffer - IPBUFFSIZE
tth004a:
add esi, IPBUFFSIZE
loop tth004a
 
; we have resend buffer location in esi
mov ecx, IPBUFFSIZE
 
; copy data across
cld
rep movsb
 
; queue packet
 
 
 
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ edi + 16 ]
cmp edx, ecx
jne tth004b
mov eax, IPIN_QUEUE
 
tth004b:
pop ebx
 
call queue
 
 
tth005:
popa
 
inc ecx
add esi, 4
jmp tth001
 
tth003:
ret
 
 
 
 
;***************************************************************************
; Function
; tcp_rx
;
; Description
; TCP protocol handler
; This is a kernel function, called by ip_rx
; IP buffer address given in edx
; IP buffer number in eax
; Free up (or re-use) IP buffer when finished
;
;***************************************************************************
tcp_rx:
; The process is as follows.
; Look for a socket with matching remote IP, remote port, local port
; if not found, then
; look for remote IP + local port match ( where sockets remote port = 0)
; if not found, then
; look for a socket where local socket port == IP packets remote port
; where sockets remote port, remote IP = 0
; discard if not found
; Call sockets tcbStateMachine, with pointer to packet.
; the state machine will not delete the packet, so do that here.
 
push eax
 
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; IP Packet SA = Remote IP
; IP Packet TCP Source Port = remote Port
 
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
ss1:
sub eax, SOCKETBUFFSIZE
movzx ebx, word [edx + 22] ; get the dest. port from the TCP hdr
cmp [eax + sockets + 12], bx ; compare with socket's local port
jnz nxttst1 ; different - try next socket
 
movzx ebx, word [edx + 20] ; get the source port from the TCP hdr
cmp [eax + sockets + 20], bx ; compare with socket's remote port
jnz nxttst1 ; different - try next socket
 
 
mov ebx, [edx + 12] ; get the source IP Addr from the IP hdr
cmp [eax + sockets + 16], ebx ; compare with socket's remote IP
jnz nxttst1 ; different - try next socket
 
; We have a complete match - use this socket
jmp tcprx_001
 
nxttst1:
loop ss1 ; Return back if no match
 
; If we got here, there was no match
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; IP Packet SA = Remote IP
; socket remote Port = 0
 
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
 
ss2:
sub eax, SOCKETBUFFSIZE
 
movzx ebx, word [edx + 22] ; get the dest. port from the TCP hdr
cmp [eax + sockets + 12], bx ; compare with socket's local port
jnz nxttst2 ; different - try next socket
 
mov ebx, [edx + 12] ; get the source IP Addr from the IP hdr
cmp [eax + sockets + 16], ebx ; compare with socket's remote IP
jnz nxttst2 ; different - try next socket
 
mov ebx, 0
cmp [eax + sockets + 20], bx ; only match a remote socket of 0
jnz nxttst2 ; different - try next socket
 
; We have a complete match - use this socket
jmp tcprx_001
 
nxttst2:
loop ss2 ; Return back if no match
 
; If we got here, there was no match
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; socket Remote IP = 0
; socket remote Port = 0
 
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
 
ss3:
sub eax, SOCKETBUFFSIZE
 
movzx ebx, word [edx + 22] ; get destination port from the TCP hdr
cmp [eax + sockets + 12], bx ; compare with socket's local port
jnz nxttst3 ; different - try next socket
 
mov ebx, 0
cmp [eax + sockets + 20], bx ; only match a remote socket of 0
jnz nxttst3 ; different - try next socket
 
mov ebx, 0
cmp [eax + sockets + 16], ebx ; only match a socket remote IP of 0
jnz nxttst3 ; different - try next socket
 
; We have a complete match - use this socket
jmp tcprx_001
 
nxttst3:
loop ss3 ; Return back if no match
 
; If we got here, we need to reject the packet
inc dword [dumped_rx_count]
jmp tcprx_exit
 
tcprx_001:
; We have a valid socket/TCB, so call the TCB State Machine for that skt.
; socket is pointed to by [eax + sockets]
; IP packet is pointed to by [edx]
; IP buffer number is on stack ( it will be popped at the end)
call tcpStateMachine
 
tcprx_exit:
pop eax
call freeBuff
 
ret
 
 
 
;***************************************************************************
; Function
; buildTCPPacket
;
; Description
; builds an IP Packet with TCP data fully populated for transmission
; You may destroy any and all registers
; TCP control flags specified in bl
; This TCB is in [sktAddr]
; User data pointed to by esi
; Data length in ecx
; Transmit buffer number in eax
;
;***************************************************************************
buildTCPPacket:
push ecx ; Save data length
 
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
mov edx, eax
 
mov [edx + 33], bl ; TCP flags
 
mov ebx, [sktAddr]
 
; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
 
; Fill in the IP header ( some data is in the socket descriptor)
mov eax, [ebx + 8]
mov [edx + 12], eax ; source IP
mov eax, [ebx + 16]
mov [edx + 16], eax ; Destination IP
 
mov al, 0x45
mov [edx], al ; Version, IHL
xor al, al
mov [edx + 1], al ; Type of service
 
pop eax ; Get the TCP data length
push eax
 
add eax, 20 + 20 ; add IP header and TCP header lengths
mov [edx + 2], ah
mov [edx + 3], al
xor al, al
mov [edx + 4], al
mov [edx + 5], al
mov al, 0x40
mov [edx + 6], al
xor al, al
mov [edx + 7], al
mov al, 0x20
mov [edx + 8], al
mov al, 6 ; TCP protocol
mov [edx + 9], al
 
; Checksum left unfilled
xor ax, ax
mov [edx + 10], ax
 
; Fill in the TCP header ( some data is in the socket descriptor)
mov ax, [ebx + 12]
mov [edx + 20], ax ; Local Port
 
mov ax, [ebx + 20]
mov [edx + 20 + 2], ax ; desitination Port
 
; Checksum left unfilled
xor ax, ax
mov [edx + 20 + 16], ax
 
; sequence number
mov eax, [ebx + 48]
mov [edx + 20 + 4], eax
 
; ack number
mov eax, [ebx + 56]
mov [edx + 20 + 8], eax
 
; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
; 768 bytes seems better
mov ax, 0x0003
mov [edx + 20 + 14], ax
 
; Urgent pointer (0)
mov ax, 0
mov [edx + 20 + 18], ax
 
; data offset ( 0x50 )
mov al, 0x50
mov [edx + 20 + 12], al
 
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
 
cmp ebx, 0
jz btp_001
 
mov edi, edx
add edi, 40
cld
rep movsb ; copy the data across
 
btp_001:
; we have edx as IPbuffer ptr.
; Fill in the TCP checksum
; First, fill in pseudoheader
mov eax, [edx + 12]
mov [pseudoHeader], eax
mov eax, [edx + 16]
mov [pseudoHeader+4], eax
mov ax, 0x0600 ; 0 + protocol
mov [pseudoHeader+8], ax
add ebx, 20
mov eax, ebx
mov [pseudoHeader+10], ah
mov [pseudoHeader+11], al
 
mov eax, pseudoHeader
mov [checkAdd1], eax
mov [checkSize1], word 12
mov eax, edx
add eax, 20
mov [checkAdd2], eax
mov eax, ebx
mov [checkSize2], ax
 
call checksum
 
; store it in the TCP checksum ( in the correct order! )
mov ax, [checkResult]
 
mov [edx + 20 + 16], ah
mov [edx + 20 + 17], al
 
; Fill in the IP header checksum
mov eax, edx
mov [checkAdd1], eax
mov [checkSize1], word 20
mov [checkAdd2], dword 0
mov [checkSize2], word 0
 
call checksum
 
mov ax, [checkResult]
mov [edx + 10], ah
mov [edx + 11], al
 
ret
 
 
; Increments the 32 bit value pointed to by esi in internet order
inc_inet_esi:
push eax
add esi, 3
mov al, byte[esi]
inc al
mov byte[esi], al
cmp al, 0
jnz iie_exit
dec esi
mov al, byte[esi]
inc al
mov byte[esi], al
cmp al, 0
jnz iie_exit
dec esi
mov al, byte[esi]
inc al
mov byte[esi], al
cmp al, 0
jnz iie_exit
dec esi
mov al, byte[esi]
inc al
mov byte[esi], al
 
iie_exit:
pop eax
ret
 
 
; Increments the 32 bit value pointed to by esi in internet order
; by the value in ecx
add_inet_esi:
push eax
 
mov al, [esi]
shl eax, 8
inc esi
mov al, [esi]
shl eax, 8
inc esi
mov al, [esi]
shl eax, 8
inc esi
mov al, [esi]
add eax, ecx
mov [esi], al
dec esi
shr eax, 8
mov [esi], al
dec esi
shr eax, 8
mov [esi], al
dec esi
shr eax, 8
mov [esi], al
pop eax
ret
 
 
iglobal
TCBStateHandler:
dd stateTCB_LISTEN
dd stateTCB_SYN_SENT
dd stateTCB_SYN_RECEIVED
dd stateTCB_ESTABLISHED
dd stateTCB_FIN_WAIT_1
dd stateTCB_FIN_WAIT_2
dd stateTCB_CLOSE_WAIT
dd stateTCB_CLOSING
dd stateTCB_LAST_ACK
dd stateTCB_TIME_WAIT
dd stateTCB_CLOSED
endg
 
;***************************************************************************
; Function
; tcpStateMachine
;
; Description
; TCP state machine
; This is a kernel function, called by tcp_rx
;
; IP buffer address given in edx
; Socket/TCB address in [eax + sockets]
;
; The IP buffer will be released by the caller
;***************************************************************************
tcpStateMachine:
mov ebx, sockets
add ebx, eax
mov [sktAddr], ebx
 
; as a packet has been received, update the TCB timer
mov ecx, TWOMSL
mov [ebx + 32], ecx
 
; If the received packet has an ACK bit set,
; remove any packets in the resend queue that this
; received packet acknowledges
pusha
mov cl, [edx + 33]
and cl, 0x10
cmp cl, 0x10
jne tsm001 ; No ACK, so no data yet
 
 
; get skt number in al
shr eax, 12
 
; The ack number is in [edx + 28], inet format
; skt in al
 
mov esi, resendQ
mov ecx, 0
 
t001:
cmp ecx, NUMRESENDENTRIES
je t003 ; None left
cmp [esi], al
je t002 ; found one
inc ecx
add esi, 4
jmp t001
 
t002: ; Can we delete this buffer?
 
; If yes, goto t004. No, goto t001
; Get packet data address
 
push ecx
inc ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
mov edi, resendBuffer - IPBUFFSIZE
t002a:
add edi, IPBUFFSIZE
loop t002a
 
; we have dest buffer location in edi. incoming packet in edx.
; Get this packets sequence number
; preserve al, ecx, esi, edx
 
mov cl, [edi + 24]
shl ecx, 8
mov cl, [edi + 25]
shl ecx, 8
mov cl, [edi + 26]
shl ecx, 8
mov cl, [edi + 27]
movzx ebx, byte [edi + 3]
mov bh, [edi + 2]
sub ebx, 40
add ecx, ebx ; ecx is now seq# of last byte +1, intel format
 
; get recievd ack #, in intel format
mov bl, [edx + 28]
shl ebx, 8
mov bl, [edx + 29]
shl ebx, 8
mov bl, [edx + 30]
shl ebx, 8
mov bl, [edx + 31]
 
cmp ebx, ecx ; Finally. ecx = rx'ed ack. ebx = last byte in que
; DANGER! need to handle case that we have just
; passed the 2**32, and wrapped round!
pop ecx
 
jae t004 ; if rx > old, delete old
inc ecx
add esi, 4
jmp t001
 
 
t004:
dec dword [arp_rx_count] ; ************ TEST ONLY!
 
mov [esi], byte 0xFF
inc ecx
add esi, 4
jmp t001
 
t003:
 
tsm001:
popa
 
; Call handler for given TCB state
mov ebx, [eax + sockets+28]
cmp ebx, TCB_LISTEN
jb tsm_exit
cmp ebx, TCB_CLOSED
ja tsm_exit
 
dec ebx
call dword [TCBStateHandler+ebx*4]
 
tsm_exit:
ret
 
 
 
stateTCB_LISTEN:
; In this case, we are expecting a SYN packet
; For now, if the packet is a SYN, process it, and send a response
; If not, ignore it
 
; Look at control flags
mov bl, [edx + 33]
and bl, 0x02
cmp bl, 0x02
jnz stl_exit
 
; We have a SYN. update the socket with this IP packets details,
; And send a response
 
mov ebx, [edx + 12] ; IP source address
mov [eax + sockets + 16], ebx
mov bx, [edx + 20] ; IP source port
mov [eax + sockets + 20], bx
mov ebx, [edx + 24] ; IRS
mov [eax + sockets + 40], ebx
mov [eax + sockets + 56], ebx
mov esi, sockets
add esi, eax
add esi, 56
call inc_inet_esi ; RCV.NXT
mov ebx, [eax + sockets + 36] ; ISS
mov [eax + sockets + 48], ebx ; SND.NXT
 
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stl_exit
 
push eax
mov bl, 0x12 ; SYN + ACK
mov ecx, 0
mov esi, 0
 
call buildTCPPacket
 
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne stl_notlocal
mov eax, IPIN_QUEUE
 
stl_notlocal:
; Send it.
pop ebx
call queue
 
 
mov ebx, TCB_SYN_RECEIVED
mov esi, [sktAddr]
mov [esi + 28], ebx
 
; increament SND.NXT in socket
add esi, 48
call inc_inet_esi
 
stl_exit:
ret
 
 
 
stateTCB_SYN_SENT:
; We are awaiting an ACK to our SYN, with a SYM
; Look at control flags - expecting an ACK
mov bl, [edx + 33]
and bl, 0x12
cmp bl, 0x12
jnz stss_exit
 
mov ebx, TCB_ESTABLISHED
mov esi, [sktAddr]
mov [esi + 28], ebx
 
; Store the recv.nxt field
mov eax, [edx + 24]
 
; Update our recv.nxt field
mov esi, [sktAddr]
add esi, 56
mov [esi], eax
call inc_inet_esi
 
; Send an ACK
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stss_exit
 
push eax
 
mov bl, 0x10 ; ACK
mov ecx, 0
mov esi, 0
 
call buildTCPPacket
 
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne stss_notlocal
mov eax, IPIN_QUEUE
 
stss_notlocal:
; Send it.
pop ebx
call queue
 
stss_exit:
ret
 
 
 
stateTCB_SYN_RECEIVED:
; In this case, we are expecting an ACK packet
; For now, if the packet is an ACK, process it,
; If not, ignore it
 
; Look at control flags - expecting an ACK
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz stsr_exit
 
mov ebx, TCB_ESTABLISHED
mov esi, [sktAddr]
mov [esi + 28], ebx
 
stsr_exit:
ret
 
 
 
stateTCB_ESTABLISHED:
; Here we are expecting data, or a request to close
; OR both...
 
; Did we receive a FIN or RST?
mov bl, [edx + 33]
and bl, 0x05
cmp bl, 0
je ste_chkack
 
; It was a fin or reset.
 
; Remove resend entries from the queue - I dont want to send any more data
pusha
 
mov ebx, [sktAddr]
sub ebx, sockets
shr ebx, 12 ; get skt #
 
mov esi, resendQ
mov ecx, 0
 
ste001:
cmp ecx, NUMRESENDENTRIES
je ste003 ; None left
cmp [esi], bl
je ste002 ; found one
inc ecx
add esi, 4
jmp ste001
 
ste002:
dec dword [arp_rx_count] ; ************ TEST ONLY!
 
mov [esi], byte 0xFF
jmp ste001
 
ste003:
popa
 
; was it a reset?
mov bl, [edx + 33]
and bl, 0x04
cmp bl, 0x04
jne ste003a
 
mov esi, [sktAddr]
mov ebx, TCB_CLOSED
mov [esi + 28], ebx
jmp ste_exit
 
ste003a:
; Send an ACK to that fin, and enter closewait state
 
mov esi, [sktAddr]
mov ebx, TCB_CLOSE_WAIT
mov [esi + 28], ebx
add esi, 56
mov eax, [esi] ; save original
call inc_inet_esi
;; jmp ste_ack - NO, there may be data
 
ste_chkack:
; Check that we received an ACK
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz ste_exit
 
 
; TODO - done, I think!
; First, look at the incoming window. If this is less than or equal to 1024,
; Set the socket window timer to 1. This will stop an additional packets being
; queued.
; ** I may need to tweak this value, since I do not know how many packets are already queued
mov ch, [edx + 34]
mov cl, [edx + 35]
cmp cx, 1024
ja ste004
 
mov ecx, [sktAddr]
mov [ecx+72], dword 1
 
ste004:
 
; OK, here is the deal
; My recv.nct field holds the seq of the expected next rec byte
; if the recevied sequence number is not equal to this, do not
; increment the recv.nxt field, do not copy data - just send a
; repeat ack.
 
; recv.nxt is in dword [edx+24], in inext format
; recv seq is in [sktAddr]+56, in inet format
; just do a comparision
mov ecx, [sktAddr]
add ecx, 56
 
cmp [ecx - 56 + 28], dword TCB_CLOSE_WAIT
mov ecx, [ecx]
jne stenofin
mov ecx, eax
 
stenofin:
cmp ecx, [edx+24]
jne ste_ack
 
 
; Read the data bytes, store in socket buffer
xor ecx, ecx
mov ch, [edx + 2]
mov cl, [edx + 3]
sub ecx, 40 ; Discard 40 bytes of header
 
cmp ecx, 0
jnz ste_data ; Read data, if any
 
; If we had received a fin, we need to ACK it.
mov esi, [sktAddr]
mov ebx, [esi + 28]
cmp ebx, TCB_CLOSE_WAIT
jz ste_ack
jnz ste_exit
 
ste_data:
push ecx
mov esi, [sktAddr]
 
add [esi + 24], ecx ; increment the count of bytes in buffer
 
mov eax, [esi + 4] ; get socket owner PID
push eax
 
mov eax, [esi + 24] ; get # of bytes already in buffer
 
; point to the location to store the data
add esi, eax
sub esi, ecx
add esi, SOCKETHEADERSIZE
 
add edx, 40 ; edx now points to the data
mov edi, esi
mov esi, edx
 
cld
rep movsb ; copy the data across
 
; flag an event to the application
pop eax
mov ecx,1
mov esi,0x3020+0x4
 
news:
cmp [esi],eax
je foundPID1
inc ecx
add esi,0x20
cmp ecx,[0x3004]
jbe news
 
foundPID1:
shl ecx,8
or dword [ecx+0x80000+0xA8],dword 10000000b ; stack event
 
pop ecx
 
; Update our recv.nxt field
mov esi, [sktAddr]
add esi, 56
call add_inet_esi
 
ste_ack:
; Send an ACK
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je ste_exit
 
push eax
 
mov bl, 0x10 ; ACK
mov ecx, 0
mov esi, 0
 
call buildTCPPacket
 
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne ste_notlocal
mov eax, IPIN_QUEUE
ste_notlocal:
 
; Send it.
pop ebx
call queue
 
ste_exit:
ret
 
 
 
stateTCB_FIN_WAIT_1:
; We can either receive an ACK of a fin, or a fin
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz stfw1_001
 
; It was an ACK
mov esi, [sktAddr]
mov ebx, TCB_FIN_WAIT_2
mov [esi + 28], ebx
jmp stfw1_exit
 
stfw1_001:
; It must be a fin then
mov esi, [sktAddr]
mov ebx, TCB_CLOSING
mov [esi + 28], ebx
add esi, 56
call inc_inet_esi
 
; Send an ACK
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stfw1_exit
 
push eax
 
mov bl, 0x10 ; ACK
mov ecx, 0
mov esi, 0
 
call buildTCPPacket
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne stfw1_notlocal
mov eax, IPIN_QUEUE
 
stfw1_notlocal:
; Send it.
pop ebx
call queue
 
stfw1_exit:
ret
 
 
 
stateTCB_FIN_WAIT_2:
mov esi, [sktAddr]
 
; Get data length
xor ecx, ecx
mov ch, [edx+2]
mov cl, [edx+3]
sub ecx, 40
 
mov bl, [edx + 33]
and bl, 0x01
cmp bl, 0x01
jne stfw2001
 
; Change state, as we have a fin
mov ebx, TCB_TIME_WAIT
mov [esi + 28], ebx
 
inc ecx ; FIN is part of the sequence space
 
stfw2001:
add esi, 56
call add_inet_esi
 
; Send an ACK
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stfw2_exit
 
push eax
 
mov bl, 0x10 ; ACK
mov ecx, 0
mov esi, 0
 
call buildTCPPacket
 
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne stfw2_notlocal
mov eax, IPIN_QUEUE
 
stfw2_notlocal:
; Send it.
pop ebx
call queue
 
; Only delete the socket if we received the FIN
 
mov bl, [edx + 33]
and bl, 0x01
cmp bl, 0x01
jne stfw2_exit
 
; mov edi, [sktAddr]
 
; delete the socket. Should really wait for 2MSL
; xor eax, eax
; mov ecx,SOCKETHEADERSIZE
; cld
; rep stosb
 
stfw2_exit:
ret
 
 
 
stateTCB_CLOSE_WAIT:
; Intentionally left empty
; socket_close_tcp handles this
ret
 
 
 
stateTCB_CLOSING:
; We can either receive an ACK of a fin, or a fin
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz stc_exit
 
; It was an ACK
 
mov edi, [sktAddr]
 
; delete the socket
xor eax, eax
mov ecx,SOCKETHEADERSIZE
cld
rep stosb
 
stc_exit:
ret
 
 
 
stateTCB_LAST_ACK:
; Look at control flags - expecting an ACK
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz stla_exit
 
mov edi, [sktAddr]
 
; delete the socket
xor eax, eax
mov ecx,SOCKETHEADERSIZE
cld
rep stosb
 
stla_exit:
ret
 
 
 
stateTCB_TIME_WAIT:
ret
 
 
 
stateTCB_CLOSED:
ret
/kernel/trunk/network/udp.inc
0,0 → 1,137
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; UDP.INC ;;
;; ;;
;; UDP Processes for Menuet OS TCP/IP stack ;;
;; ;;
;; Version 0.3 29 August 2002 ;;
;; ;;
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;*******************************************************************
; Interface
;
; udp_rx Handles received IP packets with the UDP protocol
;
;*******************************************************************
;***************************************************************************
; Function
; udp_rx
;
; Description
; UDP protocol handler
; This is a kernel function, called by ip_rx
; IP buffer address given in edx
; Free up (or re-use) IP buffer when finished
;
;***************************************************************************
udp_rx:
push eax
; First validate the header & checksum. Discard buffer if error
; Look for a socket where
; IP Packet UDP Destination Port = local Port
; IP Packet SA = Remote IP
movzx ebx, word [edx + 22] ; get the local port from
; the IP packet's UDP header
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
fs1:
sub eax, SOCKETBUFFSIZE
cmp [eax + sockets + 12], bx ; bx will hold the 'wrong' value,
; but the comparision is correct
loopnz fs1 ; Return back if no match
jz fs_done
; No match, so exit
jmp udprx_001
fs_done:
; For dhcp, we must allow any remote server to respond.
; I will accept the first incoming response to be the one
; I bind to, if the socket is opened with a destination IP address of
; 255.255.255.255
mov ebx, [eax + sockets + 16]
cmp ebx, 0xffffffff
je udprx_002
mov ebx, [edx + 12] ; get the Source address from the IP packet
cmp [eax + sockets + 16], ebx
jne udprx_001 ; Quit if the source IP is not valid
 
udprx_002:
; OK - we have a valid UDP packet for this socket.
; First, update the sockets remote port number with the incoming msg
; - it will have changed
; from the original ( 69 normally ) to allow further connects
movzx ebx, word [edx + 20] ; get the UDP source port
; ( was 69, now new )
mov [eax + sockets + 20], bx
; Now, copy data to socket. We have socket address as [eax + sockets].
; We have IP packet in edx
; get # of bytes in ecx
movzx ecx, byte [edx + 3] ; total length of IP packet. Subtract
mov ch, byte [edx + 2] ; 20 + 8 gives data length
sub ecx, 28
mov ebx, eax
add ebx, sockets ; ebx = address of actual socket
mov eax, [ebx+ 4] ; get socket owner PID
push eax
mov eax, [ebx + 24] ; get # of bytes already in buffer
add [ebx + 24], ecx ; increment the count of bytes in buffer
; point to the location to store the data
add ebx, eax
add ebx, SOCKETHEADERSIZE
 
; ebx = location for first byte, ecx has count,
; edx points to data
add edx, 28 ; edx now points to the data
mov edi, ebx
mov esi, edx
cld
rep movsb ; copy the data across
; flag an event to the application
pop eax
mov ecx,1
mov esi,0x3020+0x4
newsearch:
cmp [esi],eax
je foundPID
inc ecx
add esi,0x20
cmp ecx,[0x3004]
jbe newsearch
foundPID:
shl ecx,8
or dword [ecx+0x80000+0xA8],dword 10000000b ; stack event
 
mov [check_idle_semaphore],200
 
udprx_001:
pop eax
call freeBuff ; Discard the packet
ret