linux/drivers/uio/uio_netx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX).
   4 * See http://www.hilscher.com for details.
   5 *
   6 * (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
   7 * (C) 2008 Manuel Traut <manut@linutronix.de>
   8 *
   9 */
  10
  11#include <linux/device.h>
  12#include <linux/io.h>
  13#include <linux/module.h>
  14#include <linux/pci.h>
  15#include <linux/slab.h>
  16#include <linux/uio_driver.h>
  17
  18#define PCI_VENDOR_ID_HILSCHER          0x15CF
  19#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
  20#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
  21#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
  22#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
  23#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
  24#define PCI_SUBDEVICE_ID_NXPCA          0x3335
  25
  26#define DPM_HOST_INT_EN0        0xfff0
  27#define DPM_HOST_INT_STAT0      0xffe0
  28
  29#define DPM_HOST_INT_MASK       0xe600ffff
  30#define DPM_HOST_INT_GLOBAL_EN  0x80000000
  31
  32static irqreturn_t netx_handler(int irq, struct uio_info *dev_info)
  33{
  34        void __iomem *int_enable_reg = dev_info->mem[0].internal_addr
  35                                        + DPM_HOST_INT_EN0;
  36        void __iomem *int_status_reg = dev_info->mem[0].internal_addr
  37                                        + DPM_HOST_INT_STAT0;
  38
  39        /* Is one of our interrupts enabled and active ? */
  40        if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
  41                & DPM_HOST_INT_MASK))
  42                return IRQ_NONE;
  43
  44        /* Disable interrupt */
  45        iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN,
  46                int_enable_reg);
  47        return IRQ_HANDLED;
  48}
  49
  50static int netx_pci_probe(struct pci_dev *dev,
  51                                        const struct pci_device_id *id)
  52{
  53        struct uio_info *info;
  54        int bar;
  55
  56        info = devm_kzalloc(&dev->dev, sizeof(struct uio_info), GFP_KERNEL);
  57        if (!info)
  58                return -ENOMEM;
  59
  60        if (pci_enable_device(dev))
  61                return -ENODEV;
  62
  63        if (pci_request_regions(dev, "netx"))
  64                goto out_disable;
  65
  66        switch (id->device) {
  67        case PCI_DEVICE_ID_HILSCHER_NETX:
  68                bar = 0;
  69                info->name = "netx";
  70                break;
  71        case PCI_DEVICE_ID_HILSCHER_NETPLC:
  72                bar = 0;
  73                info->name = "netplc";
  74                break;
  75        default:
  76                bar = 2;
  77                info->name = "netx_plx";
  78        }
  79
  80        /* BAR0 or 2 points to the card's dual port memory */
  81        info->mem[0].addr = pci_resource_start(dev, bar);
  82        if (!info->mem[0].addr)
  83                goto out_release;
  84        info->mem[0].internal_addr = ioremap(pci_resource_start(dev, bar),
  85                                                pci_resource_len(dev, bar));
  86
  87        if (!info->mem[0].internal_addr)
  88                        goto out_release;
  89
  90        info->mem[0].size = pci_resource_len(dev, bar);
  91        info->mem[0].memtype = UIO_MEM_PHYS;
  92        info->irq = dev->irq;
  93        info->irq_flags = IRQF_SHARED;
  94        info->handler = netx_handler;
  95        info->version = "0.0.1";
  96
  97        /* Make sure all interrupts are disabled */
  98        iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0);
  99
 100        if (uio_register_device(&dev->dev, info))
 101                goto out_unmap;
 102
 103        pci_set_drvdata(dev, info);
 104        dev_info(&dev->dev, "Found %s card, registered UIO device.\n",
 105                                info->name);
 106
 107        return 0;
 108
 109out_unmap:
 110        iounmap(info->mem[0].internal_addr);
 111out_release:
 112        pci_release_regions(dev);
 113out_disable:
 114        pci_disable_device(dev);
 115        return -ENODEV;
 116}
 117
 118static void netx_pci_remove(struct pci_dev *dev)
 119{
 120        struct uio_info *info = pci_get_drvdata(dev);
 121
 122        /* Disable all interrupts */
 123        iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0);
 124        uio_unregister_device(info);
 125        pci_release_regions(dev);
 126        pci_disable_device(dev);
 127        iounmap(info->mem[0].internal_addr);
 128}
 129
 130static struct pci_device_id netx_pci_ids[] = {
 131        {
 132                .vendor =       PCI_VENDOR_ID_HILSCHER,
 133                .device =       PCI_DEVICE_ID_HILSCHER_NETX,
 134                .subvendor =    0,
 135                .subdevice =    0,
 136        },
 137        {
 138                .vendor =       PCI_VENDOR_ID_HILSCHER,
 139                .device =       PCI_DEVICE_ID_HILSCHER_NETPLC,
 140                .subvendor =    PCI_VENDOR_ID_HILSCHER,
 141                .subdevice =    PCI_SUBDEVICE_ID_NETPLC_RAM,
 142        },
 143        {
 144                .vendor =       PCI_VENDOR_ID_HILSCHER,
 145                .device =       PCI_DEVICE_ID_HILSCHER_NETPLC,
 146                .subvendor =    PCI_VENDOR_ID_HILSCHER,
 147                .subdevice =    PCI_SUBDEVICE_ID_NETPLC_FLASH,
 148        },
 149        {
 150                .vendor =       PCI_VENDOR_ID_PLX,
 151                .device =       PCI_DEVICE_ID_PLX_9030,
 152                .subvendor =    PCI_VENDOR_ID_PLX,
 153                .subdevice =    PCI_SUBDEVICE_ID_NXSB_PCA,
 154        },
 155        {
 156                .vendor =       PCI_VENDOR_ID_PLX,
 157                .device =       PCI_DEVICE_ID_PLX_9030,
 158                .subvendor =    PCI_VENDOR_ID_PLX,
 159                .subdevice =    PCI_SUBDEVICE_ID_NXPCA,
 160        },
 161        { 0, }
 162};
 163
 164static struct pci_driver netx_pci_driver = {
 165        .name = "netx",
 166        .id_table = netx_pci_ids,
 167        .probe = netx_pci_probe,
 168        .remove = netx_pci_remove,
 169};
 170
 171module_pci_driver(netx_pci_driver);
 172MODULE_DEVICE_TABLE(pci, netx_pci_ids);
 173MODULE_LICENSE("GPL v2");
 174MODULE_AUTHOR("Hans J. Koch, Manuel Traut");
 175