Got rid of unnecessary casts when initializing comedi_driver.board_name
[comedi.git] / comedi / drivers / pcmuio.c
1 /*
2     comedi/drivers/pcmuio.c
3     Driver for Winsystems PC-104 based 48-channel and 96-channel DIO boards.
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2006 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: pcmuio.o
24 Description: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems.
25 Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A
26 Author: Calin Culianu <calin@ajvar.org>
27 Updated: Fri, 13 Jan 2006 12:01:01 -0500
28 Status: works
29
30 A driver for the relatively straightforward-to-program PCM-UIO48A and
31 PCM-UIO96A boards from Winsystems.  These boards use either one or two
32 (in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO).
33 This chip is interesting in that each I/O line is individually
34 programmable for INPUT or OUTPUT (thus comedi_dio_config can be done
35 on a per-channel basis).  Also, each chip supports edge-triggered
36 interrupts for the first 24 I/O lines.  Of course, since the
37 96-channel version of the board has two ASICs, it can detect polarity
38 changes on up to 48 I/O lines.  Since this is essentially an (non-PnP)
39 ISA board, I/O Address and IRQ selection are done through jumpers on
40 the board.  You need to pass that information to this driver as the
41 first and second comedi_config option, respectively.  Note that the
42 48-channel version uses 16 bytes of IO memory and the 96-channel
43 version uses 32-bytes (in case you are worried about conflicts).  The
44 48-channel board is split into two 24-channel comedi subdevices.
45 The 96-channel board is split into 4 24-channel DIO subdevices.
46
47 Note that IRQ support has been added, but it is untested.
48
49 To use edge-detection IRQ support, pass the IRQs of both ASICS
50 (for the 96 channel version) or just 1 ASIC (for 48-channel version).
51 Then, use use comedi_commands with TRIG_NOW.
52 Your callback will be called each time an edge is triggered, and the data
53 values will be two sample_t's, which should be concatenated to form one
54 32-bit unsigned int.  This value is the mask of channels that had
55 edges detected from your channel list.  Note that the bits positions
56 in the mask correspond to positions in your chanlist when you specified
57 the command and *not* channel id's!
58
59 To set the polarity of the edge-detection interrupts pass a nonzero value for
60 either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both
61 CR_RANGE and CR_AREF if you want edge-down polarity.
62
63 In the 48-channel version:
64
65 On subdev 0, the first 24 channels channels are edge-detect channels.
66
67 In the 96-channel board you have the collowing channels that can do edge detection:
68
69 subdev 0, channels 0-24  (first 24 channels of 1st ASIC)
70 subdev 2, channels 0-24  (first 24 channels of 2nd ASIC)
71
72 Configuration Options:
73   [0] - I/O port base address
74   [1] - IRQ (for first ASIC, or first 24 channels)
75   [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!)
76 */
77
78
79 #include <linux/comedidev.h>
80
81 #include <linux/pci.h> /* for PCI devices */
82
83 #define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
84 #define CHANS_PER_PORT   8
85 #define PORTS_PER_ASIC   6
86 #define INTR_PORTS_PER_ASIC   3
87 #define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
88 #define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
89 #define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
90 #define INTR_CHANS_PER_ASIC 24
91 #define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
92 #define MAX_DIO_CHANS   (PORTS_PER_ASIC*2*CHANS_PER_PORT)
93 #define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
94 #define SDEV_NO ((int)(s - dev->subdevices))
95 #define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
96 /* IO Memory sizes */
97 #define ASIC_IOSIZE (0x10)
98 #define PCMUIO48_IOSIZE ASIC_IOSIZE
99 #define PCMUIO96_IOSIZE (ASIC_IOSIZE*2)
100
101 /* Some offsets - these are all in the 16byte IO memory offset from
102    the base address.  Note that there is a paging scheme to swap out
103    offsets 0x8-0xA using the PAGELOCK register.  See the table below.
104
105   Register(s)       Pages        R/W?        Description
106   --------------------------------------------------------------
107   REG_PORTx         All          R/W         Read/Write/Configure IO
108   REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
109   REG_PAGELOCK      All          WriteOnly   Select a page
110   REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
111   REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
112   REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
113  */
114 #define REG_PORT0 0x0
115 #define REG_PORT1 0x1
116 #define REG_PORT2 0x2
117 #define REG_PORT3 0x3
118 #define REG_PORT4 0x4
119 #define REG_PORT5 0x5
120 #define REG_INT_PENDING 0x6
121 #define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page
122                             and bits 0-5 are used to 'lock down' a particular
123                             port above to make it readonly.  */
124 #define REG_POL0 0x8
125 #define REG_POL1 0x9
126 #define REG_POL2 0xA
127 #define REG_ENAB0 0x8
128 #define REG_ENAB1 0x9
129 #define REG_ENAB2 0xA
130 #define REG_INT_ID0 0x8
131 #define REG_INT_ID1 0x9
132 #define REG_INT_ID2 0xA
133
134 #define NUM_PAGED_REGS 3
135 #define NUM_PAGES 4
136 #define FIRST_PAGED_REG 0x8
137 #define REG_PAGE_BITOFFSET 6
138 #define REG_LOCK_BITOFFSET 0
139 #define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
140 #define REG_LOCK_MASK ~(REG_PAGE_MASK)
141 #define PAGE_POL 1
142 #define PAGE_ENAB 2
143 #define PAGE_INT_ID 3
144
145 /*
146  * Board descriptions for two imaginary boards.  Describing the
147  * boards in this way is optional, and completely driver-dependent.
148  * Some drivers use arrays such as this, other do not.
149  */
150 typedef struct pcmuio_board_struct
151 {
152         const char * const name;
153         const int num_asics;
154         const int num_channels_per_port;
155         const int num_ports;
156 } pcmuio_board;
157
158 static pcmuio_board pcmuio_boards[] =
159 {
160         {
161                 name:                   "pcmuio48",
162                 num_asics:              1,
163                 num_ports:              6,
164         },
165         {
166                 name:           "pcmuio96",
167                 num_asics:              2,
168                 num_ports:              12,
169         },
170 };
171
172 /*
173  * Useful for shorthand access to the particular board structure
174  */
175 #define thisboard ((pcmuio_board *)dev->board_ptr)
176
177 /* this structure is for data unique to this subdevice.  */
178 typedef struct
179 {
180     /* mapping of halfwords (bytes) in port/chanarray to iobase */
181     unsigned long iobases[PORTS_PER_SUBDEV];
182
183     /* The below is only used for intr subdevices */
184     struct {
185       int asic; /* if non-negative, this subdev has an interrupt asic */
186       int first_chan; /* if nonnegative, the first channel id for
187                          interrupts. */
188       int num_asic_chans; /* the number of asic channels in this subdev
189                              that have interrutps */
190       int asic_chan; /* if nonnegative, the first channel id with
191                         respect to the asic that has interrupts */
192       int enabled_mask; /* subdev-relative channel mask for channels
193                            we are interested in */
194       int active;
195       int stop_count;
196       int continuous;
197       spinlock_t spinlock;
198     } intr;
199 } pcmuio_subdev_private;
200
201 /* this structure is for data unique to this hardware driver.  If
202    several hardware drivers keep similar information in this structure,
203    feel free to suggest moving the variable to the comedi_device struct.  */
204 typedef struct
205 {
206   struct
207   {
208     unsigned char pagelock; /* current page and lock*/
209     unsigned char pol [NUM_PAGED_REGS]; /* shadow of POLx registers */
210     unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */
211     int num;
212     unsigned long iobase;
213     unsigned int irq;
214     spinlock_t spinlock;
215   } asics[MAX_ASICS];
216   pcmuio_subdev_private *sprivs;
217 } pcmuio_private;
218
219 /*
220  * most drivers define the following macro to make it easy to
221  * access the private structure.
222  */
223 #define devpriv ((pcmuio_private *)dev->private)
224 #define subpriv ((pcmuio_subdev_private *)s->private)
225 /*
226  * The comedi_driver structure tells the Comedi core module
227  * which functions to call to configure/deconfigure (attach/detach)
228  * the board, and also about the kernel module that contains
229  * the device code.
230  */
231 static int pcmuio_attach(comedi_device *dev, comedi_devconfig *it);
232 static int pcmuio_detach(comedi_device *dev);
233
234 static comedi_driver driver =
235 {
236         driver_name:    "pcmuio",
237         module:         THIS_MODULE,
238         attach:         pcmuio_attach,
239         detach:         pcmuio_detach,
240 /* It is not necessary to implement the following members if you are
241  * writing a driver for a ISA PnP or PCI card */
242         /* Most drivers will support multiple types of boards by
243          * having an array of board structures.  These were defined
244          * in pcmuio_boards[] above.  Note that the element 'name'
245          * was first in the structure -- Comedi uses this fact to
246          * extract the name of the board without knowing any details
247          * about the structure except for its length.
248          * When a device is attached (by comedi_config), the name
249          * of the device is given to Comedi, and Comedi tries to
250          * match it by going through the list of board names.  If
251          * there is a match, the address of the pointer is put
252          * into dev->board_ptr and driver->attach() is called.
253          *
254          * Note that these are not necessary if you can determine
255          * the type of board in software.  ISA PnP, PCI, and PCMCIA
256          * devices are such boards.
257          */
258         board_name:     &pcmuio_boards[0].name,
259         offset:         sizeof(pcmuio_board),
260         num_names:      sizeof(pcmuio_boards) / sizeof(pcmuio_board),
261 };
262
263 static int pcmuio_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,
264                                 comedi_insn *insn,lsampl_t *data);
265 static int pcmuio_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
266                                   comedi_insn *insn,lsampl_t *data);
267
268 static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG);
269 static void pcmuio_stop_intr(comedi_device *, comedi_subdevice *);
270 static int  pcmuio_cancel(comedi_device *dev, comedi_subdevice *s);
271 static int pcmuio_cmd(comedi_device *dev, comedi_subdevice *s);
272 static int pcmuio_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd);
273
274 /* some helper functions to deal with specifics of this device's registers */
275 static void init_asics(comedi_device *dev); /* sets up/clears ASIC chips to defaults */
276 static void switch_page(comedi_device *dev, int asic, int page);
277 static void lock_port(comedi_device *dev, int asic, int port);
278 static void unlock_port(comedi_device *dev, int asic, int port);
279
280 /*
281  * Attach is called by the Comedi core to configure the driver
282  * for a particular board.  If you specified a board_name array
283  * in the driver structure, dev->board_ptr contains that
284  * address.
285  */
286 static int pcmuio_attach(comedi_device *dev, comedi_devconfig *it)
287 {
288         comedi_subdevice *s;
289         int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
290         unsigned long iobase;
291         unsigned int irq[MAX_ASICS];
292
293     iobase = it->options[0];
294     irq[0] = it->options[1];
295     irq[1] = it->options[2];
296
297     printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name, iobase);
298
299     dev->iobase = iobase;
300
301     if ( !iobase || !request_region(iobase,
302                                     thisboard->num_asics*ASIC_IOSIZE,
303                                     driver.driver_name) ) {
304       printk("I/O port conflict\n");
305       return -EIO;
306     }
307
308 /*
309  * Initialize dev->board_name.  Note that we can use the "thisboard"
310  * macro now, since we just initialized it in the last line.
311  */
312     dev->board_name = thisboard->name;
313
314 /*
315  * Allocate the private structure area.  alloc_private() is a
316  * convenient macro defined in comedidev.h.
317  */
318     if (alloc_private(dev,sizeof(pcmuio_private)) < 0) {
319       printk("cannot allocate private data structure\n");
320       return -ENOMEM;
321     }
322
323     for (asic = 0; asic < MAX_ASICS; ++asic) {
324       devpriv->asics[asic].num = asic;
325       devpriv->asics[asic].iobase = dev->iobase + asic*ASIC_IOSIZE;
326       devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
327                                        this function when we
328                                        comedi_request_irqs */
329       spin_lock_init(&devpriv->asics[asic].spinlock);
330     }
331
332     chans_left = CHANS_PER_ASIC * thisboard->num_asics;
333     n_subdevs = CALC_N_SUBDEVS(chans_left);
334     devpriv->sprivs = (pcmuio_subdev_private *)kmalloc(sizeof(pcmuio_subdev_private) * n_subdevs, GFP_KERNEL);
335     if (!devpriv->sprivs) {
336         printk("cannot allocate subdevice private data structures\n");
337         return -ENOMEM;
338     }
339     memset(devpriv->sprivs, 0, sizeof(pcmuio_subdev_private) * n_subdevs);
340       /*
341        * Allocate the subdevice structures.  alloc_subdevice() is a
342        * convenient macro defined in comedidev.h.
343        *
344        * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
345        * 96-channel version of the board.
346        */
347     if ( alloc_subdevices(dev, n_subdevs ) < 0 ) {
348         printk("cannot allocate subdevice data structures\n");
349         return -ENOMEM;
350     }
351
352     memset(dev->subdevices, 0, sizeof(*dev->subdevices) * n_subdevs);
353
354     port = 0;
355     asic = 0;
356     for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no)
357     {
358       int byte_no;
359
360       s = dev->subdevices + sdev_no;
361       s->private = devpriv->sprivs + sdev_no;
362       s->maxdata = 1;
363       s->range_table = &range_digital;
364       s->subdev_flags = SDF_READABLE|SDF_WRITABLE;
365       s->type = COMEDI_SUBD_DIO;
366       s->insn_bits = pcmuio_dio_insn_bits;
367       s->insn_config = pcmuio_dio_insn_config;
368       s->n_chan = MIN(chans_left, MAX_CHANS_PER_SUBDEV);
369       subpriv->intr.asic = -1;
370       subpriv->intr.first_chan = -1;
371       subpriv->intr.asic_chan = -1;
372       subpriv->intr.num_asic_chans = -1;
373       subpriv->intr.active = 0;
374       s->len_chanlist = 1;
375
376       /* save the ioport address for each 'port' of 8 channels in the
377          subdevice */
378       for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
379           if (port >= PORTS_PER_ASIC) {
380             port = 0;
381             ++asic;
382             thisasic_chanct = 0;
383           }
384           subpriv->iobases[byte_no] = devpriv->asics[asic].iobase + port;
385
386           if (thisasic_chanct < CHANS_PER_PORT*INTR_PORTS_PER_ASIC
387               && subpriv->intr.asic < 0) {
388             /* this is an interrupt subdevice, so setup the struct */
389             subpriv->intr.asic = asic;
390             subpriv->intr.active = 0;
391             subpriv->intr.stop_count = 0;
392             subpriv->intr.first_chan = byte_no * 8;
393             subpriv->intr.asic_chan = thisasic_chanct;
394             subpriv->intr.num_asic_chans = s->n_chan - subpriv->intr.first_chan;
395             dev->read_subdev = s;
396             s->subdev_flags |= SDF_CMD_READ;
397             s->cancel = pcmuio_cancel;
398             s->do_cmd = pcmuio_cmd;
399             s->do_cmdtest = pcmuio_cmdtest;
400             s->len_chanlist = subpriv->intr.num_asic_chans;
401           }
402           thisasic_chanct += CHANS_PER_PORT;
403       }
404       spin_lock_init(&subpriv->intr.spinlock);
405
406       chans_left -= s->n_chan;
407
408       if (!chans_left) {
409         asic = 0; /* reset the asic to our first asic, to do intr subdevs */
410         port = 0;
411       }
412
413     }
414
415     init_asics(dev); /* clear out all the registers, basically */
416
417     for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
418       if (irq[asic] && comedi_request_irq(irq[asic], interrupt_pcmuio, IRQF_SHARED, thisboard->name, dev)) {
419         int i;
420         /* unroll the allocated irqs.. */
421         for (i = asic-1; i >= 0; --i) {
422           comedi_free_irq(irq[i], dev);
423           devpriv->asics[i].irq = irq[i] = 0;
424         }
425         irq[asic] = 0;
426       }
427       devpriv->asics[asic].irq = irq[asic];
428     }
429
430     dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
431                           irqs.. */
432
433     if (irq[0]) {
434       printk("irq: %u ", irq[0]);
435       if (irq[1] && thisboard->num_asics == 2)
436         printk("second ASIC irq: %u ", irq[1]);
437     } else {
438       printk("(IRQ mode disabled) ");
439     }
440
441     printk("attached\n");
442
443     return 1;
444 }
445
446
447 /*
448  * _detach is called to deconfigure a device.  It should deallocate
449  * resources.
450  * This function is also called when _attach() fails, so it should be
451  * careful not to release resources that were not necessarily
452  * allocated by _attach().  dev->private and dev->subdevices are
453  * deallocated automatically by the core.
454  */
455 static int pcmuio_detach(comedi_device *dev)
456 {
457     int i;
458
459     printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
460     if (dev->iobase)
461       release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
462
463     for (i = 0; i < MAX_ASICS; ++i) {
464       if (devpriv->asics[i].irq)
465         comedi_free_irq(devpriv->asics[i].irq, dev);
466     }
467
468     if (devpriv && devpriv->sprivs)
469       kfree(devpriv->sprivs);
470
471     return 0;
472 }
473
474
475 /* DIO devices are slightly special.  Although it is possible to
476  * implement the insn_read/insn_write interface, it is much more
477  * useful to applications if you implement the insn_bits interface.
478  * This allows packed reading/writing of the DIO channels.  The
479  * comedi core can convert between insn_bits and insn_read/write */
480 static int pcmuio_dio_insn_bits(comedi_device *dev, comedi_subdevice *s,
481                                 comedi_insn *insn, lsampl_t *data)
482 {
483     int byte_no;
484     if (insn->n != 2) return -EINVAL;
485
486      /* NOTE:
487         reading a 0 means this channel was high
488         writine a 0 sets the channel high
489         reading a 1 means this channel was low
490         writing a 1 means set this channel low
491
492         Therefore everything is always inverted. */
493
494         /* The insn data is a mask in data[0] and the new data
495          * in data[1], each channel cooresponding to a bit. */
496
497 #ifdef DAMMIT_ITS_BROKEN
498         /* DEBUG */
499     printk("write mask: %08x  data: %08x\n", data[0], data[1]);
500 #endif
501
502     s->state = 0;
503
504     for (byte_no = 0; byte_no < s->n_chan/CHANS_PER_PORT; ++byte_no) {
505            /* address of 8-bit port */
506         unsigned long ioaddr = subpriv->iobases[byte_no],
507            /* bit offset of port in 32-bit doubleword */
508             offset = byte_no * 8;
509                       /* this 8-bit port's data */
510         unsigned char byte = 0,
511                       /* The write mask for this port (if any) */
512                       write_mask_byte = (data[0] >> offset) & 0xff,
513                       /* The data byte for this port */
514                       data_byte = (data[1] >> offset) & 0xff;
515
516         byte = inb(ioaddr); /* read all 8-bits for this port */
517
518 #ifdef DAMMIT_ITS_BROKEN
519         /* DEBUG */
520         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);
521 #endif
522
523         if ( write_mask_byte ) {
524           /* this byte has some write_bits -- so set the output lines */
525           byte &= ~write_mask_byte; /* clear bits for write mask */
526           byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */
527           /* Write out the new digital output state */
528           outb(byte, ioaddr);
529         }
530
531 #ifdef DAMMIT_ITS_BROKEN
532         /* DEBUG */
533         printk("data_out_byte %02x\n", (unsigned)byte);
534 #endif
535         /* save the digital input lines for this byte.. */
536         s->state |= ((unsigned int)byte) << offset;
537     }
538
539     /* now return the DIO lines to data[1] - note they came inverted! */
540     data[1] = ~s->state;
541
542 #ifdef DAMMIT_ITS_BROKEN
543     /* DEBUG */
544     printk("s->state %08x data_out %08x\n", s->state, data[1]);
545 #endif
546
547     return 2;
548 }
549
550 /* The input or output configuration of each digital line is
551  * configured by a special insn_config instruction.  chanspec
552  * contains the channel to be changed, and data[0] contains the
553  * value COMEDI_INPUT or COMEDI_OUTPUT. */
554 static int pcmuio_dio_insn_config(comedi_device *dev, comedi_subdevice *s,
555                                   comedi_insn *insn, lsampl_t *data)
556 {
557     int chan = CR_CHAN(insn->chanspec), byte_no = chan/8, bit_no = chan % 8;
558     unsigned long ioaddr;
559     unsigned char byte;
560
561     /* Compute ioaddr for this channel */
562     ioaddr = subpriv->iobases[byte_no];
563
564      /* NOTE:
565         writing a 0 an IO channel's bit sets the channel to INPUT
566         and pulls the line high as well
567
568         writing a 1 to an IO channel's  bit pulls the line low
569
570         All channels are implicitly always in OUTPUT mode -- but when
571         they are high they can be considered to be in INPUT mode..
572
573         Thus, we only force channels low if the config request was INPUT,
574         otherwise we do nothing to the hardware.    */
575
576         switch(data[0])
577         {
578         case INSN_CONFIG_DIO_OUTPUT:
579           /* save to io_bits -- don't actually do anything since
580              all input channels are also output channels... */
581           s->io_bits |= 1<<chan;
582           break;
583         case INSN_CONFIG_DIO_INPUT:
584           /* write a 0 to the actual register representing the channel
585              to set it to 'input'.  0 means "float high". */
586           byte = inb(ioaddr);
587           byte &= ~(1<<bit_no); /**< set input channel to '0' */
588
589           /* write out byte -- this is the only time we actually affect the
590              hardware as all channels are implicitly output -- but input
591              channels are set to float-high */
592           outb(byte, ioaddr);
593
594           /* save to io_bits */
595           s->io_bits &= ~(1<<chan);
596           break;
597
598         case INSN_CONFIG_DIO_QUERY:
599           /* retreive from shadow register */
600           data[1] = (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
601           return insn->n;
602           break;
603
604         default:
605           return -EINVAL;
606           break;
607         }
608
609         return insn->n;
610 }
611
612 static void init_asics(comedi_device *dev) /* sets up an
613                                               ASIC chip to defaults */
614 {
615   int asic;
616
617   for (asic = 0; asic < thisboard->num_asics; ++asic)
618   {
619     int port, page;
620     unsigned long baseaddr = dev->iobase + asic*ASIC_IOSIZE;
621
622     switch_page(dev, asic,  0); /* switch back to page 0 */
623
624     /* first, clear all the DIO port bits */
625     for (port = 0; port < PORTS_PER_ASIC; ++port)
626       outb(0, baseaddr + REG_PORT0 + port);
627
628     /* Next, clear all the paged registers for each page */
629     for (page = 1; page < NUM_PAGES; ++page)
630     {
631       int reg;
632       /* now clear all the paged registers*/
633       switch_page(dev, asic, page);
634       for (reg = FIRST_PAGED_REG; reg < FIRST_PAGED_REG+NUM_PAGED_REGS; ++reg)
635         outb(0, baseaddr + reg);
636     }
637
638     /* DEBUG  set rising edge interrupts on port0 of both asics*/
639     /*switch_page(dev, asic, PAGE_POL);
640       outb(0xff, baseaddr + REG_POL0);
641       switch_page(dev, asic, PAGE_ENAB);
642       outb(0xff, baseaddr + REG_ENAB0);*/
643     /* END DEBUG */
644
645     switch_page(dev, asic,  0); /* switch back to default page 0 */
646
647   }
648 }
649
650
651 static void switch_page(comedi_device *dev, int asic, int page)
652 {
653   if (asic < 0 || asic >= thisboard->num_asics) return; /* paranoia */
654   if (page < 0 || page >= NUM_PAGES) return; /* more paranoia */
655
656   devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
657   devpriv->asics[asic].pagelock |= page<<REG_PAGE_BITOFFSET;
658
659   /* now write out the shadow register */
660   outb(devpriv->asics[asic].pagelock,
661        dev->iobase + ASIC_IOSIZE*asic + REG_PAGELOCK);
662 }
663
664 static void lock_port(comedi_device *dev, int asic, int port)
665 {
666   if (asic < 0 || asic >= thisboard->num_asics) return; /* paranoia */
667   if (port < 0 || port >= PORTS_PER_ASIC) return; /* more paranoia */
668
669   devpriv->asics[asic].pagelock |= 0x1<<port;
670   /* now write out the shadow register */
671   outb(devpriv->asics[asic].pagelock, dev->iobase + ASIC_IOSIZE*asic + REG_PAGELOCK);
672   return;
673   (void)lock_port(dev, asic, port); /* not reached, suppress compiler warnings*/
674 }
675
676 static void unlock_port(comedi_device *dev, int asic, int port)
677 {
678   if (asic < 0 || asic >= thisboard->num_asics) return; /* paranoia */
679   if (port < 0 || port >= PORTS_PER_ASIC) return; /* more paranoia */
680   devpriv->asics[asic].pagelock &= ~(0x1<<port) | REG_LOCK_MASK;
681   /* now write out the shadow register */
682   outb(devpriv->asics[asic].pagelock, dev->iobase + ASIC_IOSIZE*asic + REG_PAGELOCK);
683   (void)unlock_port(dev, asic, port); /* not reached, suppress compiler warnings*/
684 }
685
686 static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG)
687 {
688   int asic, got1 = 0;
689   comedi_device *dev = (comedi_device *)d;
690
691   for (asic = 0; asic < MAX_ASICS; ++asic) {
692     if (irq == devpriv->asics[asic].irq) {
693       unsigned long flags;
694       unsigned triggered = 0;
695       unsigned long iobase = devpriv->asics[asic].iobase;
696       /* it is an interrupt for ASIC #asic */
697       unsigned char int_pend;
698
699       comedi_spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
700
701       int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
702
703       if (int_pend) {
704         int port;
705         for (port = 0; port < INTR_PORTS_PER_ASIC; ++port) {
706           if (int_pend & (0x1<<port)) {
707             unsigned char io_lines_with_edges = 0;
708             switch_page(dev, asic, PAGE_INT_ID);
709             io_lines_with_edges = inb(iobase + REG_INT_ID0 + port);
710
711             if (io_lines_with_edges)
712               /* clear pending interrupt */
713               outb(0, iobase + REG_INT_ID0 + port);
714
715             triggered |= io_lines_with_edges << port*8;
716           }
717         }
718
719         ++got1;
720       }
721
722       comedi_spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags);
723
724       if (triggered) {
725         comedi_subdevice *s;
726         /* TODO here: dispatch io lines to subdevs with commands.. */
727         printk("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered);
728         for (s = dev->subdevices; s < dev->subdevices + dev->n_subdevices; ++s) {
729           if (subpriv->intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */
730             unsigned long flags;
731             unsigned oldevents;
732
733             comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
734
735             oldevents = s->async->events;
736
737             if (subpriv->intr.active) {
738               unsigned mytrig = ((triggered >> subpriv->intr.asic_chan) & ((0x1<<subpriv->intr.num_asic_chans)-1)) << subpriv->intr.first_chan;
739               if (mytrig & subpriv->intr.enabled_mask) {
740                 lsampl_t val = 0;
741                 unsigned int n, ch, len;
742
743                 len = s->async->cmd.chanlist_len;
744                 for (n = 0; n < len; n++) {
745                   ch = CR_CHAN(s->async->cmd.chanlist[n]);
746                   if (mytrig & (1U << ch)) {
747                     val |= (1U << n);
748                   }
749                 }
750                 /* Write the scan to the buffer. */
751                 if (comedi_buf_put(s->async, ((sampl_t *)&val)[0])
752                     && comedi_buf_put(s->async, ((sampl_t *)&val)[1]) ) {
753                   s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
754                 } else {
755                   /* Overflow! Stop acquisition!! */
756                   /* TODO: STOP_ACQUISITION_CALL_HERE!! */
757                   pcmuio_stop_intr(dev, s);
758                 }
759
760                 /* Check for end of acquisition. */
761                 if (!subpriv->intr.continuous) {
762                   /* stop_src == TRIG_COUNT */
763                   if (subpriv->intr.stop_count > 0) {
764                     subpriv->intr.stop_count--;
765                     if (subpriv->intr.stop_count == 0) {
766                       s->async->events |= COMEDI_CB_EOA;
767                       /* TODO: STOP_ACQUISITION_CALL_HERE!! */
768                       pcmuio_stop_intr(dev, s);
769                     }
770                   }
771                 }
772               }
773             }
774
775             comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
776
777             if (oldevents != s->async->events) {
778               comedi_event(dev, s, s->async->events);
779             }
780
781           }
782
783         }
784       }
785
786     }
787   }
788   if (!got1) return IRQ_NONE; /* interrupt from other source */
789   return IRQ_HANDLED;
790 }
791
792
793 static void pcmuio_stop_intr(comedi_device *dev, comedi_subdevice *s)
794 {
795   int nports, firstport, asic, port;
796
797   if ( (asic = subpriv->intr.asic) < 0 ) return; /* not an interrupt subdev */
798
799   subpriv->intr.enabled_mask = 0;
800   subpriv->intr.active = 0;
801   s->async->inttrig = 0;
802   nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
803   firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
804   switch_page(dev, asic, PAGE_ENAB);
805   for (port = firstport; port < firstport+nports; ++port) {
806     /* disable all intrs for this subdev.. */
807     outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
808   }
809 }
810
811 static int pcmuio_start_intr(comedi_device *dev, comedi_subdevice *s)
812 {
813   if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
814     /* An empty acquisition! */
815     s->async->events |= COMEDI_CB_EOA;
816     subpriv->intr.active = 0;
817     return 1;
818   } else {
819     unsigned bits = 0, pol_bits = 0, n;
820     int nports, firstport, asic, port;
821     comedi_cmd *cmd = &s->async->cmd;
822
823     if ( (asic = subpriv->intr.asic) < 0 ) return 1; /* not an interrupt
824                                                         subdev */
825     subpriv->intr.enabled_mask = 0;
826     subpriv->intr.active = 1;
827     nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
828     firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
829     if (cmd->chanlist) {
830       for (n = 0; n < cmd->chanlist_len; n++) {
831         bits |= (1U << CR_CHAN(cmd->chanlist[n]));
832         pol_bits |=
833           (CR_AREF(cmd->chanlist[n]) || CR_RANGE(cmd->chanlist[n]) ? 1U : 0U)
834             << CR_CHAN(cmd->chanlist[n]);
835       }
836     }
837     bits &=  ((0x1<<subpriv->intr.num_asic_chans)-1) << subpriv->intr.first_chan;
838     subpriv->intr.enabled_mask = bits;
839
840     switch_page(dev, asic, PAGE_ENAB);
841     for (port = firstport; port < firstport+nports; ++port) {
842       unsigned enab = bits >> (subpriv->intr.first_chan + (port-firstport)*8) & 0xff,
843                pol = pol_bits >> (subpriv->intr.first_chan + (port-firstport)*8) & 0xff ;
844       /* set enab intrs for this subdev.. */
845       outb(enab, devpriv->asics[asic].iobase + REG_ENAB0 + port);
846       switch_page(dev, asic, PAGE_POL);
847       outb(pol, devpriv->asics[asic].iobase + REG_ENAB0 + port);
848     }
849   }
850   return 0;
851 }
852
853 static int  pcmuio_cancel(comedi_device *dev, comedi_subdevice *s)
854 {
855   unsigned long flags;
856
857   comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
858   if (subpriv->intr.active)  pcmuio_stop_intr(dev, s);
859   comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
860
861   return 0;
862 }
863
864 /*
865  * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
866  */
867 static int
868 pcmuio_inttrig_start_intr(comedi_device *dev, comedi_subdevice *s, unsigned int trignum)
869 {
870         unsigned long flags;
871         int event = 0;
872
873         if (trignum != 0) return -EINVAL;
874
875         comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
876         s->async->inttrig = 0;
877         if (subpriv->intr.active) {
878                 event = pcmuio_start_intr(dev, s);
879         }
880         comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
881
882         if (event) {
883                 comedi_event(dev, s, s->async->events);
884         }
885
886         return 1;
887 }
888
889
890 /*
891  * 'do_cmd' function for an 'INTERRUPT' subdevice.
892  */
893 static int
894 pcmuio_cmd(comedi_device *dev, comedi_subdevice *s)
895 {
896         comedi_cmd *cmd = &s->async->cmd;
897         unsigned long flags;
898         int event = 0;
899
900         comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
901         subpriv->intr.active = 1;
902
903         /* Set up end of acquisition. */
904         switch (cmd->stop_src) {
905         case TRIG_COUNT:
906                 subpriv->intr.continuous = 0;
907                 subpriv->intr.stop_count = cmd->stop_arg;
908                 break;
909         default:
910                 /* TRIG_NONE */
911                 subpriv->intr.continuous = 1;
912                 subpriv->intr.stop_count = 0;
913                 break;
914         }
915
916         /* Set up start of acquisition. */
917         switch (cmd->start_src) {
918         case TRIG_INT:
919                 s->async->inttrig = pcmuio_inttrig_start_intr;
920                 break;
921         default:
922                 /* TRIG_NOW */
923                 event = pcmuio_start_intr(dev, s);
924                 break;
925         }
926         comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
927
928         if (event) {
929                 comedi_event(dev, s, s->async->events);
930         }
931
932         return 0;
933 }
934
935 /*
936  * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
937  */
938 static int
939 pcmuio_cmdtest(comedi_device *dev, comedi_subdevice *s,
940                comedi_cmd *cmd)
941 {
942         int err = 0;
943         unsigned int tmp;
944
945         /* step 1: make sure trigger sources are trivially valid */
946
947         tmp = cmd->start_src;
948         cmd->start_src &= (TRIG_NOW | TRIG_INT);
949         if (!cmd->start_src || tmp != cmd->start_src) err++;
950
951         tmp = cmd->scan_begin_src;
952         cmd->scan_begin_src &= TRIG_EXT;
953         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++;
954
955         tmp = cmd->convert_src;
956         cmd->convert_src &= TRIG_NOW;
957         if (!cmd->convert_src || tmp != cmd->convert_src) err++;
958
959         tmp = cmd->scan_end_src;
960         cmd->scan_end_src &= TRIG_COUNT;
961         if (!cmd->scan_end_src || tmp != cmd->scan_end_src) err++;
962
963         tmp = cmd->stop_src;
964         cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
965         if (!cmd->stop_src || tmp != cmd->stop_src) err++;
966
967         if (err) return 1;
968
969         /* step 2: make sure trigger sources are unique and mutually compatible */
970
971         /* these tests are true if more than one _src bit is set */
972         if ((cmd->start_src & (cmd->start_src - 1)) != 0) err++;
973         if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) err++;
974         if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) err++;
975         if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) err++;
976         if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) err++;
977
978         if (err) return 2;
979
980         /* step 3: make sure arguments are trivially compatible */
981
982         /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
983         if (cmd->start_arg != 0) {
984                 cmd->start_arg = 0;
985                 err++;
986         }
987
988         /* cmd->scan_begin_src == TRIG_EXT */
989         if (cmd->scan_begin_arg != 0) {
990                 cmd->scan_begin_arg = 0;
991                 err++;
992         }
993
994         /* cmd->convert_src == TRIG_NOW */
995         if (cmd->convert_arg != 0) {
996                 cmd->convert_arg = 0;
997                 err++;
998         }
999
1000         /* cmd->scan_end_src == TRIG_COUNT */
1001         if (cmd->scan_end_arg != cmd->chanlist_len) {
1002                 cmd->scan_end_arg = cmd->chanlist_len;
1003                 err++;
1004         }
1005
1006         switch (cmd->stop_src) {
1007         case TRIG_COUNT:
1008                 /* any count allowed */
1009                 break;
1010         case TRIG_NONE:
1011                 if (cmd->stop_arg != 0) {
1012                   cmd->stop_arg = 0;
1013                   err++;
1014                 }
1015                 break;
1016         default:
1017                 break;
1018         }
1019
1020         if (err) return 3;
1021
1022         /* step 4: fix up any arguments */
1023
1024         /* if (err) return 4; */
1025
1026         return 0;
1027 }
1028
1029 /*
1030  * A convenient macro that defines init_module() and cleanup_module(),
1031  * as necessary.
1032  */
1033 COMEDI_INITCLEANUP(driver);
1034
1035