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