pcmmio.c revision 56b8421ceef7f2dae95b882034ebf6958bad58f6
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("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
375	       iobase);
376
377	dev->iobase = iobase;
378
379	if (!iobase || !request_region(iobase,
380				       thisboard->total_iosize,
381				       driver.driver_name)) {
382		printk("I/O port conflict\n");
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("cannot allocate private data structure\n");
398		return -ENOMEM;
399	}
400
401	for (asic = 0; asic < MAX_ASICS; ++asic) {
402		devpriv->asics[asic].num = asic;
403		devpriv->asics[asic].iobase =
404		    dev->iobase + 16 + asic * ASIC_IOSIZE;
405		/*
406		 * this gets actually set at the end of this function when we
407		 * request_irqs
408		 */
409		devpriv->asics[asic].irq = 0;
410		spin_lock_init(&devpriv->asics[asic].spinlock);
411	}
412
413	chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
414	n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
415	n_subdevs = n_dio_subdevs + 2;
416	devpriv->sprivs =
417	    kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
418		    GFP_KERNEL);
419	if (!devpriv->sprivs) {
420		printk("cannot allocate subdevice private data structures\n");
421		return -ENOMEM;
422	}
423	/*
424	 * Allocate the subdevice structures.  alloc_subdevice() is a
425	 * convenient macro defined in comedidev.h.
426	 *
427	 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
428	 */
429	if (alloc_subdevices(dev, n_subdevs) < 0) {
430		printk("cannot allocate subdevice data structures\n");
431		return -ENOMEM;
432	}
433
434	/* First, AI */
435	sdev_no = 0;
436	s = dev->subdevices + sdev_no;
437	s->private = devpriv->sprivs + sdev_no;
438	s->maxdata = (1 << thisboard->ai_bits) - 1;
439	s->range_table = thisboard->ai_range_table;
440	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
441	s->type = COMEDI_SUBD_AI;
442	s->n_chan = thisboard->n_ai_chans;
443	s->len_chanlist = s->n_chan;
444	s->insn_read = thisboard->ai_rinsn;
445	subpriv->iobase = dev->iobase + 0;
446	/* initialize the resource enable register by clearing it */
447	outb(0, subpriv->iobase + 3);
448	outb(0, subpriv->iobase + 4 + 3);
449
450	/* Next, AO */
451	++sdev_no;
452	s = dev->subdevices + sdev_no;
453	s->private = devpriv->sprivs + sdev_no;
454	s->maxdata = (1 << thisboard->ao_bits) - 1;
455	s->range_table = thisboard->ao_range_table;
456	s->subdev_flags = SDF_READABLE;
457	s->type = COMEDI_SUBD_AO;
458	s->n_chan = thisboard->n_ao_chans;
459	s->len_chanlist = s->n_chan;
460	s->insn_read = thisboard->ao_rinsn;
461	s->insn_write = thisboard->ao_winsn;
462	subpriv->iobase = dev->iobase + 8;
463	/* initialize the resource enable register by clearing it */
464	outb(0, subpriv->iobase + 3);
465	outb(0, subpriv->iobase + 4 + 3);
466
467	++sdev_no;
468	port = 0;
469	asic = 0;
470	for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
471		int byte_no;
472
473		s = dev->subdevices + sdev_no;
474		s->private = devpriv->sprivs + sdev_no;
475		s->maxdata = 1;
476		s->range_table = &range_digital;
477		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
478		s->type = COMEDI_SUBD_DIO;
479		s->insn_bits = pcmmio_dio_insn_bits;
480		s->insn_config = pcmmio_dio_insn_config;
481		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
482		subpriv->dio.intr.asic = -1;
483		subpriv->dio.intr.first_chan = -1;
484		subpriv->dio.intr.asic_chan = -1;
485		subpriv->dio.intr.num_asic_chans = -1;
486		subpriv->dio.intr.active = 0;
487		s->len_chanlist = 1;
488
489		/* save the ioport address for each 'port' of 8 channels in the
490		   subdevice */
491		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
492			if (port >= PORTS_PER_ASIC) {
493				port = 0;
494				++asic;
495				thisasic_chanct = 0;
496			}
497			subpriv->iobases[byte_no] =
498			    devpriv->asics[asic].iobase + port;
499
500			if (thisasic_chanct <
501			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
502			    && subpriv->dio.intr.asic < 0) {
503				/*
504				 * this is an interrupt subdevice,
505				 * so setup the struct
506				 */
507				subpriv->dio.intr.asic = asic;
508				subpriv->dio.intr.active = 0;
509				subpriv->dio.intr.stop_count = 0;
510				subpriv->dio.intr.first_chan = byte_no * 8;
511				subpriv->dio.intr.asic_chan = thisasic_chanct;
512				subpriv->dio.intr.num_asic_chans =
513				    s->n_chan - subpriv->dio.intr.first_chan;
514				s->cancel = pcmmio_cancel;
515				s->do_cmd = pcmmio_cmd;
516				s->do_cmdtest = pcmmio_cmdtest;
517				s->len_chanlist =
518				    subpriv->dio.intr.num_asic_chans;
519			}
520			thisasic_chanct += CHANS_PER_PORT;
521		}
522		spin_lock_init(&subpriv->dio.intr.spinlock);
523
524		chans_left -= s->n_chan;
525
526		if (!chans_left) {
527			/*
528			 * reset the asic to our first asic,
529			 * to do intr subdevs
530			 */
531			asic = 0;
532			port = 0;
533		}
534
535	}
536
537	init_asics(dev);	/* clear out all the registers, basically */
538
539	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
540		if (irq[asic]
541		    && request_irq(irq[asic], interrupt_pcmmio,
542				   IRQF_SHARED, thisboard->name, dev)) {
543			int i;
544			/* unroll the allocated irqs.. */
545			for (i = asic - 1; i >= 0; --i) {
546				free_irq(irq[i], dev);
547				devpriv->asics[i].irq = irq[i] = 0;
548			}
549			irq[asic] = 0;
550		}
551		devpriv->asics[asic].irq = irq[asic];
552	}
553
554	dev->irq = irq[0];	/*
555				 * grr.. wish comedi dev struct supported
556				 * multiple irqs..
557				 */
558
559	if (irq[0]) {
560		printk("irq: %u ", irq[0]);
561		if (thisboard->dio_num_asics == 2 && irq[1])
562			printk("second ASIC irq: %u ", irq[1]);
563	} else {
564		printk("(IRQ mode disabled) ");
565	}
566
567	printk("attached\n");
568
569	return 1;
570}
571
572/*
573 * _detach is called to deconfigure a device.  It should deallocate
574 * resources.
575 * This function is also called when _attach() fails, so it should be
576 * careful not to release resources that were not necessarily
577 * allocated by _attach().  dev->private and dev->subdevices are
578 * deallocated automatically by the core.
579 */
580static int pcmmio_detach(struct comedi_device *dev)
581{
582	int i;
583
584	printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
585	if (dev->iobase)
586		release_region(dev->iobase, thisboard->total_iosize);
587
588	for (i = 0; i < MAX_ASICS; ++i) {
589		if (devpriv && devpriv->asics[i].irq)
590			free_irq(devpriv->asics[i].irq, dev);
591	}
592
593	if (devpriv && devpriv->sprivs)
594		kfree(devpriv->sprivs);
595
596	return 0;
597}
598
599/* DIO devices are slightly special.  Although it is possible to
600 * implement the insn_read/insn_write interface, it is much more
601 * useful to applications if you implement the insn_bits interface.
602 * This allows packed reading/writing of the DIO channels.  The
603 * comedi core can convert between insn_bits and insn_read/write */
604static int pcmmio_dio_insn_bits(struct comedi_device *dev,
605				struct comedi_subdevice *s,
606				struct comedi_insn *insn, unsigned int *data)
607{
608	int byte_no;
609	if (insn->n != 2)
610		return -EINVAL;
611
612	/* NOTE:
613	   reading a 0 means this channel was high
614	   writine a 0 sets the channel high
615	   reading a 1 means this channel was low
616	   writing a 1 means set this channel low
617
618	   Therefore everything is always inverted. */
619
620	/* The insn data is a mask in data[0] and the new data
621	 * in data[1], each channel cooresponding to a bit. */
622
623#ifdef DAMMIT_ITS_BROKEN
624	/* DEBUG */
625	printk("write mask: %08x  data: %08x\n", data[0], data[1]);
626#endif
627
628	s->state = 0;
629
630	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
631		/* address of 8-bit port */
632		unsigned long ioaddr = subpriv->iobases[byte_no],
633		    /* bit offset of port in 32-bit doubleword */
634		    offset = byte_no * 8;
635		/* this 8-bit port's data */
636		unsigned char byte = 0,
637		    /* The write mask for this port (if any) */
638		    write_mask_byte = (data[0] >> offset) & 0xff,
639		    /* The data byte for this port */
640		    data_byte = (data[1] >> offset) & 0xff;
641
642		byte = inb(ioaddr);	/* read all 8-bits for this port */
643
644#ifdef DAMMIT_ITS_BROKEN
645		/* DEBUG */
646		printk
647		    ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
648		     byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
649		     offset, ioaddr, (unsigned)byte);
650#endif
651
652		if (write_mask_byte) {
653			/*
654			 * this byte has some write_bits
655			 * -- so set the output lines
656			 */
657			/* clear bits for write mask */
658			byte &= ~write_mask_byte;
659			/* set to inverted data_byte */
660			byte |= ~data_byte & write_mask_byte;
661			/* Write out the new digital output state */
662			outb(byte, ioaddr);
663		}
664#ifdef DAMMIT_ITS_BROKEN
665		/* DEBUG */
666		printk("data_out_byte %02x\n", (unsigned)byte);
667#endif
668		/* save the digital input lines for this byte.. */
669		s->state |= ((unsigned int)byte) << offset;
670	}
671
672	/* now return the DIO lines to data[1] - note they came inverted! */
673	data[1] = ~s->state;
674
675#ifdef DAMMIT_ITS_BROKEN
676	/* DEBUG */
677	printk("s->state %08x data_out %08x\n", s->state, data[1]);
678#endif
679
680	return 2;
681}
682
683/* The input or output configuration of each digital line is
684 * configured by a special insn_config instruction.  chanspec
685 * contains the channel to be changed, and data[0] contains the
686 * value COMEDI_INPUT or COMEDI_OUTPUT. */
687static int pcmmio_dio_insn_config(struct comedi_device *dev,
688				  struct comedi_subdevice *s,
689				  struct comedi_insn *insn, unsigned int *data)
690{
691	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
692	    chan % 8;
693	unsigned long ioaddr;
694	unsigned char byte;
695
696	/* Compute ioaddr for this channel */
697	ioaddr = subpriv->iobases[byte_no];
698
699	/* NOTE:
700	   writing a 0 an IO channel's bit sets the channel to INPUT
701	   and pulls the line high as well
702
703	   writing a 1 to an IO channel's  bit pulls the line low
704
705	   All channels are implicitly always in OUTPUT mode -- but when
706	   they are high they can be considered to be in INPUT mode..
707
708	   Thus, we only force channels low if the config request was INPUT,
709	   otherwise we do nothing to the hardware.    */
710
711	switch (data[0]) {
712	case INSN_CONFIG_DIO_OUTPUT:
713		/* save to io_bits -- don't actually do anything since
714		   all input channels are also output channels... */
715		s->io_bits |= 1 << chan;
716		break;
717	case INSN_CONFIG_DIO_INPUT:
718		/* write a 0 to the actual register representing the channel
719		   to set it to 'input'.  0 means "float high". */
720		byte = inb(ioaddr);
721		byte &= ~(1 << bit_no);
722				/**< set input channel to '0' */
723
724		/*
725		 * write out byte -- this is the only time we actually affect
726		 * the hardware as all channels are implicitly output
727		 * -- but input channels are set to float-high
728		 */
729		outb(byte, ioaddr);
730
731		/* save to io_bits */
732		s->io_bits &= ~(1 << chan);
733		break;
734
735	case INSN_CONFIG_DIO_QUERY:
736		/* retreive from shadow register */
737		data[1] =
738		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
739		return insn->n;
740		break;
741
742	default:
743		return -EINVAL;
744		break;
745	}
746
747	return insn->n;
748}
749
750static void init_asics(struct comedi_device *dev)
751{				/* sets up an
752				   ASIC chip to defaults */
753	int asic;
754
755	for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
756		int port, page;
757		unsigned long baseaddr = devpriv->asics[asic].iobase;
758
759		switch_page(dev, asic, 0);	/* switch back to page 0 */
760
761		/* first, clear all the DIO port bits */
762		for (port = 0; port < PORTS_PER_ASIC; ++port)
763			outb(0, baseaddr + REG_PORT0 + port);
764
765		/* Next, clear all the paged registers for each page */
766		for (page = 1; page < NUM_PAGES; ++page) {
767			int reg;
768			/* now clear all the paged registers */
769			switch_page(dev, asic, page);
770			for (reg = FIRST_PAGED_REG;
771			     reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
772				outb(0, baseaddr + reg);
773		}
774
775		/* DEBUG  set rising edge interrupts on port0 of both asics */
776		/*switch_page(dev, asic, PAGE_POL);
777		   outb(0xff, baseaddr + REG_POL0);
778		   switch_page(dev, asic, PAGE_ENAB);
779		   outb(0xff, baseaddr + REG_ENAB0); */
780		/* END DEBUG */
781
782		/* switch back to default page 0 */
783		switch_page(dev, asic, 0);
784	}
785}
786
787static void switch_page(struct comedi_device *dev, int asic, int page)
788{
789	if (asic < 0 || asic >= thisboard->dio_num_asics)
790		return;		/* paranoia */
791	if (page < 0 || page >= NUM_PAGES)
792		return;		/* more paranoia */
793
794	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
795	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
796
797	/* now write out the shadow register */
798	outb(devpriv->asics[asic].pagelock,
799	     devpriv->asics[asic].iobase + REG_PAGELOCK);
800}
801
802#ifdef notused
803static void lock_port(struct comedi_device *dev, int asic, int port)
804{
805	if (asic < 0 || asic >= thisboard->dio_num_asics)
806		return;		/* paranoia */
807	if (port < 0 || port >= PORTS_PER_ASIC)
808		return;		/* more paranoia */
809
810	devpriv->asics[asic].pagelock |= 0x1 << port;
811	/* now write out the shadow register */
812	outb(devpriv->asics[asic].pagelock,
813	     devpriv->asics[asic].iobase + REG_PAGELOCK);
814	return;
815}
816
817static void unlock_port(struct comedi_device *dev, int asic, int port)
818{
819	if (asic < 0 || asic >= thisboard->dio_num_asics)
820		return;		/* paranoia */
821	if (port < 0 || port >= PORTS_PER_ASIC)
822		return;		/* more paranoia */
823	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
824	/* now write out the shadow register */
825	outb(devpriv->asics[asic].pagelock,
826	     devpriv->asics[asic].iobase + REG_PAGELOCK);
827}
828#endif /* notused */
829
830static irqreturn_t interrupt_pcmmio(int irq, void *d)
831{
832	int asic, got1 = 0;
833	struct comedi_device *dev = (struct comedi_device *)d;
834
835	for (asic = 0; asic < MAX_ASICS; ++asic) {
836		if (irq == devpriv->asics[asic].irq) {
837			unsigned long flags;
838			unsigned triggered = 0;
839			unsigned long iobase = devpriv->asics[asic].iobase;
840			/* it is an interrupt for ASIC #asic */
841			unsigned char int_pend;
842
843			spin_lock_irqsave(&devpriv->asics[asic].spinlock,
844					  flags);
845
846			int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
847
848			if (int_pend) {
849				int port;
850				for (port = 0; port < INTR_PORTS_PER_ASIC;
851				     ++port) {
852					if (int_pend & (0x1 << port)) {
853						unsigned char
854						    io_lines_with_edges = 0;
855						switch_page(dev, asic,
856							    PAGE_INT_ID);
857						io_lines_with_edges =
858						    inb(iobase +
859							REG_INT_ID0 + port);
860
861						if (io_lines_with_edges)
862							/*
863							 * clear pending
864							 * interrupt
865							 */
866							outb(0, iobase +
867							     REG_INT_ID0 +
868							     port);
869
870						triggered |=
871						    io_lines_with_edges <<
872						    port * 8;
873					}
874				}
875
876				++got1;
877			}
878
879			spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
880					       flags);
881
882			if (triggered) {
883				struct comedi_subdevice *s;
884				/*
885				 * TODO here: dispatch io lines to subdevs
886				 * with commands..
887				 */
888				printk
889				    ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
890				     irq, asic, triggered);
891				for (s = dev->subdevices + 2;
892				     s < dev->subdevices + dev->n_subdevices;
893				     ++s) {
894					/*
895					 * this is an interrupt subdev,
896					 * and it matches this asic!
897					 */
898					if (subpriv->dio.intr.asic == asic) {
899						unsigned long flags;
900						unsigned oldevents;
901
902						spin_lock_irqsave(&subpriv->dio.
903								  intr.spinlock,
904								  flags);
905
906						oldevents = s->async->events;
907
908						if (subpriv->dio.intr.active) {
909							unsigned mytrig =
910							    ((triggered >>
911							      subpriv->dio.intr.asic_chan)
912							     &
913							     ((0x1 << subpriv->
914							       dio.intr.
915							       num_asic_chans) -
916							      1)) << subpriv->
917							    dio.intr.first_chan;
918							if (mytrig &
919							    subpriv->dio.
920							    intr.enabled_mask) {
921								unsigned int val
922								    = 0;
923								unsigned int n,
924								    ch, len;
925
926								len =
927								    s->
928								    async->cmd.chanlist_len;
929								for (n = 0;
930								     n < len;
931								     n++) {
932									ch = CR_CHAN(s->async->cmd.chanlist[n]);
933									if (mytrig & (1U << ch))
934										val |= (1U << n);
935								}
936								/* Write the scan to the buffer. */
937								if (comedi_buf_put(s->async, ((short *)&val)[0])
938								    &&
939								    comedi_buf_put
940								    (s->async,
941								     ((short *)
942								      &val)[1])) {
943									s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
944								} else {
945									/* Overflow! Stop acquisition!! */
946									/* TODO: STOP_ACQUISITION_CALL_HERE!! */
947									pcmmio_stop_intr
948									    (dev,
949									     s);
950								}
951
952								/* Check for end of acquisition. */
953								if (!subpriv->dio.intr.continuous) {
954									/* stop_src == TRIG_COUNT */
955									if (subpriv->dio.intr.stop_count > 0) {
956										subpriv->dio.intr.stop_count--;
957										if (subpriv->dio.intr.stop_count == 0) {
958											s->async->events |= COMEDI_CB_EOA;
959											/* TODO: STOP_ACQUISITION_CALL_HERE!! */
960											pcmmio_stop_intr
961											    (dev,
962											     s);
963										}
964									}
965								}
966							}
967						}
968
969						spin_unlock_irqrestore
970						    (&subpriv->dio.intr.
971						     spinlock, flags);
972
973						if (oldevents !=
974						    s->async->events) {
975							comedi_event(dev, s);
976						}
977
978					}
979
980				}
981			}
982
983		}
984	}
985	if (!got1)
986		return IRQ_NONE;	/* interrupt from other source */
987	return IRQ_HANDLED;
988}
989
990static void pcmmio_stop_intr(struct comedi_device *dev,
991			     struct comedi_subdevice *s)
992{
993	int nports, firstport, asic, port;
994
995	asic = subpriv->dio.intr.asic;
996	if (asic < 0)
997		return;		/* not an interrupt subdev */
998
999	subpriv->dio.intr.enabled_mask = 0;
1000	subpriv->dio.intr.active = 0;
1001	s->async->inttrig = 0;
1002	nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
1003	firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
1004	switch_page(dev, asic, PAGE_ENAB);
1005	for (port = firstport; port < firstport + nports; ++port) {
1006		/* disable all intrs for this subdev.. */
1007		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
1008	}
1009}
1010
1011static int pcmmio_start_intr(struct comedi_device *dev,
1012			     struct comedi_subdevice *s)
1013{
1014	if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
1015		/* An empty acquisition! */
1016		s->async->events |= COMEDI_CB_EOA;
1017		subpriv->dio.intr.active = 0;
1018		return 1;
1019	} else {
1020		unsigned bits = 0, pol_bits = 0, n;
1021		int nports, firstport, asic, port;
1022		struct comedi_cmd *cmd = &s->async->cmd;
1023
1024		asic = subpriv->dio.intr.asic;
1025		if (asic < 0)
1026			return 1;	/* not an interrupt
1027					   subdev */
1028		subpriv->dio.intr.enabled_mask = 0;
1029		subpriv->dio.intr.active = 1;
1030		nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
1031		firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
1032		if (cmd->chanlist) {
1033			for (n = 0; n < cmd->chanlist_len; n++) {
1034				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
1035				pol_bits |= (CR_AREF(cmd->chanlist[n])
1036					     || CR_RANGE(cmd->
1037							 chanlist[n]) ? 1U : 0U)
1038				    << CR_CHAN(cmd->chanlist[n]);
1039			}
1040		}
1041		bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
1042			 1) << subpriv->dio.intr.first_chan;
1043		subpriv->dio.intr.enabled_mask = bits;
1044
1045		{
1046			/*
1047			 * the below code configures the board
1048			 * to use a specific IRQ from 0-15.
1049			 */
1050			unsigned char b;
1051			/*
1052			 * set resource enable register
1053			 * to enable IRQ operation
1054			 */
1055			outb(1 << 4, dev->iobase + 3);
1056			/* set bits 0-3 of b to the irq number from 0-15 */
1057			b = dev->irq & ((1 << 4) - 1);
1058			outb(b, dev->iobase + 2);
1059			/* done, we told the board what irq to use */
1060		}
1061
1062		switch_page(dev, asic, PAGE_ENAB);
1063		for (port = firstport; port < firstport + nports; ++port) {
1064			unsigned enab =
1065			    bits >> (subpriv->dio.intr.first_chan + (port -
1066								     firstport)
1067				     * 8) & 0xff, pol =
1068			    pol_bits >> (subpriv->dio.intr.first_chan +
1069					 (port - firstport) * 8) & 0xff;
1070			/* set enab intrs for this subdev.. */
1071			outb(enab,
1072			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
1073			switch_page(dev, asic, PAGE_POL);
1074			outb(pol,
1075			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
1076		}
1077	}
1078	return 0;
1079}
1080
1081static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1082{
1083	unsigned long flags;
1084
1085	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1086	if (subpriv->dio.intr.active)
1087		pcmmio_stop_intr(dev, s);
1088	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1089
1090	return 0;
1091}
1092
1093/*
1094 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1095 */
1096static int
1097pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
1098			  unsigned int trignum)
1099{
1100	unsigned long flags;
1101	int event = 0;
1102
1103	if (trignum != 0)
1104		return -EINVAL;
1105
1106	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1107	s->async->inttrig = 0;
1108	if (subpriv->dio.intr.active)
1109		event = pcmmio_start_intr(dev, s);
1110	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1111
1112	if (event)
1113		comedi_event(dev, s);
1114
1115	return 1;
1116}
1117
1118/*
1119 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1120 */
1121static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1122{
1123	struct comedi_cmd *cmd = &s->async->cmd;
1124	unsigned long flags;
1125	int event = 0;
1126
1127	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1128	subpriv->dio.intr.active = 1;
1129
1130	/* Set up end of acquisition. */
1131	switch (cmd->stop_src) {
1132	case TRIG_COUNT:
1133		subpriv->dio.intr.continuous = 0;
1134		subpriv->dio.intr.stop_count = cmd->stop_arg;
1135		break;
1136	default:
1137		/* TRIG_NONE */
1138		subpriv->dio.intr.continuous = 1;
1139		subpriv->dio.intr.stop_count = 0;
1140		break;
1141	}
1142
1143	/* Set up start of acquisition. */
1144	switch (cmd->start_src) {
1145	case TRIG_INT:
1146		s->async->inttrig = pcmmio_inttrig_start_intr;
1147		break;
1148	default:
1149		/* TRIG_NOW */
1150		event = pcmmio_start_intr(dev, s);
1151		break;
1152	}
1153	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1154
1155	if (event)
1156		comedi_event(dev, s);
1157
1158	return 0;
1159}
1160
1161static int
1162pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1163	       struct comedi_cmd *cmd)
1164{
1165	return comedi_pcm_cmdtest(dev, s, cmd);
1166}
1167
1168static int adc_wait_ready(unsigned long iobase)
1169{
1170	unsigned long retry = 100000;
1171	while (retry--)
1172		if (inb(iobase + 3) & 0x80)
1173			return 0;
1174	return 1;
1175}
1176
1177/* All this is for AI and AO */
1178static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1179		    struct comedi_insn *insn, unsigned int *data)
1180{
1181	int n;
1182	unsigned long iobase = subpriv->iobase;
1183
1184	/*
1185	   1. write the CMD byte (to BASE+2)
1186	   2. read junk lo byte (BASE+0)
1187	   3. read junk hi byte (BASE+1)
1188	   4. (mux settled so) write CMD byte again (BASE+2)
1189	   5. read valid lo byte(BASE+0)
1190	   6. read valid hi byte(BASE+1)
1191
1192	   Additionally note that the BASE += 4 if the channel >= 8
1193	 */
1194
1195	/* convert n samples */
1196	for (n = 0; n < insn->n; n++) {
1197		unsigned chan = CR_CHAN(insn->chanspec), range =
1198		    CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
1199		unsigned char command_byte = 0;
1200		unsigned iooffset = 0;
1201		short sample, adc_adjust = 0;
1202
1203		if (chan > 7)
1204			chan -= 8, iooffset = 4;	/*
1205							 * use the second dword
1206							 * for channels > 7
1207							 */
1208
1209		if (aref != AREF_DIFF) {
1210			aref = AREF_GROUND;
1211			command_byte |= 1 << 7;	/*
1212						 * set bit 7 to indicate
1213						 * single-ended
1214						 */
1215		}
1216		if (range < 2)
1217			adc_adjust = 0x8000;	/*
1218						 * bipolar ranges
1219						 * (-5,5 .. -10,10 need to be
1220						 * adjusted -- that is.. they
1221						 * need to wrap around by
1222						 * adding 0x8000
1223						 */
1224
1225		if (chan % 2) {
1226			command_byte |= 1 << 6;	/*
1227						 * odd-numbered channels
1228						 * have bit 6 set
1229						 */
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		/* chan/range/aref select */
1240		outb(command_byte, iobase + iooffset + 2);
1241
1242		/* wait for the adc to say it finised the conversion */
1243		adc_wait_ready(iobase + iooffset);
1244
1245		/* select the chan/range/aref AGAIN */
1246		outb(command_byte, iobase + iooffset + 2);
1247
1248		adc_wait_ready(iobase + iooffset);
1249
1250		/* read data lo byte */
1251		sample = inb(iobase + iooffset + 0);
1252
1253		/* read data hi byte */
1254		sample |= inb(iobase + iooffset + 1) << 8;
1255		sample += adc_adjust;	/* adjustment .. munge data */
1256		data[n] = sample;
1257	}
1258	/* return the number of samples read/written */
1259	return n;
1260}
1261
1262static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1263		    struct comedi_insn *insn, unsigned int *data)
1264{
1265	int n;
1266	for (n = 0; n < insn->n; n++) {
1267		unsigned chan = CR_CHAN(insn->chanspec);
1268		if (chan < s->n_chan)
1269			data[n] = subpriv->ao.shadow_samples[chan];
1270	}
1271	return n;
1272}
1273
1274static int wait_dac_ready(unsigned long iobase)
1275{
1276	unsigned long retry = 100000L;
1277
1278	/* This may seem like an absurd way to handle waiting and violates the
1279	   "no busy waiting" policy. The fact is that the hardware is
1280	   normally so fast that we usually only need one time through the loop
1281	   anyway. The longer timeout is for rare occasions and for detecting
1282	   non-existant hardware.  */
1283
1284	while (retry--) {
1285		if (inb(iobase + 3) & 0x80)
1286			return 0;
1287
1288	}
1289	return 1;
1290}
1291
1292static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1293		    struct comedi_insn *insn, unsigned int *data)
1294{
1295	int n;
1296	unsigned iobase = subpriv->iobase, iooffset = 0;
1297
1298	for (n = 0; n < insn->n; n++) {
1299		unsigned chan = CR_CHAN(insn->chanspec), range =
1300		    CR_RANGE(insn->chanspec);
1301		if (chan < s->n_chan) {
1302			unsigned char command_byte = 0, range_byte =
1303			    range & ((1 << 4) - 1);
1304			if (chan >= 4)
1305				chan -= 4, iooffset += 4;
1306			/* set the range.. */
1307			outb(range_byte, iobase + iooffset + 0);
1308			outb(0, iobase + iooffset + 1);
1309
1310			/* tell it to begin */
1311			command_byte = (chan << 1) | 0x60;
1312			outb(command_byte, iobase + iooffset + 2);
1313
1314			wait_dac_ready(iobase + iooffset);
1315
1316			/* low order byte */
1317			outb(data[n] & 0xff, iobase + iooffset + 0);
1318
1319			/* high order byte */
1320			outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
1321
1322			/*
1323			 * set bit 4 of command byte to indicate
1324			 * data is loaded and trigger conversion
1325			 */
1326			command_byte = 0x70 | (chan << 1);
1327			/* trigger converion */
1328			outb(command_byte, iobase + iooffset + 2);
1329
1330			wait_dac_ready(iobase + iooffset);
1331
1332			/* save to shadow register for ao_rinsn */
1333			subpriv->ao.shadow_samples[chan] = data[n];
1334		}
1335	}
1336	return n;
1337}
1338
1339/*
1340 * A convenient macro that defines init_module() and cleanup_module(),
1341 * as necessary.
1342 */
1343static int __init driver_init_module(void)
1344{
1345	return comedi_driver_register(&driver);
1346}
1347
1348static void __exit driver_cleanup_module(void)
1349{
1350	comedi_driver_unregister(&driver);
1351}
1352
1353module_init(driver_init_module);
1354module_exit(driver_cleanup_module);
1355
1356MODULE_AUTHOR("Comedi http://www.comedi.org");
1357MODULE_DESCRIPTION("Comedi low-level driver");
1358MODULE_LICENSE("GPL");
1359