1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51#include <linux/pci.h>
52
53#include "../comedidev.h"
54
55
56
57
58#define PCI7X3X_DIO_REG 0x00
59#define PCI743X_DIO_REG 0x04
60
61enum apci1516_boardid {
62 BOARD_PCI7230,
63 BOARD_PCI7233,
64 BOARD_PCI7234,
65 BOARD_PCI7432,
66 BOARD_PCI7433,
67 BOARD_PCI7434,
68};
69
70struct adl_pci7x3x_boardinfo {
71 const char *name;
72 int nsubdevs;
73 int di_nchan;
74 int do_nchan;
75};
76
77static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = {
78 [BOARD_PCI7230] = {
79 .name = "adl_pci7230",
80 .nsubdevs = 2,
81 .di_nchan = 16,
82 .do_nchan = 16,
83 },
84 [BOARD_PCI7233] = {
85 .name = "adl_pci7233",
86 .nsubdevs = 1,
87 .di_nchan = 32,
88 },
89 [BOARD_PCI7234] = {
90 .name = "adl_pci7234",
91 .nsubdevs = 1,
92 .do_nchan = 32,
93 },
94 [BOARD_PCI7432] = {
95 .name = "adl_pci7432",
96 .nsubdevs = 2,
97 .di_nchan = 32,
98 .do_nchan = 32,
99 },
100 [BOARD_PCI7433] = {
101 .name = "adl_pci7433",
102 .nsubdevs = 2,
103 .di_nchan = 64,
104 },
105 [BOARD_PCI7434] = {
106 .name = "adl_pci7434",
107 .nsubdevs = 2,
108 .do_nchan = 64,
109 }
110};
111
112static 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{
117 unsigned long reg = (unsigned long)s->private;
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
130
131
132
133 data[1] = s->state;
134
135 return insn->n;
136}
137
138static 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{
143 unsigned long reg = (unsigned long)s->private;
144
145 data[1] = inl(dev->iobase + reg);
146
147 return insn->n;
148}
149
150static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
151 unsigned long context)
152{
153 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
154 const struct adl_pci7x3x_boardinfo *board = NULL;
155 struct comedi_subdevice *s;
156 int subdev;
157 int nchan;
158 int ret;
159
160 if (context < ARRAY_SIZE(adl_pci7x3x_boards))
161 board = &adl_pci7x3x_boards[context];
162 if (!board)
163 return -ENODEV;
164 dev->board_ptr = board;
165 dev->board_name = board->name;
166
167 ret = comedi_pci_enable(dev);
168 if (ret)
169 return ret;
170 dev->iobase = pci_resource_start(pcidev, 2);
171
172
173
174
175
176
177
178
179
180
181
182
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
193 s = &dev->subdevices[subdev];
194
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) {
208 s = &dev->subdevices[subdev];
209
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
226 s = &dev->subdevices[subdev];
227
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) {
241 s = &dev->subdevices[subdev];
242
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
262static struct comedi_driver adl_pci7x3x_driver = {
263 .driver_name = "adl_pci7x3x",
264 .module = THIS_MODULE,
265 .auto_attach = adl_pci7x3x_auto_attach,
266 .detach = comedi_pci_disable,
267};
268
269static int adl_pci7x3x_pci_probe(struct pci_dev *dev,
270 const struct pci_device_id *id)
271{
272 return comedi_pci_auto_config(dev, &adl_pci7x3x_driver,
273 id->driver_data);
274}
275
276static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = {
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 },
283 { 0 }
284};
285MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table);
286
287static struct pci_driver adl_pci7x3x_pci_driver = {
288 .name = "adl_pci7x3x",
289 .id_table = adl_pci7x3x_pci_table,
290 .probe = adl_pci7x3x_pci_probe,
291 .remove = comedi_pci_auto_unconfig,
292};
293module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver);
294
295MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards");
296MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
297MODULE_LICENSE("GPL");
298