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_SUBDEVICE_ID_NXSB_PCA 0x3235 22 #define PCI_SUBDEVICE_ID_NXPCA 0x3335 23 24 #define DPM_HOST_INT_EN0 0xfff0 25 #define DPM_HOST_INT_STAT0 0xffe0 26 27 #define DPM_HOST_INT_MASK 0xe600ffff 28 #define DPM_HOST_INT_GLOBAL_EN 0x80000000 29 30 static irqreturn_t netx_handler(int irq, struct uio_info *dev_info) 31 { 32 void __iomem *int_enable_reg = dev_info->mem[0].internal_addr 33 + DPM_HOST_INT_EN0; 34 void __iomem *int_status_reg = dev_info->mem[0].internal_addr 35 + DPM_HOST_INT_STAT0; 36 37 /* Is one of our interrupts enabled and active ? */ 38 if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) 39 & DPM_HOST_INT_MASK)) 40 return IRQ_NONE; 41 42 /* Disable interrupt */ 43 iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, 44 int_enable_reg); 45 return IRQ_HANDLED; 46 } 47 48 static int __devinit netx_pci_probe(struct pci_dev *dev, 49 const struct pci_device_id *id) 50 { 51 struct uio_info *info; 52 int bar; 53 54 info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); 55 if (!info) 56 return -ENOMEM; 57 58 if (pci_enable_device(dev)) 59 goto out_free; 60 61 if (pci_request_regions(dev, "netx")) 62 goto out_disable; 63 64 switch (id->device) { 65 case PCI_DEVICE_ID_HILSCHER_NETX: 66 bar = 0; 67 info->name = "netx"; 68 break; 69 default: 70 bar = 2; 71 info->name = "netx_plx"; 72 } 73 74 /* BAR0 or 2 points to the card's dual port memory */ 75 info->mem[0].addr = pci_resource_start(dev, bar); 76 if (!info->mem[0].addr) 77 goto out_release; 78 info->mem[0].internal_addr = ioremap(pci_resource_start(dev, bar), 79 pci_resource_len(dev, bar)); 80 81 if (!info->mem[0].internal_addr) 82 goto out_release; 83 84 info->mem[0].size = pci_resource_len(dev, bar); 85 info->mem[0].memtype = UIO_MEM_PHYS; 86 info->irq = dev->irq; 87 info->irq_flags = IRQF_SHARED; 88 info->handler = netx_handler; 89 info->version = "0.0.1"; 90 91 /* Make sure all interrupts are disabled */ 92 iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0); 93 94 if (uio_register_device(&dev->dev, info)) 95 goto out_unmap; 96 97 pci_set_drvdata(dev, info); 98 dev_info(&dev->dev, "Found %s card, registered UIO device.\n", 99 info->name); 100 101 return 0; 102 103 out_unmap: 104 iounmap(info->mem[0].internal_addr); 105 out_release: 106 pci_release_regions(dev); 107 out_disable: 108 pci_disable_device(dev); 109 out_free: 110 kfree(info); 111 return -ENODEV; 112 } 113 114 static void netx_pci_remove(struct pci_dev *dev) 115 { 116 struct uio_info *info = pci_get_drvdata(dev); 117 118 /* Disable all interrupts */ 119 iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0); 120 uio_unregister_device(info); 121 pci_release_regions(dev); 122 pci_disable_device(dev); 123 pci_set_drvdata(dev, NULL); 124 iounmap(info->mem[0].internal_addr); 125 126 kfree(info); 127 } 128 129 static struct pci_device_id netx_pci_ids[] = { 130 { 131 .vendor = PCI_VENDOR_ID_HILSCHER, 132 .device = PCI_DEVICE_ID_HILSCHER_NETX, 133 .subvendor = 0, 134 .subdevice = 0, 135 }, 136 { 137 .vendor = PCI_VENDOR_ID_PLX, 138 .device = PCI_DEVICE_ID_PLX_9030, 139 .subvendor = PCI_VENDOR_ID_PLX, 140 .subdevice = PCI_SUBDEVICE_ID_NXSB_PCA, 141 }, 142 { 143 .vendor = PCI_VENDOR_ID_PLX, 144 .device = PCI_DEVICE_ID_PLX_9030, 145 .subvendor = PCI_VENDOR_ID_PLX, 146 .subdevice = PCI_SUBDEVICE_ID_NXPCA, 147 }, 148 { 0, } 149 }; 150 151 static struct pci_driver netx_pci_driver = { 152 .name = "netx", 153 .id_table = netx_pci_ids, 154 .probe = netx_pci_probe, 155 .remove = netx_pci_remove, 156 }; 157 158 static int __init netx_init_module(void) 159 { 160 return pci_register_driver(&netx_pci_driver); 161 } 162 163 static void __exit netx_exit_module(void) 164 { 165 pci_unregister_driver(&netx_pci_driver); 166 } 167 168 module_init(netx_init_module); 169 module_exit(netx_exit_module); 170 171 MODULE_DEVICE_TABLE(pci, netx_pci_ids); 172 MODULE_LICENSE("GPL v2"); 173 MODULE_AUTHOR("Hans J. Koch, Manuel Traut"); 174