
tmpl       dd ?
PCIVENDOR  db 'Vendor: ',0
PCIDEVICE  db 'Device: ',0

;VendorSign        db 13 dup(0)

;_get_cpuid:
;          xor   eax, eax
;          _cpuid        ; TASM 3.2 dont have cpuid pentium instructions
;          push  ebx
;          shl   ebx, 16
;          mov   word ptr VendorSign,  bx
;          pop   ebx
;          mov   word ptr VendorSign+2,bx
;          push  edx
;          shl   edx, 16
;          mov   word ptr VendorSign+4,  dx
;          pop   edx
;          mov   word ptr VendorSign+6,  dx
;          push  ecx
;          shl   ecx, 16
;          mov   word ptr VendorSign+8,  cx
;          pop   ecx
;          mov   word ptr VendorSign+10, cx
;          ; mov  byte ptr VendorSign+12, eax ; 00
;          lea   si, VendorSign
;          mov   al, 01
;          int   21h
;_skipcpuid:

; ===========================================================================
enumerate_pcidevices proc far
; ===========================================================================
enumerate_pci:
           mov al, pcibus ; this is also indicator that machine is 486+/32bit
           or  al, al
           jnz  _pci
           ret
_pci:
           xor ax, ax
           mov pcitype, ax
           xor ax, ax
           mov dx, 0cf8h
           out dx, al
           mov dx, 0cfah
           out dx, al
           mov dx, 0cf8h
           in  al, dx
           mov ah, al
           mov dx, 0cfah
           in  al, dx
           or  al, al
           jnz its_pci_type1
           or  ah, ah
           jnz its_pci_type1
           mov al, 2
           mov pcitype, ax
           jmp short disp_pcitype
its_pci_type1:
           mov dx, 0cf8h
           in  eax, dx
           mov tmpl, eax
           mov eax, 80000000h
           mov dx, 0cf8h
           out dx, eax
           in  eax, dx
           cmp eax, 80000000h
           jne not_pcitype1
           mov al, 1
           mov pcitype, ax
not_pcitype1:
           mov eax, tmpl
           mov dx, 0cf8h
           out dx, eax
disp_pcitype:
           mov ax, pcitype
           cmp ax, 1
           jne pcichk_2
           mov ecx, 511
_pcit1l:
           push ecx
           mov  eax, 80000000h
           mov  ebx, ecx
           add  eax, ebx
           xor  edx, edx
           mov  ebx, 2048
           mul  ebx
           mov  dx, 0cf8h
           out  dx, eax
           mov  dx, 0cfch
           in   eax, dx
           mov  tmpl, eax
           and  eax, 0ffffh
           cmp  eax, 0ffffh
           je   _pcit1n
           mov  eax, tmpl
           shr  eax, 16
           cmp  eax, 0ffffh
           je   _pcit1n
           ; Pci  Device: Vendor: (l and 0ffff) Device: (l and 16)
           _print PCIVENDOR, 1
           mov  eax, tmpl
           and  eax, 0ffffh
           shr  eax, 16
           call put_hex
           _print PCIDEVICE, 1
           mov  eax, tmpl
           and  eax, 16
           call put_hex
           _newline
_pcit1n:
           pop  ecx
           dec  ecx
           jnz  _pcit1l
pcichk_2:
           mov  dx, 0cf8h
           mov  al, 80h
           out  dx, al
           mov  dx, 0cfah
           xor  ax, ax
           out  dx, al          ; Bus select?
           mov  cx, 15
_pcit2l:
           push cx
           mov  ax, cx
           xor  dx, dx
           mov  bx, 0100h ; 256
           mul  bx
           mov  bx, 0c000h
           add  ax, bx
           mov  dx, ax 
           in   eax, dx
           mov  eax, tmpl
           and  eax, 0ffffh
           cmp  eax, 0ffffh
           je   _pcit2n
           mov  eax, tmpl
           shr  eax, 16
           cmp  eax, 0ffffh
           je   _pcit2n
           ; Pci  Device: Vendor: (l and 0ffff) Device: (l and 16)
           _print PCIVENDOR, 1
           mov  eax, tmpl
           and  eax, 0ffffh
           shr  eax, 16
           call put_hex
           _print PCIDEVICE, 1
           mov  eax, tmpl
           and  eax, 16
           call put_hex
           _newline
_pcit2n:
           pop  cx
           dec  cx
           jnz  _pcit2l
           ret
enumerate_pcidevices endp

