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