staging: comedi: remove inline alloc_private()
[linux-2.6-block.git] / drivers / staging / comedi / drivers / pcmuio.c
1 /*
2     comedi/drivers/pcmuio.c
3     Driver for Winsystems PC-104 based 48-channel and 96-channel DIO boards.
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /*
23 Driver: pcmuio
24 Description: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems.
25 Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96)
26 Author: Calin Culianu <calin@ajvar.org>
27 Updated: Fri, 13 Jan 2006 12:01:01 -0500
28 Status: works
29
30 A driver for the relatively straightforward-to-program PCM-UIO48A and
31 PCM-UIO96A boards from Winsystems.  These boards use either one or two
32 (in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO).
33 This chip is interesting in that each I/O line is individually
34 programmable for INPUT or OUTPUT (thus comedi_dio_config can be done
35 on a per-channel basis).  Also, each chip supports edge-triggered
36 interrupts for the first 24 I/O lines.  Of course, since the
37 96-channel version of the board has two ASICs, it can detect polarity
38 changes on up to 48 I/O lines.  Since this is essentially an (non-PnP)
39 ISA board, I/O Address and IRQ selection are done through jumpers on
40 the board.  You need to pass that information to this driver as the
41 first and second comedi_config option, respectively.  Note that the
42 48-channel version uses 16 bytes of IO memory and the 96-channel
43 version uses 32-bytes (in case you are worried about conflicts).  The
44 48-channel board is split into two 24-channel comedi subdevices.
45 The 96-channel board is split into 4 24-channel DIO subdevices.
46
47 Note that IRQ support has been added, but it is untested.
48
49 To use edge-detection IRQ support, pass the IRQs of both ASICS
50 (for the 96 channel version) or just 1 ASIC (for 48-channel version).
51 Then, use use comedi_commands with TRIG_NOW.
52 Your callback will be called each time an edge is triggered, and the data
53 values will be two sample_t's, which should be concatenated to form one
54 32-bit unsigned int.  This value is the mask of channels that had
55 edges detected from your channel list.  Note that the bits positions
56 in the mask correspond to positions in your chanlist when you specified
57 the command and *not* channel id's!
58
59 To set the polarity of the edge-detection interrupts pass a nonzero value for
60 either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both
61 CR_RANGE and CR_AREF if you want edge-down polarity.
62
63 In the 48-channel version:
64
65 On subdev 0, the first 24 channels channels are edge-detect channels.
66
67 In the 96-channel board you have the collowing channels that can do edge detection:
68
69 subdev 0, channels 0-24  (first 24 channels of 1st ASIC)
70 subdev 2, channels 0-24  (first 24 channels of 2nd ASIC)
71
72 Configuration Options:
73   [0] - I/O port base address
74   [1] - IRQ (for first ASIC, or first 24 channels)
75   [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!)
76 */
77
78 #include <linux/interrupt.h>
79 #include <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 /* this structure is for data unique to this subdevice.  */
159 struct pcmuio_subdev_private {
160         /* mapping of halfwords (bytes) in port/chanarray to iobase */
161         unsigned long iobases[PORTS_PER_SUBDEV];
162
163         /* The below is only used for intr subdevices */
164         struct {
165                 int asic;       /* if non-negative, this subdev has an interrupt asic */
166                 int first_chan; /* if nonnegative, the first channel id for
167                                    interrupts. */
168                 int num_asic_chans;     /* the number of asic channels in this subdev
169                                            that have interrutps */
170                 int asic_chan;  /* if nonnegative, the first channel id with
171                                    respect to the asic that has interrupts */
172                 int enabled_mask;       /* subdev-relative channel mask for channels
173                                            we are interested in */
174                 int active;
175                 int stop_count;
176                 int continuous;
177                 spinlock_t spinlock;
178         } intr;
179 };
180
181 /* this structure is for data unique to this hardware driver.  If
182    several hardware drivers keep similar information in this structure,
183    feel free to suggest moving the variable to the struct comedi_device struct.  */
184 struct pcmuio_private {
185         struct {
186                 unsigned char pagelock; /* current page and lock */
187                 unsigned char pol[NUM_PAGED_REGS];      /* shadow of POLx registers */
188                 unsigned char enab[NUM_PAGED_REGS];     /* shadow of ENABx registers */
189                 int num;
190                 unsigned long iobase;
191                 unsigned int irq;
192                 spinlock_t spinlock;
193         } asics[MAX_ASICS];
194         struct pcmuio_subdev_private *sprivs;
195 };
196
197 #define subpriv ((struct pcmuio_subdev_private *)s->private)
198
199 /* DIO devices are slightly special.  Although it is possible to
200  * implement the insn_read/insn_write interface, it is much more
201  * useful to applications if you implement the insn_bits interface.
202  * This allows packed reading/writing of the DIO channels.  The
203  * comedi core can convert between insn_bits and insn_read/write */
204 static int pcmuio_dio_insn_bits(struct comedi_device *dev,
205                                 struct comedi_subdevice *s,
206                                 struct comedi_insn *insn, unsigned int *data)
207 {
208         int byte_no;
209
210         /* NOTE:
211            reading a 0 means this channel was high
212            writine a 0 sets the channel high
213            reading a 1 means this channel was low
214            writing a 1 means set this channel low
215
216            Therefore everything is always inverted. */
217
218         /* The insn data is a mask in data[0] and the new data
219          * in data[1], each channel cooresponding to a bit. */
220
221 #ifdef DAMMIT_ITS_BROKEN
222         /* DEBUG */
223         dev_dbg(dev->class_dev, "write mask: %08x  data: %08x\n", data[0],
224                 data[1]);
225 #endif
226
227         s->state = 0;
228
229         for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
230                 /* address of 8-bit port */
231                 unsigned long ioaddr = subpriv->iobases[byte_no],
232                     /* bit offset of port in 32-bit doubleword */
233                     offset = byte_no * 8;
234                 /* this 8-bit port's data */
235                 unsigned char byte = 0,
236                     /* The write mask for this port (if any) */
237                     write_mask_byte = (data[0] >> offset) & 0xff,
238                     /* The data byte for this port */
239                     data_byte = (data[1] >> offset) & 0xff;
240
241                 byte = inb(ioaddr);     /* read all 8-bits for this port */
242
243 #ifdef DAMMIT_ITS_BROKEN
244                 /* DEBUG */
245                 printk
246                     ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
247                      byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
248                      offset, ioaddr, (unsigned)byte);
249 #endif
250
251                 if (write_mask_byte) {
252                         /* this byte has some write_bits -- so set the output lines */
253                         byte &= ~write_mask_byte;       /* clear bits for write mask */
254                         byte |= ~data_byte & write_mask_byte;   /* set to inverted data_byte */
255                         /* Write out the new digital output state */
256                         outb(byte, ioaddr);
257                 }
258 #ifdef DAMMIT_ITS_BROKEN
259                 /* DEBUG */
260                 dev_dbg(dev->class_dev, "data_out_byte %02x\n", (unsigned)byte);
261 #endif
262                 /* save the digital input lines for this byte.. */
263                 s->state |= ((unsigned int)byte) << offset;
264         }
265
266         /* now return the DIO lines to data[1] - note they came inverted! */
267         data[1] = ~s->state;
268
269 #ifdef DAMMIT_ITS_BROKEN
270         /* DEBUG */
271         dev_dbg(dev->class_dev, "s->state %08x data_out %08x\n", s->state,
272                 data[1]);
273 #endif
274
275         return insn->n;
276 }
277
278 /* The input or output configuration of each digital line is
279  * configured by a special insn_config instruction.  chanspec
280  * contains the channel to be changed, and data[0] contains the
281  * value COMEDI_INPUT or COMEDI_OUTPUT. */
282 static int pcmuio_dio_insn_config(struct comedi_device *dev,
283                                   struct comedi_subdevice *s,
284                                   struct comedi_insn *insn, unsigned int *data)
285 {
286         int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
287             chan % 8;
288         unsigned long ioaddr;
289         unsigned char byte;
290
291         /* Compute ioaddr for this channel */
292         ioaddr = subpriv->iobases[byte_no];
293
294         /* NOTE:
295            writing a 0 an IO channel's bit sets the channel to INPUT
296            and pulls the line high as well
297
298            writing a 1 to an IO channel's  bit pulls the line low
299
300            All channels are implicitly always in OUTPUT mode -- but when
301            they are high they can be considered to be in INPUT mode..
302
303            Thus, we only force channels low if the config request was INPUT,
304            otherwise we do nothing to the hardware.    */
305
306         switch (data[0]) {
307         case INSN_CONFIG_DIO_OUTPUT:
308                 /* save to io_bits -- don't actually do anything since
309                    all input channels are also output channels... */
310                 s->io_bits |= 1 << chan;
311                 break;
312         case INSN_CONFIG_DIO_INPUT:
313                 /* write a 0 to the actual register representing the channel
314                    to set it to 'input'.  0 means "float high". */
315                 byte = inb(ioaddr);
316                 byte &= ~(1 << bit_no);
317                                 /**< set input channel to '0' */
318
319                 /* write out byte -- this is the only time we actually affect the
320                    hardware as all channels are implicitly output -- but input
321                    channels are set to float-high */
322                 outb(byte, ioaddr);
323
324                 /* save to io_bits */
325                 s->io_bits &= ~(1 << chan);
326                 break;
327
328         case INSN_CONFIG_DIO_QUERY:
329                 /* retrieve from shadow register */
330                 data[1] =
331                     (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
332                 return insn->n;
333                 break;
334
335         default:
336                 return -EINVAL;
337                 break;
338         }
339
340         return insn->n;
341 }
342
343 static void switch_page(struct comedi_device *dev, int asic, int page)
344 {
345         const struct pcmuio_board *board = comedi_board(dev);
346         struct pcmuio_private *devpriv = dev->private;
347
348         if (asic < 0 || asic >= board->num_asics)
349                 return;         /* paranoia */
350         if (page < 0 || page >= NUM_PAGES)
351                 return;         /* more paranoia */
352
353         devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
354         devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
355
356         /* now write out the shadow register */
357         outb(devpriv->asics[asic].pagelock,
358              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
359 }
360
361 static void init_asics(struct comedi_device *dev)
362 {                               /* sets up an
363                                    ASIC chip to defaults */
364         const struct pcmuio_board *board = comedi_board(dev);
365         int asic;
366
367         for (asic = 0; asic < board->num_asics; ++asic) {
368                 int port, page;
369                 unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
370
371                 switch_page(dev, asic, 0);      /* switch back to page 0 */
372
373                 /* first, clear all the DIO port bits */
374                 for (port = 0; port < PORTS_PER_ASIC; ++port)
375                         outb(0, baseaddr + REG_PORT0 + port);
376
377                 /* Next, clear all the paged registers for each page */
378                 for (page = 1; page < NUM_PAGES; ++page) {
379                         int reg;
380                         /* now clear all the paged registers */
381                         switch_page(dev, asic, page);
382                         for (reg = FIRST_PAGED_REG;
383                              reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
384                                 outb(0, baseaddr + reg);
385                 }
386
387                 /* DEBUG  set rising edge interrupts on port0 of both asics */
388                 /*switch_page(dev, asic, PAGE_POL);
389                    outb(0xff, baseaddr + REG_POL0);
390                    switch_page(dev, asic, PAGE_ENAB);
391                    outb(0xff, baseaddr + REG_ENAB0); */
392                 /* END DEBUG */
393
394                 switch_page(dev, asic, 0);      /* switch back to default page 0 */
395
396         }
397 }
398
399 #ifdef notused
400 static void lock_port(struct comedi_device *dev, int asic, int port)
401 {
402         const struct pcmuio_board *board = comedi_board(dev);
403         struct pcmuio_private *devpriv = dev->private;
404
405         if (asic < 0 || asic >= board->num_asics)
406                 return;         /* paranoia */
407         if (port < 0 || port >= PORTS_PER_ASIC)
408                 return;         /* more paranoia */
409
410         devpriv->asics[asic].pagelock |= 0x1 << port;
411         /* now write out the shadow register */
412         outb(devpriv->asics[asic].pagelock,
413              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
414 }
415
416 static void unlock_port(struct comedi_device *dev, int asic, int port)
417 {
418         const struct pcmuio_board *board = comedi_board(dev);
419         struct pcmuio_private *devpriv = dev->private;
420
421         if (asic < 0 || asic >= board->num_asics)
422                 return;         /* paranoia */
423         if (port < 0 || port >= PORTS_PER_ASIC)
424                 return;         /* more paranoia */
425         devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
426         /* now write out the shadow register */
427         outb(devpriv->asics[asic].pagelock,
428              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
429 }
430 #endif /* notused */
431
432 static void pcmuio_stop_intr(struct comedi_device *dev,
433                              struct comedi_subdevice *s)
434 {
435         int nports, firstport, asic, port;
436         struct pcmuio_private *devpriv = dev->private;
437
438         asic = subpriv->intr.asic;
439         if (asic < 0)
440                 return;         /* not an interrupt subdev */
441
442         subpriv->intr.enabled_mask = 0;
443         subpriv->intr.active = 0;
444         s->async->inttrig = NULL;
445         nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
446         firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
447         switch_page(dev, asic, PAGE_ENAB);
448         for (port = firstport; port < firstport + nports; ++port) {
449                 /* disable all intrs for this subdev.. */
450                 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
451         }
452 }
453
454 static irqreturn_t interrupt_pcmuio(int irq, void *d)
455 {
456         int asic, got1 = 0;
457         struct comedi_device *dev = (struct comedi_device *)d;
458         struct pcmuio_private *devpriv = dev->private;
459         int i;
460
461         for (asic = 0; asic < MAX_ASICS; ++asic) {
462                 if (irq == devpriv->asics[asic].irq) {
463                         unsigned long flags;
464                         unsigned triggered = 0;
465                         unsigned long iobase = devpriv->asics[asic].iobase;
466                         /* it is an interrupt for ASIC #asic */
467                         unsigned char int_pend;
468
469                         spin_lock_irqsave(&devpriv->asics[asic].spinlock,
470                                           flags);
471
472                         int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
473
474                         if (int_pend) {
475                                 int port;
476                                 for (port = 0; port < INTR_PORTS_PER_ASIC;
477                                      ++port) {
478                                         if (int_pend & (0x1 << port)) {
479                                                 unsigned char
480                                                     io_lines_with_edges = 0;
481                                                 switch_page(dev, asic,
482                                                             PAGE_INT_ID);
483                                                 io_lines_with_edges =
484                                                     inb(iobase +
485                                                         REG_INT_ID0 + port);
486
487                                                 if (io_lines_with_edges)
488                                                         /* clear pending interrupt */
489                                                         outb(0, iobase +
490                                                              REG_INT_ID0 +
491                                                              port);
492
493                                                 triggered |=
494                                                     io_lines_with_edges <<
495                                                     port * 8;
496                                         }
497                                 }
498
499                                 ++got1;
500                         }
501
502                         spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
503                                                flags);
504
505                         if (triggered) {
506                                 struct comedi_subdevice *s;
507                                 /* TODO here: dispatch io lines to subdevs with commands.. */
508                                 printk
509                                     ("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
510                                      irq, asic, triggered);
511                                 for (i = 0; i < dev->n_subdevices; i++) {
512                                         s = &dev->subdevices[i];
513                                         if (subpriv->intr.asic == asic) {       /* this is an interrupt subdev, and it matches this asic! */
514                                                 unsigned long flags;
515                                                 unsigned oldevents;
516
517                                                 spin_lock_irqsave(&subpriv->
518                                                                   intr.spinlock,
519                                                                   flags);
520
521                                                 oldevents = s->async->events;
522
523                                                 if (subpriv->intr.active) {
524                                                         unsigned mytrig =
525                                                             ((triggered >>
526                                                               subpriv->intr.asic_chan)
527                                                              &
528                                                              ((0x1 << subpriv->
529                                                                intr.
530                                                                num_asic_chans) -
531                                                               1)) << subpriv->
532                                                             intr.first_chan;
533                                                         if (mytrig &
534                                                             subpriv->intr.enabled_mask)
535                                                         {
536                                                                 unsigned int val
537                                                                     = 0;
538                                                                 unsigned int n,
539                                                                     ch, len;
540
541                                                                 len =
542                                                                     s->
543                                                                     async->cmd.chanlist_len;
544                                                                 for (n = 0;
545                                                                      n < len;
546                                                                      n++) {
547                                                                         ch = CR_CHAN(s->async->cmd.chanlist[n]);
548                                                                         if (mytrig & (1U << ch)) {
549                                                                                 val |= (1U << n);
550                                                                         }
551                                                                 }
552                                                                 /* Write the scan to the buffer. */
553                                                                 if (comedi_buf_put(s->async, ((short *)&val)[0])
554                                                                     &&
555                                                                     comedi_buf_put
556                                                                     (s->async,
557                                                                      ((short *)
558                                                                       &val)[1]))
559                                                                 {
560                                                                         s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
561                                                                 } else {
562                                                                         /* Overflow! Stop acquisition!! */
563                                                                         /* TODO: STOP_ACQUISITION_CALL_HERE!! */
564                                                                         pcmuio_stop_intr
565                                                                             (dev,
566                                                                              s);
567                                                                 }
568
569                                                                 /* Check for end of acquisition. */
570                                                                 if (!subpriv->intr.continuous) {
571                                                                         /* stop_src == TRIG_COUNT */
572                                                                         if (subpriv->intr.stop_count > 0) {
573                                                                                 subpriv->intr.stop_count--;
574                                                                                 if (subpriv->intr.stop_count == 0) {
575                                                                                         s->async->events |= COMEDI_CB_EOA;
576                                                                                         /* TODO: STOP_ACQUISITION_CALL_HERE!! */
577                                                                                         pcmuio_stop_intr
578                                                                                             (dev,
579                                                                                              s);
580                                                                                 }
581                                                                         }
582                                                                 }
583                                                         }
584                                                 }
585
586                                                 spin_unlock_irqrestore
587                                                     (&subpriv->intr.spinlock,
588                                                      flags);
589
590                                                 if (oldevents !=
591                                                     s->async->events) {
592                                                         comedi_event(dev, s);
593                                                 }
594
595                                         }
596
597                                 }
598                         }
599
600                 }
601         }
602         if (!got1)
603                 return IRQ_NONE;        /* interrupt from other source */
604         return IRQ_HANDLED;
605 }
606
607 static int pcmuio_start_intr(struct comedi_device *dev,
608                              struct comedi_subdevice *s)
609 {
610         struct pcmuio_private *devpriv = dev->private;
611
612         if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
613                 /* An empty acquisition! */
614                 s->async->events |= COMEDI_CB_EOA;
615                 subpriv->intr.active = 0;
616                 return 1;
617         } else {
618                 unsigned bits = 0, pol_bits = 0, n;
619                 int nports, firstport, asic, port;
620                 struct comedi_cmd *cmd = &s->async->cmd;
621
622                 asic = subpriv->intr.asic;
623                 if (asic < 0)
624                         return 1;       /* not an interrupt
625                                            subdev */
626                 subpriv->intr.enabled_mask = 0;
627                 subpriv->intr.active = 1;
628                 nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
629                 firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
630                 if (cmd->chanlist) {
631                         for (n = 0; n < cmd->chanlist_len; n++) {
632                                 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
633                                 pol_bits |= (CR_AREF(cmd->chanlist[n])
634                                              || CR_RANGE(cmd->
635                                                          chanlist[n]) ? 1U : 0U)
636                                     << CR_CHAN(cmd->chanlist[n]);
637                         }
638                 }
639                 bits &= ((0x1 << subpriv->intr.num_asic_chans) -
640                          1) << subpriv->intr.first_chan;
641                 subpriv->intr.enabled_mask = bits;
642
643                 switch_page(dev, asic, PAGE_ENAB);
644                 for (port = firstport; port < firstport + nports; ++port) {
645                         unsigned enab =
646                             bits >> (subpriv->intr.first_chan + (port -
647                                                                  firstport) *
648                                      8) & 0xff, pol =
649                             pol_bits >> (subpriv->intr.first_chan +
650                                          (port - firstport) * 8) & 0xff;
651                         /* set enab intrs for this subdev.. */
652                         outb(enab,
653                              devpriv->asics[asic].iobase + REG_ENAB0 + port);
654                         switch_page(dev, asic, PAGE_POL);
655                         outb(pol,
656                              devpriv->asics[asic].iobase + REG_ENAB0 + port);
657                 }
658         }
659         return 0;
660 }
661
662 static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
663 {
664         unsigned long flags;
665
666         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
667         if (subpriv->intr.active)
668                 pcmuio_stop_intr(dev, s);
669         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
670
671         return 0;
672 }
673
674 /*
675  * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
676  */
677 static int
678 pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
679                           unsigned int trignum)
680 {
681         unsigned long flags;
682         int event = 0;
683
684         if (trignum != 0)
685                 return -EINVAL;
686
687         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
688         s->async->inttrig = NULL;
689         if (subpriv->intr.active)
690                 event = pcmuio_start_intr(dev, s);
691
692         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
693
694         if (event)
695                 comedi_event(dev, s);
696
697         return 1;
698 }
699
700 /*
701  * 'do_cmd' function for an 'INTERRUPT' subdevice.
702  */
703 static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
704 {
705         struct comedi_cmd *cmd = &s->async->cmd;
706         unsigned long flags;
707         int event = 0;
708
709         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
710         subpriv->intr.active = 1;
711
712         /* Set up end of acquisition. */
713         switch (cmd->stop_src) {
714         case TRIG_COUNT:
715                 subpriv->intr.continuous = 0;
716                 subpriv->intr.stop_count = cmd->stop_arg;
717                 break;
718         default:
719                 /* TRIG_NONE */
720                 subpriv->intr.continuous = 1;
721                 subpriv->intr.stop_count = 0;
722                 break;
723         }
724
725         /* Set up start of acquisition. */
726         switch (cmd->start_src) {
727         case TRIG_INT:
728                 s->async->inttrig = pcmuio_inttrig_start_intr;
729                 break;
730         default:
731                 /* TRIG_NOW */
732                 event = pcmuio_start_intr(dev, s);
733                 break;
734         }
735         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
736
737         if (event)
738                 comedi_event(dev, s);
739
740         return 0;
741 }
742
743 static int
744 pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
745                struct comedi_cmd *cmd)
746 {
747         return comedi_pcm_cmdtest(dev, s, cmd);
748 }
749
750 static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
751 {
752         const struct pcmuio_board *board = comedi_board(dev);
753         struct pcmuio_private *devpriv;
754         struct comedi_subdevice *s;
755         int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
756         unsigned long iobase;
757         unsigned int irq[MAX_ASICS];
758         int ret;
759
760         iobase = it->options[0];
761         irq[0] = it->options[1];
762         irq[1] = it->options[2];
763
764         dev_dbg(dev->class_dev, "%s: io: %lx attach\n",
765                 dev->driver->driver_name, iobase);
766
767         dev->iobase = iobase;
768
769         if (!iobase || !request_region(iobase,
770                                        board->num_asics * ASIC_IOSIZE,
771                                        dev->driver->driver_name)) {
772                 dev_err(dev->class_dev, "I/O port conflict\n");
773                 return -EIO;
774         }
775
776         dev->board_name = board->name;
777
778         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
779         if (!devpriv)
780                 return -ENOMEM;
781         dev->private = devpriv;
782
783         for (asic = 0; asic < MAX_ASICS; ++asic) {
784                 devpriv->asics[asic].num = asic;
785                 devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
786                 devpriv->asics[asic].irq = 0;   /* this gets actually set at the end of
787                                                    this function when we
788                                                    request_irqs */
789                 spin_lock_init(&devpriv->asics[asic].spinlock);
790         }
791
792         chans_left = CHANS_PER_ASIC * board->num_asics;
793         n_subdevs = CALC_N_SUBDEVS(chans_left);
794         devpriv->sprivs =
795             kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
796                     GFP_KERNEL);
797         if (!devpriv->sprivs) {
798                 dev_warn(dev->class_dev,
799                          "cannot allocate subdevice private data structures\n");
800                 return -ENOMEM;
801         }
802
803         ret = comedi_alloc_subdevices(dev, n_subdevs);
804         if (ret)
805                 return ret;
806
807         port = 0;
808         asic = 0;
809         for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
810                 int byte_no;
811
812                 s = &dev->subdevices[sdev_no];
813                 s->private = &devpriv->sprivs[sdev_no];
814                 s->maxdata = 1;
815                 s->range_table = &range_digital;
816                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
817                 s->type = COMEDI_SUBD_DIO;
818                 s->insn_bits = pcmuio_dio_insn_bits;
819                 s->insn_config = pcmuio_dio_insn_config;
820                 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
821                 subpriv->intr.asic = -1;
822                 subpriv->intr.first_chan = -1;
823                 subpriv->intr.asic_chan = -1;
824                 subpriv->intr.num_asic_chans = -1;
825                 subpriv->intr.active = 0;
826                 s->len_chanlist = 1;
827
828                 /* save the ioport address for each 'port' of 8 channels in the
829                    subdevice */
830                 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
831                         if (port >= PORTS_PER_ASIC) {
832                                 port = 0;
833                                 ++asic;
834                                 thisasic_chanct = 0;
835                         }
836                         subpriv->iobases[byte_no] =
837                             devpriv->asics[asic].iobase + port;
838
839                         if (thisasic_chanct <
840                             CHANS_PER_PORT * INTR_PORTS_PER_ASIC
841                             && subpriv->intr.asic < 0) {
842                                 /* this is an interrupt subdevice, so setup the struct */
843                                 subpriv->intr.asic = asic;
844                                 subpriv->intr.active = 0;
845                                 subpriv->intr.stop_count = 0;
846                                 subpriv->intr.first_chan = byte_no * 8;
847                                 subpriv->intr.asic_chan = thisasic_chanct;
848                                 subpriv->intr.num_asic_chans =
849                                     s->n_chan - subpriv->intr.first_chan;
850                                 dev->read_subdev = s;
851                                 s->subdev_flags |= SDF_CMD_READ;
852                                 s->cancel = pcmuio_cancel;
853                                 s->do_cmd = pcmuio_cmd;
854                                 s->do_cmdtest = pcmuio_cmdtest;
855                                 s->len_chanlist = subpriv->intr.num_asic_chans;
856                         }
857                         thisasic_chanct += CHANS_PER_PORT;
858                 }
859                 spin_lock_init(&subpriv->intr.spinlock);
860
861                 chans_left -= s->n_chan;
862
863                 if (!chans_left) {
864                         asic = 0;       /* reset the asic to our first asic, to do intr subdevs */
865                         port = 0;
866                 }
867
868         }
869
870         init_asics(dev);        /* clear out all the registers, basically */
871
872         for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
873                 if (irq[asic]
874                     && request_irq(irq[asic], interrupt_pcmuio,
875                                    IRQF_SHARED, board->name, dev)) {
876                         int i;
877                         /* unroll the allocated irqs.. */
878                         for (i = asic - 1; i >= 0; --i) {
879                                 free_irq(irq[i], dev);
880                                 devpriv->asics[i].irq = irq[i] = 0;
881                         }
882                         irq[asic] = 0;
883                 }
884                 devpriv->asics[asic].irq = irq[asic];
885         }
886
887         dev->irq = irq[0];      /* grr.. wish comedi dev struct supported multiple
888                                    irqs.. */
889
890         if (irq[0]) {
891                 dev_dbg(dev->class_dev, "irq: %u\n", irq[0]);
892                 if (irq[1] && board->num_asics == 2)
893                         dev_dbg(dev->class_dev, "second ASIC irq: %u\n",
894                                 irq[1]);
895         } else {
896                 dev_dbg(dev->class_dev, "(IRQ mode disabled)\n");
897         }
898
899
900         return 1;
901 }
902
903 static void pcmuio_detach(struct comedi_device *dev)
904 {
905         const struct pcmuio_board *board = comedi_board(dev);
906         struct pcmuio_private *devpriv = dev->private;
907         int i;
908
909         if (dev->iobase)
910                 release_region(dev->iobase, ASIC_IOSIZE * board->num_asics);
911         for (i = 0; i < MAX_ASICS; ++i) {
912                 if (devpriv->asics[i].irq)
913                         free_irq(devpriv->asics[i].irq, dev);
914         }
915         if (devpriv && devpriv->sprivs)
916                 kfree(devpriv->sprivs);
917 }
918
919 static const struct pcmuio_board pcmuio_boards[] = {
920         {
921                 .name           = "pcmuio48",
922                 .num_asics      = 1,
923                 .num_ports      = 6,
924         }, {
925                 .name           = "pcmuio96",
926                 .num_asics      = 2,
927                 .num_ports      = 12,
928         },
929 };
930
931 static struct comedi_driver pcmuio_driver = {
932         .driver_name    = "pcmuio",
933         .module         = THIS_MODULE,
934         .attach         = pcmuio_attach,
935         .detach         = pcmuio_detach,
936         .board_name     = &pcmuio_boards[0].name,
937         .offset         = sizeof(struct pcmuio_board),
938         .num_names      = ARRAY_SIZE(pcmuio_boards),
939 };
940 module_comedi_driver(pcmuio_driver);
941
942 MODULE_AUTHOR("Comedi http://www.comedi.org");
943 MODULE_DESCRIPTION("Comedi low-level driver");
944 MODULE_LICENSE("GPL");