All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai-help] rtdm_irq_request() returns error
@ 2011-01-14 22:50 Peter Hua
  2011-01-14 22:55 ` Gilles Chanteperdrix
  0 siblings, 1 reply; 2+ messages in thread
From: Peter Hua @ 2011-01-14 22:50 UTC (permalink / raw)
  To: xenomai; +Cc: pwfhua


[-- Attachment #1.1: Type: text/plain, Size: 28161 bytes --]

Hello,

 

My call to rtdm_irq_request() is returnning error -16.  I have verified all
inputs.  I am running Xenomai 2.4.10 on Red Hat 5.5 (kernel 2.6.29.1).  Here
is the snippit; the complete file is also attached.  Please help.

 

 

err = rtdm_irq_request(&ctx->irq_handle, ctx->pdev->irq,

                               (rtdm_irq_handler_t)malibu_intr_handler,

                               irqtype,

                               context->device->proc_name,  (void *)ctx);

 

 

 

/**

* This a driver written to interface with DSP boards from Innovative
Integration

* It utilizes the RTDM device APIs from the Xenomai realtime Linux project.

*

*/

 

#include <linux/version.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/pci.h>

#include <linux/interrupt.h>

#include <linux/delay.h>

#include <linux/workqueue.h>

#include <linux/reboot.h>

#include <linux/slab.h>

#include <linux/cdev.h>

#include <linux/spinlock.h>

#include <linux/pagemap.h>

#include <linux/semaphore.h>

#include <linux/list.h>

#include <asm/uaccess.h>

#include <asm/dma.h>

#include <asm/delay.h>

#include <asm/io.h>

#include <asm/msr.h>

#include <asm/page.h>

 

#include <rtdm/rtdm_driver.h>

 

#include "malibu.h"

 

#define VENDOR_ID                 0x1303

#define       DRV_NAME            "malibu"

#define SIZE_MAX          1024

#define SOME_SUB_CLASS                1303

 

 

static void errMsg(int line, const char *place, const char *msg)

{

    printk(KERN_ALERT "malibu: Error at %s() line: %d, %s\n", place, line,
msg);

}

 

#define       MY_ERR(s)   errMsg(__LINE__, __FUNCTION__, s)

 

static void logMsg(int line, const char *place, const char *msg)

{

    printk(KERN_INFO "MalibuDrv_RT: %s() line: %d, %s\n", place, line, msg);

}

 

#define       MY_PRINT(s) logMsg(__LINE__, __FUNCTION__, s);

 

typedef struct {

    void*                 kAddr;

    uint64_t  start;

    uint64_t  end;

    uint64_t  size;

} MyBar;

 

typedef struct {

    void*                 kAddr;

    dma_addr_t       physAddr;

    uint32_t  size;

} MyBuf;

 

typedef struct {

    struct list_head list;

    struct cdev                 cdev;

    struct device     *sysdev;

    struct pci_dev   *pdev;

    dev_t                myDevT;

 

    MyBar               bars[MALIBU_BAR_MAX];

    MyBuf               bufs[MALIBU_BUF_MAX];

 

    wait_queue_head_t     intrWait;

    struct fasync_struct* async_queue;

    int                     mySig;

    void*                 intrStatusAddr;

    u32                            intrMask;

    u8                     intrWriteback;

    u32                            iQueue[MALIBU_INTR_MAX];

    u32                            iPtrLow;

    u32                            iPtrHi;

    void                  (*cntxtFunc)(void*);

    void                  *cntxtArg;

 

    u16                            devOpen;

    u8                     wrOpen;

    u8                     numBars;

    u8                     isIrqEnabled;

    int                 dev_id;

    struct rtdm_device *xen_rtdm_device;

    rtdm_irq_t         irq_handle;  /* device IRQ handle */

} MyData;

 

static struct class* devClass;

static dev_t           baseDevT;

 

static int      devCnt = 0;

LIST_HEAD(devList);

 

static int fasync(int fd, struct file *filep, int mode);

//static irqreturn_t board_handler(unsigned int irq, void *dev_id, struct
pt_regs *regs);

static int malibu_intr_handler(rtdm_irq_t * irq_context);

 

static char msgbuf[1000];

 

static int malibu_rtdm_open(struct rtdm_dev_context *context,

                        rtdm_user_info_t * user_info, int oflags)

//static int open(struct inode *inodep, struct file *filep)

{

    MyData *md, *ctx;

    bool found=false;

    int err=0;

 

    MY_PRINT("start");

    ctx = (MyData *)context->dev_private;

 

    list_for_each_entry(md, &devList, list) {

         if (md->dev_id == context->device->device_id)

         {

                found = true;

                MY_PRINT("device FOUND");

 

                sprintf (msgbuf, "md=%p, md->device_id=%d", md, md->dev_id);

                MY_PRINT(msgbuf);

 

                memcpy(ctx, md, sizeof(MyData));

 

                break;

         }

    }

 

    if(!found)

    {

        MY_ERR("no matching device");

        return -ENODEV;

    }

 

 

    if (ctx->wrOpen && (oflags & FMODE_WRITE)) {

            MY_ERR("device already opened");

            return -EBUSY;

    }

 

 

    if (oflags & FMODE_WRITE)

    {

        ctx->iPtrLow = 0;

        ctx->iPtrHi = 0;

        ctx->mySig = SIGIO;

        ctx->cntxtFunc = 0;

        ctx->cntxtArg = 0;

 

        static unsigned long irqtype = (RTDM_IRQTYPE_SHARED |
RTDM_IRQTYPE_EDGE);

 

        sprintf(msgbuf, "irqtype=%d", irqtype);

        MY_PRINT(msgbuf);

 

        err = rtdm_irq_request(&ctx->irq_handle, ctx->pdev->irq,

                               (rtdm_irq_handler_t)malibu_intr_handler,

                               irqtype,

                               context->device->proc_name,  (void *)ctx);

 

        if(err != 0)

        {

            sprintf(msgbuf, "rtdm_irq_request() failed, err=%d, irq=%d,
proc_name=%s",

                    err, ctx->pdev->irq, context->device->proc_name);

            MY_ERR(msgbuf);

            return err;

        }

 

        sprintf(msgbuf, "rtdm_irq_request() OK, irq=%d", ctx->irq_handle);

        MY_PRINT(msgbuf);

 

#if 0

        if (request_irq(md->pdev->irq, (irq_handler_t)board_handler,
IRQF_SHARED, DRV_NAME, (void*)md)) {

                MY_ERR("irq request error");

                return -ENODEV;

        }

#endif

 

        ctx->wrOpen = 1;

    }

 

    ctx->devOpen++;

 

    MY_PRINT("end OK");

    return 0;

}

 

/**

* Close the device

*

* This function is called when the device shall be closed.

*

*/

static int malibu_rtdm_close(struct rtdm_dev_context *context,

                            rtdm_user_info_t * user_info)

{   

    MyData *ctx = context->dev_private;

    rtdm_irq_free(&ctx->irq_handle);

 

    sprintf(msgbuf, "ctx=0x%p, irq=%d", ctx, ctx->irq_handle);

    MY_PRINT(msgbuf);

    MY_PRINT("closing device");

    return 0;

}

 

#if 1

static void freeBuffer(MyData* md, int n)

{

    MyBuf* b = &md->bufs[n];

    if (b->size == 0) return;

    dma_free_coherent(&md->pdev->dev, b->size, b->kAddr, b->physAddr);

    b->size = 0;

}

 

static int release(struct inode *inode, struct file *filep)

{

    int           i;

    MyData*            md = (MyData*) filep->private_data;

 

    md->devOpen--;

 

    if (filep->f_mode & FMODE_WRITE) {

            md->wrOpen = 0;

            free_irq(md->pdev->irq, md);

            for (i = 0; i < MALIBU_BUF_MAX; i++) freeBuffer(md, i);

            fasync(-1, filep, 0);

    }

 

    return 0;

}

 

//static int ioctl(struct inode *inodep, struct file *filep, unsigned int
cmd, unsigned long arg)

int malibu_rtdm_ioctl(struct rtdm_dev_context   *context,

                      rtdm_user_info_t          *user_info,

                      int                       cmd,

                      void                      *arg)

{

    MyData* md = (MyData *)context->dev_private;

    int err = 0;

    int retval = 0;

    ioc_param_struct param = {0,0};

 

    if (_IOC_TYPE(cmd) != MALIBU_IOC_MAGIC) return -ENOTTY;

 

    /*

    * the direction is a bitmask, and VERIFY_WRITE catches R/W

    * transfers. `Type' is user-oriented, while

    * access_ok is kernel-oriented, so the concept of "read" and

    * "write" is reversed (i.e. when an user wants to read data,

    * the kernel has to write them into the user space)

    *

    * always check the user space address before accessing it

    *

    * access_ok returns 0 for failure!

    */

    if (_IOC_DIR(cmd) & _IOC_READ)

      err = !rtdm_read_user_ok(user_info, arg, sizeof(ioc_param_struct));

    else if (_IOC_DIR(cmd) & _IOC_WRITE)

      err = !rtdm_rw_user_ok(user_info, arg, sizeof(ioc_param_struct));

    if (err) return -EFAULT;

 

    switch(cmd) {

            case MALIBU_GET_INFO: {

                    MalibuDrv_INFO    x;

                    x.vendorId = md->pdev->vendor;

                    x.deviceId = md->pdev->device;

                    x.subVendorId = md->pdev->subsystem_vendor;

                    x.subDeviceId = md->pdev->subsystem_device;

                    x.revision = md->pdev->revision;

                    x.bus = md->pdev->bus->number;

                    x.slot = PCI_SLOT(md->pdev->devfn);

                    x.func = PCI_FUNC(md->pdev->devfn);

                    x.numBars = md->numBars;

 

                    MY_PRINT("copying data to user");

 

                    sprintf(msgbuf, "x.vendorId=0x%x, x.deviceId=0x%x,
x.numBars=%d",

                            md->pdev->vendor, md->pdev->device, x.numBars);

                    MY_PRINT(msgbuf);

                    //return (0 == copy_to_user((void __user*)arg, &x,
sizeof(x))) ? 0 : -EFAULT;

            }

 

            case MALIBU_GET_BAR_SIZE:

                    if (*(int *)arg < 0 || *(int *)arg >= MALIBU_BAR_MAX)
