aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uio
diff options
context:
space:
mode:
authorHans-Jürgen Koch <hjk@linutronix.de>2007-03-02 07:03:12 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-18 18:57:16 -0400
commitbc4c4f45acbe1f1528d654b0b1793f25c175bf8f (patch)
treed8f20ad94d95a53d6644cbb6fb3d7220a5761761 /drivers/uio
parente3e0a28b5b067d16b8e2e5ddaedecda5bd0c3ec2 (diff)
UIO: Hilscher CIF card driver
this is a patch that adds support for Hilscher CIF DeviceNet and Profibus cards. I tested it on a Kontron CPX board, and Thomas reviewed it. You can find the user space part here: http://www.osadl.org/projects/downloads/UIO/user/cif-0.1.0.tar.gz Notes: cif_api.c is the main file you want to look at. It contains the functions to open, close, mmap and so on. cif_dps.c adds functions specific to Profibus cards, and cif_dn.c contains functions for DeviceNet cards. cif.c is a universal playground, it's just a small test program. The user space part of this UIO driver is still work in progress, and not everything is tested yet. At the moment, the thread in cif_api.c contains some code that artificially makes the card generate interrupts, this was added for testing and will be removed later. But the driver already contains all the functions needed for useful operation, so it gives a good idea of how such a thing looks like. For comparison, here's what you get from the manufacturer (www.hilscher.com) when you ask for a Linux 2.6 driver: http://www.tglx.de/private/hjk/cif-orig-2.6.tar.bz2 WARNING: Don't look at the code for too long, you might become sick :-) Signed-off-by: Hans-Jürgen Koch <hjk@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/uio')
-rw-r--r--drivers/uio/Kconfig13
-rw-r--r--drivers/uio/Makefile3
-rw-r--r--drivers/uio/uio_cif.c156
3 files changed, 171 insertions, 1 deletions
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 6b1a62d45e46..b778ed71f636 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -13,4 +13,17 @@ config UIO
13 13
14 If you don't know what to do here, say N. 14 If you don't know what to do here, say N.
15 15
16config UIO_CIF
17 tristate "generic Hilscher CIF Card driver"
18 depends on UIO && PCI
19 default n
20 help
21 Driver for Hilscher CIF DeviceNet and Profibus cards. This
22 driver requires a userspace component that handles all of the
23 heavy lifting and can be found at:
24 http://www.osadl.org/projects/downloads/UIO/user/cif-*
25
26 To compile this driver as a module, choose M here: the module
27 will be called uio_cif.
28
16endmenu 29endmenu
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index 9b7c83063e15..7fecfb459da5 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -1 +1,2 @@
1obj-$(CONFIG_UIO) += uio.o 1obj-$(CONFIG_UIO) += uio.o
2obj-$(CONFIG_UIO_CIF) += uio_cif.o
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
new file mode 100644
index 000000000000..838bae460831
--- /dev/null
+++ b/drivers/uio/uio_cif.c
@@ -0,0 +1,156 @@
1/*
2 * UIO Hilscher CIF card driver
3 *
4 * (C) 2007 Hans J. Koch <hjk@linutronix.de>
5 * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de>
6 *
7 * Licensed under GPL version 2 only.
8 *
9 */
10
11#include <linux/device.h>
12#include <linux/module.h>
13#include <linux/pci.h>
14#include <linux/uio_driver.h>
15
16#include <asm/io.h>
17
18#ifndef PCI_DEVICE_ID_PLX_9030
19#define PCI_DEVICE_ID_PLX_9030 0x9030
20#endif
21
22#define PLX9030_INTCSR 0x4C
23#define INTSCR_INT1_ENABLE 0x01
24#define INTSCR_INT1_STATUS 0x04
25#define INT1_ENABLED_AND_ACTIVE (INTSCR_INT1_ENABLE | INTSCR_INT1_STATUS)
26
27#define PCI_SUBVENDOR_ID_PEP 0x1518
28#define CIF_SUBDEVICE_PROFIBUS 0x430
29#define CIF_SUBDEVICE_DEVICENET 0x432
30
31
32static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info)
33{
34 void __iomem *plx_intscr = dev_info->mem[0].internal_addr
35 + PLX9030_INTCSR;
36
37 if ((ioread8(plx_intscr) & INT1_ENABLED_AND_ACTIVE)
38 != INT1_ENABLED_AND_ACTIVE)
39 return IRQ_NONE;
40
41 /* Disable interrupt */
42 iowrite8(ioread8(plx_intscr) & ~INTSCR_INT1_ENABLE, plx_intscr);
43 return IRQ_HANDLED;
44}
45
46static int __devinit hilscher_pci_probe(struct pci_dev *dev,
47 const struct pci_device_id *id)
48{
49 struct uio_info *info;
50
51 info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
52 if (!info)
53 return -ENOMEM;
54
55 if (pci_enable_device(dev))
56 goto out_free;
57
58 if (pci_request_regions(dev, "hilscher"))
59 goto out_disable;
60
61 info->mem[0].addr = pci_resource_start(dev, 0);
62 if (!info->mem[0].addr)
63 goto out_release;
64 info->mem[0].internal_addr = ioremap(pci_resource_start(dev, 0),
65 pci_resource_len(dev, 0));
66 if (!info->mem[0].internal_addr)
67 goto out_release;
68
69 info->mem[0].size = pci_resource_len(dev, 0);
70 info->mem[0].memtype = UIO_MEM_PHYS;
71 info->mem[1].addr = pci_resource_start(dev, 2);
72 info->mem[1].size = pci_resource_len(dev, 2);
73 info->mem[1].memtype = UIO_MEM_PHYS;
74 switch (id->subdevice) {
75 case CIF_SUBDEVICE_PROFIBUS:
76 info->name = "CIF_Profibus";
77 break;
78 case CIF_SUBDEVICE_DEVICENET:
79 info->name = "CIF_Devicenet";
80 break;
81 default:
82 info->name = "CIF_???";
83 }
84 info->version = "0.0.1";
85 info->irq = dev->irq;
86 info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
87 info->handler = hilscher_handler;
88
89 if (uio_register_device(&dev->dev, info))
90 goto out_unmap;
91
92 pci_set_drvdata(dev, info);
93
94 return 0;
95out_unmap:
96 iounmap(info->mem[0].internal_addr);
97out_release:
98 pci_release_regions(dev);
99out_disable:
100 pci_disable_device(dev);
101out_free:
102 kfree (info);
103 return -ENODEV;
104}
105
106static void hilscher_pci_remove(struct pci_dev *dev)
107{
108 struct uio_info *info = pci_get_drvdata(dev);
109
110 uio_unregister_device(info);
111 pci_release_regions(dev);
112 pci_disable_device(dev);
113 pci_set_drvdata(dev, NULL);
114 iounmap(info->mem[0].internal_addr);
115
116 kfree (info);
117}
118
119static struct pci_device_id hilscher_pci_ids[] = {
120 {
121 .vendor = PCI_VENDOR_ID_PLX,
122 .device = PCI_DEVICE_ID_PLX_9030,
123 .subvendor = PCI_SUBVENDOR_ID_PEP,
124 .subdevice = CIF_SUBDEVICE_PROFIBUS,
125 },
126 {
127 .vendor = PCI_VENDOR_ID_PLX,
128 .device = PCI_DEVICE_ID_PLX_9030,
129 .subvendor = PCI_SUBVENDOR_ID_PEP,
130 .subdevice = CIF_SUBDEVICE_DEVICENET,
131 },
132 { 0, }
133};
134
135static struct pci_driver hilscher_pci_driver = {
136 .name = "hilscher",
137 .id_table = hilscher_pci_ids,
138 .probe = hilscher_pci_probe,
139 .remove = hilscher_pci_remove,
140};
141
142static int __init hilscher_init_module(void)
143{
144 return pci_register_driver(&hilscher_pci_driver);
145}
146
147static void __exit hilscher_exit_module(void)
148{
149 pci_unregister_driver(&hilscher_pci_driver);
150}
151
152module_init(hilscher_init_module);
153module_exit(hilscher_exit_module);
154
155MODULE_LICENSE("GPL v2");
156MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");