How to port a Linux driver to QNX?

Hi,
I am a newbie to QNX. Now there is a project for us to develop embedded automation software on QNX. A very simple time-synchronization driver for Linux must be ported onto QNX.
Can anyone give me some directions to follow and do this porting?

The online documentation and the book version describe in great detail how to build a resource manager.

A resource manager allows a process to own part of the name space, eg. /dev/your_device, and thereby receive open calls to that name space. Once connected, other calls, eg. read(), write(), ioctl() are passed to routines in the driver for handling. It is up to you to move the appropriate Linux code into the right place.

Along with the complications of a resource manager, there are QNX specific issues related to handing hardware I/O ports, shared memory and interrupts. There also is the question of whether to have a single threaded driver, or to use the thread pool feature. Robert Krten’s book on Neutrino has some good information on all of this.

amazon.com/Getting-Started-N … ywords=QNX

QNX provides some source examples such as the /dev/null driver.

Thanks maschoen for the reply.
I just browse the book and try the atoz example. It does work.
But I was confused by the example as compared to Linux driver.
Does resource manager act as a device driver?
Considering atoz example, is the resource manager a running process?
How to read/write bytes from/to PCI hardware in my resource manager?
I want to port a pci driver, the code lists as follows:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>

MODULE_LICENSE("Dual BSD/GPL");

#define	PCISZK 0
#define	PCISZK_DRIVER_NAME "PCI_SZK"

static int PCISZK_open(struct inode *inode, struct file *filp);
static int PCISZK_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
static int PCISZK_write( struct file *filp, char *buf, size_t count, loff_t *f_pos);
static int PCISZK_release(struct inode *inode, struct file *filp);

void meminb(void *src,void *dest,int length);
void memoutb(void *src,void *dest,int length);

static struct pci_device_id PCISZK_ID[] = {
	{PCI_DEVICE(0x10B5, 0x9050), },
	{0,}
};

MODULE_DEVICE_TABLE(pci,PCISZK_ID);

struct PCI_SZK {
	unsigned long iobase;
	unsigned long iolen;
	unsigned int irq;
	unsigned long ioaddr;
}card;

struct file_operations PCISZK_fops = { 
	.read= PCISZK_read,
	.write= PCISZK_write,
	.open= PCISZK_open,
	.release= PCISZK_release
};

static int PCISZK_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
{
	printk("<1>Enter probe\n"); 
	if (pci_enable_device(pci_dev)){
		printk("<1>cannot enable device\n");
		return -EIO;
 	}
	
  card.iobase = pci_resource_start(pci_dev, 1);
	card.iolen = pci_resource_len(pci_dev, 1);
	printk("<1>iobase id %lu\n,iolen is %lu\n",card.iobase,card.iolen);

  card.irq = pci_dev->irq;

	unsigned long mem_base2;
	mem_base2 = pci_resource_start(pci_dev,2);
	request_mem_region(mem_base2,0x30,PCISZK_DRIVER_NAME);
	card.ioaddr = ioremap(mem_base2,0x30);
	
	printk("<1>Exit probe\n");
	return 0;
}

void PCISZK_remove(struct pci_dev *pdev)
{
	printk("<1>Exit module\n");
}

static struct pci_driver PCISZK_DRIVER = {
    name:       PCISZK_DRIVER_NAME,	
    id_table:   PCISZK_ID,	
    probe:      PCISZK_probe,
    remove:     PCISZK_remove
};

static int PCISZK_Driver_Init(void)
{
	int result = register_chrdev(61, "PCI_SZK", &PCISZK_fops);
		if (result < 0) { 
		printk("Can not register PCI dev!"); 
		return result; 
	}
	if (pci_register_driver(&PCISZK_DRIVER)) {
		pci_unregister_driver(&PCISZK_DRIVER);
		printk("<1>PCI register faild\n");
		return -ENODEV;
	}
	printk("<1>PCI register success\n");
	return 0;
}

static void PCISZK_Driver_Exit(void)
{
	unregister_chrdev(61, "PCI_SZK");
	iounmap(card.ioaddr);
	pci_unregister_driver(&PCISZK_DRIVER);
}

module_init(PCISZK_Driver_Init);
module_exit(PCISZK_Driver_Exit);