return -EINVAL;

                    return md->bars[*(int *)arg].size;

 

            case MALIBU_ALLOC_BUFFER: {

                    int                        n;

                    MalibuDrv_Buffer  x;

                    MyBuf*                           b;

 

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return
-EACCES;

 

                    for (n = 0; n < MALIBU_BUF_MAX; n++) {

                            if (md->bufs[n].size == 0) break;

                    }

                    if (n == MALIBU_BUF_MAX) {

                            MY_ERR("");

                            return -ENOMEM;

                    }

                    if (copy_from_user(&x, (const void __user*)arg,
sizeof(x))) return -EFAULT;

                    b = &md->bufs[n];

 

                    b->size = ((x.size + PAGE_SIZE - 1) / PAGE_SIZE) *
PAGE_SIZE;

                    b->kAddr = dma_alloc_coherent(&md->pdev->dev, b->size,
&b->physAddr, GFP_KERNEL);

                    if (b->kAddr == 0) {

                            b->size = 0;

                            MY_ERR("");

                            return -ENOMEM;

                    }

                    x.physAddr = b->physAddr;

                    x.bufNum = n;

                    x.fileOffset = (n + MALIBU_BAR_MAX) * MALIBU_MMAP_SIZE;

                    if (copy_to_user((void __user*)arg, &x, sizeof(x))) {

                            freeBuffer(md, x.bufNum);

                            return -EFAULT;

                    }

                    ((uint32_t*)b->kAddr)[0] = 0x12345678;

                    ((uint32_t*)b->kAddr)[1] = n;

                    ((uint32_t*)b->kAddr)[2] = md->myDevT;

                    return 0;

            }

 

            case MALIBU_FREE_BUFFER: {

                    int                        i;

                    MalibuDrv_Buffer  x;

 

                    //TODO:if (!(filep->f_mode & FMODE_WRITE)) return
-EACCES;

 

                    if (copy_from_user(&x, (const void __user*)arg,
sizeof(x))) return -EFAULT;

                    for (i = 0; i < MALIBU_BUF_MAX; i++) {

                            if (md->bufs[i].physAddr == x.physAddr) {

                                    freeBuffer(md, i);

                                    break;

                            }

                    }

                    if (i == MALIBU_BUF_MAX) {

                            MY_ERR("");

                            return -ENOMEM;

                    }

                    return 0;

            }

 

            case MALIBU_ISR_ENABLE:

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return
-EACCES;

                    enable_irq(md->pdev->irq);

                    md->isIrqEnabled = 1;

                    return 0;

            case MALIBU_ISR_DISABLE:

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return
-EACCES;

                    md->isIrqEnabled = 0;

                    disable_irq(md->pdev->irq);

                    return 0;

            case MALIBU_GET_ISR_ENABLED:

                    return md->isIrqEnabled;

            case MALIBU_GET_ISR_DEPTH:

                    return (md->iPtrLow - md->iPtrHi);

            case MALIBU_ISR_CLEAR_ALL:

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return
-EACCES;

                    disable_irq(md->pdev->irq);

                    md->iPtrLow = 0;

                    md->iPtrHi = 0;

                    enable_irq(md->pdev->irq);

                    return 0;     // no implemented yet

            case MALIBU_DEQUEUE_ISR: {

                    MalibuDrv_DequeueISR  x;

                    unsigned long                j;

                    int                        ret;

 

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return
-EACCES;

                    if (copy_from_user(&x, (const void __user*)arg,
(caddr_t)&x.depth - (caddr_t)&x)) return -EFAULT;

 

                    x.depth = 0;

                    x.cntxtFunc = md->cntxtFunc;

                    x.cntxtArg = md->cntxtArg;

                    x.errno = 0;

                    x.depth = 0;

 

                    j = timeval_to_jiffies(&x.timeout);

                    if (j == 0) {

                            if (md->iPtrLow != md->iPtrHi) {

                                    while (md->iPtrLow != md->iPtrHi &&
x.depth < MALIBU_INTR_MAX) {

                                            x.data[x.depth++] =
md->iQueue[md->iPtrHi % MALIBU_INTR_MAX];

                                            md->iPtrHi++;

                                    }

                            }

                            else {

                                    x.errno = ENODATA;

                            }

                    }

                    else {

                            ret =
wait_event_interruptible_timeout(md->intrWait, md->iPtrLow != md->iPtrHi,
j);

                            if (ret == 0) x.errno = ETIME;

                            else if (ret == -ERESTARTSYS) x.errno =
ERESTARTSYS;

                            else {

                                    while (md->iPtrLow != md->iPtrHi &&
x.depth < MALIBU_INTR_MAX) {

                                            x.data[x.depth++] =
md->iQueue[md->iPtrHi % MALIBU_INTR_MAX];

                                            md->iPtrHi++;

                                    }

                                    jiffies_to_timeval(ret, &x.timeout);

                            }

                    }

                    if (copy_to_user((void __user*)arg, &x,
(caddr_t)&x.data[x.depth] - (caddr_t)&x)) return -EFAULT;

                    return 0;

            }

            case MALIBU_SET_ISR_CTRL: {

                    MalibuDrv_IntCtrl  x;

 

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return
-EACCES;

                    if (copy_from_user(&x, (const void __user*)arg,
sizeof(x))) return -EFAULT;

                    md->intrMask = x.mask;

                    md->intrWriteback = x.type;

                    if (x.bar > MALIBU_BAR_MAX) {

                            MY_ERR("");

                            return -EINVAL;

                    }

                    if (x.byteOffset > md->bars[x.bar].size) {

                            MY_ERR("");

                            return -EINVAL;

                    }

                    md->intrStatusAddr = md->bars[x.bar].kAddr +
x.byteOffset;

                    md->cntxtFunc = x.cntxtFunc;

                    md->cntxtArg = x.cntxtArg;

                    return 0;

            }

            case MALIBU_SET_SIG:

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return
-EACCES;

                    md->mySig = arg;

                    return 0;

            case MALIBU_FAKE_SIG: {

                    MalibuDrv_FakeISR         x;

 

                    if (copy_from_user(&x, (const void __user*)arg,
sizeof(x))) return -EFAULT;

                    if ((md->iPtrLow - md->iPtrHi) <
MALIBU_INTR_MAX-x.depth-1) {

                            int      i;

 

                            for (i = 0; i < x.depth; i++) {

                                    md->iQueue[md->iPtrLow %
MALIBU_INTR_MAX] = x.data[i];

                                    md->iPtrLow++;

                            }

                            wake_up_interruptible(&md->intrWait);

                            if (md->async_queue)
kill_fasync(&md->async_queue, md->mySig, POLL_IN);

                    }

                    return 0;

            }

            default:

                    return -EINVAL;

    }

}

 

