A problem about the driver developing about PCI6503

Recently, I am developing a drvier about PCI6503 in QNX, but it could not work may be some mistake, I have looked for it but get none for a long time. Now I put the all code to openqnx with my boss’s permitte, regard someone can make it good.

The program’s work step is:
1 Get the root prority.
2 Get the pci_* server’s support.
3 Check the pci device is ok.
4 Get Some Information about the pci device.
5 Print the information.
6 Remap the pci mite address and pci board register address.
7 Get the prority to access to BAR1.
8 Operate the board by the point.
9 Release the resource.

Problem description:
The Former code is good because The printed information is OK, the later is the problem’s source.

About PCI6503:
It is USA NI’s 24 DIO pci board, there is a 8255 PPI in it, which have three 8-bit port to control DIO input or output.
BASE+0: PORTA
BASE+1: PORTB
BASE+2: PORTC
BASE+3: CONFIG REGISTER
To configure the PCI MITE chip, you must first write an algorithm that finds and stores all configuration information about the board. To do this, use PCIBIOS calls to search PCI configuration space for the National Instruments vendor ID (0x1093) and PCI-DIO-96 device ID (0x0160), PXI-6508 device ID (0x13c0), or PCI-6503 device ID (0x17d0). If a board is found, the algorithm can store all the board’s configuration information into a data structure. Base Address Register 0 (BAR0) corresponds to the base address of the PCI MITE, while Base Address Register1 (BAR1) is the base address of the board registers. The size of each of these windows is 4KB. Both addresses will most likely be mapped above 1MB in the memory map. This means that you must know how to perform memory cycles to extended memory to communicate with the board. The memory map provides information to re-map the board under 1MB, which simplifies communication with the board. To accomplish this, use PCI BIOS read and write calls. Use the pseudocode in this section to re-map the board below 1MB. If you choose not to re-map the board, you must still perform steps4 and5. All values in this example are 32bits.

  1. Write the address to which you want to re-map the PCI MITE to PCI configuration space offset 0x10 (BAR0).
  2. Write the value 0x0000aeae to offset 0x340 from the new PCI MITE address.
  3. Write the address to which you want to re-map the board (other than the PCI MITE) to PCI configuration space offset 0x14 (BAR1).
  4. Create the window data value by masking the new board address:window data value = ((0xffffff00 and new board address) or (0x00000080))If you are not remapping the board, then the new board address is the value in BAR1.
  5. Write the window data value to offset 0xc0 from the new PCI MITE address.
    If you are not remapping the board, then the new PCI MITE address is the value in BAR0.The following pseudocode re-maps the PCI MITE to memory address 0xd0000 and the board to memory address 0xd1000.
    CWrite(0x10,0x000d0000);
    Write(0xd0340,0x0000aeae);
    CWrite(0x14,0x000d1000);
    Write(0xd00c0,0x000d1080) ;

My Code here:

#include <sys/neutrino.h>
#include <hw/pci.h>
#include <hw/pci_devices.h>
#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>

#define PCI_DEBUG

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
#define PCI_CARD_DEVICE_ID 0x17d0
#define PCI_CARD_VENDOR_ID 0x1093

//-----------------------------------------------------------------------------
uint32_t dev_address_value_test;
uint32_t mem_address_value_test;

/********************************************************************************
********************************************************************************/
void pci_printf(struct pci_dev_info *inf)
{
uint32_t i;

fprintf (stdout, “\n device id = %x”, inf->DeviceId);
fprintf (stdout, “\n Vendo id = %x”, inf->VendorId);
fprintf (stdout, “\n BusNumber = %x”, inf->BusNumber);
fprintf (stdout, “\n device number = %x”, ((inf->DevFunc)>>3)&0x1F);
fprintf (stdout, “\n Function number = %x”, (inf->DevFunc)&0x07);
fprintf (stdout, “\n Revision = %x”, inf->Revision);
fprintf (stdout, “\n device class = %x”, inf->Class);
fprintf (stdout, “\n device irq = %x”, inf->Irq);
fprintf (stdout, “\n pcibase address = %x”, ((inf->CpuBaseAddress)));
fprintf (stdout, “\n base address size = %x”, (
(inf->BaseAddressSize)));

pci_read_config32 (inf->BusNumber, inf->DevFunc, 0x10, 1, &i);
fprintf (stdout, “\n Base address 0 = %x”, i);

pci_read_config32 (inf->BusNumber, inf->DevFunc, 0x14, 1, &i);
fprintf (stdout, “\n Base address 1 = %x”, i);
}

