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 /*
20 Driver: das800
21 Description: Keithley Metrabyte DAS800 (& compatibles)
22 Author: Frank Mori Hess <fmhess@users.sourceforge.net>
23 Devices: [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)
28 Status: works, cio-das802/16 untested - email me if you have tested it
29 
30 Configuration options:
31   [0] - I/O port base address
32   [1] - IRQ (optional, required for timed or externally triggered conversions)
33 
34 Notes:
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.
46 
47 cmd 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
53 */
54 
55 #include <linux/module.h>
56 #include <linux/interrupt.h>
57 #include <linux/delay.h>
58 
59 #include "../comedidev.h"
60 
61 #include "comedi_8254.h"
62 
63 #define N_CHAN_AI             8	/*  number of analog input channels */
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
85 #define   CIO_FFOV              0x8   /* cio-das802/16 fifo overflow */
86 #define   CIO_ENHF              0x90  /* cio-das802/16 fifo half full int ena */
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 
97 #define DAS802_16_HALF_FIFO_SZ	128
98 
99 struct das800_board {
100 	const char *name;
101 	int ai_speed;
102 	const struct comedi_lrange *ai_range;
103 	int resolution;
104 };
105 
106 static const struct comedi_lrange range_das801_ai = {
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 	}
118 };
119 
120 static const struct comedi_lrange range_cio_das801_ai = {
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 	}
132 };
133 
134 static const struct comedi_lrange range_das802_ai = {
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 	}
146 };
147 
148 static const struct comedi_lrange range_das80216_ai = {
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 	}
159 };
160 
161 enum das800_boardinfo {
162 	BOARD_DAS800,
163 	BOARD_CIODAS800,
164 	BOARD_DAS801,
165 	BOARD_CIODAS801,
166 	BOARD_DAS802,
167 	BOARD_CIODAS802,
168 	BOARD_CIODAS80216,
169 };
170 
171 static const struct das800_board das800_boards[] = {
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 	},
214 };
215 
216 struct das800_private {
217 	unsigned int do_bits;	/* digital output bits */
218 };
219 
das800_ind_write(struct comedi_device * dev,unsigned val,unsigned reg)220 static 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 
das800_ind_read(struct comedi_device * dev,unsigned reg)231 static 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 
das800_enable(struct comedi_device * dev)241 static void das800_enable(struct comedi_device *dev)
242 {
243 	const struct das800_board *thisboard = dev->board_ptr;
244 	struct das800_private *devpriv = dev->private;
245 	unsigned long irq_flags;
246 
247 	spin_lock_irqsave(&dev->spinlock, irq_flags);
248 	/*  enable fifo-half full interrupts for cio-das802/16 */
249 	if (thisboard->resolution == 16)
250 		outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
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);
255 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
256 }
257 
das800_disable(struct comedi_device * dev)258 static void das800_disable(struct comedi_device *dev)
259 {
260 	unsigned long irq_flags;
261 
262 	spin_lock_irqsave(&dev->spinlock, irq_flags);
263 	/* disable hardware triggering of conversions */
264 	das800_ind_write(dev, 0x0, CONV_CONTROL);
265 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
266 }
267 
das800_cancel(struct comedi_device * dev,struct comedi_subdevice * s)268 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
269 {
270 	das800_disable(dev);
271 	return 0;
272 }
273 
das800_ai_check_chanlist(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)274 static 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 
das800_ai_do_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)302 static int das800_ai_do_cmdtest(struct comedi_device *dev,
303 				struct comedi_subdevice *s,
304 				struct comedi_cmd *cmd)
305 {
306 	const struct das800_board *thisboard = dev->board_ptr;
307 	int err = 0;
308 
309 	/* Step 1 : check if triggers are trivially valid */
310 
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);
317 
318 	if (err)
319 		return 1;
320 
321 	/* Step 2a : make sure trigger sources are unique */
322 
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);
326 
327 	/* Step 2b : and mutually compatible */
328 
329 	if (err)
330 		return 2;
331 
332 	/* Step 3: check if arguments are trivially valid */
333 
334 	err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
335 
336 	if (cmd->convert_src == TRIG_TIMER) {
337 		err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
338 						    thisboard->ai_speed);
339 	}
340 
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);
344 
345 	if (cmd->stop_src == TRIG_COUNT)
346 		err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
347 	else	/* TRIG_NONE */
348 		err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
349 
350 	if (err)
351 		return 3;
352 
353 	/* step 4: fix up any arguments */
354 
355 	if (cmd->convert_src == TRIG_TIMER) {
356 		unsigned int arg = cmd->convert_arg;
357 
358 		comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
359 		err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
360 	}
361 
362 	if (err)
363 		return 4;
364 
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);
368 
369 	if (err)
370 		return 5;
371 
372 	return 0;
373 }
374 
das800_ai_do_cmd(struct comedi_device * dev,struct comedi_subdevice * s)375 static int das800_ai_do_cmd(struct comedi_device *dev,
376 			    struct comedi_subdevice *s)
377 {
378 	const struct das800_board *thisboard = dev->board_ptr;
379 	struct comedi_async *async = s->async;
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;
384 	unsigned int scan_chans = (end_chan << 3) | start_chan;
385 	int conv_bits;
386 	unsigned long irq_flags;
387 
388 	das800_disable(dev);
389 
390 	spin_lock_irqsave(&dev->spinlock, irq_flags);
391 	/* set scan limits */
392 	das800_ind_write(dev, scan_chans, SCAN_LIMITS);
393 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
394 
395 	/* set gain */
396 	if (thisboard->resolution == 12 && gain > 0)
397 		gain += 0x7;
398 	gain &= 0xf;
399 	outb(gain, dev->iobase + DAS800_GAIN);
400 
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;
406 	if (cmd->start_src == TRIG_EXT)
407 		conv_bits |= DTEN;
408 	if (cmd->convert_src == TRIG_TIMER) {
409 		conv_bits |= CASC | ITE;
410 		comedi_8254_update_divisors(dev->pacer);
411 		comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
412 	}
413 
414 	spin_lock_irqsave(&dev->spinlock, irq_flags);
415 	das800_ind_write(dev, conv_bits, CONV_CONTROL);
416 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
417 
418 	das800_enable(dev);
419 	return 0;
420 }
421 
das800_ai_get_sample(struct comedi_device * dev)422 static 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 
das800_interrupt(int irq,void * d)430 static irqreturn_t das800_interrupt(int irq, void *d)
431 {
432 	struct comedi_device *dev = d;
433 	struct das800_private *devpriv = dev->private;
434 	struct comedi_subdevice *s = dev->read_subdev;
435 	struct comedi_async *async;
436 	struct comedi_cmd *cmd;
437 	unsigned long irq_flags;
438 	unsigned int status;
439 	unsigned int val;
440 	bool fifo_empty;
441 	bool fifo_overflow;
442 	int i;
443 
444 	status = inb(dev->iobase + DAS800_STATUS);
445 	if (!(status & IRQ))
446 		return IRQ_NONE;
447 	if (!dev->attached)
448 		return IRQ_HANDLED;
449 
450 	async = s->async;
451 	cmd = &async->cmd;
452 
453 	spin_lock_irqsave(&dev->spinlock, irq_flags);
454 	status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN;
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 */
461 	if (status == 0) {
462 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
463 		return IRQ_HANDLED;
464 	}
465 
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);
471 		} else {
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);
476 		}
477 		if (fifo_empty || fifo_overflow)
478 			break;
479 
480 		if (s->maxdata == 0x0fff)
481 			val >>= 4;	/* 12-bit sample */
482 
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;
490 		}
491 	}
492 
493 	if (fifo_overflow) {
494 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
495 		async->events |= COMEDI_CB_ERROR;
496 		comedi_handle_events(dev, s);
497 		return IRQ_HANDLED;
498 	}
499 
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 		 */
505 		das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
506 				 CONTROL1);
507 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
508 	} else {
509 		/* otherwise, stop taking data */
510 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
511 		das800_disable(dev);
512 	}
513 	comedi_handle_events(dev, s);
514 	return IRQ_HANDLED;
515 }
516 
das800_ai_eoc(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)517 static int das800_ai_eoc(struct comedi_device *dev,
518 			 struct comedi_subdevice *s,
519 			 struct comedi_insn *insn,
520 			 unsigned long context)
521 {
522 	unsigned int status;
523 
524 	status = inb(dev->iobase + DAS800_STATUS);
525 	if ((status & BUSY) == 0)
526 		return 0;
527 	return -EBUSY;
528 }
529 
das800_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)530 static int das800_ai_insn_read(struct comedi_device *dev,
531 			       struct comedi_subdevice *s,
532 			       struct comedi_insn *insn,
533 			       unsigned int *data)
534 {
535 	struct das800_private *devpriv = dev->private;
536 	unsigned int chan = CR_CHAN(insn->chanspec);
537 	unsigned int range = CR_RANGE(insn->chanspec);
538 	unsigned long irq_flags;
539 	unsigned int val;
540 	int ret;
541 	int i;
542 
543 	das800_disable(dev);
544 
545 	/* set multiplexer */
546 	spin_lock_irqsave(&dev->spinlock, irq_flags);
547 	das800_ind_write(dev, chan | devpriv->do_bits, CONTROL1);
548 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
549 
550 	/* set gain / range */
551 	if (s->maxdata == 0x0fff && range)
552 		range += 0x7;
553 	range &= 0xf;
554 	outb(range, dev->iobase + DAS800_GAIN);
555 
556 	udelay(5);
557 
558 	for (i = 0; i < insn->n; i++) {
559 		/* trigger conversion */
560 		outb_p(0, dev->iobase + DAS800_MSB);
561 
562 		ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0);
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;
570 	}
571 
572 	return insn->n;
573 }
574 
das800_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)575 static int das800_di_insn_bits(struct comedi_device *dev,
576 			       struct comedi_subdevice *s,
577 			       struct comedi_insn *insn,
578 			       unsigned int *data)
579 {
580 	data[1] = (inb(dev->iobase + DAS800_STATUS) >> 4) & 0x7;
581 
582 	return insn->n;
583 }
584 
das800_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)585 static int das800_do_insn_bits(struct comedi_device *dev,
586 			       struct comedi_subdevice *s,
587 			       struct comedi_insn *insn,
588 			       unsigned int *data)
589 {
590 	struct das800_private *devpriv = dev->private;
591 	unsigned long irq_flags;
592 
593 	if (comedi_dio_update_state(s, data)) {
594 		devpriv->do_bits = s->state << 4;
595 
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 	}
601 
602 	data[1] = s->state;
603 
604 	return insn->n;
605 }
606 
das800_probe(struct comedi_device * dev)607 static int das800_probe(struct comedi_device *dev)
608 {
609 	const struct das800_board *thisboard = dev->board_ptr;
610 	int board = thisboard ? thisboard - das800_boards : -EINVAL;
611 	int id_bits;
612 	unsigned long irq_flags;
613 
614 	spin_lock_irqsave(&dev->spinlock, irq_flags);
615 	id_bits = das800_ind_read(dev, ID) & 0x3;
616 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
617 
618 	switch (id_bits) {
619 	case 0x0:
620 		if (board == BOARD_DAS800 || board == BOARD_CIODAS800)
621 			break;
622 		dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
623 		board = BOARD_DAS800;
624 		break;
625 	case 0x2:
626 		if (board == BOARD_DAS801 || board == BOARD_CIODAS801)
627 			break;
628 		dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
629 		board = BOARD_DAS801;
630 		break;
631 	case 0x3:
632 		if (board == BOARD_DAS802 || board == BOARD_CIODAS802 ||
633 		    board == BOARD_CIODAS80216)
634 			break;
635 		dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
636 		board = BOARD_DAS802;
637 		break;
638 	default:
639 		dev_dbg(dev->class_dev, "Board model: 0x%x (unknown)\n",
640 			id_bits);
641 		board = -EINVAL;
642 		break;
643 	}
644 	return board;
645 }
646 
das800_attach(struct comedi_device * dev,struct comedi_devconfig * it)647 static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
648 {
649 	const struct das800_board *thisboard;
650 	struct das800_private *devpriv;
651 	struct comedi_subdevice *s;
652 	unsigned int irq = it->options[1];
653 	unsigned long irq_flags;
654 	int board;
655 	int ret;
656 
657 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
658 	if (!devpriv)
659 		return -ENOMEM;
660 
661 	ret = comedi_request_region(dev, it->options[0], 0x8);
662 	if (ret)
663 		return ret;
664 
665 	board = das800_probe(dev);
666 	if (board < 0) {
667 		dev_dbg(dev->class_dev, "unable to determine board type\n");
668 		return -ENODEV;
669 	}
670 	dev->board_ptr = das800_boards + board;
671 	thisboard = dev->board_ptr;
672 	dev->board_name = thisboard->name;
673 
674 	if (irq > 1 && irq <= 7) {
675 		ret = request_irq(irq, das800_interrupt, 0, dev->board_name,
676 				  dev);
677 		if (ret == 0)
678 			dev->irq = irq;
679 	}
680 
681 	dev->pacer = comedi_8254_init(dev->iobase + DAS800_8254,
682 				      I8254_OSC_BASE_1MHZ, I8254_IO8, 0);
683 	if (!dev->pacer)
684 		return -ENOMEM;
685 
686 	ret = comedi_alloc_subdevices(dev, 3);
687 	if (ret)
688 		return ret;
689 
690 	/* Analog Input subdevice */
691 	s = &dev->subdevices[0];
692 	dev->read_subdev = s;
693 	s->type		= COMEDI_SUBD_AI;
694 	s->subdev_flags	= SDF_READABLE | SDF_GROUND;
695 	s->n_chan	= 8;
696 	s->maxdata	= (1 << thisboard->resolution) - 1;
697 	s->range_table	= thisboard->ai_range;
698 	s->insn_read	= das800_ai_insn_read;
699 	if (dev->irq) {
700 		s->subdev_flags	|= SDF_CMD_READ;
701 		s->len_chanlist	= 8;
702 		s->do_cmdtest	= das800_ai_do_cmdtest;
703 		s->do_cmd	= das800_ai_do_cmd;
704 		s->cancel	= das800_cancel;
705 	}
706 
707 	/* Digital Input subdevice */
708 	s = &dev->subdevices[1];
709 	s->type		= COMEDI_SUBD_DI;
710 	s->subdev_flags	= SDF_READABLE;
711 	s->n_chan	= 3;
712 	s->maxdata	= 1;
713 	s->range_table	= &range_digital;
714 	s->insn_bits	= das800_di_insn_bits;
715 
716 	/* Digital Output subdevice */
717 	s = &dev->subdevices[2];
718 	s->type		= COMEDI_SUBD_DO;
719 	s->subdev_flags	= SDF_WRITABLE;
720 	s->n_chan	= 4;
721 	s->maxdata	= 1;
722 	s->range_table	= &range_digital;
723 	s->insn_bits	= das800_do_insn_bits;
724 
725 	das800_disable(dev);
726 
727 	/* initialize digital out channels */
728 	spin_lock_irqsave(&dev->spinlock, irq_flags);
729 	das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
730 	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
731 
732 	return 0;
733 };
734 
735 static struct comedi_driver driver_das800 = {
736 	.driver_name	= "das800",
737 	.module		= THIS_MODULE,
738 	.attach		= das800_attach,
739 	.detach		= comedi_legacy_detach,
740 	.num_names	= ARRAY_SIZE(das800_boards),
741 	.board_name	= &das800_boards[0].name,
742 	.offset		= sizeof(struct das800_board),
743 };
744 module_comedi_driver(driver_das800);
745 
746 MODULE_AUTHOR("Comedi http://www.comedi.org");
747 MODULE_DESCRIPTION("Comedi low-level driver");
748 MODULE_LICENSE("GPL");
749