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#include <linux/module.h>
45#include "../comedidev.h"
46
47static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
48 4, {
49 UNI_RANGE(5),
50 UNI_RANGE(2.5),
51 UNI_RANGE(1.25),
52 UNI_RANGE(0.625)
53 }
54};
55
56static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = {
57 4, {
58 BIP_RANGE(2.5),
59 BIP_RANGE(1.25),
60 BIP_RANGE(0.625),
61 BIP_RANGE(0.3125)
62 }
63};
64
65static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = {
66 4, {
67 BIP_RANGE(5),
68 BIP_RANGE(2.5),
69 BIP_RANGE(1.25),
70 BIP_RANGE(0.625)
71 }
72};
73
74static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = {
75 4, {
76 UNI_RANGE(5),
77 UNI_RANGE(0.5),
78 UNI_RANGE(0.05),
79 UNI_RANGE(0.01)
80 }
81};
82
83static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = {
84 4, {
85 BIP_RANGE(2.5),
86 BIP_RANGE(0.25),
87 BIP_RANGE(0.025),
88 BIP_RANGE(0.005)
89 }
90};
91
92static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = {
93 4, {
94 BIP_RANGE(5),
95 BIP_RANGE(0.5),
96 BIP_RANGE(0.05),
97 BIP_RANGE(0.01)
98 }
99};
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170#define TIMEOUT 10000
171
172#define DT2811_ADCSR 0
173#define DT2811_ADGCR 1
174#define DT2811_ADDATLO 2
175#define DT2811_ADDATHI 3
176#define DT2811_DADAT0LO 2
177#define DT2811_DADAT0HI 3
178#define DT2811_DADAT1LO 4
179#define DT2811_DADAT1HI 5
180#define DT2811_DIO 6
181#define DT2811_TMRCTR 7
182
183
184
185
186
187
188
189#define DT2811_ADDONE 0x80
190#define DT2811_ADERROR 0x40
191#define DT2811_ADBUSY 0x20
192#define DT2811_CLRERROR 0x10
193#define DT2811_INTENB 0x04
194#define DT2811_ADMODE 0x03
195
196struct dt2811_board {
197 const char *name;
198 const struct comedi_lrange *bip_5;
199 const struct comedi_lrange *bip_2_5;
200 const struct comedi_lrange *unip_5;
201};
202
203enum { card_2811_pgh, card_2811_pgl };
204
205struct dt2811_private {
206 int ntrig;
207 int curadchan;
208 enum {
209 adc_singleended, adc_diff, adc_pseudo_diff
210 } adc_mux;
211 enum {
212 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
213 } dac_range[2];
214 const struct comedi_lrange *range_type_list[2];
215};
216
217static const struct comedi_lrange *dac_range_types[] = {
218 &range_bipolar5,
219 &range_bipolar2_5,
220 &range_unipolar5
221};
222
223static int dt2811_ai_eoc(struct comedi_device *dev,
224 struct comedi_subdevice *s,
225 struct comedi_insn *insn,
226 unsigned long context)
227{
228 unsigned int status;
229
230 status = inb(dev->iobase + DT2811_ADCSR);
231 if ((status & DT2811_ADBUSY) == 0)
232 return 0;
233 return -EBUSY;
234}
235
236static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
237 struct comedi_insn *insn, unsigned int *data)
238{
239 int chan = CR_CHAN(insn->chanspec);
240 int ret;
241 int i;
242
243 for (i = 0; i < insn->n; i++) {
244 outb(chan, dev->iobase + DT2811_ADGCR);
245
246 ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0);
247 if (ret)
248 return ret;
249
250 data[i] = inb(dev->iobase + DT2811_ADDATLO);
251 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
252 data[i] &= 0xfff;
253 }
254
255 return i;
256}
257
258static int dt2811_ao_insn_write(struct comedi_device *dev,
259 struct comedi_subdevice *s,
260 struct comedi_insn *insn,
261 unsigned int *data)
262{
263 unsigned int chan = CR_CHAN(insn->chanspec);
264 unsigned int val = s->readback[chan];
265 int i;
266
267 for (i = 0; i < insn->n; i++) {
268 val = data[i];
269 outb(val & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
270 outb((val >> 8) & 0xff,
271 dev->iobase + DT2811_DADAT0HI + 2 * chan);
272 }
273 s->readback[chan] = val;
274
275 return insn->n;
276}
277
278static int dt2811_di_insn_bits(struct comedi_device *dev,
279 struct comedi_subdevice *s,
280 struct comedi_insn *insn, unsigned int *data)
281{
282 data[1] = inb(dev->iobase + DT2811_DIO);
283
284 return insn->n;
285}
286
287static int dt2811_do_insn_bits(struct comedi_device *dev,
288 struct comedi_subdevice *s,
289 struct comedi_insn *insn,
290 unsigned int *data)
291{
292 if (comedi_dio_update_state(s, data))
293 outb(s->state, dev->iobase + DT2811_DIO);
294
295 data[1] = s->state;
296
297 return insn->n;
298}
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
321{
322
323 const struct dt2811_board *board = dev->board_ptr;
324 struct dt2811_private *devpriv;
325 int ret;
326 struct comedi_subdevice *s;
327
328 ret = comedi_request_region(dev, it->options[0], 0x8);
329 if (ret)
330 return ret;
331
332#if 0
333 outb(0, dev->iobase + DT2811_ADCSR);
334 udelay(100);
335 i = inb(dev->iobase + DT2811_ADDATLO);
336 i = inb(dev->iobase + DT2811_ADDATHI);
337#endif
338
339 ret = comedi_alloc_subdevices(dev, 4);
340 if (ret)
341 return ret;
342
343 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
344 if (!devpriv)
345 return -ENOMEM;
346
347 switch (it->options[2]) {
348 case 0:
349 devpriv->adc_mux = adc_singleended;
350 break;
351 case 1:
352 devpriv->adc_mux = adc_diff;
353 break;
354 case 2:
355 devpriv->adc_mux = adc_pseudo_diff;
356 break;
357 default:
358 devpriv->adc_mux = adc_singleended;
359 break;
360 }
361 switch (it->options[4]) {
362 case 0:
363 devpriv->dac_range[0] = dac_bipolar_5;
364 break;
365 case 1:
366 devpriv->dac_range[0] = dac_bipolar_2_5;
367 break;
368 case 2:
369 devpriv->dac_range[0] = dac_unipolar_5;
370 break;
371 default:
372 devpriv->dac_range[0] = dac_bipolar_5;
373 break;
374 }
375 switch (it->options[5]) {
376 case 0:
377 devpriv->dac_range[1] = dac_bipolar_5;
378 break;
379 case 1:
380 devpriv->dac_range[1] = dac_bipolar_2_5;
381 break;
382 case 2:
383 devpriv->dac_range[1] = dac_unipolar_5;
384 break;
385 default:
386 devpriv->dac_range[1] = dac_bipolar_5;
387 break;
388 }
389
390 s = &dev->subdevices[0];
391
392 s->type = COMEDI_SUBD_AI;
393 s->subdev_flags = SDF_READABLE | SDF_GROUND;
394 s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
395 s->insn_read = dt2811_ai_insn;
396 s->maxdata = 0xfff;
397 switch (it->options[3]) {
398 case 0:
399 default:
400 s->range_table = board->bip_5;
401 break;
402 case 1:
403 s->range_table = board->bip_2_5;
404 break;
405 case 2:
406 s->range_table = board->unip_5;
407 break;
408 }
409
410 s = &dev->subdevices[1];
411
412 s->type = COMEDI_SUBD_AO;
413 s->subdev_flags = SDF_WRITABLE;
414 s->n_chan = 2;
415 s->maxdata = 0xfff;
416 s->range_table_list = devpriv->range_type_list;
417 devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
418 devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
419 s->insn_write = dt2811_ao_insn_write;
420
421 ret = comedi_alloc_subdev_readback(s);
422 if (ret)
423 return ret;
424
425 s = &dev->subdevices[2];
426
427 s->type = COMEDI_SUBD_DI;
428 s->subdev_flags = SDF_READABLE;
429 s->n_chan = 8;
430 s->insn_bits = dt2811_di_insn_bits;
431 s->maxdata = 1;
432 s->range_table = &range_digital;
433
434 s = &dev->subdevices[3];
435
436 s->type = COMEDI_SUBD_DO;
437 s->subdev_flags = SDF_WRITABLE;
438 s->n_chan = 8;
439 s->insn_bits = dt2811_do_insn_bits;
440 s->maxdata = 1;
441 s->state = 0;
442 s->range_table = &range_digital;
443
444 return 0;
445}
446
447static const struct dt2811_board boardtypes[] = {
448 {
449 .name = "dt2811-pgh",
450 .bip_5 = &range_dt2811_pgh_ai_5_bipolar,
451 .bip_2_5 = &range_dt2811_pgh_ai_2_5_bipolar,
452 .unip_5 = &range_dt2811_pgh_ai_5_unipolar,
453 }, {
454 .name = "dt2811-pgl",
455 .bip_5 = &range_dt2811_pgl_ai_5_bipolar,
456 .bip_2_5 = &range_dt2811_pgl_ai_2_5_bipolar,
457 .unip_5 = &range_dt2811_pgl_ai_5_unipolar,
458 },
459};
460
461static struct comedi_driver dt2811_driver = {
462 .driver_name = "dt2811",
463 .module = THIS_MODULE,
464 .attach = dt2811_attach,
465 .detach = comedi_legacy_detach,
466 .board_name = &boardtypes[0].name,
467 .num_names = ARRAY_SIZE(boardtypes),
468 .offset = sizeof(struct dt2811_board),
469};
470module_comedi_driver(dt2811_driver);
471
472MODULE_AUTHOR("Comedi http://www.comedi.org");
473MODULE_DESCRIPTION("Comedi low-level driver");
474MODULE_LICENSE("GPL");
475