/********************************************************************************
********************************************************************************/
#define PCI_YES 1
#define ATTACH_PCI_FAILURE -1
#define FIND_FAILURE -2
#define ADDR_ERROR -3
#define ATTACH_DEVICE_FAILURE -4

int pci_card_detect(unsigned index,
unsigned *pci_handle,
struct pci_dev_info *inf,
uint32_t *dev_handle,
uint32_t *mem_handle)
{
uint32_t addr_handle;
uint32_t io_addr;

unsigned bus;
unsigned dev;
unsigned func;
unsigned dev_func;

uint8_t* x;
uint32_t *p;
uint32_t value;

uint32_t BAR0, BAR1;

uint32_t *addr[2];

ThreadCtl (_NTO_TCTL_IO, 0);

*pci_handle = pci_attach(0);
if (*pci_handle == -1)
return ATTACH_PCI_FAILURE;

if (pci_find_device (inf->DeviceId,
inf->VendorId,
index,
&bus,
&dev_func) != PCI_SUCCESS)
return FIND_FAILURE;

dev_handle = pci_attach_device (NULL,
(PCI_SHARE|PCI_SEARCH_VENDEV|PCI_INIT_ALL),
0,
inf);
if (dev_handle == NULL)
return ATTACH_DEVICE_FAILURE;

//print some information which have been found.
pci_printf(inf);

if ( pci_read_config32 (inf->BusNumber,
inf->DevFunc,
0x10,
1,
&BAR0)!= PCI_SUCCESS)
return ADDR_ERROR;

if ( pci_read_config32 (inf->BusNumber,
inf->DevFunc,
0x14,
1,
&BAR1)!= PCI_SUCCESS)
return ADDR_ERROR;

addr_handle = PCI_IO_ADDR(BAR0); //PCI_MEM_ADDR(BAR0);

fprintf (stdout, “\n 1 board mite addr: %x”, addr_handle);

addr[0] = mmap_device_memory (NULL,
*(inf->BaseAddressSize),
(PROT_READ|PROT_WRITE),
0,
(uint64_t)addr_handle);

fprintf (stdout, “\n 1 board mite new : %x”, addr[0]);

addr_handle = PCI_IO_ADDR(BAR1);//PCI_MEM_ADDR(BAR1);

fprintf (stdout, “\n 2 board reg addr : %x”, addr_handle);

addr[1] = mmap_device_memory (NULL,
*(inf->BaseAddressSize),
(PROT_READ|PROT_WRITE),
0,
(uint64_t)addr_handle);
fprintf (stdout, “\n 2 board reg new : %x”, addr[1]);

mem_handle = addr[1];
if (mem_handle == MAP_FAILED)
return;

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
fprintf (stdout, “\n 1 dev_handle: %x”, dev_handle);
fprintf (stdout, “\n 1 mem_handle: %x”, mem_handle);

dev_address_value_test = (uint32_t)dev_handle;
mem_address_value_test = (uint32_t)mem_handle;
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

// access to BAR1
pci_write_config32 (inf->BusNumber,
inf->DevFunc,
0x10, //BAR0
1,
&addr[0]);//set the new pci mite value to BAR0

((uint32_t)addr[0] + 0x340) = 0xaeae;

pci_write_config32 (inf->BusNumber,
inf->DevFunc,
0x14,//BAR1
1,
&addr[1]);//set the new pci board reg value to BAR1

((uint32_t)addr[0] + 0xc0) = ((uint32_t)addr[1]& 0xffffff00)|0x80;

//Set Configer Register (all is output port)
x = (uint8_t*)mem_handle+0x03;
*x = 0x80;

fprintf (stdout, “\n Configer register addr = %x”, x);

fprintf (stdout, “\n Configer register value = %x\n”, *x);

//Port A output
x = (uint8_t*)mem_handle+0x0000;
*x = 0xaa;
fprintf (stdout, “\n Port A address = %x”, x);
fprintf (stdout, “\n Port A value = %x\n”, *x);

//Port B output
x = (uint8_t*)mem_handle+0x0001;
*x = 0xaa;
fprintf (stdout, “\n Port B address = %x”, x);
fprintf (stdout, “\n Port B value = %x\n”, *x);

//Port C output
x = (uint8_t*)mem_handle+0x0002;
*x = 0xaa;
fprintf (stdout, “\n Port C address = %x”, x);
fprintf (stdout, “\n Port C value = %x”, *x);

return PCI_YES;
}

