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