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 | ||
242 | COMEDI_INITCLEANUP(driver_dt2811); | |
243 | ||
da91b269 | 244 | static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 | 245 | struct comedi_insn *insn, unsigned int *data); |
da91b269 | 246 | static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 MT |
247 | struct comedi_insn *insn, unsigned int *data); |
248 | static int dt2811_ao_insn_read(struct comedi_device *dev, | |
249 | struct comedi_subdevice *s, | |
250 | struct comedi_insn *insn, unsigned int *data); | |
251 | static int dt2811_di_insn_bits(struct comedi_device *dev, | |
252 | struct comedi_subdevice *s, | |
253 | struct comedi_insn *insn, unsigned int *data); | |
254 | static int dt2811_do_insn_bits(struct comedi_device *dev, | |
255 | struct comedi_subdevice *s, | |
256 | struct comedi_insn *insn, unsigned int *data); | |
3c443716 DS |
257 | |
258 | enum { card_2811_pgh, card_2811_pgl }; | |
d89da617 BP |
259 | |
260 | struct dt2811_private { | |
3c443716 DS |
261 | int ntrig; |
262 | int curadchan; | |
263 | enum { | |
264 | adc_singleended, adc_diff, adc_pseudo_diff | |
265 | } adc_mux; | |
266 | enum { | |
267 | dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5 | |
268 | } dac_range[2]; | |
9ced1de6 | 269 | const struct comedi_lrange *range_type_list[2]; |
790c5541 | 270 | unsigned int ao_readback[2]; |
d89da617 | 271 | }; |
3c443716 | 272 | |
d89da617 | 273 | #define devpriv ((struct dt2811_private *)dev->private) |
3c443716 | 274 | |
9ced1de6 | 275 | static const struct comedi_lrange *dac_range_types[] = { |
3c443716 DS |
276 | &range_bipolar5, |
277 | &range_bipolar2_5, | |
278 | &range_unipolar5 | |
279 | }; | |
280 | ||
281 | #define DT2811_TIMEOUT 5 | |
282 | ||
283 | #if 0 | |
70265d24 | 284 | static irqreturn_t dt2811_interrupt(int irq, void *d) |
3c443716 DS |
285 | { |
286 | int lo, hi; | |
287 | int data; | |
71b5f4f1 | 288 | struct comedi_device *dev = d; |
3c443716 DS |
289 | |
290 | if (!dev->attached) { | |
291 | comedi_error(dev, "spurious interrupt"); | |
292 | return IRQ_HANDLED; | |
293 | } | |
294 | ||
295 | lo = inb(dev->iobase + DT2811_ADDATLO); | |
296 | hi = inb(dev->iobase + DT2811_ADDATHI); | |
297 | ||
298 | data = lo + (hi << 8); | |
299 | ||
300 | if (!(--devpriv->ntrig)) { | |
301 | /* how to turn off acquisition */ | |
302 | s->async->events |= COMEDI_SB_EOA; | |
303 | } | |
304 | comedi_event(dev, s); | |
305 | return IRQ_HANDLED; | |
306 | } | |
307 | #endif | |
308 | ||
309 | /* | |
310 | options[0] Board base address | |
311 | options[1] IRQ | |
312 | options[2] Input configuration | |
3b9fdcd5 IC |
313 | 0 == single-ended |
314 | 1 == differential | |
315 | 2 == pseudo-differential | |
3c443716 | 316 | options[3] Analog input range configuration |
3b9fdcd5 IC |
317 | 0 == bipolar 5 (-5V -- +5V) |
318 | 1 == bipolar 2.5V (-2.5V -- +2.5V) | |
319 | 2 == unipolar 5V (0V -- +5V) | |
3c443716 | 320 | options[4] Analog output 0 range configuration |
3b9fdcd5 IC |
321 | 0 == bipolar 5 (-5V -- +5V) |
322 | 1 == bipolar 2.5V (-2.5V -- +2.5V) | |
323 | 2 == unipolar 5V (0V -- +5V) | |
3c443716 | 324 | options[5] Analog output 1 range configuration |
3b9fdcd5 IC |
325 | 0 == bipolar 5 (-5V -- +5V) |
326 | 1 == bipolar 2.5V (-2.5V -- +2.5V) | |
327 | 2 == unipolar 5V (0V -- +5V) | |
3c443716 DS |
328 | */ |
329 | ||
da91b269 | 330 | static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
3c443716 | 331 | { |
2696fb57 BP |
332 | /* int i, irq; */ |
333 | /* unsigned long irqs; */ | |
334 | /* long flags; */ | |
335 | ||
3c443716 | 336 | int ret; |
34c43922 | 337 | struct comedi_subdevice *s; |
3c443716 DS |
338 | unsigned long iobase; |
339 | ||
340 | iobase = it->options[0]; | |
341 | ||
3b9fdcd5 | 342 | printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase); |
3c443716 DS |
343 | |
344 | if (!request_region(iobase, DT2811_SIZE, driver_name)) { | |
3b9fdcd5 | 345 | printk(KERN_ERR "I/O port conflict\n"); |
3c443716 DS |
346 | return -EIO; |
347 | } | |
348 | ||
349 | dev->iobase = iobase; | |
350 | dev->board_name = this_board->name; | |
351 | ||
352 | #if 0 | |
353 | outb(0, dev->iobase + DT2811_ADCSR); | |
5f74ea14 | 354 | udelay(100); |
3c443716 DS |
355 | i = inb(dev->iobase + DT2811_ADDATLO); |
356 | i = inb(dev->iobase + DT2811_ADDATHI); | |
357 | #endif | |
358 | ||
359 | #if 0 | |
360 | irq = it->options[1]; | |
361 | if (irq < 0) { | |
362 | save_flags(flags); | |
363 | sti(); | |
364 | irqs = probe_irq_on(); | |
365 | ||
366 | outb(DT2811_CLRERROR | DT2811_INTENB, | |
0a85b6f0 | 367 | dev->iobase + DT2811_ADCSR); |
3c443716 DS |
368 | outb(0, dev->iobase + DT2811_ADGCR); |
369 | ||
5f74ea14 | 370 | udelay(100); |
3c443716 DS |
371 | |
372 | irq = probe_irq_off(irqs); | |
373 | restore_flags(flags); | |
374 | ||
3b9fdcd5 IC |
375 | /*outb(DT2811_CLRERROR|DT2811_INTENB, |
376 | dev->iobase+DT2811_ADCSR);*/ | |
3c443716 | 377 | |
3b9fdcd5 IC |
378 | if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR) |
379 | printk(KERN_ERR "error probing irq (bad)\n"); | |
3c443716 DS |
380 | dev->irq = 0; |
381 | if (irq > 0) { | |
382 | i = inb(dev->iobase + DT2811_ADDATLO); | |
383 | i = inb(dev->iobase + DT2811_ADDATHI); | |
3b9fdcd5 | 384 | printk(KERN_INFO "(irq = %d)\n", irq); |
5f74ea14 | 385 | ret = request_irq(irq, dt2811_interrupt, 0, |
0a85b6f0 | 386 | driver_name, dev); |
3c443716 DS |
387 | if (ret < 0) |
388 | return -EIO; | |
389 | dev->irq = irq; | |
390 | } else if (irq == 0) { | |
3b9fdcd5 | 391 | printk(KERN_INFO "(no irq)\n"); |
3c443716 | 392 | } else { |
3b9fdcd5 | 393 | printk(KERN_ERR "( multiple irq's -- this is bad! )\n"); |
3c443716 DS |
394 | } |
395 | } | |
396 | #endif | |
397 | ||
c3744138 BP |
398 | ret = alloc_subdevices(dev, 4); |
399 | if (ret < 0) | |
3c443716 | 400 | return ret; |
c3744138 BP |
401 | |
402 | ret = alloc_private(dev, sizeof(struct dt2811_private)); | |
403 | if (ret < 0) | |
3c443716 | 404 | return ret; |
c3744138 | 405 | |
3c443716 DS |
406 | switch (it->options[2]) { |
407 | case 0: | |
408 | devpriv->adc_mux = adc_singleended; | |
409 | break; | |
410 | case 1: | |
411 | devpriv->adc_mux = adc_diff; | |
412 | break; | |
413 | case 2: | |
414 | devpriv->adc_mux = adc_pseudo_diff; | |
415 | break; | |
416 | default: | |
417 | devpriv->adc_mux = adc_singleended; | |
418 | break; | |
419 | } | |
420 | switch (it->options[4]) { | |
421 | case 0: | |
422 | devpriv->dac_range[0] = dac_bipolar_5; | |
423 | break; | |
424 | case 1: | |
425 | devpriv->dac_range[0] = dac_bipolar_2_5; | |
426 | break; | |
427 | case 2: | |
428 | devpriv->dac_range[0] = dac_unipolar_5; | |
429 | break; | |
430 | default: | |
431 | devpriv->dac_range[0] = dac_bipolar_5; | |
432 | break; | |
433 | } | |
434 | switch (it->options[5]) { | |
435 | case 0: | |
436 | devpriv->dac_range[1] = dac_bipolar_5; | |
437 | break; | |
438 | case 1: | |
439 | devpriv->dac_range[1] = dac_bipolar_2_5; | |
440 | break; | |
441 | case 2: | |
442 | devpriv->dac_range[1] = dac_unipolar_5; | |
443 | break; | |
444 | default: | |
445 | devpriv->dac_range[1] = dac_bipolar_5; | |
446 | break; | |
447 | } | |
448 | ||
449 | s = dev->subdevices + 0; | |
450 | /* initialize the ADC subdevice */ | |
451 | s->type = COMEDI_SUBD_AI; | |
452 | s->subdev_flags = SDF_READABLE | SDF_GROUND; | |
453 | s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16; | |
454 | s->insn_read = dt2811_ai_insn; | |
455 | s->maxdata = 0xfff; | |
456 | switch (it->options[3]) { | |
457 | case 0: | |
458 | default: | |
459 | s->range_table = this_board->bip_5; | |
460 | break; | |
461 | case 1: | |
462 | s->range_table = this_board->bip_2_5; | |
463 | break; | |
464 | case 2: | |
465 | s->range_table = this_board->unip_5; | |
466 | break; | |
467 | } | |
468 | ||
469 | s = dev->subdevices + 1; | |
470 | /* ao subdevice */ | |
471 | s->type = COMEDI_SUBD_AO; | |
472 | s->subdev_flags = SDF_WRITABLE; | |
473 | s->n_chan = 2; | |
474 | s->insn_write = dt2811_ao_insn; | |
475 | s->insn_read = dt2811_ao_insn_read; | |
476 | s->maxdata = 0xfff; | |
477 | s->range_table_list = devpriv->range_type_list; | |
478 | devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]]; | |
479 | devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]]; | |
480 | ||
481 | s = dev->subdevices + 2; | |
482 | /* di subdevice */ | |
483 | s->type = COMEDI_SUBD_DI; | |
484 | s->subdev_flags = SDF_READABLE; | |
485 | s->n_chan = 8; | |
486 | s->insn_bits = dt2811_di_insn_bits; | |
487 | s->maxdata = 1; | |
488 | s->range_table = &range_digital; | |
489 | ||
490 | s = dev->subdevices + 3; | |
491 | /* do subdevice */ | |
492 | s->type = COMEDI_SUBD_DO; | |
493 | s->subdev_flags = SDF_WRITABLE; | |
494 | s->n_chan = 8; | |
495 | s->insn_bits = dt2811_do_insn_bits; | |
496 | s->maxdata = 1; | |
497 | s->state = 0; | |
498 | s->range_table = &range_digital; | |
499 | ||
500 | return 0; | |
501 | } | |
502 | ||
da91b269 | 503 | static int dt2811_detach(struct comedi_device *dev) |
3c443716 | 504 | { |
3b9fdcd5 | 505 | printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor); |
3c443716 | 506 | |
3b9fdcd5 | 507 | if (dev->irq) |
5f74ea14 | 508 | free_irq(dev->irq, dev); |
3b9fdcd5 | 509 | if (dev->iobase) |
3c443716 | 510 | release_region(dev->iobase, DT2811_SIZE); |
3c443716 DS |
511 | |
512 | return 0; | |
513 | } | |
514 | ||
da91b269 | 515 | static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 | 516 | struct comedi_insn *insn, unsigned int *data) |
3c443716 DS |
517 | { |
518 | int chan = CR_CHAN(insn->chanspec); | |
519 | int timeout = DT2811_TIMEOUT; | |
520 | int i; | |
521 | ||
522 | for (i = 0; i < insn->n; i++) { | |
523 | outb(chan, dev->iobase + DT2811_ADGCR); | |
524 | ||
525 | while (timeout | |
0a85b6f0 | 526 | && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) |
3c443716 DS |
527 | timeout--; |
528 | if (!timeout) | |
529 | return -ETIME; | |
530 | ||
531 | data[i] = inb(dev->iobase + DT2811_ADDATLO); | |
532 | data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; | |
533 | data[i] &= 0xfff; | |
534 | } | |
535 | ||
536 | return i; | |
537 | } | |
538 | ||
539 | #if 0 | |
540 | /* Wow. This is code from the Comedi stone age. But it hasn't been | |
541 | * replaced, so I'll let it stay. */ | |
3b9fdcd5 | 542 | int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig) |
3c443716 | 543 | { |
71b5f4f1 | 544 | struct comedi_device *dev = comedi_devices + minor; |
3c443716 DS |
545 | |
546 | if (adtrig->n < 1) | |
547 | return 0; | |
548 | dev->curadchan = adtrig->chan; | |
549 | switch (dev->i_admode) { | |
550 | case COMEDI_MDEMAND: | |
551 | dev->ntrig = adtrig->n - 1; | |
3b9fdcd5 | 552 | /* not neccessary */ |
3c443716 | 553 | /*printk("dt2811: AD soft trigger\n"); */ |
3b9fdcd5 IC |
554 | /*outb(DT2811_CLRERROR|DT2811_INTENB, |
555 | dev->iobase+DT2811_ADCSR); */ | |
3c443716 DS |
556 | outb(dev->curadchan, dev->iobase + DT2811_ADGCR); |
557 | do_gettimeofday(&trigtime); | |
558 | break; | |
559 | case COMEDI_MCONTS: | |
560 | dev->ntrig = adtrig->n; | |
561 | break; | |
562 | } | |
563 | ||
564 | return 0; | |
565 | } | |
566 | #endif | |
567 | ||
da91b269 | 568 | static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
0a85b6f0 | 569 | struct comedi_insn *insn, unsigned int *data) |
3c443716 DS |
570 | { |
571 | int i; | |
572 | int chan; | |
573 | ||
574 | chan = CR_CHAN(insn->chanspec); | |
575 | ||
576 | for (i = 0; i < insn->n; i++) { | |
577 | outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan); | |
578 | outb((data[i] >> 8) & 0xff, | |
0a85b6f0 | 579 | dev->iobase + DT2811_DADAT0HI + 2 * chan); |
3c443716 DS |
580 | devpriv->ao_readback[chan] = data[i]; |
581 | } | |
582 | ||
583 | return i; | |
584 | } | |
585 | ||
0a85b6f0 MT |
586 | static int dt2811_ao_insn_read(struct comedi_device *dev, |
587 | struct comedi_subdevice *s, | |
588 | struct comedi_insn *insn, unsigned int *data) | |
3c443716 DS |
589 | { |
590 | int i; | |
591 | int chan; | |
592 | ||
593 | chan = CR_CHAN(insn->chanspec); | |
594 | ||
3b9fdcd5 | 595 | for (i = 0; i < insn->n; i++) |
3c443716 | 596 | data[i] = devpriv->ao_readback[chan]; |
3c443716 DS |
597 | |
598 | return i; | |
599 | } | |
600 | ||
0a85b6f0 MT |
601 | static int dt2811_di_insn_bits(struct comedi_device *dev, |
602 | struct comedi_subdevice *s, | |
603 | struct comedi_insn *insn, unsigned int *data) | |
3c443716 DS |
604 | { |
605 | if (insn->n != 2) | |
606 | return -EINVAL; | |
607 | ||
608 | data[1] = inb(dev->iobase + DT2811_DIO); | |
609 | ||
610 | return 2; | |
611 | } | |
612 | ||
0a85b6f0 MT |
613 | static int dt2811_do_insn_bits(struct comedi_device *dev, |
614 | struct comedi_subdevice *s, | |
615 | struct comedi_insn *insn, unsigned int *data) | |
3c443716 DS |
616 | { |
617 | if (insn->n != 2) | |
618 | return -EINVAL; | |
619 | ||
620 | s->state &= ~data[0]; | |
621 | s->state |= data[0] & data[1]; | |
622 | outb(s->state, dev->iobase + DT2811_DIO); | |
623 | ||
624 | data[1] = s->state; | |
625 | ||
626 | return 2; | |
627 | } | |
90f703d3 AT |
628 | |
629 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
630 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
631 | MODULE_LICENSE("GPL"); |