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