forked from KolibriOS/kolibrios
8a7ebf6b32
added pci ids of dec21x4x cards to netcfg bugfixes in dex21x4x driver, pcnet32 driver, rtl8139 driver and sis900 driver new network program (ICMP) to ping computers, uses new RAW socket code (experimental) git-svn-id: svn://kolibrios.org@1541 a494cfbc-eb01-0410-851d-a64ba20cac60
1307 lines
32 KiB
NASM
1307 lines
32 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;; Ethernet driver for KolibriOS ;;
|
|
;; This is an adaptation of MenuetOS driver with minimal changes. ;;
|
|
;; Changes were made by CleverMouse. Original copyright follows. ;;
|
|
;; ;;
|
|
;; 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 ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
format MS COFF
|
|
|
|
API_VERSION equ 0x01000100
|
|
DRIVER_VERSION equ 5
|
|
|
|
MAX_DEVICES equ 16
|
|
|
|
DEBUG equ 1
|
|
__DEBUG__ equ 1
|
|
__DEBUG_LEVEL__ equ 1
|
|
|
|
include 'proc32.inc'
|
|
include 'imports.inc'
|
|
include 'fdo.inc'
|
|
include 'netdrv.inc'
|
|
|
|
public START
|
|
public version
|
|
|
|
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 *
|
|
MAX_ETH_FRAME_SIZE equ 1516
|
|
|
|
virtual at ebx
|
|
device:
|
|
|
|
ETH_DEVICE
|
|
|
|
.io_addr dd ?
|
|
.pci_bus db ?
|
|
.pci_dev db ?
|
|
.irq_line db ?
|
|
.cur_rx db ?
|
|
.cur_tx db ?
|
|
.last_tx db ?
|
|
.pci_revision db ?
|
|
.table_entries db ?
|
|
|
|
dw ? ; align 4
|
|
|
|
.special_func dd ?
|
|
|
|
.txd rd (4 * NUM_TX_DESC)
|
|
.rxd rd (4 * NUM_RX_DESC)
|
|
|
|
.size = $ - device
|
|
|
|
end virtual
|
|
|
|
macro ee_delay {
|
|
push eax
|
|
in eax, dx
|
|
in eax, dx
|
|
in eax, dx
|
|
in eax, dx
|
|
in eax, dx
|
|
in eax, dx
|
|
in eax, dx
|
|
in eax, dx
|
|
in eax, dx
|
|
in eax, dx
|
|
pop eax
|
|
}
|
|
|
|
|
|
section '.flat' code readable align 16
|
|
|
|
; Driver entry point - register our service when the driver is loading.
|
|
; TODO: add needed operations when unloading
|
|
START:
|
|
cmp dword [esp+4], 1
|
|
jne .exit
|
|
stdcall RegService, my_service, service_proc
|
|
ret 4
|
|
.exit:
|
|
xor eax, eax
|
|
ret 4
|
|
|
|
; Service procedure for the driver - handle all I/O requests for the driver.
|
|
; Currently handled requests are: SRV_GETVERSION = 0 and SRV_HOOK = 1.
|
|
service_proc:
|
|
; 1. Get parameter from the stack: [esp+4] is the first parameter,
|
|
; pointer to IOCTL structure.
|
|
mov edx, [esp+4] ; edx -> IOCTL
|
|
; 2. Get request code and select a handler for the code.
|
|
mov eax, [IOCTL.io_code]
|
|
test eax, eax ; check for SRV_GETVERSION
|
|
jnz @f
|
|
; 3. This is SRV_GETVERSION request, no input, 4 bytes output, API_VERSION.
|
|
; 3a. Output size must be at least 4 bytes.
|
|
cmp [IOCTL.out_size], 4
|
|
jl .fail
|
|
; 3b. Write result to the output buffer.
|
|
mov eax, [IOCTL.output]
|
|
mov [eax], dword API_VERSION
|
|
; 3c. Return success.
|
|
xor eax, eax
|
|
ret 4
|
|
@@:
|
|
dec eax ; check for SRV_HOOK
|
|
jnz .fail
|
|
; 4. This is SRV_HOOK request, input defines the device to hook, no output.
|
|
; 4a. The driver works only with PCI devices,
|
|
; so input must be at least 3 bytes long.
|
|
cmp [IOCTL.inp_size], 3
|
|
jl .fail
|
|
; 4b. First byte of input is bus type, 1 stands for PCI.
|
|
mov eax, [IOCTL.input]
|
|
cmp byte [eax], 1
|
|
jne .fail
|
|
; 4c. Second and third bytes of the input define the device: bus and dev.
|
|
; Word in bx holds both bytes.
|
|
mov bx, [eax+1]
|
|
; 4d. Check if the device was already hooked,
|
|
; scan through the list of known devices.
|
|
; check if the device is already listed
|
|
mov esi, device_list
|
|
mov ecx, [devices]
|
|
test ecx, ecx
|
|
jz .firstdevice
|
|
|
|
; mov eax, [IOCTL.input] ; get the pci bus and device numbers
|
|
mov ax , [eax+1] ;
|
|
.nextdevice:
|
|
mov ebx, [esi]
|
|
cmp ax , word [device.pci_bus] ; compare with pci and device num in device list (notice the usage of word instead of byte)
|
|
je .find_devicenum ; Device is already loaded, let's find it's device number
|
|
add esi, 4
|
|
loop .nextdevice
|
|
; 4e. This device doesn't have its own eth_device structure yet, let's create one
|
|
.firstdevice:
|
|
; 4f. Check that we have place for new device.
|
|
cmp [devices], MAX_DEVICES
|
|
jge .fail
|
|
; 4g. Allocate memory for device descriptor and receive+transmit buffers.
|
|
stdcall KernelAlloc, device.size
|
|
test eax, eax
|
|
jz .fail
|
|
; 4h. Zero the structure.
|
|
mov edi, eax
|
|
mov ecx, (device.size + 3) shr 2
|
|
xor eax, eax
|
|
rep stosd
|
|
; 4i. Save PCI coordinates
|
|
mov eax, [IOCTL.input]
|
|
mov cl , [eax+1]
|
|
mov [device.pci_bus], cl
|
|
mov cl , [eax+2]
|
|
mov [device.pci_dev], cl
|
|
; 4j. Fill in the direct call addresses into the struct.
|
|
; Note that get_MAC pointer is filled in initialization by probe.
|
|
mov [device.reset], init
|
|
mov [device.transmit], transmit
|
|
; mov [device.get_MAC], read_mac
|
|
mov [device.set_MAC], write_mac
|
|
mov [device.unload], unload
|
|
mov [device.name], my_service
|
|
|
|
; 4k. Now, it's time to find the base io addres of the PCI device
|
|
; TODO: implement check if bus and dev exist on this machine
|
|
|
|
; Now, it's time to find the base io addres of the PCI device
|
|
find_io [device.pci_bus], [device.pci_dev], [device.io_addr]
|
|
|
|
; We've found the io address, find IRQ now
|
|
find_irq [device.pci_bus], [device.pci_dev], [device.irq_line]
|
|
|
|
; 4m. Add new device to the list (required for int_handler).
|
|
mov eax, [devices]
|
|
mov [device_list+4*eax], ebx
|
|
inc [devices]
|
|
|
|
; 4m. Ok, the eth_device structure is ready, let's probe the device
|
|
call probe
|
|
test eax, eax
|
|
jnz .destroy
|
|
; 4n. If device was successfully initialized, register it for the kernel.
|
|
|
|
mov [device.type], NET_TYPE_ETH
|
|
call NetRegDev
|
|
|
|
cmp eax, -1
|
|
je .destroy
|
|
|
|
ret 4
|
|
|
|
; 5. If the device was already loaded, find the device number and return it in eax
|
|
|
|
.find_devicenum:
|
|
mov ebx, eax
|
|
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx
|
|
; into a device number in edi
|
|
mov eax, edi ; Application wants it in eax instead
|
|
ret 4
|
|
|
|
; If an error occured, remove all allocated data and exit (returning -1 in eax)
|
|
|
|
.destroy:
|
|
dec [devices]
|
|
; todo: reset device into virgin state
|
|
|
|
.err:
|
|
stdcall KernelFree, ebx
|
|
|
|
|
|
.fail:
|
|
xor eax, eax
|
|
ret 4
|
|
|
|
|
|
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
|
|
;; ;;
|
|
;; Actual Hardware dependent code starts here ;;
|
|
;; ;;
|
|
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
|
|
|
|
unload:
|
|
; TODO: (in this particular order)
|
|
;
|
|
; - Stop the device
|
|
; - Detach int handler
|
|
; - Remove device from local list
|
|
; - call unregister function in kernel
|
|
; - Remove all allocated structures and buffers the card used
|
|
|
|
or eax,-1
|
|
|
|
ret
|
|
|
|
;********************************************************************
|
|
; 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.
|
|
;
|
|
; ToDo:
|
|
; - Enable MII interface for reading speed
|
|
; and duplex settings.
|
|
; - Update receive routine to support packet fragmentation.
|
|
; - Add additional support for other sis900 based cards
|
|
;
|
|
;********************************************************************
|
|
|
|
ETH_ALEN equ 6 ; Size of Ethernet address
|
|
ETH_HLEN equ 14 ; Size of ethernet header
|
|
ETH_ZLEN equ 60 ; Minimum packet length
|
|
DSIZE equ 0x00000fff
|
|
CRC_SIZE equ 4
|
|
RFADDR_shift equ 16
|
|
|
|
; Symbolic offsets to registers.
|
|
cr equ 0x0 ; Command Register
|
|
cfg equ 0x4 ; Configuration Register
|
|
mear equ 0x8 ; EEPROM Access Register
|
|
ptscr equ 0xc ; PCI Test Control Register
|
|
isr equ 0x10 ; Interrupt Status Register
|
|
imr equ 0x14 ; Interrupt Mask Register
|
|
ier equ 0x18 ; Interrupt Enable Register
|
|
epar equ 0x18 ; Enhanced PHY Access Register
|
|
txdp equ 0x20 ; Transmit Descriptor Pointer Register
|
|
txcfg equ 0x24 ; Transmit Configuration Register
|
|
rxdp equ 0x30 ; Receive Descriptor Pointer Register
|
|
rxcfg equ 0x34 ; Receive Configuration Register
|
|
flctrl equ 0x38 ; Flow Control Register
|
|
rxlen equ 0x3c ; Receive Packet Length Register
|
|
rfcr equ 0x48 ; Receive Filter Control Register
|
|
rfdr equ 0x4C ; Receive Filter Data Register
|
|
pmctrl equ 0xB0 ; Power Management Control Register
|
|
pmer equ 0xB4 ; Power Management Wake-up Event Register
|
|
|
|
; Command Register Bits
|
|
RELOAD equ 0x00000400
|
|
ACCESSMODE equ 0x00000200
|
|
RESET equ 0x00000100
|
|
SWI equ 0x00000080
|
|
RxRESET equ 0x00000020
|
|
TxRESET equ 0x00000010
|
|
RxDIS equ 0x00000008
|
|
RxENA equ 0x00000004
|
|
TxDIS equ 0x00000002
|
|
TxENA equ 0x00000001
|
|
|
|
; Configuration Register Bits
|
|
DESCRFMT equ 0x00000100 ; 7016 specific
|
|
REQALG equ 0x00000080
|
|
SB equ 0x00000040
|
|
POW equ 0x00000020
|
|
EXD equ 0x00000010
|
|
PESEL equ 0x00000008
|
|
LPM equ 0x00000004
|
|
BEM equ 0x00000001
|
|
RND_CNT equ 0x00000400
|
|
FAIR_BACKOFF equ 0x00000200
|
|
EDB_MASTER_EN equ 0x00002000
|
|
|
|
; Eeprom Access Reigster Bits
|
|
MDC equ 0x00000040
|
|
MDDIR equ 0x00000020
|
|
MDIO equ 0x00000010 ; 7016 specific
|
|
EECS equ 0x00000008
|
|
EECLK equ 0x00000004
|
|
EEDO equ 0x00000002
|
|
EEDI equ 0x00000001
|
|
|
|
; TX Configuration Register Bits
|
|
ATP equ 0x10000000 ;Automatic Transmit Padding
|
|
MLB equ 0x20000000 ;Mac Loopback Enable
|
|
HBI equ 0x40000000 ;HeartBeat Ignore (Req for full-dup)
|
|
CSI equ 0x80000000 ;CarrierSenseIgnore (Req for full-du
|
|
|
|
; RX Configuration Register Bits
|
|
AJAB equ 0x08000000 ;
|
|
ATX equ 0x10000000 ;Accept Transmit Packets
|
|
ARP equ 0x40000000 ;accept runt packets (<64bytes)
|
|
AEP equ 0x80000000 ;accept error packets
|
|
|
|
; Interrupt Reigster Bits
|
|
WKEVT equ 0x10000000
|
|
TxPAUSEEND equ 0x08000000
|
|
TxPAUSE equ 0x04000000
|
|
TxRCMP equ 0x02000000
|
|
RxRCMP equ 0x01000000
|
|
DPERR equ 0x00800000
|
|
SSERR equ 0x00400000
|
|
RMABT equ 0x00200000
|
|
RTABT equ 0x00100000
|
|
RxSOVR equ 0x00010000
|
|
HIBERR equ 0x00008000
|
|
SWINT equ 0x00001000
|
|
MIBINT equ 0x00000800
|
|
TxURN equ 0x00000400
|
|
TxIDLE equ 0x00000200
|
|
TxERR equ 0x00000100
|
|
TxDESC equ 0x00000080
|
|
TxOK equ 0x00000040
|
|
RxORN equ 0x00000020
|
|
RxIDLE equ 0x00000010
|
|
RxEARLY equ 0x00000008
|
|
RxERR equ 0x00000004
|
|
RxDESC equ 0x00000002
|
|
RxOK equ 0x00000001
|
|
|
|
; Interrupt Enable Register Bits
|
|
IE equ RxOK + TxOK
|
|
|
|
; 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
|
|
|
|
; Receive Filter Control Register Bits
|
|
RFEN equ 0x80000000
|
|
RFAAB equ 0x40000000
|
|
RFAAM equ 0x20000000
|
|
RFAAP equ 0x10000000
|
|
RFPromiscuous equ 0x70000000
|
|
|
|
; Reveive Filter Data Mask
|
|
RFDAT equ 0x0000FFFF
|
|
|
|
; Eeprom Address
|
|
EEPROMSignature equ 0x00
|
|
EEPROMVendorID equ 0x02
|
|
EEPROMDeviceID equ 0x03
|
|
EEPROMMACAddr equ 0x08
|
|
EEPROMChecksum equ 0x0b
|
|
|
|
;The EEPROM commands include the alway-set leading bit.
|
|
EEread equ 0x0180
|
|
EEwrite equ 0x0140
|
|
EEerase equ 0x01C0
|
|
EEwriteEnable equ 0x0130
|
|
EEwriteDisable equ 0x0100
|
|
EEeraseAll equ 0x0120
|
|
EEwriteAll equ 0x0110
|
|
EEaddrMask equ 0x013F
|
|
EEcmdShift equ 16
|
|
|
|
;For SiS962 or SiS963, request the eeprom software access
|
|
EEREQ equ 0x00000400
|
|
EEDONE equ 0x00000200
|
|
EEGNT equ 0x00000100
|
|
|
|
|
|
;***************************************************************************
|
|
;
|
|
; probe
|
|
;
|
|
; Searches for an ethernet card, enables it and clears the rx buffer
|
|
;
|
|
; TODO: probe mii transceivers
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
probe:
|
|
|
|
stdcall PciWrite8, dword [device.pci_bus], dword [device.pci_dev], 0x40, 0 ; Wake Up Chip
|
|
|
|
make_bus_master [device.pci_bus], [device.pci_dev]
|
|
|
|
; Get Card Revision
|
|
stdcall PciRead8, dword [device.pci_bus], dword [device.pci_dev], 0x08
|
|
mov [pci_revision], al ; save the revision for later use
|
|
|
|
; Look up through the specific_table
|
|
mov esi, specific_table
|
|
.loop:
|
|
cmp dword [esi], 0 ; Check if we reached end of the list
|
|
je .error
|
|
cmp al, [esi] ; Check if revision is OK
|
|
je .ok
|
|
add esi, 12 ; Advance to next entry
|
|
jmp .loop
|
|
|
|
.error:
|
|
DEBUGF 1, "Device not supported!\n"
|
|
or eax, -1
|
|
ret
|
|
|
|
; Find Get Mac Function
|
|
.ok:
|
|
mov eax, [esi+4] ; Get pointer to "get MAC" function
|
|
mov [get_mac_func], eax
|
|
mov eax, [esi+8] ; Get pointer to special initialization fn
|
|
mov [special_func], eax
|
|
|
|
; Get MAC
|
|
call [get_mac_func]
|
|
|
|
; Call special initialization fn if requested
|
|
|
|
cmp [special_func],0
|
|
je @f
|
|
call [special_func]
|
|
@@:
|
|
|
|
; Set table entries
|
|
|
|
mov byte [table_entries], 16
|
|
cmp [pci_revision], SIS635A_900_REV
|
|
jae @f
|
|
cmp [pci_revision], SIS900B_900_REV
|
|
je @f
|
|
mov byte [table_entries], 8
|
|
@@:
|
|
|
|
; TODO: Probe for mii transceiver
|
|
|
|
|
|
;***************************************************************************
|
|
;
|
|
; init
|
|
;
|
|
; resets the ethernet controller chip and various
|
|
; data structures required for sending and receiving packets.
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
init:
|
|
|
|
call reset
|
|
call init_rxfilter
|
|
call init_txd
|
|
call init_rxd
|
|
call set_rx_mode
|
|
call set_tx_mode
|
|
;call check_mode
|
|
|
|
; enable interrupts on packet receive
|
|
|
|
xor eax, eax
|
|
inc eax ; eax = 1 = RxOK
|
|
set_io 0
|
|
set_io imr
|
|
out dx, eax
|
|
|
|
; globally enable interrupts
|
|
|
|
set_io ier
|
|
out dx, eax ; eax is still 1
|
|
xor eax, eax
|
|
|
|
mov [device.mtu], 1514
|
|
|
|
ret
|
|
|
|
;***************************************************************************
|
|
;
|
|
; reset
|
|
;
|
|
; disables interrupts and soft resets the controller chip
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
reset:
|
|
movzx eax, [device.irq_line]
|
|
stdcall AttachIntHandler, eax, int_handler, 0
|
|
|
|
;--------------------------------------------
|
|
; Disable Interrupts and reset Receive Filter
|
|
|
|
set_io 0
|
|
set_io ier
|
|
xor eax, eax
|
|
out dx, eax
|
|
|
|
set_io imr
|
|
out dx, eax
|
|
|
|
set_io rfcr
|
|
out dx, eax
|
|
|
|
;-----------
|
|
; Reset Card
|
|
|
|
set_io cr
|
|
in eax, dx ; Get current Command Register
|
|
or eax, RESET + RxRESET + TxRESET ; set flags
|
|
out dx, eax ; Write new Command Register
|
|
|
|
;----------
|
|
; Wait loop
|
|
|
|
set_io isr
|
|
mov ecx, 1000
|
|
.loop:
|
|
dec ecx
|
|
jz .error
|
|
in eax, dx ; move interrup status to eax
|
|
cmp eax, 0x03000000
|
|
jne .loop
|
|
|
|
;------------------------------------------------------
|
|
; Set Configuration Register depending on Card Revision
|
|
|
|
set_io cfg
|
|
mov eax, PESEL ; Configuration Register Bit
|
|
cmp [pci_revision], SIS635A_900_REV
|
|
je .match
|
|
cmp [pci_revision], SIS900B_900_REV ; Check card revision
|
|
je .match
|
|
out dx, eax ; no revision match
|
|
jmp .done
|
|
|
|
.match: ; Revision match
|
|
or eax, RND_CNT ; Configuration Register Bit
|
|
out dx, eax
|
|
|
|
.done:
|
|
xor eax, eax
|
|
ret
|
|
|
|
.error:
|
|
DEBUGF 1, "Reset failed!\n"
|
|
or eax, -1
|
|
ret
|
|
|
|
|
|
;***************************************************************************
|
|
;
|
|
; sis_init_rxfilter
|
|
;
|
|
; sets receive filter address to our MAC address
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
init_rxfilter:
|
|
|
|
;------------------------------------
|
|
; Get Receive Filter Control Register
|
|
|
|
set_io 0
|
|
set_io rfcr
|
|
in eax, dx
|
|
push eax
|
|
|
|
;-----------------------------------------------
|
|
; disable packet filtering before setting filter
|
|
|
|
and eax, not RFEN
|
|
out dx, eax
|
|
|
|
;--------------------------------------
|
|
; load MAC addr to filter data register
|
|
|
|
xor ecx, ecx
|
|
RXINT_Mac_Write: ; high word of eax tells card which mac byte to write
|
|
mov eax, ecx
|
|
set_io 0
|
|
set_io rfcr
|
|
shl eax, 16 ;
|
|
out dx, eax ;
|
|
set_io rfdr
|
|
mov ax, word [device.mac+ecx*2] ; Get Mac ID word
|
|
out dx, ax ; Send Mac ID
|
|
inc cl ; send next word
|
|
cmp cl, 3 ; more to send?
|
|
jne RXINT_Mac_Write
|
|
|
|
;------------------------
|
|
; enable packet filtering
|
|
|
|
pop eax ;old register value
|
|
set_io rfcr
|
|
or eax, RFEN ;enable filtering
|
|
out dx, eax ;set register
|
|
|
|
ret
|
|
|
|
;***************************************************************************
|
|
;
|
|
; init_txd
|
|
;
|
|
; initializes the Tx descriptor
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
init_txd:
|
|
|
|
;-------------------------
|
|
; initialize TX descriptor
|
|
|
|
mov dword [device.txd], 0 ; put link to next descriptor in link field
|
|
mov dword [device.txd+4], 0 ; clear status field
|
|
mov dword [device.txd+8], 0 ; ptr to buffer
|
|
|
|
;----------------------------------
|
|
; load Transmit Descriptor Register
|
|
|
|
set_io 0
|
|
set_io txdp ; TX Descriptor Pointer
|
|
lea eax, [device.txd]
|
|
GetRealAddr
|
|
out dx, eax ; move the pointer
|
|
|
|
ret
|
|
|
|
;***************************************************************************
|
|
;
|
|
; init_rxd
|
|
;
|
|
; initializes the Rx descriptor ring
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
init_rxd:
|
|
|
|
; init RX descriptors
|
|
mov ecx, NUM_RX_DESC
|
|
lea esi, [device.rxd]
|
|
|
|
.loop:
|
|
lea eax, [esi + 16]
|
|
GetRealAddr
|
|
mov dword [esi+0], eax
|
|
mov dword [esi+4], RX_BUFF_SZ
|
|
|
|
stdcall KernelAlloc, RX_BUFF_SZ
|
|
test eax, eax
|
|
jz .fail
|
|
mov dword [esi+12], eax
|
|
GetRealAddr
|
|
mov dword [esi+8], eax
|
|
add esi, 16
|
|
loop .loop
|
|
|
|
lea eax, [device.rxd]
|
|
GetRealAddr
|
|
mov dword [esi - 16], eax ; correct last descriptor link ptr
|
|
|
|
; And output ptr to first desc, to device
|
|
|
|
set_io 0
|
|
set_io rxdp
|
|
out dx, eax
|
|
|
|
mov [device.cur_rx], 0 ; Set curent rx discriptor to 0
|
|
|
|
.fail: ;;; TODO: abort instead!
|
|
ret
|
|
|
|
|
|
;***************************************************************************
|
|
;
|
|
; set_tx_mode
|
|
;
|
|
; sets the transmit mode to allow for full duplex
|
|
;
|
|
; 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
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
set_tx_mode:
|
|
|
|
set_io 0
|
|
set_io cr
|
|
in eax, dx ; Get current Command Register
|
|
or eax, TxENA ; Enable Receive
|
|
out dx, eax
|
|
|
|
set_io txcfg ; Transmit config Register offset
|
|
mov eax, ATP + HBI + CSI +0x00600120
|
|
; allow automatic padding
|
|
; allow heartbeat ignore
|
|
; allow carrier sense ignore
|
|
; Max DMA Burst (128 bytes)
|
|
; TX Fill Threshold
|
|
; TX Drain Threshold
|
|
out dx, eax
|
|
|
|
ret
|
|
|
|
;***************************************************************************
|
|
;
|
|
; set_rx_mode
|
|
;
|
|
; sets the receive mode to accept all broadcast packets and packets
|
|
; with our MAC address, and reject all multicast packets. Also allows
|
|
; full-duplex
|
|
;
|
|
; 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
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
set_rx_mode:
|
|
|
|
;----------------------------------------------
|
|
; update Multicast Hash Table in Receive Filter
|
|
|
|
xor cl, cl
|
|
.loop:
|
|
set_io 0
|
|
set_io 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
|
|
|
|
set_io rfdr ; Receive Filter Control Reg offset
|
|
mov eax, 0xffff ; entry value
|
|
out dx, ax ; write value to table in card
|
|
|
|
inc cl ; next entry
|
|
cmp cl, [table_entries]
|
|
jl .loop
|
|
|
|
;------------------------------------
|
|
; Set Receive Filter Control Register
|
|
|
|
set_io rfcr ; Receive Filter Control Register offset
|
|
mov eax, RFAAB + RFAAM + RFAAP + RFEN
|
|
; accecpt all broadcast packets
|
|
; accept all multicast packets
|
|
; Accept all packets
|
|
; enable receiver filter
|
|
out dx, eax
|
|
;----------------
|
|
; Enable Receiver
|
|
|
|
set_io cr
|
|
in eax, dx ; Get current Command Register
|
|
or eax, RxENA ; Enable Receive
|
|
out dx, eax
|
|
|
|
;-------------------
|
|
; Configure Receiver
|
|
|
|
set_io rxcfg ; Receive Config Register offset
|
|
mov eax, ATX + 0x00600002
|
|
; Accept Transmit Packets
|
|
; (Req for full-duplex and PMD Loopback)
|
|
; Max DMA Burst
|
|
; RX Drain Threshold, 8X8 bytes or 64bytes
|
|
out dx, eax
|
|
|
|
ret
|
|
|
|
;***************************************************************************
|
|
;
|
|
; SIS960_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
|
|
;
|
|
; SiS962 or SiS963 model, use EEPROM to store MAC address.
|
|
; 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 accessed 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.
|
|
;
|
|
; Return 0 is EAX = failure
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
SIS960_get_mac_addr:
|
|
|
|
;-------------------------------
|
|
; Send Request for eeprom access
|
|
|
|
set_io 0
|
|
set_io mear ; Eeprom access register
|
|
mov eax, EEREQ ; Request access to eeprom
|
|
out dx, eax ; Send request
|
|
|
|
;-----------------------------------------------------
|
|
; Loop 4000 times and if access not granted, error out
|
|
|
|
mov ecx, 4000
|
|
.loop:
|
|
in eax, dx ; get eeprom status
|
|
test eax, EEGNT ; see if eeprom access granted flag is set
|
|
jnz .got_access ; if it is, go access the eeprom
|
|
loop .loop ; else keep waiting
|
|
|
|
DEBUGF 1, "Access to EEprom failed!\n", 0
|
|
|
|
set_io mear ; Eeprom access register
|
|
mov eax, EEDONE ; tell eeprom we are done
|
|
out dx, eax
|
|
|
|
or eax, -1 ; error
|
|
ret
|
|
|
|
.got_access:
|
|
|
|
;------------------------------------------
|
|
; EEprom access granted, read MAC from card
|
|
|
|
; zero based so 3-16 bit reads will take place
|
|
|
|
mov ecx, 2
|
|
.read_loop:
|
|
mov eax, EEPROMMACAddr ; Base Mac Address
|
|
add eax, ecx ; Current Mac Byte Offset
|
|
push ecx
|
|
call read_eeprom ; try to read 16 bits
|
|
pop ecx
|
|
mov word [device.mac+ecx*2], ax ; save 16 bits to the MAC ID varible
|
|
dec ecx ; one less word to read
|
|
jns .read_loop ; if more read more
|
|
mov eax, 1 ; return non-zero indicating success
|
|
|
|
DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2
|
|
|
|
;-------------------------------------
|
|
; Tell EEPROM We are Done Accessing It
|
|
|
|
.done:
|
|
set_io 0
|
|
set_io mear ; Eeprom access register
|
|
mov eax, EEDONE ; tell eeprom we are done
|
|
out dx, eax
|
|
|
|
xor eax, eax ; ok
|
|
ret
|
|
|
|
|
|
|
|
|
|
;***************************************************************************
|
|
;
|
|
; get_mac_addr: - Get MAC address for stand alone SiS900 model
|
|
;
|
|
; Older SiS900 and friends, use EEPROM to store MAC address.
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
get_mac_addr:
|
|
|
|
;------------------------------------
|
|
; check to see if we have sane EEPROM
|
|
|
|
mov eax, EEPROMSignature ; Base Eeprom Signature
|
|
call read_eeprom ; try to read 16 bits
|
|
cmp ax, 0xffff
|
|
je .err
|
|
test ax, ax
|
|
je .err
|
|
|
|
;-----------
|
|
; Read MacID
|
|
|
|
; zero based so 3-16 bit reads will take place
|
|
|
|
mov ecx, 2
|
|
.loop:
|
|
mov eax, EEPROMMACAddr ;Base Mac Address
|
|
add eax, ecx ;Current Mac Byte Offset
|
|
push ecx
|
|
call read_eeprom ;try to read 16 bits
|
|
pop ecx
|
|
mov word [device.mac+ecx*2], ax ;save 16 bits to the MAC ID storage
|
|
dec ecx ;one less word to read
|
|
jns mac_read_loop ;if more read more
|
|
|
|
DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2
|
|
|
|
xor eax, eax
|
|
ret
|
|
|
|
|
|
.err:
|
|
DEBUGF 1, "Access to EEprom failed!\n", 0
|
|
|
|
or eax, -1
|
|
ret
|
|
|
|
|
|
;***************************************************************************
|
|
;
|
|
; Get_Mac_SIS635_900_REV: - Get MAC address for model 635
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
Get_Mac_SIS635_900_REV:
|
|
|
|
set_io 0
|
|
set_io rfcr
|
|
in eax, dx
|
|
mov edi, eax ; EDI=rfcrSave
|
|
|
|
set_io cr
|
|
or eax, RELOAD
|
|
out dx, eax
|
|
|
|
xor eax, eax
|
|
out dx, eax
|
|
|
|
;-----------------------------------------------
|
|
; Disable packet filtering before setting filter
|
|
|
|
set_io rfcr
|
|
mov eax, edi
|
|
and edi, not RFEN
|
|
out dx, eax
|
|
|
|
;---------------------------------
|
|
; Load MAC to filter data register
|
|
|
|
mov ecx, 3
|
|
lea edi, [device.mac]
|
|
.loop:
|
|
set_io 0
|
|
set_io rfcr
|
|
mov eax, ecx
|
|
shl eax, RFADDR_shift
|
|
out dx, eax
|
|
|
|
set_io rfdr
|
|
in eax, dx
|
|
stosw
|
|
loop .loop
|
|
|
|
;------------------------
|
|
; Enable packet filtering
|
|
|
|
; set_io rfcr
|
|
; mov eax, edi
|
|
; or eax, RFEN
|
|
; out dx, eax
|
|
|
|
xor eax, eax
|
|
ret
|
|
|
|
;***************************************************************************
|
|
;
|
|
; read_eeprom
|
|
;
|
|
; reads and returns a given location from EEPROM
|
|
;
|
|
; IN: si = addr
|
|
; OUT: ax = data
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
read_eeprom:
|
|
|
|
set_io 0
|
|
set_io mear
|
|
|
|
xor eax, eax ; start send
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
or eax, EECLK
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
;------------------------------------
|
|
; Send the read command
|
|
|
|
or esi, EEread
|
|
mov ecx, 1 shl 9
|
|
|
|
.loop:
|
|
mov eax, EECS
|
|
test esi, ecx
|
|
jz @f
|
|
or eax, EEDI
|
|
@@:
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
or eax, EECLK
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
shr esi, 1
|
|
jnc .loop
|
|
|
|
mov eax, EECS
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
;------------------------
|
|
; Read 16-bits of data in
|
|
|
|
xor esi, esi
|
|
mov cx, 16
|
|
.loop2:
|
|
mov eax, EECS
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
or eax, EECLK
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
in eax, dx
|
|
shl esi, 1
|
|
test eax, EEDO
|
|
jz @f
|
|
inc esi
|
|
@@:
|
|
loop .loop2
|
|
|
|
;----------------------------
|
|
; Terminate the EEPROM access
|
|
|
|
xor eax, eax
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
mov eax, EECLK
|
|
out dx, eax
|
|
ee_delay
|
|
|
|
movzx eax, si
|
|
|
|
ret
|
|
|
|
|
|
|
|
align 4
|
|
write_mac:
|
|
DEBUGF 1,'Setting MAC is not supported for SIS900 card.\n'
|
|
add esp, 6
|
|
ret
|
|
|
|
;***************************************************************************
|
|
;
|
|
; int_handler
|
|
;
|
|
; handles received IRQs, which signal received packets
|
|
;
|
|
; Currently only supports one descriptor per packet, if packet is fragmented
|
|
; between multiple descriptors you will lose part of the packet
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
int_handler:
|
|
; find pointer of device which made IRQ occur
|
|
mov esi, device_list
|
|
mov ecx, [devices]
|
|
test ecx, ecx
|
|
jz .nothing
|
|
.nextdevice:
|
|
mov ebx, [esi]
|
|
set_io 0
|
|
set_io isr
|
|
in eax, dx ; note that this clears all interrupts
|
|
test ax, IE
|
|
jnz .got_it
|
|
loop .nextdevice
|
|
.nothing:
|
|
ret
|
|
.got_it:
|
|
|
|
test ax, RxOK
|
|
jz .no_rx
|
|
|
|
push ax
|
|
|
|
;-----------
|
|
; Get Status
|
|
movzx eax, [device.cur_rx] ; find current discriptor
|
|
shl eax, 4 ; * 16
|
|
mov ecx, dword[device.rxd+eax+4] ; get receive status
|
|
|
|
;-------------------------------------------
|
|
; Check RX_Status to see if packet is waiting
|
|
test ecx, 0x80000000
|
|
jnz .is_packet
|
|
ret
|
|
|
|
;----------------------------------------------
|
|
; There is a packet waiting check it for errors
|
|
.is_packet:
|
|
test ecx, 0x67C0000 ; see if there are any errors
|
|
jnz .error_status
|
|
|
|
;---------------------
|
|
; Check size of packet
|
|
and ecx, DSIZE ; get packet size minus CRC
|
|
sub ecx, CRC_SIZE ; make sure packet contains data
|
|
jle .error_size
|
|
|
|
; update statistics
|
|
inc dword [device.packets_rx]
|
|
add dword [device.bytes_rx], ecx
|
|
adc dword [device.bytes_rx+4], 0
|
|
|
|
push ebx
|
|
push .return
|
|
push ecx ; packet size
|
|
push [device.rxd+eax+12] ; packet ptr
|
|
DEBUGF 1, "Packet received OK\n"
|
|
jmp EthReceiver
|
|
.return:
|
|
pop ebx
|
|
|
|
; Reset status, allow ethernet card access to descriptor
|
|
movzx ecx, [device.cur_rx]
|
|
shl ecx, 4 ; *16
|
|
mov ecx, [device.rxd+ecx]
|
|
stdcall KernelAlloc, RX_BUFF_SZ
|
|
test eax, eax
|
|
jz .fail
|
|
mov dword [ecx+12], eax
|
|
GetRealAddr
|
|
mov dword [ecx+8], eax
|
|
mov dword [ecx+4], RX_BUFF_SZ
|
|
|
|
inc [device.cur_rx] ; get next descriptor
|
|
and [device.cur_rx], NUM_RX_DESC-1 ; only 4 descriptors 0-3
|
|
|
|
; Enable Receiver
|
|
set_io 0
|
|
set_io cr ; Command Register offset
|
|
in eax, dx ; Get current Command Register
|
|
or eax, RxENA ; Enable Receiver
|
|
out dx, eax
|
|
|
|
pop ax
|
|
jmp .no_rx
|
|
|
|
.error_status:
|
|
|
|
DEBUGF 1, "Packet error: %x\n", ecx
|
|
jmp .continue
|
|
|
|
.error_size:
|
|
|
|
DEBUGF 1, "Packet too large/small\n"
|
|
jmp .continue
|
|
|
|
.no_rx:
|
|
test ax, TxOk
|
|
jz .no_tx
|
|
|
|
;;; TODO: free all unused buffers
|
|
stdcall KernelFree, eax
|
|
|
|
.no_tx:
|
|
|
|
ret
|
|
|
|
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; transmit
|
|
; Description
|
|
; Transmits a packet of data via the ethernet card
|
|
; buffer pointer in [esp+4]
|
|
; size of buffer in [esp+8]
|
|
; pointer to device structure in ebx
|
|
;
|
|
; only one transmit descriptor is used
|
|
;
|
|
;***************************************************************************
|
|
align 4
|
|
transmit:
|
|
|
|
cmp dword [esp+8], MAX_ETH_FRAME_SIZE
|
|
jg transmit_finish
|
|
|
|
cmp dword [esp+8], 60
|
|
jl transmit_finish
|
|
|
|
movzx ecx, [device.cur_tx]
|
|
mov ecx, [device.txd+ecx*16]
|
|
|
|
;; TODO: check if desc is empty (for example: check for eax, 0x6200000 at [ecx+4]
|
|
;;; or: count number of available descriptors
|
|
|
|
mov eax, [esp+4]
|
|
mov dword [ecx + 12], eax
|
|
GetRealAddr
|
|
mov dword [ecx + 8], eax
|
|
|
|
mov eax, [esp+8]
|
|
and eax, DSIZE
|
|
or eax, 0x80000000 ; card owns descriptor
|
|
mov dword [ecx + 4], eax
|
|
|
|
; update stats
|
|
inc [device.packets_tx]
|
|
add dword [device.bytes_tx], ecx
|
|
adc dword [device.bytes_tx+4], 0
|
|
|
|
ret 8
|
|
|
|
|
|
; End of code
|
|
|
|
align 4 ; Place all initialised data here
|
|
|
|
devices dd 0
|
|
|
|
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,get_mac_addr,0
|
|
dd 0 ; end of list
|
|
|
|
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF)
|
|
my_service db 'SIS900',0 ; max 16 chars include zero
|
|
|
|
include_debug_strings ; All data wich FDO uses will be included here
|
|
|
|
section '.data' data readable writable align 16; place all uninitialized data place here
|
|
|
|
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling
|
|
|