1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Comedi driver for Keithley DAS-1700/DAS-1800 series boards
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
10/*
11 * Driver: das1800
12 * Description: Keithley Metrabyte DAS1800 (& compatibles)
13 * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
14 * Devices: [Keithley Metrabyte] DAS-1701ST (das-1701st),
15 * DAS-1701ST-DA (das-1701st-da), DAS-1701/AO (das-1701ao),
16 * DAS-1702ST (das-1702st), DAS-1702ST-DA (das-1702st-da),
17 * DAS-1702HR (das-1702hr), DAS-1702HR-DA (das-1702hr-da),
18 * DAS-1702/AO (das-1702ao), DAS-1801ST (das-1801st),
19 * DAS-1801ST-DA (das-1801st-da), DAS-1801HC (das-1801hc),
20 * DAS-1801AO (das-1801ao), DAS-1802ST (das-1802st),
21 * DAS-1802ST-DA (das-1802st-da), DAS-1802HR (das-1802hr),
22 * DAS-1802HR-DA (das-1802hr-da), DAS-1802HC (das-1802hc),
23 * DAS-1802AO (das-1802ao)
24 * Status: works
25 *
26 * Configuration options:
27 * [0] - I/O port base address
28 * [1] - IRQ (optional, required for analog input cmd support)
29 * [2] - DMA0 (optional, requires irq)
30 * [3] - DMA1 (optional, requires irq and dma0)
31 *
32 * analog input cmd triggers supported:
33 *
34 * start_src TRIG_NOW command starts immediately
35 * TRIG_EXT command starts on external pin TGIN
36 *
37 * scan_begin_src TRIG_FOLLOW paced/external scans start immediately
38 * TRIG_TIMER burst scans start periodically
39 * TRIG_EXT burst scans start on external pin XPCLK
40 *
41 * scan_end_src TRIG_COUNT scan ends after last channel
42 *
43 * convert_src TRIG_TIMER paced/burst conversions are timed
44 * TRIG_EXT conversions on external pin XPCLK
45 * (requires scan_begin_src == TRIG_FOLLOW)
46 *
47 * stop_src TRIG_COUNT command stops after stop_arg scans
48 * TRIG_EXT command stops on external pin TGIN
49 * TRIG_NONE command runs until canceled
50 *
51 * If TRIG_EXT is used for both the start_src and stop_src, the first TGIN
52 * trigger starts the command, and the second trigger will stop it. If only
53 * one is TRIG_EXT, the first trigger will either stop or start the command.
54 * The external pin TGIN is normally set for negative edge triggering. It
55 * can be set to positive edge with the CR_INVERT flag. If TRIG_EXT is used
56 * for both the start_src and stop_src they must have the same polarity.
57 *
58 * Minimum conversion speed is limited to 64 microseconds (convert_arg <= 64000)
59 * for 'burst' scans. This limitation does not apply for 'paced' scans. The
60 * maximum conversion speed is limited by the board (convert_arg >= ai_speed).
61 * Maximum conversion speeds are not always achievable depending on the
62 * board setup (see user manual).
63 *
64 * NOTES:
65 * Only the DAS-1801ST has been tested by me.
66 * Unipolar and bipolar ranges cannot be mixed in the channel/gain list.
67 *
68 * The waveform analog output on the 'ao' cards is not supported.
69 * If you need it, send me (Frank Hess) an email.
70 */
71
72#include <linux/module.h>
73#include <linux/interrupt.h>
74#include <linux/slab.h>
75#include <linux/io.h>
76#include <linux/comedi/comedidev.h>
77#include <linux/comedi/comedi_8254.h>
78#include <linux/comedi/comedi_isadma.h>
79
80/* misc. defines */
81#define DAS1800_SIZE 16 /* uses 16 io addresses */
82#define FIFO_SIZE 1024 /* 1024 sample fifo */
83#define DMA_BUF_SIZE 0x1ff00 /* size in bytes of dma buffers */
84
85/* Registers for the das1800 */
86#define DAS1800_FIFO 0x0
87#define DAS1800_QRAM 0x0
88#define DAS1800_DAC 0x0
89#define DAS1800_SELECT 0x2
90#define ADC 0x0
91#define QRAM 0x1
92#define DAC(a) (0x2 + a)
93#define DAS1800_DIGITAL 0x3
94#define DAS1800_CONTROL_A 0x4
95#define FFEN 0x1
96#define CGEN 0x4
97#define CGSL 0x8
98#define TGEN 0x10
99#define TGSL 0x20
100#define TGPL 0x40
101#define ATEN 0x80
102#define DAS1800_CONTROL_B 0x5
103#define DMA_CH5 0x1
104#define DMA_CH6 0x2
105#define DMA_CH7 0x3
106#define DMA_CH5_CH6 0x5
107#define DMA_CH6_CH7 0x6
108#define DMA_CH7_CH5 0x7
109#define DMA_ENABLED 0x3
110#define DMA_DUAL 0x4
111#define IRQ3 0x8
112#define IRQ5 0x10
113#define IRQ7 0x18
114#define IRQ10 0x28
115#define IRQ11 0x30
116#define IRQ15 0x38
117#define FIMD 0x40
118#define DAS1800_CONTROL_C 0X6
119#define IPCLK 0x1
120#define XPCLK 0x3
121#define BMDE 0x4
122#define CMEN 0x8
123#define UQEN 0x10
124#define SD 0x40
125#define UB 0x80
126#define DAS1800_STATUS 0x7
127#define INT 0x1
128#define DMATC 0x2
129#define CT0TC 0x8
130#define OVF 0x10
131#define FHF 0x20
132#define FNE 0x40
133#define CVEN 0x80
134#define CVEN_MASK 0x40
135#define CLEAR_INTR_MASK (CVEN_MASK | 0x1f)
136#define DAS1800_BURST_LENGTH 0x8
137#define DAS1800_BURST_RATE 0x9
138#define DAS1800_QRAM_ADDRESS 0xa
139#define DAS1800_COUNTER 0xc
140
141#define IOBASE2 0x400
142
143static const struct comedi_lrange das1801_ai_range = {
144 8, {
145 BIP_RANGE(5), /* bipolar gain = 1 */
146 BIP_RANGE(1), /* bipolar gain = 10 */
147 BIP_RANGE(0.1), /* bipolar gain = 50 */
148 BIP_RANGE(0.02), /* bipolar gain = 250 */
149 UNI_RANGE(5), /* unipolar gain = 1 */
150 UNI_RANGE(1), /* unipolar gain = 10 */
151 UNI_RANGE(0.1), /* unipolar gain = 50 */
152 UNI_RANGE(0.02) /* unipolar gain = 250 */
153 }
154};
155
156static const struct comedi_lrange das1802_ai_range = {
157 8, {
158 BIP_RANGE(10), /* bipolar gain = 1 */
159 BIP_RANGE(5), /* bipolar gain = 2 */
160 BIP_RANGE(2.5), /* bipolar gain = 4 */
161 BIP_RANGE(1.25), /* bipolar gain = 8 */
162 UNI_RANGE(10), /* unipolar gain = 1 */
163 UNI_RANGE(5), /* unipolar gain = 2 */
164 UNI_RANGE(2.5), /* unipolar gain = 4 */
165 UNI_RANGE(1.25) /* unipolar gain = 8 */
166 }
167};
168
169/*
170 * The waveform analog outputs on the 'ao' boards are not currently
171 * supported. They have a comedi_lrange of:
172 * { 2, { BIP_RANGE(10), BIP_RANGE(5) } }
173 */
174
175enum das1800_boardid {
176 BOARD_DAS1701ST,
177 BOARD_DAS1701ST_DA,
178 BOARD_DAS1702ST,
179 BOARD_DAS1702ST_DA,
180 BOARD_DAS1702HR,
181 BOARD_DAS1702HR_DA,
182 BOARD_DAS1701AO,
183 BOARD_DAS1702AO,
184 BOARD_DAS1801ST,
185 BOARD_DAS1801ST_DA,
186 BOARD_DAS1802ST,
187 BOARD_DAS1802ST_DA,
188 BOARD_DAS1802HR,
189 BOARD_DAS1802HR_DA,
190 BOARD_DAS1801HC,
191 BOARD_DAS1802HC,
192 BOARD_DAS1801AO,
193 BOARD_DAS1802AO
194};
195
196/* board probe id values (hi byte of the digital input register) */
197#define DAS1800_ID_ST_DA 0x3
198#define DAS1800_ID_HR_DA 0x4
199#define DAS1800_ID_AO 0x5
200#define DAS1800_ID_HR 0x6
201#define DAS1800_ID_ST 0x7
202#define DAS1800_ID_HC 0x8
203
204struct das1800_board {
205 const char *name;
206 unsigned char id;
207 unsigned int ai_speed;
208 unsigned int is_01_series:1;
209};
210
211static const struct das1800_board das1800_boards[] = {
212 [BOARD_DAS1701ST] = {
213 .name = "das-1701st",
214 .id = DAS1800_ID_ST,
215 .ai_speed = 6250,
216 .is_01_series = 1,
217 },
218 [BOARD_DAS1701ST_DA] = {
219 .name = "das-1701st-da",
220 .id = DAS1800_ID_ST_DA,
221 .ai_speed = 6250,
222 .is_01_series = 1,
223 },
224 [BOARD_DAS1702ST] = {
225 .name = "das-1702st",
226 .id = DAS1800_ID_ST,
227 .ai_speed = 6250,
228 },
229 [BOARD_DAS1702ST_DA] = {
230 .name = "das-1702st-da",
231 .id = DAS1800_ID_ST_DA,
232 .ai_speed = 6250,
233 },
234 [BOARD_DAS1702HR] = {
235 .name = "das-1702hr",
236 .id = DAS1800_ID_HR,
237 .ai_speed = 20000,
238 },
239 [BOARD_DAS1702HR_DA] = {
240 .name = "das-1702hr-da",
241 .id = DAS1800_ID_HR_DA,
242 .ai_speed = 20000,
243 },
244 [BOARD_DAS1701AO] = {
245 .name = "das-1701ao",
246 .id = DAS1800_ID_AO,
247 .ai_speed = 6250,
248 .is_01_series = 1,
249 },
250 [BOARD_DAS1702AO] = {
251 .name = "das-1702ao",
252 .id = DAS1800_ID_AO,
253 .ai_speed = 6250,
254 },
255 [BOARD_DAS1801ST] = {
256 .name = "das-1801st",
257 .id = DAS1800_ID_ST,
258 .ai_speed = 3000,
259 .is_01_series = 1,
260 },
261 [BOARD_DAS1801ST_DA] = {
262 .name = "das-1801st-da",
263 .id = DAS1800_ID_ST_DA,
264 .ai_speed = 3000,
265 .is_01_series = 1,
266 },
267 [BOARD_DAS1802ST] = {
268 .name = "das-1802st",
269 .id = DAS1800_ID_ST,
270 .ai_speed = 3000,
271 },
272 [BOARD_DAS1802ST_DA] = {
273 .name = "das-1802st-da",
274 .id = DAS1800_ID_ST_DA,
275 .ai_speed = 3000,
276 },
277 [BOARD_DAS1802HR] = {
278 .name = "das-1802hr",
279 .id = DAS1800_ID_HR,
280 .ai_speed = 10000,
281 },
282 [BOARD_DAS1802HR_DA] = {
283 .name = "das-1802hr-da",
284 .id = DAS1800_ID_HR_DA,
285 .ai_speed = 10000,
286 },
287 [BOARD_DAS1801HC] = {
288 .name = "das-1801hc",
289 .id = DAS1800_ID_HC,
290 .ai_speed = 3000,
291 .is_01_series = 1,
292 },
293 [BOARD_DAS1802HC] = {
294 .name = "das-1802hc",
295 .id = DAS1800_ID_HC,
296 .ai_speed = 3000,
297 },
298 [BOARD_DAS1801AO] = {
299 .name = "das-1801ao",
300 .id = DAS1800_ID_AO,
301 .ai_speed = 3000,
302 .is_01_series = 1,
303 },
304 [BOARD_DAS1802AO] = {
305 .name = "das-1802ao",
306 .id = DAS1800_ID_AO,
307 .ai_speed = 3000,
308 },
309};
310
311struct das1800_private {
312 struct comedi_isadma *dma;
313 int irq_dma_bits;
314 int dma_bits;
315 unsigned short *fifo_buf;
316 unsigned long iobase2;
317 bool ai_is_unipolar;
318};
319
320static void das1800_ai_munge(struct comedi_device *dev,
321 struct comedi_subdevice *s,
322 void *data, unsigned int num_bytes,
323 unsigned int start_chan_index)
324{
325 struct das1800_private *devpriv = dev->private;
326 unsigned short *array = data;
327 unsigned int num_samples = comedi_bytes_to_samples(s, nbytes: num_bytes);
328 unsigned int i;
329
330 if (devpriv->ai_is_unipolar)
331 return;
332
333 for (i = 0; i < num_samples; i++)
334 array[i] = comedi_offset_munge(s, val: array[i]);
335}
336
337static void das1800_handle_fifo_half_full(struct comedi_device *dev,
338 struct comedi_subdevice *s)
339{
340 struct das1800_private *devpriv = dev->private;
341 unsigned int nsamples = comedi_nsamples_left(s, FIFO_SIZE / 2);
342
343 insw(port: dev->iobase + DAS1800_FIFO, addr: devpriv->fifo_buf, count: nsamples);
344 comedi_buf_write_samples(s, data: devpriv->fifo_buf, nsamples);
345}
346
347static void das1800_handle_fifo_not_empty(struct comedi_device *dev,
348 struct comedi_subdevice *s)
349{
350 struct comedi_cmd *cmd = &s->async->cmd;
351 unsigned short dpnt;
352
353 while (inb(port: dev->iobase + DAS1800_STATUS) & FNE) {
354 dpnt = inw(port: dev->iobase + DAS1800_FIFO);
355 comedi_buf_write_samples(s, data: &dpnt, nsamples: 1);
356
357 if (cmd->stop_src == TRIG_COUNT &&
358 s->async->scans_done >= cmd->stop_arg)
359 break;
360 }
361}
362
363static void das1800_flush_dma_channel(struct comedi_device *dev,
364 struct comedi_subdevice *s,
365 struct comedi_isadma_desc *desc)
366{
367 unsigned int residue = comedi_isadma_disable(dma_chan: desc->chan);
368 unsigned int nbytes = desc->size - residue;
369 unsigned int nsamples;
370
371 /* figure out how many points to read */
372 nsamples = comedi_bytes_to_samples(s, nbytes);
373 nsamples = comedi_nsamples_left(s, nsamples);
374
375 comedi_buf_write_samples(s, data: desc->virt_addr, nsamples);
376}
377
378static void das1800_flush_dma(struct comedi_device *dev,
379 struct comedi_subdevice *s)
380{
381 struct das1800_private *devpriv = dev->private;
382 struct comedi_isadma *dma = devpriv->dma;
383 struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
384 const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
385
386 das1800_flush_dma_channel(dev, s, desc);
387
388 if (dual_dma) {
389 /* switch to other channel and flush it */
390 dma->cur_dma = 1 - dma->cur_dma;
391 desc = &dma->desc[dma->cur_dma];
392 das1800_flush_dma_channel(dev, s, desc);
393 }
394
395 /* get any remaining samples in fifo */
396 das1800_handle_fifo_not_empty(dev, s);
397}
398
399static void das1800_handle_dma(struct comedi_device *dev,
400 struct comedi_subdevice *s, unsigned int status)
401{
402 struct das1800_private *devpriv = dev->private;
403 struct comedi_isadma *dma = devpriv->dma;
404 struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
405 const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
406
407 das1800_flush_dma_channel(dev, s, desc);
408
409 /* re-enable dma channel */
410 comedi_isadma_program(desc);
411
412 if (status & DMATC) {
413 /* clear DMATC interrupt bit */
414 outb(CLEAR_INTR_MASK & ~DMATC, port: dev->iobase + DAS1800_STATUS);
415 /* switch dma channels for next time, if appropriate */
416 if (dual_dma)
417 dma->cur_dma = 1 - dma->cur_dma;
418 }
419}
420
421static int das1800_ai_cancel(struct comedi_device *dev,
422 struct comedi_subdevice *s)
423{
424 struct das1800_private *devpriv = dev->private;
425 struct comedi_isadma *dma = devpriv->dma;
426 struct comedi_isadma_desc *desc;
427 int i;
428
429 /* disable and stop conversions */
430 outb(value: 0x0, port: dev->iobase + DAS1800_STATUS);
431 outb(value: 0x0, port: dev->iobase + DAS1800_CONTROL_B);
432 outb(value: 0x0, port: dev->iobase + DAS1800_CONTROL_A);
433
434 if (dma) {
435 for (i = 0; i < 2; i++) {
436 desc = &dma->desc[i];
437 if (desc->chan)
438 comedi_isadma_disable(dma_chan: desc->chan);
439 }
440 }
441
442 return 0;
443}
444
445static void das1800_ai_handler(struct comedi_device *dev)
446{
447 struct das1800_private *devpriv = dev->private;
448 struct comedi_subdevice *s = dev->read_subdev;
449 struct comedi_async *async = s->async;
450 struct comedi_cmd *cmd = &async->cmd;
451 unsigned int status = inb(port: dev->iobase + DAS1800_STATUS);
452
453 /* select adc register (spinlock is already held) */
454 outb(ADC, port: dev->iobase + DAS1800_SELECT);
455
456 /* get samples with dma, fifo, or polled as necessary */
457 if (devpriv->irq_dma_bits & DMA_ENABLED)
458 das1800_handle_dma(dev, s, status);
459 else if (status & FHF)
460 das1800_handle_fifo_half_full(dev, s);
461 else if (status & FNE)
462 das1800_handle_fifo_not_empty(dev, s);
463
464 /* if the card's fifo has overflowed */
465 if (status & OVF) {
466 /* clear OVF interrupt bit */
467 outb(CLEAR_INTR_MASK & ~OVF, port: dev->iobase + DAS1800_STATUS);
468 dev_err(dev->class_dev, "FIFO overflow\n");
469 async->events |= COMEDI_CB_ERROR;
470 comedi_handle_events(dev, s);
471 return;
472 }
473 /* stop taking data if appropriate */
474 /* stop_src TRIG_EXT */
475 if (status & CT0TC) {
476 /* clear CT0TC interrupt bit */
477 outb(CLEAR_INTR_MASK & ~CT0TC, port: dev->iobase + DAS1800_STATUS);
478 /* get all remaining samples before quitting */
479 if (devpriv->irq_dma_bits & DMA_ENABLED)
480 das1800_flush_dma(dev, s);
481 else
482 das1800_handle_fifo_not_empty(dev, s);
483 async->events |= COMEDI_CB_EOA;
484 } else if (cmd->stop_src == TRIG_COUNT &&
485 async->scans_done >= cmd->stop_arg) {
486 async->events |= COMEDI_CB_EOA;
487 }
488
489 comedi_handle_events(dev, s);
490}
491
492static int das1800_ai_poll(struct comedi_device *dev,
493 struct comedi_subdevice *s)
494{
495 unsigned long flags;
496
497 /*
498 * Protects the indirect addressing selected by DAS1800_SELECT
499 * in das1800_ai_handler() also prevents race with das1800_interrupt().
500 */
501 spin_lock_irqsave(&dev->spinlock, flags);
502
503 das1800_ai_handler(dev);
504
505 spin_unlock_irqrestore(lock: &dev->spinlock, flags);
506
507 return comedi_buf_n_bytes_ready(s);
508}
509
510static irqreturn_t das1800_interrupt(int irq, void *d)
511{
512 struct comedi_device *dev = d;
513 unsigned int status;
514
515 if (!dev->attached) {
516 dev_err(dev->class_dev, "premature interrupt\n");
517 return IRQ_HANDLED;
518 }
519
520 /*
521 * Protects the indirect addressing selected by DAS1800_SELECT
522 * in das1800_ai_handler() also prevents race with das1800_ai_poll().
523 */
524 spin_lock(lock: &dev->spinlock);
525
526 status = inb(port: dev->iobase + DAS1800_STATUS);
527
528 /* if interrupt was not caused by das-1800 */
529 if (!(status & INT)) {
530 spin_unlock(lock: &dev->spinlock);
531 return IRQ_NONE;
532 }
533 /* clear the interrupt status bit INT */
534 outb(CLEAR_INTR_MASK & ~INT, port: dev->iobase + DAS1800_STATUS);
535 /* handle interrupt */
536 das1800_ai_handler(dev);
537
538 spin_unlock(lock: &dev->spinlock);
539 return IRQ_HANDLED;
540}
541
542static int das1800_ai_fixup_paced_timing(struct comedi_device *dev,
543 struct comedi_cmd *cmd)
544{
545 unsigned int arg = cmd->convert_arg;
546
547 /*
548 * Paced mode:
549 * scan_begin_src is TRIG_FOLLOW
550 * convert_src is TRIG_TIMER
551 *
552 * The convert_arg sets the pacer sample acquisition time.
553 * The max acquisition speed is limited to the boards
554 * 'ai_speed' (this was already verified). The min speed is
555 * limited by the cascaded 8254 timer.
556 */
557 comedi_8254_cascade_ns_to_timer(i8254: dev->pacer, nanosec: &arg, flags: cmd->flags);
558 return comedi_check_trigger_arg_is(arg: &cmd->convert_arg, val: arg);
559}
560
561static int das1800_ai_fixup_burst_timing(struct comedi_device *dev,
562 struct comedi_cmd *cmd)
563{
564 unsigned int arg = cmd->convert_arg;
565 int err = 0;
566
567 /*
568 * Burst mode:
569 * scan_begin_src is TRIG_TIMER or TRIG_EXT
570 * convert_src is TRIG_TIMER
571 *
572 * The convert_arg sets burst sample acquisition time.
573 * The max acquisition speed is limited to the boards
574 * 'ai_speed' (this was already verified). The min speed is
575 * limiited to 64 microseconds,
576 */
577 err |= comedi_check_trigger_arg_max(arg: &arg, val: 64000);
578
579 /* round to microseconds then verify */
580 switch (cmd->flags & CMDF_ROUND_MASK) {
581 case CMDF_ROUND_NEAREST:
582 default:
583 arg = DIV_ROUND_CLOSEST(arg, 1000);
584 break;
585 case CMDF_ROUND_DOWN:
586 arg = arg / 1000;
587 break;
588 case CMDF_ROUND_UP:
589 arg = DIV_ROUND_UP(arg, 1000);
590 break;
591 }
592 err |= comedi_check_trigger_arg_is(arg: &cmd->convert_arg, val: arg * 1000);
593
594 /*
595 * The pacer can be used to set the scan sample rate. The max scan
596 * speed is limited by the conversion speed and the number of channels
597 * to convert. The min speed is limited by the cascaded 8254 timer.
598 */
599 if (cmd->scan_begin_src == TRIG_TIMER) {
600 arg = cmd->convert_arg * cmd->chanlist_len;
601 err |= comedi_check_trigger_arg_min(arg: &cmd->scan_begin_arg, val: arg);
602
603 arg = cmd->scan_begin_arg;
604 comedi_8254_cascade_ns_to_timer(i8254: dev->pacer, nanosec: &arg, flags: cmd->flags);
605 err |= comedi_check_trigger_arg_is(arg: &cmd->scan_begin_arg, val: arg);
606 }
607
608 return err;
609}
610
611static int das1800_ai_check_chanlist(struct comedi_device *dev,
612 struct comedi_subdevice *s,
613 struct comedi_cmd *cmd)
614{
615 unsigned int range = CR_RANGE(cmd->chanlist[0]);
616 bool unipolar0 = comedi_range_is_unipolar(s, range);
617 int i;
618
619 for (i = 1; i < cmd->chanlist_len; i++) {
620 range = CR_RANGE(cmd->chanlist[i]);
621
622 if (unipolar0 != comedi_range_is_unipolar(s, range)) {
623 dev_dbg(dev->class_dev,
624 "unipolar and bipolar ranges cannot be mixed in the chanlist\n");
625 return -EINVAL;
626 }
627 }
628
629 return 0;
630}
631
632static int das1800_ai_cmdtest(struct comedi_device *dev,
633 struct comedi_subdevice *s,
634 struct comedi_cmd *cmd)
635{
636 const struct das1800_board *board = dev->board_ptr;
637 int err = 0;
638
639 /* Step 1 : check if triggers are trivially valid */
640
641 err |= comedi_check_trigger_src(src: &cmd->start_src, TRIG_NOW | TRIG_EXT);
642 err |= comedi_check_trigger_src(src: &cmd->scan_begin_src,
643 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
644 err |= comedi_check_trigger_src(src: &cmd->convert_src,
645 TRIG_TIMER | TRIG_EXT);
646 err |= comedi_check_trigger_src(src: &cmd->scan_end_src, TRIG_COUNT);
647 err |= comedi_check_trigger_src(src: &cmd->stop_src,
648 TRIG_COUNT | TRIG_EXT | TRIG_NONE);
649
650 if (err)
651 return 1;
652
653 /* Step 2a : make sure trigger sources are unique */
654
655 err |= comedi_check_trigger_is_unique(src: cmd->start_src);
656 err |= comedi_check_trigger_is_unique(src: cmd->scan_begin_src);
657 err |= comedi_check_trigger_is_unique(src: cmd->convert_src);
658 err |= comedi_check_trigger_is_unique(src: cmd->stop_src);
659
660 /* Step 2b : and mutually compatible */
661
662 /* burst scans must use timed conversions */
663 if (cmd->scan_begin_src != TRIG_FOLLOW &&
664 cmd->convert_src != TRIG_TIMER)
665 err |= -EINVAL;
666
667 /* the external pin TGIN must use the same polarity */
668 if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
669 err |= comedi_check_trigger_arg_is(arg: &cmd->start_arg,
670 val: cmd->stop_arg);
671
672 if (err)
673 return 2;
674
675 /* Step 3: check if arguments are trivially valid */
676
677 if (cmd->start_arg == TRIG_NOW)
678 err |= comedi_check_trigger_arg_is(arg: &cmd->start_arg, val: 0);
679
680 if (cmd->convert_src == TRIG_TIMER) {
681 err |= comedi_check_trigger_arg_min(arg: &cmd->convert_arg,
682 val: board->ai_speed);
683 }
684
685 err |= comedi_check_trigger_arg_min(arg: &cmd->chanlist_len, val: 1);
686 err |= comedi_check_trigger_arg_is(arg: &cmd->scan_end_arg,
687 val: cmd->chanlist_len);
688
689 switch (cmd->stop_src) {
690 case TRIG_COUNT:
691 err |= comedi_check_trigger_arg_min(arg: &cmd->stop_arg, val: 1);
692 break;
693 case TRIG_NONE:
694 err |= comedi_check_trigger_arg_is(arg: &cmd->stop_arg, val: 0);
695 break;
696 default:
697 break;
698 }
699
700 if (err)
701 return 3;
702
703 /* Step 4: fix up any arguments */
704
705 if (cmd->convert_src == TRIG_TIMER) {
706 if (cmd->scan_begin_src == TRIG_FOLLOW)
707 err |= das1800_ai_fixup_paced_timing(dev, cmd);
708 else /* TRIG_TIMER or TRIG_EXT */
709 err |= das1800_ai_fixup_burst_timing(dev, cmd);
710 }
711
712 if (err)
713 return 4;
714
715 /* Step 5: check channel list if it exists */
716 if (cmd->chanlist && cmd->chanlist_len > 0)
717 err |= das1800_ai_check_chanlist(dev, s, cmd);
718
719 if (err)
720 return 5;
721
722 return 0;
723}
724
725static unsigned char das1800_ai_chanspec_bits(struct comedi_subdevice *s,
726 unsigned int chanspec)
727{
728 unsigned int range = CR_RANGE(chanspec);
729 unsigned int aref = CR_AREF(chanspec);
730 unsigned char bits;
731
732 bits = UQEN;
733 if (aref != AREF_DIFF)
734 bits |= SD;
735 if (aref == AREF_COMMON)
736 bits |= CMEN;
737 if (comedi_range_is_unipolar(s, range))
738 bits |= UB;
739
740 return bits;
741}
742
743static unsigned int das1800_ai_transfer_size(struct comedi_device *dev,
744 struct comedi_subdevice *s,
745 unsigned int maxbytes,
746 unsigned int ns)
747{
748 struct comedi_cmd *cmd = &s->async->cmd;
749 unsigned int max_samples = comedi_bytes_to_samples(s, nbytes: maxbytes);
750 unsigned int samples;
751
752 samples = max_samples;
753
754 /* for timed modes, make dma buffer fill in 'ns' time */
755 switch (cmd->scan_begin_src) {
756 case TRIG_FOLLOW: /* not in burst mode */
757 if (cmd->convert_src == TRIG_TIMER)
758 samples = ns / cmd->convert_arg;
759 break;
760 case TRIG_TIMER:
761 samples = ns / (cmd->scan_begin_arg * cmd->chanlist_len);
762 break;
763 }
764
765 /* limit samples to what is remaining in the command */
766 samples = comedi_nsamples_left(s, nsamples: samples);
767
768 if (samples > max_samples)
769 samples = max_samples;
770 if (samples < 1)
771 samples = 1;
772
773 return comedi_samples_to_bytes(s, nsamples: samples);
774}
775
776static void das1800_ai_setup_dma(struct comedi_device *dev,
777 struct comedi_subdevice *s)
778{
779 struct das1800_private *devpriv = dev->private;
780 struct comedi_isadma *dma = devpriv->dma;
781 struct comedi_isadma_desc *desc;
782 unsigned int bytes;
783
784 if ((devpriv->irq_dma_bits & DMA_ENABLED) == 0)
785 return;
786
787 dma->cur_dma = 0;
788 desc = &dma->desc[0];
789
790 /* determine a dma transfer size to fill buffer in 0.3 sec */
791 bytes = das1800_ai_transfer_size(dev, s, maxbytes: desc->maxsize, ns: 300000000);
792
793 desc->size = bytes;
794 comedi_isadma_program(desc);
795
796 /* set up dual dma if appropriate */
797 if (devpriv->irq_dma_bits & DMA_DUAL) {
798 desc = &dma->desc[1];
799 desc->size = bytes;
800 comedi_isadma_program(desc);
801 }
802}
803
804static void das1800_ai_set_chanlist(struct comedi_device *dev,
805 unsigned int *chanlist, unsigned int len)
806{
807 unsigned long flags;
808 unsigned int i;
809
810 /* protects the indirect addressing selected by DAS1800_SELECT */
811 spin_lock_irqsave(&dev->spinlock, flags);
812
813 /* select QRAM register and set start address */
814 outb(QRAM, port: dev->iobase + DAS1800_SELECT);
815 outb(value: len - 1, port: dev->iobase + DAS1800_QRAM_ADDRESS);
816
817 /* make channel / gain list */
818 for (i = 0; i < len; i++) {
819 unsigned int chan = CR_CHAN(chanlist[i]);
820 unsigned int range = CR_RANGE(chanlist[i]);
821 unsigned short val;
822
823 val = chan | ((range & 0x3) << 8);
824 outw(value: val, port: dev->iobase + DAS1800_QRAM);
825 }
826
827 /* finish write to QRAM */
828 outb(value: len - 1, port: dev->iobase + DAS1800_QRAM_ADDRESS);
829
830 spin_unlock_irqrestore(lock: &dev->spinlock, flags);
831}
832
833static int das1800_ai_cmd(struct comedi_device *dev,
834 struct comedi_subdevice *s)
835{
836 struct das1800_private *devpriv = dev->private;
837 int control_a, control_c;
838 struct comedi_async *async = s->async;
839 const struct comedi_cmd *cmd = &async->cmd;
840 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
841
842 /*
843 * Disable dma on CMDF_WAKE_EOS, or CMDF_PRIORITY (because dma in
844 * handler is unsafe at hard real-time priority).
845 */
846 if (cmd->flags & (CMDF_WAKE_EOS | CMDF_PRIORITY))
847 devpriv->irq_dma_bits &= ~DMA_ENABLED;
848 else
849 devpriv->irq_dma_bits |= devpriv->dma_bits;
850 /* interrupt on end of conversion for CMDF_WAKE_EOS */
851 if (cmd->flags & CMDF_WAKE_EOS) {
852 /* interrupt fifo not empty */
853 devpriv->irq_dma_bits &= ~FIMD;
854 } else {
855 /* interrupt fifo half full */
856 devpriv->irq_dma_bits |= FIMD;
857 }
858
859 das1800_ai_cancel(dev, s);
860
861 devpriv->ai_is_unipolar = comedi_range_is_unipolar(s, range: range0);
862
863 control_a = FFEN;
864 if (cmd->stop_src == TRIG_EXT)
865 control_a |= ATEN;
866 if (cmd->start_src == TRIG_EXT)
867 control_a |= TGEN | CGSL;
868 else /* TRIG_NOW */
869 control_a |= CGEN;
870 if (control_a & (ATEN | TGEN)) {
871 if ((cmd->start_arg & CR_INVERT) || (cmd->stop_arg & CR_INVERT))
872 control_a |= TGPL;
873 }
874
875 control_c = das1800_ai_chanspec_bits(s, chanspec: cmd->chanlist[0]);
876 /* set clock source to internal or external */
877 if (cmd->scan_begin_src == TRIG_FOLLOW) {
878 /* not in burst mode */
879 if (cmd->convert_src == TRIG_TIMER) {
880 /* trig on cascaded counters */
881 control_c |= IPCLK;
882 } else { /* TRIG_EXT */
883 /* trig on falling edge of external trigger */
884 control_c |= XPCLK;
885 }
886 } else if (cmd->scan_begin_src == TRIG_TIMER) {
887 /* burst mode with internal pacer clock */
888 control_c |= BMDE | IPCLK;
889 } else { /* TRIG_EXT */
890 /* burst mode with external trigger */
891 control_c |= BMDE | XPCLK;
892 }
893
894 das1800_ai_set_chanlist(dev, chanlist: cmd->chanlist, len: cmd->chanlist_len);
895
896 /* setup cascaded counters for conversion/scan frequency */
897 if ((cmd->scan_begin_src == TRIG_FOLLOW ||
898 cmd->scan_begin_src == TRIG_TIMER) &&
899 cmd->convert_src == TRIG_TIMER) {
900 comedi_8254_update_divisors(i8254: dev->pacer);
901 comedi_8254_pacer_enable(i8254: dev->pacer, counter1: 1, counter2: 2, enable: true);
902 }
903
904 /* setup counter 0 for 'about triggering' */
905 if (cmd->stop_src == TRIG_EXT)
906 comedi_8254_load(i8254: dev->pacer, counter: 0, val: 1, mode: I8254_MODE0 | I8254_BINARY);
907
908 das1800_ai_setup_dma(dev, s);
909 outb(value: control_c, port: dev->iobase + DAS1800_CONTROL_C);
910 /* set conversion rate and length for burst mode */
911 if (control_c & BMDE) {
912 outb(value: cmd->convert_arg / 1000 - 1, /* microseconds - 1 */
913 port: dev->iobase + DAS1800_BURST_RATE);
914 outb(value: cmd->chanlist_len - 1, port: dev->iobase + DAS1800_BURST_LENGTH);
915 }
916
917 /* enable and start conversions */
918 outb(value: devpriv->irq_dma_bits, port: dev->iobase + DAS1800_CONTROL_B);
919 outb(value: control_a, port: dev->iobase + DAS1800_CONTROL_A);
920 outb(CVEN, port: dev->iobase + DAS1800_STATUS);
921
922 return 0;
923}
924
925static int das1800_ai_eoc(struct comedi_device *dev,
926 struct comedi_subdevice *s,
927 struct comedi_insn *insn,
928 unsigned long context)
929{
930 unsigned char status;
931
932 status = inb(port: dev->iobase + DAS1800_STATUS);
933 if (status & FNE)
934 return 0;
935 return -EBUSY;
936}
937
938static int das1800_ai_insn_read(struct comedi_device *dev,
939 struct comedi_subdevice *s,
940 struct comedi_insn *insn,
941 unsigned int *data)
942{
943 unsigned int range = CR_RANGE(insn->chanspec);
944 bool is_unipolar = comedi_range_is_unipolar(s, range);
945 int ret = 0;
946 int n;
947 unsigned short dpnt;
948 unsigned long flags;
949
950 outb(value: das1800_ai_chanspec_bits(s, chanspec: insn->chanspec),
951 port: dev->iobase + DAS1800_CONTROL_C); /* software pacer */
952 outb(CVEN, port: dev->iobase + DAS1800_STATUS); /* enable conversions */
953 outb(value: 0x0, port: dev->iobase + DAS1800_CONTROL_A); /* reset fifo */
954 outb(FFEN, port: dev->iobase + DAS1800_CONTROL_A);
955
956 das1800_ai_set_chanlist(dev, chanlist: &insn->chanspec, len: 1);
957
958 /* protects the indirect addressing selected by DAS1800_SELECT */
959 spin_lock_irqsave(&dev->spinlock, flags);
960
961 /* select ai fifo register */
962 outb(ADC, port: dev->iobase + DAS1800_SELECT);
963
964 for (n = 0; n < insn->n; n++) {
965 /* trigger conversion */
966 outb(value: 0, port: dev->iobase + DAS1800_FIFO);
967
968 ret = comedi_timeout(dev, s, insn, cb: das1800_ai_eoc, context: 0);
969 if (ret)
970 break;
971
972 dpnt = inw(port: dev->iobase + DAS1800_FIFO);
973 if (!is_unipolar)
974 dpnt = comedi_offset_munge(s, val: dpnt);
975 data[n] = dpnt;
976 }
977 spin_unlock_irqrestore(lock: &dev->spinlock, flags);
978
979 return ret ? ret : insn->n;
980}
981
982static int das1800_ao_insn_write(struct comedi_device *dev,
983 struct comedi_subdevice *s,
984 struct comedi_insn *insn,
985 unsigned int *data)
986{
987 unsigned int chan = CR_CHAN(insn->chanspec);
988 unsigned int update_chan = s->n_chan - 1;
989 unsigned long flags;
990 int i;
991
992 /* protects the indirect addressing selected by DAS1800_SELECT */
993 spin_lock_irqsave(&dev->spinlock, flags);
994
995 for (i = 0; i < insn->n; i++) {
996 unsigned int val = data[i];
997
998 s->readback[chan] = val;
999
1000 val = comedi_offset_munge(s, val);
1001
1002 /* load this channel (and update if it's the last channel) */
1003 outb(DAC(chan), port: dev->iobase + DAS1800_SELECT);
1004 outw(value: val, port: dev->iobase + DAS1800_DAC);
1005
1006 /* update all channels */
1007 if (chan != update_chan) {
1008 val = comedi_offset_munge(s, val: s->readback[update_chan]);
1009
1010 outb(DAC(update_chan), port: dev->iobase + DAS1800_SELECT);
1011 outw(value: val, port: dev->iobase + DAS1800_DAC);
1012 }
1013 }
1014 spin_unlock_irqrestore(lock: &dev->spinlock, flags);
1015
1016 return insn->n;
1017}
1018
1019static int das1800_di_insn_bits(struct comedi_device *dev,
1020 struct comedi_subdevice *s,
1021 struct comedi_insn *insn,
1022 unsigned int *data)
1023{
1024 data[1] = inb(port: dev->iobase + DAS1800_DIGITAL) & 0xf;
1025 data[0] = 0;
1026
1027 return insn->n;
1028}
1029
1030static int das1800_do_insn_bits(struct comedi_device *dev,
1031 struct comedi_subdevice *s,
1032 struct comedi_insn *insn,
1033 unsigned int *data)
1034{
1035 if (comedi_dio_update_state(s, data))
1036 outb(value: s->state, port: dev->iobase + DAS1800_DIGITAL);
1037
1038 data[1] = s->state;
1039
1040 return insn->n;
1041}
1042
1043static void das1800_init_dma(struct comedi_device *dev,
1044 struct comedi_devconfig *it)
1045{
1046 struct das1800_private *devpriv = dev->private;
1047 unsigned int *dma_chan;
1048
1049 /*
1050 * it->options[2] is DMA channel 0
1051 * it->options[3] is DMA channel 1
1052 *
1053 * Encode the DMA channels into 2 digit hexadecimal for switch.
1054 */
1055 dma_chan = &it->options[2];
1056
1057 switch ((dma_chan[0] & 0x7) | (dma_chan[1] << 4)) {
1058 case 0x5: /* dma0 == 5 */
1059 devpriv->dma_bits = DMA_CH5;
1060 break;
1061 case 0x6: /* dma0 == 6 */
1062 devpriv->dma_bits = DMA_CH6;
1063 break;
1064 case 0x7: /* dma0 == 7 */
1065 devpriv->dma_bits = DMA_CH7;
1066 break;
1067 case 0x65: /* dma0 == 5, dma1 == 6 */
1068 devpriv->dma_bits = DMA_CH5_CH6;
1069 break;
1070 case 0x76: /* dma0 == 6, dma1 == 7 */
1071 devpriv->dma_bits = DMA_CH6_CH7;
1072 break;
1073 case 0x57: /* dma0 == 7, dma1 == 5 */
1074 devpriv->dma_bits = DMA_CH7_CH5;
1075 break;
1076 default:
1077 return;
1078 }
1079
1080 /* DMA can use 1 or 2 buffers, each with a separate channel */
1081 devpriv->dma = comedi_isadma_alloc(dev, n_desc: dma_chan[1] ? 2 : 1,
1082 dma_chan1: dma_chan[0], dma_chan2: dma_chan[1],
1083 DMA_BUF_SIZE, COMEDI_ISADMA_READ);
1084 if (!devpriv->dma)
1085 devpriv->dma_bits = 0;
1086}
1087
1088static void das1800_free_dma(struct comedi_device *dev)
1089{
1090 struct das1800_private *devpriv = dev->private;
1091
1092 if (devpriv)
1093 comedi_isadma_free(dma: devpriv->dma);
1094}
1095
1096static int das1800_probe(struct comedi_device *dev)
1097{
1098 const struct das1800_board *board = dev->board_ptr;
1099 unsigned char id;
1100
1101 id = (inb(port: dev->iobase + DAS1800_DIGITAL) >> 4) & 0xf;
1102
1103 /*
1104 * The dev->board_ptr will be set by comedi_device_attach() if the
1105 * board name provided by the user matches a board->name in this
1106 * driver. If so, this function sanity checks the id to verify that
1107 * the board is correct.
1108 */
1109 if (board) {
1110 if (board->id == id)
1111 return 0;
1112 dev_err(dev->class_dev,
1113 "probed id does not match board id (0x%x != 0x%x)\n",
1114 id, board->id);
1115 return -ENODEV;
1116 }
1117
1118 /*
1119 * If the dev->board_ptr is not set, the user is trying to attach
1120 * an unspecified board to this driver. In this case the id is used
1121 * to 'probe' for the dev->board_ptr.
1122 */
1123 switch (id) {
1124 case DAS1800_ID_ST_DA:
1125 /* das-1701st-da, das-1702st-da, das-1801st-da, das-1802st-da */
1126 board = &das1800_boards[BOARD_DAS1801ST_DA];
1127 break;
1128 case DAS1800_ID_HR_DA:
1129 /* das-1702hr-da, das-1802hr-da */
1130 board = &das1800_boards[BOARD_DAS1802HR_DA];
1131 break;
1132 case DAS1800_ID_AO:
1133 /* das-1701ao, das-1702ao, das-1801ao, das-1802ao */
1134 board = &das1800_boards[BOARD_DAS1801AO];
1135 break;
1136 case DAS1800_ID_HR:
1137 /* das-1702hr, das-1802hr */
1138 board = &das1800_boards[BOARD_DAS1802HR];
1139 break;
1140 case DAS1800_ID_ST:
1141 /* das-1701st, das-1702st, das-1801st, das-1802st */
1142 board = &das1800_boards[BOARD_DAS1801ST];
1143 break;
1144 case DAS1800_ID_HC:
1145 /* das-1801hc, das-1802hc */
1146 board = &das1800_boards[BOARD_DAS1801HC];
1147 break;
1148 default:
1149 dev_err(dev->class_dev, "invalid probe id 0x%x\n", id);
1150 return -ENODEV;
1151 }
1152 dev->board_ptr = board;
1153 dev->board_name = board->name;
1154 dev_warn(dev->class_dev,
1155 "probed id 0x%0x: %s series (not recommended)\n",
1156 id, board->name);
1157 return 0;
1158}
1159
1160static int das1800_attach(struct comedi_device *dev,
1161 struct comedi_devconfig *it)
1162{
1163 const struct das1800_board *board;
1164 struct das1800_private *devpriv;
1165 struct comedi_subdevice *s;
1166 unsigned int irq = it->options[1];
1167 bool is_16bit;
1168 int ret;
1169 int i;
1170
1171 devpriv = comedi_alloc_devpriv(dev, size: sizeof(*devpriv));
1172 if (!devpriv)
1173 return -ENOMEM;
1174
1175 ret = comedi_request_region(dev, start: it->options[0], DAS1800_SIZE);
1176 if (ret)
1177 return ret;
1178
1179 ret = das1800_probe(dev);
1180 if (ret)
1181 return ret;
1182 board = dev->board_ptr;
1183
1184 is_16bit = board->id == DAS1800_ID_HR || board->id == DAS1800_ID_HR_DA;
1185
1186 /* waveform 'ao' boards have additional io ports */
1187 if (board->id == DAS1800_ID_AO) {
1188 unsigned long iobase2 = dev->iobase + IOBASE2;
1189
1190 ret = __comedi_request_region(dev, start: iobase2, DAS1800_SIZE);
1191 if (ret)
1192 return ret;
1193 devpriv->iobase2 = iobase2;
1194 }
1195
1196 if (irq == 3 || irq == 5 || irq == 7 || irq == 10 || irq == 11 ||
1197 irq == 15) {
1198 ret = request_irq(irq, handler: das1800_interrupt, flags: 0,
1199 name: dev->board_name, dev);
1200 if (ret == 0) {
1201 dev->irq = irq;
1202
1203 switch (irq) {
1204 case 3:
1205 devpriv->irq_dma_bits |= 0x8;
1206 break;
1207 case 5:
1208 devpriv->irq_dma_bits |= 0x10;
1209 break;
1210 case 7:
1211 devpriv->irq_dma_bits |= 0x18;
1212 break;
1213 case 10:
1214 devpriv->irq_dma_bits |= 0x28;
1215 break;
1216 case 11:
1217 devpriv->irq_dma_bits |= 0x30;
1218 break;
1219 case 15:
1220 devpriv->irq_dma_bits |= 0x38;
1221 break;
1222 }
1223 }
1224 }
1225
1226 /* an irq and one dma channel is required to use dma */
1227 if (dev->irq & it->options[2])
1228 das1800_init_dma(dev, it);
1229
1230 devpriv->fifo_buf = kmalloc_array(FIFO_SIZE,
1231 size: sizeof(*devpriv->fifo_buf),
1232 GFP_KERNEL);
1233 if (!devpriv->fifo_buf)
1234 return -ENOMEM;
1235
1236 dev->pacer = comedi_8254_io_alloc(iobase: dev->iobase + DAS1800_COUNTER,
1237 I8254_OSC_BASE_5MHZ, I8254_IO8, regshift: 0);
1238 if (IS_ERR(ptr: dev->pacer))
1239 return PTR_ERR(ptr: dev->pacer);
1240
1241 ret = comedi_alloc_subdevices(dev, num_subdevices: 4);
1242 if (ret)
1243 return ret;
1244
1245 /*
1246 * Analog Input subdevice
1247 *
1248 * The "hc" type boards have 64 analog input channels and a 64
1249 * entry QRAM fifo.
1250 *
1251 * All the other board types have 16 on-board channels. Each channel
1252 * can be expanded to 16 channels with the addition of an EXP-1800
1253 * expansion board for a total of 256 channels. The QRAM fifo on
1254 * these boards has 256 entries.
1255 *
1256 * From the datasheets it's not clear what the comedi channel to
1257 * actual physical channel mapping is when EXP-1800 boards are used.
1258 */
1259 s = &dev->subdevices[0];
1260 s->type = COMEDI_SUBD_AI;
1261 s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
1262 if (board->id != DAS1800_ID_HC)
1263 s->subdev_flags |= SDF_COMMON;
1264 s->n_chan = (board->id == DAS1800_ID_HC) ? 64 : 256;
1265 s->maxdata = is_16bit ? 0xffff : 0x0fff;
1266 s->range_table = board->is_01_series ? &das1801_ai_range
1267 : &das1802_ai_range;
1268 s->insn_read = das1800_ai_insn_read;
1269 if (dev->irq) {
1270 dev->read_subdev = s;
1271 s->subdev_flags |= SDF_CMD_READ;
1272 s->len_chanlist = s->n_chan;
1273 s->do_cmd = das1800_ai_cmd;
1274 s->do_cmdtest = das1800_ai_cmdtest;
1275 s->poll = das1800_ai_poll;
1276 s->cancel = das1800_ai_cancel;
1277 s->munge = das1800_ai_munge;
1278 }
1279
1280 /* Analog Output subdevice */
1281 s = &dev->subdevices[1];
1282 if (board->id == DAS1800_ID_ST_DA || board->id == DAS1800_ID_HR_DA) {
1283 s->type = COMEDI_SUBD_AO;
1284 s->subdev_flags = SDF_WRITABLE;
1285 s->n_chan = (board->id == DAS1800_ID_ST_DA) ? 4 : 2;
1286 s->maxdata = is_16bit ? 0xffff : 0x0fff;
1287 s->range_table = &range_bipolar10;
1288 s->insn_write = das1800_ao_insn_write;
1289
1290 ret = comedi_alloc_subdev_readback(s);
1291 if (ret)
1292 return ret;
1293
1294 /* initialize all channels to 0V */
1295 for (i = 0; i < s->n_chan; i++) {
1296 /* spinlock is not necessary during the attach */
1297 outb(DAC(i), port: dev->iobase + DAS1800_SELECT);
1298 outw(value: 0, port: dev->iobase + DAS1800_DAC);
1299 }
1300 } else if (board->id == DAS1800_ID_AO) {
1301 /*
1302 * 'ao' boards have waveform analog outputs that are not
1303 * currently supported.
1304 */
1305 s->type = COMEDI_SUBD_UNUSED;
1306 } else {
1307 s->type = COMEDI_SUBD_UNUSED;
1308 }
1309
1310 /* Digital Input subdevice */
1311 s = &dev->subdevices[2];
1312 s->type = COMEDI_SUBD_DI;
1313 s->subdev_flags = SDF_READABLE;
1314 s->n_chan = 4;
1315 s->maxdata = 1;
1316 s->range_table = &range_digital;
1317 s->insn_bits = das1800_di_insn_bits;
1318
1319 /* Digital Output subdevice */
1320 s = &dev->subdevices[3];
1321 s->type = COMEDI_SUBD_DO;
1322 s->subdev_flags = SDF_WRITABLE;
1323 s->n_chan = (board->id == DAS1800_ID_HC) ? 8 : 4;
1324 s->maxdata = 1;
1325 s->range_table = &range_digital;
1326 s->insn_bits = das1800_do_insn_bits;
1327
1328 das1800_ai_cancel(dev, s: dev->read_subdev);
1329
1330 /* initialize digital out channels */
1331 outb(value: 0, port: dev->iobase + DAS1800_DIGITAL);
1332
1333 return 0;
1334};
1335
1336static void das1800_detach(struct comedi_device *dev)
1337{
1338 struct das1800_private *devpriv = dev->private;
1339
1340 das1800_free_dma(dev);
1341 if (devpriv) {
1342 kfree(objp: devpriv->fifo_buf);
1343 if (devpriv->iobase2)
1344 release_region(devpriv->iobase2, DAS1800_SIZE);
1345 }
1346 comedi_legacy_detach(dev);
1347}
1348
1349static struct comedi_driver das1800_driver = {
1350 .driver_name = "das1800",
1351 .module = THIS_MODULE,
1352 .attach = das1800_attach,
1353 .detach = das1800_detach,
1354 .num_names = ARRAY_SIZE(das1800_boards),
1355 .board_name = &das1800_boards[0].name,
1356 .offset = sizeof(struct das1800_board),
1357};
1358module_comedi_driver(das1800_driver);
1359
1360MODULE_AUTHOR("Comedi https://www.comedi.org");
1361MODULE_DESCRIPTION("Comedi driver for DAS1800 compatible ISA boards");
1362MODULE_LICENSE("GPL");
1363

source code of linux/drivers/comedi/drivers/das1800.c