kolibrios/kernel/branches/flat_kernel/network/eth_drv/pci.inc
Sergey Semyonov (Serge) f591baba3e create branch
git-svn-id: svn://kolibrios.org@387 a494cfbc-eb01-0410-851d-a64ba20cac60
2007-03-05 20:17:43 +00:00

341 lines
8.3 KiB
PHP

;***************************************************************************
;
; PCI CODE FOLLOWS
;
; the following functions provide access to the PCI interface.
; These functions are used by scan_bus, and also some ethernet drivers
;
;***************************************************************************
; PCI Bus defines
PCI_HEADER_TYPE equ 0x0e ;8 bit
PCI_BASE_ADDRESS_0 equ 0x10 ;32 bit
PCI_BASE_ADDRESS_5 equ 0x24 ;32 bits
PCI_BASE_ADDRESS_SPACE_IO equ 0x01
PCI_VENDOR_ID equ 0x00 ;16 bit
PCI_BASE_ADDRESS_IO_MASK equ 0xFFFFFFFC
;***************************************************************************
; Function
; config_cmd
;
; Description
; creates a command dword for use with the PCI bus
; bus # in ebx
; devfn in ecx
; where in edx
;
; command dword returned in eax
; Only eax destroyed
;***************************************************************************
config_cmd:
push ecx
mov eax, ebx
shl eax, 16
or eax, 0x80000000
shl ecx, 8
or eax, ecx
pop ecx
or eax, edx
and eax, 0xFFFFFFFC
ret
;***************************************************************************
; Function
; pcibios_read_config_byte
;
; Description
; reads a byte from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; byte returned in al ( rest of eax zero )
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_byte:
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
xor eax, eax
and dx, 0x03
add dx, 0xCFC
; and dx, 0xFFC
in al, dx
ret
;***************************************************************************
; Function
; pcibios_read_config_word
;
; Description
; reads a word from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; word returned in ax ( rest of eax zero )
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_word:
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
xor eax, eax
and dx, 0x02
add dx, 0xCFC
; and dx, 0xFFC
in ax, dx
ret
;***************************************************************************
; Function
; pcibios_read_config_dword
;
; Description
; reads a dword from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; dword returned in eax
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_dword:
push edx
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
xor eax, eax
mov dx, 0xCFC
in eax, dx
pop edx
ret
;***************************************************************************
; Function
; pcibios_write_config_byte
;
; Description
; write a byte in al to the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; Only eax/edx destroyed
;***************************************************************************
pcibios_write_config_byte:
push ax
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
pop ax
and dx, 0x03
add dx, 0xCFC
out dx, al
ret
;***************************************************************************
; Function
; pcibios_write_config_word
;
; Description
; write a word in ax to the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; Only eax/edx destroyed
;***************************************************************************
pcibios_write_config_word:
push ax
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
pop ax
and dx, 0x02
add dx, 0xCFC
out dx, ax
ret
;***************************************************************************
; Function
; delay_us
;
; Description
; delays for 30 to 60 us
;
; I would prefer this routine to be able to delay for
; a selectable number of microseconds, but this works for now.
;
; If you know a better way to do 2us delay, pleae tell me!
;***************************************************************************
delay_us:
push eax
push ecx
mov ecx,2
in al,0x61
and al,0x10
mov ah,al
cld
dcnt1:
in al,0x61
and al,0x10
cmp al,ah
jz dcnt1
mov ah,al
loop dcnt1
pop ecx
pop eax
ret
;***************************************************************************
; Function
; scan_bus
;
; Description
; Scans the PCI bus for a supported device
; If a supported device is found, the drvr_ variables are initialised
; to that drivers functions ( as defined in the PCICards table)
;
; io_addr holds card I/O space. 32 bit, but only LS 16 bits valid
; pci_data holds the PCI vendor + device code
; pci_dev holds PCI bus dev #
; pci_bus holds PCI bus #
;
; io_addr will be zero if no card found
;
;***************************************************************************
scan_bus:
xor eax, eax
mov [hdrtype], al
mov [pci_data], eax
xor ebx, ebx ; ebx = bus# 0 .. 255
sb_bus_loop:
xor ecx, ecx ; ecx = devfn# 0 .. 254 ( not 255? )
sb_devf_loop:
mov eax, ecx
and eax, 0x07
cmp eax, 0
jne sb_001
mov edx, PCI_HEADER_TYPE
call pcibios_read_config_byte
mov [hdrtype], al
jmp sb_002
sb_001:
mov al, [hdrtype]
and al, 0x80
cmp al, 0x80
jne sb_inc_devf
sb_002:
mov edx, PCI_VENDOR_ID
call pcibios_read_config_dword
mov [vendor_device], eax
cmp eax, 0xffffffff
je sb_empty
cmp eax, 0
jne sb_check_vendor
sb_empty:
mov [hdrtype], byte 0
jmp sb_inc_devf
sb_check_vendor:
; iterate though PCICards until end or match found
mov esi, PCICards
sb_check:
cmp [esi], dword 0
je sb_inc_devf ; Quit if at last entry
cmp eax, [esi]
je sb_got_card
add esi, PCICARDS_ENTRY_SIZE
jmp sb_check
sb_got_card:
; indicate that we have found the card
mov [pci_data], eax
mov [pci_dev], ecx
mov [pci_bus], ebx
; Define the driver functions
push eax
mov eax, [esi+4]
mov [drvr_probe], eax
mov eax, [esi+8]
mov [drvr_reset], eax
mov eax, [esi+12]
mov [drvr_poll], eax
mov eax, [esi+16]
mov [drvr_transmit], eax
mov eax, [esi+20]
mov [drvr_cable], eax
pop eax
mov edx, PCI_BASE_ADDRESS_0
sb_reg_check:
call pcibios_read_config_dword
mov [io_addr], eax
and eax, PCI_BASE_ADDRESS_IO_MASK
cmp eax, 0
je sb_inc_reg
mov eax, [io_addr]
and eax, PCI_BASE_ADDRESS_SPACE_IO
cmp eax, 0
je sb_inc_reg
mov eax, [io_addr]
and eax, PCI_BASE_ADDRESS_IO_MASK
mov [io_addr], eax
sb_exit1:
ret
sb_inc_reg:
add edx, 4
cmp edx, PCI_BASE_ADDRESS_5
jbe sb_reg_check
sb_inc_devf:
inc ecx
cmp ecx, 255
jb sb_devf_loop
inc ebx
cmp ebx, 256
jb sb_bus_loop
; We get here if we didn't find our card
; set io_addr to 0 as an indication
xor eax, eax
mov [io_addr], eax
sb_exit2:
ret