;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                 ;;
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved.    ;;
;; Distributed under terms of the GNU General Public License       ;;
;;                                                                 ;;
;; I8255x (Intel eepro 100) driver for KolibriOS                   ;;
;;                                                                 ;;
;;    Written by hidnplayr@kolibrios.org                           ;;
;;                                                                 ;;
;;    v0.0 - march 2009                                            ;;
;;                                                                 ;;
;;          GNU GENERAL PUBLIC LICENSE                             ;;
;;             Version 2, June 1991                                ;;
;;                                                                 ;;
;; current status (september 2009) - INCOMPLETE                    ;;
;;                                                                 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

$Revision$

format MS COFF

	API_VERSION		equ 0x01000100

	DEBUG			equ 1
	__DEBUG__		equ 1
	__DEBUG_LEVEL__ 	equ 1

include 'proc32.inc'
include 'imports.inc'
include 'fdo.inc'

OS_BASE 	equ 0;
new_app_base	equ 0x60400000
PROC_BASE	equ OS_BASE+0x0080000

public START
public service_proc
public version

struc IOCTL {
      .handle		dd ?
      .io_code		dd ?
      .input		dd ?
      .inp_size 	dd ?
      .output		dd ?
      .out_size 	dd ?
}

virtual at 0
  IOCTL IOCTL
end virtual

struc ETH_DEVICE {
; pointers to procedures
      .unload		dd ?
      .reset		dd ?
      .transmit 	dd ?
      .set_MAC		dd ?
      .get_MAC		dd ?
      .set_mode 	dd ?
      .get_mode 	dd ?
; status
      .bytes_tx 	dd ?
      .bytes_rx 	dd ?
      .packets_tx	dd ?
      .packets_rx	dd ?
      .mode		dd ?  ; This dword contains cable status (10mbit/100mbit, full/half duplex, auto negotiation or not,..)
      .name		dd ?
; device specific
      .io_addr		dd ?
      .pci_bus		db ?
      .pci_dev		db ?
      .irq_line 	db ?
      .status		dw ? ;
      .command		dw ? ;
      .link		dd ? ;
      .rx_buf_addr	dd ? ;
      .count		dw ? ;
      .size		dw ? ;
      .packet		dd ? ;
      .eeprom_data	rd 16

	.txfd:
	.txfd_status		 dw  ?
	.txfd_command		 dw  ?
	.txfd_link		 dd  ?
	.txfd_tx_desc_addr	 dd  ?
	.txfd_count		 dd  ?
	.txfd_tx_buf_addr0	 dd  ?
	.txfd_tx_buf_size0	 dd  ?
	.txfd_tx_buf_addr1	 dd  ?
	.txfd_tx_buf_size1	 dd  ?

      .size_:

}

virtual at 0
  device ETH_DEVICE
end virtual


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


confcmd:
	.status:	 dw  0
	.command:	 dw  0
	.link:		 dd  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


	MAX_I8255x		equ 16	 ; Max number of devices this driver may handle


; 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



