Skip navigation.
Home
The QNX Community Portal

View topic - How to port a Linux driver to QNX?

How to port a Linux driver to QNX?

QNX Application portings.

How to port a Linux driver to QNX?

Postby Allen Chen » Fri May 24, 2013 6:33 am

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?
Allen Chen
New Member
 
Posts: 9
Joined: Fri May 24, 2013 6:26 am

Re: How to port a Linux driver to QNX?

Postby maschoen » Fri May 24, 2013 8:09 am

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.

http://www.amazon.com/Getting-Started-N ... ywords=QNX

QNX provides some source examples such as the /dev/null driver.
maschoen
QNX Master
 
Posts: 2640
Joined: Wed Jun 25, 2003 5:18 pm

Re: How to port a Linux driver to QNX?

Postby Allen Chen » Fri May 24, 2013 2:48 pm

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:

Code: Select all
#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.
Allen Chen
New Member
 
Posts: 9
Joined: Fri May 24, 2013 6:26 am

Re: How to port a Linux driver to QNX?

Postby maschoen » Mon May 27, 2013 11:58 pm

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.

Allen Chen wrote:...
Does resource manager act as a device driver?

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.

Considering atoz example, is the resource manager a running process?


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.

How to read/write bytes from/to PCI hardware in my resource manager?


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.

I want to port a pci driver, the code lists as follows:

...


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.
maschoen
QNX Master
 
Posts: 2640
Joined: Wed Jun 25, 2003 5:18 pm

Re: How to port a Linux driver to QNX?

Postby Allen Chen » Tue May 28, 2013 6:44 am

Hi maschoen, I understand resource manager now.
Is there an example for PCI driver?
Allen Chen
New Member
 
Posts: 9
Joined: Fri May 24, 2013 6:26 am

Re: How to port a Linux driver to QNX?

Postby Allen Chen » Tue May 28, 2013 9:39 am

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.
Allen Chen
New Member
 
Posts: 9
Joined: Fri May 24, 2013 6:26 am

Re: How to port a Linux driver to QNX?

Postby Allen Chen » Tue May 28, 2013 11:34 am

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

Code: Select all
#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.

Code: Select all
#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.

Code: Select all
#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.
Allen Chen
New Member
 
Posts: 9
Joined: Fri May 24, 2013 6:26 am

Re: How to port a Linux driver to QNX?

Postby Tim » Tue May 28, 2013 5:16 pm

Tim
Senior Member
 
Posts: 1388
Joined: Wed Mar 10, 2004 12:28 am


Return to Porting

Who is online

Users browsing this forum: No registered users and 1 guest