* [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.