Commit | Line | Data |
---|---|---|
c76a326f DF |
1 | /* |
2 | comedi/drivers/adl_pci7230.c | |
3 | ||
4 | Hardware comedi driver fot PCI7230 Adlink card | |
5 | Copyright (C) 2010 David Fernandez <dfcastelao@gmail.com> | |
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_pci7230 | |
24 | Description: Driver for the Adlink PCI-7230 32 ch. isolated digital io board | |
25 | Devices: [ADLink] PCI-7230 (adl_pci7230) | |
26 | Author: David Fernandez <dfcastelao@gmail.com> | |
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 PCI7230_DI 0x00 | |
42 | #define PCI7230_DO 0x00 | |
43 | ||
44 | #define PCI_DEVICE_ID_PCI7230 0x7230 | |
45 | ||
46 | static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = { | |
47 | { | |
48 | PCI_VENDOR_ID_ADLINK, | |
49 | PCI_DEVICE_ID_PCI7230, | |
50 | PCI_ANY_ID, | |
51 | PCI_ANY_ID, | |
52 | 0, | |
53 | 0, | |
54 | 0 | |
55 | }, | |
56 | {0} | |
57 | }; | |
58 | ||
59 | MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table); | |
60 | ||
61 | struct adl_pci7230_private { | |
62 | int data; | |
63 | struct pci_dev *pci_dev; | |
64 | }; | |
65 | ||
66 | #define devpriv ((struct adl_pci7230_private *)dev->private) | |
67 | ||
68 | static int adl_pci7230_attach(struct comedi_device *dev, | |
69 | struct comedi_devconfig *it); | |
70 | static int adl_pci7230_detach(struct comedi_device *dev); | |
71 | static struct comedi_driver driver_adl_pci7230 = { | |
72 | .driver_name = "adl_pci7230", | |
73 | .module = THIS_MODULE, | |
74 | .attach = adl_pci7230_attach, | |
75 | .detach = adl_pci7230_detach, | |
76 | }; | |
77 | ||
78 | /* Digital IO */ | |
79 | ||
80 | static int adl_pci7230_di_insn_bits(struct comedi_device *dev, | |
81 | struct comedi_subdevice *s, | |
82 | struct comedi_insn *insn, | |
83 | unsigned int *data); | |
84 | ||
85 | static int adl_pci7230_do_insn_bits(struct comedi_device *dev, | |
86 | struct comedi_subdevice *s, | |
87 | struct comedi_insn *insn, | |
88 | unsigned int *data); | |
89 | ||
90 | static int adl_pci7230_attach(struct comedi_device *dev, | |
91 | struct comedi_devconfig *it) | |
92 | { | |
20fb2280 | 93 | struct pci_dev *pcidev = NULL; |
c76a326f DF |
94 | struct comedi_subdevice *s; |
95 | int bus, slot; | |
96 | ||
97 | printk(KERN_INFO "comedi%d: adl_pci7230\n", dev->minor); | |
98 | ||
99 | dev->board_name = "pci7230"; | |
100 | bus = it->options[0]; | |
101 | slot = it->options[1]; | |
102 | ||
103 | if (alloc_private(dev, sizeof(struct adl_pci7230_private)) < 0) | |
104 | return -ENOMEM; | |
105 | ||
106 | if (alloc_subdevices(dev, 2) < 0) | |
107 | return -ENOMEM; | |
108 | ||
20fb2280 | 109 | for_each_pci_dev(pcidev) { |
c76a326f DF |
110 | if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && |
111 | pcidev->device == PCI_DEVICE_ID_PCI7230) { | |
112 | if (bus || slot) { | |
113 | /* requested particular bus/slot */ | |
114 | if (pcidev->bus->number != bus || | |
115 | PCI_SLOT(pcidev->devfn) != slot) { | |
116 | continue; | |
117 | } | |
118 | } | |
119 | devpriv->pci_dev = pcidev; | |
120 | break; | |
121 | } | |
122 | } | |
123 | if (pcidev == NULL) { | |
124 | printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", | |
125 | dev->minor, bus, slot); | |
126 | return -EIO; | |
127 | } | |
128 | if (comedi_pci_enable(pcidev, "adl_pci7230") < 0) { | |
129 | printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n", | |
130 | dev->minor); | |
131 | return -EIO; | |
132 | } | |
133 | dev->iobase = pci_resource_start(pcidev, 2); | |
134 | printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase); | |
135 | ||
136 | s = dev->subdevices + 0; | |
137 | /* Isolated do */ | |
138 | s->type = COMEDI_SUBD_DO; | |
139 | s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; | |
140 | s->n_chan = 16; | |
141 | s->maxdata = 1; | |
142 | s->range_table = &range_digital; | |
143 | s->insn_bits = adl_pci7230_do_insn_bits; | |
144 | ||
145 | s = dev->subdevices + 1; | |
146 | /* Isolated di */ | |
147 | s->type = COMEDI_SUBD_DI; | |
148 | s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; | |
149 | s->n_chan = 16; | |
150 | s->maxdata = 1; | |
151 | s->range_table = &range_digital; | |
152 | s->insn_bits = adl_pci7230_di_insn_bits; | |
153 | ||
154 | printk(KERN_DEBUG "comedi: attached\n"); | |
155 | ||
156 | return 1; | |
157 | } | |
158 | ||
159 | static int adl_pci7230_detach(struct comedi_device *dev) | |
160 | { | |
161 | printk(KERN_DEBUG "comedi%d: pci7230: remove\n", dev->minor); | |
162 | ||
163 | if (devpriv && devpriv->pci_dev) { | |
164 | if (dev->iobase) | |
165 | comedi_pci_disable(devpriv->pci_dev); | |
166 | pci_dev_put(devpriv->pci_dev); | |
167 | } | |
168 | ||
169 | return 0; | |
170 | } | |
171 | ||
172 | static int adl_pci7230_do_insn_bits(struct comedi_device *dev, | |
173 | struct comedi_subdevice *s, | |
174 | struct comedi_insn *insn, | |
175 | unsigned int *data) | |
176 | { | |
177 | if (insn->n != 2) | |
178 | return -EINVAL; | |
179 | ||
180 | if (data[0]) { | |
181 | s->state &= ~data[0]; | |
182 | s->state |= (data[0] & data[1]); | |
183 | ||
184 | outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO); | |
185 | } | |
186 | ||
187 | return 2; | |
188 | } | |
189 | ||
190 | static int adl_pci7230_di_insn_bits(struct comedi_device *dev, | |
191 | struct comedi_subdevice *s, | |
192 | struct comedi_insn *insn, | |
193 | unsigned int *data) | |
194 | { | |
195 | if (insn->n != 2) | |
196 | return -EINVAL; | |
197 | ||
198 | data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff; | |
199 | ||
200 | return 2; | |
201 | } | |
202 | ||
727b286b AT |
203 | static int __devinit driver_adl_pci7230_pci_probe(struct pci_dev *dev, |
204 | const struct pci_device_id | |
205 | *ent) | |
206 | { | |
207 | return comedi_pci_auto_config(dev, driver_adl_pci7230.driver_name); | |
208 | } | |
209 | ||
210 | static void __devexit driver_adl_pci7230_pci_remove(struct pci_dev *dev) | |
211 | { | |
212 | comedi_pci_auto_unconfig(dev); | |
213 | } | |
214 | ||
215 | static struct pci_driver driver_adl_pci7230_pci_driver = { | |
216 | .id_table = adl_pci7230_pci_table, | |
217 | .probe = &driver_adl_pci7230_pci_probe, | |
218 | .remove = __devexit_p(&driver_adl_pci7230_pci_remove) | |
219 | }; | |
220 | ||
221 | static int __init driver_adl_pci7230_init_module(void) | |
222 | { | |
223 | int retval; | |
224 | ||
225 | retval = comedi_driver_register(&driver_adl_pci7230); | |
226 | if (retval < 0) | |
227 | return retval; | |
228 | ||
229 | driver_adl_pci7230_pci_driver.name = | |
230 | (char *)driver_adl_pci7230.driver_name; | |
231 | return pci_register_driver(&driver_adl_pci7230_pci_driver); | |
232 | } | |
233 | ||
234 | static void __exit driver_adl_pci7230_cleanup_module(void) | |
235 | { | |
236 | pci_unregister_driver(&driver_adl_pci7230_pci_driver); | |
237 | comedi_driver_unregister(&driver_adl_pci7230); | |
238 | } | |
239 | ||
240 | module_init(driver_adl_pci7230_init_module); | |
241 | module_exit(driver_adl_pci7230_cleanup_module); | |
90f703d3 AT |
242 | |
243 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
244 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
245 | MODULE_LICENSE("GPL"); |