//static irqreturn_t board_handler(unsigned int irq, void *dev_id, struct
pt_regs *regs)

static int malibu_intr_handler(rtdm_irq_t * irq_context)

{

#if 0

    uint32_t  rd;

    MyData*            md = (MyData*) dev_id;

 

    if(md->pdev->irq != irq) return IRQ_NONE;

 

    rd = ioread32(md->intrStatusAddr);

 

    if ((rd & md->intrMask) == 0) return IRQ_NONE;

 

    if ((md->iPtrLow - md->iPtrHi) < MALIBU_INTR_MAX-1) {

            md->iQueue[md->iPtrLow % MALIBU_INTR_MAX] = rd;

            md->iPtrLow++;

            wake_up_interruptible(&md->intrWait);

            if (md->async_queue && md->mySig) kill_fasync(&md->async_queue,
md->mySig, POLL_IN);

    }

    if (md->intrWriteback) iowrite32(rd, md->intrStatusAddr);

#endif

 

    return IRQ_HANDLED;

}

 

static void vma_open(struct vm_area_struct* vma) { }

static void vma_close(struct vm_area_struct* vma) { }

 

static struct vm_operations_struct remap_vm_ops = {

    .open = vma_open,

    .close = vma_close,

};

 

static int mmap(struct file *filep, struct vm_area_struct *vma)

{

    MyData*            md = (MyData*) filep->private_data;

    unsigned long   off = vma->vm_pgoff << PAGE_SHIFT;

    unsigned long   vsize = vma->vm_end - vma->vm_start;

    unsigned long   seg = off / MALIBU_MMAP_SIZE;

    unsigned long   seg_off = off % MALIBU_MMAP_SIZE;

    unsigned long   psize, pfn;

 

    if (seg >= 0 && seg < MALIBU_BAR_MAX) {

            if (md->bars[seg].size == 0) return -EINVAL;

            pfn = (md->bars[seg].start + seg_off) >> PAGE_SHIFT;

            psize = md->bars[seg].size - seg_off;

    }

    else if (seg >= MALIBU_BAR_MAX && seg < MALIBU_BAR_MAX + MALIBU_BUF_MAX)
{

            seg -= MALIBU_BAR_MAX;

            if (md->bufs[seg].size == 0) return -EINVAL;

            pfn = __pa(md->bufs[seg].kAddr + seg_off) >> PAGE_SHIFT;

            psize = md->bufs[seg].size - seg_off;

    }

    else return -EINVAL;

 

    if (vsize > psize) return -EINVAL;

    if (remap_pfn_range(vma, vma->vm_start, pfn, vsize, vma->vm_page_prot))
return -EAGAIN;

 

    vma->vm_ops = &remap_vm_ops;

    vma_open(vma);

    return 0;

}

 

static int fasync(int fd, struct file *filep, int mode)

{

    MyData*            md = (MyData*) filep->private_data;

    return fasync_helper(fd, filep, mode, &md->async_queue);

}

 

static struct file_operations myFileOps = {

    .owner     = THIS_MODULE,

    .open       = malibu_rtdm_open,

    .release   = release,

    .ioctl        = malibu_rtdm_ioctl,

    .mmap    = mmap,

    .fasync    = fasync,

};

 

 

 

static ssize_t showDevInfo(struct device *dev, struct device_attribute*
attr, char *buf)

{

    MyData* md = (MyData*)dev->driver_data;

    return snprintf(buf, PAGE_SIZE,

            "vendor=0x%x\n"

            "device=0x%x\n"

            "subsystem_vendor=0x%x\n"

            "subsystem_device=0x%x\n"

            "revision=0x%x\n"

            "bus=0x%x\n"

            "slot=0x%x\n"

            "func=0x%x\n"

            "numBars=%d\n",

            md->pdev->vendor,

            md->pdev->device,

            md->pdev->subsystem_vendor,

            md->pdev->subsystem_device,

            md->pdev->revision,

            md->pdev->bus->number,

            PCI_SLOT(md->pdev->devfn),

            PCI_FUNC(md->pdev->devfn),

            md->numBars);

}

static DEVICE_ATTR(devInfo, 0444, showDevInfo, NULL);

 

 

/**

* This structure describe the malibu RTDM device

*

*/

static struct rtdm_device malibu_rtdm_device = {

    .struct_version = RTDM_DEVICE_STRUCT_VER,

 

    .device_flags = RTDM_NAMED_DEVICE,

    .context_size = sizeof(MyData),

    .device_name = DRV_NAME,

 

    .open_rt =  malibu_rtdm_open,

    .open_nrt = malibu_rtdm_open,

 

    .ops = {

            .close_rt = malibu_rtdm_close,

            .close_nrt = malibu_rtdm_close,

            .ioctl_rt =  malibu_rtdm_ioctl,

            .ioctl_nrt = malibu_rtdm_ioctl,

            //.read_nrt = NULL,

            //.write_nrt = NULL,

    },

 

 

    .device_class = RTDM_CLASS_EXPERIMENTAL,

    .device_sub_class = SOME_SUB_CLASS,

    .profile_version = 1,

