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.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 ************************************************************************
24 */
25 /*
26 Driver: das800
27 Description: Keithley Metrabyte DAS800 (& compatibles)
28 Author: Frank Mori Hess <fmhess@users.sourceforge.net>
29 Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801),
30   DAS-802 (das-802),
31   [Measurement Computing] CIO-DAS800 (cio-das800),
32   CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802),
33   CIO-DAS802/16 (cio-das802/16)
34 Status: works, cio-das802/16 untested - email me if you have tested it
35 
36 Configuration options:
37   [0] - I/O port base address
38   [1] - IRQ (optional, required for timed or externally triggered conversions)
39 
40 Notes:
41 	IRQ can be omitted, although the cmd interface will not work without it.
42 
43 	All entries in the channel/gain list must use the same gain and be
44 	consecutive channels counting upwards in channel number (these are
45 	hardware limitations.)
46 
47 	I've never tested the gain setting stuff since I only have a
48 	DAS-800 board with fixed gain.
49 
50 	The cio-das802/16 does not have a fifo-empty status bit!  Therefore
51 	only fifo-half-full transfers are possible with this card.
52 */
53 /*
54 
55 cmd triggers supported:
56 	start_src:      TRIG_NOW | TRIG_EXT
57 	scan_begin_src: TRIG_FOLLOW
58 	scan_end_src:   TRIG_COUNT
59 	convert_src:    TRIG_TIMER | TRIG_EXT
60 	stop_src:       TRIG_NONE | TRIG_COUNT
61 
62 
63 */
64 
65 #include <linux/interrupt.h>
66 #include "../comedidev.h"
67 
68 #include <linux/ioport.h>
69 #include <linux/delay.h>
70 
71 #include "8253.h"
72 #include "comedi_fc.h"
73 
74 #define DAS800_SIZE           8
75 #define TIMER_BASE            1000
76 #define N_CHAN_AI             8	/*  number of analog input channels */
77 
78 /* Registers for the das800 */
79 
80 #define DAS800_LSB            0
81 #define   FIFO_EMPTY            0x1
82 #define   FIFO_OVF              0x2
83 #define DAS800_MSB            1
84 #define DAS800_CONTROL1       2
85 #define   CONTROL1_INTE         0x8
86 #define DAS800_CONV_CONTROL   2
87 #define   ITE                   0x1
88 #define   CASC                  0x2
89 #define   DTEN                  0x4
90 #define   IEOC                  0x8
91 #define   EACS                  0x10
92 #define   CONV_HCEN             0x80
93 #define DAS800_SCAN_LIMITS    2
94 #define DAS800_STATUS         2
95 #define   IRQ                   0x8
96 #define   BUSY                  0x80
97 #define DAS800_GAIN           3
98 #define   CIO_FFOV              0x8	/*  fifo overflow for cio-das802/16 */
99 #define   CIO_ENHF              0x90	/*  interrupt fifo half full for cio-das802/16 */
100 #define   CONTROL1              0x80
101 #define   CONV_CONTROL          0xa0
102 #define   SCAN_LIMITS           0xc0
103 #define   ID                    0xe0
104 #define DAS800_8254           4
105 #define DAS800_STATUS2        7
106 #define   STATUS2_HCEN          0x80
107 #define   STATUS2_INTE          0X20
108 #define DAS800_ID             7
109 
110 struct das800_board {
111 	const char *name;
112 	int ai_speed;
113 	const struct comedi_lrange *ai_range;
114 	int resolution;
115 };
116 
117 /* analog input ranges */
118 static const struct comedi_lrange range_das800_ai = {
119 	1,
120 	{
121 	 RANGE(-5, 5),
122 	 }
123 };
124 
125 static const struct comedi_lrange range_das801_ai = {
126 	9,
127 	{
128 	 RANGE(-5, 5),
129 	 RANGE(-10, 10),
130 	 RANGE(0, 10),
131 	 RANGE(-0.5, 0.5),
132 	 RANGE(0, 1),
133 	 RANGE(-0.05, 0.05),
134 	 RANGE(0, 0.1),
135 	 RANGE(-0.01, 0.01),
136 	 RANGE(0, 0.02),
137 	 }
138 };
139 
140 static const struct comedi_lrange range_cio_das801_ai = {
141 	9,
142 	{
143 	 RANGE(-5, 5),
144 	 RANGE(-10, 10),
145 	 RANGE(0, 10),
146 	 RANGE(-0.5, 0.5),
147 	 RANGE(0, 1),
148 	 RANGE(-0.05, 0.05),
149 	 RANGE(0, 0.1),
150 	 RANGE(-0.005, 0.005),
151 	 RANGE(0, 0.01),
152 	 }
153 };
154 
155 static const struct comedi_lrange range_das802_ai = {
156 	9,
157 	{
158 	 RANGE(-5, 5),
159 	 RANGE(-10, 10),
160 	 RANGE(0, 10),
161 	 RANGE(-2.5, 2.5),
162 	 RANGE(0, 5),
163 	 RANGE(-1.25, 1.25),
164 	 RANGE(0, 2.5),
165 	 RANGE(-0.625, 0.625),
166 	 RANGE(0, 1.25),
167 	 }
168 };
169 
170 static const struct comedi_lrange range_das80216_ai = {
171 	8,
172 	{
173 	 RANGE(-10, 10),
174 	 RANGE(0, 10),
175 	 RANGE(-5, 5),
176 	 RANGE(0, 5),
177 	 RANGE(-2.5, 2.5),
178 	 RANGE(0, 2.5),
179 	 RANGE(-1.25, 1.25),
180 	 RANGE(0, 1.25),
181 	 }
182 };
183 
184 enum { das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 };
185 
186 static const struct das800_board das800_boards[] = {
187 	{
188 	 .name = "das-800",
189 	 .ai_speed = 25000,
190 	 .ai_range = &range_das800_ai,
191 	 .resolution = 12,
192 	 },
193 	{
194 	 .name = "cio-das800",
195 	 .ai_speed = 20000,
196 	 .ai_range = &range_das800_ai,
197 	 .resolution = 12,
198 	 },
199 	{
200 	 .name = "das-801",
201 	 .ai_speed = 25000,
202 	 .ai_range = &range_das801_ai,
203 	 .resolution = 12,
204 	 },
205 	{
206 	 .name = "cio-das801",
207 	 .ai_speed = 20000,
208 	 .ai_range = &range_cio_das801_ai,
209 	 .resolution = 12,
210 	 },
211 	{
212 	 .name = "das-802",
213 	 .ai_speed = 25000,
214 	 .ai_range = &range_das802_ai,
215 	 .resolution = 12,
216 	 },
217 	{
218 	 .name = "cio-das802",
219 	 .ai_speed = 20000,
220 	 .ai_range = &range_das802_ai,
221 	 .resolution = 12,
222 	 },
223 	{
224 	 .name = "cio-das802/16",
225 	 .ai_speed = 10000,
226 	 .ai_range = &range_das80216_ai,
227 	 .resolution = 16,
228 	 },
229 };
230 
231 /*
232  * Useful for shorthand access to the particular board structure
233  */
234 #define thisboard ((const struct das800_board *)dev->board_ptr)
235 
236 struct das800_private {
237 	volatile unsigned int count;	/* number of data points left to be taken */
238 	volatile int forever;	/* flag indicating whether we should take data forever */
239 	unsigned int divisor1;	/* value to load into board's counter 1 for timed conversions */
240 	unsigned int divisor2;	/* value to load into board's counter 2 for timed conversions */
241 	volatile int do_bits;	/* digital output bits */
242 };
243 
244 #define devpriv ((struct das800_private *)dev->private)
245 
246 static int das800_attach(struct comedi_device *dev,
247 			 struct comedi_devconfig *it);
248 static int das800_detach(struct comedi_device *dev);
249 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
250 
251 static struct comedi_driver driver_das800 = {
252 	.driver_name = "das800",
253 	.module = THIS_MODULE,
254 	.attach = das800_attach,
255 	.detach = das800_detach,
256 	.num_names = ARRAY_SIZE(das800_boards),
257 	.board_name = &das800_boards[0].name,
258 	.offset = sizeof(struct das800_board),
259 };
260 
261 static irqreturn_t das800_interrupt(int irq, void *d);
262 static void enable_das800(struct comedi_device *dev);
263 static void disable_das800(struct comedi_device *dev);
264 static int das800_ai_do_cmdtest(struct comedi_device *dev,
265 				struct comedi_subdevice *s,
266 				struct comedi_cmd *cmd);
267 static int das800_ai_do_cmd(struct comedi_device *dev,
268 			    struct comedi_subdevice *s);
269 static int das800_ai_rinsn(struct comedi_device *dev,
270 			   struct comedi_subdevice *s, struct comedi_insn *insn,
271 			   unsigned int *data);
272 static int das800_di_rbits(struct comedi_device *dev,
273 			   struct comedi_subdevice *s, struct comedi_insn *insn,
274 			   unsigned int *data);
275 static int das800_do_wbits(struct comedi_device *dev,
276 			   struct comedi_subdevice *s, struct comedi_insn *insn,
277 			   unsigned int *data);
278 static int das800_probe(struct comedi_device *dev);
279 static int das800_set_frequency(struct comedi_device *dev);
280 
281 /* checks and probes das-800 series board type */
das800_probe(struct comedi_device * dev)282 static int das800_probe(struct comedi_device *dev)
283 {
284 	int id_bits;
285 	unsigned long irq_flags;
286 	int board;
287 
288 	/*  'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */
289 	spin_lock_irqsave(&dev->spinlock, irq_flags);
290 	outb(ID, dev->iobase + DAS800_GAIN);	/* select base address + 7 to be ID register */
291 	id_bits = inb(dev->iobase + DAS800_ID) & 0x3;	/* get id bits */
292 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
293 
294 	board = thisboard - das800_boards;
295 
296 	switch (id_bits) {
297 	case 0x0:
298 		if (board == das800) {
299 			dev_dbg(dev->hw_dev, "Board model: DAS-800\n");
300 			return board;
301 		}
302 		if (board == ciodas800) {
303 			dev_dbg(dev->hw_dev, "Board model: CIO-DAS800\n");
304 			return board;
305 		}
306 		dev_dbg(dev->hw_dev, "Board model (probed): DAS-800\n");
307 		return das800;
308 		break;
309 	case 0x2:
310 		if (board == das801) {
311 			dev_dbg(dev->hw_dev, "Board model: DAS-801\n");
312 			return board;
313 		}
314 		if (board == ciodas801) {
315 			dev_dbg(dev->hw_dev, "Board model: CIO-DAS801\n");
316 			return board;
317 		}
318 		dev_dbg(dev->hw_dev, "Board model (probed): DAS-801\n");
319 		return das801;
320 		break;
321 	case 0x3:
322 		if (board == das802) {
323 			dev_dbg(dev->hw_dev, "Board model: DAS-802\n");
324 			return board;
325 		}
326 		if (board == ciodas802) {
327 			dev_dbg(dev->hw_dev, "Board model: CIO-DAS802\n");
328 			return board;
329 		}
330 		if (board == ciodas80216) {
331 			dev_dbg(dev->hw_dev, "Board model: CIO-DAS802/16\n");
332 			return board;
333 		}
334 		dev_dbg(dev->hw_dev, "Board model (probed): DAS-802\n");
335 		return das802;
336 		break;
337 	default:
338 		dev_dbg(dev->hw_dev, "Board model: probe returned 0x%x (unknown)\n",
339 			id_bits);
340 		return board;
341 		break;
342 	}
343 	return -1;
344 }
345 
346 /*
347  * A convenient macro that defines init_module() and cleanup_module(),
348  * as necessary.
349  */
driver_das800_init_module(void)350 static int __init driver_das800_init_module(void)
351 {
352 	return comedi_driver_register(&driver_das800);
353 }
354 
driver_das800_cleanup_module(void)355 static void __exit driver_das800_cleanup_module(void)
356 {
357 	comedi_driver_unregister(&driver_das800);
358 }
359 
360 module_init(driver_das800_init_module);
361 module_exit(driver_das800_cleanup_module);
362 
363 /* interrupt service routine */
das800_interrupt(int irq,void * d)364 static irqreturn_t das800_interrupt(int irq, void *d)
365 {
366 	short i;		/* loop index */
367 	short dataPoint = 0;
368 	struct comedi_device *dev = d;
369 	struct comedi_subdevice *s = dev->read_subdev;	/* analog input subdevice */
370 	struct comedi_async *async;
371 	int status;
372 	unsigned long irq_flags;
373 	static const int max_loops = 128;	/*  half-fifo size for cio-das802/16 */
374 	/*  flags */
375 	int fifo_empty = 0;
376 	int fifo_overflow = 0;
377 
378 	status = inb(dev->iobase + DAS800_STATUS);
379 	/* if interrupt was not generated by board or driver not attached, quit */
380 	if (!(status & IRQ))
381 		return IRQ_NONE;
382 	if (!(dev->attached))
383 		return IRQ_HANDLED;
384 
385 	/* wait until here to initialize async, since we will get null dereference
386 	 * if interrupt occurs before driver is fully attached!
387 	 */
388 	async = s->async;
389 
390 	/*  if hardware conversions are not enabled, then quit */
391 	spin_lock_irqsave(&dev->spinlock, irq_flags);
392 	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select base address + 7 to be STATUS2 register */
393 	status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;
394 	/* don't release spinlock yet since we want to make sure no one else disables hardware conversions */
395 	if (status == 0) {
396 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
397 		return IRQ_HANDLED;
398 	}
399 
400 	/* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */
401 	for (i = 0; i < max_loops; i++) {
402 		/* read 16 bits from dev->iobase and dev->iobase + 1 */
403 		dataPoint = inb(dev->iobase + DAS800_LSB);
404 		dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
405 		if (thisboard->resolution == 12) {
406 			fifo_empty = dataPoint & FIFO_EMPTY;
407 			fifo_overflow = dataPoint & FIFO_OVF;
408 			if (fifo_overflow)
409 				break;
410 		} else {
411 			fifo_empty = 0;	/*  cio-das802/16 has no fifo empty status bit */
412 		}
413 		if (fifo_empty)
414 			break;
415 		/* strip off extraneous bits for 12 bit cards */
416 		if (thisboard->resolution == 12)
417 			dataPoint = (dataPoint >> 4) & 0xfff;
418 		/* if there are more data points to collect */
419 		if (devpriv->count > 0 || devpriv->forever == 1) {
420 			/* write data point to buffer */
421 			cfc_write_to_buffer(s, dataPoint);
422 			if (devpriv->count > 0)
423 				devpriv->count--;
424 		}
425 	}
426 	async->events |= COMEDI_CB_BLOCK;
427 	/* check for fifo overflow */
428 	if (thisboard->resolution == 12) {
429 		fifo_overflow = dataPoint & FIFO_OVF;
430 		/*  else cio-das802/16 */
431 	} else {
432 		fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
433 	}
434 	if (fifo_overflow) {
435 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
436 		comedi_error(dev, "DAS800 FIFO overflow");
437 		das800_cancel(dev, dev->subdevices + 0);
438 		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
439 		comedi_event(dev, s);
440 		async->events = 0;
441 		return IRQ_HANDLED;
442 	}
443 	if (devpriv->count > 0 || devpriv->forever == 1) {
444 		/* Re-enable card's interrupt.
445 		 * We already have spinlock, so indirect addressing is safe */
446 		outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */
447 		outb(CONTROL1_INTE | devpriv->do_bits,
448 		     dev->iobase + DAS800_CONTROL1);
449 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
450 		/* otherwise, stop taking data */
451 	} else {
452 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
453 		disable_das800(dev);	/* diable hardware triggered conversions */
454 		async->events |= COMEDI_CB_EOA;
455 	}
456 	comedi_event(dev, s);
457 	async->events = 0;
458 	return IRQ_HANDLED;
459 }
460 
das800_attach(struct comedi_device * dev,struct comedi_devconfig * it)461 static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
462 {
463 	struct comedi_subdevice *s;
464 	unsigned long iobase = it->options[0];
465 	unsigned int irq = it->options[1];
466 	unsigned long irq_flags;
467 	int board;
468 
469 	dev_info(dev->hw_dev, "comedi%d: das800: io 0x%lx\n", dev->minor,
470 		 iobase);
471 	if (irq)
472 		dev_dbg(dev->hw_dev, "irq %u\n", irq);
473 
474 	/* allocate and initialize dev->private */
475 	if (alloc_private(dev, sizeof(struct das800_private)) < 0)
476 		return -ENOMEM;
477 
478 	if (iobase == 0) {
479 		dev_err(dev->hw_dev, "io base address required for das800\n");
480 		return -EINVAL;
481 	}
482 
483 	/* check if io addresses are available */
484 	if (!request_region(iobase, DAS800_SIZE, "das800")) {
485 		dev_err(dev->hw_dev, "I/O port conflict\n");
486 		return -EIO;
487 	}
488 	dev->iobase = iobase;
489 
490 	board = das800_probe(dev);
491 	if (board < 0) {
492 		dev_dbg(dev->hw_dev, "unable to determine board type\n");
493 		return -ENODEV;
494 	}
495 	dev->board_ptr = das800_boards + board;
496 
497 	/* grab our IRQ */
498 	if (irq == 1 || irq > 7) {
499 		dev_err(dev->hw_dev, "irq out of range\n");
500 		return -EINVAL;
501 	}
502 	if (irq) {
503 		if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
504 			dev_err(dev->hw_dev, "unable to allocate irq %u\n",
505 				irq);
506 			return -EINVAL;
507 		}
508 	}
509 	dev->irq = irq;
510 
511 	dev->board_name = thisboard->name;
512 
513 	if (alloc_subdevices(dev, 3) < 0)
514 		return -ENOMEM;
515 
516 	/* analog input subdevice */
517 	s = dev->subdevices + 0;
518 	dev->read_subdev = s;
519 	s->type = COMEDI_SUBD_AI;
520 	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
521 	s->n_chan = 8;
522 	s->len_chanlist = 8;
523 	s->maxdata = (1 << thisboard->resolution) - 1;
524 	s->range_table = thisboard->ai_range;
525 	s->do_cmd = das800_ai_do_cmd;
526 	s->do_cmdtest = das800_ai_do_cmdtest;
527 	s->insn_read = das800_ai_rinsn;
528 	s->cancel = das800_cancel;
529 
530 	/* di */
531 	s = dev->subdevices + 1;
532 	s->type = COMEDI_SUBD_DI;
533 	s->subdev_flags = SDF_READABLE;
534 	s->n_chan = 3;
535 	s->maxdata = 1;
536 	s->range_table = &range_digital;
537 	s->insn_bits = das800_di_rbits;
538 
539 	/* do */
540 	s = dev->subdevices + 2;
541 	s->type = COMEDI_SUBD_DO;
542 	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
543 	s->n_chan = 4;
544 	s->maxdata = 1;
545 	s->range_table = &range_digital;
546 	s->insn_bits = das800_do_wbits;
547 
548 	disable_das800(dev);
549 
550 	/* initialize digital out channels */
551 	spin_lock_irqsave(&dev->spinlock, irq_flags);
552 	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */
553 	outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
554 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
555 
556 	return 0;
557 };
558 
das800_detach(struct comedi_device * dev)559 static int das800_detach(struct comedi_device *dev)
560 {
561 	dev_info(dev->hw_dev, "comedi%d: das800: remove\n", dev->minor);
562 
563 	/* only free stuff if it has been allocated by _attach */
564 	if (dev->iobase)
565 		release_region(dev->iobase, DAS800_SIZE);
566 	if (dev->irq)
567 		free_irq(dev->irq, dev);
568 	return 0;
569 };
570 
das800_cancel(struct comedi_device * dev,struct comedi_subdevice * s)571 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
572 {
573 	devpriv->forever = 0;
574 	devpriv->count = 0;
575 	disable_das800(dev);
576 	return 0;
577 }
578 
579 /* enable_das800 makes the card start taking hardware triggered conversions */
enable_das800(struct comedi_device * dev)580 static void enable_das800(struct comedi_device *dev)
581 {
582 	unsigned long irq_flags;
583 	spin_lock_irqsave(&dev->spinlock, irq_flags);
584 	/*  enable fifo-half full interrupts for cio-das802/16 */
585 	if (thisboard->resolution == 16)
586 		outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
587 	outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be conversion control register */
588 	outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL);	/* enable hardware triggering */
589 	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */
590 	outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);	/* enable card's interrupt */
591 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
592 }
593 
594 /* disable_das800 stops hardware triggered conversions */
disable_das800(struct comedi_device * dev)595 static void disable_das800(struct comedi_device *dev)
596 {
597 	unsigned long irq_flags;
598 	spin_lock_irqsave(&dev->spinlock, irq_flags);
599 	outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be conversion control register */
600 	outb(0x0, dev->iobase + DAS800_CONV_CONTROL);	/* disable hardware triggering of conversions */
601 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
602 }
603 
das800_ai_do_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)604 static int das800_ai_do_cmdtest(struct comedi_device *dev,
605 				struct comedi_subdevice *s,
606 				struct comedi_cmd *cmd)
607 {
608 	int err = 0;
609 	int tmp;
610 	int gain, startChan;
611 	int i;
612 
613 	/* step 1: make sure trigger sources are trivially valid */
614 
615 	tmp = cmd->start_src;
616 	cmd->start_src &= TRIG_NOW | TRIG_EXT;
617 	if (!cmd->start_src || tmp != cmd->start_src)
618 		err++;
619 
620 	tmp = cmd->scan_begin_src;
621 	cmd->scan_begin_src &= TRIG_FOLLOW;
622 	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
623 		err++;
624 
625 	tmp = cmd->convert_src;
626 	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
627 	if (!cmd->convert_src || tmp != cmd->convert_src)
628 		err++;
629 
630 	tmp = cmd->scan_end_src;
631 	cmd->scan_end_src &= TRIG_COUNT;
632 	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
633 		err++;
634 
635 	tmp = cmd->stop_src;
636 	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
637 	if (!cmd->stop_src || tmp != cmd->stop_src)
638 		err++;
639 
640 	if (err)
641 		return 1;
642 
643 	/* step 2: make sure trigger sources are unique and mutually compatible */
644 
645 	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
646 		err++;
647 	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
648 		err++;
649 	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
650 		err++;
651 
652 	if (err)
653 		return 2;
654 
655 	/* step 3: make sure arguments are trivially compatible */
656 
657 	if (cmd->start_arg != 0) {
658 		cmd->start_arg = 0;
659 		err++;
660 	}
661 	if (cmd->convert_src == TRIG_TIMER) {
662 		if (cmd->convert_arg < thisboard->ai_speed) {
663 			cmd->convert_arg = thisboard->ai_speed;
664 			err++;
665 		}
666 	}
667 	if (!cmd->chanlist_len) {
668 		cmd->chanlist_len = 1;
669 		err++;
670 	}
671 	if (cmd->scan_end_arg != cmd->chanlist_len) {
672 		cmd->scan_end_arg = cmd->chanlist_len;
673 		err++;
674 	}
675 	if (cmd->stop_src == TRIG_COUNT) {
676 		if (!cmd->stop_arg) {
677 			cmd->stop_arg = 1;
678 			err++;
679 		}
680 	} else {		/* TRIG_NONE */
681 		if (cmd->stop_arg != 0) {
682 			cmd->stop_arg = 0;
683 			err++;
684 		}
685 	}
686 
687 	if (err)
688 		return 3;
689 
690 	/* step 4: fix up any arguments */
691 
692 	if (cmd->convert_src == TRIG_TIMER) {
693 		tmp = cmd->convert_arg;
694 		/* calculate counter values that give desired timing */
695 		i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
696 					       &(devpriv->divisor2),
697 					       &(cmd->convert_arg),
698 					       cmd->flags & TRIG_ROUND_MASK);
699 		if (tmp != cmd->convert_arg)
700 			err++;
701 	}
702 
703 	if (err)
704 		return 4;
705 
706 	/*  check channel/gain list against card's limitations */
707 	if (cmd->chanlist) {
708 		gain = CR_RANGE(cmd->chanlist[0]);
709 		startChan = CR_CHAN(cmd->chanlist[0]);
710 		for (i = 1; i < cmd->chanlist_len; i++) {
711 			if (CR_CHAN(cmd->chanlist[i]) !=
712 			    (startChan + i) % N_CHAN_AI) {
713 				comedi_error(dev,
714 					     "entries in chanlist must be consecutive channels, counting upwards\n");
715 				err++;
716 			}
717 			if (CR_RANGE(cmd->chanlist[i]) != gain) {
718 				comedi_error(dev,
719 					     "entries in chanlist must all have the same gain\n");
720 				err++;
721 			}
722 		}
723 	}
724 
725 	if (err)
726 		return 5;
727 
728 	return 0;
729 }
730 
das800_ai_do_cmd(struct comedi_device * dev,struct comedi_subdevice * s)731 static int das800_ai_do_cmd(struct comedi_device *dev,
732 			    struct comedi_subdevice *s)
733 {
734 	int startChan, endChan, scan, gain;
735 	int conv_bits;
736 	unsigned long irq_flags;
737 	struct comedi_async *async = s->async;
738 
739 	if (!dev->irq) {
740 		comedi_error(dev,
741 			     "no irq assigned for das-800, cannot do hardware conversions");
742 		return -1;
743 	}
744 
745 	disable_das800(dev);
746 
747 	/* set channel scan limits */
748 	startChan = CR_CHAN(async->cmd.chanlist[0]);
749 	endChan = (startChan + async->cmd.chanlist_len - 1) % 8;
750 	scan = (endChan << 3) | startChan;
751 
752 	spin_lock_irqsave(&dev->spinlock, irq_flags);
753 	outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN);	/* select base address + 2 to be scan limits register */
754 	outb(scan, dev->iobase + DAS800_SCAN_LIMITS);	/* set scan limits */
755 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
756 
757 	/* set gain */
758 	gain = CR_RANGE(async->cmd.chanlist[0]);
759 	if (thisboard->resolution == 12 && gain > 0)
760 		gain += 0x7;
761 	gain &= 0xf;
762 	outb(gain, dev->iobase + DAS800_GAIN);
763 
764 	switch (async->cmd.stop_src) {
765 	case TRIG_COUNT:
766 		devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
767 		devpriv->forever = 0;
768 		break;
769 	case TRIG_NONE:
770 		devpriv->forever = 1;
771 		devpriv->count = 0;
772 		break;
773 	default:
774 		break;
775 	}
776 
777 	/* enable auto channel scan, send interrupts on end of conversion
778 	 * and set clock source to internal or external
779 	 */
780 	conv_bits = 0;
781 	conv_bits |= EACS | IEOC;
782 	if (async->cmd.start_src == TRIG_EXT)
783 		conv_bits |= DTEN;
784 	switch (async->cmd.convert_src) {
785 	case TRIG_TIMER:
786 		conv_bits |= CASC | ITE;
787 		/* set conversion frequency */
788 		i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
789 					       &(devpriv->divisor2),
790 					       &(async->cmd.convert_arg),
791 					       async->cmd.
792 					       flags & TRIG_ROUND_MASK);
793 		if (das800_set_frequency(dev) < 0) {
794 			comedi_error(dev, "Error setting up counters");
795 			return -1;
796 		}
797 		break;
798 	case TRIG_EXT:
799 		break;
800 	default:
801 		break;
802 	}
803 
804 	spin_lock_irqsave(&dev->spinlock, irq_flags);
805 	outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be conversion control register */
806 	outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL);
807 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
808 	async->events = 0;
809 	enable_das800(dev);
810 	return 0;
811 }
812 
das800_ai_rinsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)813 static int das800_ai_rinsn(struct comedi_device *dev,
814 			   struct comedi_subdevice *s, struct comedi_insn *insn,
815 			   unsigned int *data)
816 {
817 	int i, n;
818 	int chan;
819 	int range;
820 	int lsb, msb;
821 	int timeout = 1000;
822 	unsigned long irq_flags;
823 
824 	disable_das800(dev);	/* disable hardware conversions (enables software conversions) */
825 
826 	/* set multiplexer */
827 	chan = CR_CHAN(insn->chanspec);
828 
829 	spin_lock_irqsave(&dev->spinlock, irq_flags);
830 	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */
831 	outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
832 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
833 
834 	/* set gain / range */
835 	range = CR_RANGE(insn->chanspec);
836 	if (thisboard->resolution == 12 && range)
837 		range += 0x7;
838 	range &= 0xf;
839 	outb(range, dev->iobase + DAS800_GAIN);
840 
841 	udelay(5);
842 
843 	for (n = 0; n < insn->n; n++) {
844 		/* trigger conversion */
845 		outb_p(0, dev->iobase + DAS800_MSB);
846 
847 		for (i = 0; i < timeout; i++) {
848 			if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
849 				break;
850 		}
851 		if (i == timeout) {
852 			comedi_error(dev, "timeout");
853 			return -ETIME;
854 		}
855 		lsb = inb(dev->iobase + DAS800_LSB);
856 		msb = inb(dev->iobase + DAS800_MSB);
857 		if (thisboard->resolution == 12) {
858 			data[n] = (lsb >> 4) & 0xff;
859 			data[n] |= (msb << 4);
860 		} else {
861 			data[n] = (msb << 8) | lsb;
862 		}
863 	}
864 
865 	return n;
866 }
867 
das800_di_rbits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)868 static int das800_di_rbits(struct comedi_device *dev,
869 			   struct comedi_subdevice *s, struct comedi_insn *insn,
870 			   unsigned int *data)
871 {
872 	unsigned int bits;
873 
874 	bits = inb(dev->iobase + DAS800_STATUS) >> 4;
875 	bits &= 0x7;
876 	data[1] = bits;
877 	data[0] = 0;
878 
879 	return 2;
880 }
881 
das800_do_wbits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)882 static int das800_do_wbits(struct comedi_device *dev,
883 			   struct comedi_subdevice *s, struct comedi_insn *insn,
884 			   unsigned int *data)
885 {
886 	int wbits;
887 	unsigned long irq_flags;
888 
889 	/*  only set bits that have been masked */
890 	data[0] &= 0xf;
891 	wbits = devpriv->do_bits >> 4;
892 	wbits &= ~data[0];
893 	wbits |= data[0] & data[1];
894 	devpriv->do_bits = wbits << 4;
895 
896 	spin_lock_irqsave(&dev->spinlock, irq_flags);
897 	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */
898 	outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1);
899 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
900 
901 	data[1] = wbits;
902 
903 	return 2;
904 }
905 
906 /* loads counters with divisor1, divisor2 from private structure */
das800_set_frequency(struct comedi_device * dev)907 static int das800_set_frequency(struct comedi_device *dev)
908 {
909 	int err = 0;
910 
911 	if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
912 		err++;
913 	if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
914 		err++;
915 	if (err)
916 		return -1;
917 
918 	return 0;
919 }
920 
921 MODULE_AUTHOR("Comedi http://www.comedi.org");
922 MODULE_DESCRIPTION("Comedi low-level driver");
923 MODULE_LICENSE("GPL");
924