;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                 ;;
;; Copyright (C) KolibriOS team 2004-2018. All rights reserved.    ;;
;; Distributed under terms of the GNU General Public License       ;;
;;                                                                 ;;
;;          GNU GENERAL PUBLIC LICENSE                             ;;
;;             Version 2, June 1991                                ;;
;;                                                                 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

struct  PCI_header

        vendor_id       dw ?    ; 0x00
        device_id       dw ?    ; 0x02
        command         dw ?    ; 0x04
        status          dw ?    ; 0x06
        revision_id     db ?    ; 0x08
        prog_if         db ?    ; 0x09
        subclass        db ?    ; 0x0A
        class_code      db ?    ; 0x0B
        cache_line_size db ?    ; 0x0C
        latency_timer   db ?    ; 0x0D
        header_type     db ?    ; 0x0E
        bist            db ?    ; 0x0F

ends

struct  PCI_header00    PCI_header

        base_addr_0     dd ?    ; 0x10
        base_addr_1     dd ?    ; 0x14
        base_addr_2     dd ?    ; 0x18
        base_addr_3     dd ?    ; 0x1C
        base_addr_4     dd ?    ; 0x20
        base_addr_5     dd ?    ; 0x24
        cardbus_cis_ptr dd ?    ; 0x28
        subsys_vendor   dw ?    ; 0x2C
        subsys_id       dw ?    ; 0x2E
        exp_rom_addr    dd ?    ; 0x30
        cap_ptr         db ?    ; 0x34
                        rb 7    ; reserved
        interrupt_line  db ?    ; 0x3C
        interrupt_pin   db ?    ; 0x3D
        min_grant       db ?    ; 0x3E
        max_latency     db ?    ; 0x3F

ends

struct  PCI_header01    PCI_header

        base_addr_0     dd ?    ; 0x10
        base_addr_1     dd ?    ; 0x14
        prim_bus_nr     db ?    ; 0x18
        sec_bus_nr      db ?    ; 0x19
        sub_bus_nr      db ?    ; 0x1A
        sec_lat_tmr     db ?    ; 0x1B
        io_base         db ?    ; 0x1C
        io_limit        db ?    ; 0x1D
        sec_status      dw ?    ; 0x1E
        mem_base        dw ?    ; 0x20
        mem_limit       dw ?    ; 0x22
        pref_mem_base   dw ?    ; 0x24
        pref_mem_limit  dw ?    ; 0x26
        pref_base_up    dd ?    ; 0x28
        pref_limit_up   dd ?    ; 0x2C
        io_base_up      dw ?    ; 0x30
        io_limit_up     dw ?    ; 0x32
        cap_ptr         db ?    ; 0x34
                        rb 3    ; reserved
        exp_rom_addr    dd ?    ; 0x38
        interrupt_line  db ?    ; 0x3C
        interrupt_pin   db ?    ; 0x3E
        bridge_ctrl     dw ?    ; 0x3F

ends

struct  PCI_header02    PCI_header

        base_addr       dd ?    ; 0x10
        cap_list_offs   db ?    ; 0x14
                        rb 1    ; reserved
        sec_stat        dw ?    ; 0x16
        pci_bus_nr      db ?    ; 0x18
        cardbus_bus_nr  db ?    ; 0x19
        sub_bus_nr      db ?    ; 0x1A
        cardbus_lat_tmr db ?    ; 0x1B
        mbar_0          dd ?    ; 0x1C
        mlimit_0        dd ?    ; 0x20
        mbar_1          dd ?    ; 0x24
        mlimit_1        dd ?    ; 0x28
        iobar_0         dd ?    ; 0x2C
        iolimit_0       dd ?    ; 0x30
        iobar_1         dd ?    ; 0x34
        iolimit_1       dd ?    ; 0x38
        interrupt_line  db ?    ; 0x3C
        interrupt_pin   db ?    ; 0x3D
        bridge_ctrl     dw ?    ; 0x3E
        subs_did        dw ?    ; 0x40
        subs_vid        dw ?    ; 0x42
        legacy_bar      dd ?    ; 0x44

ends

; Base address bits
        PCI_BASE_ADDRESS_SPACE_IO               = 0x01
        PCI_BASE_ADDRESS_IO_MASK                = 0xFFFFFFFC
        PCI_BASE_ADDRESS_MEM_MASK               = 0xFFFFFFF0
        PCI_BASE_ADDRESS_MEM_TYPE_MASK          = 0x00000006
        PCI_BASE_ADDRESS_MEM_TYPE_32            = 0x0
        PCI_BASE_ADDRESS_MEM_TYPE_RESERVED      = 0x02
        PCI_BASE_ADDRESS_MEM_TYPE_64            = 0x4


; command bits
        PCI_CMD_PIO                     = 0x01          ; bit0: io space control
        PCI_CMD_MMIO                    = 0x02          ; bit1: memory space control
        PCI_CMD_MASTER                  = 0x04          ; bit2: device acts as a PCI master
        PCI_CMD_INTX_DISABLE            = 0x400         ; INTx emulation disable

; status bits
        PCI_STATUS_CAPA                 = 0x10          ; bit4: new capabilities available


if used PCI_find_io
proc PCI_find_io stdcall bus, dev

        push    esi
        xor     eax, eax
        mov     esi, PCI_header00.base_addr_0
  .check:
        invoke  PciRead32, [bus], [dev], esi
        test    eax, PCI_BASE_ADDRESS_IO_MASK
        jz      .inc
        test    eax, PCI_BASE_ADDRESS_SPACE_IO
        jz      .inc
        and     eax, PCI_BASE_ADDRESS_IO_MASK
        pop     esi
        ret

  .inc:
        add     esi, 4
        cmp     esi, PCI_header00.base_addr_5
        jbe     .check
        pop     esi
        xor     eax, eax
        ret

endp
end if


if used PCI_find_mmio
proc PCI_find_mmio stdcall bus, dev

        push    esi ebx
        mov     esi, PCI_header00.base_addr_0
  .check:
        invoke  PciRead32, [bus], [dev], esi
        DEBUGF  1, "BAR: 0x%x\n", eax
        mov     ebx, eax
        test    eax, PCI_BASE_ADDRESS_SPACE_IO  ; MMIO address?
        jnz     .next
        and     ebx, PCI_BASE_ADDRESS_MEM_TYPE_MASK
        cmp     bl, PCI_BASE_ADDRESS_MEM_TYPE_64
        je      .is64
        cmp     bl, PCI_BASE_ADDRESS_MEM_TYPE_32
        jne     .next
        ; Ok, we have a 32-bit BAR.
        and     eax, PCI_BASE_ADDRESS_MEM_MASK
        pop     ebx esi
        DEBUGF  1, "32-bit MMIO address found: 0x%x\n", eax
        ret

  .is64:
        ; Ok, we have a 64-bit BAR, check if the upper 32-bits are 0, then we can use it..
        push    eax
        add     esi, 4
        cmp     esi, PCI_header00.base_addr_5
        ja      .fail
        invoke  PciRead32, [bus], [dev], esi
        test    eax, eax
        pop     eax
        jnz     .next
        and     eax, PCI_BASE_ADDRESS_MEM_MASK
        pop     ebx esi
        DEBUGF  1, "64-bit MMIO address found: 0x00000000%x\n", eax
        ret

  .next:
        add     esi, 4
        cmp     esi, PCI_header00.base_addr_5
        jbe     .check
  .fail:
        xor     eax, eax
        pop     ebx esi
        DEBUGF  1, "No usable MMIO addresses found!\n"
        ret

endp
end if