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