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