/********************************************************************************
********************************************************************************/
void close_card (struct pci_dev_info *inf,
int pci_handle,
void *dev_handle,
void *mem_handle)
{
if (mem_handle == MAP_FAILED)
return;

if (munmap_device_memory (mem_handle, (*(inf->BaseAddressSize))) == -1)
fprintf (stdout, “\n Error:munmap failed!”);

if (pci_detach_device(dev_handle) != PCI_SUCCESS)
fprintf(stdout, “\n Error:detach device failed status!\n”);

if (pci_detach (pci_handle) != PCI_SUCCESS)
fprintf (stdout, “\n Error:detach pci sever failed status!!%s\n”, strerror (errno));
return;
}

/*******************************************************************************/
int main(int argc, char *argv)
{
struct pci_dev_info inf;

int pci_handle;
uint32_t addr_handle;
uint32_t *mem_handle;
uint32_t *dev_handle;
unsigned index = 0;

fprintf (stdout, “======================================================”);

memset (&inf, 0, sizeof (struct pci_dev_info));
inf.VendorId = PCI_CARD_VENDOR_ID;
inf.DeviceId = PCI_CARD_DEVICE_ID;

if (pci_card_detect (index, &pci_handle, &inf, dev_handle,mem_handle) = PCI_YES)
{
dev_handle = (uint32_t*)dev_address_value_test;
mem_handle = (uint32_t*)mem_address_value_test;

close_card(&inf, pci_handle, dev_handle, mem_handle);
}

fprintf (stdout, “\n======================================================\n”);
return 0;
}
/*******************************************************************************/

You still have a problem with handling pointer.

dev_handle = pci_attach_device (… ) will not allow the pci_card_detect fonction to RETURN the value, you need
*dev_handle

I’m not sure exactly what the problem is, I haven’t look further then that problem.

This program have been compiled successfully, It can run, but could not work with the hardware!

The Information about of the board with the "PCI -V"command:
Class = Unknown (Unknown)
Vendor ID = 1093h, National Instruments
Device ID = 17d0h, PCI-6503
PCI index = 0h
Class Codes = ff0000h
Revision ID = 0h
Bus number = 1
Device number = 12
Function num = 0
Status Reg = 280h
Command Reg = 7h
Header type = 0h Single-function
BIST = 0h Build-in-self-test not supported
Latency Timer = 20h
Cache Line Size= 8h un-cacheable
PCI Mem Address = de021000h 32bit length 4096 enabled
PCI Mem Address = de022000h 32bit length 4096 enabled
Max Lat = 0ns
Min Gnt = 0ns
PCI Int Pin = INT A
Interrupt line = 5

The Information that this program output:

device id = 17d0
Vendo id = 1093
BusNumber = 1
device number = c
Function number = 0
Revision = 0
device class = ff0000
device irq = 5
pcibase address = de021000
base address size = 1000
Base address 0 = de021000
Base address 1 = de022000
1 board mite addr: de021000
1 board mite new : 40100000
2 board reg addr : de022000
2 board reg new : 40101000
1 dev_handle: 8057018
1 mem_handle: 40101000
Configer register addr = 40101003
Configer register value = ff

Port A address = 40101000
Port A value = ff

Port B address = 40101001
Port B value = ff

Port C address = 40101002
Port C value = ff

