And if that image link doesn't work, here:
http://s56.photobucket.com/albums/g162/rhyno_dagreat/?action=view¤t=i_have_ac97_audio.jpg
;NOTE: I (Rhyno), will have my own comments in here on how this works, so I can show you what I do
;understand. These comment titles with be preceded and suffixed with three asterisks (***), From here, look
;at RHYNO'S COMMENT ON START.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; By Dex. ;;
;; PCIFindDevice: scan through PCI space, ;;
;; looking for a device+vendor ID. ;;
;; C:\fasm pci.asm pci.com ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;***RHYNO'S COMMENT ON START***
;What you're doing here is making the data segment and the extra segment the same as the code segment,
;then displaying a welcome message and setting up EAX with the Device ID & the Vendor ID
;in such a way that:
;
; |Device ID | Vendor ID|
; 31---------15---------0
;
;and then calling pciFindDevice with that information, and if it returns and the carry flag is 0, then
;it prints that it found the graphics card. If it returns with a carry, then the device wasn't found and
;the program exits.
;***END OF RHYNO'S COMMENT - from here, go to comment (2)***
use16
org 0x100
;====================================================;
; Start. ;
;====================================================;
start:
mov ax,cs
mov ds,ax
mov es,ax
call Cls
call Cursor
call Welcome
mov ax, 24D5h ; put your Device ID here
shl eax,16
mov ax, 8086h ; put your Vendor ID here
call pciFindDevice
jnc @f
mov dx,NotFound ; couldn't find graphic card
mov ah,9
int 21h
jmp exit
WelcomeMessage db "Press any key to test for your card ",10,13,"$"
NotFound db "Error: Unable to find graphic card",10,13,"$"
Found db "Found graphic card",10,13,"$"
@@:
mov dx,Found ; Found graphic card
mov ah,9
int 21h
exit:
xor ax,ax
int 16h
int 20h
;===============================================================
; 8/16/32bit PCI reader
;
; Entry: EAX=PCI Bus/Device/fn/register number
; BIT30 set if 32 bit access requested
; BIT29 set if 16 bit access requested
; otherwise defaults to 8bit read
;
; Exit: DL,DX,EDX register data depending on requested read size
;
; Note: this routine is meant to be called via pciRegRead8, pciRegread16,
; or pciRegRead32, listed below.
;
; Note2: don't attempt to read 32bits of data from a non dword aligned reg
; number. Likewise, don't do 16bit reads from non word aligned reg #
;
BIT30 EQU 40000000h
BIT31 EQU 80000000h
PCI_INDEX_PORT EQU 0CF8h
PCI_DATA_PORT EQU 0CFCh
PCI32 EQU BIT31 ; bitflag to signal 32bit access
PCI16 EQU BIT30 ; bitflag for 16bit access
VIA_VID equ 8086h ; Intel vendor ID
VIA_DID equ 24D5h ; AC'97 Audio device ID
;***RHYNO'S COMMENT ON pciRegRead (4)***
;First of all EBX and CX are pushed on the stack for later. Then it takes
;the contents of EAX (which were the generic 32 bit PCI bus address), and
;saves a copy in EBX, and saves a copy of DH because DH will contain a return
;value. Then the top to bits of EAX are cleared again, and the top bit is set
;again to make it a PCI access request. The next line I don't quite understand,
;
; and al, NOT 3
;
;but the line after that the PCI Index Port (0xCF8) is moved into DX and the data
;in EAX is sent out through that port. Then the PCI Data Port (0xCFCh) is moved into
;DX, and the original low byte of EAX (stored in BL) is moved back to AL, then ANDed
;with 3. Then AL is added to the low byte (Not sure why it's anded and added?) of the PCI Data Port stored in DX, and
;it does a 32 bit read into EAX from DX. Then the contents of EBX are tested to see
;if the high bit is set. If they are, then the contents of EAX are copied to EDX.
;If it's not, then the contents of AX are stored in DX and then it tests to see if the
;top two bits of EBX are set. If they aren't, then CL is moved into DH for 8 bit read.
;If the top two bits are set, then EBX is stored in EAX and EAX is masked to turn off the
;top two bits. Then the original CX and EBX are popped of the stack, and the function is returned.
;***END OF RHYNO'S COMMENT***
pciRegRead:
push ebx
push cx
mov ebx,eax ; save eax, dh
mov cl,dh
and eax,NOT PCI32+PCI16 ; clear out data size request
or eax,BIT31 ; make a PCI access request
and al,NOT 3 ; force index to be dword
mov dx,PCI_INDEX_PORT
out dx,eax ; write PCI selector
mov dx,PCI_DATA_PORT
mov al,bl
and al,3 ; figure out which port to
add dl,al ; read to
in eax,dx ; do 32bit read
test ebx,PCI32
jz @f
mov edx,eax ; return 32bits of data
@@:
mov dx,ax ; return 16bits of data
test ebx,PCI32+PCI16
jnz @f
mov dh,cl ; restore dh for 8 bit read
@@:
mov eax,ebx ; restore eax
and eax,NOT PCI32+PCI16 ; clear out data size request
pop cx
pop ebx
ret
pciRegRead8:
and eax,NOT PCI32+PCI16 ; clear out data size request
jmp pciRegRead ; call generic PCI access
pciRegRead16:
and eax,NOT PCI32+PCI16 ; clear out data size request
or eax,PCI16 ; call generic PCI access
jmp pciRegRead
;***RHYNO'S COMMENT ON pciRegRead32 (3)***
;What happens is it takes the current address on the PCI bus given via EAX,
;then masks (ANDs) it with the inverse of the first two bits set to clear those two bits.
;It then ORs them with the top bit to set that one for generic PCI access. It then goes to
;pciRegRead.
;***END OF RHYNO'S COMMENT - from here go to comment (4)***
pciRegRead32:
and eax,NOT PCI32+PCI16 ; clear out data size request
or eax,PCI32 ; call generic PCI access
jmp pciRegRead
;===============================================================
; PCIFindDevice: scan through PCI space looking for a device+vendor ID
;
; Entry: EAX=Device+vendor ID
;
; Exit: EAX=PCI address if device found
; CY clear if found, set if not found. EAX invalid if CY set.
;
; [old stackless] Destroys: ebx, edx, esi, edi, cl
;
;***RHYNO'S COMMENT (2)***
;What pciFindDevice does is it first pushes cx, edx, esi, and edi onto the stack
;and then saves original copy of EAX (vendor and device IDs) inside of the source
;index register. Then it stores 100h before the starting address of the PCI bus in
;the destination index and adds 100h to it (100h being the size of a PCI configuration space
;or 256 bytes total), then sets the carry flag. It then checks to make sure it's not at the end of the PCI bus.
;If it is, it exits the scan (in which it pushes everything onto the stack, stores
;the PCI address into EAX from the destination index and turns off the high bit. It then pops everything
;off the stack and returns.), else it moves the current address into eax and calls pciRegRead32.
;It then checks to see if the returned vendor and device IDs are the same as the ones given.
;If they are not, then it goes to the next PCI config space and checks that one. If they are the same, then
;it clears the carry flag and exits with the given information.
;***END OF RHYNO'S COMMENT - from here go to comment (3)***
pciFindDevice:
push cx
push edx
push esi
push edi
mov esi,eax ; save off vend+device ID
mov edi,(80000000h - 100h) ; start with bus 0, dev 0 func 0
nextPCIDevice:
add edi,100h
cmp edi,80fff800h ; scanned all devices?
stc
jz PCIscanExit ; not found
mov eax, edi ; read PCI registers
call pciRegRead32
cmp edx, esi ; found device?
jnz nextPCIDevice
clc
PCIscanExit :
pushf
mov eax,edi ; return found PCI address
and eax,NOT BIT31 ; return only bus/dev/fn #
popf
pop edi
pop esi
pop edx
pop cx
ret
;====================================================;
; Clear screen. ;
;====================================================;
Cls:
mov ax,0x0600
mov bh,0x07
mov cx,0x0000
mov dx,0x184f
int 10h
ret
;====================================================;
; Set cursor. ;
;====================================================;
Cursor:
mov ah,02
mov bh,00
mov dx,0x0100
int 10h
ret
;====================================================;
; Welcome. ;
;====================================================;
Welcome:
mov dx,WelcomeMessage
mov ah,9
int 21h
xor ax,ax
int 16h
ret
VendorDeviceID dd 0