static int PCISZK_open(struct inode *inode, struct file *filp) {
	return 0;

}
static int PCISZK_release(struct inode *inode, struct file *filp) {

	return 0;  
}

static int PCISZK_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) {
 	
	unsigned char SZKDriver_buffer[11];
	unsigned char pageflag = inb(card.ioaddr + 0x0f);
	if(pageflag & 0x80){
		meminb(card.ioaddr + 0x20,SZKDriver_buffer,11);
	}else{
		meminb(card.ioaddr + 0x10,SZKDriver_buffer,11);
	}
	
	copy_to_user(buf,SZKDriver_buffer,11);

	return 11;
}

static int PCISZK_write( struct file *filp, char *buf, size_t count, loff_t *f_pos) {

	unsigned char SZKDriver_buffer[8];
	copy_from_user(SZKDriver_buffer ,buf ,8);
	memoutb(SZKDriver_buffer,card.ioaddr + 1, 8);
	writeb(0x55,card.ioaddr);
	return 8; 
}

void meminb(void *src,void *dest,int length){
	for(;length > 0 ;length--){
		*(char *)dest++ = readb((char *)src++);
	}
}

void memoutb(void *src,void *dest,int length){
	for(;length > 0 ;length--){
		writeb(*(char *)src++,(char *)dest++);
	}
}

Could you please anwser my questions?
Thank you very much.

Your question/confusion is quite understandable. The structure of QNX, a message passing microkernel, is very different from Linux, a monolithic kernel. Applications that avoid using message passing, can look the same on either OS. Drivers at the lowest level will look the same, but their interface to the OS will be very different.

A resource manager is a very generic form that can be a hardware driver.
It can also be used as a system resource that is software only in nature.

Any QNX program running as root can access hardware, but in many cases, a resource manager is the ideal format to use for a QNX driver.

Yes, in general a QNX driver is a separate process. In particular, a resource manager is a separate process with one or more threads. This is a great strength of QNX as it is possible for
a driver(process) to crash, and have the system recover without rebooting by restarting the driver.

The hardware aspect of this question is your responsibility. If you have Linux driver code, you should find the answer in that code. The OS interface side is found in the examples and description of a resource manager. In particular, the read()/write() code are function calls that you provide to the resource manager.

Most parts of this code have an obvious location within the resource manager format.
The system structures and pci_() interface will be different.
You will need to write your own interrupt handler, which can be very simple.

Hi maschoen, I understand resource manager now.
Is there an example for PCI driver?

Hi maschoen. I can find the pci device now. But the values of pci_dev_info.PciAddress[6] returned by pci_attach_device calling are all 0.
I find the pci device from the output results of pci -vvv command that all space access (I/O and memory for example) are disabled except INTx.

I wrote a program to test the IRIG-B time-synchronizing PCI card.

#include <hw/pci.h>
#include <hw/inout.h>
#include <hw/pci_devices.h>
#include <sys/neutrino.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define PCI_VENDOR_ID_SZK 0x10B5
#define PCI_DEVICE_ID_SZK 0x9050

