1,6 → 1,6 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; 3Com network driver for KolibriOS ;; |
90,15 → 90,20 |
COMPATIBLE_API = 0x0100 |
API_VERSION = (COMPATIBLE_API shl 16) + CURRENT_API |
|
MAX_DEVICES = 16 |
; configureable area |
|
MAX_DEVICES = 16 ; Maximum number of devices this driver may handle |
|
FORCE_FD = 0 ; forcing full duplex mode makes sense at some cards and link types |
|
NUM_RX_DESC = 4 ; a power of 2 number |
NUM_TX_DESC = 4 ; a power of 2 number |
NUM_RX_DESC = 32 ; Number of receive descriptors (must be power of 2) |
NUM_TX_DESC = 16 ; Number of transmit descriptors (must be power of 2) |
|
__DEBUG__ = 1 |
__DEBUG__ = 1 ; 1 = on, 0 = off |
__DEBUG_LEVEL__ = 2 ; 1 = verbose, 2 = errors only |
|
; end configureable area |
|
section '.flat' readable writable executable |
|
include '../proc32.inc' |
107,6 → 112,17 |
include '../fdo.inc' |
include '../netdrv.inc' |
|
|
if (bsr NUM_RX_DESC)>(bsf NUM_RX_DESC) |
display 'NUM_RX_DESC must be a power of two' |
err |
end if |
|
if (bsr NUM_TX_DESC)>(bsf NUM_TX_DESC) |
display 'NUM_TX_DESC must be a power of two' |
err |
end if |
|
; Registers |
REG_POWER_MGMT_CTRL = 0x7c |
REG_UP_LIST_PTR = 0x38 |
402,11 → 418,11 |
|
; check if the device is already listed |
|
mov ecx, [vortex_devices] |
mov ecx, [devices] |
test ecx, ecx |
jz .maybeboomerang |
jz .firstdevice |
|
mov esi, vortex_list |
mov esi, device_list |
mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
419,31 → 435,9 |
add esi, 4 |
loop .nextdevice |
|
|
.maybeboomerang: |
mov ecx, [boomerang_devices] |
test ecx, ecx |
jz .firstdevice |
|
mov esi, boomerang_list |
mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers |
mov ax, [eax+1] ; |
.nextdevice2: |
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 .nextdevice2 |
|
|
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
mov ecx, [boomerang_devices] |
add ecx, [vortex_devices] |
cmp ecx, MAX_DEVICES ; First check if the driver can handle one more card |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
|
allocate_and_clear ebx, sizeof.device, .fail ; Allocate the buffer for device structure |
481,15 → 475,10 |
test eax, eax |
jnz .err ; If an error occured, exit |
|
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; |
inc [devices] ; |
|
movzx ecx, [ebx + device.ver_id] |
test word [hw_versions+2+ecx*4], IS_VORTEX |
jz .not_vortex |
|
mov eax, [vortex_devices] ; Add the device structure to our device list |
mov [vortex_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [vortex_devices] ; |
|
.register: |
mov [ebx + device.type], NET_TYPE_ETH |
invoke NetRegDev |
500,13 → 489,6 |
call start_device |
ret |
|
.not_vortex: |
mov eax, [boomerang_devices] ; Add the device structure to our device list |
mov [boomerang_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [boomerang_devices] |
|
jmp .register |
|
; If the device was already loaded, find the device number and return it in eax |
|
.find_devicenum: |
697,13 → 679,19 |
; or al, 0x14 |
out dx, ax |
; wait for GlobalReset to complete |
mov ecx, 64000 |
mov ecx, 2000 |
.rsloop: |
in ax , dx |
test ah , 10000b ; CmdInProgress |
|
pusha |
mov esi, 1 |
invoke Sleep |
popa |
|
loopz .rsloop |
|
DEBUGF 1,"Waiting for nic to boot..\n" |
DEBUGF 1,"Waiting for NIC to boot..\n" |
; wait for 2 seconds for NIC to boot |
mov esi, 2000 ; WTF? FIXME |
invoke Sleep ; 2 seconds |
1140,38 → 1128,36 |
|
mov al, MII_BMCR |
push eax |
call mdio_read ; returns with window #4 |
or ah, 0x80 ; software reset |
call mdio_read |
or ax, BMCR_RESET |
mov esi, eax |
mov eax, [esp] |
call mdio_write ; returns with window #4 |
call mdio_write |
|
; wait for reset to complete |
mov esi, 2000 |
invoke Sleep ; 2s FIXME |
|
mov eax, [esp] |
call mdio_read ; returns with window #4 |
test ah, 0x80 |
mov al, MII_BMCR |
call mdio_read |
test ax, BMCR_RESET |
jnz .fail1 |
mov eax, [esp] |
|
; wait for a while after reset |
mov esi, 20 |
invoke Sleep ; 20ms |
|
mov eax, [esp] |
mov al , MII_BMSR |
call mdio_read ; returns with window #4 |
test al, 1 ; extended capability supported? |
call mdio_read |
test al, BMSR_ERCAP |
jz .fail2 |
DEBUGF 1,"Extended capability supported\n" |
|
; auto-neg capable? |
test al , 1000b |
jz .fail2 ; not auto-negotiation capable |
test al, BMSR_ANEGCAPABLE |
jz .fail2 |
DEBUGF 1,"Auto-negotiation capable\n" |
|
; auto-neg complete? |
test al , 100000b |
test al, BMSR_ANEGCOMPLETE |
jnz .auto_neg_ok |
DEBUGF 1,"Restarting auto-negotiation\n" |
|
1180,7 → 1166,7 |
mov al, MII_ADVERTISE |
push eax |
call mdio_read ; returns with window #4 |
or ax , 1111b shl 5; advertise only 10base-T and 100base-TX |
or ax, ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL |
mov esi, eax |
pop eax |
call mdio_write ; returns with window #4 |
1187,16 → 1173,18 |
mov eax, [esp] |
call mdio_read ; returns with window #4 |
mov esi, eax |
or bh , 10010b ; restart auto-negotiation |
or bx, BMCR_ANENABLE or BMCR_ANRESTART |
mov eax, [esp] |
call mdio_write ; returns with window #4 |
mov esi, 4000 |
invoke Sleep ; 4 seconds |
mov eax, [esp] |
|
mov al , MII_BMSR |
call mdio_read ; returns with window #4 |
test al , 100000b ; auto-neg complete? |
test al, BMSR_ANEGCOMPLETE |
jnz .auto_neg_ok |
|
jmp .fail3 |
.auto_neg_ok: |
DEBUGF 1,"Auto-negotiation complete\n" |
2137,15 → 2125,14 |
;; ;; |
;; Transmit (vortex) ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; pointer to device structure in ebx ;; |
;; In: pointer to device structure in ebx ;; |
;; Out: eax = 0 on success ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
align 16 |
proc vortex_transmit stdcall bufferptr |
|
pushf |
cli |
spin_lock_irqsave |
|
mov esi, [bufferptr] |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length] |
2156,9 → 2143,9 |
[eax+13]:2,[eax+12]:2 |
|
cmp [esi + NET_BUFF.length], 1514 |
ja .fail |
ja .error |
cmp [esi + NET_BUFF.length], 60 |
jb .fail |
jb .error |
|
call check_tx_status |
|
2172,7 → 2159,7 |
set_io [ebx + device.io_addr], REG_MASTER_STATUS |
in ax, dx |
test ah, 0x80 |
jnz .fail ; no DMA for sending |
jnz .overrun ; no DMA for sending |
|
; program frame address to be sent |
set_io [ebx + device.io_addr], REG_MASTER_ADDRESS |
2190,18 → 2177,35 |
set_io [ebx + device.io_addr], REG_COMMAND |
mov ax, (10100b shl 11) + 1 ; StartDMADown |
out dx, ax |
.finish: |
popf |
|
; Update stats |
inc [ebx + device.packets_tx] |
mov eax, [esi + NET_BUFF.length] |
add dword[ebx + device.bytes_tx], eax |
adc dword[ebx + device.bytes_tx + 4], 0 |
|
spin_unlock_irqrestore |
xor eax, eax |
ret |
|
.fail: |
DEBUGF 2,"Send failed\n" |
.error: |
DEBUGF 2, "TX packet error\n" |
inc [ebx + device.packets_tx_err] |
invoke NetFree, [bufferptr] |
popf |
|
spin_unlock_irqrestore |
or eax, -1 |
ret |
|
.overrun: |
DEBUGF 2, "TX overrun\n" |
inc [ebx + device.packets_tx_ovr] |
invoke NetFree, [bufferptr] |
|
spin_unlock_irqrestore |
or eax, -1 |
ret |
|
endp |
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2208,15 → 2212,14 |
;; ;; |
;; Transmit (boomerang) ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; pointer to device structure in ebx ;; |
;; In: pointer to device structure in ebx ;; |
;; Out: eax = 0 on success ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
align 16 |
proc boomerang_transmit stdcall bufferptr |
|
pushf |
cli |
spin_lock_irqsave |
|
mov esi, [bufferptr] |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length] |
2227,9 → 2230,9 |
[eax+13]:2,[eax+12]:2 |
|
cmp [esi + NET_BUFF.length], 1514 |
ja .fail |
ja .error |
cmp [esi + NET_BUFF.length], 60 |
jb .fail |
jb .error |
|
call check_tx_status ; Reset TX engine if needed |
|
2339,17 → 2342,35 |
|
.finish: |
mov [ebx + device.curr_tx], edi |
popf |
|
; Update stats |
inc [ebx + device.packets_tx] |
mov eax, [esi + NET_BUFF.length] |
add dword[ebx + device.bytes_tx], eax |
adc dword[ebx + device.bytes_tx + 4], 0 |
|
spin_unlock_irqrestore |
xor eax, eax |
ret |
|
.fail: |
DEBUGF 2,"Send failed\n" |
.error: |
DEBUGF 2, "TX packet error\n" |
inc [ebx + device.packets_tx_err] |
invoke NetFree, [bufferptr] |
popf |
|
spin_unlock_irqrestore |
or eax, -1 |
ret |
|
.overrun: |
DEBUGF 2, "TX overrun\n" |
inc [ebx + device.packets_tx_ovr] |
invoke NetFree, [bufferptr] |
|
spin_unlock_irqrestore |
or eax, -1 |
ret |
|
endp |
|
|
2448,24 → 2469,16 |
;; Vortex Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
align 4 |
align 16 |
int_vortex: |
|
push ebx esi edi |
|
DEBUGF 1,"INT\n" |
mov ebx, [esp+4*4] |
DEBUGF 1,"INT for 0x%x\n", ebx |
|
; find pointer of device wich made IRQ occur |
; TODO? if we are paranoid, we can check that the value from ebx is present in the current device_list |
|
mov ecx, [vortex_devices] |
test ecx, ecx |
jz .nothing |
mov esi, vortex_list |
.nextdevice: |
mov ebx, [esi] |
|
|
set_io [ebx + device.io_addr], 0 |
set_io [ebx + device.io_addr], REG_INT_STATUS |
in ax, dx |
2472,22 → 2485,8 |
and ax, S_5_INTS |
jnz .nothing |
|
add esi, 4 |
DEBUGF 1,"Status: %x\n", eax:4 |
|
test ax , ax |
jnz .got_it |
loop .nextdevice |
|
.nothing: |
pop edi esi ebx |
xor eax, eax |
|
ret |
|
.got_it: |
|
DEBUGF 1,"Device: %x Status: %x\n", ebx, eax:4 |
|
test ax, RxComplete |
jz .noRX |
|
2576,10 → 2575,7 |
out dx, ax |
|
.finish: |
|
|
.noRX: |
|
test ax, DMADone |
jz .noDMA |
|
2595,17 → 2591,11 |
out dx, ax |
|
.nodmaclear: |
|
pop ax |
|
DEBUGF 1, "DMA Done!\n", cx |
|
|
|
.noDMA: |
|
|
|
.ACK: |
set_io [ebx + device.io_addr], 0 |
set_io [ebx + device.io_addr], REG_COMMAND |
2613,52 → 2603,43 |
out dx, ax |
|
pop edi esi ebx |
xor eax, eax |
inc eax |
|
ret |
|
.nothing: |
pop edi esi ebx |
xor eax, eax |
|
ret |
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Boomerang Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
align 4 |
align 16 |
int_boomerang: |
|
push ebx esi edi |
|
DEBUGF 1,"INT\n" |
mov ebx, [esp+4*4] |
DEBUGF 1,"INT for 0x%x\n", ebx |
|
; find pointer of device wich made IRQ occur |
; TODO? if we are paranoid, we can check that the value from ebx is present in the current device_list |
|
mov ecx, [boomerang_devices] |
test ecx, ecx |
jz .nothing |
mov esi, boomerang_list |
.nextdevice: |
mov ebx, [esi] |
|
set_io [ebx + device.io_addr], 0 |
set_io [ebx + device.io_addr], REG_INT_STATUS |
in ax, dx |
test ax, S_5_INTS |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
pop edi esi ebx |
xor eax, eax |
|
ret |
|
jz .nothing |
.got_it: |
DEBUGF 1,"Status: %x\n", ax |
|
DEBUGF 1,"Device: %x Status: %x\n", ebx, ax |
push ax |
|
; disable all INTS |
2796,12 → 2777,20 |
out dx, ax |
|
pop edi esi ebx |
xor eax, eax |
inc eax |
|
ret |
|
.nothing: |
pop edi esi ebx |
xor eax, eax |
|
ret |
|
|
|
|
; End of code |
|
data fixups |
2919,10 → 2908,8 |
include_debug_strings ; All data wich FDO uses will be included here |
|
align 4 |
vortex_devices dd 0 |
boomerang_devices dd 0 |
vortex_list rd MAX_DEVICES |
boomerang_list rd MAX_DEVICES |
devices dd 0 |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
|
|
|