Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2010. 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: 1591 $
  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_api.0
  39.         dd      pci_api.1
  40.         dd      pci_api.2
  41.         dd      pci_api.not_support     ;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_api.not_support     ;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. f62_rcall:
  55.         dd      pci_read_reg.0          ;4 byte
  56.         dd      pci_read_reg.1          ;5 word
  57.         dd      pci_read_reg.2          ;6 dword
  58. f62_rcall2:
  59.         dd      pci_read_reg_2.0        ;4 byte
  60.         dd      pci_read_reg_2.1        ;5 word
  61.         dd      pci_read_reg_2.2        ;6 dword
  62. f62_wcall:
  63.         dd      pci_write_reg.0         ;4 byte
  64.         dd      pci_write_reg.1         ;5 word
  65.         dd      pci_write_reg.2         ;6 dword
  66. f62_wcall2:
  67.         dd      pci_write_reg_2.0       ;4 byte
  68.         dd      pci_write_reg_2.1       ;5 word
  69.         dd      pci_write_reg_2.2       ;6 dword
  70. endg
  71.  
  72.  
  73. align 4
  74. pci_api:
  75.         movzx   eax,bl
  76.         cmp  [pci_access_enabled],1
  77.         jne  .no_pci_access_for_applications
  78.  
  79. if defined mmio_pci_addr
  80.         cmp eax, 13
  81.         jb .not_support
  82. else
  83.         cmp eax, 10
  84.         jb .not_support
  85. end if 
  86.         call dword [f62call+eax*4]
  87.         mov     dword [esp+32],eax
  88.         ret
  89.  
  90.  
  91.  
  92. ;       or al,al
  93. ;       jnz pci_fn_1
  94.         ; PCI function 0: get pci version (AH.AL)
  95. .0:
  96.         movzx   eax, word [BOOT_VAR+0x9022]
  97.         ret
  98.  
  99. ;pci_fn_1:
  100. ;       cmp al,1
  101. ;       jnz pci_fn_2
  102.  
  103.         ; PCI function 1: get last bus in AL
  104. .1:
  105.         movzx   eax, byte [BOOT_VAR+0x9021]
  106.         ret
  107.  
  108. ;pci_fn_2:
  109. ;       cmp al,2
  110. ;       jne pci_fn_3
  111.         ; PCI function 2: get pci access mechanism
  112. .2:
  113.         movzx   eax, byte [BOOT_VAR+0x9020]
  114.         ret
  115. ;pci_fn_3:
  116.  
  117. ;       cmp al,4
  118. ;       jz pci_read_reg   ;byte
  119. ;       cmp al,5
  120. ;       jz pci_read_reg   ;word
  121. ;       cmp al,6
  122. ;       jz pci_read_reg   ;dword
  123.  
  124. ;       cmp al,8
  125. ;       jz pci_write_reg  ;byte
  126. ;       cmp al,9
  127. ;       jz pci_write_reg  ;word
  128. ;       cmp al,10
  129. ;       jz pci_write_reg  ;dword
  130.  
  131. ;if defined mmio_pci_addr
  132. ;       cmp al,11           ;  user-level MMIO functions
  133. ;       jz pci_mmio_init
  134. ;       cmp al,12
  135. ;       jz pci_mmio_map
  136. ;       cmp al,13
  137. ;       jz pci_mmio_unmap
  138. ;end if
  139.  
  140. .not_support:
  141. .no_pci_access_for_applications:
  142.         or      eax,-1
  143.         ret
  144.  
  145. ;***************************************************************************
  146. ;   Function
  147. ;      pci_make_config_cmd
  148. ;
  149. ;   Description
  150. ;       creates a command dword  for use with the PCI bus
  151. ;       bus # in bh;ah
  152. ;       device+func in ch;bh (dddddfff)
  153. ;       register in cl;bl
  154. ;
  155. ;      command dword returned in ebx;eax ( 10000000 bbbbbbbb dddddfff rrrrrr00 )
  156. ;***************************************************************************
  157.  
  158. align 4
  159.  
  160. pci_make_config_cmd:
  161.     shl     ebx,8;eax,8    ; move bus to bits 16-23
  162.     mov     bx,cx;ax,bx    ; combine all
  163.     and     ebx,0xffffff;eax,0xffffff
  164.     or      ebx,0x80000000;eax,0x80000000
  165.     ret
  166.  
  167. ;***************************************************************************
  168. ;   Function
  169. ;      pci_read_reg:
  170. ;
  171. ;   Description
  172. ;       read a register from the PCI config space into EAX/AX/AL
  173. ;       IN: ah=bus,device+func=bh,register address=bl
  174. ;           number of bytes to read (1,2,4) coded into AL, bits 0-1
  175. ;           (0 - byte, 1 - word, 2 - dword)
  176. ;***************************************************************************
  177.  
  178. align 4
  179.  
  180. pci_read_reg:
  181.         cmp     byte [BOOT_VAR+0x9020],2 ;what mechanism will we use?
  182.         je      pci_read_reg_2
  183.  
  184.                 ; mechanism 1
  185. ;       push    esi   ; save register size into ESI
  186.         mov     esi,ebx;eax
  187.         and     esi,3
  188.  
  189.         call    pci_make_config_cmd
  190.         mov     eax,ebx;ebx,eax
  191.                 ; get current state
  192.         mov     dx,0xcf8
  193.         in      eax, dx
  194.         push    eax
  195.                 ; set up addressing to config data
  196.         mov     eax,ebx
  197.         and     al,0xfc ; make address dword-aligned
  198.         out     dx,eax
  199.                 ; get requested DWORD of config data
  200.         mov     dl,0xfc
  201.         and     bl,3
  202.         or      dl,bl    ; add to port address first 2 bits of register address
  203.  
  204. ;       or      esi,esi
  205. ;       jz      pci_read_byte1
  206. ;       cmp     esi,1
  207. ;       jz      pci_read_word1
  208. ;       cmp     esi,2
  209. ;       jz      pci_read_dword1
  210. ;       jmp     pci_fin_read1
  211.         jmp     dword [f62_rcall+esi*4]
  212.  
  213. .0:
  214.         in      al,dx
  215.         jmp .pci_fin_read1
  216. .1:
  217.         in      ax,dx
  218.         jmp .pci_fin_read1
  219. .2:
  220.         in      eax,dx
  221. ;       jmp     pci_fin_read1
  222. .pci_fin_read1:
  223.                 ; restore configuration control
  224.         xchg    eax,[esp]
  225.         mov     dx,0xcf8
  226.         out     dx,eax
  227.  
  228.         pop     eax
  229.         ;pop    esi
  230.         ret
  231. pci_read_reg_2:
  232.  
  233.         test    ch,128;bh,128   ;mech#2 only supports 16 devices per bus
  234.         jnz     pci_api.not_support
  235.  
  236. ;       push esi   ; save register size into ESI
  237.         mov esi,ebx;eax
  238.         and esi,3
  239.  
  240.         push    ebx;eax
  241.         mov     eax,ebx
  242.                 ;store current state of config space
  243.         mov     dx,0xcf8
  244.         in      al,dx
  245.         mov     ah,al
  246.         mov     dl,0xfa
  247.         in      al,dx
  248.  
  249.         xchg    eax,[esp]
  250.                 ; out 0xcfa,bus
  251.         mov     al,ah
  252.         out     dx,al
  253.                 ; out 0xcf8,0x80
  254.         mov     dl,0xf8
  255.         mov     al,0x80
  256.         out     dx,al
  257.                 ; compute addr
  258.         shr     ch,3;bh,3 ; func is ignored in mechanism 2
  259.         or      ch,0xc0;bh,0xc0
  260.         mov     dx,cx;bx
  261.  
  262. ;       or      esi,esi
  263. ;       jz      pci_read_byte2
  264. ;       cmp     esi,1
  265. ;       jz      pci_read_word2
  266. ;       cmp     esi,2
  267. ;       jz      pci_read_dword2
  268. ;       jmp     pci_fin_read2
  269.         jmp     dword [f62_rcall2+esi*4]
  270.  
  271. .0:
  272.         in      al,dx
  273.         jmp .pci_fin_read2
  274. .1:
  275.         in      ax,dx
  276.         jmp .pci_fin_read2
  277. .2:
  278.         in      eax,dx
  279. ;       jmp pci_fin_read2
  280.  
  281. .pci_fin_read2:
  282.  
  283.                 ; restore configuration space
  284.         xchg    eax,[esp]
  285.         mov     dx,0xcfa
  286.         out     dx,al
  287.         mov     dl,0xf8
  288.         mov     al,ah
  289.         out     dx,al
  290.  
  291.         pop     eax
  292. ;       pop     esi
  293.         ret
  294.  
  295. ;pci_read_reg_err:
  296. ;       or      dword [esp+32],-1
  297. ;       ret
  298.  
  299.  
  300. ;***************************************************************************
  301. ;   Function
  302. ;      pci_write_reg:
  303. ;
  304. ;   Description
  305. ;       write a register from ECX/CX/CL into the PCI config space
  306. ;       IN: ah=bus,device+func=bh,register address (dword aligned)=bl,
  307. ;           value to write in ecx
  308. ;           number of bytes to write (1,2,4) coded into AL, bits 0-1
  309. ;           (0 - byte, 1 - word, 2 - dword)
  310. ;***************************************************************************
  311.  
  312. align 4
  313.  
  314. pci_write_reg:
  315.         cmp byte [BOOT_VAR+0x9020],2 ;what mechanism will we use?
  316.         je pci_write_reg_2
  317.  
  318.                 ; mechanism 1
  319. ;       push    esi   ; save register size into ESI
  320.         mov     esi,ebx;eax
  321.         and     esi,3   ;not need
  322.  
  323.         call    pci_make_config_cmd
  324.         mov     eax,ebx;ebx,eax
  325.         mov     ecx,edx         ;cross registers
  326.                 ; get current state into ecx
  327.         mov     dx,0xcf8
  328.         in      eax, dx
  329.         push    eax
  330.                 ; set up addressing to config data
  331.         mov     eax,ebx
  332.         and     al,0xfc ; make address dword-aligned
  333.         out     dx,eax
  334.                 ; write DWORD of config data
  335.         mov     dl,0xfc
  336.         and     bl,3
  337.         or      dl,bl
  338.         mov     eax,ecx
  339.  
  340. ;       or      esi,esi
  341. ;       jz      pci_write_byte1
  342. ;       cmp     esi,1
  343. ;       jz      pci_write_word1
  344. ;       cmp     esi,2
  345. ;       jz      pci_write_dword1
  346. ;       jmp     pci_fin_write1
  347.         jmp     dword [f62_wcall+esi*4]
  348. .0:
  349.         out     dx,al
  350.         jmp .pci_fin_write1
  351. .1:
  352.         out     dx,ax
  353.         jmp .pci_fin_write1
  354. .2:
  355.         out     dx,eax
  356. .pci_fin_write1:
  357.  
  358.                 ; restore configuration control
  359.         pop     eax
  360.         mov     dl,0xf8
  361.         out     dx,eax
  362.  
  363.         xor     eax,eax
  364.         ;pop    esi
  365.         ret
  366. pci_write_reg_2:
  367.  
  368.         test    ch,128;bh,128   ;mech#2 only supports 16 devices per bus
  369.         jnz     pci_api.not_support
  370.  
  371.  
  372. ;       push esi   ; save register size into ESI
  373.         mov esi,eax
  374.         and esi,3       ;not need
  375.  
  376.         push    eax
  377.         mov     ecx,edx         ;cross registers
  378.                 ;store current state of config space
  379.         mov     dx,0xcf8
  380.         in      al,dx
  381.         mov     ah,al
  382.         mov     dl,0xfa
  383.         in      al,dx
  384.         xchg    eax,[esp]
  385.                 ; out 0xcfa,bus
  386.         mov     al,ah
  387.         out     dx,al
  388.                 ; out 0xcf8,0x80
  389.         mov     dl,0xf8
  390.         mov     al,0x80
  391.         out     dx,al
  392.                 ; compute addr
  393.         shr     bh,3 ; func is ignored in mechanism 2
  394.         or      bh,0xc0
  395.         mov     dx,bx
  396.                 ; write register
  397.         mov     eax,ecx
  398.  
  399. ;       or      esi,esi
  400. ;       jz      pci_write_byte2
  401. ;       cmp     esi,1
  402. ;       jz      pci_write_word2
  403. ;       cmp     esi,2
  404. ;       jz      pci_write_dword2
  405. ;       jmp     pci_fin_write2
  406.         jmp     dword [f62_wcall2+esi*4]
  407. .0:
  408.         out     dx,al
  409.         jmp .pci_fin_write2
  410. .1:
  411.         out     dx,ax
  412.         jmp .pci_fin_write2
  413. .2:
  414.         out     dx,eax
  415. .pci_fin_write2:
  416.                 ; restore configuration space
  417.         pop     eax
  418.         mov     dx,0xcfa
  419.         out     dx,al
  420.         mov     dl,0xf8
  421.         mov     al,ah
  422.         out     dx,al
  423.  
  424.         xor     eax,eax
  425.         ;pop    esi
  426.         ret
  427.  
  428. ;pci_write_reg_err:
  429. ;       xor     eax,eax
  430. ;       dec     eax
  431. ;       ret
  432.  
  433. if defined mmio_pci_addr        ; must be set above
  434. ;***************************************************************************
  435. ;   Function
  436. ;      pci_mmio_init
  437. ;
  438. ;   Description
  439. ;       IN:  cx = device's PCI bus address (bbbbbbbbdddddfff)
  440. ;   Returns  eax = user heap space available (bytes)
  441. ;   Error codes
  442. ;       eax = -1 : PCI user access blocked,
  443. ;       eax = -2 : device not registered for uMMIO service
  444. ;       eax = -3 : user heap initialization failure
  445. ;***************************************************************************
  446. pci_mmio_init:
  447.     cmp     cx, mmio_pci_addr  
  448.     jz      @f
  449.     mov     eax,-2
  450.     ret
  451. @@:
  452.     call    init_heap      ; (if not initialized yet)
  453.     or      eax,eax
  454.     jz      @f
  455.     ret
  456. @@:
  457.     mov     eax,-3
  458.     ret
  459.  
  460.  
  461. ;***************************************************************************
  462. ;   Function
  463. ;      pci_mmio_map
  464. ;
  465. ;   Description
  466. ;       maps a block of PCI memory to user-accessible linear address
  467. ;
  468. ;       WARNING! This VERY EXPERIMENTAL service is for one chosen PCI device only!
  469. ;       The target device address should be set in kernel var mmio_pci_addr
  470. ;
  471. ;       IN:  ah = BAR#;
  472. ;       IN: ebx = block size (bytes);
  473. ;       IN: ecx = offset in MMIO block (in 4K-pages, to avoid misaligned pages);
  474. ;
  475. ;   Returns eax = MMIO block's linear address in the userspace (if no error)
  476. ;
  477. ;
  478. ;   Error codes
  479. ;       eax = -1 : user access to PCI blocked,
  480. ;       eax = -2 : an invalid BAR register referred
  481. ;       eax = -3 : no i/o space on that BAR
  482. ;       eax = -4 : a port i/o BAR register referred
  483. ;       eax = -5 : dynamic userspace allocation problem
  484. ;***************************************************************************
  485.  
  486. pci_mmio_map:
  487. ;cross
  488.         mov     eax,ebx
  489.         mov     ebx,ecx
  490.         mov     ecx,edx
  491. ;;;;;;;;;;;;;;;;;;;
  492.     and     edx,0x0ffff
  493.     cmp     ah,6
  494.     jc     .bar_0_5
  495.     jz     .bar_rom
  496.     mov     eax,-2
  497.     ret
  498. .bar_rom:
  499.     mov    ah, 8        ; bar6 = Expansion ROM base address
  500. .bar_0_5:
  501.     push    ecx
  502.     add     ebx, 4095
  503.     and     ebx,-4096
  504.     push    ebx
  505.     mov     bl, ah      ; bl = BAR# (0..5), however bl=8 for BAR6
  506.     shl     bl, 1
  507.     shl     bl, 1
  508.     add     bl, 0x10    ; now bl = BAR offset in PCI config. space
  509.     mov     ax, mmio_pci_addr
  510.     mov     bh, al      ; bh = dddddfff
  511.     mov     al, 2       ; al : DW to read
  512.     call    pci_read_reg
  513.     or      eax, eax
  514.     jnz     @f
  515.     mov     eax,-3      ; empty I/O space
  516.     jmp     mmio_ret_fail
  517. @@:
  518.     test    eax, 1
  519.     jz      @f
  520.     mov     eax,-4      ; damned ports (not MMIO space)
  521.     jmp     mmio_ret_fail
  522. @@:
  523.     pop     ecx         ; ecx = block size, bytes (expanded to whole page)
  524.     mov     ebx, ecx    ; user_alloc destroys eax, ecx, edx, but saves ebx
  525.     and     eax, 0xFFFFFFF0
  526.     push    eax               ; store MMIO physical address + keep 2DWords in the stack
  527.     stdcall user_alloc, ecx
  528.     or      eax, eax
  529.     jnz     mmio_map_over
  530.     mov     eax,-5      ; problem with page allocation
  531.  
  532. mmio_ret_fail:
  533.     pop     ecx
  534.     pop     edx
  535.     ret
  536.  
  537. mmio_map_over:
  538.     mov     ecx, ebx    ; ecx = size (bytes, expanded to whole page)
  539.     shr     ecx, 12     ; ecx = number of pages
  540.     mov     ebx, eax    ; ebx = linear address
  541.     pop     eax         ; eax = MMIO start
  542.     pop     edx         ; edx = MMIO shift (pages)
  543.     shl     edx, 12     ; edx = MMIO shift (bytes)
  544.     add     eax, edx    ; eax = uMMIO physical address
  545.     or      eax, PG_SHARED
  546.     or      eax, PG_UW
  547.     or      eax, PG_NOCACHE
  548.     mov     edi, ebx
  549.     call    commit_pages
  550.     mov     eax, edi
  551.     ret
  552.  
  553. ;***************************************************************************
  554. ;   Function
  555. ;      pci_mmio_unmap_page
  556. ;
  557. ;   Description
  558. ;       unmaps the linear space previously tied to a PCI memory block
  559. ;
  560. ;       IN: ebx = linear address of space previously allocated by pci_mmio_map
  561. ;       returns eax = 1 if successfully unmapped
  562. ;
  563. ;   Error codes
  564. ;       eax = -1 if no user PCI access allowed,
  565. ;       eax =  0 if unmapping failed
  566. ;***************************************************************************
  567.  
  568. pci_mmio_unmap:
  569.     stdcall user_free, ecx;ebx
  570.     ret
  571.  
  572. end if
  573.  
  574. ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  575. uglobal
  576. align 4
  577. ; VendID (2), DevID (2), Revision = 0 (1), Class Code (3), FNum (1), Bus (1)
  578. pci_emu_dat:    times   30*10 db 0
  579. endg
  580. ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  581. align 4
  582. sys_pcibios:
  583.         cmp     [pci_access_enabled], 1
  584.         jne     .unsupported_func
  585.         cmp     [pci_bios_entry], 0
  586.         jz      .emulate_bios
  587.  
  588.         push    ds
  589.         mov     ax, pci_data_sel
  590.         mov     ds, ax
  591.         mov     eax, ebp
  592.         mov     ah, 0B1h
  593.         call    pword [cs:pci_bios_entry]
  594.         pop     ds
  595.  
  596.         jmp     .return
  597.         ;-=-=-=-=-=-=-=-=
  598. .emulate_bios:
  599.         cmp     ebp, 1                  ; PCI_FUNCTION_ID
  600.         jnz     .not_PCI_BIOS_PRESENT
  601.         mov     edx, 'PCI '
  602.         mov     al, [OS_BASE+0x2F0000 + 0x9020]
  603.         mov     bx, [OS_BASE+0x2F0000 + 0x9022]
  604.         mov     cl, [OS_BASE+0x2F0000 + 0x9021]
  605.         xor     ah, ah
  606.         jmp     .return_abcd
  607.  
  608. .not_PCI_BIOS_PRESENT:
  609.         cmp     ebp, 2                  ; FIND_PCI_DEVICE
  610.         jne     .not_FIND_PCI_DEVICE
  611.         mov     ebx, pci_emu_dat
  612. ..nxt:  cmp     [ebx], dx
  613.         jne     ..no
  614.         cmp     [ebx + 2], cx
  615.         jne     ..no
  616.         dec     si
  617.         jns     ..no
  618.         mov     bx, [ebx + 4]
  619.         xor     ah, ah
  620.         jmp     .return_ab
  621. ..no:   cmp     word[ebx], 0
  622.         je      ..dev_not_found
  623.         add     ebx, 10
  624.         jmp     ..nxt
  625. ..dev_not_found:
  626.         mov     ah, 0x86                ; DEVICE_NOT_FOUND
  627.         jmp     .return_a
  628.  
  629. .not_FIND_PCI_DEVICE:
  630.         cmp     ebp, 3                  ; FIND_PCI_CLASS_CODE
  631.         jne     .not_FIND_PCI_CLASS_CODE
  632.         mov     esi, pci_emu_dat
  633.         shl     ecx, 8
  634. ..nxt2: cmp     [esi], ecx
  635.         jne     ..no2
  636.         mov     bx, [esi]
  637.         xor     ah, ah
  638.         jmp     .return_ab
  639. ..no2:  cmp     dword[esi], 0
  640.         je      ..dev_not_found
  641.         add     esi, 10
  642.         jmp     ..nxt2
  643.  
  644. .not_FIND_PCI_CLASS_CODE:
  645.         cmp     ebp, 8                  ; READ_CONFIG_*
  646.         jb      .not_READ_CONFIG
  647.         cmp     ebp, 0x0A
  648.         ja      .not_READ_CONFIG
  649.         mov     eax, ebp
  650.         mov     ah, bh
  651.         mov     edx, edi
  652.         mov     bh, bl
  653.         mov     bl, dl
  654.         call    pci_read_reg
  655.         mov     ecx, eax
  656.         xor     ah, ah                  ; SUCCESSFUL
  657.         jmp     .return_abc
  658. .not_READ_CONFIG:
  659.         cmp     ebp, 0x0B               ; WRITE_CONFIG_*
  660.         jb      .not_WRITE_CONFIG
  661.         cmp     ebp, 0x0D
  662.         ja      .not_WRITE_CONFIG
  663.         lea     eax, [ebp+1]
  664.         mov     ah, bh
  665.         mov     edx, edi
  666.         mov     bh, bl
  667.         mov     bl, dl
  668.         call    pci_write_reg
  669.         xor     ah, ah                  ; SUCCESSFUL
  670.         jmp     .return_abc
  671. .not_WRITE_CONFIG:
  672. .unsupported_func:
  673.         mov     ah, 0x81                ; FUNC_NOT_SUPPORTED
  674. .return:mov     dword[esp + 4 ], edi
  675.         mov     dword[esp + 8], esi
  676. .return_abcd:
  677.         mov     dword[esp + 24], edx
  678. .return_abc:
  679.         mov     dword[esp + 28], ecx
  680. .return_ab:
  681.         mov     dword[esp + 20], ebx
  682. .return_a:
  683.         mov     dword[esp + 32], eax
  684.         ret
  685.