Subversion Repositories Kolibri OS

Rev

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: 4418 $
  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. proc pci_enum
  663.         push    ebp
  664.         mov     ebp, esp
  665.         push    0
  666. virtual at ebp-4
  667. .devfn          db      ?
  668. .bus            db      ?
  669. end virtual
  670. .loop:
  671.         mov     ah, [.bus]
  672.         mov     al, 2
  673.         mov     bh, [.devfn]
  674.         mov     bl, 0
  675.         call    pci_read_reg
  676.         cmp     eax, 0xFFFFFFFF
  677.         jnz     .has_device
  678.         test    byte [.devfn], 7
  679.         jnz     .next_func
  680.         jmp     .no_device
  681. .has_device:
  682.         push    eax
  683.         movi    eax, sizeof.PCIDEV
  684.         call    malloc
  685.         pop     ecx
  686.         test    eax, eax
  687.         jz      .nomemory
  688.         mov     edi, eax
  689.         mov     [edi+PCIDEV.vendor_device_id], ecx
  690.         mov     eax, pcidev_list
  691.         mov     ecx, [eax+PCIDEV.bk]
  692.         mov     [edi+PCIDEV.bk], ecx
  693.         mov     [edi+PCIDEV.fd], eax
  694.         mov     [ecx+PCIDEV.fd], edi
  695.         mov     [eax+PCIDEV.bk], edi
  696.         mov     eax, dword [.devfn]
  697.         mov     dword [edi+PCIDEV.devfn], eax
  698.         mov     dword [edi+PCIDEV.owner], 0
  699.         mov     bh, al
  700.         mov     al, 2
  701.         mov     bl, 8
  702.         call    pci_read_reg
  703.         shr     eax, 8
  704.         mov     [edi+PCIDEV.class], eax
  705.         test    byte [.devfn], 7
  706.         jnz     .next_func
  707.         mov     ah, [.bus]
  708.         mov     al, 0
  709.         mov     bh, [.devfn]
  710.         mov     bl, 0Eh
  711.         call    pci_read_reg
  712.         test    al, al
  713.         js      .next_func
  714. .no_device:
  715.         or      byte [.devfn], 7
  716. .next_func:
  717.         inc     dword [.devfn]
  718.         mov     ah, [.bus]
  719.         cmp     ah, [BOOT_VARS+0x9021]
  720.         jbe     .loop
  721. .nomemory:
  722.         leave
  723.         ret
  724. endp
  725.