最近搞PCI6503的QNX驱动,不知道什么地方出了问题,老是驱动不了。经过老板同意,将全部代码贴上,希望能得高手指点。另外在贴的时候,原来都排好的,贴上都歪了,不整齐了,如果有必要还要请重新排一下。
这段代码的执行步骤是:
1 取得root权限
2 取得pci_*服务器的支持
3 查找pci设备时候存在,若存在则继续
4 取得板卡的info信息
5 将info信息打印
6 映射板卡的pci mite地址和pci register地址
7 取得进入BAR1的操作权限
8 通过映射指针对板卡进行操作
9 资源回收
问题现象描述:
打印信息正确,说明代码前面部分问题不大,但是执行完,发现板卡根本就不动。问题应该是打印代码后。
关于pci6503的介绍:
它是美国NI公司的24路DIO板,它上面有一个8255并行扩展芯片,通过它的三个端口PORTA/PORTB/PORTC实现数字量的输入和输出。关于它的寄存器级开发说明如下:
BASE+0: PORTA
BASE+1: PORTB
BASE+2: PORTC
BASE+3: CONFIG REGISTER
另外,在进行操作前,该板卡需要先获得BASE的操作权限,原文如下:
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.
- Write the address to which you want to re-map the PCI MITE to PCI configuration space offset 0x10 (BAR0).
- Write the value 0x0000aeae to offset 0x340 from the new PCI MITE address.
- Write the address to which you want to re-map the board (other than the PCI MITE) to PCI configuration space offset 0x14 (BAR1).
- 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.
- 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) ;
我的代码如下:
/*******************************************************************************
- 文件名称:PCI6503_QNX_Driver.C
- 文件说明:在QNX下,对NI公司24路DI/O板卡PCI6503的底层驱动开发。
- 运行环境:QNX6.2.1
- 程序员 :倪启明
- 时 间:2007年06月26日
*******************************************************************************/
#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;
/********************************************************************************
- 函数名称:pci_printf
- 函数说明:打印PCI设备信息
- 程序员 :倪启明
- 日 期:2007年06月18日
********************************************************************************/
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);
}
/********************************************************************************
- 函数名称:pci_card_detect
- 函数说明:对PCI设备进行探测
- 函数输入:devcieNo 设备号,
-
vendor 厂商号,
-
index 同类型板卡标识(从0开始)
- 函数输出:pci_handle PCI句柄
-
inf 设备信息
-
dev_handle 设备句柄
- 返回值 :PCI_YES 表示存在
- 程序员 :倪启明
- 日 期:2007年06月18日
********************************************************************************/
#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];
//取得root操作权限
ThreadCtl (_NTO_TCTL_IO, 0);
//将程序连接到PCI server上,使得整个程序可以使用QNX系统提供的pci_*()函数
*pci_handle = pci_attach(0);
if (*pci_handle == -1)
return ATTACH_PCI_FAILURE;
//PCI设备检测
if (pci_find_device (inf->DeviceId,
inf->VendorId,
index,
&bus,
&dev_func) != PCI_SUCCESS)
return FIND_FAILURE;
//将inf与PCI设备相连,同时取得设备信息
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);
//取得PCI MITE基地址
if ( pci_read_config32 (inf->BusNumber,
inf->DevFunc,
0x10,
1,
&BAR0)!= PCI_SUCCESS)
return ADDR_ERROR;
//取得PCI板卡寄存器基地址
if ( pci_read_config32 (inf->BusNumber,
inf->DevFunc,
0x14,
1,
&BAR1)!= PCI_SUCCESS)
return ADDR_ERROR;
//板卡pci mite映射
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;
}
/********************************************************************************
- 函数名称:close_card
- 函数说明:驱动退出时的资源释放处理
- 程序员 :倪启明
- 日 期:2007年06月18日
********************************************************************************/
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”);
//收回与PCI server的关联
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; //PCI函数使用句柄
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;
//PCI设备探测
if (pci_card_detect (index,
&pci_handle, //pci句柄
&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;
}
/*******************************************************************************/