kolibrios/drivers/ethernet/i8255x.asm
hidnplayr b21956c356 Bugfix for #4467
git-svn-id: svn://kolibrios.org@4470 a494cfbc-eb01-0410-851d-a64ba20cac60
2014-01-17 15:07:07 +00:00

1255 lines
29 KiB
NASM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; i8255x (Intel eepro 100) driver for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;; Some parts of this driver are based on the code of eepro100.c ;;
;; from linux. ;;
;; ;;
;; Intel's programming manual for i8255x: ;;
;; http://www.intel.com/design/network/manuals/8255x_opensdm.htm ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TODO: use separate descriptors in memory instead of placing them in front of packets!
format MS COFF
API_VERSION = 0x01000100
DRIVER_VERSION = 5
MAX_DEVICES = 16
DEBUG = 1
__DEBUG__ = 1
__DEBUG_LEVEL__ = 2 ; 1 = verbose, 2 = errors only
include '../struct.inc'
include '../macros.inc'
include '../proc32.inc'
include '../imports.inc'
include '../fdo.inc'
include '../netdrv.inc'
public START
public service_proc
public version
virtual at ebx
device:
ETH_DEVICE
.io_addr dd ?
.pci_bus dd ?
.pci_dev dd ?
.irq_line db ?
.rx_desc dd ?
.ee_bus_width db ?
rb 0x100 - (($ - device) and 0xff)
txfd:
.status dw ?
.command dw ?
.link dd ?
.tx_desc_addr dd ?
.count dd ?
.tx_buf_addr0 dd ?
.tx_buf_size0 dd ?
rb 0x100 - (($ - device) and 0xff)
confcmd:
.status dw ?
.command dw ?
.link dd ?
.data rb 64
rb 0x100 - (($ - device) and 0xff)
lstats:
tx_good_frames dd ?
tx_coll16_errs dd ?
tx_late_colls dd ?
tx_underruns dd ?
tx_lost_carrier dd ?
tx_deferred dd ?
tx_one_colls dd ?
tx_multi_colls dd ?
tx_total_colls dd ?
rx_good_frames dd ?
rx_crc_errs dd ?
rx_align_errs dd ?
rx_resource_errs dd ?
rx_overrun_errs dd ?
rx_colls_errs dd ?
rx_runt_errs dd ?
last_tx_buffer dd ? ;;; fixme
sizeof.device_struct = $ - device
end virtual
virtual at 0
rxfd:
.status dw ?
.command dw ?
.link dd ?
.rx_buf_addr dd ?
.count dw ?
.size dw ?
.packet:
end virtual
; Serial EEPROM
EE_SK = 1 shl 0 ; serial clock
EE_CS = 1 shl 1 ; chip select
EE_DI = 1 shl 2 ; data in
EE_DO = 1 shl 3 ; data out
EE_MASK = EE_SK + EE_CS + EE_DI + EE_DO
; opcodes, first bit is start bit and must be 1
EE_READ = 110b
EE_WRITE = 101b
EE_ERASE = 111b
; The SCB accepts the following controls for the Tx and Rx units:
CU_START = 0x0010
CU_RESUME = 0x0020
CU_STATSADDR = 0x0040
CU_SHOWSTATS = 0x0050 ; Dump statistics counters.
CU_CMD_BASE = 0x0060 ; Base address to add CU commands.
CU_DUMPSTATS = 0x0070 ; Dump then reset stats counters.
RX_START = 0x0001
RX_RESUME = 0x0002
RX_ABORT = 0x0004
RX_ADDR_LOAD = 0x0006
RX_RESUMENR = 0x0007
INT_MASK = 0x0100
DRVR_INT = 0x0200 ; Driver generated interrupt
CmdIASetup = 0x0001
CmdConfigure = 0x0002
CmdTx = 0x0004
CmdTxFlex = 0x0008
Cmdsuspend = 0x4000
reg_scb_status = 0
reg_scb_cmd = 2
reg_scb_ptr = 4
reg_port = 8
reg_eeprom = 14
reg_mdi_ctrl = 16
macro delay {
push eax
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
in ax, dx
pop eax
}
section '.flat' code readable align 16
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; proc START ;;
;; ;;
;; (standard driver proc) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
proc START stdcall, state:dword
cmp [state], 1
jne .exit
.entry:
DEBUGF 1,"Loading driver\n"
stdcall RegService, my_service, service_proc
ret
.fail:
.exit:
xor eax, eax
ret
endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; proc SERVICE_PROC ;;
;; ;;
;; (standard driver proc) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 4
proc service_proc stdcall, ioctl:dword
mov edx, [ioctl]
mov eax, [edx + IOCTL.io_code]
;------------------------------------------------------
cmp eax, 0 ;SRV_GETVERSION
jne @F
cmp [edx + IOCTL.out_size], 4
jb .fail
mov eax, [edx + IOCTL.output]
mov [eax], dword API_VERSION
xor eax, eax
ret
;------------------------------------------------------
@@:
cmp eax, 1 ;SRV_HOOK
jne .fail
cmp [edx + IOCTL.inp_size], 3 ; Data input must be at least 3 bytes
jb .fail
mov eax, [edx + IOCTL.input]
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given
jne .fail ; other types arent supported for this card yet
; check if the device is already listed
mov esi, device_list
mov ecx, [devices]
test ecx, ecx
jz .firstdevice
; mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers
mov ax , [eax+1] ;
.nextdevice:
mov ebx, [esi]
cmp al, byte[device.pci_bus]
jne @f
cmp ah, byte[device.pci_dev]
je .find_devicenum ; Device is already loaded, let's find it's device number
@@:
add esi, 4
loop .nextdevice
; This device doesnt have its own eth_device structure yet, lets create one
.firstdevice:
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card
jae .fail
allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure
; Fill in the direct call addresses into the struct
mov [device.reset], reset
mov [device.transmit], transmit
mov [device.unload], unload
mov [device.name], my_service
; save the pci bus and device numbers
mov eax, [edx + IOCTL.input]
movzx ecx, byte[eax+1]
mov [device.pci_bus], ecx
movzx ecx, byte[eax+2]
mov [device.pci_dev], ecx
; Now, it's time to find the base io addres of the PCI device
PCI_find_io
; We've found the io address, find IRQ now
PCI_find_irq
DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4
; Ok, the eth_device structure is ready, let's probe the device
pushf
cli ; disable ints until initialisation is done
call probe ; this function will output in eax
test eax, eax
jnz .err ; If an error occured, exit
mov eax, [devices] ; Add the device structure to our device list
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device)
inc [devices] ;
popf
mov [device.type], NET_TYPE_ETH
call NetRegDev
cmp eax, -1
je .err
ret
; If the device was already loaded, find the device number and return it in eax
.find_devicenum:
DEBUGF 2,"Trying to find device number of already registered device\n"
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx
; into a device number in edi
mov eax, edi ; Application wants it in eax instead
DEBUGF 2,"Kernel says: %u\n", eax
ret
; If an error occured, remove all allocated data and exit (returning -1 in eax)
.err:
stdcall KernelFree, ebx
.fail:
or eax, -1
ret
;------------------------------------------------------
endp
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
;; ;;
;; Actual Hardware dependent code starts here ;;
;; ;;
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
unload:
; TODO: (in this particular order)
;
; - Stop the device
; - Detach int handler
; - Remove device from local list (device_list)
; - call unregister function in kernel
; - Remove all allocated structures and buffers the card used
or eax,-1
ret
;-------------
;
; Probe
;
;-------------
align 4
probe:
DEBUGF 1,"Probing\n"
PCI_make_bus_master
;---------------------------
; First, identify the device
stdcall PciRead32, [device.pci_bus], [device.pci_dev], PCI_VENDOR_ID ; get device/vendor id
DEBUGF 1,"Vendor_id=0x%x\n", ax
cmp ax, 0x8086
jne .notfound
shr eax, 16
DEBUGF 1,"Device_id=0x%x\n", ax
mov ecx, DEVICE_IDs
mov edi, device_id_list
repne scasw
jne .notfound
jmp .found
.notfound:
DEBUGF 2,"Unsupported device!\n"
or eax, -1
ret
.found:
call ee_get_width
call MAC_read_eeprom
;;; TODO: detect phy
;----------
;
; Reset
;
;----------
align 4
reset:
movzx eax, [device.irq_line]
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1
stdcall AttachIntHandler, eax, int_handler, dword 0
test eax, eax
jnz @f
DEBUGF 2,"Could not attach int handler!\n"
; or eax, -1
; ret
@@:
DEBUGF 1,"Resetting\n"
;---------------
; reset the card
set_io 0
set_io reg_port
xor eax, eax ; Software Reset
out dx, eax
mov esi, 10
call Sleep ; Give the card time to warm up.
;---------------------------------
; Tell device where to store stats
lea eax, [lstats]
GetRealAddr
set_io 0
set_io reg_scb_ptr
out dx, eax
mov ax, INT_MASK + CU_STATSADDR
set_io reg_scb_cmd
out dx, ax
call cmd_wait
;-----------------
; setup RX
set_io reg_scb_ptr
xor eax, eax
out dx, eax
set_io reg_scb_cmd
mov ax, INT_MASK + RX_ADDR_LOAD
out dx, ax
call cmd_wait
;-----------------------------
; Create RX and TX descriptors
call create_ring
; RX start
set_io 0
set_io reg_scb_ptr
mov eax, [device.rx_desc]
GetRealAddr
out dx, eax
mov ax, INT_MASK + RX_START
set_io reg_scb_cmd
out dx, ax
call cmd_wait
; Set-up TX
set_io reg_scb_ptr
xor eax, eax
out dx, eax
set_io reg_scb_cmd
mov ax, INT_MASK + CU_CMD_BASE
out dx, ax
call cmd_wait
; --------------------
mov [confcmd.command], CmdConfigure + Cmdsuspend
mov [confcmd.status], 0
lea eax, [txfd]
GetRealAddr
mov [confcmd.link], eax
mov esi, confcmd_data
lea edi, [confcmd.data]
mov ecx, 22
rep movsb
mov byte[confcmd.data + 1], 0x88 ; fifo of 8 each
mov byte[confcmd.data + 4], 0
mov byte[confcmd.data + 5], 0x80
mov byte[confcmd.data + 15], 0x48
mov byte[confcmd.data + 19], 0x80
mov byte[confcmd.data + 21], 0x05
mov [txfd.command], CmdIASetup
mov [txfd.status], 0
lea eax, [confcmd]
GetRealAddr
mov [txfd.link], eax
;;; copy in our MAC
lea edi, [txfd.tx_desc_addr]
lea esi, [device.mac]
movsd
movsw
set_io reg_scb_ptr
lea eax, [txfd]
GetRealAddr
out dx, eax
; Start CU & enable ints
set_io reg_scb_cmd
mov ax, CU_START
out dx, ax
call cmd_wait
;-----------------------
; build txfd structure (again!)
lea eax, [txfd]
GetRealAddr
mov [txfd.link], eax
mov [txfd.count], 0x02208000
lea eax, [txfd.tx_buf_addr0]
GetRealAddr
mov [txfd.tx_desc_addr], eax
; Indicate that we have successfully reset the card
DEBUGF 1,"Reset complete\n"
mov [device.mtu], 1514
; Set link state to unknown
mov [device.state], ETH_LINK_UNKOWN
xor eax, eax ; indicate that we have successfully reset the card
ret
align 4
create_ring:
DEBUGF 1,"Creating ring\n"
;---------------------
; build rxfd structure
stdcall KernelAlloc, 2000
mov [device.rx_desc], eax
mov esi, eax
GetRealAddr
mov [esi + rxfd.status], 0x0000
mov [esi + rxfd.command], 0x0000
mov [esi + rxfd.link], eax
mov [esi + rxfd.count], 0
mov [esi + rxfd.size], 1528
;-----------------------
; build txfd structure
lea eax, [txfd]
GetRealAddr
mov [txfd.link], eax
mov [txfd.count], 0x02208000
lea eax, [txfd.tx_buf_addr0]
GetRealAddr
mov [txfd.tx_desc_addr], eax
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Transmit ;;
;; ;;
;; In: buffer pointer in [esp+4] ;;
;; size of buffer in [esp+8] ;;
;; pointer to device structure in ebx ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 4
transmit:
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8]
mov eax, [esp+4]
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
[eax+13]:2,[eax+12]:2
cmp dword [esp+8], 1514
ja .error ; packet is too long
cmp dword [esp+8], 60
jb .error ; packet is too short
;;; TODO: check if current descriptor is in use
; fill in buffer address and size
mov eax, [esp+4]
mov [last_tx_buffer], eax ;;; FIXME
GetRealAddr
mov [txfd.tx_buf_addr0], eax
mov eax, [esp+8]
mov [txfd.tx_buf_size0], eax
mov [txfd.status], 0
mov [txfd.command], Cmdsuspend + CmdTx + CmdTxFlex + 1 shl 15 ;;; EL bit
; mov [txfd.count], 0x02208000 ;;;;;;;;;;;
; Inform device of the new/updated transmit descriptor
lea eax, [txfd]
GetRealAddr
set_io 0
set_io reg_scb_ptr
out dx, eax
; Start the transmit
mov ax, CU_START
set_io reg_scb_cmd
out dx, ax
call cmd_wait
; set_io 0 ;; why?
; in ax, dx ;;
;
; @@:
; cmp [txfd.status], 0 ; wait for completion? dont seems a good idea to me..
; je @r
;
; set_io 0 ;; why?
; in ax, dx ;;
; Update stats
inc [device.packets_tx]
mov eax, [esp + 8]
add dword [device.bytes_tx], eax
adc dword [device.bytes_tx + 4], 0
DEBUGF 1,"Transmit OK\n"
xor eax, eax
ret 8
.error:
stdcall KernelFree, [esp+4]
or eax, -1
ret 8
;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Interrupt handler ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;
align 4
int_handler:
push ebx esi edi
DEBUGF 1,"INT\n"
; find pointer of device wich made IRQ occur
mov ecx, [devices]
test ecx, ecx
jz .nothing
mov esi, device_list
.nextdevice:
mov ebx, [esi]
; set_io 0 ; reg_scb_status = 0
set_io reg_scb_status
in ax, dx
out dx, ax ; send it back to ACK
test ax, ax
jnz .got_it
.continue:
add esi, 4
dec ecx
jnz .nextdevice
.nothing:
pop edi esi ebx
xor eax, eax
ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver)
.got_it:
DEBUGF 1,"Device: %x Status: %x\n", ebx, ax
test ax, 1 shl 14 ; did we receive a frame?
jz .no_rx
push ax
DEBUGF 1,"Receiving\n"
push ebx
.rx_loop:
pop ebx
mov esi, [device.rx_desc]
cmp [esi + rxfd.status], 0 ; we could also check bits C and OK (bit 15 and 13)
je .nodata
DEBUGF 1,"rxfd status=0x%x\n", [esi + rxfd.status]:4
movzx ecx, [esi + rxfd.count]
and ecx, 0x3fff
push ebx
push .rx_loop
push ecx
add esi, rxfd.packet
push esi
; Update stats
add dword [device.bytes_rx], ecx
adc dword [device.bytes_rx + 4], 0
inc dword [device.packets_rx]
; allocate new descriptor
stdcall KernelAlloc, 2000
mov [device.rx_desc], eax
mov esi, eax
GetRealAddr
mov [esi + rxfd.status], 0x0000
mov [esi + rxfd.command], 0xc000 ; End of list + Suspend
mov [esi + rxfd.link], eax
mov [esi + rxfd.count], 0
mov [esi + rxfd.size], 1528
; restart RX
set_io 0
set_io reg_scb_ptr
; lea eax, [device.rx_desc]
; GetRealAddr
out dx, eax
set_io reg_scb_cmd
mov ax, RX_START
out dx, ax
call cmd_wait
; And give packet to kernel
jmp Eth_input
.nodata:
DEBUGF 1, "no more data\n"
pop ax
.no_rx:
; Cleanup after TX
cmp [txfd.status], 0
je .done
cmp [last_tx_buffer], 0
je .done
push ax
DEBUGF 1, "Removing packet 0x%x from RAM!\n", [last_tx_buffer]
stdcall KernelFree, [last_tx_buffer]
mov [last_tx_buffer], 0
pop ax
.done:
and ax, 00111100b
cmp ax, 00001000b
jne .fail
DEBUGF 1, "out of resources!\n"
; Restart the RX
; allocate new descriptor
stdcall KernelAlloc, 2000
mov [device.rx_desc], eax
mov esi, eax
GetRealAddr
mov [esi + rxfd.status], 0x0000
mov [esi + rxfd.command], 0xc000 ; End of list + Suspend
mov [esi + rxfd.link], eax
mov [esi + rxfd.count], 0
mov [esi + rxfd.size], 1528
; restart RX
set_io 0
set_io reg_scb_ptr
; lea eax, [device.rx_desc]
; GetRealAddr
out dx, eax
set_io reg_scb_cmd
mov ax, RX_START
out dx, ax
call cmd_wait
.fail:
pop edi esi ebx
xor eax, eax
inc eax
ret
align 4
cmd_wait:
in al, dx
test al, al
jnz cmd_wait
ret
align 4
ee_read: ; esi = address to read
DEBUGF 1,"Eeprom read from 0x%x\n", esi
set_io 0
set_io reg_eeprom
;-----------------------------------------------------
; Prepend start bit + read opcode to the address field
; and shift it to the very left bits of esi
mov cl, 29
sub cl, [device.ee_bus_width]
shl esi, cl
or esi, EE_READ shl 29
movzx ecx, [device.ee_bus_width]
add ecx, 3
mov al, EE_CS
out dx, al
delay
;-----------------------
; Write this to the chip
.loop:
mov al, EE_CS + EE_SK
shl esi, 1
jnc @f
or al, EE_DI
@@:
out dx, al
delay
and al, not EE_SK
out dx, al
delay
loop .loop
;------------------------------
; Now read the data from eeprom
xor esi, esi
mov ecx, 16
.loop2:
shl esi, 1
mov al, EE_CS + EE_SK
out dx, al
delay
in al, dx
test al, EE_DO
jz @f
inc esi
@@:
mov al, EE_CS
out dx, al
delay
loop .loop2
;-----------------------
; de-activate the eeprom
xor ax, ax
out dx, ax
DEBUGF 1,"0x%x\n", esi:4
ret
align 4
ee_write: ; esi = address to write to, di = data
DEBUGF 1,"Eeprom write 0x%x to 0x%x\n", di, esi
set_io 0
set_io reg_eeprom
;-----------------------------------------------------
; Prepend start bit + write opcode to the address field
; and shift it to the very left bits of esi
mov cl, 29
sub cl, [device.ee_bus_width]
shl esi, cl
or esi, EE_WRITE shl 29
movzx ecx, [device.ee_bus_width]
add ecx, 3
mov al, EE_CS ; enable chip
out dx, al
;-----------------------
; Write this to the chip
.loop:
mov al, EE_CS + EE_SK
shl esi, 1
jnc @f
or al, EE_DI
@@:
out dx, al
delay
and al, not EE_SK
out dx, al
delay
loop .loop
;-----------------------------
; Now write the data to eeprom
mov ecx, 16
.loop2:
mov al, EE_CS + EE_SK
shl di, 1
jnc @f
or al, EE_DI
@@:
out dx, al
delay
and al, not EE_SK
out dx, al
delay
loop .loop2
;-----------------------
; de-activate the eeprom
xor al, al
out dx, al
ret
align 4
ee_get_width:
set_io 0
set_io reg_eeprom
mov al, EE_CS ; activate eeprom
out dx, al
delay
mov si, EE_READ shl 13
xor ecx, ecx
.loop:
mov al, EE_CS + EE_SK
shl si, 1
jnc @f
or al, EE_DI
@@:
out dx, al
delay
and al, not EE_SK
out dx, al
delay
inc ecx
cmp ecx, 15
jae .give_up
in al, dx
test al, EE_DO
jnz .loop
xor al, al
out dx, al ; de-activate eeprom
sub cl, 3 ; dont count the opcode bits
mov [device.ee_bus_width], cl
DEBUGF 1, "Eeprom width=%u bit\n", ecx
ret
.give_up:
DEBUGF 2, "Eeprom not found!\n"
xor al, al
out dx, al ; de-activate eeprom
ret
; cx = phy addr
; dx = phy reg addr
; ax = data
align 4
mdio_read:
DEBUGF 1,"MDIO read\n"
shl ecx, 21 ; PHY addr
shl edx, 16 ; PHY reg addr
mov eax, ecx
or eax, edx
or eax, 10b shl 26 ; read opcode
set_io 0
set_io reg_mdi_ctrl
out dx, eax
.wait:
delay
in eax, dx
test eax, 1 shl 28 ; ready bit
jz .wait
ret
; ax = data
; cx = phy addr
; dx = phy reg addr
; ax = data
align 4
mdio_write:
DEBUGF 1,"MDIO write\n"
and eax, 0xffff
shl ecx, 21 ; PHY addr
shl edx, 16 ; PHY reg addr
or eax, ecx
or eax, edx
or eax, 01b shl 26 ; write opcode
set_io 0
set_io reg_mdi_ctrl
out dx, eax
.wait:
delay
in eax, dx
test eax, 1 shl 28 ; ready bit
jz .wait
ret
read_mac:
ret
align 4
MAC_read_eeprom:
mov esi, 0
call ee_read
mov word[device.mac], si
mov esi, 1
call ee_read
mov word[device.mac+2], si
mov esi, 2
call ee_read
mov word[device.mac+4], si
ret
align 4
MAC_write:
;;;;
ret
; End of code
align 4 ; Place all initialised data here
devices dd 0 ; number of currently running devices
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF)
my_service db 'i8255x', 0 ; max 16 chars include zero
devicename db 'Intel Etherexpress pro/100', 0
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 ; 22 bytes total
device_id_list:
dw 0x1029
dw 0x1030
dw 0x1031
dw 0x1032
dw 0x1033
dw 0x1034
dw 0x1038
dw 0x1039
dw 0x103A
dw 0x103B
dw 0x103C
dw 0x103D
dw 0x103E
dw 0x1050
dw 0x1051
dw 0x1052
dw 0x1053
dw 0x1054
dw 0x1055
dw 0x1056
dw 0x1057
dw 0x1059
dw 0x1064
dw 0x1065
dw 0x1066
dw 0x1067
dw 0x1068
dw 0x1069
dw 0x106A
dw 0x106B
dw 0x1091
dw 0x1092
dw 0x1093
dw 0x1094
dw 0x1095
dw 0x10fe
dw 0x1209
dw 0x1229
dw 0x2449
dw 0x2459
dw 0x245D
dw 0x27DC
DEVICE_IDs = ($ - device_id_list) / 2
mac_82557_D100_A = 0
mac_82557_D100_B = 1
mac_82557_D100_C = 2
mac_82558_D101_A4 = 4
mac_82558_D101_B0 = 5
mac_82559_D101M = 8
mac_82559_D101S = 9
mac_82550_D102 = 12
mac_82550_D102_C = 13
mac_82551_E = 14
mac_82551_F = 15
mac_82551_10 = 16
mac_unknown = 0xFF
phy_100a = 0x000003E0
phy_100c = 0x035002A8
phy_82555_tx = 0x015002A8
phy_nsc_tx = 0x5C002000
phy_82562_et = 0x033002A8
phy_82562_em = 0x032002A8
phy_82562_ek = 0x031002A8
phy_82562_eh = 0x017002A8
phy_82552_v = 0xd061004d
phy_unknown = 0xFFFFFFFF
include_debug_strings ; All data wich FDO uses will be included here
section '.data' data readable writable align 16 ; place all uninitialized data place here
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling