/kernel/trunk/core/conf_lib.inc |
---|
72,7 → 72,54 |
udev_midibase db 'midibase',0 |
udev_midibase_def db '0x320',0 |
endg |
;set up netvork configuration |
proc set_network_conf |
locals |
par db 30 dup(?) |
endl |
pushad |
;[net] |
;active |
lea eax, [par] |
invoke ini.get_int, conf_fname, unet, unet_active, 0 |
or eax, eax |
jz .do_not_set_net |
mov eax, [stack_config] |
and eax, 0xFFFFFF80 |
add eax, 3 |
mov [stack_config], eax |
call ash_eth_enable |
;addr |
lea eax, [par] |
push eax |
invoke ini.get_str, conf_fname, unet, unet_addr, eax, 30, unet_def |
pop eax |
stdcall do_inet_adr, eax |
mov [stack_ip], eax |
;mask |
lea eax, [par] |
push eax |
invoke ini.get_str, conf_fname, unet, unet_mask, eax, 30, unet_def |
pop eax |
stdcall do_inet_adr, eax |
mov [subnet_mask], eax |
;gate |
lea eax, [par] |
push eax |
invoke ini.get_str, conf_fname, unet, unet_gate, eax, 30, unet_def |
pop eax |
stdcall do_inet_adr, eax |
mov [gateway_ip], eax |
.do_not_set_net: |
popad |
ret |
endp |
iglobal |
if lang eq sp |
include 'core/conf_lib-sp.inc' |
/kernel/trunk/core/syscall.inc |
---|
112,11 → 112,11 |
align 4 |
servetable: |
dd socket ; 53-Socket interface |
dd 0 |
dd 0 |
dd 0 |
dd 0 |
dd 0 |
dd file_system ; 58-Common file system interface |
dd 0 |
dd 0 |
182,8 → 182,8 |
dd sys_apm ; 49-Advanced Power Management (APM) |
dd syscall_set_window_shape ; 50-Window shape & scale |
dd syscall_threads ; 51-Threads |
dd undefined_syscall ; 52-Stack driver status |
dd undefined_syscall ; 53-Socket interface |
dd stack_driver_stat ; 52-Stack driver status |
dd cross_order ; 53-Socket interface |
dd undefined_syscall ; 54-reserved |
dd sound_interface ; 55-Sound interface |
dd undefined_syscall ; 56-reserved |
204,9 → 204,9 |
dd syscall_window_settings ; 71-Window settings |
dd sys_sendwindowmsg ; 72-Send window message |
dd blit_32 ; 73-blitter; |
dd sys_network ; 74-reserved for new stack |
dd sys_socket ; 75-reserved for new stack |
dd sys_protocols ; 76-reserved for new stack |
dd undefined_syscall ; 74-reserved for new stack |
dd undefined_syscall ; 75-reserved for new stack |
dd undefined_syscall ; 76-reserved for new stack |
times 255 - ( ($-servetable2) /4 ) dd undefined_syscall |
dd sys_end ; -1-end application |
/kernel/trunk/core/exports.inc |
---|
101,12 → 101,6 |
szUSBNormalTransferAsync db 'USBNormalTransferAsync',0 |
szUSBControlTransferAsync db 'USBControlTransferAsync',0 |
szNetRegDev db 'NetRegDev',0 |
szNetUnRegDev db 'NetUnRegDev',0 |
szNetPtrToNum db 'NetPtrToNum',0 |
szNetLinkChanged db 'NetLinkChanged',0 |
szEth_input db 'Eth_input',0 |
align 16 |
kernel_export: |
dd szRegService , reg_service |
197,12 → 191,6 |
dd szUSBNormalTransferAsync, usb_normal_transfer_async |
dd szUSBControlTransferAsync, usb_control_async |
dd szNetRegDev , NET_add_device |
dd szNetUnRegDev , NET_remove_device |
dd szNetPtrToNum , NET_ptr_to_num |
dd szNetLinkChanged , NET_link_changed |
dd szEth_input , ETH_input |
exp_lfb: |
dd szLFBAddress , 0 |
dd 0 ;terminator, must be zero |
/kernel/trunk/const.inc |
---|
399,8 → 399,7 |
EVENT_IPC equ 0x00000040 |
EVENT_NETWORK equ 0x00000080 |
EVENT_DEBUG equ 0x00000100 |
EVENT_NETWORK2 equ 0x00000200 |
EVENT_EXTENDED equ 0x00000400 |
EVENT_EXTENDED equ 0x00000200 |
EV_INTR equ 1 |
/kernel/trunk/gui/event.inc |
---|
515,8 → 515,8 |
jz .no_events ; исчерпали все биты маски, но ничего не нашли ??? |
btr ecx, eax ; сбрасываем проверяемый бит маски |
; переходим на обработчик этого (eax) бита |
cmp eax, 10 |
jae .loop ; eax=[10..31], ignored (event 10...32) |
cmp eax, 9 |
jae .loop ; eax=[9..31], ignored (event 10...32) |
cmp eax, 3 |
je .loop ; eax=3, ignored (event 4) |
527,7 → 527,7 |
cmp eax, 5 |
je .mouse_check ; eax=5, retvals=eax+1 (event 6) |
ja .FlagAutoReset ; eax=[6..9], retvals=eax+1 (event 7...10) |
ja .FlagAutoReset ; eax=[6..8], retvals=eax+1 (event 7...9) |
cmp eax, 1 |
jae .BtKy ; eax=[1,2], retvals=eax+1 (event 2,3) |
/kernel/trunk/kernel.asm |
---|
77,7 → 77,7 |
USE_COM_IRQ equ 1 ; make irq 3 and irq 4 available for PCI devices |
; Enabling the next line will enable serial output console |
debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used |
;debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used |
; The following constant, if nonzero, duplicates debug output to the screen. |
debug_direct_print equ 0 |
638,6 → 638,12 |
mov dword [current_slot], SLOT_BASE + 256*2 |
mov dword [TASK_BASE], CURRENT_TASK + 32*2 |
stdcall kernel_alloc, 0x10000/8 |
mov edi, eax |
mov [network_free_ports], eax |
or eax, -1 |
mov ecx, 0x10000/32 |
rep stosd |
; REDIRECT ALL IRQ'S TO INT'S 0x20-0x2f |
mov esi, boot_initirq |
877,6 → 883,12 |
stdcall map_page, tss._io_map_1, \ |
[SLOT_BASE+256+APPDATA.io_map+4], PG_MAP |
mov ax, [OS_BASE+0x10000+bx_from_load] |
cmp ax, 'r1'; if not rused ram disk - load network configuration from files {SPraid.simba} |
je no_st_network |
call set_network_conf |
no_st_network: |
; LOAD FIRST APPLICATION |
cli |
2017,13 → 2029,6 |
popa |
@@: |
;-------------------------------------- |
; kill all sockets this process owns |
pusha |
mov edx, [TASK_BASE] |
mov edx, [edx+TASKDATA.pid] |
call SOCKET_process_end |
popa |
;-------------------------------------- |
mov ecx, [current_slot] |
mov eax, [ecx+APPDATA.tls_base] |
test eax, eax |
2150,12 → 2155,6 |
test eax, eax |
jz noprocessterminate |
;-------------------------------------- |
; terminate all network sockets it used |
pusha |
mov eax, edx |
call SOCKET_process_end |
popa |
;-------------------------------------- |
cmp [_display.select_cursor], 0 |
je .restore_end |
; restore default cursor before killing |
5367,6 → 5366,28 |
align 4 |
stack_driver_stat: |
call app_stack_handler ; Stack status |
; mov [check_idle_semaphore],5 ; enable these for zero delay |
; call change_task ; between sent packet |
mov [esp+32], eax |
ret |
align 4 |
socket: ; Socket interface |
call app_socket_handler |
; mov [check_idle_semaphore],5 ; enable these for zero delay |
; call change_task ; between sent packet |
mov [esp+36], eax |
mov [esp+24], ebx |
ret |
paleholder: |
ret |
;------------------------------------------------------------------------------ |
/kernel/trunk/network/tcp_usreq.inc |
---|
File deleted |
\ No newline at end of file |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/ethernet.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/ARP.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/IPv6.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/IPv4.inc |
---|
File deleted |
\ No newline at end of file |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/tcp_output.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/PPPoE.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/tcp_subr.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/tcp_input.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/loopback.inc |
---|
File deleted |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/tcp_timer.inc |
---|
File deleted |
\ No newline at end of file |
Property changes: |
Deleted: svn:eol-style |
-native |
\ No newline at end of property |
/kernel/trunk/network/stack.inc |
---|
1,789 → 1,918 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; STACK.INC ;; |
;; ;; |
;; TCP/IP stack for KolibriOS ;; |
;; TCP/IP stack for Menuet OS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; |
;; ;; |
;; Some parts of code are based on the work of: ;; |
;; Mike Hibbett (menuetos network stack) ;; |
;; Eugen Brasoveanu (solar os network stack and drivers) ;; |
;; mike.dld (kolibrios socket code) ;; |
;; See file COPYING for details ;; |
;; ;; |
;; TCP part is based on 4.4BSD ;; |
;; Version 0.7 ;; |
;; Added a timer per socket to allow delays when rx window ;; |
;; gets below 1KB ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;;10.01.2007 Bugfix for checksum function from Paolo Franchetti ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 3523 $ |
$Revision$ |
;******************************************************************* |
; Interface |
; The interfaces defined in ETHERNET.INC plus: |
; stack_init |
; stack_handler |
; app_stack_handler |
; app_socket_handler |
; checksum |
; |
;******************************************************************* |
uglobal |
net_10ms dd ? |
net_tmr_count dw ? |
StackCounters: |
dumped_rx_count dd 0 |
arp_tx_count: |
dd 0 |
arp_rx_count: |
dd 0 |
ip_rx_count: |
dd 0 |
ip_tx_count: |
dd 0 |
endg |
MAX_NET_DEVICES = 16 |
ARP_BLOCK = 1 ; true or false |
; socket buffers |
SOCKETBUFFSIZE equ 4096 ; state + config + buffer. |
SOCKETHEADERSIZE equ SOCKET.rxData ; thus 4096 - SOCKETHEADERSIZE bytes data |
MIN_EPHEMERAL_PORT = 49152 |
MIN_EPHEMERAL_PORT_N = 0x00C0 ; same in Network byte order (FIXME) |
MAX_EPHEMERAL_PORT = 61000 |
MAX_EPHEMERAL_PORT_N = 0x48EE ; same in Network byte order (FIXME) |
;NUM_SOCKETS equ 16 ; Number of open sockets supported. Was 20 |
; Ethernet protocol numbers |
ETHER_ARP = 0x0608 |
ETHER_IPv4 = 0x0008 |
ETHER_IPv6 = 0xDD86 |
ETHER_PPP_DISCOVERY = 0x6388 |
ETHER_PPP_SESSION = 0x6488 |
; IPBUFF status values |
BUFF_EMPTY equ 0 |
BUFF_RX_FULL equ 1 |
BUFF_ALLOCATED equ 2 |
BUFF_TX_FULL equ 3 |
; PPP protocol numbers |
PPP_IPv4 = 0x2100 |
PPP_IPV6 = 0x5780 |
NUM_IPBUFFERS equ 20 ; buffers allocated for TX/RX |
;Protocol family |
AF_UNSPEC = 0 |
AF_LOCAL = 1 |
AF_INET4 = 2 |
AF_INET6 = 10 |
AF_PPP = 777 |
NUMQUEUES equ 4 |
; Internet protocol numbers |
IP_PROTO_IP = 0 |
IP_PROTO_ICMP = 1 |
IP_PROTO_TCP = 6 |
IP_PROTO_UDP = 17 |
EMPTY_QUEUE equ 0 |
IPIN_QUEUE equ 1 |
IPOUT_QUEUE equ 2 |
NET1OUT_QUEUE equ 3 |
; PPP protocol number |
PPP_PROTO_ETHERNET = 666 |
NO_BUFFER equ 0xFFFF |
IPBUFFSIZE equ 1500 ; MTU of an ethernet packet |
NUMQUEUEENTRIES equ NUM_IPBUFFERS |
NUMRESENDENTRIES equ 18 ; Buffers for TCP resend packets |
; Socket types |
SOCK_STREAM = 1 |
SOCK_DGRAM = 2 |
SOCK_RAW = 3 |
; These are the 0x40 function codes for application access to the stack |
STACK_DRIVER_STATUS equ 52 |
SOCKET_INTERFACE equ 53 |
; Socket options |
SO_ACCEPTCON = 1 shl 0 |
SO_BROADCAST = 1 shl 1 |
SO_DEBUG = 1 shl 2 |
SO_DONTROUTE = 1 shl 3 |
SO_KEEPALIVE = 1 shl 4 |
SO_OOBINLINE = 1 shl 5 |
SO_REUSEADDR = 1 shl 6 |
SO_REUSEPORT = 1 shl 7 |
SO_USELOOPBACK = 1 shl 8 |
SO_BINDTODEVICE = 1 shl 9 |
SO_BLOCK = 1 shl 10 ; TO BE REMOVED |
SO_NONBLOCK = 1 shl 31 |
; 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 |
; Socket flags for user calls |
MSG_PEEK = 0x02 |
MSG_DONTWAIT = 0x40 |
; 32 bit word |
stack_config equ stack_data |
; Socket level |
SOL_SOCKET = 0 |
; 32 bit word - IP Address in network format |
stack_ip equ stack_data + 4 |
; 1 byte. 0 == inactive, 1 = active |
ethernet_active equ stack_data + 9 |
; Socket States |
SS_NOFDREF = 0x0001 ; no file table ref any more |
SS_ISCONNECTED = 0x0002 ; socket connected to a peer |
SS_ISCONNECTING = 0x0004 ; in process of connecting to peer |
SS_ISDISCONNECTING = 0x0008 ; in process of disconnecting |
SS_CANTSENDMORE = 0x0010 ; can't send more data to peer |
SS_CANTRCVMORE = 0x0020 ; can't receive more data from peer |
SS_RCVATMARK = 0x0040 ; at mark on input |
SS_ISABORTING = 0x0080 ; aborting fd references - close() |
SS_RESTARTSYS = 0x0100 ; restart blocked system calls |
SS_ISDISCONNECTED = 0x0800 ; socket disconnected from peer |
SS_ASYNC = 0x0100 ; async i/o notify |
SS_ISCONFIRMING = 0x0200 ; deciding to accept connection req |
SS_MORETOCOME = 0x0400 |
; TODO :: empty memory area |
SS_BLOCKED = 0x8000 |
; 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 |
SOCKET_MAXDATA = 4096*32 ; must be 4096*(power of 2) where 'power of 2' is at least 8 |
; receive and transmit IP buffer allocation |
;sockets equ stack_data + 62 |
Next_free2 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 + 1518 |
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 ) |
; Network driver types |
NET_TYPE_LOOPBACK = 0 |
NET_TYPE_ETH = 1 |
NET_TYPE_SLIP = 2 |
;resendQ equ queueList + ( 2 * NUMQUEUEENTRIES ) |
;resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP |
; equ resendBuffer + ( IPBUFFSIZE * NUMRESENDENTRIES ) |
MAX_backlog = 20 ; maximum backlog for stream sockets |
; Error Codes |
ENOBUFS = 55 |
ECONNREFUSED = 61 |
ECONNRESET = 52 |
ETIMEDOUT = 60 |
ECONNABORTED = 53 |
; Api protocol numbers |
API_ETH = 0 |
API_IPv4 = 1 |
API_ICMP = 2 |
API_UDP = 3 |
API_TCP = 4 |
API_ARP = 5 |
API_PPPOE = 6 |
API_IPv6 = 7 |
;resendQ equ 0x770000 |
;resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP ; XTODO: validate size |
resendBuffer equ resendQ + ( 8 * NUMRESENDENTRIES ) ; for TCP |
HWACC_TCP_IPv4 = 1 shl 0 |
struct NET_DEVICE |
uglobal |
net_sockets rd 2 |
endg |
type dd ? ; Type field |
mtu dd ? ; Maximal Transmission Unit |
name dd ? ; Ptr to 0 terminated string |
unload dd ? ; Ptrs to driver functions |
reset dd ? ; |
transmit dd ? ; |
bytes_tx dq ? ; Statistics, updated by the driver |
bytes_rx dq ? ; |
packets_tx dd ? ; |
packets_rx dd ? ; |
state dd ? ; link state (0 = no link) |
hwacc dd ? ; bitmask stating enabled HW accelerations (offload engines) |
ends |
; Exactly as it says.. |
macro pseudo_random reg { |
add reg, [esp] |
rol reg, 5 |
xor reg, [timer_ticks] |
; add reg, [CPU_FREQ] |
imul reg, 214013 |
xor reg, 0xdeadbeef |
rol reg, 9 |
; simple macro for memory set operation |
macro _memset_dw adr,value,amount |
{ |
mov edi, adr |
mov ecx, amount |
if value = 0 |
xor eax, eax |
else |
mov eax, value |
end if |
cld |
rep stosd |
} |
; Network to Hardware byte order (dword) |
macro ntohd reg { |
rol word reg, 8 |
rol dword reg, 16 |
rol word reg , 8 |
} |
; Network to Hardware byte order (word) |
macro ntohw reg { |
rol word reg, 8 |
} |
; Below, the main network layer source code is included |
; |
include "queue.inc" |
include "loopback.inc" |
include "ethernet.inc" |
include "PPPoE.inc" |
include "ARP.inc" |
include "IPv4.inc" |
include "IPv6.inc" |
include "icmp.inc" |
include "udp.inc" |
include "tcp.inc" |
include "eth_drv/ethernet.inc" |
include "ip.inc" |
include "socket.inc" |
align 4 |
uglobal |
NET_RUNNING dd ? |
NET_DEFAULT dd ? |
NET_DRV_LIST rd MAX_NET_DEVICES |
endg |
;----------------------------------------------------------------- |
; |
;*************************************************************************** |
; Function |
; stack_init |
; |
; This function calls all network init procedures |
; 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 |
; |
; IN: / |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
;*************************************************************************** |
stack_init: |
; Init two address spaces with default values |
_memset_dw stack_data_start, 0, 0x20000/4 |
_memset_dw resendQ, 0, NUMRESENDENTRIES * 2 |
; Init the network drivers list |
xor eax, eax |
mov edi, NET_RUNNING |
mov ecx, (MAX_NET_DEVICES + 2) |
rep stosd |
mov [net_sockets], 0 |
mov [net_sockets + 4], 0 |
PPPoE_init |
; Queries initialization |
call queueInit |
IPv4_init |
; IPv6_init |
ICMP_init |
ARP_init |
UDP_init |
TCP_init |
SOCKET_init |
mov [net_tmr_count], 0 |
; The following block sets up the 1s timer |
mov al, 0x0 |
out 0x70, al |
in al, 0x71 |
mov [last_1sTick], al |
ret |
; Wakeup every tick. |
proc stack_handler_has_work? |
mov eax, [timer_ticks] |
cmp eax, [net_10ms] |
cmp eax, [last_1hsTick] |
ret |
endp |
;----------------------------------------------------------------- |
; |
;*************************************************************************** |
; Function |
; stack_handler |
; |
; This function is called in kernel loop |
; Description |
; The kernel loop routine for the stack |
; This is a kernel function, called in the main loop |
; |
; IN: / |
; OUT: / |
; |
;----------------------------------------------------------------- |
;*************************************************************************** |
align 4 |
stack_handler: |
; Test for 10ms tick |
mov eax, [timer_ticks] |
cmp eax, [net_10ms] |
je .exit |
mov [net_10ms], eax |
call ethernet_driver |
call ip_rx |
cmp [NET_RUNNING], 0 |
je .exit |
test [net_10ms], 0x0f ; 160ms |
jnz .exit |
; Test for 10ms tick, call tcp timer |
mov eax, [timer_ticks];[0xfdf0] |
cmp eax, [last_1hsTick] |
je sh_001 |
TCP_timer_160ms |
mov [last_1hsTick], eax |
call tcp_tx_handler |
test [net_10ms], 0x3f ; 640ms |
jnz .exit |
sh_001: |
TCP_timer_640ms |
ARP_decrease_entry_ttls |
IPv4_decrease_fragment_ttls |
; 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 |
.exit: |
ret |
mov [last_1sTick], al |
stdcall arp_table_manager, ARP_TABLE_TIMER, 0, 0 |
call tcp_tcb_handler |
sh_exit: |
ret |
align 4 |
NET_link_changed: |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; Checksum [by Johnny_B] |
;; IN: |
;; buf_ptr=POINTER to buffer |
;; buf_size=SIZE of buffer |
;; OUT: |
;; AX=16-bit checksum |
;; Saves all used registers |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
proc checksum_jb stdcall uses ebx esi ecx,\ |
buf_ptr:DWORD, buf_size:DWORD |
DEBUGF 1,"NET_link_changed device=0x%x status=0x%x\n", ebx, [ebx + NET_DEVICE.state] |
xor eax, eax |
xor ebx, ebx;accumulator |
mov esi, dword[buf_ptr] |
mov ecx, dword[buf_size] |
shr ecx, 1; ecx=ecx/2 |
jnc @f ; if CF==0 then size is even number |
mov bh, byte[esi + ecx*2] |
@@: |
cld |
align 4 |
NET_send_event: |
DEBUGF 1,"NET_send_event\n" |
; Send event to all applications |
push edi ecx |
mov edi, SLOT_BASE |
mov ecx, [TASK_COUNT] |
.loop: |
add edi, 256 |
or [edi + APPDATA.event_mask], EVENT_NETWORK2 |
lodsw ;eax=word[esi],esi=esi+2 |
xchg ah, al;cause must be a net byte-order |
add ebx, eax |
loop .loop |
pop ecx edi |
mov eax, ebx |
shr eax, 16 |
add ax, bx |
not ax |
ret |
endp |
;----------------------------------------------------------------- |
;*************************************************************************** |
; Function |
; checksum |
; |
; NET_add_device: |
; 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 |
; |
; This function is called by the network drivers, |
; to register each running NIC to the kernel |
; |
; IN: Pointer to device structure in ebx |
; OUT: Device num in eax, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
NET_add_device: |
;*************************************************************************** |
DEBUGF 1,"NET_Add_Device: %x\n", ebx ;;; TODO: use mutex to lock net device list |
cmp [NET_RUNNING], MAX_NET_DEVICES |
jae .error |
checksum: |
pusha |
mov eax, [checkAdd1] |
xor edx, edx ; edx is the accumulative checksum |
xor ebx, ebx |
mov cx, [checkSize1] |
shr cx, 1 |
jz cs1_1 |
;---------------------------------- |
; Check if device is already listed |
mov eax, ebx |
mov ecx, MAX_NET_DEVICES ; We need to check whole list because a device may be removed without re-organizing list |
mov edi, NET_DRV_LIST |
cs1: |
mov bh, [eax] |
mov bl, [eax + 1] |
repne scasd ; See if device is already in the list |
jz .error |
add eax, 2 |
add edx, ebx |
;---------------------------- |
; Find empty slot in the list |
xor eax, eax |
mov ecx, MAX_NET_DEVICES |
mov edi, NET_DRV_LIST |
loopw cs1 |
repne scasd |
jnz .error |
cs1_1: |
and word [checkSize1], 0x01 |
jz cs_test2 |
sub edi, 4 |
mov bh, [eax] |
xor bl, bl |
;----------------------------- |
; Add device to the found slot |
mov [edi], ebx ; add device to list |
add edx, ebx |
mov eax, edi ; Calculate device number in eax |
sub eax, NET_DRV_LIST |
shr eax, 2 |
cs_test2: |
mov cx, [checkSize2] |
cmp cx, 0 |
jz cs_exit ; Finished if no 2nd buffer |
inc [NET_RUNNING] ; Indicate that one more network device is up and running |
mov eax, [checkAdd2] |
cmp eax, 1 ; If it's the first network device, try to set it as default |
jne @f |
push eax |
call NET_set_default |
pop eax |
@@: |
shr cx, 1 |
jz cs2_1 |
call NET_send_event |
cs2: |
mov bh, [eax] |
mov bl, [eax + 1] |
DEBUGF 1,"Device number: %u\n", eax |
ret |
add eax, 2 |
add edx, ebx |
.error: |
or eax, -1 |
DEBUGF 2,"Adding network device failed\n" |
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 |
; |
; NET_set_default |
; Description |
; This is an application service, called by int 0x40, function 52 |
; It provides application access to the network interface layer |
; |
; API to set the default interface |
; |
; IN: Device num in eax |
; OUT: Device num in eax, -1 on error |
; |
;----------------------------------------------------------------- |
;*************************************************************************** |
iglobal |
align 4 |
NET_set_default: |
f52call: |
dd app_stack_handler.00 |
dd app_stack_handler.01 |
dd app_stack_handler.02 |
dd app_stack_handler.03 |
dd app_stack_handler.fail ;04 |
dd app_stack_handler.fail ;05 |
dd stack_insert_packet ;app_stack_handler.06 |
dd app_stack_handler.fail ;07 |
dd stack_get_packet ;app_stack_handler.08 |
dd app_stack_handler.09 |
dd app_stack_handler.10 |
dd app_stack_handler.11 |
dd app_stack_handler.12 |
dd app_stack_handler.13 |
dd app_stack_handler.14 |
dd app_stack_handler.15 |
endg |
app_stack_handler: |
;in ebx,ecx |
;out eax |
cmp ebx, 15 |
ja .fail ;if more than 15 then exit |
DEBUGF 1,"NET_set_default: device=%x\n", eax |
jmp dword [f52call+ebx*4] |
cmp eax, MAX_NET_DEVICES |
jae .error |
cmp [NET_DRV_LIST+eax*4], 0 |
je .error |
.00: |
; Read the configuration word |
mov eax, [stack_config] |
ret |
mov [NET_DEFAULT], eax |
.01: |
; read the IP address |
mov eax, [stack_ip] |
ret |
DEBUGF 1,"NET_set_default: succes\n" |
.02: |
; write the configuration word |
mov [stack_config], ecx |
; <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 cl, 0x7f |
cmp cl, 3 |
je ash_eth_enable |
; Ethernet isn't enabled, so make sure that the card is disabled |
mov [ethernet_active], byte 0 |
ret |
.error: |
or eax, -1 |
DEBUGF 1,"NET_set_default: failed\n" |
.03: |
; write the IP Address |
mov [stack_ip], ecx |
ret |
;old functions was deleted |
;.06: |
; Insert an IP packet into the stacks received packet queue |
; call stack_insert_packet |
; ret |
; Test for any packets queued for transmission over the network |
;----------------------------------------------------------------- |
; |
; NET_Remove_Device: |
; |
; This function is called by etwork drivers, |
; to unregister network devices from the kernel |
; |
; IN: Pointer to device structure in ebx |
; OUT: eax: -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
NET_remove_device: |
;.08: |
; call stack_get_packet |
; Extract a packet queued for transmission by the network |
; ret |
cmp [NET_RUNNING], 0 |
je .error |
.09: |
; read the gateway IP address |
mov eax, [gateway_ip] |
ret |
cmp [NET_DRV_LIST], ebx |
jne @f |
mov [NET_DRV_LIST], 0 |
cmp [NET_RUNNING], 1 |
je @f |
; there are still active devices, find one and make it default |
xor eax, eax |
mov ecx, MAX_NET_DEVICES |
mov edi, NET_DRV_LIST |
repe scasd |
je @f |
shr edi, 2 |
dec edi |
mov [NET_DEFAULT], edi |
@@: |
.10: |
; read the subnet mask |
mov eax, [subnet_mask] |
ret |
.11: |
; write the gateway IP Address |
mov [gateway_ip], ecx |
ret |
;---------------------------- |
; Find the driver in the list |
.12: |
; write the subnet mask |
mov [subnet_mask], ecx |
ret |
mov eax, ebx |
mov ecx, MAX_NET_DEVICES |
mov edi, NET_DRV_LIST+4 |
.13: |
; read the dns |
mov eax, [dns_ip] |
ret |
repne scasd |
jnz .error |
.14: |
; write the dns IP Address |
mov [dns_ip], ecx |
ret |
;------------------------ |
; Remove it from the list |
.15: |
;<added by Frank Sommer> |
; in ecx we need 4 to read the last 2 bytes |
; or we need 0 to read the first 4 bytes |
cmp ecx, 4 |
ja .param_error |
xor eax, eax |
mov dword [edi-4], eax |
; read MAC, returned (in mirrored byte order) in eax |
mov eax, [node_addr + ecx] |
ret |
call NET_send_event |
dec [NET_RUNNING] |
.param_error: |
or eax, -1 ; params not accepted |
ret |
.error: |
.16: |
; 0 -> arp_probe |
; 1 -> arp_announce |
; 2 -> arp_responce (not supported yet) |
test ecx, ecx |
je a_probe |
dec ebx |
jz a_ann ; arp announce |
.fail: |
or eax, -1 |
ret |
; cmp ebx,2 |
; jne a_resp ; arp response |
; arp probe, sender IP must be set to 0.0.0.0, target IP is set to address being probed |
; ecx: pointer to target MAC, MAC should set to 0 by application |
; edx: target IP |
a_probe: |
push dword [stack_ip] |
;----------------------------------------------------------------- |
; |
; NET_ptr_to_num |
; |
; IN: ebx = ptr to device struct |
; OUT: edi = -1 on error, device number otherwise |
; |
;----------------------------------------------------------------- |
align 4 |
NET_ptr_to_num: |
push ecx |
mov edx, [stack_ip] |
and [stack_ip], dword 0 |
mov esi, ecx ; pointer to target MAC address |
call arp_request |
mov ecx, MAX_NET_DEVICES |
mov edi, NET_DRV_LIST |
pop dword [stack_ip] |
ret |
.loop: |
cmp ebx, [edi] |
jz .found |
add edi, 4 |
dec ecx |
jnz .loop |
; arp announce, sender IP must be set to target IP |
; ecx: pointer to target MAC |
a_ann: |
mov edx, [stack_ip] |
mov esi, ecx ; pointer to target MAC address |
call arp_request |
ret |
; repnz scasd could work too if eax is used instead of ebx! |
.17: |
;</added by Frank Sommer> |
; modified by [smb] |
or edi, -1 |
pop ecx |
;<added by Johnny_B> |
; ARPTable manager interface |
;see "proc arp_table_manager" for more details |
stdcall arp_table_manager, ecx, edx, esi;Opcode,Index,Extra |
ret |
;</added by Johnny_B> |
.found: |
sub edi, NET_DRV_LIST |
shr edi, 2 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
ash_eth_enable: |
; Probe for the card. This will reset it and enable the interface |
; if found |
call eth_probe |
test eax, eax |
jz ash_eth_done ; Abort if no hardware found |
pop ecx |
mov [ethernet_active], byte 1 |
ash_eth_done: |
ret |
;----------------------------------------------------------------- |
;*************************************************************************** |
; Function |
; app_socket_handler |
; |
; checksum_1 |
; Description |
; This is an application service, called by int 0x40, function 53 |
; It provides application access to stack socket services |
; such as opening sockets |
; |
; This is the first of two functions needed to calculate a checksum. |
; |
; IN: edx = start offset for semi-checksum |
; esi = pointer to data |
; ecx = data size |
; OUT: edx = semi-checksum |
; |
; |
; Code was optimized by diamond |
; |
;----------------------------------------------------------------- |
;*************************************************************************** |
iglobal |
align 4 |
checksum_1: |
f53call: |
dd socket_open ;00 |
dd socket_close ;01 |
dd socket_poll ;02 |
dd socket_read ;03 |
dd socket_write ;04 |
dd socket_open_tcp ;05 |
dd socket_status ;06 |
dd socket_write_tcp ;07 |
dd socket_close_tcp ;08 |
dd is_localport_unused ;09 |
dd app_socket_handler.10 |
dd socket_read_packet ;11 |
endg |
shr ecx, 1 |
pushf |
jz .no_2 |
app_socket_handler: |
;in ebx,ecx,edx,wsi |
;out eax |
cmp eax, 255 |
je stack_internal_status |
shr ecx, 1 |
pushf |
jz .no_4 |
cmp eax, 11 |
ja .fail ;if more than 15 then exit |
shr ecx, 1 |
pushf |
jz .no_8 |
jmp dword [f53call+eax*4] |
.loop: |
add dl, [esi+1] |
adc dh, [esi+0] |
.10: |
mov eax, dword[drvr_cable] |
test eax, eax |
jnz @f ; if function is not implented, return -1 |
or al, -1 |
ret |
@@: |
jmp dword[drvr_cable] |
adc dl, [esi+3] |
adc dh, [esi+2] |
.fail: |
or eax, -1 |
ret |
uglobal |
ARPTmp: |
times 14 db 0 |
endg |
adc dl, [esi+5] |
adc dh, [esi+4] |
;*************************************************************************** |
; 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 |
; |
;*************************************************************************** |
; This sub function allows access to debugging information on the stack |
; ecx 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 |
adc dl, [esi+7] |
adc dh, [esi+6] |
adc edx, 0 |
add esi, 8 |
; 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 ) |
dec ecx |
jnz .loop |
adc edx, 0 |
stack_internal_status: |
cmp ebx, 100 |
jnz notsis100 |
.no_8: |
popf |
jnc .no_4 |
; 100 : return length of EMPTY QUEUE |
mov ebx, EMPTY_QUEUE |
call queueSize |
ret |
add dl, [esi+1] |
adc dh, [esi+0] |
notsis100: |
cmp ebx, 101 |
jnz notsis101 |
adc dl, [esi+3] |
adc dh, [esi+2] |
; 101 : return length of IPOUT QUEUE |
mov ebx, IPOUT_QUEUE |
call queueSize |
ret |
adc edx, 0 |
add esi, 4 |
notsis101: |
cmp ebx, 102 |
jnz notsis102 |
.no_4: |
popf |
jnc .no_2 |
; 102 : return length of IPIN QUEUE |
mov ebx, IPIN_QUEUE |
call queueSize |
ret |
add dl, [esi+1] |
adc dh, [esi+0] |
notsis102: |
cmp ebx, 103 |
jnz notsis103 |
adc edx, 0 |
inc esi |
inc esi |
; 103 : return length of NET1OUT QUEUE |
mov ebx, NET1OUT_QUEUE |
call queueSize |
ret |
.no_2: |
popf |
jnc .end |
notsis103: |
cmp ebx, 200 |
jnz notsis200 |
add dh, [esi+0] |
adc edx, 0 |
.end: |
; 200 : return num entries in arp table |
movzx eax, byte [NumARP] |
ret |
;----------------------------------------------------------------- |
; |
; checksum_2 |
; |
; This function calculates the final ip/tcp/udp checksum for you |
; |
; IN: edx = semi-checksum |
; OUT: dx = checksum (in INET byte order) |
; |
;----------------------------------------------------------------- |
align 4 |
checksum_2: |
notsis200: |
cmp ebx, 201 |
jnz notsis201 |
mov ecx, edx |
shr ecx, 16 |
and edx, 0xffff |
add edx, ecx |
; 201 : return arp table size |
mov eax, 20; ARP_TABLE_SIZE |
ret |
mov ecx, edx |
shr ecx, 16 |
add dx, cx |
test dx, dx ; it seems that ZF is not set when CF is set :( |
not dx |
jnz .not_zero |
dec dx |
.not_zero: |
xchg dl, dh |
notsis201: |
cmp ebx, 202 |
jnz notsis202 |
DEBUGF 1,"Checksum: %x\n", dx |
; 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 |
;---------------------------------------------------------------- |
; |
; System function to work with network devices (75) |
; |
;---------------------------------------------------------------- |
align 4 |
sys_network: ; FIXME: make default device easily accessible |
notsis203: |
cmp ebx, 204 |
jnz notsis204 |
cmp ebx, -1 |
jne @f |
; 204 - return MAC high dword |
mov eax, [ARPTmp+4] |
ret |
mov eax, [NET_RUNNING] |
jmp .return |
notsis204: |
cmp ebx, 205 |
jnz notsis205 |
@@: |
cmp bh, MAX_NET_DEVICES ; Check if device number exists |
jae .doesnt_exist |
; 205 - return MAC ls word |
movzx eax, word [ARPTmp+8] |
ret |
mov esi, ebx |
and esi, 0x0000ff00 |
shr esi, 6 |
notsis205: |
cmp ebx, 206 |
jnz notsis206 |
cmp dword [esi + NET_DRV_LIST], 0 ; check if driver is running |
je .doesnt_exist |
; 206 - return status word |
movzx eax, word [ARPTmp+10] |
ret |
mov eax, [esi + NET_DRV_LIST] |
notsis206: |
cmp ebx, 207 |
jnz notsis207 |
and ebx, 0x000000ff |
cmp ebx, .number |
ja .doesnt_exist |
jmp dword [.table + 4*ebx] |
; 207 - return ttl word |
movzx eax, word [ARPTmp+12] |
ret |
.table: |
dd .get_type ; 0 |
dd .get_dev_name ; 1 |
dd .reset ; 2 |
dd .stop ; 3 |
dd .get_ptr ; 4 |
dd .get_drv_name ; 5 |
dd .set_default ; 6 |
.number = ($ - .table) / 4 - 1 |
notsis207: |
cmp ebx, 2 |
jnz notsis2 |
.get_type: ; 0 = Get device type (ethernet/token ring/...) |
; 2 : return number of IP packets received |
mov eax, [ip_rx_count] |
ret |
mov eax, [eax + NET_DEVICE.type] |
jmp .return |
notsis2: |
cmp ebx, 3 |
jnz notsis3 |
; 3 : return number of packets transmitted |
mov eax, [ip_tx_count] |
ret |
.get_dev_name: ; 1 = Get device name |
notsis3: |
cmp ebx, 4 |
jnz notsis4 |
mov esi, [eax + NET_DEVICE.name] |
mov edi, ecx |
; 4 : return number of received packets dumped |
mov eax, [dumped_rx_count] |
ret |
mov ecx, 64/4 ; max length |
rep movsd |
notsis4: |
cmp ebx, 5 |
jnz notsis5 |
xor eax, eax |
jmp .return |
; 5 : return number of arp packets received |
mov eax, [arp_rx_count] |
ret |
.reset: ; 2 = Reset the device |
notsis5: |
cmp ebx, 6 |
jnz notsis6 |
call [eax + NET_DEVICE.reset] |
jmp .return |
; 6 : return status of packet driver |
; ( 0 == not active, FFFFFFFF = successful ) |
mov eax, [eth_status] |
ret |
.stop: ; 3 = Stop driver for this device |
notsis6: |
xor eax, eax |
ret |
call [eax + NET_DEVICE.unload] |
jmp .return |
.get_ptr: ; 4 = Get driver pointer |
;*************************************************************************** |
; 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 |
jmp .return |
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 |
.get_drv_name: ; 5 = Get driver name |
push eax ; save address of IP data |
; Get the address of the callers data |
mov edi, [TASK_BASE] |
add edi, TASKDATA.mem_start |
add edx, [edi] |
mov edi, edx |
pop eax |
xor eax, eax |
jmp .return |
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 |
.set_default: ; 6 = Set default device |
mov eax, 1500 |
ret |
call NET_set_default |
jmp .return |
sgp_non_exit: |
xor eax, eax |
ret |
.doesnt_exist: |
mov eax, -1 |
.return: |
mov [esp+32], eax |
ret |
;---------------------------------------------------------------- |
;*************************************************************************** |
; Function |
; stack_insert_packet |
; |
; System function to work with protocols (76) |
; 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 |
; |
;---------------------------------------------------------------- |
align 4 |
sys_protocols: |
cmp bh, MAX_NET_DEVICES ; Check if device number exists |
jae .doesnt_exist |
;*************************************************************************** |
stack_insert_packet: |
mov esi, ebx |
and esi, 0x0000ff00 |
shr esi, 6 ; now we have the device num * 4 in esi |
cmp [esi + NET_DRV_LIST], 0 ; check if driver is running |
je .doesnt_exist |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sip_err_exit |
push .return ; return address (we will be using jumps instead of calls) |
push eax |
mov eax, ebx ; set ax to protocol number |
shr eax, 16 ; |
; save the pointers to the data buffer & size |
push edx |
push ecx |
cmp ax, API_ETH |
je ETH_api |
; convert buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
cmp ax, API_IPv4 |
je IPv4_api |
mov edx, eax |
cmp ax, API_ICMP |
je ICMP_api |
; So, edx holds the IPbuffer ptr |
cmp ax, API_UDP |
je UDP_api |
pop ecx ; count of bytes to send |
mov ebx, ecx ; need the length later |
pop eax ; get callers ptr to data to send |
cmp ax, API_TCP |
je TCP_api |
; Get the address of the callers data |
mov edi, [TASK_BASE] |
add edi, TASKDATA.mem_start |
add eax, [edi] |
mov esi, eax |
cmp ax, API_ARP |
je ARP_api |
mov edi, edx |
cld |
rep movsb ; copy the data across |
cmp ax, API_PPPOE |
je PPPoE_api |
pop ebx |
cmp ax, API_IPv6 |
je IPv6_api |
mov eax, IPIN_QUEUE |
call queue |
add esp, 4 ; if we reached here, no function was called, so we need to balance stack |
inc dword [ip_rx_count] |
.doesnt_exist: |
mov eax, -1 |
mov eax, 0 |
ret |
.return: |
mov [esp+28+4], eax ; return eax value to the program |
sip_err_exit: |
mov eax, 0xFFFFFFFF |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/udp.inc |
---|
1,325 → 1,153 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; UDP.INC ;; |
;; ;; |
;; Part of the tcp/ip network stack for KolibriOS ;; |
;; UDP Processes for Menuet OS TCP/IP stack ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; See file COPYING for details ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 2995 $ |
$Revision$ |
struct UDP_header |
;******************************************************************* |
; Interface |
; |
; udp_rx Handles received IP packets with the UDP protocol |
; |
;******************************************************************* |
SourcePort dw ? |
DestinationPort dw ? |
Length dw ? ; Length of (UDP Header + Data) |
Checksum dw ? |
ends |
align 4 |
uglobal |
UDP_PACKETS_TX rd MAX_NET_DEVICES |
UDP_PACKETS_RX rd MAX_NET_DEVICES |
endg |
;----------------------------------------------------------------- |
; |
; UDP_init |
; UDP Payload ( Data field in IP datagram ) |
; |
; This function resets all UDP variables |
; 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 |
; |
;----------------------------------------------------------------- |
macro UDP_init { |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Source Port | Destination Port | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Length ( UDP Header + Data ) | Checksum | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | UDP Data | |
; +-+-+-.......... -+ |
; |
xor eax, eax |
mov edi, UDP_PACKETS_TX |
mov ecx, 2*MAX_NET_DEVICES |
rep stosd |
struc UDP_PACKET |
{ .SourcePort dw ? ;+00 |
.DestinationPort dw ? ;+02 |
.Length dw ? ;+04 - Length of (UDP Header + Data) |
.Checksum dw ? ;+06 |
.Data db ? ;+08 |
} |
virtual at 0 |
UDP_PACKET UDP_PACKET |
end virtual |
macro UDP_checksum IP1, IP2 { ; esi = ptr to udp packet, ecx = packet size, destroys: ecx, edx |
; Pseudoheader |
mov edx, IP_PROTO_UDP |
add dl, [IP1+1] |
adc dh, [IP1+0] |
adc dl, [IP1+3] |
adc dh, [IP1+2] |
adc dl, [IP2+1] |
adc dh, [IP2+0] |
adc dl, [IP2+3] |
adc dh, [IP2+2] |
adc dl, cl ; byte[esi+UDP_header.Length+1] |
adc dh, ch ; byte[esi+UDP_header.Length+0] |
; Done with pseudoheader, now do real header |
adc dl, byte[esi+UDP_header.SourcePort+1] |
adc dh, byte[esi+UDP_header.SourcePort+0] |
adc dl, byte[esi+UDP_header.DestinationPort+1] |
adc dh, byte[esi+UDP_header.DestinationPort+0] |
adc dl, byte[esi+UDP_header.Length+1] |
adc dh, byte[esi+UDP_header.Length+0] |
adc edx, 0 |
; Done with header, now do data |
push esi |
movzx ecx, [esi+UDP_header.Length] |
rol cx , 8 |
sub cx , sizeof.UDP_header |
add esi, sizeof.UDP_header |
call checksum_1 |
call checksum_2 |
pop esi |
add [esi+UDP_header.Checksum], dx ; this final instruction will set or clear ZF :) |
} |
;----------------------------------------------------------------- |
;*************************************************************************** |
; Function |
; udp_rx [by Johnny_B] |
; |
; UDP_input: |
; Description |
; UDP 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 |
; |
; Called by IPv4_input, |
; this procedure will inject the udp data diagrams in the application sockets. |
; |
; IN: [esp] = Pointer to buffer |
; [esp+4] = size of buffer |
; ebx = ptr to device struct |
; ecx = UDP Packet size |
; esi = ptr to UDP header |
; edi = ptr to ipv4 source and dest address |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
UDP_input: |
;*************************************************************************** |
DEBUGF 1,"UDP_input: size=%u\n", ecx |
proc udp_rx stdcall |
push eax |
; First validate, checksum |
; First validate the header & checksum. Discard buffer if error |
neg [esi + UDP_header.Checksum] ; substract checksum from 0 |
jz .no_checksum ; if checksum is zero, it is considered valid |
; otherwise, we will re-calculate the checksum and add it to this value, thus creating 0 when it is correct |
UDP_checksum (edi), (edi+4) |
jnz .checksum_mismatch |
.no_checksum: |
DEBUGF 1,"UDP_input: checksum ok\n" |
; Convert length to little endian |
rol [esi + UDP_header.Length], 8 |
; Look for a socket where |
; IP Packet UDP Destination Port = local Port |
; IP Packet SA = Remote IP |
mov cx, [esi + UDP_header.SourcePort] |
mov dx, [esi + UDP_header.DestinationPort] |
mov edi, [edi + 4] ; ipv4 source address |
mov eax, net_sockets |
mov ax, [edx + 20 + UDP_PACKET.DestinationPort] ; get the local port from |
; the IP packet's UDP header |
mov ebx, net_sockets |
.next_socket: |
mov eax, [eax + SOCKET.NextPtr] |
or eax, eax |
jz .dump |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .exit ; No match, so exit |
cmp [ebx + SOCKET.LocalPort], ax ; ax will hold the 'wrong' value, |
; but the comparision is correct |
jne .next_socket ; Return back if no match |
cmp [eax + SOCKET.Domain], AF_INET4 |
jne .next_socket |
; 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 |
cmp [ebx + SOCKET.RemoteIP], 0xffffffff |
je @f |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
jne .next_socket |
mov eax, [edx + IP_PACKET.SourceAddress] ; get the Source address from the IP packet |
cmp [ebx + SOCKET.RemoteIP], eax |
jne .exit ; Quit if the source IP is not valid |
cmp [eax + UDP_SOCKET.LocalPort], dx |
jne .next_socket |
@@: ; 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 |
mov ax, [edx + 20 + UDP_PACKET.SourcePort] ; get the UDP source port |
; ( was 69, now new ) |
mov [ebx + SOCKET.RemotePort], ax |
DEBUGF 1,"UDP_input: socket=%x\n", eax |
; Now, copy data to socket. We have socket address as [eax + sockets]. |
; We have IP packet in edx |
;;; TODO: when packet is processed, check more sockets! |
; get # of bytes in ecx |
movzx ecx, [edx + IP_PACKET.TotalLength] ; total length of IP packet. Subtract |
xchg cl, ch ; 20 + 8 gives data length |
sub ecx, 28 |
; cmp [eax + IP_SOCKET.RemoteIP], 0xffffffff |
; je @f |
; cmp [eax + IP_SOCKET.RemoteIP], edi |
; jne .next_socket |
; @@: |
; |
; FIXME: UDP should check remote IP, but not under all circumstances! |
mov eax, [ebx + SOCKET.rxDataCount] ; get # of bytes already in buffer |
add [ebx + SOCKET.rxDataCount], ecx ; increment the count of bytes in buffer |
cmp [eax + UDP_SOCKET.firstpacket], 0 |
je .updateport |
; ecx has count, edx points to data |
cmp [eax + UDP_SOCKET.RemotePort], cx |
jne .dump |
add edx, 28 ; edx now points to the data |
lea edi, [ebx + eax + SOCKETHEADERSIZE] |
mov esi, edx |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
cld |
rep movsb ; copy the data across |
.updatesock: |
inc [UDP_PACKETS_RX] ; Fixme: correct interface? |
; flag an event to the application |
mov eax, [ebx + SOCKET.PID] ; get socket owner PID |
mov ecx, 1 |
mov esi, TASK_DATA + TASKDATA.pid |
movzx ecx, [esi + UDP_header.Length] |
sub ecx, sizeof.UDP_header |
add esi, sizeof.UDP_header |
.next_pid: |
cmp [esi], eax |
je .found_pid |
inc ecx |
add esi, 0x20 |
cmp ecx, [TASK_COUNT] |
jbe .next_pid |
jmp SOCKET_input |
jmp .exit |
.updateport: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
.found_pid: |
shl ecx, 8 |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event |
DEBUGF 1,"UDP_input: new remote port=%x\n", cx ; FIXME: find a way to print big endian values with debugf |
mov [eax + UDP_SOCKET.RemotePort], cx |
inc [eax + UDP_SOCKET.firstpacket] |
jmp .updatesock |
.checksum_mismatch: |
DEBUGF 2,"UDP_input: checksum mismatch\n" |
.dump: |
call kernel_free |
add esp, 4 ; pop (balance stack) |
DEBUGF 2,"UDP_input: dumping\n" |
.exit: |
pop eax |
call freeBuff ; Discard the packet |
ret |
;----------------------------------------------------------------- |
; |
; UDP_output |
; |
; IN: eax = socket pointer |
; ecx = number of bytes to send |
; esi = pointer to data |
; |
;----------------------------------------------------------------- |
align 4 |
UDP_output: |
DEBUGF 1,"UDP_output: socket=%x bytes=%u data_ptr=%x\n", eax, ecx, esi |
mov dx, [eax + UDP_SOCKET.RemotePort] |
DEBUGF 1,"UDP_output: remote port=%x, ", dx ; FIXME: find a way to print big endian values with debugf |
rol edx, 16 |
mov dx, [eax + UDP_SOCKET.LocalPort] |
DEBUGF 1,"local port=%x\n", dx |
sub esp, 8 ; Data ptr and data size will be placed here |
push edx esi |
mov ebx, [eax + SOCKET.device] |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov eax, [eax + IP_SOCKET.RemoteIP] |
mov di, IP_PROTO_UDP shl 8 + 128 |
add ecx, sizeof.UDP_header |
call IPv4_output |
jz .fail |
mov [esp + 8], eax ; pointer to buffer start |
mov [esp + 8 + 4], edx ; buffer size |
mov [edi + UDP_header.Length], cx |
rol [edi + UDP_header.Length], 8 |
pop esi |
push edi ecx |
sub ecx, sizeof.UDP_header |
add edi, sizeof.UDP_header |
shr ecx, 2 |
rep movsd |
mov ecx, [esp] |
and ecx, 3 |
rep movsb |
pop ecx edi |
pop dword [edi + UDP_header.SourcePort] |
; Checksum |
mov esi, edi |
mov [edi + UDP_header.Checksum], 0 |
UDP_checksum (edi-4), (edi-8) ; FIXME: IPv4 packet could have options.. |
DEBUGF 1,"UDP_output: sending with device %x\n", ebx |
call [ebx + NET_DEVICE.transmit] |
test eax, eax |
jnz @f |
inc [UDP_PACKETS_TX] ; FIXME: correct device? |
@@: |
ret |
.fail: |
DEBUGF 1,"UDP_output: failed\n" |
add esp, 4+4+8 |
or eax, -1 |
ret |
;--------------------------------------------------------------------------- |
; |
; UDP_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;--------------------------------------------------------------------------- |
align 4 |
UDP_api: |
movzx eax, bh |
shl eax, 2 |
test bl, bl |
jz .packets_tx ; 0 |
dec bl |
jz .packets_rx ; 1 |
.error: |
mov eax, -1 |
ret |
.packets_tx: |
mov eax, [UDP_PACKETS_TX + eax] |
ret |
.packets_rx: |
mov eax, [UDP_PACKETS_RX + eax] |
ret |
endp |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/ethernet.inc |
---|
0,0 → 1,525 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ETHERNET.INC ;; |
;; ;; |
;; Ethernet network layer for Menuet OS ;; |
;; ;; |
;; 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
;******************************************************************** |
; Interface |
; ethernet_driver called by stack_handler in stack.inc |
; eth_probe called by app_stack_handler in stack.inc |
; |
;******************************************************************** |
ETHER_IP equ 0x0008 ; Reversed from 0800 for intel |
ETHER_ARP equ 0x0608 ; Reversed from 0806 for intel |
ETHER_RARP equ 0x3580 |
struc ETH_FRAME |
{ .DstMAC dp ? ;destination MAC-address [6 bytes] |
.SrcMAC dp ? ;source MAC-address [6 bytes] |
.Type dw ? ;type of the upper-layer protocol [2 bytes] |
.Data db ? ;data [46-1500 bytes] |
} |
virtual at Ether_buffer |
ETH_FRAME ETH_FRAME |
end virtual |
; 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 "drivers/rtl8029.inc" |
include "drivers/i8255x.inc" |
include "drivers/rtl8139.inc" |
include "drivers/3c59x.inc" |
include "drivers/sis900.inc" |
include "drivers/pcnet32.inc" |
include "drivers/rtl8169.inc" |
include "drivers/forcedeth.inc" |
include "drivers/r6040.inc" |
; 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 24 ; Size of each PCICARDS entry |
iglobal |
PCICards: |
dd 0x12098086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 |
dd 0x10298086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 |
dd 0x12298086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 |
dd 0x10308086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 |
dd 0x24498086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 |
dd 0x10688086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit, 0 |
dd 0x802910ec, rtl8029_probe, rtl8029_reset, rtl8029_poll, rtl8029_transmit, 0 |
dd 0x813910ec, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x813810ec, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x12111113, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x13601500, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x13604033, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x13001186, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x13401186, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0xab0613d1, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0xa1171259, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0xa11e1259, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0xab0614ea, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0xab0714ea, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x123411db, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x91301432, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x101202ac, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x0106018a, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x1211126c, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x81391743, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x8139021b, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit, rtl8139_cable |
dd 0x816810ec, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 |
dd 0x816910ec, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 |
dd 0x011616ec, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 |
dd 0x43001186, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 |
dd 0x816710ec, rtl8169_probe, rtl8169_reset, rtl8169_poll, rtl8169_transmit, 0 |
dd 0x590010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x592010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x597010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x595010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x595110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x595210b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x900010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x900110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x900410b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x900510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x900610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x900A10b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x905010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x905110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x905510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x905810b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x905A10b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x920010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x980010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x980510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x764610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x505510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x605510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x605610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x5b5710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x505710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x515710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x525710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x656010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x656210b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x656410b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x450010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit, 0 |
dd 0x09001039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit, 0 |
dd 0x70161039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit, 0 |
dd 0x20001022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit, 0 |
dd 0x26251022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit, 0 |
dd 0x20011022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit, 0 |
dd 0x006610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; nVidia Corporation nForce2 Ethernet Controller |
dd 0x01c310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x00D610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x008610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x008c10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x00e610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x00df10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x005610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x005710de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x003710de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x003810de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x026810de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x026910de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x037210de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x037310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x03e510de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x03e610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x03ee10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x03ef10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x045010de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x045110de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x045210de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x045310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x054c10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x054d10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x054e10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x054f10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x07dc10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x07dd10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x07de10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x07df10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x076010de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; MCP77 Ethernet Controller |
dd 0x076110de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x076210de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x076310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x0ab010de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x0ab110de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x0ab210de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x0ab310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x0d7d10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested |
dd 0x604017F3, r6040_probe, r6040_reset, r6040_poll, r6040_transmit, 0 |
rb PCICARDS_ENTRY_SIZE ; end of list marker, do not remove |
endg |
uglobal |
;Net-stack's interface's settings |
node_addr: |
db 0,0,0,0,0,0 |
gateway_ip: |
dd 0 |
dns_ip: |
dd 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 |
drvr_cable: |
dd 0 |
endg |
iglobal |
broadcast_add: |
db 0xff,0xff,0xff,0xff,0xff,0xff |
subnet_mask: |
dd 0x00ffffff ; 255.255.255.0 |
endg |
include "arp.inc" ;arp-protocol functions |
include "pci.inc" ;PCI bus access functions |
;*************************************************************************** |
; 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 |
; |
;*************************************************************************** |
proc eth_tx stdcall uses ebx esi edi |
local MACAddress dp ? ;allocate 6 bytes in the stack |
; Look for a buffer to tx |
mov eax, NET1OUT_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je .exit ; Exit if no buffer available |
push eax;save buffer number |
; convert buffer pointer eax to the absolute address |
imul eax, IPBUFFSIZE |
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 ) |
cld |
mov esi, broadcast_add |
lea edi, [MACAddress] |
movsd |
movsw |
cmp edx, 0xffffffff |
je .send ; If it is broadcast, just send |
lea eax, [MACAddress];cause this is local variable |
stdcall arp_table_manager, ARP_TABLE_IP_TO_MAC, edx, eax;opcode,IP,MAC_ptr - Get the MAC address. |
cmp eax, ARP_VALID_MAPPING |
je .send |
; No valid entry. Has the request been sent, but timed out? |
cmp eax, ARP_RESPONSE_TIMEOUT |
je .freebuf |
.wait_response: ;we wait arp-response |
; Re-queue the packet, and exit |
pop ebx |
mov eax, NET1OUT_QUEUE |
call queue ; Get the buffer back |
jmp .exit |
.send: ;if ARP_VALID_MAPPING then send the packet |
lea edi, [MACAddress] ; Pointer to 48 bit destination address |
movzx ecx, word[ebx+2] ; Size of IP packet to send |
xchg ch, cl ; because mirror byte-order |
mov esi, ebx ; Pointer to packet data |
mov bx, ETHER_IP ; Type of packet |
push ebp |
call dword [drvr_transmit]; Call the drivers transmit function |
pop ebp |
; OK, we have sent a packet, so increment the count |
inc dword [ip_tx_count] |
; And finally, return the buffer to the free queue |
.freebuf: |
pop eax |
call freeBuff |
.exit: |
ret |
endp |
;*************************************************************************** |
; 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 |
; |
;*************************************************************************** |
;uglobal |
; ether_IP_handler_cnt dd ? |
;endg |
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, ETH_FRAME.Data |
; Now store it all away |
mov ecx, IPBUFFSIZE / 4 ; Copy all of the available |
; data across - worse case |
cld |
rep movsd |
; inc [ether_IP_handler_cnt] |
; DEBUGF 1, "K : ether_IP_handler (%u)\n", [ether_IP_handler_cnt] |
; And finally, place the buffer in the IPRX queue |
pop ebx |
mov eax, IPIN_QUEUE |
call queue |
eiph00x: |
ret |
;*************************************************************************** |
; 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 .exit |
; Check the protocol. Call appropriate handler |
mov ax, [ETH_FRAME.Type]; The address of the protocol word |
cmp ax, ETHER_IP |
je .is_ip ; It's IP |
cmp ax, ETHER_ARP |
je .is_arp ; It is ARP |
; DEBUGF 1,"K : eth_rx - dumped (%u)\n", ax |
inc [dumped_rx_count] |
jmp .exit ; If not IP or ARP, ignore |
.is_ip: |
; DEBUGF 1,"K : eth_rx - IP packet\n" |
inc dword [ip_rx_count] |
call ether_IP_handler |
jmp .exit |
.is_arp: |
; DEBUGF 1,"K : eth_rx - ARP packet\n" |
; At this point, the packet is still in the Ether_buffer |
call arp_handler |
.exit: |
ret |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/pcnet32.inc |
---|
0,0 → 1,848 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; PCNET32.INC ;; |
;; ;; |
;; Ethernet driver for Menuet OS ;; |
;; ;; |
;; - Version 1.0 31 July 2004: ;; |
;; Initial release ;; |
;; ;; |
;; - Version 1.01 29 March 2008: ;; |
;; Adapted to work with kolibrios flat kernel ;; |
;; Debug info is updated, and now uses DEBUGF macro ;; |
;; by hidnplayr@kolibrios.org ;; |
;; ;; |
;; 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
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 eax, ebx |
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 eax, ebx |
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 |
sub ebx, OS_BASE |
.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 eax, pcnet32_rx_ring |
sub eax, OS_BASE |
mov dword [pcnet32_private.rx_ring], eax |
mov eax, pcnet32_tx_ring |
sub eax, OS_BASE |
mov dword [pcnet32_private.tx_ring], eax |
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 |
; DEBUGF 1," K : ASEL, enable auto-negotiation\n" |
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 |
sub eax, OS_BASE |
and eax, 0xffff |
call dword [pcnet32_access.write_csr] |
mov eax, pcnet32_private |
sub eax, OS_BASE |
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: |
; DEBUGF 1," K : hardware reset\n" |
xor ebx, ebx |
mov eax, 0x0002 |
call dword [pcnet32_access.write_csr] |
xor ebx, ebx |
call dword [pcnet32_access.read_csr] |
; DEBUGF 1," K : PCNET reset complete\n" |
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 |
; DEBUGF 1," K : Using WIO\n" |
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 |
; DEBUGF 1," K : Using DWIO\n" |
mov esi, pcnet32_dwio |
jmp .L1 |
.no_dev: |
DEBUGF 1," K : PCNET32 not found\n" |
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 |
; DEBUGF 1," K : PCNET32 chip version OK\n" |
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 |
DEBUGF 1," K : Invalid chip rev\n" |
jmp .no_dev |
.L2: |
; DEBUGF 1," K : PCnet/PCI 79C970\n" |
jmp .L10 |
.L3: |
; DEBUGF 1," K : PCnet/PCI 79C970\n" |
jmp .L10 |
.L4: |
; DEBUGF 1," K : PCnet/PCI II 79C970A\n" |
mov [pcnet32_private.fdx], 1 |
jmp .L10 |
.L5: |
; DEBUGF 1," K : PCnet/FAST 79C971\n" |
mov [pcnet32_private.fdx], 1 |
mov [pcnet32_private.mii], 1 |
mov [pcnet32_private.fset], 1 |
mov [pcnet32_private.ltint], 1 |
jmp .L10 |
.L6: |
; DEBUGF 1," K : PCnet/FAST+ 79C972\n" |
mov [pcnet32_private.fdx], 1 |
mov [pcnet32_private.mii], 1 |
mov [pcnet32_private.fset], 1 |
jmp .L10 |
.L7: |
; DEBUGF 1," K : PCnet/FAST III 79C973\n" |
mov [pcnet32_private.fdx], 1 |
mov [pcnet32_private.mii], 1 |
jmp .L10 |
.L8: |
; DEBUGF 1," K : PCnet/Home 79C978\n" |
mov [pcnet32_private.fdx], 1 |
mov ebx, 49 |
call dword [pcnet32_access.read_bcr] |
call dword [pcnet32_access.write_bcr] |
jmp .L10 |
.L9: |
; DEBUGF 1," K : PCnet/FAST III 79C975\n" |
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 |
; DEBUGF 1," K : MAC read\n" |
call pcnet32_adjust_pci_device |
; DEBUGF 1," K : PCI done\n" |
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 eax, pcnet32_rx_ring |
sub eax, OS_BASE |
mov dword [pcnet32_private.rx_ring], eax |
mov eax, pcnet32_tx_ring |
sub eax, OS_BASE |
mov dword [pcnet32_private.tx_ring], eax |
; DEBUGF 1," K : Switching to 32\n" |
mov ebx, 20 |
mov eax, 2 |
call dword [pcnet32_access.write_bcr] |
mov ebx, 1 |
mov eax, ((pcnet32_private - OS_BASE) and 0xffff) |
call dword [pcnet32_access.write_csr] |
mov ebx, 2 |
mov eax, ((pcnet32_private - OS_BASE) 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 ax, ax |
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 |
mov ecx, [ebx+pcnet32_rx_head.msg_length] |
and ecx, 0xfff |
sub ecx, 4 |
mov [eth_rx_data_len], cx |
; DEBUGF 1," K : PCNETRX: %ub\n",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 |
; DEBUGF 1," K : PCNETTX\n" |
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 |
sub eax, OS_BASE |
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: |
DEBUGF 1," K : PCNET: Send timeout\n" |
.L3: |
mov dword [edi+pcnet32_tx_head.base], 0 |
pop ecx |
pop ebx |
pop esi |
pop edi |
ret |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/3c59x.inc |
---|
0,0 → 1,2404 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
;; 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 |
{ |
sub reg, OS_BASE |
} |
macro dma_to_virt reg |
{ |
add reg, OS_BASE |
} |
macro zero_to_virt reg |
{ |
} |
macro virt_to_zero reg |
{ |
} |
macro zero_to_dma reg |
{ |
sub reg, OS_BASE |
} |
macro dma_to_zero reg |
{ |
add reg, OS_BASE |
} |
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, 200000 |
.tx_reset_loop: |
in ax, dx |
test ah, 10000b ; check CmdInProgress |
jz .tx_set_prev |
dec ecx |
jns .tx_reset_loop |
.tx_set_prev: |
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 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/forcedeth.inc |
---|
0,0 → 1,2696 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; FORCEDETH.INC ;; |
;; ;; |
;; Ethernet driver for Kolibri OS ;; |
;; ;; |
;; Version 0.1 24 June 2008 - 23 Sep 2008 ;; |
;; ;; |
;; Driver for chips of NVIDIA nForce2 ;; |
;; References: ;; |
;; forcedeth.c - linux driver (etherboot project) ;; |
;; ethernet driver template by Mike Hibbett ;; |
;; ;; |
;; The copyright statement is ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;; Copyright 2008 shurf, ;; |
;; cit.utc@gmail.com ;; |
;; ;; |
;; See file COPYING for details ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
;******************************************************************** |
; Interface |
; forcedeth_reset |
; forcedeth_probe |
; forcedeth_poll |
; forcedeth_transmit |
; forcedeth_cable |
; |
;******************************************************************** |
;************************************************************************** |
; forcedeth Register Definitions |
;************************************************************************** |
PCI_REG_COMMAND equ 0x04 ; command register |
PCI_COMMAND_IO equ 0x01 ; Enable response in I/O space |
PCI_COMMAND_MASTER equ 0x04 ; Enable bus mastering |
PCI_LATENCY_TIMER equ 0x0d ; 8 bits |
PCI_VENDOR_ID equ 0x00 ; 16 bit |
PCI_REVISION_ID equ 0x08 ; 8 bits |
PCI_BASE_ADDRESS_0 equ 0x10 ; 32 bits |
PCI_BASE_ADDRESS_1 equ 0x14 ; 32 bits |
PCI_BASE_ADDRESS_2 equ 0x18 ; 32 bits |
PCI_BASE_ADDRESS_3 equ 0x1c ; 32 bits |
PCI_BASE_ADDRESS_4 equ 0x20 ; 32 bits |
PCI_BASE_ADDRESS_5 equ 0x24 ; 32 bits |
PCI_BASE_ADDRESS_SPACE_IO equ 0x01 |
PCI_BASE_ADDRESS_IO_MASK equ (not 0x03) |
PCI_BASE_ADDRESS_MEM_MASK equ (not 0x0f) |
PCI_BASE_ADDRESS_MEM_TYPE_MASK equ 0x06 |
PCI_BASE_ADDRESS_MEM_TYPE_32 equ 0x00 ; 32 bit address |
PCI_BASE_ADDRESS_MEM_TYPE_1M equ 0x02 ; Below 1M [obsolete] |
PCI_BASE_ADDRESS_MEM_TYPE_64 equ 0x04 ; 64 bit address |
; NIC specific static variables go here |
PCI_DEVICE_ID_NVIDIA_NVENET_1 equ 0x01c3 |
PCI_DEVICE_ID_NVIDIA_NVENET_2 equ 0x0066 |
PCI_DEVICE_ID_NVIDIA_NVENET_4 equ 0x0086 |
PCI_DEVICE_ID_NVIDIA_NVENET_5 equ 0x008c |
PCI_DEVICE_ID_NVIDIA_NVENET_3 equ 0x00d6 |
PCI_DEVICE_ID_NVIDIA_NVENET_7 equ 0x00df |
PCI_DEVICE_ID_NVIDIA_NVENET_6 equ 0x00e6 |
PCI_DEVICE_ID_NVIDIA_NVENET_8 equ 0x0056 |
PCI_DEVICE_ID_NVIDIA_NVENET_9 equ 0x0057 |
PCI_DEVICE_ID_NVIDIA_NVENET_10 equ 0x0037 |
PCI_DEVICE_ID_NVIDIA_NVENET_11 equ 0x0038 |
PCI_DEVICE_ID_NVIDIA_NVENET_12 equ 0x0268 |
PCI_DEVICE_ID_NVIDIA_NVENET_13 equ 0x0269 |
PCI_DEVICE_ID_NVIDIA_NVENET_14 equ 0x0372 |
PCI_DEVICE_ID_NVIDIA_NVENET_15 equ 0x0373 |
ETH_DATA_LEN equ 1500 |
; rx/tx mac addr + type + vlan + align + slack |
RX_NIC_BUFSIZE equ (ETH_DATA_LEN + 64) |
; even more slack |
RX_ALLOC_BUFSIZE equ (ETH_DATA_LEN + 128) |
NvRegIrqStatus equ 0x00 |
NvRegIrqMask equ 0x04 |
NvRegUnknownSetupReg6 equ 0x08 |
NvRegPollingInterval equ 0x0c |
NvRegMacReset equ 0x3c |
NvRegMisc1 equ 0x80 |
NvRegTransmitterControl equ 0x84 |
NvRegTransmitterStatus equ 0x88 |
NvRegPacketFilterFlags equ 0x8c |
NvRegOffloadConfig equ 0x90 |
NvRegReceiverControl equ 0x94 |
NvRegReceiverStatus equ 0x98 |
NvRegRandomSeed equ 0x9c |
NvRegUnknownSetupReg1 equ 0xA0 |
NvRegUnknownSetupReg2 equ 0xA4 |
NvRegMacAddrA equ 0xA8 ; MAC address low |
NvRegMacAddrB equ 0xAC ; MAC address high |
NvRegMulticastAddrA equ 0xB0 |
NvRegMulticastAddrB equ 0xB4 |
NvRegMulticastMaskA equ 0xB8 |
NvRegMulticastMaskB equ 0xBC |
NvRegPhyInterface equ 0xC0 |
NvRegTxRingPhysAddr equ 0x100 |
NvRegRxRingPhysAddr equ 0x104 |
NvRegRingSizes equ 0x108 |
NvRegUnknownTransmitterReg equ 0x10c |
NvRegLinkSpeed equ 0x110 |
NvRegUnknownSetupReg5 equ 0x130 |
NvRegUnknownSetupReg3 equ 0x13c |
NvRegTxRxControl equ 0x144 |
NvRegMIIStatus equ 0x180 |
NvRegUnknownSetupReg4 equ 0x184 |
NvRegAdapterControl equ 0x188 |
NvRegMIISpeed equ 0x18c |
NvRegMIIControl equ 0x190 |
NvRegMIIData equ 0x194 |
NvRegWakeUpFlags equ 0x200 |
NvRegPowerState equ 0x26c |
NvRegPowerState2 equ 0x600 |
NVREG_UNKSETUP1_VAL equ 0x16070f |
NVREG_UNKSETUP2_VAL equ 0x16 |
NVREG_UNKSETUP3_VAL1 equ 0x200010 |
NVREG_UNKSETUP4_VAL equ 8 |
NVREG_UNKSETUP5_BIT31 equ (1 shl 31) |
NVREG_UNKSETUP6_VAL equ 3 |
NVREG_TXRXCTL_RXCHECK equ 0x0400 |
NVREG_MIISTAT_ERROR equ 0x0001 |
NVREG_MIISTAT_MASK equ 0x000f |
NVREG_MIISTAT_MASK2 equ 0x000f |
NVREG_MIICTL_INUSE equ 0x08000 |
NVREG_MIICTL_WRITE equ 0x00400 |
NVREG_MIICTL_ADDRSHIFT equ 5 |
NVREG_MIISPEED_BIT8 equ (1 shl 8) |
NVREG_MIIDELAY equ 5 |
NVREG_IRQ_RX_ERROR equ 0x0001 |
NVREG_IRQ_RX equ 0x0002 |
NVREG_IRQ_RX_NOBUF equ 0x0004 |
NVREG_IRQ_LINK equ 0x0040 |
NVREG_IRQ_TIMER equ 0x0020 |
NVREG_IRQMASK_WANTED_2 equ 0x0147 |
NVREG_IRQ_RX_ALL equ (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF) |
NVREG_IRQ_TX_ALL equ 0 ; ??????????? |
NVREG_IRQ_OTHER_ALL equ (NVREG_IRQ_LINK or NVREG_IRQ_TIMER) |
NVREG_IRQSTAT_MASK equ 0x1ff |
NVREG_TXRXCTL_KICK equ 0x0001 |
NVREG_TXRXCTL_BIT1 equ 0x0002 |
NVREG_TXRXCTL_BIT2 equ 0x0004 |
NVREG_TXRXCTL_IDLE equ 0x0008 |
NVREG_TXRXCTL_RESET equ 0x0010 |
NVREG_TXRXCTL_RXCHECK equ 0x0400 |
NVREG_MCASTADDRA_FORCE equ 0x01 |
NVREG_MAC_RESET_ASSERT equ 0x0F3 |
NVREG_MISC1_HD equ 0x02 |
NVREG_MISC1_FORCE equ 0x3b0f3c |
NVREG_PFF_ALWAYS equ 0x7F0008 |
NVREG_PFF_PROMISC equ 0x80 |
NVREG_PFF_MYADDR equ 0x20 |
NVREG_OFFLOAD_HOMEPHY equ 0x601 |
NVREG_OFFLOAD_NORMAL equ RX_NIC_BUFSIZE |
NVREG_RNDSEED_MASK equ 0x00ff |
NVREG_RNDSEED_FORCE equ 0x7f00 |
NVREG_RNDSEED_FORCE2 equ 0x2d00 |
NVREG_RNDSEED_FORCE3 equ 0x7400 |
; NVREG_POLL_DEFAULT is the interval length of the timer source on the nic |
; NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms |
NVREG_POLL_DEFAULT equ 970 |
NVREG_ADAPTCTL_START equ 0x02 |
NVREG_ADAPTCTL_LINKUP equ 0x04 |
NVREG_ADAPTCTL_PHYVALID equ 0x40000 |
NVREG_ADAPTCTL_RUNNING equ 0x100000 |
NVREG_ADAPTCTL_PHYSHIFT equ 24 |
NVREG_WAKEUPFLAGS_VAL equ 0x7770 |
NVREG_POWERSTATE_POWEREDUP equ 0x8000 |
NVREG_POWERSTATE_VALID equ 0x0100 |
NVREG_POWERSTATE_MASK equ 0x0003 |
NVREG_POWERSTATE_D0 equ 0x0000 |
NVREG_POWERSTATE_D1 equ 0x0001 |
NVREG_POWERSTATE_D2 equ 0x0002 |
NVREG_POWERSTATE_D3 equ 0x0003 |
NVREG_POWERSTATE2_POWERUP_MASK equ 0x0F11 |
NVREG_POWERSTATE2_POWERUP_REV_A3 equ 0x0001 |
NVREG_RCVCTL_START equ 0x01 |
NVREG_RCVSTAT_BUSY equ 0x01 |
NVREG_XMITCTL_START equ 0x01 |
NVREG_LINKSPEED_FORCE equ 0x10000 |
NVREG_LINKSPEED_10 equ 1000 |
NVREG_LINKSPEED_100 equ 100 |
NVREG_LINKSPEED_1000 equ 50 |
NVREG_RINGSZ_TXSHIFT equ 0 |
NVREG_RINGSZ_RXSHIFT equ 16 |
LPA_1000FULL equ 0x0800 |
; Link partner ability register. |
LPA_SLCT equ 0x001f ; Same as advertise selector |
LPA_10HALF equ 0x0020 ; Can do 10mbps half-duplex |
LPA_10FULL equ 0x0040 ; Can do 10mbps full-duplex |
LPA_100HALF equ 0x0080 ; Can do 100mbps half-duplex |
LPA_100FULL equ 0x0100 ; Can do 100mbps full-duplex |
LPA_100BASE4 equ 0x0200 ; Can do 100mbps 4k packets |
LPA_RESV equ 0x1c00 ; Unused... |
LPA_RFAULT equ 0x2000 ; Link partner faulted |
LPA_LPACK equ 0x4000 ; Link partner acked us |
LPA_NPAGE equ 0x8000 ; Next page bit |
MII_READ equ (-1) |
MII_PHYSID1 equ 0x02 ; PHYS ID 1 |
MII_PHYSID2 equ 0x03 ; PHYS ID 2 |
MII_BMCR equ 0x00 ; Basic mode control register |
MII_BMSR equ 0x01 ; Basic mode status register |
MII_ADVERTISE equ 0x04 ; Advertisement control reg |
MII_LPA equ 0x05 ; Link partner ability reg |
MII_SREVISION equ 0x16 ; Silicon revision |
MII_RESV1 equ 0x17 ; Reserved... |
MII_NCONFIG equ 0x1c ; Network interface config |
; PHY defines |
PHY_OUI_MARVELL equ 0x5043 |
PHY_OUI_CICADA equ 0x03f1 |
PHYID1_OUI_MASK equ 0x03ff |
PHYID1_OUI_SHFT equ 6 |
PHYID2_OUI_MASK equ 0xfc00 |
PHYID2_OUI_SHFT equ 10 |
PHY_INIT1 equ 0x0f000 |
PHY_INIT2 equ 0x0e00 |
PHY_INIT3 equ 0x01000 |
PHY_INIT4 equ 0x0200 |
PHY_INIT5 equ 0x0004 |
PHY_INIT6 equ 0x02000 |
PHY_GIGABIT equ 0x0100 |
PHY_TIMEOUT equ 0x1 |
PHY_ERROR equ 0x2 |
PHY_100 equ 0x1 |
PHY_1000 equ 0x2 |
PHY_HALF equ 0x100 |
PHY_RGMII equ 0x10000000 |
; desc_ver values: |
; This field has two purposes: |
; - Newer nics uses a different ring layout. The layout is selected by |
; comparing np->desc_ver with DESC_VER_xy. |
; - It contains bits that are forced on when writing to NvRegTxRxControl. |
DESC_VER_1 equ 0x0 |
DESC_VER_2 equ (0x02100 or NVREG_TXRXCTL_RXCHECK) |
MAC_ADDR_LEN equ 6 |
NV_TX_LASTPACKET equ (1 shl 16) |
NV_TX_RETRYERROR equ (1 shl 19) |
NV_TX_LASTPACKET1 equ (1 shl 24) |
NV_TX_DEFERRED equ (1 shl 26) |
NV_TX_CARRIERLOST equ (1 shl 27) |
NV_TX_LATECOLLISION equ (1 shl 28) |
NV_TX_UNDERFLOW equ (1 shl 29) |
NV_TX_ERROR equ (1 shl 30) |
NV_TX_VALID equ (1 shl 31) |
NV_TX2_LASTPACKET equ (1 shl 29) |
NV_TX2_RETRYERROR equ (1 shl 18) |
NV_TX2_LASTPACKET1 equ (1 shl 23) |
NV_TX2_DEFERRED equ (1 shl 25) |
NV_TX2_CARRIERLOST equ (1 shl 26) |
NV_TX2_LATECOLLISION equ (1 shl 27) |
NV_TX2_UNDERFLOW equ (1 shl 28) |
; error and valid are the same for both |
NV_TX2_ERROR equ (1 shl 30) |
NV_TX2_VALID equ (1 shl 31) |
NV_RX_DESCRIPTORVALID equ (1 shl 16) |
NV_RX_AVAIL equ (1 shl 31) |
NV_RX2_DESCRIPTORVALID equ (1 shl 29) |
RX_RING equ 4 |
TX_RING equ 2 |
FLAG_MASK_V1 equ 0xffff0000 |
FLAG_MASK_V2 equ 0xffffc000 |
LEN_MASK_V1 equ (0xffffffff xor FLAG_MASK_V1) |
LEN_MASK_V2 equ (0xffffffff xor FLAG_MASK_V2) |
; Miscelaneous hardware related defines: |
NV_PCI_REGSZ_VER1 equ 0x270 |
NV_PCI_REGSZ_VER2 equ 0x604 |
; various timeout delays: all in usec |
NV_TXRX_RESET_DELAY equ 4 |
NV_TXSTOP_DELAY1 equ 10 |
NV_TXSTOP_DELAY1MAX equ 500000 |
NV_TXSTOP_DELAY2 equ 100 |
NV_RXSTOP_DELAY1 equ 10 |
NV_RXSTOP_DELAY1MAX equ 500000 |
NV_RXSTOP_DELAY2 equ 100 |
NV_SETUP5_DELAY equ 5 |
NV_SETUP5_DELAYMAX equ 50000 |
NV_POWERUP_DELAY equ 5 |
NV_POWERUP_DELAYMAX equ 5000 |
NV_MIIBUSY_DELAY equ 50 |
NV_MIIPHY_DELAY equ 10 |
NV_MIIPHY_DELAYMAX equ 10000 |
NV_MAC_RESET_DELAY equ 64 |
NV_WAKEUPPATTERNS equ 5 |
NV_WAKEUPMASKENTRIES equ 4 |
; Advertisement control register. |
ADVERTISE_SLCT equ 0x001f ; Selector bits |
ADVERTISE_CSMA equ 0x0001 ; Only selector supported |
ADVERTISE_10HALF equ 0x0020 ; Try for 10mbps half-duplex |
ADVERTISE_10FULL equ 0x0040 ; Try for 10mbps full-duplex |
ADVERTISE_100HALF equ 0x0080 ; Try for 100mbps half-duplex |
ADVERTISE_100FULL equ 0x0100 ; Try for 100mbps full-duplex |
ADVERTISE_100BASE4 equ 0x0200 ; Try for 100mbps 4k packets |
ADVERTISE_RESV equ 0x1c00 ; Unused... |
ADVERTISE_RFAULT equ 0x2000 ; Say we can detect faults |
ADVERTISE_LPACK equ 0x4000 ; Ack link partners response |
ADVERTISE_NPAGE equ 0x8000 ; Next page bit |
ADVERTISE_FULL equ (ADVERTISE_100FULL or ADVERTISE_10FULL or ADVERTISE_CSMA) |
ADVERTISE_ALL equ (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL) |
MII_1000BT_CR equ 0x09 |
MII_1000BT_SR equ 0x0a |
ADVERTISE_1000FULL equ 0x0200 |
ADVERTISE_1000HALF equ 0x0100 |
BMCR_ANRESTART equ 0x0200 ; Auto negotiation restart |
BMCR_ANENABLE equ 0x1000 ; Enable auto negotiation |
BMCR_SPEED100 equ 0x2000 ; Select 100Mbps |
BMCR_LOOPBACK equ 0x4000 ; TXD loopback bits |
BMCR_RESET equ 0x8000 ; Reset the DP83840 |
; Basic mode status register. |
BMSR_ERCAP equ 0x0001 ; Ext-reg capability |
BMSR_JCD equ 0x0002 ; Jabber detected |
BMSR_LSTATUS equ 0x0004 ; Link status |
BMSR_ANEGCAPABLE equ 0x0008 ; Able to do auto-negotiation |
BMSR_RFAULT equ 0x0010 ; Remote fault detected |
BMSR_ANEGCOMPLETE equ 0x0020 ; Auto-negotiation complete |
BMSR_RESV equ 0x07c0 ; Unused... |
BMSR_10HALF equ 0x0800 ; Can do 10mbps, half-duplex |
BMSR_10FULL equ 0x1000 ; Can do 10mbps, full-duplex |
BMSR_100HALF equ 0x2000 ; Can do 100mbps, half-duplex |
BMSR_100FULL equ 0x4000 ; Can do 100mbps, full-duplex |
BMSR_100BASE4 equ 0x8000 ; Can do 100mbps, 4k packets |
ETH_ALEN equ 6 |
ETH_HLEN equ (2 * ETH_ALEN + 2) |
ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for |
; mininmum 64bytes frame length |
uglobal |
forcedeth_mmio_addr dd 0 ; memory map physical address |
forcedeth_mmio_size dd 0 ; size of memory bar |
forcedeth_vendor_id dw 0 ; Vendor ID |
forcedeth_device_id dw 0 ; Device ID |
forcedeth_orig_mac0 dd 0 ; MAC |
forcedeth_orig_mac1 dd 0 ; MAC |
forcedeth_mapio_addr dd 0 ; mapped IO address |
forcedeth_txflags dd 0 ; |
forcedeth_desc_ver dd 0 ; |
forcedeth_irqmask dd 0 ; IRQ-mask |
forcedeth_wolenabled dd 0 ; WOL |
forcedeth_in_shutdown dd 0 ; |
forcedeth_cur_rx dd 0 ; |
forcedeth_refill_rx dd 0 ; |
forcedeth_phyaddr dd 0 ; |
forcedeth_phy_oui dd 0 ; |
forcedeth_gigabit dd 0 ; |
forcedeth_needs_mac_reset dd 0 ; |
forcedeth_linkspeed dd 0 ; |
forcedeth_duplex dd 0 ; |
forcedeth_next_tx dd 0 ; next TX descriptor number |
forcedeth_nic_tx dd 0 ; ??? d'nt used ??? |
forcedeth_packetlen dd 0 ; |
forcedeth_nocable dd 0 ; no cable present |
endg |
struc forcedeth_TxDesc { |
.PacketBuffer dd ? |
.FlagLen dd ? |
} |
virtual at 0 |
forcedeth_TxDesc forcedeth_TxDesc |
sizeof.forcedeth_TxDesc = $ - forcedeth_TxDesc |
end virtual |
struc forcedeth_RxDesc { |
.PacketBuffer dd ? |
.FlagLen dd ? |
} |
virtual at 0 |
forcedeth_RxDesc forcedeth_RxDesc |
sizeof.forcedeth_RxDesc = $ - forcedeth_RxDesc |
end virtual |
virtual at eth_data_start |
; Define the TX Descriptor |
align 256 |
forcedeth_tx_ring rb TX_RING * sizeof.forcedeth_TxDesc |
; Create a static buffer of size RX_BUF_SZ for each |
; TX Descriptor. All descriptors point to a |
; part of this buffer |
align 256 |
forcedeth_txb rb TX_RING * RX_NIC_BUFSIZE |
; Define the RX Descriptor |
align 256 |
forcedeth_rx_ring rb RX_RING * sizeof.forcedeth_RxDesc |
; Create a static buffer of size RX_BUF_SZ for each |
; RX Descriptor. All descriptors point to a |
; part of this buffer |
align 256 |
forcedeth_rxb rb RX_RING * RX_NIC_BUFSIZE |
end virtual |
;*************************************************************************** |
; Function |
; forcedeth_reset |
; Description |
; Place the chip (ie, the ethernet card) into a virgin state |
; No inputs |
; All registers destroyed |
; |
;*************************************************************************** |
forcedeth_reset: |
; 1) erase previous misconfiguration |
; 4.1-1: stop adapter: ignored, 4.3 seems to be overkill |
; writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA) |
mov edi, dword [forcedeth_mapio_addr] |
mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE |
; writel(0, base + NvRegMulticastAddrB) |
mov dword [edi+NvRegMulticastAddrB], 0 |
; writel(0, base + NvRegMulticastMaskA) |
mov dword [edi+NvRegMulticastMaskA], 0 |
; writel(0, base + NvRegMulticastMaskB) |
mov dword [edi+NvRegMulticastMaskB], 0 |
; writel(0, base + NvRegPacketFilterFlags) |
mov dword [edi+NvRegPacketFilterFlags], 0 |
; writel(0, base + NvRegTransmitterControl) |
mov dword [edi+NvRegTransmitterControl], 0 |
; writel(0, base + NvRegReceiverControl) |
mov dword [edi+NvRegReceiverControl], 0 |
; writel(0, base + NvRegAdapterControl) |
mov dword [edi+NvRegAdapterControl], 0 |
; 2) initialize descriptor rings |
; init_ring(nic) |
call forcedeth_init_ring |
; writel(0, base + NvRegLinkSpeed) |
mov dword [edi+NvRegLinkSpeed], 0 |
; writel(0, base + NvRegUnknownTransmitterReg) |
mov dword [edi+NvRegUnknownTransmitterReg], 0 |
; txrx_reset(nic) |
call forcedeth_txrx_reset |
; writel(0, base + NvRegUnknownSetupReg6) |
mov dword [edi+NvRegUnknownSetupReg6], 0 |
; np->in_shutdown = 0 |
mov dword [forcedeth_in_shutdown], 0 |
; 3) set mac address |
; writel(mac[0], base + NvRegMacAddrA) |
mov eax, dword [forcedeth_orig_mac0] |
mov dword [edi+NvRegMacAddrA], eax |
; writel(mac[1], base + NvRegMacAddrB) |
mov eax, dword [forcedeth_orig_mac1] |
mov dword [edi+NvRegMacAddrB], eax |
; 4) give hw rings |
; writel((u32) virt_to_le32desc(&rx_ring[0]), base + NvRegRxRingPhysAddr) |
mov eax, forcedeth_rx_ring |
;DEBUGF 1," K : FORCEDETH: rx_ring at 0x%x\n", eax |
sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
mov dword [edi+NvRegRxRingPhysAddr], eax |
; writel((u32) virt_to_le32desc(&tx_ring[0]), base + NvRegTxRingPhysAddr) |
mov eax, forcedeth_tx_ring |
sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
mov dword [edi+NvRegTxRingPhysAddr], eax |
; writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes) |
mov dword [edi+NvRegRingSizes], (((RX_RING - 1) shl NVREG_RINGSZ_RXSHIFT) + ((TX_RING - 1) shl NVREG_RINGSZ_TXSHIFT)) |
; 5) continue setup |
; np->linkspeed = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 |
mov dword [forcedeth_linkspeed], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) |
; np->duplex = 0 |
mov dword [forcedeth_duplex], 0 |
; writel(np->linkspeed, base + NvRegLinkSpeed) |
mov dword [edi+NvRegLinkSpeed], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) |
; writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3) |
mov dword [edi+NvRegUnknownSetupReg3], NVREG_UNKSETUP3_VAL1 |
; writel(np->desc_ver, base + NvRegTxRxControl) |
mov eax, dword [forcedeth_desc_ver] |
mov dword [edi+NvRegTxRxControl], eax |
; pci_push(base) |
call forcedeth_pci_push |
; writel(NVREG_TXRXCTL_BIT1 | np->desc_ver, base + NvRegTxRxControl) |
or eax, NVREG_TXRXCTL_BIT1 |
mov dword [edi+NvRegTxRxControl], eax |
; reg_delay(NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, "open: SetupReg5, Bit 31 remained off\n") |
push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;; |
stdcall forcedeth_reg_delay, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, 0 |
pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;; |
; writel(0, base + NvRegUnknownSetupReg4) |
mov dword [edi+NvRegUnknownSetupReg4], 0 |
; writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus) |
mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK2 |
; printf("%d-Mbs Link, %s-Duplex\n", np->linkspeed & NVREG_LINKSPEED_10 ? 10 : 100, np->duplex ? "Full" : "Half") |
;;;;;;;;;;; DEBUGF |
; 6) continue setup |
; writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1) |
mov dword [edi+NvRegMisc1], (NVREG_MISC1_FORCE or NVREG_MISC1_HD) |
; writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus) |
mov eax, dword [edi+NvRegTransmitterStatus] |
mov dword [edi+NvRegTransmitterStatus], eax |
; writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags) |
mov dword [edi+NvRegPacketFilterFlags], NVREG_PFF_ALWAYS |
; writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig) |
mov dword [edi+NvRegOffloadConfig], NVREG_OFFLOAD_NORMAL |
; writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus) |
mov eax, dword [edi+NvRegReceiverStatus] |
mov dword [edi+NvRegReceiverStatus], eax |
; Get a random number |
; i = random() |
push edi |
stdcall sys_clock ; eax = 0x00SSMMHH (current system time) |
pop edi |
; writel(NVREG_RNDSEED_FORCE | (i & NVREG_RNDSEED_MASK), base + NvRegRandomSeed) |
and eax, NVREG_RNDSEED_MASK |
or eax, NVREG_RNDSEED_FORCE |
mov dword [edi+NvRegRandomSeed], eax |
; writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1) |
mov dword [edi+NvRegUnknownSetupReg1], NVREG_UNKSETUP1_VAL |
; writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2) |
mov dword [edi+NvRegUnknownSetupReg2], NVREG_UNKSETUP2_VAL |
; writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval) |
mov dword [edi+NvRegPollingInterval], NVREG_POLL_DEFAULT |
; writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6) |
mov dword [edi+NvRegUnknownSetupReg6], NVREG_UNKSETUP6_VAL |
; writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT) | NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING, |
; base + NvRegAdapterControl) |
mov eax, dword [forcedeth_phyaddr] |
shl eax, NVREG_ADAPTCTL_PHYSHIFT |
or eax, (NVREG_ADAPTCTL_PHYVALID or NVREG_ADAPTCTL_RUNNING) |
mov dword [edi+NvRegAdapterControl], eax |
; writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed) |
mov dword [edi+NvRegMIISpeed], (NVREG_MIISPEED_BIT8 or NVREG_MIIDELAY) |
; writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4) |
mov dword [edi+NvRegUnknownSetupReg4], NVREG_UNKSETUP4_VAL |
; writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags) |
mov dword [edi+NvRegWakeUpFlags], NVREG_WAKEUPFLAGS_VAL |
; i = readl(base + NvRegPowerState) |
mov eax, dword [edi+NvRegPowerState] |
; if ((i & NVREG_POWERSTATE_POWEREDUP) == 0) |
test eax, NVREG_POWERSTATE_POWEREDUP |
jnz @f |
; writel(NVREG_POWERSTATE_POWEREDUP | i, base + NvRegPowerState) |
or eax, NVREG_POWERSTATE_POWEREDUP |
mov dword [edi+NvRegPowerState], eax |
@@: |
; pci_push(base) |
call forcedeth_pci_push |
; nv_udelay(10) |
mov esi, 10 |
call forcedeth_nv_udelay |
; writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState) |
mov eax, dword [edi+NvRegPowerState] |
or eax, NVREG_POWERSTATE_VALID |
mov dword [edi+NvRegPowerState], eax |
; ??? disable all interrupts ??? |
; writel(0, base + NvRegIrqMask) |
mov dword [edi+NvRegIrqMask], 0 |
;;; ; ??? Mask RX interrupts |
;;; mov dword [edi+NvRegIrqMask], NVREG_IRQ_RX_ALL |
;;; ; ??? Mask TX interrupts |
;;; ;mov dword [edi+NvRegIrqMask], NVREG_IRQ_TX_ALL |
;;; ; ??? Mask OTHER interrupts |
;;; mov dword [edi+NvRegIrqMask], NVREG_IRQ_OTHER_ALL |
; pci_push(base) |
call forcedeth_pci_push |
; writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus) |
mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK2 |
; writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus) |
mov dword [edi+NvRegIrqStatus], NVREG_IRQSTAT_MASK |
; pci_push(base) |
call forcedeth_pci_push |
; writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA) |
mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE |
; writel(0, base + NvRegMulticastAddrB) |
mov dword [edi+NvRegMulticastAddrB], 0 |
; writel(0, base + NvRegMulticastMaskA) |
mov dword [edi+NvRegMulticastMaskA], 0 |
; writel(0, base + NvRegMulticastMaskB) |
mov dword [edi+NvRegMulticastMaskB], 0 |
; writel(NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags) |
mov dword [edi+NvRegPacketFilterFlags], (NVREG_PFF_ALWAYS or NVREG_PFF_MYADDR) |
; set_multicast(nic) |
call forcedeth_set_multicast |
; One manual link speed update: Interrupts are enabled, future link |
; speed changes cause interrupts and are handled by nv_link_irq(). |
; miistat = readl(base + NvRegMIIStatus) |
mov eax, dword [edi+NvRegMIIStatus] |
; writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); |
mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK |
; dprintf(("startup: got 0x%hX.\n", miistat)); |
;;; DEBUGF 1," K : FORCEDETH: startup: got 0x%x\n", eax |
; ret = update_linkspeed(nic) |
call forcedeth_update_linkspeed |
push eax |
; start_tx(nic) |
call forcedeth_start_tx |
pop eax |
; if (ret) { |
; //Start Connection netif_carrier_on(dev); |
; } else { |
; printf("no link during initialization.\n"); |
; } |
;*** added by shurf (21.09.2008) |
mov dword [forcedeth_nocable], 0 |
;*** |
test eax, eax |
jnz .return |
DEBUGF 1," K : FORCEDETH: no link during initialization.\n" |
;*** added by shurf (21.09.2008) |
mov dword [forcedeth_nocable], 1 |
;*** |
.return: |
; Indicate that we have successfully reset the card |
mov eax, dword [pci_data] |
mov dword [eth_status], eax |
ret |
;*************************************************************************** |
; Function |
; forcedeth_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 |
; |
;*************************************************************************** |
forcedeth_probe: |
; DEBUGF 1," K : FORCEDETH: 0x%x 0x%x, 0x%x\n", [io_addr]:8,[pci_bus]:2,[pci_dev]:2 |
mov dword [forcedeth_needs_mac_reset], 0 |
; BEGIN of adjust_pci_device() |
; read word from PCI-device |
mov al, 1 ;;;;;;;;;;;;;;2 |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_REG_COMMAND |
call pci_read_reg |
mov bx, ax ; new command |
or bx, PCI_COMMAND_MASTER |
or bx, PCI_COMMAND_IO |
cmp bx, ax |
je @f |
; Enabling PCI-device (make card as bus master) |
DEBUGF 1," K : FORCEDETH: Updating PCI command 0x%x->0x%x\n", ax, bx |
mov cx, bx |
mov al, 1 ;;;;;;;;;;;;2 |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_REG_COMMAND |
call pci_write_reg |
; Check latency settings |
@@: |
; Get current latency settings from Latency timer register (byte) |
mov al, 0 ;;;;;;;;;1 |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_LATENCY_TIMER |
call pci_read_reg |
; see if its at least 32 |
cmp al, 32 |
jge @f |
; set latency to 32 |
DEBUGF 1, "K : FORCEDETH: PCI latency timer (CFLT) is unreasonably low at %d.\n", al |
DEBUGF 1, "K : FORCEDETH: Setting to 32 clocks.\n" |
mov cl, 32 |
mov al, 0 ;;;;;;;1 |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_LATENCY_TIMER |
call pci_write_reg |
; END of adjust_pci_device() |
@@: |
; BEGIN of pci_bar_start (addr = pci_bar_start(pci, PCI_BASE_ADDRESS_0)) |
mov al, 2 ; dword |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_BASE_ADDRESS_0 |
call pci_read_reg |
test eax, PCI_BASE_ADDRESS_SPACE_IO |
jz @f |
and eax, PCI_BASE_ADDRESS_IO_MASK |
jmp .next |
@@: |
push eax |
and eax, PCI_BASE_ADDRESS_MEM_TYPE_MASK |
cmp eax, PCI_BASE_ADDRESS_MEM_TYPE_64 |
jne .not64 |
mov al, 2 ; dword |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_BASE_ADDRESS_0 + 4 |
call pci_read_reg |
or eax, eax |
jz .not64 |
DEBUGF 1,"K : FORCEDETH: pci_bar_start: Unhandled 64bit BAR\n" |
or eax, -1 |
jmp .next |
.not64: |
pop eax |
and eax, PCI_BASE_ADDRESS_MEM_MASK |
.next: |
; END of pci_bar_start |
; addr = eax |
mov dword [forcedeth_mmio_addr], eax |
; BEGIN of pci_bar_size (sz = pci_bar_size(pci, PCI_BASE_ADDRESS_0)) |
; Save original bar |
mov al, 2 ; dword |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_BASE_ADDRESS_0 |
call pci_read_reg |
mov dword [forcedeth_tmp_start], eax |
; Compute which bits can be set |
; (ecx - value to write) |
mov al, 2 ; dword |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_BASE_ADDRESS_0 |
mov ecx, (not 0) |
call pci_write_reg |
mov al, 2 ; dword |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_BASE_ADDRESS_0 |
call pci_read_reg |
push eax |
; Restore the original size |
mov al, 2 ; dword |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_BASE_ADDRESS_0 |
mov ecx, dword [forcedeth_tmp_start] |
call pci_write_reg |
; Find the significant bits |
pop eax |
test dword [forcedeth_tmp_start], PCI_BASE_ADDRESS_SPACE_IO |
jz @f |
and eax, PCI_BASE_ADDRESS_IO_MASK |
jmp .next2 |
@@: |
and eax, PCI_BASE_ADDRESS_MEM_MASK |
.next2: |
; Find the lowest bit set |
mov ecx, eax |
sub eax, 1 |
not eax |
and ecx, eax |
; END of pci_bar_start |
mov dword [forcedeth_mmio_size], ecx |
DEBUGF 1," K : FORCEDETH: mmio_addr= 0x%x [mmio_size= 0x%x]\n", [forcedeth_mmio_addr]:8, [forcedeth_mmio_size]:8 |
; Get Vendor and Device ID |
mov al, 2 |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_VENDOR_ID |
call pci_read_reg |
mov word [forcedeth_vendor_id], ax |
shr eax, 16 |
mov word [forcedeth_device_id], ax |
DEBUGF 1," K : FORCEDETH: vendor_id= 0x%x device_id= 0x%x\n", [forcedeth_vendor_id]:4, [forcedeth_device_id]:4 |
; handle different descriptor versions |
mov eax, dword [forcedeth_device_id] |
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_1 |
je .ver1 |
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_2 |
je .ver1 |
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_3 |
je .ver1 |
mov dword [forcedeth_desc_ver], DESC_VER_2 |
jmp @f |
.ver1: |
mov dword [forcedeth_desc_ver], DESC_VER_1 |
@@: |
; read the mac address |
; map memory |
stdcall map_io_mem, [forcedeth_mmio_addr], [forcedeth_mmio_size], (PG_SW+PG_NOCACHE) |
test eax, eax |
jz .fail |
mov dword [forcedeth_mapio_addr], eax |
mov edi, eax |
mov eax, dword [edi+NvRegMacAddrA] |
mov dword [forcedeth_orig_mac0], eax |
mov edx, dword [edi+NvRegMacAddrB] |
mov dword [forcedeth_orig_mac1], edx |
; save MAC-address to global variable node_addr |
mov dword [node_addr], eax |
mov word [node_addr+4], dx |
; reverse if desired |
cmp word [forcedeth_device_id], 0x03E5 |
jae .no_reverse_mac |
mov al, byte [node_addr] |
xchg al, byte [node_addr+5] |
mov byte [node_addr], al |
mov al, byte [node_addr+1] |
xchg al, byte [node_addr+4] |
mov byte [node_addr+4], al |
mov al, byte [node_addr+2] |
xchg al, byte [node_addr+3] |
mov byte [node_addr+3], al |
.no_reverse_mac: |
; DEBUGF 1," K : FORCEDETH: orig_mac0= 0x%x\n", [forcedeth_orig_mac0]:8 |
; DEBUGF 1," K : FORCEDETH: orig_mac1= 0x%x\n", [forcedeth_orig_mac1]:8 |
DEBUGF 1," K : FORCEDETH: MAC = %x-%x-%x-%x-%x-%x\n", [node_addr+0]:2,[node_addr+1]:2,[node_addr+2]:2,[node_addr+3]:2,[node_addr+4]:2,[node_addr+5]:2, |
; disable WOL |
mov edi, dword [forcedeth_mapio_addr] |
mov dword [edi+NvRegWakeUpFlags], 0 |
mov dword [forcedeth_wolenabled], 0 |
mov dword [forcedeth_txflags], (NV_TX2_LASTPACKET or NV_TX2_VALID) |
cmp dword [forcedeth_desc_ver], DESC_VER_1 |
jne @f |
mov dword [forcedeth_txflags], (NV_TX_LASTPACKET or NV_TX_VALID) |
@@: |
; BEGIN of switch (pci->dev_id) |
cmp word [forcedeth_device_id], 0x01C3 |
jne .next_0x0066 |
; nforce |
mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER) |
jmp .end_switch |
.next_0x0066: |
cmp word [forcedeth_device_id], 0x0066 |
je @f |
cmp word [forcedeth_device_id], 0x00D6 |
je @f |
jmp .next_0x0086 |
@@: |
mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER) |
cmp dword [forcedeth_desc_ver], DESC_VER_1 |
jne @f |
or dword [forcedeth_txflags], NV_TX_LASTPACKET1 |
jmp .end_switch |
@@: |
or dword [forcedeth_txflags], NV_TX2_LASTPACKET1 |
jmp .end_switch |
.next_0x0086: |
cmp word [forcedeth_device_id], 0x0086 |
je @f |
cmp word [forcedeth_device_id], 0x008c |
je @f |
cmp word [forcedeth_device_id], 0x00e6 |
je @f |
cmp word [forcedeth_device_id], 0x00df |
je @f |
cmp word [forcedeth_device_id], 0x0056 |
je @f |
cmp word [forcedeth_device_id], 0x0057 |
je @f |
cmp word [forcedeth_device_id], 0x0037 |
je @f |
cmp word [forcedeth_device_id], 0x0038 |
je @f |
jmp .next_0x0268 |
@@: |
; np->irqmask = NVREG_IRQMASK_WANTED_2; |
; np->irqmask |= NVREG_IRQ_TIMER; |
mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER) |
; if (np->desc_ver == DESC_VER_1) |
cmp dword [forcedeth_desc_ver], DESC_VER_1 |
jne @f |
; np->tx_flags |= NV_TX_LASTPACKET1; |
or dword [forcedeth_txflags], NV_TX_LASTPACKET1 |
jmp .end_switch |
; else |
@@: |
; np->tx_flags |= NV_TX2_LASTPACKET1; |
or dword [forcedeth_txflags], NV_TX2_LASTPACKET1 |
; break; |
jmp .end_switch |
.next_0x0268: |
; cmp word [forcedeth_device_id], 0x0268 |
; je @f |
; cmp word [forcedeth_device_id], 0x0269 |
; je @f |
; cmp word [forcedeth_device_id], 0x0372 |
; je @f |
; cmp word [forcedeth_device_id], 0x0373 |
; je @f |
; jmp .default_switch |
;@@: |
cmp word [forcedeth_device_id], 0x0268 |
jb .default_switch |
; pci_read_config_byte(pci, PCI_REVISION_ID, &revision_id); |
mov al, 0 ; byte |
mov bh, [pci_dev] |
mov ah, [pci_bus] |
mov bl, PCI_REVISION_ID |
call pci_read_reg |
mov ecx, eax ; cl = revision_id |
; take phy and nic out of low power mode |
; powerstate = readl(base + NvRegPowerState2); |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [edi+NvRegPowerState2] ; eax = powerstate |
; powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK; |
and eax, not NVREG_POWERSTATE2_POWERUP_MASK |
; if ((pci->dev_id==PCI_DEVICE_ID_NVIDIA_NVENET_12||pci->dev_id==PCI_DEVICE_ID_NVIDIA_NVENET_13)&&revision_id>=0xA3) |
cmp dword [forcedeth_device_id], PCI_DEVICE_ID_NVIDIA_NVENET_12 |
je @f |
cmp dword [forcedeth_device_id], PCI_DEVICE_ID_NVIDIA_NVENET_13 |
je @f |
jmp .end_if |
@@: |
cmp cl, 0xA3 |
jl .end_if |
; powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3; |
or eax, NVREG_POWERSTATE2_POWERUP_REV_A3 |
.end_if: |
; writel(powerstate, base + NvRegPowerState2); |
mov dword [edi+NvRegPowerState2], eax |
; //DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ |
; np->irqmask = NVREG_IRQMASK_WANTED_2; |
; np->irqmask |= NVREG_IRQ_TIMER; |
mov dword [forcedeth_irqmask], 0 ;;;;;;;;;;;;;;;;(NVREG_IRQMASK_WANTED_2 or NVREG_IRQ_TIMER) |
; needs_mac_reset = 1; |
mov dword [forcedeth_needs_mac_reset], 1 |
; if (np->desc_ver == DESC_VER_1) |
cmp dword [forcedeth_desc_ver], DESC_VER_1 |
jne @f |
; np->tx_flags |= NV_TX_LASTPACKET1; |
or dword [forcedeth_txflags], NV_TX_LASTPACKET1 |
jmp .end_if2 |
@@: |
; else |
; np->tx_flags |= NV_TX2_LASTPACKET1; |
or dword [forcedeth_txflags], NV_TX2_LASTPACKET1 |
.end_if2: |
; break; |
jmp .end_switch |
.default_switch: |
DEBUGF 1," K : FORCEDETH: Your card was undefined in this driver.\n" |
DEBUGF 1," K : FORCEDETH: Review driver_data in Kolibri driver and send a patch\n" |
.end_switch: |
; END of switch (pci->dev_id) |
; Find a suitable phy |
mov dword [forcedeth_tmp_i], 1 |
.for_loop: |
; for (i = 1; i <= 32; i++) |
; phyaddr = i & 0x1f |
mov ebx, dword [forcedeth_tmp_i] |
and ebx, 0x1f |
; id1 = mii_rw(phyaddr, MII_PHYSID1, MII_READ) |
;EBX - addr, EAX - miireg, ECX - value |
mov eax, MII_PHYSID1 |
mov ecx, MII_READ |
call forcedeth_mii_rw ; id1 = eax |
; if (id1 < 0 || id1 == 0xffff) |
cmp eax, 0xffffffff |
je .continue_for |
test eax, 0x80000000 |
jnz .continue_for |
mov dword [forcedeth_tmp_id1], eax |
; id2 = mii_rw(nic, phyaddr, MII_PHYSID2, MII_READ) |
mov eax, MII_PHYSID2 |
mov ecx, MII_READ |
call forcedeth_mii_rw ; id2 = eax |
; if (id2 < 0 || id2 == 0xffff) |
cmp eax, 0xffffffff |
je .continue_for |
test eax, 0x80000000 |
jnz .continue_for |
mov dword [forcedeth_tmp_id2], eax |
jmp .break_for |
.continue_for: |
inc dword [forcedeth_tmp_i] |
cmp dword [forcedeth_tmp_i], 32 |
jle .for_loop |
jmp .end_for |
.break_for: |
;;;; DEBUGF 1," K : FORCEDETH: id1=0x%x id2=0x%x\n", [forcedeth_tmp_id1]:8, [forcedeth_tmp_id2]:8 |
; id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT |
mov eax, dword [forcedeth_tmp_id1] |
and eax, PHYID1_OUI_MASK |
shl eax, PHYID1_OUI_SHFT |
mov dword [forcedeth_tmp_id1], eax |
; id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT |
mov eax, dword [forcedeth_tmp_id2] |
and eax, PHYID2_OUI_MASK |
shr eax, PHYID2_OUI_SHFT |
mov dword [forcedeth_tmp_id2], eax |
DEBUGF 1," K : FORCEDETH: Found PHY 0x%x:0x%x at address 0x%x\n", [forcedeth_tmp_id1]:8, [forcedeth_tmp_id2]:8, ebx |
; np->phyaddr = phyaddr; |
mov dword [forcedeth_phyaddr], ebx |
; np->phy_oui = id1 | id2; |
mov eax, dword [forcedeth_tmp_id1] |
or eax, dword [forcedeth_tmp_id2] |
mov dword [forcedeth_phy_oui], eax |
.end_for: |
; if (i == 33) |
cmp dword [forcedeth_tmp_i], 33 |
jne @f |
; PHY in isolate mode? No phy attached and user wants to |
; test loopback? Very odd, but can be correct. |
DEBUGF 1," K : FORCEDETH: Could not find a valid PHY.\n" |
jmp .next3 |
@@: |
; if (i != 33) |
; reset it |
call forcedeth_phy_init |
.next3: |
; dprintf(("%s: forcedeth.c: subsystem: %hX:%hX bound to %s\n", |
; pci->name, pci->vendor, pci->dev_id, pci->name)); |
DEBUGF 1," K : FORCEDETH: subsystem: 0x%x:0x%x bound to forcedeth\n", [forcedeth_vendor_id]:4, [forcedeth_device_id]:4 |
; if(needs_mac_reset) mac_reset(nic); |
cmp dword [forcedeth_needs_mac_reset], 0 |
je @f |
call forcedeth_mac_reset |
@@: |
; if(!forcedeth_reset(nic)) return 0; // no valid link |
call forcedeth_reset |
test eax, eax |
jnz @f |
mov eax, 0 |
jmp .return |
@@: |
; point to NIC specific routines |
; dev->disable = forcedeth_disable; |
; nic->poll = forcedeth_poll; |
; nic->transmit = forcedeth_transmit; |
; nic->irq = forcedeth_irq; |
;;;;;;;;;stdcall attach_int_handler, 11, forcedeth_int_handler, 0 |
; return 1 |
mov eax, 1 |
jmp .return |
.fail: |
mov eax, 0 |
.return: |
ret |
uglobal |
forcedeth_tmp_start dd ? |
forcedeth_tmp_reg dd ? |
forcedeth_tmp_i dd ? |
forcedeth_tmp_id1 dd ? |
forcedeth_tmp_id2 dd ? |
forcedeth_tmp_phyinterface dd ? |
forcedeth_tmp_newls dd ? |
forcedeth_tmp_newdup dd ? |
forcedeth_tmp_retval dd ? |
forcedeth_tmp_control_1000 dd ? |
forcedeth_tmp_lpa dd ? |
forcedeth_tmp_adv dd ? |
forcedeth_tmp_len dd ? |
forcedeth_tmp_valid dd ? |
forcedeth_tmp_nr dd ? |
forcedeth_tmp_ptxb dd ? |
endg |
;*************************************************************************** |
; Function |
; forcedeth_poll |
; |
; Description |
; Polls the ethernet card for a received packet |
; Received data, if any, ends up in Ether_buffer |
; |
;*************************************************************************** |
forcedeth_poll: |
mov word [eth_rx_data_len], 0 |
; ???????????????????????????? |
; ??? Clear events? ??? |
mov edi, dword [forcedeth_mapio_addr] |
mov dword [edi+NvRegIrqStatus], NVREG_IRQSTAT_MASK |
; ???????????????????????????? |
.top: |
; i = np->cur_rx % RX_RING |
mov eax, dword [forcedeth_cur_rx] |
and eax, (RX_RING-1) |
mov dword [forcedeth_tmp_i], eax |
; Flags = le32_to_cpu(rx_ring[i].FlagLen) |
; Flags = rx_ring[i].FlagLen |
mov cl, sizeof.forcedeth_RxDesc |
mul cl |
add eax, forcedeth_rx_ring |
mov ebx, eax |
mov eax, [ebx + forcedeth_RxDesc.FlagLen] |
; if (Flags & NV_RX_AVAIL) |
test eax, NV_RX_AVAIL |
; return 0; /* still owned by hardware, */ |
; still owned by hardware |
jnz .return0 |
;;;;; DEBUGF 1,"poll: FlagLen = %x\n", eax |
; if (np->desc_ver == DESC_VER_1) { |
cmp dword [forcedeth_desc_ver], DESC_VER_1 |
jne @f |
; if (!(Flags & NV_RX_DESCRIPTORVALID)) |
test eax, NV_RX_DESCRIPTORVALID |
; return 0; |
jz .return0 |
jmp .next |
; } else { |
@@: |
; if (!(Flags & NV_RX2_DESCRIPTORVALID)) |
test eax, NV_RX2_DESCRIPTORVALID |
; return 0; |
jz .return0 |
; } |
.next: |
; len = nv_descr_getlength(&rx_ring[i], np->desc_ver) |
; len = rx_ring[i].FlagLen & ((np->desc_ver == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2); |
; eax = FlagLen |
cmp dword [forcedeth_desc_ver], DESC_VER_1 |
jne @f |
and eax, LEN_MASK_V1 |
jmp .next2 |
@@: |
and eax, LEN_MASK_V2 |
.next2: |
; mov dword [forcedeth_tmp_len], eax |
; valid = 1 |
mov dword [forcedeth_tmp_valid], 1 |
; got a valid packet - forward it to the network core |
; nic->packetlen = len; |
mov dword [forcedeth_packetlen], eax |
; |
mov word [eth_rx_data_len], ax |
;;;;;;;;; DEBUGF 1,"poll: packet len = 0x%x\n", [forcedeth_packetlen] |
; memcpy(nic->packet, rxb + (i * RX_NIC_BUFSIZE), nic->packetlen); |
; Copy packet to system buffer (Ether_buffer) |
;???? ecx = (len-4) |
mov ecx, eax |
push ecx |
shr ecx, 2 |
; rxb + (i * RX_NIC_BUFSIZE) |
mov eax, dword [forcedeth_tmp_i] |
mov bx, RX_NIC_BUFSIZE |
mul bx |
add eax, forcedeth_rxb |
mov esi, eax |
mov edi, Ether_buffer |
cld ; set to increment |
rep movsd ; mov dword from [esi++] to [edi++] |
pop ecx |
and ecx, 3 ; copy rest 1-3 bytes |
rep movsb |
; wmb(); |
; ??? |
; np->cur_rx++; |
inc dword [forcedeth_cur_rx] |
; if (!valid) |
cmp dword [forcedeth_tmp_valid], 0 |
jne @f |
; goto top; |
jmp .top |
@@: |
; alloc_rx(nic); |
call forcedeth_alloc_rx |
; return 1; |
jmp .return1 |
;;;;; DEBUGF 1,"K : FORCEDETH: poll: ...\n" |
.return0: |
mov eax, 0 |
jmp .return |
.return1: |
mov eax, 1 |
.return: |
;;push eax |
; ???????????????????????????????????????????????? |
; ????? clear interrupt mask/status |
; read IRQ status |
;;mov edi, dword [forcedeth_mapio_addr] |
;;mov eax, dword [edi+NvRegIrqStatus] |
; clear events |
;;and eax, not (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF or NVREG_IRQ_LINK or NVREG_IRQ_TIMER) |
; write IRQ status |
;;mov dword [edi+NvRegIrqStatus], eax |
; ???????????????????????????????????????????????? |
;;pop eax |
ret |
;*************************************************************************** |
; Function |
; forcedeth_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 |
; |
;*************************************************************************** |
forcedeth_transmit: |
; send the packet to destination |
;pusha |
;DEBUGF 1,"K : FORCEDETH: transmit: packet type = 0x%x\n", ebx |
;DEBUGF 1,"K : FORCEDETH: transmit: packet len = 0x%x\n", ecx |
;mov eax, dword [edi] |
;DEBUGF 1,"K : FORCEDETH: transmit: dest adr = 0x%x\n", eax |
;mov eax, dword [edi+4] |
;DEBUGF 1,"K : FORCEDETH: transmit: dest adr2 = 0x%x\n", eax |
;mov eax, dword [node_addr] |
;DEBUGF 1,"K : FORCEDETH: transmit: src adr = 0x%x\n", eax |
;mov eax, dword [node_addr+4] |
;DEBUGF 1,"K : FORCEDETH: transmit: src adr2 = 0x%x\n", eax |
;popa |
; int nr = np->next_tx % TX_RING |
mov eax, dword [forcedeth_next_tx] |
and eax, (TX_RING-1) |
mov dword [forcedeth_tmp_nr], eax |
; point to the current txb incase multiple tx_rings are used |
; ptxb = txb + (nr * RX_NIC_BUFSIZE) |
push ecx |
mov cx, RX_NIC_BUFSIZE |
mul cx ; AX*CX, result to DX:AX |
add eax, forcedeth_txb |
mov dword [forcedeth_tmp_ptxb], eax |
push esi |
mov esi, edi ; dst MAC |
mov edi, eax ; packet buffer |
cld ; set to increment |
; copy the packet to ring buffer |
; memcpy(ptxb, d, ETH_ALEN); /* dst */ |
movsd |
movsw |
; memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ |
mov esi, node_addr |
movsd |
movsw |
; nstype = htons((u16) t); /* type */ |
; memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* type */ |
mov word [edi], bx |
add edi, 2 |
; memcpy(ptxb + ETH_HLEN, p, s); |
pop esi |
pop ecx |
push ecx |
shr ecx, 2 ; count in dwords |
rep movsd ; copy dwords from [esi+=4] to [edi+=4] |
pop ecx |
push ecx |
and ecx, 3 ; copy rest 1-3 bytes |
rep movsb ; copy bytess from [esi++] to [edi++] |
; s += ETH_HLEN; |
; while (s < ETH_ZLEN) /* pad to min length */ |
; ptxb[s++] = '\0'; |
; pad to min length |
pop ecx |
add ecx, ETH_HLEN |
push ecx ; header length + data length |
cmp ecx, ETH_ZLEN |
jge @f |
mov eax, ETH_ZLEN |
sub eax, ecx |
xchg eax, ecx |
mov al, 0 |
rep stosb ; copy byte from al to [edi++] |
@@: |
; tx_ring[nr].PacketBuffer = (u32) virt_to_le32desc(ptxb); |
mov eax, dword [forcedeth_tmp_nr] |
mov cl, sizeof.forcedeth_TxDesc |
mul cl |
add eax, forcedeth_tx_ring |
mov ebx, eax |
mov eax, dword [forcedeth_tmp_ptxb] |
sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
mov [ebx + forcedeth_TxDesc.PacketBuffer], eax |
;DEBUGF 1,"K : FORCEDETH: transmit: PacketBuffer = 0x%x\n", eax |
;DEBUGF 1,"K : FORCEDETH: transmit: txflags = 0x%x\n", [forcedeth_txflags]:8 |
; wmb(); |
; tx_ring[nr].FlagLen = cpu_to_le32((s - 1) | np->tx_flags); |
pop eax ; header length + data length |
mov ecx, dword [forcedeth_txflags] |
or eax, ecx |
mov [ebx + forcedeth_TxDesc.FlagLen], eax |
; writel(NVREG_TXRXCTL_KICK | np->desc_ver, base + NvRegTxRxControl); |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [forcedeth_desc_ver] |
or eax, NVREG_TXRXCTL_KICK |
mov dword [edi+NvRegTxRxControl], eax |
; pci_push(base); |
call forcedeth_pci_push |
; np->next_tx++ |
inc dword [forcedeth_next_tx]; may be need to reset? Overflow? |
ret |
;*************************************************************************** |
; Function |
; forcedeth_cable |
; |
; Description |
; Return AL=0, if cable is not connected |
; Returm AL=1, if cable is connected |
; |
;*************************************************************************** |
forcedeth_cable: |
mov al, 1 |
cmp dword [forcedeth_nocable], 1 |
jne .return |
mov al, 0 |
.return: |
ret |
;*************************************************************************** |
; read/write a register on the PHY. |
; Caller must guarantee serialization |
; Input: EAX - miireg, EBX - addr, ECX - value |
; Output: EAX - retval |
forcedeth_mii_rw: |
push ebx |
push eax ; save miireg |
; writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus) |
mov edi, dword [forcedeth_mapio_addr] |
mov dword [edi+NvRegMIIStatus], NVREG_MIISTAT_MASK |
; reg = readl(base + NvRegMIIControl) |
mov eax, dword [edi+NvRegMIIControl] |
test eax, NVREG_MIICTL_INUSE |
jz @f |
; writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl) |
mov dword [edi+NvRegMIIControl], NVREG_MIICTL_INUSE |
; nv_udelay(NV_MIIBUSY_DELAY) |
mov esi, NV_MIIBUSY_DELAY |
call forcedeth_nv_udelay |
@@: |
; reg = (addr << NVREG_MIICTL_ADDRSHIFT) | miireg |
pop edx ; restore miireg |
mov eax, ebx |
shl eax, NVREG_MIICTL_ADDRSHIFT |
or eax, edx |
mov dword [forcedeth_tmp_reg], eax |
cmp ecx, MII_READ |
je @f |
; writel(value, base + NvRegMIIData) |
mov dword [edi+NvRegMIIData], ecx |
; reg |= NVREG_MIICTL_WRITE |
or dword [forcedeth_tmp_reg], NVREG_MIICTL_WRITE |
@@: |
; writel(reg, base + NvRegMIIControl) |
mov eax, dword [forcedeth_tmp_reg] |
mov dword [edi+NvRegMIIControl], eax |
push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;; |
; reg_delay(NvRegMIIControl, NVREG_MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL) |
stdcall forcedeth_reg_delay, NvRegMIIControl, NVREG_MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, 0 |
pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;; |
test eax, eax |
jz @f |
;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw of reg %d at PHY %d timed out.\n", edx, ebx |
mov eax, 0xffffffff |
jmp .return |
@@: |
cmp ecx, MII_READ |
je @f |
;it was a write operation - fewer failures are detectable |
;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw wrote 0x%x to reg %d at PHY %d\n", ecx, edx, ebx |
mov eax, 0 |
jmp .return |
@@: |
; readl(base + NvRegMIIStatus) |
mov eax, dword [edi+NvRegMIIStatus] |
test eax, NVREG_MIISTAT_ERROR |
jz @f |
;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw of reg %d at PHY %d failed.\n", edx, ebx |
mov eax, 0xffffffff |
jmp .return |
@@: |
; retval = readl(base + NvRegMIIData) |
mov eax, dword [edi+NvRegMIIData] |
;;;;;;;; DEBUGF 1,"K : FORCEDETH: mii_rw read from reg %d at PHY %d: 0x%x.\n", edx, ebx, eax |
.return: |
pop ebx |
ret |
; Input: ESI - delay |
; Output: none |
forcedeth_nv_udelay: |
push ebx |
cmp dword [forcedeth_in_shutdown], 0 |
jne @f |
call forcedeth_udelay ; delay on ESI |
jmp .return |
@@: |
.loop: |
cmp esi, 0 |
je .return |
; Don't allow an rx_ring overflow to happen |
; while shutting down the NIC it will |
; kill the receive function. |
call forcedeth_drop_rx |
mov ebx, 3 ; sleep = 3 |
cmp ebx, esi ; if(sleep > delay) |
jle @f |
mov ebx, esi ; sleep = delay |
@@: |
push esi |
mov esi, ebx |
; udelay(sleep) |
call forcedeth_udelay ; delay on ESI |
pop esi |
sub esi, ebx ; delay -= sleep |
jmp .loop |
.return: |
pop ebx |
ret |
; Input: none |
; Output: none |
forcedeth_drop_rx: |
push eax ebx ecx edi |
; events = readl(base + NvRegIrqStatus) |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [edi+NvRegIrqStatus] |
test eax, eax |
jz @f |
; writel(events, base + NvRegIrqStatus) |
mov dword [edi+NvRegIrqStatus], eax |
@@: |
;if (!(events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF))) |
test eax, (NVREG_IRQ_RX_ERROR or NVREG_IRQ_RX or NVREG_IRQ_RX_NOBUF) |
jz .return |
.loop: |
; i = np->cur_rx % RX_RING |
mov eax, dword [forcedeth_cur_rx] |
and eax, (RX_RING-1) |
; //Flags = le32_to_cpu(rx_ring[i].FlagLen) |
; Flags = rx_ring[i].FlagLen |
mov cl, sizeof.forcedeth_RxDesc |
mul cl |
add eax, forcedeth_rx_ring |
mov ebx, eax |
mov eax, [ebx + forcedeth_RxDesc.FlagLen] |
; len = nv_descr_getlength(&rx_ring[i], np->desc_ver) |
; > len = Flags & ((np->desc_ver == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2) |
; ??? len don't used later !!! ??? |
; ... |
test eax, NV_RX_AVAIL |
jnz .return ; still owned by hardware, |
; wmb() |
; ??? may be empty function ??? |
; np->cur_rx++ |
inc dword [forcedeth_cur_rx] |
; alloc_rx(NULL) |
call forcedeth_alloc_rx |
.return: |
pop edi ecx ebx eax |
ret |
; Fill rx ring entries. |
; Return 1 if the allocations for the skbs failed and the |
; rx engine is without Available descriptors |
; Input: none |
; Output: none |
forcedeth_alloc_rx: |
push eax ebx ecx edx |
; refill_rx = np->refill_rx |
mov ecx, dword [forcedeth_refill_rx] |
.loop: |
cmp dword [forcedeth_cur_rx], ecx |
je .loop_end |
; nr = refill_rx % RX_RING |
mov eax, ecx |
and eax, (RX_RING-1) ; nr |
; rx_ring[nr].PacketBuffer = &rxb[nr * RX_NIC_BUFSIZE] |
push ecx |
push eax |
mov cl, sizeof.forcedeth_RxDesc |
mul cl |
add eax, forcedeth_rx_ring |
mov ebx, eax |
pop eax |
mov cx, RX_NIC_BUFSIZE |
mul cx |
pop ecx |
add eax, forcedeth_rxb |
sub eax, OS_BASE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
mov [ebx + forcedeth_RxDesc.PacketBuffer], eax |
; wmb() |
; ... |
; rx_ring[nr].FlagLen = RX_NIC_BUFSIZE | NV_RX_AVAIL |
mov [ebx + forcedeth_RxDesc.FlagLen], (RX_NIC_BUFSIZE or NV_RX_AVAIL) |
inc ecx |
jmp .loop |
.loop_end: |
; np->refill_rx = refill_rx |
mov [forcedeth_refill_rx], ecx |
.return: |
pop edx ecx ebx eax |
ret |
; Delay in millisec |
; Input: ESI - delay in ms |
; Output: none |
forcedeth_udelay: |
call delay_ms |
ret |
; Input: offset:word, mask:dword, target:dword, delay:word, delaymax:word, msg:dword |
; Output: EAX - 0|1 |
;;;;proc forcedeth_reg_delay,offset:word,mask:dword,target:dword,delay:word,delaymax:word,msg:dword |
proc forcedeth_reg_delay,offset:dword,mask:dword,target:dword,delay:dword,delaymax:dword,msg:dword |
push ebx esi edi |
; pci_push(base) |
call forcedeth_pci_push |
.loop: |
; nv_udelay(delay) |
mov esi, dword [delay] |
call forcedeth_nv_udelay ; delay in esi |
mov eax, dword [delaymax] |
sub eax, dword [delay] |
mov dword [delaymax], eax |
; if (delaymax < 0) |
test dword [delaymax], 0x80000000 |
jz @f |
; return 1 |
mov eax, 1 |
jmp .return |
@@: |
; while ((readl(base + offset) & mask) != target) |
mov edi, dword [forcedeth_mapio_addr] |
mov ebx, dword [offset] |
mov eax, dword [edi+ebx] |
and eax, dword [mask] |
cmp eax, dword [target] |
jne .loop |
xor eax, eax |
.return: |
pop edi esi ebx |
ret |
endp |
; Input: none |
; Output: none |
forcedeth_pci_push: |
push eax edi |
;force out pending posted writes |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [edi] |
pop edi eax |
ret |
; Input: none |
; Output: EAX - result (0 = OK, other = error) |
forcedeth_phy_init: |
push ebx ecx |
; set advertise register |
; reg = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ); |
; EBX - addr, EAX - miireg, ECX - value |
mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_ADVERTISE |
mov ecx, MII_READ |
call forcedeth_mii_rw ; reg = eax |
; reg |= |
; (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | |
; ADVERTISE_100FULL | 0x800 | 0x400); |
or eax, (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL or 0x800 or 0x400) |
; if (mii_rw(nic, np->phyaddr, MII_ADVERTISE, reg)) |
; EBX - addr, EAX - miireg, ECX - value |
mov ecx, eax ; reg |
mov eax, MII_ADVERTISE |
call forcedeth_mii_rw ; eax -> return |
test eax, eax |
jz @f |
; printf("phy write to advertise failed.\n"); |
DEBUGF 1," K : FORCEDETH: phy write to advertise failed.\n" |
; return PHY_ERROR; |
mov eax, PHY_ERROR |
jmp .return |
@@: |
; get phy interface type |
; phyinterface = readl(base + NvRegPhyInterface); |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [edi+NvRegPhyInterface] ; phyinterface = eax |
mov dword [forcedeth_tmp_phyinterface], eax |
;;;;;;;;;;;;;;;;;;;;;;;;; |
DEBUGF 1," K : FORCEDETH: phy interface type = 0x%x\n", [forcedeth_tmp_phyinterface]:8 |
;;;;;;;;;;;;;;;;;;;;;;;;; |
; see if gigabit phy |
; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ); |
; EBX - addr, EAX - miireg, ECX - value |
mov eax, MII_BMSR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; mii_status = eax |
; if (mii_status & PHY_GIGABIT) |
test eax, PHY_GIGABIT |
jnz .gigabit |
; np->gigabit = 0; |
mov dword [forcedeth_gigabit], 0 |
jmp .next_if |
.gigabit: |
; np->gigabit = PHY_GIGABIT; |
mov dword [forcedeth_gigabit], PHY_GIGABIT |
; mii_control_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ); |
; EBX - addr, EAX - miireg, ECX - value |
mov eax, MII_1000BT_CR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; mii_control_1000 = eax |
; mii_control_1000 &= ~ADVERTISE_1000HALF; |
and eax, (not ADVERTISE_1000HALF) |
; if (phyinterface & PHY_RGMII) |
test dword [forcedeth_tmp_phyinterface], PHY_RGMII |
jz @f |
; mii_control_1000 |= ADVERTISE_1000FULL |
or eax, ADVERTISE_1000FULL |
jmp .next |
@@: |
; mii_control_1000 &= ~ADVERTISE_1000FULL |
and eax, (not ADVERTISE_1000FULL) |
.next: |
; if (mii_rw(nic, np->phyaddr, MII_1000BT_CR, mii_control_1000)) |
; EBX - addr, EAX - miireg, ECX - value |
mov ecx, eax |
mov eax, MII_1000BT_CR |
call forcedeth_mii_rw ; eax -> return |
test eax, eax |
jz .next_if |
; printf("phy init failed.\n"); |
DEBUGF 1," K : FORCEDETH: phy init failed.\n" |
; return PHY_ERROR; |
mov eax, PHY_ERROR |
jmp .return |
.next_if: |
; reset the phy |
; if (phy_reset(nic)) |
call forcedeth_phy_reset |
test eax, eax |
jz @f |
; printf("phy reset failed\n") |
DEBUGF 1," K : FORCEDETH: phy reset failed.\n" |
; return PHY_ERROR |
mov eax, PHY_ERROR |
jmp .return |
@@: |
; phy vendor specific configuration |
; if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII)) |
cmp dword [forcedeth_phy_oui], PHY_OUI_CICADA |
jne .next_if2 |
test dword [forcedeth_tmp_phyinterface], PHY_RGMII |
jz .next_if2 |
; phy_reserved = mii_rw(nic, np->phyaddr, MII_RESV1, MII_READ) |
; EBX - addr, EAX - miireg, ECX - value |
mov eax, MII_RESV1 |
mov ecx, MII_READ |
call forcedeth_mii_rw ; phy_reserved = eax |
; phy_reserved &= ~(PHY_INIT1 | PHY_INIT2) |
and eax, (not (PHY_INIT1 or PHY_INIT2)) |
; phy_reserved |= (PHY_INIT3 | PHY_INIT4) |
or eax, (PHY_INIT3 or PHY_INIT4) |
; if (mii_rw(nic, np->phyaddr, MII_RESV1, phy_reserved)) |
; EBX - addr, EAX - miireg, ECX - value |
mov ecx, eax |
mov eax, MII_RESV1 |
call forcedeth_mii_rw ; eax -> return |
test eax, eax |
jz @f |
; printf("phy init failed.\n") |
DEBUGF 1," K : FORCEDETH: phy init failed.\n" |
; return PHY_ERROR |
mov eax, PHY_ERROR |
jmp .return |
@@: |
; phy_reserved = mii_rw(nic, np->phyaddr, MII_NCONFIG, MII_READ); |
; EBX - addr, EAX - miireg, ECX - value |
mov eax, MII_NCONFIG |
mov ecx, MII_READ |
call forcedeth_mii_rw ; phy_reserved = eax |
; phy_reserved |= PHY_INIT5 |
or eax, PHY_INIT5 |
; if (mii_rw(nic, np->phyaddr, MII_NCONFIG, phy_reserved)) |
; EBX - addr, EAX - miireg, ECX - value |
mov ecx, eax |
mov eax, MII_NCONFIG |
call forcedeth_mii_rw ; eax -> return |
test eax, eax |
jz .next_if2 |
; printf("phy init failed.\n") |
DEBUGF 1," K : FORCEDETH: phy init failed.\n" |
; return PHY_ERROR |
mov eax, PHY_ERROR |
jmp .return |
.next_if2: |
; if (np->phy_oui == PHY_OUI_CICADA) |
cmp dword [forcedeth_phy_oui], PHY_OUI_CICADA |
jne .restart |
; phy_reserved = mii_rw(nic, np->phyaddr, MII_SREVISION, MII_READ) |
; EBX - addr, EAX - miireg, ECX - value |
mov eax, MII_SREVISION |
mov ecx, MII_READ |
call forcedeth_mii_rw ; phy_reserved = eax |
; phy_reserved |= PHY_INIT6 |
or eax, PHY_INIT6 |
; if (mii_rw(nic, np->phyaddr, MII_SREVISION, phy_reserved)) |
mov ecx, eax |
mov eax, MII_SREVISION |
call forcedeth_mii_rw ; eax -> return |
test eax, eax |
jz .restart |
; printf("phy init failed.\n"); |
DEBUGF 1," K : FORCEDETH: phy init failed.\n" |
; return PHY_ERROR; |
jmp .return |
.restart: |
; restart auto negotiation |
; mii_control = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ) |
; EBX - addr, EAX - miireg, ECX - value |
mov eax, MII_BMCR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; mii_control = eax |
; mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE) |
or eax, (BMCR_ANRESTART or BMCR_ANENABLE) |
; if (mii_rw(nic, np->phyaddr, MII_BMCR, mii_control)) |
mov ecx, eax |
mov eax, MII_BMCR |
call forcedeth_mii_rw ; eax -> return |
test eax, eax |
jz .ok |
; return PHY_ERROR; |
mov eax, PHY_ERROR |
jmp .return |
.ok: |
mov eax, 0 |
.return: |
pop ecx ebx |
ret |
; Input: none |
; Output: EAX - result (0 = OK, other = error) |
forcedeth_phy_reset: |
push ebx ecx edx |
; miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ); |
; EBX - addr, EAX - miireg, ECX - value |
mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_BMCR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; miicontrol = eax |
; miicontrol |= BMCR_RESET; |
or eax, BMCR_RESET |
push eax |
; if (mii_rw(nic, np->phyaddr, MII_BMCR, miicontrol)) |
; EBX - addr, EAX - miireg, ECX - value |
mov ecx, eax |
mov eax, MII_BMCR |
call forcedeth_mii_rw ; miicontrol = eax |
test eax, eax |
jz @f |
pop eax |
mov eax, 0xffffffff |
jmp .return |
@@: |
pop eax |
; wait for 500ms |
; mdelay(500) |
mov esi, 500 |
call forcedeth_udelay |
; must wait till reset is deasserted |
; while (miicontrol & BMCR_RESET) { |
mov edx, 100 |
.while_loop: |
test eax, BMCR_RESET |
jz .while_loop_exit |
; mdelay(10); |
mov esi, 10 |
call forcedeth_udelay |
; miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ); |
; EBX - addr, EAX - miireg, ECX - value |
mov eax, MII_BMCR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; miicontrol = eax |
; FIXME: 100 tries seem excessive |
; if (tries++ > 100) |
dec edx |
jnz .while_loop |
; return -1; |
mov eax, 0xffffffff |
jmp .return |
.while_loop_exit: |
; return 0 |
mov eax, 0 |
.return: |
pop edx ecx ebx |
ret |
; Input: none |
; Output: none |
forcedeth_mac_reset: |
push esi edi |
; dprintf("mac_reset\n") |
DEBUGF 1," K : FORCEDETH: mac_reset.\n" |
; writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl) |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [forcedeth_desc_ver] |
or eax, (NVREG_TXRXCTL_BIT2 or NVREG_TXRXCTL_RESET) |
mov dword [edi+NvRegTxRxControl], eax |
; pci_push(base) |
call forcedeth_pci_push |
; writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset) |
mov dword [edi+NvRegMacReset], NVREG_MAC_RESET_ASSERT |
; pci_push(base) |
call forcedeth_pci_push |
; udelay(NV_MAC_RESET_DELAY) |
mov esi, NV_MAC_RESET_DELAY |
call forcedeth_nv_udelay |
; writel(0, base + NvRegMacReset) |
mov dword [edi+NvRegMacReset], 0 |
; pci_push(base) |
call forcedeth_pci_push |
; udelay(NV_MAC_RESET_DELAY) |
mov esi, NV_MAC_RESET_DELAY |
call forcedeth_nv_udelay |
; writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl) |
mov eax, dword [forcedeth_desc_ver] |
or eax, NVREG_TXRXCTL_BIT2 |
mov dword [edi+NvRegTxRxControl], eax |
; pci_push(base) |
call forcedeth_pci_push |
pop edi esi |
ret |
; Input: none |
; Output: none |
forcedeth_init_ring: |
push eax ebx ecx |
; np->next_tx = np->nic_tx = 0 |
mov dword[forcedeth_next_tx], 0 |
mov dword[forcedeth_nic_tx], 0 |
; for (i = 0; i < TX_RING; i++) |
mov ecx, TX_RING |
.for_loop: |
; tx_ring[i].FlagLen = 0; |
mov eax, ecx |
dec eax |
mov bl, sizeof.forcedeth_TxDesc |
mul bl |
add eax, forcedeth_tx_ring |
mov ebx, eax |
mov dword [ebx + forcedeth_TxDesc.FlagLen], 0 |
loop .for_loop |
; np->cur_rx = RX_RING; |
mov dword [forcedeth_cur_rx], RX_RING |
; np->refill_rx = 0; |
mov dword [forcedeth_refill_rx], 0 |
;for (i = 0; i < RX_RING; i++) |
mov ecx, RX_RING |
.for_loop2: |
; rx_ring[i].FlagLen = 0; |
mov eax, ecx |
dec eax |
mov bl, sizeof.forcedeth_RxDesc |
mul bl |
add eax, forcedeth_rx_ring |
mov ebx, eax |
mov dword [ebx + forcedeth_RxDesc.FlagLen], 0 |
loop .for_loop2 |
; alloc_rx(nic); |
call forcedeth_alloc_rx |
.return: |
pop ecx ebx eax |
ret |
; Input: none |
; Output: none |
forcedeth_txrx_reset: |
push eax esi edi |
; dprintf(("txrx_reset\n")) |
DEBUGF 1," K : FORCEDETH: txrx_reset.\n" |
; writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl) |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [forcedeth_desc_ver] |
or eax, (NVREG_TXRXCTL_BIT2 or NVREG_TXRXCTL_RESET) |
mov dword [edi+NvRegTxRxControl], eax |
; pci_push(base) |
call forcedeth_pci_push |
; nv_udelay(NV_TXRX_RESET_DELAY) |
mov esi, NV_TXRX_RESET_DELAY |
call forcedeth_nv_udelay |
; writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl) |
mov eax, dword [forcedeth_desc_ver] |
or eax, NVREG_TXRXCTL_BIT2 |
mov dword [edi+NvRegTxRxControl], eax |
; pci_push(base) |
call forcedeth_pci_push |
.return: |
pop edi esi eax |
ret |
; Input: none |
; Output: none |
forcedeth_set_multicast: |
push edi |
; u32 addr[2]; |
; u32 mask[2]; |
; u32 pff; |
; u32 alwaysOff[2]; |
; u32 alwaysOn[2]; |
; |
; memset(addr, 0, sizeof(addr)); |
; memset(mask, 0, sizeof(mask)); |
; |
; pff = NVREG_PFF_MYADDR; |
; |
; alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; |
; |
; addr[0] = alwaysOn[0]; |
; addr[1] = alwaysOn[1]; |
; mask[0] = alwaysOn[0] | alwaysOff[0]; |
; mask[1] = alwaysOn[1] | alwaysOff[1]; |
; |
; addr[0] |= NVREG_MCASTADDRA_FORCE; |
; pff |= NVREG_PFF_ALWAYS; |
; stop_rx(); |
call forcedeth_stop_rx |
; writel(addr[0], base + NvRegMulticastAddrA); |
mov edi, dword [forcedeth_mapio_addr] |
mov dword [edi+NvRegMulticastAddrA], NVREG_MCASTADDRA_FORCE |
; writel(addr[1], base + NvRegMulticastAddrB); |
mov dword [edi+NvRegMulticastAddrB], 0 |
; writel(mask[0], base + NvRegMulticastMaskA); |
mov dword [edi+NvRegMulticastMaskA], 0 |
; writel(mask[1], base + NvRegMulticastMaskB); |
mov dword [edi+NvRegMulticastMaskB], 0 |
; writel(pff, base + NvRegPacketFilterFlags); |
mov dword [edi+NvRegPacketFilterFlags], (NVREG_PFF_MYADDR or NVREG_PFF_ALWAYS) |
; start_rx(nic); |
call forcedeth_start_rx |
.return: |
pop edi |
ret |
; Input: none |
; Output: none |
forcedeth_start_rx: |
push edi |
; dprintf(("start_rx\n")) |
DEBUGF 1," K : FORCEDETH: start_rx.\n" |
; Already running? Stop it. |
; if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [edi+NvRegReceiverControl] |
test eax, NVREG_RCVCTL_START |
jz @f |
; writel(0, base + NvRegReceiverControl) |
mov dword [edi+NvRegReceiverControl], 0 |
; pci_push(base) |
call forcedeth_pci_push |
@@: |
; writel(np->linkspeed, base + NvRegLinkSpeed); |
mov eax, dword [forcedeth_linkspeed] |
mov dword [edi+NvRegLinkSpeed], eax |
; pci_push(base); |
call forcedeth_pci_push |
; writel(NVREG_RCVCTL_START, base + NvRegReceiverControl); |
mov dword [edi+NvRegReceiverControl], NVREG_RCVCTL_START |
; pci_push(base); |
call forcedeth_pci_push |
.return: |
pop edi |
ret |
; Input: none |
; Output: none |
forcedeth_stop_rx: |
push esi edi |
; dprintf(("stop_rx\n")) |
DEBUGF 1," K : FORCEDETH: stop_rx.\n" |
; writel(0, base + NvRegReceiverControl) |
mov edi, dword [forcedeth_mapio_addr] |
mov dword [edi+NvRegReceiverControl], 0 |
push ebx edx edi ;;;;;;;;;;;;;;;;;;;;;; |
; reg_delay(NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, "stop_rx: ReceiverStatus remained busy"); |
stdcall forcedeth_reg_delay, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, 0 |
pop edi edx ebx ;;;;;;;;;;;;;;;;;;;;;; |
; nv_udelay(NV_RXSTOP_DELAY2) |
mov esi, NV_RXSTOP_DELAY2 |
call forcedeth_nv_udelay |
; writel(0, base + NvRegLinkSpeed) |
mov dword [edi+NvRegLinkSpeed], 0 |
.return: |
pop edi esi |
ret |
; Input: none |
; Output: EAX |
forcedeth_update_linkspeed: |
push ebx ecx esi edi |
; BMSR_LSTATUS is latched, read it twice: |
; we want the current value. |
; mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ) |
;EBX - addr, EAX - miireg, ECX - value |
mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_BMSR |
mov ecx, MII_READ |
call forcedeth_mii_rw |
; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ) |
;EBX - addr, EAX - miireg, ECX - value |
mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_BMSR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; mii_status = eax |
; yhlu |
; for(i=0;i<30;i++) { |
mov ecx, 30 |
.for_loop: |
push ecx |
; mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ); |
;EBX - addr, EAX - miireg, ECX - value |
;mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_BMSR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; mii_status = eax |
; if((mii_status & BMSR_LSTATUS) && (mii_status & BMSR_ANEGCOMPLETE)) break; |
test eax, BMSR_LSTATUS |
jz @f |
test eax, BMSR_ANEGCOMPLETE |
jz @f |
; break |
pop ecx |
jmp .break |
@@: |
; mdelay(100); |
push eax ; ??? |
mov esi, 100 |
call forcedeth_udelay |
pop eax ; ??? |
pop ecx |
loop .for_loop |
.break: |
; if (!(mii_status & BMSR_LSTATUS)) { |
test eax, BMSR_LSTATUS |
jnz @f |
; printf("no link detected by phy - falling back to 10HD.\n") |
DEBUGF 1," K : FORCEDETH: update_linkspeed: no link detected by phy - falling back to 10HD.\n" |
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 |
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) |
; newdup = 0; |
mov dword [forcedeth_tmp_newdup], 0 |
; retval = 0; |
mov dword [forcedeth_tmp_retval], 0 |
; goto set_speed; |
jmp .set_speed |
@@: |
; check auto negotiation is complete |
; if (!(mii_status & BMSR_ANEGCOMPLETE)) { |
test eax, BMSR_ANEGCOMPLETE |
jnz @f |
; still in autonegotiation - configure nic for 10 MBit HD and wait. |
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 |
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) |
; newdup = 0 |
mov dword [forcedeth_tmp_newdup], 0 |
; retval = 0 |
mov dword [forcedeth_tmp_retval], 0 |
; printf("autoneg not completed - falling back to 10HD.\n") |
DEBUGF 1," K : FORCEDETH: update_linkspeed: autoneg not completed - falling back to 10HD.\n" |
; goto set_speed |
jmp .set_speed |
@@: |
; retval = 1 |
mov dword [forcedeth_tmp_retval], 1 |
; if (np->gigabit == PHY_GIGABIT) { |
cmp dword [forcedeth_gigabit], PHY_GIGABIT |
jne .end_if |
; control_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ) |
;EBX - addr, EAX - miireg, ECX - value |
;mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_1000BT_CR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; control_1000 = eax |
mov dword [forcedeth_tmp_control_1000], eax |
; status_1000 = mii_rw(nic, np->phyaddr, MII_1000BT_SR, MII_READ) |
;EBX - addr, EAX - miireg, ECX - value |
;mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_1000BT_SR |
mov ecx, MII_READ |
call forcedeth_mii_rw ; status_1000 = eax |
;mov dword [forcedeth_tmp_status_1000], eax |
; if ((control_1000 & ADVERTISE_1000FULL) && |
; (status_1000 & LPA_1000FULL)) { |
test eax, LPA_1000FULL |
jz .end_if |
test dword [forcedeth_tmp_control_1000], ADVERTISE_1000FULL |
jz .end_if |
; printf ("update_linkspeed: GBit ethernet detected.\n") |
DEBUGF 1," K : FORCEDETH: update_linkspeed: GBit ethernet detected.\n" |
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_1000 |
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_1000) |
; newdup = 1 |
mov dword [forcedeth_tmp_newdup], 1 |
; goto set_speed |
jmp .set_speed |
.end_if: |
; adv = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ); |
;EBX - addr, EAX - miireg, ECX - value |
;mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_ADVERTISE |
mov ecx, MII_READ |
call forcedeth_mii_rw ; adv = eax |
mov dword [forcedeth_tmp_adv], eax |
; lpa = mii_rw(nic, np->phyaddr, MII_LPA, MII_READ); |
;EBX - addr, EAX - miireg, ECX - value |
;mov ebx, dword [forcedeth_phyaddr] |
mov eax, MII_LPA |
mov ecx, MII_READ |
call forcedeth_mii_rw ; lpa = eax |
mov dword [forcedeth_tmp_lpa], eax |
; dprintf(("update_linkspeed: PHY advertises 0x%hX, lpa 0x%hX.\n", adv, lpa)); |
DEBUGF 1," K : FORCEDETH: update_linkspeed: PHY advertises 0x%x, lpa 0x%x.\n", [forcedeth_tmp_adv]:8, [forcedeth_tmp_lpa]:8 |
; FIXME: handle parallel detection properly, handle gigabit ethernet |
; lpa = lpa & adv |
mov eax, dword [forcedeth_tmp_adv] |
and dword [forcedeth_tmp_lpa], eax |
mov eax, dword [forcedeth_tmp_lpa] |
; if (lpa & LPA_100FULL) { |
test eax, LPA_100FULL |
jz @f |
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100 |
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_100) |
; newdup = 1 |
mov dword [forcedeth_tmp_newdup], 1 |
jmp .set_speed |
@@: |
; } else if (lpa & LPA_100HALF) { |
test eax, LPA_100HALF |
jz @f |
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_100 |
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_100) |
; newdup = 0 |
mov dword [forcedeth_tmp_newdup], 0 |
jmp .set_speed |
@@: |
; } else if (lpa & LPA_10FULL) { |
test eax, LPA_10FULL |
jz @f |
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 |
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) |
; newdup = 1 |
mov dword [forcedeth_tmp_newdup], 1 |
jmp .set_speed |
@@: |
; } else if (lpa & LPA_10HALF) { |
test eax, LPA_10HALF |
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10; |
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) |
; newdup = 0; |
mov dword [forcedeth_tmp_newdup], 0 |
jmp .set_speed |
@@: |
; } else { |
; printf("bad ability %hX - falling back to 10HD.\n", lpa) |
DEBUGF 1," K : FORCEDETH: update_linkspeed: bad ability 0x%x - falling back to 10HD.\n", eax |
; newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10 |
mov dword [forcedeth_tmp_newls], (NVREG_LINKSPEED_FORCE or NVREG_LINKSPEED_10) |
; newdup = 0 |
mov dword [forcedeth_tmp_newdup], 0 |
; } |
.set_speed: |
; if (np->duplex == newdup && np->linkspeed == newls) |
mov eax, dword [forcedeth_tmp_newdup] |
cmp eax, dword [forcedeth_duplex] |
jne .end_if2 |
mov eax, dword [forcedeth_tmp_newls] |
cmp eax, dword [forcedeth_linkspeed] |
jne .end_if2 |
; return retval; |
jmp .return |
.end_if2: |
; dprintf(("changing link setting from %d/%s to %d/%s.\n", |
; np->linkspeed, np->duplex ? "Full-Duplex": "Half-Duplex", newls, newdup ? "Full-Duplex": "Half-Duplex")) |
DEBUGF 1," K : FORCEDETH: update_linkspeed: changing link from %x/XD to %x/XD.\n", [forcedeth_linkspeed]:8, [forcedeth_tmp_newls]:8 ; !!!!!!!!!!!!!!!!!!!!!!!!!!!! |
; np->duplex = newdup |
mov eax, dword [forcedeth_tmp_newdup] |
mov dword [forcedeth_duplex], eax |
; np->linkspeed = newls |
mov eax, [forcedeth_tmp_newls] |
mov dword [forcedeth_linkspeed], eax |
; if (np->gigabit == PHY_GIGABIT) { |
cmp dword [forcedeth_gigabit], PHY_GIGABIT |
jne .end_if3 |
; phyreg = readl(base + NvRegRandomSeed); |
mov edi, dword [forcedeth_mapio_addr] |
mov eax, dword [edi+NvRegRandomSeed] |
; phyreg &= ~(0x3FF00); |
and eax, not (0x3FF00) |
mov ecx, eax ; phyreg = ecx |
; if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10) |
mov eax, dword [forcedeth_linkspeed] |
and eax, 0xFFF |
cmp eax, NVREG_LINKSPEED_10 |
jne @f |
; phyreg |= NVREG_RNDSEED_FORCE3 |
or ecx, NVREG_RNDSEED_FORCE3 |
jmp .end_if4 |
@@: |
; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) |
cmp eax, NVREG_LINKSPEED_100 |
jne @f |
; phyreg |= NVREG_RNDSEED_FORCE2 |
or ecx, NVREG_RNDSEED_FORCE2 |
jmp .end_if4 |
@@: |
; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) |
cmp eax, NVREG_LINKSPEED_1000 |
jne .end_if4 |
; phyreg |= NVREG_RNDSEED_FORCE |
or ecx, NVREG_RNDSEED_FORCE |
.end_if4: |
; writel(phyreg, base + NvRegRandomSeed) |
mov dword [edi+NvRegRandomSeed], ecx |
.end_if3: |
; phyreg = readl(base + NvRegPhyInterface) |
mov ecx, dword [edi+NvRegPhyInterface] |
; phyreg &= ~(PHY_HALF | PHY_100 | PHY_1000) |
and ecx, not (PHY_HALF or PHY_100 or PHY_1000) |
; if (np->duplex == 0) |
cmp dword [forcedeth_duplex], 0 |
jne @f |
; phyreg |= PHY_HALF |
or ecx, PHY_HALF |
@@: |
; if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) |
mov eax, dword [forcedeth_linkspeed] |
and eax, 0xFFF |
cmp eax, NVREG_LINKSPEED_100 |
jne @f |
; phyreg |= PHY_100 |
or ecx, PHY_100 |
jmp .end_if5 |
@@: |
; else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) |
cmp eax, NVREG_LINKSPEED_1000 |
jne .end_if5 |
; phyreg |= PHY_1000 |
or ecx, PHY_1000 |
.end_if5: |
; writel(phyreg, base + NvRegPhyInterface) |
mov dword [edi+NvRegPhyInterface], ecx |
; writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD), base + NvRegMisc1); |
cmp dword [forcedeth_duplex], 0 |
je @f |
mov ecx, 0 |
jmp .next |
@@: |
mov ecx, NVREG_MISC1_HD |
.next: |
or ecx, NVREG_MISC1_FORCE |
mov dword [edi+NvRegMisc1], ecx |
; pci_push(base) |
call forcedeth_pci_push |
; writel(np->linkspeed, base + NvRegLinkSpeed) |
mov eax, dword [forcedeth_linkspeed] |
mov dword [edi+NvRegLinkSpeed], eax |
; pci_push(base) |
call forcedeth_pci_push |
.return: |
; return retval |
mov eax, dword [forcedeth_tmp_retval] |
pop edi esi ecx ebx |
ret |
; Input: none |
; Output: none |
forcedeth_start_tx: |
push edi |
; dprintf(("start_tx\n")) |
DEBUGF 1," K : FORCEDETH: start_tx.\n" |
; writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl) |
mov edi, dword [forcedeth_mapio_addr] |
mov dword [edi+NvRegTransmitterControl], NVREG_XMITCTL_START |
; pci_push(base) |
call forcedeth_pci_push |
.return: |
pop edi |
ret |
; Interrupt handler |
forcedeth_int_handler: |
DEBUGF 1," K : FORCEDETH: interrupt handler.\n" |
ret |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/i8255x.inc |
---|
0,0 → 1,794 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; 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 ;; |
;; ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
;******************************************************************** |
; 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_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: |
DEBUGF 1," K : Probing i8255x device \n" |
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 |
sub eax, OS_BASE |
mov [rxfd_link], eax |
mov eax, Ether_buffer |
sub eax, OS_BASE |
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 |
sub eax, OS_BASE |
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 |
sub eax, OS_BASE |
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 |
sub eax, OS_BASE |
mov [confcmd_link], eax |
mov ax, 1 |
mov [txfd_command], ax ; CmdIASetup |
mov ax, 0 |
mov [txfd_status], ax |
mov eax, confcmd |
sub eax, OS_BASE |
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 |
sub eax, OS_BASE |
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_reset |
; Description |
; Place the chip (ie, the ethernet card) into a virgin state |
; No inputs |
; All registers destroyed |
; |
;*************************************************************************** |
I8255x_reset: |
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 |
sub eax, OS_BASE |
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 |
sub eax, OS_BASE |
mov [txfd_tx_desc_addr], eax |
mov eax, hdr |
sub eax, OS_BASE |
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 |
sub eax, OS_BASE |
mov [txfd_tx_buf_addr1], eax |
mov eax, ecx |
mov [txfd_tx_buf_size1], eax |
mov eax, txfd |
sub eax, OS_BASE |
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 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/rtl8029.inc |
---|
0,0 → 1,976 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; 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! ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
;******************************************************************** |
; 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 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/rtl8139.inc |
---|
0,0 → 1,624 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; 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 ;; |
;; ;; |
;; 10.01.2007 Bugfix for l8139_transmit from Paolo Franchetti ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
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 eax, RTL8139_RX_CONFIG |
add edx, RTL8139_REG_RXCONFIG - RTL8139_REG_COMMAND |
out dx, eax |
; 1024 bytes DMA burst, total retries = 16 + 8 * 16 = 144 |
mov eax, (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, eax |
; 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 ; simba |
sub eax, OS_BASE |
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 |
test ax, 0x1fff ; or no size given |
jz .send_packet |
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 |
; 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 |
sub eax, OS_BASE |
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 |
rtl8139_cable: |
pusha |
mov edx, [io_addr] |
add edx, 0x58 |
in al, dx |
test al, 1 SHL 2 |
jnz .notconnected |
popa |
xor al, al |
inc al |
ret |
.notconnected: |
popa |
xor al, al |
ret |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/rtl8169.inc |
---|
0,0 → 1,1239 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; RTL8169.INC ;; |
;; ;; |
;; Ethernet driver for Menuet OS ;; |
;; ;; |
;; Version 0.1 11 February 2007 ;; |
;; ;; |
;; Driver for chips of RealTek 8169 family ;; |
;; References: ;; |
;; r8169.c - linux driver (etherboot project) ;; |
;; ethernet driver template by Mike Hibbett ;; |
;; ;; |
;; The copyright statement is ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;; Copyright 2007 mike.dld, ;; |
;; mike.dld@gmail.com ;; |
;; ;; |
;; See file COPYING for details ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
ETH_ALEN equ 6 |
ETH_HLEN equ (2 * ETH_ALEN + 2) |
ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for |
; mininmum 64bytes frame length |
RTL8169_REG_MAC0 equ 0x0 ; Ethernet hardware address |
RTL8169_REG_MAR0 equ 0x8 ; Multicast filter |
RTL8169_REG_TxDescStartAddr equ 0x20 |
RTL8169_REG_TxHDescStartAddr equ 0x28 |
RTL8169_REG_FLASH equ 0x30 |
RTL8169_REG_ERSR equ 0x36 |
RTL8169_REG_ChipCmd equ 0x37 |
RTL8169_REG_TxPoll equ 0x38 |
RTL8169_REG_IntrMask equ 0x3C |
RTL8169_REG_IntrStatus equ 0x3E |
RTL8169_REG_TxConfig equ 0x40 |
RTL8169_REG_RxConfig equ 0x44 |
RTL8169_REG_RxMissed equ 0x4C |
RTL8169_REG_Cfg9346 equ 0x50 |
RTL8169_REG_Config0 equ 0x51 |
RTL8169_REG_Config1 equ 0x52 |
RTL8169_REG_Config2 equ 0x53 |
RTL8169_REG_Config3 equ 0x54 |
RTL8169_REG_Config4 equ 0x55 |
RTL8169_REG_Config5 equ 0x56 |
RTL8169_REG_MultiIntr equ 0x5C |
RTL8169_REG_PHYAR equ 0x60 |
RTL8169_REG_TBICSR equ 0x64 |
RTL8169_REG_TBI_ANAR equ 0x68 |
RTL8169_REG_TBI_LPAR equ 0x6A |
RTL8169_REG_PHYstatus equ 0x6C |
RTL8169_REG_RxMaxSize equ 0xDA |
RTL8169_REG_CPlusCmd equ 0xE0 |
RTL8169_REG_RxDescStartAddr equ 0xE4 |
RTL8169_REG_ETThReg equ 0xEC |
RTL8169_REG_FuncEvent equ 0xF0 |
RTL8169_REG_FuncEventMask equ 0xF4 |
RTL8169_REG_FuncPresetState equ 0xF8 |
RTL8169_REG_FuncForceEvent equ 0xFC |
; InterruptStatusBits |
RTL8169_ISB_SYSErr equ 0x8000 |
RTL8169_ISB_PCSTimeout equ 0x4000 |
RTL8169_ISB_SWInt equ 0x0100 |
RTL8169_ISB_TxDescUnavail equ 0x80 |
RTL8169_ISB_RxFIFOOver equ 0x40 |
RTL8169_ISB_LinkChg equ 0x20 |
RTL8169_ISB_RxOverflow equ 0x10 |
RTL8169_ISB_TxErr equ 0x08 |
RTL8169_ISB_TxOK equ 0x04 |
RTL8169_ISB_RxErr equ 0x02 |
RTL8169_ISB_RxOK equ 0x01 |
; RxStatusDesc |
RTL8169_SD_RxRES equ 0x00200000 |
RTL8169_SD_RxCRC equ 0x00080000 |
RTL8169_SD_RxRUNT equ 0x00100000 |
RTL8169_SD_RxRWT equ 0x00400000 |
; ChipCmdBits |
RTL8169_CMD_Reset equ 0x10 |
RTL8169_CMD_RxEnb equ 0x08 |
RTL8169_CMD_TxEnb equ 0x04 |
RTL8169_CMD_RxBufEmpty equ 0x01 |
; Cfg9346Bits |
RTL8169_CFG_9346_Lock equ 0x00 |
RTL8169_CFG_9346_Unlock equ 0xC0 |
; rx_mode_bits |
RTL8169_RXM_AcceptErr equ 0x20 |
RTL8169_RXM_AcceptRunt equ 0x10 |
RTL8169_RXM_AcceptBroadcast equ 0x08 |
RTL8169_RXM_AcceptMulticast equ 0x04 |
RTL8169_RXM_AcceptMyPhys equ 0x02 |
RTL8169_RXM_AcceptAllPhys equ 0x01 |
; RxConfigBits |
RTL8169_RXC_FIFOShift equ 13 |
RTL8169_RXC_DMAShift equ 8 |
; TxConfigBits |
RTL8169_TXC_InterFrameGapShift equ 24 |
RTL8169_TXC_DMAShift equ 8 ; DMA burst value (0-7) is shift this many bits |
; rtl8169_PHYstatus |
RTL8169_PHYS_TBI_Enable equ 0x80 |
RTL8169_PHYS_TxFlowCtrl equ 0x40 |
RTL8169_PHYS_RxFlowCtrl equ 0x20 |
RTL8169_PHYS_1000bpsF equ 0x10 |
RTL8169_PHYS_100bps equ 0x08 |
RTL8169_PHYS_10bps equ 0x04 |
RTL8169_PHYS_LinkStatus equ 0x02 |
RTL8169_PHYS_FullDup equ 0x01 |
; GIGABIT_PHY_registers |
RTL8169_PHY_CTRL_REG equ 0 |
RTL8169_PHY_STAT_REG equ 1 |
RTL8169_PHY_AUTO_NEGO_REG equ 4 |
RTL8169_PHY_1000_CTRL_REG equ 9 |
; GIGABIT_PHY_REG_BIT |
RTL8169_PHY_Restart_Auto_Nego equ 0x0200 |
RTL8169_PHY_Enable_Auto_Nego equ 0x1000 |
; PHY_STAT_REG = 1; |
RTL8169_PHY_Auto_Neco_Comp equ 0x0020 |
; PHY_AUTO_NEGO_REG = 4; |
RTL8169_PHY_Cap_10_Half equ 0x0020 |
RTL8169_PHY_Cap_10_Full equ 0x0040 |
RTL8169_PHY_Cap_100_Half equ 0x0080 |
RTL8169_PHY_Cap_100_Full equ 0x0100 |
; PHY_1000_CTRL_REG = 9; |
RTL8169_PHY_Cap_1000_Full equ 0x0200 |
RTL8169_PHY_Cap_1000_Half equ 0x0100 |
RTL8169_PHY_Cap_PAUSE equ 0x0400 |
RTL8169_PHY_Cap_ASYM_PAUSE equ 0x0800 |
RTL8169_PHY_Cap_Null equ 0x0 |
; _MediaType |
RTL8169_MT_10_Half equ 0x01 |
RTL8169_MT_10_Full equ 0x02 |
RTL8169_MT_100_Half equ 0x04 |
RTL8169_MT_100_Full equ 0x08 |
RTL8169_MT_1000_Full equ 0x10 |
; _TBICSRBit |
RTL8169_TBI_LinkOK equ 0x02000000 |
; _DescStatusBit |
RTL8169_DSB_OWNbit equ 0x80000000 |
RTL8169_DSB_EORbit equ 0x40000000 |
RTL8169_DSB_FSbit equ 0x20000000 |
RTL8169_DSB_LSbit equ 0x10000000 |
; MAC address length |
MAC_ADDR_LEN equ 6 |
; max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4) |
MAX_ETH_FRAME_SIZE equ 1536 |
TX_FIFO_THRESH equ 256 ; In bytes |
RX_FIFO_THRESH equ 7 ; 7 means NO threshold, Rx buffer level before first PCI xfer |
RX_DMA_BURST equ 7 ; Maximum PCI burst, '6' is 1024 |
TX_DMA_BURST equ 7 ; Maximum PCI burst, '6' is 1024 |
ETTh equ 0x3F ; 0x3F means NO threshold |
EarlyTxThld equ 0x3F ; 0x3F means NO early transmit |
RxPacketMaxSize equ 0x0800 ; Maximum size supported is 16K-1 |
InterFrameGap equ 0x03 ; 3 means InterFrameGap = the shortest one |
NUM_TX_DESC equ 1 ; Number of Tx descriptor registers |
NUM_RX_DESC equ 4 ; Number of Rx descriptor registers |
RX_BUF_SIZE equ 1536 ; Rx Buffer size |
HZ equ 1000 |
RTL_MIN_IO_SIZE equ 0x80 |
TX_TIMEOUT equ (6*HZ) |
RTL8169_TIMER_EXPIRE_TIME equ 100 |
ETH_HDR_LEN equ 14 |
DEFAULT_MTU equ 1500 |
DEFAULT_RX_BUF_LEN equ 1536 |
;#ifdef RTL8169_JUMBO_FRAME_SUPPORT |
;#define MAX_JUMBO_FRAME_MTU ( 10000 ) |
;#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN ) |
;#else |
MAX_RX_SKBDATA_SIZE equ 1600 |
;#endif //end #ifdef RTL8169_JUMBO_FRAME_SUPPORT |
;#ifdef RTL8169_USE_IO |
;!!!#define RTL_W8(reg, val8) outb ((val8), ioaddr + (reg)) |
macro RTL_W8 reg,val8 { |
if ~reg eq dx |
mov dx, word[rtl8169_tpc.mmio_addr] |
add dx, reg |
end if |
if ~val8 eq al |
mov al, val8 |
end if |
out dx, al |
} |
;!!!#define RTL_W16(reg, val16) outw ((val16), ioaddr + (reg)) |
macro RTL_W16 reg,val16 { |
if ~reg eq dx |
mov dx, word[rtl8169_tpc.mmio_addr] |
add dx, reg |
end if |
if ~val16 eq ax |
mov ax, val16 |
end if |
out dx, ax |
} |
;!!!#define RTL_W32(reg, val32) outl ((val32), ioaddr + (reg)) |
macro RTL_W32 reg,val32 { |
if ~reg eq dx |
mov dx, word[rtl8169_tpc.mmio_addr] |
add dx, reg |
end if |
if ~val32 eq eax |
mov eax, val32 |
end if |
out dx, eax |
} |
;!!!#define RTL_R8(reg) inb (ioaddr + (reg)) |
macro RTL_R8 reg { |
if ~reg eq dx |
mov dx, word[rtl8169_tpc.mmio_addr] |
add dx, reg |
end if |
in al, dx |
} |
;!!!#define RTL_R16(reg) inw (ioaddr + (reg)) |
macro RTL_R16 reg { |
if ~reg eq dx |
mov dx, word[rtl8169_tpc.mmio_addr] |
add dx, reg |
end if |
in ax, dx |
} |
;!!!#define RTL_R32(reg) ((unsigned long) inl (ioaddr + (reg))) |
macro RTL_R32 reg { |
if ~reg eq dx |
mov dx, word[rtl8169_tpc.mmio_addr] |
add dx, reg |
end if |
in eax, dx |
} |
;#else |
; write/read MMIO register |
;#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) |
;#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) |
;#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) |
;#define RTL_R8(reg) readb (ioaddr + (reg)) |
;#define RTL_R16(reg) readw (ioaddr + (reg)) |
;#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) |
;#endif |
MCFG_METHOD_01 equ 0x01 |
MCFG_METHOD_02 equ 0x02 |
MCFG_METHOD_03 equ 0x03 |
MCFG_METHOD_04 equ 0x04 |
MCFG_METHOD_05 equ 0x05 |
MCFG_METHOD_11 equ 0x0b |
MCFG_METHOD_12 equ 0x0c |
MCFG_METHOD_13 equ 0x0d |
MCFG_METHOD_14 equ 0x0e |
MCFG_METHOD_15 equ 0x0f |
PCFG_METHOD_1 equ 0x01 ; PHY Reg 0x03 bit0-3 == 0x0000 |
PCFG_METHOD_2 equ 0x02 ; PHY Reg 0x03 bit0-3 == 0x0001 |
PCFG_METHOD_3 equ 0x03 ; PHY Reg 0x03 bit0-3 == 0x0002 |
PCI_COMMAND_IO equ 0x1 ; Enable response in I/O space |
PCI_COMMAND_MEM equ 0x2 ; Enable response in mem space |
PCI_COMMAND_MASTER equ 0x4 ; Enable bus mastering |
PCI_LATENCY_TIMER equ 0x0d ; 8 bits |
PCI_COMMAND_SPECIAL equ 0x8 ; Enable response to special cycles |
PCI_COMMAND_INVALIDATE equ 0x10 ; Use memory write and invalidate |
PCI_COMMAND_VGA_PALETTE equ 0x20 ; Enable palette snooping |
PCI_COMMAND_PARITY equ 0x40 ; Enable parity checking |
PCI_COMMAND_WAIT equ 0x80 ; Enable address/data stepping |
PCI_COMMAND_SERR equ 0x100 ; Enable SERR |
PCI_COMMAND_FAST_BACK equ 0x200 ; Enable back-to-back writes |
struc rtl8169_TxDesc { |
.status dd ? |
.vlan_tag dd ? |
.buf_addr dd ? |
.buf_Haddr dd ? |
} |
virtual at 0 |
rtl8169_TxDesc rtl8169_TxDesc |
sizeof.rtl8169_TxDesc = $ - rtl8169_TxDesc |
end virtual |
struc rtl8169_RxDesc { |
.status dd ? |
.vlan_tag dd ? |
.buf_addr dd ? |
.buf_Haddr dd ? |
} |
virtual at 0 |
rtl8169_RxDesc rtl8169_RxDesc |
sizeof.rtl8169_RxDesc = $ - rtl8169_RxDesc |
end virtual |
virtual at eth_data_start |
; Define the TX Descriptor |
align 256 |
rtl8169_tx_ring rb NUM_TX_DESC * sizeof.rtl8169_TxDesc |
; Create a static buffer of size RX_BUF_SZ for each |
; TX Descriptor. All descriptors point to a |
; part of this buffer |
align 256 |
rtl8169_txb rb NUM_TX_DESC * RX_BUF_SIZE |
; Define the RX Descriptor |
align 256 |
rtl8169_rx_ring rb NUM_RX_DESC * sizeof.rtl8169_RxDesc |
; Create a static buffer of size RX_BUF_SZ for each |
; RX Descriptor All descriptors point to a |
; part of this buffer |
align 256 |
rtl8169_rxb rb NUM_RX_DESC * RX_BUF_SIZE |
rtl8169_tpc: |
.mmio_addr dd ? ; memory map physical address |
.chipset dd ? |
.pcfg dd ? |
.mcfg dd ? |
.cur_rx dd ? ; Index into the Rx descriptor buffer of next Rx pkt |
.cur_tx dd ? ; Index into the Tx descriptor buffer of next Rx pkt |
.TxDescArrays dd ? ; Index of Tx Descriptor buffer |
.RxDescArrays dd ? ; Index of Rx Descriptor buffer |
.TxDescArray dd ? ; Index of 256-alignment Tx Descriptor buffer |
.RxDescArray dd ? ; Index of 256-alignment Rx Descriptor buffer |
.RxBufferRing rd NUM_RX_DESC ; Index of Rx Buffer array |
.Tx_skbuff rd NUM_TX_DESC |
end virtual |
rtl8169_intr_mask = RTL8169_ISB_LinkChg or RTL8169_ISB_RxOverflow or RTL8169_ISB_RxFIFOOver or RTL8169_ISB_TxErr or RTL8169_ISB_TxOK or RTL8169_ISB_RxErr or RTL8169_ISB_RxOK |
rtl8169_rx_config = (RX_FIFO_THRESH shl RTL8169_RXC_FIFOShift) or (RX_DMA_BURST shl RTL8169_RXC_DMAShift) or 0x0000000E |
iglobal |
;static struct { |
; const char *name; |
; u8 mcfg; /* depend on RTL8169 docs */ |
; u32 RxConfigMask; /* should clear the bits supported by this chip */ |
;} |
rtl_chip_info dd \ |
MCFG_METHOD_01, 0xff7e1880, \ ; RTL8169 |
MCFG_METHOD_02, 0xff7e1880, \ ; RTL8169s/8110s |
MCFG_METHOD_03, 0xff7e1880, \ ; RTL8169s/8110s |
MCFG_METHOD_04, 0xff7e1880, \ ; RTL8169sb/8110sb |
MCFG_METHOD_05, 0xff7e1880, \ ; RTL8169sc/8110sc |
MCFG_METHOD_11, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E |
MCFG_METHOD_12, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E |
MCFG_METHOD_13, 0xff7e1880, \ ; RTL8101e // PCI-E 8139 |
MCFG_METHOD_14, 0xff7e1880, \ ; RTL8100e // PCI-E 8139 |
MCFG_METHOD_15, 0xff7e1880 ; RTL8100e // PCI-E 8139 |
mac_info dd \ |
0x38800000, MCFG_METHOD_15, \ |
0x38000000, MCFG_METHOD_12, \ |
0x34000000, MCFG_METHOD_13, \ |
0x30800000, MCFG_METHOD_14, \ |
0x30000000, MCFG_METHOD_11, \ |
0x18000000, MCFG_METHOD_05, \ |
0x10000000, MCFG_METHOD_04, \ |
0x04000000, MCFG_METHOD_03, \ |
0x00800000, MCFG_METHOD_02, \ |
0x00000000, MCFG_METHOD_01 ; catch-all |
endg |
PCI_COMMAND_IO equ 0x1 ; Enable response in I/O space |
PCI_COMMAND_MEM equ 0x2 ; Enable response in mem space |
PCI_COMMAND_MASTER equ 0x4 ; Enable bus mastering |
PCI_LATENCY_TIMER equ 0x0d ; 8 bits |
PCI_COMMAND_SPECIAL equ 0x8 ; Enable response to special cycles |
PCI_COMMAND_INVALIDATE equ 0x10 ; Use memory write and invalidate |
PCI_COMMAND_VGA_PALETTE equ 0x20 ; Enable palette snooping |
PCI_COMMAND_PARITY equ 0x40 ; Enable parity checking |
PCI_COMMAND_WAIT equ 0x80 ; Enable address/data stepping |
PCI_COMMAND_SERR equ 0x100 ; Enable SERR |
PCI_COMMAND_FAST_BACK equ 0x200 ; Enable back-to-back writes |
PCI_VENDOR_ID equ 0x00 ; 16 bits |
PCI_DEVICE_ID equ 0x02 ; 16 bits |
PCI_COMMAND equ 0x04 ; 16 bits |
PCI_BASE_ADDRESS_0 equ 0x10 ; 32 bits |
PCI_BASE_ADDRESS_1 equ 0x14 ; 32 bits |
PCI_BASE_ADDRESS_2 equ 0x18 ; 32 bits |
PCI_BASE_ADDRESS_3 equ 0x1c ; 32 bits |
PCI_BASE_ADDRESS_4 equ 0x20 ; 32 bits |
PCI_BASE_ADDRESS_5 equ 0x24 ; 32 bits |
PCI_BASE_ADDRESS_MEM_TYPE_MASK equ 0x06 |
PCI_BASE_ADDRESS_MEM_TYPE_32 equ 0x00 ; 32 bit address |
PCI_BASE_ADDRESS_MEM_TYPE_1M equ 0x02 ; Below 1M [obsolete] |
PCI_BASE_ADDRESS_MEM_TYPE_64 equ 0x04 ; 64 bit address |
PCI_BASE_ADDRESS_IO_MASK equ (not 0x03) |
PCI_BASE_ADDRESS_MEM_MASK equ (not 0x0f) |
PCI_BASE_ADDRESS_SPACE_IO equ 0x01 |
PCI_ROM_ADDRESS equ 0x30 ; 32 bits |
proc CONFIG_CMD,where:byte |
movzx eax, byte[pci_bus] |
shl eax, 8 |
mov al, [pci_dev] |
shl eax, 8 |
mov al, [where] |
and al, not 3 |
or eax, 0x80000000 |
ret |
endp |
proc pci_read_config_byte,where:dword |
push edx |
stdcall CONFIG_CMD, [where] |
mov dx, 0xCF8 |
out dx, eax |
mov edx, [where] |
and edx, 3 |
add edx, 0xCFC |
in al, dx |
pop edx |
ret |
endp |
proc pci_read_config_word,where:dword |
push edx |
stdcall CONFIG_CMD, [where] |
mov dx, 0xCF8 |
out dx, eax |
mov edx, [where] |
and edx, 2 |
add edx, 0xCFC |
in ax, dx |
pop edx |
ret |
endp |
proc pci_read_config_dword,where:dword |
push edx |
stdcall CONFIG_CMD, [where] |
mov edx, 0xCF8 |
out dx, eax |
mov edx, 0xCFC |
in eax, dx |
pop edx |
ret |
endp |
proc pci_write_config_byte,where:dword,value:byte |
push edx |
stdcall CONFIG_CMD, [where] |
mov dx, 0xCF8 |
out dx, eax |
mov edx, [where] |
and edx, 3 |
add edx, 0xCFC |
mov al, [value] |
out dx, al |
pop edx |
ret |
endp |
proc pci_write_config_word,where:dword,value:word |
push edx |
stdcall CONFIG_CMD, [where] |
mov dx, 0xCF8 |
out dx, eax |
mov edx, [where] |
and edx, 2 |
add edx, 0xCFC |
mov ax, [value] |
out dx, ax |
pop edx |
ret |
endp |
proc pci_write_config_dword,where:dword,value:dword |
push edx |
stdcall CONFIG_CMD, [where] |
mov edx, 0xCF8 |
out dx, eax |
mov edx, 0xCFC |
mov eax, [value] |
out dx, eax |
pop edx |
ret |
endp |
; Set device to be a busmaster in case BIOS neglected to do so. |
; Also adjust PCI latency timer to a reasonable value, 32. |
proc adjust_pci_device |
; DEBUGF 1,"K : adjust_pci_device\n" |
stdcall pci_read_config_word, PCI_COMMAND |
mov bx, ax |
or bx, PCI_COMMAND_MASTER or PCI_COMMAND_IO |
cmp ax, bx |
je @f |
; DEBUGF 1,"K : adjust_pci_device: The PCI BIOS has not enabled this device!\nK : Updating PCI command %x->%x. pci_bus %x pci_device_fn %x\n",ax,bx,[pci_bus]:2,[pci_dev]:2 |
stdcall pci_write_config_word, PCI_COMMAND, ebx |
@@: |
stdcall pci_read_config_byte, PCI_LATENCY_TIMER |
cmp al, 32 |
jae @f |
; DEBUGF 1,"K : adjust_pci_device: PCI latency timer (CFLT) is unreasonably low at %d.\nK : Setting to 32 clocks.\n",al |
stdcall pci_write_config_byte, PCI_LATENCY_TIMER, 32 |
@@: |
ret |
endp |
; Find the start of a pci resource |
proc pci_bar_start,index:dword |
stdcall pci_read_config_dword, [index] |
test eax, PCI_BASE_ADDRESS_SPACE_IO |
jz @f |
and eax, PCI_BASE_ADDRESS_IO_MASK |
jmp .exit |
@@: |
push eax |
and eax, PCI_BASE_ADDRESS_MEM_TYPE_MASK |
cmp eax, PCI_BASE_ADDRESS_MEM_TYPE_64 |
jne .not64 |
mov eax, [index] |
add eax, 4 |
stdcall pci_read_config_dword, eax |
or eax, eax |
jz .not64 |
; DEBUGF 1,"K : pci_bar_start: Unhandled 64bit BAR\n" |
add esp, 4 |
or eax, -1 |
ret |
.not64: |
pop eax |
and eax, PCI_BASE_ADDRESS_MEM_MASK |
.exit: |
ret |
endp |
proc rtl8169_init_board |
; DEBUGF 1,"K : rtl8169_init_board\n" |
call adjust_pci_device |
stdcall pci_bar_start, PCI_BASE_ADDRESS_0 |
mov [rtl8169_tpc.mmio_addr], eax |
; Soft reset the chip |
RTL_W8 RTL8169_REG_ChipCmd,RTL8169_CMD_Reset |
; Check that the chip has finished the reset |
mov ecx, 1000 |
@@: |
RTL_R8 RTL8169_REG_ChipCmd |
test al, RTL8169_CMD_Reset |
jz @f |
stdcall udelay, 10 |
loop @b |
@@: |
; identify config method |
RTL_R32 RTL8169_REG_TxConfig |
and eax, 0x7c800000 |
; DEBUGF 1,"K : rtl8169_init_board: TxConfig & 0x7c800000 = 0x%x\n",eax |
mov esi, mac_info-8 |
@@: |
add esi, 8 |
mov ecx, eax |
and ecx, [esi] |
cmp ecx, [esi] |
jne @b |
mov eax, [esi+4] |
mov [rtl8169_tpc.mcfg], eax |
mov [rtl8169_tpc.pcfg], PCFG_METHOD_3 |
stdcall RTL8169_READ_GMII_REG, 3 |
and al, 0x0f |
or al, al |
jnz @f |
mov [rtl8169_tpc.pcfg], PCFG_METHOD_1 |
jmp .pconf |
@@: |
dec al |
jnz .pconf |
mov [rtl8169_tpc.pcfg], PCFG_METHOD_2 |
.pconf: |
; identify chip attached to board |
mov ecx, 10 |
mov eax, [rtl8169_tpc.mcfg] |
@@: |
dec ecx |
js @f |
cmp eax, [rtl_chip_info+ecx*8] |
jne @b |
mov [rtl8169_tpc.chipset], ecx |
jmp .match |
@@: |
; if unknown chip, assume array element #0, original RTL-8169 in this case |
; DEBUGF 1,"K : rtl8169_init_board: PCI device: unknown chip version, assuming RTL-8169\n" |
RTL_R32 RTL8169_REG_TxConfig |
; DEBUGF 1,"K : rtl8169_init_board: PCI device: TxConfig = 0x%x\n",eax |
mov [rtl8169_tpc.chipset], 0 |
xor eax, eax |
inc eax |
ret |
.match: |
xor eax, eax |
ret |
endp |
proc rtl8169_hw_PHY_config |
; DEBUGF 1,"K : rtl8169_hw_PHY_config: priv.mcfg=%d, priv.pcfg=%d\n",[rtl8169_tpc.mcfg],[rtl8169_tpc.pcfg] |
; DBG_PRINT("priv->mcfg=%d, priv->pcfg=%d\n", tpc->mcfg, tpc->pcfg); |
cmp [rtl8169_tpc.mcfg], MCFG_METHOD_04 |
jne .not_4 |
; stdcall RTL8169_WRITE_GMII_REG,0x1F,0x0001 |
; stdcall RTL8169_WRITE_GMII_REG,0x1b,0x841e |
; stdcall RTL8169_WRITE_GMII_REG,0x0e,0x7bfb |
; stdcall RTL8169_WRITE_GMII_REG,0x09,0x273a |
stdcall RTL8169_WRITE_GMII_REG, 0x1F, 0x0002 |
stdcall RTL8169_WRITE_GMII_REG, 0x01, 0x90D0 |
stdcall RTL8169_WRITE_GMII_REG, 0x1F, 0x0000 |
jmp .exit |
.not_4: |
cmp [rtl8169_tpc.mcfg], MCFG_METHOD_02 |
je @f |
cmp [rtl8169_tpc.mcfg], MCFG_METHOD_03 |
jne .not_2_or_3 |
@@: |
stdcall RTL8169_WRITE_GMII_REG, 0x1F, 0x0001 |
stdcall RTL8169_WRITE_GMII_REG, 0x15, 0x1000 |
stdcall RTL8169_WRITE_GMII_REG, 0x18, 0x65C7 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x0000 |
stdcall RTL8169_WRITE_GMII_REG, 0x03, 0x00A1 |
stdcall RTL8169_WRITE_GMII_REG, 0x02, 0x0008 |
stdcall RTL8169_WRITE_GMII_REG, 0x01, 0x1020 |
stdcall RTL8169_WRITE_GMII_REG, 0x00, 0x1000 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x0800 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x0000 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x7000 |
stdcall RTL8169_WRITE_GMII_REG, 0x03, 0xFF41 |
stdcall RTL8169_WRITE_GMII_REG, 0x02, 0xDE60 |
stdcall RTL8169_WRITE_GMII_REG, 0x01, 0x0140 |
stdcall RTL8169_WRITE_GMII_REG, 0x00, 0x0077 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x7800 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x7000 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xA000 |
stdcall RTL8169_WRITE_GMII_REG, 0x03, 0xDF01 |
stdcall RTL8169_WRITE_GMII_REG, 0x02, 0xDF20 |
stdcall RTL8169_WRITE_GMII_REG, 0x01, 0xFF95 |
stdcall RTL8169_WRITE_GMII_REG, 0x00, 0xFA00 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xA800 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xA000 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xB000 |
stdcall RTL8169_WRITE_GMII_REG, 0x03, 0xFF41 |
stdcall RTL8169_WRITE_GMII_REG, 0x02, 0xDE20 |
stdcall RTL8169_WRITE_GMII_REG, 0x01, 0x0140 |
stdcall RTL8169_WRITE_GMII_REG, 0x00, 0x00BB |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xB800 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xB000 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xF000 |
stdcall RTL8169_WRITE_GMII_REG, 0x03, 0xDF01 |
stdcall RTL8169_WRITE_GMII_REG, 0x02, 0xDF20 |
stdcall RTL8169_WRITE_GMII_REG, 0x01, 0xFF95 |
stdcall RTL8169_WRITE_GMII_REG, 0x00, 0xBF00 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xF800 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0xF000 |
stdcall RTL8169_WRITE_GMII_REG, 0x04, 0x0000 |
stdcall RTL8169_WRITE_GMII_REG, 0x1F, 0x0000 |
stdcall RTL8169_WRITE_GMII_REG, 0x0B, 0x0000 |
jmp .exit |
.not_2_or_3: |
; DBG_PRINT("tpc->mcfg=%d. Discard hw PHY config.\n", tpc->mcfg); |
; DEBUGF 1,"K : tpc.mcfg=%d, discard hw PHY config\n",[rtl8169_tpc.mcfg] |
.exit: |
ret |
endp |
;proc pci_write_config_byte |
; ret |
;endp |
proc RTL8169_WRITE_GMII_REG,RegAddr:byte,value:dword |
;;; DEBUGF 1,"K : RTL8169_WRITE_GMII_REG: 0x%x 0x%x\n",[RegAddr]:2,[value] |
movzx eax, [RegAddr] |
shl eax, 16 |
or eax, [value] |
or eax, 0x80000000 |
RTL_W32 RTL8169_REG_PHYAR,eax |
stdcall udelay, 1 ;;;1000 |
mov ecx, 2000 |
; Check if the RTL8169 has completed writing to the specified MII register |
@@: |
RTL_R32 RTL8169_REG_PHYAR |
test eax, 0x80000000 |
jz .exit |
stdcall udelay, 1 ;;;100 |
loop @b |
.exit: |
ret |
endp |
proc RTL8169_READ_GMII_REG,RegAddr:byte |
;;; DEBUGF 1,"K : RTL8169_READ_GMII_REG: 0x%x\n",[RegAddr]:2 |
push ecx |
movzx eax, [RegAddr] |
shl eax, 16 |
; or eax,0x0 |
RTL_W32 RTL8169_REG_PHYAR,eax |
stdcall udelay, 1 ;;;1000 |
mov ecx, 2000 |
; Check if the RTL8169 has completed retrieving data from the specified MII register |
@@: |
RTL_R32 RTL8169_REG_PHYAR |
test eax, 0x80000000 |
jnz .exit |
stdcall udelay, 1 ;;;100 |
loop @b |
or eax, -1 |
pop ecx |
ret |
.exit: |
RTL_R32 RTL8169_REG_PHYAR |
and eax, 0xFFFF |
pop ecx |
ret |
endp |
proc rtl8169_set_rx_mode |
; DEBUGF 1,"K : rtl8169_set_rx_mode\n" |
; IFF_ALLMULTI |
; Too many to filter perfectly -- accept all multicasts |
RTL_R32 RTL8169_REG_RxConfig |
mov ecx, [rtl8169_tpc.chipset] |
and eax, [rtl_chip_info + ecx * 8 + 4]; RxConfigMask |
or eax, rtl8169_rx_config or (RTL8169_RXM_AcceptBroadcast or RTL8169_RXM_AcceptMulticast or RTL8169_RXM_AcceptMyPhys) |
RTL_W32 RTL8169_REG_RxConfig,eax |
; Multicast hash filter |
RTL_W32 RTL8169_REG_MAR0 + 0,0xffffffff |
RTL_W32 RTL8169_REG_MAR0 + 4,0xffffffff |
ret |
endp |
proc rtl8169_init_ring |
; DEBUGF 1,"K : rtl8169_init_ring\n" |
xor eax, eax |
mov [rtl8169_tpc.cur_rx], eax |
mov [rtl8169_tpc.cur_tx], eax |
mov edi, [rtl8169_tpc.TxDescArray] |
mov ecx, (NUM_TX_DESC * sizeof.rtl8169_TxDesc) / 4 |
cld |
rep stosd |
mov edi, [rtl8169_tpc.RxDescArray] |
mov ecx, (NUM_RX_DESC * sizeof.rtl8169_RxDesc) / 4 |
rep stosd |
mov edi, rtl8169_tpc.Tx_skbuff |
mov eax, rtl8169_txb |
mov ecx, NUM_TX_DESC |
@@: |
stosd |
inc eax ; add eax,RX_BUF_SIZE ??? |
loop @b |
;!!! for (i = 0; i < NUM_RX_DESC; i++) { |
;!!! if (i == (NUM_RX_DESC - 1)) |
;!!! tpc->RxDescArray[i].status = (OWNbit | EORbit) | RX_BUF_SIZE; |
;!!! else |
;!!! tpc->RxDescArray[i].status = OWNbit | RX_BUF_SIZE; |
;!!! tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; |
;!!! tpc->RxDescArray[i].buf_addr = virt_to_bus(tpc->RxBufferRing[i]); |
;!!! } |
mov esi, rtl8169_tpc.RxBufferRing |
mov edi, [rtl8169_tpc.RxDescArray] |
mov eax, rtl8169_rxb |
mov ecx, NUM_RX_DESC |
@@: |
mov [esi], eax |
mov [edi+rtl8169_RxDesc.buf_addr], eax |
sub [edi+rtl8169_RxDesc.buf_addr], OS_BASE ; shurf 28.09.2008 |
mov [edi+rtl8169_RxDesc.status], RTL8169_DSB_OWNbit or RX_BUF_SIZE |
add esi, 4 |
add edi, sizeof.rtl8169_RxDesc |
add eax, RX_BUF_SIZE |
loop @b |
or [edi - sizeof.rtl8169_RxDesc + rtl8169_RxDesc.status], RTL8169_DSB_EORbit |
ret |
endp |
proc rtl8169_hw_start |
; DEBUGF 1,"K : rtl8169_hw_start\n" |
; Soft reset the chip |
RTL_W8 RTL8169_REG_ChipCmd,RTL8169_CMD_Reset |
; Check that the chip has finished the reset |
mov ecx, 1000 |
@@: |
RTL_R8 RTL8169_REG_ChipCmd |
and al, RTL8169_CMD_Reset |
jz @f |
stdcall udelay, 10 |
loop @b |
@@: |
RTL_W8 RTL8169_REG_Cfg9346,RTL8169_CFG_9346_Unlock |
RTL_W8 RTL8169_REG_ChipCmd,RTL8169_CMD_TxEnb or RTL8169_CMD_RxEnb |
RTL_W8 RTL8169_REG_ETThReg,ETTh |
; For gigabit rtl8169 |
RTL_W16 RTL8169_REG_RxMaxSize,RxPacketMaxSize |
; Set Rx Config register |
RTL_R32 RTL8169_REG_RxConfig |
mov ecx, [rtl8169_tpc.chipset] |
and eax, [rtl_chip_info + ecx * 8 + 4]; RxConfigMask |
or eax, rtl8169_rx_config |
RTL_W32 RTL8169_REG_RxConfig,eax |
; Set DMA burst size and Interframe Gap Time |
RTL_W32 RTL8169_REG_TxConfig,(TX_DMA_BURST shl RTL8169_TXC_DMAShift) or (InterFrameGap shl RTL8169_TXC_InterFrameGapShift) |
RTL_R16 RTL8169_REG_CPlusCmd |
RTL_W16 RTL8169_REG_CPlusCmd,ax |
RTL_R16 RTL8169_REG_CPlusCmd |
or ax, 1 shl 3 |
cmp [rtl8169_tpc.mcfg], MCFG_METHOD_02 |
jne @f |
cmp [rtl8169_tpc.mcfg], MCFG_METHOD_03 |
jne @f |
or ax, 1 shl 14 |
; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n" |
jmp .set |
@@:;DEBUGF 1,"K : Set MAC Reg C+CR Offset 0xE0: bit-3\n" |
.set: |
RTL_W16 RTL8169_REG_CPlusCmd,ax |
; RTL_W16 0xE2,0x1517 |
; RTL_W16 0xE2,0x152a |
; RTL_W16 0xE2,0x282a |
RTL_W16 0xE2,0x0000 |
MOV [rtl8169_tpc.cur_rx],0 |
push eax ; shurf 28.09.2008 |
mov eax, [rtl8169_tpc.TxDescArray] ; shurf 28.09.2008 |
sub eax, OS_BASE ; shurf 28.09.2008 |
RTL_W32 RTL8169_REG_TxDescStartAddr,eax ;[rtl8169_tpc.TxDescArray] ; shurf 28.09.2008 |
mov eax, [rtl8169_tpc.RxDescArray] ; shurf 28.09.2008 |
sub eax, OS_BASE ; shurf 28.09.2008 |
RTL_W32 RTL8169_REG_RxDescStartAddr,eax ;[rtl8169_tpc.RxDescArray] ; shurf 28.09.2008 |
pop eax ; shurf 28.09.2008 |
RTL_W8 RTL8169_REG_Cfg9346,RTL8169_CFG_9346_Lock |
stdcall udelay, 10 |
RTL_W32 RTL8169_REG_RxMissed,0 |
call rtl8169_set_rx_mode |
; no early-rx interrupts |
RTL_R16 RTL8169_REG_MultiIntr |
and ax, 0xF000 |
RTL_W16 RTL8169_REG_MultiIntr,ax |
RTL_W16 RTL8169_REG_IntrMask,0 ; rtl8169_intr_mask |
ret |
endp |
proc udelay,msec:dword |
push esi |
mov esi, [msec] |
call delay_ms |
pop esi |
ret |
endp |
;*************************************************************************** |
; Function |
; rtl8169_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 |
; |
;*************************************************************************** |
proc rtl8169_probe |
; DEBUGF 1,"K : rtl8169_probe: 0x%x : 0x%x 0x%x\n",[io_addr]:8,[pci_bus]:2,[pci_dev]:2 |
call rtl8169_init_board |
mov ecx, MAC_ADDR_LEN |
mov edx, [rtl8169_tpc.mmio_addr] |
add edx, RTL8169_REG_MAC0 |
xor ebx, ebx |
; Get MAC address. FIXME: read EEPROM |
@@: |
RTL_R8 dx |
mov [node_addr+ebx], al |
inc edx |
inc ebx |
loop @b |
; DEBUGF 1,"K : rtl8169_probe: MAC = %x-%x-%x-%x-%x-%x\n",[node_addr+0]:2,[node_addr+1]:2,[node_addr+2]:2,[node_addr+3]:2,[node_addr+4]:2,[node_addr+5]:2 |
; Config PHY |
stdcall rtl8169_hw_PHY_config |
; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n" |
RTL_W8 0x82,0x01 |
cmp [rtl8169_tpc.mcfg], MCFG_METHOD_03 |
jae @f |
; DEBUGF 1,"K : Set PCI Latency=0x40\n" |
; stdcall pci_write_config_byte,PCI_LATENCY_TIMER,0x40 |
@@: |
cmp [rtl8169_tpc.mcfg], MCFG_METHOD_02 |
jne @f |
; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n" |
RTL_W8 0x82,0x01 |
; DEBUGF 1,"K : Set PHY Reg 0x0bh = 0x00h\n" |
stdcall RTL8169_WRITE_GMII_REG, 0x0b, 0x0000 ; w 0x0b 15 0 0 |
@@: |
; if TBI is not enabled |
RTL_R8 RTL8169_REG_PHYstatus |
test al, RTL8169_PHYS_TBI_Enable |
jz .tbi_dis |
stdcall RTL8169_READ_GMII_REG, RTL8169_PHY_AUTO_NEGO_REG |
; enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged |
and eax, 0x0C1F |
or eax, RTL8169_PHY_Cap_10_Half or RTL8169_PHY_Cap_10_Full or RTL8169_PHY_Cap_100_Half or RTL8169_PHY_Cap_100_Full |
stdcall RTL8169_WRITE_GMII_REG, RTL8169_PHY_AUTO_NEGO_REG, eax |
; enable 1000 Full Mode |
stdcall RTL8169_WRITE_GMII_REG, RTL8169_PHY_1000_CTRL_REG, RTL8169_PHY_Cap_1000_Full or RTL8169_PHY_Cap_1000_Half; rtl8168 |
; Enable auto-negotiation and restart auto-nigotiation |
stdcall RTL8169_WRITE_GMII_REG, RTL8169_PHY_CTRL_REG, RTL8169_PHY_Enable_Auto_Nego or RTL8169_PHY_Restart_Auto_Nego |
stdcall udelay, 100 |
mov ecx, 10000 |
; wait for auto-negotiation process |
@@: |
dec ecx |
jz @f |
stdcall RTL8169_READ_GMII_REG, RTL8169_PHY_STAT_REG |
stdcall udelay, 100 |
test eax, RTL8169_PHY_Auto_Neco_Comp |
jz @b |
RTL_R8 RTL8169_REG_PHYstatus |
jmp @f |
.tbi_dis: |
stdcall udelay, 100 |
@@: |
call rtl8169_reset |
ret |
endp |
;*************************************************************************** |
; Function |
; rt8169_reset |
; Description |
; Place the chip (ie, the ethernet card) into a virgin state |
; Destroyed registers |
; eax, ebx, ecx, edx |
; |
;*************************************************************************** |
proc rtl8169_reset |
; DEBUGF 1,"K : rtl8169_reset: 0x%x : 0x%x 0x%x\n",[io_addr]:8,[pci_bus]:2,[pci_dev]:2 |
mov [rtl8169_tpc.TxDescArrays], rtl8169_tx_ring |
; Tx Desscriptor needs 256 bytes alignment |
mov [rtl8169_tpc.TxDescArray], rtl8169_tx_ring |
mov [rtl8169_tpc.RxDescArrays], rtl8169_rx_ring |
; Rx Desscriptor needs 256 bytes alignment |
mov [rtl8169_tpc.RxDescArray], rtl8169_rx_ring |
call rtl8169_init_ring |
call rtl8169_hw_start |
; Construct a perfect filter frame with the mac address as first match |
; and broadcast for all others |
mov edi, rtl8169_txb |
or al, -1 |
mov ecx, 192 |
cld |
rep stosb |
mov esi, node_addr |
mov edi, rtl8169_txb |
movsd |
movsw |
mov eax, [pci_data] |
mov [eth_status], eax |
ret |
endp |
;*************************************************************************** |
; Function |
; rtl8169_transmit |
; Description |
; Transmits a packet of data via the ethernet card |
; d - edi - Pointer to 48 bit destination address |
; t - bx - Type of packet |
; s - ecx - size of packet |
; p - esi - pointer to packet data |
; Destroyed registers |
; eax, edx, esi, edi |
; |
;*************************************************************************** |
proc rtl8169_transmit |
; DEBUGF 1,"K : rtl8169_transmit\n" ;: 0x%x : 0x%x 0x%x 0x%x 0x%x\n",[io_addr]:8,edi,bx,ecx,esi |
push ecx edx esi |
mov eax, MAX_ETH_FRAME_SIZE |
mul [rtl8169_tpc.cur_tx] |
mov esi, edi |
; point to the current txb incase multiple tx_rings are used |
mov edi, [rtl8169_tpc.Tx_skbuff + eax * 4] |
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 |
;!!! s += ETH_HLEN; |
;!!! s &= 0x0FFF; |
;!!! while (s < ETH_ZLEN) |
;!!! ptxb[s++] = '\0'; |
mov edi, eax |
pop ecx |
push eax |
add ecx, ETH_HLEN |
and ecx, 0x0FFF |
xor al, al |
add edi, ecx |
@@: |
cmp ecx, ETH_ZLEN |
jae @f |
stosb |
inc ecx |
jmp @b |
@@: |
pop eax |
mov ebx, eax |
mov eax, sizeof.rtl8169_TxDesc |
mul [rtl8169_tpc.cur_tx] |
add eax, [rtl8169_tpc.TxDescArray] |
xchg eax, ebx |
mov [ebx + rtl8169_TxDesc.buf_addr], eax |
sub [ebx + rtl8169_TxDesc.buf_addr], OS_BASE ; shurf 28.09.2008 |
mov eax, ecx |
cmp eax, ETH_ZLEN |
jae @f |
mov eax, ETH_ZLEN |
@@: |
or eax, RTL8169_DSB_OWNbit or RTL8169_DSB_FSbit or RTL8169_DSB_LSbit |
cmp [rtl8169_tpc.cur_tx], NUM_TX_DESC - 1 |
jne @f |
or eax, RTL8169_DSB_EORbit |
@@: |
mov [ebx + rtl8169_TxDesc.status], eax |
RTL_W8 RTL8169_REG_TxPoll,0x40 ; set polling bit |
inc [rtl8169_tpc.cur_tx] |
and [rtl8169_tpc.cur_tx], NUM_TX_DESC - 1 |
;!!! to = currticks() + TX_TIMEOUT; |
;!!! while ((tpc->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */ |
mov ecx, TX_TIMEOUT / 10 |
@@: |
test [ebx + rtl8169_TxDesc.status], RTL8169_DSB_OWNbit |
jnz @f |
stdcall udelay, 10 |
loop @b |
; DEBUGF 1,"K : rtl8169_transmit: TX Time Out\n" |
@@: |
ret |
endp |
;*************************************************************************** |
; Function |
; rtl8169_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 |
; |
;*************************************************************************** |
proc rtl8169_poll |
; DEBUGF 1,"K : rtl8169_poll\n" ;: 0x%x : none\n",[io_addr]:8 |
mov word[eth_rx_data_len], 0 |
mov eax, sizeof.rtl8169_RxDesc |
mul [rtl8169_tpc.cur_rx] |
add eax, [rtl8169_tpc.RxDescArray] |
mov ebx, eax |
; DEBUGF 1,"K : rtl8169_RxDesc.status = 0x%x\n",[ebx + rtl8169_RxDesc.status] |
test [ebx + rtl8169_RxDesc.status], RTL8169_DSB_OWNbit; 0x80000600 |
jnz .exit |
; DEBUGF 1,"K : rtl8169_tpc.cur_rx = %u\n",[rtl8169_tpc.cur_rx] |
; h/w no longer present (hotplug?) or major error, bail |
RTL_R16 RTL8169_REG_IntrStatus |
; DEBUGF 1,"K : IntrStatus = 0x%x\n",ax |
cmp ax, 0xFFFF |
je .exit |
push eax |
and ax, not (RTL8169_ISB_RxFIFOOver or RTL8169_ISB_RxOverflow or RTL8169_ISB_RxOK) |
RTL_W16 RTL8169_REG_IntrStatus,ax |
mov eax, [ebx + rtl8169_RxDesc.status] |
; DEBUGF 1,"K : RxDesc.status = 0x%x\n",eax |
test eax, RTL8169_SD_RxRES |
jnz .else |
and eax, 0x00001FFF |
; jz .exit.pop |
add eax, -4 |
mov [eth_rx_data_len], ax |
; DEBUGF 1,"K : rtl8169_poll: data length = %u\n",ax |
push eax |
mov ecx, eax |
shr ecx, 2 |
mov eax, [rtl8169_tpc.cur_rx] |
mov edx, [rtl8169_tpc.RxBufferRing + eax * 4] |
mov esi, edx |
mov edi, Ether_buffer |
cld |
rep movsd |
pop ecx |
and ecx, 3 |
rep movsb |
mov eax, RTL8169_DSB_OWNbit or RX_BUF_SIZE |
cmp [rtl8169_tpc.cur_rx], NUM_RX_DESC - 1 |
jne @f |
or eax, RTL8169_DSB_EORbit |
@@: |
mov [ebx + rtl8169_RxDesc.status], eax |
mov [ebx + rtl8169_RxDesc.buf_addr], edx |
sub [ebx + rtl8169_RxDesc.buf_addr], OS_BASE ; shurf 28.09.2008 |
jmp @f |
.else: |
; DEBUGF 1,"K : rtl8169_poll: Rx Error\n" |
; FIXME: shouldn't I reset the status on an error |
@@: |
inc [rtl8169_tpc.cur_rx] |
and [rtl8169_tpc.cur_rx], NUM_RX_DESC - 1 |
.exit.pop: |
pop eax |
and ax, RTL8169_ISB_RxFIFOOver or RTL8169_ISB_RxOverflow or RTL8169_ISB_RxOK |
RTL_W16 RTL8169_REG_IntrStatus,ax |
.exit: |
ret |
endp |
proc rtl8169_cable |
ret |
endp |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/sis900.inc |
---|
0,0 → 1,1166 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
;******************************************************************** |
; 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 - OS_BASE;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 - OS_BASE ; 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 - OS_BASE ; |
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 - OS_BASE ; |
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 - OS_BASE |
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], bx |
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 |
add esi, OS_BASE ; get linear address |
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 |
str1 db 'Transmitting packet:',13,10,0 |
str2 db ' ',0 |
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 - OS_BASE |
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 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers/r6040.inc |
---|
0,0 → 1,813 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; R6040 driver for KolibriOS ;; |
;; ;; |
;; based on R6040.c from linux ;; |
;; ;; |
;; Written by Asper (asper.85@mail.ru) ;; |
;; and hidnplayr (hidnplayr@gmail.com) ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;******************************************************************** |
; Interface |
; r6040_reset |
; r6040_probe |
; r6040_poll |
; r6040_transmit |
; |
; These functions are referenced in ethernet.inc |
; |
;******************************************************************** |
;; A few user-configurable values. |
TX_RING_SIZE equ 4 |
RX_RING_SIZE equ 4 |
; ethernet address length |
ETH_ALEN equ 6 |
ETH_HLEN equ (2 * ETH_ALEN + 2) |
ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for |
; mininmum 64bytes frame length |
; system timer frequency |
HZ equ 1000 |
; max time out delay time |
W_MAX_TIMEOUT equ 0x0FFF |
;; Size of the in-memory receive ring. |
RX_BUF_LEN_IDX equ 3 ;; 0==8K, 1==16K, 2==32K, 3==64K |
RX_BUF_LEN equ (8192 << RX_BUF_LEN_IDX) |
;-; Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). |
;-TX_BUF_SIZE equ 1536 |
;-RX_BUF_SIZE equ 1536 |
;; PCI Tuning Parameters |
; Threshold is bytes transferred to chip before transmission starts. |
TX_FIFO_THRESH equ 256 ;; In bytes, rounded down to 32 byte units. |
;; The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. |
RX_FIFO_THRESH equ 4 ;; Rx buffer level before first PCI xfer. |
RX_DMA_BURST equ 4 ;; Maximum PCI burst, '4' is 256 bytes |
TX_DMA_BURST equ 4 |
;; Operational parameters that usually are not changed. |
PHY1_ADDR equ 1 ;For MAC1 |
PHY2_ADDR equ 3 ;For MAC2 |
PHY_MODE equ 0x3100 ;PHY CHIP Register 0 |
PHY_CAP equ 0x01E1 ;PHY CHIP Register 4 |
;; Time in jiffies before concluding the transmitter is hung. |
TX_TIMEOUT equ ((6000*HZ)/1000) |
R6040_IO_SIZE equ 256 ; RDC MAC I/O Size |
MAX_MAC equ 2 ; MAX RDC MAC |
;************************************************************************** |
; RDC R6040 Register Definitions |
;************************************************************************** |
MCR0 equ 0x00 ;Control register 0 |
MCR1 equ 0x01 ;Control register 1 |
MAC_RST equ 0x0001 ;Reset the MAC |
MBCR equ 0x08 ;Bus control |
MT_ICR equ 0x0C ;TX interrupt control |
MR_ICR equ 0x10 ;RX interrupt control |
MTPR equ 0x14 ;TX poll command register |
MR_BSR equ 0x18 ;RX buffer size |
MR_DCR equ 0x1A ;RX descriptor control |
MLSR equ 0x1C ;Last status |
MMDIO equ 0x20 ;MDIO control register |
MDIO_WRITE equ 0x4000 ;MDIO write |
MDIO_READ equ 0x2000 ;MDIO read |
MMRD equ 0x24 ;MDIO read data register |
MMWD equ 0x28 ;MDIO write data register |
MTD_SA0 equ 0x2C ;TX descriptor start address 0 |
MTD_SA1 equ 0x30 ;TX descriptor start address 1 |
MRD_SA0 equ 0x34 ;RX descriptor start address 0 |
MRD_SA1 equ 0x38 ;RX descriptor start address 1 |
MISR equ 0x3C ;Status register |
MIER equ 0x40 ;INT enable register |
MSK_INT equ 0x0000 ;Mask off interrupts |
RX_FINISH equ 0x0001 ;RX finished |
RX_NO_DESC equ 0x0002 ;No RX descriptor available |
RX_FIFO_FULL equ 0x0004 ;RX FIFO full |
RX_EARLY equ 0x0008 ;RX early |
TX_FINISH equ 0x0010 ;TX finished |
TX_EARLY equ 0x0080 ;TX early |
EVENT_OVRFL equ 0x0100 ;Event counter overflow |
LINK_CHANGED equ 0x0200 ;PHY link changed |
ME_CISR equ 0x44 ;Event counter INT status |
ME_CIER equ 0x48 ;Event counter INT enable |
MR_CNT equ 0x50 ;Successfully received packet counter |
ME_CNT0 equ 0x52 ;Event counter 0 |
ME_CNT1 equ 0x54 ;Event counter 1 |
ME_CNT2 equ 0x56 ;Event counter 2 |
ME_CNT3 equ 0x58 ;Event counter 3 |
MT_CNT equ 0x5A ;Successfully transmit packet counter |
ME_CNT4 equ 0x5C ;Event counter 4 |
MP_CNT equ 0x5E ;Pause frame counter register |
MAR0 equ 0x60 ;Hash table 0 |
MAR1 equ 0x62 ;Hash table 1 |
MAR2 equ 0x64 ;Hash table 2 |
MAR3 equ 0x66 ;Hash table 3 |
MID_0L equ 0x68 ;Multicast address MID0 Low |
MID_0M equ 0x6A ;Multicast address MID0 Medium |
MID_0H equ 0x6C ;Multicast address MID0 High |
MID_1L equ 0x70 ;MID1 Low |
MID_1M equ 0x72 ;MID1 Medium |
MID_1H equ 0x74 ;MID1 High |
MID_2L equ 0x78 ;MID2 Low |
MID_2M equ 0x7A ;MID2 Medium |
MID_2H equ 0x7C ;MID2 High |
MID_3L equ 0x80 ;MID3 Low |
MID_3M equ 0x82 ;MID3 Medium |
MID_3H equ 0x84 ;MID3 High |
PHY_CC equ 0x88 ;PHY status change configuration register |
PHY_ST equ 0x8A ;PHY status register |
MAC_SM equ 0xAC ;MAC status machine |
MAC_ID equ 0xBE ;Identifier register |
MAX_BUF_SIZE equ 0x600 ;1536 |
MBCR_DEFAULT equ 0x012A ;MAC Bus Control Register |
MCAST_MAX equ 3 ;Max number multicast addresses to filter |
;Descriptor status |
DSC_OWNER_MAC equ 0x8000 ;MAC is the owner of this descriptor |
DSC_RX_OK equ 0x4000 ;RX was successfull |
DSC_RX_ERR equ 0x0800 ;RX PHY error |
DSC_RX_ERR_DRI equ 0x0400 ;RX dribble packet |
DSC_RX_ERR_BUF equ 0x0200 ;RX length exceeds buffer size |
DSC_RX_ERR_LONG equ 0x0100 ;RX length > maximum packet length |
DSC_RX_ERR_RUNT equ 0x0080 ;RX packet length < 64 byte |
DSC_RX_ERR_CRC equ 0x0040 ;RX CRC error |
DSC_RX_BCAST equ 0x0020 ;RX broadcast (no error) |
DSC_RX_MCAST equ 0x0010 ;RX multicast (no error) |
DSC_RX_MCH_HIT equ 0x0008 ;RX multicast hit in hash table (no error) |
DSC_RX_MIDH_HIT equ 0x0004 ;RX MID table hit (no error) |
DSC_RX_IDX_MID_MASK equ 3 ;RX mask for the index of matched MIDx |
;PHY settings |
ICPLUS_PHY_ID equ 0x0243 |
RX_INTS equ RX_FIFO_FULL or RX_NO_DESC or RX_FINISH |
TX_INTS equ TX_FINISH |
INT_MASK equ RX_INTS or TX_INTS |
r6040_txb equ (eth_data_start) |
r6040_rxb equ ((r6040_txb+(MAX_BUF_SIZE*TX_RING_SIZE)+32) and 0xfffffff0) |
r6040_tx_ring equ ((r6040_rxb+(MAX_BUF_SIZE*RX_RING_SIZE)+32) and 0xfffffff0) |
r6040_rx_ring equ ((r6040_tx_ring+(r6040_x_head.sizeof*TX_RING_SIZE)+32) and 0xfffffff0) |
virtual at ((r6040_rx_ring+(r6040_x_head.sizeof*RX_RING_SIZE)+32) and 0xfffffff0) |
r6040_private: |
.rx_ring dd ? |
.tx_ring dd ? |
.cur_rx dw ? |
.cur_tx dw ? |
.phy_addr dw ? |
.phy_mode dw ? |
.mcr0 dw ? |
.mcr1 dw ? |
.switch_sig dw ? |
end virtual |
virtual at 0 |
r6040_x_head: |
.status dw ? ;0-1 |
.len dw ? ;2-3 |
.buf dd ? ;4-7 |
.ndesc dd ? ;8-B |
.rev1 dd ? ;C-F |
.vbufp dd ? ;10-13 |
.vndescp dd ? ;14-17 |
.skb_ptr dd ? ;18-1B |
.rev2 dd ? ;1C-1F |
.sizeof: |
end virtual |
; Read a word data from PHY Chip |
proc r6040_phy_read stdcall, phy_addr:dword, reg:dword |
push ecx edx |
mov eax, [phy_addr] |
shl eax, 8 |
add eax, [reg] |
add eax, MDIO_READ |
mov edx, [io_addr] |
add edx, MMDIO |
out dx, ax |
;Wait for the read bit to be cleared. |
mov ecx, 2048 ;limit |
xor eax, eax |
.read: |
in ax, dx |
test ax, MDIO_READ |
jz @f |
dec ecx |
test ecx, ecx |
jnz .read |
@@: |
mov edx, [io_addr] |
add edx, MMRD |
in ax, dx |
and eax, 0xFFFF |
pop edx ecx |
ret |
endp |
; Write a word data to PHY Chip |
proc r6040_phy_write stdcall, phy_addr:dword, reg:dword, val:dword |
push eax ecx edx |
mov eax, [val] |
mov edx, [io_addr] |
add edx, MMWD |
out dx, ax |
;Write the command to the MDIO bus |
mov eax, [phy_addr] |
shl eax, 8 |
add eax, [reg] |
add eax, MDIO_WRITE |
mov edx, [io_addr] |
add edx, MMDIO |
out dx, ax |
;Wait for the write bit to be cleared. |
mov ecx, 2048 ;limit |
xor eax, eax |
.write: |
in ax, dx |
test ax, MDIO_WRITE |
jz @f |
dec ecx |
test ecx, ecx |
jnz .write |
@@: |
pop edx ecx eax |
ret |
endp |
macro r6040_mdio_write reg, val { |
stdcall r6040_phy_read, [io_addr], [r6040_private.phy_addr], reg |
} |
macro r6040_mdio_write reg, val { |
stdcall r6040_phy_write, [io_addr], [r6040_private.phy_addr], reg, val |
} |
proc r6040_init_ring_desc stdcall, desc_ring:dword, size:dword |
push eax ecx esi |
mov ecx, [size] |
test ecx, ecx |
jz .out |
mov esi, [desc_ring] |
mov eax, esi |
.next_desc: |
add eax, r6040_x_head.sizeof - OS_BASE |
mov [esi+r6040_x_head.ndesc], eax |
add eax, OS_BASE |
mov [esi+r6040_x_head.vndescp], eax |
mov esi, eax |
dec ecx |
jnz .next_desc |
sub esi, r6040_x_head.sizeof |
mov eax, [desc_ring] |
mov [esi+r6040_x_head.vndescp], eax |
sub eax, OS_BASE |
mov [esi+r6040_x_head.ndesc], eax |
.out: |
pop esi ecx eax |
ret |
endp |
r6040_init_rxbufs: |
stdcall r6040_init_ring_desc, r6040_rx_ring, RX_RING_SIZE |
; Allocate skbs for the rx descriptors |
mov esi, r6040_rx_ring |
mov ebx, r6040_rxb |
mov ecx, RX_RING_SIZE |
mov eax, r6040_rx_ring |
.next_desc: |
mov [esi+r6040_x_head.skb_ptr], ebx |
mov [esi+r6040_x_head.buf], ebx |
sub [esi+r6040_x_head.buf], OS_BASE |
mov [esi+r6040_x_head.status], DSC_OWNER_MAC |
mov eax, [esi+r6040_x_head.vndescp] |
mov esi, eax |
add ebx, MAX_BUF_SIZE |
dec ecx |
jnz .next_desc |
xor eax, eax |
.out: |
ret |
r6040_probe: |
DEBUGF 1, "Probing r6040\n" |
call adjust_pci_device |
; If PHY status change register is still set to zero |
; it means the bootloader didn't initialize it |
mov edx, [io_addr] |
add edx, PHY_CC |
in ax, dx |
test ax, ax |
jnz @f |
mov eax, 0x9F07 |
out dx, ax |
@@: |
; Set MAC address |
mov ecx, 3 |
mov edi, node_addr |
mov edx, [io_addr] |
add edx, MID_0L |
.mac: |
in ax, dx |
stosw |
add edx, 2 |
dec ecx |
jnz .mac |
; Some bootloaders/BIOSes do not initialize |
; MAC address, warn about that |
and eax, 0xFF |
or eax, [node_addr] |
test eax, eax |
jnz @f |
DEBUGF 1, "K : MAC address not initialized\n" ;, generating random" |
;Asper: Add here generate function call! |
; Temporary workaround: init by constant adress |
mov dword [node_addr], 0x00006000 |
mov word [node_addr+4], 0x0001 |
@@: |
; Init RDC private data |
mov [r6040_private.mcr0], 0x1002 |
;mov [r6040_private.phy_addr], 1 ; Asper: Only one network card is supported now. |
mov [r6040_private.switch_sig], 0 |
; Check the vendor ID on the PHY, if 0xFFFF assume none attached |
stdcall r6040_phy_read, 1, 2 |
cmp ax, 0xFFFF |
jne @f |
DEBUGF 1, "K : Failed to detect an attached PHY\n" ;, generating random" |
mov eax, -1 |
ret |
@@: |
; Set MAC address |
call r6040_mac_address |
; Initialize and alloc RX/TX buffers |
stdcall r6040_init_ring_desc, r6040_tx_ring, TX_RING_SIZE |
call r6040_init_rxbufs ;r6040_alloc_rxbufs |
test eax, eax |
jnz .out |
; Read the PHY ID |
mov [r6040_private.phy_mode], 0x8000 |
stdcall r6040_phy_read, 0, 2 |
mov [r6040_private.switch_sig], ax |
cmp ax, ICPLUS_PHY_ID |
jne @f |
stdcall r6040_phy_write, 29, 31, 0x175C ; Enable registers |
jmp .phy_readen |
@@: |
; PHY Mode Check |
movzx eax, [r6040_private.phy_addr] |
stdcall r6040_phy_write, eax, 4, PHY_CAP |
stdcall r6040_phy_write, eax, 0, PHY_MODE |
; if PHY_MODE = 0x3100 |
call r6040_phy_mode_chk |
mov [r6040_private.phy_mode], ax |
jmp .phy_readen |
; end if |
; if not (PHY_MODE and 0x0100) |
mov [r6040_private.phy_mode], 0 |
; end if |
.phy_readen: |
; Set duplex mode |
mov ax, [r6040_private.phy_mode] |
or [r6040_private.mcr0], ax |
; improve performance (by RDC guys) |
stdcall r6040_phy_read, 30, 17 |
or ax, 0x4000 |
stdcall r6040_phy_write, 30, 17, eax |
stdcall r6040_phy_read, 30, 17 |
xor ax, -1 |
or ax, 0x2000 |
xor ax, -1 |
stdcall r6040_phy_write, 30, 17, eax |
stdcall r6040_phy_write, 0, 19, 0x0000 |
stdcall r6040_phy_write, 0, 30, 0x01F0 |
; Initialize all Mac registers |
call r6040_reset |
xor eax, eax |
.out: |
ret |
align 4 |
r6040_reset: |
DEBUGF 1, "Resetting r6040\n" |
push eax ecx edx |
; Mask off Interrupt |
mov eax, MSK_INT |
mov edx, [io_addr] |
add edx, MIER |
out dx, ax |
;Reset RDC MAC |
mov eax, MAC_RST |
mov edx, [io_addr] |
add edx, MCR1 |
out dx, ax |
mov ecx, 2048 ;limit |
.read: |
in ax, dx |
test ax, 0x1 |
jnz @f |
dec ecx |
test ecx, ecx |
jnz .read |
@@: |
;Reset internal state machine |
mov ax, 2 |
mov edx, [io_addr] |
add edx, MAC_SM |
out dx, ax |
xor ax, ax |
out dx, ax |
mov esi, 5 |
call delay_ms |
;MAC Bus Control Register |
mov ax, MBCR_DEFAULT |
mov edx, [io_addr] |
add edx, MBCR |
out dx, ax |
;Buffer Size Register |
mov ax, MAX_BUF_SIZE |
mov edx, [io_addr] |
add edx, MR_BSR |
out dx, ax |
;Write TX ring start address |
mov eax, r6040_tx_ring - OS_BASE ;Asper: Maybe we can just write dword? Hidnplayr: better use word, as described in datasheet. |
mov edx, [io_addr] |
add edx, MTD_SA0 |
out dx, ax |
shr eax, 16 |
add edx, MTD_SA1 - MTD_SA0 |
out dx, ax |
;Write RX ring start address |
mov eax, r6040_rx_ring - OS_BASE ;Asper: Maybe we can just write dword? |
mov edx, [io_addr] |
add edx, MRD_SA0 |
out dx, ax |
shr eax, 16 |
add edx, MRD_SA1 - MRD_SA0 |
out dx, ax |
;Set interrupt waiting time and packet numbers |
xor ax, ax |
mov edx, [io_addr] |
add edx, MT_ICR |
out dx, ax |
;Asper: ~ Disable ints ;Enable interrupts |
;mov ax, MSK_INT ;INT_MASK ;Asper ~ |
;mov edx, [io_addr] |
;add edx, MIER |
;out dx, ax |
;Enable TX and RX |
mov ax, [r6040_private.mcr0] |
or ax, 0x0002 |
mov edx, [io_addr] |
out dx, ax |
;Let TX poll the descriptors |
;we may got called by r6040_tx_timeout which has left |
;some unset tx buffers |
xor ax, ax |
inc ax |
mov edx, [io_addr] |
add edx, MTPR |
out dx, ax |
pop edx ecx eax |
DEBUGF 1, "reset ok!\n" |
; Indicate that we have successfully reset the card |
mov eax, [pci_data] |
mov [eth_status], eax |
ret |
proc r6040_tx_timeout |
push eax edx |
;... |
inc [stats.tx_errors] |
;Reset MAC and re-init all registers |
call r6040_init_mac_regs |
pop edx eax |
ret |
endp |
proc r6040_get_stats |
push eax edx |
mov edx, [io_addr] |
add edx, ME_CNT1 |
in al, dx |
add [stats.rx_crc_errors], al |
mov edx, [io_addr] |
add edx, ME_CNT0 |
in al, dx |
add [stats.multicast], al |
pop edx eax |
ret |
endp |
;... |
proc r6040_phy_mode_chk |
push ebx |
;PHY Link Status Check |
movzx eax, [r6040_private.phy_addr] |
stdcall r6040_phy_read, eax, 1 |
test eax, 0x4 |
jnz @f |
mov eax, 0x8000 ;Link Failed, full duplex |
@@: |
;PHY Chip Auto-Negotiation Status |
movzx eax, [r6040_private.phy_addr] |
stdcall r6040_phy_read, eax, 1 |
test eax, 0x0020 |
jz .force_mode |
;Auto Negotuiation Mode |
movzx eax, [r6040_private.phy_addr] |
stdcall r6040_phy_read, eax, 5 |
mov ebx, eax |
movzx eax, [r6040_private.phy_addr] |
stdcall r6040_phy_read, eax, 4 |
and eax, ebx |
test eax, 0x140 |
jz .ret_0 |
jmp .ret_0x8000 |
.force_mode: |
;Force Mode |
movzx eax, [r6040_private.phy_addr] |
stdcall r6040_phy_read, eax, 0 |
test eax, 0x100 |
jz .ret_0 |
.ret_0x8000: |
mov eax, 0x8000 |
pop ebx |
ret |
.ret_0: |
xor eax, eax |
pop ebx |
ret |
endp |
;*************************************************************************** |
; Function |
; r6040_rx |
; 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 |
;*************************************************************************** |
r6040_poll: |
push ebx ecx esi edi |
xor eax, eax |
mov [eth_rx_data_len], ax |
movzx eax, [r6040_private.cur_rx] |
mov ebx, eax |
shl ebx, 5 |
mov cx, [ebx+r6040_rx_ring+r6040_x_head.status] ; Read the descriptor status |
test cx, DSC_OWNER_MAC |
jnz .out |
test cx, DSC_RX_ERR ; Global error status set |
jz .no_dsc_rx_err |
;... |
jmp .out |
.no_dsc_rx_err: |
; Packet successfully received |
movzx ecx, [ebx+r6040_rx_ring+r6040_x_head.len] |
and ecx, 0xFFF |
sub ecx, 4 ; Do not count the CRC |
mov [eth_rx_data_len], cx |
mov esi, [ebx+r6040_rx_ring+r6040_x_head.skb_ptr] |
push ecx |
shr ecx, 2 |
mov edi, Ether_buffer |
cld |
rep movsd |
pop ecx |
and ecx, 3 |
rep movsb |
or [ebx+r6040_rx_ring+r6040_x_head.status], DSC_OWNER_MAC |
inc [r6040_private.cur_rx] |
and [r6040_private.cur_rx], RX_RING_SIZE-1 |
xor eax, eax |
.out: |
pop edi esi ecx ebx |
ret |
;*************************************************************************** |
; Function |
; r6040_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 |
; |
;*************************************************************************** |
r6040_transmit: |
cmp ecx, MAX_BUF_SIZE |
jg .out ; packet is too long |
push edi esi ebx ecx |
movzx eax, [r6040_private.cur_tx] |
shl eax, 5 |
; DEBUGF 1,"R6040: TX buffer status: 0x%x, eax=%u\n", [eax + r6040_tx_ring + r6040_x_head.status]:4, eax |
test [r6040_tx_ring + eax + r6040_x_head.status], 0x8000 ; check if buffer is available |
jz .l3 |
push ecx esi |
mov ecx, [timer_ticks] |
add ecx, 100 |
.l2: |
test [r6040_tx_ring + eax + r6040_x_head.status], 0x8000 |
jz .l5 |
cmp ecx, [timer_ticks] |
jb .l4 |
mov esi, 10 |
call delay_ms |
jmp .l2 |
.l4: |
pop esi ecx |
DEBUGF 1,"R6040: Send timeout\n" |
jmp .out |
.l5: |
pop esi ecx |
.l3: |
push eax |
mov esi, edi |
; point to the current tx buffer |
movzx edi, [r6040_private.cur_tx] |
imul edi, MAX_BUF_SIZE |
add edi, r6040_txb |
lea eax, [edi - OS_BASE] ; real buffer address in eax |
; copy destination address |
movsd |
movsw |
; copy source address |
mov esi, node_addr |
movsd |
movsw |
; copy packet type |
mov [edi], bx |
add edi, 2 |
mov esi, [esp+8+4] |
mov ecx, [esp+4] |
; copy the packet data |
push ecx |
shr ecx, 2 |
rep movsd |
pop ecx |
and ecx, 3 |
rep movsb |
pop edi |
mov ecx, [esp] |
add ecx, ETH_HLEN |
cmp cx, ETH_ZLEN |
jae @f |
mov cx, ETH_ZLEN |
@@: |
mov [r6040_tx_ring + edi + r6040_x_head.len], cx |
mov [r6040_tx_ring + edi + r6040_x_head.buf], eax |
mov [r6040_tx_ring + edi + r6040_x_head.status], 0x8000 |
; Trigger the MAC to check the TX descriptor |
mov ax, 0x01 |
mov edx, [io_addr] |
add edx, MTPR |
out dx, ax |
inc [r6040_private.cur_tx] |
and [r6040_private.cur_tx], TX_RING_SIZE-1 |
xor eax, eax |
pop ecx ebx esi edi |
.out: |
ret |
r6040_mac_address: |
push eax ecx edx esi edi |
; MAC operation register |
mov ax, 1 |
mov edx, [io_addr] |
add edx, MCR1 |
out dx, ax |
; Reset MAC |
mov ax, 2 |
mov edx, [io_addr] |
add edx, MAC_SM |
out dx, ax |
; Reset internal state machine |
xor ax, ax |
out dx, ax |
mov esi, 5 |
call delay_ms |
; Restore MAC Address |
mov ecx, 3 |
mov edi, node_addr |
mov edx, [io_addr] |
add edx, MID_0L |
.mac: |
in ax, dx |
stosw |
add edx, 2 |
dec ecx |
jnz .mac |
pop edi esi edx ecx eax |
ret |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/drivers |
---|
Property changes: |
Added: svn:ignore |
+*.mnt |
+lang.inc |
+*.bat |
+out.txt |
+scin* |
+*.obj |
/kernel/trunk/network/eth_drv/arp.inc |
---|
0,0 → 1,557 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ARP.INC ;; |
;; ;; |
;; Address Resolution Protocol ;; |
;; ;; |
;; This file contains the following: ;; |
;; arp_table_manager - Manages an ARPTable ;; |
;; arp_request - Sends an ARP request on the ethernet ;; |
;; arp_handler - Called when an ARP packet is received ;; |
;; ;; |
;; Changes history: ;; |
;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net ;; |
;; 11.11.2006 - [Johnny_B] and [smb] ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
ARP_NO_ENTRY equ 0 |
ARP_VALID_MAPPING equ 1 |
ARP_AWAITING_RESPONSE equ 2 |
ARP_RESPONSE_TIMEOUT equ 3 |
struc ARP_ENTRY ;=14 bytes |
{ .IP dd ? ;+00 |
.MAC dp ? ;+04 |
.Status dw ? ;+10 |
.TTL dw ? ;+12 : ( in seconds ) |
} |
virtual at 0 |
ARP_ENTRY ARP_ENTRY |
end virtual |
; 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 static 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 |
; The follow is the ARP Table. |
; This table must be manually updated and the kernel recompilied if |
; changes are made to it. |
; Empty entries are filled with zeros |
ARP_ENTRY_SIZE equ 14 ; Number of bytes per entry |
ARP_TABLE_SIZE equ 20 ; Size of table |
ARP_TABLE_ENTRIES equ 0 ; Number of static entries in the table |
;TO ADD A STATIC ENTRY, DONT FORGET, PUT "ARPTable" from "uglobal" to "iglobal"!!! |
;AND ALSO - IP and MAC have net byte-order, BUT STATUS AND TTL HAVE A MIRROR BYTE-ORDER!!! |
uglobal |
ARPTable: |
;example, static entry -> db 11,22,33,44, 0x11,0x22,0x33,0x44,0x55,0x66, 0x01,0x00, 0xFF,0xFF |
times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE db 0 |
endg |
iglobal |
NumARP: |
dd ARP_TABLE_ENTRIES |
ARPTable_ptr dd ARPTable ;pointer to ARPTable |
endg |
ARP_REQ_OPCODE equ 0x0100 ;request |
ARP_REP_OPCODE equ 0x0200 ;reply |
struc ARP_PACKET |
{ .HardwareType dw ? ;+00 |
.ProtocolType dw ? ;+02 |
.HardwareSize db ? ;+04 |
.ProtocolSize db ? ;+05 |
.Opcode dw ? ;+06 |
.SenderMAC dp ? ;+08 |
.SenderIP dd ? ;+14 |
.TargetMAC dp ? ;+18 |
.TargetIP dd ? ;+24 |
} |
virtual at 0 |
ARP_PACKET ARP_PACKET |
end virtual |
;*************************************************************************** |
; Function |
; arp_table_manager [by Johnny_B] |
; |
; Description |
; Does a most required operations with ARP-table |
; IN: |
; Operation: see Opcode's constants below |
; Index: Index of entry in the ARP-table |
; Extra: Extra parameter for some Opcodes |
; OUT: |
; EAX = Returned value depends on opcodes, more detailed see below |
; |
;*************************************************************************** |
;Opcode's constants |
ARP_TABLE_ADD equ 1 |
ARP_TABLE_DEL equ 2 |
ARP_TABLE_GET equ 3 |
ARP_TABLE_GET_ENTRIES_NUMBER equ 4 |
ARP_TABLE_IP_TO_MAC equ 5 |
ARP_TABLE_TIMER equ 6 |
;Index's constants |
EXTRA_IS_ARP_PACKET_PTR equ 0 ;if Extra contain pointer to ARP_PACKET |
EXTRA_IS_ARP_ENTRY_PTR equ -1 ;if Extra contain pointer to ARP_ENTRY |
align 4 |
proc arp_table_manager stdcall uses ebx esi edi ecx edx,\ |
Opcode:DWORD,Index:DWORD,Extra:DWORD |
mov ebx, dword[ARPTable_ptr];ARPTable base |
mov ecx, dword[NumARP] ;ARP-entries counter |
mov eax, dword[Opcode] |
cmp eax, ARP_TABLE_TIMER |
je .timer |
cmp eax, ARP_TABLE_ADD |
je .add |
cmp eax, ARP_TABLE_DEL |
je .del |
cmp eax, ARP_TABLE_GET |
je .get |
cmp eax, ARP_TABLE_IP_TO_MAC |
je .ip_to_mac |
cmp eax, ARP_TABLE_GET_ENTRIES_NUMBER |
je .get_entries_number |
jmp .exit ;if unknown opcode |
;;BEGIN TIMER |
;;Description: it must be callback every second. It is responsible for removing expired routes. |
;;IN: Operation: ARP_TABLE_TIMER |
;; Index: must be zero |
;; Extra: must be zero |
;;OUT: |
;; EAX=not defined |
;; |
.timer: |
test ecx, ecx |
jz .exit;if NumARP=0 nothing to do |
sub ecx, ARP_TABLE_ENTRIES;ecx=dynamic entries number |
jz .exit;if NumARP=number of static entries then exit |
add ebx, ARP_TABLE_ENTRIES*ARP_ENTRY_SIZE;ebx=dynamic entries base |
.timer_loop: |
movsx esi, word [ebx + ARP_ENTRY.TTL] |
cmp esi, 0xFFFFFFFF |
je .timer_loop_end;if TTL==0xFFFF then it's static entry |
test esi, esi |
jnz .timer_loop_end_with_dec;if TTL!=0 |
; Ok, TTL is 0 |
;if Status==AWAITING_RESPONSE and TTL==0 |
;then we have to change it to ARP_RESPONSE_TIMEOUT |
cmp word [ebx + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE |
jne @f |
mov word [ebx + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT |
mov word [ebx + ARP_ENTRY.TTL], word 0x000A;10 sec |
jmp .timer_loop_end |
@@: |
;if TTL==0 and Status==VALID_MAPPING, we have to delete it |
;if TTL==0 and Status==RESPONSE_TIMEOUT, delete too |
mov esi, dword[NumARP] |
sub esi, ecx ;esi=index of entry, will be deleted |
stdcall arp_table_manager, ARP_TABLE_DEL, esi, 0;opcode,index,extra |
jmp .timer_loop_end |
.timer_loop_end_with_dec: |
dec word [ebx + ARP_ENTRY.TTL];decrease TTL |
.timer_loop_end: |
add ebx, ARP_ENTRY_SIZE |
loop .timer_loop |
jmp .exit |
;;END TIMER |
;;BEGIN ADD |
;;Description: it adds an entry in the table. If ARP-table already |
;; contains same IP, it will be updated. |
;;IN: Operation: ARP_TABLE_ADD |
;; Index: specifies what contains Extra-parameter |
;; Extra: if Index==EXTRA_IS_ARP_PACKET_PTR, |
;; then Extra contains pointer to ARP_PACKET, |
;; otherwise Extra contains pointer to ARP_ENTRY |
;;OUT: |
;; EAX=index of entry, that has been added |
;; |
.add: |
sub esp, ARP_ENTRY_SIZE;Allocate ARP_ENTRY_SIZE byte in stack |
mov esi, [Extra];pointer |
mov edi, [Index];opcode |
cmp edi, EXTRA_IS_ARP_PACKET_PTR |
je .arp_packet_to_entry;if Extra contain ptr to ARP_PACKET and we have to form arp-entry |
;else it contain ptr to arp-entry |
cld |
; esi already has been loaded |
mov edi, esp ;ebx + eax=ARPTable_base + ARP-entry_base(where we will add) |
mov ecx, ARP_ENTRY_SIZE/2;ARP_ENTRY_SIZE must be even number!!! |
rep movsw ;copy |
jmp .search |
.arp_packet_to_entry: |
mov edx, dword[esi + ARP_PACKET.SenderIP];esi=base of ARP_PACKET |
mov [esp + ARP_ENTRY.IP], edx |
cld |
lea esi, [esi + ARP_PACKET.SenderMAC] |
lea edi, [esp + ARP_ENTRY.MAC] |
movsd |
movsw |
mov word[esp + ARP_ENTRY.Status], ARP_VALID_MAPPING; specify the type - a valid entry |
mov word[esp + ARP_ENTRY.TTL], 0x0E10; = 1 hour |
.search: |
mov edx, dword[esp + ARP_ENTRY.IP];edx=IP-address, which we'll search |
mov ecx, dword[NumARP] ;ecx=ARP-entries counter |
jecxz .add_to_end ;if ARP-entries number == 0 |
imul eax, ecx, ARP_ENTRY_SIZE ;eax=current table size(in bytes) |
@@: |
sub eax, ARP_ENTRY_SIZE |
cmp dword[ebx + eax + ARP_ENTRY.IP], edx |
loopnz @b |
jz .replace ; found, replace existing entry, ptr to it is in eax |
.add_to_end: |
;else add to end |
or eax, -1;set eax=0xFFFFFFFF if adding is impossible |
mov ecx, dword[NumARP] |
cmp ecx, ARP_TABLE_SIZE |
je .add_exit;if arp-entries number is equal to arp-table maxsize |
imul eax, dword[NumARP], ARP_ENTRY_SIZE;eax=ptr to end of ARPTable |
inc dword [NumARP];increase ARP-entries counter |
.replace: |
cld |
mov esi, esp ;esp=base of ARP-entry, that will be added |
lea edi, [ebx + eax] ;ebx + eax=ARPTable_base + ARP-entry_base(where we will add) |
mov ecx, ARP_ENTRY_SIZE/2;ARP_ENTRY_SIZE must be even number!!! |
rep movsw |
mov ecx, ARP_ENTRY_SIZE |
xor edx, edx;"div" takes operand from EDX:EAX |
div ecx ;eax=index of entry, which has been added |
.add_exit: |
add esp, ARP_ENTRY_SIZE;free stack |
jmp .exit |
;;END ADD |
;;BEGIN DEL |
;;Description: it deletes an entry in the table. |
;;IN: Operation: ARP_TABLE_DEL |
;; Index: index of entry, that should be deleted |
;; Extra: must be zero |
;;OUT: |
;; EAX=not defined |
;; |
.del: |
mov esi, [Index] |
imul esi, ARP_ENTRY_SIZE |
mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY_SIZE |
sub ecx, esi |
lea edi, [ebx + esi] ;edi=ptr to entry that should be deleted |
lea esi, [edi + ARP_ENTRY_SIZE];esi=ptr to next entry |
shr ecx, 1 ;ecx/2 => ARP_ENTRY_SIZE MUST BE EVEN NUMBER! |
cld |
rep movsw |
dec dword[NumARP];decrease arp-entries counter |
jmp .exit |
;;END DEL |
;;BEGIN GET |
;;Description: it reads an entry of table into buffer. |
;;IN: Operation: ARP_TABLE_GET |
;; Index: index of entry, that should be read |
;; Extra: pointer to buffer for reading(size must be equal to ARP_ENTRY_SIZE) |
;;OUT: |
;; EAX=not defined |
;; |
.get: |
mov esi, [Index] |
imul esi, ARP_ENTRY_SIZE;esi=ptr to required ARP_ENTRY |
mov edi, [Extra] ;edi=buffer for reading |
mov ecx, ARP_ENTRY_SIZE/2; must be even number!!! |
cld |
rep movsw |
jmp .exit |
;;END GET |
;;BEGIN IP_TO_MAC |
;;Description: it gets an IP from Index, scans each entry in the table and writes |
;; MAC, that relates to specified IP, into buffer specified in Extra. |
;; And if it cannot find an IP-address in the table, it does an ARP-request of that. |
;;IN: Operation: ARP_TABLE_IP_TO_MAC |
;; Index: IP that should be transformed into MAC |
;; Extra: pointer to buffer where will be written the MAC-address. |
;;OUT: |
;; EAX=ARP table entry status code. |
;; If EAX==ARP_NO_ENTRY, IP isn't found in the table and we have sent the request. |
;; If EAX==ARP_AWAITING_RESPONSE, we wait the response from remote system. |
;; If EAX==ARP_RESPONSE_TIMEOUT, remote system not responds too long. |
;; If EAX==ARP_VALID_MAPPING, all is ok, we've got a true MAC. |
;; |
;; If MAC will equal to a zero, in the buffer. It means, that IP-address was not yet |
;; resolved, or that doesn't exist. I recommend you, to do at most 3-5 calls of this |
;; function with 1sec delay. sure, only if it not return a valid MAC after a first call. |
;; |
.ip_to_mac: |
xor eax, eax |
mov edi, dword[Extra] |
cld |
stosd |
stosw |
; first, check destination IP to see if it is on 'this' network. |
; The test is: |
; if ( destIP & subnet_mask == stack_ip & subnet_mask ) |
; destination is local |
; else |
; destination is remote, so pass to gateway |
mov eax, [Index] ;eax=required IP |
mov esi, eax |
and esi, [subnet_mask] |
mov ecx, [stack_ip] |
and ecx, [subnet_mask] |
cmp esi, ecx |
je @f ;if we and target IP are located in the same network |
mov eax, [gateway_ip] |
mov [Index], eax |
@@: |
cmp dword[NumARP], 0 |
je .ip_to_mac_send_request;if ARP-table not contain an entries, we have to request IP. |
;EAX will be containing a zero, it's equal to ARP_NO_ENTRY |
mov ecx, dword[NumARP] |
imul esi, ecx, ARP_ENTRY_SIZE;esi=current ARP-table size |
@@: |
sub esi, ARP_ENTRY_SIZE |
cmp [ebx + esi], eax ; ebx=ARPTable base |
loopnz @b ; Return back if non match |
jnz .ip_to_mac_send_request; and request IP->MAC if none found in the table |
; Return the entry status in eax |
movzx eax, word[ebx + esi + ARP_ENTRY.Status] |
; esi holds index |
cld |
lea esi, [ebx + esi + ARP_ENTRY.MAC] |
mov edi, [Extra];edi=ptr to buffer for write MAC |
movsd |
movsw |
jmp .exit |
.ip_to_mac_send_request: |
stdcall arp_request, [Index], stack_ip, node_addr;TargetIP,SenderIP_ptr,SenderMAC_ptr |
mov eax, ARP_NO_ENTRY |
jmp .exit |
;;END IP_TO_MAC |
;;BEGIN GET_ENTRIES_NUMBER |
;;Description: returns an ARP-entries number in the ARPTable |
;;IN: Operation: ARP_TABLE_GET_ENTRIES_NUMBER |
;; Index: must be zero |
;; Extra: must be zero |
;;OUT: |
;; EAX=ARP-entries number in the ARPTable |
.get_entries_number: |
mov eax, dword[NumARP] |
jmp .exit |
;;END GET_ENTRIES_NUMBER |
.exit: |
ret |
endp |
;*************************************************************************** |
; 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 |
stdcall arp_table_manager, ARP_TABLE_ADD, EXTRA_IS_ARP_PACKET_PTR, ETH_FRAME.Data + ARP_PACKET |
inc dword[arp_rx_count];increase ARP-packets counter |
cmp word[ETH_FRAME.Data + ARP_PACKET.Opcode], ARP_REQ_OPCODE; Is this a request packet? |
jne .exit ; No - so exit |
mov eax, [stack_ip] |
cmp eax, dword[ETH_FRAME.Data + ARP_PACKET.TargetIP] ; Is it looking for my IP address? |
jne .exit ; No - so quit now |
; OK, it is a request for my MAC address. Build the frame and send it |
; We can reuse the packet. |
mov word[ETH_FRAME.Data + ARP_PACKET.Opcode], ARP_REP_OPCODE |
cld |
mov esi, ETH_FRAME.Data + ARP_PACKET.SenderMAC |
mov edi, ETH_FRAME.Data + ARP_PACKET.TargetMAC |
movsd |
movsw |
mov esi, ETH_FRAME.Data + ARP_PACKET.SenderIP |
mov edi, ETH_FRAME.Data + ARP_PACKET.TargetIP |
movsd |
mov esi, node_addr |
mov edi, ETH_FRAME.Data + ARP_PACKET.SenderMAC |
movsd |
movsw |
mov esi, stack_ip |
mov edi, ETH_FRAME.Data + ARP_PACKET.SenderIP |
movsd |
; Now, send it! |
mov edi, ETH_FRAME.Data + ARP_PACKET.TargetMAC;ptr to destination MAC address |
mov bx, ETHER_ARP ;type of protocol |
mov ecx, 28 ;data size |
mov esi, ETH_FRAME.Data + ARP_PACKET ;ptr to data |
push ebp |
call dword [drvr_transmit] ;transmit packet |
pop ebp |
.exit: |
ret |
;*************************************************************************** |
; Function |
; arp_request [by Johnny_B] |
; |
; Description |
; Sends an ARP request on the ethernet |
; IN: |
; TargetIP : requested IP address |
; SenderIP_ptr : POINTER to sender's IP address(our system's address) |
; SenderMAC_ptr : POINTER to sender's MAC address(our system's address) |
; OUT: |
; EAX=0 (if all is ok), otherwise EAX is not defined |
; |
; EBX,ESI,EDI will be saved |
; |
;*************************************************************************** |
proc arp_request stdcall uses ebx esi edi,\ |
TargetIP:DWORD, SenderIP_ptr:DWORD, SenderMAC_ptr:DWORD |
inc dword[arp_tx_count]; increase counter |
sub esp, 28; allocate memory for ARP_PACKET |
mov word[esp + ARP_PACKET.HardwareType], 0x0100;Ethernet |
mov word[esp + ARP_PACKET.ProtocolType], 0x0008;IP |
mov byte[esp + ARP_PACKET.HardwareSize], 0x06;MAC-addr length |
mov byte[esp + ARP_PACKET.ProtocolSize], 0x04;IP-addr length |
mov word[esp + ARP_PACKET.Opcode], 0x0100 ;Request |
cld |
mov esi, [SenderMAC_ptr] |
lea edi, [esp + ARP_PACKET.SenderMAC] ;Our MAC-addr |
movsd |
movsw |
mov esi, [SenderIP_ptr] |
lea edi, [esp + ARP_PACKET.SenderIP] ;Our IP-addr |
movsd |
xor eax, eax |
lea edi, [esp + ARP_PACKET.TargetMAC] ;Required MAC-addr(zeroed) |
stosd |
stosw |
mov esi, dword[TargetIP] |
mov dword[esp + ARP_PACKET.TargetIP], esi;Required IP-addr(we get it as function parameter) |
; Now, send it! |
mov edi, broadcast_add ; Pointer to 48 bit destination address |
mov bx, ETHER_ARP ; Type of packet |
mov ecx, 28 ; size of packet |
lea esi, [esp + ARP_PACKET]; pointer to packet data |
push ebp |
call dword [drvr_transmit]; Call the drivers transmit function |
pop ebp |
add esp, 28; free memory, allocated before for ARP_PACKET |
; Add an entry in the ARP table, awaiting response |
sub esp, ARP_ENTRY_SIZE;allocate memory for ARP-entry |
mov esi, dword[TargetIP] |
mov dword[esp + ARP_ENTRY.IP], esi |
lea edi, [esp + ARP_ENTRY.MAC] |
xor eax, eax |
stosd |
stosw |
mov word[esp + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE |
mov word[esp + ARP_ENTRY.TTL], 0x000A; 10 seconds |
stdcall arp_table_manager, ARP_TABLE_ADD, EXTRA_IS_ARP_ENTRY_PTR, esp |
add esp, ARP_ENTRY_SIZE; free memory |
.exit: |
ret |
endp |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv/pci.inc |
---|
0,0 → 1,351 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
;*************************************************************************** |
; |
; PCI CODE FOLLOWS |
; |
; the following functions provide access to the PCI interface. |
; These functions are used by scan_bus, and also some ethernet drivers |
; |
;*************************************************************************** |
; 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 |
;*************************************************************************** |
; 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 |
mov eax, [esi+20] |
mov [drvr_cable], 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 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/eth_drv |
---|
Property changes: |
Added: svn:ignore |
+*.mnt |
+lang.inc |
+*.bat |
+out.txt |
+scin* |
+*.obj |
/kernel/trunk/network/ip.inc |
---|
0,0 → 1,248 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
; IP underlying protocols numbers |
PROTOCOL_ICMP equ 1 |
PROTOCOL_TCP equ 6 |
PROTOCOL_UDP equ 17 |
struc IP_PACKET |
{ .VersionAndIHL db ? ;+00 - Version[0-3 bits] and IHL(header length)[4-7 bits] |
.TypeOfService db ? ;+01 |
.TotalLength dw ? ;+02 |
.Identification dw ? ;+04 |
.FlagsAndFragmentOffset dw ? ;+06 - Flags[0-2] and FragmentOffset[3-15] |
.TimeToLive db ? ;+08 |
.Protocol db ? ;+09 |
.HeaderChecksum dw ? ;+10 |
.SourceAddress dd ? ;+12 |
.DestinationAddress dd ? ;+16 |
.DataOrOptional dd ? ;+20 |
} |
virtual at 0 |
IP_PACKET IP_PACKET |
end virtual |
;******************************************************************* |
; Interface |
; |
; ip_rx processes all packets received by the network layer |
; It calls the appropriate protocol handler |
; |
; |
; |
;******************************************************************* |
; |
; IP Packet after reception - Normal IP packet format |
; |
; 0 1 2 3 |
; 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 |
; |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;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 | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;20 | Data | |
; +-+-+-.......... -+ |
; |
; |
; [smb] attention! according to RFC 791 IP packet may have 'options' sections, |
; so we can't simply think, that data have offset 20. We must calculate offset from |
; IHL field |
; |
macro GET_IHL reg, header_addr |
{ |
movzx reg, byte [header_addr] |
; we need 4-7 bits, so.... |
and reg, 0x0000000F |
; IHL keeps number of octets, so we need to << 2 'reg' |
shl reg, 2 |
} |
include "tcp.inc" |
include "udp.inc" |
include "icmp.inc" |
;*************************************************************************** |
; Function |
; ip_rx |
; |
; Description |
; This is a kernel function, called by stack_handler |
; Processes all IP-packets received by the network layer |
; It calls the appropriate protocol handler |
; |
;*************************************************************************** |
proc ip_rx stdcall |
local buffer_number dd ? |
; Look for a buffer to tx |
mov eax, IPIN_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je .exit ; Exit if no buffer available |
mov [buffer_number], eax;save buffer number |
; convert buffer pointer eax to the absolute address |
imul eax, IPBUFFSIZE |
add eax, IPbuffs |
mov ebx, eax; ebx=pointer to IP_PACKET |
; DEBUGF 1, "K : ip_rx - proto: %u\n", [ebx + IP_PACKET.Protocol]:1 |
; Validate the IP checksum |
mov dx, word[ebx + IP_PACKET.HeaderChecksum] |
xchg dh, dl ; Get the checksum in intel format |
mov [ebx + IP_PACKET.HeaderChecksum], 0; clear checksum field - need to when |
; recalculating checksum |
; this needs two data pointers and two size #. |
; 2nd pointer can be of length 0 |
GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx |
stdcall checksum_jb, ebx, ecx;buf_ptr, buf_size |
cmp dx, ax |
; DEBUGF 1, "K : ip_rx - checksums: %x - %x\n", dx, ax |
jnz .dump.1;if CHECKSUM isn't valid then dump packet |
mov edx, ebx; EDX (IP-BUFFER POINTER) WILL BE USED FOR *_rx HANDLERS BELOW!!! |
; DEBUGF 1, "K : ip_rx - dest: %x - %x\n", [ebx + IP_PACKET.DestinationAddress], [stack_ip] |
; Validate the IP address, if it isn't broadcast |
mov eax, [stack_ip] |
cmp dword[ebx + IP_PACKET.DestinationAddress], eax |
je @f |
; If the IP address is 255.255.255.255, accept it |
; - it is a broadcast packet, which we need for dhcp |
mov eax, [ebx + IP_PACKET.DestinationAddress] |
cmp eax, 0xffffffff |
je @f |
mov ecx, [stack_ip] |
and eax, [subnet_mask] |
and ecx, [subnet_mask] |
cmp eax, ecx |
jne .dump.2 |
mov eax, [ebx + IP_PACKET.DestinationAddress] |
or eax, [subnet_mask] |
cmp eax, 0xffffffff |
jne .dump.2 |
@@: |
mov al, [ebx + IP_PACKET.VersionAndIHL] |
and al, 0x0f;get IHL(header length) |
cmp al, 0x05;if IHL!= 5*4(20 bytes) |
; DEBUGF 1, "K : ip_rx - ihl: %x - 05\n", al |
jnz .dump.3 ;then dump it |
; DEBUGF 1, "K : ip_rx - ttl: %x - 00\n", [ebx + IP_PACKET.TimeToLive]:2 |
cmp [ebx + IP_PACKET.TimeToLive], 0 |
je .dump.4 ;if TTL==0 then dump it |
mov ax, [ebx + IP_PACKET.FlagsAndFragmentOffset] |
and ax, 0xFFBF;get flags |
; DEBUGF 1, "K : ip_rx - flags: %x - 0000\n", ax |
cmp ax, 0 ;if some flags was set then we dump this packet |
jnz .dump.5 ;the flags should be used for fragmented packets |
; Check the protocol, and call the appropriate handler |
; Each handler will re-use or free the queue buffer as appropriate |
mov al, [ebx + IP_PACKET.Protocol] |
cmp al , PROTOCOL_TCP |
jne .not_tcp |
; DEBUGF 1,"K : ip_rx - TCP packet\n" |
mov eax, dword[buffer_number] |
call tcp_rx |
jmp .exit |
.not_tcp: |
cmp al, PROTOCOL_UDP |
jne .not_udp |
; DEBUGF 1,"K : ip_rx - UDP packet\n" |
mov eax, dword[buffer_number] |
call udp_rx |
jmp .exit |
.not_udp: |
cmp al, PROTOCOL_ICMP |
jne .dump.6 ;protocol ain't supported |
; DEBUGF 1,"K : ip_rx - ICMP packet\n" |
;GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx |
mov eax, dword[buffer_number] |
stdcall icmp_rx, eax, ebx, ecx;buffer_number,IPPacketBase,IPHeaderLength |
jmp .exit |
.dump.1: |
; DEBUGF 1, "K : ip_rx - dumped (checksum: 0x%x-0x%x)\n", dx, ax |
jmp .dump.x |
.dump.2: |
; DEBUGF 1, "K : ip_rx - dumped (ip: %u.%u.%u.%u)\n", [ebx + IP_PACKET.DestinationAddress + 0]:1, [ebx + IP_PACKET.DestinationAddress + 1]:1, [ebx + IP_PACKET.DestinationAddress + 2]:1, [ebx + IP_PACKET.DestinationAddress + 3]:1 |
jmp .dump.x |
.dump.3: |
; DEBUGF 1, "K : ip_rx - dumped (ihl: %u)\n", al |
jmp .dump.x |
.dump.4: |
; DEBUGF 1, "K : ip_rx - dumped (ttl: %u)\n", [ebx + IP_PACKET.TimeToLive] |
jmp .dump.x |
.dump.5: |
; DEBUGF 1, "K : ip_rx - dumped (flags: 0x%x)\n", ax |
jmp .dump.x |
.dump.6: |
; DEBUGF 1, "K : ip_rx - dumped (proto: %u)\n", [ebx + IP_PACKET.Protocol]:1 |
.dump.x: |
inc dword[dumped_rx_count] |
mov eax, [buffer_number] |
call freeBuff |
.exit: |
ret |
endp |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/icmp.inc |
---|
1,431 → 1,193 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ICMP.INC ;; |
;; ;; |
;; Part of the tcp/ip network stack for KolibriOS ;; |
;; Internet Control Message Protocol ( RFC 792 ) ;; |
;; ;; |
;; Based on the work of [Johnny_B] and [smb] ;; |
;; Last revision: 11.11.2006 ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; This file contains the following: ;; |
;; icmp_rx - processes ICMP-packets received by the IP layer ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; Changes history: ;; |
;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net ;; |
;; 11.11.2006 - [Johnny_B] and [smb] ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; Current status: ;; |
;; This implemetation of ICMP proto supports message of ECHO type. |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
$Revision: 2924 $ |
; ICMP types & codes |
struc ICMP_PACKET |
{ .Type db ? ;+00 |
.Code db ? ;+01 |
.Checksum dw ? ;+02 |
.Identifier dw ? ;+04 |
.SequenceNumber dw ? ;+06 |
.Data db ? ;+08 |
} |
ICMP_ECHOREPLY = 0 ; echo reply message |
virtual at 0 |
ICMP_PACKET ICMP_PACKET |
end virtual |
ICMP_UNREACH = 3 |
ICMP_UNREACH_NET = 0 ; bad net |
ICMP_UNREACH_HOST = 1 ; bad host |
ICMP_UNREACH_PROTOCOL = 2 ; bad protocol |
ICMP_UNREACH_PORT = 3 ; bad port |
ICMP_UNREACH_NEEDFRAG = 4 ; IP_DF caused drop |
ICMP_UNREACH_SRCFAIL = 5 ; src route failed |
ICMP_UNREACH_NET_UNKNOWN = 6 ; unknown net |
ICMP_UNREACH_HOST_UNKNOWN = 7 ; unknown host |
ICMP_UNREACH_ISOLATED = 8 ; src host isolated |
ICMP_UNREACH_NET_PROHIB = 9 ; prohibited access |
ICMP_UNREACH_HOST_PROHIB = 10 ; ditto |
ICMP_UNREACH_TOSNET = 11 ; bad tos for net |
ICMP_UNREACH_TOSHOST = 12 ; bad tos for host |
ICMP_UNREACH_FILTER_PROHIB = 13 ; admin prohib |
ICMP_UNREACH_HOST_PRECEDENCE = 14 ; host prec vio. |
ICMP_UNREACH_PRECEDENCE_CUTOFF = 15 ; prec cutoff |
ICMP_SOURCEQUENCH = 4 ; Packet lost, slow down |
ICMP_REDIRECT = 5 ; shorter route, codes: |
ICMP_REDIRECT_NET = 0 ; for network |
ICMP_REDIRECT_HOST = 1 ; for host |
ICMP_REDIRECT_TOSNET = 2 ; for tos and net |
ICMP_REDIRECT_TOSHOST = 3 ; for tos and host |
ICMP_ALTHOSTADDR = 6 ; alternate host address |
ICMP_ECHO = 8 ; echo service |
ICMP_ROUTERADVERT = 9 ; router advertisement |
ICMP_ROUTERADVERT_NORMAL = 0 ; normal advertisement |
ICMP_ROUTERADVERT_NOROUTE_COMMON= 16 ; selective routing |
ICMP_ROUTERSOLICIT = 10 ; router solicitation |
ICMP_TIMXCEED = 11 ; time exceeded, code: |
ICMP_TIMXCEED_INTRANS = 0 ; ttl==0 in transit |
ICMP_TIMXCEED_REASS = 1 ; ttl==0 in reass |
ICMP_PARAMPROB = 12 ; ip header bad |
ICMP_PARAMPROB_ERRATPTR = 0 ; error at param ptr |
ICMP_PARAMPROB_OPTABSENT = 1 ; req. opt. absent |
ICMP_PARAMPROB_LENGTH = 2 ; bad length |
ICMP_TSTAMP = 13 ; timestamp request |
ICMP_TSTAMPREPLY = 14 ; timestamp reply |
ICMP_IREQ = 15 ; information request |
ICMP_IREQREPLY = 16 ; information reply |
ICMP_MASKREQ = 17 ; address mask request |
ICMP_MASKREPLY = 18 ; address mask reply |
ICMP_TRACEROUTE = 30 ; traceroute |
ICMP_DATACONVERR = 31 ; data conversion error |
ICMP_MOBILE_REDIRECT = 32 ; mobile host redirect |
ICMP_IPV6_WHEREAREYOU = 33 ; IPv6 where-are-you |
ICMP_IPV6_IAMHERE = 34 ; IPv6 i-am-here |
ICMP_MOBILE_REGREQUEST = 35 ; mobile registration req |
ICMP_MOBILE_REGREPLY = 36 ; mobile registreation reply |
ICMP_SKIP = 39 ; SKIP |
ICMP_PHOTURIS = 40 ; Photuris |
ICMP_PHOTURIS_UNKNOWN_INDEX = 1 ; unknown sec index |
ICMP_PHOTURIS_AUTH_FAILED = 2 ; auth failed |
ICMP_PHOTURIS_DECRYPT_FAILED = 3 ; decrypt failed |
struct ICMP_header |
Type db ? |
Code db ? |
Checksum dw ? |
Identifier dw ? |
SequenceNumber dw ? |
ends |
align 4 |
uglobal |
ICMP_PACKETS_TX rd MAX_NET_DEVICES |
ICMP_PACKETS_RX rd MAX_NET_DEVICES |
endg |
;----------------------------------------------------------------- |
; Example: |
; ECHO message format |
; |
; ICMP_init |
; |
;----------------------------------------------------------------- |
; 0 1 2 3 |
; 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Type | Code | Checksum | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Identifier | Sequence Number | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Data ... |
; +-+-+-+-+- |
; |
macro ICMP_init { |
xor eax, eax |
mov edi, ICMP_PACKETS_TX |
mov ecx, 2*MAX_NET_DEVICES |
rep stosd |
} |
;----------------------------------------------------------------- |
; |
; ICMP_input: |
; ICMP types & codes, RFC 792 and FreeBSD's ICMP sources |
; |
; This procedure will send reply's to ICMP echo's |
; and insert packets into sockets when needed |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; ebx = pointer to device struct |
; ecx = ICMP Packet size |
; esi = ptr to ICMP Packet data |
; edi = ptr to ipv4 source and dest address |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
ICMP_input: |
DEBUGF 1,"ICMP_input:\n" |
ICMP_ECHOREPLY equ 0 ; echo reply message |
; First, check the checksum (altough some implementations ignore it) |
ICMP_UNREACH equ 3 |
ICMP_UNREACH_NET equ 0 ; bad net |
ICMP_UNREACH_HOST equ 1 ; bad host |
ICMP_UNREACH_PROTOCOL equ 2 ; bad protocol |
ICMP_UNREACH_PORT equ 3 ; bad port |
ICMP_UNREACH_NEEDFRAG equ 4 ; IP_DF caused drop |
ICMP_UNREACH_SRCFAIL equ 5 ; src route failed |
ICMP_UNREACH_NET_UNKNOWN equ 6 ; unknown net |
ICMP_UNREACH_HOST_UNKNOWN equ 7 ; unknown host |
ICMP_UNREACH_ISOLATED equ 8 ; src host isolated |
ICMP_UNREACH_NET_PROHIB equ 9 ; prohibited access |
ICMP_UNREACH_HOST_PROHIB equ 10 ; ditto |
ICMP_UNREACH_TOSNET equ 11 ; bad tos for net |
ICMP_UNREACH_TOSHOST equ 12 ; bad tos for host |
ICMP_UNREACH_FILTER_PROHIB equ 13 ; admin prohib |
ICMP_UNREACH_HOST_PRECEDENCE equ 14 ; host prec vio. |
ICMP_UNREACH_PRECEDENCE_CUTOFF equ 15 ; prec cutoff |
push esi ecx |
push [esi + ICMP_header.Checksum] |
mov [esi + ICMP_header.Checksum], 0 |
xor edx, edx |
call checksum_1 |
call checksum_2 |
pop si |
cmp dx, si |
pop ecx edx |
jne .checksum_mismatch |
ICMP_SOURCEQUENCH equ 4 ; packet lost, slow down |
cmp [edx + ICMP_header.Type], ICMP_ECHO ; Is this an echo request? |
jne .check_sockets |
ICMP_REDIRECT equ 5 ; shorter route, codes: |
ICMP_REDIRECT_NET equ 0 ; for network |
ICMP_REDIRECT_HOST equ 1 ; for host |
ICMP_REDIRECT_TOSNET equ 2 ; for tos and net |
ICMP_REDIRECT_TOSHOST equ 3 ; for tos and host |
; We well re-use the packet so we can create the response as fast as possible |
; Notice: this only works on pure ethernet |
ICMP_ALTHOSTADDR equ 6 ; alternate host address |
ICMP_ECHO equ 8 ; echo service |
ICMP_ROUTERADVERT equ 9 ; router advertisement |
ICMP_ROUTERADVERT_NORMAL equ 0 ; normal advertisement |
ICMP_ROUTERADVERT_NOROUTE_COMMON equ 16 ; selective routing |
DEBUGF 1,"got echo request\n" |
mov [edx + ICMP_header.Type], ICMP_ECHOREPLY ; Change Packet type to reply |
ICMP_ROUTERSOLICIT equ 10 ; router solicitation |
ICMP_TIMXCEED equ 11 ; time exceeded, code: |
ICMP_TIMXCEED_INTRANS equ 0 ; ttl==0 in transit |
ICMP_TIMXCEED_REASS equ 1 ; ttl==0 in reass |
mov esi, [esp] ; Start of buffer |
ICMP_PARAMPROB equ 12 ; ip header bad |
ICMP_PARAMPROB_ERRATPTR equ 0 ; error at param ptr |
ICMP_PARAMPROB_OPTABSENT equ 1 ; req. opt. absent |
ICMP_PARAMPROB_LENGTH equ 2 ; bad length |
cmp dword[edi + 4], 1 shl 24 + 127 |
je .loopback |
ICMP_TSTAMP equ 13 ; timestamp request |
ICMP_TSTAMPREPLY equ 14 ; timestamp reply |
ICMP_IREQ equ 15 ; information request |
ICMP_IREQREPLY equ 16 ; information reply |
ICMP_MASKREQ equ 17 ; address mask request |
ICMP_MASKREPLY equ 18 ; address mask reply |
ICMP_TRACEROUTE equ 30 ; traceroute |
ICMP_DATACONVERR equ 31 ; data conversion error |
ICMP_MOBILE_REDIRECT equ 32 ; mobile host redirect |
ICMP_IPV6_WHEREAREYOU equ 33 ; IPv6 where-are-you |
ICMP_IPV6_IAMHERE equ 34 ; IPv6 i-am-here |
ICMP_MOBILE_REGREQUEST equ 35 ; mobile registration req |
ICMP_MOBILE_REGREPLY equ 36 ; mobile registreation reply |
ICMP_SKIP equ 39 ; SKIP |
; Update stats (and validate device ptr) |
call NET_ptr_to_num |
cmp edi,-1 |
je .dump |
inc [ICMP_PACKETS_RX + 4*edi] |
inc [ICMP_PACKETS_TX + 4*edi] |
ICMP_PHOTURIS equ 40 ; Photuris |
ICMP_PHOTURIS_UNKNOWN_INDEX equ 1 ; unknown sec index |
ICMP_PHOTURIS_AUTH_FAILED equ 2 ; auth failed |
ICMP_PHOTURIS_DECRYPT_FAILED equ 3 ; decrypt failed |
; exchange dest and source address in IP header |
; exchange dest and source MAC in ETH header |
push dword [esi + ETH_header.DstMAC] |
push dword [esi + ETH_header.SrcMAC] |
pop dword [esi + ETH_header.DstMAC] |
pop dword [esi + ETH_header.SrcMAC] |
push word [esi + ETH_header.DstMAC + 4] |
push word [esi + ETH_header.SrcMAC + 4] |
pop word [esi + ETH_header.DstMAC + 4] |
pop word [esi + ETH_header.SrcMAC + 4] |
add esi, sizeof.ETH_header-2 |
.loopback: |
add esi, 2 |
push [esi + IPv4_header.SourceAddress] |
push [esi + IPv4_header.DestinationAddress] |
pop [esi + IPv4_header.SourceAddress] |
pop [esi + IPv4_header.DestinationAddress] |
; Recalculate ip header checksum |
movzx ecx, [esi + IPv4_header.VersionAndIHL] ; Calculate IP Header length by using IHL field |
and ecx, 0x0f |
shl cx, 2 |
mov edi, ecx ; IP header length |
mov eax, edx ; ICMP packet start addr |
push esi ; Calculate the IP checksum |
xor edx, edx ; |
call checksum_1 ; |
call checksum_2 ; |
pop esi ; |
mov [esi + IPv4_header.HeaderChecksum], dx ; |
; Recalculate ICMP CheckSum |
movzx ecx, [esi + IPv4_header.TotalLength] ; Find length of IP Packet |
xchg ch, cl ; |
sub ecx, edi ; IP packet length - IP header length = ICMP packet length |
mov esi, eax ; Calculate ICMP checksum |
xor edx, edx ; |
call checksum_1 ; |
call checksum_2 ; |
mov [eax + ICMP_header.Checksum], dx ; |
; Transmit the packet (notice that packet ptr and packet size have been on stack since start of the procedure!) |
call [ebx + NET_DEVICE.transmit] |
ret |
.check_sockets: |
; Look for an open ICMP socket |
mov esi, [edi] ; ipv4 source address |
mov eax, net_sockets |
.try_more: |
; mov , [edx + ICMP_header.Identifier] |
.next_socket: |
mov eax, [eax + SOCKET.NextPtr] |
or eax, eax |
jz .dump |
cmp [eax + SOCKET.Domain], AF_INET4 |
jne .next_socket |
cmp [eax + SOCKET.Protocol], IP_PROTO_ICMP |
jne .next_socket |
cmp [eax + IP_SOCKET.RemoteIP], esi |
jne .next_socket |
; cmp [eax + ICMP_SOCKET.Identifier], |
; jne .next_socket |
; call IPv4_dest_to_dev |
; cmp edi,-1 |
; je .dump |
; inc [ICMP_PACKETS_RX+edi] |
DEBUGF 1,"socket=%x\n", eax |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
mov esi, edx |
jmp SOCKET_input |
.checksum_mismatch: |
DEBUGF 1,"checksum mismatch\n" |
.dump: |
DEBUGF 1,"ICMP_input: dumping\n" |
call kernel_free |
add esp, 4 ; pop (balance stack) |
ret |
;----------------------------------------------------------------- |
;*************************************************************************** |
; Function |
; icmp_rx [by Johnny_B] |
; |
; ICMP_output |
; Description |
; ICMP protocol handler |
; This is a kernel function, called by ip_rx |
; |
; IN: eax = dest ip |
; ebx = source ip |
; ecx = data length |
; dh = type |
; dl = code |
; esi = data offset |
; edi = identifier shl 16 + sequence number |
; IN: |
; buffer_number - # of IP-buffer. This buffer must be reused or marked as empty afterwards |
; IPPacketBase - IP_PACKET base address |
; IPHeaderLength - Header length of IP_PACKET |
; |
;----------------------------------------------------------------- |
align 4 |
ICMP_output: |
DEBUGF 1,"Creating ICMP Packet\n" |
push esi edi dx |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov eax, [eax + IP_SOCKET.RemoteIP] |
add ecx, sizeof.ICMP_header |
mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL |
call IPv4_output |
jz .exit |
DEBUGF 1,"full icmp packet size: %u\n", edx |
pop word [edi + ICMP_header.Type] ; Write both type and code bytes at once |
pop dword [edi + ICMP_header.Identifier] ; identifier and sequence number |
mov [edi + ICMP_header.Checksum], 0 |
push ebx ecx edx |
mov esi, edi |
xor edx, edx |
call checksum_1 |
call checksum_2 |
mov [edi + ICMP_header.Checksum], dx |
pop edx ecx ebx esi |
sub ecx, sizeof.ICMP_header |
add edi, sizeof.ICMP_header |
push cx |
shr cx, 2 |
rep movsd |
pop cx |
and cx, 3 |
rep movsb |
sub edi, edx ;;; TODO: find a better way to remember start of packet |
push edx edi |
DEBUGF 1,"Sending ICMP Packet\n" |
call [ebx + NET_DEVICE.transmit] |
ret |
.exit: |
DEBUGF 1,"Creating ICMP Packet failed\n" |
add esp, 2*4 + 2 |
ret |
;----------------------------------------------------------------- |
; OUT: |
; EAX=not defined |
; |
; ICMP_output |
; All used registers will be saved |
; |
; IN: eax = socket ptr |
; ecx = data length |
; esi = data offset |
; |
;----------------------------------------------------------------- |
align 4 |
ICMP_output_raw: |
;*************************************************************************** |
proc icmp_rx stdcall uses ebx esi edi,\ |
buffer_number:DWORD,IPPacketBase:DWORD,IPHeaderLength:DWORD |
DEBUGF 1,"Creating ICMP Packet for socket %x, data ptr=%x\n", eax, edx |
mov esi, [IPPacketBase];esi=IP_PACKET base address |
mov edi, esi |
add edi, [IPHeaderLength];edi=ICMP_PACKET base address |
push edx |
cmp byte[edi + ICMP_PACKET.Type], ICMP_ECHO; Is this an echo request? discard if not |
jz .icmp_echo |
mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov eax, [eax + IP_SOCKET.RemoteIP] |
call IPv4_output |
jz .exit |
mov eax, [buffer_number] |
call freeBuff |
jmp .exit |
pop esi |
push edx |
push eax |
.icmp_echo: |
push edi ecx |
DEBUGF 1,"copying %u bytes from %x to %x\n", ecx, esi, edi |
rep movsb |
pop ecx edi |
; swap the source and destination addresses |
mov ecx, [esi + IP_PACKET.DestinationAddress] |
mov ebx, [esi + IP_PACKET.SourceAddress] |
mov [esi + IP_PACKET.DestinationAddress], ebx |
mov [esi + IP_PACKET.SourceAddress], ecx |
mov [edi + ICMP_header.Checksum], 0 |
; recalculate the IP header checksum |
mov eax, [IPHeaderLength] |
stdcall checksum_jb, esi, eax;buf_ptr,buf_size |
mov esi, edi |
xor edx, edx |
call checksum_1 |
call checksum_2 |
mov [edi + ICMP_header.Checksum], dx |
mov byte[esi + IP_PACKET.HeaderChecksum], ah |
mov byte[esi + IP_PACKET.HeaderChecksum + 1], al ; ?? correct byte order? |
DEBUGF 1,"Sending ICMP Packet\n" |
call [ebx + NET_DEVICE.transmit] |
ret |
.exit: |
DEBUGF 1,"Creating ICMP Packet failed\n" |
add esp, 4 |
ret |
mov byte[edi + ICMP_PACKET.Type], ICMP_ECHOREPLY; change the request to a response |
mov word[edi + ICMP_PACKET.Checksum], 0; clear ICMP checksum prior to re-calc |
; Calculate the length of the ICMP data ( IP payload) |
xor eax, eax |
mov ah, byte[esi + IP_PACKET.TotalLength] |
mov al, byte[esi + IP_PACKET.TotalLength + 1] |
sub ax, word[IPHeaderLength];ax=ICMP-packet length |
stdcall checksum_jb, edi, eax;buf_ptr,buf_size |
mov byte[edi + ICMP_PACKET.Checksum], ah |
mov byte[edi + ICMP_PACKET.Checksum + 1], al |
;----------------------------------------------------------------- |
; |
; ICMP_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;----------------------------------------------------------------- |
align 4 |
ICMP_api: |
; Queue packet for transmission |
mov ebx, [buffer_number] |
mov eax, NET1OUT_QUEUE |
call queue |
movzx eax, bh |
shl eax, 2 |
test bl, bl |
jz .packets_tx ; 0 |
dec bl |
jz .packets_rx ; 1 |
.error: |
mov eax, -1 |
.exit: |
ret |
.packets_tx: |
mov eax, [ICMP_PACKETS_TX + eax] |
ret |
.packets_rx: |
mov eax, [ICMP_PACKETS_RX + eax] |
ret |
endp |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/queue.inc |
---|
1,100 → 1,229 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; queue.inc ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; QUEUE.INC ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; Buffer queue management for Menuet OS TCP/IP Stack ;; |
;; ;; |
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; |
;; ;; |
;; See file COPYING for details ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 2305 $ |
$Revision$ |
; The Queues implemented by these macros form a ring-buffer. |
; The data to these queue's always looks like this: |
;******************************************************************* |
; Interface |
; |
; At top, you have the queue struct, wich has the size (number of currently queued packets, read and write pointers. |
; This struct is followed by a number of slots wich you can read and write to using the macros. |
; How these slots look like is up to you to chose, normally they should have at least a pointer to where the real data is. |
; (you can see some examples below) |
; 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 |
; |
;******************************************************************* |
struct queue |
;*************************************************************************** |
; 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 |
;*************************************************************************** |
;uglobal |
; freeBuff_cnt dd ? |
;endg |
freeBuff: |
; inc [freeBuff_cnt] |
; DEBUGF 1, "K : freeBuff (%u)\n", [freeBuff_cnt] |
push ebx |
push ecx |
mov ebx, queues + EMPTY_QUEUE * 2 |
cli ; Ensure that another process does not interfer |
mov cx, [ebx] |
mov [ebx], ax |
mov [queueList + eax * 2], cx |
sti |
pop ecx |
pop ebx |
size dd ? ; number of queued packets in this queue |
w_ptr dd ? ; current writing pointer in queue |
r_ptr dd ? ; current reading pointer |
ret |
ends |
; The following macros share these inputs: |
;*************************************************************************** |
; 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 |
; ptr = pointer to where the queue data is located |
; size = number of slots/entrys in the queue |
; entry_size = size of one slot, in bytes |
; failaddr = the address where macro will jump to when there is no data in the queue |
qs_001: |
inc eax |
shl ecx, 1 |
add ecx, queueList |
movzx ecx, word [ecx] |
cmp cx, NO_BUFFER |
je qs_exit |
jmp qs_001 |
; additionally, add_to_queue requires you to set esi to the data wich you want to queue |
; get_from_queue on the other hand will return a pointer in esi, to the entry you're interessed in |
; PS: macros WILL destroy ecx and edi |
qs_exit: |
ret |
macro add_to_queue ptr, size, entry_size, failaddr { |
cmp [ptr + queue.size], size ; Check if queue isnt full |
jae failaddr |
;*************************************************************************** |
; 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 |
;*************************************************************************** |
;uglobal |
; queue_cnt dd ? |
;endg |
queue: |
; inc [queue_cnt] |
; DEBUGF 1, "K : queue (%u)\n", [queue_cnt] |
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 |
inc [ptr + queue.size] ; if not full, queue one more |
cli |
shl eax, 1 |
add eax, queues ; eax now holds address of queue |
movzx ebx, word [eax] |
mov edi, [ptr + queue.w_ptr] ; Current write pointer (FIFO!) |
mov ecx, entry_size/4 ; Write the queue entry |
rep movsd ; |
cmp bx, NO_BUFFER |
jne qu_001 |
lea ecx, [size*entry_size+ptr+sizeof.queue] |
cmp edi, ecx ; entry size |
jb .no_wrap |
pop ebx |
; The list is empty, so add this to the head |
mov [eax], bx |
jmp qu_exit |
sub edi, size*entry_size |
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 |
.no_wrap: |
mov [ptr + queue.w_ptr], edi |
mov ebx, eax |
pop eax |
mov [ebx], ax |
} |
qu_exit: |
sti |
ret |
macro get_from_queue ptr, size, entry_size, failaddr { |
;*************************************************************************** |
; 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 |
; |
;*************************************************************************** |
;uglobal |
; dequeue_cnt dd ? |
;endg |
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 |
; inc [dequeue_cnt] |
; DEBUGF 1, "K : dequeue (%u)\n", [dequeue_cnt] |
push eax |
shl eax, 1 |
add eax, queueList ; eax now holds address of queue entry |
mov ax, [eax] |
mov [ebx], ax |
pop eax |
cmp [ptr + queue.size], 0 ; any packets queued? |
je failaddr |
dq_exit: |
sti |
pop ebx |
ret |
dec [ptr + queue.size] ; if so, dequeue one |
mov esi, [ptr + queue.r_ptr] |
push esi |
;*************************************************************************** |
; 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 |
add esi, entry_size |
qi001: |
mov [esi], ax |
inc esi |
inc esi |
loop qi001 |
lea ecx, [size*entry_size+ptr+sizeof.queue] |
cmp esi, ecx ; entry size |
jb .no_wrap |
mov esi, queues + ( 2 * EMPTY_QUEUE ) |
sub esi, size*entry_size |
; Initialise empty queue list |
.no_wrap: |
mov dword [ptr + queue.r_ptr], esi |
xor ax, ax |
mov [esi], ax |
pop esi |
mov ecx, NUMQUEUEENTRIES - 1 |
mov esi, queueList |
} |
qi002: |
inc ax |
mov [esi], ax |
inc esi |
inc esi |
loop qi002 |
macro init_queue ptr { |
mov ax, NO_BUFFER |
mov [esi], ax |
mov [ptr + queue.size] , 0 |
lea edi, [ptr + sizeof.queue] |
mov [ptr + queue.w_ptr], edi |
mov [ptr + queue.r_ptr], edi |
} |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/socket.inc |
---|
1,2284 → 1,1129 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Part of the TCP/IP network stack for KolibriOS ;; |
;; SOCKET.INC ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org, ;; |
;; and Clevermouse. ;; |
;; Sockets constants, structures and functions ;; |
;; ;; |
;; Based on code by mike.dld ;; |
;; This file contains the following: ;; |
;; is_localport_unused ;; |
;; get_free_socket ;; |
;; socket_open ;; |
;; socket_open_tcp ;; |
;; socket_close ;; |
;; socket_close_tcp ;; |
;; socket_poll ;; |
;; socket_status ;; |
;; socket_read ;; |
;; socket_write ;; |
;; socket_write_tcp ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; Changes history: ;; |
;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net ;; |
;; 11.11.2006 - [Johnny_B] and [smb] ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 3514 $ |
$Revision$ |
; socket data structure |
struct SOCKET |
PrevPtr dd ? ; pointer to previous socket in list |
NextPtr dd ? ; pointer to next socket in list |
PrevPtr dd ? ; pointer to previous socket in list |
Number dd ? ; socket number |
mutex MUTEX |
PID dd ? ; process ID |
TID dd ? ; thread ID |
Domain dd ? ; INET/LOCAL/.. |
Type dd ? ; RAW/STREAM/DGRAP |
Protocol dd ? ; ICMP/IPv4/ARP/TCP/UDP |
errorcode dd ? |
device dd ? ; driver pointer, socket pointer if it's an LOCAL socket |
options dd ? |
state dd ? |
backlog dw ? ; how many incoming connections that can be queued |
snd_proc dd ? |
rcv_proc dd ? |
ends |
struct IP_SOCKET SOCKET |
LocalIP rd 4 ; network byte order |
RemoteIP rd 4 ; network byte order |
ends |
struct TCP_SOCKET IP_SOCKET |
LocalPort dw ? ; network byte order |
RemotePort dw ? ; network byte order |
t_state dd ? ; TCB state |
t_rxtshift db ? |
rb 3 ; align |
t_rxtcur dd ? |
t_dupacks dd ? |
t_maxseg dd ? |
t_force dd ? |
t_flags dd ? |
;--------------- |
; RFC783 page 21 |
; send sequence |
SND_UNA dd ? ; sequence number of unack'ed sent Packets |
SND_NXT dd ? ; next send sequence number to use |
SND_UP dd ? ; urgent pointer |
SND_WL1 dd ? ; window minus one |
SND_WL2 dd ? ; |
ISS dd ? ; initial send sequence number |
Number dd ? ; socket number (unique within single process) |
PID dd ? ; application process id |
LocalIP dd ? ; local IP address |
LocalPort dw ? ; local port |
RemoteIP dd ? ; remote IP address |
RemotePort dw ? ; remote port |
OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state) |
OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state) |
rxDataCount dd ? ; rx data count |
TCBState dd ? ; TCB state |
TCBTimer dd ? ; TCB timer (seconds) |
ISS dd ? ; initial send sequence |
IRS dd ? ; initial receive sequence |
SND_UNA dd ? ; sequence number of unack'ed sent packets |
SND_NXT dd ? ; bext send sequence number to use |
SND_WND dd ? ; send window |
; receive sequence |
RCV_NXT dd ? ; next receive sequence number to use |
RCV_WND dd ? ; receive window |
RCV_NXT dd ? ; next receive sequence number to use |
RCV_UP dd ? ; urgent pointer |
IRS dd ? ; initial receive sequence number |
;--------------------- |
; Additional variables |
; receive variables |
RCV_ADV dd ? |
; retransmit variables |
SND_MAX dd ? |
; congestion control |
SND_CWND dd ? |
SND_SSTHRESH dd ? |
;---------------------- |
; Transmit timing stuff |
t_idle dd ? |
t_rtt dd ? |
t_rtseq dd ? |
t_srtt dd ? |
t_rttvar dd ? |
t_rttmin dd ? |
max_sndwnd dd ? |
;----------------- |
; Out-of-band data |
t_oobflags dd ? |
t_iobc dd ? |
t_softerror dd ? |
;--------- |
; RFC 1323 ; the order of next 4 elements may not change |
SND_SCALE db ? |
RCV_SCALE db ? |
requested_s_scale db ? |
request_r_scale db ? |
ts_recent dd ? ; a copy of the most-recent valid timestamp from the other end |
ts_recent_age dd ? |
last_ack_sent dd ? |
;------- |
; Timers |
timer_retransmission dd ? ; rexmt |
timer_persist dd ? |
timer_keepalive dd ? ; keepalive/syn timeout |
timer_timed_wait dd ? ; also used as 2msl timer |
; extra |
ts_ecr dd ? ; timestamp echo reply |
ts_val dd ? |
seg_next dd ? ; re-assembly queue |
temp_bits db ? |
rb 3 ; align |
SEG_LEN dd ? ; segment length |
SEG_WND dd ? ; segment window |
wndsizeTimer dd ? ; window size timer |
mutex MUTEX ; lock mutex |
rxData dd ? ; receive data buffer here |
ends |
struct UDP_SOCKET IP_SOCKET |
; TCP opening modes |
SOCKET_PASSIVE = 0 |
SOCKET_ACTIVE = 1 |
LocalPort dw ? ; network byte order |
RemotePort dw ? ; network byte order |
firstpacket db ? |
; socket types |
SOCK_STREAM = 1 |
SOCK_DGRAM = 2 |
ends |
struct ICMP_SOCKET IP_SOCKET |
Identifier dw ? |
ends |
struct RING_BUFFER |
mutex MUTEX |
start_ptr dd ? ; Pointer to start of buffer |
end_ptr dd ? ; pointer to end of buffer |
read_ptr dd ? ; Read pointer |
write_ptr dd ? ; Write pointer |
size dd ? ; Number of bytes buffered |
ends |
struct STREAM_SOCKET TCP_SOCKET |
rcv RING_BUFFER |
snd RING_BUFFER |
ends |
struct socket_queue_entry |
data_ptr dd ? |
buf_ptr dd ? |
data_size dd ? |
ends |
SOCKETBUFFSIZE = 4096 ; in bytes |
SOCKET_QUEUE_SIZE = 10 ; maximum number of incoming packets queued for 1 socket |
; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start |
SOCKET_QUEUE_LOCATION = (SOCKETBUFFSIZE - SOCKET_QUEUE_SIZE*sizeof.socket_queue_entry - sizeof.queue) |
; pointer to bitmap of free ports (1=free, 0=used) |
uglobal |
net_sockets rd 4 |
last_socket_num dd ? |
last_UDP_port dw ? ; These values give the number of the last used ephemeral port |
last_TCP_port dw ? ; |
align 4 |
network_free_ports dd ? |
endg |
iglobal |
align 4 |
network_free_hint dd 1024/8 |
endg |
;----------------------------------------------------------------- |
;; Allocate memory for socket data and put new socket into the list |
; Newly created socket is initialized with calling PID and number and |
; put into beginning of list (which is a fastest way). |
; |
; SOCKET_init |
; |
;----------------------------------------------------------------- |
macro SOCKET_init { |
; @return socket structure address in EAX |
;; |
proc net_socket_alloc stdcall uses ebx ecx edx edi |
stdcall kernel_alloc, SOCKETBUFFSIZE |
DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax |
; check if we can allocate needed amount of memory |
or eax, eax |
jz .exit |
; zero-initialize allocated memory |
push eax |
mov edi, eax |
mov ecx, SOCKETBUFFSIZE / 4 |
cld |
xor eax, eax |
mov edi, net_sockets |
mov ecx, 5 |
rep stosd |
@@: |
pseudo_random eax |
cmp ax, MIN_EPHEMERAL_PORT |
jb @r |
cmp ax, MAX_EPHEMERAL_PORT |
ja @r |
xchg al, ah |
mov [last_UDP_port], ax |
@@: |
pseudo_random eax |
cmp ax, MIN_EPHEMERAL_PORT |
jb @r |
cmp ax, MAX_EPHEMERAL_PORT |
ja @r |
xchg al, ah |
mov [last_TCP_port], ax |
} |
;----------------------------------------------------------------- |
; |
; Socket API (function 74) |
; |
;----------------------------------------------------------------- |
align 4 |
sys_socket: |
cmp ebx, 255 |
jz SOCKET_debug |
cmp ebx, .number |
ja s_error |
jmp dword [.table + 4*ebx] |
.table: |
dd SOCKET_open ; 0 |
dd SOCKET_close ; 1 |
dd SOCKET_bind ; 2 |
dd SOCKET_listen ; 3 |
dd SOCKET_connect ; 4 |
dd SOCKET_accept ; 5 |
dd SOCKET_send ; 6 |
dd SOCKET_receive ; 7 |
dd SOCKET_set_opt ; 8 |
dd SOCKET_get_opt ; 9 |
dd SOCKET_pair ; 10 |
.number = ($ - .table) / 4 - 1 |
s_error: |
DEBUGF 2,"SOCKET: error\n" |
mov dword [esp+32], -1 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_open |
; |
; IN: domain in ecx |
; type in edx |
; protocol in esi |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_open: |
DEBUGF 2,"SOCKET_open: domain=%u type=%u protocol=%x ", ecx, edx, esi |
push ecx edx esi |
call SOCKET_alloc |
pop esi edx ecx |
jz s_error |
mov [esp+32], edi ; return socketnumber |
DEBUGF 2,"socknum=%u\n", edi |
; push edx |
; and edx, SO_NONBLOCK |
or [eax + SOCKET.options], SO_NONBLOCK ;edx |
; pop edx |
; and edx, not SO_NONBLOCK |
mov [eax + SOCKET.Domain], ecx |
mov [eax + SOCKET.Type], edx |
mov [eax + SOCKET.Protocol], esi |
cmp ecx, AF_INET4 |
jne .no_inet4 |
cmp edx, SOCK_DGRAM |
je .udp |
cmp edx, SOCK_STREAM |
je .tcp |
cmp edx, SOCK_RAW |
je .raw |
.no_inet4: |
cmp ecx, AF_PPP |
jne .no_ppp |
cmp esi, PPP_PROTO_ETHERNET |
je .pppoe |
.no_ppp: |
DEBUGF 2,"Unknown socket family/protocol\n" |
ret |
align 4 |
.raw: |
test esi, esi ; IP_PROTO_IP |
jz .ip |
cmp esi, IP_PROTO_ICMP |
je .icmp |
cmp esi, IP_PROTO_UDP |
je .udp |
cmp esi, IP_PROTO_TCP |
je .tcp |
ret |
align 4 |
.udp: |
mov [eax + SOCKET.Protocol], IP_PROTO_UDP |
mov [eax + SOCKET.snd_proc], SOCKET_send_udp |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
ret |
align 4 |
.tcp: |
mov [eax + SOCKET.Protocol], IP_PROTO_TCP |
mov [eax + SOCKET.snd_proc], SOCKET_send_tcp |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_stream |
TCP_init_socket eax |
ret |
align 4 |
.ip: |
mov [eax + SOCKET.snd_proc], SOCKET_send_ip |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
ret |
align 4 |
.icmp: |
mov [eax + SOCKET.snd_proc], SOCKET_send_icmp |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
ret |
align 4 |
.pppoe: |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
mov [eax + SOCKET.snd_proc], SOCKET_send_pppoe |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_bind |
; |
; IN: socket number in ecx |
; pointer to sockaddr struct in edx |
; length of that struct in esi |
; OUT: 0 on success |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_bind: |
DEBUGF 2,"SOCKET_bind: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi |
call SOCKET_num_to_ptr |
jz s_error |
cmp esi, 2 |
jb s_error |
cmp word [edx], AF_INET4 |
je .af_inet4 |
cmp word [edx], AF_LOCAL |
je .af_local |
jmp s_error |
.af_local: |
; TODO: write code here |
mov dword [esp+32], 0 |
ret |
.af_inet4: |
cmp esi, 6 |
jb s_error |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
je .udp |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
jmp s_error |
.tcp: |
.udp: |
mov ebx, [edx + 4] ; First, fill in the IP |
test ebx, ebx ; If IP is 0, use default |
jnz @f |
mov ebx, [NET_DEFAULT] |
mov ebx, [IP_LIST + 4*ebx] |
@@: |
mov [eax + IP_SOCKET.LocalIP], ebx |
mov bx, [edx + 2] ; Now fill in the local port if it's still available |
call SOCKET_check_port |
jz s_error ; ZF is set by socket_check_port, on error |
DEBUGF 1,"SOCKET_bind: local ip=%u.%u.%u.%u\n",\ |
[eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\ |
[eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1 |
mov dword [esp+32], 0 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_connect |
; |
; IN: socket number in ecx |
; pointer to sockaddr struct in edx |
; length of that struct in esi |
; OUT: 0 on success |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_connect: |
DEBUGF 2,"SOCKET_connect: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi |
call SOCKET_num_to_ptr |
jz s_error |
cmp esi, 8 |
jb s_error |
cmp word [edx], AF_INET4 |
je .af_inet4 |
jmp s_error |
.af_inet4: |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST] ; FIXME |
pop [eax + IP_SOCKET.LocalIP] |
@@: |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
je .udp |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
cmp [eax + SOCKET.Protocol], IP_PROTO_IP |
je .ip |
cmp [eax + SOCKET.Protocol], IP_PROTO_ICMP |
je .ip |
jmp s_error |
align 4 |
.udp: |
pusha |
mov ebx, eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushw [edx + 2] |
pop [eax + UDP_SOCKET.RemotePort] |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
cmp [eax + UDP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
mov [eax + UDP_SOCKET.firstpacket], 0 |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
mov dword [esp+32], 0 |
ret |
align 4 |
.tcp: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushw [edx + 2] |
pop [eax + TCP_SOCKET.RemotePort] |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
cmp [eax + TCP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
mov [eax + TCP_SOCKET.timer_persist], 0 |
mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT |
push [TCP_sequence_num] |
add [TCP_sequence_num], 6400 |
pop [eax + TCP_SOCKET.ISS] |
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init |
TCP_sendseqinit eax |
; mov [ebx + TCP_SOCKET.timer_retransmission], ;; todo: create macro to set retransmission timer |
mov ebx, eax |
lea eax, [ebx + STREAM_SOCKET.snd] |
call SOCKET_ring_create |
lea eax, [ebx + STREAM_SOCKET.rcv] |
call SOCKET_ring_create |
pusha |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
popa |
call mutex_init |
mov eax, ebx |
call TCP_output |
;;; TODO: wait for successfull connection if blocking socket |
mov dword [esp+32], 0 |
ret |
align 4 |
.ip: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
mov dword [esp+32], 0 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_listen |
; |
; IN: socket number in ecx |
; backlog in edx |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_listen: |
DEBUGF 2,"SOCKET_listen: socknum=%u backlog=%u\n", ecx, edx |
call SOCKET_num_to_ptr |
jz s_error |
cmp [eax + SOCKET.Domain], AF_INET4 |
jne s_error |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
jne s_error |
cmp [eax + TCP_SOCKET.LocalPort], 0 |
je s_error |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST] |
pop [eax + IP_SOCKET.LocalIP] |
@@: |
cmp edx, MAX_backlog |
jbe @f |
mov edx, MAX_backlog |
@@: |
mov [eax + SOCKET.backlog], dx |
or [eax + SOCKET.options], SO_ACCEPTCON |
mov [eax + TCP_SOCKET.t_state], TCPS_LISTEN |
mov [eax + TCP_SOCKET.timer_keepalive], 0 ; disable keepalive timer |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up sockets queue |
pop eax |
mov dword [esp+32], 0 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_accept |
; |
; IN: socket number in ecx |
; addr in edx |
; addrlen in esi |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_accept: |
DEBUGF 2,"SOCKET_accept: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi |
call SOCKET_num_to_ptr |
jz s_error |
test [eax + SOCKET.options], SO_ACCEPTCON |
jz s_error |
cmp [eax + SOCKET.Domain], AF_INET4 |
jne s_error |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
jne s_error |
.loop: |
get_from_queue (eax + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .block |
; Ok, we got a socket ptr |
mov eax, [esi] |
; Change thread ID to that of the current thread |
mov ebx, [TASK_BASE] |
mov ebx, [ebx + TASKDATA.pid] |
mov [eax + SOCKET.TID], ebx |
; Convert it to a socket number |
call SOCKET_ptr_to_num |
jz s_error |
; and return it to caller |
mov [esp+32], eax |
ret |
.block: |
test [eax + SOCKET.options], SO_NONBLOCK |
jnz s_error |
call SOCKET_block |
jmp .loop |
;----------------------------------------------------------------- |
; |
; SOCKET_close |
; |
; IN: socket number in ecx |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_close: |
DEBUGF 2,"SOCKET_close: socknum=%u\n", ecx |
call SOCKET_num_to_ptr |
jz s_error |
mov dword [esp+32], 0 ; The socket exists, so we will succeed in closing it. |
.socket: |
or [eax + SOCKET.options], SO_NONBLOCK ; Mark the socket as non blocking, we dont want it to block any longer! |
test [eax + SOCKET.state], SS_BLOCKED ; Is the socket still in blocked state? |
; add socket to the list by changing pointers |
mov ebx, net_sockets |
push [ebx + SOCKET.NextPtr] |
mov [ebx + SOCKET.NextPtr], eax |
mov [eax + SOCKET.PrevPtr], ebx |
pop ebx |
mov [eax + SOCKET.NextPtr], ebx |
or ebx, ebx |
jz @f |
call SOCKET_notify.unblock ; Unblock it. |
@@: |
mov [ebx + SOCKET.PrevPtr], eax |
cmp [eax + SOCKET.Domain], AF_INET4 |
jne .free |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
.free: |
call SOCKET_free |
ret |
.tcp: |
cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED ; state must be LISTEN, SYN_SENT or CLOSED |
jb .free |
call TCP_usrclosed |
call TCP_output ;;;; Fixme: is this nescessary?? |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_receive |
; |
; IN: socket number in ecx |
; addr to buffer in edx |
; length of buffer in esi |
; flags in edi |
; OUT: eax is number of bytes copied, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_receive: |
DEBUGF 2,"SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi |
call SOCKET_num_to_ptr |
jz s_error |
jmp [eax + SOCKET.rcv_proc] |
align 4 |
SOCKET_receive_dgram: |
DEBUGF 1,"SOCKET_receive: DGRAM\n" |
mov ebx, esi |
mov edi, edx ; addr to buffer |
.loop: |
get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .block ; destroys esi and ecx |
mov ecx, [esi + socket_queue_entry.data_size] |
DEBUGF 1,"SOCKET_receive: %u bytes data\n", ecx |
cmp ecx, ebx |
ja .too_small |
push [esi + socket_queue_entry.buf_ptr] ; save the buffer addr so we can clear it later |
mov esi, [esi + socket_queue_entry.data_ptr] |
DEBUGF 1,"SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi |
mov [esp+32+4], ecx ; return number of bytes copied |
; copy the data |
shr ecx, 1 |
jnc .nb |
movsb |
.nb: |
shr ecx, 1 |
jnc .nw |
movsw |
.nw: |
test ecx, ecx |
jz .nd |
rep movsd |
.nd: |
call kernel_free ; remove the packet |
ret |
.too_small: |
DEBUGF 2,"SOCKET_receive: Buffer too small\n" |
jmp s_error |
.block: |
test [eax + SOCKET.options], SO_NONBLOCK |
jnz s_error |
call SOCKET_block |
jmp .loop |
align 4 |
SOCKET_receive_local: |
; does this socket have a PID yet? |
cmp [eax + SOCKET.PID], 0 |
jne @f |
; Change PID to that of current process |
@@: ; set socket owner PID to the one of calling process |
mov ebx, [TASK_BASE] |
mov ebx, [ebx + TASKDATA.pid] |
mov [eax + SOCKET.PID], ebx |
mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :( |
@@: |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_stream |
; find first free socket number and use it |
;mov edx, ebx |
mov ebx, net_sockets |
xor ecx, ecx |
.next_socket_number: |
inc ecx |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .last_socket_number |
cmp [ebx + SOCKET.Number], ecx |
jne .next_socket |
;cmp [ebx + SOCKET.PID], edx |
;jne .next_socket |
mov ebx, net_sockets |
jmp .next_socket_number |
align 4 |
SOCKET_receive_stream: |
.last_socket_number: |
mov [eax + SOCKET.Number], ecx |
DEBUGF 1,"SOCKET_receive: STREAM\n" |
mov ebx, edi |
mov ecx, esi |
mov edi, edx |
xor edx, edx |
test ebx, MSG_DONTWAIT |
jnz .dontwait |
.loop: |
cmp [eax + STREAM_SOCKET.rcv + RING_BUFFER.size], 0 |
je .block |
.dontwait: |
test ebx, MSG_PEEK |
jnz .peek |
add eax, STREAM_SOCKET.rcv |
call SOCKET_ring_read |
call SOCKET_ring_free |
mov [esp+32], ecx ; return number of bytes copied |
.exit: |
ret |
endp |
.peek: |
mov ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size] |
mov [esp+32], ecx ; return number of bytes available |
ret |
.block: |
test [eax + SOCKET.options], SO_NONBLOCK |
jnz .return0 |
call SOCKET_block |
jmp .loop |
.return0: |
xor ecx, ecx |
mov [esp+32], ecx |
ret |
;----------------------------------------------------------------- |
;; Free socket data memory and pop socket off the list |
; |
; SOCKET_send |
; |
; |
; IN: socket number in ecx |
; pointer to data in edx |
; datalength in esi |
; flags in edi |
; OUT: -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_send: |
; @param sockAddr is a socket structure address |
;; |
proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD |
mov eax, [sockAddr] |
DEBUGF 1, "K : net_socket_free (0x%x)\n", eax |
; check if we got something similar to socket structure address |
or eax, eax |
jz .error |
DEBUGF 2,"SOCKET_send: socknum=%u data ptr=%x length=%u flags=%x\n", ecx, edx, esi, edi |
; make sure sockAddr is one of the socket addresses in the list |
mov ebx, net_sockets |
;mov ecx, [TASK_BASE] |
;mov ecx, [ecx + TASKDATA.pid] |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .error |
cmp ebx, eax |
jne .next_socket |
;cmp [ebx + SOCKET.PID], ecx |
;jne .next_socket |
call SOCKET_num_to_ptr |
jz s_error |
mov ecx, esi |
mov esi, edx |
jmp [eax + SOCKET.snd_proc] |
align 4 |
SOCKET_send_udp: |
DEBUGF 1,"SOCKET_send: UDP\n" |
mov [esp+32], ecx |
call UDP_output |
cmp eax, -1 |
je s_error |
ret |
align 4 |
SOCKET_send_tcp: |
DEBUGF 1,"SOCKET_send: TCP\n" |
; okay, we found the correct one |
; mark local port as unused |
movzx ebx, [eax + SOCKET.LocalPort] |
push eax |
add eax, STREAM_SOCKET.snd |
call SOCKET_ring_write |
mov eax, [network_free_ports] |
xchg bl, bh |
lock bts [eax], ebx |
pop eax |
; remove it from the list first, changing pointers |
mov ebx, [eax + SOCKET.NextPtr] |
mov eax, [eax + SOCKET.PrevPtr] |
mov [eax + SOCKET.NextPtr], ebx |
or ebx, ebx |
jz @f |
mov [ebx + SOCKET.PrevPtr], eax |
mov [esp+32], ecx |
call TCP_output |
@@: ; and finally free the memory structure used |
stdcall kernel_free, [sockAddr] |
ret |
align 4 |
SOCKET_send_ip: |
DEBUGF 1,"SOCKET_send: IPv4\n" |
mov [esp+32], ecx |
call IPv4_output_raw |
cmp eax, -1 |
je s_error |
.error: |
DEBUGF 1, "K : failed\n" |
ret |
endp |
align 4 |
SOCKET_send_icmp: |
DEBUGF 1,"SOCKET_send: ICMP\n" |
mov [esp+32], ecx |
call ICMP_output_raw |
cmp eax, -1 |
je s_error |
ret |
align 4 |
SOCKET_send_pppoe: |
DEBUGF 1,"SOCKET_send: PPPoE\n" |
mov [esp+32], ecx |
mov ebx, [eax + SOCKET.device] |
call PPPoE_discovery_output |
cmp eax, -1 |
je s_error |
ret |
align 4 |
SOCKET_send_local: |
; does this socket have a PID yet? |
cmp [eax + SOCKET.PID], 0 |
jne @f |
; Change PID to that of current process |
mov ebx, [TASK_BASE] |
mov ebx, [ebx + TASKDATA.pid] |
mov [eax + SOCKET.PID], ebx |
mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :( |
@@: |
mov [eax + SOCKET.snd_proc], SOCKET_send_local_ |
align 4 |
SOCKET_send_local_: |
DEBUGF 1,"SOCKET_send: LOCAL\n" |
; get the other side's socket and check if it still exists |
mov eax, [eax + SOCKET.device] |
call SOCKET_check |
jz s_error |
; allright, shove in the data! |
push eax |
add eax, STREAM_SOCKET.rcv |
call SOCKET_ring_write |
pop eax |
; return the number of written bytes (or errorcode) to application |
mov [esp+32], ecx |
; and notify the other end |
call SOCKET_notify |
ret |
;----------------------------------------------------------------- |
;; Get socket structure address by its number |
; Scan through sockets list to find the socket with specified number. |
; This proc uses SOCKET.PID indirectly to check if socket is owned by |
; calling process. |
; |
; SOCKET_get_options |
; |
; IN: ecx = socket number |
; edx = pointer to the options: |
; dd level, optname, optval, optlen |
; OUT: -1 on error |
; |
; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP. |
; TODO: find best way to notify that send()'ed data were acknowledged |
; Also pseudo-optname -3 is valid and returns socket state, one of TCPS_*. |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_get_opt: |
; @param sockNum is a socket number |
; @return socket structure address or 0 (not found) in EAX |
;; |
proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD |
mov eax, [sockNum] |
; check if we got something similar to socket number |
or eax, eax |
jz .error |
DEBUGF 2,"SOCKET_get_opt\n" |
; scan through sockets list |
mov ebx, net_sockets |
;mov ecx, [TASK_BASE] |
;mov ecx, [ecx + TASKDATA.pid] |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .error |
cmp [ebx + SOCKET.Number], eax |
jne .next_socket |
;cmp [ebx + SOCKET.PID], ecx |
;jne .next_socket |
call SOCKET_num_to_ptr |
jz s_error |
cmp dword [edx], IP_PROTO_TCP |
jne s_error |
cmp dword [edx+4], -2 |
je @f |
cmp dword [edx+4], -3 |
jne s_error |
@@: |
; mov eax, [edx+12] |
; test eax, eax |
; jz .fail |
; cmp dword [eax], 4 |
; mov dword [eax], 4 |
; jb .fail |
; stdcall net_socket_num_to_addr, ecx |
; test eax, eax |
; jz .fail |
; ; todo: check that eax is really TCP socket |
; mov ecx, [eax + TCP_SOCKET.last_ack_number] |
; cmp dword [edx+4], -2 |
; jz @f |
; mov ecx, [eax + TCP_SOCKET.state] |
@@: |
mov eax, [edx+8] |
test eax, eax |
jz @f |
mov [eax], ecx |
@@: |
mov dword [esp+32], 0 |
; okay, we found the correct one |
mov eax, ebx |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_set_options |
; |
; IN: ecx = socket number |
; edx = pointer to the options: |
; dd level, optname, optlen, optval |
; OUT: -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_set_opt: |
DEBUGF 2,"SOCKET_set_opt\n" |
call SOCKET_num_to_ptr |
jz s_error |
cmp dword [edx], SOL_SOCKET |
jne s_error |
cmp dword [edx+4], SO_BINDTODEVICE |
je .bind |
cmp dword [edx+4], SO_BLOCK |
je .block |
jmp s_error |
.bind: |
cmp dword [edx+8], 0 |
je .unbind |
movzx edx, byte [edx + 9] |
cmp edx, MAX_NET_DEVICES |
ja s_error |
mov edx, [NET_DRV_LIST + 4*edx] |
test edx, edx |
jz s_error |
mov [eax + SOCKET.device], edx |
DEBUGF 1,"SOCKET_set_opt: Bound socket %x to device %x\n",eax, edx |
mov dword [esp+32], 0 ; success! |
.error: |
xor eax, eax |
ret |
endp |
.unbind: |
mov [eax + SOCKET.device], 0 |
mov dword [esp+32], 0 ; success! |
ret |
.block: |
cmp dword [edx+8], 0 |
je .unblock |
and [eax + SOCKET.options], not SO_NONBLOCK |
mov dword [esp+32], 0 ; success! |
ret |
.unblock: |
or [eax + SOCKET.options], SO_NONBLOCK |
mov dword [esp+32], 0 ; success! |
ret |
;----------------------------------------------------------------- |
;; Get socket number by its structure address |
; Scan through sockets list to find the socket with specified address. |
; This proc uses SOCKET.PID indirectly to check if socket is owned by |
; calling process. |
; |
; SOCKET_pair |
; |
; Allocates a pair of linked LOCAL domain sockets |
; |
; IN: / |
; OUT: eax is socket1 num, -1 on error |
; ebx is socket2 num |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_pair: |
; @param sockAddr is a socket structure address |
; @return socket number (SOCKET.Number) or 0 (not found) in EAX |
;; |
proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD |
mov eax, [sockAddr] |
; check if we got something similar to socket structure address |
or eax, eax |
jz .error |
DEBUGF 2,"SOCKET_pair\n" |
call SOCKET_alloc |
jz s_error |
mov [esp+32], edi ; application's eax |
mov [eax + SOCKET.Domain], AF_LOCAL |
mov [eax + SOCKET.Type], SOCK_STREAM |
mov [eax + SOCKET.Protocol], 0 ;;; CHECKME |
mov [eax + SOCKET.snd_proc], SOCKET_send_local |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_local |
mov [eax + SOCKET.PID], 0 |
mov ebx, eax |
call SOCKET_alloc |
; scan through sockets list |
mov ebx, net_sockets |
;mov ecx, [TASK_BASE] |
;mov ecx, [ecx + TASKDATA.pid] |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .error |
mov [esp+24], edi ; application's ebx |
cmp ebx, eax |
jne .next_socket |
;cmp [ebx + SOCKET.PID], ecx |
;jne .next_socket |
mov [eax + SOCKET.Domain], AF_LOCAL |
mov [eax + SOCKET.Type], SOCK_STREAM |
mov [eax + SOCKET.Protocol], 0 ;;; CHECKME |
mov [eax + SOCKET.snd_proc], SOCKET_send_local |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_local |
mov [eax + SOCKET.PID], 0 |
; Link the two sockets to eachother |
mov [eax + SOCKET.device], ebx |
mov [ebx + SOCKET.device], eax |
lea eax, [eax + STREAM_SOCKET.rcv] |
call SOCKET_ring_create |
lea eax, [ebx + STREAM_SOCKET.rcv] |
call SOCKET_ring_create |
pop eax |
; okay, we found the correct one |
mov eax, [ebx + SOCKET.Number] |
ret |
.error: |
mov eax, ebx |
call SOCKET_free |
jmp s_error |
xor eax, eax |
ret |
endp |
;----------------------------------------------------------------- |
;; [53.9] Check if local port is used by any socket in the system. |
; Scan through sockets list, checking SOCKET.LocalPort. |
; Useful when you want a to generate a unique local port number. |
; This proc doesn't guarantee that after calling it and trying to use |
; the port reported being free in calls to socket_open/socket_open_tcp it'll |
; still be free or otherwise it'll still be used if reported being in use. |
; |
; SOCKET_debug |
; |
; Copies socket variables to application buffer |
; |
; IN: ecx = socket number |
; edx = pointer to buffer |
; |
; OUT: -1 on error |
;----------------------------------------------------------------- |
align 4 |
SOCKET_debug: |
DEBUGF 1,"SOCKET_debug\n" |
mov edi, edx |
test ecx, ecx |
jz .returnall |
call SOCKET_num_to_ptr |
jz s_error |
mov esi, eax |
mov ecx, SOCKETBUFFSIZE/4 |
rep movsd |
mov dword [esp+32], 0 |
; @param BX is a port number |
; @return 1 (port is free) or 0 (port is in use) in EAX |
;; |
proc is_localport_unused stdcall |
movzx ebx, bx |
mov eax, [network_free_ports] |
bt [eax], ebx |
setc al |
movzx eax, al |
ret |
endp |
.returnall: |
mov ebx, net_sockets |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
;====================================== |
set_local_port: |
;-------------------------------------- |
;? Set local port in socket structure. |
;-------------------------------------- |
;> eax -> struct SOCKET |
;> bx = local port, or 0 if the kernel must select it itself |
;-------------------------------------- |
;< CF set on error / cleared on success |
;< [eax+SOCKET.LocalPort] filled on success |
;====================================== |
; 0. Prepare: save registers, make eax point to ports table, expand port to ebx. |
push eax ecx |
mov eax, [network_free_ports] |
movzx ebx, bx |
; 1. Test, whether the kernel should choose port itself. If no, proceed to 5. |
test ebx, ebx |
jz .done |
mov eax, [ebx + SOCKET.Number] |
stosd |
jmp .next_socket |
.done: |
xor eax, eax |
stosd |
mov dword [esp+32], 0 |
jnz .given |
; 2. Yes, it should. Set ecx = limit of table, eax = start value |
lea ecx, [eax+0x10000/8] |
add eax, [network_free_hint] |
; 3. First scan loop: from free hint to end of table. |
.scan1: |
; 3a. For each dword, find bit set to 1 |
bsf ebx, [eax] |
jz .next1 |
; 3b. If such bit has been found, atomically test again and clear it. |
lock btr [eax], ebx |
; 3c. If the bit was still set (usual case), we have found and reserved one port. |
; Proceed to 6. |
jc .found |
; 3d. Otherwise, someone has reserved it between bsf and btr, so retry search. |
jmp .scan1 |
.next1: |
; 3e. All bits are cleared, so advance to next dword. |
add eax, 4 |
; 3f. Check limit and continue loop. |
cmp eax, ecx |
jb .scan1 |
; 4. Second scan loop: from port 1024 (start of non-system ports) to free hint. |
mov eax, [network_free_ports] |
mov ecx, eax |
add ecx, [network_free_hint] |
add eax, 1024/8 |
; 4a. Test whether there is something to scan. |
cmp eax, ecx |
jae .fail |
; 4b. Enter the loop, the process is same as for 3. |
.scan2: |
bsf ebx, [eax] |
jz .next2 |
lock btr [eax], ebx |
jc .found |
jmp .scan2 |
.next2: |
add eax, 4 |
cmp eax, ecx |
jb .scan2 |
; 4c. None found. Fail. |
.fail: |
pop ecx eax |
stc |
ret |
; 5. No, the kernel should reserve selected port. |
.given: |
; 5a. Atomically test old value and clear bit. |
lock btr [eax], ebx |
; 5b. If the bit was set, reservation is successful. Proceed to 8. |
jc .set |
; 5c. Otherwise, fail. |
jmp .fail |
.found: |
; 6. We have found the bit set to 1, convert the position to port number. |
sub eax, [network_free_ports] |
lea ebx, [ebx+eax*8] |
; 7. Update free hint. |
add eax, 4 |
cmp eax, 65536/8 |
jb @f |
mov eax, 1024/8 |
@@: |
mov [network_free_hint], eax |
.set: |
; 8. Restore eax, set SOCKET.LocalPort and return. |
pop ecx eax |
xchg bl, bh ; Intel -> network byte order |
mov [eax + SOCKET.LocalPort], bx |
clc |
ret |
;----------------------------------------------------------------- |
;; [53.0] Open DGRAM socket (connectionless, unreliable) |
; |
; SOCKET_find_port |
; |
; Fills in the local port number for TCP and UDP sockets |
; This procedure always works because the number of sockets is |
; limited to a smaller number then the number of possible ports |
; |
; IN: eax = socket pointer |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_find_port: |
; @param BX is local port number |
; @param CX is remote port number |
; @param EDX is remote IP address |
; @return socket number or -1 (error) in EAX |
;; |
proc socket_open stdcall |
call net_socket_alloc |
or eax, eax |
jz .error |
DEBUGF 2,"SOCKET_find_port\n" |
DEBUGF 1, "K : socket_open (0x%x)\n", eax |
push ebx esi ecx |
push eax |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
je .udp |
call set_local_port |
jc .error.free |
xchg ch, cl |
mov [eax + SOCKET.RemotePort], cx |
mov ebx, [stack_ip] |
mov [eax + SOCKET.LocalIP], ebx |
mov [eax + SOCKET.RemoteIP], edx |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
pop ecx esi ebx |
;pop eax ; Get the socket number back, so we can return it |
stdcall net_socket_addr_to_num |
ret |
.udp: |
mov bx, [last_UDP_port] |
call .findit |
mov [last_UDP_port], bx |
.error.free: |
stdcall net_socket_free;, eax |
pop ecx esi ebx |
.error: |
DEBUGF 1, "K : socket_open (fail)\n" |
or eax, -1 |
ret |
endp |
.tcp: |
mov bx, [last_TCP_port] |
call .findit |
mov [last_TCP_port], bx |
pop ecx esi ebx |
ret |
.restart: |
mov bx, MIN_EPHEMERAL_PORT_N |
.findit: |
cmp bx, MAX_EPHEMERAL_PORT_N |
je .restart |
add bh, 1 |
adc bl, 0 |
call SOCKET_check_port |
jz .findit |
ret |
;----------------------------------------------------------------- |
;; [53.5] Open STREAM socket (connection-based, sequenced, reliable, two-way) |
; |
; SOCKET_check_port (to be used with AF_INET only!) |
; |
; Checks if a local port number is unused |
; If the proposed port number is unused, it is filled in in the socket structure |
; |
; IN: eax = socket ptr (to find out if its a TCP/UDP socket) |
; bx = proposed socket number (network byte order) |
; |
; OUT: ZF = set on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_check_port: |
; @param BX is local port number |
; @param CX is remote port number |
; @param EDX is remote IP address |
; @param ESI is open mode (SOCKET_ACTIVE, SOCKET_PASSIVE) |
; @return socket number or -1 (error) in EAX |
;; |
proc socket_open_tcp stdcall |
local sockAddr dd ? |
DEBUGF 2,"SOCKET_check_port: " |
cmp esi, SOCKET_PASSIVE |
jne .skip_port_check |
mov ecx, [eax + SOCKET.Protocol] |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov esi, net_sockets |
push ebx |
mov eax, ebx |
xchg al, ah |
mov ebx, net_sockets |
.next_socket: |
mov esi, [esi + SOCKET.NextPtr] |
or esi, esi |
jz .port_ok |
cmp [esi + SOCKET.Protocol], ecx |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .last_socket |
cmp [ebx + SOCKET.TCBState], TCB_LISTEN |
jne .next_socket |
cmp [esi + IP_SOCKET.LocalIP], edx |
cmp [ebx + SOCKET.LocalPort], ax |
jne .next_socket |
cmp [esi + UDP_SOCKET.LocalPort], bx |
jne .next_socket |
xchg al, ah |
DEBUGF 1, "K : error: port %u is listened by 0x%x\n", ax, ebx |
pop ebx |
jmp .error |
DEBUGF 2,"local port %x already in use\n", bx ; FIXME: find a way to print big endian values with debugf |
ret |
.last_socket: |
pop ebx |
.port_ok: |
DEBUGF 2,"local port %x is free\n", bx ; FIXME: find a way to print big endian values with debugf |
mov [eax + UDP_SOCKET.LocalPort], bx |
or bx, bx ; clear the zero-flag |
ret |
.skip_port_check: |
call net_socket_alloc |
or eax, eax |
jz .error |
DEBUGF 1, "K : socket_open_tcp (0x%x)\n", eax |
mov [sockAddr], eax |
;----------------------------------------------------------------- |
; |
; SOCKET_input |
; |
; Updates a (stateless) socket with received data |
; |
; Note: the mutex should already be set ! |
; |
; IN: eax = socket ptr |
; ecx = data size |
; esi = ptr to data |
; [esp] = ptr to buf |
; [esp + 4] = buf size |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_input: |
; TODO - check this works! |
;mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer. |
DEBUGF 2,"SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx |
call set_local_port |
jc .error.free |
xchg ch, cl |
mov [eax + SOCKET.RemotePort], cx |
mov [eax + SOCKET.OrigRemotePort], cx |
mov ebx, [stack_ip] |
mov [eax + SOCKET.LocalIP], ebx |
mov [eax + SOCKET.RemoteIP], edx |
mov [eax + SOCKET.OrigRemoteIP], edx |
mov [esp+4], ecx |
push esi |
mov esi, esp |
mov ebx, TCB_LISTEN |
cmp esi, SOCKET_PASSIVE |
je @f |
mov ebx, TCB_SYN_SENT |
@@: |
mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB |
add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, SOCKET_input.full |
cmp ebx, TCB_LISTEN |
je .exit |
DEBUGF 1,"SOCKET_input: success\n" |
add esp, sizeof.socket_queue_entry |
; 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 .exit |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
popa |
push eax |
jmp SOCKET_notify |
mov bl, TH_SYN |
xor ecx, ecx |
stdcall build_tcp_packet, [sockAddr] |
.full: |
DEBUGF 2,"SOCKET_input: socket %x is full!\n", eax |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
popa |
.not_local: |
; Send it. |
pop ebx |
call queue |
call kernel_free |
add esp, 8 |
mov esi, [sockAddr] |
; increment SND.NXT in socket |
add esi, SOCKET.SND_NXT |
call inc_inet_esi |
.exit: |
; Get the socket number back, so we can return it |
stdcall net_socket_addr_to_num, [sockAddr] |
ret |
.error.free: |
stdcall net_socket_free, eax |
;-------------------------- |
; |
; eax = ptr to ring struct (just a buffer of the right size) |
; |
align 4 |
SOCKET_ring_create: |
push esi |
mov esi, eax |
push edx |
stdcall create_ring_buffer, SOCKET_MAXDATA, PG_SW |
pop edx |
DEBUGF 1,"SOCKET_ring_created: %x\n", eax |
pusha |
lea ecx, [esi + RING_BUFFER.mutex] |
call mutex_init |
popa |
mov [esi + RING_BUFFER.start_ptr], eax |
mov [esi + RING_BUFFER.write_ptr], eax |
mov [esi + RING_BUFFER.read_ptr], eax |
mov [esi + RING_BUFFER.size], 0 |
add eax, SOCKET_MAXDATA |
mov [esi + RING_BUFFER.end_ptr], eax |
mov eax, esi |
pop esi |
.error: |
DEBUGF 1, "K : socket_open_tcp (fail)\n" |
or eax, -1 |
ret |
endp |
;----------------------------------------------------------------- |
;; [53.1] Close DGRAM socket |
; |
; SOCKET_ring_write |
; |
; Adds data to a stream socket, and updates write pointer and size |
; |
; IN: eax = ptr to ring struct |
; ecx = data size |
; esi = ptr to data |
; |
; OUT: ecx = number of bytes stored |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_ring_write: |
; @param EBX is socket number |
; @return 0 (closed successfully) or -1 (error) in EAX |
;; |
proc socket_close stdcall |
DEBUGF 1, "K : socket_close (0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
DEBUGF 1,"SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx |
stdcall net_socket_free, eax |
; lock mutex |
pusha |
lea ecx, [eax + RING_BUFFER.mutex] |
call mutex_lock ; TODO: check what registers this function actually destroys |
popa |
xor eax, eax |
ret |
; calculate available size |
mov edi, SOCKET_MAXDATA |
sub edi, [eax + RING_BUFFER.size] ; available buffer size in edi |
cmp ecx, edi |
jbe .copy |
mov ecx, edi |
.copy: |
mov edi, [eax + RING_BUFFER.write_ptr] |
DEBUGF 2,"SOCKET_ring_write: %u bytes from %x to %x\n", ecx, esi, edi |
; update write ptr |
push edi |
add edi, ecx |
cmp edi, [eax + RING_BUFFER.end_ptr] |
jb @f |
sub edi, SOCKET_MAXDATA ; WRAP |
@@: |
mov [eax + RING_BUFFER.write_ptr], edi |
pop edi |
; update size |
add [eax + RING_BUFFER.size], ecx |
; copy the data |
push ecx |
shr ecx, 1 |
jnc .nb |
movsb |
.nb: |
shr ecx, 1 |
jnc .nw |
movsw |
.nw: |
test ecx, ecx |
jz .nd |
rep movsd |
.nd: |
pop ecx |
; unlock mutex |
push eax ecx |
lea ecx, [eax + RING_BUFFER.mutex] |
call mutex_unlock ; TODO: check what registers this function actually destroys |
pop ecx eax |
.error: |
DEBUGF 1, "K : socket_close (fail)\n" |
or eax, -1 |
ret |
endp |
;----------------------------------------------------------------- |
;; [53.8] Close STREAM socket |
; Closing TCP sockets takes time, so when you get successful return code |
; from this function doesn't always mean that socket is actually closed. |
; |
; SOCKET_ring_read |
; |
; IN: eax = ring struct ptr |
; ecx = bytes to read |
; edx = offset |
; edi = ptr to buffer start |
; |
; OUT: eax = unchanged |
; ecx = number of bytes read (0 on error) |
; edx = destroyed |
; esi = destroyed |
; edi = ptr to buffer end |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_ring_read: |
; @param EBX is socket number |
; @return 0 (closed successfully) or -1 (error) in EAX |
;; |
proc socket_close_tcp stdcall |
local sockAddr dd ? |
DEBUGF 1,"SOCKET_ring_read: ringbuff=%x ptr=%x size=%u offset=%x\n", eax, edi, ecx, edx |
DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx |
; first, remove any resend entries |
pusha |
lea ecx, [eax + RING_BUFFER.mutex] |
call mutex_lock ; TODO: check what registers this function actually destroys |
popa |
mov esi, [eax + RING_BUFFER.read_ptr] |
add esi, edx ; esi = start_ptr + offset |
mov esi, resendQ |
mov ecx, 0 |
neg edx |
add edx, [eax + RING_BUFFER.size] ; edx = snd.size - offset |
jle .no_data_at_all |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je .last_resendq ; None left |
cmp [esi + 4], ebx |
je @f ; found one |
inc ecx |
add esi, 8 |
jmp .next_resendq |
pusha |
lea ecx, [eax + RING_BUFFER.mutex] |
call mutex_unlock ; TODO: check what registers this function actually destroys |
popa |
@@: |
mov dword[esi + 4], 0 |
inc ecx |
add esi, 8 |
jmp .next_resendq |
cmp ecx, edx |
ja .less_data |
.copy: |
DEBUGF 2,"SOCKET_ring_read: %u bytes from %x to %x\n", ecx, esi, edi |
push ecx |
shr ecx, 1 |
jnc .nb |
movsb |
.nb: |
shr ecx, 1 |
jnc .nw |
movsw |
.nw: |
test ecx, ecx |
jz .nd |
rep movsd |
.nd: |
pop ecx |
ret |
.no_data_at_all: |
pusha |
lea ecx, [eax + RING_BUFFER.mutex] |
call mutex_unlock ; TODO: check what registers this function actually destroys |
.last_resendq: |
popa |
DEBUGF 1,"SOCKET_ring_read: no data at all!\n" |
xor ecx, ecx |
ret |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
.less_data: |
mov ecx, edx |
jmp .copy |
mov ebx, eax |
mov [sockAddr], eax |
cmp [ebx + SOCKET.TCBState], TCB_LISTEN |
je .destroy_tcb |
cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT |
je .destroy_tcb |
cmp [ebx + SOCKET.TCBState], TCB_CLOSED |
je .destroy_tcb |
;----------------------------------------------------------------- |
; |
; SOCKET_ring_free |
; |
; Free's some bytes from the ringbuffer |
; |
; IN: eax = ptr to ring struct |
; ecx = data size |
; |
; OUT: ecx = number of bytes free-ed |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_ring_free: |
; Now construct the response, and queue for sending by IP |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je .error |
DEBUGF 1,"SOCKET_ring_free: %u bytes from ring %x\n", ecx, eax |
push eax ecx |
lea ecx, [eax + RING_BUFFER.mutex] |
call mutex_lock ; TODO: check what registers this function actually destroys |
pop ecx eax |
sub [eax + RING_BUFFER.size], ecx |
jb .error |
add [eax + RING_BUFFER.read_ptr], ecx |
mov edx, [eax + RING_BUFFER.end_ptr] |
cmp [eax + RING_BUFFER.read_ptr], edx |
jb @f |
sub [eax + RING_BUFFER.read_ptr], SOCKET_MAXDATA |
@@: |
push eax ecx |
lea ecx, [eax + RING_BUFFER.mutex] ; TODO: check what registers this function actually destroys |
call mutex_unlock |
pop ecx eax |
ret |
.error: ; we could free all available bytes, but that would be stupid, i guess.. |
DEBUGF 1,"SOCKET_ring_free: buffer=%x error!\n", eax |
add [eax + RING_BUFFER.size], ecx |
push eax |
lea ecx, [eax + RING_BUFFER.mutex] |
call mutex_unlock ; TODO: check what registers this function actually destroys |
pop eax |
mov bl, TH_FIN+TH_ACK |
xor ecx, ecx |
ret |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
mov ebx, [sockAddr] |
; increament SND.NXT in socket |
lea esi, [ebx + SOCKET.SND_NXT] |
call inc_inet_esi |
;----------------------------------------------------------------- |
; |
; SOCKET_block |
; |
; Suspends the thread attached to a socket |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_block: |
; Get the socket state |
mov eax, [ebx + SOCKET.TCBState] |
cmp eax, TCB_SYN_RECEIVED |
je .fin_wait_1 |
cmp eax, TCB_ESTABLISHED |
je .fin_wait_1 |
DEBUGF 1,"SOCKET_block: %x\n", eax |
; assume CLOSE WAIT |
; Send a fin, then enter last-ack state |
mov [ebx + SOCKET.TCBState], TCB_LAST_ACK |
jmp .send |
pushf |
cli |
.fin_wait_1: |
; Send a fin, then enter finwait2 state |
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1 |
; Set the 'socket is blocked' flag |
or [eax + SOCKET.state], SS_BLOCKED |
.send: |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
; Suspend the thread |
push edx |
mov edx, [TASK_BASE] |
mov [edx + TASKDATA.state], 1 ; Suspended |
.not_local: |
; Send it. |
pop ebx |
call queue |
jmp .exit |
; Remember the thread ID so we can wake it up again |
mov edx, [edx + TASKDATA.pid] |
DEBUGF 1,"SOCKET_block: suspending thread: %u\n", edx |
mov [eax + SOCKET.TID], edx |
pop edx |
.destroy_tcb: |
call change_task |
popf |
; Clear the socket variables |
stdcall net_socket_free, ebx |
DEBUGF 1,"SOCKET_block: continueing\n" |
.exit: |
xor eax, eax |
ret |
.error: |
DEBUGF 1, "K : socket_close_tcp (fail)\n" |
or eax, -1 |
ret |
endp |
;----------------------------------------------------------------- |
;; [53.2] Poll socket |
; |
; SOCKET_notify |
; |
; notify's the owner of a socket that something happened |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_notify: |
DEBUGF 1,"SOCKET_notify: %x\n", eax |
call SOCKET_check |
; @param EBX is socket number |
; @return count or bytes in rx buffer or 0 (error) in EAX |
;; |
proc socket_poll stdcall |
; DEBUGF 1, "socket_poll(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
test [eax + SOCKET.state], SS_BLOCKED |
jnz .unblock |
mov eax, [eax + SOCKET.rxDataCount] |
ret |
test [eax + SOCKET.options], SO_NONBLOCK |
jz .error |
.error: |
xor eax, eax |
ret |
endp |
push eax ecx esi |
; socket exists and is of non blocking type. |
; We'll try to flag an event to the thread |
mov eax, [eax + SOCKET.TID] |
test eax, eax |
jz .done |
mov ecx, 1 |
mov esi, TASK_DATA + TASKDATA.pid |
.next_pid: |
cmp [esi], eax |
je .found_pid |
inc ecx |
add esi, 0x20 |
cmp ecx, [TASK_COUNT] |
jbe .next_pid |
; PID not found, TODO: close socket! |
jmp .done |
.found_pid: |
shl ecx, 8 |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK |
DEBUGF 1,"SOCKET_notify: Raised a network event!\n" |
jmp .done |
.unblock: |
push eax ecx esi |
; Clear the 'socket is blocked' flag |
and [eax + SOCKET.state], not SS_BLOCKED |
; Find the thread's TASK_DATA |
mov eax, [eax + SOCKET.TID] |
test eax, eax |
;; [53.6] Get socket TCB state |
; |
; @param EBX is socket number |
; @return socket TCB state or 0 (error) in EAX |
;; |
proc socket_status stdcall |
;; DEBUGF 1, "socket_status(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
xor ecx, ecx |
inc ecx |
mov esi, TASK_DATA |
.next: |
cmp [esi + TASKDATA.pid], eax |
je .found |
inc ecx |
add esi, 0x20 |
cmp ecx, [TASK_COUNT] |
jbe .next |
jmp .error |
.found: |
; Run the thread |
mov [esi + TASKDATA.state], 0 ; Running |
DEBUGF 1,"SOCKET_notify: Unblocked socket!\n" |
mov eax, [eax + SOCKET.TCBState] |
ret |
.done: |
pop esi ecx eax |
.error: |
xor eax, eax |
ret |
endp |
;-------------------------------------------------------------------- |
;; [53.3] Get one byte from rx buffer |
; This function can return 0 in two cases: if there's one byte read and |
; non left, and if an error occured. Behavior should be changed and function |
; shouldn't be used for now. Consider using [53.11] instead. |
; |
; SOCKET_alloc |
; |
; Allocate memory for socket data and put new socket into the list |
; Newly created socket is initialized with calling PID and number and |
; put into beginning of list (which is a fastest way). |
; |
; IN: / |
; OUT: eax = 0 on error, socket ptr otherwise |
; edi = socket number |
; ZF = cleared on error |
; |
;-------------------------------------------------------------------- |
align 4 |
SOCKET_alloc: |
push ebx |
stdcall kernel_alloc, SOCKETBUFFSIZE |
DEBUGF 1, "SOCKET_alloc: ptr=%x\n", eax |
; @param EBX is socket number |
; @return number of bytes left in rx buffer or 0 (error) in EAX |
; @return byte read in BL |
;; |
proc socket_read stdcall |
; DEBUGF 1, "socket_read(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .exit |
jz .error |
; zero-initialize allocated memory |
push eax |
mov edi, eax |
mov ecx, SOCKETBUFFSIZE / 4 |
xor eax, eax |
rep stosd |
pop eax |
; set send-and receive procedures to return -1 |
mov [eax + SOCKET.snd_proc], s_error |
mov [eax + SOCKET.rcv_proc], s_error |
; find first free socket number and use it |
mov edi, [last_socket_num] |
.next_socket_number: |
inc edi |
jz .next_socket_number ; avoid socket nr 0 |
cmp edi, -1 |
je .next_socket_number ; avoid socket nr -1 |
mov ebx, net_sockets |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
test ebx, ebx |
jz .last_socket |
cmp [ebx + SOCKET.Number], edi |
jne .next_socket |
jmp .next_socket_number |
.last_socket: |
mov [last_socket_num], edi |
mov [eax + SOCKET.Number], edi |
DEBUGF 1, "SOCKET_alloc: number=%u\n", edi |
; Fill in PID |
mov ebx, [TASK_BASE] |
mov ebx, [ebx + TASKDATA.pid] |
mov [eax + SOCKET.PID], ebx |
mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :( |
; init mutex |
pusha |
mov ebx, eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_init |
popa |
call mutex_lock |
; add socket to the list by re-arranging some pointers |
mov ebx, [net_sockets + SOCKET.NextPtr] |
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
test eax, eax |
jz .error_release |
mov [eax + SOCKET.PrevPtr], net_sockets |
mov [eax + SOCKET.NextPtr], ebx |
dec eax |
mov esi, ebx ; esi is address of socket |
mov [ebx + SOCKET.rxDataCount], eax ; store new count |
movzx eax, byte[ebx + SOCKET.rxData] ; get the byte |
test ebx, ebx |
jz @f |
mov ecx, SOCKETBUFFSIZE - SOCKET.rxData - 1 |
lea edi, [esi + SOCKET.rxData] |
lea esi, [edi + 1] |
cld |
push ecx |
shr ecx, 2 |
rep movsd |
pop ecx |
and ecx, 3 |
rep movsb |
pusha |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_lock |
popa |
mov ebx, eax |
call mutex_unlock |
mov eax, ebx |
ret |
mov [ebx + SOCKET.PrevPtr], eax |
pusha |
.error_release: |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
popa |
@@: |
mov [net_sockets + SOCKET.NextPtr], eax |
or eax, eax ; used to clear zero flag |
.exit: |
pop ebx |
.error: |
xor ebx, ebx |
xor eax, eax |
ret |
endp |
;---------------------------------------------------- |
;; [53.11] Get specified number of bytes from rx buffer |
; Number of bytes in rx buffer can be less than requested size. In this case, |
; only available number of bytes is read. |
; This function can return 0 in two cases: if there's no data to read, and if |
; an error occured. Behavior should be changed. |
; |
; SOCKET_free |
; |
; Free socket data memory and remove socket from the list |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;---------------------------------------------------- |
align 4 |
SOCKET_free: |
DEBUGF 1, "SOCKET_free: %x\n", eax |
call SOCKET_check |
; @param EBX is socket number |
; @param ECX is pointer to application buffer |
; @param EDX is application buffer size (number of bytes to read) |
; @return number of bytes read or 0 (error) in EAX |
;; |
proc socket_read_packet stdcall |
; DEBUGF 1, "socket_read_packet(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx ; get real socket address |
or eax, eax |
jz .error |
push ebx |
mov ebx, eax |
pusha |
push ecx edx |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pop edx ecx |
cmp [eax + SOCKET.Domain], AF_INET4 |
jnz .no_tcp |
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
test eax, eax ; if count of bytes is zero.. |
jz .exit ; exit function (eax will be zero) |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
jnz .no_tcp |
test edx, edx ; if buffer size is zero, copy all data |
jz .copy_all_bytes |
cmp edx, eax ; if buffer size is larger then the bytes of data, copy all data |
jge .copy_all_bytes |
sub eax, edx ; store new count (data bytes in buffer - bytes we're about to copy) |
mov [ebx + SOCKET.rxDataCount], eax ; |
push eax |
mov eax, edx ; number of bytes we want to copy must be in eax |
call .start_copy ; copy to the application |
mov esi, ebx ; now we're going to copy the remaining bytes to the beginning |
add esi, SOCKET.rxData ; we dont need to copy the header |
mov edi, esi ; edi is where we're going to copy to |
add esi, edx ; esi is from where we copy |
pop ecx ; count of bytes we have left |
push ecx ; push it again so we can re-use it later |
shr ecx, 2 ; divide eax by 4 |
cld |
rep movsd ; copy all full dwords |
pop ecx |
and ecx, 3 |
rep movsb ; copy remaining bytes |
.exit: |
lea ecx, [ebx + SOCKET.mutex] |
mov ebx, eax |
stdcall kernel_free, [ebx + STREAM_SOCKET.rcv.start_ptr] |
stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr] |
call mutex_unlock |
mov eax, ebx |
.no_tcp: |
ret ; at last, exit |
push eax ; this will be passed to kernel_free |
mov ebx, [eax + SOCKET.NextPtr] |
mov eax, [eax + SOCKET.PrevPtr] |
DEBUGF 1, "SOCKET_free: linking socket %x to socket %x\n", eax, ebx |
test eax, eax |
jz @f |
mov [eax + SOCKET.NextPtr], ebx |
@@: |
test ebx, ebx |
jz @f |
mov [ebx + SOCKET.PrevPtr], eax |
@@: |
call kernel_free |
pop ebx |
DEBUGF 1, "SOCKET_free: success!\n" |
.error: |
xor eax, eax |
ret |
;------------------------------------ |
; |
; SOCKET_fork |
; |
; Create a child socket |
; |
; IN: socket nr in ebx |
; OUT: child socket nr in eax |
; |
;----------------------------------- |
align 4 |
SOCKET_fork: |
.copy_all_bytes: |
xor esi, esi |
mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero) |
call .start_copy |
lea ecx, [ebx + SOCKET.mutex] |
mov ebx, eax |
call mutex_unlock |
mov eax, ebx |
ret |
DEBUGF 1,"SOCKET_fork: %x\n", ebx |
; Exit if backlog queue is full |
mov eax, [ebx + SOCKET_QUEUE_LOCATION + queue.size] |
cmp ax, [ebx + SOCKET.backlog] |
jae .fail |
; Allocate new socket |
push ebx |
call SOCKET_alloc |
pop ebx |
jz .fail |
push eax |
mov esi, esp |
add_to_queue (ebx + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .fail2 |
pop eax |
; Copy structure from current socket to new |
; We start at PID to preserve the socket num, and the 2 pointers at beginning of socket |
lea esi, [ebx + SOCKET.PID] |
lea edi, [eax + SOCKET.PID] |
mov ecx, (SOCKET_QUEUE_LOCATION - SOCKET.PID + 3)/4 |
.start_copy: |
mov edi, ecx |
mov esi, ebx |
add esi, SOCKET.rxData ; we dont need to copy the header |
mov ecx, eax ; eax is count of bytes |
push ecx |
shr ecx, 2 ; divide eax by 4 |
cld ; copy all full dwords |
rep movsd |
pop ecx |
and ecx, 3 |
rep movsb ; copy the rest bytes |
retn ; exit, or go back to shift remaining bytes if any |
endp |
and [eax + SOCKET.options], not SO_ACCEPTCON |
ret |
.fail2: |
add esp, 4+4+4 |
.fail: |
DEBUGF 1,"SOCKET_fork: failed\n" |
xor eax, eax |
ret |
;--------------------------------------------------- |
;; [53.4] Send data through DGRAM socket |
; |
; SOCKET_num_to_ptr |
; |
; Get socket structure address by its number |
; |
; IN: ecx = socket number |
; OUT: eax = 0 on error, socket ptr otherwise |
; ZF = set on error |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_num_to_ptr: |
DEBUGF 1,"SOCKET_num_to_ptr: num=%u ", ecx |
mov eax, net_sockets |
.next_socket: |
mov eax, [eax + SOCKET.NextPtr] |
; @param EBX is socket number |
; @param ECX is application data size (number of bytes to send) |
; @param EDX is pointer to application data buffer |
; @return 0 (sent successfully) or -1 (error) in EAX |
;; |
proc socket_write stdcall |
; DEBUGF 1, "socket_write(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx ; get real socket address |
or eax, eax |
jz .error |
cmp [eax + SOCKET.Number], ecx |
jne .next_socket |
test eax, eax |
mov ebx, eax |
DEBUGF 1,"ptr=%x\n", eax |
ret |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je .error |
.error: |
DEBUGF 1,"not found\n", eax |
ret |
; Save the queue entry number |
push eax |
; save the pointers to the data buffer & size |
push edx |
push ecx |
;--------------------------------------------------- |
; |
; SOCKET_ptr_to_num |
; |
; Get socket number by its address |
; |
; IN: eax = socket ptr |
; OUT: eax = 0 on error, socket num otherwise |
; ZF = set on error |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_ptr_to_num: |
; convert buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
DEBUGF 1,"SOCKET_ptr_to_num: ptr=%x ", eax |
mov edx, eax |
call SOCKET_check |
jz .error |
; So, ebx holds the socket ptr, edx holds the IPbuffer ptr |
mov eax, [eax + SOCKET.Number] |
; Fill in the IP header (some data is in the socket descriptor) |
mov eax, [ebx + SOCKET.LocalIP] |
mov [edx + IP_PACKET.SourceAddress], eax |
mov eax, [ebx + SOCKET.RemoteIP] |
mov [edx + IP_PACKET.DestinationAddress], eax |
DEBUGF 1,"num=%u\n", eax |
ret |
mov [edx + IP_PACKET.VersionAndIHL], 0x45 |
mov [edx + IP_PACKET.TypeOfService], 0 |
.error: |
DEBUGF 1,"not found\n", eax |
ret |
pop eax ; Get the UDP data length |
push eax |
add eax, 20 + 8 ; add IP header and UDP header lengths |
xchg al, ah |
mov [edx + IP_PACKET.TotalLength], ax |
xor eax, eax |
mov [edx + IP_PACKET.Identification], ax |
mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040 |
mov [edx + IP_PACKET.TimeToLive], 0x20 |
mov [edx + IP_PACKET.Protocol], PROTOCOL_UDP |
;--------------------------------------------------- |
; |
; SOCKET_check |
; |
; checks if the given value is really a socket ptr |
; |
; IN: eax = socket ptr |
; OUT: eax = 0 on error, unchanged otherwise |
; ZF = set on error |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_check: |
; Checksum left unfilled |
mov [edx + IP_PACKET.HeaderChecksum], ax |
DEBUGF 1,"SOCKET_check: %x\n", eax |
; Fill in the UDP header (some data is in the socket descriptor) |
mov ax, [ebx + SOCKET.LocalPort] |
mov [edx + 20 + UDP_PACKET.SourcePort], ax |
push ebx |
mov ebx, net_sockets |
mov ax, [ebx + SOCKET.RemotePort] |
mov [edx + 20 + UDP_PACKET.DestinationPort], ax |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .done |
cmp ebx, eax |
jnz .next_socket |
pop eax |
push eax |
.done: |
mov eax, ebx |
test eax, eax |
pop ebx |
add eax, 8 |
xchg al, ah |
mov [edx + 20 + UDP_PACKET.Length], ax |
ret |
; Checksum left unfilled |
xor eax, eax |
mov [edx + 20 + UDP_PACKET.Checksum], 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, [TASK_BASE] |
add edi, TASKDATA.mem_start |
add eax, [edi] |
mov esi, eax |
;--------------------------------------------------- |
; |
; SOCKET_check_owner |
; |
; checks if the caller application owns the socket |
; |
; IN: eax = socket ptr |
; OUT: ZF = true/false |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_check_owner: |
mov edi, edx |
add edi, 28 |
cld |
rep movsb ; copy the data across |
DEBUGF 1,"SOCKET_check_owner: %x\n", eax |
; we have edx as IPbuffer ptr. |
; Fill in the UDP checksum |
; First, fill in pseudoheader |
mov eax, [edx + IP_PACKET.SourceAddress] |
mov [pseudoHeader], eax |
mov eax, [edx + IP_PACKET.DestinationAddress] |
mov [pseudoHeader + 4], eax |
mov word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0 ; 0 + protocol |
add ebx, 8 |
mov eax, ebx |
xchg al, ah |
mov [pseudoHeader + 10], ax |
push ebx |
mov ebx, [TASK_BASE] |
mov ebx, [ebx + TASKDATA.pid] |
cmp [eax + SOCKET.PID], ebx |
pop ebx |
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 |
ret |
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') |
test ax, ax |
jnz @f |
mov ax, 0xffff |
@@: |
xchg al, ah |
mov [edx + 20 + UDP_PACKET.Checksum], ax |
;------------------------------------------------------ |
; |
; SOCKET_process_end |
; |
; Kernel calls this function when a certain process ends |
; This function will check if the process had any open sockets |
; And update them accordingly |
; |
; IN: edx = pid |
; OUT: / |
; |
;------------------------------------------------------ |
align 4 |
SOCKET_process_end: |
; Fill in the IP header checksum |
GET_IHL ecx,edx ; get IP-Header length |
stdcall checksum_jb, edx, ecx; buf_ptr, buf_size |
xchg al, ah |
mov [edx + IP_PACKET.HeaderChecksum], ax |
DEBUGF 1, "SOCKET_process_end: %x\n", edx |
; Check destination IP address. |
; If it is the local host IP, route it back to IP_RX |
push ebx |
mov ebx, net_sockets |
pop ebx |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
.next_socket_test: |
test ebx, ebx |
jz .done |
mov eax, NET1OUT_QUEUE |
mov ecx, [edx + SOCKET.RemoteIP] |
mov edx, [stack_ip] |
cmp edx, ecx |
jne .not_local |
mov eax, IPIN_QUEUE |
cmp [ebx + SOCKET.PID], edx |
jne .next_socket |
.not_local: |
; Send it. |
call queue |
DEBUGF 1, "SOCKET_process_end: killing socket %x\n", ebx |
xor eax, eax |
ret |
mov [ebx + SOCKET.PID], 0 |
mov eax, ebx |
mov ebx, [ebx + SOCKET.NextPtr] |
pusha |
call SOCKET_close.socket |
popa |
jmp .next_socket_test |
.done: |
pop ebx |
.error: |
or eax, -1 |
ret |
endp |
;----------------------------------------------------------------- |
;; [53.7] Send data through STREAM socket |
; |
; SOCKET_is_connecting |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
; @param EBX is socket number |
; @param ECX is application data size (number of bytes to send) |
; @param EDX is pointer to application data buffer |
; @return 0 (sent successfully) or -1 (error) in EAX |
;; |
proc socket_write_tcp stdcall |
local sockAddr dd ? |
align 4 |
SOCKET_is_connecting: |
; DEBUGF 1, "socket_write_tcp(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
DEBUGF 1,"SOCKET_is_connecting: %x\n", eax |
mov ebx, eax |
mov [sockAddr], ebx |
and [eax + SOCKET.options], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING) |
or [eax + SOCKET.options], SS_ISCONNECTING |
; If the sockets window timer is nonzero, do not queue packet |
cmp [ebx + SOCKET.wndsizeTimer], 0 |
jne .error |
jmp SOCKET_notify |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je .error |
push eax |
; Get the address of the callers data |
mov edi, [TASK_BASE] |
add edi, TASKDATA.mem_start |
add edx, [edi] |
mov esi, edx |
;----------------------------------------------------------------- |
; |
; SOCKET_is_connected |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
pop eax |
push eax |
align 4 |
SOCKET_is_connected: |
push ecx |
mov bl, TH_ACK |
stdcall build_tcp_packet, [sockAddr] |
pop ecx |
DEBUGF 1,"SOCKET_is_connected: %x\n", eax |
; Check destination IP address. |
; If it is the local host IP, route it back to IP_RX |
and [eax + SOCKET.options], not (SS_ISCONNECTING + SS_ISDISCONNECTING + SS_ISCONFIRMING) |
or [eax + SOCKET.options], SS_ISCONNECTED |
pop ebx |
push ecx |
jmp SOCKET_notify |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
.not_local: |
pop ecx |
push ebx ; save ipbuffer number |
call queue |
mov esi, [sockAddr] |
;----------------------------------------------------------------- |
; |
; SOCKET_is_disconnecting |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
; increament SND.NXT in socket |
; Amount to increment by is in ecx |
add esi, SOCKET.SND_NXT |
call add_inet_esi |
align 4 |
SOCKET_is_disconnecting: |
pop ebx |
DEBUGF 1,"SOCKET_is_disconnecting: %x\n", eax |
; 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 |
and [eax + SOCKET.options], not (SS_ISCONNECTING) |
or [eax + SOCKET.options], SS_ISDISCONNECTING + SS_CANTRCVMORE + SS_CANTSENDMORE |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je .exit ; None found |
cmp dword[esi + 4], 0 |
je @f ; found one |
inc ecx |
add esi, 8 |
jmp .next_resendq |
jmp SOCKET_notify |
@@: |
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 |
stdcall net_socket_addr_to_num, [sockAddr] |
mov [esi + 4], eax |
mov byte[esi + 1], TCP_RETRIES |
mov word[esi + 2], TCP_TIMEOUT |
;----------------------------------------------------------------- |
; |
; SOCKET_is_disconnected |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
inc ecx |
; Now get buffer location, and copy buffer across. argh! more copying,, |
mov edi, resendBuffer - IPBUFFSIZE |
align 4 |
SOCKET_is_disconnected: |
@@: |
add edi, IPBUFFSIZE |
loop @b |
DEBUGF 1,"SOCKET_is_disconnected: %x\n", eax |
; 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 |
and [eax + SOCKET.options], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING) |
or [eax + SOCKET.options], SS_CANTRCVMORE + SS_CANTSENDMORE |
; do copy |
mov ecx, IPBUFFSIZE |
cld |
rep movsb |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
.exit: |
xor eax, eax |
ret |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
je .udp |
jmp SOCKET_notify |
.tcp: |
.udp: |
mov [eax + UDP_SOCKET.LocalPort], 0 ; UDP and TCP structs store localport at the same offset |
mov [eax + UDP_SOCKET.RemotePort], 0 |
jmp SOCKET_notify |
;----------------------------------------------------------------- |
; |
; SOCKET_cant_recv_more |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_cant_recv_more: |
DEBUGF 1,"SOCKET_cant_recv_more: %x\n", eax |
or [eax + SOCKET.options], SS_CANTRCVMORE |
.error: |
or eax, -1 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_cant_send_more |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_cant_send_more: |
DEBUGF 1,"SOCKET_cant_send_more: %x\n", eax |
or [eax + SOCKET.options], SS_CANTSENDMORE |
ret |
endp |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/trunk/network/tcp.inc |
---|
1,224 → 1,1176 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Part of the TCP/IP network stack for KolibriOS ;; |
;; TCP.INC ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; TCP Processes for Menuet OS TCP/IP stack ;; |
;; ;; |
;; Based on the code of 4.4BSD ;; |
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 3406 $ |
$Revision$ |
; Socket states |
TCPS_CLOSED = 0 |
TCPS_LISTEN = 1 |
TCPS_SYN_SENT = 2 |
TCPS_SYN_RECEIVED = 3 |
TCPS_ESTABLISHED = 4 |
TCPS_CLOSE_WAIT = 5 |
TCPS_FIN_WAIT_1 = 6 |
TCPS_CLOSING = 7 |
TCPS_LAST_ACK = 8 |
TCPS_FIN_WAIT_2 = 9 |
TCPS_TIMED_WAIT = 10 |
; Socket Flags |
TF_ACKNOW = 1 shl 0 ; ack peer immediately |
TF_DELACK = 1 shl 1 ; ack, but try to delay it |
TF_NODELAY = 1 shl 2 ; don't delay packets to coalesce |
TF_NOOPT = 1 shl 3 ; don't use tcp options |
TF_SENTFIN = 1 shl 4 ; have sent FIN |
TF_REQ_SCALE = 1 shl 5 ; have/will request window scaling |
TF_RCVD_SCALE = 1 shl 6 ; other side has requested scaling |
TF_REQ_TSTMP = 1 shl 7 ; have/will request timestamps |
TF_RCVD_TSTMP = 1 shl 8 ; a timestamp was received in SYN |
TF_SACK_PERMIT = 1 shl 9 ; other side said I could SACK |
; 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_TIMED_WAIT equ 10 |
TCB_CLOSED equ 11 |
; Segment flags |
TH_FIN = 1 shl 0 |
TH_SYN = 1 shl 1 |
TH_RST = 1 shl 2 |
TH_PUSH = 1 shl 3 |
TH_ACK = 1 shl 4 |
TH_URG = 1 shl 5 |
TH_FIN = 0x01 |
TH_SYN = 0x02 |
TH_RST = 0x04 |
TH_PUSH = 0x08 |
TH_ACK = 0x10 |
TH_URG = 0x20 |
; Segment header options |
TCP_OPT_EOL = 0 ; End of option list. |
TCP_OPT_NOP = 1 ; No-Operation. |
TCP_OPT_MAXSEG = 2 ; Maximum Segment Size. |
TCP_OPT_WINDOW = 3 ; window scale |
TCP_OPT_SACK_PERMIT = 4 ; Selective Acknowledgement |
TCP_OPT_SACK = 5 |
TCP_OPT_TIMESTAMP = 8 |
TWOMSL equ 10 ; # of secs to wait before closing socket |
; Fundamental timer values |
TCP_time_MSL = 47 ; max segment lifetime (30s) |
TCP_time_re_min = 2 ; min retransmission (1,28s) |
TCP_time_re_max = 100 ; max retransmission (64s) |
TCP_time_pers_min = 8 ; min persist (5,12s) |
TCP_time_pers_max = 94 ; max persist (60,16s) |
TCP_time_keep_init = 118 ; connection establishment (75,52s) |
TCP_time_keep_idle = 4608 ; idle time before 1st probe (2h) |
TCP_time_keep_interval = 118 ; between probes when no response (75,52s) |
TCP_time_rtt_default = 5 ; default Round Trip Time (3,2s) |
TCP_time_srtt_default = 0 ; |
TCP_time_max_idle = 8*TCP_time_keep_interval ; FIXME |
TCP_RETRIES equ 5 ; Number of times to resend a packet |
TCP_TIMEOUT equ 20 ; resend if not replied to in x hs |
; timer constants |
TCP_max_rxtshift = 12 ; max retransmissions waiting for ACK |
TCP_max_keepcnt = 8 ; max keepalive probes |
;******************************************************************* |
; 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 |
; |
;******************************************************************* |
; TCP Payload ( Data field in IP datagram ) |
; |
TCP_max_winshift = 14 |
TCP_max_win = 65535 |
; 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 |
TCP_re_xmit_thresh = 3 |
TCP_mss_default = 1480 ; default max segment size |
struc TCP_PACKET |
{ .SourcePort dw ? ;+00 |
.DestinationPort dw ? ;+02 |
.SequenceNumber dd ? ;+04 |
.AckNumber dd ? ;+08 |
.DataOffset db ? ;+12 - DataOffset[0-3 bits] and Reserved[4-7] |
.Flags db ? ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN |
.Window dw ? ;+14 |
.Checksum dw ? ;+16 |
.UrgentPointer dw ? ;+18 |
.Options rb 3 ;+20 |
.Padding db ? ;+23 |
.Data db ? ;+24 |
} |
; smoothed round trip time and estimated variance are stored as fixed point numbers, |
; shifted by the value below. |
; With these scales, srtt has 3 bits to the right of the binary point, and thus an "alpha" |
; of .875. rttvar has 2 bits to the right and thus "alpha" of 0.75 |
TCP_RTT_SHIFT = 3 |
TCP_RTTVAR_SHIFT = 2 |
virtual at 0 |
TCP_PACKET TCP_PACKET |
end virtual |
; bits used by tcp_input and tcp_output |
TCP_BIT_NEEDOUTPUT = 1 shl 0 |
TCP_BIT_TIMESTAMP = 1 shl 1 |
TCP_BIT_DROPSOCKET = 1 shl 2 |
TCP_BIT_SENDALOT = 1 shl 0 |
TCP_PAWS_IDLE = 24*24*60*60*100 ; 24 days, in 1/100 seconds |
;*************************************************************************** |
; Function |
; tcp_tcb_handler |
; |
; Description |
; Handles sockets in the timewait state, closing them |
; when the TCB timer expires |
; |
;*************************************************************************** |
TCP_QUEUE_SIZE = 50 |
proc tcp_tcb_handler stdcall uses ebx |
; scan through all the sockets, decrementing active timers |
struct TCP_header |
mov ebx, net_sockets |
SourcePort dw ? |
DestinationPort dw ? |
SequenceNumber dd ? |
AckNumber dd ? |
DataOffset db ? ; DataOffset[0-3 bits] and Reserved[4-7] |
Flags db ? ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN |
Window dw ? |
Checksum dw ? |
UrgentPointer dw ? |
cmp [ebx + SOCKET.NextPtr], 0 |
je .exit |
;DEBUGF 1, "K : sockets:\n" |
ends |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .exit |
struct TCP_queue_entry |
;DEBUGF 1, "K : %x-%x: %x-%x-%x-%u\n", [ebx + SOCKET.PID]:2, [ebx + SOCKET.Number]:2, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState] |
ip_ptr dd ? |
segment_ptr dd ? |
segment_size dd ? |
device_ptr dd ? |
cmp [ebx + SOCKET.TCBTimer], 0 |
jne .decrement_tcb |
cmp [ebx + SOCKET.wndsizeTimer], 0 |
jne .decrement_wnd |
jmp .next_socket |
buffer_ptr dd ? |
timestamp dd ? |
.decrement_tcb: |
; decrement it, delete socket if TCB timer = 0 & socket in timewait state |
dec [ebx + SOCKET.TCBTimer] |
jnz .next_socket |
ends |
cmp [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
jne .next_socket |
align 4 |
uglobal |
TCP_segments_tx rd MAX_NET_DEVICES |
TCP_segments_rx rd MAX_NET_DEVICES |
TCP_segments_missed rd MAX_NET_DEVICES |
TCP_segments_dumped rd MAX_NET_DEVICES |
; TCP_bytes_rx rq MAX_NET_DEVICES |
; TCP_bytes_tx rq MAX_NET_DEVICES |
TCP_sequence_num dd ? |
TCP_queue rd TCP_QUEUE_SIZE*sizeof.TCP_queue_entry/4 |
TCP_input_event dd ? |
endg |
push [ebx + SOCKET.PrevPtr] |
stdcall net_socket_free, ebx |
pop ebx |
jmp .next_socket |
.decrement_wnd: |
; TODO - prove it works! |
dec [ebx + SOCKET.wndsizeTimer] |
jmp .next_socket |
;----------------------------------------------------------------- |
.exit: |
ret |
endp |
;*************************************************************************** |
; Function |
; tcp_tx_handler |
; |
; TCP_init |
; Description |
; Handles queued TCP data |
; This is a kernel function, called by stack_handler |
; |
; This function resets all TCP variables |
; |
;----------------------------------------------------------------- |
macro TCP_init { |
;*************************************************************************** |
xor eax, eax |
mov edi, TCP_segments_tx |
mov ecx, (6*MAX_NET_DEVICES) |
rep stosd |
proc tcp_tx_handler stdcall |
; 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 |
pseudo_random eax |
mov [TCP_sequence_num], eax |
mov esi, resendQ |
mov ecx, 0 |
init_queue TCP_queue |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je .exit ; None left |
cmp dword[esi + 4], 0 |
jne @f ; found one |
inc ecx |
add esi, 8 |
jmp .next_resendq |
push 1 |
@@: ; we have one. decrement it's timer by 1 |
dec word[esi + 2] |
jz @f |
inc ecx |
add esi, 8 |
jmp .next_resendq ; Timer not zero, so move on |
@@: |
xor ebx, ebx |
; 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] |
jnz @f |
; retries now 0, so delete from queue |
xchg [esi + 4], ebx |
@@: ; resend packet |
pushad |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
jne .tth004z |
; TODO - try again in 10ms. |
test ebx, ebx |
jnz @f |
mov [esi + 4], ebx |
@@: ; Mark it to expire in 10ms - 1 tick |
mov byte[esi + 1], 1 |
mov word[esi + 2], 1 |
jmp .tth005 |
.tth004z: |
; we have a buffer # in ax |
push eax ecx |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
; we have the buffer address in eax |
mov edi, eax |
pop ecx |
; Now get buffer location, and copy buffer across. argh! more copying,, |
imul esi, ecx, IPBUFFSIZE |
add esi, resendBuffer |
; we have resend buffer location in esi |
mov ecx, IPBUFFSIZE |
; copy data across |
push edi |
cld |
rep movsb |
pop edi |
; queue packet |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
cmp edx, [edi + IP_PACKET.DestinationAddress] |
jne .not_local |
mov eax, IPIN_QUEUE |
.not_local: |
pop ebx |
mov ecx, TCP_process_input |
call new_sys_threads |
call queue |
} |
.tth005: |
popad |
inc ecx |
add esi, 8 |
jmp .next_resendq |
include 'tcp_timer.inc' |
include 'tcp_subr.inc' |
include 'tcp_usreq.inc' |
include 'tcp_input.inc' |
include 'tcp_output.inc' |
.exit: |
ret |
endp |
;--------------------------------------------------------------------------- |
;*************************************************************************** |
; Function |
; tcp_rx |
; |
; TCP_API |
; 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 |
; |
; This function is called by system function 76 |
;*************************************************************************** |
proc tcp_rx stdcall uses ebx |
; 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 ebx, net_sockets |
.next_socket.1: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .next_socket.1.exit |
; DEBUGF 1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get the dest. port from the TCP hdr |
cmp [ebx + SOCKET.LocalPort], ax ; get the dest. port from the TCP hdr |
jne .next_socket.1 ; different - try next socket |
; DEBUGF 1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP] |
mov eax, [edx + IP_PACKET.SourceAddress] ; get the source IP Addr from the IP hdr |
cmp [ebx + SOCKET.RemoteIP], eax ; compare with socket's remote IP |
jne .next_socket.1 ; different - try next socket |
; DEBUGF 1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4 |
mov ax, [edx + 20 + TCP_PACKET.SourcePort] ; get the source port from the TCP hdr |
cmp [ebx + SOCKET.RemotePort], ax ; compare with socket's remote port |
jne .next_socket.1 ; different - try next socket |
; We have a complete match - use this socket |
jmp .change_state |
.next_socket.1.exit: |
; 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 ebx, net_sockets |
.next_socket.2: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .next_socket.2.exit |
; DEBUGF 1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get the dest. port from the TCP hdr |
cmp [ebx + SOCKET.LocalPort], ax ; compare with socket's local port |
jne .next_socket.2 ; different - try next socket |
; DEBUGF 1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP] |
mov eax, [edx + IP_PACKET.SourceAddress] ; get the source IP Addr from the IP hdr |
cmp [ebx + SOCKET.RemoteIP], eax ; compare with socket's remote IP |
jne .next_socket.2 ; different - try next socket |
; DEBUGF 1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4 |
cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0 |
jne .next_socket.2 ; different - try next socket |
; We have a complete match - use this socket |
jmp .change_state |
.next_socket.2.exit: |
; 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 ebx, net_sockets |
.next_socket.3: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .next_socket.3.exit |
; DEBUGF 1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get destination port from the TCP hdr |
cmp [ebx + SOCKET.LocalPort], ax ; compare with socket's local port |
jne .next_socket.3 ; different - try next socket |
; DEBUGF 1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP] |
cmp [ebx + SOCKET.RemoteIP], 0 ; only match a socket remote IP of 0 |
jne .next_socket.3 ; different - try next socket |
; DEBUGF 1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4 |
cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0 |
jne .next_socket.3 ; different - try next socket |
; We have a complete match - use this socket |
jmp .change_state |
.next_socket.3.exit: |
; If we got here, we need to reject the packet |
DEBUGF 1, "K : tcp_rx - dumped\n" |
DEBUGF 1, "K : --------: %x-%x-%x (flags: %x)\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [edx + IP_PACKET.SourceAddress], [edx + 20 + TCP_PACKET.SourcePort]:4, [edx + 20 + TCP_PACKET.Flags]:2 |
inc [dumped_rx_count] |
jmp .exit |
.change_state: |
; We have a valid socket/TCB, so call the TCB State Machine for that skt. |
; socket is pointed to by ebx |
; IP packet is pointed to by edx |
; IP buffer number is on stack ( it will be popped at the end) |
stdcall tcpStateMachine, ebx |
.exit: |
pop eax |
call freeBuff |
ret |
endp |
;*************************************************************************** |
; Function |
; buildTCPPacket |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; 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 |
; |
; OUT: |
;*************************************************************************** |
proc build_tcp_packet stdcall, sockAddr:DWORD |
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 + 20 + TCP_PACKET.Flags], bl ; TCP flags |
mov ebx, [sockAddr] |
; 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 + SOCKET.LocalIP] |
mov [edx + IP_PACKET.SourceAddress], eax |
mov eax, [ebx + SOCKET.RemoteIP] |
mov [edx + IP_PACKET.DestinationAddress], eax |
mov [edx + IP_PACKET.VersionAndIHL], 0x45 |
mov [edx + IP_PACKET.TypeOfService], 0 |
pop eax ; Get the TCP data length |
push eax |
add eax, 20 + 20 ; add IP header and TCP header lengths |
rol ax, 8 |
mov [edx + IP_PACKET.TotalLength], ax |
mov [edx + IP_PACKET.Identification], 0 |
mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040 |
mov [edx + IP_PACKET.TimeToLive], 0x20 |
mov [edx + IP_PACKET.Protocol], PROTOCOL_TCP |
; Checksum left unfilled |
mov [edx + IP_PACKET.HeaderChecksum], 0 |
; Fill in the TCP header (some data is in the socket descriptor) |
mov ax, [ebx + SOCKET.LocalPort] |
mov [edx + 20 + TCP_PACKET.SourcePort], ax ; Local Port |
mov ax, [ebx + SOCKET.RemotePort] |
mov [edx + 20 + TCP_PACKET.DestinationPort], ax ; desitination Port |
; Checksum left unfilled |
mov [edx + 20 + TCP_PACKET.Checksum], 0 |
; sequence number |
mov eax, [ebx + SOCKET.SND_NXT] |
mov [edx + 20 + TCP_PACKET.SequenceNumber], eax |
; ack number |
mov eax, [ebx + SOCKET.RCV_NXT] |
mov [edx + 20 + TCP_PACKET.AckNumber], eax |
; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size) |
; 768 bytes seems better |
mov [edx + 20 + TCP_PACKET.Window], 0x0003 |
; Urgent pointer (0) |
mov [edx + 20 + TCP_PACKET.UrgentPointer], 0 |
; data offset ( 0x50 ) |
mov [edx + 20 + TCP_PACKET.DataOffset], 0x50 |
pop ecx ; count of bytes to send |
mov ebx, ecx ; need the length later |
cmp ebx, 0 |
jz @f |
mov edi, edx |
add edi, 40 |
cld |
rep movsb ; copy the data across |
@@: ; we have edx as IPbuffer ptr. |
; Fill in the TCP checksum |
; First, fill in pseudoheader |
mov eax, [edx + IP_PACKET.SourceAddress] |
mov [pseudoHeader], eax |
mov eax, [edx + IP_PACKET.DestinationAddress] |
mov [pseudoHeader + 4], eax |
mov word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0 |
add ebx, 20 |
mov [pseudoHeader + 10], bh |
mov [pseudoHeader + 11], bl |
mov eax, pseudoHeader |
mov [checkAdd1], eax |
mov word[checkSize1], 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] |
rol ax, 8 |
mov [edx + 20 + TCP_PACKET.Checksum], ax |
; Fill in the IP header checksum |
GET_IHL eax, edx ; get IP-Header length |
stdcall checksum_jb, edx, eax ; buf_ptr, buf_size |
rol ax, 8 |
mov [edx + IP_PACKET.HeaderChecksum], ax |
ret |
endp |
; Increments the 32 bit value pointed to by esi in internet order |
proc inc_inet_esi stdcall |
push eax |
mov eax, [esi] |
bswap eax |
inc eax |
bswap eax |
mov [esi], eax |
pop eax |
ret |
endp |
; Increments the 32 bit value pointed to by esi in internet order |
; by the value in ecx |
proc add_inet_esi stdcall |
push eax |
mov eax, [esi] |
bswap eax |
add eax, ecx |
bswap eax |
mov [esi], eax |
pop eax |
ret |
endp |
iglobal |
TCBStateHandler dd \ |
stateTCB_LISTEN, \ |
stateTCB_SYN_SENT, \ |
stateTCB_SYN_RECEIVED, \ |
stateTCB_ESTABLISHED, \ |
stateTCB_FIN_WAIT_1, \ |
stateTCB_FIN_WAIT_2, \ |
stateTCB_CLOSE_WAIT, \ |
stateTCB_CLOSING, \ |
stateTCB_LAST_ACK, \ |
stateTCB_TIME_WAIT, \ |
stateTCB_CLOSED |
endg |
;*************************************************************************** |
; Function |
; tcpStateMachine |
; |
;--------------------------------------------------------------------------- |
align 4 |
TCP_api: |
; Description |
; TCP state machine |
; This is a kernel function, called by tcp_rx |
; |
; IP buffer address given in edx |
; Socket/TCB address in ebx |
; |
; The IP buffer will be released by the caller |
;*************************************************************************** |
movzx eax, bh |
shl eax, 2 |
proc tcpStateMachine stdcall, sockAddr:DWORD |
; as a packet has been received, update the TCB timer |
mov [ebx + SOCKET.TCBTimer], TWOMSL |
test bl, bl |
jz .packets_tx ; 0 |
dec bl |
jz .packets_rx ; 1 |
dec bl |
jz .packets_missed ; 2 |
dec bl |
jz .packets_dumped ; 3 |
; If the received packet has an ACK bit set, |
; remove any packets in the resend queue that this |
; received packet acknowledges |
pushad |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .call_handler ; No ACK, so no data yet |
.error: |
mov eax, -1 |
; get skt number in eax |
stdcall net_socket_addr_to_num, ebx |
; The ack number is in [edx + 28], inet format |
; skt in eax |
mov esi, resendQ |
xor ecx, ecx |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je .call_handler ; None left |
cmp [esi + 4], eax |
je @f ; found one |
inc ecx |
add esi, 8 |
jmp .next_resendq |
@@: ; Can we delete this buffer? |
; If yes, goto @@. No, goto .next_resendq |
; Get packet data address |
push ecx |
; Now get buffer location, and copy buffer across. argh! more copying,, |
imul edi, ecx, IPBUFFSIZE |
add edi, resendBuffer |
; we have dest buffer location in edi. incoming packet in edx. |
; Get this packets sequence number |
; preserve al, ecx, esi, edx |
mov ecx, [edi + 20 + TCP_PACKET.SequenceNumber] |
bswap ecx |
movzx ebx, word[edi + 2] |
xchg bl, bh |
sub ebx, 40 |
add ecx, ebx ; ecx is now seq# of last byte +1, intel format |
; get recievd ack #, in intel format |
mov ebx, [edx + 20 + TCP_PACKET.AckNumber] |
bswap ebx |
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 @f ; if rx > old, delete old |
inc ecx |
add esi, 8 |
jmp .next_resendq |
@@: |
mov dword[esi + 4], 0 |
inc ecx |
add esi, 8 |
jmp .next_resendq |
.call_handler: |
popad |
; Call handler for given TCB state |
mov eax, [ebx + SOCKET.TCBState] |
cmp eax, TCB_LISTEN |
jb .exit |
cmp eax, TCB_CLOSED |
ja .exit |
stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr] |
.exit: |
ret |
endp |
.packets_tx: |
mov eax, [TCP_segments_tx + eax] |
;*************************************************************************** |
; Function |
; signal_network_event |
; |
; Description |
; Signals about network event to socket owner |
; This is a kernel function, called from TCP handler |
; |
; Socket/TCB address in ebx |
;*************************************************************************** |
proc signal_network_event |
push ecx esi eax |
mov eax, [ebx + SOCKET.PID] |
mov ecx, 1 |
mov esi, TASK_DATA + TASKDATA.pid |
.next_pid: |
cmp [esi], eax |
je .found_pid |
inc ecx |
add esi, 0x20 |
cmp ecx, [TASK_COUNT] |
jbe .next_pid |
.found_pid: |
shl ecx, 8 |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event |
pop eax esi ecx |
ret |
endp |
.packets_rx: |
mov eax, [TCP_segments_rx + eax] |
proc stateTCB_LISTEN stdcall, sockAddr:DWORD |
; 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 |
test [edx + 20 + TCP_PACKET.Flags], TH_SYN |
jz .exit |
; We have a SYN. update the socket with this IP packets details, |
; And send a response |
mov eax, [edx + IP_PACKET.SourceAddress] |
mov [ebx + SOCKET.RemoteIP], eax |
mov ax, [edx + 20 + TCP_PACKET.SourcePort] |
mov [ebx + SOCKET.RemotePort], ax |
mov eax, [edx + 20 + TCP_PACKET.SequenceNumber] |
mov [ebx + SOCKET.IRS], eax |
mov [ebx + SOCKET.RCV_NXT], eax |
lea esi, [ebx + SOCKET.RCV_NXT] |
call inc_inet_esi ; RCV.NXT |
mov eax, [ebx + SOCKET.ISS] |
mov [ebx + SOCKET.SND_NXT], eax |
; Now construct the response, and queue for sending by IP |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je .exit |
push ebx |
push eax |
mov bl, TH_SYN + TH_ACK |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
.not_local: |
; Send it. |
pop ebx |
call queue |
pop ebx |
mov esi, [sockAddr] |
mov [esi + SOCKET.TCBState], TCB_SYN_RECEIVED |
call signal_network_event |
; increment SND.NXT in socket |
add esi, SOCKET.SND_NXT |
call inc_inet_esi |
.exit: |
ret |
endp |
.packets_missed: |
mov eax, [TCP_segments_missed + eax] |
proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD |
; We are awaiting an ACK to our SYN, with a SYM |
; Look at control flags - expecting an ACK |
mov al, [edx + 20 + TCP_PACKET.Flags] |
and al, TH_SYN + TH_ACK |
cmp al, TH_SYN + TH_ACK |
je .syn_ack |
test al, TH_SYN |
jz .exit |
mov [ebx + SOCKET.TCBState], TCB_SYN_RECEIVED |
push TH_SYN + TH_ACK |
jmp .send |
.syn_ack: |
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED |
push TH_ACK |
.send: |
call signal_network_event |
; Store the recv.nxt field |
mov eax, [edx + 20 + TCP_PACKET.SequenceNumber] |
; Update our recv.nxt field |
mov [ebx + SOCKET.RCV_NXT], eax |
lea esi, [ebx + SOCKET.RCV_NXT] |
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 |
pop ebx |
je .exit |
push eax |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
.not_local: |
; Send it. |
pop ebx |
call queue |
.exit: |
ret |
endp |
.packets_dumped: |
mov eax, [TCP_segments_dumped + eax] |
proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD |
; In this case, we are expecting an ACK packet |
; For now, if the packet is an ACK, process it, |
; If not, ignore it |
test [edx + 20 + TCP_PACKET.Flags], TH_RST |
jz .check_ack |
push [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP] |
pop [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort] |
mov [ebx + SOCKET.TCBState], TCB_LISTEN |
jmp .signal |
.check_ack: |
; Look at control flags - expecting an ACK |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .exit |
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED |
.signal: |
call signal_network_event |
.exit: |
ret |
endp |
proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD |
; Here we are expecting data, or a request to close |
; OR both... |
; Ignore all packets with sequnce number other than next expected |
; recv.nxt is in dword [edx+24], in inet format |
; recv seq is in [sktAddr]+56, in inet format |
; just do a comparision |
mov eax, [ebx + SOCKET.RCV_NXT] |
cmp eax, [edx + 20 + TCP_PACKET.SequenceNumber] |
jne .exit |
; Did we receive a FIN or RST? |
test [edx + 20 + TCP_PACKET.Flags], TH_FIN+TH_RST |
jz .check_ack |
; It was a fin or reset. |
; Remove resend entries from the queue - I dont want to send any more data |
pushad |
; get skt # |
stdcall net_socket_addr_to_num, ebx |
mov esi, resendQ |
mov ecx, 0 |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je .last_resendq ; None left |
cmp [esi + 4], eax |
je @f ; found one |
inc ecx |
add esi, 8 |
jmp .next_resendq |
@@: |
mov dword[esi + 4], 0 |
inc ecx |
add esi, 8 |
jmp .next_resendq |
.last_resendq: |
popad |
@@: ; Send an ACK to that fin, and enter closewait state |
mov [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT |
test [edx + 20 + TCP_PACKET.Flags], TH_RST |
je @f |
mov [ebx + SOCKET.TCBState], TCB_CLOSED |
@@: |
call signal_network_event |
lea esi, [ebx + SOCKET.RCV_NXT] |
mov eax, [esi] ; save original |
call inc_inet_esi |
;; jmp ste_ack - NO, there may be data |
.check_ack: |
; Check that we received an ACK |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .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 cx, [edx + 20 + TCP_PACKET.Window] |
xchg cl, ch |
cmp cx, 1024 |
ja @f |
mov [ebx + SOCKET.wndsizeTimer], 1 |
@@: ; OK, here is the deal |
; Read the data bytes, store in socket buffer |
movzx ecx, [edx + IP_PACKET.TotalLength] |
xchg cl, ch |
sub ecx, 40 ; Discard 40 bytes of header |
ja .data ; Read data, if any |
; If we had received a fin, we need to ACK it. |
cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT |
je .ack |
jmp .exit |
.data: |
push ecx |
push ecx edx |
lea ecx, [ebx+SOCKET.mutex] |
call mutex_lock |
pop edx ecx |
push ebx |
mov eax, [ebx + SOCKET.rxDataCount] |
add eax, ecx |
cmp eax, SOCKETBUFFSIZE - SOCKETHEADERSIZE |
ja .overflow |
mov [ebx + SOCKET.rxDataCount], eax ; increment the count of bytes in buffer |
; point to the location to store the data |
lea edi, [ebx + eax + SOCKETHEADERSIZE] |
sub edi, ecx |
add edx, 40 ; edx now points to the data |
mov esi, edx |
cld |
rep movsb ; copy the data across |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
; flag an event to the application |
pop ebx |
call signal_network_event |
pop ecx |
; Update our recv.nxt field |
lea esi, [ebx + SOCKET.RCV_NXT] |
call add_inet_esi |
.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 .exit |
push eax |
mov bl, TH_ACK |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
.not_local: |
; Send it. |
pop ebx |
call queue |
.exit: |
ret |
.overflow: |
; no place in buffer |
; so simply restore stack and exit |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
pop eax ecx |
ret |
endp |
proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD |
; We can either receive an ACK of a fin, or a fin |
mov al, [edx + 20 + TCP_PACKET.Flags] |
and al, TH_FIN + TH_ACK |
cmp al, TH_ACK |
jne @f |
; It was an ACK |
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2 |
jmp .exit |
@@: |
mov [ebx + SOCKET.TCBState], TCB_CLOSING |
cmp al, TH_FIN |
je @f |
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
@@: |
lea esi, [ebx + SOCKET.RCV_NXT] |
call inc_inet_esi |
; Send an ACK |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je .exit |
push eax |
mov bl, TH_ACK |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
.not_local: |
; Send it. |
pop ebx |
call queue |
.exit: |
ret |
endp |
proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD |
test [edx + 20 + TCP_PACKET.Flags], TH_FIN |
jz .exit |
; Change state, as we have a fin |
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
lea esi, [ebx + SOCKET.RCV_NXT] |
call inc_inet_esi |
; Send an ACK |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je .exit |
push eax |
mov bl, TH_ACK |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
.not_local: |
; Send it. |
pop ebx |
call queue |
.exit: |
ret |
endp |
proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD |
; Intentionally left empty |
; socket_close_tcp handles this |
ret |
endp |
proc stateTCB_CLOSING stdcall, sockAddr:DWORD |
; We can either receive an ACK of a fin, or a fin |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .exit |
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
.exit: |
ret |
endp |
proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD |
; Look at control flags - expecting an ACK |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .exit |
; delete the socket |
stdcall net_socket_free, ebx |
.exit: |
ret |
endp |
proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD |
ret |
endp |
proc stateTCB_CLOSED stdcall, sockAddr:DWORD |
ret |
endp |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |