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