    .driver_name = DRV_NAME,

    .driver_version = RTDM_DRIVER_VER(0, 1, 0),

    .peripheral_name = "Malibu RT driver",

    .provider_name = "Innovative Integration",

    .proc_name = DRV_NAME,

};

 

static int allocEachDev(struct pci_dev *pdev, const struct pci_device_id
*id)

{

    struct rtdm_device  *rtdm_dev;

    int    ret_val = 0;

    MyData *md, *lPtr;

    int  i, bCntr, error, b;

 

    MY_PRINT("start");

 

    if(id->vendor != VENDOR_ID) {

            MY_ERR("");

            return -ENODEV;

    }

 

    md = (MyData*) kzalloc(sizeof(MyData), GFP_KERNEL);

 

    md->pdev = pdev;

 

    sprintf(msgbuf, "pdev->irq=%d", pdev->irq);

    MY_PRINT(msgbuf);

 

    if (pci_enable_device(pdev)) {

            MY_ERR("");

            kfree(md);

            return -ENODEV;

    }

 

    pci_set_master(pdev);

 

    b = 0;

    for (i = 0; i < MALIBU_BAR_MAX; i++) {

            md->bars[b].start        = pci_resource_start(pdev, i);

            md->bars[b].end          = pci_resource_end(pdev, i);

            md->bars[b].size          = pci_resource_len(pdev, i);

            printk(KERN_ERR "bar=%d start=%llx end=%llx len=%llx\n", i,

                    md->bars[b].start,

                    md->bars[b].end,

                    md->bars[b].size);

            if (md->bars[b].size == 0) continue;

            md->bars[b].kAddr      = (void*) ioremap(md->bars[i].start,
md->bars[i].end - md->bars[i].start);

            b++;

    }

    md->numBars = i;

 

    init_waitqueue_head(&md->intrWait);

 

    cdev_init(&md->cdev, &myFileOps);

    md->cdev.owner = THIS_MODULE;

    md->myDevT = MKDEV(MAJOR(baseDevT), MINOR(baseDevT)+devCnt);

    if (cdev_add(&md->cdev, md->myDevT, 1)) {

            MY_ERR("");

            pci_disable_device(md->pdev);

            kfree(md);

            return -ENODEV;

    }

 

    bCntr = 0;

    list_for_each_entry(lPtr, &devList, list) {

            if (lPtr->pdev->device == pdev->device) bCntr++;

    }

 

    md->sysdev = device_create(devClass, &md->pdev->dev, md->myDevT, NULL,
"malibu%04x_%d", pdev->device, bCntr);

    if (IS_ERR(md->sysdev)) {

            MY_ERR("");

            cdev_del(&md->cdev);

            pci_disable_device(md->pdev);

            kfree(md);

            return -ENODEV;

    }

    md->sysdev->driver_data = (void*)md;

 

    error = device_create_file(md->sysdev, &dev_attr_devInfo);

    if (error) {

            MY_ERR("");

            device_destroy(devClass, md->myDevT);

            cdev_del(&md->cdev);

            for (i = 0; i < MALIBU_BAR_MAX; i++) {

                    if (md->bars[i].size) {

                            iounmap(md->bars[i].kAddr);

                            md->bars[i].size = 0;

                    }

            }

            pci_disable_device(md->pdev);

            kfree(md);

            return error;

    }

 

    md->dev_id = devCnt;

 

 

    //alloc mem for rtdm structure

    rtdm_dev = kmalloc(sizeof(struct rtdm_device), GFP_KERNEL);

    if(!rtdm_dev){

      MY_ERR("rtdm_device kmalloc failed\n");

      ret_val = -ENOMEM; //Insufficient storage space is available.

      return ret_val;

    }

 

    //copy the structure to the new memory

    memcpy(rtdm_dev, &malibu_rtdm_device, sizeof(struct rtdm_device));

 

    //create filename

    snprintf(rtdm_dev->device_name,

             RTDM_MAX_DEVNAME_LEN, "malibu_%d", devCnt);

 

    rtdm_dev->device_id = devCnt;

 

    //define two other members of the rtdm_device structure

    rtdm_dev->proc_name = rtdm_dev->device_name;

 

    ret_val = rtdm_dev_register(rtdm_dev);

 

    if(ret_val < 0){

      MY_ERR("failed to register device with RTDM\n");

      ret_val = -ENODEV;

      return ret_val;

    }

 

    md->xen_rtdm_device = rtdm_dev;

 

    list_add_tail(&md->list, &devList);

 

    //always do this last

    devCnt++;

 

    MY_PRINT("end OK");

    return 0;

}

 

static void removeAllDev(struct pci_dev *pdev)

{

    MyData *md, *tmp;

 

    MY_PRINT("start");

 

    list_for_each_entry_safe(md, tmp, &devList, list)

    {

        if (md == NULL)

        {

            MY_PRINT("md is NULL");

            return;

        }

 

        int       i;

 

        list_del(&md->list);

 

 

        device_remove_file(md->sysdev, &dev_attr_devInfo);

        device_destroy(devClass, md->myDevT);

        cdev_del(&md->cdev);

 

        for (i = 0; i < MALIBU_BUF_MAX; i++) freeBuffer(md, i);

 

        for (i = 0; i < MALIBU_BAR_MAX; i++) {

            if (md->bars[i].size) {

                iounmap(md->bars[i].kAddr);

                md->bars[i].size = 0;

            }

        }

 

        pci_disable_device(md->pdev);

 

        //remove char device from the system

        //unregister RTdriver

        rtdm_dev_unregister(md->xen_rtdm_device, 1000);

 

        kfree(md->xen_rtdm_device);

        kfree(md);

 

        devCnt--;

}

 

    MY_PRINT("end");

}

#endif

 

static struct pci_device_id ids[] = {

    { PCI_DEVICE(VENDOR_ID, PCI_ANY_ID) },

    { 0 },

};

 

static struct pci_driver pci_driver = {

    .name      = DRV_NAME,

    .id_table  = ids,

    .probe     = allocEachDev,

    .remove   = removeAllDev,

};

 

 

//MODULE_DEVICE_TABLE(pci, ids);

 

static ssize_t showDevCount(struct class *cls, char *buf)

{

    return sprintf(buf, "%d\n", devCnt);

}

 

static CLASS_ATTR(devCount, 0444, showDevCount, NULL);

 

/**

* This function is called when the module is loaded

*

* It simply registers the RTDM device.

*

*/

static int __init mod_init(void)

{

    int error;

 

    MY_PRINT("initializing MalibuDrv_RT module");

 

    devClass = class_create(THIS_MODULE, DRV_NAME);

    if (IS_ERR(devClass)) {

            MY_ERR("");

            return PTR_ERR(devClass);

    }

 

    error = class_create_file(devClass, &class_attr_devCount);

    if (error) {

            MY_ERR("");

            class_destroy(devClass);

            return error;

    }

 

    error = alloc_chrdev_region(&baseDevT, 0, MALIBU_MAX_DEVS, DRV_NAME);

    if (error) {

            MY_ERR("");

            class_remove_file(devClass, &class_attr_devCount);

            class_destroy(devClass);

            return error;

    }

 

    error = pci_register_driver(&pci_driver);

    if (error) {

        MY_ERR("");

        unregister_chrdev_region(baseDevT, MALIBU_MAX_DEVS);

        class_remove_file(devClass, &class_attr_devCount);

        class_destroy(devClass);

        return error;

    }

 

    return error;

}

 

