staging: comedi: comedi_test: simplify time since last AI scan
[deliverable/linux.git] / drivers / staging / comedi / drivers / das800.c
CommitLineData
3726e56b
FMH
1/*
2 comedi/drivers/das800.c
3 Driver for Keitley das800 series boards and compatibles
4 Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
5
6 COMEDI - Linux Control and Measurement Device Interface
7 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
3726e56b
FMH
18*/
19/*
20Driver: das800
21Description: Keithley Metrabyte DAS800 (& compatibles)
22Author: Frank Mori Hess <fmhess@users.sourceforge.net>
23Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801),
24 DAS-802 (das-802),
25 [Measurement Computing] CIO-DAS800 (cio-das800),
26 CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802),
27 CIO-DAS802/16 (cio-das802/16)
28Status: works, cio-das802/16 untested - email me if you have tested it
29
30Configuration options:
31 [0] - I/O port base address
32 [1] - IRQ (optional, required for timed or externally triggered conversions)
33
34Notes:
35 IRQ can be omitted, although the cmd interface will not work without it.
36
37 All entries in the channel/gain list must use the same gain and be
38 consecutive channels counting upwards in channel number (these are
39 hardware limitations.)
40
41 I've never tested the gain setting stuff since I only have a
42 DAS-800 board with fixed gain.
43
44 The cio-das802/16 does not have a fifo-empty status bit! Therefore
45 only fifo-half-full transfers are possible with this card.
3726e56b
FMH
46
47cmd triggers supported:
48 start_src: TRIG_NOW | TRIG_EXT
49 scan_begin_src: TRIG_FOLLOW
50 scan_end_src: TRIG_COUNT
51 convert_src: TRIG_TIMER | TRIG_EXT
52 stop_src: TRIG_NONE | TRIG_COUNT
3726e56b
FMH
53*/
54
ce157f80 55#include <linux/module.h>
25436dc9 56#include <linux/interrupt.h>
3726e56b
FMH
57#include <linux/delay.h>
58
e4690dec
HS
59#include "../comedidev.h"
60
e4690dec 61#include "comedi_8254.h"
3726e56b 62
2696fb57 63#define N_CHAN_AI 8 /* number of analog input channels */
3726e56b
FMH
64
65/* Registers for the das800 */
66
67#define DAS800_LSB 0
68#define FIFO_EMPTY 0x1
69#define FIFO_OVF 0x2
70#define DAS800_MSB 1
71#define DAS800_CONTROL1 2
72#define CONTROL1_INTE 0x8
73#define DAS800_CONV_CONTROL 2
74#define ITE 0x1
75#define CASC 0x2
76#define DTEN 0x4
77#define IEOC 0x8
78#define EACS 0x10
79#define CONV_HCEN 0x80
80#define DAS800_SCAN_LIMITS 2
81#define DAS800_STATUS 2
82#define IRQ 0x8
83#define BUSY 0x80
84#define DAS800_GAIN 3
eca7cf72
HS
85#define CIO_FFOV 0x8 /* cio-das802/16 fifo overflow */
86#define CIO_ENHF 0x90 /* cio-das802/16 fifo half full int ena */
3726e56b
FMH
87#define CONTROL1 0x80
88#define CONV_CONTROL 0xa0
89#define SCAN_LIMITS 0xc0
90#define ID 0xe0
91#define DAS800_8254 4
92#define DAS800_STATUS2 7
93#define STATUS2_HCEN 0x80
94#define STATUS2_INTE 0X20
95#define DAS800_ID 7
96
7f340859
HS
97#define DAS802_16_HALF_FIFO_SZ 128
98
febc2ed6 99struct das800_board {
3726e56b
FMH
100 const char *name;
101 int ai_speed;
9ced1de6 102 const struct comedi_lrange *ai_range;
3726e56b 103 int resolution;
febc2ed6 104};
3726e56b 105
9ced1de6 106static const struct comedi_lrange range_das801_ai = {
b678075f
HS
107 9, {
108 BIP_RANGE(5),
109 BIP_RANGE(10),
110 UNI_RANGE(10),
111 BIP_RANGE(0.5),
112 UNI_RANGE(1),
113 BIP_RANGE(0.05),
114 UNI_RANGE(0.1),
115 BIP_RANGE(0.01),
116 UNI_RANGE(0.02)
117 }
3726e56b
FMH
118};
119
9ced1de6 120static const struct comedi_lrange range_cio_das801_ai = {
b678075f
HS
121 9, {
122 BIP_RANGE(5),
123 BIP_RANGE(10),
124 UNI_RANGE(10),
125 BIP_RANGE(0.5),
126 UNI_RANGE(1),
127 BIP_RANGE(0.05),
128 UNI_RANGE(0.1),
129 BIP_RANGE(0.005),
130 UNI_RANGE(0.01)
131 }
3726e56b
FMH
132};
133
9ced1de6 134static const struct comedi_lrange range_das802_ai = {
b678075f
HS
135 9, {
136 BIP_RANGE(5),
137 BIP_RANGE(10),
138 UNI_RANGE(10),
139 BIP_RANGE(2.5),
140 UNI_RANGE(5),
141 BIP_RANGE(1.25),
142 UNI_RANGE(2.5),
143 BIP_RANGE(0.625),
144 UNI_RANGE(1.25)
145 }
3726e56b
FMH
146};
147
9ced1de6 148static const struct comedi_lrange range_das80216_ai = {
b678075f
HS
149 8, {
150 BIP_RANGE(10),
151 UNI_RANGE(10),
152 BIP_RANGE(5),
153 UNI_RANGE(5),
154 BIP_RANGE(2.5),
155 UNI_RANGE(2.5),
156 BIP_RANGE(1.25),
157 UNI_RANGE(1.25)
158 }
3726e56b
FMH
159};
160
c1a59171
HS
161enum das800_boardinfo {
162 BOARD_DAS800,
163 BOARD_CIODAS800,
164 BOARD_DAS801,
165 BOARD_CIODAS801,
166 BOARD_DAS802,
167 BOARD_CIODAS802,
168 BOARD_CIODAS80216,
169};
3726e56b 170
febc2ed6 171static const struct das800_board das800_boards[] = {
c1a59171
HS
172 [BOARD_DAS800] = {
173 .name = "das-800",
174 .ai_speed = 25000,
175 .ai_range = &range_bipolar5,
176 .resolution = 12,
177 },
178 [BOARD_CIODAS800] = {
179 .name = "cio-das800",
180 .ai_speed = 20000,
181 .ai_range = &range_bipolar5,
182 .resolution = 12,
183 },
184 [BOARD_DAS801] = {
185 .name = "das-801",
186 .ai_speed = 25000,
187 .ai_range = &range_das801_ai,
188 .resolution = 12,
189 },
190 [BOARD_CIODAS801] = {
191 .name = "cio-das801",
192 .ai_speed = 20000,
193 .ai_range = &range_cio_das801_ai,
194 .resolution = 12,
195 },
196 [BOARD_DAS802] = {
197 .name = "das-802",
198 .ai_speed = 25000,
199 .ai_range = &range_das802_ai,
200 .resolution = 12,
201 },
202 [BOARD_CIODAS802] = {
203 .name = "cio-das802",
204 .ai_speed = 20000,
205 .ai_range = &range_das802_ai,
206 .resolution = 12,
207 },
208 [BOARD_CIODAS80216] = {
209 .name = "cio-das802/16",
210 .ai_speed = 10000,
211 .ai_range = &range_das80216_ai,
212 .resolution = 16,
213 },
3726e56b
FMH
214};
215
938f185d 216struct das800_private {
ad5774fc 217 unsigned int do_bits; /* digital output bits */
938f185d 218};
3726e56b 219
0a8fc089
HS
220static void das800_ind_write(struct comedi_device *dev,
221 unsigned val, unsigned reg)
222{
223 /*
224 * Select dev->iobase + 2 to be desired register
225 * then write to that register.
226 */
227 outb(reg, dev->iobase + DAS800_GAIN);
228 outb(val, dev->iobase + 2);
229}
230
231static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg)
232{
233 /*
234 * Select dev->iobase + 7 to be desired register
235 * then read from that register.
236 */
237 outb(reg, dev->iobase + DAS800_GAIN);
238 return inb(dev->iobase + 7);
239}
240
57d1ebf7 241static void das800_enable(struct comedi_device *dev)
3726e56b 242{
4f3aa186 243 const struct das800_board *board = dev->board_ptr;
9a1a6cf8 244 struct das800_private *devpriv = dev->private;
3726e56b 245 unsigned long irq_flags;
9a1a6cf8 246
5f74ea14 247 spin_lock_irqsave(&dev->spinlock, irq_flags);
2696fb57 248 /* enable fifo-half full interrupts for cio-das802/16 */
4f3aa186 249 if (board->resolution == 16)
3726e56b 250 outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
0a8fc089
HS
251 /* enable hardware triggering */
252 das800_ind_write(dev, CONV_HCEN, CONV_CONTROL);
253 /* enable card's interrupt */
254 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
5f74ea14 255 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3726e56b
FMH
256}
257
57d1ebf7 258static void das800_disable(struct comedi_device *dev)
3726e56b
FMH
259{
260 unsigned long irq_flags;
0a8fc089 261
5f74ea14 262 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089
HS
263 /* disable hardware triggering of conversions */
264 das800_ind_write(dev, 0x0, CONV_CONTROL);
5f74ea14 265 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3726e56b
FMH
266}
267
fe9b0850
HS
268static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
269{
57d1ebf7 270 das800_disable(dev);
fe9b0850
HS
271 return 0;
272}
273
1626657f
HS
274static int das800_ai_check_chanlist(struct comedi_device *dev,
275 struct comedi_subdevice *s,
276 struct comedi_cmd *cmd)
277{
278 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
279 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
280 int i;
281
282 for (i = 1; i < cmd->chanlist_len; i++) {
283 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
284 unsigned int range = CR_RANGE(cmd->chanlist[i]);
285
286 if (chan != (chan0 + i) % s->n_chan) {
287 dev_dbg(dev->class_dev,
288 "chanlist must be consecutive, counting upwards\n");
289 return -EINVAL;
290 }
291
292 if (range != range0) {
293 dev_dbg(dev->class_dev,
294 "chanlist must all have the same gain\n");
295 return -EINVAL;
296 }
297 }
298
299 return 0;
300}
301
0a85b6f0
MT
302static int das800_ai_do_cmdtest(struct comedi_device *dev,
303 struct comedi_subdevice *s,
304 struct comedi_cmd *cmd)
3726e56b 305{
4f3aa186 306 const struct das800_board *board = dev->board_ptr;
3726e56b 307 int err = 0;
3726e56b 308
27020ffe 309 /* Step 1 : check if triggers are trivially valid */
3726e56b 310
5519108b
IA
311 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
312 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
313 err |= comedi_check_trigger_src(&cmd->convert_src,
314 TRIG_TIMER | TRIG_EXT);
315 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
316 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
3726e56b
FMH
317
318 if (err)
319 return 1;
320
27020ffe 321 /* Step 2a : make sure trigger sources are unique */
3726e56b 322
5519108b
IA
323 err |= comedi_check_trigger_is_unique(cmd->start_src);
324 err |= comedi_check_trigger_is_unique(cmd->convert_src);
325 err |= comedi_check_trigger_is_unique(cmd->stop_src);
27020ffe
HS
326
327 /* Step 2b : and mutually compatible */
3726e56b
FMH
328
329 if (err)
330 return 2;
331
50b825ff 332 /* Step 3: check if arguments are trivially valid */
3726e56b 333
5519108b 334 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
50b825ff 335
5519108b
IA
336 if (cmd->convert_src == TRIG_TIMER) {
337 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
4f3aa186 338 board->ai_speed);
5519108b 339 }
50b825ff 340
5519108b
IA
341 err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1);
342 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
343 cmd->chanlist_len);
50b825ff
HS
344
345 if (cmd->stop_src == TRIG_COUNT)
5519108b 346 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
50b825ff 347 else /* TRIG_NONE */
5519108b 348 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
3726e56b
FMH
349
350 if (err)
351 return 3;
352
353 /* step 4: fix up any arguments */
354
355 if (cmd->convert_src == TRIG_TIMER) {
e4690dec
HS
356 unsigned int arg = cmd->convert_arg;
357
358 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
5519108b 359 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
3726e56b
FMH
360 }
361
362 if (err)
363 return 4;
364
1626657f
HS
365 /* Step 5: check channel list if it exists */
366 if (cmd->chanlist && cmd->chanlist_len > 0)
367 err |= das800_ai_check_chanlist(dev, s, cmd);
3726e56b
FMH
368
369 if (err)
370 return 5;
371
372 return 0;
373}
374
0a85b6f0
MT
375static int das800_ai_do_cmd(struct comedi_device *dev,
376 struct comedi_subdevice *s)
3726e56b 377{
4f3aa186 378 const struct das800_board *board = dev->board_ptr;
d24160f8 379 struct comedi_async *async = s->async;
8ffffae6
HS
380 struct comedi_cmd *cmd = &async->cmd;
381 unsigned int gain = CR_RANGE(cmd->chanlist[0]);
382 unsigned int start_chan = CR_CHAN(cmd->chanlist[0]);
383 unsigned int end_chan = (start_chan + cmd->chanlist_len - 1) % 8;
d24160f8 384 unsigned int scan_chans = (end_chan << 3) | start_chan;
3726e56b
FMH
385 int conv_bits;
386 unsigned long irq_flags;
3726e56b 387
57d1ebf7 388 das800_disable(dev);
3726e56b 389
5f74ea14 390 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 391 /* set scan limits */
d24160f8 392 das800_ind_write(dev, scan_chans, SCAN_LIMITS);
5f74ea14 393 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3726e56b
FMH
394
395 /* set gain */
4f3aa186 396 if (board->resolution == 12 && gain > 0)
3726e56b
FMH
397 gain += 0x7;
398 gain &= 0xf;
399 outb(gain, dev->iobase + DAS800_GAIN);
400
3726e56b
FMH
401 /* enable auto channel scan, send interrupts on end of conversion
402 * and set clock source to internal or external
403 */
404 conv_bits = 0;
405 conv_bits |= EACS | IEOC;
8ffffae6 406 if (cmd->start_src == TRIG_EXT)
3726e56b 407 conv_bits |= DTEN;
8ffffae6 408 if (cmd->convert_src == TRIG_TIMER) {
3726e56b 409 conv_bits |= CASC | ITE;
e4690dec
HS
410 comedi_8254_update_divisors(dev->pacer);
411 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
3726e56b
FMH
412 }
413
5f74ea14 414 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 415 das800_ind_write(dev, conv_bits, CONV_CONTROL);
5f74ea14 416 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
0a8fc089 417
57d1ebf7 418 das800_enable(dev);
3726e56b
FMH
419 return 0;
420}
421
b4780a3a
HS
422static unsigned int das800_ai_get_sample(struct comedi_device *dev)
423{
424 unsigned int lsb = inb(dev->iobase + DAS800_LSB);
425 unsigned int msb = inb(dev->iobase + DAS800_MSB);
426
427 return (msb << 8) | lsb;
428}
429
fe9b0850
HS
430static irqreturn_t das800_interrupt(int irq, void *d)
431{
fe9b0850 432 struct comedi_device *dev = d;
fe9b0850 433 struct das800_private *devpriv = dev->private;
7f340859 434 struct comedi_subdevice *s = dev->read_subdev;
9dad12fe
HS
435 struct comedi_async *async;
436 struct comedi_cmd *cmd;
fe9b0850 437 unsigned long irq_flags;
7f340859
HS
438 unsigned int status;
439 unsigned int val;
440 bool fifo_empty;
441 bool fifo_overflow;
442 int i;
fe9b0850
HS
443
444 status = inb(dev->iobase + DAS800_STATUS);
fe9b0850
HS
445 if (!(status & IRQ))
446 return IRQ_NONE;
7f340859 447 if (!dev->attached)
fe9b0850
HS
448 return IRQ_HANDLED;
449
9dad12fe
HS
450 async = s->async;
451 cmd = &async->cmd;
452
fe9b0850 453 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 454 status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN;
7f340859
HS
455 /*
456 * Don't release spinlock yet since we want to make sure
457 * no one else disables hardware conversions.
458 */
459
460 /* if hardware conversions are not enabled, then quit */
fe9b0850
HS
461 if (status == 0) {
462 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
463 return IRQ_HANDLED;
464 }
465
7f340859
HS
466 for (i = 0; i < DAS802_16_HALF_FIFO_SZ; i++) {
467 val = das800_ai_get_sample(dev);
468 if (s->maxdata == 0x0fff) {
469 fifo_empty = !!(val & FIFO_EMPTY);
470 fifo_overflow = !!(val & FIFO_OVF);
fe9b0850 471 } else {
7f340859
HS
472 /* cio-das802/16 has no fifo empty status bit */
473 fifo_empty = false;
474 fifo_overflow = !!(inb(dev->iobase + DAS800_GAIN) &
475 CIO_FFOV);
fe9b0850 476 }
7f340859 477 if (fifo_empty || fifo_overflow)
fe9b0850 478 break;
7f340859
HS
479
480 if (s->maxdata == 0x0fff)
481 val >>= 4; /* 12-bit sample */
482
5e62863a
HS
483 val &= s->maxdata;
484 comedi_buf_write_samples(s, &val, 1);
485
486 if (cmd->stop_src == TRIG_COUNT &&
487 async->scans_done >= cmd->stop_arg) {
488 async->events |= COMEDI_CB_EOA;
489 break;
fe9b0850
HS
490 }
491 }
7f340859 492
fe9b0850
HS
493 if (fifo_overflow) {
494 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3e6cb74f 495 async->events |= COMEDI_CB_ERROR;
837a1264 496 comedi_handle_events(dev, s);
fe9b0850
HS
497 return IRQ_HANDLED;
498 }
7f340859 499
5e62863a
HS
500 if (!(async->events & COMEDI_CB_CANCEL_MASK)) {
501 /*
502 * Re-enable card's interrupt.
503 * We already have spinlock, so indirect addressing is safe
504 */
0a8fc089
HS
505 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
506 CONTROL1);
fe9b0850 507 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
fe9b0850 508 } else {
7f340859 509 /* otherwise, stop taking data */
fe9b0850 510 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
57d1ebf7 511 das800_disable(dev);
fe9b0850 512 }
837a1264 513 comedi_handle_events(dev, s);
fe9b0850
HS
514 return IRQ_HANDLED;
515}
516
90bc68ec
HS
517static int das800_ai_eoc(struct comedi_device *dev,
518 struct comedi_subdevice *s,
519 struct comedi_insn *insn,
520 unsigned long context)
b4780a3a 521{
90bc68ec 522 unsigned int status;
b4780a3a 523
90bc68ec
HS
524 status = inb(dev->iobase + DAS800_STATUS);
525 if ((status & BUSY) == 0)
526 return 0;
527 return -EBUSY;
b4780a3a
HS
528}
529
d7427345
HS
530static int das800_ai_insn_read(struct comedi_device *dev,
531 struct comedi_subdevice *s,
532 struct comedi_insn *insn,
533 unsigned int *data)
3726e56b 534{
9a1a6cf8 535 struct das800_private *devpriv = dev->private;
b4780a3a
HS
536 unsigned int chan = CR_CHAN(insn->chanspec);
537 unsigned int range = CR_RANGE(insn->chanspec);
3726e56b 538 unsigned long irq_flags;
b4780a3a
HS
539 unsigned int val;
540 int ret;
541 int i;
3726e56b 542
57d1ebf7 543 das800_disable(dev);
3726e56b
FMH
544
545 /* set multiplexer */
5f74ea14 546 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 547 das800_ind_write(dev, chan | devpriv->do_bits, CONTROL1);
5f74ea14 548 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3726e56b
FMH
549
550 /* set gain / range */
b4780a3a 551 if (s->maxdata == 0x0fff && range)
3726e56b
FMH
552 range += 0x7;
553 range &= 0xf;
554 outb(range, dev->iobase + DAS800_GAIN);
555
5f74ea14 556 udelay(5);
3726e56b 557
b4780a3a 558 for (i = 0; i < insn->n; i++) {
3726e56b
FMH
559 /* trigger conversion */
560 outb_p(0, dev->iobase + DAS800_MSB);
561
90bc68ec 562 ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0);
b4780a3a
HS
563 if (ret)
564 return ret;
565
566 val = das800_ai_get_sample(dev);
567 if (s->maxdata == 0x0fff)
568 val >>= 4; /* 12-bit sample */
569 data[i] = val & s->maxdata;
3726e56b
FMH
570 }
571
b4780a3a 572 return insn->n;
3726e56b
FMH
573}
574
d7427345
HS
575static int das800_di_insn_bits(struct comedi_device *dev,
576 struct comedi_subdevice *s,
577 struct comedi_insn *insn,
578 unsigned int *data)
3726e56b 579{
e245b6d1 580 data[1] = (inb(dev->iobase + DAS800_STATUS) >> 4) & 0x7;
3726e56b 581
a2714e3e 582 return insn->n;
3726e56b
FMH
583}
584
d7427345
HS
585static int das800_do_insn_bits(struct comedi_device *dev,
586 struct comedi_subdevice *s,
587 struct comedi_insn *insn,
588 unsigned int *data)
3726e56b 589{
9a1a6cf8 590 struct das800_private *devpriv = dev->private;
3726e56b
FMH
591 unsigned long irq_flags;
592
97f4289a 593 if (comedi_dio_update_state(s, data)) {
26234771 594 devpriv->do_bits = s->state << 4;
3726e56b 595
26234771
HS
596 spin_lock_irqsave(&dev->spinlock, irq_flags);
597 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
598 CONTROL1);
599 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
600 }
3726e56b 601
26234771 602 data[1] = s->state;
3726e56b 603
a2714e3e 604 return insn->n;
3726e56b
FMH
605}
606
a69153f6 607static const struct das800_board *das800_probe(struct comedi_device *dev)
4f71ceeb 608{
4f3aa186
HS
609 const struct das800_board *board = dev->board_ptr;
610 int index = board ? board - das800_boards : -EINVAL;
4f71ceeb
HS
611 int id_bits;
612 unsigned long irq_flags;
4f71ceeb 613
a69153f6
HS
614 /*
615 * The dev->board_ptr will be set by comedi_device_attach() if the
616 * board name provided by the user matches a board->name in this
617 * driver. If so, this function sanity checks the id_bits to verify
618 * that the board is correct.
619 *
620 * If the dev->board_ptr is not set, the user is trying to attach
621 * an unspecified board to this driver. In this case the id_bits
622 * are used to 'probe' for the correct dev->board_ptr.
623 */
4f71ceeb 624 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 625 id_bits = das800_ind_read(dev, ID) & 0x3;
4f71ceeb
HS
626 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
627
4f71ceeb
HS
628 switch (id_bits) {
629 case 0x0:
a69153f6 630 if (index == BOARD_DAS800 || index == BOARD_CIODAS800)
4f3aa186 631 return board;
a69153f6 632 index = BOARD_DAS800;
4f71ceeb
HS
633 break;
634 case 0x2:
a69153f6 635 if (index == BOARD_DAS801 || index == BOARD_CIODAS801)
4f3aa186 636 return board;
a69153f6 637 index = BOARD_DAS801;
4f71ceeb
HS
638 break;
639 case 0x3:
a69153f6
HS
640 if (index == BOARD_DAS802 || index == BOARD_CIODAS802 ||
641 index == BOARD_CIODAS80216)
4f3aa186 642 return board;
a69153f6 643 index = BOARD_DAS802;
4f71ceeb
HS
644 break;
645 default:
c1a59171 646 dev_dbg(dev->class_dev, "Board model: 0x%x (unknown)\n",
4f71ceeb 647 id_bits);
a69153f6 648 return NULL;
4f71ceeb 649 }
a69153f6
HS
650 dev_dbg(dev->class_dev, "Board model (probed): %s series\n",
651 das800_boards[index].name);
652
653 return &das800_boards[index];
4f71ceeb
HS
654}
655
92046ae4
HS
656static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
657{
4f3aa186 658 const struct das800_board *board;
92046ae4
HS
659 struct das800_private *devpriv;
660 struct comedi_subdevice *s;
661 unsigned int irq = it->options[1];
662 unsigned long irq_flags;
92046ae4
HS
663 int ret;
664
0bdab509 665 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
92046ae4
HS
666 if (!devpriv)
667 return -ENOMEM;
92046ae4 668
862755ec 669 ret = comedi_request_region(dev, it->options[0], 0x8);
92046ae4
HS
670 if (ret)
671 return ret;
672
4f3aa186
HS
673 board = das800_probe(dev);
674 if (!board)
92046ae4 675 return -ENODEV;
4f3aa186
HS
676 dev->board_ptr = board;
677 dev->board_name = board->name;
92046ae4 678
f05ffb6e
HS
679 if (irq > 1 && irq <= 7) {
680 ret = request_irq(irq, das800_interrupt, 0, dev->board_name,
681 dev);
682 if (ret == 0)
683 dev->irq = irq;
92046ae4 684 }
92046ae4 685
e4690dec
HS
686 dev->pacer = comedi_8254_init(dev->iobase + DAS800_8254,
687 I8254_OSC_BASE_1MHZ, I8254_IO8, 0);
688 if (!dev->pacer)
689 return -ENOMEM;
690
92046ae4
HS
691 ret = comedi_alloc_subdevices(dev, 3);
692 if (ret)
693 return ret;
694
d7427345 695 /* Analog Input subdevice */
92046ae4
HS
696 s = &dev->subdevices[0];
697 dev->read_subdev = s;
77630119
HS
698 s->type = COMEDI_SUBD_AI;
699 s->subdev_flags = SDF_READABLE | SDF_GROUND;
700 s->n_chan = 8;
4f3aa186
HS
701 s->maxdata = (1 << board->resolution) - 1;
702 s->range_table = board->ai_range;
d7427345 703 s->insn_read = das800_ai_insn_read;
77630119
HS
704 if (dev->irq) {
705 s->subdev_flags |= SDF_CMD_READ;
706 s->len_chanlist = 8;
707 s->do_cmdtest = das800_ai_do_cmdtest;
708 s->do_cmd = das800_ai_do_cmd;
709 s->cancel = das800_cancel;
710 }
92046ae4 711
d7427345 712 /* Digital Input subdevice */
92046ae4 713 s = &dev->subdevices[1];
d7427345
HS
714 s->type = COMEDI_SUBD_DI;
715 s->subdev_flags = SDF_READABLE;
716 s->n_chan = 3;
717 s->maxdata = 1;
718 s->range_table = &range_digital;
719 s->insn_bits = das800_di_insn_bits;
720
721 /* Digital Output subdevice */
92046ae4 722 s = &dev->subdevices[2];
d7427345 723 s->type = COMEDI_SUBD_DO;
453fd2b3 724 s->subdev_flags = SDF_WRITABLE;
d7427345
HS
725 s->n_chan = 4;
726 s->maxdata = 1;
727 s->range_table = &range_digital;
728 s->insn_bits = das800_do_insn_bits;
92046ae4 729
57d1ebf7 730 das800_disable(dev);
92046ae4
HS
731
732 /* initialize digital out channels */
733 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 734 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
92046ae4
HS
735 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
736
737 return 0;
738};
739
79a8c0e2
HS
740static struct comedi_driver driver_das800 = {
741 .driver_name = "das800",
742 .module = THIS_MODULE,
743 .attach = das800_attach,
744 .detach = comedi_legacy_detach,
745 .num_names = ARRAY_SIZE(das800_boards),
746 .board_name = &das800_boards[0].name,
747 .offset = sizeof(struct das800_board),
748};
749module_comedi_driver(driver_das800);
750
90f703d3
AT
751MODULE_AUTHOR("Comedi http://www.comedi.org");
752MODULE_DESCRIPTION("Comedi low-level driver");
753MODULE_LICENSE("GPL");
This page took 1.011268 seconds and 5 git commands to generate.