From mboxrd@z Thu Jan 1 00:00:00 1970 Message-ID: <512C806F.2020209@hilscher.com> Date: Tue, 26 Feb 2013 10:29:19 +0100 From: Jerome Poncin MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="iso-8859-1"; Format="flowed" Subject: [Xenomai] Hilscher driver for cifX boards List-Id: Discussions about the Xenomai project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: xenomai@xenomai.org 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=E8me R=E9giment d'Aviation Miniparc du Ch=EAne 69500 BRON France T=E9l. : +33 (0) 4 72 37 98 40 Fax : +33 (0) 4 78 26 83 27 http://www.hilscher.fr HILSCHER FRANCE J=E9r=F4me Poncin jponcin@hilscher.com Ing=E9nieur D=E9veloppement Logiciel T=E9l. : +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 #include #include #include #include #include /**************************************************************************= */ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RTDM board driver for CifX cards"); MODULE_AUTHOR("Hilscher France (JP) "); /**************************************************************************= */ /*! * \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, netJAC= K */ #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 memor= y */ #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 ca= rd */ #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_i= nfo_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 =3D 0; static const struct rtdm_device __initdata cifx_device_tmpl =3D { .struct_version =3D RTDM_DEVICE_STRUCT_VER, = .device_flags =3D RTDM_NAMED_DEVICE, .context_size =3D 0, .device_name =3D "", .open_nrt =3D cifx_pci_open, .ops =3D { .close_nrt =3D cifx_pci_close, .read_nrt =3D cifx_pci_read, .write_nrt =3D cifx_pci_write, = .ioctl_rt =3D NULL, .ioctl_nrt =3D NULL, .read_rt =3D NULL, .write_rt =3D NULL, }, .device_class =3D RTDM_CLASS_EXPERIMENTAL, .device_sub_class =3D RTDM_SUBCLASS_GENERIC, .profile_version =3D 1, .driver_name =3D DRIVER_NAME, .driver_version =3D RTDM_DRIVER_VER(1, 0, 0), .provider_name =3D PROVIDER_NAME, }; static struct pci_device_id cifx_pci_tbl[] =3D { { .vendor =3D PCI_VENDOR_ID_HILSCHER, .device =3D PCI_DEVICE_ID_HILSCHER_NETX, .subvendor =3D 0, .subdevice =3D 0, }, { .vendor =3D PCI_VENDOR_ID_PLX, .device =3D PCI_DEVICE_ID_PLX_9030, .subvendor =3D PCI_VENDOR_ID_PLX, .subdevice =3D PCI_SUBDEVICE_ID_NXSB_PCA, }, { .vendor =3D PCI_VENDOR_ID_PLX, .device =3D PCI_DEVICE_ID_PLX_9030, .subvendor =3D PCI_VENDOR_ID_PLX, .subdevice =3D PCI_SUBDEVICE_ID_NXPCA, }, { .vendor =3D PCI_VENDOR_ID_HILSCHER, .device =3D PCI_DEVICE_ID_HILSCHER_NETPLC, .subvendor =3D PCI_VENDOR_ID_HILSCHER, .subdevice =3D PCI_SUBDEVICE_ID_NETPLC_RAM, }, { .vendor =3D PCI_VENDOR_ID_HILSCHER, .device =3D PCI_DEVICE_ID_HILSCHER_NETPLC, .subvendor =3D PCI_VENDOR_ID_HILSCHER, .subdevice =3D PCI_SUBDEVICE_ID_NETPLC_FLASH, }, { .vendor =3D PCI_VENDOR_ID_HILSCHER, .device =3D PCI_DEVICE_ID_HILSCHER_NETJACK, .subvendor =3D PCI_VENDOR_ID_HILSCHER, .subdevice =3D PCI_SUBDEVICE_ID_NETJACK_RAM, }, { .vendor =3D PCI_VENDOR_ID_HILSCHER, .device =3D PCI_DEVICE_ID_HILSCHER_NETJACK, .subvendor =3D PCI_VENDOR_ID_HILSCHER, .subdevice =3D PCI_SUBDEVICE_ID_NETJACK_FLASH, }, { 0, } }; /* This structure describe the RTDM cifX Driver */ static struct pci_driver cifx_pci_driver =3D { .name =3D "cifx", .id_table =3D cifx_pci_tbl, .probe =3D cifx_pci_probe, .remove =3D 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 =3D (struct rtdm_device *)rtdm_irq_get_arg(irq= , void); io_info_t *device_data =3D (io_info_t *) info->device_data; = if (device_data->priv !=3D NULL) { /* This is a PLX device and cannot produce an IRQ */ return RTDM_IRQ_NONE; } = else { = void __iomem *int_enable_reg =3D device_data->mem[DPM_INDEX].internal_add= r + DPM_HOST_INT_EN0; void __iomem *int_status_reg =3D device_data->mem[DPM_INDEX].internal_add= r + 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 =3D (pxa_dev_info *) ((io_info_t *)info->device_= data)->priv; uint32_t __iomem *plx_timing; = if (!pxa_info) return -ENODEV; = plx_timing =3D pxa_info->plx + PLX_TIMING_OFFSET; *plx_timing =3D 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 =3D (pxa_dev_info *) ((io_info_t *)info->device_dat= a)->priv; = if (!pxa_info) return -ENODEV; = switch (pxa_info->dpm_mode) = { case 8: pxa_info->plx_timing =3D NX_PCA_PCI_8_BIT_DPM_MODE; break; case 16: pxa_info->plx_timing =3D NX_PCA_PCI_16_BIT_DPM_MODE; break; case 32: pxa_info->plx_timing =3D 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 =3D (pxa_dev_info *) ((io_info_t *)info->device_d= ata)->priv; uint32_t __iomem *plx_gpio; = if (!pxa_info) return -ENODEV; = plx_gpio =3D pxa_info->plx + PLX_GPIO_OFFSET; = if ((*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK= )) pxa_info->dpm_mode =3D 8; else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && (*plx_gpio & PLX_GPIO_DATA1= _MASK)) pxa_info->dpm_mode =3D 32; else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA= 1_MASK)) pxa_info->dpm_mode =3D 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 =3D (struct rtdm_device *)context->device; int32_t ret; if (oflags =3D=3D TRUE) { if (((io_info_t *)info->device_data)->irq_registered =3D=3D FALSE) { = if ((ret =3D rtdm_irq_request(&(((io_info_t *)info->device_data)->irq_ha= ndle), ((io_info_t *)info->device_data)->irq, cifx_handler, RTDM_IRQTYPE_SH= ARED, info->device_name, (void *)info)) !=3D 0) { #ifdef DEBUG switch (ret) { case -EINVAL : = rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : an inv= alid parameter was passed\n"); break; = case -EBUSY : = rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : the sp= ecified 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 =3D 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 =3D (struct rtdm_device *)context->device; = if (((io_info_t *)info->device_data)->irq_registered =3D=3D TRUE) { if (((io_info_t *)info->device_data)->irq_enable =3D=3D TRUE) { if (rtdm_irq_disable(&(((io_info_t *)info->device_data)->irq_handle)) != =3D 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_in= fo_t *user_info, void *buf, size_t nbyte) { struct rtdm_device *info =3D (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_i= nfo_t * user_info, const void *buf, size_t nbyte) { struct rtdm_device *info =3D (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 =3D=3D sizeof(uint8_t)) { if (rtdm_safe_copy_from_user(user_info, &irq_enable, buf, nbyte)) { nbyte =3D 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) !=3D irq_enable) { if (((io_info_t *)info->device_data)->irq_registered =3D=3D TRUE) { if (irq_enable =3D=3D TRUE) { if (rtdm_irq_enable(&(((io_info_t *)info->device_data)->irq_handle)) = !=3D 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))= !=3D 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 =3D 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 =3D=3D sizeof(io_map_mem)) { if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) { nbyte =3D 0; = #ifdef DEBUG rtdm_printk("cifx rtdm driver error : can't copy data from driver\n"); #endif /* DEBUG */ } else { if (*map_mem.virt_addr =3D=3D NULL) { ret =3D 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, N= ULL); = if (ret !=3D 0) { nbyte =3D 0; #ifdef DEBUG = switch (ret) { case -EINVAL : = rtdm_printk("cifx rtdm driver error : an invalid start address, siz= e, or destination address was passed\n"); = break; = case -ENOMEM : = rtdm_printk("cifx rtdm driver error : there is insufficient free me= mory 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 alre= ady locked by the user process\n"); = = break; = case -EPERM : = rtdm_printk("cifx rtdm driver error : an illegal invocation environ= ment is detected\n"); = = break; = default : rtdm_printk("cifx rtdm driver error : rtdm_safe_copy_from_user erro= r\n"); = = break; } #endif /* DEBUG */ = } } = else { ret =3D rtdm_munmap(user_info, *map_mem.virt_addr, (size_t)map_mem.leng= th); = if (ret !=3D 0) { nbyte =3D 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 environm= ent is detected\n"); = = break; = = default : = rtdm_printk("cifx rtdm driver error : rtdm_safe_copy_from_user error= \n"); = = break; } #endif /* DEBUG */ } } } = } else { nbyte =3D 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 =3D NULL; io_info_t *device_data =3D NULL; = int32_t bar; int32_t ret; = info =3D rtdm_malloc(sizeof(struct rtdm_device)); = if (info =3D=3D NULL) { #ifdef DEBUG rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n"); #endif /* DEBUG */ return -ENOMEM; } = if ((ret =3D pci_enable_device(dev)) !=3D 0) { #ifdef DEBUG rtdm_printk("cifx rtdm driver error : pci_enable_device error : %i\n", re= t); #endif /* DEBUG */ = goto out_free; } = if ((ret =3D pci_request_regions(dev, DRIVER_NAME)) !=3D 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 =3D id->device; snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_n= um); info->proc_name =3D info->device_name; = switch (id->device) = { case PCI_DEVICE_ID_HILSCHER_NETX: bar =3D DPM_BAR; info->peripheral_name =3D CIFX_RTDM_CARD_NAME; break; case PCI_DEVICE_ID_HILSCHER_NETPLC: bar =3D DPM_BAR; info->peripheral_name =3D CIFX_RTDM_NETPLC_CARD_NAME; break; case PCI_DEVICE_ID_HILSCHER_NETJACK: bar =3D DPM_BAR; info->peripheral_name =3D CIFX_RTDM_NETJACK_CARD_NAME; break; default: bar =3D PLX_DPM_BAR; info->peripheral_name =3D CIFX_RTDM_PLX_CARD_NAME; break; } = info->device_data =3D NULL; device_data =3D rtdm_malloc(sizeof(io_info_t)); = if (device_data =3D=3D 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 =3D pci_resource_start(dev, bar); = if (device_data->mem[DPM_INDEX].addr =3D=3D 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 =3D ioremap_nocache(pci_resource= _start(dev, bar), pci_resource_len(dev, bar)); = if (device_data->mem[DPM_INDEX].internal_addr =3D=3D 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->me= m[DPM_INDEX].addr); device_data->mem[DPM_INDEX].size =3D pci_resource_len(dev, bar); device_data->mem[DPM_INDEX].memtype =3D MEM_PHYS; = /* map extended mem (BAR 1 points to the extended memory) */ device_data->mem[EXT_MEM_INDEX].addr =3D 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 !=3D 0) { device_data->mem[EXT_MEM_INDEX].internal_addr =3D ioremap_nocache(pci_res= ource_start(dev, EXT_MEM_BAR), pci_resource_len(dev, EXT_MEM_BAR)); = = if (device_data->mem[EXT_MEM_INDEX].internal_addr =3D=3D 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)devi= ce_data->mem[EXT_MEM_INDEX].addr); device_data->mem[EXT_MEM_INDEX].size =3D pci_resource_len(dev, EXT_MEM= _BAR); device_data->mem[EXT_MEM_INDEX].memtype =3D MEM_PHYS; } = if ((id->device =3D=3D PCI_DEVICE_ID_HILSCHER_NETX) = || (id->device =3D=3D PCI_DEVICE_ID_HILSCHER_NETPLC) = || (id->device =3D=3D 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 =3D NULL; } = else if (id->subdevice =3D=3D PCI_SUBDEVICE_ID_NXPCA) = { /* map PLX registers */ pxa_dev_info *pxa_info =3D (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_inf= o)); = if (pxa_info =3D=3D NULL) { #ifdef DEBUG rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n"); #endif /* DEBUG */ = goto out_unmap; } = device_data->priv =3D pxa_info; = /* set PXA PLX Timings */ pxa_info->plx =3D ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR), p= ci_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 =3D (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_inf= o)); = if (pxa_info =3D=3D NULL) { #ifdef DEBUG rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n"); #endif /* DEBUG */ goto out_free_pxa; } = pxa_info->plx =3D NULL; pxa_info->plx_timing =3D 0; pxa_info->dpm_mode =3D 0; device_data->priv =3D pxa_info; } = device_data->irq =3D dev->irq; device_data->irq_enable =3D FALSE; device_data->irq_registered =3D FALSE; = info->device_data =3D device_data; if ((ret =3D rtdm_dev_register(info)) !=3D 0) { #ifdef DEBUG switch(ret) { case -EINVAL : rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the dev= ice 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 con= text for an exclusive device cannot be allocated\n"); break; = case -EEXIST : = rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the spe= cified device name of protocol ID is already in use\n"); break; = case -EAGAIN : = rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : some /p= roc entry cannot be created\n"); break; = = default : = rtdm_printk("cifx rtdm driver error : rtdm_dev_register error\n"); break; } #endif /* DEBUG */ = if (id->subdevice !=3D PCI_SUBDEVICE_ID_NXPCA) goto out_unmap; else goto out_unmap_plx; } = pci_set_drvdata(dev, info); = if (id->device =3D=3D PCI_DEVICE_ID_HILSCHER_NETX) dev_info(&dev->dev, "registered CifX card\n"); else if (id->device =3D=3D PCI_DEVICE_ID_HILSCHER_NETPLC) dev_info(&dev->dev, "registered netPLC card\n"); else if (id->device =3D=3D PCI_DEVICE_ID_HILSCHER_NETJACK) dev_info(&dev->dev, "registered netJACK card\n"); else if (id->subdevice =3D=3D PCI_SUBDEVICE_ID_NXSB_PCA) dev_info(&dev->dev, "registered NXSB-PCA adapter card\n"); else = { pxa_dev_info *pxa_info =3D (pxa_dev_info *)((io_info_t *)info->device_dat= a)->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 != =3D 0) iounmap(((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_add= r); out_release: pci_release_regions(dev); = out_disable: pci_disable_device(dev); = out_free: if (info->device_data !=3D 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 =3D pci_get_drvdata(dev); io_info_t *device_data =3D (io_info_t *)info->device_data; = pxa_dev_info *pxa_info =3D (pxa_dev_info *)device_data->priv; int32_t ret; if (info->device_data =3D=3D NULL) { #ifdef DEBUG rtdm_printk("cifx rtdm driver error : device_data NULL pointer\n"); #endif /* DEBUG */ return; } = if (pxa_info !=3D NULL) = { /* Disable all interrupts */ iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0= ); = if (pxa_info->plx !=3D NULL) iounmap((void *)pxa_info->plx); rtdm_free((void *)pxa_info); = } = if ((ret =3D rtdm_dev_unregister(info, 1000)) !=3D 0) { #ifdef DEBUG switch(ret) { case -ENODEV : = rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the d= evice was not registered\n"); break; = case -EAGAIN : = rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the d= evice 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 !=3D 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 */