/**

* This function is called when the module is unloaded

*

* It unregister the RTDM device, polling at 1000 ms for pending users.

*

*/

static void __exit mod_exit(void)

{

    MY_PRINT("unregistering MalibuDrv_RT module");

 

    pci_unregister_driver(&pci_driver);

    unregister_chrdev_region(baseDevT, MALIBU_MAX_DEVS);

    class_remove_file(devClass, &class_attr_devCount);

    class_destroy(devClass);

}

 

 

module_init(mod_init);

module_exit(mod_exit);

MODULE_LICENSE("GPL");

 

Thanks,

Peter Hua

 


[-- Attachment #1.2: Type: text/html, Size: 190362 bytes --]

[-- Attachment #2: malibu.c --]
[-- Type: text/plain, Size: 26796 bytes --]

/**
* This a driver written to interface with DSP boards from Innovative Integration
* It utilizes the RTDM device APIs from the Xenomai realtime Linux project.
*
*/

#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/spinlock.h>
#include <linux/pagemap.h>
#include <linux/semaphore.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <asm/msr.h>
#include <asm/page.h>

#include <rtdm/rtdm_driver.h>

#include "malibu.h"

#define VENDOR_ID		0x1303
#define	DRV_NAME		"malibu"
#define SIZE_MAX		1024
#define SOME_SUB_CLASS		1303


static void errMsg(int line, const char *place, const char *msg)
{
    printk(KERN_ALERT "malibu: Error at %s() line: %d, %s\n", place, line, msg);
}

#define	MY_ERR(s)	errMsg(__LINE__, __FUNCTION__, s)

static void logMsg(int line, const char *place, const char *msg)
{
    printk(KERN_INFO "MalibuDrv_RT: %s() line: %d, %s\n", place, line, msg);
}

#define	MY_PRINT(s)	logMsg(__LINE__, __FUNCTION__, s);

typedef struct {
    void*		kAddr;
    uint64_t	start;
    uint64_t	end;
    uint64_t	size;
} MyBar;

typedef struct {
    void*		kAddr;
    dma_addr_t	physAddr;
    uint32_t	size;
} MyBuf;

typedef struct {
    struct list_head	list;
    struct cdev		cdev;
    struct device	*sysdev;
    struct pci_dev	*pdev;
    dev_t		myDevT;

    MyBar		bars[MALIBU_BAR_MAX];
    MyBuf		bufs[MALIBU_BUF_MAX];

    wait_queue_head_t	intrWait;
    struct fasync_struct* async_queue;
    int			mySig;
    void*		intrStatusAddr;
    u32			intrMask;
    u8			intrWriteback;
    u32			iQueue[MALIBU_INTR_MAX];
    u32			iPtrLow;
    u32			iPtrHi;
    void		(*cntxtFunc)(void*);
    void		*cntxtArg;

    u16			devOpen;
    u8			wrOpen;
    u8			numBars;
    u8			isIrqEnabled;
    int                 dev_id;
    struct rtdm_device *xen_rtdm_device;
    rtdm_irq_t         irq_handle;  /* device IRQ handle */
} MyData;

static struct class*	devClass;
static dev_t 		baseDevT;

static int	devCnt = 0;
LIST_HEAD(devList);

static int fasync(int fd, struct file *filep, int mode);
//static irqreturn_t board_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);
static int malibu_intr_handler(rtdm_irq_t * irq_context);

static char msgbuf[1000];

static int malibu_rtdm_open(struct rtdm_dev_context *context,
                        rtdm_user_info_t * user_info, int oflags)
//static int open(struct inode *inodep, struct file *filep)
{
    MyData *md, *ctx;
    bool found=false;
    int err=0;

    MY_PRINT("start");
    ctx = (MyData *)context->dev_private;

    list_for_each_entry(md, &devList, list) {
         if (md->dev_id == context->device->device_id)
         {
                found = true;
                MY_PRINT("device FOUND");

                sprintf (msgbuf, "md=%p, md->device_id=%d", md, md->dev_id);
                MY_PRINT(msgbuf);

                memcpy(ctx, md, sizeof(MyData));

                break;
         }
    }

    if(!found)
    {
        MY_ERR("no matching device");
        return -ENODEV;
    }


    if (ctx->wrOpen && (oflags & FMODE_WRITE)) {
            MY_ERR("device already opened");
            return -EBUSY;
    }


    if (oflags & FMODE_WRITE)
    {
        ctx->iPtrLow = 0;
        ctx->iPtrHi = 0;
        ctx->mySig = SIGIO;
        ctx->cntxtFunc = 0;
        ctx->cntxtArg = 0;

        static unsigned long irqtype = (RTDM_IRQTYPE_SHARED | RTDM_IRQTYPE_EDGE);

        sprintf(msgbuf, "irqtype=%d", irqtype);
        MY_PRINT(msgbuf);

        err = rtdm_irq_request(&ctx->irq_handle, ctx->pdev->irq,
                               (rtdm_irq_handler_t)malibu_intr_handler,
                               irqtype,
                               context->device->proc_name,  (void *)ctx);

        if(err != 0)
        {
            sprintf(msgbuf, "rtdm_irq_request() failed, err=%d, irq=%d, proc_name=%s",
                    err, ctx->pdev->irq, context->device->proc_name);
            MY_ERR(msgbuf);
            return err;
        }

        sprintf(msgbuf, "rtdm_irq_request() OK, irq=%d", ctx->irq_handle);
        MY_PRINT(msgbuf);

#if 0
        if (request_irq(md->pdev->irq, (irq_handler_t)board_handler, IRQF_SHARED, DRV_NAME, (void*)md)) {
                MY_ERR("irq request error");
                return -ENODEV;
        }
#endif

        ctx->wrOpen = 1;
    }

    ctx->devOpen++;

    MY_PRINT("end OK");
    return 0;
}

/**
* Close the device
*
* This function is called when the device shall be closed.
*
*/
static int malibu_rtdm_close(struct rtdm_dev_context *context,
                            rtdm_user_info_t * user_info)
{   
    MyData *ctx = context->dev_private;
    rtdm_irq_free(&ctx->irq_handle);

    sprintf(msgbuf, "ctx=0x%p, irq=%d", ctx, ctx->irq_handle);
    MY_PRINT(msgbuf);
    MY_PRINT("closing device");
    return 0;
}

#if 1
static void freeBuffer(MyData* md, int n)
{
    MyBuf* b = &md->bufs[n];
    if (b->size == 0) return;
    dma_free_coherent(&md->pdev->dev, b->size, b->kAddr, b->physAddr);
    b->size = 0;
}

static int release(struct inode *inode, struct file *filep)
{
    int		i;
    MyData*		md = (MyData*) filep->private_data;

    md->devOpen--;

    if (filep->f_mode & FMODE_WRITE) {
            md->wrOpen = 0;
            free_irq(md->pdev->irq, md);
            for (i = 0; i < MALIBU_BUF_MAX; i++) freeBuffer(md, i);
            fasync(-1, filep, 0);
    }

    return 0;
}

//static int ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg)
int malibu_rtdm_ioctl(struct rtdm_dev_context   *context,
                      rtdm_user_info_t          *user_info,
                      int                       cmd,
                      void                      *arg)
{
    MyData* md = (MyData *)context->dev_private;
    int err = 0;
    int retval = 0;
    ioc_param_struct param = {0,0};

    if (_IOC_TYPE(cmd) != MALIBU_IOC_MAGIC) return -ENOTTY;

    /*
    * the direction is a bitmask, and VERIFY_WRITE catches R/W
    * transfers. `Type' is user-oriented, while
    * access_ok is kernel-oriented, so the concept of "read" and
    * "write" is reversed (i.e. when an user wants to read data,
    * the kernel has to write them into the user space)
    *
    * always check the user space address before accessing it
    *
    * access_ok returns 0 for failure!
    */
    if (_IOC_DIR(cmd) & _IOC_READ)
      err = !rtdm_read_user_ok(user_info, arg, sizeof(ioc_param_struct));
    else if (_IOC_DIR(cmd) & _IOC_WRITE)
      err = !rtdm_rw_user_ok(user_info, arg, sizeof(ioc_param_struct));
    if (err) return -EFAULT;

    switch(cmd) {
            case MALIBU_GET_INFO: {
                    MalibuDrv_INFO	x;
                    x.vendorId = md->pdev->vendor;
                    x.deviceId = md->pdev->device;
                    x.subVendorId = md->pdev->subsystem_vendor;
                    x.subDeviceId = md->pdev->subsystem_device;
                    x.revision = md->pdev->revision;
                    x.bus = md->pdev->bus->number;
                    x.slot = PCI_SLOT(md->pdev->devfn);
                    x.func = PCI_FUNC(md->pdev->devfn);
                    x.numBars = md->numBars;

                    MY_PRINT("copying data to user");

                    sprintf(msgbuf, "x.vendorId=0x%x, x.deviceId=0x%x, x.numBars=%d",
                            md->pdev->vendor, md->pdev->device, x.numBars);
                    MY_PRINT(msgbuf);
                    //return (0 == copy_to_user((void __user*)arg, &x, sizeof(x))) ? 0 : -EFAULT;
            }

            case MALIBU_GET_BAR_SIZE:
                    if (*(int *)arg < 0 || *(int *)arg >= MALIBU_BAR_MAX) return -EINVAL;
                    return md->bars[*(int *)arg].size;

            case MALIBU_ALLOC_BUFFER: {
                    int			n;
                    MalibuDrv_Buffer	x;
                    MyBuf*			b;

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return -EACCES;

                    for (n = 0; n < MALIBU_BUF_MAX; n++) {
                            if (md->bufs[n].size == 0) break;
                    }
                    if (n == MALIBU_BUF_MAX) {
                            MY_ERR("");
                            return -ENOMEM;
                    }
                    if (copy_from_user(&x, (const void __user*)arg, sizeof(x))) return -EFAULT;
                    b = &md->bufs[n];

                    b->size = ((x.size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
                    b->kAddr = dma_alloc_coherent(&md->pdev->dev, b->size, &b->physAddr, GFP_KERNEL);
                    if (b->kAddr == 0) {
                            b->size = 0;
                            MY_ERR("");
                            return -ENOMEM;
                    }
                    x.physAddr = b->physAddr;
                    x.bufNum = n;
                    x.fileOffset = (n + MALIBU_BAR_MAX) * MALIBU_MMAP_SIZE;
                    if (copy_to_user((void __user*)arg, &x, sizeof(x))) {
                            freeBuffer(md, x.bufNum);
                            return -EFAULT;
                    }
                    ((uint32_t*)b->kAddr)[0] = 0x12345678;
                    ((uint32_t*)b->kAddr)[1] = n;
                    ((uint32_t*)b->kAddr)[2] = md->myDevT;
                    return 0;
            }

            case MALIBU_FREE_BUFFER: {
                    int			i;
                    MalibuDrv_Buffer	x;

                    //TODO:if (!(filep->f_mode & FMODE_WRITE)) return -EACCES;

                    if (copy_from_user(&x, (const void __user*)arg, sizeof(x))) return -EFAULT;
                    for (i = 0; i < MALIBU_BUF_MAX; i++) {
                            if (md->bufs[i].physAddr == x.physAddr) {
                                    freeBuffer(md, i);
                                    break;
                            }
                    }
                    if (i == MALIBU_BUF_MAX) {
                            MY_ERR("");
                            return -ENOMEM;
                    }
                    return 0;
            }

            case MALIBU_ISR_ENABLE:
                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return -EACCES;
                    enable_irq(md->pdev->irq);
                    md->isIrqEnabled = 1;
                    return 0;
            case MALIBU_ISR_DISABLE:
                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return -EACCES;
                    md->isIrqEnabled = 0;
                    disable_irq(md->pdev->irq);
                    return 0;
            case MALIBU_GET_ISR_ENABLED:
                    return md->isIrqEnabled;
            case MALIBU_GET_ISR_DEPTH:
                    return (md->iPtrLow - md->iPtrHi);
            case MALIBU_ISR_CLEAR_ALL:
                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return -EACCES;
                    disable_irq(md->pdev->irq);
                    md->iPtrLow = 0;
                    md->iPtrHi = 0;
                    enable_irq(md->pdev->irq);
                    return 0;	// no implemented yet
            case MALIBU_DEQUEUE_ISR: {
                    MalibuDrv_DequeueISR	x;
                    unsigned long		j;
                    int			ret;

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return -EACCES;
                    if (copy_from_user(&x, (const void __user*)arg, (caddr_t)&x.depth - (caddr_t)&x)) return -EFAULT;

                    x.depth = 0;
                    x.cntxtFunc = md->cntxtFunc;
                    x.cntxtArg = md->cntxtArg;
                    x.errno = 0;
                    x.depth = 0;

                    j = timeval_to_jiffies(&x.timeout);
                    if (j == 0) {
                            if (md->iPtrLow != md->iPtrHi) {
                                    while (md->iPtrLow != md->iPtrHi && x.depth < MALIBU_INTR_MAX) {
                                            x.data[x.depth++] = md->iQueue[md->iPtrHi % MALIBU_INTR_MAX];
                                            md->iPtrHi++;
                                    }
                            }
                            else {
                                    x.errno = ENODATA;
                            }
                    }
                    else {
                            ret = wait_event_interruptible_timeout(md->intrWait, md->iPtrLow != md->iPtrHi, j);
                            if (ret == 0) x.errno = ETIME;
                            else if (ret == -ERESTARTSYS) x.errno = ERESTARTSYS;
                            else {
                                    while (md->iPtrLow != md->iPtrHi && x.depth < MALIBU_INTR_MAX) {
                                            x.data[x.depth++] = md->iQueue[md->iPtrHi % MALIBU_INTR_MAX];
                                            md->iPtrHi++;
                                    }
                                    jiffies_to_timeval(ret, &x.timeout);
                            }
                    }
                    if (copy_to_user((void __user*)arg, &x, (caddr_t)&x.data[x.depth] - (caddr_t)&x)) return -EFAULT;
                    return 0;
            }
            case MALIBU_SET_ISR_CTRL: {
                    MalibuDrv_IntCtrl	x;

                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return -EACCES;
                    if (copy_from_user(&x, (const void __user*)arg, sizeof(x))) return -EFAULT;
                    md->intrMask = x.mask;
                    md->intrWriteback = x.type;
                    if (x.bar > MALIBU_BAR_MAX) {
                            MY_ERR("");
                            return -EINVAL;
                    }
                    if (x.byteOffset > md->bars[x.bar].size) {
                            MY_ERR("");
                            return -EINVAL;
                    }
                    md->intrStatusAddr = md->bars[x.bar].kAddr + x.byteOffset;
                    md->cntxtFunc = x.cntxtFunc;
                    md->cntxtArg = x.cntxtArg;
                    return 0;
            }
            case MALIBU_SET_SIG:
                    //TODO: if (!(filep->f_mode & FMODE_WRITE)) return -EACCES;
                    md->mySig = arg;
                    return 0;
            case MALIBU_FAKE_SIG: {
                    MalibuDrv_FakeISR	x;

                    if (copy_from_user(&x, (const void __user*)arg, sizeof(x))) return -EFAULT;
                    if ((md->iPtrLow - md->iPtrHi) < MALIBU_INTR_MAX-x.depth-1) {
                            int	i;

                            for (i = 0; i < x.depth; i++) {
                                    md->iQueue[md->iPtrLow % MALIBU_INTR_MAX] = x.data[i];
                                    md->iPtrLow++;
                            }
                            wake_up_interruptible(&md->intrWait);
                            if (md->async_queue) kill_fasync(&md->async_queue, md->mySig, POLL_IN);
                    }
                    return 0;
            }
            default:
                    return -EINVAL;
    }
}

//static irqreturn_t board_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
static int malibu_intr_handler(rtdm_irq_t * irq_context)
{
#if 0
    uint32_t	rd;
    MyData*		md = (MyData*) dev_id;

    if(md->pdev->irq != irq) return IRQ_NONE;

    rd = ioread32(md->intrStatusAddr);

    if ((rd & md->intrMask) == 0) return IRQ_NONE;

    if ((md->iPtrLow - md->iPtrHi) < MALIBU_INTR_MAX-1) {
            md->iQueue[md->iPtrLow % MALIBU_INTR_MAX] = rd;
            md->iPtrLow++;
            wake_up_interruptible(&md->intrWait);
            if (md->async_queue && md->mySig) kill_fasync(&md->async_queue, md->mySig, POLL_IN);
    }
    if (md->intrWriteback) iowrite32(rd, md->intrStatusAddr);
#endif

    return IRQ_HANDLED;
}

static void vma_open(struct vm_area_struct* vma) { }
static void vma_close(struct vm_area_struct* vma) { }

static struct vm_operations_struct remap_vm_ops = {
    .open = vma_open,
    .close = vma_close,
};

static int mmap(struct file *filep, struct vm_area_struct *vma)
{
    MyData*		md = (MyData*) filep->private_data;
    unsigned long	off = vma->vm_pgoff << PAGE_SHIFT;
    unsigned long	vsize = vma->vm_end - vma->vm_start;
    unsigned long	seg = off / MALIBU_MMAP_SIZE;
    unsigned long	seg_off = off % MALIBU_MMAP_SIZE;
    unsigned long	psize, pfn;

    if (seg >= 0 && seg < MALIBU_BAR_MAX) {
            if (md->bars[seg].size == 0) return -EINVAL;
            pfn = (md->bars[seg].start + seg_off) >> PAGE_SHIFT;
            psize = md->bars[seg].size - seg_off;
    }
    else if (seg >= MALIBU_BAR_MAX && seg < MALIBU_BAR_MAX + MALIBU_BUF_MAX) {
            seg -= MALIBU_BAR_MAX;
            if (md->bufs[seg].size == 0) return -EINVAL;
            pfn = __pa(md->bufs[seg].kAddr + seg_off) >> PAGE_SHIFT;
            psize = md->bufs[seg].size - seg_off;
    }
    else return -EINVAL;

    if (vsize > psize) return -EINVAL;
    if (remap_pfn_range(vma, vma->vm_start, pfn, vsize, vma->vm_page_prot)) return -EAGAIN;

    vma->vm_ops = &remap_vm_ops;
    vma_open(vma);
    return 0;
}

static int fasync(int fd, struct file *filep, int mode)
{
    MyData*		md = (MyData*) filep->private_data;
    return fasync_helper(fd, filep, mode, &md->async_queue);
}

static struct file_operations myFileOps = {
    .owner   	= THIS_MODULE,
    .open    	= malibu_rtdm_open,
    .release 	= release,
    .ioctl	= malibu_rtdm_ioctl,
    .mmap	= mmap,
    .fasync	= fasync,
};



static ssize_t showDevInfo(struct device *dev, struct device_attribute* attr, char *buf)
{
    MyData* md = (MyData*)dev->driver_data;
    return snprintf(buf, PAGE_SIZE,
            "vendor=0x%x\n"
            "device=0x%x\n"
            "subsystem_vendor=0x%x\n"
            "subsystem_device=0x%x\n"
            "revision=0x%x\n"
            "bus=0x%x\n"
            "slot=0x%x\n"
            "func=0x%x\n"
            "numBars=%d\n",
            md->pdev->vendor,
            md->pdev->device,
            md->pdev->subsystem_vendor,
            md->pdev->subsystem_device,
            md->pdev->revision,
            md->pdev->bus->number,
            PCI_SLOT(md->pdev->devfn),
            PCI_FUNC(md->pdev->devfn),
            md->numBars);
}
static DEVICE_ATTR(devInfo, 0444, showDevInfo, NULL);


/**
* This structure describe the malibu RTDM device
*
*/
static struct rtdm_device malibu_rtdm_device = {
    .struct_version = RTDM_DEVICE_STRUCT_VER,

    .device_flags = RTDM_NAMED_DEVICE,
    .context_size = sizeof(MyData),
    .device_name = DRV_NAME,

    .open_rt =  malibu_rtdm_open,
    .open_nrt = malibu_rtdm_open,

    .ops = {
            .close_rt = malibu_rtdm_close,
            .close_nrt = malibu_rtdm_close,
            .ioctl_rt =  malibu_rtdm_ioctl,
            .ioctl_nrt = malibu_rtdm_ioctl,
            //.read_nrt = NULL,
            //.write_nrt = NULL,
    },


    .device_class = RTDM_CLASS_EXPERIMENTAL,
    .device_sub_class = SOME_SUB_CLASS,
    .profile_version = 1,
    .driver_name = DRV_NAME,
    .driver_version = RTDM_DRIVER_VER(0, 1, 0),
    .peripheral_name = "Malibu RT driver",
    .provider_name = "Innovative Integration",
    .proc_name = DRV_NAME,
};

static int allocEachDev(struct pci_dev *pdev, const struct pci_device_id *id)
{
    struct rtdm_device  *rtdm_dev;
    int    ret_val = 0;
    MyData *md, *lPtr;
    int	i, bCntr, error, b;

    MY_PRINT("start");

    if(id->vendor != VENDOR_ID) {
            MY_ERR("");
            return -ENODEV;
    }

    md = (MyData*) kzalloc(sizeof(MyData), GFP_KERNEL);

    md->pdev = pdev;

    sprintf(msgbuf, "pdev->irq=%d", pdev->irq);
    MY_PRINT(msgbuf);

    if (pci_enable_device(pdev)) {
            MY_ERR("");
            kfree(md);
            return -ENODEV;
    }

    pci_set_master(pdev);

    b = 0;
    for (i = 0; i < MALIBU_BAR_MAX; i++) {
            md->bars[b].start	= pci_resource_start(pdev, i);
            md->bars[b].end	= pci_resource_end(pdev, i);
            md->bars[b].size	= pci_resource_len(pdev, i);
            printk(KERN_ERR "bar=%d start=%llx end=%llx len=%llx\n", i,
                    md->bars[b].start,
                    md->bars[b].end,
                    md->bars[b].size);
            if (md->bars[b].size == 0) continue;
            md->bars[b].kAddr	= (void*) ioremap(md->bars[i].start, md->bars[i].end - md->bars[i].start);
            b++;
    }
    md->numBars = i;

    init_waitqueue_head(&md->intrWait);

    cdev_init(&md->cdev, &myFileOps);
    md->cdev.owner = THIS_MODULE;
    md->myDevT = MKDEV(MAJOR(baseDevT), MINOR(baseDevT)+devCnt);
    if (cdev_add(&md->cdev, md->myDevT, 1)) {
            MY_ERR("");
            pci_disable_device(md->pdev);
            kfree(md);
            return -ENODEV;
    }

    bCntr = 0;
    list_for_each_entry(lPtr, &devList, list) {
            if (lPtr->pdev->device == pdev->device) bCntr++;
    }

    md->sysdev = device_create(devClass, &md->pdev->dev, md->myDevT, NULL, "malibu%04x_%d", pdev->device, bCntr);
    if (IS_ERR(md->sysdev)) {
            MY_ERR("");
            cdev_del(&md->cdev);
            pci_disable_device(md->pdev);
            kfree(md);
            return -ENODEV;
    }
    md->sysdev->driver_data = (void*)md;

    error = device_create_file(md->sysdev, &dev_attr_devInfo);
    if (error) {
            MY_ERR("");
            device_destroy(devClass, md->myDevT);
            cdev_del(&md->cdev);
            for (i = 0; i < MALIBU_BAR_MAX; i++) {
                    if (md->bars[i].size) {
                            iounmap(md->bars[i].kAddr);
                            md->bars[i].size = 0;
                    }
            }
            pci_disable_device(md->pdev);
            kfree(md);
            return error;
    }

    md->dev_id = devCnt;


    //alloc mem for rtdm structure
    rtdm_dev = kmalloc(sizeof(struct rtdm_device), GFP_KERNEL);
    if(!rtdm_dev){
      MY_ERR("rtdm_device kmalloc failed\n");
      ret_val = -ENOMEM; //Insufficient storage space is available.
      return ret_val;
    }

    //copy the structure to the new memory
    memcpy(rtdm_dev, &malibu_rtdm_device, sizeof(struct rtdm_device));

    //create filename
    snprintf(rtdm_dev->device_name,
             RTDM_MAX_DEVNAME_LEN, "malibu_%d", devCnt);

    rtdm_dev->device_id = devCnt;

    //define two other members of the rtdm_device structure
    rtdm_dev->proc_name = rtdm_dev->device_name;

    ret_val = rtdm_dev_register(rtdm_dev);

    if(ret_val < 0){
      MY_ERR("failed to register device with RTDM\n");
      ret_val = -ENODEV;
      return ret_val;
    }

    md->xen_rtdm_device = rtdm_dev;

    list_add_tail(&md->list, &devList);

    //always do this last
    devCnt++;

    MY_PRINT("end OK");
    return 0;
}

static void removeAllDev(struct pci_dev *pdev)
{
    MyData *md, *tmp;

    MY_PRINT("start");

    list_for_each_entry_safe(md, tmp, &devList, list)
    {
        if (md == NULL)
        {
            MY_PRINT("md is NULL");
            return;
        }

        int	i;

        list_del(&md->list);


        device_remove_file(md->sysdev, &dev_attr_devInfo);
        device_destroy(devClass, md->myDevT);
        cdev_del(&md->cdev);

        for (i = 0; i < MALIBU_BUF_MAX; i++) freeBuffer(md, i);

        for (i = 0; i < MALIBU_BAR_MAX; i++) {
            if (md->bars[i].size) {
                iounmap(md->bars[i].kAddr);
                md->bars[i].size = 0;
            }
        }

        pci_disable_device(md->pdev);

        //remove char device from the system
        //unregister RTdriver
        rtdm_dev_unregister(md->xen_rtdm_device, 1000);

        kfree(md->xen_rtdm_device);
        kfree(md);

        devCnt--;
}

    MY_PRINT("end");
}
#endif

static struct pci_device_id ids[] = {
    { PCI_DEVICE(VENDOR_ID, PCI_ANY_ID) },
    { 0 },
};

static struct pci_driver pci_driver = {
    .name	= DRV_NAME,
    .id_table	= ids,
    .probe	= allocEachDev,
    .remove	= removeAllDev,
};


//MODULE_DEVICE_TABLE(pci, ids);

static ssize_t showDevCount(struct class *cls, char *buf)
{
    return sprintf(buf, "%d\n", devCnt);
}

static CLASS_ATTR(devCount, 0444, showDevCount, NULL);

/**
* This function is called when the module is loaded
*
* It simply registers the RTDM device.
*
*/
static int __init mod_init(void)
{
    int 	error;

    MY_PRINT("initializing MalibuDrv_RT module");

    devClass = class_create(THIS_MODULE, DRV_NAME);
    if (IS_ERR(devClass)) {
            MY_ERR("");
            return PTR_ERR(devClass);
    }

    error = class_create_file(devClass, &class_attr_devCount);
    if (error) {
            MY_ERR("");
            class_destroy(devClass);
            return error;
    }

    error = alloc_chrdev_region(&baseDevT, 0, MALIBU_MAX_DEVS, DRV_NAME);
    if (error) {
            MY_ERR("");
            class_remove_file(devClass, &class_attr_devCount);
            class_destroy(devClass);
            return error;
    }

    error = pci_register_driver(&pci_driver);
    if (error) {
        MY_ERR("");
        unregister_chrdev_region(baseDevT, MALIBU_MAX_DEVS);
        class_remove_file(devClass, &class_attr_devCount);
        class_destroy(devClass);
        return error;
    }

    return error;
}

/**
* This function is called when the module is unloaded
*
* It unregister the RTDM device, polling at 1000 ms for pending users.
*
*/
static void __exit mod_exit(void)
{
    MY_PRINT("unregistering MalibuDrv_RT module");

    pci_unregister_driver(&pci_driver);
    unregister_chrdev_region(baseDevT, MALIBU_MAX_DEVS);
    class_remove_file(devClass, &class_attr_devCount);
    class_destroy(devClass);
}


module_init(mod_init);
module_exit(mod_exit);
MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Xenomai-help] rtdm_irq_request() returns error
  2011-01-14 22:50 [Xenomai-help] rtdm_irq_request() returns error Peter Hua
@ 2011-01-14 22:55 ` Gilles Chanteperdrix
  0 siblings, 0 replies; 2+ messages in thread
From: Gilles Chanteperdrix @ 2011-01-14 22:55 UTC (permalink / raw)
  To: Peter Hua; +Cc: xenomai, pwfhua

Peter Hua wrote:
> Hello,
> 
>  
> 
> My call to rtdm_irq_request() is returnning error -16.  I have verified
> all inputs.  I am running Xenomai 2.4.10 on Red Hat 5.5 (kernel
> 2.6.29.1).  Here is the snippit; the complete file is also attached. 
> Please help.

See rtdm_irq_request documentation on Xenomai website. The error code is
documented.

-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2011-01-14 22:55 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-14 22:50 [Xenomai-help] rtdm_irq_request() returns error Peter Hua
2011-01-14 22:55 ` Gilles Chanteperdrix

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.