int main()
{
	int pidx;
	void *hdl;
	int phdl;
	struct pci_dev_info inf;
	int i;
	uintptr_t iobase;
	
	ThreadCtl(_NTO_TCTL_IO, 0);
	phdl = pci_attach(0);
	if (phdl == -1) {
		fprintf(stderr, "Error: unable to initialize PCI\n");
		return EXIT_FAILURE;
	}
	memset(&inf, 0, sizeof(inf));
	pidx = 0;

	inf.VendorId = PCI_VENDOR_ID_SZK;
	inf.DeviceId = PCI_DEVICE_ID_SZK;
	hdl = pci_attach_device(NULL, 0, pidx, &inf);
	if (hdl == NULL) {
		fprintf(stderr, "Error: unable to locate adapter\n");
	}
	void *retval = pci_attach_device(hdl, PCI_SHARE | PCI_INIT_ALL, pidx, &inf);
	if (retval == NULL) {
		fprintf(stderr, "Error: unable to allocate resources\n");
	}

	printf("Found PCI: DeviceId = %04x, VendorId = %04x, BusNumber = %d, DevFunc = %d\n", 
		inf.DeviceId, inf.VendorId, inf.BusNumber, inf.DevFunc);

	for (i = 0; i < 6; i++) {
		printf("BaseAddressSize[%d] = %d, CpuBaseAddress[%d] = %llx, PciBaseAddress[%d] = %llx\n", 
			i, inf.BaseAddressSize[i], i, inf.CpuBaseAddress[i], i, inf.PciBaseAddress[i]);
		if (inf.BaseAddressSize[i] > 0) 
			printf("Aperture %d: "
				"Base 0x%llx Length %d bytes Type %s\n", i, 
				PCI_IS_MEM(inf.CpuBaseAddress[i]) ? 
				PCI_MEM_ADDR(inf.CpuBaseAddress[i]) : 
				PCI_IO_ADDR(inf.CpuBaseAddress[i]),
				inf.BaseAddressSize[i],
				PCI_IS_MEM(inf.CpuBaseAddress[i]) ? "MEM" : "IO");
	}
	printf("PCI irq = %d\n", inf.Irq);
	iobase = mmap_device_io(inf.BaseAddressSize[2], inf.CpuBaseAddress[2]);
	printf("mmap_device_io iobase = %x\n", iobase);
	uint8_t page = in8(iobase + 0x0f);
	printf("page flag = %d\n", page);
	uint8_t tmval;
	if (page & 0x80) {
		for (i = 0; i < 11; i++) {
			tmval = in8(iobase + 0x20 + i);
			printf("%02x ", tmval);
		}
	} else {
		for (i = 0; i < 11; i++) {
			tmval = in8(iobase + 0x10 + i);
			printf("%02x ", tmval);
		}
	}
	printf("\n");
	munmap_device_io(iobase, 0x30);
	pci_detach(phdl);
	return EXIT_SUCCESS;
}

Run testpci, it will output all the values of BaseAddressSize, CpuBaseAddress, PciBaseAddress are 0.

#testpci
Found PCI: DeviceId = 9050, VendorId = 10b5, BusNumber = 7, DevFunc = 104
BaseAddressSize[0] = 0, CpuBaseAddress[0] = 0, PciBaseAddress[0] = 0
BaseAddressSize[1] = 0, CpuBaseAddress[1] = 0, PciBaseAddress[1] = 0
BaseAddressSize[2] = 0, CpuBaseAddress[2] = 0, PciBaseAddress[2] = 0
BaseAddressSize[3] = 0, CpuBaseAddress[3] = 0, PciBaseAddress[3] = 0
BaseAddressSize[4] = 0, CpuBaseAddress[4] = 0, PciBaseAddress[4] = 0
BaseAddressSize[5] = 0, CpuBaseAddress[5] = 0, PciBaseAddress[5] = 0
PCI irq = 255
mmap_device_io iobase = 0
page flag = 0
9f ff b9 ff 9e ff bf ff 00 ff ff 

I also run pci -vv, the IRIG-B card is found.

#pci -vv

PCI version    = 3.00

Class          = Bridge (Other)
Vendor ID      = 10b5h, PLX Technology, Inc. 
Device ID      = 9050h,  PCI <-> IOBus Bridge
PCI index      = 0h
Class Codes    = 068000h
Revision ID    = 2h
Bus number     = 7
Device number  = 13
Function num   = 0
Status Reg     = 280h
Command Reg    = 0h
	I/O space access disabled
	Memory space access disabled
	Bus Master disabled
	Special Cycle operations ignored
	Memory Write and Invalidate disabled
	Palette Snooping disabled
	Parity Error Response disabled
	Data/Address stepping disabled
	SERR# driver disabled
	Fast back-to-back transactions to different agents disabled
	PCI INTx enabled
Header type    = 0h Single-function
BIST           = 0h Build-in-self-test not supported
Latency Timer  = 0h
Cache Line Size= 10h un-cacheable
Subsystem Vendor ID = 1h
Subsystem ID        = 4859h
Max Lat        = 0ns
Min Gnt        = 0ns
PCI Int Pin    = INT A
Interrupt line = no connection
Device Dependent Registers:
0x040:  0000 0000 0000 0000   0000 0000 0000 0000 
...
0x0f0:  0000 0000 0000 0000   0000 0000 0000 0000 

I think testpci.c is not written correctly, but I don’t know where it is.
Please give me some advise to solve the problem.

You might want to read this post

openqnx.com/phpbbforum/viewtopic.php?t=7883

Tim