357,7 → 357,6 |
.has_hwcksm db ? |
.preamble db ? |
.dn_list_ptr_cleared db ? |
.self_directed_packet rb 20 |
|
.size = $ - device |
|
473,12 → 472,7 |
cmp ecx, MAX_DEVICES ; First check if the driver can handle one more card |
jge .fail |
|
push edx |
stdcall KernelAlloc, dword device.size ; Allocate the buffer for eth_device structure |
pop edx |
test eax, eax |
jz .fail |
mov ebx, eax ; ebx is always used as a pointer to the structure (in driver, but also in kernel code) |
allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure |
|
; Fill in the direct call addresses into the struct |
|
516,13 → 510,11 |
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 [device.type], NET_TYPE_ETH |
call NetRegDev |
|
529,17 → 521,15 |
cmp eax, -1 |
je .destroy |
|
call start |
|
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] |
|
call .register |
jmp .register |
|
; If the device was already loaded, find the device number and return it in eax |
|
741,9 → 731,9 |
|
call write_mac |
|
call rx_reset |
call tx_reset |
|
;<<<<<<<<<<<<<< |
|
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW + 1 |
out dx, ax |
768,6 → 758,14 |
call set_rx_mode |
call set_active_port |
|
;>>>>>>>>>> |
|
call create_rx_ring |
call rx_reset |
call tx_reset |
|
;>>>>>>>>>>>>>>>>>> |
|
set_io 0 |
set_io REG_COMMAND |
mov ax, RxEnable |
803,7 → 801,8 |
|
|
align 4 |
start: |
start_device: |
DEBUGF 1,"Starting the device\n" |
|
set_io 0 |
set_io REG_COMMAND |
822,12 → 821,13 |
set_io REG_MEDIA_STATUS |
mov ecx, 20 ; wait for max 2s |
.link_detect_loop: |
mov esi, 10 |
stdcall Sleep ; 100 ms |
mov esi, 100 |
call Sleep ; 100 ms |
in ax, dx |
test ah, 1000b ; linkDetect |
jnz @f |
loop .link_detect_loop |
DEBUGF 1,"Link detect timed-out!\n" |
@@: |
|
; print link type |
836,11 → 836,12 |
jz @f |
sub ax, 4 |
@@: |
|
mov esi, [link_str+eax*4] |
DEBUGF 1,"Established Link type: %s\n", esi |
|
; enable interrupts |
|
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW + 1 |
out dx, ax |
854,11 → 855,6 |
mov ax, SetIntrEnb + S_5_INTS |
out dx, ax |
|
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW + 1 |
|
|
ret |
|
|
870,6 → 866,8 |
align 4 |
set_rx_mode: |
|
DEBUGF 1,"Setting RX mode\n" |
|
set_io 0 |
set_io REG_COMMAND |
|
880,7 → 878,6 |
else |
mov ax, SetRxFilter + RxStation + RxBroadcast |
end if |
|
out dx, ax |
|
ret |
905,7 → 902,7 |
align 4 |
global_reset: |
|
DEBUGF 1,"Global reset: " |
DEBUGF 1,"Global reset..\n" |
|
; GlobalReset |
set_io 0 |
918,13 → 915,12 |
.loop: |
in ax , dx |
test ah , 10000b ; check CmdInProgress |
; jz .finish |
loopz .loop |
;.finish: |
; 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, 200 |
stdcall Sleep ; 2 seconds |
mov esi, 2000 |
call Sleep ; 2 seconds |
|
DEBUGF 1,"Ok!\n" |
|
990,9 → 986,24 |
.loop: |
in ax, dx |
test ah, 10000b ; check CmdInProgress |
jz .done |
dec ecx |
jnz .loop |
.done: |
|
lea eax, [device.upd_buffer] |
mov [device.curr_upd], eax |
GetRealAddr |
set_io 0 |
set_io REG_UP_LIST_PTR |
out dx, eax |
|
.rx_enable: |
ret |
|
|
align 4 |
create_rx_ring: |
; create upd ring |
lea eax, [device.upd_buffer] |
GetRealAddr |
1024,19 → 1035,10 |
dec ecx |
jnz .upd_loop |
|
lea eax, [device.upd_buffer] |
mov [device.curr_upd], eax |
GetRealAddr |
set_io 0 |
set_io REG_UP_LIST_PTR |
out dx, eax |
|
.rx_enable: |
ret |
|
|
|
|
;--------------------------------------------------------------------------- |
; Function |
; try_link_detect |
1058,8 → 1060,16 |
DEBUGF 1,"trying to detect link\n" |
|
; create self-directed packet |
stdcall KernelAlloc, 20 ; create a buffer for the self-directed packet |
test eax, eax |
jz .fail |
|
pushd 20 ; Packet parameters for device.transmit |
push eax ; |
|
mov edi, eax |
|
lea esi, [device.mac] |
lea edi, [device.self_directed_packet] |
movsw |
movsd |
sub esi, 6 |
1069,9 → 1079,6 |
stosw |
|
; download self-directed packet |
push 20 |
lea eax, [device.self_directed_packet] |
push eax |
call [device.transmit] |
|
; switch to register window 4 |
1098,6 → 1105,7 |
jmp .finish |
|
.link_detected: |
DEBUGF 1,"link detected!\n" |
setb al |
|
.finish: |
1107,8 → 1115,11 |
@@: |
ret |
|
.fail: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; try_phy |
1116,7 → 1127,7 |
; 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. |
; auto-negotiation devices, for instance the BCM5000. ; TODO: BCM5000 |
; Parameters |
; ah - PHY index |
; ebx - device stucture |
1131,7 → 1142,8 |
align 4 |
try_phy: |
|
DEBUGF 1,"trying phy\n" |
DEBUGF 1,"PHY=%u\n", ah |
DEBUGF 1,"Detecting if device is auto-negotiation capable\n" |
|
mov al, REG_MII_BMCR |
push eax |
1142,31 → 1154,35 |
call mdio_write ; returns with window #4 |
|
; wait for reset to complete |
mov esi, 200 |
mov esi, 2000 |
stdcall Sleep ; 2s |
mov eax, [esp] |
call mdio_read ; returns with window #4 |
test ah , 0x80 |
jnz .fail_finish |
jnz .fail1 |
mov eax, [esp] |
|
; wait for a while after reset |
mov esi, 2 |
mov esi, 20 |
stdcall Sleep ; 20ms |
mov eax, [esp] |
mov al , REG_MII_BMSR |
call mdio_read ; returns with window #4 |
test al , 1 ; extended capability supported? |
jz .no_ext_cap |
jz .fail2 |
|
; auto-neg capable? |
test al , 1000b |
jz .fail_finish ; not auto-negotiation capable |
jz .fail2 ; not auto-negotiation capable |
|
DEBUGF 1,"Device is auto-negotiation capable\n" |
|
; auto-neg complete? |
test al , 100000b |
jnz .auto_neg_ok |
|
DEBUGF 1,"Restarting auto-negotiation\n" |
|
; restart auto-negotiation |
mov eax, [esp] |
mov al , REG_MII_ANAR |
1182,7 → 1198,7 |
or bh , 10010b ; restart auto-negotiation |
mov eax, [esp] |
call mdio_write ; returns with window #4 |
mov esi, 400 |
mov esi, 4000 |
stdcall Sleep ; 4 seconds |
mov eax, [esp] |
mov al , REG_MII_BMSR |
1189,9 → 1205,11 |
call mdio_read ; returns with window #4 |
test al , 100000b ; auto-neg complete? |
jnz .auto_neg_ok |
jmp .fail_finish |
jmp .fail3 |
.auto_neg_ok: |
|
DEBUGF 1,"Auto-negotiation complete\n" |
|
; compare advertisement and link partner ability registers |
mov eax, [esp] |
mov al , REG_MII_ANAR |
1221,19 → 1239,32 |
jz .half_duplex |
or ax , 0x120 ; set full duplex and flow control |
.half_duplex: |
DEBUGF 1,"Using half-duplex\n" |
out dx , ax |
mov al , 1 |
ret |
.no_ext_cap: |
|
; not yet implemented BCM5000 |
.fail_finish: |
|
.fail1: |
DEBUGF 1,"reset failed!\n" |
pop eax |
xor al, al |
ret |
|
.fail2: |
DEBUGF 1,"This device is not auto-negotiation capable!\n" |
pop eax |
xor al, al |
ret |
|
.fail3: |
DEBUGF 1,"auto-negotiation reset failed!\n" |
pop eax |
xor al, al |
ret |
|
|
|
;*************************************************************************** |
; Function |
; try_mii |
1255,7 → 1286,7 |
align 4 |
try_mii: |
|
DEBUGF 1,"trying mii\n" |
DEBUGF 1,"trying to find MII PHY\n" |
|
; switch to register window 3 |
set_io 0 |
1267,11 → 1298,13 |
and eax, (1111b shl 20) |
cmp eax, (1000b shl 20) ; is auto-negotiation set? |
jne .mii_device |
; auto-negotiation is set |
|
DEBUGF 1,"auto-negotiation is set\n" |
; switch to register window 4 |
set_io REG_COMMAND |
mov ax , 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 |
1278,26 → 1311,33 |
call try_phy |
test al , al |
jz .fail_finish |
|
mov cl , 24 |
jmp .check_preamble |
|
.mii_device: |
cmp eax, (0110b shl 20) |
jne .fail_finish |
|
set_io 0 |
set_io REG_COMMAND |
mov ax , SELECT_REGISTER_WINDOW+4 |
out dx , ax |
|
set_io REG_PHYSICAL_MGMT |
in ax , dx |
and al , (1 shl BIT_MGMT_DIR) or (1 shl BIT_MGMT_DATA) |
cmp al , (1 shl BIT_MGMT_DATA) |
je .search_for_phy |
|
xor al , al |
ret |
|
.search_for_phy: |
; search for PHY |
mov cx , 31 |
.search_phy_loop: |
DEBUGF 1,"Searching the PHY\n" |
cmp cx , 24 |
je .next_phy |
mov ah , cl ; ah = phy |
1317,11 → 1357,14 |
jnz .check_preamble |
.next_phy: |
loopw .search_phy_loop |
|
.fail_finish: |
xor al, al |
ret |
|
; epilog |
.check_preamble: |
DEBUGF 1,"Using PHY: %u\nChecking PreAmble\n", cl |
push eax ; eax contains the return value of try_phy |
; check hard coded preamble forcing |
movzx eax, [device.ver_id] |
1328,6 → 1371,7 |
test word [eax*4+hw_versions+2], EXTRA_PREAMBLE |
setnz [device.preamble] ; force preamble |
jnz .finish |
|
; check mii for preamble suppression |
mov ah, cl |
mov al, REG_MII_BMSR |
1334,6 → 1378,7 |
call mdio_read |
test al, 1000000b ; preamble suppression? |
setz [device.preamble] ; no |
|
.finish: |
pop eax |
ret |
1384,9 → 1429,16 |
call rx_reset |
call tx_reset |
|
; download a self-directed test packet |
; create self-directed packet |
stdcall KernelAlloc, 20 ; create a buffer for the self-directed packet |
test eax, eax |
jz .fail |
|
pushd 20 ; Packet parameters for device.transmit |
push eax ; |
|
mov edi, eax |
lea esi, [device.mac] |
lea edi, [device.self_directed_packet] |
movsw |
movsd |
sub esi, 6 |
1395,14 → 1447,12 |
mov ax , 0x0608 |
stosw |
|
push 20 |
lea eax, [device.self_directed_packet] |
push eax |
; download self-directed packet |
call [device.transmit] |
|
; wait for 2s |
mov esi, 200 |
stdcall Sleep ; 2s |
mov esi, 2000 |
call Sleep |
|
; check if self-directed packet is received |
mov eax, [device.packets_rx] |
1420,6 → 1470,7 |
in ax , dx |
and ax , not 0x120 |
out dx , ax |
.fail: |
xor eax, eax |
|
.finish: |
1468,6 → 1519,7 |
mov ax, (10b shl 11) ; EnableDcConverter |
out dx, ax |
.complete_loopback: |
|
mov cx, 2 ; give a port 3 chances to complete a loopback |
.next_try: |
push ecx |
1475,10 → 1527,12 |
pop ecx |
test eax, eax |
loopzw .next_try |
|
.finish: |
xchg eax, [esp] |
test al, al |
jz .aui_finish |
|
; issue DisableDcConverter command |
set_io 0 |
set_io REG_COMMAND |
1509,7 → 1563,7 |
align 4 |
set_active_port: |
|
DEBUGF 1,"Setting active port: " |
DEBUGF 1,"Trying to find the active port\n" |
|
; switch to register window 3 |
set_io 0 |
1516,6 → 1570,7 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
|
set_io REG_INTERNAL_CONFIG |
in eax, dx |
test eax, (1 shl 24) ; check if autoselect enable |
1538,14 → 1593,10 |
jz .mii_device |
DEBUGF 1,"Using auto negotiation\n" |
ret |
|
.mii_device: |
|
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
|
; check for off-chip mii device |
set_io REG_MEDIA_OPTIONS |
in ax, dx |
1561,13 → 1612,10 |
jz .base_fx |
DEBUGF 1,"Using off-chip mii device\n" |
ret |
|
.base_fx: |
|
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
; check for 100BASE-FX |
set_io REG_MEDIA_OPTIONS |
in ax, dx ; read media option register |
1583,13 → 1631,10 |
jz .aui_enable |
DEBUGF 1,"Using 100Base-FX\n" |
ret |
|
.aui_enable: |
|
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
; check for 10Mbps AUI connector |
set_io REG_MEDIA_OPTIONS |
in ax, dx ; read media option register |
1606,18 → 1651,16 |
jz .coax_available |
DEBUGF 1,"Using 10Mbps aui\n" |
ret |
|
.coax_available: |
|
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
; check for coaxial 10BASE-2 port |
set_io REG_MEDIA_OPTIONS |
in ax, dx ; read media option register |
test al, 10000b ; check 10BASE-2 |
jz .set_first_available_media |
|
set_io REG_INTERNAL_CONFIG |
in eax, dx |
and eax, not (1111b shl 20) |
1629,9 → 1672,10 |
jz .set_first_available_media |
DEBUGF 1,"Using 10BASE-2 port\n" |
ret |
|
.set_first_available_media: |
DEBUGF 1,"Using the first available media\n" |
|
|
;*************************************************************************** |
; Function |
; set_available_media |
1638,7 → 1682,7 |
; Description |
; sets the first available media |
; Parameters |
; ebp - io_addr |
; ebx - ptr to device struct |
; Return value |
; al - 0 |
; al - 1 |
1650,23 → 1694,26 |
align 4 |
set_available_media: |
|
DEBUGF 1,"Using the first available media\n" |
|
DEBUGF 1,"Setting the available media\n" |
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
|
set_io REG_MEDIA_OPTIONS |
in ax, dx |
DEBUGF 1,"available media:%x\n", al |
mov cl, al |
|
set_io REG_INTERNAL_CONFIG |
in eax, dx |
push eax |
set_io REG_MEDIA_OPTIONS |
in ax, dx |
test al, 10b |
and eax, not (1111b shl 20) ; these bits hold the 'transceiver select' value |
|
test cl, 10b ; baseTXAvailable |
jz @f |
; baseTXAvailable |
pop eax |
and eax, not (1111b shl 20) |
|
DEBUGF 1,"base TX is available\n" |
or eax, (100b shl 20) |
if defined FORCE_FD |
mov word [device.mode], (1 shl 8) |
1675,76 → 1722,74 |
end if |
jmp .set_media |
@@: |
test al, 100b |
|
test cl, 100b ; baseFXAvailable |
jz @f |
; baseFXAvailable |
pop eax |
and eax, not (1111b shl 20) |
|
DEBUGF 1,"base FX is available\n" |
or eax, (101b shl 20) |
|
mov word [device.mode], (1 shl 10) |
|
jmp .set_media |
@@: |
test al, 1000000b |
|
test cl, 1000000b ; miiDevice |
jz @f |
; miiDevice |
pop eax |
and eax, not (1111b shl 20) |
|
DEBUGF 1,"mii-device is available\n" |
or eax, (0110b shl 20) |
|
mov word [device.mode], (1 shl 13) |
|
jmp .set_media |
@@: |
test al, 1000b |
|
test cl, 1000b ; 10bTAvailable |
jz @f |
|
DEBUGF 1,"10base-T is available\n" |
.set_default: |
; 10bTAvailable |
pop eax |
and eax, not (1111b shl 20) |
if FORCE_FD |
mov word [device.mode], (1 shl 6) |
else |
mov word [device.mode], (1 shl 5) |
end if ; FORCE_FD |
end if |
jmp .set_media |
@@: |
test al, 10000b |
|
test cl, 10000b ; coaxAvailable |
jz @f |
; coaxAvailable |
|
DEBUGF 1,"coax is available\n" |
push eax |
set_io REG_COMMAND |
mov ax, (10b shl 11) ; EnableDcConverter |
out dx, ax |
pop eax |
and eax, not (1111b shl 20) |
|
or eax, (11b shl 20) |
|
mov word [device.mode], (1 shl 12) |
|
jmp .set_media |
@@: |
test al, 10000b |
|
test cl, 10000b ; auiAvailable |
jz .set_default |
; auiAvailable |
pop eax |
and eax, not (1111b shl 20) |
|
DEBUGF 1,"AUI is available\n" |
or eax, (1 shl 20) |
|
mov word [device.mode], (1 shl 11) |
|
.set_media: |
set_io 0 |
set_io REG_INTERNAL_CONFIG |
out dx, eax |
|
if FORCE_FD |
; set fullDuplexEnable in MacControl register |
DEBUGF 1,"Forcing full duplex\n" |
set_io REG_MAC_CONTROL |
in ax, dx |
or ax, 0x120 |
out dx, ax |
end if ; FORCE_FD |
end if |
|
mov al, 1 |
|
ret |
|
|
1771,15 → 1816,11 |
test al, 10000b ; is there "new capabilities" linked list? |
jz .device_awake |
|
DEBUGF 1,"1 " |
|
; search for power management register |
stdcall PciRead16, ecx, edx, PCI_REG_CAP_PTR |
cmp al, 0x3f |
jbe .device_awake |
|
DEBUGF 1,"2 " |
|
; traverse the list |
movzx esi, al |
.pm_loop: |
1797,8 → 1838,6 |
; waku up the device if necessary |
.set_pm_state: |
|
DEBUGF 1,"3 " |
|
add esi, PCI_REG_PM_CTRL |
stdcall PciRead32, ecx, edx, esi |
test al, 3 |
1805,8 → 1844,8 |
jz .device_awake |
and al, not 11b ; set state to D0 |
stdcall PciWrite32, ecx, edx, esi, eax |
|
.device_awake: |
|
DEBUGF 1,"Device is awake\n" |
|
ret |
1895,6 → 1934,8 |
; out dx, ax |
;.finish: |
; ret |
|
|
;*************************************************************************** |
; Function |
; read_eeprom |
1906,7 → 1947,7 |
; Return value: |
; ax - word read |
; Destroyed registers |
; ax, ebx, edx, ebp |
; ax, ebx, edx |
; |
;*************************************************************************** |
|
1913,7 → 1954,7 |
align 4 |
read_eeprom: |
|
DEBUGF 1,"Reading from eeprom:\n" |
DEBUGF 1,"Reading from eeprom.. " |
|
push eax |
; switch to register window 0 |
2011,7 → 2052,7 |
align 4 |
mdio_read: |
|
DEBUGF 1,"reading MII registers\n" |
DEBUGF 1,"Reading MII registers\n" |
|
push eax |
call mdio_sync ; returns with window #4 |
2099,12 → 2140,13 |
mov ax, si |
mov esi, eax |
mov ecx, 31 |
|
.cmd_loop: |
mov ax, (1 shl BIT_MGMT_DIR) ; write mii |
bt esi, ecx |
jnc .zero_bit |
jnc @f |
or al, (1 shl BIT_MGMT_DATA) |
.zero_bit: |
@@: |
out dx, ax |
push eax |
in ax, dx ; delay |
2139,6 → 2181,7 |
set_io 0 |
set_io REG_TX_STATUS |
mov ecx, 31 ; max number of queue entries |
|
.tx_status_loop: |
in al, dx |
test al, al |
2150,6 → 2193,7 |
xor al, al |
out dx, al |
loop .tx_status_loop |
|
.finish: |
|
ret |
2357,9 → 2401,8 |
;--------------------------------- |
; Write MAC |
|
|
align 4 |
write_mac: ; Tested - ok |
write_mac: |
|
DEBUGF 1,"Writing mac\n" |
|
2381,15 → 2424,13 |
inc dx |
outsw |
|
|
;---------------------------- |
; Read MAC |
|
|
align 4 |
read_mac: ; Tested - ok |
read_mac: |
|
|
|
set_io 0 |
set_io REG_COMMAND |
|
2416,7 → 2457,6 |
;------------------------------------ |
; Read MAC from eeprom |
|
|
align 4 |
read_mac_eeprom: ; Tested - ok |
|
2431,7 → 2471,6 |
pop ecx |
xchg ah, al ; htons |
mov word [device.mac+ecx*2-2], ax |
|
loop .mac_loop |
|
DEBUGF 1,"%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 |
2554,8 → 2593,6 |
; check for master operation in progress |
set_io REG_MASTER_STATUS ; TODO: use timeout and reset after timeout expired |
.dma_loop: |
xor esi, esi |
stdcall Sleep |
in ax, dx |
test ah, 0x80 |
jnz .dma_loop |