WinXP - Reading and Writing PCI Config Space from a Driver...

Hi All,

Is there an easier way or an efficient way to access the PCI config space
from a driver that is not owning that device ?

I’m trying to write a PCI Space Viewer sort of a utility that will have to
read and write registers from the PCI Space.

I also see that HalGetBusData and similar functions are obsolete and the
DDK documentation recommends using IRP_MN_READ_CONFIG etc. I would like to
know if anybody have used it before and if so, how do I use it in my
“NON-Device” driver ?

Thanks in advance,
Vasu.

The following code is from one of my program, and I referenced the source
code of Linux kernel-2.4.18.
Only write pci functions are placed there.And you can write your own read
functions.
I think it’t no obsolute even under XP.

/*
* bus : 0-based bus number
* dev : 0-based device number
* fun : 0-based function number
* reg : the offset of the PCI configuration’s register to which you’d to
write
* value : the value you’d to write to the register
*/

#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~~3))

BOOLEAN
WRITE_PCI_CONFIG_BYTE (ULONG bus, ULONG dev, ULONG fun, UCHAR reg, UCHAR
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register), PCI_CONF1_ADDRESS(bus, dev,
fun, reg));
//outl((u32)value, 0xCFC);
Register = 0xCFC + (reg & 3);
WRITE_PORT_UCHAR((PUCHAR)((ULONG)Register), value);
return TRUE;
}

BOOLEAN
WRITE_PCI_CONFIG_WORD (ULONG bus, ULONG dev, ULONG fun, UCHAR reg, USHORT
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register), PCI_CONF1_ADDRESS(bus, dev,
fun, reg));
//outl((u32)value, 0xCFC);
Register = 0xCFC + (reg & 2);
WRITE_PORT_USHORT((PUSHORT)((ULONG)Register), value);
return TRUE;
}

BOOLEAN
WRITE_PCI_CONFIG_DWORD (ULONG bus, ULONG dev, ULONG fun, UCHAR reg, ULONG
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//ouDtl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register), PCI_CONF1_ADDRESS(bus, dev,
fun, reg));
//outl((u32)value, 0xCFC);
Register = 0xCFC;
WRITE_PORT_ULONG((PULONG)((ULONG)Register), value);
return TRUE;
}

#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~~3))

this PCI_CONFI1_ADDRESS is for the generation of PCI bridge device (which
header type is 1), and if for normal PCI device, you should not use it. The
linux source code can give you some help.

-----Original Message-----
From: yuanjun
To: NT Developers Interest List
Date: 2002Äê4ÔÂ23ÈÕ 10:01
Subject: [ntdev] Re: WinXP - Reading and Writing PCI Config Space from a
Driver…

>The following code is from one of my program, and I referenced the source
>code of Linux kernel-2.4.18.
>Only write pci functions are placed there.And you can write your own read
>functions.
>I think it’t no obsolute even under XP.
>
>
>/*
> * bus : 0-based bus number
> * dev : 0-based device number
> * fun : 0-based function number
> * reg : the offset of the PCI configuration’s register to which you’d
to
>write
> * value : the value you’d to write to the register
> */
>
>#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) <br>> (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~~3))
>
>
>BOOLEAN
>WRITE_PCI_CONFIG_BYTE (ULONG bus, ULONG dev, ULONG fun, UCHAR reg, UCHAR
>value)
>{
> USHORT Register;
>
> if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
> return FALSE;
>
> //outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
> Register = 0xCF8;
> WRITE_PORT_ULONG((PULONG)((ULONG)Register), PCI_CONF1_ADDRESS(bus, dev,
>fun, reg));
> //outl((u32)value, 0xCFC);
> Register = 0xCFC + (reg & 3);
> WRITE_PORT_UCHAR((PUCHAR)((ULONG)Register), value);
> return TRUE;
>}
>
>BOOLEAN
>WRITE_PCI_CONFIG_WORD (ULONG bus, ULONG dev, ULONG fun, UCHAR reg, USHORT
>value)
>{
> USHORT Register;
>
> if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
> return FALSE;
>
> //outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
> Register = 0xCF8;
> WRITE_PORT_ULONG((PULONG)((ULONG)Register), PCI_CONF1_ADDRESS(bus, dev,
>fun, reg));
> //outl((u32)value, 0xCFC);
> Register = 0xCFC + (reg & 2);
> WRITE_PORT_USHORT((PUSHORT)((ULONG)Register), value);
> return TRUE;
>}
>
>BOOLEAN
>WRITE_PCI_CONFIG_DWORD (ULONG bus, ULONG dev, ULONG fun, UCHAR reg, ULONG
>value)
>{
> USHORT Register;
>
> if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
> return FALSE;
>
> //ouDtl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
> Register = 0xCF8;
> WRITE_PORT_ULONG((PULONG)((ULONG)Register), PCI_CONF1_ADDRESS(bus, dev,
>fun, reg));
> //outl((u32)value, 0xCFC);
> Register = 0xCFC;
> WRITE_PORT_ULONG((PULONG)((ULONG)Register), value);
> return TRUE;
>}
>
>
>—
>You are currently subscribed to ntdev as: KDriver@163.com
>To unsubscribe send a blank email to %%email.unsub%%

You do this on nt at the peril of system integrity. You want to
read/write pci config space, a resource SHARED by other threads of
execution, you perhaps ought to use the SERIALIZATION MECHANISM provided
by the operating system that makes this SAFE. Linux not withstanding.

=====================
Mark Roddy
Windows XP/2000/NT Consultant, Microsoft MVP
Hollis Technology Solutions 603-321-1032
www.hollistech.com
xxxxx@hollistech.com
For Windows Device Driver Training: see www.azius.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of yuanjun
Sent: Monday, April 22, 2002 9:55 PM
To: NT Developers Interest List
Subject: [ntdev] Re: WinXP - Reading and Writing PCI Config
Space from a Driver…

The following code is from one of my program, and I
referenced the source code of Linux kernel-2.4.18. Only write
pci functions are placed there.And you can write your own
read functions. I think it’t no obsolute even under XP.

/*
* bus : 0-based bus number
* dev : 0-based device number
* fun : 0-based function number
* reg : the offset of the PCI configuration’s register to
which you’d to
write
* value : the value you’d to write to the register
*/

#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))

BOOLEAN
WRITE_PCI_CONFIG_BYTE (ULONG bus, ULONG dev, ULONG fun, UCHAR
reg, UCHAR
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register),
PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
0xCFC); Register = 0xCFC + (reg & 3);
WRITE_PORT_UCHAR((PUCHAR)((ULONG)Register), value); return TRUE; }

BOOLEAN
WRITE_PCI_CONFIG_WORD (ULONG bus, ULONG dev, ULONG fun, UCHAR
reg, USHORT
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register),
PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
0xCFC); Register = 0xCFC + (reg & 2);
WRITE_PORT_USHORT((PUSHORT)((ULONG)Register), value); return TRUE; }

BOOLEAN
WRITE_PCI_CONFIG_DWORD (ULONG bus, ULONG dev, ULONG fun,
UCHAR reg, ULONG
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//ouDtl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register),
PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
0xCFC); Register = 0xCFC;
WRITE_PORT_ULONG((PULONG)((ULONG)Register), value); return TRUE; }


You are currently subscribed to ntdev as:
xxxxx@hollistech.com To unsubscribe send a blank email to
%%email.unsub%%

xxxxx@hollistech.com said:

You want to read/write pci config space, a resource SHARED by other
threads of execution, you perhaps ought to use the SERIALIZATION
MECHANISM provided by the operating system that makes this SAFE. Linux
not withstanding.

There are better ways to do this under Linux, too. There are functions
for reading/writing configuration space registers that should be used
instead of frobbing the host bridge.

Linux people get to think about alphas, PPCs, SPARCs, SH4, ad nauseum
and hacks like this won’t get you very far.

Also, Linux has user-mode means for reading PCI configuration space.
(Writing PCI configuration from user mode is a bit more problematic
for obvious reasons:-)

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of yuanjun
Sent: Monday, April 22, 2002 9:55 PM
To: NT Developers Interest List
Subject: [ntdev] Re: WinXP - Reading and Writing PCI Config
Space from a Driver…

The following code is from one of my program, and I
referenced the source code of Linux kernel-2.4.18. Only write
pci functions are placed there.And you can write your own
read functions. I think it’t no obsolute even under XP.

/*
* bus : 0-based bus number
* dev : 0-based device number
* fun : 0-based function number
* reg : the offset of the PCI configuration’s register to
which you’d to
write
* value : the value you’d to write to the register
*/

#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))

BOOLEAN
WRITE_PCI_CONFIG_BYTE (ULONG bus, ULONG dev, ULONG fun, UCHAR
reg, UCHAR
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register),
PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
0xCFC); Register = 0xCFC + (reg & 3);
WRITE_PORT_UCHAR((PUCHAR)((ULONG)Register), value); return TRUE; }

BOOLEAN
WRITE_PCI_CONFIG_WORD (ULONG bus, ULONG dev, ULONG fun, UCHAR
reg, USHORT
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register),
PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
0xCFC); Register = 0xCFC + (reg & 2);
WRITE_PORT_USHORT((PUSHORT)((ULONG)Register), value); return TRUE; }

BOOLEAN
WRITE_PCI_CONFIG_DWORD (ULONG bus, ULONG dev, ULONG fun,
UCHAR reg, ULONG
value)
{
USHORT Register;

if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
return FALSE;

//ouDtl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
Register = 0xCF8;
WRITE_PORT_ULONG((PULONG)((ULONG)Register),
PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
0xCFC); Register = 0xCFC;
WRITE_PORT_ULONG((PULONG)((ULONG)Register), value); return TRUE; }

> The following code is from one of my program, and I referenced
the source

code of Linux kernel-2.4.18.

Writes must not be used this way on NT - you cannot synchronize with the usual NT’s writers, and can crash the machine with ease if
you will write something to bridges.

Max

Hi, Mark
What is the SERIALIZATION MECHANISM provided by the WinXP then?
I read and write the PCI configruation space of a TI PCI2250 PCI-PCI bridge
this way under windows NT 4.0 (SP6), will it be a problem without any
SERIALIZATION MECHANISM?

thank you!

-----Original Message-----
From: Mark Roddy
To: NT Developers Interest List
Date: 2002Äê4ÔÂ23ÈÕ 20:03
Subject: [ntdev] Re: WinXP - Reading and Writing PCI Config Space from a
Driver…

>You do this on nt at the peril of system integrity. You want to
>read/write pci config space, a resource SHARED by other threads of
>execution, you perhaps ought to use the SERIALIZATION MECHANISM provided
>by the operating system that makes this SAFE. Linux not withstanding.
>
>=====================
>Mark Roddy
>Windows XP/2000/NT Consultant, Microsoft MVP
>Hollis Technology Solutions 603-321-1032
>www.hollistech.com
>xxxxx@hollistech.com
>For Windows Device Driver Training: see www.azius.com
>
>
>
>
>> -----Original Message-----
>> From: xxxxx@lists.osr.com
>> [mailto:xxxxx@lists.osr.com] On Behalf Of yuanjun
>> Sent: Monday, April 22, 2002 9:55 PM
>> To: NT Developers Interest List
>> Subject: [ntdev] Re: WinXP - Reading and Writing PCI Config
>> Space from a Driver…
>>
>>
>> The following code is from one of my program, and I
>> referenced the source code of Linux kernel-2.4.18. Only write
>> pci functions are placed there.And you can write your own
>> read functions. I think it’t no obsolute even under XP.
>>
>>
>> /*
>> * bus : 0-based bus number
>> * dev : 0-based device number
>> * fun : 0-based function number
>> * reg : the offset of the PCI configuration’s register to
>> which you’d to
>> write
>> * value : the value you’d to write to the register
>> */
>>
>> #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) <br>>> (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
>>
>>
>> BOOLEAN
>> WRITE_PCI_CONFIG_BYTE (ULONG bus, ULONG dev, ULONG fun, UCHAR
>> reg, UCHAR
>> value)
>> {
>> USHORT Register;
>>
>> if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
>> return FALSE;
>>
>> //outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
>> Register = 0xCF8;
>> WRITE_PORT_ULONG((PULONG)((ULONG)Register),
>> PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
>> 0xCFC); Register = 0xCFC + (reg & 3);
>> WRITE_PORT_UCHAR((PUCHAR)((ULONG)Register), value); return TRUE; }
>>
>> BOOLEAN
>> WRITE_PCI_CONFIG_WORD (ULONG bus, ULONG dev, ULONG fun, UCHAR
>> reg, USHORT
>> value)
>> {
>> USHORT Register;
>>
>> if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
>> return FALSE;
>>
>> //outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
>> Register = 0xCF8;
>> WRITE_PORT_ULONG((PULONG)((ULONG)Register),
>> PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
>> 0xCFC); Register = 0xCFC + (reg & 2);
>> WRITE_PORT_USHORT((PUSHORT)((ULONG)Register), value); return TRUE; }
>>
>> BOOLEAN
>> WRITE_PCI_CONFIG_DWORD (ULONG bus, ULONG dev, ULONG fun,
>> UCHAR reg, ULONG
>> value)
>> {
>> USHORT Register;
>>
>> if ((bus > 255) || (dev > 31) || (fun > 7) || (reg > 255))
>> return FALSE;
>>
>> //ouDtl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
>> Register = 0xCF8;
>> WRITE_PORT_ULONG((PULONG)((ULONG)Register),
>> PCI_CONF1_ADDRESS(bus, dev, fun, reg)); //outl((u32)value,
>> 0xCFC); Register = 0xCFC;
>> WRITE_PORT_ULONG((PULONG)((ULONG)Register), value); return TRUE; }
>>
>>
>> —
>> You are currently subscribed to ntdev as:
>> xxxxx@hollistech.com To unsubscribe send a blank email to
>> %%email.unsub%%
>>
>>
>>
>
>
>
>—
>You are currently subscribed to ntdev as: xxxxx@21cn.com
>To unsubscribe send a blank email to %%email.unsub%%
>