Commit | Line | Data |
---|---|---|
bb71f8b3 JG |
1 | /* |
2 | comedi/drivers/adl_pci7296.c | |
3 | ||
4 | COMEDI - Linux Control and Measurement Device Interface | |
5 | Copyright (C) 2000 David A. Schleef <ds@schleef.org> | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | ||
21 | */ | |
22 | /* | |
23 | Driver: adl_pci7296 | |
24 | Description: Driver for the Adlink PCI-7296 96 ch. digital io board | |
25 | Devices: [ADLink] PCI-7296 (adl_pci7296) | |
26 | Author: Jon Grierson <jd@renko.co.uk> | |
27 | Updated: Mon, 14 Apr 2008 15:05:56 +0100 | |
28 | Status: testing | |
29 | ||
30 | Configuration Options: | |
31 | [0] - PCI bus of device (optional) | |
32 | [1] - PCI slot of device (optional) | |
33 | If bus/slot is not specified, the first supported | |
34 | PCI device found will be used. | |
35 | */ | |
36 | ||
37 | #include "../comedidev.h" | |
38 | #include <linux/kernel.h> | |
39 | ||
40 | #include "comedi_pci.h" | |
41 | #include "8255.h" | |
2696fb57 | 42 | /* #include "8253.h" */ |
bb71f8b3 JG |
43 | |
44 | #define PORT1A 0 | |
45 | #define PORT2A 4 | |
46 | #define PORT3A 8 | |
47 | #define PORT4A 12 | |
48 | ||
49 | #define PCI_DEVICE_ID_PCI7296 0x7296 | |
50 | ||
51 | static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = { | |
0a85b6f0 MT |
52 | { |
53 | PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296, PCI_ANY_ID, | |
54 | PCI_ANY_ID, 0, 0, 0}, { | |
55 | 0} | |
bb71f8b3 JG |
56 | }; |
57 | ||
58 | MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table); | |
59 | ||
8dca707e | 60 | struct adl_pci7296_private { |
bb71f8b3 JG |
61 | int data; |
62 | struct pci_dev *pci_dev; | |
8dca707e BP |
63 | }; |
64 | ||
8dca707e | 65 | #define devpriv ((struct adl_pci7296_private *)dev->private) |
bb71f8b3 | 66 | |
0a85b6f0 MT |
67 | static int adl_pci7296_attach(struct comedi_device *dev, |
68 | struct comedi_devconfig *it); | |
da91b269 | 69 | static int adl_pci7296_detach(struct comedi_device *dev); |
139dfbdf | 70 | static struct comedi_driver driver_adl_pci7296 = { |
68c3dbff BP |
71 | .driver_name = "adl_pci7296", |
72 | .module = THIS_MODULE, | |
73 | .attach = adl_pci7296_attach, | |
74 | .detach = adl_pci7296_detach, | |
bb71f8b3 JG |
75 | }; |
76 | ||
0a85b6f0 MT |
77 | static int adl_pci7296_attach(struct comedi_device *dev, |
78 | struct comedi_devconfig *it) | |
bb71f8b3 | 79 | { |
20fb2280 | 80 | struct pci_dev *pcidev = NULL; |
34c43922 | 81 | struct comedi_subdevice *s; |
bb71f8b3 JG |
82 | int bus, slot; |
83 | int ret; | |
84 | ||
1ab1774f | 85 | printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor); |
bb71f8b3 JG |
86 | |
87 | dev->board_name = "pci7432"; | |
88 | bus = it->options[0]; | |
89 | slot = it->options[1]; | |
90 | ||
8dca707e | 91 | if (alloc_private(dev, sizeof(struct adl_pci7296_private)) < 0) |
bb71f8b3 JG |
92 | return -ENOMEM; |
93 | ||
94 | if (alloc_subdevices(dev, 4) < 0) | |
95 | return -ENOMEM; | |
96 | ||
20fb2280 | 97 | for_each_pci_dev(pcidev) { |
bb71f8b3 | 98 | if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && |
0a85b6f0 | 99 | pcidev->device == PCI_DEVICE_ID_PCI7296) { |
bb71f8b3 JG |
100 | if (bus || slot) { |
101 | /* requested particular bus/slot */ | |
102 | if (pcidev->bus->number != bus | |
0a85b6f0 | 103 | || PCI_SLOT(pcidev->devfn) != slot) { |
bb71f8b3 JG |
104 | continue; |
105 | } | |
106 | } | |
107 | devpriv->pci_dev = pcidev; | |
108 | if (comedi_pci_enable(pcidev, "adl_pci7296") < 0) { | |
1ab1774f | 109 | printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n", |
0a85b6f0 | 110 | dev->minor); |
bb71f8b3 JG |
111 | return -EIO; |
112 | } | |
113 | ||
114 | dev->iobase = pci_resource_start(pcidev, 2); | |
1ab1774f BJ |
115 | printk(KERN_INFO "comedi: base addr %4lx\n", |
116 | dev->iobase); | |
bb71f8b3 | 117 | |
2696fb57 | 118 | /* four 8255 digital io subdevices */ |
bb71f8b3 JG |
119 | s = dev->subdevices + 0; |
120 | subdev_8255_init(dev, s, NULL, | |
0a85b6f0 | 121 | (unsigned long)(dev->iobase)); |
bb71f8b3 JG |
122 | |
123 | s = dev->subdevices + 1; | |
124 | ret = subdev_8255_init(dev, s, NULL, | |
0a85b6f0 MT |
125 | (unsigned long)(dev->iobase + |
126 | PORT2A)); | |
bb71f8b3 JG |
127 | if (ret < 0) |
128 | return ret; | |
129 | ||
130 | s = dev->subdevices + 2; | |
131 | ret = subdev_8255_init(dev, s, NULL, | |
0a85b6f0 MT |
132 | (unsigned long)(dev->iobase + |
133 | PORT3A)); | |
bb71f8b3 JG |
134 | if (ret < 0) |
135 | return ret; | |
136 | ||
137 | s = dev->subdevices + 3; | |
138 | ret = subdev_8255_init(dev, s, NULL, | |
0a85b6f0 MT |
139 | (unsigned long)(dev->iobase + |
140 | PORT4A)); | |
bb71f8b3 JG |
141 | if (ret < 0) |
142 | return ret; | |
143 | ||
1ab1774f BJ |
144 | printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", |
145 | dev->minor); | |
bb71f8b3 JG |
146 | |
147 | return 1; | |
148 | } | |
149 | } | |
150 | ||
1ab1774f | 151 | printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", |
0a85b6f0 | 152 | dev->minor, bus, slot); |
bb71f8b3 JG |
153 | return -EIO; |
154 | } | |
155 | ||
da91b269 | 156 | static int adl_pci7296_detach(struct comedi_device *dev) |
bb71f8b3 | 157 | { |
1ab1774f | 158 | printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor); |
bb71f8b3 JG |
159 | |
160 | if (devpriv && devpriv->pci_dev) { | |
1ab1774f | 161 | if (dev->iobase) |
bb71f8b3 | 162 | comedi_pci_disable(devpriv->pci_dev); |
bb71f8b3 JG |
163 | pci_dev_put(devpriv->pci_dev); |
164 | } | |
2696fb57 | 165 | /* detach four 8255 digital io subdevices */ |
bb71f8b3 JG |
166 | if (dev->subdevices) { |
167 | subdev_8255_cleanup(dev, dev->subdevices + 0); | |
168 | subdev_8255_cleanup(dev, dev->subdevices + 1); | |
169 | subdev_8255_cleanup(dev, dev->subdevices + 2); | |
170 | subdev_8255_cleanup(dev, dev->subdevices + 3); | |
171 | ||
172 | } | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
727b286b AT |
177 | static int __devinit driver_adl_pci7296_pci_probe(struct pci_dev *dev, |
178 | const struct pci_device_id | |
179 | *ent) | |
180 | { | |
181 | return comedi_pci_auto_config(dev, driver_adl_pci7296.driver_name); | |
182 | } | |
183 | ||
184 | static void __devexit driver_adl_pci7296_pci_remove(struct pci_dev *dev) | |
185 | { | |
186 | comedi_pci_auto_unconfig(dev); | |
187 | } | |
188 | ||
189 | static struct pci_driver driver_adl_pci7296_pci_driver = { | |
190 | .id_table = adl_pci7296_pci_table, | |
191 | .probe = &driver_adl_pci7296_pci_probe, | |
192 | .remove = __devexit_p(&driver_adl_pci7296_pci_remove) | |
193 | }; | |
194 | ||
195 | static int __init driver_adl_pci7296_init_module(void) | |
196 | { | |
197 | int retval; | |
198 | ||
199 | retval = comedi_driver_register(&driver_adl_pci7296); | |
200 | if (retval < 0) | |
201 | return retval; | |
202 | ||
203 | driver_adl_pci7296_pci_driver.name = | |
204 | (char *)driver_adl_pci7296.driver_name; | |
205 | return pci_register_driver(&driver_adl_pci7296_pci_driver); | |
206 | } | |
207 | ||
208 | static void __exit driver_adl_pci7296_cleanup_module(void) | |
209 | { | |
210 | pci_unregister_driver(&driver_adl_pci7296_pci_driver); | |
211 | comedi_driver_unregister(&driver_adl_pci7296); | |
212 | } | |
213 | ||
214 | module_init(driver_adl_pci7296_init_module); | |
215 | module_exit(driver_adl_pci7296_cleanup_module); | |
90f703d3 AT |
216 | |
217 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
218 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
219 | MODULE_LICENSE("GPL"); |