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