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