pci config issue

I am attempting to make use of some features on the IO Hub/ South Bridge on my SBC, but I can only seem to write a value of 0x03 to any of the bytes in the PCI configuration space. I have verified that this is the case with both my PCI reading routines and the pci -vvv comand.

QNX 6.3.2
Intel x86

[code]void pci_write()
{
void* hdl;
int phdl;
struct pci_dev_info inf;

unsigned char pciBuffer[100];
int readReturn;

unsigned long vendor;
unsigned long device;
unsigned long index;
unsigned long start;
unsigned long num;
unsigned long size;

// attach to the PCI Server
phdl = pci_attach(0);
if(phdl == -1)
{
    printf("cannot access PCI Server\n");
    pci_detach(phdl);
    return;
}

memset(&inf, 0, sizeof(inf));

getval_ul(&vendor);
getval_ul(&device);
getval_ul(&index);

inf.VendorId = vendor;
inf.DeviceId = device;

hdl = pci_attach_device(NULL, PCI_SHARE | PCI_SEARCH_VENDEV, index, &inf);
if(hdl == NULL)
{
    printf("cannot access PCI Device\n");
    pci_detach_device(hdl);
    pci_detach(phdl);
    return;
}

getval_ul(&start);
getval_ul(&num);
getval_ul(&size);

if((size != 1) && (size != 2) && (size != 4))
{
    printf("size parameter must be 1, 2 or 4\n");
    pci_detach_device(hdl);
    pci_detach(phdl);
}

int i, j;

for(i = 0; i < num; ++i);
{
    unsigned long data;

    getval_ul(&data);
    for(j = 0; j < size; ++j)
    {
        pciBuffer[(i * size) + j] = ((unsigned char*)(&data))[j];
        printf("byte %d = 0x%02x, 0x%02x\n", j, ((unsigned char*)(&data))[j], pciBuffer[(i * size) + j]);
    }
    for(j = size; j < 4; ++j)
    {
        printf("byte %d = 0x%02x, 0x%02x\n", j, ((unsigned char*)(&data))[j], pciBuffer[(i * size) + j]);
    }
}

readReturn = pci_write_config(hdl, start, num, size, &(pciBuffer[0]));
if(readReturn != PCI_SUCCESS)
{
    printf("unable to write to PCI config space\n");
    pci_detach_device(hdl);
    pci_detach(phdl);
    return;
}

pci_detach_device(hdl);
pci_detach(phdl);

}
[/code]

Does the code just look right, or is everyone at a loss for this weirdness???

The handling of various size with the isize and the casting make the code hard to follow they are cleaner and more efficent way of handling this. For example use a pointer to pciBuffer that you’d increment by one every time you write to it so no more need for the (isize) + j stuff.

Also for the size stuff since there is only 3 cases 1, 2 and 4 you could use a switch case, which would get rid of the loop and thus produce faster code. Not to mention easer to understand code.

That being said the code does seems to do what you want it to do. This might be related to the perticular hardware you are using.

Handling the 3 cases separately would have made it easier to read, but that happens when you are trying to hack something together quick for a proof of concept. Anyways, I eventually downloaded the north bridge data sheet and did the pci config writes manually, and it worked properly. Now the whole purpose of this was to enable a device to be viewed on the bus, and I need to figure out how to rescan / enumerate the bus to get access to that one device… the pci_rescan_bus() qnx call didn’t do the trick, so I probably have to figure out how to do that manually as well.

That is what I mean but using switch case. Still makes the code as flexible as yours. From experience pci-bios doesn’t really like having the hardware changed under its feet. Maybe you could try enable your device (if possible) before pci-bios gets a chance to run.

union data_u {
unsigned long aLong;
struct {
unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
unsigned char byte4;
}
} data;

getval_ul( &data.aLong );

switch size
{
case 4:
*(pci_buffer++) = data.byte1;
*(pci_buffer++) = data.byte2;
*(pci_buffer++) = data.byte3;
*(pci_buffer++) = data.byte4;
break;
case 2:
*(pci_buffer++) = data.byte1;
*(pci_buffer++) = data.byte2;
break;
case 1:
*(pci_buffer++) = data.byte1;
break;
}