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