uio_netx.c revision 8f314cfc1259d3f5039b142ce6fdc90367c22d82
18f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch/* 28f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX). 38f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch * See http://www.hilscher.com for details. 48f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch * 58f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch * (C) 2007 Hans J. Koch <hjk@linutronix.de> 68f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch * (C) 2008 Manuel Traut <manut@linutronix.de> 78f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch * 88f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch * Licensed under GPL version 2 only. 98f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch * 108f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch */ 118f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 128f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#include <linux/device.h> 138f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#include <linux/io.h> 148f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#include <linux/module.h> 158f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#include <linux/pci.h> 168f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#include <linux/uio_driver.h> 178f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 188f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#define PCI_VENDOR_ID_HILSCHER 0x15CF 198f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#define PCI_DEVICE_ID_HILSCHER_NETX 0x0000 208f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235 218f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#define PCI_SUBDEVICE_ID_NXPCA 0x3335 228f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 238f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#define DPM_HOST_INT_EN0 0xfff0 248f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#define DPM_HOST_INT_STAT0 0xffe0 258f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 268f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#define DPM_HOST_INT_MASK 0xe600ffff 278f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch#define DPM_HOST_INT_GLOBAL_EN 0x80000000 288f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 298f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochstatic irqreturn_t netx_handler(int irq, struct uio_info *dev_info) 308f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch{ 318f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch void __iomem *int_enable_reg = dev_info->mem[0].internal_addr 328f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch + DPM_HOST_INT_EN0; 338f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch void __iomem *int_status_reg = dev_info->mem[0].internal_addr 348f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch + DPM_HOST_INT_STAT0; 358f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 368f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch /* Is one of our interrupts enabled and active ? */ 378f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) 388f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch & DPM_HOST_INT_MASK)) 398f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch return IRQ_NONE; 408f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 418f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch /* Disable interrupt */ 428f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, 438f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch int_enable_reg); 448f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch return IRQ_HANDLED; 458f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch} 468f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 478f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochstatic int __devinit netx_pci_probe(struct pci_dev *dev, 488f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch const struct pci_device_id *id) 498f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch{ 508f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch struct uio_info *info; 518f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch int bar; 528f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 538f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); 548f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch if (!info) 558f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch return -ENOMEM; 568f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 578f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch if (pci_enable_device(dev)) 588f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch goto out_free; 598f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 608f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch if (pci_request_regions(dev, "netx")) 618f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch goto out_disable; 628f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 638f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch switch (id->device) { 648f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch case PCI_DEVICE_ID_HILSCHER_NETX: 658f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch bar = 0; 668f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->name = "netx"; 678f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch break; 688f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch default: 698f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch bar = 2; 708f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->name = "netx_plx"; 718f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch } 728f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 738f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch /* BAR0 or 2 points to the card's dual port memory */ 748f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->mem[0].addr = pci_resource_start(dev, bar); 758f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch if (!info->mem[0].addr) 768f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch goto out_release; 778f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->mem[0].internal_addr = ioremap(pci_resource_start(dev, bar), 788f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch pci_resource_len(dev, bar)); 798f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 808f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch if (!info->mem[0].internal_addr) 818f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch goto out_release; 828f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 838f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->mem[0].size = pci_resource_len(dev, bar); 848f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->mem[0].memtype = UIO_MEM_PHYS; 858f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->irq = dev->irq; 868f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->irq_flags = IRQF_SHARED; 878f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->handler = netx_handler; 888f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->version = "0.0.1"; 898f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 908f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch /* Make sure all interrupts are disabled */ 918f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0); 928f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 938f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch if (uio_register_device(&dev->dev, info)) 948f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch goto out_unmap; 958f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 968f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch pci_set_drvdata(dev, info); 978f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch dev_info(&dev->dev, "Found %s card, registered UIO device.\n", 988f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch info->name); 998f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1008f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch return 0; 1018f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1028f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochout_unmap: 1038f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch iounmap(info->mem[0].internal_addr); 1048f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochout_release: 1058f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch pci_release_regions(dev); 1068f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochout_disable: 1078f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch pci_disable_device(dev); 1088f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochout_free: 1098f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch kfree(info); 1108f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch return -ENODEV; 1118f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch} 1128f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1138f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochstatic void netx_pci_remove(struct pci_dev *dev) 1148f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch{ 1158f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch struct uio_info *info = pci_get_drvdata(dev); 1168f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1178f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch /* Disable all interrupts */ 1188f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0); 1198f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch uio_unregister_device(info); 1208f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch pci_release_regions(dev); 1218f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch pci_disable_device(dev); 1228f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch pci_set_drvdata(dev, NULL); 1238f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch iounmap(info->mem[0].internal_addr); 1248f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1258f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch kfree(info); 1268f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch} 1278f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1288f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochstatic struct pci_device_id netx_pci_ids[] = { 1298f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch { 1308f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .vendor = PCI_VENDOR_ID_HILSCHER, 1318f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .device = PCI_DEVICE_ID_HILSCHER_NETX, 1328f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .subvendor = 0, 1338f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .subdevice = 0, 1348f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch }, 1358f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch { 1368f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .vendor = PCI_VENDOR_ID_PLX, 1378f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .device = PCI_DEVICE_ID_PLX_9030, 1388f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .subvendor = PCI_VENDOR_ID_PLX, 1398f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .subdevice = PCI_SUBDEVICE_ID_NXSB_PCA, 1408f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch }, 1418f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch { 1428f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .vendor = PCI_VENDOR_ID_PLX, 1438f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .device = PCI_DEVICE_ID_PLX_9030, 1448f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .subvendor = PCI_VENDOR_ID_PLX, 1458f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .subdevice = PCI_SUBDEVICE_ID_NXPCA, 1468f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch }, 1478f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch { 0, } 1488f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch}; 1498f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1508f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochstatic struct pci_driver netx_pci_driver = { 1518f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .name = "netx", 1528f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .id_table = netx_pci_ids, 1538f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .probe = netx_pci_probe, 1548f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch .remove = netx_pci_remove, 1558f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch}; 1568f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1578f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochstatic int __init netx_init_module(void) 1588f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch{ 1598f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch return pci_register_driver(&netx_pci_driver); 1608f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch} 1618f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1628f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochstatic void __exit netx_exit_module(void) 1638f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch{ 1648f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch pci_unregister_driver(&netx_pci_driver); 1658f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch} 1668f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1678f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochmodule_init(netx_init_module); 1688f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Kochmodule_exit(netx_exit_module); 1698f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. Koch 1708f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. KochMODULE_DEVICE_TABLE(pci, netx_pci_ids); 1718f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. KochMODULE_LICENSE("GPL v2"); 1728f314cfc1259d3f5039b142ce6fdc90367c22d82Hans J. KochMODULE_AUTHOR("Hans J. Koch, Manuel Traut"); 173