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
52
53
54
55#include <linux/module.h>
56
57#include "../comedi_pci.h"
58
59
60
61
62#define PCI7X3X_DIO_REG 0x00
63#define PCI743X_DIO_REG 0x04
64
65enum apci1516_boardid {
66 BOARD_PCI7230,
67 BOARD_PCI7233,
68 BOARD_PCI7234,
69 BOARD_PCI7432,
70 BOARD_PCI7433,
71 BOARD_PCI7434,
72};
73
74struct adl_pci7x3x_boardinfo {
75 const char *name;
76 int nsubdevs;
77 int di_nchan;
78 int do_nchan;
79};
80
81static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = {
82 [BOARD_PCI7230] = {
83 .name = "adl_pci7230",
84 .nsubdevs = 2,
85 .di_nchan = 16,
86 .do_nchan = 16,
87 },
88 [BOARD_PCI7233] = {
89 .name = "adl_pci7233",
90 .nsubdevs = 1,
91 .di_nchan = 32,
92 },
93 [BOARD_PCI7234] = {
94 .name = "adl_pci7234",
95 .nsubdevs = 1,
96 .do_nchan = 32,
97 },
98 [BOARD_PCI7432] = {
99 .name = "adl_pci7432",
100 .nsubdevs = 2,
101 .di_nchan = 32,
102 .do_nchan = 32,
103 },
104 [BOARD_PCI7433] = {
105 .name = "adl_pci7433",
106 .nsubdevs = 2,
107 .di_nchan = 64,
108 },
109 [BOARD_PCI7434] = {
110 .name = "adl_pci7434",
111 .nsubdevs = 2,
112 .do_nchan = 64,
113 }
114};
115
116static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev,
117 struct comedi_subdevice *s,
118 struct comedi_insn *insn,
119 unsigned int *data)
120{
121 unsigned long reg = (unsigned long)s->private;
122
123 if (comedi_dio_update_state(s, data)) {
124 unsigned int val = s->state;
125
126 if (s->n_chan == 16) {
127
128
129
130
131
132
133 val |= val << 16;
134 }
135 outl(val, dev->iobase + reg);
136 }
137
138 data[1] = s->state;
139
140 return insn->n;
141}
142
143static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev,
144 struct comedi_subdevice *s,
145 struct comedi_insn *insn,
146 unsigned int *data)
147{
148 unsigned long reg = (unsigned long)s->private;
149
150 data[1] = inl(dev->iobase + reg);
151
152 return insn->n;
153}
154
155static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
156 unsigned long context)
157{
158 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
159 const struct adl_pci7x3x_boardinfo *board = NULL;
160 struct comedi_subdevice *s;
161 int subdev;
162 int nchan;
163 int ret;
164
165 if (context < ARRAY_SIZE(adl_pci7x3x_boards))
166 board = &adl_pci7x3x_boards[context];
167 if (!board)
168 return -ENODEV;
169 dev->board_ptr = board;
170 dev->board_name = board->name;
171
172 ret = comedi_pci_enable(dev);
173 if (ret)
174 return ret;
175 dev->iobase = pci_resource_start(pcidev, 2);
176
177 ret = comedi_alloc_subdevices(dev, board->nsubdevs);
178 if (ret)
179 return ret;
180
181 subdev = 0;
182
183 if (board->di_nchan) {
184 nchan = min(board->di_nchan, 32);
185
186 s = &dev->subdevices[subdev];
187
188 s->type = COMEDI_SUBD_DI;
189 s->subdev_flags = SDF_READABLE;
190 s->n_chan = nchan;
191 s->maxdata = 1;
192 s->insn_bits = adl_pci7x3x_di_insn_bits;
193 s->range_table = &range_digital;
194
195 s->private = (void *)PCI7X3X_DIO_REG;
196
197 subdev++;
198
199 nchan = board->di_nchan - nchan;
200 if (nchan) {
201 s = &dev->subdevices[subdev];
202
203 s->type = COMEDI_SUBD_DI;
204 s->subdev_flags = SDF_READABLE;
205 s->n_chan = nchan;
206 s->maxdata = 1;
207 s->insn_bits = adl_pci7x3x_di_insn_bits;
208 s->range_table = &range_digital;
209
210 s->private = (void *)PCI743X_DIO_REG;
211
212 subdev++;
213 }
214 }
215
216 if (board->do_nchan) {
217 nchan = min(board->do_nchan, 32);
218
219 s = &dev->subdevices[subdev];
220
221 s->type = COMEDI_SUBD_DO;
222 s->subdev_flags = SDF_WRITABLE;
223 s->n_chan = nchan;
224 s->maxdata = 1;
225 s->insn_bits = adl_pci7x3x_do_insn_bits;
226 s->range_table = &range_digital;
227
228 s->private = (void *)PCI7X3X_DIO_REG;
229
230 subdev++;
231
232 nchan = board->do_nchan - nchan;
233 if (nchan) {
234 s = &dev->subdevices[subdev];
235
236 s->type = COMEDI_SUBD_DO;
237 s->subdev_flags = SDF_WRITABLE;
238 s->n_chan = nchan;
239 s->maxdata = 1;
240 s->insn_bits = adl_pci7x3x_do_insn_bits;
241 s->range_table = &range_digital;
242
243 s->private = (void *)PCI743X_DIO_REG;
244
245 subdev++;
246 }
247 }
248
249 return 0;
250}
251
252static struct comedi_driver adl_pci7x3x_driver = {
253 .driver_name = "adl_pci7x3x",
254 .module = THIS_MODULE,
255 .auto_attach = adl_pci7x3x_auto_attach,
256 .detach = comedi_pci_detach,
257};
258
259static int adl_pci7x3x_pci_probe(struct pci_dev *dev,
260 const struct pci_device_id *id)
261{
262 return comedi_pci_auto_config(dev, &adl_pci7x3x_driver,
263 id->driver_data);
264}
265
266static const struct pci_device_id adl_pci7x3x_pci_table[] = {
267 { PCI_VDEVICE(ADLINK, 0x7230), BOARD_PCI7230 },
268 { PCI_VDEVICE(ADLINK, 0x7233), BOARD_PCI7233 },
269 { PCI_VDEVICE(ADLINK, 0x7234), BOARD_PCI7234 },
270 { PCI_VDEVICE(ADLINK, 0x7432), BOARD_PCI7432 },
271 { PCI_VDEVICE(ADLINK, 0x7433), BOARD_PCI7433 },
272 { PCI_VDEVICE(ADLINK, 0x7434), BOARD_PCI7434 },
273 { 0 }
274};
275MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table);
276
277static struct pci_driver adl_pci7x3x_pci_driver = {
278 .name = "adl_pci7x3x",
279 .id_table = adl_pci7x3x_pci_table,
280 .probe = adl_pci7x3x_pci_probe,
281 .remove = comedi_pci_auto_unconfig,
282};
283module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver);
284
285MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards");
286MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
287MODULE_LICENSE("GPL");
288