/kernel/trunk/network/eth_drv/arp.inc |
---|
0,0 → 1,546 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; ARP.INC |
;; |
;; Address Resolution Protocol |
;; |
;; Last revision: 10.11.2006 |
;; |
;; 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] |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
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 |
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 |
; 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 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 |
call dword [drvr_transmit] ;transmit packet |
.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 |
call dword [drvr_transmit] ; Call the drivers transmit function |
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 |
/kernel/trunk/network/eth_drv/drivers/3c59x.inc |
---|
0,0 → 1,2380 |
;; 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 |
{ |
if defined E3C59X_LINUX |
sub reg, [virt_addr] |
add reg, [dma_addr] |
end if |
} |
macro dma_to_virt reg |
{ |
if defined E3C59X_LINUX |
sub reg, [dma_addr] |
add reg, [virt_addr] |
end if |
} |
macro zero_to_virt reg |
{ |
if defined E3C59X_LINUX |
add reg, [virt_addr] |
end if |
} |
macro virt_to_zero reg |
{ |
if defined E3C59X_LINUX |
sub reg, [virt_addr] |
end if |
} |
macro zero_to_dma reg |
{ |
if defined E3C59X_LINUX |
add reg, [dma_addr] |
end if |
} |
macro dma_to_zero reg |
{ |
if defined E3C59X_LINUX |
sub reg, [dma_addr] |
end if |
} |
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, 2000 |
.tx_reset_loop: |
in ax, dx |
test ah, 10000b ; check CmdInProgress |
jz .tx_enable |
dec ecx |
jns .tx_reset_loop |
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 |
/kernel/trunk/network/eth_drv/drivers/i8255x.inc |
---|
0,0 → 1,739 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; 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 ;; |
;; ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;******************************************************************** |
; 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_reset |
; Description |
; Place the chip (ie, the ethernet card) into a virgin state |
; No inputs |
; All registers destroyed |
; |
;*************************************************************************** |
I8255x_reset: |
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: |
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 |
mov [rxfd_link], eax |
mov eax, Ether_buffer |
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 |
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 |
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 |
mov [confcmd_link], eax |
mov ax, 1 |
mov [txfd_command], ax ; CmdIASetup |
mov ax, 0 |
mov [txfd_status], ax |
mov eax, confcmd |
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 |
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_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 |
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 |
mov [txfd_tx_desc_addr], eax |
mov eax, hdr |
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 |
mov [txfd_tx_buf_addr1], eax |
mov eax, ecx |
mov [txfd_tx_buf_size1], eax |
mov eax, txfd |
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 |
/kernel/trunk/network/eth_drv/drivers/pcnet32.inc |
---|
0,0 → 1,814 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; PCNET32.INC ;; |
;; ;; |
;; Ethernet driver for Menuet OS ;; |
;; ;; |
;; Version 1.0 31 July 2004 ;; |
;; ;; |
;; 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;macro PutStr X |
;{ |
; local .__xyz1 |
; local .__xyz2 |
; push esi |
; mov esi,.__xyz1 |
; call sys_msg_board_str |
; push eax |
; mov eax,1 |
; call delay_hs |
; pop eax |
; jmp .__xyz2 |
;.__xyz1: |
; db X |
; db 13,10,0 |
;.__xyz2: |
; pop esi |
;} |
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 ebx,eax |
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 ebx,eax |
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 |
.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 dword [pcnet32_private.rx_ring],pcnet32_rx_ring |
mov dword [pcnet32_private.tx_ring],pcnet32_tx_ring |
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 |
; PutStr "ASEL, enable auto-negotiation" |
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 |
and eax,0xffff |
call dword [pcnet32_access.write_csr] |
mov eax,pcnet32_private |
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: |
; PutStr "hardware reset" |
xor ebx,ebx |
mov eax,0x0002 |
call dword [pcnet32_access.write_csr] |
xor ebx,ebx |
call dword [pcnet32_access.read_csr] |
; PutStr "PCNET reset complete" |
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 |
; PutStr "Using WIO" |
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 |
; PutStr "Using DWIO" |
mov esi,pcnet32_dwio |
jmp .L1 |
.no_dev: |
; PutStr "PCNET32 not found" |
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 |
; PutStr "PCNET32 chip version OK" |
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 |
; PutStr "Invalid chip rev" |
jmp .no_dev |
.L2: |
; PutStr "PCnet/PCI 79C970" |
jmp .L10 |
.L3: |
; PutStr "PCnet/PCI 79C970" |
jmp .L10 |
.L4: |
; PutStr "PCnet/PCI II 79C970A" |
mov [pcnet32_private.fdx],1 |
jmp .L10 |
.L5: |
; PutStr "PCnet/FAST 79C971" |
mov [pcnet32_private.fdx],1 |
mov [pcnet32_private.mii],1 |
mov [pcnet32_private.fset],1 |
mov [pcnet32_private.ltint],1 |
jmp .L10 |
.L6: |
; PutStr "PCnet/FAST+ 79C972" |
mov [pcnet32_private.fdx],1 |
mov [pcnet32_private.mii],1 |
mov [pcnet32_private.fset],1 |
jmp .L10 |
.L7: |
; PutStr "PCnet/FAST III 79C973" |
mov [pcnet32_private.fdx],1 |
mov [pcnet32_private.mii],1 |
jmp .L10 |
.L8: |
; PutStr "PCnet/Home 79C978" |
mov [pcnet32_private.fdx],1 |
mov ebx,49 |
call dword [pcnet32_access.read_bcr] |
call dword [pcnet32_access.write_bcr] |
jmp .L10 |
.L9: |
; PutStr "PCnet/FAST III 79C975" |
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 |
; PutStr "MAC read" |
call pcnet32_adjust_pci_device |
; PutStr "PCI done" |
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 dword [pcnet32_private.rx_ring],pcnet32_rx_ring |
mov dword [pcnet32_private.tx_ring],pcnet32_tx_ring |
; PutStr "Switching to 32" |
mov ebx,20 |
mov eax,2 |
call dword [pcnet32_access.write_bcr] |
mov ebx,1 |
mov eax,(pcnet32_private and 0xffff) |
call dword [pcnet32_access.write_csr] |
mov ebx,2 |
mov eax,(pcnet32_private 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 eax,eax |
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 |
; PutStr "PCNETRX" |
mov ecx,[ebx+pcnet32_rx_head.msg_length] |
and ecx,0xfff |
sub ecx,4 |
mov [eth_rx_data_len],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 |
; PutStr "PCNETTX" |
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 |
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: |
; PutStr "PCNET: Send timeout" |
.L3: |
mov dword [edi+pcnet32_tx_head.base],0 |
pop ecx |
pop ebx |
pop esi |
pop edi |
ret |
/kernel/trunk/network/eth_drv/drivers/rtl8029.inc |
---|
0,0 → 1,955 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; 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! ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;******************************************************************** |
; 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 |
/kernel/trunk/network/eth_drv/drivers/rtl8139.inc |
---|
0,0 → 1,595 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; 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 ;; |
;; ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
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 ax, RTL8139_RX_CONFIG |
add edx, RTL8139_REG_RXCONFIG - RTL8139_REG_COMMAND |
out dx, ax |
; 1024 bytes DMA burst, total retries = 16 + 8 * 16 = 144 |
mov ax, (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, ax |
; 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 |
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 |
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 |
test ax, 0x1fff ; or no size given |
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 |
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 |
/kernel/trunk/network/eth_drv/drivers/sis900.inc |
---|
0,0 → 1,1148 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;******************************************************************** |
; 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 ;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 ; 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 ; |
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 ; |
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 |
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], ebx |
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 |
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 |
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 |
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 |
/kernel/trunk/network/eth_drv/ethernet.inc |
---|
36,6 → 36,22 |
; |
;******************************************************************** |
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 |
75,19 → 91,13 |
; Include individual drivers source files at this point. |
; If you create a new driver, include it below. |
include "rtl8029.inc" |
include "i8255x.inc" |
include "rtl8139.inc" |
include "3c59x.inc" |
include "sis900.inc" |
include "pcnet32.inc" |
include "drivers/rtl8029.inc" |
include "drivers/i8255x.inc" |
include "drivers/rtl8139.inc" |
include "drivers/3c59x.inc" |
include "drivers/sis900.inc" |
include "drivers/pcnet32.inc" |
; DEBUGGING_STATE enables or disables output of received and transmitted |
; data over the serial port |
DEBUGGING_ENABLED equ 1 |
DEBUGGING_DISABLED equ 0 |
DEBUGGING_STATE equ DEBUGGING_DISABLED |
; PCICards |
; ======== |
; PCI vendor and hardware types for hardware supported by the above drivers |
173,26 → 183,12 |
dd 0,0,0,0,0 ; end of list marker, do not remove |
endg |
; 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 |
ETHER_IP equ 0x0008 ; Reversed from 0800 for intel |
ETHER_ARP equ 0x0608 ; Reversed from 0806 for intel |
ETHER_RARP equ 0x3580 |
ARP_REQ_OPCODE equ 0x0100 |
ARP_REP_OPCODE equ 0x0200 |
uglobal |
arp_rx_count: dd 0 |
ip_rx_count: dd 0 |
dumped_rx_count: dd 0 |
ip_tx_count: dd 0 |
;Net-stack's interface's settings |
node_addr: db 0,0,0,0,0,0 |
gateway_ip: db 0, 0, 0, 0 |
dns_ip: dd 0 |
eth_rx_data_len: dw 0 |
eth_status: dd 0 |
io_addr: dd 0 |
208,189 → 204,19 |
drvr_poll: dd 0 |
drvr_transmit: dd 0 |
; These hold the destination Host identity for ARP responses |
remote_ip_add: dd 0 |
remote_hw_add: db 0, 0, 0, 0, 0, 0 |
endg |
iglobal |
broadcast_add: db 0xff,0xff,0xff,0xff,0xff,0xff |
subnet_mask: dd 0x00ffffff |
subnet_mask: dd 0x00ffffff ; 255.255.255.0 |
endg |
uglobal |
; This is used by getMACfromIP |
MACAddress: db 0,0,0,0,0,0 |
gateway_ip: db 0, 0, 0, 0 |
dns_ip: dd 0 |
endg |
include "arp.inc" ;arp-protocol functions |
include "pci.inc" ;PCI bus access functions |
; The follow is the ARP Table. |
; This table must be manually updated and the kernel recompilied if |
; changes are made to it. |
; ARP_TABLE_SIZE defines the size of the table |
; ARP_TABLE_ENTRIES defines the number of entries in the table |
; Each entry is 10 bytes: 4 Byte IP address, 6 byte MAC Address, |
; 2 bytes status, 2 bytes TTL ( in seconds ) |
; Empty entries are filled with zeros |
; 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 permanent 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 |
ARP_NO_ENTRY equ 0 |
ARP_VALID_MAPPING equ 1 |
ARP_AWAITING_RESPONSE equ 2 |
ARP_RESPONSE_TIMEOUT equ 3 |
ARP_ENTRY_SIZE equ 14 ; Number of bytes per entry |
ARP_TABLE_SIZE equ 20 ; Size of table |
ARP_TABLE_ENTRIES equ 0 ; Inital, hardcoded entries |
uglobal |
ARPTable: |
times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE db 0 |
endg |
iglobal |
NumARP: db ARP_TABLE_ENTRIES |
endg |
;*************************************************************************** |
; 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 erx_exit |
if DEBUGGING_STATE = DEBUGGING_ENABLED |
pusha |
mov eax, 0 ;Indicate that this is a received packet |
mov cx, [eth_rx_data_len] |
mov esi, Ether_buffer |
cmp word [esi + 12], ETHER_IP |
jnz erxd_done |
; cmp byte [esi + 14 + 9], 0x06 ; TCP |
; jnz erxd_done |
call eth_dump |
erxd_done: |
popa |
end if |
; Check the protocol. Call appropriate handler |
mov eax, Ether_buffer |
add eax, 12 ; The address of the protocol word |
mov ax, [eax] |
cmp ax, ETHER_ARP |
je erx_001 ; It is ARP |
cmp ax, ETHER_IP |
je erx_002 ; It's IP |
; inc dword [dumped_rx_count] |
jmp erx_exit ; If not IP or ARP, ignore |
erx_001: |
mov eax, [arp_rx_count] |
inc eax |
mov [arp_rx_count], eax |
; At this point, the packet is still in the Ether_buffer |
call arp_handler |
jmp erx_exit |
erx_002: |
mov eax, [ip_rx_count] |
inc eax |
mov [ip_rx_count], eax |
; Check to see if the MAC address is in our arp table |
; refresh the arp ttl if so |
mov esi, Ether_buffer |
add esi, 6 |
call refreshARP |
call ether_IP_handler |
jmp erx_exit |
erx_exit: |
ret |
;*************************************************************************** |
; Function |
; eth_tx |
; |
; Description |
403,18 → 229,19 |
; Places buffer on empty queue when the tx routine finished |
; |
;*************************************************************************** |
eth_tx: |
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 eth_exit ; Exit if no buffer available |
je .exit ; Exit if no buffer available |
push eax |
push eax ;save buffer number |
; convert buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
imul eax, IPBUFFSIZE |
add eax, IPbuffs |
; Extract the destination IP |
425,94 → 252,37 |
; If the destination address is 255.255.255.255, |
; set the MACAddress to all ones ( broadcast ) |
mov [MACAddress], dword 0xffffffff |
mov [MACAddress + 4], word 0xffff |
cld |
mov esi, broadcast_add |
lea edi, [MACAddress] |
movsd |
movsw |
cmp edx, 0xffffffff |
je etx_send ; If it is broadcast, just send |
je .send ; If it is broadcast, just send |
call getMACfromIP ; Get the MAC address. |
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 |
jz etx_send |
je .send |
; No valid entry. Are we waiting for a response? |
cmp eax, ARP_AWAITING_RESPONSE |
jne etx_001 |
; 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 |
jmp etx_exit |
call queue ; Get the buffer back |
jmp .exit |
etx_001: |
; HAs the request been sent, but timed out? |
cmp eax, ARP_RESPONSE_TIMEOUT |
jne etx_002 |
pop eax |
call freeBuff |
jmp etx_exit |
etx_002: |
; There is no entry. Re queue the request, and ask ARP to send a request |
; IP address is in edx |
push edx |
call arp_request |
pop ebx |
; Add an entry in the ARP table, awaiting response |
cmp byte [NumARP], ARP_TABLE_SIZE |
je etx_003 ; We cannot add a new entry in the table |
inc byte [NumARP] |
movzx eax, byte [NumARP] |
mov ecx, ARP_ENTRY_SIZE |
mul ecx |
sub eax, ARP_ENTRY_SIZE |
mov [eax + ARPTable], ebx |
xor ebx, ebx |
mov [eax + ARPTable + 4], ebx |
mov [eax + ARPTable + 8], bx |
; set the status field up - awaiting response |
mov cl, 0x00 |
mov [eax + ARPTable + 10], cl |
mov cl, 0x02 |
mov [eax + ARPTable + 11], cl |
; Initialise the time to live field - 10s |
mov cx, 0x000A |
mov [eax + ARPTable + 12], cx |
etx_003: |
pop ebx ; Get the buffer back |
mov eax, NET1OUT_QUEUE |
call queue |
jmp etx_exit |
etx_send: |
xor ecx, ecx |
mov ch, [ebx+2] |
mov cl, [ebx+3] ; ; Size of IP packet to send |
mov esi, ebx |
mov edi, MACAddress |
if DEBUGGING_STATE = DEBUGGING_ENABLED |
pusha |
mov cx, 42 |
mov eax, 1 ; Indicate that this is a tx packet |
call eth_dump |
popa |
end if |
mov bx, ETHER_IP |
.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 |
call dword [drvr_transmit] ; Call the drivers transmit function |
; OK, we have sent a packet, so increment the count |
519,11 → 289,13 |
inc dword [ip_tx_count] |
; And finally, return the buffer to the free queue |
.freebuf: |
pop eax |
call freeBuff |
etx_exit: |
.exit: |
ret |
endp |
;*************************************************************************** |
; Function |
554,7 → 326,7 |
mov edi, eax |
; get a pointer to the start of the DATA |
mov esi, Ether_buffer + 14 |
mov esi, ETH_FRAME.Data |
; Now store it all away |
mov ecx, IPBUFFSIZE / 4 ; Copy all of the available |
571,1131 → 343,94 |
ret |
;*************************************************************************** |
; |
; ARP CODE FOLLOWS |
; |
; The ARP code is used by ethernet drivers to translate an destination |
; IP address into an ethernet hardware address. Functions to broadcast |
; requests and handle response are (or will be) here. |
; The IP layer has no knowledge of ARP, as this is a network interface |
; issue |
; |
;*************************************************************************** |
;*************************************************************************** |
; Function |
; arp_timer |
; |
; eth_probe |
; Description |
; Called every 1s |
; It is responsible for removing expired routes |
; All registers may be destroyed |
; Searches for an ethernet card. If found, the card is enabled and |
; the ethernet -> IP link established |
; |
;*************************************************************************** |
arp_timer: |
; loop through all the ARP entries, decrementing each one |
; that doesn't have a TTL of 0xFFFF |
movzx eax, byte [NumARP] |
arp_001: |
cmp eax, 0 |
je arp_003 |
push eax |
dec eax |
mov ecx, ARP_ENTRY_SIZE |
mul ecx |
cmp word [ eax + ARPTable + 12], 0xFFFF |
je arp_002 |
cmp word [ eax + ARPTable + 12], 0 |
je arp_002 |
dec word [eax + ARPTable + 12] |
arp_002: |
pop eax |
dec eax |
jmp arp_001 |
; Now, look for entries with a TTL of 0 |
; Valid entries and response timeout entries get removed |
; awaiting response gets converted into a response timeout, with a |
; short life time - this allows queued packets to be flushed |
arp_003: |
movzx edx, byte [NumARP] |
cmp edx, 0 |
je arp_exit |
; EDX holds the # of entries to search through |
mov eax, 0 |
arp_005: |
cmp word [ eax + ARPTable + 12], 0 |
jne arp_004 |
; If it's status code is 0001 or 0003, delete the entry |
cmp word [eax + ARPTable + 10], 0x0100 |
je arp_007 |
cmp word [eax + ARPTable + 10], 0x0300 |
je arp_007 |
; The only other valid code is 0002 - indicating a |
; timeout while waiting for a response. Change the |
; entry to response timed out |
mov [eax + ARPTable + 10], word 0x0300 |
mov [eax + ARPTable + 12], word 0x000A |
jmp arp_004 |
arp_007: |
; Delete this entry |
mov edi, ARPTable |
add edi, eax |
mov esi, edi |
add esi, ARP_ENTRY_SIZE |
mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY_SIZE |
sub ecx, eax |
rep movsb |
dec byte [NumARP] |
jmp arp_006 |
arp_004: |
add eax, ARP_ENTRY_SIZE |
arp_006: |
dec edx |
cmp edx, 0 |
jne arp_005 |
arp_exit: |
ret |
;*************************************************************************** |
; Function |
; arp_request |
; This function scans the PCI bus looking for a supported device. |
; ISA bus is currently not supported. |
; |
; Description |
; Sends an ARP request on the ethernet |
; The requested IP address is in edx |
; All registers may be destroyed |
; |
; eax is 0 if no hardware found |
;*************************************************************************** |
arp_request: |
mov ebx, Ether_buffer |
mov ax, 0x0100 |
mov [ebx], ax |
add ebx, 2 |
mov ax, 0x0008 |
mov [ebx], ax |
add ebx, 2 |
mov ax, 0x0406 |
mov [ebx], ax |
add ebx, 2 |
mov ax, 0x0100 |
mov [ebx], ax |
add ebx, 2 |
mov ecx, node_addr |
mov eax, [ecx] |
mov [ebx], eax |
add ecx, 4 |
add ebx, 4 |
mov ax, [ecx] |
mov [ebx], ax |
add ebx, 2 |
mov eax, [stack_ip] |
mov [ebx], eax |
add ebx, 4 |
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 |
mov [ebx], eax |
add ebx, 4 |
mov [ebx], ax |
cmp [io_addr], eax |
je ep_00x ; Return 0 in eax if no cards found |
add ebx, 2 |
mov [ebx], edx |
call dword [drvr_probe] ; Call the drivers probe function |
; Now, send it! |
mov eax, [io_addr] ; return a non zero value |
; Pointer to 48 bit destination address in edi |
; Type of packet in bx |
; size of packet in ecx |
; pointer to packet data in esi |
mov edi, broadcast_add |
;if DEBUGGING_STATE = DEBUGGING_ENABLED |
; pusha |
; mov eax, 1 ; Indicate that this is a tx packet |
; mov ecx, 28 |
; mov esi, Ether_buffer |
; call eth_dump |
; popa |
;end if |
mov bx, ETHER_ARP |
mov ecx, 28 |
mov esi, Ether_buffer |
call dword [drvr_transmit] ; Call the drivers transmit function |
ep_00x: |
ret |
;*************************************************************************** |
; Function |
; arp_handler |
; ethernet_driver |
; |
; 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 |
; The ethernet RX and TX handler |
; This is a kernel function, called by stack_handler |
; |
;*************************************************************************** |
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 |
ethernet_driver: |
; Do nothing if the driver is inactive |
cmp [ethernet_active], byte 0 |
je eth_exit |
mov ebx, Ether_buffer |
call eth_rx |
call eth_tx |
mov edx, ebx |
add edx, 20 |
mov ax, [edx] |
cmp ax, ARP_REQ_OPCODE ; Is this a request packet? |
jne arph_resp ; No - so test for response |
mov edx, ebx |
add edx, 38 |
mov eax, [edx] |
cmp eax, [stack_ip] ; Is it looking for my IP address? |
jne arph_exit ; No - so quit now |
; OK, it is a request for my MAC address. Build the frame and send it |
; Save the important data from the original packet |
; remote MAC address first |
mov ecx, remote_hw_add |
mov edx, ebx |
add edx, 22 ; edx points to Source h/w address |
mov eax, [edx] |
mov [ecx], eax |
add edx, 4 |
add ecx, 4 |
mov ax, [edx] |
mov [ecx],ax |
; and also the remote IP address |
add edx, 2 |
mov eax,[edx] |
mov [remote_ip_add], eax |
; So now we can reuse the packet. ebx still holds the address of |
; the header + packet |
; We dont need the header ( first 14 bytes ) |
mov edx, ebx |
add edx, 20 |
mov ax, ARP_REP_OPCODE |
mov [edx], ax |
add edx, 2 |
mov ecx, node_addr |
mov eax, [ecx] |
mov [edx], eax |
add ecx, 4 |
add edx, 4 |
mov ax, [ecx] |
mov [edx], ax |
add edx, 2 |
mov eax, [stack_ip] |
mov [edx], eax |
add edx, 4 |
mov ecx, remote_hw_add |
mov eax, [ecx] |
mov [edx], eax |
add ecx, 4 |
add edx, 4 |
mov ax, [ecx] |
mov [edx], ax |
add edx, 2 |
mov eax, [remote_ip_add] |
mov [edx], eax |
; Now, send it! |
; Pointer to 48 bit destination address in edi |
; Type of packet in bx |
; size of packet in ecx |
; pointer to packet data in esi |
mov edi, remote_hw_add |
;if DEBUGGING_STATE = DEBUGGING_ENABLED |
; pusha |
; mov eax, 1 ; Indicate that this is a tx packet |
; mov ecx, 28 |
; mov esi, Ether_buffer + 14 |
; call eth_dump |
; popa |
;end if |
mov bx, ETHER_ARP |
mov ecx, 28 |
mov esi, Ether_buffer + 14 |
call dword [drvr_transmit] ; Call the drivers transmit function |
jmp arph_exit |
arph_resp: |
cmp ax, ARP_REP_OPCODE ; Is this a replypacket? |
jne arph_resp ; No - so quit |
; This was a reply, probably directed at me. |
; save the remotes MAC & IP |
mov ecx, remote_hw_add |
mov edx, ebx |
add edx, 22 ; edx points to Source h/w address |
mov eax, [edx] |
mov [ecx], eax |
add edx, 4 |
add ecx, 4 |
mov ax, [edx] |
mov [ecx],ax |
; and also the remote IP address |
add edx, 2 |
mov eax,[edx] |
mov [remote_ip_add], eax |
; Now, add an entry in the table for this IP address if it doesn't exist |
push eax |
movzx eax, byte [NumARP] |
mov ecx, ARP_ENTRY_SIZE |
mul ecx |
pop edx |
movzx ecx, byte [NumARP] |
cmp ecx, 0 |
je arph_002 |
arph_001: |
sub eax, ARP_ENTRY_SIZE |
cmp [eax + ARPTable], edx |
loopnz arph_001 ; Return back if non match |
jnz arph_002 ; None found, add to end |
mov ecx, [remote_hw_add] |
mov [eax + ARPTable + 4], ecx |
mov cx, [remote_hw_add+4] |
mov [eax + ARPTable + 8], cx |
; specify the type - a valid entry |
mov cl, 0x00 |
mov [eax + ARPTable + 10], cl |
mov cl, 0x01 |
mov [eax + ARPTable + 11], cl |
; Initialise the time to live field - 1 hour |
mov cx, 0x0E10 |
mov [eax + ARPTable + 12], cx |
jmp arph_exit |
arph_002: |
cmp byte [NumARP], ARP_TABLE_SIZE |
je arph_exit |
inc byte [NumARP] |
movzx eax, byte [NumARP] |
mov ecx, ARP_ENTRY_SIZE |
mul ecx |
sub eax, ARP_ENTRY_SIZE |
mov ecx, [remote_ip_add] |
mov [eax + ARPTable], ecx |
mov ecx, [remote_hw_add] |
mov [eax + ARPTable + 4], ecx |
mov cx, [remote_hw_add+4] |
mov [eax + ARPTable + 8], cx |
mov cl, 0x00 |
mov [eax + ARPTable + 10], cl |
mov cl, 0x01 |
mov [eax + ARPTable + 11], cl |
; Initialise the time to live field - 1 hour |
mov cx, 0x0E10 |
mov [eax + ARPTable + 12], cx |
arph_exit: |
eth_exit: |
ret |
; pointer to MAC in esi |
refreshARP: |
mov ebx, [esi] |
mov dx, [esi+4] |
push edx |
movzx eax, byte [NumARP] |
mov ecx, ARP_ENTRY_SIZE |
mul ecx |
pop edx |
movzx ecx, byte [NumARP] |
cmp ecx, 0 |
je rf_exit |
rf_001: |
sub eax, ARP_ENTRY_SIZE |
cmp [eax + ARPTable+4], ebx |
je rf_002 |
loop rf_001 |
jmp rf_exit |
rf_002: |
cmp [eax + ARPTable+8], dx |
je rf_gotone |
loop rf_001 |
jmp rf_exit |
rf_gotone: |
; Initialise the time to live field - 1 hour |
mov cx, 0x0E10 |
mov [eax + ARPTable + 12], cx |
rf_exit: |
ret |
;*************************************************************************** |
; Function |
; getMACfromIP |
; eth_rx |
; |
; Description |
; Takes an IP address in edx and scans the ARP table for |
; a matching entry |
; If a match is found, it's MAC address is stored in MACAddress. |
; Otherwise the value 0 is writen to MACAddress |
; eax holds ARP table entry status code ( ARP_ ) |
; ebx unchanged |
; 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 |
; |
;*************************************************************************** |
getMACfromIP: |
; first, check destination IP to see if it is on 'this' network. |
; The test is: |
; if ( destIP & subnet_mask == stack_ip & subnet_mask ) |
; desitnation is local |
; else |
; destination is remote, so pass to gateway |
eth_rx: |
xor ax, ax |
mov [eth_rx_data_len], ax |
call dword [drvr_poll] ; Call the drivers poll function |
mov eax, edx |
and eax, [subnet_mask] |
mov ecx, [stack_ip] |
and ecx, [subnet_mask] |
cmp eax, ecx |
je gm0 |
mov ax, [eth_rx_data_len] |
cmp ax, 0 |
je .exit |
mov edx, [gateway_ip] |
gm0: |
push edx |
xor eax, eax |
mov [MACAddress], eax |
mov [MACAddress + 4], ax |
movzx eax, byte [NumARP] |
mov ecx, ARP_ENTRY_SIZE |
mul ecx |
; Check the protocol. Call appropriate handler |
pop edx |
mov ax, [ETH_FRAME.Type] ; The address of the protocol word |
movzx ecx, byte [NumARP] |
cmp ecx, 0 |
je gm_none |
gm1: |
sub eax, ARP_ENTRY_SIZE |
cmp [eax + ARPTable], edx |
loopnz gm1 ; Return back if non match |
jnz gm_none ; Quit if none found |
cmp ax, ETHER_IP |
je .is_ip ; It's IP |
; eax holds index |
mov ecx, [eax + ARPTable + 4] |
mov [MACAddress], ecx |
mov cx, [eax + ARPTable + 8] |
mov [MACAddress+4], cx |
cmp ax, ETHER_ARP |
je .is_arp ; It is ARP |
; Return the entry status in eax |
mov ch, [eax + ARPTable + 10] |
mov cl, [eax + ARPTable + 11] |
movzx eax, cx |
jmp gm_exit |
jmp .exit ; If not IP or ARP, ignore |
gm_none: |
mov eax, ARP_NO_ENTRY |
.is_ip: |
inc dword [ip_rx_count] |
call ether_IP_handler |
jmp .exit |
gm_exit: |
ret |
.is_arp: |
;*************************************************************************** |
; |
; PCI CODE FOLLOWS |
; |
; the following functions provide access to the PCI interface. |
; These functions are used by scan_bus, and also some ethernet drivers |
; |
;*************************************************************************** |
; At this point, the packet is still in the Ether_buffer |
call arp_handler |
;*************************************************************************** |
; 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 |
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 |
;*************************************************************************** |
; |
; DEBUGGING CODE FOLLOWS |
; |
; If debugging data output is not required, ALL code & data below may |
; be removed. |
; |
;*************************************************************************** |
if DEBUGGING_STATE = DEBUGGING_ENABLED |
;*************************************************************************** |
; Function |
; eth_dump |
; |
; Description |
; Dumps a tx or rx ethernet packet over the rs232 link |
; This is a debugging routine that seriously slows down the stack. |
; Use with caution. |
; |
; Baud rate is 57600, 8n1 com1 |
; eax : type (0 == rx, 1 == tx ) |
; cx : # of bytes in buffer |
; esi : address of buffer start |
; edi : pointer to MACAddress ( tx only ) |
; |
;*************************************************************************** |
eth_dump: |
pusha |
; Set the port to the desired speed |
mov ebx, 0x3f8 ; combase |
mov edx, ebx |
add edx, 3 ; data format register |
mov al, 0x80 ; enable access to divisor latch |
out dx, al |
mov edx, ebx |
add edx, 1 ; interrupt enable register |
mov al, 0x00 ; No interruts enabled |
out dx, al |
mov edx, ebx |
mov al, 0x20 / 16 ; set baud rate to 57600 0x10 =115200 |
out dx, al |
mov edx, ebx |
add edx, 3 ; data format register |
mov al, 0x03 ; 8 data bits |
out dx, al |
mov edx, ebx |
add edx, 4 ; Modem control register |
mov al, 0x08 ; out2 enabled. No handshaking. |
out dx, al |
mov edx, ebx |
add edx, 1 ; interrupt enable register |
mov al, 0x01 ; Receive data interrupt enabled, |
out dx, al |
popa |
; First, display the type of the buffer. |
; If it is a tx buffer, display the macaddress |
pusha |
cmp eax, 0 |
jne dd001 |
mov bl, 0x0a |
call tx_byted |
mov bl, 0x0d |
call tx_byted |
; Output "RX:" |
mov bl, 'R' |
call tx_byted |
mov bl, 'X' |
call tx_byted |
mov bl, ':' |
call tx_byted |
jmp dump_data |
dd001: |
mov bl, 0x0a |
call tx_byted |
mov bl, 0x0d |
call tx_byted |
; Output TX: xxxxxxxxxxxx |
mov bl, 'T' |
call tx_byted |
mov bl, 'X' |
call tx_byted |
mov bl, ':' |
call tx_byted |
mov bl, ' ' |
call tx_byted |
; Display MAC address |
xor eax, eax |
mov al, [edi] |
shr al, 4 |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
xor eax, eax |
mov al, [edi] |
and al, 0x0f |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
inc edi |
xor eax, eax |
mov al, [edi] |
shr al, 4 |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
xor eax, eax |
mov al, [edi] |
and al, 0x0f |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
inc edi |
xor eax, eax |
mov al, [edi] |
shr al, 4 |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
xor eax, eax |
mov al, [edi] |
and al, 0x0f |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
inc edi |
xor eax, eax |
mov al, [edi] |
shr al, 4 |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
xor eax, eax |
mov al, [edi] |
and al, 0x0f |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
inc edi |
xor eax, eax |
mov al, [edi] |
shr al, 4 |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
xor eax, eax |
mov al, [edi] |
and al, 0x0f |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
inc edi |
xor eax, eax |
mov al, [edi] |
shr al, 4 |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
xor eax, eax |
mov al, [edi] |
and al, 0x0f |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
dump_data: |
popa |
; OK, we come in here with |
; cx == number of byte to send |
; esi == buffer start |
; |
dd_000: |
mov bl, 0x0a |
call tx_byted |
mov bl, 0x0d |
call tx_byted |
mov eax, 16 ; Number of characters on the line |
mov edi, esi ; Save first byte position for later |
push ecx |
dd_001: |
push eax |
; Print a byte, and a space |
xor eax, eax |
mov al, [esi] |
shr al, 4 |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
xor eax, eax |
mov al, [esi] |
and al, 0x0f |
mov bl, [eax + hexchars] |
call tx_byted ; byte in bl eax ebx edx destroyed |
mov bl, ' ' |
call tx_byted |
pop eax |
inc esi |
dec ecx |
cmp ecx, 0 |
je dd_0011 ; Print the ASCII format |
dec eax |
cmp eax, 0 |
je dd_002 ; Print the ASCII format |
jmp dd_001 ; Print rest of line |
dd_0011: |
; First, complete the 16 bytes of data, by printing spaces |
dec eax |
cmp eax, 0 |
je dd_002 |
push eax |
mov bl, ' ' |
call tx_byted |
mov bl, ' ' |
call tx_byted |
mov bl, ' ' |
call tx_byted |
pop eax |
jmp dd_0011 |
dd_002: |
pop ecx |
mov esi, edi ; Go back to the start of the line data |
mov eax, 16 |
outLineAscii: |
push eax |
xor eax, eax |
mov al, [esi] |
mov bl, '.' |
cmp al, 0x1F |
jle outAscii |
cmp al, 0x7e |
jge outAscii |
mov bl, al |
outAscii: |
call tx_byted ; byte in bl eax ebx edx destroyed |
pop eax |
dec ecx |
inc esi |
cmp ecx, 0 |
je dd_003 |
dec eax |
cmp eax, 0 |
je dd_003 |
jmp outLineAscii |
dd_003: |
cmp ecx, 0 |
je dd_004 |
jmp dd_000 |
dd_004: |
ret |
;*************************************************************************** |
; Function |
; tx_byte |
; |
; Description |
; Send a byte in bl out of the com port 1 |
; destroys eax, edx |
; |
;*************************************************************************** |
tx_byted: |
push ebx ; Save the byte |
mov ebx, 0x3f8 ; get the com port address |
; Wait for transmit buffer to empty. This could take 1ms @ 9600baud |
mov edx, ebx |
add edx, 5 |
wait_txd: |
in al, dx ; read uart serialisation status |
and al, 0x40 |
cmp al, 0 |
jz wait_txd ; loop until free |
mov edx, ebx |
pop eax ; restore the byte to send |
out dx, al |
ret |
iglobal |
; This is used for translating hex to ASCII for display or output |
hexchars db '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' |
endg |
end if |
.exit: |
ret |
/kernel/trunk/network/eth_drv/pci.inc |
---|
0,0 → 1,339 |
;*************************************************************************** |
; |
; 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 |
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 |