You don’t need step 6, i.e. you don’t need to re-map device memory. In QNX you can access memory above 1MB as easy as the memory below 1MB. In other words, you don’t have to write anything in config space. All you need is to read physical address from BAR0 (and BAR1 later) and using mmap_device_memory() get a pointer which you can use to access that physical memory. Read carefully documentation for mmap_device_memory(). Currently you allocate physical memory (i.e. chunk of memory which is represended by real memory chips) and then re-map your device to respond to this memory range; ending up with two physically memory banks (one is computer memory bank and second is memory bank on your device) which are responding to the same memory access cycles. Beside of this you have a lot of mistakes pointed above by Mario, please read a good book on C programming, chapter on what is variable, what is pointer to variable and how to use pointers.
I hope this helps,
Cheers!

Sorry, looking thru your code second time I see you are not allocating physical memory. Just throw away all pci_write_config32() calls and all “0xaeae re-mapping biz”. Those addr[0] and addr[1] do have meaning for your process only, and absolutly useless for hardware - do not write them back to BAR0 & BAR1.

I have changed the code which modify the BAR0 and BAR1, But do nothing

I don’t think the problem is the code mistake, but the pci device didn’t opened. So if you have some experiment on pci board developing, please tell me how to do.

Maybe first you can tell us when you run the program, which function call it is faild? (You have a lot of fprintf(), any one hit?)

Mario pointed out you have a wrong dev_handle, did you also change that?

The programer can run ok untill usually stop without any software mistake.

The problem is hareware could not work when it running.

Now, I re-write the program for more clear.

It was built successfully, and there is no errors when the program running. But the problem is also alive: the device could not work on the software’s operation.

the re-write code:

/*******************************************************************************

  • file name :PCI6503_QNX_Driver.C
  • description :the driver for NI’s PCI6503
  • enviroment :QNX6.2.1
  • programmer :Qiming Ni
  • date :06/26/2007
    *******************************************************************************/

#include <sys/neutrino.h>
#include <hw/pci.h>
#include <hw/pci_devices.h>
#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>

#define PCI_DEBUG

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
#define PCI_CARD_DEVICE_ID 0x17d0
#define PCI_CARD_VENDOR_ID 0x1093

/********************************************************************************

  • function :pci_printf

  • description :printf the pci info

  • programmer :Qiming Ni

  • date :06/18/2007
    ********************************************************************************/
    void pci_printf(struct pci_dev_info *inf)
    {
    uint32_t i;

    fprintf (stdout, “\n device id = %x”, inf->DeviceId);
    fprintf (stdout, “\n Vendo id = %x”, inf->VendorId);
    fprintf (stdout, “\n BusNumber = %x”, inf->BusNumber);
    fprintf (stdout, “\n device number = %x”, ((inf->DevFunc)>>3)&0x1F);
    fprintf (stdout, “\n Function number = %x”, (inf->DevFunc)&0x07);
    fprintf (stdout, “\n Revision = %x”, inf->Revision);
    fprintf (stdout, “\n device class = %x”, inf->Class);
    fprintf (stdout, “\n device irq = %x”, inf->Irq);
    fprintf (stdout, “\n pcibase address = %x”, ((inf->CpuBaseAddress)));
    fprintf (stdout, “\n base address size = %x”, (
    (inf->BaseAddressSize)));

    pci_read_config32 (inf->BusNumber, inf->DevFunc, 0x10, 1, &i);
    fprintf (stdout, “\n Base address 0 = %x”, i);

    pci_read_config32 (inf->BusNumber, inf->DevFunc, 0x14, 1, &i);
    fprintf (stdout, “\n Base address 1 = %x”, i);
    }

