Subversion Repositories Kolibri OS

Rev

Rev 3626 | Rev 3910 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;                                                              ;;
  7. ;;  PCI32.INC                                                   ;;
  8. ;;                                                              ;;
  9. ;;  32 bit PCI driver code                                      ;;
  10. ;;                                                              ;;
  11. ;;  Version 0.3  April 9, 2007                                  ;;
  12. ;;  Version 0.2  December 21st, 2002                            ;;
  13. ;;                                                              ;;
  14. ;;  Author: Victor Prodan, victorprodan@yahoo.com               ;;
  15. ;;          Mihailov Ilia, ghost.nsk@gmail.com                  ;;
  16. ;;    Credits:                                                  ;;
  17. ;;          Ralf Brown                                          ;;
  18. ;;          Mike Hibbett, mikeh@oceanfree.net                   ;;
  19. ;;                                                              ;;
  20. ;;  See file COPYING for details                                ;;
  21. ;;                                                              ;;
  22. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  23.  
  24. $Revision: 3908 $
  25.  
  26. ;***************************************************************************
  27. ;   Function
  28. ;      pci_api:
  29. ;
  30. ;   Description
  31. ;       entry point for system PCI calls
  32. ;***************************************************************************
  33. ;mmio_pci_addr  equ  0x400               ; set actual PCI address here to activate user-MMIO
  34.  
  35. iglobal
  36. align 4
  37. f62call:
  38.         dd      pci_fn_0
  39.         dd      pci_fn_1
  40.         dd      pci_fn_2
  41.         dd      pci_service_not_supported       ;3
  42.         dd      pci_read_reg            ;4 byte
  43.         dd      pci_read_reg            ;5 word
  44.         dd      pci_read_reg            ;6 dword
  45.         dd      pci_service_not_supported   ;7
  46.         dd      pci_write_reg           ;8 byte
  47.         dd      pci_write_reg           ;9 word
  48.         dd      pci_write_reg           ;10 dword
  49. if defined mmio_pci_addr
  50.         dd      pci_mmio_init           ;11
  51.         dd      pci_mmio_map            ;12
  52.         dd      pci_mmio_unmap          ;13
  53. end if
  54.  
  55. endg
  56.  
  57. align 4
  58.  
  59. pci_api:
  60.  
  61. ;cross
  62.         mov     eax, ebx
  63.         mov     ebx, ecx
  64.         mov     ecx, edx
  65.  
  66.         cmp     [pci_access_enabled], 1
  67.         jne     pci_service_not_supported
  68.  
  69.         movzx   edx, al
  70.  
  71. if defined mmio_pci_addr
  72.         cmp     al, 13
  73.         ja      pci_service_not_supported
  74. else
  75.         cmp     al, 10
  76.         ja      pci_service_not_supported
  77. end if
  78.  
  79.         call    dword [f62call+edx*4]
  80.         mov     dword [esp+32], eax
  81.         ret
  82.  
  83.  
  84. align 4
  85. pci_api_drv:
  86.  
  87.         cmp     [pci_access_enabled], 1
  88.         jne     .fail
  89.  
  90.         cmp     eax, 2
  91.         ja      .fail
  92.  
  93.         jmp     dword [f62call+eax*4]
  94.  
  95. .fail:
  96.         or      eax, -1
  97.         ret
  98.  
  99.  
  100. ;; ============================================
  101.  
  102. pci_fn_0:
  103. ; PCI function 0: get pci version (AH.AL)
  104.         movzx   eax, word [BOOT_VARS+0x9022]
  105.         ret
  106.  
  107. pci_fn_1:
  108. ; PCI function 1: get last bus in AL
  109.         mov     al, [BOOT_VARS+0x9021]
  110.         ret
  111.  
  112. pci_fn_2:
  113. ; PCI function 2: get pci access mechanism
  114.         mov     al, [BOOT_VARS+0x9020]
  115.         ret
  116.  
  117. pci_service_not_supported:
  118.         or      eax, -1
  119.         mov     dword [esp+32], eax
  120.         ret
  121.  
  122. ;***************************************************************************
  123. ;   Function
  124. ;      pci_make_config_cmd
  125. ;
  126. ;   Description
  127. ;       creates a command dword  for use with the PCI bus
  128. ;       bus # in ah
  129. ;       device+func in bh (dddddfff)
  130. ;       register in bl
  131. ;
  132. ;      command dword returned in eax ( 10000000 bbbbbbbb dddddfff rrrrrr00 )
  133. ;***************************************************************************
  134.  
  135. align 4
  136.  
  137. pci_make_config_cmd:
  138.         shl     eax, 8     ; move bus to bits 16-23
  139.         mov     ax, bx     ; combine all
  140.         and     eax, 0xffffff
  141.         or      eax, 0x80000000
  142.         ret
  143.  
  144. ;***************************************************************************
  145. ;   Function
  146. ;      pci_read_reg:
  147. ;
  148. ;   Description
  149. ;       read a register from the PCI config space into EAX/AX/AL
  150. ;       IN: ah=bus,device+func=bh,register address=bl
  151. ;           number of bytes to read (1,2,4) coded into AL, bits 0-1
  152. ;           (0 - byte, 1 - word, 2 - dword)
  153. ;***************************************************************************
  154.  
  155. align 4
  156.  
  157. pci_read_reg:
  158.         push    ebx esi
  159.         cmp     byte [BOOT_VARS+0x9020], 2;what mechanism will we use?
  160.         je      pci_read_reg_2
  161.  
  162.                 ; mechanism 1
  163.         mov     esi, eax ; save register size into ESI
  164.         and     esi, 3
  165.  
  166.         call    pci_make_config_cmd
  167.         mov     ebx, eax
  168.                 ; get current state
  169.         mov     dx, 0xcf8
  170.         in      eax, dx
  171.         push    eax
  172.                 ; set up addressing to config data
  173.         mov     eax, ebx
  174.         and     al, 0xfc; make address dword-aligned
  175.         out     dx, eax
  176.                 ; get requested DWORD of config data
  177.         mov     dl, 0xfc
  178.         and     bl, 3
  179.         or      dl, bl   ; add to port address first 2 bits of register address
  180.  
  181.         or      esi, esi
  182.         jz      pci_read_byte1
  183.         cmp     esi, 1
  184.         jz      pci_read_word1
  185.         cmp     esi, 2
  186.         jz      pci_read_dword1
  187.         jmp     pci_fin_read1
  188.  
  189. pci_read_byte1:
  190.         in      al, dx
  191.         jmp     pci_fin_read1
  192. pci_read_word1:
  193.         in      ax, dx
  194.         jmp     pci_fin_read1
  195. pci_read_dword1:
  196.         in      eax, dx
  197.         jmp     pci_fin_read1
  198. pci_fin_read1:
  199.                 ; restore configuration control
  200.         xchg    eax, [esp]
  201.         mov     dx, 0xcf8
  202.         out     dx, eax
  203.  
  204.         pop     eax
  205.         pop     esi ebx
  206.         ret
  207. pci_read_reg_2:
  208.  
  209.         test    bh, 128 ;mech#2 only supports 16 devices per bus
  210.         jnz     pci_read_reg_err
  211.  
  212.         mov     esi, eax ; save register size into ESI
  213.         and     esi, 3
  214.  
  215.         push    eax
  216.                 ;store current state of config space
  217.         mov     dx, 0xcf8
  218.         in      al, dx
  219.         mov     ah, al
  220.         mov     dl, 0xfa
  221.         in      al, dx
  222.  
  223.         xchg    eax, [esp]
  224.                 ; out 0xcfa,bus
  225.         mov     al, ah
  226.         out     dx, al
  227.                 ; out 0xcf8,0x80
  228.         mov     dl, 0xf8
  229.         mov     al, 0x80
  230.         out     dx, al
  231.                 ; compute addr
  232.         shr     bh, 3; func is ignored in mechanism 2
  233.         or      bh, 0xc0
  234.         mov     dx, bx
  235.  
  236.         or      esi, esi
  237.         jz      pci_read_byte2
  238.         cmp     esi, 1
  239.         jz      pci_read_word2
  240.         cmp     esi, 2
  241.         jz      pci_read_dword2
  242.         jmp     pci_fin_read2
  243.  
  244. pci_read_byte2:
  245.         in      al, dx
  246.         jmp     pci_fin_read2
  247. pci_read_word2:
  248.         in      ax, dx
  249.         jmp     pci_fin_read2
  250. pci_read_dword2:
  251.         in      eax, dx
  252. ;       jmp pci_fin_read2
  253. pci_fin_read2:
  254.  
  255.                 ; restore configuration space
  256.         xchg    eax, [esp]
  257.         mov     dx, 0xcfa
  258.         out     dx, al
  259.         mov     dl, 0xf8
  260.         mov     al, ah
  261.         out     dx, al
  262.  
  263.         pop     eax
  264.         pop     esi ebx
  265.         ret
  266.  
  267. pci_read_reg_err:
  268.         xor     eax, eax
  269.         dec     eax
  270.         pop     esi ebx
  271.         ret
  272.  
  273.  
  274. ;***************************************************************************
  275. ;   Function
  276. ;      pci_write_reg:
  277. ;
  278. ;   Description
  279. ;       write a register from ECX/CX/CL into the PCI config space
  280. ;       IN: ah=bus,device+func=bh,register address (dword aligned)=bl,
  281. ;           value to write in ecx
  282. ;           number of bytes to write (1,2,4) coded into AL, bits 0-1
  283. ;           (0 - byte, 1 - word, 2 - dword)
  284. ;***************************************************************************
  285.  
  286. align 4
  287.  
  288. pci_write_reg:
  289.         push    esi ebx
  290.         cmp     byte [BOOT_VARS+0x9020], 2;what mechanism will we use?
  291.         je      pci_write_reg_2
  292.  
  293.                 ; mechanism 1
  294.         mov     esi, eax ; save register size into ESI
  295.         and     esi, 3
  296.  
  297.         call    pci_make_config_cmd
  298.         mov     ebx, eax
  299.                 ; get current state into ecx
  300.         mov     dx, 0xcf8
  301.         in      eax, dx
  302.         push    eax
  303.                 ; set up addressing to config data
  304.         mov     eax, ebx
  305.         and     al, 0xfc; make address dword-aligned
  306.         out     dx, eax
  307.                 ; write DWORD of config data
  308.         mov     dl, 0xfc
  309.         and     bl, 3
  310.         or      dl, bl
  311.         mov     eax, ecx
  312.  
  313.         or      esi, esi
  314.         jz      pci_write_byte1
  315.         cmp     esi, 1
  316.         jz      pci_write_word1
  317.         cmp     esi, 2
  318.         jz      pci_write_dword1
  319.         jmp     pci_fin_write1
  320.  
  321. pci_write_byte1:
  322.         out     dx, al
  323.         jmp     pci_fin_write1
  324. pci_write_word1:
  325.         out     dx, ax
  326.         jmp     pci_fin_write1
  327. pci_write_dword1:
  328.         out     dx, eax
  329.         jmp     pci_fin_write1
  330. pci_fin_write1:
  331.  
  332.                 ; restore configuration control
  333.         pop     eax
  334.         mov     dl, 0xf8
  335.         out     dx, eax
  336.  
  337.         xor     eax, eax
  338.         pop     ebx esi
  339.  
  340.         ret
  341. pci_write_reg_2:
  342.  
  343.         test    bh, 128 ;mech#2 only supports 16 devices per bus
  344.         jnz     pci_write_reg_err
  345.  
  346.  
  347.         mov     esi, eax ; save register size into ESI
  348.         and     esi, 3
  349.  
  350.         push    eax
  351.                 ;store current state of config space
  352.         mov     dx, 0xcf8
  353.         in      al, dx
  354.         mov     ah, al
  355.         mov     dl, 0xfa
  356.         in      al, dx
  357.         xchg    eax, [esp]
  358.                 ; out 0xcfa,bus
  359.         mov     al, ah
  360.         out     dx, al
  361.                 ; out 0xcf8,0x80
  362.         mov     dl, 0xf8
  363.         mov     al, 0x80
  364.         out     dx, al
  365.                 ; compute addr
  366.         shr     bh, 3; func is ignored in mechanism 2
  367.         or      bh, 0xc0
  368.         mov     dx, bx
  369.                 ; write register
  370.         mov     eax, ecx
  371.  
  372.         or      esi, esi
  373.         jz      pci_write_byte2
  374.         cmp     esi, 1
  375.         jz      pci_write_word2
  376.         cmp     esi, 2
  377.         jz      pci_write_dword2
  378.         jmp     pci_fin_write2
  379.  
  380. pci_write_byte2:
  381.         out     dx, al
  382.         jmp     pci_fin_write2
  383. pci_write_word2:
  384.         out     dx, ax
  385.         jmp     pci_fin_write2
  386. pci_write_dword2:
  387.         out     dx, eax
  388.         jmp     pci_fin_write2
  389. pci_fin_write2:
  390.                 ; restore configuration space
  391.         pop     eax
  392.         mov     dx, 0xcfa
  393.         out     dx, al
  394.         mov     dl, 0xf8
  395.         mov     al, ah
  396.         out     dx, al
  397.  
  398.         xor     eax, eax
  399.         pop     ebx esi
  400.         ret
  401.  
  402. pci_write_reg_err:
  403.         xor     eax, eax
  404.         dec     eax
  405.         pop     ebx esi
  406.         ret
  407.  
  408. if defined mmio_pci_addr        ; must be set above
  409. ;***************************************************************************
  410. ;   Function
  411. ;      pci_mmio_init
  412. ;
  413. ;   Description
  414. ;       IN:  bx = device's PCI bus address (bbbbbbbbdddddfff)
  415. ;   Returns  eax = user heap space available (bytes)
  416. ;   Error codes
  417. ;       eax = -1 : PCI user access blocked,
  418. ;       eax = -2 : device not registered for uMMIO service
  419. ;       eax = -3 : user heap initialization failure
  420. ;***************************************************************************
  421. pci_mmio_init:
  422.         cmp     bx, mmio_pci_addr
  423.         jz      @f
  424.         mov     eax, -2
  425.         ret
  426. @@:
  427.         call    init_heap  ; (if not initialized yet)
  428.         or      eax, eax
  429.         jz      @f
  430.         ret
  431. @@:
  432.         mov     eax, -3
  433.         ret
  434.  
  435.  
  436. ;***************************************************************************
  437. ;   Function
  438. ;      pci_mmio_map
  439. ;
  440. ;   Description
  441. ;       maps a block of PCI memory to user-accessible linear address
  442. ;
  443. ;       WARNING! This VERY EXPERIMENTAL service is for one chosen PCI device only!
  444. ;       The target device address should be set in kernel var mmio_pci_addr
  445. ;
  446. ;       IN:  ah = BAR#;
  447. ;       IN: ebx = block size (bytes);
  448. ;       IN: ecx = offset in MMIO block (in 4K-pages, to avoid misaligned pages);
  449. ;
  450. ;   Returns eax = MMIO block's linear address in the userspace (if no error)
  451. ;
  452. ;
  453. ;   Error codes
  454. ;       eax = -1 : user access to PCI blocked,
  455. ;       eax = -2 : an invalid BAR register referred
  456. ;       eax = -3 : no i/o space on that BAR
  457. ;       eax = -4 : a port i/o BAR register referred
  458. ;       eax = -5 : dynamic userspace allocation problem
  459. ;***************************************************************************
  460.  
  461. pci_mmio_map:
  462.         and     edx, 0x0ffff
  463.         cmp     ah, 6
  464.         jc      .bar_0_5
  465.         jz      .bar_rom
  466.         mov     eax, -2
  467.         ret
  468. .bar_rom:
  469.         mov     ah, 8   ; bar6 = Expansion ROM base address
  470. .bar_0_5:
  471.         push    ecx
  472.         add     ebx, 4095
  473.         and     ebx, -4096
  474.         push    ebx
  475.         mov     bl, ah  ; bl = BAR# (0..5), however bl=8 for BAR6
  476.         shl     bl, 1
  477.         shl     bl, 1
  478.         add     bl, 0x10; now bl = BAR offset in PCI config. space
  479.         mov     ax, mmio_pci_addr
  480.         mov     bh, al  ; bh = dddddfff
  481.         mov     al, 2   ; al : DW to read
  482.         call    pci_read_reg
  483.         or      eax, eax
  484.         jnz     @f
  485.         mov     eax, -3 ; empty I/O space
  486.         jmp     mmio_ret_fail
  487. @@:
  488.         test    eax, 1
  489.         jz      @f
  490.         mov     eax, -4 ; damned ports (not MMIO space)
  491.         jmp     mmio_ret_fail
  492. @@:
  493.         pop     ecx     ; ecx = block size, bytes (expanded to whole page)
  494.         mov     ebx, ecx; user_alloc destroys eax, ecx, edx, but saves ebx
  495.         and     eax, 0xFFFFFFF0
  496.         push    eax           ; store MMIO physical address + keep 2DWords in the stack
  497.         stdcall user_alloc, ecx
  498.         or      eax, eax
  499.         jnz     mmio_map_over
  500.         mov     eax, -5 ; problem with page allocation
  501.  
  502. mmio_ret_fail:
  503.         pop     ecx
  504.         pop     edx
  505.         ret
  506.  
  507. mmio_map_over:
  508.         mov     ecx, ebx; ecx = size (bytes, expanded to whole page)
  509.         shr     ecx, 12 ; ecx = number of pages
  510.         mov     ebx, eax; ebx = linear address
  511.         pop     eax     ; eax = MMIO start
  512.         pop     edx     ; edx = MMIO shift (pages)
  513.         shl     edx, 12 ; edx = MMIO shift (bytes)
  514.         add     eax, edx; eax = uMMIO physical address
  515.         or      eax, PG_SHARED
  516.         or      eax, PG_UW
  517.         or      eax, PG_NOCACHE
  518.         mov     edi, ebx
  519.         call    commit_pages
  520.         mov     eax, edi
  521.         ret
  522.  
  523. ;***************************************************************************
  524. ;   Function
  525. ;      pci_mmio_unmap_page
  526. ;
  527. ;   Description
  528. ;       unmaps the linear space previously tied to a PCI memory block
  529. ;
  530. ;       IN: ebx = linear address of space previously allocated by pci_mmio_map
  531. ;       returns eax = 1 if successfully unmapped
  532. ;
  533. ;   Error codes
  534. ;       eax = -1 if no user PCI access allowed,
  535. ;       eax =  0 if unmapping failed
  536. ;***************************************************************************
  537.  
  538. pci_mmio_unmap:
  539.         stdcall user_free, ebx
  540.         ret
  541.  
  542. end if
  543.  
  544. ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  545. uglobal
  546. align 4
  547. ; VendID (2), DevID (2), Revision = 0 (1), Class Code (3), FNum (1), Bus (1)
  548. pci_emu_dat:
  549.                 times   30*10 db 0
  550. endg
  551. ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  552. align 4
  553. sys_pcibios:
  554.         cmp     [pci_access_enabled], 1
  555.         jne     .unsupported_func
  556.         cmp     [pci_bios_entry], 0
  557.         jz      .emulate_bios
  558.  
  559.         push    ds
  560.         mov     ax, pci_data_sel
  561.         mov     ds, ax
  562.         mov     eax, ebp
  563.         mov     ah, 0B1h
  564.         call    pword [cs:pci_bios_entry]
  565.         pop     ds
  566.  
  567.         jmp     .return
  568.         ;-=-=-=-=-=-=-=-=
  569. .emulate_bios:
  570.         cmp     ebp, 1                  ; PCI_FUNCTION_ID
  571.         jnz     .not_PCI_BIOS_PRESENT
  572.         mov     edx, 'PCI '
  573.         mov     al, [BOOT_VARS + 0x9020]
  574.         mov     bx, [BOOT_VARS + 0x9022]
  575.         mov     cl, [BOOT_VARS + 0x9021]
  576.         xor     ah, ah
  577.         jmp     .return_abcd
  578.  
  579. .not_PCI_BIOS_PRESENT:
  580.         cmp     ebp, 2                  ; FIND_PCI_DEVICE
  581.         jne     .not_FIND_PCI_DEVICE
  582.         mov     ebx, pci_emu_dat
  583. ..nxt:
  584.         cmp     [ebx], dx
  585.         jne     ..no
  586.         cmp     [ebx + 2], cx
  587.         jne     ..no
  588.         dec     si
  589.         jns     ..no
  590.         mov     bx, [ebx + 4]
  591.         xor     ah, ah
  592.         jmp     .return_ab
  593. ..no:
  594.         cmp     word[ebx], 0
  595.         je      ..dev_not_found
  596.         add     ebx, 10
  597.         jmp     ..nxt
  598. ..dev_not_found:
  599.         mov     ah, 0x86                ; DEVICE_NOT_FOUND
  600.         jmp     .return_a
  601.  
  602. .not_FIND_PCI_DEVICE:
  603.         cmp     ebp, 3                  ; FIND_PCI_CLASS_CODE
  604.         jne     .not_FIND_PCI_CLASS_CODE
  605.         mov     esi, pci_emu_dat
  606.         shl     ecx, 8
  607. ..nxt2:
  608.         cmp     [esi], ecx
  609.         jne     ..no2
  610.         mov     bx, [esi]
  611.         xor     ah, ah
  612.         jmp     .return_ab
  613. ..no2:
  614.         cmp     dword[esi], 0
  615.         je      ..dev_not_found
  616.         add     esi, 10
  617.         jmp     ..nxt2
  618.  
  619. .not_FIND_PCI_CLASS_CODE:
  620.         cmp     ebp, 8                  ; READ_CONFIG_*
  621.         jb      .not_READ_CONFIG
  622.         cmp     ebp, 0x0A
  623.         ja      .not_READ_CONFIG
  624.         mov     eax, ebp
  625.         mov     ah, bh
  626.         mov     edx, edi
  627.         mov     bh, bl
  628.         mov     bl, dl
  629.         call    pci_read_reg
  630.         mov     ecx, eax
  631.         xor     ah, ah                  ; SUCCESSFUL
  632.         jmp     .return_abc
  633. .not_READ_CONFIG:
  634.         cmp     ebp, 0x0B               ; WRITE_CONFIG_*
  635.         jb      .not_WRITE_CONFIG
  636.         cmp     ebp, 0x0D
  637.         ja      .not_WRITE_CONFIG
  638.         lea     eax, [ebp+1]
  639.         mov     ah, bh
  640.         mov     edx, edi
  641.         mov     bh, bl
  642.         mov     bl, dl
  643.         call    pci_write_reg
  644.         xor     ah, ah                  ; SUCCESSFUL
  645.         jmp     .return_abc
  646. .not_WRITE_CONFIG:
  647. .unsupported_func:
  648.         mov     ah, 0x81                ; FUNC_NOT_SUPPORTED
  649. .return:
  650.         mov     dword[esp + 4 ], edi
  651.         mov     dword[esp + 8], esi
  652. .return_abcd:
  653.         mov     dword[esp + 24], edx
  654. .return_abc:
  655.         mov     dword[esp + 28], ecx
  656. .return_ab:
  657.         mov     dword[esp + 20], ebx
  658. .return_a:
  659.         mov     dword[esp + 32], eax
  660.         ret
  661.  
  662. PCI_VENDOR_ID           equ 0x00
  663. PCI_CLASS_REVISION      equ 0x08
  664. PCI_HEADER_TYPE         equ 0x0E
  665. PCI_SUBSYSTEM_VENDOR_ID equ 0x2c
  666. PCI_IRQ_LINE            equ 0x3C
  667.  
  668. proc pci_enum
  669.         push    ebp
  670.         mov     ebp, esp
  671.         push    0
  672. virtual at ebp-4
  673. .devfn          db      ?
  674. .bus            db      ?
  675. end virtual
  676. .loop:
  677.         mov     ah, [.bus]
  678.         mov     al, 2
  679.         mov     bh, [.devfn]
  680.         mov     bl, PCI_VENDOR_ID
  681.         call    pci_read_reg
  682.         cmp     eax, 0xFFFFFFFF
  683.         jnz     .has_device
  684.         test    byte [.devfn], 7
  685.         jnz     .next_func
  686.         jmp     .no_device
  687. .has_device:
  688.         push    eax
  689.         movi    eax, sizeof.PCIDEV
  690.         call    malloc
  691.         pop     ecx
  692.         test    eax, eax
  693.         jz      .nomemory
  694.         mov     edi, eax
  695.         mov     [edi+PCIDEV.vid_did], ecx
  696.         mov     edx, pcidev_list
  697.         list_add_tail edi, edx
  698.         mov     eax, dword [.devfn]
  699.         mov     word [edi+PCIDEV.devfn], ax
  700.         mov     bh, al
  701.         mov     al, 2
  702.         mov     bl, PCI_CLASS_REVISION
  703.         call    pci_read_reg
  704.         shr     eax, 8                                ;FIXME use byte mask
  705.         mov     [edi+PCIDEV.class], eax
  706.  
  707.         mov     ah, [.bus]
  708.         mov     bh, byte [.devfn]
  709.         mov     al, 2
  710.         mov     bl, PCI_SUBSYSTEM_VENDOR_ID
  711.         call    pci_read_reg
  712.         mov     [edi+PCIDEV.svid_sdid], eax
  713.  
  714.         mov     ah, [.bus]
  715.         mov     al, 0
  716.         mov     bh, [.devfn]
  717.         mov     bl, PCI_IRQ_LINE
  718.         call    pci_read_reg
  719.         mov     [edi+PCIDEV.irq_line], al
  720.  
  721.         test    byte [.devfn], 7
  722.         jnz     .next_func
  723.         mov     ah, [.bus]
  724.         mov     al, 0
  725.         mov     bh, [.devfn]
  726.         mov     bl, PCI_HEADER_TYPE
  727.         call    pci_read_reg
  728.         test    al, al
  729.         js      .next_func
  730. .no_device:
  731.         or      byte [.devfn], 7
  732. .next_func:
  733.         inc     dword [.devfn]
  734.         mov     ah, [.bus]
  735.         cmp     ah, [BOOT_VARS+0x9021]
  736.         jbe     .loop
  737. .nomemory:
  738.         leave
  739.         ret
  740. endp
  741.  
  742.  
  743. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  744.  
  745. ;internal functions
  746. ;ecx (bus << 8)|devfn
  747. ;edx register
  748.  
  749. align 4
  750. pci_bus:
  751. .conf1_index:
  752. ; dword CF8 = (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) | (devfn << 8) | (reg & 0xFC))
  753.                                 push    edx
  754.                                 mov             eax, edx                        ; eax = reg
  755.                                 shl             eax, 16                         ; eax = reg << 16
  756.                                 shl   ecx, 8                    ; ecx = (bus << 16)|(devfn<<8)
  757.                                 mov             al, dl                          ; eax = (reg << 16)|reg
  758.                                 and             eax, 0x0F0000FC           ; eax = ((reg & 0xF00) << 16)|(reg & 0xFC)
  759.                                 lea             eax, [0x80000000+eax+ecx]
  760.                                 mov     dx, 0xCF8
  761.                                 out             dx, eax
  762.                                 pop             edx
  763.                                 xor             eax, eax
  764.                                 ret
  765.  
  766. align 4
  767. .conf2_index:
  768. ; byte CF8 = 0xF0 | (fn << 1)
  769. ; byte CFA = bus
  770.                                 push    edx
  771.                                 mov             eax, ecx                ; (bus << 8)|devfn
  772.                                 and             al, 7                                           ; fn
  773.                                 lea             eax, [0xF0+eax+eax]
  774.                                 mov     dx, 0xCF8
  775.                                 out             dx, al
  776.                                 mov             al, ch                  ; bus
  777.                                 mov             dx, 0xCFA
  778.                                 out   dx, al
  779.                                 pop             edx
  780.                                 xor             eax, eax
  781.                                 ret
  782.  
  783. align 4
  784. .conf1_read8:
  785.                                 call  .conf1_index
  786.                                 and     dx, 3
  787.                                 add             dx, 0xCFC
  788.                                 in              al, dx
  789.                                 ret
  790.  
  791. align 4
  792. .conf1_read16:
  793.                                 call  .conf1_index
  794.                                 and     dx, 2
  795.                                 add             dx, 0xCFC
  796.                                 in              ax, dx
  797.                                 ret
  798.  
  799. align 4
  800. .conf1_read32:
  801.                                 call  .conf1_index
  802.                                 mov     dx, 0xCFC
  803.                                 in              eax, dx
  804.                                 ret
  805.  
  806. align 4
  807. .conf1_write8:
  808.                                 call  .conf1_index
  809.                                 mov             eax, [esp+4]
  810.                                 and     dx, 3
  811.                                 add             dx, 0xCFC
  812.                                 out             dx, al
  813.                                 ret   4
  814.  
  815. align 4
  816. .conf1_write16:
  817.                                 call  .conf1_index
  818.                                 mov             eax, [esp+4]
  819.                                 and     dx, 2
  820.                                 add             dx, 0xCFC
  821.                                 out             dx, ax
  822.                                 ret   4
  823.  
  824. align 4
  825. .conf1_write32:
  826.                                 call  .conf1_index
  827.                                 mov             eax, [esp+4]
  828.                                 mov             dx, 0xCFC
  829.                                 out   dx, eax
  830.                                 ret   4
  831.  
  832. align 4
  833. .conf2_read8:
  834. ; in (0xC000 | (dev << 8) | reg)
  835.                                 call  .conf2_index
  836.                                 and             ecx, 0xF1               ;ecx = dev << 3
  837.                                 shl             ecx, 5                  ;ecx = dev << 8
  838.                                 lea   edx, [0xC000+edx+ecx]
  839.                                 in              al, dx
  840.                                 ret
  841.  
  842. align 4
  843. .conf2_read16:
  844.                                 call  .conf2_index
  845.                                 and             ecx, 0xF1
  846.                                 shl             ecx, 5
  847.                                 lea   edx, [0xC000+edx+ecx]
  848.                                 in              ax, dx
  849.                                 ret
  850.  
  851. align 4
  852. .conf2_read32:
  853.                                 call  .conf2_index
  854.                                 and             ecx, 0xF1
  855.                                 shl             ecx, 5
  856.                                 lea   edx, [0xC000+edx+ecx]
  857.                                 in              eax, dx
  858.                                 ret
  859.  
  860. ;proc pci_read8   stdcall, bus:dword, devfn:dword, reg:dword
  861. ;proc pci_read16  stdcall, bus:dword, devfn:dword, reg:dword
  862. ;proc pci_read32  stdcall, bus:dword, devfn:dword, reg:dword
  863.  
  864. ;proc pci_write8  stdcall, bus:dword, devfn:dword, reg:dword, val:dword
  865. ;proc pci_write16 stdcall, bus:dword, devfn:dword, reg:dword, val:dword
  866. ;proc pci_write32 stdcall, bus:dword, devfn:dword, reg:dword, val:dword
  867.  
  868. PCI_R8  equ 0
  869. PCI_R16 equ 4
  870. PCI_R32 equ 8
  871.  
  872. PCI_W8  equ 12
  873. PCI_W16 equ 16
  874. PCI_W32 equ 20
  875.  
  876. align 8
  877. pci_fn_table:
  878. pci_bus_read8           dd pci_bus.conf1_read8           ;0
  879. pci_bus_read16  dd pci_bus.conf1_read16          ;4
  880. pci_bus_read32  dd pci_bus.conf1_read32          ;8
  881. pci_bus_write8  dd pci_bus.conf1_write8          ;12
  882. pci_bus_write16 dd pci_bus.conf1_write16         ;16
  883. pci_bus_write32 dd pci_bus.conf1_write32         ;20
  884.  
  885. align 4
  886. pci_read8:
  887.                                 mov             eax, PCI_R8
  888.                                 jmp             @F
  889.  
  890. align 4
  891. pci_read16:
  892.                                 mov             eax, PCI_R16
  893.                                 jmp             @F
  894.  
  895. align 4
  896. pci_read32:
  897.                                 mov             eax, PCI_R32
  898.  
  899. align 4
  900. @@:
  901. .bus                    equ esp+4
  902. .devfn          equ esp+8
  903. .pci_reg        equ esp+12
  904.  
  905.                                 xor             ecx, ecx
  906.                                 mov   ch, [.bus]
  907.                                 mov   cl, [.devfn]
  908.                                 movzx edx, word [.pci_reg]
  909.  
  910.                                 pushfd
  911.                                 cli
  912.  
  913.                                 call    dword [pci_fn_table+eax]
  914.  
  915.                                 popfd
  916.  
  917.                                 ret     12
  918.  
  919. align 4
  920. pci_write8:
  921.                                 mov             eax, PCI_W8
  922.                                 jmp             @F
  923.  
  924. align 4
  925. pci_write16:
  926.                                 mov             eax, PCI_W16
  927.                                 jmp             @F
  928.  
  929. align 4
  930. pci_write32:
  931.                                 mov             eax, PCI_W32
  932.  
  933. align 4
  934. @@:
  935. .bus                    equ esp+4
  936. .devfn          equ esp+8
  937. .pci_reg        equ esp+12
  938. .val      equ esp+16
  939.  
  940.                                 xor             ecx, ecx
  941.                                 mov   ch, [.bus]
  942.                                 mov   cl, [.devfn]
  943.                                 movzx edx, word [.pci_reg]
  944.  
  945.                                 pushfd
  946.                                 cli
  947.  
  948.                                 push  dword [esp+20]
  949.                                 call    dword [pci_fn_table+eax]
  950.  
  951.                                 popfd
  952.  
  953.                                 ret     16
  954.