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