Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
uio_netx.c
Go to the documentation of this file.
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 <[email protected]>
6  * (C) 2008 Manuel Traut <[email protected]>
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 
33 static irqreturn_t netx_handler(int irq, struct uio_info *dev_info)
34 {
35  void __iomem *int_enable_reg = dev_info->mem[0].internal_addr
37  void __iomem *int_status_reg = dev_info->mem[0].internal_addr
39 
40  /* Is one of our interrupts enabled and active ? */
41  if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
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 
51 static int __devinit 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) {
69  bar = 0;
70  info->name = "netx";
71  break;
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 
110 out_unmap:
111  iounmap(info->mem[0].internal_addr);
112 out_release:
113  pci_release_regions(dev);
114 out_disable:
115  pci_disable_device(dev);
116 out_free:
117  kfree(info);
118  return -ENODEV;
119 }
120 
121 static 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  pci_set_drvdata(dev, NULL);
131  iounmap(info->mem[0].internal_addr);
132 
133  kfree(info);
134 }
135 
136 static struct pci_device_id netx_pci_ids[] = {
137  {
138  .vendor = PCI_VENDOR_ID_HILSCHER,
139  .device = PCI_DEVICE_ID_HILSCHER_NETX,
140  .subvendor = 0,
141  .subdevice = 0,
142  },
143  {
144  .vendor = PCI_VENDOR_ID_HILSCHER,
146  .subvendor = PCI_VENDOR_ID_HILSCHER,
147  .subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
148  },
149  {
150  .vendor = PCI_VENDOR_ID_HILSCHER,
152  .subvendor = PCI_VENDOR_ID_HILSCHER,
153  .subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
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_NXSB_PCA,
160  },
161  {
162  .vendor = PCI_VENDOR_ID_PLX,
163  .device = PCI_DEVICE_ID_PLX_9030,
164  .subvendor = PCI_VENDOR_ID_PLX,
165  .subdevice = PCI_SUBDEVICE_ID_NXPCA,
166  },
167  { 0, }
168 };
169 
170 static struct pci_driver netx_pci_driver = {
171  .name = "netx",
172  .id_table = netx_pci_ids,
173  .probe = netx_pci_probe,
174  .remove = netx_pci_remove,
175 };
176 
177 static int __init netx_init_module(void)
178 {
179  return pci_register_driver(&netx_pci_driver);
180 }
181 
182 static void __exit netx_exit_module(void)
183 {
184  pci_unregister_driver(&netx_pci_driver);
185 }
186 
187 module_init(netx_init_module);
188 module_exit(netx_exit_module);
189 
190 MODULE_DEVICE_TABLE(pci, netx_pci_ids);
191 MODULE_LICENSE("GPL v2");
192 MODULE_AUTHOR("Hans J. Koch, Manuel Traut");