kolibrios-fun/drivers/ethernet/sis900.asm

1261 lines
40 KiB
NASM
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. 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 PE DLL native
entry START
CURRENT_API = 0x0200
COMPATIBLE_API = 0x0100
API_VERSION = (COMPATIBLE_API shl 16) + CURRENT_API
NUM_RX_DESC = 4 ; Number of RX descriptors
NUM_TX_DESC = 4 ; Number of TX descriptors
RX_BUFF_SZ = 1520 ; Buffer size for each Rx buffer
MAX_DEVICES = 16
__DEBUG__ = 1
__DEBUG_LEVEL__ = 2 ; 1 = verbose, 2 = errors only
DSIZE = 0x00000fff
CRC_SIZE = 4
RFADDR_shift = 16
; If you are having problems sending/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
RX_DMA = 0x00600000
TX_DMA = 0x00600000
;-------------------------------------------------------------------------------------------------
; Symbolic offsets to registers.
cr = 0x0 ; Command Register
cfg = 0x4 ; Configuration Register
mear = 0x8 ; EEPROM Access Register
ptscr = 0xc ; PCI Test Control Register
isr = 0x10 ; Interrupt Status Register
imr = 0x14 ; Interrupt Mask Register
ier = 0x18 ; Interrupt Enable Register
epar = 0x18 ; Enhanced PHY Access Register
txdp = 0x20 ; Transmit Descriptor Pointer Register
txcfg = 0x24 ; Transmit Configuration Register
rxdp = 0x30 ; Receive Descriptor Pointer Register
rxcfg = 0x34 ; Receive Configuration Register
flctrl = 0x38 ; Flow Control Register
rxlen = 0x3c ; Receive Packet Length Register
rfcr = 0x48 ; Receive Filter Control Register
rfdr = 0x4C ; Receive Filter Data Register
pmctrl = 0xB0 ; Power Management Control Register
pmer = 0xB4 ; Power Management Wake-up Event Register
; Command Register Bits
RELOAD = 0x00000400
ACCESSMODE = 0x00000200
RESET = 0x00000100
SWI = 0x00000080
RxRESET = 0x00000020
TxRESET = 0x00000010
RxDIS = 0x00000008
RxENA = 0x00000004
TxDIS = 0x00000002
TxENA = 0x00000001
; Configuration Register Bits
DESCRFMT = 0x00000100 ; 7016 specific
REQALG = 0x00000080
SB = 0x00000040
POW = 0x00000020
EXD = 0x00000010
PESEL = 0x00000008
LPM = 0x00000004
BEM = 0x00000001
RND_CNT = 0x00000400
FAIR_BACKOFF = 0x00000200
EDB_MASTER_EN = 0x00002000
; Eeprom Access Reigster Bits
MDC = 0x00000040
MDDIR = 0x00000020
MDIO = 0x00000010 ; 7016 specific
EECS = 0x00000008
EECLK = 0x00000004
EEDO = 0x00000002
EEDI = 0x00000001
; TX Configuration Register Bits
ATP = 0x10000000 ; Automatic Transmit Padding
MLB = 0x20000000 ; Mac Loopback Enable
HBI = 0x40000000 ; HeartBeat Ignore (Req for full-dup)
CSI = 0x80000000 ; CarrierSenseIgnore (Req for full-du
; RX Configuration Register Bits
AJAB = 0x08000000 ;
ATX = 0x10000000 ; Accept Transmit Packets
ARP = 0x40000000 ; accept runt packets (<64bytes)
AEP = 0x80000000 ; accept error packets
; Interrupt Register Bits
WKEVT = 0x10000000
TxPAUSEEND = 0x08000000
TxPAUSE = 0x04000000
TxRCMP = 0x02000000 ; Transmit Reset Complete
RxRCMP = 0x01000000 ; Receive Reset Complete
DPERR = 0x00800000
SSERR = 0x00400000
RMABT = 0x00200000
RTABT = 0x00100000
RxSOVR = 0x00010000
HIBERR = 0x00008000
SWINT = 0x00001000
MIBINT = 0x00000800
TxURN = 0x00000400
TxIDLE = 0x00000200
TxERR = 0x00000100
TxDESC = 0x00000080
TxOK = 0x00000040
RxORN = 0x00000020
RxIDLE = 0x00000010
RxEARLY = 0x00000008
RxERR = 0x00000004
RxDESC = 0x00000002
RxOK = 0x00000001
; Interrupt Enable Register Bits
IE = RxOK + TxOK
; Revision ID
SIS900B_900_REV = 0x03
SIS630A_900_REV = 0x80
SIS630E_900_REV = 0x81
SIS630S_900_REV = 0x82
SIS630EA1_900_REV = 0x83
SIS630ET_900_REV = 0x84
SIS635A_900_REV = 0x90
SIS900_960_REV = 0x91
; Receive Filter Control Register Bits
RFEN = 0x80000000 ; enable
RFAAB = 0x40000000 ; accept all broadcasts
RFAAM = 0x20000000 ; accept all multicasts
RFAAP = 0x10000000 ; accept all packets
; Reveive Filter Data Mask
RFDAT = 0x0000FFFF
; Eeprom Address
EEPROMSignature = 0x00
EEPROMVendorID = 0x02
EEPROMDeviceID = 0x03
EEPROMMACAddr = 0x08
EEPROMChecksum = 0x0b
; The EEPROM commands include the alway-set leading bit.
EEread = 0x0180
EEwrite = 0x0140
EEerase = 0x01C0
EEwriteEnable = 0x0130
EEwriteDisable = 0x0100
EEeraseAll = 0x0120
EEwriteAll = 0x0110
EEaddrMask = 0x013F
EEcmdShift = 16
; For SiS962 or SiS963, request the eeprom software access
EEREQ = 0x00000400
EEDONE = 0x00000200
EEGNT = 0x00000100
section '.flat' readable writable executable
include '../proc32.inc'
include '../struct.inc'
include '../macros.inc'
include '../fdo.inc'
include '../netdrv.inc'
struct device ETH_DEVICE
io_addr dd ?
pci_bus dd ?
pci_dev dd ?
irq_line db ?
cur_rx db ?
cur_tx db ?
last_tx db ?
pci_revision db ?
table_entries db ?
rb 0x100 - ($ and 0xff) ; align 256
txd rd (4 * NUM_TX_DESC)
rxd rd (4 * NUM_RX_DESC)
ends
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
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; proc START ;;
;; ;;
;; (standard driver proc) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Driver entry point - register our service when the driver is loading.
; TODO: add needed operations when unloading
proc START c, reason:dword, cmdline:dword
cmp [reason], DRV_ENTRY
jne .fail
DEBUGF 2,"Loading driver\n"
invoke RegService, my_service, service_proc
ret
.fail:
xor eax, eax
ret
endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; proc SERVICE_PROC ;;
;; ;;
;; (standard driver proc) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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, [edx + 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 [edx + IOCTL.out_size], 4
jb .fail
; 3b. Write result to the output buffer.
mov eax, [edx + 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 [edx + IOCTL.inp_size], 3
jb .fail
; 4b. First byte of input is bus type, 1 stands for PCI.
mov eax, [edx + 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, [edx + IOCTL.input] ; get the pci bus and device numbers
mov ax, [eax+1] ;
.nextdevice:
mov ebx, [esi]
cmp al, byte[ebx + device.pci_bus]
jne @f
cmp ah, byte[ebx + device.pci_dev]
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
jae .fail
; 4g. Allocate memory for device descriptor and receive+transmit buffers.
; 4h. Zero the structure.
allocate_and_clear ebx, sizeof.device, .fail
; 4i. Save PCI coordinates
mov eax, [edx + IOCTL.input]
movzx ecx, byte[eax+1]
mov [ebx + device.pci_bus], ecx
movzx ecx, byte[eax+2]
mov [ebx + device.pci_dev], ecx
; 4j. Fill in the direct call addresses into the struct.
mov [ebx + device.reset], reset
mov [ebx + device.transmit], transmit
mov [ebx + device.unload], unload
mov [ebx + 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
stdcall PCI_find_io, [ebx + device.pci_bus], [ebx + device.pci_dev]
mov [ebx + device.io_addr], eax
; We've found the io address, find IRQ now
invoke PciRead8, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.interrupt_line
mov [ebx + device.irq_line], al
; 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 [ebx + device.type], NET_TYPE_ETH
invoke 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:
invoke 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:
invoke 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
;***************************************************************************
;
; probe
;
; checks the card and enables it
;
; TODO: probe mii transceivers
;
;***************************************************************************
align 4
probe:
DEBUGF 1, "Probe\n"
; wake up device
; TODO: check capabilities pointer instead of using hardcoded offset.
invoke PciWrite8, [ebx + device.pci_bus], [ebx + device.pci_dev], 0x40, 0
; Make the device a bus master
invoke PciRead32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.command
or al, PCI_CMD_MASTER
invoke PciWrite32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.command, eax
; Adjust PCI latency to be at least 64
invoke PciRead8, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.max_latency
cmp al, 64
jae @f
mov al, 64
invoke PciWrite8, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.max_latency, eax
@@:
; Get Card Revision
invoke PciRead8, [ebx + device.pci_bus], [ebx + device.pci_dev], 0x08
mov [ebx + device.pci_revision], al ; save the revision for later use
; Look up through the specific_table
mov esi, specific_table
.tableloop:
cmp dword[esi], 0 ; Check if we reached end of the list
je .notsupported
cmp al, [esi] ; Check if revision is OK
je .ok
add esi, 12 ; Advance to next entry
jmp .tableloop
.ok:
call dword[esi + 4] ; "get MAC" function
; Set table entries
mov [ebx + device.table_entries], 16
cmp [ebx + device.pci_revision], SIS635A_900_REV
jae @f
cmp [ebx + device.pci_revision], SIS900B_900_REV
je @f
mov [ebx + device.table_entries], 8
@@:
; TODO: Probe for mii transceiver
jmp reset
.notsupported:
DEBUGF 2, "Device not supported\n"
or eax, -1
ret
reset:
DEBUGF 1, "reset\n"
movzx eax, [ebx + device.irq_line]
invoke AttachIntHandler, eax, int_handler, ebx
test eax, eax
jnz @f
DEBUGF 2,"Could not attach int handler!\n"
or eax, -1
ret
@@:
;--------------------------------------------
; Disable Interrupts and reset Receive Filter
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], ier
xor eax, eax
out dx, eax
set_io [ebx + device.io_addr], imr
out dx, eax
set_io [ebx + device.io_addr], rfcr
out dx, eax
;-----------
; Reset Card
set_io [ebx + device.io_addr], 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 [ebx + device.io_addr], isr
mov ecx, 1000
.loop:
dec ecx
jz .fail
in eax, dx ; read interrupt status
test eax, TxRCMP + RxRCMP
jz .loop
DEBUGF 1, "status=%x\n", eax
;------------------------------------------------------
; Set Configuration Register depending on Card Revision
set_io [ebx + device.io_addr], cfg
mov eax, PESEL ; Configuration Register Bit
cmp [ebx + device.pci_revision], SIS635A_900_REV
je .match
cmp [ebx + device.pci_revision], SIS900B_900_REV ; Check card revision
jne .done
.match: ; Revision match
or eax, RND_CNT ; Configuration Register Bit
.done:
out dx, eax
DEBUGF 1, "Initialising RX Filter\n"
; Get Receive Filter Control Register
set_io [ebx + device.io_addr], 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
.macloop:
mov eax, ecx
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], rfcr
shl eax, 16 ; high word of eax tells card which mac byte to write
out dx, eax ;
set_io [ebx + device.io_addr], rfdr
mov ax, word [ebx + 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 .macloop
; enable packet filtering
pop eax ; old register value
set_io [ebx + device.io_addr], rfcr
or eax, RFEN ; enable filtering
out dx, eax ; set register
DEBUGF 1, "Initialising TX Descriptors\n"
mov ecx, NUM_TX_DESC
lea esi, [ebx + device.txd]
.txdescloop:
lea eax, [esi + 16] ; next ptr
invoke GetPhysAddr
mov dword[esi], eax ; link to next desc
mov dword[esi + 4], 0 ; status field
mov dword[esi + 8], 0 ; ptr to buffer
add esi, 16
dec ecx
jnz .txdescloop
lea eax, [ebx + device.txd]
invoke GetPhysAddr
mov dword[esi - 16], eax ; correct last descriptor link ptr
set_io [ebx + device.io_addr], txdp ; TX Descriptor Pointer
; lea eax, [ebx + device.txd]
; invoke GetPhysAddr
out dx, eax
mov [ebx + device.cur_tx], 0 ; Set current tx descriptor to 0
mov [ebx + device.last_tx], 0
DEBUGF 1, "Initialising RX Descriptors\n"
mov ecx, NUM_RX_DESC
lea esi, [ebx + device.rxd]
.rxdescloop:
lea eax, [esi + 16] ; next ptr
invoke GetPhysAddr
mov dword [esi], eax
mov dword [esi + 4], RX_BUFF_SZ ; size
push ecx esi
invoke KernelAlloc, RX_BUFF_SZ
pop esi ecx
test eax, eax
jz .fail
mov dword [esi + 12], eax ; address
invoke GetPhysAddr
mov dword [esi + 8], eax ; real address
add esi, 16
dec ecx
jnz .rxdescloop
lea eax, [ebx + device.rxd]
invoke GetPhysAddr
mov dword [esi - 16], eax ; correct last descriptor link ptr
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], rxdp
; lea eax, [ebx + device.rxd]
; invoke GetPhysAddr
out dx, eax
mov [ebx + device.cur_rx], 0 ; Set current rx descriptor to 0
DEBUGF 1, "setting RX mode\n"
xor cl, cl
.rxfilterloop:
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], 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 [ebx + device.io_addr], 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, [ebx + device.table_entries]
jb .rxfilterloop
set_io [ebx + device.io_addr], rfcr ; Receive Filter Control Register offset
mov eax, RFAAB + RFAAM + RFAAP + RFEN
out dx, eax
set_io [ebx + device.io_addr], rxcfg ; Receive Config Register offset
mov eax, ATX + RX_DMA + 2 ; 0x2 : RX Drain Threshold = 8*8=64 bytes
out dx, eax
DEBUGF 1, "setting TX mode\n"
set_io [ebx + device.io_addr], txcfg ; Transmit config Register offset
mov eax, ATP + HBI + CSI + TX_DMA + 0x120 ; TX Fill threshold = 0x100
; TX Drain Threshold = 0x20
out dx, eax
DEBUGF 1, "Enabling interrupts\n"
set_io [ebx + device.io_addr], imr
mov eax, IE ; Interrupt enable mask
out dx, eax
set_io [ebx + device.io_addr], cr
in eax, dx
or eax, RxENA ; Enable Receive
out dx, eax
set_io [ebx + device.io_addr], ier ; Interrupt enable
mov eax, 1
out dx, eax
mov [ebx + device.mtu], 1514
; Set link state to unknown
mov [ebx + device.state], ETH_LINK_UNKNOWN
xor eax, eax
ret
.fail:
DEBUGF 2, "Resetting device failed\n"
or eax, -1
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:
DEBUGF 1, "SIS960 - get mac:\n"
;-------------------------------
; Send Request for eeprom access
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], 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 2, "Access to EEprom failed!\n", 0
set_io [ebx + device.io_addr], 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 [ebx + 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 1,"%x-%x-%x-%x-%x-%x\n",\
[ebx + device.mac]:2,[ebx + device.mac+1]:2,[ebx + device.mac+2]:2,[ebx + device.mac+3]:2,[ebx + device.mac+4]:2,[ebx + device.mac+5]:2
;-------------------------------------
; Tell EEPROM We are Done Accessing It
.done:
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], 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
SIS900_get_mac_addr:
DEBUGF 1, "SIS900 - get mac:\n"
;------------------------------------
; 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 [ebx + device.mac+ecx*2], ax ; save 16 bits to the MAC ID storage
dec ecx ; one less word to read
jns .loop ; if more read more
DEBUGF 1,"%x-%x-%x-%x-%x-%x\n",\
[ebx + device.mac]:2,[ebx + device.mac+1]:2,[ebx + device.mac+2]:2,[ebx + device.mac+3]:2,[ebx + device.mac+4]:2,[ebx + 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:
DEBUGF 1, "SIS635 - get mac:\n"
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], rfcr
in eax, dx
mov esi, eax
set_io [ebx + device.io_addr], cr
or eax, RELOAD
out dx, eax
xor eax, eax
out dx, eax
;-----------------------------------------------
; Disable packet filtering before setting filter
set_io [ebx + device.io_addr], rfcr
mov eax, esi
and eax, not RFEN
out dx, eax
;---------------------------------
; Load MAC to filter data register
xor ecx, ecx
lea edi, [ebx + device.mac]
.loop:
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], rfcr
mov eax, ecx
shl eax, RFADDR_shift
out dx, eax
set_io [ebx + device.io_addr], rfdr
in ax, dx
stosw
inc ecx
cmp ecx, 3
jb .loop
;------------------------
; Enable packet filtering
set_io [ebx + device.io_addr], rfcr
mov eax, esi
or eax, RFEN
out dx, eax
DEBUGF 1,"%x-%x-%x-%x-%x-%x\n",\
[ebx + device.mac]:2,[ebx + device.mac+1]:2,[ebx + device.mac+2]:2,[ebx + device.mac+3]:2,[ebx + device.mac+4]:2,[ebx + device.mac+5]:2
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 [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], 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 2,'Setting MAC is not supported for SIS900 card.\n'
add esp, 6
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
;
;***************************************************************************
align 4
proc transmit stdcall bufferptr, buffersize
pushf
cli
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [buffersize]
mov eax, [bufferptr]
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
[eax+13]:2,[eax+12]:2
cmp [buffersize], 1514
ja .fail
cmp [buffersize], 60
jb .fail
movzx ecx, [ebx + device.cur_tx]
shl ecx, 4 ; *16
lea ecx, [ebx + device.txd + ecx]
test dword[ecx + 4], 0x80000000 ; card owns descriptor ?
jnz .fail
mov eax, [bufferptr]
mov dword[ecx + 12], eax
invoke GetPhysAddr
mov dword[ecx + 8], eax ; buffer address
mov eax, [buffersize]
and eax, DSIZE
or eax, 0x80000000 ; card owns descriptor
mov dword[ecx + 4], eax ; status field
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], cr
in eax, dx
or eax, TxENA ; Enable the transmit state machine
out dx, eax
inc [ebx + device.cur_tx]
and [ebx + device.cur_tx], NUM_TX_DESC-1
; update stats
mov ecx, [buffersize]
inc [ebx + device.packets_tx]
add dword [ebx + device.bytes_tx], ecx
adc dword [ebx + device.bytes_tx + 4], 0
DEBUGF 1,"Transmit OK\n"
popf
xor eax, eax
ret
.fail:
DEBUGF 2,"Transmit failed\n"
invoke KernelFree, [bufferptr]
popf
or eax, -1
ret
endp
;***************************************************************************
;
; 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:
push ebx esi edi
DEBUGF 1,"INT\n"
; find pointer of device which made IRQ occur
mov ecx, [devices]
test ecx, ecx
jz .nothing
mov esi, device_list
.nextdevice:
mov ebx, [esi]
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], isr
in eax, dx ; note that this clears all interrupts
test ax, IE
jnz .got_it
.continue:
add esi, 4
dec ecx
jnz .nextdevice
.nothing:
pop edi esi ebx
xor eax, eax
ret
.got_it:
DEBUGF 1,"Device: %x Status: %x\n", ebx, ax
test ax, RxOK
jz .no_rx_
push ax
.rx_loop:
;-----------
; Get Status
movzx eax, [ebx + device.cur_rx] ; find current descriptor
shl eax, 4 ; * 16
mov ecx, dword[ebx + device.rxd + eax + 4] ; get receive status
;-------------------------------------------
; Check RX_Status to see if packet is waiting
test ecx, 0x80000000
jz .no_rx
;----------------------------------------------
; There is a packet waiting check it for errors
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
jbe .error_size
; update statistics
inc dword [ebx + device.packets_rx]
add dword [ebx + device.bytes_rx], ecx
adc dword [ebx + device.bytes_rx + 4], 0
push ebx
push .return
push ecx ; packet size
pushd [ebx + device.rxd + eax + 12] ; packet ptr
DEBUGF 1, "Packet received OK\n"
jmp [Eth_input]
.return:
pop ebx
; Reset status, allow ethernet card access to descriptor
invoke KernelAlloc, RX_BUFF_SZ
test eax, eax
jz .fail
movzx ecx, [ebx + device.cur_rx]
shl ecx, 4 ; *16
lea ecx, [ebx + device.rxd + ecx]
mov dword [ecx + 12], eax
invoke GetPhysAddr
mov dword [ecx + 8], eax
mov dword [ecx + 4], RX_BUFF_SZ
inc [ebx + device.cur_rx] ; get next descriptor
and [ebx + device.cur_rx], NUM_RX_DESC-1 ; only 4 descriptors 0-3
jmp .rx_loop
.no_rx:
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], cr
in eax, dx
or eax, RxENA ; Re-Enable the Receive state machine
out dx, eax
pop ax
.no_rx_:
test ax, TxOK
jz .no_tx
DEBUGF 1, "TX ok!\n"
.tx_loop:
movzx ecx, [ebx + device.last_tx]
shl ecx, 4 ; *16
lea ecx, [ebx + device.txd + ecx]
test dword[ecx + 4], 0x80000000 ; card owns descr
jnz .no_tx
cmp dword[ecx + 12], 0
je .no_tx
DEBUGF 1, "Freeing packet = %x\n", [ecx + 12]:8
push dword[ecx + 12]
mov dword[ecx + 12], 0
invoke KernelFree
inc [ebx + device.last_tx]
and [ebx + device.last_tx], NUM_TX_DESC-1
jmp .tx_loop
.no_tx:
.fail:
pop edi esi ebx
xor eax, eax
inc eax
ret
ret
.error_status:
DEBUGF 2, "Packet error: %x\n", ecx
jmp .fail
.error_size:
DEBUGF 2, "Packet too large/small\n"
jmp .fail
; End of code
data fixups
end data
include '../peimport.inc'
my_service db 'SIS900',0 ; max 16 chars include zero
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 ; end of list
include_debug_strings ; All data wich FDO uses will be included here
align 4
devices dd 0
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling