Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2015. 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: 5577 $
  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.         mov     dx, 0xcf8
  169.         in      eax, dx
  170.         push    eax
  171.                 ; set up addressing to config data
  172.         mov     eax, ebx
  173.         and     al, 0xfc; make address dword-aligned
  174.         out     dx, eax
  175.                 ; get requested DWORD of config data
  176.         mov     dl, 0xfc
  177.         and     bl, 3
  178.         or      dl, bl   ; add to port address first 2 bits of register address
  179.  
  180.         or      esi, esi
  181.         jz      pci_read_byte1
  182.         cmp     esi, 1
  183.         jz      pci_read_word1
  184.         cmp     esi, 2
  185.         jz      pci_read_dword1
  186.         jmp     pci_fin_read1
  187.  
  188. pci_read_byte1:
  189.         in      al, dx
  190.         jmp     pci_fin_read1
  191. pci_read_word1:
  192.         in      ax, dx
  193.         jmp     pci_fin_read1
  194. pci_read_dword1:
  195.         in      eax, dx
  196.         jmp     pci_fin_read1
  197. pci_fin_read1:
  198.                 ; restore configuration control
  199.         xchg    eax, [esp]
  200.         mov     dx, 0xcf8
  201.         out     dx, eax
  202.  
  203.         pop     eax
  204.         pop     esi ebx
  205.         ret
  206. pci_read_reg_2:
  207.  
  208.         test    bh, 128 ;mech#2 only supports 16 devices per bus
  209.         jnz     pci_read_reg_err
  210.  
  211.         mov     esi, eax ; save register size into ESI
  212.         and     esi, 3
  213.  
  214.         push    eax
  215.                 ;store current state of config space
  216.         mov     dx, 0xcf8
  217.         in      al, dx
  218.         mov     ah, al
  219.         mov     dl, 0xfa
  220.         in      al, dx
  221.  
  222.         xchg    eax, [esp]
  223.                 ; out 0xcfa,bus
  224.         mov     al, ah
  225.         out     dx, al
  226.                 ; out 0xcf8,0x80
  227.         mov     dl, 0xf8
  228.         mov     al, 0x80
  229.         out     dx, al
  230.                 ; compute addr
  231.         shr     bh, 3; func is ignored in mechanism 2
  232.         or      bh, 0xc0
  233.         mov     dx, bx
  234.  
  235.         or      esi, esi
  236.         jz      pci_read_byte2
  237.         cmp     esi, 1
  238.         jz      pci_read_word2
  239.         cmp     esi, 2
  240.         jz      pci_read_dword2
  241.         jmp     pci_fin_read2
  242.  
  243. pci_read_byte2:
  244.         in      al, dx
  245.         jmp     pci_fin_read2
  246. pci_read_word2:
  247.         in      ax, dx
  248.         jmp     pci_fin_read2
  249. pci_read_dword2:
  250.         in      eax, dx
  251. ;       jmp pci_fin_read2
  252. pci_fin_read2:
  253.  
  254.                 ; restore configuration space
  255.         xchg    eax, [esp]
  256.         mov     dx, 0xcfa
  257.         out     dx, al
  258.         mov     dl, 0xf8
  259.         mov     al, ah
  260.         out     dx, al
  261.  
  262.         pop     eax
  263.         pop     esi ebx
  264.         ret
  265.  
  266. pci_read_reg_err:
  267.         xor     eax, eax
  268.         dec     eax
  269.         pop     esi ebx
  270.         ret
  271.  
  272.  
  273. ;***************************************************************************
  274. ;   Function
  275. ;      pci_write_reg:
  276. ;
  277. ;   Description
  278. ;       write a register from ECX/CX/CL into the PCI config space
  279. ;       IN: ah=bus,device+func=bh,register address (dword aligned)=bl,
  280. ;           value to write in ecx
  281. ;           number of bytes to write (1,2,4) coded into AL, bits 0-1
  282. ;           (0 - byte, 1 - word, 2 - dword)
  283. ;***************************************************************************
  284.  
  285. align 4
  286.  
  287. pci_write_reg:
  288.         push    esi ebx
  289.         cmp     byte [BOOT_VARS+0x9020], 2;what mechanism will we use?
  290.         je      pci_write_reg_2
  291.  
  292.                 ; mechanism 1
  293.         mov     esi, eax ; save register size into ESI
  294.         and     esi, 3
  295.  
  296.         call    pci_make_config_cmd
  297.         mov     ebx, eax
  298.                 ; get current state into ecx
  299.         mov     dx, 0xcf8
  300.         in      eax, dx
  301.         push    eax
  302.                 ; set up addressing to config data
  303.         mov     eax, ebx
  304.         and     al, 0xfc; make address dword-aligned
  305.         out     dx, eax
  306.                 ; write DWORD of config data
  307.         mov     dl, 0xfc
  308.         and     bl, 3
  309.         or      dl, bl
  310.         mov     eax, ecx
  311.  
  312.         or      esi, esi
  313.         jz      pci_write_byte1
  314.         cmp     esi, 1
  315.         jz      pci_write_word1
  316.         cmp     esi, 2
  317.         jz      pci_write_dword1
  318.         jmp     pci_fin_write1
  319.  
  320. pci_write_byte1:
  321.         out     dx, al
  322.         jmp     pci_fin_write1
  323. pci_write_word1:
  324.         out     dx, ax
  325.         jmp     pci_fin_write1
  326. pci_write_dword1:
  327.         out     dx, eax
  328.         jmp     pci_fin_write1
  329. pci_fin_write1:
  330.  
  331.                 ; restore configuration control
  332.         pop     eax
  333.         mov     dl, 0xf8
  334.         out     dx, eax
  335.  
  336.         xor     eax, eax
  337.         pop     ebx esi
  338.  
  339.         ret
  340. pci_write_reg_2:
  341.  
  342.         test    bh, 128 ;mech#2 only supports 16 devices per bus
  343.         jnz     pci_write_reg_err
  344.  
  345.  
  346.         mov     esi, eax ; save register size into ESI
  347.         and     esi, 3
  348.  
  349.         push    eax
  350.                 ;store current state of config space
  351.         mov     dx, 0xcf8
  352.         in      al, dx
  353.         mov     ah, al
  354.         mov     dl, 0xfa
  355.         in      al, dx
  356.         xchg    eax, [esp]
  357.                 ; out 0xcfa,bus
  358.         mov     al, ah
  359.         out     dx, al
  360.                 ; out 0xcf8,0x80
  361.         mov     dl, 0xf8
  362.         mov     al, 0x80
  363.         out     dx, al
  364.                 ; compute addr
  365.         shr     bh, 3; func is ignored in mechanism 2
  366.         or      bh, 0xc0
  367.         mov     dx, bx
  368.                 ; write register
  369.         mov     eax, ecx
  370.  
  371.         or      esi, esi
  372.         jz      pci_write_byte2
  373.         cmp     esi, 1
  374.         jz      pci_write_word2
  375.         cmp     esi, 2
  376.         jz      pci_write_dword2
  377.         jmp     pci_fin_write2
  378.  
  379. pci_write_byte2:
  380.         out     dx, al
  381.         jmp     pci_fin_write2
  382. pci_write_word2:
  383.         out     dx, ax
  384.         jmp     pci_fin_write2
  385. pci_write_dword2:
  386.         out     dx, eax
  387.         jmp     pci_fin_write2
  388. pci_fin_write2:
  389.                 ; restore configuration space
  390.         pop     eax
  391.         mov     dx, 0xcfa
  392.         out     dx, al
  393.         mov     dl, 0xf8
  394.         mov     al, ah
  395.         out     dx, al
  396.  
  397.         xor     eax, eax
  398.         pop     ebx esi
  399.         ret
  400.  
  401. pci_write_reg_err:
  402.         xor     eax, eax
  403.         dec     eax
  404.         pop     ebx esi
  405.         ret
  406.  
  407. if defined mmio_pci_addr        ; must be set above
  408. ;***************************************************************************
  409. ;   Function
  410. ;      pci_mmio_init
  411. ;
  412. ;   Description
  413. ;       IN:  bx = device's PCI bus address (bbbbbbbbdddddfff)
  414. ;   Returns  eax = user heap space available (bytes)
  415. ;   Error codes
  416. ;       eax = -1 : PCI user access blocked,
  417. ;       eax = -2 : device not registered for uMMIO service
  418. ;       eax = -3 : user heap initialization failure
  419. ;***************************************************************************
  420. pci_mmio_init:
  421.         cmp     bx, mmio_pci_addr
  422.         jz      @f
  423.         mov     eax, -2
  424.         ret
  425. @@:
  426.         call    init_heap  ; (if not initialized yet)
  427.         or      eax, eax
  428.         jz      @f
  429.         ret
  430. @@:
  431.         mov     eax, -3
  432.         ret
  433.  
  434.  
  435. ;***************************************************************************
  436. ;   Function
  437. ;      pci_mmio_map
  438. ;
  439. ;   Description
  440. ;       maps a block of PCI memory to user-accessible linear address
  441. ;
  442. ;       WARNING! This VERY EXPERIMENTAL service is for one chosen PCI device only!
  443. ;       The target device address should be set in kernel var mmio_pci_addr
  444. ;
  445. ;       IN:  ah = BAR#;
  446. ;       IN: ebx = block size (bytes);
  447. ;       IN: ecx = offset in MMIO block (in 4K-pages, to avoid misaligned pages);
  448. ;
  449. ;   Returns eax = MMIO block's linear address in the userspace (if no error)
  450. ;
  451. ;
  452. ;   Error codes
  453. ;       eax = -1 : user access to PCI blocked,
  454. ;       eax = -2 : an invalid BAR register referred
  455. ;       eax = -3 : no i/o space on that BAR
  456. ;       eax = -4 : a port i/o BAR register referred
  457. ;       eax = -5 : dynamic userspace allocation problem
  458. ;***************************************************************************
  459.  
  460. pci_mmio_map:
  461.         and     edx, 0x0ffff
  462.         cmp     ah, 6
  463.         jc      .bar_0_5
  464.         jz      .bar_rom
  465.         mov     eax, -2
  466.         ret
  467. .bar_rom:
  468.         mov     ah, 8   ; bar6 = Expansion ROM base address
  469. .bar_0_5:
  470.         push    ecx
  471.         add     ebx, 4095
  472.         and     ebx, -4096
  473.         push    ebx
  474.         mov     bl, ah  ; bl = BAR# (0..5), however bl=8 for BAR6
  475.         shl     bl, 1
  476.         shl     bl, 1
  477.         add     bl, 0x10; now bl = BAR offset in PCI config. space
  478.         mov     ax, mmio_pci_addr
  479.         mov     bh, al  ; bh = dddddfff
  480.         mov     al, 2   ; al : DW to read
  481.         call    pci_read_reg
  482.         or      eax, eax
  483.         jnz     @f
  484.         mov     eax, -3 ; empty I/O space
  485.         jmp     mmio_ret_fail
  486. @@:
  487.         test    eax, 1
  488.         jz      @f
  489.         mov     eax, -4 ; damned ports (not MMIO space)
  490.         jmp     mmio_ret_fail
  491. @@:
  492.         pop     ecx     ; ecx = block size, bytes (expanded to whole page)
  493.         mov     ebx, ecx; user_alloc destroys eax, ecx, edx, but saves ebx
  494.         and     eax, 0xFFFFFFF0
  495.         push    eax           ; store MMIO physical address + keep 2DWords in the stack
  496.         stdcall user_alloc, ecx
  497.         or      eax, eax
  498.         jnz     mmio_map_over
  499.         mov     eax, -5 ; problem with page allocation
  500.  
  501. mmio_ret_fail:
  502.         pop     ecx
  503.         pop     edx
  504.         ret
  505.  
  506. mmio_map_over:
  507.         mov     ecx, ebx; ecx = size (bytes, expanded to whole page)
  508.         shr     ecx, 12 ; ecx = number of pages
  509.         mov     ebx, eax; ebx = linear address
  510.         pop     eax     ; eax = MMIO start
  511.         pop     edx     ; edx = MMIO shift (pages)
  512.         shl     edx, 12 ; edx = MMIO shift (bytes)
  513.         add     eax, edx; eax = uMMIO physical address
  514.         or      eax, PG_SHARED
  515.         or      eax, PG_UW
  516.         or      eax, PG_NOCACHE
  517.         mov     edi, ebx
  518.         call    commit_pages
  519.         mov     eax, edi
  520.         ret
  521.  
  522. ;***************************************************************************
  523. ;   Function
  524. ;      pci_mmio_unmap_page
  525. ;
  526. ;   Description
  527. ;       unmaps the linear space previously tied to a PCI memory block
  528. ;
  529. ;       IN: ebx = linear address of space previously allocated by pci_mmio_map
  530. ;       returns eax = 1 if successfully unmapped
  531. ;
  532. ;   Error codes
  533. ;       eax = -1 if no user PCI access allowed,
  534. ;       eax =  0 if unmapping failed
  535. ;***************************************************************************
  536.  
  537. pci_mmio_unmap:
  538.         stdcall user_free, ebx
  539.         ret
  540.  
  541. end if
  542.  
  543. ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  544. uglobal
  545. align 4
  546. ; VendID (2), DevID (2), Revision = 0 (1), Class Code (3), FNum (1), Bus (1)
  547. pci_emu_dat:
  548.                 times   30*10 db 0
  549. endg
  550. ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  551. align 4
  552. sys_pcibios:
  553.         cmp     [pci_access_enabled], 1
  554.         jne     .unsupported_func
  555.         cmp     [pci_bios_entry], 0
  556.         jz      .emulate_bios
  557.  
  558.         push    ds
  559.         mov     ax, pci_data_sel
  560.         mov     ds, ax
  561.         mov     eax, ebp
  562.         mov     ah, 0B1h
  563.         call    pword [cs:pci_bios_entry]
  564.         pop     ds
  565.  
  566.         jmp     .return
  567.         ;-=-=-=-=-=-=-=-=
  568. .emulate_bios:
  569.         cmp     ebp, 1                  ; PCI_FUNCTION_ID
  570.         jnz     .not_PCI_BIOS_PRESENT
  571.         mov     edx, 'PCI '
  572.         mov     al, [BOOT_VARS + 0x9020]
  573.         mov     bx, [BOOT_VARS + 0x9022]
  574.         mov     cl, [BOOT_VARS + 0x9021]
  575.         xor     ah, ah
  576.         jmp     .return_abcd
  577.  
  578. .not_PCI_BIOS_PRESENT:
  579.         cmp     ebp, 2                  ; FIND_PCI_DEVICE
  580.         jne     .not_FIND_PCI_DEVICE
  581.         mov     ebx, pci_emu_dat
  582. ..nxt:
  583.         cmp     [ebx], dx
  584.         jne     ..no
  585.         cmp     [ebx + 2], cx
  586.         jne     ..no
  587.         dec     si
  588.         jns     ..no
  589.         mov     bx, [ebx + 4]
  590.         xor     ah, ah
  591.         jmp     .return_ab
  592. ..no:
  593.         cmp     word[ebx], 0
  594.         je      ..dev_not_found
  595.         add     ebx, 10
  596.         jmp     ..nxt
  597. ..dev_not_found:
  598.         mov     ah, 0x86                ; DEVICE_NOT_FOUND
  599.         jmp     .return_a
  600.  
  601. .not_FIND_PCI_DEVICE:
  602.         cmp     ebp, 3                  ; FIND_PCI_CLASS_CODE
  603.         jne     .not_FIND_PCI_CLASS_CODE
  604.         mov     esi, pci_emu_dat
  605.         shl     ecx, 8
  606. ..nxt2:
  607.         cmp     [esi], ecx
  608.         jne     ..no2
  609.         mov     bx, [esi]
  610.         xor     ah, ah
  611.         jmp     .return_ab
  612. ..no2:
  613.         cmp     dword[esi], 0
  614.         je      ..dev_not_found
  615.         add     esi, 10
  616.         jmp     ..nxt2
  617.  
  618. .not_FIND_PCI_CLASS_CODE:
  619.         cmp     ebp, 8                  ; READ_CONFIG_*
  620.         jb      .not_READ_CONFIG
  621.         cmp     ebp, 0x0A
  622.         ja      .not_READ_CONFIG
  623.         mov     eax, ebp
  624.         mov     ah, bh
  625.         mov     edx, edi
  626.         mov     bh, bl
  627.         mov     bl, dl
  628.         call    pci_read_reg
  629.         mov     ecx, eax
  630.         xor     ah, ah                  ; SUCCESSFUL
  631.         jmp     .return_abc
  632. .not_READ_CONFIG:
  633.         cmp     ebp, 0x0B               ; WRITE_CONFIG_*
  634.         jb      .not_WRITE_CONFIG
  635.         cmp     ebp, 0x0D
  636.         ja      .not_WRITE_CONFIG
  637.         lea     eax, [ebp+1]
  638.         mov     ah, bh
  639.         mov     edx, edi
  640.         mov     bh, bl
  641.         mov     bl, dl
  642.         call    pci_write_reg
  643.         xor     ah, ah                  ; SUCCESSFUL
  644.         jmp     .return_abc
  645. .not_WRITE_CONFIG:
  646. .unsupported_func:
  647.         mov     ah, 0x81                ; FUNC_NOT_SUPPORTED
  648. .return:
  649.         mov     dword[esp + 4 ], edi
  650.         mov     dword[esp + 8], esi
  651. .return_abcd:
  652.         mov     dword[esp + 24], edx
  653. .return_abc:
  654.         mov     dword[esp + 28], ecx
  655. .return_ab:
  656.         mov     dword[esp + 20], ebx
  657. .return_a:
  658.         mov     dword[esp + 32], eax
  659.         ret
  660.  
  661. PCI_VENDOR_ID           equ 0x00
  662. PCI_CLASS_REVISION      equ 0x08
  663. PCI_HEADER_TYPE         equ 0x0E
  664. PCI_SUBSYSTEM_VENDOR_ID equ 0x2c
  665. PCI_IRQ_LINE            equ 0x3C
  666.  
  667. proc pci_enum
  668.         push    ebp
  669.         mov     ebp, esp
  670.         push    0
  671. virtual at ebp-4
  672. .devfn          db      ?
  673. .bus            db      ?
  674. end virtual
  675. .loop:
  676.         mov     ah, [.bus]
  677.         mov     al, 2
  678.         mov     bh, [.devfn]
  679.         mov     bl, PCI_VENDOR_ID
  680.         call    pci_read_reg
  681.         cmp     eax, 0xFFFFFFFF
  682.         jnz     .has_device
  683.         test    byte [.devfn], 7
  684.         jnz     .next_func
  685.         jmp     .no_device
  686. .has_device:
  687.         push    eax
  688.         movi    eax, sizeof.PCIDEV
  689.         call    malloc
  690.         pop     ecx
  691.         test    eax, eax
  692.         jz      .nomemory
  693.         mov     edi, eax
  694.         mov     [edi+PCIDEV.vendor_device_id], ecx
  695.         mov     edx, pcidev_list
  696.         list_add_tail edi, edx
  697.         mov     eax, dword [.devfn]
  698.         mov     word [edi+PCIDEV.devfn], ax
  699.         mov     bh, al
  700.         mov     al, 2
  701.         mov     bl, PCI_CLASS_REVISION
  702.         call    pci_read_reg
  703.         shr     eax, 8                                ;FIXME use byte mask
  704.         mov     [edi+PCIDEV.class], eax
  705.  
  706. ;        mov     ah, [.bus]
  707. ;        mov     bh, byte [.devfn]
  708. ;        mov     al, 2
  709. ;        mov     bl, PCI_SUBSYSTEM_VENDOR_ID
  710. ;        call    pci_read_reg
  711. ;        mov     [edi+PCIDEV.svid_sdid], eax
  712.  
  713. ;        mov     ah, [.bus]
  714. ;        mov     al, 0
  715. ;        mov     bh, [.devfn]
  716. ;        mov     bl, PCI_IRQ_LINE
  717. ;        call    pci_read_reg
  718. ;        mov     [edi+PCIDEV.irq_line], al
  719.  
  720.         test    byte [.devfn], 7
  721.         jnz     .next_func
  722.         mov     ah, [.bus]
  723.         mov     al, 0
  724.         mov     bh, [.devfn]
  725.         mov     bl, PCI_HEADER_TYPE
  726.         call    pci_read_reg
  727.         test    al, al
  728.         js      .next_func
  729. .no_device:
  730.         or      byte [.devfn], 7
  731. .next_func:
  732.         inc     dword [.devfn]
  733.         mov     ah, [.bus]
  734.         cmp     ah, [BOOT_VARS+0x9021]
  735.         jbe     .loop
  736. .nomemory:
  737.         leave
  738.         ret
  739. endp
  740.  
  741. ; Export for drivers. Just returns the pointer to the pci-devices list.
  742. proc get_pcidev_list
  743.         mov     eax, pcidev_list
  744.         ret
  745. endp
  746.  
  747. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  748.  
  749. ;internal functions
  750. ;ecx (bus << 8)|devfn
  751. ;edx register
  752.  
  753. align 4
  754. pci_bus:
  755. .conf1_index:
  756. ; dword CF8 = (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) | (devfn << 8) | (reg & 0xFC))
  757.                                 push    edx
  758.                                 mov             eax, edx                        ; eax = reg
  759.                                 shl             eax, 16                         ; eax = reg << 16
  760.                                 shl   ecx, 8                    ; ecx = (bus << 16)|(devfn<<8)
  761.                                 mov             al, dl                          ; eax = (reg << 16)|reg
  762.                                 and             eax, 0x0F0000FC           ; eax = ((reg & 0xF00) << 16)|(reg & 0xFC)
  763.                                 lea             eax, [0x80000000+eax+ecx]
  764.                                 mov     dx, 0xCF8
  765.                                 out             dx, eax
  766.                                 pop             edx
  767.                                 xor             eax, eax
  768.                                 ret
  769.  
  770. align 4
  771. .conf2_index:
  772. ; byte CF8 = 0xF0 | (fn << 1)
  773. ; byte CFA = bus
  774.                                 push    edx
  775.                                 mov             eax, ecx                ; (bus << 8)|devfn
  776.                                 and             al, 7                                           ; fn
  777.                                 lea             eax, [0xF0+eax+eax]
  778.                                 mov     dx, 0xCF8
  779.                                 out             dx, al
  780.                                 mov             al, ch                  ; bus
  781.                                 mov             dx, 0xCFA
  782.                                 out   dx, al
  783.                                 pop             edx
  784.                                 xor             eax, eax
  785.                                 ret
  786.  
  787. align 4
  788. .conf1_read8:
  789.                                 call  .conf1_index
  790.                                 and     dx, 3
  791.                                 add             dx, 0xCFC
  792.                                 in              al, dx
  793.                                 ret
  794.  
  795. align 4
  796. .conf1_read16:
  797.                                 call  .conf1_index
  798.                                 and     dx, 2
  799.                                 add             dx, 0xCFC
  800.                                 in              ax, dx
  801.                                 ret
  802.  
  803. align 4
  804. .conf1_read32:
  805.                                 call  .conf1_index
  806.                                 mov     dx, 0xCFC
  807.                                 in              eax, dx
  808.                                 ret
  809.  
  810. align 4
  811. .conf1_write8:
  812.                                 call  .conf1_index
  813.                                 mov             eax, [esp+4]
  814.                                 and     dx, 3
  815.                                 add             dx, 0xCFC
  816.                                 out             dx, al
  817.                                 ret   4
  818.  
  819. align 4
  820. .conf1_write16:
  821.                                 call  .conf1_index
  822.                                 mov             eax, [esp+4]
  823.                                 and     dx, 2
  824.                                 add             dx, 0xCFC
  825.                                 out             dx, ax
  826.                                 ret   4
  827.  
  828. align 4
  829. .conf1_write32:
  830.                                 call  .conf1_index
  831.                                 mov             eax, [esp+4]
  832.                                 mov             dx, 0xCFC
  833.                                 out   dx, eax
  834.                                 ret   4
  835.  
  836. align 4
  837. .conf2_read8:
  838. ; in (0xC000 | (dev << 8) | reg)
  839.                                 call  .conf2_index
  840.                                 and             ecx, 0xF1               ;ecx = dev << 3
  841.                                 shl             ecx, 5                  ;ecx = dev << 8
  842.                                 lea   edx, [0xC000+edx+ecx]
  843.                                 in              al, dx
  844.                                 ret
  845.  
  846. align 4
  847. .conf2_read16:
  848.                                 call  .conf2_index
  849.                                 and             ecx, 0xF1
  850.                                 shl             ecx, 5
  851.                                 lea   edx, [0xC000+edx+ecx]
  852.                                 in              ax, dx
  853.                                 ret
  854.  
  855. align 4
  856. .conf2_read32:
  857.                                 call  .conf2_index
  858.                                 and             ecx, 0xF1
  859.                                 shl             ecx, 5
  860.                                 lea   edx, [0xC000+edx+ecx]
  861.                                 in              eax, dx
  862.                                 ret
  863.  
  864.  
  865. PCI_R8  equ 0
  866. PCI_R16 equ 4
  867. PCI_R32 equ 8
  868.  
  869. PCI_W8  equ 12
  870. PCI_W16 equ 16
  871. PCI_W32 equ 20
  872.  
  873.  
  874. align 4
  875. pci_conf1_rw:
  876. ;internal function
  877. ;eax accessor
  878. ;ecx (bus << 8)|devfn
  879.  
  880. .val      equ esp+4
  881.  
  882. ; dword CF8 = (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) | (devfn << 8) | (reg & 0xFC))
  883.  
  884.                                 pushfd
  885.                                 cli
  886.  
  887.                                 push  edx
  888.                                 push  eax
  889.                                 mov             eax, edx                        ; eax = reg
  890.                                 shl             eax, 16                         ; eax = reg << 16
  891.                                 shl   ecx, 8                    ; ecx = (bus << 16)|(devfn<<8)
  892.                                 mov             al, dl                          ; eax = (reg << 16)|reg
  893.                                 and             eax, 0x0F0000FC           ; eax = ((reg & 0xF00) << 16)|(reg & 0xFC)
  894.                                 lea             eax, [0x80000000+eax+ecx]
  895.                                 mov     dx, 0xCF8
  896.                                 out             dx, eax
  897.                                 pop             eax
  898.                                 pop   edx
  899.                                 jmp   dword [.fntab+eax]
  900. .r32:
  901.                                 mov     dx, 0xCFC
  902.                                 in              eax, dx
  903. .rdone:
  904.                                 popfd
  905.                                 ret
  906. .r16:
  907.                                 and     dx, 2
  908.                                 add             dx, 0xCFC
  909.                                 in              al, dx
  910.                                 jmp   .rdone
  911. .r8:
  912.                                 and     dx, 3
  913.                                 add             dx, 0xCFC
  914.                                 in              al, dx
  915.                                 jmp   .rdone
  916. .w32:
  917.                                 mov             eax, [esp+8]
  918.                                 mov             dx, 0xCFC
  919.                                 out   dx, eax
  920. .wdone:
  921.                                 popfd
  922.                                 ret   4
  923. .w16:
  924.                                 mov             eax, [esp+8]
  925.                                 and     dx, 2
  926.                                 add             dx, 0xCFC
  927.                                 out             dx, ax
  928.                                 jmp   .wdone
  929. .w8:
  930.                                 mov             eax, [esp+8]
  931.                                 and     dx, 3
  932.                                 add             dx, 0xCFC
  933.                                 out             dx, al
  934.                                 jmp   .wdone
  935.  
  936. align 4
  937. .fntab:
  938.                                 dd .r8
  939.                                 dd .r16
  940.                                 dd .r32
  941.                                 dd .w8
  942.                                 dd .w16
  943.                                 dd .w32
  944.  
  945. align 4
  946. pci_fn_rw       dd pci_conf1_rw
  947.  
  948. ;proc pci_bus_read8   fastcall, busaddr:dword, reg:dword
  949. ;proc pci_bus_read16  fastcall, busaddr:dword, reg:dword
  950. ;proc pci_bus_read32  fastcall, busaddr:dword, reg:dword
  951.  
  952. align 4
  953. pci_bus_read8:
  954.                                 xor     eax, eax
  955.                                 jmp     dword [pci_fn_rw]
  956.  
  957. align 4
  958. pci_bus_read16:
  959.                                 mov             eax, PCI_R16
  960.                                 jmp     dword [pci_fn_rw]
  961.  
  962. align 4
  963. pci_bus_read32:
  964.                                 mov             eax, PCI_R32
  965.                                 jmp     dword [pci_fn_rw]
  966.  
  967. ;proc pci_bus_write8  fastcall, busaddr:dword, reg:dword, val: dword
  968. ;proc pci_bus_write16 fastcall, busaddr:dword, reg:dword, val: dword
  969. ;proc pci_bus_write32 fastcall, busaddr:dword, reg:dword, val: dword
  970.  
  971. align 4
  972. pci_bus_write8:
  973.                                 mov       eax, PCI_W8
  974.                                 jmp     dword [pci_fn_rw]
  975.  
  976. align 4
  977. pci_bus_write16:
  978.                                 mov             eax, PCI_W16
  979.                                 jmp     dword [pci_fn_rw]
  980.  
  981. align 4
  982. pci_bus_write32:
  983.                                 mov             eax, PCI_W32
  984.                                 jmp     dword [pci_fn_rw]
  985.  
  986. ;deprecated proc pci_read8   stdcall, bus:dword, devfn:dword, reg:dword
  987. ;deprecated proc pci_read16  stdcall, bus:dword, devfn:dword, reg:dword
  988. ;deprecated proc pci_read32  stdcall, bus:dword, devfn:dword, reg:dword
  989.  
  990. align 4
  991. pci_read8:
  992. .bus                    equ esp+4
  993. .devfn          equ esp+8
  994. .pci_reg        equ esp+12
  995. .val      equ esp+16
  996.  
  997.                                 movzx ecx, byte [.devfn]
  998.                                 mov   ch, [.bus]
  999.                                 movzx edx, word [.pci_reg]
  1000.                                 call    pci_bus_read8
  1001.                                 ret     12
  1002.  
  1003. align 4
  1004. pci_read16:
  1005. .bus                    equ esp+4
  1006. .devfn          equ esp+8
  1007. .pci_reg        equ esp+12
  1008. .val      equ esp+16
  1009.  
  1010.                                 movzx ecx, byte [.devfn]
  1011.                                 mov   ch, [.bus]
  1012.                                 movzx edx, word [.pci_reg]
  1013.                                 call    pci_bus_read16
  1014.                                 ret     12
  1015.  
  1016. align 4
  1017. pci_read32:
  1018. .bus                    equ esp+4
  1019. .devfn          equ esp+8
  1020. .pci_reg        equ esp+12
  1021. .val      equ esp+16
  1022.  
  1023.                                 movzx ecx, byte [.devfn]
  1024.                                 mov   ch, [.bus]
  1025.                                 movzx edx, word [.pci_reg]
  1026.                                 call    pci_bus_read32
  1027.                                 ret     12
  1028.  
  1029. ;deprecated proc pci_write8  stdcall, bus:dword, devfn:dword, reg:dword, val:dword
  1030. ;deprecated proc pci_write16 stdcall, bus:dword, devfn:dword, reg:dword, val:dword
  1031. ;deprecated proc pci_write32 stdcall, bus:dword, devfn:dword, reg:dword, val:dword
  1032.  
  1033. align 4
  1034. pci_write8:
  1035. .bus                    equ esp+4
  1036. .devfn          equ esp+8
  1037. .pci_reg        equ esp+12
  1038. .val      equ esp+16
  1039.  
  1040.                                 movzx ecx, byte [.devfn]
  1041.                                 mov   ch, [.bus]
  1042.                                 movzx edx, word [.pci_reg]
  1043.                                 push    dword [esp+16]
  1044.                                 call    pci_bus_write8
  1045.                                 ret     16
  1046.  
  1047. align 4
  1048. pci_write16:
  1049. .bus                    equ esp+4
  1050. .devfn          equ esp+8
  1051. .pci_reg        equ esp+12
  1052. .val      equ esp+16
  1053.  
  1054.                                 movzx ecx, byte [.devfn]
  1055.                                 mov   ch, [.bus]
  1056.                                 movzx edx, word [.pci_reg]
  1057.                                 push    dword [esp+16]
  1058.                                 call    pci_bus_write16
  1059.                                 ret     16
  1060.  
  1061. align 4
  1062. pci_write32:
  1063. .bus                    equ esp+4
  1064. .devfn          equ esp+8
  1065. .pci_reg        equ esp+12
  1066. .val      equ esp+16
  1067.  
  1068.                                 movzx ecx, byte [.devfn]
  1069.                                 mov   ch, [.bus]
  1070.                                 movzx edx, word [.pci_reg]
  1071.                                 push    dword [esp+16]
  1072.                                 call    pci_bus_write32
  1073.                                 ret     16
  1074.  
  1075.  
  1076.  
  1077.