adl_pci9111.c revision 8c7524e6f0b7d3ca70b957e032ee4f761c7deddf
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: not applicable, uses PCI auto config
51*/
52
53/*
54CHANGELOG:
55
562005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
57a multiple of chanlist_len*convert_arg.
582002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
592002/02/18 Added external trigger support for analog input.
60
61TODO:
62
63	- Really test implemented functionality.
64	- Add support for the PCI-9111DG with a probe routine to identify
65	  the card type (perhaps with the help of the channel number readback
66	  of the A/D Data register).
67	- Add external multiplexer support.
68
69*/
70
71#include "../comedidev.h"
72
73#include <linux/delay.h>
74#include <linux/interrupt.h>
75
76#include "8253.h"
77#include "comedi_fc.h"
78
79#define PCI9111_DRIVER_NAME	"adl_pci9111"
80#define PCI9111_HR_DEVICE_ID	0x9111
81
82#define PCI9111_FIFO_HALF_SIZE	512
83
84#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS	10000
85
86#define PCI9111_RANGE_SETTING_DELAY		10
87#define PCI9111_AI_INSTANT_READ_UDELAY_US	2
88#define PCI9111_AI_INSTANT_READ_TIMEOUT		100
89
90#define PCI9111_8254_CLOCK_PERIOD_NS		500
91
92/*
93 * IO address map and bit defines
94 */
95#define PCI9111_AI_FIFO_REG		0x00
96#define PCI9111_AO_REG			0x00
97#define PCI9111_DIO_REG			0x02
98#define PCI9111_EDIO_REG		0x04
99#define PCI9111_AI_CHANNEL_REG		0x06
100#define PCI9111_AI_RANGE_STAT_REG	0x08
101#define PCI9111_AI_STAT_AD_BUSY		(1 << 7)
102#define PCI9111_AI_STAT_FF_FF		(1 << 6)
103#define PCI9111_AI_STAT_FF_HF		(1 << 5)
104#define PCI9111_AI_STAT_FF_EF		(1 << 4)
105#define PCI9111_AI_RANGE_MASK		(7 << 0)
106#define PCI9111_AI_TRIG_CTRL_REG	0x0a
107#define PCI9111_AI_TRIG_CTRL_TRGEVENT	(1 << 5)
108#define PCI9111_AI_TRIG_CTRL_POTRG	(1 << 4)
109#define PCI9111_AI_TRIG_CTRL_PTRG	(1 << 3)
110#define PCI9111_AI_TRIG_CTRL_ETIS	(1 << 2)
111#define PCI9111_AI_TRIG_CTRL_TPST	(1 << 1)
112#define PCI9111_AI_TRIG_CTRL_ASCAN	(1 << 0)
113#define PCI9111_INT_CTRL_REG		0x0c
114#define PCI9111_INT_CTRL_ISC2		(1 << 3)
115#define PCI9111_INT_CTRL_FFEN		(1 << 2)
116#define PCI9111_INT_CTRL_ISC1		(1 << 1)
117#define PCI9111_INT_CTRL_ISC0		(1 << 0)
118#define PCI9111_SOFT_TRIG_REG		0x0e
119#define PCI9111_8254_BASE_REG		0x40
120#define PCI9111_INT_CLR_REG		0x48
121
122static const struct comedi_lrange pci9111_hr_ai_range = {
123	5,
124	{
125	 BIP_RANGE(10),
126	 BIP_RANGE(5),
127	 BIP_RANGE(2.5),
128	 BIP_RANGE(1.25),
129	 BIP_RANGE(0.625)
130	 }
131};
132
133/*  Private data structure */
134
135struct pci9111_private_data {
136	unsigned long lcr_io_base; /* Local configuration register base
137				    * address */
138
139	int stop_counter;
140	int stop_is_none;
141
142	unsigned int scan_delay;
143	unsigned int chanlist_len;
144	unsigned int chunk_counter;
145	unsigned int chunk_num_samples;
146
147	int ao_readback;	/*  Last written analog output data */
148
149	unsigned int timer_divisor_1; /* Divisor values for the 8254 timer
150				       * pacer */
151	unsigned int timer_divisor_2;
152
153	int is_valid;		/*  Is device valid */
154
155	short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
156};
157
158/*  ------------------------------------------------------------------ */
159/*  PLX9050 SECTION */
160/*  ------------------------------------------------------------------ */
161
162#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
163
164#define PLX9050_LINTI1_ENABLE		(1 << 0)
165#define PLX9050_LINTI1_ACTIVE_HIGH	(1 << 1)
166#define PLX9050_LINTI1_STATUS		(1 << 2)
167#define PLX9050_LINTI2_ENABLE		(1 << 3)
168#define PLX9050_LINTI2_ACTIVE_HIGH	(1 << 4)
169#define PLX9050_LINTI2_STATUS		(1 << 5)
170#define PLX9050_PCI_INTERRUPT_ENABLE	(1 << 6)
171#define PLX9050_SOFTWARE_INTERRUPT	(1 << 7)
172
173static void plx9050_interrupt_control(unsigned long io_base,
174				      bool LINTi1_enable,
175				      bool LINTi1_active_high,
176				      bool LINTi2_enable,
177				      bool LINTi2_active_high,
178				      bool interrupt_enable)
179{
180	int flags = 0;
181
182	if (LINTi1_enable)
183		flags |= PLX9050_LINTI1_ENABLE;
184	if (LINTi1_active_high)
185		flags |= PLX9050_LINTI1_ACTIVE_HIGH;
186	if (LINTi2_enable)
187		flags |= PLX9050_LINTI2_ENABLE;
188	if (LINTi2_active_high)
189		flags |= PLX9050_LINTI2_ACTIVE_HIGH;
190
191	if (interrupt_enable)
192		flags |= PLX9050_PCI_INTERRUPT_ENABLE;
193
194	outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
195}
196
197/*  ------------------------------------------------------------------ */
198/*  MISCELLANEOUS SECTION */
199/*  ------------------------------------------------------------------ */
200
201/*  8254 timer */
202
203static void pci9111_timer_set(struct comedi_device *dev)
204{
205	struct pci9111_private_data *dev_private = dev->private;
206	unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG;
207
208	i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY);
209	i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
210	i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
211
212	udelay(1);
213
214	i8254_write(timer_base, 1, 2, dev_private->timer_divisor_2);
215	i8254_write(timer_base, 1, 1, dev_private->timer_divisor_1);
216}
217
218enum pci9111_trigger_sources {
219	software,
220	timer_pacer,
221	external
222};
223
224static void pci9111_trigger_source_set(struct comedi_device *dev,
225				       enum pci9111_trigger_sources source)
226{
227	int flags;
228
229	/* Read the current trigger mode control bits */
230	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
231	/* Mask off the EITS and TPST bits */
232	flags &= 0x9;
233
234	switch (source) {
235	case software:
236		break;
237
238	case timer_pacer:
239		flags |= PCI9111_AI_TRIG_CTRL_TPST;
240		break;
241
242	case external:
243		flags |= PCI9111_AI_TRIG_CTRL_ETIS;
244		break;
245	}
246
247	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
248}
249
250static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
251{
252	int flags;
253
254	/* Read the current trigger mode control bits */
255	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
256	/* Mask off the PTRG bit */
257	flags &= 0x7;
258
259	if (pretrigger)
260		flags |= PCI9111_AI_TRIG_CTRL_PTRG;
261
262	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
263}
264
265static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
266{
267	int flags;
268
269	/* Read the current trigger mode control bits */
270	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
271	/* Mask off the ASCAN bit */
272	flags &= 0xe;
273
274	if (autoscan)
275		flags |= PCI9111_AI_TRIG_CTRL_ASCAN;
276
277	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
278}
279
280enum pci9111_ISC0_sources {
281	irq_on_eoc,
282	irq_on_fifo_half_full
283};
284
285enum pci9111_ISC1_sources {
286	irq_on_timer_tick,
287	irq_on_external_trigger
288};
289
290static void pci9111_interrupt_source_set(struct comedi_device *dev,
291					 enum pci9111_ISC0_sources irq_0_source,
292					 enum pci9111_ISC1_sources irq_1_source)
293{
294	int flags;
295
296	/* Read the current interrupt control bits */
297	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
298	/* Shift the bits so they are compatible with the write register */
299	flags >>= 4;
300	/* Mask off the ISCx bits */
301	flags &= 0xc0;
302
303	/* Now set the new ISCx bits */
304	if (irq_0_source == irq_on_fifo_half_full)
305		flags |= PCI9111_INT_CTRL_ISC0;
306
307	if (irq_1_source == irq_on_external_trigger)
308		flags |= PCI9111_INT_CTRL_ISC1;
309
310	outb(flags, dev->iobase + PCI9111_INT_CTRL_REG);
311}
312
313static void pci9111_fifo_reset(struct comedi_device *dev)
314{
315	unsigned long int_ctrl_reg = dev->iobase + PCI9111_INT_CTRL_REG;
316
317	/* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */
318	outb(0, int_ctrl_reg);
319	outb(PCI9111_INT_CTRL_FFEN, int_ctrl_reg);
320	outb(0, int_ctrl_reg);
321}
322
323/*  ------------------------------------------------------------------ */
324/*  HARDWARE TRIGGERED ANALOG INPUT SECTION */
325/*  ------------------------------------------------------------------ */
326
327/*  Cancel analog input autoscan */
328
329static int pci9111_ai_cancel(struct comedi_device *dev,
330			     struct comedi_subdevice *s)
331{
332	struct pci9111_private_data *dev_private = dev->private;
333
334	/*  Disable interrupts */
335
336	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
337				  true, false);
338
339	pci9111_trigger_source_set(dev, software);
340
341	pci9111_autoscan_set(dev, false);
342
343	pci9111_fifo_reset(dev);
344
345	return 0;
346}
347
348/*  Test analog input command */
349
350#define pci9111_check_trigger_src(src, flags)	do {			\
351		tmp = src;						\
352		src &= flags;						\
353		if (!src || tmp != src)					\
354			error++;					\
355	} while (false);
356
357static int
358pci9111_ai_do_cmd_test(struct comedi_device *dev,
359		       struct comedi_subdevice *s, struct comedi_cmd *cmd)
360{
361	struct pci9111_private_data *dev_private = dev->private;
362	int tmp;
363	int error = 0;
364	int range, reference;
365	int i;
366
367	/*  Step 1 : check if trigger are trivialy valid */
368
369	pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
370	pci9111_check_trigger_src(cmd->scan_begin_src,
371				  TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
372	pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
373	pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
374	pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
375
376	if (error)
377		return 1;
378
379	/*  step 2 : make sure trigger sources are unique and mutually
380	 *  compatible */
381
382	if (cmd->start_src != TRIG_NOW)
383		error++;
384
385	if ((cmd->scan_begin_src != TRIG_TIMER) &&
386	    (cmd->scan_begin_src != TRIG_FOLLOW) &&
387	    (cmd->scan_begin_src != TRIG_EXT))
388		error++;
389
390	if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT))
391		error++;
392	if ((cmd->convert_src == TRIG_TIMER) &&
393	    !((cmd->scan_begin_src == TRIG_TIMER) ||
394	      (cmd->scan_begin_src == TRIG_FOLLOW)))
395		error++;
396	if ((cmd->convert_src == TRIG_EXT) &&
397	    !((cmd->scan_begin_src == TRIG_EXT) ||
398	      (cmd->scan_begin_src == TRIG_FOLLOW)))
399		error++;
400
401
402	if (cmd->scan_end_src != TRIG_COUNT)
403		error++;
404	if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
405		error++;
406
407	if (error)
408		return 2;
409
410	/*  Step 3 : make sure arguments are trivialy compatible */
411
412	if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
413		cmd->start_arg = 0;
414		error++;
415	}
416
417	if ((cmd->convert_src == TRIG_TIMER) &&
418	    (cmd->convert_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) {
419		cmd->convert_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS;
420		error++;
421	}
422	if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
423		cmd->convert_arg = 0;
424		error++;
425	}
426
427	if ((cmd->scan_begin_src == TRIG_TIMER) &&
428	    (cmd->scan_begin_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) {
429		cmd->scan_begin_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS;
430		error++;
431	}
432	if ((cmd->scan_begin_src == TRIG_FOLLOW)
433	    && (cmd->scan_begin_arg != 0)) {
434		cmd->scan_begin_arg = 0;
435		error++;
436	}
437	if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
438		cmd->scan_begin_arg = 0;
439		error++;
440	}
441
442	if ((cmd->scan_end_src == TRIG_COUNT) &&
443	    (cmd->scan_end_arg != cmd->chanlist_len)) {
444		cmd->scan_end_arg = cmd->chanlist_len;
445		error++;
446	}
447
448	if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
449		cmd->stop_arg = 1;
450		error++;
451	}
452	if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
453		cmd->stop_arg = 0;
454		error++;
455	}
456
457	if (error)
458		return 3;
459
460	/*  Step 4 : fix up any arguments */
461
462	if (cmd->convert_src == TRIG_TIMER) {
463		tmp = cmd->convert_arg;
464		i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
465					       &(dev_private->timer_divisor_1),
466					       &(dev_private->timer_divisor_2),
467					       &(cmd->convert_arg),
468					       cmd->flags & TRIG_ROUND_MASK);
469		if (tmp != cmd->convert_arg)
470			error++;
471	}
472	/*  There's only one timer on this card, so the scan_begin timer must */
473	/*  be a multiple of chanlist_len*convert_arg */
474
475	if (cmd->scan_begin_src == TRIG_TIMER) {
476
477		unsigned int scan_begin_min;
478		unsigned int scan_begin_arg;
479		unsigned int scan_factor;
480
481		scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
482
483		if (cmd->scan_begin_arg != scan_begin_min) {
484			if (scan_begin_min < cmd->scan_begin_arg) {
485				scan_factor =
486				    cmd->scan_begin_arg / scan_begin_min;
487				scan_begin_arg = scan_factor * scan_begin_min;
488				if (cmd->scan_begin_arg != scan_begin_arg) {
489					cmd->scan_begin_arg = scan_begin_arg;
490					error++;
491				}
492			} else {
493				cmd->scan_begin_arg = scan_begin_min;
494				error++;
495			}
496		}
497	}
498
499	if (error)
500		return 4;
501
502	/*  Step 5 : check channel list */
503
504	if (cmd->chanlist) {
505
506		range = CR_RANGE(cmd->chanlist[0]);
507		reference = CR_AREF(cmd->chanlist[0]);
508
509		if (cmd->chanlist_len > 1) {
510			for (i = 0; i < cmd->chanlist_len; i++) {
511				if (CR_CHAN(cmd->chanlist[i]) != i) {
512					comedi_error(dev,
513						     "entries in chanlist must be consecutive "
514						     "channels,counting upwards from 0\n");
515					error++;
516				}
517				if (CR_RANGE(cmd->chanlist[i]) != range) {
518					comedi_error(dev,
519						     "entries in chanlist must all have the same gain\n");
520					error++;
521				}
522				if (CR_AREF(cmd->chanlist[i]) != reference) {
523					comedi_error(dev,
524						     "entries in chanlist must all have the same reference\n");
525					error++;
526				}
527			}
528		}
529	}
530
531	if (error)
532		return 5;
533
534	return 0;
535
536}
537
538/*  Analog input command */
539
540static int pci9111_ai_do_cmd(struct comedi_device *dev,
541			     struct comedi_subdevice *s)
542{
543	struct pci9111_private_data *dev_private = dev->private;
544	struct comedi_cmd *async_cmd = &s->async->cmd;
545
546	if (!dev->irq) {
547		comedi_error(dev,
548			     "no irq assigned for PCI9111, cannot do hardware conversion");
549		return -1;
550	}
551	/*  Set channel scan limit */
552	/*  PCI9111 allows only scanning from channel 0 to channel n */
553	/*  TODO: handle the case of an external multiplexer */
554
555	if (async_cmd->chanlist_len > 1) {
556		outb(async_cmd->chanlist_len - 1,
557			dev->iobase + PCI9111_AI_CHANNEL_REG);
558		pci9111_autoscan_set(dev, true);
559	} else {
560		outb(CR_CHAN(async_cmd->chanlist[0]),
561			dev->iobase + PCI9111_AI_CHANNEL_REG);
562		pci9111_autoscan_set(dev, false);
563	}
564
565	/*  Set gain */
566	/*  This is the same gain on every channel */
567
568	outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK,
569		dev->iobase + PCI9111_AI_RANGE_STAT_REG);
570
571	/* Set counter */
572
573	switch (async_cmd->stop_src) {
574	case TRIG_COUNT:
575		dev_private->stop_counter =
576		    async_cmd->stop_arg * async_cmd->chanlist_len;
577		dev_private->stop_is_none = 0;
578		break;
579
580	case TRIG_NONE:
581		dev_private->stop_counter = 0;
582		dev_private->stop_is_none = 1;
583		break;
584
585	default:
586		comedi_error(dev, "Invalid stop trigger");
587		return -1;
588	}
589
590	/*  Set timer pacer */
591
592	dev_private->scan_delay = 0;
593	switch (async_cmd->convert_src) {
594	case TRIG_TIMER:
595		i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
596					       &(dev_private->timer_divisor_1),
597					       &(dev_private->timer_divisor_2),
598					       &(async_cmd->convert_arg),
599					       async_cmd->
600					       flags & TRIG_ROUND_MASK);
601
602		pci9111_trigger_source_set(dev, software);
603		pci9111_timer_set(dev);
604		pci9111_fifo_reset(dev);
605		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
606					     irq_on_timer_tick);
607		pci9111_trigger_source_set(dev, timer_pacer);
608		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
609					  false, true, true);
610
611		if (async_cmd->scan_begin_src == TRIG_TIMER) {
612			dev_private->scan_delay =
613				(async_cmd->scan_begin_arg /
614				 (async_cmd->convert_arg *
615				  async_cmd->chanlist_len)) - 1;
616		}
617
618		break;
619
620	case TRIG_EXT:
621
622		pci9111_trigger_source_set(dev, external);
623		pci9111_fifo_reset(dev);
624		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
625					     irq_on_timer_tick);
626		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
627					  false, true, true);
628
629		break;
630
631	default:
632		comedi_error(dev, "Invalid convert trigger");
633		return -1;
634	}
635
636	dev_private->stop_counter *= (1 + dev_private->scan_delay);
637	dev_private->chanlist_len = async_cmd->chanlist_len;
638	dev_private->chunk_counter = 0;
639	dev_private->chunk_num_samples =
640	    dev_private->chanlist_len * (1 + dev_private->scan_delay);
641
642	return 0;
643}
644
645static void pci9111_ai_munge(struct comedi_device *dev,
646			     struct comedi_subdevice *s, void *data,
647			     unsigned int num_bytes,
648			     unsigned int start_chan_index)
649{
650	short *array = data;
651	unsigned int maxdata = s->maxdata;
652	unsigned int invert = (maxdata + 1) >> 1;
653	unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
654	unsigned int num_samples = num_bytes / sizeof(short);
655	unsigned int i;
656
657	for (i = 0; i < num_samples; i++)
658		array[i] = ((array[i] >> shift) & maxdata) ^ invert;
659}
660
661/*  ------------------------------------------------------------------ */
662/*  INTERRUPT SECTION */
663/*  ------------------------------------------------------------------ */
664
665static irqreturn_t pci9111_interrupt(int irq, void *p_device)
666{
667	struct comedi_device *dev = p_device;
668	struct pci9111_private_data *dev_private = dev->private;
669	struct comedi_subdevice *s = dev->read_subdev;
670	struct comedi_async *async;
671	unsigned int status;
672	unsigned long irq_flags;
673	unsigned char intcsr;
674
675	if (!dev->attached) {
676		/*  Ignore interrupt before device fully attached. */
677		/*  Might not even have allocated subdevices yet! */
678		return IRQ_NONE;
679	}
680
681	async = s->async;
682
683	spin_lock_irqsave(&dev->spinlock, irq_flags);
684
685	/*  Check if we are source of interrupt */
686	intcsr = inb(dev_private->lcr_io_base +
687		     PLX9050_REGISTER_INTERRUPT_CONTROL);
688	if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
689	      && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
690		   == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
691		  || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
692		      == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
693		/*  Not the source of the interrupt. */
694		/*  (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
695		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
696		return IRQ_NONE;
697	}
698
699	if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
700	    (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
701		/*  Interrupt comes from fifo_half-full signal */
702
703		status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
704
705		/* '0' means FIFO is full, data may have been lost */
706		if (!(status & PCI9111_AI_STAT_FF_FF)) {
707			spin_unlock_irqrestore(&dev->spinlock, irq_flags);
708			comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
709			outb(0, dev->iobase + PCI9111_INT_CLR_REG);
710			pci9111_ai_cancel(dev, s);
711			async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
712			comedi_event(dev, s);
713
714			return IRQ_HANDLED;
715		}
716
717		/* '0' means FIFO is half-full */
718		if (!(status & PCI9111_AI_STAT_FF_HF)) {
719			unsigned int num_samples;
720			unsigned int bytes_written = 0;
721
722			num_samples =
723			    PCI9111_FIFO_HALF_SIZE >
724			    dev_private->stop_counter
725			    && !dev_private->
726			    stop_is_none ? dev_private->stop_counter :
727			    PCI9111_FIFO_HALF_SIZE;
728			insw(dev->iobase + PCI9111_AI_FIFO_REG,
729			     dev_private->ai_bounce_buffer, num_samples);
730
731			if (dev_private->scan_delay < 1) {
732				bytes_written =
733				    cfc_write_array_to_buffer(s,
734							      dev_private->
735							      ai_bounce_buffer,
736							      num_samples *
737							      sizeof(short));
738			} else {
739				int position = 0;
740				int to_read;
741
742				while (position < num_samples) {
743					if (dev_private->chunk_counter <
744					    dev_private->chanlist_len) {
745						to_read =
746						    dev_private->chanlist_len -
747						    dev_private->chunk_counter;
748
749						if (to_read >
750						    num_samples - position)
751							to_read =
752							    num_samples -
753							    position;
754
755						bytes_written +=
756						    cfc_write_array_to_buffer
757						    (s,
758						     dev_private->ai_bounce_buffer
759						     + position,
760						     to_read * sizeof(short));
761					} else {
762						to_read =
763						    dev_private->chunk_num_samples
764						    -
765						    dev_private->chunk_counter;
766						if (to_read >
767						    num_samples - position)
768							to_read =
769							    num_samples -
770							    position;
771
772						bytes_written +=
773						    sizeof(short) * to_read;
774					}
775
776					position += to_read;
777					dev_private->chunk_counter += to_read;
778
779					if (dev_private->chunk_counter >=
780					    dev_private->chunk_num_samples)
781						dev_private->chunk_counter = 0;
782				}
783			}
784
785			dev_private->stop_counter -=
786			    bytes_written / sizeof(short);
787		}
788	}
789
790	if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
791		async->events |= COMEDI_CB_EOA;
792		pci9111_ai_cancel(dev, s);
793	}
794
795	outb(0, dev->iobase + PCI9111_INT_CLR_REG);
796
797	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
798
799	comedi_event(dev, s);
800
801	return IRQ_HANDLED;
802}
803
804/*  ------------------------------------------------------------------ */
805/*  INSTANT ANALOG INPUT OUTPUT SECTION */
806/*  ------------------------------------------------------------------ */
807
808/*  analog instant input */
809
810static int pci9111_ai_insn_read(struct comedi_device *dev,
811				struct comedi_subdevice *s,
812				struct comedi_insn *insn, unsigned int *data)
813{
814	unsigned int chan = CR_CHAN(insn->chanspec);
815	unsigned int range = CR_RANGE(insn->chanspec);
816	unsigned int maxdata = s->maxdata;
817	unsigned int invert = (maxdata + 1) >> 1;
818	unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
819	unsigned int status;
820	int timeout;
821	int i;
822
823	outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG);
824
825	status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
826	if ((status & PCI9111_AI_RANGE_MASK) != range) {
827		outb(range & PCI9111_AI_RANGE_MASK,
828			dev->iobase + PCI9111_AI_RANGE_STAT_REG);
829	}
830
831	pci9111_fifo_reset(dev);
832
833	for (i = 0; i < insn->n; i++) {
834		/* Generate a software trigger */
835		outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG);
836
837		timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
838
839		while (timeout--) {
840			status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
841			/* '1' means FIFO is not empty */
842			if (status & PCI9111_AI_STAT_FF_EF)
843				goto conversion_done;
844		}
845
846		comedi_error(dev, "A/D read timeout");
847		data[i] = 0;
848		pci9111_fifo_reset(dev);
849		return -ETIME;
850
851conversion_done:
852
853		data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG);
854		data[i] = ((data[i] >> shift) & maxdata) ^ invert;
855	}
856
857	return i;
858}
859
860static int pci9111_ao_insn_write(struct comedi_device *dev,
861				 struct comedi_subdevice *s,
862				 struct comedi_insn *insn,
863				 unsigned int *data)
864{
865	struct pci9111_private_data *dev_private = dev->private;
866	unsigned int val = 0;
867	int i;
868
869	for (i = 0; i < insn->n; i++) {
870		val = data[i];
871		outw(val, dev->iobase + PCI9111_AO_REG);
872	}
873	dev_private->ao_readback = val;
874
875	return insn->n;
876}
877
878static int pci9111_ao_insn_read(struct comedi_device *dev,
879				struct comedi_subdevice *s,
880				struct comedi_insn *insn,
881				unsigned int *data)
882{
883	struct pci9111_private_data *dev_private = dev->private;
884	int i;
885
886	for (i = 0; i < insn->n; i++)
887		data[i] = dev_private->ao_readback;
888
889	return insn->n;
890}
891
892static int pci9111_di_insn_bits(struct comedi_device *dev,
893				struct comedi_subdevice *s,
894				struct comedi_insn *insn,
895				unsigned int *data)
896{
897	data[1] = inw(dev->iobase + PCI9111_DIO_REG);
898
899	return insn->n;
900}
901
902static int pci9111_do_insn_bits(struct comedi_device *dev,
903				struct comedi_subdevice *s,
904				struct comedi_insn *insn,
905				unsigned int *data)
906{
907	unsigned int mask = data[0];
908	unsigned int bits = data[1];
909
910	if (mask) {
911		s->state &= ~mask;
912		s->state |= (bits & mask);
913
914		outw(s->state, dev->iobase + PCI9111_DIO_REG);
915	}
916
917	data[1] = s->state;
918
919	return insn->n;
920}
921
922/*  ------------------------------------------------------------------ */
923/*  INITIALISATION SECTION */
924/*  ------------------------------------------------------------------ */
925
926/*  Reset device */
927
928static int pci9111_reset(struct comedi_device *dev)
929{
930	struct pci9111_private_data *dev_private = dev->private;
931
932	/*  Set trigger source to software */
933
934	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
935				  true, false);
936
937	pci9111_trigger_source_set(dev, software);
938	pci9111_pretrigger_set(dev, false);
939	pci9111_autoscan_set(dev, false);
940
941	/*  Reset 8254 chip */
942
943	dev_private->timer_divisor_1 = 0;
944	dev_private->timer_divisor_2 = 0;
945
946	pci9111_timer_set(dev);
947
948	return 0;
949}
950
951static int pci9111_attach_pci(struct comedi_device *dev,
952			      struct pci_dev *pcidev)
953{
954	struct pci9111_private_data *dev_private;
955	struct comedi_subdevice *s;
956	int ret;
957
958	comedi_set_hw_dev(dev, &pcidev->dev);
959	dev->board_name = dev->driver->driver_name;
960
961	ret = alloc_private(dev, sizeof(*dev_private));
962	if (ret)
963		return ret;
964	dev_private = dev->private;
965
966	ret = comedi_pci_enable(pcidev, dev->board_name);
967	if (ret)
968		return ret;
969	dev_private->lcr_io_base = pci_resource_start(pcidev, 1);
970	dev->iobase = pci_resource_start(pcidev, 2);
971
972	pci9111_reset(dev);
973
974	if (pcidev->irq > 0) {
975		ret = request_irq(dev->irq, pci9111_interrupt,
976				  IRQF_SHARED, dev->board_name, dev);
977		if (ret)
978			return ret;
979		dev->irq = pcidev->irq;
980	}
981
982	ret = comedi_alloc_subdevices(dev, 4);
983	if (ret)
984		return ret;
985
986	s = &dev->subdevices[0];
987	dev->read_subdev = s;
988	s->type		= COMEDI_SUBD_AI;
989	s->subdev_flags	= SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
990	s->n_chan	= 16;
991	s->maxdata	= 0xffff;
992	s->len_chanlist	= 16;
993	s->range_table	= &pci9111_hr_ai_range;
994	s->cancel	= pci9111_ai_cancel;
995	s->insn_read	= pci9111_ai_insn_read;
996	s->do_cmdtest	= pci9111_ai_do_cmd_test;
997	s->do_cmd	= pci9111_ai_do_cmd;
998	s->munge	= pci9111_ai_munge;
999
1000	s = &dev->subdevices[1];
1001	s->type		= COMEDI_SUBD_AO;
1002	s->subdev_flags	= SDF_WRITABLE | SDF_COMMON;
1003	s->n_chan	= 1;
1004	s->maxdata	= 0x0fff;
1005	s->len_chanlist	= 1;
1006	s->range_table	= &range_bipolar10;
1007	s->insn_write	= pci9111_ao_insn_write;
1008	s->insn_read	= pci9111_ao_insn_read;
1009
1010	s = &dev->subdevices[2];
1011	s->type		= COMEDI_SUBD_DI;
1012	s->subdev_flags	= SDF_READABLE;
1013	s->n_chan	= 16;
1014	s->maxdata	= 1;
1015	s->range_table	= &range_digital;
1016	s->insn_bits	= pci9111_di_insn_bits;
1017
1018	s = &dev->subdevices[3];
1019	s->type		= COMEDI_SUBD_DO;
1020	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
1021	s->n_chan	= 16;
1022	s->maxdata	= 1;
1023	s->range_table	= &range_digital;
1024	s->insn_bits	= pci9111_do_insn_bits;
1025
1026	dev_private->is_valid = 1;
1027
1028	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
1029
1030	return 0;
1031}
1032
1033static void pci9111_detach(struct comedi_device *dev)
1034{
1035	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1036	struct pci9111_private_data *dev_private = dev->private;
1037
1038	if (dev_private) {
1039		if (dev_private->is_valid)
1040			pci9111_reset(dev);
1041	}
1042	if (dev->irq != 0)
1043		free_irq(dev->irq, dev);
1044	if (pcidev) {
1045		if (dev->iobase)
1046			comedi_pci_disable(pcidev);
1047		pci_dev_put(pcidev);
1048	}
1049}
1050
1051static struct comedi_driver adl_pci9111_driver = {
1052	.driver_name	= "adl_pci9111",
1053	.module		= THIS_MODULE,
1054	.attach_pci	= pci9111_attach_pci,
1055	.detach		= pci9111_detach,
1056};
1057
1058static int __devinit pci9111_pci_probe(struct pci_dev *dev,
1059				       const struct pci_device_id *ent)
1060{
1061	return comedi_pci_auto_config(dev, &adl_pci9111_driver);
1062}
1063
1064static void __devexit pci9111_pci_remove(struct pci_dev *dev)
1065{
1066	comedi_pci_auto_unconfig(dev);
1067}
1068
1069static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
1070	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
1071	/* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
1072	{ 0 }
1073};
1074MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
1075
1076static struct pci_driver adl_pci9111_pci_driver = {
1077	.name		= "adl_pci9111",
1078	.id_table	= pci9111_pci_table,
1079	.probe		= pci9111_pci_probe,
1080	.remove		= __devexit_p(pci9111_pci_remove),
1081};
1082module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
1083
1084MODULE_AUTHOR("Comedi http://www.comedi.org");
1085MODULE_DESCRIPTION("Comedi low-level driver");
1086MODULE_LICENSE("GPL");
1087