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

Reply via email to