enableA20 proc far
	;; This subroutine will enable the A20 address line in the keyboard
	;; controller.  Takes no arguments.  Returns 0 in EAX on success, 
	;; -1 on failure.  Written for use in 16-bit code, see lines marked
	;; with 32-BIT for use in 32-bit code.

	pusha

	;; Make sure interrupts are disabled
	cli

	;; Keep a counter so that we can make up to 5 attempts to turn
	;; on A20 if necessary
	mov CX, 5

	.startAttempt1:		
	;; Wait for the controller to be ready for a command
	.commandWait1:
	xor AX, AX
	in AL, 64h
	bt AX, 1
	jc .commandWait1

	;; Tell the controller we want to read the current status.
	;; Send the command D0h: read output port.
	mov AL, 0D0h
	out 64h, AL

	;; Wait for the controller to be ready with a byte of data
	.dataWait1:
	xor AX, AX
	in AL, 64h
	bt AX, 0
	jnc .dataWait1

	;; Read the current port status from port 60h
	xor AX, AX
	in AL, 60h

	;; Save the current value of (E)AX
	push AX			; 16-BIT
	;; push EAX		; 32-BIT

	;; Wait for the controller to be ready for a command
	.commandWait2:
	in AL, 64h
	bt AX, 1
	jc .commandWait2

	;; Tell the controller we want to write the status byte again
	mov AL, 0D1h
	out 64h, AL	

	;; Wait for the controller to be ready for the data
	.commandWait3:
	xor AX, AX
	in AL, 64h
	bt AX, 1
	jc .commandWait3

	;; Write the new value to port 60h.  Remember we saved the old
	;; value on the stack
	pop AX			; 16-BIT
	;; pop EAX		; 32-BIT

	;; Turn on the A20 enable bit
	or AL, 00000010b
	out 60h, AL

	;; Finally, we will attempt to read back the A20 status
	;; to ensure it was enabled.

	;; Wait for the controller to be ready for a command
	.commandWait4:
	xor AX, AX
	in AL, 64h
	bt AX, 1
	jc .commandWait4

	;; Send the command D0h: read output port.
	mov AL, 0D0h
	out 64h, AL	

	;; Wait for the controller to be ready with a byte of data
	.dataWait2:
	xor AX, AX
	in AL, 64h
	bt AX, 0
	jnc .dataWait2

	;; Read the current port status from port 60h
	xor AX, AX
	in AL, 60h

	;; Is A20 enabled?
	bt AX, 1

	;; Check the result.  If carry is on, A20 is on.
	jc .success

	;; Should we retry the operation?  If the counter value in ECX
	;; has not reached zero, we will retry
	loop .startAttempt1


	;; Well, our initial attempt to set A20 has failed.  Now we will
	;; try a backup method (which is supposedly not supported on many
	;; chipsets, but which seems to be the only method that works on
	;; other chipsets).


	;; Keep a counter so that we can make up to 5 attempts to turn
	;; on A20 if necessary
	mov CX, 5

	.startAttempt2:
	;; Wait for the keyboard to be ready for another command
	.commandWait6:
	xor AX, AX
	in AL, 64h
	bt AX, 1
	jc .commandWait6

	;; Tell the controller we want to turn on A20
	mov AL, 0DFh
	out 64h, AL

	;; Again, we will attempt to read back the A20 status
	;; to ensure it was enabled.

	;; Wait for the controller to be ready for a command
	.commandWait7:
	xor AX, AX
	in AL, 64h
	bt AX, 1
	jc .commandWait7

	;; Send the command D0h: read output port.
	mov AL, 0D0h
	out 64h, AL	

	;; Wait for the controller to be ready with a byte of data
	.dataWait3:
	xor AX, AX
	in AL, 64h
	bt AX, 0
	jnc .dataWait3

	;; Read the current port status from port 60h
	xor AX, AX
	in AL, 60h

	;; Is A20 enabled?
	bt AX, 1

	;; Check the result.  If carry is on, A20 is on, but we might warn
	;; that we had to use this alternate method
	jc .warn

	;; Should we retry the operation?  If the counter value in ECX
	;; has not reached zero, we will retry
	loop .startAttempt2


	;; OK, we weren't able to set the A20 address line.  Do you want
	;; to put an error message here?
	jmp .fail


	.warn:
	;; Here you may or may not want to print a warning message about
	;; the fact that we had to use the nonstandard alternate enabling
	;; method

	.success:
	sti
	popa
	xor EAX, EAX
	ret

	.fail:
	sti
	popa
	mov EAX, -1
	ret
enableA20 endp
