[go: nahoru, domu]

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