Subversion Repositories Kolibri OS

Rev

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

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