;/***********************************************************************/
;/*                       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.






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 I8255x 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, [ebx+IOCTL.io_code]

;------------------------------------------------------

	cmp	eax, 0 ;SRV_GETVERSION
	jne	@F

	cmp	[edx+IOCTL.out_size], 4
	jl	.fail
	mov	eax, [edx+IOCTL.output]
	mov	[eax], dword API_VERSION

	xor	eax, eax
	ret

;------------------------------------------------------
  @@:
	cmp	eax, 1 ;SRV_HOOK
	jne	.fail

	mov	eax, [esp]
	DEBUGF 1,"esp=%x [esp]=%x\n",esp,eax

	cmp	[edx + IOCTL.inp_size], 3		; Data input must be at least 3 bytes
	jl	.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, I8255x_LIST
	mov	ecx, [I8255x_DEV]
	test	ecx, ecx
	jz	.firstdevice
	mov	eax, [edx+IOCTL.input]			; get the pci bus and device numbers
	mov	bx , [eax+1]				;
  .nextdevice:
	DEBUGF 1,"1"
	lodsd
	cmp	bx , word [eax + device.pci_bus]	; compare with pci and device num in RTL8139 list (notice the usage of word instead of byte)
	je	.find_devicenum 			; Device is already loaded, let's find it's device number

	loop	.nextdevice

; This device doesnt have its own eth_device structure yet, lets create one
  .firstdevice:
	cmp	[I8255x_DEV], MAX_I8255x		; First check if the driver can handle one more card
	jge	.fail

	push	edx
	stdcall KernelAlloc, device.size		; Allocate the buffer for eth_device structure
	pop	edx
	test	eax, eax
	jz	.fail
	mov	ebx, eax				; ebx is always used as a pointer to the structure (in driver, but also in kernel code)

; Fill in the direct call addresses into the struct

	mov	dword [ebx+device.reset], reset
	mov	dword [ebx+device.transmit], transmit
;        mov     dword [ebx+device.get_MAC], read_mac
;        mov     dword [ebx+device.set_MAC], write_mac
	mov	dword [ebx+device.unload], unload
	mov	dword [ebx+device.name], devicename

; save the pci bus and device numbers

	mov	eax, [edx+IOCTL.input]
	mov	cl , [eax+1]
	mov	[ebx+device.pci_bus], cl
	mov	cl , [eax+2]
	mov	[ebx+device.pci_dev], cl

; Now, it's time to find the base io addres of the PCI device
; TODO: implement check if bus and dev exist on this machine

	mov	edx, PCI_BASE_ADDRESS_0
  .reg_check:
	movzx	eax, byte [ebx+device.pci_bus]
	movzx	ecx, byte [ebx+device.pci_dev]

	push	edx ecx
	stdcall PciRead16, eax ,ecx ,edx
	pop	ecx edx

	mov	[ebx+device.io_addr], eax
	and	eax, PCI_BASE_ADDRESS_IO_MASK
	test	eax, eax
	jz	.inc_reg
	mov	eax, [ebx+device.io_addr]
	and	eax, PCI_BASE_ADDRESS_SPACE_IO
	test	eax, eax
	jz	.inc_reg

	mov	eax, [ebx+device.io_addr]
	and	eax, PCI_BASE_ADDRESS_IO_MASK
	mov	[ebx+device.io_addr], eax
	jmp	.got_io

  .inc_reg:
	add	edx, 4
	cmp	edx, PCI_BASE_ADDRESS_5
	jbe	.reg_check

  .got_io:

; We've found the io address, find IRQ now

	movzx	eax, byte [ebx+device.pci_bus]
	movzx	ecx, byte [ebx+device.pci_dev]
	push	ebx
	stdcall PciRead8, eax ,ecx ,0x3c				; 0x3c is the offset where irq can be found
	pop	ebx
	mov	byte [ebx+device.irq_line], al

	DEBUGF	1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
	[ebx+device.pci_dev]:1,[ebx+device.pci_bus]:1,[ebx+device.irq_line]:1,[ebx+device.io_addr]:4

; Allocate the Receive buffer

	stdcall KernelAlloc, dword (RX_BUFFER_SIZE+MAX_ETH_FRAME_SIZE)
	test	eax, eax
	jz	.err
	mov	[ebx+device.rx_buffer], eax				; Save the address to it into the device struct

; Now, Clear the allocated buffer

	cld
	mov	edi, eax
	mov	ecx, (RX_BUFFER_SIZE)/4 				; divide by 4 because we are going to use DWORD
	xor	eax, eax
	rep	stosd

; Allocate the Transmit Buffer

	stdcall KernelAlloc, dword (TX_BUFFER_SIZE)
	test	eax, eax
	jz	.err
	mov	[ebx+device.tx_buffer], eax

; This one needs to be cleared too..

	mov	edi, eax
	mov	ecx, (TX_BUFFER_SIZE)/4
	xor	eax, eax
	rep	stosd

; Ok, the eth_device structure is ready, let's probe the device

	call	probe							; this function will output in eax
	test	eax, eax
	jnz	.err							; If an error occured, exit

	mov	eax, [I8255x_DEV]					; Add the device structure to our device list
	mov	[I8255x_LIST+4*eax], ebx				; (IRQ handler uses this list to find device)
	inc	[I8255x_DEV]						;

	jmp	EthRegDev						; Register the device to kernel (ebx points to device struct)
									; Notice the jump instead of call, it is the same as
									;
									; call EthRegDev
									; ret
									;
									; Also notice that the value EthRegDev returned in eax, will be returned to
									; the caller application

; If the device was already loaded, find the device number and return it in eax

  .find_devicenum:
	DEBUGF	1,"Trying to find device number of already registered device\n"
	mov	ebx, eax
	call	EthStruc2Dev						; 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	1,"Kernel says: %u\n", eax
	ret

; If an error occured, remove all allocated data and exit (returning -1 in eax)

  .err:
	stdcall KernelFree, dword [ebx+device.rx_buffer]
	stdcall KernelFree, dword [ebx+device.tx_buffer]
	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 (RTL8139_LIST)
	; - call unregister function in kernel
	; - Remove all allocated structures and buffers the card used

	or	eax,-1

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
;
;***************************************************************************

probe:

	DEBUGF 1," Probing i8255x device: "

; enable the device

	movzx	eax, byte [ebx+device.pci_bus]
	movzx	ecx, byte [ebx+device.pci_dev]
	stdcall PciRead16, eax ,ecx ,PCI_REG_CMD

	mov	cx , ax
	or	cx , 0x05
	movzx	eax, byte [ebx+device.pci_bus]
	movzx	edx, byte [ebx+device.pci_dev]
	stdcall PciWrite16, eax ,edx ,PCI_REG_CMD, ecx

; do something else TODO

	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.

;***************************************************************************
;   Function
;      I8255x_reset
;   Description
;      Place the chip (ie, the ethernet card) into a virgin state
;      No inputs
;      All registers destroyed
;
;***************************************************************************

reset:

	; Now reset the card

	mov	edx, [ebx+device.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, [ebx+device.io_addr]
	add	edx, 4		  ; SCBPointer
	out	dx, eax

	mov	eax, 0x0140	    ; INT_MASK | CU_STATSADDR
	mov	edx, [ebx+device.io_addr]
	add	edx, 2		  ; SCBCmd
	out	dx, ax

	call	wait_for_cmd_done

	mov	eax, 0
	mov	edx, [ebx+device.io_addr]
	add	edx, 4		  ; SCBPointer
	out	dx, eax

	mov	eax, 0x0106	    ; INT_MASK | RX_ADDR_LOAD
	mov	edx, [ebx+device.io_addr]
	add	edx, 2		  ; SCBCmd
	out	dx, ax

	call	wait_for_cmd_done
   ; build rxrd structure
	mov	ax, 0x0001
	mov	[ebx+device.status], ax
	mov	ax, 0x0000
	mov	[rxfd_command], ax

	mov	eax, rxfd_status
	sub	eax, OS_BASE
	mov	[ebx+device.link], eax

	mov	eax, Ether_buffer
	sub	eax, OS_BASE
	mov	[ebx+device.rx_buf_addr], eax

	mov	ax, 0
	mov	[ebx+device.count], ax

	mov	ax, 1528
	mov	[ebx+device.size], ax

	mov	edx, [ebx+device.io_addr]
	add	edx, 4		 ; SCBPointer

	mov	eax, rxfd_status
	sub	eax, OS_BASE
	out	dx, eax

	mov	edx, [ebx+device.io_addr]
	add	edx, 2		 ; SCBCmd

	mov	ax, 0x0101	   ; INT_MASK | RX_START
	out	dx, ax

	call	wait_for_cmd_done

   ; start the receiver

	mov	ax, 0
	mov	[ebx+device.status], ax

	mov	ax, 0xc000
	mov	[ebx+device.command], ax

	mov	edx, [ebx+device.io_addr]
	add	edx, 4		 ; SCBPointer

	mov	eax, rxfd_status
	sub	eax, OS_BASE
	out	dx, eax

	mov	edx, [ebx+device.io_addr]
	add	edx, 2		 ; SCBCmd

	mov	ax, 0x0101	   ; INT_MASK | RX_START
	out	dx, ax

   ; Init TX Stuff

	mov	edx, [ebx+device.io_addr]
	add	edx, 4		 ; SCBPointer

	mov	eax, 0
	out	dx, eax

	mov	edx, [ebx+device.io_addr]
	add	edx, 2		 ; SCBCmd

	mov	ax, 0x0160	   ; INT_MASK | CU_CMD_BASE
	out	dx, ax

	call	wait_for_cmd_done

   ; Set TX Base address

   ; First, set up confcmd values

	mov	ax, 2
	mov	[confcmd_command], ax
	mov	eax, txfd
	sub	eax, OS_BASE
	mov	[confcmd_link], eax

	mov	ax, 1
	mov	[txfd_command], ax	   ; CmdIASetup

	mov	ax, 0
	mov	[txfd_status], ax

	mov	eax, confcmd
	sub	eax, OS_BASE
	mov	[txfd_link], eax



   ; ETH_ALEN is 6 bytes

	mov	esi, eeprom_data
	mov	edi, node_addr
	mov	ecx, 3

drp000:

	mov	eax, [esi]
	mov	[edi], al
	shr	eax, 8
	inc	edi
	mov	[edi], al
	inc	edi
	add	esi, 4
	loop	drp000

   ; Hard code your MAC address into node_addr at this point,
   ; If you cannot read the MAC address from the eeprom in the previous step.
   ; You also have to write the mac address into txfd_tx_desc_addr, rather
   ; than taking data from eeprom_data

	mov	esi, eeprom_data
	mov	edi, txfd_tx_desc_addr
	mov	ecx, 3

drp001:

	mov	eax, [esi]
	mov	[edi], al
	shr	eax, 8
	inc	edi
	mov	[edi], al
	inc	edi
	add	esi, 4
	loop	drp001

	mov	esi, eeprom_data + (6 * 4)
	mov	eax, [esi]
	shr	eax, 8
	and	eax, 0x3f
	cmp	eax, 4		  ; DP83840
	je	drp002
	cmp	eax, 10 	   ; DP83840A
	je	drp002
	jmp	drp003

drp002:

	mov	ebx, [esi]
	and	ebx, 0x1f
	push	ebx
	mov	ecx, 23
	call	mdio_read
	pop	ebx
	or	eax, 0x0422
	mov	ecx, 23
	mov	edx, eax
	call	mdio_write

drp003:

	mov	ax, 0x4002	   ; Cmdsuspend | CmdConfigure
	mov	[confcmd_command], ax
	mov	ax, 0
	mov	[confcmd_status], ax
	mov	eax, txfd
	mov	[confcmd_link], eax
	mov	ebx, confcmd_data
	mov	al, 0x88	 ; fifo of 8 each
	mov	[ebx + 1], al
	mov	al, 0
	mov	[ebx + 4], al
	mov	al, 0x80
	mov	[ebx + 5], al
	mov	al, 0x48
	mov	[ebx + 15], al
	mov	al, 0x80
	mov	[ebx + 19], al
	mov	al, 0x05
	mov	[ebx + 21], al

	mov	eax, txfd
	sub	eax, OS_BASE
	mov	edx, [ebx+device.io_addr]
	add	edx, 4		  ; SCBPointer
	out	dx, eax

	mov	eax, 0x0110	    ; INT_MASK | CU_START
	mov	edx, [ebx+device.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]
	test	ax, ax
	jz	drp004

skip:
   ; Indicate that we have successfully reset the card

	xor	eax, eax

	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
;
;***************************************************************************

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                         ;;
;; Transmit                                ;;
;;                                         ;;
;; In: buffer pointer in [esp]             ;;
;;     size of buffer in [esp+4]           ;;
;;     pointer to device structure in ebx  ;;
;;                                         ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

align 4
transmit:

	DEBUGF	1,"Transmitting packet, buffer:%x, size:%u\n",[esp],[esp+4]
	mov	eax, [esp]
	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+4], MAX_ETH_FRAME_SIZE
	jg	.finish 			; packet is too long
	cmp	dword [esp+4], 60
	jl	.finish 			; packet is too short

;        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, [ebx+device.io_addr]
	in	ax, dx
	and	ax, 0xfc00
	out	dx, ax

	mov	[ebx+device.txfd_status], 0
	mov	[ebx+device.txfd_command], 0x400C		  ; Cmdsuspend | CmdTx | CmdTxFlex
	lea	eax, [ebx+device.txfd]
	mov	[txfd_link], eax
	mov	[txfd_count], 0x02208000
	mov	eax, txfd_tx_buf_addr0
	call	GetPgAddr
	mov	[txfd_tx_desc_addr], eax
	mov	eax, hdr
	call	GetPgAddr
	mov	[txfd_tx_buf_addr0], eax
	mov	eax, 14   ; sizeof hdr
	mov	[txfd_tx_buf_size0], eax

	; Copy the buffer address and size in
;        mov     eax, esi
;        sub     eax, OS_BASE
;        mov     [txfd_tx_buf_addr1], eax
;        mov     eax, ecx
;        mov     [txfd_tx_buf_size1], eax

	mov	eax, ebx
	call	GetPgAddr
	add	eax, device.txfd
	mov	edx, [ebx+device.io_addr]
	add	edx, 4		  ; SCBPointer
	out	dx, eax

	mov	ax, 0x0110	   ; INT_MASK | CU_START
	mov	edx, [ebx+device.io_addr]
	add	edx, 2		  ; SCBCmd
	out	dx, ax

	call	wait_for_cmd_done

	mov	edx, [ebx+device.io_addr]
	in	ax, dx

I8t_001:

	mov	ax, [ebx+device.txfd_status]
	cmp	ax, 0
	je	I8t_001

	mov	edx, [ebx+device.io_addr]
	in	ax, dx

  .finish:

	ret



;***************************************************************************
; Function
;    I8255x_poll
;
; Description
;    Polls the ethernet card for a received packet
;    Received data, if any, ends up in Ether_buffer
;
;***************************************************************************
I8255x_poll:

	mov	ax, 0	   ; assume no data
	mov	[eth_rx_data_len], ax

	mov	ax, [rxfd_status]
	cmp	ax, 0
	je	i8p_exit

	mov	ax, 0
	mov	[rxfd_status], ax

	mov	ax, 0xc000
	mov	[rxfd_command], ax

	mov	edx, [io_addr]
	add	edx, 4		 ; SCBPointer

	mov	eax, rxfd_status
	sub	eax, OS_BASE
	out	dx, eax

	mov	edx, [ebx+device.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
;      wait_for_cmd_done
;
;   Description
;       waits for the hardware to complete a command
;       port address in edx
;
;       al destroyed
;***************************************************************************

wait_for_cmd_done:

;        mov     edx, [ebx + device.io_addr]

  .loop:
	in	al , dx
	test	al , al
	jnz	.loop

	ret



;***************************************************************************
;   Function
;      mdio_read
;
;   Description
;       This probably reads a register in the "physical media interface chip"
;         Phy_id in ebx   NOW EAX
;         location in ecx
;
;       Data returned in eax
;
;***************************************************************************

mdio_read:

	mov	edx, [ebx + device.io_addr]
	add	edx, 16 	; SCBCtrlMDI

;        mov     eax, 0x08000000
;        shl     ecx, 16
;        or      eax, ecx
;        shl     ebx, 21
;        or      eax, ebx
				   ;
	shl	ecx, 16 	   ;
	shl	eax, 21 	   ;
	or	eax, ecx	   ;
	or	eax, 0x08000000    ;
	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   NOW EAX
;         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

	shl	ecx, 16 	  ;
	shl	ebx, 21 	  ;
	or	eax, ecx	  ;
	or	eax, edx	  ;
	or	eax, 0x04000000   ;

	mov	edx, [ebx + device.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


;***************************************************************************
;   Function
;      do_eeprom_cmd
;
;   Description
;       writes a cmd to the ethernet cards eeprom, by bit bashing
;       cmd in ebx        NOW EAX
;       cmd length in ecx
;       return in eax
;***************************************************************************

do_eeprom_cmd:

	push	eax
	mov	edx, [ebx + device.io_addr]
	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, [esp]
	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

	add	esp, 4
	mov	eax, edi

	ret





; End of code

align 4 					; Place all initialised data here

I8255x_DEV    dd 0
version       dd (5 shl 16) or (API_VERSION and 0xFFFF)
my_service    db 'I8255x',0			; max 16 chars include zero
devicename    db 'Intel Etherexpress pro/100',0



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

I8255x_LIST rd I8255x			  ; This list contains all pointers to device structures the driver is handling

