Commit | Line | Data |
---|---|---|
8f567c37 HS |
1 | /* |
2 | * COMEDI driver for the ADLINK PCI-723x/743x series boards. | |
3 | * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com> | |
4 | * | |
5 | * Based on the adl_pci7230 driver written by: | |
6 | * David Fernandez <dfcastelao@gmail.com> | |
7 | * and the adl_pci7432 driver written by: | |
8 | * Michel Lachaine <mike@mikelachaine.ca> | |
9 | * | |
10 | * COMEDI - Linux Control and Measurement Device Interface | |
11 | * Copyright (C) 2000 David A. Schleef <ds@schleef.org> | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or modify | |
14 | * it under the terms of the GNU General Public License as published by | |
15 | * the Free Software Foundation; either version 2 of the License, or | |
16 | * (at your option) any later version. | |
17 | * | |
18 | * This program is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | * GNU General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
24 | * along with this program; if not, write to the Free Software | |
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
26 | */ | |
27 | ||
28 | /* | |
29 | Driver: adl_pci7x3x | |
30 | Description: 32/64-Channel Isolated Digital I/O Boards | |
31 | Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output | |
32 | (ADLink) PCI-7233 [adl_pci7233] - 32 input | |
33 | (ADLink) PCI-7234 [adl_pci7234] - 32 output | |
34 | (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output | |
35 | (ADLink) PCI-7433 [adl_pci7433] - 64 input | |
36 | (ADLink) PCI-7434 [adl_pci7434] - 64 output | |
37 | Author: H Hartley Sweeten <hsweeten@visionengravers.com> | |
38 | Updated: Thu, 02 Aug 2012 14:27:46 -0700 | |
39 | Status: untested | |
40 | ||
8f567c37 HS |
41 | The PCI-7230, PCI-7432 and PCI-7433 boards also support external |
42 | interrupt signals on digital input channels 0 and 1. The PCI-7233 | |
43 | has dual-interrupt sources for change-of-state (COS) on any 16 | |
44 | digital input channels of LSB and for COS on any 16 digital input | |
45 | lines of MSB. Interrupts are not currently supported by this | |
46 | driver. | |
47 | ||
4a79f730 | 48 | Configuration Options: not applicable, uses comedi PCI auto config |
8f567c37 HS |
49 | */ |
50 | ||
33782dd5 HS |
51 | #include <linux/pci.h> |
52 | ||
8f567c37 HS |
53 | #include "../comedidev.h" |
54 | ||
8f567c37 HS |
55 | /* |
56 | * Register I/O map (32-bit access only) | |
57 | */ | |
58 | #define PCI7X3X_DIO_REG 0x00 | |
59 | #define PCI743X_DIO_REG 0x04 | |
60 | ||
b5357e61 HS |
61 | enum apci1516_boardid { |
62 | BOARD_PCI7230, | |
63 | BOARD_PCI7233, | |
64 | BOARD_PCI7234, | |
65 | BOARD_PCI7432, | |
66 | BOARD_PCI7433, | |
67 | BOARD_PCI7434, | |
68 | }; | |
69 | ||
8f567c37 HS |
70 | struct adl_pci7x3x_boardinfo { |
71 | const char *name; | |
8f567c37 HS |
72 | int nsubdevs; |
73 | int di_nchan; | |
74 | int do_nchan; | |
75 | }; | |
76 | ||
77 | static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = { | |
b5357e61 | 78 | [BOARD_PCI7230] = { |
8f567c37 | 79 | .name = "adl_pci7230", |
8f567c37 HS |
80 | .nsubdevs = 2, |
81 | .di_nchan = 16, | |
82 | .do_nchan = 16, | |
b5357e61 HS |
83 | }, |
84 | [BOARD_PCI7233] = { | |
8f567c37 | 85 | .name = "adl_pci7233", |
8f567c37 HS |
86 | .nsubdevs = 1, |
87 | .di_nchan = 32, | |
b5357e61 HS |
88 | }, |
89 | [BOARD_PCI7234] = { | |
8f567c37 | 90 | .name = "adl_pci7234", |
8f567c37 HS |
91 | .nsubdevs = 1, |
92 | .do_nchan = 32, | |
b5357e61 HS |
93 | }, |
94 | [BOARD_PCI7432] = { | |
8f567c37 | 95 | .name = "adl_pci7432", |
8f567c37 HS |
96 | .nsubdevs = 2, |
97 | .di_nchan = 32, | |
98 | .do_nchan = 32, | |
b5357e61 HS |
99 | }, |
100 | [BOARD_PCI7433] = { | |
8f567c37 | 101 | .name = "adl_pci7433", |
8f567c37 HS |
102 | .nsubdevs = 2, |
103 | .di_nchan = 64, | |
b5357e61 HS |
104 | }, |
105 | [BOARD_PCI7434] = { | |
8f567c37 | 106 | .name = "adl_pci7434", |
8f567c37 HS |
107 | .nsubdevs = 2, |
108 | .do_nchan = 64, | |
109 | } | |
110 | }; | |
111 | ||
112 | static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev, | |
113 | struct comedi_subdevice *s, | |
114 | struct comedi_insn *insn, | |
115 | unsigned int *data) | |
116 | { | |
69af5997 | 117 | unsigned long reg = (unsigned long)s->private; |
8f567c37 HS |
118 | unsigned int mask = data[0]; |
119 | unsigned int bits = data[1]; | |
120 | ||
121 | if (mask) { | |
122 | s->state &= ~mask; | |
123 | s->state |= (bits & mask); | |
124 | ||
125 | outl(s->state, dev->iobase + reg); | |
126 | } | |
127 | ||
128 | /* | |
129 | * NOTE: The output register is not readable. | |
130 | * This returned state will not be correct until all the | |
131 | * outputs have been updated. | |
132 | */ | |
133 | data[1] = s->state; | |
134 | ||
135 | return insn->n; | |
136 | } | |
137 | ||
138 | static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev, | |
139 | struct comedi_subdevice *s, | |
140 | struct comedi_insn *insn, | |
141 | unsigned int *data) | |
142 | { | |
69af5997 | 143 | unsigned long reg = (unsigned long)s->private; |
8f567c37 HS |
144 | |
145 | data[1] = inl(dev->iobase + reg); | |
146 | ||
147 | return insn->n; | |
148 | } | |
149 | ||
a690b7e5 | 150 | static int adl_pci7x3x_auto_attach(struct comedi_device *dev, |
b5357e61 | 151 | unsigned long context) |
8f567c37 | 152 | { |
750af5e5 | 153 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
b5357e61 | 154 | const struct adl_pci7x3x_boardinfo *board = NULL; |
8f567c37 HS |
155 | struct comedi_subdevice *s; |
156 | int subdev; | |
157 | int nchan; | |
158 | int ret; | |
159 | ||
b5357e61 HS |
160 | if (context < ARRAY_SIZE(adl_pci7x3x_boards)) |
161 | board = &adl_pci7x3x_boards[context]; | |
8f567c37 HS |
162 | if (!board) |
163 | return -ENODEV; | |
164 | dev->board_ptr = board; | |
165 | dev->board_name = board->name; | |
166 | ||
818f569f | 167 | ret = comedi_pci_enable(dev); |
8f567c37 HS |
168 | if (ret) |
169 | return ret; | |
170 | dev->iobase = pci_resource_start(pcidev, 2); | |
171 | ||
172 | /* | |
173 | * One or two subdevices are setup by this driver depending on | |
174 | * the number of digital inputs and/or outputs provided by the | |
175 | * board. Each subdevice has a maximum of 32 channels. | |
176 | * | |
177 | * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output | |
178 | * PCI-7233 - 1 subdevice: 0 - 32 input | |
179 | * PCI-7234 - 1 subdevice: 0 - 32 output | |
180 | * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output | |
181 | * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input | |
182 | * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output | |
183 | */ | |
184 | ret = comedi_alloc_subdevices(dev, board->nsubdevs); | |
185 | if (ret) | |
186 | return ret; | |
187 | ||
188 | subdev = 0; | |
189 | ||
190 | if (board->di_nchan) { | |
191 | nchan = min(board->di_nchan, 32); | |
192 | ||
2bac8ab3 | 193 | s = &dev->subdevices[subdev]; |
8f567c37 HS |
194 | /* Isolated digital inputs 0 to 15/31 */ |
195 | s->type = COMEDI_SUBD_DI; | |
196 | s->subdev_flags = SDF_READABLE; | |
197 | s->n_chan = nchan; | |
198 | s->maxdata = 1; | |
199 | s->insn_bits = adl_pci7x3x_di_insn_bits; | |
200 | s->range_table = &range_digital; | |
201 | ||
202 | s->private = (void *)PCI7X3X_DIO_REG; | |
203 | ||
204 | subdev++; | |
205 | ||
206 | nchan = board->di_nchan - nchan; | |
207 | if (nchan) { | |
2bac8ab3 | 208 | s = &dev->subdevices[subdev]; |
8f567c37 HS |
209 | /* Isolated digital inputs 32 to 63 */ |
210 | s->type = COMEDI_SUBD_DI; | |
211 | s->subdev_flags = SDF_READABLE; | |
212 | s->n_chan = nchan; | |
213 | s->maxdata = 1; | |
214 | s->insn_bits = adl_pci7x3x_di_insn_bits; | |
215 | s->range_table = &range_digital; | |
216 | ||
217 | s->private = (void *)PCI743X_DIO_REG; | |
218 | ||
219 | subdev++; | |
220 | } | |
221 | } | |
222 | ||
223 | if (board->do_nchan) { | |
224 | nchan = min(board->do_nchan, 32); | |
225 | ||
2bac8ab3 | 226 | s = &dev->subdevices[subdev]; |
8f567c37 HS |
227 | /* Isolated digital outputs 0 to 15/31 */ |
228 | s->type = COMEDI_SUBD_DO; | |
229 | s->subdev_flags = SDF_WRITABLE; | |
230 | s->n_chan = nchan; | |
231 | s->maxdata = 1; | |
232 | s->insn_bits = adl_pci7x3x_do_insn_bits; | |
233 | s->range_table = &range_digital; | |
234 | ||
235 | s->private = (void *)PCI7X3X_DIO_REG; | |
236 | ||
237 | subdev++; | |
238 | ||
239 | nchan = board->do_nchan - nchan; | |
240 | if (nchan) { | |
2bac8ab3 | 241 | s = &dev->subdevices[subdev]; |
8f567c37 HS |
242 | /* Isolated digital outputs 32 to 63 */ |
243 | s->type = COMEDI_SUBD_DO; | |
244 | s->subdev_flags = SDF_WRITABLE; | |
245 | s->n_chan = nchan; | |
246 | s->maxdata = 1; | |
247 | s->insn_bits = adl_pci7x3x_do_insn_bits; | |
248 | s->range_table = &range_digital; | |
249 | ||
250 | s->private = (void *)PCI743X_DIO_REG; | |
251 | ||
252 | subdev++; | |
253 | } | |
254 | } | |
255 | ||
256 | dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n", | |
257 | dev->board_name, board->di_nchan, board->do_nchan); | |
258 | ||
259 | return 0; | |
260 | } | |
261 | ||
8f567c37 HS |
262 | static struct comedi_driver adl_pci7x3x_driver = { |
263 | .driver_name = "adl_pci7x3x", | |
264 | .module = THIS_MODULE, | |
750af5e5 | 265 | .auto_attach = adl_pci7x3x_auto_attach, |
7f072f54 | 266 | .detach = comedi_pci_disable, |
8f567c37 HS |
267 | }; |
268 | ||
a690b7e5 | 269 | static int adl_pci7x3x_pci_probe(struct pci_dev *dev, |
b8f4ac23 | 270 | const struct pci_device_id *id) |
8f567c37 | 271 | { |
b8f4ac23 HS |
272 | return comedi_pci_auto_config(dev, &adl_pci7x3x_driver, |
273 | id->driver_data); | |
8f567c37 HS |
274 | } |
275 | ||
8f567c37 | 276 | static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = { |
b5357e61 HS |
277 | { PCI_VDEVICE(ADLINK, 0x7230), BOARD_PCI7230 }, |
278 | { PCI_VDEVICE(ADLINK, 0x7233), BOARD_PCI7233 }, | |
279 | { PCI_VDEVICE(ADLINK, 0x7234), BOARD_PCI7234 }, | |
280 | { PCI_VDEVICE(ADLINK, 0x7432), BOARD_PCI7432 }, | |
281 | { PCI_VDEVICE(ADLINK, 0x7433), BOARD_PCI7433 }, | |
282 | { PCI_VDEVICE(ADLINK, 0x7434), BOARD_PCI7434 }, | |
8f567c37 HS |
283 | { 0 } |
284 | }; | |
285 | MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table); | |
286 | ||
287 | static struct pci_driver adl_pci7x3x_pci_driver = { | |
288 | .name = "adl_pci7x3x", | |
289 | .id_table = adl_pci7x3x_pci_table, | |
290 | .probe = adl_pci7x3x_pci_probe, | |
9901a4d7 | 291 | .remove = comedi_pci_auto_unconfig, |
8f567c37 HS |
292 | }; |
293 | module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver); | |
294 | ||
295 | MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards"); | |
296 | MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); | |
297 | MODULE_LICENSE("GPL"); |