Commit | Line | Data |
---|---|---|
3c443716 DS |
1 | /* |
2 | comedi/drivers/dt2811.c | |
3 | Hardware driver for Data Translation DT2811 | |
4 | ||
5 | COMEDI - Linux Control and Measurement Device Interface | |
6 | History: | |
7 | Base Version - David A. Schleef <ds@schleef.org> | |
8 | December 1998 - Updated to work. David does not have a DT2811 | |
9 | board any longer so this was suffering from bitrot. | |
10 | Updated performed by ... | |
11 | ||
12 | This program is free software; you can redistribute it and/or modify | |
13 | it under the terms of the GNU General Public License as published by | |
14 | the Free Software Foundation; either version 2 of the License, or | |
15 | (at your option) any later version. | |
16 | ||
17 | This program is distributed in the hope that it will be useful, | |
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | GNU General Public License for more details. | |
21 | ||
22 | You should have received a copy of the GNU General Public License | |
23 | along with this program; if not, write to the Free Software | |
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 | */ | |
26 | /* | |
27 | Driver: dt2811 | |
28 | Description: Data Translation DT2811 | |
29 | Author: ds | |
30 | Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh) | |
31 | Status: works | |
32 | ||
33 | Configuration options: | |
34 | [0] - I/O port base address | |
35 | [1] - IRQ, although this is currently unused | |
36 | [2] - A/D reference | |
3b9fdcd5 IC |
37 | 0 = signle-ended |
38 | 1 = differential | |
3c443716 DS |
39 | 2 = pseudo-differential (common reference) |
40 | [3] - A/D range | |
3b9fdcd5 IC |
41 | 0 = [-5, 5] |
42 | 1 = [-2.5, 2.5] | |
43 | 2 = [0, 5] | |
3c443716 DS |
44 | [4] - D/A 0 range (same choices) |
45 | [4] - D/A 1 range (same choices) | |
46 | */ | |
47 | ||
25436dc9 | 48 | #include <linux/interrupt.h> |
3c443716 DS |
49 | #include "../comedidev.h" |
50 | ||
51 | #include <linux/ioport.h> | |
52 | ||
53 | static const char *driver_name = "dt2811"; | |
54 | ||
3b9fdcd5 IC |
55 | static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { |
56 | 4, { | |
57 | RANGE(0, 5), | |
58 | RANGE(0, 2.5), | |
59 | RANGE(0, 1.25), | |
60 | RANGE(0, 0.625) | |
61 | } | |
3c443716 | 62 | }; |
0a85b6f0 | 63 | |
3b9fdcd5 IC |
64 | static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = { |
65 | 4, { | |
66 | RANGE(-2.5, 2.5), | |
67 | RANGE(-1.25, 1.25), | |
68 | RANGE(-0.625, 0.625), | |
69 | RANGE(-0.3125, 0.3125) | |
70 | } | |
3c443716 | 71 | }; |
0a85b6f0 | 72 | |
3b9fdcd5 IC |
73 | static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = { |
74 | 4, { | |
75 | RANGE(-5, 5), | |
76 | RANGE(-2.5, 2.5), | |
77 | RANGE(-1.25, 1.25), | |
78 | RANGE(-0.625, 0.625) | |
79 | } | |
3c443716 | 80 | }; |
0a85b6f0 | 81 | |
3b9fdcd5 IC |
82 | static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = { |
83 | 4, { | |
84 | RANGE(0, 5), | |
85 | RANGE(0, 0.5), | |
86 | RANGE(0, 0.05), | |
87 | RANGE(0, 0.01) | |
88 | } | |
3c443716 | 89 | }; |
0a85b6f0 | 90 | |
3b9fdcd5 IC |
91 | static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = { |
92 | 4, { | |
93 | RANGE(-2.5, 2.5), | |
94 | RANGE(-0.25, 0.25), | |
95 | RANGE(-0.025, 0.025), | |
96 | RANGE(-0.005, 0.005) | |
97 | } | |
3c443716 | 98 | }; |
0a85b6f0 | 99 | |
3b9fdcd5 IC |
100 | static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { |
101 | 4, { | |
102 | RANGE(-5, 5), | |
103 | RANGE(-0.5, 0.5), | |
104 | RANGE(-0.05, 0.05), | |
105 | RANGE(-0.01, 0.01) | |
106 | } | |
3c443716 DS |
107 | }; |
108 | ||
109 | /* | |
110 | ||
111 | 0x00 ADCSR R/W A/D Control/Status Register | |
112 | bit 7 - (R) 1 indicates A/D conversion done | |
113 | reading ADDAT clears bit | |
114 | (W) ignored | |
115 | bit 6 - (R) 1 indicates A/D error | |
116 | (W) ignored | |
117 | bit 5 - (R) 1 indicates A/D busy, cleared at end | |
118 | of conversion | |
119 | (W) ignored | |
120 | bit 4 - (R) 0 | |
121 | (W) | |
122 | bit 3 - (R) 0 | |
123 | bit 2 - (R/W) 1 indicates interrupts enabled | |
124 | bits 1,0 - (R/W) mode bits | |
125 | 00 single conversion on ADGCR load | |
126 | 01 continuous conversion, internal clock, | |
127 | (clock enabled on ADGCR load) | |
128 | 10 continuous conversion, internal clock, | |
129 | external trigger | |
130 | 11 continuous conversion, external clock, | |
131 | external trigger | |
132 | ||
133 | 0x01 ADGCR R/W A/D Gain/Channel Register | |
134 | bit 6,7 - (R/W) gain select | |
135 | 00 gain=1, both PGH, PGL models | |
136 | 01 gain=2 PGH, 10 PGL | |
137 | 10 gain=4 PGH, 100 PGL | |
138 | 11 gain=8 PGH, 500 PGL | |
139 | bit 4,5 - reserved | |
140 | bit 3-0 - (R/W) channel select | |
141 | channel number from 0-15 | |
142 | ||
143 | 0x02,0x03 (R) ADDAT A/D Data Register | |
144 | (W) DADAT0 D/A Data Register 0 | |
145 | 0x02 low byte | |
146 | 0x03 high byte | |
147 | ||
148 | 0x04,0x05 (W) DADAT0 D/A Data Register 1 | |
149 | ||
150 | 0x06 (R) DIO0 Digital Input Port 0 | |
151 | (W) DIO1 Digital Output Port 1 | |
152 | ||
153 | 0x07 TMRCTR (R/W) Timer/Counter Register | |
154 | bits 6,7 - reserved | |
155 | bits 5-3 - Timer frequency control (mantissa) | |
156 | 543 divisor freqency (kHz) | |
157 | 000 1 600 | |
158 | 001 10 60 | |
159 | 010 2 300 | |
160 | 011 3 200 | |
161 | 100 4 150 | |
162 | 101 5 120 | |
163 | 110 6 100 | |
164 | 111 12 50 | |
165 | bits 2-0 - Timer frequency control (exponent) | |
166 | 210 multiply divisor/divide frequency by | |
167 | 000 1 | |
168 | 001 10 | |
169 | 010 100 | |
170 | 011 1000 | |
171 | 100 10000 | |
172 | 101 100000 | |
173 | 110 1000000 | |
174 | 111 10000000 | |
175 | ||
176 | */ | |
177 | ||
178 | #define TIMEOUT 10000 | |
179 | ||
180 | #define DT2811_SIZE 8 | |
181 | ||
182 | #define DT2811_ADCSR 0 | |
183 | #define DT2811_ADGCR 1 | |
184 | #define DT2811_ADDATLO 2 | |
185 | #define DT2811_ADDATHI 3 | |
186 | #define DT2811_DADAT0LO 2 | |
187 | #define DT2811_DADAT0HI 3 | |
188 | #define DT2811_DADAT1LO 4 | |
189 | #define DT2811_DADAT1HI 5 | |
190 | #define DT2811_DIO 6 | |
191 | #define DT2811_TMRCTR 7 | |
192 | ||
193 | /* | |
194 | * flags | |
195 | */ | |
196 | ||
197 | /* ADCSR */ | |
198 | ||
199 | #define DT2811_ADDONE 0x80 | |
200 | #define DT2811_ADERROR 0x40 | |
201 | #define DT2811_ADBUSY 0x20 | |
202 | #define DT2811_CLRERROR 0x10 | |
203 | #define DT2811_INTENB 0x04 | |
204 | #define DT2811_ADMODE 0x03 | |
205 | ||
42f1884d BP |
206 | struct dt2811_board { |
207 | ||
3c443716 | 208 | const char *name; |
9ced1de6 BP |
209 | const struct comedi_lrange *bip_5; |
210 | const struct comedi_lrange *bip_2_5; | |
211 | const struct comedi_lrange *unip_5; | |
42f1884d BP |
212 | }; |
213 | ||
214 | static const struct dt2811_board boardtypes[] = { | |
3c443716 | 215 | {"dt2811-pgh", |
0a85b6f0 MT |
216 | &range_dt2811_pgh_ai_5_bipolar, |
217 | &range_dt2811_pgh_ai_2_5_bipolar, | |
218 | &range_dt2811_pgh_ai_5_unipolar, | |
219 | }, | |
3c443716 | 220 | {"dt2811-pgl", |
0a85b6f0 MT |
221 | &range_dt2811_pgl_ai_5_bipolar, |
222 | &range_dt2811_pgl_ai_2_5_bipolar, | |
223 | &range_dt2811_pgl_ai_5_unipolar, | |
224 | }, | |
3c443716 DS |
225 | }; |
226 | ||
42f1884d | 227 | #define this_board ((const struct dt2811_board *)dev->board_ptr) |
3c443716 | 228 | |
0a85b6f0 MT |
229 | static int dt2811_attach(struct comedi_device *dev, |
230 | struct comedi_devconfig *it); | |
da91b269 | 231 | static int dt2811_detach(struct comedi_device *dev); |
139dfbdf | 232 | static struct comedi_driver driver_dt2811 = { |
68c3dbff BP |
233 | .driver_name = "dt2811", |
234 | .module = THIS_MODULE, | |
235 | .attach = dt2811_attach, | |
236 | .detach = dt2811_detach, | |
237 | .board_name = &boardtypes[0].name, | |
8629efa4 | 238 | .num_names = ARRAY_SIZE(boardtypes), |
68c3dbff | 239 | .offset = sizeof(struct dt2811_board), |
3c443716 DS |
240 | }; |
241 | ||
7114a280 AT |
242 | static int __init driver_dt2811_init_module(void) |
243 | { | |
244 | return comedi_driver_register(&driver_dt2811); | |
245 | } | |
246 | ||
247 | static void __exit driver_dt2811_cleanup_module(void) | |
248 | { | |
249 | comedi_driver_unregister(&driver_dt2811); | |
250 | } | |
251 | ||
252 | module_init(driver_dt2811_init_module); | |
253 | module_exit(driver_dt2811_cleanup_module); | |
3c443716 | 254 | |
da91b269 | 255 | static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 | 256 | struct comedi_insn *insn, unsigned int *data); |
da91b269 | 257 | static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 MT |
258 | struct comedi_insn *insn, unsigned int *data); |
259 | static int dt2811_ao_insn_read(struct comedi_device *dev, | |
260 | struct comedi_subdevice *s, | |
261 | struct comedi_insn *insn, unsigned int *data); | |
262 | static int dt2811_di_insn_bits(struct comedi_device *dev, | |
263 | struct comedi_subdevice *s, | |
264 | struct comedi_insn *insn, unsigned int *data); | |
265 | static int dt2811_do_insn_bits(struct comedi_device *dev, | |
266 | struct comedi_subdevice *s, | |
267 | struct comedi_insn *insn, unsigned int *data); | |
3c443716 DS |
268 | |
269 | enum { card_2811_pgh, card_2811_pgl }; | |
d89da617 BP |
270 | |
271 | struct dt2811_private { | |
3c443716 DS |
272 | int ntrig; |
273 | int curadchan; | |
274 | enum { | |
275 | adc_singleended, adc_diff, adc_pseudo_diff | |
276 | } adc_mux; | |
277 | enum { | |
278 | dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5 | |
279 | } dac_range[2]; | |
9ced1de6 | 280 | const struct comedi_lrange *range_type_list[2]; |
790c5541 | 281 | unsigned int ao_readback[2]; |
d89da617 | 282 | }; |
3c443716 | 283 | |
d89da617 | 284 | #define devpriv ((struct dt2811_private *)dev->private) |
3c443716 | 285 | |
9ced1de6 | 286 | static const struct comedi_lrange *dac_range_types[] = { |
3c443716 DS |
287 | &range_bipolar5, |
288 | &range_bipolar2_5, | |
289 | &range_unipolar5 | |
290 | }; | |
291 | ||
292 | #define DT2811_TIMEOUT 5 | |
293 | ||
294 | #if 0 | |
70265d24 | 295 | static irqreturn_t dt2811_interrupt(int irq, void *d) |
3c443716 DS |
296 | { |
297 | int lo, hi; | |
298 | int data; | |
71b5f4f1 | 299 | struct comedi_device *dev = d; |
3c443716 DS |
300 | |
301 | if (!dev->attached) { | |
302 | comedi_error(dev, "spurious interrupt"); | |
303 | return IRQ_HANDLED; | |
304 | } | |
305 | ||
306 | lo = inb(dev->iobase + DT2811_ADDATLO); | |
307 | hi = inb(dev->iobase + DT2811_ADDATHI); | |
308 | ||
309 | data = lo + (hi << 8); | |
310 | ||
311 | if (!(--devpriv->ntrig)) { | |
312 | /* how to turn off acquisition */ | |
313 | s->async->events |= COMEDI_SB_EOA; | |
314 | } | |
315 | comedi_event(dev, s); | |
316 | return IRQ_HANDLED; | |
317 | } | |
318 | #endif | |
319 | ||
320 | /* | |
321 | options[0] Board base address | |
322 | options[1] IRQ | |
323 | options[2] Input configuration | |
3b9fdcd5 IC |
324 | 0 == single-ended |
325 | 1 == differential | |
326 | 2 == pseudo-differential | |
3c443716 | 327 | options[3] Analog input range configuration |
3b9fdcd5 IC |
328 | 0 == bipolar 5 (-5V -- +5V) |
329 | 1 == bipolar 2.5V (-2.5V -- +2.5V) | |
330 | 2 == unipolar 5V (0V -- +5V) | |
3c443716 | 331 | options[4] Analog output 0 range configuration |
3b9fdcd5 IC |
332 | 0 == bipolar 5 (-5V -- +5V) |
333 | 1 == bipolar 2.5V (-2.5V -- +2.5V) | |
334 | 2 == unipolar 5V (0V -- +5V) | |
3c443716 | 335 | options[5] Analog output 1 range configuration |
3b9fdcd5 IC |
336 | 0 == bipolar 5 (-5V -- +5V) |
337 | 1 == bipolar 2.5V (-2.5V -- +2.5V) | |
338 | 2 == unipolar 5V (0V -- +5V) | |
3c443716 DS |
339 | */ |
340 | ||
da91b269 | 341 | static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
3c443716 | 342 | { |
2696fb57 BP |
343 | /* int i, irq; */ |
344 | /* unsigned long irqs; */ | |
345 | /* long flags; */ | |
346 | ||
3c443716 | 347 | int ret; |
34c43922 | 348 | struct comedi_subdevice *s; |
3c443716 DS |
349 | unsigned long iobase; |
350 | ||
351 | iobase = it->options[0]; | |
352 | ||
3b9fdcd5 | 353 | printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase); |
3c443716 DS |
354 | |
355 | if (!request_region(iobase, DT2811_SIZE, driver_name)) { | |
3b9fdcd5 | 356 | printk(KERN_ERR "I/O port conflict\n"); |
3c443716 DS |
357 | return -EIO; |
358 | } | |
359 | ||
360 | dev->iobase = iobase; | |
361 | dev->board_name = this_board->name; | |
362 | ||
363 | #if 0 | |
364 | outb(0, dev->iobase + DT2811_ADCSR); | |
5f74ea14 | 365 | udelay(100); |
3c443716 DS |
366 | i = inb(dev->iobase + DT2811_ADDATLO); |
367 | i = inb(dev->iobase + DT2811_ADDATHI); | |
368 | #endif | |
369 | ||
370 | #if 0 | |
371 | irq = it->options[1]; | |
372 | if (irq < 0) { | |
373 | save_flags(flags); | |
374 | sti(); | |
375 | irqs = probe_irq_on(); | |
376 | ||
377 | outb(DT2811_CLRERROR | DT2811_INTENB, | |
0a85b6f0 | 378 | dev->iobase + DT2811_ADCSR); |
3c443716 DS |
379 | outb(0, dev->iobase + DT2811_ADGCR); |
380 | ||
5f74ea14 | 381 | udelay(100); |
3c443716 DS |
382 | |
383 | irq = probe_irq_off(irqs); | |
384 | restore_flags(flags); | |
385 | ||
3b9fdcd5 IC |
386 | /*outb(DT2811_CLRERROR|DT2811_INTENB, |
387 | dev->iobase+DT2811_ADCSR);*/ | |
3c443716 | 388 | |
3b9fdcd5 IC |
389 | if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR) |
390 | printk(KERN_ERR "error probing irq (bad)\n"); | |
3c443716 DS |
391 | dev->irq = 0; |
392 | if (irq > 0) { | |
393 | i = inb(dev->iobase + DT2811_ADDATLO); | |
394 | i = inb(dev->iobase + DT2811_ADDATHI); | |
3b9fdcd5 | 395 | printk(KERN_INFO "(irq = %d)\n", irq); |
5f74ea14 | 396 | ret = request_irq(irq, dt2811_interrupt, 0, |
0a85b6f0 | 397 | driver_name, dev); |
3c443716 DS |
398 | if (ret < 0) |
399 | return -EIO; | |
400 | dev->irq = irq; | |
401 | } else if (irq == 0) { | |
3b9fdcd5 | 402 | printk(KERN_INFO "(no irq)\n"); |
3c443716 | 403 | } else { |
3b9fdcd5 | 404 | printk(KERN_ERR "( multiple irq's -- this is bad! )\n"); |
3c443716 DS |
405 | } |
406 | } | |
407 | #endif | |
408 | ||
c3744138 BP |
409 | ret = alloc_subdevices(dev, 4); |
410 | if (ret < 0) | |
3c443716 | 411 | return ret; |
c3744138 BP |
412 | |
413 | ret = alloc_private(dev, sizeof(struct dt2811_private)); | |
414 | if (ret < 0) | |
3c443716 | 415 | return ret; |
c3744138 | 416 | |
3c443716 DS |
417 | switch (it->options[2]) { |
418 | case 0: | |
419 | devpriv->adc_mux = adc_singleended; | |
420 | break; | |
421 | case 1: | |
422 | devpriv->adc_mux = adc_diff; | |
423 | break; | |
424 | case 2: | |
425 | devpriv->adc_mux = adc_pseudo_diff; | |
426 | break; | |
427 | default: | |
428 | devpriv->adc_mux = adc_singleended; | |
429 | break; | |
430 | } | |
431 | switch (it->options[4]) { | |
432 | case 0: | |
433 | devpriv->dac_range[0] = dac_bipolar_5; | |
434 | break; | |
435 | case 1: | |
436 | devpriv->dac_range[0] = dac_bipolar_2_5; | |
437 | break; | |
438 | case 2: | |
439 | devpriv->dac_range[0] = dac_unipolar_5; | |
440 | break; | |
441 | default: | |
442 | devpriv->dac_range[0] = dac_bipolar_5; | |
443 | break; | |
444 | } | |
445 | switch (it->options[5]) { | |
446 | case 0: | |
447 | devpriv->dac_range[1] = dac_bipolar_5; | |
448 | break; | |
449 | case 1: | |
450 | devpriv->dac_range[1] = dac_bipolar_2_5; | |
451 | break; | |
452 | case 2: | |
453 | devpriv->dac_range[1] = dac_unipolar_5; | |
454 | break; | |
455 | default: | |
456 | devpriv->dac_range[1] = dac_bipolar_5; | |
457 | break; | |
458 | } | |
459 | ||
460 | s = dev->subdevices + 0; | |
461 | /* initialize the ADC subdevice */ | |
462 | s->type = COMEDI_SUBD_AI; | |
463 | s->subdev_flags = SDF_READABLE | SDF_GROUND; | |
464 | s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16; | |
465 | s->insn_read = dt2811_ai_insn; | |
466 | s->maxdata = 0xfff; | |
467 | switch (it->options[3]) { | |
468 | case 0: | |
469 | default: | |
470 | s->range_table = this_board->bip_5; | |
471 | break; | |
472 | case 1: | |
473 | s->range_table = this_board->bip_2_5; | |
474 | break; | |
475 | case 2: | |
476 | s->range_table = this_board->unip_5; | |
477 | break; | |
478 | } | |
479 | ||
480 | s = dev->subdevices + 1; | |
481 | /* ao subdevice */ | |
482 | s->type = COMEDI_SUBD_AO; | |
483 | s->subdev_flags = SDF_WRITABLE; | |
484 | s->n_chan = 2; | |
485 | s->insn_write = dt2811_ao_insn; | |
486 | s->insn_read = dt2811_ao_insn_read; | |
487 | s->maxdata = 0xfff; | |
488 | s->range_table_list = devpriv->range_type_list; | |
489 | devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]]; | |
490 | devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]]; | |
491 | ||
492 | s = dev->subdevices + 2; | |
493 | /* di subdevice */ | |
494 | s->type = COMEDI_SUBD_DI; | |
495 | s->subdev_flags = SDF_READABLE; | |
496 | s->n_chan = 8; | |
497 | s->insn_bits = dt2811_di_insn_bits; | |
498 | s->maxdata = 1; | |
499 | s->range_table = &range_digital; | |
500 | ||
501 | s = dev->subdevices + 3; | |
502 | /* do subdevice */ | |
503 | s->type = COMEDI_SUBD_DO; | |
504 | s->subdev_flags = SDF_WRITABLE; | |
505 | s->n_chan = 8; | |
506 | s->insn_bits = dt2811_do_insn_bits; | |
507 | s->maxdata = 1; | |
508 | s->state = 0; | |
509 | s->range_table = &range_digital; | |
510 | ||
511 | return 0; | |
512 | } | |
513 | ||
da91b269 | 514 | static int dt2811_detach(struct comedi_device *dev) |
3c443716 | 515 | { |
3b9fdcd5 | 516 | printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor); |
3c443716 | 517 | |
3b9fdcd5 | 518 | if (dev->irq) |
5f74ea14 | 519 | free_irq(dev->irq, dev); |
3b9fdcd5 | 520 | if (dev->iobase) |
3c443716 | 521 | release_region(dev->iobase, DT2811_SIZE); |
3c443716 DS |
522 | |
523 | return 0; | |
524 | } | |
525 | ||
da91b269 | 526 | static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 | 527 | struct comedi_insn *insn, unsigned int *data) |
3c443716 DS |
528 | { |
529 | int chan = CR_CHAN(insn->chanspec); | |
530 | int timeout = DT2811_TIMEOUT; | |
531 | int i; | |
532 | ||
533 | for (i = 0; i < insn->n; i++) { | |
534 | outb(chan, dev->iobase + DT2811_ADGCR); | |
535 | ||
536 | while (timeout | |
0a85b6f0 | 537 | && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) |
3c443716 DS |
538 | timeout--; |
539 | if (!timeout) | |
540 | return -ETIME; | |
541 | ||
542 | data[i] = inb(dev->iobase + DT2811_ADDATLO); | |
543 | data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; | |
544 | data[i] &= 0xfff; | |
545 | } | |
546 | ||
547 | return i; | |
548 | } | |
549 | ||
550 | #if 0 | |
551 | /* Wow. This is code from the Comedi stone age. But it hasn't been | |
552 | * replaced, so I'll let it stay. */ | |
3b9fdcd5 | 553 | int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig) |
3c443716 | 554 | { |
71b5f4f1 | 555 | struct comedi_device *dev = comedi_devices + minor; |
3c443716 DS |
556 | |
557 | if (adtrig->n < 1) | |
558 | return 0; | |
559 | dev->curadchan = adtrig->chan; | |
560 | switch (dev->i_admode) { | |
561 | case COMEDI_MDEMAND: | |
562 | dev->ntrig = adtrig->n - 1; | |
25985edc | 563 | /* not necessary */ |
3c443716 | 564 | /*printk("dt2811: AD soft trigger\n"); */ |
3b9fdcd5 IC |
565 | /*outb(DT2811_CLRERROR|DT2811_INTENB, |
566 | dev->iobase+DT2811_ADCSR); */ | |
3c443716 DS |
567 | outb(dev->curadchan, dev->iobase + DT2811_ADGCR); |
568 | do_gettimeofday(&trigtime); | |
569 | break; | |
570 | case COMEDI_MCONTS: | |
571 | dev->ntrig = adtrig->n; | |
572 | break; | |
573 | } | |
574 | ||
575 | return 0; | |
576 | } | |
577 | #endif | |
578 | ||
da91b269 | 579 | static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 | 580 | struct comedi_insn *insn, unsigned int *data) |
3c443716 DS |
581 | { |
582 | int i; | |
583 | int chan; | |
584 | ||
585 | chan = CR_CHAN(insn->chanspec); | |
586 | ||
587 | for (i = 0; i < insn->n; i++) { | |
588 | outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan); | |
589 | outb((data[i] >> 8) & 0xff, | |
0a85b6f0 | 590 | dev->iobase + DT2811_DADAT0HI + 2 * chan); |
3c443716 DS |
591 | devpriv->ao_readback[chan] = data[i]; |
592 | } | |
593 | ||
594 | return i; | |
595 | } | |
596 | ||
0a85b6f0 MT |
597 | static int dt2811_ao_insn_read(struct comedi_device *dev, |
598 | struct comedi_subdevice *s, | |
599 | struct comedi_insn *insn, unsigned int *data) | |
3c443716 DS |
600 | { |
601 | int i; | |
602 | int chan; | |
603 | ||
604 | chan = CR_CHAN(insn->chanspec); | |
605 | ||
3b9fdcd5 | 606 | for (i = 0; i < insn->n; i++) |
3c443716 | 607 | data[i] = devpriv->ao_readback[chan]; |
3c443716 DS |
608 | |
609 | return i; | |
610 | } | |
611 | ||
0a85b6f0 MT |
612 | static int dt2811_di_insn_bits(struct comedi_device *dev, |
613 | struct comedi_subdevice *s, | |
614 | struct comedi_insn *insn, unsigned int *data) | |
3c443716 DS |
615 | { |
616 | if (insn->n != 2) | |
617 | return -EINVAL; | |
618 | ||
619 | data[1] = inb(dev->iobase + DT2811_DIO); | |
620 | ||
621 | return 2; | |
622 | } | |
623 | ||
0a85b6f0 MT |
624 | static int dt2811_do_insn_bits(struct comedi_device *dev, |
625 | struct comedi_subdevice *s, | |
626 | struct comedi_insn *insn, unsigned int *data) | |
3c443716 DS |
627 | { |
628 | if (insn->n != 2) | |
629 | return -EINVAL; | |
630 | ||
631 | s->state &= ~data[0]; | |
632 | s->state |= data[0] & data[1]; | |
633 | outb(s->state, dev->iobase + DT2811_DIO); | |
634 | ||
635 | data[1] = s->state; | |
636 | ||
637 | return 2; | |
638 | } | |
90f703d3 AT |
639 | |
640 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
641 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
642 | MODULE_LICENSE("GPL"); |