adl_pci9111.c revision bb73fc99bd2a071800e64e985ed464763b9a8d75
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*/
21
22/*
23Driver: adl_pci9111
24Description: Adlink PCI-9111HR
25Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
26Devices: [ADLink] PCI-9111HR (adl_pci9111)
27Status: experimental
28
29Supports:
30
31	- ai_insn read
32	- ao_insn read/write
33	- di_insn read
34	- do_insn read/write
35	- ai_do_cmd mode with the following sources:
36
37	- start_src		TRIG_NOW
38	- scan_begin_src	TRIG_FOLLOW	TRIG_TIMER	TRIG_EXT
39	- convert_src				TRIG_TIMER	TRIG_EXT
40	- scan_end_src		TRIG_COUNT
41	- stop_src		TRIG_COUNT	TRIG_NONE
42
43The scanned channels must be consecutive and start from 0. They must
44all have the same range and aref.
45
46Configuration options: not applicable, uses PCI auto config
47*/
48
49/*
50CHANGELOG:
51
522005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
53a multiple of chanlist_len*convert_arg.
542002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
552002/02/18 Added external trigger support for analog input.
56
57TODO:
58
59	- Really test implemented functionality.
60	- Add support for the PCI-9111DG with a probe routine to identify
61	  the card type (perhaps with the help of the channel number readback
62	  of the A/D Data register).
63	- Add external multiplexer support.
64
65*/
66
67#include <linux/module.h>
68#include <linux/pci.h>
69#include <linux/delay.h>
70#include <linux/interrupt.h>
71
72#include "../comedidev.h"
73
74#include "8253.h"
75#include "plx9052.h"
76#include "comedi_fc.h"
77
78#define PCI9111_DRIVER_NAME	"adl_pci9111"
79#define PCI9111_HR_DEVICE_ID	0x9111
80
81#define PCI9111_FIFO_HALF_SIZE	512
82
83#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS	10000
84
85#define PCI9111_RANGE_SETTING_DELAY		10
86#define PCI9111_AI_INSTANT_READ_UDELAY_US	2
87
88/*
89 * IO address map and bit defines
90 */
91#define PCI9111_AI_FIFO_REG		0x00
92#define PCI9111_AO_REG			0x00
93#define PCI9111_DIO_REG			0x02
94#define PCI9111_EDIO_REG		0x04
95#define PCI9111_AI_CHANNEL_REG		0x06
96#define PCI9111_AI_RANGE_STAT_REG	0x08
97#define PCI9111_AI_STAT_AD_BUSY		(1 << 7)
98#define PCI9111_AI_STAT_FF_FF		(1 << 6)
99#define PCI9111_AI_STAT_FF_HF		(1 << 5)
100#define PCI9111_AI_STAT_FF_EF		(1 << 4)
101#define PCI9111_AI_RANGE_MASK		(7 << 0)
102#define PCI9111_AI_TRIG_CTRL_REG	0x0a
103#define PCI9111_AI_TRIG_CTRL_TRGEVENT	(1 << 5)
104#define PCI9111_AI_TRIG_CTRL_POTRG	(1 << 4)
105#define PCI9111_AI_TRIG_CTRL_PTRG	(1 << 3)
106#define PCI9111_AI_TRIG_CTRL_ETIS	(1 << 2)
107#define PCI9111_AI_TRIG_CTRL_TPST	(1 << 1)
108#define PCI9111_AI_TRIG_CTRL_ASCAN	(1 << 0)
109#define PCI9111_INT_CTRL_REG		0x0c
110#define PCI9111_INT_CTRL_ISC2		(1 << 3)
111#define PCI9111_INT_CTRL_FFEN		(1 << 2)
112#define PCI9111_INT_CTRL_ISC1		(1 << 1)
113#define PCI9111_INT_CTRL_ISC0		(1 << 0)
114#define PCI9111_SOFT_TRIG_REG		0x0e
115#define PCI9111_8254_BASE_REG		0x40
116#define PCI9111_INT_CLR_REG		0x48
117
118/* PLX 9052 Local Interrupt 1 enabled and active */
119#define PCI9111_LI1_ACTIVE	(PLX9052_INTCSR_LI1ENAB |	\
120				 PLX9052_INTCSR_LI1STAT)
121
122/* PLX 9052 Local Interrupt 2 enabled and active */
123#define PCI9111_LI2_ACTIVE	(PLX9052_INTCSR_LI2ENAB |	\
124				 PLX9052_INTCSR_LI2STAT)
125
126static const struct comedi_lrange pci9111_ai_range = {
127	5, {
128		BIP_RANGE(10),
129		BIP_RANGE(5),
130		BIP_RANGE(2.5),
131		BIP_RANGE(1.25),
132		BIP_RANGE(0.625)
133	}
134};
135
136struct pci9111_private_data {
137	unsigned long lcr_io_base;
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;
148
149	unsigned int div1;
150	unsigned int div2;
151
152	unsigned short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
153};
154
155static void plx9050_interrupt_control(unsigned long io_base,
156				      bool LINTi1_enable,
157				      bool LINTi1_active_high,
158				      bool LINTi2_enable,
159				      bool LINTi2_active_high,
160				      bool interrupt_enable)
161{
162	int flags = 0;
163
164	if (LINTi1_enable)
165		flags |= PLX9052_INTCSR_LI1ENAB;
166	if (LINTi1_active_high)
167		flags |= PLX9052_INTCSR_LI1POL;
168	if (LINTi2_enable)
169		flags |= PLX9052_INTCSR_LI2ENAB;
170	if (LINTi2_active_high)
171		flags |= PLX9052_INTCSR_LI2POL;
172
173	if (interrupt_enable)
174		flags |= PLX9052_INTCSR_PCIENAB;
175
176	outb(flags, io_base + PLX9052_INTCSR);
177}
178
179static void pci9111_timer_set(struct comedi_device *dev)
180{
181	struct pci9111_private_data *dev_private = dev->private;
182	unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG;
183
184	i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY);
185	i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
186	i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
187
188	udelay(1);
189
190	i8254_write(timer_base, 1, 2, dev_private->div2);
191	i8254_write(timer_base, 1, 1, dev_private->div1);
192}
193
194enum pci9111_trigger_sources {
195	software,
196	timer_pacer,
197	external
198};
199
200static void pci9111_trigger_source_set(struct comedi_device *dev,
201				       enum pci9111_trigger_sources source)
202{
203	int flags;
204
205	/* Read the current trigger mode control bits */
206	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
207	/* Mask off the EITS and TPST bits */
208	flags &= 0x9;
209
210	switch (source) {
211	case software:
212		break;
213
214	case timer_pacer:
215		flags |= PCI9111_AI_TRIG_CTRL_TPST;
216		break;
217
218	case external:
219		flags |= PCI9111_AI_TRIG_CTRL_ETIS;
220		break;
221	}
222
223	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
224}
225
226static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
227{
228	int flags;
229
230	/* Read the current trigger mode control bits */
231	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
232	/* Mask off the PTRG bit */
233	flags &= 0x7;
234
235	if (pretrigger)
236		flags |= PCI9111_AI_TRIG_CTRL_PTRG;
237
238	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
239}
240
241static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
242{
243	int flags;
244
245	/* Read the current trigger mode control bits */
246	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
247	/* Mask off the ASCAN bit */
248	flags &= 0xe;
249
250	if (autoscan)
251		flags |= PCI9111_AI_TRIG_CTRL_ASCAN;
252
253	outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
254}
255
256enum pci9111_ISC0_sources {
257	irq_on_eoc,
258	irq_on_fifo_half_full
259};
260
261enum pci9111_ISC1_sources {
262	irq_on_timer_tick,
263	irq_on_external_trigger
264};
265
266static void pci9111_interrupt_source_set(struct comedi_device *dev,
267					 enum pci9111_ISC0_sources irq_0_source,
268					 enum pci9111_ISC1_sources irq_1_source)
269{
270	int flags;
271
272	/* Read the current interrupt control bits */
273	flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
274	/* Shift the bits so they are compatible with the write register */
275	flags >>= 4;
276	/* Mask off the ISCx bits */
277	flags &= 0xc0;
278
279	/* Now set the new ISCx bits */
280	if (irq_0_source == irq_on_fifo_half_full)
281		flags |= PCI9111_INT_CTRL_ISC0;
282
283	if (irq_1_source == irq_on_external_trigger)
284		flags |= PCI9111_INT_CTRL_ISC1;
285
286	outb(flags, dev->iobase + PCI9111_INT_CTRL_REG);
287}
288
289static void pci9111_fifo_reset(struct comedi_device *dev)
290{
291	unsigned long int_ctrl_reg = dev->iobase + PCI9111_INT_CTRL_REG;
292
293	/* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */
294	outb(0, int_ctrl_reg);
295	outb(PCI9111_INT_CTRL_FFEN, int_ctrl_reg);
296	outb(0, int_ctrl_reg);
297}
298
299static int pci9111_ai_cancel(struct comedi_device *dev,
300			     struct comedi_subdevice *s)
301{
302	struct pci9111_private_data *dev_private = dev->private;
303
304	/*  Disable interrupts */
305	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
306				  true, false);
307
308	pci9111_trigger_source_set(dev, software);
309
310	pci9111_autoscan_set(dev, false);
311
312	pci9111_fifo_reset(dev);
313
314	return 0;
315}
316
317static int pci9111_ai_do_cmd_test(struct comedi_device *dev,
318				  struct comedi_subdevice *s,
319				  struct comedi_cmd *cmd)
320{
321	struct pci9111_private_data *dev_private = dev->private;
322	int tmp;
323	int error = 0;
324	int range, reference;
325	int i;
326
327	/* Step 1 : check if triggers are trivially valid */
328
329	error |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
330	error |= cfc_check_trigger_src(&cmd->scan_begin_src,
331					TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
332	error |= cfc_check_trigger_src(&cmd->convert_src,
333					TRIG_TIMER | TRIG_EXT);
334	error |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
335	error |= cfc_check_trigger_src(&cmd->stop_src,
336					TRIG_COUNT | TRIG_NONE);
337
338	if (error)
339		return 1;
340
341	/* Step 2a : make sure trigger sources are unique */
342
343	error |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
344	error |= cfc_check_trigger_is_unique(cmd->convert_src);
345	error |= cfc_check_trigger_is_unique(cmd->stop_src);
346
347	/* Step 2b : and mutually compatible */
348
349	if ((cmd->convert_src == TRIG_TIMER) &&
350	    !((cmd->scan_begin_src == TRIG_TIMER) ||
351	      (cmd->scan_begin_src == TRIG_FOLLOW)))
352		error |= -EINVAL;
353	if ((cmd->convert_src == TRIG_EXT) &&
354	    !((cmd->scan_begin_src == TRIG_EXT) ||
355	      (cmd->scan_begin_src == TRIG_FOLLOW)))
356		error |= -EINVAL;
357
358	if (error)
359		return 2;
360
361	/* Step 3: check if arguments are trivially valid */
362
363	error |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
364
365	if (cmd->convert_src == TRIG_TIMER)
366		error |= cfc_check_trigger_arg_min(&cmd->convert_arg,
367					PCI9111_AI_ACQUISITION_PERIOD_MIN_NS);
368	else	/* TRIG_EXT */
369		error |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
370
371	if (cmd->scan_begin_src == TRIG_TIMER)
372		error |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
373					PCI9111_AI_ACQUISITION_PERIOD_MIN_NS);
374	else	/* TRIG_FOLLOW || TRIG_EXT */
375		error |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
376
377	error |= cfc_check_trigger_arg_is(&cmd->scan_end_arg,
378					  cmd->chanlist_len);
379
380	if (cmd->stop_src == TRIG_COUNT)
381		error |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
382	else	/* TRIG_NONE */
383		error |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
384
385	if (error)
386		return 3;
387
388	/*  Step 4 : fix up any arguments */
389
390	if (cmd->convert_src == TRIG_TIMER) {
391		tmp = cmd->convert_arg;
392		i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
393					  &dev_private->div1,
394					  &dev_private->div2,
395					  &cmd->convert_arg, cmd->flags);
396		if (tmp != cmd->convert_arg)
397			error++;
398	}
399	/*  There's only one timer on this card, so the scan_begin timer must */
400	/*  be a multiple of chanlist_len*convert_arg */
401
402	if (cmd->scan_begin_src == TRIG_TIMER) {
403
404		unsigned int scan_begin_min;
405		unsigned int scan_begin_arg;
406		unsigned int scan_factor;
407
408		scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
409
410		if (cmd->scan_begin_arg != scan_begin_min) {
411			if (scan_begin_min < cmd->scan_begin_arg) {
412				scan_factor =
413				    cmd->scan_begin_arg / scan_begin_min;
414				scan_begin_arg = scan_factor * scan_begin_min;
415				if (cmd->scan_begin_arg != scan_begin_arg) {
416					cmd->scan_begin_arg = scan_begin_arg;
417					error++;
418				}
419			} else {
420				cmd->scan_begin_arg = scan_begin_min;
421				error++;
422			}
423		}
424	}
425
426	if (error)
427		return 4;
428
429	/*  Step 5 : check channel list */
430
431	if (cmd->chanlist) {
432
433		range = CR_RANGE(cmd->chanlist[0]);
434		reference = CR_AREF(cmd->chanlist[0]);
435
436		if (cmd->chanlist_len > 1) {
437			for (i = 0; i < cmd->chanlist_len; i++) {
438				if (CR_CHAN(cmd->chanlist[i]) != i) {
439					comedi_error(dev,
440						     "entries in chanlist must be consecutive "
441						     "channels,counting upwards from 0\n");
442					error++;
443				}
444				if (CR_RANGE(cmd->chanlist[i]) != range) {
445					comedi_error(dev,
446						     "entries in chanlist must all have the same gain\n");
447					error++;
448				}
449				if (CR_AREF(cmd->chanlist[i]) != reference) {
450					comedi_error(dev,
451						     "entries in chanlist must all have the same reference\n");
452					error++;
453				}
454			}
455		}
456	}
457
458	if (error)
459		return 5;
460
461	return 0;
462
463}
464
465static int pci9111_ai_do_cmd(struct comedi_device *dev,
466			     struct comedi_subdevice *s)
467{
468	struct pci9111_private_data *dev_private = dev->private;
469	struct comedi_cmd *async_cmd = &s->async->cmd;
470
471	/*  Set channel scan limit */
472	/*  PCI9111 allows only scanning from channel 0 to channel n */
473	/*  TODO: handle the case of an external multiplexer */
474
475	if (async_cmd->chanlist_len > 1) {
476		outb(async_cmd->chanlist_len - 1,
477			dev->iobase + PCI9111_AI_CHANNEL_REG);
478		pci9111_autoscan_set(dev, true);
479	} else {
480		outb(CR_CHAN(async_cmd->chanlist[0]),
481			dev->iobase + PCI9111_AI_CHANNEL_REG);
482		pci9111_autoscan_set(dev, false);
483	}
484
485	/*  Set gain */
486	/*  This is the same gain on every channel */
487
488	outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK,
489		dev->iobase + PCI9111_AI_RANGE_STAT_REG);
490
491	/* Set counter */
492	if (async_cmd->stop_src == TRIG_COUNT) {
493		dev_private->stop_counter =
494		    async_cmd->stop_arg * async_cmd->chanlist_len;
495		dev_private->stop_is_none = 0;
496	} else {	/* TRIG_NONE */
497		dev_private->stop_counter = 0;
498		dev_private->stop_is_none = 1;
499	}
500
501	/*  Set timer pacer */
502	dev_private->scan_delay = 0;
503	if (async_cmd->convert_src == TRIG_TIMER) {
504		pci9111_trigger_source_set(dev, software);
505		pci9111_timer_set(dev);
506		pci9111_fifo_reset(dev);
507		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
508					     irq_on_timer_tick);
509		pci9111_trigger_source_set(dev, timer_pacer);
510		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
511					  false, true, true);
512
513		if (async_cmd->scan_begin_src == TRIG_TIMER) {
514			dev_private->scan_delay =
515				(async_cmd->scan_begin_arg /
516				 (async_cmd->convert_arg *
517				  async_cmd->chanlist_len)) - 1;
518		}
519	} else {	/* TRIG_EXT */
520		pci9111_trigger_source_set(dev, external);
521		pci9111_fifo_reset(dev);
522		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
523					     irq_on_timer_tick);
524		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
525					  false, true, true);
526
527	}
528
529	dev_private->stop_counter *= (1 + dev_private->scan_delay);
530	dev_private->chanlist_len = async_cmd->chanlist_len;
531	dev_private->chunk_counter = 0;
532	dev_private->chunk_num_samples =
533	    dev_private->chanlist_len * (1 + dev_private->scan_delay);
534
535	return 0;
536}
537
538static void pci9111_ai_munge(struct comedi_device *dev,
539			     struct comedi_subdevice *s, void *data,
540			     unsigned int num_bytes,
541			     unsigned int start_chan_index)
542{
543	unsigned short *array = data;
544	unsigned int maxdata = s->maxdata;
545	unsigned int invert = (maxdata + 1) >> 1;
546	unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
547	unsigned int num_samples = num_bytes / sizeof(short);
548	unsigned int i;
549
550	for (i = 0; i < num_samples; i++)
551		array[i] = ((array[i] >> shift) & maxdata) ^ invert;
552}
553
554static irqreturn_t pci9111_interrupt(int irq, void *p_device)
555{
556	struct comedi_device *dev = p_device;
557	struct pci9111_private_data *dev_private = dev->private;
558	struct comedi_subdevice *s = dev->read_subdev;
559	struct comedi_async *async;
560	unsigned int status;
561	unsigned long irq_flags;
562	unsigned char intcsr;
563
564	if (!dev->attached) {
565		/*  Ignore interrupt before device fully attached. */
566		/*  Might not even have allocated subdevices yet! */
567		return IRQ_NONE;
568	}
569
570	async = s->async;
571
572	spin_lock_irqsave(&dev->spinlock, irq_flags);
573
574	/*  Check if we are source of interrupt */
575	intcsr = inb(dev_private->lcr_io_base + PLX9052_INTCSR);
576	if (!(((intcsr & PLX9052_INTCSR_PCIENAB) != 0) &&
577	      (((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) ||
578	       ((intcsr & PCI9111_LI2_ACTIVE) == PCI9111_LI2_ACTIVE)))) {
579		/*  Not the source of the interrupt. */
580		/*  (N.B. not using PLX9052_INTCSR_SOFTINT) */
581		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
582		return IRQ_NONE;
583	}
584
585	if ((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) {
586		/*  Interrupt comes from fifo_half-full signal */
587
588		status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
589
590		/* '0' means FIFO is full, data may have been lost */
591		if (!(status & PCI9111_AI_STAT_FF_FF)) {
592			spin_unlock_irqrestore(&dev->spinlock, irq_flags);
593			comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
594			outb(0, dev->iobase + PCI9111_INT_CLR_REG);
595			pci9111_ai_cancel(dev, s);
596			async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
597			comedi_event(dev, s);
598
599			return IRQ_HANDLED;
600		}
601
602		/* '0' means FIFO is half-full */
603		if (!(status & PCI9111_AI_STAT_FF_HF)) {
604			unsigned int num_samples;
605			unsigned int bytes_written = 0;
606
607			num_samples =
608			    PCI9111_FIFO_HALF_SIZE >
609			    dev_private->stop_counter
610			    && !dev_private->
611			    stop_is_none ? dev_private->stop_counter :
612			    PCI9111_FIFO_HALF_SIZE;
613			insw(dev->iobase + PCI9111_AI_FIFO_REG,
614			     dev_private->ai_bounce_buffer, num_samples);
615
616			if (dev_private->scan_delay < 1) {
617				bytes_written =
618				    cfc_write_array_to_buffer(s,
619							      dev_private->
620							      ai_bounce_buffer,
621							      num_samples *
622							      sizeof(short));
623			} else {
624				int position = 0;
625				int to_read;
626
627				while (position < num_samples) {
628					if (dev_private->chunk_counter <
629					    dev_private->chanlist_len) {
630						to_read =
631						    dev_private->chanlist_len -
632						    dev_private->chunk_counter;
633
634						if (to_read >
635						    num_samples - position)
636							to_read =
637							    num_samples -
638							    position;
639
640						bytes_written +=
641						    cfc_write_array_to_buffer
642						    (s,
643						     dev_private->ai_bounce_buffer
644						     + position,
645						     to_read * sizeof(short));
646					} else {
647						to_read =
648						    dev_private->chunk_num_samples
649						    -
650						    dev_private->chunk_counter;
651						if (to_read >
652						    num_samples - position)
653							to_read =
654							    num_samples -
655							    position;
656
657						bytes_written +=
658						    sizeof(short) * to_read;
659					}
660
661					position += to_read;
662					dev_private->chunk_counter += to_read;
663
664					if (dev_private->chunk_counter >=
665					    dev_private->chunk_num_samples)
666						dev_private->chunk_counter = 0;
667				}
668			}
669
670			dev_private->stop_counter -=
671			    bytes_written / sizeof(short);
672		}
673	}
674
675	if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
676		async->events |= COMEDI_CB_EOA;
677		pci9111_ai_cancel(dev, s);
678	}
679
680	outb(0, dev->iobase + PCI9111_INT_CLR_REG);
681
682	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
683
684	comedi_event(dev, s);
685
686	return IRQ_HANDLED;
687}
688
689static int pci9111_ai_eoc(struct comedi_device *dev,
690			  struct comedi_subdevice *s,
691			  struct comedi_insn *insn,
692			  unsigned long context)
693{
694	unsigned int status;
695
696	status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
697	if (status & PCI9111_AI_STAT_FF_EF)
698		return 0;
699	return -EBUSY;
700}
701
702static int pci9111_ai_insn_read(struct comedi_device *dev,
703				struct comedi_subdevice *s,
704				struct comedi_insn *insn, unsigned int *data)
705{
706	unsigned int chan = CR_CHAN(insn->chanspec);
707	unsigned int range = CR_RANGE(insn->chanspec);
708	unsigned int maxdata = s->maxdata;
709	unsigned int invert = (maxdata + 1) >> 1;
710	unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
711	unsigned int status;
712	int ret;
713	int i;
714
715	outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG);
716
717	status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
718	if ((status & PCI9111_AI_RANGE_MASK) != range) {
719		outb(range & PCI9111_AI_RANGE_MASK,
720			dev->iobase + PCI9111_AI_RANGE_STAT_REG);
721	}
722
723	pci9111_fifo_reset(dev);
724
725	for (i = 0; i < insn->n; i++) {
726		/* Generate a software trigger */
727		outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG);
728
729		ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0);
730		if (ret) {
731			pci9111_fifo_reset(dev);
732			return ret;
733		}
734
735		data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG);
736		data[i] = ((data[i] >> shift) & maxdata) ^ invert;
737	}
738
739	return i;
740}
741
742static int pci9111_ao_insn_write(struct comedi_device *dev,
743				 struct comedi_subdevice *s,
744				 struct comedi_insn *insn,
745				 unsigned int *data)
746{
747	struct pci9111_private_data *dev_private = dev->private;
748	unsigned int val = 0;
749	int i;
750
751	for (i = 0; i < insn->n; i++) {
752		val = data[i];
753		outw(val, dev->iobase + PCI9111_AO_REG);
754	}
755	dev_private->ao_readback = val;
756
757	return insn->n;
758}
759
760static int pci9111_ao_insn_read(struct comedi_device *dev,
761				struct comedi_subdevice *s,
762				struct comedi_insn *insn,
763				unsigned int *data)
764{
765	struct pci9111_private_data *dev_private = dev->private;
766	int i;
767
768	for (i = 0; i < insn->n; i++)
769		data[i] = dev_private->ao_readback;
770
771	return insn->n;
772}
773
774static int pci9111_di_insn_bits(struct comedi_device *dev,
775				struct comedi_subdevice *s,
776				struct comedi_insn *insn,
777				unsigned int *data)
778{
779	data[1] = inw(dev->iobase + PCI9111_DIO_REG);
780
781	return insn->n;
782}
783
784static int pci9111_do_insn_bits(struct comedi_device *dev,
785				struct comedi_subdevice *s,
786				struct comedi_insn *insn,
787				unsigned int *data)
788{
789	if (comedi_dio_update_state(s, data))
790		outw(s->state, dev->iobase + PCI9111_DIO_REG);
791
792	data[1] = s->state;
793
794	return insn->n;
795}
796
797static int pci9111_reset(struct comedi_device *dev)
798{
799	struct pci9111_private_data *dev_private = dev->private;
800
801	/*  Set trigger source to software */
802	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
803				  true, false);
804
805	pci9111_trigger_source_set(dev, software);
806	pci9111_pretrigger_set(dev, false);
807	pci9111_autoscan_set(dev, false);
808
809	/* Reset 8254 chip */
810	dev_private->div1 = 0;
811	dev_private->div2 = 0;
812	pci9111_timer_set(dev);
813
814	return 0;
815}
816
817static int pci9111_auto_attach(struct comedi_device *dev,
818					 unsigned long context_unused)
819{
820	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
821	struct pci9111_private_data *dev_private;
822	struct comedi_subdevice *s;
823	int ret;
824
825	dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private));
826	if (!dev_private)
827		return -ENOMEM;
828
829	ret = comedi_pci_enable(dev);
830	if (ret)
831		return ret;
832	dev_private->lcr_io_base = pci_resource_start(pcidev, 1);
833	dev->iobase = pci_resource_start(pcidev, 2);
834
835	pci9111_reset(dev);
836
837	if (pcidev->irq) {
838		ret = request_irq(pcidev->irq, pci9111_interrupt,
839				  IRQF_SHARED, dev->board_name, dev);
840		if (ret == 0)
841			dev->irq = pcidev->irq;
842	}
843
844	ret = comedi_alloc_subdevices(dev, 4);
845	if (ret)
846		return ret;
847
848	s = &dev->subdevices[0];
849	s->type		= COMEDI_SUBD_AI;
850	s->subdev_flags	= SDF_READABLE | SDF_COMMON;
851	s->n_chan	= 16;
852	s->maxdata	= 0xffff;
853	s->range_table	= &pci9111_ai_range;
854	s->insn_read	= pci9111_ai_insn_read;
855	if (dev->irq) {
856		dev->read_subdev = s;
857		s->subdev_flags	|= SDF_CMD_READ;
858		s->len_chanlist	= s->n_chan;
859		s->do_cmdtest	= pci9111_ai_do_cmd_test;
860		s->do_cmd	= pci9111_ai_do_cmd;
861		s->cancel	= pci9111_ai_cancel;
862		s->munge	= pci9111_ai_munge;
863	}
864
865	s = &dev->subdevices[1];
866	s->type		= COMEDI_SUBD_AO;
867	s->subdev_flags	= SDF_WRITABLE | SDF_COMMON;
868	s->n_chan	= 1;
869	s->maxdata	= 0x0fff;
870	s->len_chanlist	= 1;
871	s->range_table	= &range_bipolar10;
872	s->insn_write	= pci9111_ao_insn_write;
873	s->insn_read	= pci9111_ao_insn_read;
874
875	s = &dev->subdevices[2];
876	s->type		= COMEDI_SUBD_DI;
877	s->subdev_flags	= SDF_READABLE;
878	s->n_chan	= 16;
879	s->maxdata	= 1;
880	s->range_table	= &range_digital;
881	s->insn_bits	= pci9111_di_insn_bits;
882
883	s = &dev->subdevices[3];
884	s->type		= COMEDI_SUBD_DO;
885	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
886	s->n_chan	= 16;
887	s->maxdata	= 1;
888	s->range_table	= &range_digital;
889	s->insn_bits	= pci9111_do_insn_bits;
890
891	return 0;
892}
893
894static void pci9111_detach(struct comedi_device *dev)
895{
896	if (dev->iobase)
897		pci9111_reset(dev);
898	if (dev->irq != 0)
899		free_irq(dev->irq, dev);
900	comedi_pci_disable(dev);
901}
902
903static struct comedi_driver adl_pci9111_driver = {
904	.driver_name	= "adl_pci9111",
905	.module		= THIS_MODULE,
906	.auto_attach	= pci9111_auto_attach,
907	.detach		= pci9111_detach,
908};
909
910static int pci9111_pci_probe(struct pci_dev *dev,
911			     const struct pci_device_id *id)
912{
913	return comedi_pci_auto_config(dev, &adl_pci9111_driver,
914				      id->driver_data);
915}
916
917static const struct pci_device_id pci9111_pci_table[] = {
918	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
919	/* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
920	{ 0 }
921};
922MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
923
924static struct pci_driver adl_pci9111_pci_driver = {
925	.name		= "adl_pci9111",
926	.id_table	= pci9111_pci_table,
927	.probe		= pci9111_pci_probe,
928	.remove		= comedi_pci_auto_unconfig,
929};
930module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
931
932MODULE_AUTHOR("Comedi http://www.comedi.org");
933MODULE_DESCRIPTION("Comedi low-level driver");
934MODULE_LICENSE("GPL");
935