📄 pci.cpp
字号:
/*++
Copyright (c) 2004 Sten
Contact information:
mail: stenri@mail.ru
This code was mainly ported from jeff leyda's .wav file player for DOS.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Module Name:
pci.cpp
Abstract: PCI bus functions
Revision History:
Sten 01/01/2004
Initial release. Started expiriments on using AC'97.. Wow!!
--*/
extern "C" {
#pragma warning ( push, 3 )
#include <ntddk.h>
#pragma warning ( pop )
}
#pragma warning ( disable: 4514 ) // unreferenced inline function has been removed
#include <windef.h>
#include <ntverp.h>
#include "pci.h"
/*
void cs_write(unsigned long port, unsigned char val)
{
outl(port & 0xfffffffc | 0x80000000, 0x0cf8); outb(val, 0xcfc + (port & 0x3));
}
unsigned char cs_read_b(unsigned long port)
{
outl(port & 0xfffffffc | 0x80000000, 0x0cf8); return(inb(0xcfc + (port & 0x3)));
}
unsigned short cs_read_w(unsigned long port)
{
outl(port & 0xfffffffc | 0x80000000, 0x0cf8); return(inw(0xcfc + (port & 0x3)));
}
unsigned long cs_read_l(unsigned long port)
{
outl(port & 0xfffffffc | 0x80000000, 0x0cf8); return(inl(0xcfc + (port & 0x3)));
}
// Enable ACPI by set B7 on Reg 0x40, LPC
void cs_write_b(unsigned long port, unsigned long val)
{
outl(port, 0x0cf8);
b = inb(0x0cfc) | 0x80;
outb(val, 0xcfc);
}
*/
///////////////////////////////////////////////////////////////////////////////////
//
// 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 #
//
///////////////////////////////////////////////////////////////////////////////////
void __declspec (naked) pciRegRead (void)
{
__asm
{
push ebx
push ecx
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 not32_bit
mov edx, eax ; return 32bits of data
not32_bit:
mov dx, ax ; return 16bits of data
test ebx, PCI32+PCI16
jnz do16_bit
mov dh, cl ; restore dh for 8 bit read
do16_bit:
mov eax, ebx ; restore eax
and eax, NOT PCI32+PCI16 ; clear out data size request
pop ecx
pop ebx
ret
}
}
void __declspec (naked) pciRegRead8 (void)
{
__asm
{
and eax, NOT PCI16+PCI32 ; set up 8 bit read size
jmp pciRegRead ; call generic PCI access
}
}
void __declspec (naked) pciRegRead16 (void)
{
__asm
{
and eax, NOT PCI16+PCI32 ; set up 16 bit read size
or eax, PCI16 ; call generic PCI access
jmp pciRegRead
}
}
void __declspec (naked) pciRegRead32 (void)
{
__asm
{
and eax, NOT PCI16+PCI32 ; set up 32 bit read size
or eax, PCI32 ; call generic PCI access
jmp pciRegRead
}
}
///////////////////////////////////////////////////////////////////////////////////
//
// 8/16/32bit PCI writer
//
// Entry: EAX=PCI Bus/Device/fn/register number
// BIT31 set if 32 bit access requested
// BIT30 set if 16 bit access requested
// otherwise defaults to 8bit read
// DL/DX/EDX data to write depending on size
//
//
// note: this routine is meant to be called via pciRegWrite8, pciRegWrite16,
// or pciRegWrite32 as detailed below.
//
// Note2: don't attempt to write 32bits of data from a non dword aligned reg
// number. Likewise, don't do 16bit writes from non word aligned reg #
//
///////////////////////////////////////////////////////////////////////////////////
void __declspec (naked) pciRegWrite (void)
{
__asm
{
push ebx
push cx
mov ebx, eax ; save eax, dx
mov cx, dx
or eax, BIT31 ; make a PCI access request
and eax, NOT PCI16 ; clear out data size 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 ; write to
mov eax, edx ; put data into eax
mov ax, cx
out dx, al
test ebx, PCI16+PCI32 ; only 8bit access? bail
jz cleanup
out dx, ax ; write 16 bit value
test ebx, PCI16 ; 16bit requested? bail
jnz cleanup
out dx, eax ; write full 32bit
cleanup:
mov eax, ebx ; restore eax
and eax, NOT PCI32+PCI16 ; clear out data size request
mov dx, cx ; restore dx
pop cx
pop ebx
ret
}
}
void __declspec (naked) pciRegWrite8 (void)
{
__asm
{
and eax, NOT PCI16+PCI32 ; set up 8 bit write size
jmp pciRegWrite ; call generic PCI access
}
}
void __declspec (naked) pciRegWrite16 (void)
{
__asm
{
and eax, NOT PCI16+PCI32 ; set up 16 bit write size
or eax, PCI16 ; call generic PCI access
jmp pciRegWrite
}
}
void __declspec (naked) pciRegWrite32 (void)
{
__asm
{
and eax, NOT PCI16+PCI32 ; set up 32 bit write size
or eax, PCI32 ; call generic PCI access
jmp pciRegWrite
}
}
///////////////////////////////////////////////////////////////////////////////////
//
// 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
//
///////////////////////////////////////////////////////////////////////////////////
DWORD pciFindDevice ( DWORD dwID )
{
DWORD val;
__asm
{
push ecx
push edx
push esi
push edi
mov eax, dwID
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:
jnc all_ok
pushfd
xor edi, edi
popfd
all_ok:
pushfd
mov eax, edi ; return found PCI address
and eax, NOT BIT31 ; return only bus/dev/fn #
popfd
pop edi
pop esi
pop edx
pop ecx
mov val, eax
}
return val;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -