How it works is pretty tricky. PCI devices use Base Address Registers to let the BIOS and operating system decide where to find their memory areas. Each PCI device is allowed to specify several memory areas or IOs that it wants, and allows the BIOS / OS to decide where to put it. Complicating matters, there is only one register, which is used to indicate the size AND address. How it works?
When the card is first turned on, there will be something like 0xFFFF0000 in this 32-bit address register. Any binary 1 means "the OS can change this," any binary value 0 means "must remain zero." Thus, this tells the OS that any of the first 16 bits can be set according to what the OS wants, but the lower 16 bits should remain zero. It also means that this memory area occupies 16 bits of address space, or 64k. Because of this, memory areas must be aligned with their size. If the card requires 64 KB of address space, the OS can only store memory addresses that are multiples of 64 KB. When the OS decided where it wants to find this memory on 64 KB of memory, it writes it back to this register, overwriting the initial 0xFFFF0000 that was there.
In other words, the card tells the OS what size / alignment is needed for the memory, then the OS overwrites the same register / variable with an address for the memory. After that, you cannot get the size back from the register without resetting the address.
This means that there is no portable way to ask for a map, how large is its region, all you can ask is WHERE is the area.
So why does it work on Linux? Because it asks for a kernel for this information. The kernel has an API to provide this material, just as lspci works. I am not a Windows expert, but I do not know how an application can query the Windows kernel for this information. There may be an API to do this somehow, or you may need to write something that works on the kernel side to pass this information back to you. If you look in the libpci source, for windows it calls the "generic" version of pci_fill_info (), which returns:
return flags & ~PCI_FILL_SIZES;
which basically means "I am returning everything you requested, but the dimensions."
But it does not matter. If everything you do wants to read / write to I2C registers, they are usually (always?) In the first 4K control / configuration area. You can probably just match 4K (one page) and ignore the fact that there could be more. You should also be warned that you may need to take additional steps to stop the real driver for this card from reading / writing while you are at it. If you beat the I2C bus bit manually and the driver tries at the same time, it can cause a mess on the bus.
There may also be an existing way to ask the radeon driver to execute I2C requests for you, which can avoid all of this.
(also note that I simplify and hush up a lot of details about how BARs work, including 64-bit addresses, I / O space, etc., read the PCI documentation if you want to know more)