adl_pci9111.c revision c50a39824d350c3f9c3ba5edc2ffdf0b3b743cb7
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_check_chanlist(struct comedi_device *dev,
318				     struct comedi_subdevice *s,
319				     struct comedi_cmd *cmd)
320{
321	unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
322	unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
323	int i;
324
325	for (i = 1; i < cmd->chanlist_len; i++) {
326		unsigned int chan = CR_CHAN(cmd->chanlist[i]);
327		unsigned int range = CR_RANGE(cmd->chanlist[i]);
328		unsigned int aref = CR_AREF(cmd->chanlist[i]);
329
330		if (chan != i) {
331			dev_dbg(dev->class_dev,
332				"entries in chanlist must be consecutive channels,counting upwards from 0\n");
333			return -EINVAL;
334		}
335
336		if (range != range0) {
337			dev_dbg(dev->class_dev,
338				"entries in chanlist must all have the same gain\n");
339			return -EINVAL;
340		}
341
342		if (aref != aref0) {
343			dev_dbg(dev->class_dev,
344				"entries in chanlist must all have the same reference\n");
345			return -EINVAL;
346		}
347	}
348
349	return 0;
350}
351
352static int pci9111_ai_do_cmd_test(struct comedi_device *dev,
353				  struct comedi_subdevice *s,
354				  struct comedi_cmd *cmd)
355{
356	struct pci9111_private_data *dev_private = dev->private;
357	int err = 0;
358	int tmp;
359
360	/* Step 1 : check if triggers are trivially valid */
361
362	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
363	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
364					TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
365	err |= cfc_check_trigger_src(&cmd->convert_src,
366					TRIG_TIMER | TRIG_EXT);
367	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
368	err |= cfc_check_trigger_src(&cmd->stop_src,
369					TRIG_COUNT | TRIG_NONE);
370
371	if (err)
372		return 1;
373
374	/* Step 2a : make sure trigger sources are unique */
375
376	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
377	err |= cfc_check_trigger_is_unique(cmd->convert_src);
378	err |= cfc_check_trigger_is_unique(cmd->stop_src);
379
380	/* Step 2b : and mutually compatible */
381
382	if ((cmd->convert_src == TRIG_TIMER) &&
383	    !((cmd->scan_begin_src == TRIG_TIMER) ||
384	      (cmd->scan_begin_src == TRIG_FOLLOW)))
385		err |= -EINVAL;
386	if ((cmd->convert_src == TRIG_EXT) &&
387	    !((cmd->scan_begin_src == TRIG_EXT) ||
388	      (cmd->scan_begin_src == TRIG_FOLLOW)))
389		err |= -EINVAL;
390
391	if (err)
392		return 2;
393
394	/* Step 3: check if arguments are trivially valid */
395
396	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
397
398	if (cmd->convert_src == TRIG_TIMER)
399		err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
400					PCI9111_AI_ACQUISITION_PERIOD_MIN_NS);
401	else	/* TRIG_EXT */
402		err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
403
404	if (cmd->scan_begin_src == TRIG_TIMER)
405		err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
406					PCI9111_AI_ACQUISITION_PERIOD_MIN_NS);
407	else	/* TRIG_FOLLOW || TRIG_EXT */
408		err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
409
410	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
411
412	if (cmd->stop_src == TRIG_COUNT)
413		err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
414	else	/* TRIG_NONE */
415		err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
416
417	if (err)
418		return 3;
419
420	/*  Step 4 : fix up any arguments */
421
422	if (cmd->convert_src == TRIG_TIMER) {
423		tmp = cmd->convert_arg;
424		i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
425					  &dev_private->div1,
426					  &dev_private->div2,
427					  &cmd->convert_arg, cmd->flags);
428		if (tmp != cmd->convert_arg)
429			err |= -EINVAL;
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					err |= -EINVAL;
450				}
451			} else {
452				cmd->scan_begin_arg = scan_begin_min;
453				err |= -EINVAL;
454			}
455		}
456	}
457
458	if (err)
459		return 4;
460
461	/* Step 5: check channel list if it exists */
462	if (cmd->chanlist && cmd->chanlist_len > 0)
463		err |= pci9111_ai_check_chanlist(dev, s, cmd);
464
465	if (err)
466		return 5;
467
468	return 0;
469
470}
471
472static int pci9111_ai_do_cmd(struct comedi_device *dev,
473			     struct comedi_subdevice *s)
474{
475	struct pci9111_private_data *dev_private = dev->private;
476	struct comedi_cmd *async_cmd = &s->async->cmd;
477
478	/*  Set channel scan limit */
479	/*  PCI9111 allows only scanning from channel 0 to channel n */
480	/*  TODO: handle the case of an external multiplexer */
481
482	if (async_cmd->chanlist_len > 1) {
483		outb(async_cmd->chanlist_len - 1,
484			dev->iobase + PCI9111_AI_CHANNEL_REG);
485		pci9111_autoscan_set(dev, true);
486	} else {
487		outb(CR_CHAN(async_cmd->chanlist[0]),
488			dev->iobase + PCI9111_AI_CHANNEL_REG);
489		pci9111_autoscan_set(dev, false);
490	}
491
492	/*  Set gain */
493	/*  This is the same gain on every channel */
494
495	outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK,
496		dev->iobase + PCI9111_AI_RANGE_STAT_REG);
497
498	/* Set counter */
499	if (async_cmd->stop_src == TRIG_COUNT) {
500		dev_private->stop_counter =
501		    async_cmd->stop_arg * async_cmd->chanlist_len;
502		dev_private->stop_is_none = 0;
503	} else {	/* TRIG_NONE */
504		dev_private->stop_counter = 0;
505		dev_private->stop_is_none = 1;
506	}
507
508	/*  Set timer pacer */
509	dev_private->scan_delay = 0;
510	if (async_cmd->convert_src == TRIG_TIMER) {
511		pci9111_trigger_source_set(dev, software);
512		pci9111_timer_set(dev);
513		pci9111_fifo_reset(dev);
514		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
515					     irq_on_timer_tick);
516		pci9111_trigger_source_set(dev, timer_pacer);
517		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
518					  false, true, true);
519
520		if (async_cmd->scan_begin_src == TRIG_TIMER) {
521			dev_private->scan_delay =
522				(async_cmd->scan_begin_arg /
523				 (async_cmd->convert_arg *
524				  async_cmd->chanlist_len)) - 1;
525		}
526	} else {	/* TRIG_EXT */
527		pci9111_trigger_source_set(dev, external);
528		pci9111_fifo_reset(dev);
529		pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
530					     irq_on_timer_tick);
531		plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
532					  false, true, true);
533
534	}
535
536	dev_private->stop_counter *= (1 + dev_private->scan_delay);
537	dev_private->chanlist_len = async_cmd->chanlist_len;
538	dev_private->chunk_counter = 0;
539	dev_private->chunk_num_samples =
540	    dev_private->chanlist_len * (1 + dev_private->scan_delay);
541
542	return 0;
543}
544
545static void pci9111_ai_munge(struct comedi_device *dev,
546			     struct comedi_subdevice *s, void *data,
547			     unsigned int num_bytes,
548			     unsigned int start_chan_index)
549{
550	unsigned short *array = data;
551	unsigned int maxdata = s->maxdata;
552	unsigned int invert = (maxdata + 1) >> 1;
553	unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
554	unsigned int num_samples = num_bytes / sizeof(short);
555	unsigned int i;
556
557	for (i = 0; i < num_samples; i++)
558		array[i] = ((array[i] >> shift) & maxdata) ^ invert;
559}
560
561static irqreturn_t pci9111_interrupt(int irq, void *p_device)
562{
563	struct comedi_device *dev = p_device;
564	struct pci9111_private_data *dev_private = dev->private;
565	struct comedi_subdevice *s = dev->read_subdev;
566	struct comedi_async *async;
567	unsigned int status;
568	unsigned long irq_flags;
569	unsigned char intcsr;
570
571	if (!dev->attached) {
572		/*  Ignore interrupt before device fully attached. */
573		/*  Might not even have allocated subdevices yet! */
574		return IRQ_NONE;
575	}
576
577	async = s->async;
578
579	spin_lock_irqsave(&dev->spinlock, irq_flags);
580
581	/*  Check if we are source of interrupt */
582	intcsr = inb(dev_private->lcr_io_base + PLX9052_INTCSR);
583	if (!(((intcsr & PLX9052_INTCSR_PCIENAB) != 0) &&
584	      (((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) ||
585	       ((intcsr & PCI9111_LI2_ACTIVE) == PCI9111_LI2_ACTIVE)))) {
586		/*  Not the source of the interrupt. */
587		/*  (N.B. not using PLX9052_INTCSR_SOFTINT) */
588		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
589		return IRQ_NONE;
590	}
591
592	if ((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) {
593		/*  Interrupt comes from fifo_half-full signal */
594
595		status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
596
597		/* '0' means FIFO is full, data may have been lost */
598		if (!(status & PCI9111_AI_STAT_FF_FF)) {
599			spin_unlock_irqrestore(&dev->spinlock, irq_flags);
600			comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
601			outb(0, dev->iobase + PCI9111_INT_CLR_REG);
602			async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
603			cfc_handle_events(dev, s);
604
605			return IRQ_HANDLED;
606		}
607
608		/* '0' means FIFO is half-full */
609		if (!(status & PCI9111_AI_STAT_FF_HF)) {
610			unsigned int num_samples;
611			unsigned int bytes_written = 0;
612
613			num_samples =
614			    PCI9111_FIFO_HALF_SIZE >
615			    dev_private->stop_counter
616			    && !dev_private->
617			    stop_is_none ? dev_private->stop_counter :
618			    PCI9111_FIFO_HALF_SIZE;
619			insw(dev->iobase + PCI9111_AI_FIFO_REG,
620			     dev_private->ai_bounce_buffer, num_samples);
621
622			if (dev_private->scan_delay < 1) {
623				bytes_written =
624				    cfc_write_array_to_buffer(s,
625							      dev_private->
626							      ai_bounce_buffer,
627							      num_samples *
628							      sizeof(short));
629			} else {
630				int position = 0;
631				int to_read;
632
633				while (position < num_samples) {
634					if (dev_private->chunk_counter <
635					    dev_private->chanlist_len) {
636						to_read =
637						    dev_private->chanlist_len -
638						    dev_private->chunk_counter;
639
640						if (to_read >
641						    num_samples - position)
642							to_read =
643							    num_samples -
644							    position;
645
646						bytes_written +=
647						    cfc_write_array_to_buffer
648						    (s,
649						     dev_private->ai_bounce_buffer
650						     + position,
651						     to_read * sizeof(short));
652					} else {
653						to_read =
654						    dev_private->chunk_num_samples
655						    -
656						    dev_private->chunk_counter;
657						if (to_read >
658						    num_samples - position)
659							to_read =
660							    num_samples -
661							    position;
662
663						bytes_written +=
664						    sizeof(short) * to_read;
665					}
666
667					position += to_read;
668					dev_private->chunk_counter += to_read;
669
670					if (dev_private->chunk_counter >=
671					    dev_private->chunk_num_samples)
672						dev_private->chunk_counter = 0;
673				}
674			}
675
676			dev_private->stop_counter -=
677			    bytes_written / sizeof(short);
678		}
679	}
680
681	if (dev_private->stop_counter == 0 && !dev_private->stop_is_none)
682		async->events |= COMEDI_CB_EOA;
683
684	outb(0, dev->iobase + PCI9111_INT_CLR_REG);
685
686	spin_unlock_irqrestore(&dev->spinlock, irq_flags);
687
688	cfc_handle_events(dev, s);
689
690	return IRQ_HANDLED;
691}
692
693static int pci9111_ai_eoc(struct comedi_device *dev,
694			  struct comedi_subdevice *s,
695			  struct comedi_insn *insn,
696			  unsigned long context)
697{
698	unsigned int status;
699
700	status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
701	if (status & PCI9111_AI_STAT_FF_EF)
702		return 0;
703	return -EBUSY;
704}
705
706static int pci9111_ai_insn_read(struct comedi_device *dev,
707				struct comedi_subdevice *s,
708				struct comedi_insn *insn, unsigned int *data)
709{
710	unsigned int chan = CR_CHAN(insn->chanspec);
711	unsigned int range = CR_RANGE(insn->chanspec);
712	unsigned int maxdata = s->maxdata;
713	unsigned int invert = (maxdata + 1) >> 1;
714	unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
715	unsigned int status;
716	int ret;
717	int i;
718
719	outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG);
720
721	status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
722	if ((status & PCI9111_AI_RANGE_MASK) != range) {
723		outb(range & PCI9111_AI_RANGE_MASK,
724			dev->iobase + PCI9111_AI_RANGE_STAT_REG);
725	}
726
727	pci9111_fifo_reset(dev);
728
729	for (i = 0; i < insn->n; i++) {
730		/* Generate a software trigger */
731		outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG);
732
733		ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0);
734		if (ret) {
735			pci9111_fifo_reset(dev);
736			return ret;
737		}
738
739		data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG);
740		data[i] = ((data[i] >> shift) & maxdata) ^ invert;
741	}
742
743	return i;
744}
745
746static int pci9111_ao_insn_write(struct comedi_device *dev,
747				 struct comedi_subdevice *s,
748				 struct comedi_insn *insn,
749				 unsigned int *data)
750{
751	struct pci9111_private_data *dev_private = dev->private;
752	unsigned int val = 0;
753	int i;
754
755	for (i = 0; i < insn->n; i++) {
756		val = data[i];
757		outw(val, dev->iobase + PCI9111_AO_REG);
758	}
759	dev_private->ao_readback = val;
760
761	return insn->n;
762}
763
764static int pci9111_ao_insn_read(struct comedi_device *dev,
765				struct comedi_subdevice *s,
766				struct comedi_insn *insn,
767				unsigned int *data)
768{
769	struct pci9111_private_data *dev_private = dev->private;
770	int i;
771
772	for (i = 0; i < insn->n; i++)
773		data[i] = dev_private->ao_readback;
774
775	return insn->n;
776}
777
778static int pci9111_di_insn_bits(struct comedi_device *dev,
779				struct comedi_subdevice *s,
780				struct comedi_insn *insn,
781				unsigned int *data)
782{
783	data[1] = inw(dev->iobase + PCI9111_DIO_REG);
784
785	return insn->n;
786}
787
788static int pci9111_do_insn_bits(struct comedi_device *dev,
789				struct comedi_subdevice *s,
790				struct comedi_insn *insn,
791				unsigned int *data)
792{
793	if (comedi_dio_update_state(s, data))
794		outw(s->state, dev->iobase + PCI9111_DIO_REG);
795
796	data[1] = s->state;
797
798	return insn->n;
799}
800
801static int pci9111_reset(struct comedi_device *dev)
802{
803	struct pci9111_private_data *dev_private = dev->private;
804
805	/*  Set trigger source to software */
806	plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
807				  true, false);
808
809	pci9111_trigger_source_set(dev, software);
810	pci9111_pretrigger_set(dev, false);
811	pci9111_autoscan_set(dev, false);
812
813	/* Reset 8254 chip */
814	dev_private->div1 = 0;
815	dev_private->div2 = 0;
816	pci9111_timer_set(dev);
817
818	return 0;
819}
820
821static int pci9111_auto_attach(struct comedi_device *dev,
822					 unsigned long context_unused)
823{
824	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
825	struct pci9111_private_data *dev_private;
826	struct comedi_subdevice *s;
827	int ret;
828
829	dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private));
830	if (!dev_private)
831		return -ENOMEM;
832
833	ret = comedi_pci_enable(dev);
834	if (ret)
835		return ret;
836	dev_private->lcr_io_base = pci_resource_start(pcidev, 1);
837	dev->iobase = pci_resource_start(pcidev, 2);
838
839	pci9111_reset(dev);
840
841	if (pcidev->irq) {
842		ret = request_irq(pcidev->irq, pci9111_interrupt,
843				  IRQF_SHARED, dev->board_name, dev);
844		if (ret == 0)
845			dev->irq = pcidev->irq;
846	}
847
848	ret = comedi_alloc_subdevices(dev, 4);
849	if (ret)
850		return ret;
851
852	s = &dev->subdevices[0];
853	s->type		= COMEDI_SUBD_AI;
854	s->subdev_flags	= SDF_READABLE | SDF_COMMON;
855	s->n_chan	= 16;
856	s->maxdata	= 0xffff;
857	s->range_table	= &pci9111_ai_range;
858	s->insn_read	= pci9111_ai_insn_read;
859	if (dev->irq) {
860		dev->read_subdev = s;
861		s->subdev_flags	|= SDF_CMD_READ;
862		s->len_chanlist	= s->n_chan;
863		s->do_cmdtest	= pci9111_ai_do_cmd_test;
864		s->do_cmd	= pci9111_ai_do_cmd;
865		s->cancel	= pci9111_ai_cancel;
866		s->munge	= pci9111_ai_munge;
867	}
868
869	s = &dev->subdevices[1];
870	s->type		= COMEDI_SUBD_AO;
871	s->subdev_flags	= SDF_WRITABLE | SDF_COMMON;
872	s->n_chan	= 1;
873	s->maxdata	= 0x0fff;
874	s->len_chanlist	= 1;
875	s->range_table	= &range_bipolar10;
876	s->insn_write	= pci9111_ao_insn_write;
877	s->insn_read	= pci9111_ao_insn_read;
878
879	s = &dev->subdevices[2];
880	s->type		= COMEDI_SUBD_DI;
881	s->subdev_flags	= SDF_READABLE;
882	s->n_chan	= 16;
883	s->maxdata	= 1;
884	s->range_table	= &range_digital;
885	s->insn_bits	= pci9111_di_insn_bits;
886
887	s = &dev->subdevices[3];
888	s->type		= COMEDI_SUBD_DO;
889	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
890	s->n_chan	= 16;
891	s->maxdata	= 1;
892	s->range_table	= &range_digital;
893	s->insn_bits	= pci9111_do_insn_bits;
894
895	return 0;
896}
897
898static void pci9111_detach(struct comedi_device *dev)
899{
900	if (dev->iobase)
901		pci9111_reset(dev);
902	if (dev->irq != 0)
903		free_irq(dev->irq, dev);
904	comedi_pci_disable(dev);
905}
906
907static struct comedi_driver adl_pci9111_driver = {
908	.driver_name	= "adl_pci9111",
909	.module		= THIS_MODULE,
910	.auto_attach	= pci9111_auto_attach,
911	.detach		= pci9111_detach,
912};
913
914static int pci9111_pci_probe(struct pci_dev *dev,
915			     const struct pci_device_id *id)
916{
917	return comedi_pci_auto_config(dev, &adl_pci9111_driver,
918				      id->driver_data);
919}
920
921static const struct pci_device_id pci9111_pci_table[] = {
922	{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
923	/* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
924	{ 0 }
925};
926MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
927
928static struct pci_driver adl_pci9111_pci_driver = {
929	.name		= "adl_pci9111",
930	.id_table	= pci9111_pci_table,
931	.probe		= pci9111_pci_probe,
932	.remove		= comedi_pci_auto_unconfig,
933};
934module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
935
936MODULE_AUTHOR("Comedi http://www.comedi.org");
937MODULE_DESCRIPTION("Comedi low-level driver");
938MODULE_LICENSE("GPL");
939