/*******************************************************************************/
int main(int argc, char *argv)
{
struct pci_dev_info inf;

int      pci_handle;
uint32_t addr_handle;   
uint32_t io_addr;     
void *addr[2];          
void *dev_handle;          
unsigned index = 0;
unsigned bus; 
unsigned dev; 
unsigned func; 
unsigned dev_func; 

volatile uint8_t* x;
uint32_t value;

uint32_t BAR0, BAR1;

fprintf (stdout, "======================================================");

//intial some variable
memset (&inf, 0, sizeof (struct pci_dev_info)); 
inf.VendorId = PCI_CARD_VENDOR_ID; 
inf.DeviceId = PCI_CARD_DEVICE_ID; 

//get the hight provillege
ThreadCtl (_NTO_TCTL_IO, 0);

//open PCI server, so that you can use pci_*()
pci_handle = pci_attach(0); 
if (pci_handle == -1) 
    return 0;

//detect pci device
if (pci_find_device (inf.DeviceId, 
                     inf.VendorId, 
                     index, 
                     &bus, 
                     &dev_func) != PCI_SUCCESS) 
    return 0;

//get the device information
dev_handle = pci_attach_device (NULL,
                                (PCI_SHARE|PCI_SEARCH_VENDEV|PCI_INIT_ALL),
                                0,
                                &inf); 
if (dev_handle == NULL) 
    return 0; 

//print some information which have been found.
pci_printf (&inf);

//get pci mite address
if ( pci_read_config32 (inf.BusNumber, 
                        inf.DevFunc, 
                        0x10,
                        1, 
                        &BAR0)!= PCI_SUCCESS) 
    return 0;


//get pci board register address
if ( pci_read_config32 (inf.BusNumber, 
                        inf.DevFunc, 
                        0x14,
                        1, 
                        &BAR1)!= PCI_SUCCESS) 
    return 0;

//remap pci mite address
if (PCI_IS_MEM (BAR0))
    addr_handle = PCI_MEM_ADDR (BAR0);
else
    addr_handle = PCI_IO_ADDR (BAR0);

addr[0] = mmap_device_memory (NULL,
                              *(inf.BaseAddressSize),
                              (PROT_READ | PROT_WRITE | PROT_NOCACHE),//must NOCACHE
                              0,
                              (uint64_t)addr_handle); 

if (addr[0] == MAP_FAILED) 
    return 0; 

//remap pci board address
if (PCI_IS_MEM (BAR1))
    addr_handle = PCI_MEM_ADDR (BAR1);
else
    addr_handle = PCI_IO_ADDR (BAR1);

addr[1] = mmap_device_memory (NULL,
                              *(inf.BaseAddressSize),
                              (PROT_READ | PROT_WRITE | PROT_NOCACHE),
                              0,
                              (uint64_t)addr_handle);   

if (addr[1] == MAP_FAILED)
    return 0; 

//====================================================================================
//====================================================================================
//  set the windows date to new pci mite
x = (uint8_t*)addr[0] + 0xc0;
*((uint32_t*)x) = ((uint32_t)addr[1] & 0xffffff00)|0x80;

//Set Configer Register (all is output port)
x = (uint8_t*)addr[1]+0x03; 
*x = 0x80; 

//Port A output
x = (uint8_t*)addr[1]+0x0000;  
*x = 0xaa; 
fprintf (stdout, "\n  Port A address          = %x", x); 
fprintf (stdout, "\n  Port A value            = %x\n", *x); 

//Port B output
x = (uint8_t*)addr[1]+0x0001;  
*x = 0xaa; 
fprintf (stdout, "\n  Port B address          = %x", x); 
fprintf (stdout, "\n  Port B value            = %x\n", *x); 

//Port C output
x = (uint8_t*)addr[1]+0x0002;  
*x = 0xaa; 
fprintf (stdout, "\n  Port C address          = %x", x); 
fprintf (stdout, "\n  Port C value            = %x", *x); 

//====================================================================================
//====================================================================================
//release re-map memory
if (munmap_device_memory (addr[0], (*(inf.BaseAddressSize))) == -1) 
    fprintf (stdout, "\n Error:munmap ADDR0 failed!");  

if (munmap_device_memory (addr[1], (*(inf.BaseAddressSize))) == -1) 
    fprintf (stdout, "\n Error:munmap ADDR1 failed!"); 

//release the relation with the device
if (pci_detach_device(dev_handle) != PCI_SUCCESS)
	fprintf(stdout, "\n Error:detach device failed status!\n"); 

//release pci server
if (pci_detach (pci_handle) != PCI_SUCCESS) 
    fprintf (stdout, "\n Error:detach pci sever failed status!!%s\n", strerror (errno)); 

fprintf (stdout, "\n======================================================\n");
return 0;

}
/*******************************************************************************/