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