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