Hello,
I have a problem with driver for Hilscher cifx with IRQ.
All driver run good (I verified in polling mode) but in case I activate
IRQ the system freeze.
I checked parameters of "rtdm_irq_request" function without success (all
seems good) ! I tried to see on internet to get some information about
the use of "rtdm_irq_request", or compare my code with other driver but
it's not easy...
I give you in attached file my code because I have no idea about my
problem, and it's really difficult to have some information or trace
after system freeze...
Do you have an idea about my problem ?
Thank you very much for you help,
--
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE Jérôme Poncin
[email protected]
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44
-------------- next part --------------
/***************************************************************************
* Copyright (C) 2013
*
* Hilscher France (JP) *
* http://www.hilscher.fr/
*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/***************************************************************************/
/* Includes */
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <sys/mman.h>
#include <rtdm/rtdm_driver.h>
/***************************************************************************/
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTDM board driver for CifX cards");
MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
/***************************************************************************/
/*!
* \addtogroup cifx_pci_Core
* @{
*/
/***************************************************************************/
/* #define */
#ifndef TRUE
#define TRUE 1
#endif /* TRUE */
#ifndef FALSE
#define FALSE 0
#endif /* TRUE */
#ifndef PCI_VENDOR_ID_HILSCHER
#define PCI_VENDOR_ID_HILSCHER 0x15CF
#endif
#ifndef PCI_DEVICE_ID_HILSCHER_NETX
#define PCI_DEVICE_ID_HILSCHER_NETX 0x0000
#endif
#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
#define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010
#endif
#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
#define PCI_DEVICE_ID_HILSCHER_NETJACK 0x0020
#endif
#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
#define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235
#endif
#ifndef PCI_SUBDEVICE_ID_NXPCA
#define PCI_SUBDEVICE_ID_NXPCA 0x3335
#endif
#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
#define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000
#endif
#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
#define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001
#endif
#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
#define PCI_SUBDEVICE_ID_NETJACK_RAM 0x0000
#endif
#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
#define PCI_SUBDEVICE_ID_NETJACK_FLASH 0x0001
#endif
#define DPM_HOST_INT_EN0 0xfff0
#define DPM_HOST_INT_STAT0 0xffe0
#define PLX_GPIO_OFFSET 0x15
#define PLX_TIMING_OFFSET 0x0a
#define DPM_HOST_INT_MASK
0xe600ffff
#define DPM_HOST_INT_GLOBAL_EN 0x80000000
#define PLX_GPIO_DATA0_MASK 0x00000004
#define PLX_GPIO_DATA1_MASK 0x00000020
#define NX_PCA_PCI_8_BIT_DPM_MODE 0x5431F962
#define NX_PCA_PCI_16_BIT_DPM_MODE 0x4073F8E2
#define NX_PCA_PCI_32_BIT_DPM_MODE 0x40824122
/* number of bar */
#define DPM_BAR 0
/* points to the DPM -> netX, netPLC, netJACK */
#define EXT_MEM_BAR 1
/* points to the optional extended memory */
#define PLX_DPM_BAR 2 /* points to the DPM -> netXPLX */
#define PXA_PLX_BAR 0 /* timing config register */
/* index of io_info structure's memory array */
#define DPM_INDEX 0
/* first mapping describes DPM */
#define EXT_MEM_INDEX 1
/* second mapping describes extended memory */
#define MAX_MAPS 2
/* defines for memtype */
#define MEM_PHYS 1
#define DRIVER_NAME
"rtdm_cifx"
#define PERIPHERAL_NAME "cifx"
#define PROVIDER_NAME
"Hilscher"
#define CIFX_RTDM_PLX_CARD_NAME "netx_plx" /* name of
a NXSB-PCA or NXPCA-PCI card */
#define CIFX_RTDM_CARD_NAME "netx" /* name of
a cifX PCI card */
#define CIFX_RTDM_NETPLC_CARD_NAME "netplc" /* name of
a netPLC PCI card */
#define CIFX_RTDM_NETJACK_CARD_NAME "netjack" /* name of
a netJACK PCI card */
typedef struct {
uint32_t __iomem *plx;
uint8_t dpm_mode;
uint32_t plx_timing;
} pxa_dev_info;
typedef struct {
uint32_t addr;
uint32_t size;
int32_t memtype;
void __iomem *internal_addr;
} io_mem;
typedef struct {
io_mem mem[MAX_MAPS];
int32_t irq;
uint8_t irq_enable;
uint8_t irq_registered;
rtdm_irq_t irq_handle;
void *priv;
} io_info_t;
typedef struct {
uint32_t phys_addr;
void ** virt_addr;
uint32_t length;
} io_map_mem;
/***************************************************************************/
/* Prototypes */
static int cifx_handler(rtdm_irq_t *irq);
static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
static int cifx_pci_open(struct rtdm_dev_context *context,
rtdm_user_info_t * user_info, int oflags);
static int cifx_pci_close(struct rtdm_dev_context *context,
rtdm_user_info_t * user_info);
static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info, void *buf, size_t nbyte);
static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
rtdm_user_info_t * user_info, const void *buf, size_t nbyte);
static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id
*id);
static void cifx_pci_remove(struct pci_dev *dev);
/***************************************************************************/
/* Local variables */
static int32_t cifx_num = 0;
static const struct rtdm_device __initdata cifx_device_tmpl = {
.struct_version = RTDM_DEVICE_STRUCT_VER,
.device_flags = RTDM_NAMED_DEVICE,
.context_size = 0,
.device_name = "",
.open_nrt = cifx_pci_open,
.ops = {
.close_nrt = cifx_pci_close,
.read_nrt = cifx_pci_read,
.write_nrt = cifx_pci_write,
.ioctl_rt = NULL,
.ioctl_nrt = NULL,
.read_rt = NULL,
.write_rt = NULL,
},
.device_class = RTDM_CLASS_EXPERIMENTAL,
.device_sub_class = RTDM_SUBCLASS_GENERIC,
.profile_version = 1,
.driver_name = DRIVER_NAME,
.driver_version = RTDM_DRIVER_VER(1, 0, 0),
.provider_name = PROVIDER_NAME,
};
static struct pci_device_id cifx_pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_HILSCHER,
.device = PCI_DEVICE_ID_HILSCHER_NETX,
.subvendor = 0,
.subdevice = 0,
},
{
.vendor = PCI_VENDOR_ID_PLX,
.device = PCI_DEVICE_ID_PLX_9030,
.subvendor = PCI_VENDOR_ID_PLX,
.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
},
{
.vendor = PCI_VENDOR_ID_PLX,
.device = PCI_DEVICE_ID_PLX_9030,
.subvendor = PCI_VENDOR_ID_PLX,
.subdevice = PCI_SUBDEVICE_ID_NXPCA,
},
{
.vendor = PCI_VENDOR_ID_HILSCHER,
.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
.subvendor = PCI_VENDOR_ID_HILSCHER,
.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
},
{
.vendor = PCI_VENDOR_ID_HILSCHER,
.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
.subvendor = PCI_VENDOR_ID_HILSCHER,
.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
},
{
.vendor = PCI_VENDOR_ID_HILSCHER,
.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
.subvendor = PCI_VENDOR_ID_HILSCHER,
.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
},
{
.vendor = PCI_VENDOR_ID_HILSCHER,
.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
.subvendor = PCI_VENDOR_ID_HILSCHER,
.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
},
{ 0, }
};
/* This structure describe the RTDM cifX Driver */
static struct pci_driver cifx_pci_driver = {
.name = "cifx",
.id_table = cifx_pci_tbl,
.probe = cifx_pci_probe,
.remove = cifx_pci_remove,
};
/***************************************************************************/
/*****************************************************************************/
/*!
* \brief cifx_handler
*
* \param [in] irq Resource task pointer
*
* \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
*
* \note cifx interrupt handler
*/
/*****************************************************************************/
static inline int cifx_handler(rtdm_irq_t *irq)
{
struct rtdm_device *info = (struct rtdm_device
*)rtdm_irq_get_arg(irq, void);
io_info_t *device_data = (io_info_t *)
info->device_data;
if (device_data->priv != NULL)
{
/* This is a PLX device and cannot produce an IRQ */
return RTDM_IRQ_NONE;
}
else
{
void __iomem *int_enable_reg =
device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
void __iomem *int_status_reg =
device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;
/* Is one of our interrupts enabled and active ? */
if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) &
DPM_HOST_INT_MASK))
return IRQ_NONE;
/* Disable interrupt */
iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN,
int_enable_reg);
return RTDM_IRQ_HANDLED;
}
}
/*****************************************************************************/
/*!
* \brief cifx_pxa_set_plx_timing
*
* \param [in] info cifx rtdm device information
*
* \return 0 (OK) or Error
*
* \note Set plx timing
*/
/*****************************************************************************/
static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
{
pxa_dev_info *pxa_info = (pxa_dev_info *) ((io_info_t
*)info->device_data)->priv;
uint32_t __iomem *plx_timing;
if (!pxa_info)
return -ENODEV;
plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
*plx_timing = pxa_info->plx_timing;
return 0;
}
/*****************************************************************************/
/*!
* \brief cifx_pxa_get_plx_timing
*
* \param [in] info cifx rtdm device information
*
* \return 0 (OK) or Error
*
* \note Get plx timing
*/
/*****************************************************************************/
static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
{
pxa_dev_info *pxa_info = (pxa_dev_info *) ((io_info_t
*)info->device_data)->priv;
if (!pxa_info)
return -ENODEV;
switch (pxa_info->dpm_mode)
{
case 8:
pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
break;
case 16:
pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
break;
case 32:
pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
break;
default:
return -EINVAL;
}
return 0;
}
/*****************************************************************************/
/*!
* \brief cifx_pxa_get_dpm_mode
*
* \param [in] info cifx rtdm device information
*
* \return 0 (OK) or Error
*
* \note Get dpm mode
*/
/*****************************************************************************/
static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
{
pxa_dev_info *pxa_info = (pxa_dev_info *) ((io_info_t
*)info->device_data)->priv;
uint32_t __iomem *plx_gpio;
if (!pxa_info)
return -ENODEV;
plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
if ((*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio &
PLX_GPIO_DATA1_MASK))
pxa_info->dpm_mode = 8;
else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && (*plx_gpio &
PLX_GPIO_DATA1_MASK))
pxa_info->dpm_mode = 32;
else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio &
PLX_GPIO_DATA1_MASK))
pxa_info->dpm_mode = 16;
else
return -EINVAL;
return 0;
}
/*****************************************************************************/
/*!
* \brief cifx_pci_open
*
* \param [in] context context
* \param [in] user_info user information
* \param [in] oflags flags
*
* \return 0 (OK) or Error
*
* \note Open
*/
/*****************************************************************************/
static int cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t *
user_info, int oflags)
{
struct rtdm_device *info = (struct rtdm_device
*)context->device;
int32_t ret;
if (oflags == TRUE)
{
if (((io_info_t *)info->device_data)->irq_registered == FALSE)
{
if ((ret = rtdm_irq_request(&(((io_info_t
*)info->device_data)->irq_handle), ((io_info_t *)info->device_data)->irq,
cifx_handler, RTDM_IRQTYPE_SHARED, info->device_name, (void *)info)) != 0)
{
#ifdef DEBUG
switch (ret)
{
case -EINVAL :
rtdm_printk("cifx rtdm driver error
: rtdm_irq_request error : an invalid parameter was passed\n");
break;
case -EBUSY :
rtdm_printk("cifx rtdm driver error
: rtdm_irq_request error : the specified IRQ line is already in use\n");
break;
default :
rtdm_printk("cifx rtdm driver error
: rtdm_irq_request error\n");
break;
}
#endif /* DEBUG */
return -ENODEV;
}
else
{
((io_info_t
*)info->device_data)->irq_registered = TRUE;
}
}
}
return 0;
}
/*****************************************************************************/
/*!
* \brief cifx_pci_close
*
* \param [in] context context
* \param [in] user_info user information
*
* \return 0 (OK) or Error
*
* \note Close
*/
/*****************************************************************************/
static int cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t *
user_info)
{
struct rtdm_device *info = (struct rtdm_device
*)context->device;
if (((io_info_t *)info->device_data)->irq_registered == TRUE)
{
if (((io_info_t *)info->device_data)->irq_enable == TRUE)
{
if (rtdm_irq_disable(&(((io_info_t
*)info->device_data)->irq_handle)) != 0)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error :
rtdm_irq_disable error\n");
#endif /* DEBUG */
return -ENODEV;
}
}
}
return 0;
}
/*****************************************************************************/
/*!
* \brief cifx_pci_read
*
* \param [in] context context
* \param [in] user_info user information
* \param [in] buf user buffer
* \param [in] nbyte number of byte to read
*
* \return size read
*
* \note Read
*/
/*****************************************************************************/
static ssize_t cifx_pci_read(struct rtdm_dev_context *context, rtdm_user_info_t
*user_info, void *buf, size_t nbyte)
{
struct rtdm_device *info = (struct rtdm_device
*)context->device;
if (nbyte > sizeof(io_info_t))
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : data user size too
big\n");
#endif /* DEBUG */
return 0;
}
if (rtdm_safe_copy_to_user(user_info, buf, ((io_info_t
*)info->device_data), nbyte))
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : can't copy data from
driver\n");
#endif /* DEBUG */
}
return nbyte;
}
/*****************************************************************************/
/*!
* \brief cifx_pci_write
*
* \param [in] context context
* \param [in] user_info user information
* \param [in] buf user buffer
* \param [in] nbyte number of byte to read
*
* \return size read
*
* \note Read
*/
/*****************************************************************************/
static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
rtdm_user_info_t * user_info, const void *buf, size_t nbyte)
{
struct rtdm_device *info = (struct rtdm_device *)context->device;
uint8_t irq_enable;
io_map_mem map_mem;
int ret;
if (nbyte > sizeof(io_map_mem))
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : data user size too
big\n");
#endif /* DEBUG */
return 0;
}
if (nbyte == sizeof(uint8_t))
{
if (rtdm_safe_copy_from_user(user_info, &irq_enable, buf,
nbyte))
{
nbyte = 0;
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : can't copy data from
driver\n");
#endif /* DEBUG */
}
else
{
if ((((io_info_t *)info->device_data)->irq_enable) !=
irq_enable)
{
if (((io_info_t
*)info->device_data)->irq_registered == TRUE)
{
if (irq_enable == TRUE)
{
if (rtdm_irq_enable(&(((io_info_t
*)info->device_data)->irq_handle)) != 0)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm
driver error : rtdm_irq_enable error\n");
#endif /* DEBUG */
return -ENODEV;
}
}
else
{
if (rtdm_irq_disable(&(((io_info_t
*)info->device_data)->irq_handle)) != 0)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm
driver error : rtdm_irq_disable error\n");
#endif /* DEBUG */
return -ENODEV;
}
}
((io_info_t
*)info->device_data)->irq_enable = irq_enable;
}
else
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : try to
enable or diable IRQ but not registered\n");
#endif /* DEBUG */
}
}
}
}
else if (nbyte == sizeof(io_map_mem))
{
if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte))
{
nbyte = 0;
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : can't copy data from
driver\n");
#endif /* DEBUG */
}
else
{
if (*map_mem.virt_addr == NULL)
{
ret = rtdm_iomap_to_user(user_info,
(phys_addr_t)map_mem.phys_addr, (size_t)map_mem.length, (PROT_READ |
PROT_WRITE), map_mem.virt_addr, NULL, NULL);
if (ret != 0)
{
nbyte = 0;
#ifdef DEBUG
switch (ret)
{
case -EINVAL :
rtdm_printk("cifx
rtdm driver error : an invalid start address, size, or destination address was
passed\n");
break;
case -ENOMEM :
rtdm_printk("cifx
rtdm driver error : there is insufficient free memory or the limit of memory mapping for
the user process was reached\n");
break;
case -EAGAIN:
rtdm_printk("cifx
rtdm driver error : too much memory has been already locked by the user process\n");
break;
case -EPERM :
rtdm_printk("cifx
rtdm driver error : an illegal invocation environment is detected\n");
break;
default :
rtdm_printk("cifx
rtdm driver error : rtdm_safe_copy_from_user error\n");
break;
}
#endif /* DEBUG */
}
}
else
{
ret = rtdm_munmap(user_info,
*map_mem.virt_addr, (size_t)map_mem.length);
if (ret != 0)
{
nbyte = 0;
#ifdef DEBUG
switch (ret)
{
case -EINVAL :
rtdm_printk("cifx rtdm
driver error : an invalid address or size was passed\n");
break;
case -EPERM :
rtdm_printk("cifx rtdm
driver error : an illegal invocation environment is detected\n");
break;
default :
rtdm_printk("cifx rtdm
driver error : rtdm_safe_copy_from_user error\n");
break;
}
#endif /* DEBUG */
}
}
}
}
else
{
nbyte = 0;
}
return nbyte;
}
/*****************************************************************************/
/*!
* \brief cifx_pci_probe
*
* \param [in] dev
* \param [in] id
*
* \return 0 (OK) or Error
*
* \note Open the device.
* This function is called when the device shall be opened.
*/
/*****************************************************************************/
static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct rtdm_device *info = NULL;
io_info_t *device_data = NULL;
int32_t bar;
int32_t ret;
info = rtdm_malloc(sizeof(struct rtdm_device));
if (info == NULL)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */
return -ENOMEM;
}
if ((ret = pci_enable_device(dev)) != 0)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : pci_enable_device error :
%i\n", ret);
#endif /* DEBUG */
goto out_free;
}
if ((ret = pci_request_regions(dev, DRIVER_NAME)) != 0)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : pci_request_regions error :
%i\n", ret);
#endif /* DEBUG */
goto out_disable;
}
memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
info->device_id = id->device;
snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
cifx_num);
info->proc_name = info->device_name;
switch (id->device)
{
case PCI_DEVICE_ID_HILSCHER_NETX:
bar = DPM_BAR;
info->peripheral_name = CIFX_RTDM_CARD_NAME;
break;
case PCI_DEVICE_ID_HILSCHER_NETPLC:
bar = DPM_BAR;
info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
break;
case PCI_DEVICE_ID_HILSCHER_NETJACK:
bar = DPM_BAR;
info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
break;
default:
bar = PLX_DPM_BAR;
info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
break;
}
info->device_data = NULL;
device_data = rtdm_malloc(sizeof(io_info_t));
if (device_data == NULL)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */
goto out_release;
}
memset(device_data, 0, sizeof(io_info_t));
/* BAR 0 or 2 points to the card's dual port memory */
device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
if (device_data->mem[DPM_INDEX].addr == 0)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : pci_resource_start
error\n");
#endif /* DEBUG */
goto out_release;
}
device_data->mem[DPM_INDEX].internal_addr =
ioremap_nocache(pci_resource_start(dev, bar), pci_resource_len(dev, bar));
if (device_data->mem[DPM_INDEX].internal_addr == 0)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG */
goto out_release;
}
dev_info(&dev->dev, "DPM at %08lX\n", (long unsigned
int)device_data->mem[DPM_INDEX].addr);
device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
/* map extended mem (BAR 1 points to the extended memory) */
device_data->mem[EXT_MEM_INDEX].addr = pci_resource_start(dev,
EXT_MEM_BAR);
/* extended memory is optional, so don't care if it is not present */
if (device_data->mem[EXT_MEM_INDEX].addr != 0)
{
device_data->mem[EXT_MEM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR), pci_resource_len(dev, EXT_MEM_BAR));
if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : ioremap_nocache
error\n");
#endif /* DEBUG */
goto out_unmap;
}
dev_info(&dev->dev, "extended memory at %08lX\n", (long unsigned
int)device_data->mem[EXT_MEM_INDEX].addr);
device_data->mem[EXT_MEM_INDEX].size = pci_resource_len(dev,
EXT_MEM_BAR);
device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
}
if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
|| (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
|| (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK))
{
/* make sure all interrupts are disabled */
iowrite32(0, device_data->mem[DPM_INDEX].internal_addr +
DPM_HOST_INT_EN0);
device_data->priv = NULL;
}
else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA)
{
/* map PLX registers */
pxa_dev_info *pxa_info = (pxa_dev_info
*)rtdm_malloc(sizeof(pxa_dev_info));
if (pxa_info == NULL)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : rtdm_malloc
error\n");
#endif /* DEBUG */
goto out_unmap;
}
device_data->priv = pxa_info;
/* set PXA PLX Timings */
pxa_info->plx = ioremap_nocache(pci_resource_start(dev,
PXA_PLX_BAR), pci_resource_len(dev, PXA_PLX_BAR));
if (!pxa_info->plx)
goto out_unmap;
if (cifx_pxa_get_dpm_mode(info))
goto out_unmap_plx;
if (cifx_pxa_get_plx_timing(info))
goto out_unmap_plx;
if (cifx_pxa_set_plx_timing(info))
goto out_unmap_plx;
}
else
{
pxa_dev_info *pxa_info = (pxa_dev_info
*)rtdm_malloc(sizeof(pxa_dev_info));
if (pxa_info == NULL)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : rtdm_malloc
error\n");
#endif /* DEBUG */
goto out_free_pxa;
}
pxa_info->plx = NULL;
pxa_info->plx_timing = 0;
pxa_info->dpm_mode = 0;
device_data->priv = pxa_info;
}
device_data->irq = dev->irq;
device_data->irq_enable = FALSE;
device_data->irq_registered = FALSE;
info->device_data = device_data;
if ((ret = rtdm_dev_register(info)) != 0)
{
#ifdef DEBUG
switch(ret)
{
case -EINVAL :
rtdm_printk("cifx rtdm driver error :
rtdm_dev_register error : the device structure contains invalid entries. Check kernel log
in this case\n");
break;
case -ENOMEM :
rtdm_printk("cifx rtdm driver error :
rtdm_dev_register error : the context for an exclusive device cannot be
allocated\n");
break;
case -EEXIST :
rtdm_printk("cifx rtdm driver error :
rtdm_dev_register error : the specified device name of protocol ID is already in
use\n");
break;
case -EAGAIN :
rtdm_printk("cifx rtdm driver error :
rtdm_dev_register error : some /proc entry cannot be created\n");
break;
default :
rtdm_printk("cifx rtdm driver error :
rtdm_dev_register error\n");
break;
}
#endif /* DEBUG */
if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
goto out_unmap;
else
goto out_unmap_plx;
}
pci_set_drvdata(dev, info);
if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
dev_info(&dev->dev, "registered CifX card\n");
else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
dev_info(&dev->dev, "registered netPLC card\n");
else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
dev_info(&dev->dev, "registered netJACK card\n");
else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
else
{
pxa_dev_info *pxa_info = (pxa_dev_info *)((io_info_t
*)info->device_data)->priv;
dev_info(&dev->dev, "registered NXPCA-PCI adapter card in %d bit
mode\n", pxa_info->dpm_mode);
}
cifx_num++;
return 0;
out_unmap_plx:
iounmap(((pxa_dev_info *)(((io_info_t
*)info->device_data)->priv))->plx);
out_free_pxa:
rtdm_free(((io_info_t *)info->device_data)->priv);
out_unmap:
iounmap(((io_info_t *)info->device_data)->mem[DPM_INDEX].internal_addr);
if (((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr
!= 0)
iounmap(((io_info_t
*)info->device_data)->mem[EXT_MEM_INDEX].internal_addr);
out_release:
pci_release_regions(dev);
out_disable:
pci_disable_device(dev);
out_free:
if (info->device_data != NULL)
{
rtdm_free(info->device_data);
}
rtdm_free(info);
return -ENODEV;
}
/*****************************************************************************/
/*!
* \brief cifx_pci_remove
*
* \param [in] dev
*
* \return None
*
* \note Close the device.
* This function is called when the device shall be closed.
*/
/*****************************************************************************/
static void cifx_pci_remove(struct pci_dev *dev)
{
struct rtdm_device *info = pci_get_drvdata(dev);
io_info_t *device_data = (io_info_t
*)info->device_data;
pxa_dev_info *pxa_info = (pxa_dev_info
*)device_data->priv;
int32_t ret;
if (info->device_data == NULL)
{
#ifdef DEBUG
rtdm_printk("cifx rtdm driver error : device_data NULL
pointer\n");
#endif /* DEBUG */
return;
}
if (pxa_info != NULL)
{
/* Disable all interrupts */
iowrite32(0, device_data->mem[DPM_INDEX].internal_addr +
DPM_HOST_INT_EN0);
if (pxa_info->plx != NULL)
iounmap((void *)pxa_info->plx);
rtdm_free((void *)pxa_info);
}
if ((ret = rtdm_dev_unregister(info, 1000)) != 0)
{
#ifdef DEBUG
switch(ret)
{
case -ENODEV :
rtdm_printk("cifx rtdm driver error :
rtdm_dev_unregister error : the device was not registered\n");
break;
case -EAGAIN :
rtdm_printk("cifx rtdm driver error :
rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed
for poll_delay\n");
break;
default :
rtdm_printk("cifx rtdm driver error :
rtdm_dev_unregister error\n");
break;
}
#endif /* DEBUG */
return;
}
pci_release_regions(dev);
pci_disable_device(dev);
pci_set_drvdata(dev, NULL);
iounmap(device_data->mem[DPM_INDEX].internal_addr);
if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
rtdm_free(info->device_data);
rtdm_free(info);
if (cifx_num > 0)
cifx_num--;
}
/*****************************************************************************/
/*!
* \brief cifx_pci_init
*
* \return None
*
* \note It simply registers the RTDM device.
* This function is called when the module is loaded.
*/
/*****************************************************************************/
static int __init cifx_pci_init(void)
{
return pci_register_driver(&cifx_pci_driver);
}
/*****************************************************************************/
/*!
* \brief cifx_pci_exit
*
* \return None
*
* \note It unregister the RTDM device.
* This function is called when the module is unloaded.
*/
/*****************************************************************************/
static void __exit cifx_pci_exit(void)
{
pci_unregister_driver(&cifx_pci_driver);
}
/*****************************************************************************/
/*! \} cifx_pci_Core
*/
/*****************************************************************************/
module_init(cifx_pci_init);
module_exit(cifx_pci_exit);
/* End of file : cifx_pci.c */
_______________________________________________
Xenomai mailing list
[email protected]
http://www.xenomai.org/mailman/listinfo/xenomai