pcmmio.c revision 25436dc9d84f1be60ff549c9ab712bba2835f284
1/*
2    comedi/drivers/pcmmio.c
3    Driver for Winsystems PC-104 based multifunction IO board.
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22/*
23Driver: pcmmio
24Description: A driver for the PCM-MIO multifunction board
25Devices: [Winsystems] PCM-MIO (pcmmio)
26Author: Calin Culianu <calin@ajvar.org>
27Updated: Wed, May 16 2007 16:21:10 -0500
28Status: works
29
30A driver for the relatively new PCM-MIO multifunction board from
31Winsystems.  This board is a PC-104 based I/O board.  It contains
32four subdevices:
33  subdevice 0 - 16 channels of 16-bit AI
34  subdevice 1 - 8 channels of 16-bit AO
35  subdevice 2 - first 24 channels of the 48 channel of DIO (with edge-triggered interrupt support)
36  subdevice 3 - last 24 channels of the 48 channel DIO (no interrupt support for this bank of channels)
37
38  Some notes:
39
40  Synchronous reads and writes are the only things implemented for AI and AO,
41  even though the hardware itself can do streaming acquisition, etc.  Anyone
42  want to add asynchronous I/O for AI/AO as a feature?  Be my guest...
43
44  Asynchronous I/O for the DIO subdevices *is* implemented, however!  They are
45  basically edge-triggered interrupts for any configuration of the first
46  24 DIO-lines.
47
48  Also note that this interrupt support is untested.
49
50  A few words about edge-detection IRQ support (commands on DIO):
51
52  * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
53    of the board to the comedi_config command.  The board IRQ is not jumpered
54    but rather configured through software, so any IRQ from 1-15 is OK.
55
56  * Due to the genericity of the comedi API, you need to create a special
57    comedi_command in order to use edge-triggered interrupts for DIO.
58
59  * Use comedi_commands with TRIG_NOW.  Your callback will be called each
60    time an edge is detected on the specified DIO line(s), and the data
61    values will be two sample_t's, which should be concatenated to form
62    one 32-bit unsigned int.  This value is the mask of channels that had
63    edges detected from your channel list.  Note that the bits positions
64    in the mask correspond to positions in your chanlist when you
65    specified the command and *not* channel id's!
66
67 *  To set the polarity of the edge-detection interrupts pass a nonzero value
68    for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
69    value for both CR_RANGE and CR_AREF if you want edge-down polarity.
70
71Configuration Options:
72  [0] - I/O port base address
73  [1] - IRQ (optional -- for edge-detect interrupt support only, leave out if you don't need this feature)
74*/
75
76#include <linux/interrupt.h>
77#include "../comedidev.h"
78#include <linux/pci.h>		/* for PCI devices */
79
80#define MIN(a, b) (((a) < (b)) ? (a) : (b))
81
82/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
83#define CHANS_PER_PORT   8
84#define PORTS_PER_ASIC   6
85#define INTR_PORTS_PER_ASIC   3
86#define MAX_CHANS_PER_SUBDEV 24	/* number of channels per comedi subdevice */
87#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
88#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
89#define INTR_CHANS_PER_ASIC 24
90#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
91#define MAX_DIO_CHANS   (PORTS_PER_ASIC*1*CHANS_PER_PORT)
92#define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
93#define SDEV_NO ((int)(s - dev->subdevices))
94#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
95/* IO Memory sizes */
96#define ASIC_IOSIZE (0x0B)
97#define PCMMIO48_IOSIZE ASIC_IOSIZE
98
99/* Some offsets - these are all in the 16byte IO memory offset from
100   the base address.  Note that there is a paging scheme to swap out
101   offsets 0x8-0xA using the PAGELOCK register.  See the table below.
102
103  Register(s)       Pages        R/W?        Description
104  --------------------------------------------------------------
105  REG_PORTx         All          R/W         Read/Write/Configure IO
106  REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
107  REG_PAGELOCK      All          WriteOnly   Select a page
108  REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
109  REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
110  REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
111 */
112#define REG_PORT0 0x0
113#define REG_PORT1 0x1
114#define REG_PORT2 0x2
115#define REG_PORT3 0x3
116#define REG_PORT4 0x4
117#define REG_PORT5 0x5
118#define REG_INT_PENDING 0x6
119#define REG_PAGELOCK 0x7	/* page selector register, upper 2 bits select a page
120				   and bits 0-5 are used to 'lock down' a particular
121				   port above to make it readonly.  */
122#define REG_POL0 0x8
123#define REG_POL1 0x9
124#define REG_POL2 0xA
125#define REG_ENAB0 0x8
126#define REG_ENAB1 0x9
127#define REG_ENAB2 0xA
128#define REG_INT_ID0 0x8
129#define REG_INT_ID1 0x9
130#define REG_INT_ID2 0xA
131
132#define NUM_PAGED_REGS 3
133#define NUM_PAGES 4
134#define FIRST_PAGED_REG 0x8
135#define REG_PAGE_BITOFFSET 6
136#define REG_LOCK_BITOFFSET 0
137#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
138#define REG_LOCK_MASK ~(REG_PAGE_MASK)
139#define PAGE_POL 1
140#define PAGE_ENAB 2
141#define PAGE_INT_ID 3
142
143typedef int (*comedi_insn_fn_t) (struct comedi_device *, struct comedi_subdevice *,
144	struct comedi_insn *, unsigned int *);
145
146static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *,
147	unsigned int *);
148static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *,
149	unsigned int *);
150static int ao_winsn(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *,
151	unsigned int *);
152
153/*
154 * Board descriptions for two imaginary boards.  Describing the
155 * boards in this way is optional, and completely driver-dependent.
156 * Some drivers use arrays such as this, other do not.
157 */
158struct pcmmio_board {
159	const char *name;
160	const int dio_num_asics;
161	const int dio_num_ports;
162	const int total_iosize;
163	const int ai_bits;
164	const int ao_bits;
165	const int n_ai_chans;
166	const int n_ao_chans;
167	const struct comedi_lrange *ai_range_table, *ao_range_table;
168	comedi_insn_fn_t ai_rinsn, ao_rinsn, ao_winsn;
169};
170
171static const struct comedi_lrange ranges_ai =
172	{ 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0.,
173		10.)}
174};
175
176static const struct comedi_lrange ranges_ao =
177	{ 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
178	RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
179};
180
181static const struct pcmmio_board pcmmio_boards[] = {
182	{
183	.name = "pcmmio",
184	.dio_num_asics = 1,
185	.dio_num_ports = 6,
186	.total_iosize = 32,
187	.ai_bits = 16,
188	.ao_bits = 16,
189	.n_ai_chans = 16,
190	.n_ao_chans = 8,
191	.ai_range_table = &ranges_ai,
192	.ao_range_table = &ranges_ao,
193	.ai_rinsn = ai_rinsn,
194	.ao_rinsn = ao_rinsn,
195	.ao_winsn = ao_winsn},
196};
197
198/*
199 * Useful for shorthand access to the particular board structure
200 */
201#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
202
203/* this structure is for data unique to this subdevice.  */
204struct pcmmio_subdev_private {
205
206	union {
207		/* for DIO: mapping of halfwords (bytes) in port/chanarray to iobase */
208		unsigned long iobases[PORTS_PER_SUBDEV];
209
210		/* for AI/AO */
211		unsigned long iobase;
212	};
213	union {
214		struct {
215
216			/* The below is only used for intr subdevices */
217			struct {
218				int asic;	/* if non-negative, this subdev has an interrupt asic */
219				int first_chan;	/* if nonnegative, the first channel id for
220						   interrupts. */
221				int num_asic_chans;	/* the number of asic channels in this subdev
222							   that have interrutps */
223				int asic_chan;	/* if nonnegative, the first channel id with
224						   respect to the asic that has interrupts */
225				int enabled_mask;	/* subdev-relative channel mask for channels
226							   we are interested in */
227				int active;
228				int stop_count;
229				int continuous;
230				spinlock_t spinlock;
231			} intr;
232		} dio;
233		struct {
234			unsigned int shadow_samples[8];	/* the last unsigned int data written */
235		} ao;
236	};
237};
238
239/* this structure is for data unique to this hardware driver.  If
240   several hardware drivers keep similar information in this structure,
241   feel free to suggest moving the variable to the struct comedi_device struct.  */
242struct pcmmio_private {
243	/* stuff for DIO */
244	struct {
245		unsigned char pagelock;	/* current page and lock */
246		unsigned char pol[NUM_PAGED_REGS];	/* shadow of POLx registers */
247		unsigned char enab[NUM_PAGED_REGS];	/* shadow of ENABx registers */
248		int num;
249		unsigned long iobase;
250		unsigned int irq;
251		spinlock_t spinlock;
252	} asics[MAX_ASICS];
253	struct pcmmio_subdev_private *sprivs;
254};
255
256/*
257 * most drivers define the following macro to make it easy to
258 * access the private structure.
259 */
260#define devpriv ((struct pcmmio_private *)dev->private)
261#define subpriv ((struct pcmmio_subdev_private *)s->private)
262/*
263 * The struct comedi_driver structure tells the Comedi core module
264 * which functions to call to configure/deconfigure (attach/detach)
265 * the board, and also about the kernel module that contains
266 * the device code.
267 */
268static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
269static int pcmmio_detach(struct comedi_device *dev);
270
271static struct comedi_driver driver = {
272	.driver_name = "pcmmio",
273	.module = THIS_MODULE,
274	.attach = pcmmio_attach,
275	.detach = pcmmio_detach,
276/* It is not necessary to implement the following members if you are
277 * writing a driver for a ISA PnP or PCI card */
278	/* Most drivers will support multiple types of boards by
279	 * having an array of board structures.  These were defined
280	 * in pcmmio_boards[] above.  Note that the element 'name'
281	 * was first in the structure -- Comedi uses this fact to
282	 * extract the name of the board without knowing any details
283	 * about the structure except for its length.
284	 * When a device is attached (by comedi_config), the name
285	 * of the device is given to Comedi, and Comedi tries to
286	 * match it by going through the list of board names.  If
287	 * there is a match, the address of the pointer is put
288	 * into dev->board_ptr and driver->attach() is called.
289	 *
290	 * Note that these are not necessary if you can determine
291	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
292	 * devices are such boards.
293	 */
294	.board_name = &pcmmio_boards[0].name,
295	.offset = sizeof(struct pcmmio_board),
296	.num_names = ARRAY_SIZE(pcmmio_boards),
297};
298
299static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
300	struct comedi_insn *insn, unsigned int *data);
301static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
302	struct comedi_insn *insn, unsigned int *data);
303
304static irqreturn_t interrupt_pcmmio(int irq, void *d);
305static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
306static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
307static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
308static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
309	struct comedi_cmd *cmd);
310
311/* some helper functions to deal with specifics of this device's registers */
312static void init_asics(struct comedi_device *dev);	/* sets up/clears ASIC chips to defaults */
313static void switch_page(struct comedi_device *dev, int asic, int page);
314#ifdef notused
315static void lock_port(struct comedi_device *dev, int asic, int port);
316static void unlock_port(struct comedi_device *dev, int asic, int port);
317#endif
318
319/*
320 * Attach is called by the Comedi core to configure the driver
321 * for a particular board.  If you specified a board_name array
322 * in the driver structure, dev->board_ptr contains that
323 * address.
324 */
325static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
326{
327	struct comedi_subdevice *s;
328	int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
329		thisasic_chanct = 0;
330	unsigned long iobase;
331	unsigned int irq[MAX_ASICS];
332
333	iobase = it->options[0];
334	irq[0] = it->options[1];
335
336	printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
337		iobase);
338
339	dev->iobase = iobase;
340
341	if (!iobase || !request_region(iobase,
342			thisboard->total_iosize, driver.driver_name)) {
343		printk("I/O port conflict\n");
344		return -EIO;
345	}
346
347/*
348 * Initialize dev->board_name.  Note that we can use the "thisboard"
349 * macro now, since we just initialized it in the last line.
350 */
351	dev->board_name = thisboard->name;
352
353/*
354 * Allocate the private structure area.  alloc_private() is a
355 * convenient macro defined in comedidev.h.
356 */
357	if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
358		printk("cannot allocate private data structure\n");
359		return -ENOMEM;
360	}
361
362	for (asic = 0; asic < MAX_ASICS; ++asic) {
363		devpriv->asics[asic].num = asic;
364		devpriv->asics[asic].iobase =
365			dev->iobase + 16 + asic * ASIC_IOSIZE;
366		devpriv->asics[asic].irq = 0;	/* this gets actually set at the end of
367						   this function when we
368						   request_irqs */
369		spin_lock_init(&devpriv->asics[asic].spinlock);
370	}
371
372	chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
373	n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
374	n_subdevs = n_dio_subdevs + 2;
375	devpriv->sprivs =
376		kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), GFP_KERNEL);
377	if (!devpriv->sprivs) {
378		printk("cannot allocate subdevice private data structures\n");
379		return -ENOMEM;
380	}
381	/*
382	 * Allocate the subdevice structures.  alloc_subdevice() is a
383	 * convenient macro defined in comedidev.h.
384	 *
385	 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
386	 */
387	if (alloc_subdevices(dev, n_subdevs) < 0) {
388		printk("cannot allocate subdevice data structures\n");
389		return -ENOMEM;
390	}
391
392	/* First, AI */
393	sdev_no = 0;
394	s = dev->subdevices + sdev_no;
395	s->private = devpriv->sprivs + sdev_no;
396	s->maxdata = (1 << thisboard->ai_bits) - 1;
397	s->range_table = thisboard->ai_range_table;
398	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
399	s->type = COMEDI_SUBD_AI;
400	s->n_chan = thisboard->n_ai_chans;
401	s->len_chanlist = s->n_chan;
402	s->insn_read = thisboard->ai_rinsn;
403	subpriv->iobase = dev->iobase + 0;
404	/* initialize the resource enable register by clearing it */
405	outb(0, subpriv->iobase + 3);
406	outb(0, subpriv->iobase + 4 + 3);
407
408	/* Next, AO */
409	++sdev_no;
410	s = dev->subdevices + sdev_no;
411	s->private = devpriv->sprivs + sdev_no;
412	s->maxdata = (1 << thisboard->ao_bits) - 1;
413	s->range_table = thisboard->ao_range_table;
414	s->subdev_flags = SDF_READABLE;
415	s->type = COMEDI_SUBD_AO;
416	s->n_chan = thisboard->n_ao_chans;
417	s->len_chanlist = s->n_chan;
418	s->insn_read = thisboard->ao_rinsn;
419	s->insn_write = thisboard->ao_winsn;
420	subpriv->iobase = dev->iobase + 8;
421	/* initialize the resource enable register by clearing it */
422	outb(0, subpriv->iobase + 3);
423	outb(0, subpriv->iobase + 4 + 3);
424
425	++sdev_no;
426	port = 0;
427	asic = 0;
428	for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
429		int byte_no;
430
431		s = dev->subdevices + sdev_no;
432		s->private = devpriv->sprivs + sdev_no;
433		s->maxdata = 1;
434		s->range_table = &range_digital;
435		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
436		s->type = COMEDI_SUBD_DIO;
437		s->insn_bits = pcmmio_dio_insn_bits;
438		s->insn_config = pcmmio_dio_insn_config;
439		s->n_chan = MIN(chans_left, MAX_CHANS_PER_SUBDEV);
440		subpriv->dio.intr.asic = -1;
441		subpriv->dio.intr.first_chan = -1;
442		subpriv->dio.intr.asic_chan = -1;
443		subpriv->dio.intr.num_asic_chans = -1;
444		subpriv->dio.intr.active = 0;
445		s->len_chanlist = 1;
446
447		/* save the ioport address for each 'port' of 8 channels in the
448		   subdevice */
449		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
450			if (port >= PORTS_PER_ASIC) {
451				port = 0;
452				++asic;
453				thisasic_chanct = 0;
454			}
455			subpriv->iobases[byte_no] =
456				devpriv->asics[asic].iobase + port;
457
458			if (thisasic_chanct <
459				CHANS_PER_PORT * INTR_PORTS_PER_ASIC
460				&& subpriv->dio.intr.asic < 0) {
461				/* this is an interrupt subdevice, so setup the struct */
462				subpriv->dio.intr.asic = asic;
463				subpriv->dio.intr.active = 0;
464				subpriv->dio.intr.stop_count = 0;
465				subpriv->dio.intr.first_chan = byte_no * 8;
466				subpriv->dio.intr.asic_chan = thisasic_chanct;
467				subpriv->dio.intr.num_asic_chans =
468					s->n_chan -
469					subpriv->dio.intr.first_chan;
470				s->cancel = pcmmio_cancel;
471				s->do_cmd = pcmmio_cmd;
472				s->do_cmdtest = pcmmio_cmdtest;
473				s->len_chanlist =
474					subpriv->dio.intr.num_asic_chans;
475			}
476			thisasic_chanct += CHANS_PER_PORT;
477		}
478		spin_lock_init(&subpriv->dio.intr.spinlock);
479
480		chans_left -= s->n_chan;
481
482		if (!chans_left) {
483			asic = 0;	/* reset the asic to our first asic, to do intr subdevs */
484			port = 0;
485		}
486
487	}
488
489	init_asics(dev);	/* clear out all the registers, basically */
490
491	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
492		if (irq[asic]
493			&& request_irq(irq[asic], interrupt_pcmmio,
494				IRQF_SHARED, thisboard->name, dev)) {
495			int i;
496			/* unroll the allocated irqs.. */
497			for (i = asic - 1; i >= 0; --i) {
498				free_irq(irq[i], dev);
499				devpriv->asics[i].irq = irq[i] = 0;
500			}
501			irq[asic] = 0;
502		}
503		devpriv->asics[asic].irq = irq[asic];
504	}
505
506	dev->irq = irq[0];	/* grr.. wish comedi dev struct supported multiple
507				   irqs.. */
508
509	if (irq[0]) {
510		printk("irq: %u ", irq[0]);
511		if (irq[1] && thisboard->dio_num_asics == 2)
512			printk("second ASIC irq: %u ", irq[1]);
513	} else {
514		printk("(IRQ mode disabled) ");
515	}
516
517	printk("attached\n");
518
519	return 1;
520}
521
522/*
523 * _detach is called to deconfigure a device.  It should deallocate
524 * resources.
525 * This function is also called when _attach() fails, so it should be
526 * careful not to release resources that were not necessarily
527 * allocated by _attach().  dev->private and dev->subdevices are
528 * deallocated automatically by the core.
529 */
530static int pcmmio_detach(struct comedi_device *dev)
531{
532	int i;
533
534	printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
535	if (dev->iobase)
536		release_region(dev->iobase, thisboard->total_iosize);
537
538	for (i = 0; i < MAX_ASICS; ++i) {
539		if (devpriv && devpriv->asics[i].irq)
540			free_irq(devpriv->asics[i].irq, dev);
541	}
542
543	if (devpriv && devpriv->sprivs)
544		kfree(devpriv->sprivs);
545
546	return 0;
547}
548
549/* DIO devices are slightly special.  Although it is possible to
550 * implement the insn_read/insn_write interface, it is much more
551 * useful to applications if you implement the insn_bits interface.
552 * This allows packed reading/writing of the DIO channels.  The
553 * comedi core can convert between insn_bits and insn_read/write */
554static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
555	struct comedi_insn *insn, unsigned int *data)
556{
557	int byte_no;
558	if (insn->n != 2)
559		return -EINVAL;
560
561	/* NOTE:
562	   reading a 0 means this channel was high
563	   writine a 0 sets the channel high
564	   reading a 1 means this channel was low
565	   writing a 1 means set this channel low
566
567	   Therefore everything is always inverted. */
568
569	/* The insn data is a mask in data[0] and the new data
570	 * in data[1], each channel cooresponding to a bit. */
571
572#ifdef DAMMIT_ITS_BROKEN
573	/* DEBUG */
574	printk("write mask: %08x  data: %08x\n", data[0], data[1]);
575#endif
576
577	s->state = 0;
578
579	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
580		/* address of 8-bit port */
581		unsigned long ioaddr = subpriv->iobases[byte_no],
582			/* bit offset of port in 32-bit doubleword */
583			offset = byte_no * 8;
584		/* this 8-bit port's data */
585		unsigned char byte = 0,
586			/* The write mask for this port (if any) */
587			write_mask_byte = (data[0] >> offset) & 0xff,
588			/* The data byte for this port */
589			data_byte = (data[1] >> offset) & 0xff;
590
591		byte = inb(ioaddr);	/* read all 8-bits for this port */
592
593#ifdef DAMMIT_ITS_BROKEN
594		/* DEBUG */
595		printk("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
596#endif
597
598		if (write_mask_byte) {
599			/* this byte has some write_bits -- so set the output lines */
600			byte &= ~write_mask_byte;	/* clear bits for write mask */
601			byte |= ~data_byte & write_mask_byte;	/* set to inverted data_byte */
602			/* Write out the new digital output state */
603			outb(byte, ioaddr);
604		}
605#ifdef DAMMIT_ITS_BROKEN
606		/* DEBUG */
607		printk("data_out_byte %02x\n", (unsigned)byte);
608#endif
609		/* save the digital input lines for this byte.. */
610		s->state |= ((unsigned int)byte) << offset;
611	}
612
613	/* now return the DIO lines to data[1] - note they came inverted! */
614	data[1] = ~s->state;
615
616#ifdef DAMMIT_ITS_BROKEN
617	/* DEBUG */
618	printk("s->state %08x data_out %08x\n", s->state, data[1]);
619#endif
620
621	return 2;
622}
623
624/* The input or output configuration of each digital line is
625 * configured by a special insn_config instruction.  chanspec
626 * contains the channel to be changed, and data[0] contains the
627 * value COMEDI_INPUT or COMEDI_OUTPUT. */
628static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
629	struct comedi_insn *insn, unsigned int *data)
630{
631	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
632		chan % 8;
633	unsigned long ioaddr;
634	unsigned char byte;
635
636	/* Compute ioaddr for this channel */
637	ioaddr = subpriv->iobases[byte_no];
638
639	/* NOTE:
640	   writing a 0 an IO channel's bit sets the channel to INPUT
641	   and pulls the line high as well
642
643	   writing a 1 to an IO channel's  bit pulls the line low
644
645	   All channels are implicitly always in OUTPUT mode -- but when
646	   they are high they can be considered to be in INPUT mode..
647
648	   Thus, we only force channels low if the config request was INPUT,
649	   otherwise we do nothing to the hardware.    */
650
651	switch (data[0]) {
652	case INSN_CONFIG_DIO_OUTPUT:
653		/* save to io_bits -- don't actually do anything since
654		   all input channels are also output channels... */
655		s->io_bits |= 1 << chan;
656		break;
657	case INSN_CONFIG_DIO_INPUT:
658		/* write a 0 to the actual register representing the channel
659		   to set it to 'input'.  0 means "float high". */
660		byte = inb(ioaddr);
661		byte &= ~(1 << bit_no);
662				/**< set input channel to '0' */
663
664		/* write out byte -- this is the only time we actually affect the
665		   hardware as all channels are implicitly output -- but input
666		   channels are set to float-high */
667		outb(byte, ioaddr);
668
669		/* save to io_bits */
670		s->io_bits &= ~(1 << chan);
671		break;
672
673	case INSN_CONFIG_DIO_QUERY:
674		/* retreive from shadow register */
675		data[1] =
676			(s->
677			io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
678		return insn->n;
679		break;
680
681	default:
682		return -EINVAL;
683		break;
684	}
685
686	return insn->n;
687}
688
689static void init_asics(struct comedi_device *dev)
690{				/* sets up an
691				   ASIC chip to defaults */
692	int asic;
693
694	for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
695		int port, page;
696		unsigned long baseaddr = devpriv->asics[asic].iobase;
697
698		switch_page(dev, asic, 0);	/* switch back to page 0 */
699
700		/* first, clear all the DIO port bits */
701		for (port = 0; port < PORTS_PER_ASIC; ++port)
702			outb(0, baseaddr + REG_PORT0 + port);
703
704		/* Next, clear all the paged registers for each page */
705		for (page = 1; page < NUM_PAGES; ++page) {
706			int reg;
707			/* now clear all the paged registers */
708			switch_page(dev, asic, page);
709			for (reg = FIRST_PAGED_REG;
710				reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
711				outb(0, baseaddr + reg);
712		}
713
714		/* DEBUG  set rising edge interrupts on port0 of both asics */
715		/*switch_page(dev, asic, PAGE_POL);
716		   outb(0xff, baseaddr + REG_POL0);
717		   switch_page(dev, asic, PAGE_ENAB);
718		   outb(0xff, baseaddr + REG_ENAB0); */
719		/* END DEBUG */
720
721		switch_page(dev, asic, 0);	/* switch back to default page 0 */
722
723	}
724}
725
726static void switch_page(struct comedi_device *dev, int asic, int page)
727{
728	if (asic < 0 || asic >= thisboard->dio_num_asics)
729		return;		/* paranoia */
730	if (page < 0 || page >= NUM_PAGES)
731		return;		/* more paranoia */
732
733	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
734	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
735
736	/* now write out the shadow register */
737	outb(devpriv->asics[asic].pagelock,
738		devpriv->asics[asic].iobase + REG_PAGELOCK);
739}
740
741#ifdef notused
742static void lock_port(struct comedi_device *dev, int asic, int port)
743{
744	if (asic < 0 || asic >= thisboard->dio_num_asics)
745		return;		/* paranoia */
746	if (port < 0 || port >= PORTS_PER_ASIC)
747		return;		/* more paranoia */
748
749	devpriv->asics[asic].pagelock |= 0x1 << port;
750	/* now write out the shadow register */
751	outb(devpriv->asics[asic].pagelock,
752		devpriv->asics[asic].iobase + REG_PAGELOCK);
753	return;
754}
755
756static void unlock_port(struct comedi_device *dev, int asic, int port)
757{
758	if (asic < 0 || asic >= thisboard->dio_num_asics)
759		return;		/* paranoia */
760	if (port < 0 || port >= PORTS_PER_ASIC)
761		return;		/* more paranoia */
762	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
763	/* now write out the shadow register */
764	outb(devpriv->asics[asic].pagelock,
765		devpriv->asics[asic].iobase + REG_PAGELOCK);
766}
767#endif /* notused */
768
769static irqreturn_t interrupt_pcmmio(int irq, void *d)
770{
771	int asic, got1 = 0;
772	struct comedi_device *dev = (struct comedi_device *) d;
773
774	for (asic = 0; asic < MAX_ASICS; ++asic) {
775		if (irq == devpriv->asics[asic].irq) {
776			unsigned long flags;
777			unsigned triggered = 0;
778			unsigned long iobase = devpriv->asics[asic].iobase;
779			/* it is an interrupt for ASIC #asic */
780			unsigned char int_pend;
781
782			spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
783
784			int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
785
786			if (int_pend) {
787				int port;
788				for (port = 0; port < INTR_PORTS_PER_ASIC;
789					++port) {
790					if (int_pend & (0x1 << port)) {
791						unsigned char
792							io_lines_with_edges = 0;
793						switch_page(dev, asic,
794							PAGE_INT_ID);
795						io_lines_with_edges =
796							inb(iobase +
797							REG_INT_ID0 + port);
798
799						if (io_lines_with_edges)
800							/* clear pending interrupt */
801							outb(0, iobase +
802								REG_INT_ID0 +
803								port);
804
805						triggered |=
806							io_lines_with_edges <<
807							port * 8;
808					}
809				}
810
811				++got1;
812			}
813
814			spin_unlock_irqrestore(&devpriv->asics[asic].  spinlock, flags);
815
816			if (triggered) {
817				struct comedi_subdevice *s;
818				/* TODO here: dispatch io lines to subdevs with commands.. */
819				printk("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered);
820				for (s = dev->subdevices + 2;
821					s < dev->subdevices + dev->n_subdevices;
822					++s) {
823					if (subpriv->dio.intr.asic == asic) {	/* this is an interrupt subdev, and it matches this asic! */
824						unsigned long flags;
825						unsigned oldevents;
826
827						spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
828
829						oldevents = s->async->events;
830
831						if (subpriv->dio.intr.active) {
832							unsigned mytrig =
833								((triggered >>
834									subpriv->
835									dio.
836									intr.
837									asic_chan)
838								& ((0x1 << subpriv->dio.intr.num_asic_chans) - 1)) << subpriv->dio.intr.first_chan;
839							if (mytrig & subpriv->
840								dio.intr.
841								enabled_mask) {
842								unsigned int val =
843									0;
844								unsigned int n,
845									ch, len;
846
847								len = s->async->
848									cmd.
849									chanlist_len;
850								for (n = 0;
851									n < len;
852									n++) {
853									ch = CR_CHAN(s->async->cmd.chanlist[n]);
854									if (mytrig & (1U << ch)) {
855										val |= (1U << n);
856									}
857								}
858								/* Write the scan to the buffer. */
859								if (comedi_buf_put(s->async, ((short *) &val)[0])
860									&&
861									comedi_buf_put
862									(s->async, ((short *) &val)[1])) {
863									s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
864								} else {
865									/* Overflow! Stop acquisition!! */
866									/* TODO: STOP_ACQUISITION_CALL_HERE!! */
867									pcmmio_stop_intr
868										(dev,
869										s);
870								}
871
872								/* Check for end of acquisition. */
873								if (!subpriv->
874									dio.
875									intr.
876									continuous)
877								{
878									/* stop_src == TRIG_COUNT */
879									if (subpriv->dio.intr.stop_count > 0) {
880										subpriv->
881											dio.
882											intr.
883											stop_count--;
884										if (subpriv->dio.intr.stop_count == 0) {
885											s->async->events |= COMEDI_CB_EOA;
886											/* TODO: STOP_ACQUISITION_CALL_HERE!! */
887											pcmmio_stop_intr
888												(dev,
889												s);
890										}
891									}
892								}
893							}
894						}
895
896						spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
897
898						if (oldevents !=
899							s->async->events) {
900							comedi_event(dev, s);
901						}
902
903					}
904
905				}
906			}
907
908		}
909	}
910	if (!got1)
911		return IRQ_NONE;	/* interrupt from other source */
912	return IRQ_HANDLED;
913}
914
915static void pcmmio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s)
916{
917	int nports, firstport, asic, port;
918
919	asic = subpriv->dio.intr.asic;
920	if (asic < 0)
921		return;		/* not an interrupt subdev */
922
923	subpriv->dio.intr.enabled_mask = 0;
924	subpriv->dio.intr.active = 0;
925	s->async->inttrig = 0;
926	nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
927	firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
928	switch_page(dev, asic, PAGE_ENAB);
929	for (port = firstport; port < firstport + nports; ++port) {
930		/* disable all intrs for this subdev.. */
931		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
932	}
933}
934
935static int pcmmio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s)
936{
937	if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
938		/* An empty acquisition! */
939		s->async->events |= COMEDI_CB_EOA;
940		subpriv->dio.intr.active = 0;
941		return 1;
942	} else {
943		unsigned bits = 0, pol_bits = 0, n;
944		int nports, firstport, asic, port;
945		struct comedi_cmd *cmd = &s->async->cmd;
946
947		asic = subpriv->dio.intr.asic;
948		if (asic  < 0)
949			return 1;	/* not an interrupt
950					   subdev */
951		subpriv->dio.intr.enabled_mask = 0;
952		subpriv->dio.intr.active = 1;
953		nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
954		firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
955		if (cmd->chanlist) {
956			for (n = 0; n < cmd->chanlist_len; n++) {
957				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
958				pol_bits |= (CR_AREF(cmd->chanlist[n])
959					|| CR_RANGE(cmd->chanlist[n]) ? 1U : 0U)
960					<< CR_CHAN(cmd->chanlist[n]);
961			}
962		}
963		bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
964			1) << subpriv->dio.intr.first_chan;
965		subpriv->dio.intr.enabled_mask = bits;
966
967		{		/* the below code configures the board to use a specific IRQ from 0-15. */
968			unsigned char b;
969			/* set resource enable register to enable IRQ operation */
970			outb(1 << 4, dev->iobase + 3);
971			/* set bits 0-3 of b to the irq number from 0-15 */
972			b = dev->irq & ((1 << 4) - 1);
973			outb(b, dev->iobase + 2);
974			/* done, we told the board what irq to use */
975		}
976
977		switch_page(dev, asic, PAGE_ENAB);
978		for (port = firstport; port < firstport + nports; ++port) {
979			unsigned enab =
980				bits >> (subpriv->dio.intr.first_chan + (port -
981					firstport) * 8) & 0xff, pol =
982				pol_bits >> (subpriv->dio.intr.first_chan +
983				(port - firstport) * 8) & 0xff;
984			/* set enab intrs for this subdev.. */
985			outb(enab,
986				devpriv->asics[asic].iobase + REG_ENAB0 + port);
987			switch_page(dev, asic, PAGE_POL);
988			outb(pol,
989				devpriv->asics[asic].iobase + REG_ENAB0 + port);
990		}
991	}
992	return 0;
993}
994
995static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
996{
997	unsigned long flags;
998
999	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1000	if (subpriv->dio.intr.active)
1001		pcmmio_stop_intr(dev, s);
1002	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1003
1004	return 0;
1005}
1006
1007/*
1008 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1009 */
1010static int
1011pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
1012	unsigned int trignum)
1013{
1014	unsigned long flags;
1015	int event = 0;
1016
1017	if (trignum != 0)
1018		return -EINVAL;
1019
1020	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1021	s->async->inttrig = 0;
1022	if (subpriv->dio.intr.active) {
1023		event = pcmmio_start_intr(dev, s);
1024	}
1025	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1026
1027	if (event) {
1028		comedi_event(dev, s);
1029	}
1030
1031	return 1;
1032}
1033
1034/*
1035 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1036 */
1037static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1038{
1039	struct comedi_cmd *cmd = &s->async->cmd;
1040	unsigned long flags;
1041	int event = 0;
1042
1043	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1044	subpriv->dio.intr.active = 1;
1045
1046	/* Set up end of acquisition. */
1047	switch (cmd->stop_src) {
1048	case TRIG_COUNT:
1049		subpriv->dio.intr.continuous = 0;
1050		subpriv->dio.intr.stop_count = cmd->stop_arg;
1051		break;
1052	default:
1053		/* TRIG_NONE */
1054		subpriv->dio.intr.continuous = 1;
1055		subpriv->dio.intr.stop_count = 0;
1056		break;
1057	}
1058
1059	/* Set up start of acquisition. */
1060	switch (cmd->start_src) {
1061	case TRIG_INT:
1062		s->async->inttrig = pcmmio_inttrig_start_intr;
1063		break;
1064	default:
1065		/* TRIG_NOW */
1066		event = pcmmio_start_intr(dev, s);
1067		break;
1068	}
1069	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1070
1071	if (event) {
1072		comedi_event(dev, s);
1073	}
1074
1075	return 0;
1076}
1077
1078/*
1079 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
1080 */
1081static int
1082pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd)
1083{
1084	int err = 0;
1085	unsigned int tmp;
1086
1087	/* step 1: make sure trigger sources are trivially valid */
1088
1089	tmp = cmd->start_src;
1090	cmd->start_src &= (TRIG_NOW | TRIG_INT);
1091	if (!cmd->start_src || tmp != cmd->start_src)
1092		err++;
1093
1094	tmp = cmd->scan_begin_src;
1095	cmd->scan_begin_src &= TRIG_EXT;
1096	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1097		err++;
1098
1099	tmp = cmd->convert_src;
1100	cmd->convert_src &= TRIG_NOW;
1101	if (!cmd->convert_src || tmp != cmd->convert_src)
1102		err++;
1103
1104	tmp = cmd->scan_end_src;
1105	cmd->scan_end_src &= TRIG_COUNT;
1106	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1107		err++;
1108
1109	tmp = cmd->stop_src;
1110	cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
1111	if (!cmd->stop_src || tmp != cmd->stop_src)
1112		err++;
1113
1114	if (err)
1115		return 1;
1116
1117	/* step 2: make sure trigger sources are unique and mutually compatible */
1118
1119	/* these tests are true if more than one _src bit is set */
1120	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1121		err++;
1122	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1123		err++;
1124	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1125		err++;
1126	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1127		err++;
1128	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1129		err++;
1130
1131	if (err)
1132		return 2;
1133
1134	/* step 3: make sure arguments are trivially compatible */
1135
1136	/* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
1137	if (cmd->start_arg != 0) {
1138		cmd->start_arg = 0;
1139		err++;
1140	}
1141
1142	/* cmd->scan_begin_src == TRIG_EXT */
1143	if (cmd->scan_begin_arg != 0) {
1144		cmd->scan_begin_arg = 0;
1145		err++;
1146	}
1147
1148	/* cmd->convert_src == TRIG_NOW */
1149	if (cmd->convert_arg != 0) {
1150		cmd->convert_arg = 0;
1151		err++;
1152	}
1153
1154	/* cmd->scan_end_src == TRIG_COUNT */
1155	if (cmd->scan_end_arg != cmd->chanlist_len) {
1156		cmd->scan_end_arg = cmd->chanlist_len;
1157		err++;
1158	}
1159
1160	switch (cmd->stop_src) {
1161	case TRIG_COUNT:
1162		/* any count allowed */
1163		break;
1164	case TRIG_NONE:
1165		if (cmd->stop_arg != 0) {
1166			cmd->stop_arg = 0;
1167			err++;
1168		}
1169		break;
1170	default:
1171		break;
1172	}
1173
1174	if (err)
1175		return 3;
1176
1177	/* step 4: fix up any arguments */
1178
1179	/* if (err) return 4; */
1180
1181	return 0;
1182}
1183
1184static int adc_wait_ready(unsigned long iobase)
1185{
1186	unsigned long retry = 100000;
1187	while (retry--)
1188		if (inb(iobase + 3) & 0x80)
1189			return 0;
1190	return 1;
1191}
1192
1193/* All this is for AI and AO */
1194static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1195	struct comedi_insn *insn, unsigned int *data)
1196{
1197	int n;
1198	unsigned long iobase = subpriv->iobase;
1199
1200	/*
1201	   1. write the CMD byte (to BASE+2)
1202	   2. read junk lo byte (BASE+0)
1203	   3. read junk hi byte (BASE+1)
1204	   4. (mux settled so) write CMD byte again (BASE+2)
1205	   5. read valid lo byte(BASE+0)
1206	   6. read valid hi byte(BASE+1)
1207
1208	   Additionally note that the BASE += 4 if the channel >= 8
1209	 */
1210
1211	/* convert n samples */
1212	for (n = 0; n < insn->n; n++) {
1213		unsigned chan = CR_CHAN(insn->chanspec), range =
1214			CR_RANGE(insn->chanspec), aref =
1215			CR_AREF(insn->chanspec);
1216		unsigned char command_byte = 0;
1217		unsigned iooffset = 0;
1218		short sample, adc_adjust = 0;
1219
1220		if (chan > 7)
1221			chan -= 8, iooffset = 4;	/* use the second dword for channels > 7 */
1222
1223		if (aref != AREF_DIFF) {
1224			aref = AREF_GROUND;
1225			command_byte |= 1 << 7;	/* set bit 7 to indicate single-ended */
1226		}
1227		if (range < 2)
1228			adc_adjust = 0x8000;	/* bipolar ranges (-5,5 .. -10,10 need to be adjusted -- that is.. they need to wrap around by adding 0x8000 */
1229
1230		if (chan % 2) {
1231			command_byte |= 1 << 6;	/* odd-numbered channels have bit 6 set */
1232		}
1233
1234		/* select the channel, bits 4-5 == chan/2 */
1235		command_byte |= ((chan / 2) & 0x3) << 4;
1236
1237		/* set the range, bits 2-3 */
1238		command_byte |= (range & 0x3) << 2;
1239
1240		/* need to do this twice to make sure mux settled */
1241		outb(command_byte, iobase + iooffset + 2);	/* chan/range/aref select */
1242
1243		adc_wait_ready(iobase + iooffset);	/* wait for the adc to say it finised the conversion */
1244
1245		outb(command_byte, iobase + iooffset + 2);	/* select the chan/range/aref AGAIN */
1246
1247		adc_wait_ready(iobase + iooffset);
1248
1249		sample = inb(iobase + iooffset + 0);	/* read data lo byte */
1250		sample |= inb(iobase + iooffset + 1) << 8;	/* read data hi byte */
1251		sample += adc_adjust;	/* adjustment .. munge data */
1252		data[n] = sample;
1253	}
1254	/* return the number of samples read/written */
1255	return n;
1256}
1257
1258static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1259	struct comedi_insn *insn, unsigned int *data)
1260{
1261	int n;
1262	for (n = 0; n < insn->n; n++) {
1263		unsigned chan = CR_CHAN(insn->chanspec);
1264		if (chan < s->n_chan)
1265			data[n] = subpriv->ao.shadow_samples[chan];
1266	}
1267	return n;
1268}
1269
1270static int wait_dac_ready(unsigned long iobase)
1271{
1272	unsigned long retry = 100000L;
1273
1274	/* This may seem like an absurd way to handle waiting and violates the
1275	   "no busy waiting" policy. The fact is that the hardware is
1276	   normally so fast that we usually only need one time through the loop
1277	   anyway. The longer timeout is for rare occasions and for detecting
1278	   non-existant hardware.  */
1279
1280	while (retry--) {
1281		if (inb(iobase + 3) & 0x80)
1282			return 0;
1283
1284	}
1285	return 1;
1286}
1287
1288static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1289	struct comedi_insn *insn, unsigned int *data)
1290{
1291	int n;
1292	unsigned iobase = subpriv->iobase, iooffset = 0;
1293
1294	for (n = 0; n < insn->n; n++) {
1295		unsigned chan = CR_CHAN(insn->chanspec), range =
1296			CR_RANGE(insn->chanspec);
1297		if (chan < s->n_chan) {
1298			unsigned char command_byte = 0, range_byte =
1299				range & ((1 << 4) - 1);
1300			if (chan >= 4)
1301				chan -= 4, iooffset += 4;
1302			/* set the range.. */
1303			outb(range_byte, iobase + iooffset + 0);
1304			outb(0, iobase + iooffset + 1);
1305
1306			/* tell it to begin */
1307			command_byte = (chan << 1) | 0x60;
1308			outb(command_byte, iobase + iooffset + 2);
1309
1310			wait_dac_ready(iobase + iooffset);
1311
1312			outb(data[n] & 0xff, iobase + iooffset + 0);	/* low order byte */
1313			outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);	/* high order byte */
1314			command_byte = 0x70 | (chan << 1);	/* set bit 4 of command byte to indicate data is loaded and trigger conversion */
1315			/* trigger converion */
1316			outb(command_byte, iobase + iooffset + 2);
1317
1318			wait_dac_ready(iobase + iooffset);
1319
1320			subpriv->ao.shadow_samples[chan] = data[n];	/* save to shadow register for ao_rinsn */
1321		}
1322	}
1323	return n;
1324}
1325
1326/*
1327 * A convenient macro that defines init_module() and cleanup_module(),
1328 * as necessary.
1329 */
1330COMEDI_INITCLEANUP(driver);
1331