Merge branch 'gart/fixes' into amd-iommu/2.6.33
[linux-2.6-block.git] / drivers / staging / 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
24 Description: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems.
25 Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96)
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 #include <linux/interrupt.h>
79 #include "../comedidev.h"
80 #include "pcm_common.h"
81
82 #include <linux/pci.h>          /* for PCI devices */
83
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 struct pcmuio_board {
151         const char *name;
152         const int num_asics;
153         const int num_channels_per_port;
154         const int num_ports;
155 };
156
157 static const struct pcmuio_board pcmuio_boards[] = {
158         {
159          .name = "pcmuio48",
160          .num_asics = 1,
161          .num_ports = 6,
162          },
163         {
164          .name = "pcmuio96",
165          .num_asics = 2,
166          .num_ports = 12,
167          },
168 };
169
170 /*
171  * Useful for shorthand access to the particular board structure
172  */
173 #define thisboard ((const struct pcmuio_board *)dev->board_ptr)
174
175 /* this structure is for data unique to this subdevice.  */
176 struct pcmuio_subdev_private {
177         /* mapping of halfwords (bytes) in port/chanarray to iobase */
178         unsigned long iobases[PORTS_PER_SUBDEV];
179
180         /* The below is only used for intr subdevices */
181         struct {
182                 int asic;       /* if non-negative, this subdev has an interrupt asic */
183                 int first_chan; /* if nonnegative, the first channel id for
184                                    interrupts. */
185                 int num_asic_chans;     /* the number of asic channels in this subdev
186                                            that have interrutps */
187                 int asic_chan;  /* if nonnegative, the first channel id with
188                                    respect to the asic that has interrupts */
189                 int enabled_mask;       /* subdev-relative channel mask for channels
190                                            we are interested in */
191                 int active;
192                 int stop_count;
193                 int continuous;
194                 spinlock_t spinlock;
195         } intr;
196 };
197
198 /* this structure is for data unique to this hardware driver.  If
199    several hardware drivers keep similar information in this structure,
200    feel free to suggest moving the variable to the struct comedi_device struct.  */
201 struct pcmuio_private {
202         struct {
203                 unsigned char pagelock; /* current page and lock */
204                 unsigned char pol[NUM_PAGED_REGS];      /* shadow of POLx registers */
205                 unsigned char enab[NUM_PAGED_REGS];     /* shadow of ENABx registers */
206                 int num;
207                 unsigned long iobase;
208                 unsigned int irq;
209                 spinlock_t spinlock;
210         } asics[MAX_ASICS];
211         struct pcmuio_subdev_private *sprivs;
212 };
213
214 /*
215  * most drivers define the following macro to make it easy to
216  * access the private structure.
217  */
218 #define devpriv ((struct pcmuio_private *)dev->private)
219 #define subpriv ((struct pcmuio_subdev_private *)s->private)
220 /*
221  * The struct comedi_driver structure tells the Comedi core module
222  * which functions to call to configure/deconfigure (attach/detach)
223  * the board, and also about the kernel module that contains
224  * the device code.
225  */
226 static int pcmuio_attach(struct comedi_device *dev,
227                          struct comedi_devconfig *it);
228 static int pcmuio_detach(struct comedi_device *dev);
229
230 static struct comedi_driver driver = {
231         .driver_name = "pcmuio",
232         .module = THIS_MODULE,
233         .attach = pcmuio_attach,
234         .detach = pcmuio_detach,
235 /* It is not necessary to implement the following members if you are
236  * writing a driver for a ISA PnP or PCI card */
237         /* Most drivers will support multiple types of boards by
238          * having an array of board structures.  These were defined
239          * in pcmuio_boards[] above.  Note that the element 'name'
240          * was first in the structure -- Comedi uses this fact to
241          * extract the name of the board without knowing any details
242          * about the structure except for its length.
243          * When a device is attached (by comedi_config), the name
244          * of the device is given to Comedi, and Comedi tries to
245          * match it by going through the list of board names.  If
246          * there is a match, the address of the pointer is put
247          * into dev->board_ptr and driver->attach() is called.
248          *
249          * Note that these are not necessary if you can determine
250          * the type of board in software.  ISA PnP, PCI, and PCMCIA
251          * devices are such boards.
252          */
253         .board_name = &pcmuio_boards[0].name,
254         .offset = sizeof(struct pcmuio_board),
255         .num_names = ARRAY_SIZE(pcmuio_boards),
256 };
257
258 static int pcmuio_dio_insn_bits(struct comedi_device *dev,
259                                 struct comedi_subdevice *s,
260                                 struct comedi_insn *insn, unsigned int *data);
261 static int pcmuio_dio_insn_config(struct comedi_device *dev,
262                                   struct comedi_subdevice *s,
263                                   struct comedi_insn *insn, unsigned int *data);
264
265 static irqreturn_t interrupt_pcmuio(int irq, void *d);
266 static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
267 static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
268 static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
269 static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
270                           struct comedi_cmd *cmd);
271
272 /* some helper functions to deal with specifics of this device's registers */
273 static void init_asics(struct comedi_device *dev);      /* sets up/clears ASIC chips to defaults */
274 static void switch_page(struct comedi_device *dev, int asic, int page);
275 #ifdef notused
276 static void lock_port(struct comedi_device *dev, int asic, int port);
277 static void unlock_port(struct comedi_device *dev, int asic, int port);
278 #endif
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(struct comedi_device *dev, struct comedi_devconfig *it)
287 {
288         struct 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,
298                iobase);
299
300         dev->iobase = iobase;
301
302         if (!iobase || !request_region(iobase,
303                                        thisboard->num_asics * ASIC_IOSIZE,
304                                        driver.driver_name)) {
305                 printk("I/O port conflict\n");
306                 return -EIO;
307         }
308
309 /*
310  * Initialize dev->board_name.  Note that we can use the "thisboard"
311  * macro now, since we just initialized it in the last line.
312  */
313         dev->board_name = thisboard->name;
314
315 /*
316  * Allocate the private structure area.  alloc_private() is a
317  * convenient macro defined in comedidev.h.
318  */
319         if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
320                 printk("cannot allocate private data structure\n");
321                 return -ENOMEM;
322         }
323
324         for (asic = 0; asic < MAX_ASICS; ++asic) {
325                 devpriv->asics[asic].num = asic;
326                 devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
327                 devpriv->asics[asic].irq = 0;   /* this gets actually set at the end of
328                                                    this function when we
329                                                    request_irqs */
330                 spin_lock_init(&devpriv->asics[asic].spinlock);
331         }
332
333         chans_left = CHANS_PER_ASIC * thisboard->num_asics;
334         n_subdevs = CALC_N_SUBDEVS(chans_left);
335         devpriv->sprivs =
336             kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
337                     GFP_KERNEL);
338         if (!devpriv->sprivs) {
339                 printk("cannot allocate subdevice private data structures\n");
340                 return -ENOMEM;
341         }
342         /*
343          * Allocate the subdevice structures.  alloc_subdevice() is a
344          * convenient macro defined in comedidev.h.
345          *
346          * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
347          * 96-channel version of the board.
348          */
349         if (alloc_subdevices(dev, n_subdevs) < 0) {
350                 printk("cannot allocate subdevice data structures\n");
351                 return -ENOMEM;
352         }
353
354         port = 0;
355         asic = 0;
356         for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
357                 int byte_no;
358
359                 s = dev->subdevices + sdev_no;
360                 s->private = devpriv->sprivs + sdev_no;
361                 s->maxdata = 1;
362                 s->range_table = &range_digital;
363                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
364                 s->type = COMEDI_SUBD_DIO;
365                 s->insn_bits = pcmuio_dio_insn_bits;
366                 s->insn_config = pcmuio_dio_insn_config;
367                 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
368                 subpriv->intr.asic = -1;
369                 subpriv->intr.first_chan = -1;
370                 subpriv->intr.asic_chan = -1;
371                 subpriv->intr.num_asic_chans = -1;
372                 subpriv->intr.active = 0;
373                 s->len_chanlist = 1;
374
375                 /* save the ioport address for each 'port' of 8 channels in the
376                    subdevice */
377                 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
378                         if (port >= PORTS_PER_ASIC) {
379                                 port = 0;
380                                 ++asic;
381                                 thisasic_chanct = 0;
382                         }
383                         subpriv->iobases[byte_no] =
384                             devpriv->asics[asic].iobase + port;
385
386                         if (thisasic_chanct <
387                             CHANS_PER_PORT * INTR_PORTS_PER_ASIC
388                             && subpriv->intr.asic < 0) {
389                                 /* this is an interrupt subdevice, so setup the struct */
390                                 subpriv->intr.asic = asic;
391                                 subpriv->intr.active = 0;
392                                 subpriv->intr.stop_count = 0;
393                                 subpriv->intr.first_chan = byte_no * 8;
394                                 subpriv->intr.asic_chan = thisasic_chanct;
395                                 subpriv->intr.num_asic_chans =
396                                     s->n_chan - subpriv->intr.first_chan;
397                                 dev->read_subdev = s;
398                                 s->subdev_flags |= SDF_CMD_READ;
399                                 s->cancel = pcmuio_cancel;
400                                 s->do_cmd = pcmuio_cmd;
401                                 s->do_cmdtest = pcmuio_cmdtest;
402                                 s->len_chanlist = subpriv->intr.num_asic_chans;
403                         }
404                         thisasic_chanct += CHANS_PER_PORT;
405                 }
406                 spin_lock_init(&subpriv->intr.spinlock);
407
408                 chans_left -= s->n_chan;
409
410                 if (!chans_left) {
411                         asic = 0;       /* reset the asic to our first asic, to do intr subdevs */
412                         port = 0;
413                 }
414
415         }
416
417         init_asics(dev);        /* clear out all the registers, basically */
418
419         for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
420                 if (irq[asic]
421                     && request_irq(irq[asic], interrupt_pcmuio,
422                                    IRQF_SHARED, thisboard->name, dev)) {
423                         int i;
424                         /* unroll the allocated irqs.. */
425                         for (i = asic - 1; i >= 0; --i) {
426                                 free_irq(irq[i], dev);
427                                 devpriv->asics[i].irq = irq[i] = 0;
428                         }
429                         irq[asic] = 0;
430                 }
431                 devpriv->asics[asic].irq = irq[asic];
432         }
433
434         dev->irq = irq[0];      /* grr.. wish comedi dev struct supported multiple
435                                    irqs.. */
436
437         if (irq[0]) {
438                 printk("irq: %u ", irq[0]);
439                 if (irq[1] && thisboard->num_asics == 2)
440                         printk("second ASIC irq: %u ", irq[1]);
441         } else {
442                 printk("(IRQ mode disabled) ");
443         }
444
445         printk("attached\n");
446
447         return 1;
448 }
449
450 /*
451  * _detach is called to deconfigure a device.  It should deallocate
452  * resources.
453  * This function is also called when _attach() fails, so it should be
454  * careful not to release resources that were not necessarily
455  * allocated by _attach().  dev->private and dev->subdevices are
456  * deallocated automatically by the core.
457  */
458 static int pcmuio_detach(struct comedi_device *dev)
459 {
460         int i;
461
462         printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
463         if (dev->iobase)
464                 release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
465
466         for (i = 0; i < MAX_ASICS; ++i) {
467                 if (devpriv->asics[i].irq)
468                         free_irq(devpriv->asics[i].irq, dev);
469         }
470
471         if (devpriv && devpriv->sprivs)
472                 kfree(devpriv->sprivs);
473
474         return 0;
475 }
476
477 /* DIO devices are slightly special.  Although it is possible to
478  * implement the insn_read/insn_write interface, it is much more
479  * useful to applications if you implement the insn_bits interface.
480  * This allows packed reading/writing of the DIO channels.  The
481  * comedi core can convert between insn_bits and insn_read/write */
482 static int pcmuio_dio_insn_bits(struct comedi_device *dev,
483                                 struct comedi_subdevice *s,
484                                 struct comedi_insn *insn, unsigned int *data)
485 {
486         int byte_no;
487         if (insn->n != 2)
488                 return -EINVAL;
489
490         /* NOTE:
491            reading a 0 means this channel was high
492            writine a 0 sets the channel high
493            reading a 1 means this channel was low
494            writing a 1 means set this channel low
495
496            Therefore everything is always inverted. */
497
498         /* The insn data is a mask in data[0] and the new data
499          * in data[1], each channel cooresponding to a bit. */
500
501 #ifdef DAMMIT_ITS_BROKEN
502         /* DEBUG */
503         printk("write mask: %08x  data: %08x\n", data[0], data[1]);
504 #endif
505
506         s->state = 0;
507
508         for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
509                 /* address of 8-bit port */
510                 unsigned long ioaddr = subpriv->iobases[byte_no],
511                     /* bit offset of port in 32-bit doubleword */
512                     offset = byte_no * 8;
513                 /* this 8-bit port's data */
514                 unsigned char byte = 0,
515                     /* The write mask for this port (if any) */
516                     write_mask_byte = (data[0] >> offset) & 0xff,
517                     /* The data byte for this port */
518                     data_byte = (data[1] >> offset) & 0xff;
519
520                 byte = inb(ioaddr);     /* read all 8-bits for this port */
521
522 #ifdef DAMMIT_ITS_BROKEN
523                 /* DEBUG */
524                 printk
525                     ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
526                      byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
527                      offset, ioaddr, (unsigned)byte);
528 #endif
529
530                 if (write_mask_byte) {
531                         /* this byte has some write_bits -- so set the output lines */
532                         byte &= ~write_mask_byte;       /* clear bits for write mask */
533                         byte |= ~data_byte & write_mask_byte;   /* set to inverted data_byte */
534                         /* Write out the new digital output state */
535                         outb(byte, ioaddr);
536                 }
537 #ifdef DAMMIT_ITS_BROKEN
538                 /* DEBUG */
539                 printk("data_out_byte %02x\n", (unsigned)byte);
540 #endif
541                 /* save the digital input lines for this byte.. */
542                 s->state |= ((unsigned int)byte) << offset;
543         }
544
545         /* now return the DIO lines to data[1] - note they came inverted! */
546         data[1] = ~s->state;
547
548 #ifdef DAMMIT_ITS_BROKEN
549         /* DEBUG */
550         printk("s->state %08x data_out %08x\n", s->state, data[1]);
551 #endif
552
553         return 2;
554 }
555
556 /* The input or output configuration of each digital line is
557  * configured by a special insn_config instruction.  chanspec
558  * contains the channel to be changed, and data[0] contains the
559  * value COMEDI_INPUT or COMEDI_OUTPUT. */
560 static int pcmuio_dio_insn_config(struct comedi_device *dev,
561                                   struct comedi_subdevice *s,
562                                   struct comedi_insn *insn, unsigned int *data)
563 {
564         int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
565             chan % 8;
566         unsigned long ioaddr;
567         unsigned char byte;
568
569         /* Compute ioaddr for this channel */
570         ioaddr = subpriv->iobases[byte_no];
571
572         /* NOTE:
573            writing a 0 an IO channel's bit sets the channel to INPUT
574            and pulls the line high as well
575
576            writing a 1 to an IO channel's  bit pulls the line low
577
578            All channels are implicitly always in OUTPUT mode -- but when
579            they are high they can be considered to be in INPUT mode..
580
581            Thus, we only force channels low if the config request was INPUT,
582            otherwise we do nothing to the hardware.    */
583
584         switch (data[0]) {
585         case INSN_CONFIG_DIO_OUTPUT:
586                 /* save to io_bits -- don't actually do anything since
587                    all input channels are also output channels... */
588                 s->io_bits |= 1 << chan;
589                 break;
590         case INSN_CONFIG_DIO_INPUT:
591                 /* write a 0 to the actual register representing the channel
592                    to set it to 'input'.  0 means "float high". */
593                 byte = inb(ioaddr);
594                 byte &= ~(1 << bit_no);
595                                 /**< set input channel to '0' */
596
597                 /* write out byte -- this is the only time we actually affect the
598                    hardware as all channels are implicitly output -- but input
599                    channels are set to float-high */
600                 outb(byte, ioaddr);
601
602                 /* save to io_bits */
603                 s->io_bits &= ~(1 << chan);
604                 break;
605
606         case INSN_CONFIG_DIO_QUERY:
607                 /* retreive from shadow register */
608                 data[1] =
609                     (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
610                 return insn->n;
611                 break;
612
613         default:
614                 return -EINVAL;
615                 break;
616         }
617
618         return insn->n;
619 }
620
621 static void init_asics(struct comedi_device *dev)
622 {                               /* sets up an
623                                    ASIC chip to defaults */
624         int asic;
625
626         for (asic = 0; asic < thisboard->num_asics; ++asic) {
627                 int port, page;
628                 unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
629
630                 switch_page(dev, asic, 0);      /* switch back to page 0 */
631
632                 /* first, clear all the DIO port bits */
633                 for (port = 0; port < PORTS_PER_ASIC; ++port)
634                         outb(0, baseaddr + REG_PORT0 + port);
635
636                 /* Next, clear all the paged registers for each page */
637                 for (page = 1; page < NUM_PAGES; ++page) {
638                         int reg;
639                         /* now clear all the paged registers */
640                         switch_page(dev, asic, page);
641                         for (reg = FIRST_PAGED_REG;
642                              reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
643                                 outb(0, baseaddr + reg);
644                 }
645
646                 /* DEBUG  set rising edge interrupts on port0 of both asics */
647                 /*switch_page(dev, asic, PAGE_POL);
648                    outb(0xff, baseaddr + REG_POL0);
649                    switch_page(dev, asic, PAGE_ENAB);
650                    outb(0xff, baseaddr + REG_ENAB0); */
651                 /* END DEBUG */
652
653                 switch_page(dev, asic, 0);      /* switch back to default page 0 */
654
655         }
656 }
657
658 static void switch_page(struct comedi_device *dev, int asic, int page)
659 {
660         if (asic < 0 || asic >= thisboard->num_asics)
661                 return;         /* paranoia */
662         if (page < 0 || page >= NUM_PAGES)
663                 return;         /* more paranoia */
664
665         devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
666         devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
667
668         /* now write out the shadow register */
669         outb(devpriv->asics[asic].pagelock,
670              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
671 }
672
673 #ifdef notused
674 static void lock_port(struct comedi_device *dev, int asic, int port)
675 {
676         if (asic < 0 || asic >= thisboard->num_asics)
677                 return;         /* paranoia */
678         if (port < 0 || port >= PORTS_PER_ASIC)
679                 return;         /* more paranoia */
680
681         devpriv->asics[asic].pagelock |= 0x1 << port;
682         /* now write out the shadow register */
683         outb(devpriv->asics[asic].pagelock,
684              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
685 }
686
687 static void unlock_port(struct comedi_device *dev, int asic, int port)
688 {
689         if (asic < 0 || asic >= thisboard->num_asics)
690                 return;         /* paranoia */
691         if (port < 0 || port >= PORTS_PER_ASIC)
692                 return;         /* more paranoia */
693         devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
694         /* now write out the shadow register */
695         outb(devpriv->asics[asic].pagelock,
696              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
697 }
698 #endif /* notused */
699
700 static irqreturn_t interrupt_pcmuio(int irq, void *d)
701 {
702         int asic, got1 = 0;
703         struct comedi_device *dev = (struct comedi_device *)d;
704
705         for (asic = 0; asic < MAX_ASICS; ++asic) {
706                 if (irq == devpriv->asics[asic].irq) {
707                         unsigned long flags;
708                         unsigned triggered = 0;
709                         unsigned long iobase = devpriv->asics[asic].iobase;
710                         /* it is an interrupt for ASIC #asic */
711                         unsigned char int_pend;
712
713                         spin_lock_irqsave(&devpriv->asics[asic].spinlock,
714                                           flags);
715
716                         int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
717
718                         if (int_pend) {
719                                 int port;
720                                 for (port = 0; port < INTR_PORTS_PER_ASIC;
721                                      ++port) {
722                                         if (int_pend & (0x1 << port)) {
723                                                 unsigned char
724                                                     io_lines_with_edges = 0;
725                                                 switch_page(dev, asic,
726                                                             PAGE_INT_ID);
727                                                 io_lines_with_edges =
728                                                     inb(iobase +
729                                                         REG_INT_ID0 + port);
730
731                                                 if (io_lines_with_edges)
732                                                         /* clear pending interrupt */
733                                                         outb(0, iobase +
734                                                              REG_INT_ID0 +
735                                                              port);
736
737                                                 triggered |=
738                                                     io_lines_with_edges <<
739                                                     port * 8;
740                                         }
741                                 }
742
743                                 ++got1;
744                         }
745
746                         spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
747                                                flags);
748
749                         if (triggered) {
750                                 struct comedi_subdevice *s;
751                                 /* TODO here: dispatch io lines to subdevs with commands.. */
752                                 printk
753                                     ("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
754                                      irq, asic, triggered);
755                                 for (s = dev->subdevices;
756                                      s < dev->subdevices + dev->n_subdevices;
757                                      ++s) {
758                                         if (subpriv->intr.asic == asic) {       /* this is an interrupt subdev, and it matches this asic! */
759                                                 unsigned long flags;
760                                                 unsigned oldevents;
761
762                                                 spin_lock_irqsave(&subpriv->
763                                                                   intr.spinlock,
764                                                                   flags);
765
766                                                 oldevents = s->async->events;
767
768                                                 if (subpriv->intr.active) {
769                                                         unsigned mytrig =
770                                                             ((triggered >>
771                                                               subpriv->intr.asic_chan)
772                                                              &
773                                                              ((0x1 << subpriv->
774                                                                intr.
775                                                                num_asic_chans) -
776                                                               1)) << subpriv->
777                                                             intr.first_chan;
778                                                         if (mytrig &
779                                                             subpriv->intr.enabled_mask)
780                                                         {
781                                                                 unsigned int val
782                                                                     = 0;
783                                                                 unsigned int n,
784                                                                     ch, len;
785
786                                                                 len =
787                                                                     s->
788                                                                     async->cmd.chanlist_len;
789                                                                 for (n = 0;
790                                                                      n < len;
791                                                                      n++) {
792                                                                         ch = CR_CHAN(s->async->cmd.chanlist[n]);
793                                                                         if (mytrig & (1U << ch)) {
794                                                                                 val |= (1U << n);
795                                                                         }
796                                                                 }
797                                                                 /* Write the scan to the buffer. */
798                                                                 if (comedi_buf_put(s->async, ((short *)&val)[0])
799                                                                     &&
800                                                                     comedi_buf_put
801                                                                     (s->async,
802                                                                      ((short *)
803                                                                       &val)[1]))
804                                                                 {
805                                                                         s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
806                                                                 } else {
807                                                                         /* Overflow! Stop acquisition!! */
808                                                                         /* TODO: STOP_ACQUISITION_CALL_HERE!! */
809                                                                         pcmuio_stop_intr
810                                                                             (dev,
811                                                                              s);
812                                                                 }
813
814                                                                 /* Check for end of acquisition. */
815                                                                 if (!subpriv->intr.continuous) {
816                                                                         /* stop_src == TRIG_COUNT */
817                                                                         if (subpriv->intr.stop_count > 0) {
818                                                                                 subpriv->intr.stop_count--;
819                                                                                 if (subpriv->intr.stop_count == 0) {
820                                                                                         s->async->events |= COMEDI_CB_EOA;
821                                                                                         /* TODO: STOP_ACQUISITION_CALL_HERE!! */
822                                                                                         pcmuio_stop_intr
823                                                                                             (dev,
824                                                                                              s);
825                                                                                 }
826                                                                         }
827                                                                 }
828                                                         }
829                                                 }
830
831                                                 spin_unlock_irqrestore
832                                                     (&subpriv->intr.spinlock,
833                                                      flags);
834
835                                                 if (oldevents !=
836                                                     s->async->events) {
837                                                         comedi_event(dev, s);
838                                                 }
839
840                                         }
841
842                                 }
843                         }
844
845                 }
846         }
847         if (!got1)
848                 return IRQ_NONE;        /* interrupt from other source */
849         return IRQ_HANDLED;
850 }
851
852 static void pcmuio_stop_intr(struct comedi_device *dev,
853                              struct comedi_subdevice *s)
854 {
855         int nports, firstport, asic, port;
856
857         asic = subpriv->intr.asic;
858         if (asic < 0)
859                 return;         /* not an interrupt subdev */
860
861         subpriv->intr.enabled_mask = 0;
862         subpriv->intr.active = 0;
863         s->async->inttrig = 0;
864         nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
865         firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
866         switch_page(dev, asic, PAGE_ENAB);
867         for (port = firstport; port < firstport + nports; ++port) {
868                 /* disable all intrs for this subdev.. */
869                 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
870         }
871 }
872
873 static int pcmuio_start_intr(struct comedi_device *dev,
874                              struct comedi_subdevice *s)
875 {
876         if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
877                 /* An empty acquisition! */
878                 s->async->events |= COMEDI_CB_EOA;
879                 subpriv->intr.active = 0;
880                 return 1;
881         } else {
882                 unsigned bits = 0, pol_bits = 0, n;
883                 int nports, firstport, asic, port;
884                 struct comedi_cmd *cmd = &s->async->cmd;
885
886                 asic = subpriv->intr.asic;
887                 if (asic < 0)
888                         return 1;       /* not an interrupt
889                                            subdev */
890                 subpriv->intr.enabled_mask = 0;
891                 subpriv->intr.active = 1;
892                 nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
893                 firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
894                 if (cmd->chanlist) {
895                         for (n = 0; n < cmd->chanlist_len; n++) {
896                                 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
897                                 pol_bits |= (CR_AREF(cmd->chanlist[n])
898                                              || CR_RANGE(cmd->
899                                                          chanlist[n]) ? 1U : 0U)
900                                     << CR_CHAN(cmd->chanlist[n]);
901                         }
902                 }
903                 bits &= ((0x1 << subpriv->intr.num_asic_chans) -
904                          1) << subpriv->intr.first_chan;
905                 subpriv->intr.enabled_mask = bits;
906
907                 switch_page(dev, asic, PAGE_ENAB);
908                 for (port = firstport; port < firstport + nports; ++port) {
909                         unsigned enab =
910                             bits >> (subpriv->intr.first_chan + (port -
911                                                                  firstport) *
912                                      8) & 0xff, pol =
913                             pol_bits >> (subpriv->intr.first_chan +
914                                          (port - firstport) * 8) & 0xff;
915                         /* set enab intrs for this subdev.. */
916                         outb(enab,
917                              devpriv->asics[asic].iobase + REG_ENAB0 + port);
918                         switch_page(dev, asic, PAGE_POL);
919                         outb(pol,
920                              devpriv->asics[asic].iobase + REG_ENAB0 + port);
921                 }
922         }
923         return 0;
924 }
925
926 static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
927 {
928         unsigned long flags;
929
930         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
931         if (subpriv->intr.active)
932                 pcmuio_stop_intr(dev, s);
933         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
934
935         return 0;
936 }
937
938 /*
939  * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
940  */
941 static int
942 pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
943                           unsigned int trignum)
944 {
945         unsigned long flags;
946         int event = 0;
947
948         if (trignum != 0)
949                 return -EINVAL;
950
951         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
952         s->async->inttrig = 0;
953         if (subpriv->intr.active) {
954                 event = pcmuio_start_intr(dev, s);
955         }
956         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
957
958         if (event) {
959                 comedi_event(dev, s);
960         }
961
962         return 1;
963 }
964
965 /*
966  * 'do_cmd' function for an 'INTERRUPT' subdevice.
967  */
968 static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
969 {
970         struct comedi_cmd *cmd = &s->async->cmd;
971         unsigned long flags;
972         int event = 0;
973
974         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
975         subpriv->intr.active = 1;
976
977         /* Set up end of acquisition. */
978         switch (cmd->stop_src) {
979         case TRIG_COUNT:
980                 subpriv->intr.continuous = 0;
981                 subpriv->intr.stop_count = cmd->stop_arg;
982                 break;
983         default:
984                 /* TRIG_NONE */
985                 subpriv->intr.continuous = 1;
986                 subpriv->intr.stop_count = 0;
987                 break;
988         }
989
990         /* Set up start of acquisition. */
991         switch (cmd->start_src) {
992         case TRIG_INT:
993                 s->async->inttrig = pcmuio_inttrig_start_intr;
994                 break;
995         default:
996                 /* TRIG_NOW */
997                 event = pcmuio_start_intr(dev, s);
998                 break;
999         }
1000         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
1001
1002         if (event) {
1003                 comedi_event(dev, s);
1004         }
1005
1006         return 0;
1007 }
1008
1009 static int
1010 pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1011                struct comedi_cmd *cmd)
1012 {
1013         return comedi_pcm_cmdtest(dev, s, cmd);
1014 }
1015
1016 /*
1017  * A convenient macro that defines init_module() and cleanup_module(),
1018  * as necessary.
1019  */
1020 COMEDI_INITCLEANUP(driver);