
#include "common.h"
#include "pci.h"


int
pciGetBaseSize(int bus, int devfn, int index, Bool destructive, Bool *min)
{
  int offset;
  CARD32 addr1;
  CARD32 addr2;
  CARD32 mask1;
  CARD32 mask2;
  int bits = 0;

  /*
   * silently ignore bogus index values.  Valid values are 0-6.  0-5 are
   * the 6 base address registers, and 6 is the ROM base address register.
   */
  if (index < 0 || index > 6)
    return 0;

  if (min)
    *min = destructive;

  /* Get the PCI offset */
  if (index == 6)
    offset = PCI_MAP_ROM_REG;
  else
    offset = PCI_MAP_REG_START + (index << 2);

  addr1 = PciRead32(bus, devfn, offset);
  /*
   * Check if this is the second part of a 64 bit address.
   * XXX need to check how endianness affects 64 bit addresses.
   */
  if (index > 0 && index < 6) {
    addr2 = PciRead32(bus, devfn, offset - 4);
    if (PCI_MAP_IS_MEM(addr2) && PCI_MAP_IS64BITMEM(addr2))
      return 0;
  }

  if (destructive) {
     PciWrite32(bus, devfn, offset, 0xffffffff);
     mask1 = PciRead32(bus, devfn, offset);
     PciWrite32(bus, devfn, offset, addr1);
  } else {
    mask1 = addr1;
  }

  /* Check if this is the first part of a 64 bit address. */
  if (index < 5 && PCI_MAP_IS_MEM(mask1) && PCI_MAP_IS64BITMEM(mask1))
  {
    if (PCIGETMEMORY(mask1) == 0)
    {
      addr2 = PciRead32(bus, devfn, offset + 4);
      if (destructive)
      {
        PciWrite32(bus, devfn, offset + 4, 0xffffffff);
        mask2 = PciRead32(bus, devfn, offset + 4);
        PciWrite32(bus, devfn, offset + 4, addr2);
      }
      else
     {
       mask2 = addr2;
     }
     if (mask2 == 0)
       return 0;
     bits = 32;
     while ((mask2 & 1) == 0)
     {
       bits++;
       mask2 >>= 1;
     }
     if (bits > 32)
	  return bits;
    }
  }
  if (index < 6)
    if (PCI_MAP_IS_MEM(mask1))
      mask1 = PCIGETMEMORY(mask1);
    else
      mask1 = PCIGETIO(mask1);
  else
    mask1 = PCIGETROM(mask1);
  if (mask1 == 0)
    return 0;
  bits = 0;
  while ((mask1 & 1) == 0) {
    bits++;
    mask1 >>= 1;
  }
  /* I/O maps can be no larger than 8 bits */

  if ((index < 6) && PCI_MAP_IS_IO(addr1) && bits > 8)
    bits = 8;
  /* ROM maps can be no larger than 24 bits */
  if (index == 6 && bits > 24)
    bits = 24;
  return bits;
}

/*
    int       chipRev;
    int       subsysVendor;
    int       subsysCard;
    int       bus;
    int       devfn;
//    int       func;
    int       class;
    int       subclass;
    int       interface;
    memType   memBase[6];
    memType   ioBase[6];
    int       size[6];
    unsigned char	type[6];
    memType   biosBase;
    int       biosSize;
*/

int pciGetInfo(pciVideoPtr pci)
{
  CARD32 reg0,reg2C;
  int i;

  reg0  = PciRead32(pci->bus,pci->devfn, 0);
  reg2C = PciRead32(pci->bus,pci->devfn, 0x2C);

  pci->vendor  = reg0 & 0xFFFF;
  pci->devtype = reg0 >> 16;

  pci->subsysVendor = reg2C & 0xFFFF;
  pci->subsysCard = reg2C >> 16;

  for (i = 0; i < 6; i++)
  {
    CARD32 base;

    base = PciRead32(pci->bus,pci->devfn, PCI_MAP_REG_START + (i << 2));
    if(base)
    {
      if (base & PCI_MAP_IO)
      {
        pci->ioBase[i] = (memType)PCIGETIO(base);
        pci->type[i] = base & PCI_MAP_IO_ATTR_MASK;
      }
      else
      {
        pci->type[i] = base & PCI_MAP_MEMORY_ATTR_MASK;
        pci->memBase[i] = (memType)PCIGETMEMORY(base);
      }
		}

    pci->size[i] =
      pciGetBaseSize(pci->bus,pci->devfn, i, TRUE, &pci->validSize);
  }

}

