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