adl_pci9111.c revision b3450faf38294faea229fb9353498ae05b6e2075
1/*
2
3comedi/drivers/adl_pci9111.c
4
5Hardware driver for PCI9111 ADLink cards:
6
7PCI-9111HR
8
9Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
10
11This program is free software; you can redistribute it and/or modify
12it under the terms of the GNU General Public License as published by
13the Free Software Foundation; either version 2 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/
25
26/*
27Driver: adl_pci9111
28Description: Adlink PCI-9111HR
29Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
30Devices: [ADLink] PCI-9111HR (adl_pci9111)
31Status: experimental
32
33Supports:
34
35	- ai_insn read
36	- ao_insn read/write
37	- di_insn read
38	- do_insn read/write
39	- ai_do_cmd mode with the following sources:
40
41	- start_src		TRIG_NOW
42	- scan_begin_src	TRIG_FOLLOW	TRIG_TIMER	TRIG_EXT
43	- convert_src				TRIG_TIMER	TRIG_EXT
44	- scan_end_src		TRIG_COUNT
45	- stop_src		TRIG_COUNT	TRIG_NONE
46
47The scanned channels must be consecutive and start from 0. They must
48all have the same range and aref.
49
50Configuration options:
51
52	[0] - PCI bus number (optional)
53	[1] - PCI slot number (optional)
54
55If bus/slot is not specified, the first available PCI
56device will be used.
57
58*/
59
60/*
61CHANGELOG:
62
632005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
64a multiple of chanlist_len*convert_arg.
652002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
662002/02/18 Added external trigger support for analog input.
67
68TODO:
69
70	- Really test implemented functionality.
71	- Add support for the PCI-9111DG with a probe routine to identify
72	  the card type (perhaps with the help of the channel number readback
73	  of the A/D Data register).
74	- Add external multiplexer support.
75
76*/
77
78#include "../comedidev.h"
79
80#include <linux/delay.h>
81#include <linux/interrupt.h>
82
83#include "8253.h"
84#include "comedi_fc.h"
85
86#define PCI9111_DRIVER_NAME	"adl_pci9111"
87#define PCI9111_HR_DEVICE_ID	0x9111
88
89/*  TODO: Add other pci9111 board id */
90
91#define PCI9111_IO_RANGE	0x0100
92
93#define PCI9111_FIFO_HALF_SIZE	512
94
95#define PCI9111_AI_CHANNEL_NBR			16
96
97#define PCI9111_AI_RESOLUTION			12
98#define PCI9111_AI_RESOLUTION_MASK		0x0FFF
99#define PCI9111_AI_RESOLUTION_2_CMP_BIT		0x0800
100
101#define PCI9111_HR_AI_RESOLUTION		16
102#define PCI9111_HR_AI_RESOLUTION_MASK		0xFFFF
103#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT	0x8000
104
105#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS	10000
106#define PCI9111_AO_CHANNEL_NBR			1
107#define	PCI9111_AO_RESOLUTION			12
108#define PCI9111_AO_RESOLUTION_MASK		0x0FFF
109#define PCI9111_DI_CHANNEL_NBR			16
110#define	PCI9111_DO_CHANNEL_NBR			16
111
112#define PCI9111_RANGE_SETTING_DELAY		10
113#define PCI9111_AI_INSTANT_READ_UDELAY_US	2
114#define PCI9111_AI_INSTANT_READ_TIMEOUT		100
115
116#define PCI9111_8254_CLOCK_PERIOD_NS		500
117
118/* IO address map */
119
120#define PCI9111_REGISTER_AD_FIFO_VALUE			0x00 /* AD Data stored
121								in FIFO */
122#define PCI9111_AO_REG					0x00
123#define PCI9111_DIO_REG					0x02
124#define PCI9111_REGISTER_EXTENDED_IO_PORTS		0x04
125#define PCI9111_REGISTER_AD_CHANNEL_CONTROL		0x06 /* Channel
126								selection */
127#define PCI9111_REGISTER_AD_CHANNEL_READBACK		0x06
128#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE		0x08
129#define PCI9111_REGISTER_RANGE_STATUS_READBACK		0x08
130#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL		0x0A
131#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK	0x0A
132#define PCI9111_REGISTER_SOFTWARE_TRIGGER		0x0E
133#define PCI9111_REGISTER_INTERRUPT_CONTROL		0x0C
134#define PCI9111_8254_BASE_REG				0x40
135#define PCI9111_REGISTER_INTERRUPT_CLEAR		0x48
136
137#define PCI9111_TRIGGER_MASK				0x0F
138#define PCI9111_PTRG_OFF				(0 << 3)
139#define PCI9111_PTRG_ON					(1 << 3)
140#define PCI9111_EITS_EXTERNAL				(1 << 2)
141#define PCI9111_EITS_INTERNAL				(0 << 2)
142#define PCI9111_TPST_SOFTWARE_TRIGGER			(0 << 1)
143#define PCI9111_TPST_TIMER_PACER			(1 << 1)
144#define PCI9111_ASCAN_ON				(1 << 0)
145#define PCI9111_ASCAN_OFF				(0 << 0)
146
147#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
148#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL		(1 << 0)
149#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK		(0 << 1)
150#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG			(1 << 1)
151#define PCI9111_FFEN_SET_FIFO_ENABLE			(0 << 2)
152#define PCI9111_FFEN_SET_FIFO_DISABLE			(1 << 2)
153
154#define PCI9111_CHANNEL_MASK				0x0F
155
156#define PCI9111_RANGE_MASK				0x07
157#define PCI9111_FIFO_EMPTY_MASK				0x10
158#define PCI9111_FIFO_HALF_FULL_MASK			0x20
159#define PCI9111_FIFO_FULL_MASK				0x40
160#define PCI9111_AD_BUSY_MASK				0x80
161
162/*
163 * Define inlined function
164 */
165
166#define pci9111_trigger_and_autoscan_get() \
167	(inb(dev->iobase + PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)
168
169#define pci9111_trigger_and_autoscan_set(flags) \
170	outb(flags, dev->iobase + PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
171
172#define pci9111_interrupt_and_fifo_get() \
173	((inb(dev->iobase + PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) \
174		>> 4) & 0x03)
175
176#define pci9111_interrupt_and_fifo_set(flags) \
177	outb(flags, dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL)
178
179#define pci9111_interrupt_clear() \
180	outb(0, dev->iobase + PCI9111_REGISTER_INTERRUPT_CLEAR)
181
182#define pci9111_software_trigger() \
183	outb(0, dev->iobase + PCI9111_REGISTER_SOFTWARE_TRIGGER)
184
185#define pci9111_fifo_reset() do { \
186	outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
187		dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
188	outb(PCI9111_FFEN_SET_FIFO_DISABLE, \
189		dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
190	outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
191		dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \
192	} while (0)
193
194#define pci9111_is_fifo_full() \
195	((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
196		PCI9111_FIFO_FULL_MASK) == 0)
197
198#define pci9111_is_fifo_half_full() \
199	((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
200		PCI9111_FIFO_HALF_FULL_MASK) == 0)
201
202#define pci9111_is_fifo_empty() \
203	((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
204		PCI9111_FIFO_EMPTY_MASK) == 0)
205
206#define pci9111_ai_channel_set(channel) \
207	outb((channel)&PCI9111_CHANNEL_MASK, \
208		dev->iobase + PCI9111_REGISTER_AD_CHANNEL_CONTROL)
209
210#define pci9111_ai_channel_get() \
211	(inb(dev->iobase + PCI9111_REGISTER_AD_CHANNEL_READBACK) \
212		&PCI9111_CHANNEL_MASK)
213
214#define pci9111_ai_range_set(range) \
215	outb((range)&PCI9111_RANGE_MASK, \
216		dev->iobase + PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
217
218#define pci9111_ai_range_get() \
219	(inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK) \
220		&PCI9111_RANGE_MASK)
221
222#define pci9111_ai_get_data() \
223	(((inw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE)>>4) \
224		&PCI9111_AI_RESOLUTION_MASK) \
225			^ PCI9111_AI_RESOLUTION_2_CMP_BIT)
226
227#define pci9111_hr_ai_get_data() \
228	((inw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE) \
229		&PCI9111_HR_AI_RESOLUTION_MASK) \
230			^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT)
231
232static const struct comedi_lrange pci9111_hr_ai_range = {
233	5,
234	{
235	 BIP_RANGE(10),
236	 BIP_RANGE(5),
237	 BIP_RANGE(2.5),
238	 BIP_RANGE(1.25),
239	 BIP_RANGE(0.625)
240	 }
241};
242
243/*  */
244/*  Board specification structure */
245/*  */
246
247struct pci9111_board {
248	const char *name;	/*  driver name */
249	int device_id;
250	int ai_channel_nbr;	/*  num of A/D chans */
251	int ao_channel_nbr;	/*  num of D/A chans */
252	int ai_resolution;	/*  resolution of A/D */
253	int ai_resolution_mask;
254	int ao_resolution;	/*  resolution of D/A */
255	int ao_resolution_mask;
256	const struct comedi_lrange *ai_range_list;	/*  rangelist for A/D */
257	const struct comedi_lrange *ao_range_list;	/*  rangelist for D/A */
258	unsigned int ai_acquisition_period_min_ns;
259};
260
261static const struct pci9111_board pci9111_boards[] = {
262	{
263	 .name = "pci9111_hr",
264	 .device_id = PCI9111_HR_DEVICE_ID,
265	 .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR,
266	 .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR,
267	 .ai_resolution = PCI9111_HR_AI_RESOLUTION,
268	 .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK,
269	 .ao_resolution = PCI9111_AO_RESOLUTION,
270	 .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK,
271	 .ai_range_list = &pci9111_hr_ai_range,
272	 .ao_range_list = &range_bipolar10,
273	 .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS}
274};
275
276/*  Private data structure */
277
278struct pci9111_private_data {
279	unsigned long io_range;	/*  PCI6503 io range */
280
281	unsigned long lcr_io_base; /* Local configuration register base
282				    * address */
283	unsigned long lcr_io_range;
284
285	int stop_counter;
286	int stop_is_none;
287
288	unsigned int scan_delay;
289	unsigned int chanlist_len;
290	unsigned int chunk_counter;
291	unsigned int chunk_num_samples;
292
293	int ao_readback;	/*  Last written analog output data */
294
295	unsigned int timer_divisor_1; /* Divisor values for the 8254 timer
296				       * pacer */
297	unsigned int timer_divisor_2;
298
299	int is_valid;		/*  Is device valid */
300
301	short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
302};
303
304/*  ------------------------------------------------------------------ */
305/*  PLX9050 SECTION */
306/*  ------------------------------------------------------------------ */
307
308#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
309
310#define PLX9050_LINTI1_ENABLE		(1 << 0)
311#define PLX9050_LINTI1_ACTIVE_HIGH	(1 << 1)
312#define PLX9050_LINTI1_STATUS		(1 << 2)
313#define PLX9050_LINTI2_ENABLE		(1 << 3)
314#define PLX9050_LINTI2_ACTIVE_HIGH	(1 << 4)
315#define PLX9050_LINTI2_STATUS		(1 << 5)
316#define PLX9050_PCI_INTERRUPT_ENABLE	(1 << 6)
317#define PLX9050_SOFTWARE_INTERRUPT	(1 << 7)
318
319static void plx9050_interrupt_control(unsigned long io_base,
320				      bool LINTi1_enable,
321				      bool LINTi1_active_high,
322				      bool LINTi2_enable,
323				      bool LINTi2_active_high,
324				      bool interrupt_enable)
325{
326	int flags = 0;
327
328	if (LINTi1_enable)
329		flags |= PLX9050_LINTI1_ENABLE;
330	if (LINTi1_active_high)
331		flags |= PLX9050_LINTI1_ACTIVE_HIGH;
332	if (LINTi2_enable)
333		flags |= PLX9050_LINTI2_ENABLE;
334	if (LINTi2_active_high)
335		flags |= PLX9050_LINTI2_ACTIVE_HIGH;
336
337	if (interrupt_enable)
338		flags |= PLX9050_PCI_INTERRUPT_ENABLE;
339
340	outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
341}
342
343/*  ------------------------------------------------------------------ */
344/*  MISCELLANEOUS SECTION */
345/*  ------------------------------------------------------------------ */
346
347/*  8254 timer */
348
349static void pci9111_timer_set(struct comedi_device *dev)
350{
351	struct pci9111_private_data *dev_private = dev->private;
352	unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG;
353
354	i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY);
355	i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
356	i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
357
358	udelay(1);
359
360	i8254_write(timer_base, 1, 2, dev_private->timer_divisor_2);
361	i8254_write(timer_base, 1, 1, dev_private->timer_divisor_1);
362}
363
364enum pci9111_trigger_sources {
365	software,
366	timer_pacer,
367	external
368};
369
370static void pci9111_trigger_source_set(struct comedi_device *dev,
371				       enum pci9111_trigger_sources source)
372{
373	int flags;
374
375	flags = pci9111_trigger_and_autoscan_get() & 0x09;
376
377	switch (source) {
378	case software:
379		flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER;
380		break;
381
382	case timer_pacer:
383		flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER;
384		break;
385
386	case external:
387		flags |= PCI9111_EITS_EXTERNAL;
388		break;
389	}
390
391	pci9111_trigger_and_autoscan_set(flags);
392}
393
394static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
395{
396	int flags;
397
398	flags = pci9111_trigger_and_autoscan_get() & 0x07;
399
400	if (pretrigger)
401		flags |= PCI9111_PTRG_ON;
402
403	pci9111_trigger_and_autoscan_set(flags);
404}
405
406static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
407{
408	int flags;
409
410	flags = pci9111_trigger_and_autoscan_get() & 0x0e;
411
412	if (autoscan)
413		flags |= PCI9111_ASCAN_ON;
414
415	pci9111_trigger_and_autoscan_set(flags);
416}
417
418enum pci9111_ISC0_sources {
419	irq_on_eoc,
420	irq_on_fifo_half_full
421};
422
423enum pci9111_ISC1_sources {
424	irq_on_timer_tick,
425	irq_on_external_trigger
426};
427
428static void pci9111_interrupt_source_set(struct comedi_device *dev,
429					 enum pci9111_ISC0_sources irq_0_source,
430					 enum pci9111_ISC1_sources irq_1_source)
431{
432	int flags;
433
434	flags = pci9111_interrupt_and_fifo_get() & 0x04;
435
436	if (irq_0_source == irq_on_fifo_half_full)
437		flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL;
438
439	if (irq_1_source == irq_on_external_trigger)
440		flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG;
441
442	pci9111_interrupt_and_fifo_set(flags);
443}
444
445/*  ------------------------------------------------------------------ */
446/*  HARDWARE TRIGGERED ANALOG INPUT SECTION */
447/*  ------------------------------------------------------------------ */
448
449/*  Cancel analog input autoscan */
450
451#undef AI_DO_CMD_DEBUG
452
453static int pci9111_ai_cancel(struct comedi_device *dev,
454			     struct comedi_subdevice *s)
455{
456	struct pci9111_private_data *dev_private = dev->private;
457
458	/*  Disable interrupts */
459
460	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
461				  true, false);
462
463	pci9111_trigger_source_set(dev, software);
464
465	pci9111_autoscan_set(dev, false);
466
467	pci9111_fifo_reset();
468
469#ifdef AI_DO_CMD_DEBUG
470	printk(PCI9111_DRIVER_NAME ": ai_cancel\n");
471#endif
472
473	return 0;
474}
475
476/*  Test analog input command */
477
478#define pci9111_check_trigger_src(src, flags)	do {			\
479		tmp = src;						\
480		src &= flags;						\
481		if (!src || tmp != src)					\
482			error++;					\
483	} while (false);
484
485static int
486pci9111_ai_do_cmd_test(struct comedi_device *dev,
487		       struct comedi_subdevice *s, struct comedi_cmd *cmd)
488{
489	struct pci9111_private_data *dev_private = dev->private;
490	int tmp;
491	int error = 0;
492	int range, reference;
493	int i;
494	struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr;
495
496	/*  Step 1 : check if trigger are trivialy valid */
497
498	pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
499	pci9111_check_trigger_src(cmd->scan_begin_src,
500				  TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
501	pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
502	pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
503	pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
504
505	if (error)
506		return 1;
507
508	/*  step 2 : make sure trigger sources are unique and mutually
509	 *  compatible */
510
511	if (cmd->start_src != TRIG_NOW)
512		error++;
513
514	if ((cmd->scan_begin_src != TRIG_TIMER) &&
515	    (cmd->scan_begin_src != TRIG_FOLLOW) &&
516	    (cmd->scan_begin_src != TRIG_EXT))
517		error++;
518
519	if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT))
520		error++;
521	if ((cmd->convert_src == TRIG_TIMER) &&
522	    !((cmd->scan_begin_src == TRIG_TIMER) ||
523	      (cmd->scan_begin_src == TRIG_FOLLOW)))
524		error++;
525	if ((cmd->convert_src == TRIG_EXT) &&
526	    !((cmd->scan_begin_src == TRIG_EXT) ||
527	      (cmd->scan_begin_src == TRIG_FOLLOW)))
528		error++;
529
530
531	if (cmd->scan_end_src != TRIG_COUNT)
532		error++;
533	if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
534		error++;
535
536	if (error)
537		return 2;
538
539	/*  Step 3 : make sure arguments are trivialy compatible */
540
541	if (cmd->chanlist_len < 1) {
542		cmd->chanlist_len = 1;
543		error++;
544	}
545
546	if (cmd->chanlist_len > board->ai_channel_nbr) {
547		cmd->chanlist_len = board->ai_channel_nbr;
548		error++;
549	}
550
551	if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
552		cmd->start_arg = 0;
553		error++;
554	}
555
556	if ((cmd->convert_src == TRIG_TIMER) &&
557	    (cmd->convert_arg < board->ai_acquisition_period_min_ns)) {
558		cmd->convert_arg = board->ai_acquisition_period_min_ns;
559		error++;
560	}
561	if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
562		cmd->convert_arg = 0;
563		error++;
564	}
565
566	if ((cmd->scan_begin_src == TRIG_TIMER) &&
567	    (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) {
568		cmd->scan_begin_arg = board->ai_acquisition_period_min_ns;
569		error++;
570	}
571	if ((cmd->scan_begin_src == TRIG_FOLLOW)
572	    && (cmd->scan_begin_arg != 0)) {
573		cmd->scan_begin_arg = 0;
574		error++;
575	}
576	if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
577		cmd->scan_begin_arg = 0;
578		error++;
579	}
580
581	if ((cmd->scan_end_src == TRIG_COUNT) &&
582	    (cmd->scan_end_arg != cmd->chanlist_len)) {
583		cmd->scan_end_arg = cmd->chanlist_len;
584		error++;
585	}
586
587	if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
588		cmd->stop_arg = 1;
589		error++;
590	}
591	if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
592		cmd->stop_arg = 0;
593		error++;
594	}
595
596	if (error)
597		return 3;
598
599	/*  Step 4 : fix up any arguments */
600
601	if (cmd->convert_src == TRIG_TIMER) {
602		tmp = cmd->convert_arg;
603		i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
604					       &(dev_private->timer_divisor_1),
605					       &(dev_private->timer_divisor_2),
606					       &(cmd->convert_arg),
607					       cmd->flags & TRIG_ROUND_MASK);
608		if (tmp != cmd->convert_arg)
609			error++;
610	}
611	/*  There's only one timer on this card, so the scan_begin timer must */
612	/*  be a multiple of chanlist_len*convert_arg */
613
614	if (cmd->scan_begin_src == TRIG_TIMER) {
615
616		unsigned int scan_begin_min;
617		unsigned int scan_begin_arg;
618		unsigned int scan_factor;
619
620		scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
621
622		if (cmd->scan_begin_arg != scan_begin_min) {
623			if (scan_begin_min < cmd->scan_begin_arg) {
624				scan_factor =
625				    cmd->scan_begin_arg / scan_begin_min;
626				scan_begin_arg = scan_factor * scan_begin_min;
627				if (cmd->scan_begin_arg != scan_begin_arg) {
628					cmd->scan_begin_arg = scan_begin_arg;
629					error++;
630				}
631			} else {
632				cmd->scan_begin_arg = scan_begin_min;
633				error++;
634			}
635		}
636	}
637
638	if (error)
639		return 4;
640
641	/*  Step 5 : check channel list */
642
643	if (cmd->chanlist) {
644
645		range = CR_RANGE(cmd->chanlist[0]);
646		reference = CR_AREF(cmd->chanlist[0]);
647
648		if (cmd->chanlist_len > 1) {
649			for (i = 0; i < cmd->chanlist_len; i++) {
650				if (CR_CHAN(cmd->chanlist[i]) != i) {
651					comedi_error(dev,
652						     "entries in chanlist must be consecutive "
653						     "channels,counting upwards from 0\n");
654					error++;
655				}
656				if (CR_RANGE(cmd->chanlist[i]) != range) {
657					comedi_error(dev,
658						     "entries in chanlist must all have the same gain\n");
659					error++;
660				}
661				if (CR_AREF(cmd->chanlist[i]) != reference) {
662					comedi_error(dev,
663						     "entries in chanlist must all have the same reference\n");
664					error++;
665				}
666			}
667		} else {
668			if ((CR_CHAN(cmd->chanlist[0]) >
669			     (board->ai_channel_nbr - 1))
670			    || (CR_CHAN(cmd->chanlist[0]) < 0)) {
671				comedi_error(dev,
672					     "channel number is out of limits\n");
673				error++;
674			}
675		}
676	}
677
678	if (error)
679		return 5;
680
681	return 0;
682
683}
684
685/*  Analog input command */
686
687static int pci9111_ai_do_cmd(struct comedi_device *dev,
688			     struct comedi_subdevice *s)
689{
690	struct pci9111_private_data *dev_private = dev->private;
691	struct comedi_cmd *async_cmd = &s->async->cmd;
692
693	if (!dev->irq) {
694		comedi_error(dev,
695			     "no irq assigned for PCI9111, cannot do hardware conversion");
696		return -1;
697	}
698	/*  Set channel scan limit */
699	/*  PCI9111 allows only scanning from channel 0 to channel n */
700	/*  TODO: handle the case of an external multiplexer */
701
702	if (async_cmd->chanlist_len > 1) {
703		pci9111_ai_channel_set((async_cmd->chanlist_len) - 1);
704		pci9111_autoscan_set(dev, true);
705	} else {
706		pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0]));
707		pci9111_autoscan_set(dev, false);
708	}
709
710	/*  Set gain */
711	/*  This is the same gain on every channel */
712
713	pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0]));
714
715	/* Set counter */
716
717	switch (async_cmd->stop_src) {
718	case TRIG_COUNT:
719		dev_private->stop_counter =
720		    async_cmd->stop_arg * async_cmd->chanlist_len;
721		dev_private->stop_is_none = 0;
722		break;
723
724	case TRIG_NONE:
725		dev_private->stop_counter = 0;
726		dev_private->stop_is_none = 1;
727		break;
728
729	default:
730		comedi_error(dev, "Invalid stop trigger");
731		return -1;
732	}
733
734	/*  Set timer pacer */
735
736	dev_private->scan_delay = 0;
737	switch (async_cmd->convert_src) {
738	case TRIG_TIMER:
739		i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
740					       &(dev_private->timer_divisor_1),
741					       &(dev_private->timer_divisor_2),
742					       &(async_cmd->convert_arg),
743					       async_cmd->
744					       flags & TRIG_ROUND_MASK);
745#ifdef AI_DO_CMD_DEBUG
746		printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n",
747		       dev_private->timer_divisor_1,
748		       dev_private->timer_divisor_2);
749#endif
750
751		pci9111_trigger_source_set(dev, software);
752		pci9111_timer_set(dev);
753		pci9111_fifo_reset();
754		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
755					     irq_on_timer_tick);
756		pci9111_trigger_source_set(dev, timer_pacer);
757		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
758					  false, true, true);
759
760		if (async_cmd->scan_begin_src == TRIG_TIMER) {
761			dev_private->scan_delay =
762				(async_cmd->scan_begin_arg /
763				 (async_cmd->convert_arg *
764				  async_cmd->chanlist_len)) - 1;
765		}
766
767		break;
768
769	case TRIG_EXT:
770
771		pci9111_trigger_source_set(dev, external);
772		pci9111_fifo_reset();
773		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
774					     irq_on_timer_tick);
775		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
776					  false, true, true);
777
778		break;
779
780	default:
781		comedi_error(dev, "Invalid convert trigger");
782		return -1;
783	}
784
785	dev_private->stop_counter *= (1 + dev_private->scan_delay);
786	dev_private->chanlist_len = async_cmd->chanlist_len;
787	dev_private->chunk_counter = 0;
788	dev_private->chunk_num_samples =
789	    dev_private->chanlist_len * (1 + dev_private->scan_delay);
790
791#ifdef AI_DO_CMD_DEBUG
792	printk(PCI9111_DRIVER_NAME ": start interruptions!\n");
793	printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n",
794	       pci9111_trigger_and_autoscan_get());
795	printk(PCI9111_DRIVER_NAME ": irq source     = %2x\n",
796	       pci9111_interrupt_and_fifo_get());
797	printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n");
798	printk(PCI9111_DRIVER_NAME ": stop counter   = %d\n",
799	       dev_private->stop_counter);
800	printk(PCI9111_DRIVER_NAME ": scan delay     = %d\n",
801	       dev_private->scan_delay);
802	printk(PCI9111_DRIVER_NAME ": chanlist_len   = %d\n",
803	       dev_private->chanlist_len);
804	printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n",
805	       dev_private->chunk_num_samples);
806#endif
807
808	return 0;
809}
810
811static void pci9111_ai_munge(struct comedi_device *dev,
812			     struct comedi_subdevice *s, void *data,
813			     unsigned int num_bytes,
814			     unsigned int start_chan_index)
815{
816	unsigned int i, num_samples = num_bytes / sizeof(short);
817	short *array = data;
818	int resolution =
819	    ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
820
821	for (i = 0; i < num_samples; i++) {
822		if (resolution == PCI9111_HR_AI_RESOLUTION)
823			array[i] =
824			    (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^
825			    PCI9111_HR_AI_RESOLUTION_2_CMP_BIT;
826		else
827			array[i] =
828			    ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^
829			    PCI9111_AI_RESOLUTION_2_CMP_BIT;
830	}
831}
832
833/*  ------------------------------------------------------------------ */
834/*  INTERRUPT SECTION */
835/*  ------------------------------------------------------------------ */
836
837#undef INTERRUPT_DEBUG
838
839static irqreturn_t pci9111_interrupt(int irq, void *p_device)
840{
841	struct comedi_device *dev = p_device;
842	struct pci9111_private_data *dev_private = dev->private;
843	struct comedi_subdevice *s = dev->read_subdev;
844	struct comedi_async *async;
845	unsigned long irq_flags;
846	unsigned char intcsr;
847
848	if (!dev->attached) {
849		/*  Ignore interrupt before device fully attached. */
850		/*  Might not even have allocated subdevices yet! */
851		return IRQ_NONE;
852	}
853
854	async = s->async;
855
856	spin_lock_irqsave(&dev->spinlock, irq_flags);
857
858	/*  Check if we are source of interrupt */
859	intcsr = inb(dev_private->lcr_io_base +
860		     PLX9050_REGISTER_INTERRUPT_CONTROL);
861	if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
862	      && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
863		   == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
864		  || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
865		      == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
866		/*  Not the source of the interrupt. */
867		/*  (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
868		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
869		return IRQ_NONE;
870	}
871
872	if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
873	    (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
874		/*  Interrupt comes from fifo_half-full signal */
875
876		if (pci9111_is_fifo_full()) {
877			spin_unlock_irqrestore(&dev->spinlock, irq_flags);
878			comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
879			pci9111_interrupt_clear();
880			pci9111_ai_cancel(dev, s);
881			async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
882			comedi_event(dev, s);
883
884			return IRQ_HANDLED;
885		}
886
887		if (pci9111_is_fifo_half_full()) {
888			unsigned int num_samples;
889			unsigned int bytes_written = 0;
890
891#ifdef INTERRUPT_DEBUG
892			printk(PCI9111_DRIVER_NAME ": fifo is half full\n");
893#endif
894
895			num_samples =
896			    PCI9111_FIFO_HALF_SIZE >
897			    dev_private->stop_counter
898			    && !dev_private->
899			    stop_is_none ? dev_private->stop_counter :
900			    PCI9111_FIFO_HALF_SIZE;
901			insw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE,
902			     dev_private->ai_bounce_buffer, num_samples);
903
904			if (dev_private->scan_delay < 1) {
905				bytes_written =
906				    cfc_write_array_to_buffer(s,
907							      dev_private->
908							      ai_bounce_buffer,
909							      num_samples *
910							      sizeof(short));
911			} else {
912				int position = 0;
913				int to_read;
914
915				while (position < num_samples) {
916					if (dev_private->chunk_counter <
917					    dev_private->chanlist_len) {
918						to_read =
919						    dev_private->chanlist_len -
920						    dev_private->chunk_counter;
921
922						if (to_read >
923						    num_samples - position)
924							to_read =
925							    num_samples -
926							    position;
927
928						bytes_written +=
929						    cfc_write_array_to_buffer
930						    (s,
931						     dev_private->ai_bounce_buffer
932						     + position,
933						     to_read * sizeof(short));
934					} else {
935						to_read =
936						    dev_private->chunk_num_samples
937						    -
938						    dev_private->chunk_counter;
939						if (to_read >
940						    num_samples - position)
941							to_read =
942							    num_samples -
943							    position;
944
945						bytes_written +=
946						    sizeof(short) * to_read;
947					}
948
949					position += to_read;
950					dev_private->chunk_counter += to_read;
951
952					if (dev_private->chunk_counter >=
953					    dev_private->chunk_num_samples)
954						dev_private->chunk_counter = 0;
955				}
956			}
957
958			dev_private->stop_counter -=
959			    bytes_written / sizeof(short);
960		}
961	}
962
963	if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
964		async->events |= COMEDI_CB_EOA;
965		pci9111_ai_cancel(dev, s);
966	}
967
968	/* Very important, otherwise another interrupt request will be inserted
969	 * and will cause driver hangs on processing interrupt event. */
970
971	pci9111_interrupt_clear();
972
973	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
974
975	comedi_event(dev, s);
976
977	return IRQ_HANDLED;
978}
979
980/*  ------------------------------------------------------------------ */
981/*  INSTANT ANALOG INPUT OUTPUT SECTION */
982/*  ------------------------------------------------------------------ */
983
984/*  analog instant input */
985
986#undef AI_INSN_DEBUG
987
988static int pci9111_ai_insn_read(struct comedi_device *dev,
989				struct comedi_subdevice *s,
990				struct comedi_insn *insn, unsigned int *data)
991{
992	int resolution =
993	    ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
994
995	int timeout, i;
996
997#ifdef AI_INSN_DEBUG
998	printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n",
999	       CR_CHAN((&insn->chanspec)[0]),
1000	       CR_RANGE((&insn->chanspec)[0]), insn->n);
1001#endif
1002
1003	pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0]));
1004
1005	if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0]))
1006		pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0]));
1007
1008	pci9111_fifo_reset();
1009
1010	for (i = 0; i < insn->n; i++) {
1011		pci9111_software_trigger();
1012
1013		timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
1014
1015		while (timeout--) {
1016			if (!pci9111_is_fifo_empty())
1017				goto conversion_done;
1018		}
1019
1020		comedi_error(dev, "A/D read timeout");
1021		data[i] = 0;
1022		pci9111_fifo_reset();
1023		return -ETIME;
1024
1025conversion_done:
1026
1027		if (resolution == PCI9111_HR_AI_RESOLUTION)
1028			data[i] = pci9111_hr_ai_get_data();
1029		else
1030			data[i] = pci9111_ai_get_data();
1031	}
1032
1033#ifdef AI_INSN_DEBUG
1034	printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n",
1035	       pci9111_ai_channel_get(),
1036	       pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get());
1037#endif
1038
1039	return i;
1040}
1041
1042/*  Analog instant output */
1043
1044static int
1045pci9111_ao_insn_write(struct comedi_device *dev,
1046		      struct comedi_subdevice *s, struct comedi_insn *insn,
1047		      unsigned int *data)
1048{
1049	struct pci9111_private_data *dev_private = dev->private;
1050	int i;
1051
1052	for (i = 0; i < insn->n; i++) {
1053		outw(data[i] & PCI9111_AO_RESOLUTION_MASK,
1054			dev->iobase + PCI9111_AO_REG);
1055		dev_private->ao_readback = data[i];
1056	}
1057
1058	return i;
1059}
1060
1061static int pci9111_ao_insn_read(struct comedi_device *dev,
1062				struct comedi_subdevice *s,
1063				struct comedi_insn *insn,
1064				unsigned int *data)
1065{
1066	struct pci9111_private_data *dev_private = dev->private;
1067	int i;
1068
1069	for (i = 0; i < insn->n; i++)
1070		data[i] = dev_private->ao_readback;
1071
1072	return insn->n;
1073}
1074
1075static int pci9111_di_insn_bits(struct comedi_device *dev,
1076				struct comedi_subdevice *s,
1077				struct comedi_insn *insn,
1078				unsigned int *data)
1079{
1080	data[1] = inw(dev->iobase + PCI9111_DIO_REG);
1081
1082	return insn->n;
1083}
1084
1085static int pci9111_do_insn_bits(struct comedi_device *dev,
1086				struct comedi_subdevice *s,
1087				struct comedi_insn *insn,
1088				unsigned int *data)
1089{
1090	unsigned int mask = data[0];
1091	unsigned int bits = data[1];
1092
1093	if (mask) {
1094		s->state &= ~mask;
1095		s->state |= (bits & mask);
1096
1097		outw(s->state, dev->iobase + PCI9111_DIO_REG);
1098	}
1099
1100	data[1] = s->state;
1101
1102	return insn->n;
1103}
1104
1105/*  ------------------------------------------------------------------ */
1106/*  INITIALISATION SECTION */
1107/*  ------------------------------------------------------------------ */
1108
1109/*  Reset device */
1110
1111static int pci9111_reset(struct comedi_device *dev)
1112{
1113	struct pci9111_private_data *dev_private = dev->private;
1114
1115	/*  Set trigger source to software */
1116
1117	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
1118				  true, false);
1119
1120	pci9111_trigger_source_set(dev, software);
1121	pci9111_pretrigger_set(dev, false);
1122	pci9111_autoscan_set(dev, false);
1123
1124	/*  Reset 8254 chip */
1125
1126	dev_private->timer_divisor_1 = 0;
1127	dev_private->timer_divisor_2 = 0;
1128
1129	pci9111_timer_set(dev);
1130
1131	return 0;
1132}
1133
1134static struct pci_dev *pci9111_find_pci(struct comedi_device *dev,
1135					struct comedi_devconfig *it)
1136{
1137	struct pci_dev *pcidev = NULL;
1138	int bus = it->options[0];
1139	int slot = it->options[1];
1140	int i;
1141
1142	for_each_pci_dev(pcidev) {
1143		if (pcidev->vendor != PCI_VENDOR_ID_ADLINK)
1144			continue;
1145		for (i = 0; i < ARRAY_SIZE(pci9111_boards); i++) {
1146			if (pcidev->device != pci9111_boards[i].device_id)
1147				continue;
1148			if (bus || slot) {
1149				/* requested particular bus/slot */
1150				if (pcidev->bus->number != bus ||
1151				    PCI_SLOT(pcidev->devfn) != slot)
1152					continue;
1153			}
1154			dev->board_ptr = pci9111_boards + i;
1155			printk(KERN_ERR
1156				"comedi%d: found %s (b:s:f=%d:%d:%d), irq=%d\n",
1157				dev->minor, pci9111_boards[i].name,
1158				pcidev->bus->number, PCI_SLOT(pcidev->devfn),
1159				PCI_FUNC(pcidev->devfn), pcidev->irq);
1160			return pcidev;
1161		}
1162	}
1163	printk(KERN_ERR
1164		"comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
1165		dev->minor, bus, slot);
1166	return NULL;
1167}
1168
1169static int pci9111_attach(struct comedi_device *dev,
1170			  struct comedi_devconfig *it)
1171{
1172	struct pci9111_private_data *dev_private;
1173	struct pci_dev *pcidev;
1174	struct comedi_subdevice *s;
1175	unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
1176	int ret;
1177	const struct pci9111_board *board;
1178
1179	ret = alloc_private(dev, sizeof(*dev_private));
1180	if (ret)
1181		return ret;
1182	dev_private = dev->private;
1183
1184	/*  Probe the device to determine what device in the series it is. */
1185
1186	printk(KERN_ERR "comedi%d: " PCI9111_DRIVER_NAME " driver\n",
1187								dev->minor);
1188
1189	pcidev = pci9111_find_pci(dev, it);
1190	if (!pcidev)
1191		return -EIO;
1192	comedi_set_hw_dev(dev, &pcidev->dev);
1193	board = (struct pci9111_board *)dev->board_ptr;
1194
1195	/*  TODO: Warn about non-tested boards. */
1196
1197	/*  Read local configuration register base address
1198	 *  [PCI_BASE_ADDRESS #1]. */
1199
1200	lcr_io_base = pci_resource_start(pcidev, 1);
1201	lcr_io_range = pci_resource_len(pcidev, 1);
1202
1203	printk
1204	    ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n",
1205	     dev->minor, lcr_io_base, lcr_io_range);
1206
1207	/*  Enable PCI device and request regions */
1208	if (comedi_pci_enable(pcidev, PCI9111_DRIVER_NAME) < 0) {
1209		printk
1210		    ("comedi%d: Failed to enable PCI device and request regions\n",
1211		     dev->minor);
1212		return -EIO;
1213	}
1214	/*  Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */
1215
1216	io_base = pci_resource_start(pcidev, 2);
1217	io_range = pci_resource_len(pcidev, 2);
1218
1219	printk(KERN_ERR "comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n",
1220	       dev->minor, io_base, io_range);
1221
1222	dev->iobase = io_base;
1223	dev->board_name = board->name;
1224	dev_private->io_range = io_range;
1225	dev_private->is_valid = 0;
1226	dev_private->lcr_io_base = lcr_io_base;
1227	dev_private->lcr_io_range = lcr_io_range;
1228
1229	pci9111_reset(dev);
1230
1231	/*  Irq setup */
1232
1233	dev->irq = 0;
1234	if (pcidev->irq > 0) {
1235		dev->irq = pcidev->irq;
1236
1237		if (request_irq(dev->irq, pci9111_interrupt,
1238				IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) {
1239			printk(KERN_ERR
1240				"comedi%d: unable to allocate irq  %u\n",
1241					dev->minor, dev->irq);
1242			return -EINVAL;
1243		}
1244	}
1245
1246	/*  TODO: Add external multiplexer setup (according to option[2]). */
1247
1248	ret = comedi_alloc_subdevices(dev, 4);
1249	if (ret)
1250		return ret;
1251
1252	s = &dev->subdevices[0];
1253	dev->read_subdev = s;
1254
1255	s->type = COMEDI_SUBD_AI;
1256	s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
1257
1258	/*  TODO: Add external multiplexer data */
1259	/*     if (devpriv->usemux) { s->n_chan = devpriv->usemux; } */
1260	/*     else { s->n_chan = this_board->n_aichan; } */
1261
1262	s->n_chan = board->ai_channel_nbr;
1263	s->maxdata = board->ai_resolution_mask;
1264	s->len_chanlist = board->ai_channel_nbr;
1265	s->range_table = board->ai_range_list;
1266	s->cancel = pci9111_ai_cancel;
1267	s->insn_read = pci9111_ai_insn_read;
1268	s->do_cmdtest = pci9111_ai_do_cmd_test;
1269	s->do_cmd = pci9111_ai_do_cmd;
1270	s->munge = pci9111_ai_munge;
1271
1272	s = &dev->subdevices[1];
1273	s->type = COMEDI_SUBD_AO;
1274	s->subdev_flags = SDF_WRITABLE | SDF_COMMON;
1275	s->n_chan = board->ao_channel_nbr;
1276	s->maxdata = board->ao_resolution_mask;
1277	s->len_chanlist = board->ao_channel_nbr;
1278	s->range_table = board->ao_range_list;
1279	s->insn_write = pci9111_ao_insn_write;
1280	s->insn_read = pci9111_ao_insn_read;
1281
1282	s = &dev->subdevices[2];
1283	s->type = COMEDI_SUBD_DI;
1284	s->subdev_flags = SDF_READABLE;
1285	s->n_chan = PCI9111_DI_CHANNEL_NBR;
1286	s->maxdata = 1;
1287	s->range_table = &range_digital;
1288	s->insn_bits = pci9111_di_insn_bits;
1289
1290	s = &dev->subdevices[3];
1291	s->type = COMEDI_SUBD_DO;
1292	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1293	s->n_chan = PCI9111_DO_CHANNEL_NBR;
1294	s->maxdata = 1;
1295	s->range_table = &range_digital;
1296	s->insn_bits = pci9111_do_insn_bits;
1297
1298	dev_private->is_valid = 1;
1299
1300	return 0;
1301}
1302
1303static void pci9111_detach(struct comedi_device *dev)
1304{
1305	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1306	struct pci9111_private_data *dev_private = dev->private;
1307
1308	if (dev_private) {
1309		if (dev_private->is_valid)
1310			pci9111_reset(dev);
1311	}
1312	if (dev->irq != 0)
1313		free_irq(dev->irq, dev);
1314	if (pcidev) {
1315		if (dev->iobase)
1316			comedi_pci_disable(pcidev);
1317		pci_dev_put(pcidev);
1318	}
1319}
1320
1321static struct comedi_driver adl_pci9111_driver = {
1322	.driver_name	= "adl_pci9111",
1323	.module		= THIS_MODULE,
1324	.attach		= pci9111_attach,
1325	.detach		= pci9111_detach,
1326};
1327
1328static int __devinit pci9111_pci_probe(struct pci_dev *dev,
1329				       const struct pci_device_id *ent)
1330{
1331	return comedi_pci_auto_config(dev, &adl_pci9111_driver);
1332}
1333
1334static void __devexit pci9111_pci_remove(struct pci_dev *dev)
1335{
1336	comedi_pci_auto_unconfig(dev);
1337}
1338
1339static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
1340	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
1341	/* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
1342	{ 0 }
1343};
1344MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
1345
1346static struct pci_driver adl_pci9111_pci_driver = {
1347	.name		= "adl_pci9111",
1348	.id_table	= pci9111_pci_table,
1349	.probe		= pci9111_pci_probe,
1350	.remove		= __devexit_p(pci9111_pci_remove),
1351};
1352module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
1353
1354MODULE_AUTHOR("Comedi http://www.comedi.org");
1355MODULE_DESCRIPTION("Comedi low-level driver");
1356MODULE_LICENSE("GPL");
1357