Commit | Line | Data |
---|---|---|
ed9c5eeb ML |
1 | /* |
2 | comedi/drivers/adl_pci7432.c | |
3 | ||
4 | Hardware comedi driver fot PCI7432 Adlink card | |
5 | Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca> | |
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_pci7432 | |
24 | Description: Driver for the Adlink PCI-7432 64 ch. isolated digital io board | |
25 | Devices: [ADLink] PCI-7432 (adl_pci7432) | |
26 | Author: Michel Lachaine <mike@mikelachaine.ca> | |
27 | Status: experimental | |
28 | Updated: Mon, 14 Apr 2008 15:08:14 +0100 | |
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 | #include "comedi_pci.h" | |
40 | ||
41 | #define PCI7432_DI 0x00 | |
42 | #define PCI7432_DO 0x00 | |
43 | ||
44 | #define PCI_DEVICE_ID_PCI7432 0x7432 | |
45 | ||
46 | static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = { | |
0a85b6f0 MT |
47 | { |
48 | PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432, PCI_ANY_ID, | |
49 | PCI_ANY_ID, 0, 0, 0}, { | |
50 | 0} | |
ed9c5eeb ML |
51 | }; |
52 | ||
53 | MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table); | |
54 | ||
ddc3dbf4 | 55 | struct adl_pci7432_private { |
ed9c5eeb ML |
56 | int data; |
57 | struct pci_dev *pci_dev; | |
ddc3dbf4 | 58 | }; |
ed9c5eeb | 59 | |
ddc3dbf4 | 60 | #define devpriv ((struct adl_pci7432_private *)dev->private) |
ed9c5eeb | 61 | |
0a85b6f0 MT |
62 | static int adl_pci7432_attach(struct comedi_device *dev, |
63 | struct comedi_devconfig *it); | |
da91b269 | 64 | static int adl_pci7432_detach(struct comedi_device *dev); |
139dfbdf | 65 | static struct comedi_driver driver_adl_pci7432 = { |
68c3dbff BP |
66 | .driver_name = "adl_pci7432", |
67 | .module = THIS_MODULE, | |
68 | .attach = adl_pci7432_attach, | |
69 | .detach = adl_pci7432_detach, | |
ed9c5eeb ML |
70 | }; |
71 | ||
72 | /* Digital IO */ | |
73 | ||
0a85b6f0 MT |
74 | static int adl_pci7432_di_insn_bits(struct comedi_device *dev, |
75 | struct comedi_subdevice *s, | |
76 | struct comedi_insn *insn, | |
77 | unsigned int *data); | |
ed9c5eeb | 78 | |
0a85b6f0 MT |
79 | static int adl_pci7432_do_insn_bits(struct comedi_device *dev, |
80 | struct comedi_subdevice *s, | |
81 | struct comedi_insn *insn, | |
82 | unsigned int *data); | |
ed9c5eeb ML |
83 | |
84 | /* */ | |
85 | ||
0a85b6f0 MT |
86 | static int adl_pci7432_attach(struct comedi_device *dev, |
87 | struct comedi_devconfig *it) | |
ed9c5eeb | 88 | { |
20fb2280 | 89 | struct pci_dev *pcidev = NULL; |
34c43922 | 90 | struct comedi_subdevice *s; |
ed9c5eeb ML |
91 | int bus, slot; |
92 | ||
ff492d38 | 93 | printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor); |
ed9c5eeb ML |
94 | |
95 | dev->board_name = "pci7432"; | |
96 | bus = it->options[0]; | |
97 | slot = it->options[1]; | |
98 | ||
ddc3dbf4 | 99 | if (alloc_private(dev, sizeof(struct adl_pci7432_private)) < 0) |
ed9c5eeb ML |
100 | return -ENOMEM; |
101 | ||
102 | if (alloc_subdevices(dev, 2) < 0) | |
103 | return -ENOMEM; | |
104 | ||
20fb2280 | 105 | for_each_pci_dev(pcidev) { |
ed9c5eeb | 106 | if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && |
0a85b6f0 | 107 | pcidev->device == PCI_DEVICE_ID_PCI7432) { |
ed9c5eeb ML |
108 | if (bus || slot) { |
109 | /* requested particular bus/slot */ | |
110 | if (pcidev->bus->number != bus | |
0a85b6f0 | 111 | || PCI_SLOT(pcidev->devfn) != slot) { |
ed9c5eeb ML |
112 | continue; |
113 | } | |
114 | } | |
115 | devpriv->pci_dev = pcidev; | |
116 | if (comedi_pci_enable(pcidev, "adl_pci7432") < 0) { | |
ff492d38 | 117 | printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n", |
0a85b6f0 | 118 | dev->minor); |
ed9c5eeb ML |
119 | return -EIO; |
120 | } | |
121 | dev->iobase = pci_resource_start(pcidev, 2); | |
ff492d38 BJ |
122 | printk(KERN_INFO "comedi: base addr %4lx\n", |
123 | dev->iobase); | |
ed9c5eeb ML |
124 | |
125 | s = dev->subdevices + 0; | |
126 | s->type = COMEDI_SUBD_DI; | |
127 | s->subdev_flags = | |
0a85b6f0 | 128 | SDF_READABLE | SDF_GROUND | SDF_COMMON; |
ed9c5eeb ML |
129 | s->n_chan = 32; |
130 | s->maxdata = 1; | |
131 | s->len_chanlist = 32; | |
132 | s->io_bits = 0x00000000; | |
133 | s->range_table = &range_digital; | |
134 | s->insn_bits = adl_pci7432_di_insn_bits; | |
135 | ||
136 | s = dev->subdevices + 1; | |
137 | s->type = COMEDI_SUBD_DO; | |
138 | s->subdev_flags = | |
0a85b6f0 | 139 | SDF_WRITABLE | SDF_GROUND | SDF_COMMON; |
ed9c5eeb ML |
140 | s->n_chan = 32; |
141 | s->maxdata = 1; | |
142 | s->len_chanlist = 32; | |
143 | s->io_bits = 0xffffffff; | |
144 | s->range_table = &range_digital; | |
145 | s->insn_bits = adl_pci7432_do_insn_bits; | |
146 | ||
ff492d38 BJ |
147 | printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", |
148 | dev->minor); | |
ed9c5eeb ML |
149 | return 1; |
150 | } | |
151 | } | |
152 | ||
ff492d38 | 153 | printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", |
0a85b6f0 | 154 | dev->minor, bus, slot); |
ed9c5eeb ML |
155 | return -EIO; |
156 | } | |
157 | ||
da91b269 | 158 | static int adl_pci7432_detach(struct comedi_device *dev) |
ed9c5eeb | 159 | { |
ff492d38 | 160 | printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor); |
ed9c5eeb ML |
161 | |
162 | if (devpriv && devpriv->pci_dev) { | |
ff492d38 | 163 | if (dev->iobase) |
ed9c5eeb | 164 | comedi_pci_disable(devpriv->pci_dev); |
ed9c5eeb ML |
165 | pci_dev_put(devpriv->pci_dev); |
166 | } | |
167 | ||
168 | return 0; | |
169 | } | |
170 | ||
0a85b6f0 MT |
171 | static int adl_pci7432_do_insn_bits(struct comedi_device *dev, |
172 | struct comedi_subdevice *s, | |
173 | struct comedi_insn *insn, | |
174 | unsigned int *data) | |
ed9c5eeb | 175 | { |
ff492d38 BJ |
176 | printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n"); |
177 | printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); | |
ed9c5eeb ML |
178 | |
179 | if (insn->n != 2) | |
180 | return -EINVAL; | |
181 | ||
182 | if (data[0]) { | |
183 | s->state &= ~data[0]; | |
184 | s->state |= (data[0] & data[1]); | |
185 | ||
ff492d38 | 186 | printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state, |
0a85b6f0 | 187 | dev->iobase + PCI7432_DO); |
ed9c5eeb ML |
188 | outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO); |
189 | } | |
190 | return 2; | |
191 | } | |
192 | ||
0a85b6f0 MT |
193 | static int adl_pci7432_di_insn_bits(struct comedi_device *dev, |
194 | struct comedi_subdevice *s, | |
195 | struct comedi_insn *insn, | |
196 | unsigned int *data) | |
ed9c5eeb | 197 | { |
ff492d38 BJ |
198 | printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n"); |
199 | printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); | |
ed9c5eeb ML |
200 | |
201 | if (insn->n != 2) | |
202 | return -EINVAL; | |
203 | ||
204 | data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff; | |
ff492d38 | 205 | printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]); |
ed9c5eeb ML |
206 | |
207 | return 2; | |
208 | } | |
209 | ||
727b286b AT |
210 | static int __devinit driver_adl_pci7432_pci_probe(struct pci_dev *dev, |
211 | const struct pci_device_id | |
212 | *ent) | |
213 | { | |
214 | return comedi_pci_auto_config(dev, driver_adl_pci7432.driver_name); | |
215 | } | |
216 | ||
217 | static void __devexit driver_adl_pci7432_pci_remove(struct pci_dev *dev) | |
218 | { | |
219 | comedi_pci_auto_unconfig(dev); | |
220 | } | |
221 | ||
222 | static struct pci_driver driver_adl_pci7432_pci_driver = { | |
223 | .id_table = adl_pci7432_pci_table, | |
224 | .probe = &driver_adl_pci7432_pci_probe, | |
225 | .remove = __devexit_p(&driver_adl_pci7432_pci_remove) | |
226 | }; | |
227 | ||
228 | static int __init driver_adl_pci7432_init_module(void) | |
229 | { | |
230 | int retval; | |
231 | ||
232 | retval = comedi_driver_register(&driver_adl_pci7432); | |
233 | if (retval < 0) | |
234 | return retval; | |
235 | ||
236 | driver_adl_pci7432_pci_driver.name = | |
237 | (char *)driver_adl_pci7432.driver_name; | |
238 | return pci_register_driver(&driver_adl_pci7432_pci_driver); | |
239 | } | |
240 | ||
241 | static void __exit driver_adl_pci7432_cleanup_module(void) | |
242 | { | |
243 | pci_unregister_driver(&driver_adl_pci7432_pci_driver); | |
244 | comedi_driver_unregister(&driver_adl_pci7432); | |
245 | } | |
246 | ||
247 | module_init(driver_adl_pci7432_init_module); | |
248 | module_exit(driver_adl_pci7432_cleanup_module); | |
90f703d3 AT |
249 | |
250 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
251 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
252 | MODULE_LICENSE("GPL"); |