KVM: x86: update KVM_SAVE_MSRS_BEGIN to correct value
[cascardo/linux.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 /*
159  * Useful for shorthand access to the particular board structure
160  */
161 #define thisboard ((const struct pcmuio_board *)dev->board_ptr)
162
163 /* this structure is for data unique to this subdevice.  */
164 struct pcmuio_subdev_private {
165         /* mapping of halfwords (bytes) in port/chanarray to iobase */
166         unsigned long iobases[PORTS_PER_SUBDEV];
167
168         /* The below is only used for intr subdevices */
169         struct {
170                 int asic;       /* if non-negative, this subdev has an interrupt asic */
171                 int first_chan; /* if nonnegative, the first channel id for
172                                    interrupts. */
173                 int num_asic_chans;     /* the number of asic channels in this subdev
174                                            that have interrutps */
175                 int asic_chan;  /* if nonnegative, the first channel id with
176                                    respect to the asic that has interrupts */
177                 int enabled_mask;       /* subdev-relative channel mask for channels
178                                            we are interested in */
179                 int active;
180                 int stop_count;
181                 int continuous;
182                 spinlock_t spinlock;
183         } intr;
184 };
185
186 /* this structure is for data unique to this hardware driver.  If
187    several hardware drivers keep similar information in this structure,
188    feel free to suggest moving the variable to the struct comedi_device struct.  */
189 struct pcmuio_private {
190         struct {
191                 unsigned char pagelock; /* current page and lock */
192                 unsigned char pol[NUM_PAGED_REGS];      /* shadow of POLx registers */
193                 unsigned char enab[NUM_PAGED_REGS];     /* shadow of ENABx registers */
194                 int num;
195                 unsigned long iobase;
196                 unsigned int irq;
197                 spinlock_t spinlock;
198         } asics[MAX_ASICS];
199         struct pcmuio_subdev_private *sprivs;
200 };
201
202 /*
203  * most drivers define the following macro to make it easy to
204  * access the private structure.
205  */
206 #define devpriv ((struct pcmuio_private *)dev->private)
207 #define subpriv ((struct pcmuio_subdev_private *)s->private)
208
209 /* DIO devices are slightly special.  Although it is possible to
210  * implement the insn_read/insn_write interface, it is much more
211  * useful to applications if you implement the insn_bits interface.
212  * This allows packed reading/writing of the DIO channels.  The
213  * comedi core can convert between insn_bits and insn_read/write */
214 static int pcmuio_dio_insn_bits(struct comedi_device *dev,
215                                 struct comedi_subdevice *s,
216                                 struct comedi_insn *insn, unsigned int *data)
217 {
218         int byte_no;
219         if (insn->n != 2)
220                 return -EINVAL;
221
222         /* NOTE:
223            reading a 0 means this channel was high
224            writine a 0 sets the channel high
225            reading a 1 means this channel was low
226            writing a 1 means set this channel low
227
228            Therefore everything is always inverted. */
229
230         /* The insn data is a mask in data[0] and the new data
231          * in data[1], each channel cooresponding to a bit. */
232
233 #ifdef DAMMIT_ITS_BROKEN
234         /* DEBUG */
235         dev_dbg(dev->hw_dev, "write mask: %08x  data: %08x\n", data[0],
236                 data[1]);
237 #endif
238
239         s->state = 0;
240
241         for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
242                 /* address of 8-bit port */
243                 unsigned long ioaddr = subpriv->iobases[byte_no],
244                     /* bit offset of port in 32-bit doubleword */
245                     offset = byte_no * 8;
246                 /* this 8-bit port's data */
247                 unsigned char byte = 0,
248                     /* The write mask for this port (if any) */
249                     write_mask_byte = (data[0] >> offset) & 0xff,
250                     /* The data byte for this port */
251                     data_byte = (data[1] >> offset) & 0xff;
252
253                 byte = inb(ioaddr);     /* read all 8-bits for this port */
254
255 #ifdef DAMMIT_ITS_BROKEN
256                 /* DEBUG */
257                 printk
258                     ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
259                      byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
260                      offset, ioaddr, (unsigned)byte);
261 #endif
262
263                 if (write_mask_byte) {
264                         /* this byte has some write_bits -- so set the output lines */
265                         byte &= ~write_mask_byte;       /* clear bits for write mask */
266                         byte |= ~data_byte & write_mask_byte;   /* set to inverted data_byte */
267                         /* Write out the new digital output state */
268                         outb(byte, ioaddr);
269                 }
270 #ifdef DAMMIT_ITS_BROKEN
271                 /* DEBUG */
272                 dev_dbg(dev->hw_dev, "data_out_byte %02x\n", (unsigned)byte);
273 #endif
274                 /* save the digital input lines for this byte.. */
275                 s->state |= ((unsigned int)byte) << offset;
276         }
277
278         /* now return the DIO lines to data[1] - note they came inverted! */
279         data[1] = ~s->state;
280
281 #ifdef DAMMIT_ITS_BROKEN
282         /* DEBUG */
283         dev_dbg(dev->hw_dev, "s->state %08x data_out %08x\n", s->state,
284                 data[1]);
285 #endif
286
287         return 2;
288 }
289
290 /* The input or output configuration of each digital line is
291  * configured by a special insn_config instruction.  chanspec
292  * contains the channel to be changed, and data[0] contains the
293  * value COMEDI_INPUT or COMEDI_OUTPUT. */
294 static int pcmuio_dio_insn_config(struct comedi_device *dev,
295                                   struct comedi_subdevice *s,
296                                   struct comedi_insn *insn, unsigned int *data)
297 {
298         int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
299             chan % 8;
300         unsigned long ioaddr;
301         unsigned char byte;
302
303         /* Compute ioaddr for this channel */
304         ioaddr = subpriv->iobases[byte_no];
305
306         /* NOTE:
307            writing a 0 an IO channel's bit sets the channel to INPUT
308            and pulls the line high as well
309
310            writing a 1 to an IO channel's  bit pulls the line low
311
312            All channels are implicitly always in OUTPUT mode -- but when
313            they are high they can be considered to be in INPUT mode..
314
315            Thus, we only force channels low if the config request was INPUT,
316            otherwise we do nothing to the hardware.    */
317
318         switch (data[0]) {
319         case INSN_CONFIG_DIO_OUTPUT:
320                 /* save to io_bits -- don't actually do anything since
321                    all input channels are also output channels... */
322                 s->io_bits |= 1 << chan;
323                 break;
324         case INSN_CONFIG_DIO_INPUT:
325                 /* write a 0 to the actual register representing the channel
326                    to set it to 'input'.  0 means "float high". */
327                 byte = inb(ioaddr);
328                 byte &= ~(1 << bit_no);
329                                 /**< set input channel to '0' */
330
331                 /* write out byte -- this is the only time we actually affect the
332                    hardware as all channels are implicitly output -- but input
333                    channels are set to float-high */
334                 outb(byte, ioaddr);
335
336                 /* save to io_bits */
337                 s->io_bits &= ~(1 << chan);
338                 break;
339
340         case INSN_CONFIG_DIO_QUERY:
341                 /* retrieve from shadow register */
342                 data[1] =
343                     (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
344                 return insn->n;
345                 break;
346
347         default:
348                 return -EINVAL;
349                 break;
350         }
351
352         return insn->n;
353 }
354
355 static void switch_page(struct comedi_device *dev, int asic, int page)
356 {
357         if (asic < 0 || asic >= thisboard->num_asics)
358                 return;         /* paranoia */
359         if (page < 0 || page >= NUM_PAGES)
360                 return;         /* more paranoia */
361
362         devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
363         devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
364
365         /* now write out the shadow register */
366         outb(devpriv->asics[asic].pagelock,
367              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
368 }
369
370 static void init_asics(struct comedi_device *dev)
371 {                               /* sets up an
372                                    ASIC chip to defaults */
373         int asic;
374
375         for (asic = 0; asic < thisboard->num_asics; ++asic) {
376                 int port, page;
377                 unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
378
379                 switch_page(dev, asic, 0);      /* switch back to page 0 */
380
381                 /* first, clear all the DIO port bits */
382                 for (port = 0; port < PORTS_PER_ASIC; ++port)
383                         outb(0, baseaddr + REG_PORT0 + port);
384
385                 /* Next, clear all the paged registers for each page */
386                 for (page = 1; page < NUM_PAGES; ++page) {
387                         int reg;
388                         /* now clear all the paged registers */
389                         switch_page(dev, asic, page);
390                         for (reg = FIRST_PAGED_REG;
391                              reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
392                                 outb(0, baseaddr + reg);
393                 }
394
395                 /* DEBUG  set rising edge interrupts on port0 of both asics */
396                 /*switch_page(dev, asic, PAGE_POL);
397                    outb(0xff, baseaddr + REG_POL0);
398                    switch_page(dev, asic, PAGE_ENAB);
399                    outb(0xff, baseaddr + REG_ENAB0); */
400                 /* END DEBUG */
401
402                 switch_page(dev, asic, 0);      /* switch back to default page 0 */
403
404         }
405 }
406
407 #ifdef notused
408 static void lock_port(struct comedi_device *dev, int asic, int port)
409 {
410         if (asic < 0 || asic >= thisboard->num_asics)
411                 return;         /* paranoia */
412         if (port < 0 || port >= PORTS_PER_ASIC)
413                 return;         /* more paranoia */
414
415         devpriv->asics[asic].pagelock |= 0x1 << port;
416         /* now write out the shadow register */
417         outb(devpriv->asics[asic].pagelock,
418              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
419 }
420
421 static void unlock_port(struct comedi_device *dev, int asic, int port)
422 {
423         if (asic < 0 || asic >= thisboard->num_asics)
424                 return;         /* paranoia */
425         if (port < 0 || port >= PORTS_PER_ASIC)
426                 return;         /* more paranoia */
427         devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
428         /* now write out the shadow register */
429         outb(devpriv->asics[asic].pagelock,
430              dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
431 }
432 #endif /* notused */
433
434 static void pcmuio_stop_intr(struct comedi_device *dev,
435                              struct comedi_subdevice *s)
436 {
437         int nports, firstport, asic, port;
438
439         asic = subpriv->intr.asic;
440         if (asic < 0)
441                 return;         /* not an interrupt subdev */
442
443         subpriv->intr.enabled_mask = 0;
444         subpriv->intr.active = 0;
445         s->async->inttrig = 0;
446         nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
447         firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
448         switch_page(dev, asic, PAGE_ENAB);
449         for (port = firstport; port < firstport + nports; ++port) {
450                 /* disable all intrs for this subdev.. */
451                 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
452         }
453 }
454
455 static irqreturn_t interrupt_pcmuio(int irq, void *d)
456 {
457         int asic, got1 = 0;
458         struct comedi_device *dev = (struct comedi_device *)d;
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 (s = dev->subdevices;
511                                      s < dev->subdevices + dev->n_subdevices;
512                                      ++s) {
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         if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
611                 /* An empty acquisition! */
612                 s->async->events |= COMEDI_CB_EOA;
613                 subpriv->intr.active = 0;
614                 return 1;
615         } else {
616                 unsigned bits = 0, pol_bits = 0, n;
617                 int nports, firstport, asic, port;
618                 struct comedi_cmd *cmd = &s->async->cmd;
619
620                 asic = subpriv->intr.asic;
621                 if (asic < 0)
622                         return 1;       /* not an interrupt
623                                            subdev */
624                 subpriv->intr.enabled_mask = 0;
625                 subpriv->intr.active = 1;
626                 nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
627                 firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
628                 if (cmd->chanlist) {
629                         for (n = 0; n < cmd->chanlist_len; n++) {
630                                 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
631                                 pol_bits |= (CR_AREF(cmd->chanlist[n])
632                                              || CR_RANGE(cmd->
633                                                          chanlist[n]) ? 1U : 0U)
634                                     << CR_CHAN(cmd->chanlist[n]);
635                         }
636                 }
637                 bits &= ((0x1 << subpriv->intr.num_asic_chans) -
638                          1) << subpriv->intr.first_chan;
639                 subpriv->intr.enabled_mask = bits;
640
641                 switch_page(dev, asic, PAGE_ENAB);
642                 for (port = firstport; port < firstport + nports; ++port) {
643                         unsigned enab =
644                             bits >> (subpriv->intr.first_chan + (port -
645                                                                  firstport) *
646                                      8) & 0xff, pol =
647                             pol_bits >> (subpriv->intr.first_chan +
648                                          (port - firstport) * 8) & 0xff;
649                         /* set enab intrs for this subdev.. */
650                         outb(enab,
651                              devpriv->asics[asic].iobase + REG_ENAB0 + port);
652                         switch_page(dev, asic, PAGE_POL);
653                         outb(pol,
654                              devpriv->asics[asic].iobase + REG_ENAB0 + port);
655                 }
656         }
657         return 0;
658 }
659
660 static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
661 {
662         unsigned long flags;
663
664         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
665         if (subpriv->intr.active)
666                 pcmuio_stop_intr(dev, s);
667         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
668
669         return 0;
670 }
671
672 /*
673  * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
674  */
675 static int
676 pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
677                           unsigned int trignum)
678 {
679         unsigned long flags;
680         int event = 0;
681
682         if (trignum != 0)
683                 return -EINVAL;
684
685         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
686         s->async->inttrig = 0;
687         if (subpriv->intr.active)
688                 event = pcmuio_start_intr(dev, s);
689
690         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
691
692         if (event)
693                 comedi_event(dev, s);
694
695         return 1;
696 }
697
698 /*
699  * 'do_cmd' function for an 'INTERRUPT' subdevice.
700  */
701 static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
702 {
703         struct comedi_cmd *cmd = &s->async->cmd;
704         unsigned long flags;
705         int event = 0;
706
707         spin_lock_irqsave(&subpriv->intr.spinlock, flags);
708         subpriv->intr.active = 1;
709
710         /* Set up end of acquisition. */
711         switch (cmd->stop_src) {
712         case TRIG_COUNT:
713                 subpriv->intr.continuous = 0;
714                 subpriv->intr.stop_count = cmd->stop_arg;
715                 break;
716         default:
717                 /* TRIG_NONE */
718                 subpriv->intr.continuous = 1;
719                 subpriv->intr.stop_count = 0;
720                 break;
721         }
722
723         /* Set up start of acquisition. */
724         switch (cmd->start_src) {
725         case TRIG_INT:
726                 s->async->inttrig = pcmuio_inttrig_start_intr;
727                 break;
728         default:
729                 /* TRIG_NOW */
730                 event = pcmuio_start_intr(dev, s);
731                 break;
732         }
733         spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
734
735         if (event)
736                 comedi_event(dev, s);
737
738         return 0;
739 }
740
741 static int
742 pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
743                struct comedi_cmd *cmd)
744 {
745         return comedi_pcm_cmdtest(dev, s, cmd);
746 }
747
748 static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
749 {
750         struct comedi_subdevice *s;
751         int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
752         unsigned long iobase;
753         unsigned int irq[MAX_ASICS];
754
755         iobase = it->options[0];
756         irq[0] = it->options[1];
757         irq[1] = it->options[2];
758
759         dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
760                 dev->driver->driver_name, iobase);
761
762         dev->iobase = iobase;
763
764         if (!iobase || !request_region(iobase,
765                                        thisboard->num_asics * ASIC_IOSIZE,
766                                        dev->driver->driver_name)) {
767                 dev_err(dev->hw_dev, "I/O port conflict\n");
768                 return -EIO;
769         }
770
771 /*
772  * Initialize dev->board_name.  Note that we can use the "thisboard"
773  * macro now, since we just initialized it in the last line.
774  */
775         dev->board_name = thisboard->name;
776
777 /*
778  * Allocate the private structure area.  alloc_private() is a
779  * convenient macro defined in comedidev.h.
780  */
781         if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
782                 dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
783                 return -ENOMEM;
784         }
785
786         for (asic = 0; asic < MAX_ASICS; ++asic) {
787                 devpriv->asics[asic].num = asic;
788                 devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
789                 devpriv->asics[asic].irq = 0;   /* this gets actually set at the end of
790                                                    this function when we
791                                                    request_irqs */
792                 spin_lock_init(&devpriv->asics[asic].spinlock);
793         }
794
795         chans_left = CHANS_PER_ASIC * thisboard->num_asics;
796         n_subdevs = CALC_N_SUBDEVS(chans_left);
797         devpriv->sprivs =
798             kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
799                     GFP_KERNEL);
800         if (!devpriv->sprivs) {
801                 dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
802                 return -ENOMEM;
803         }
804         /*
805          * Allocate the subdevice structures.  alloc_subdevice() is a
806          * convenient macro defined in comedidev.h.
807          *
808          * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
809          * 96-channel version of the board.
810          */
811         if (alloc_subdevices(dev, n_subdevs) < 0) {
812                 dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
813                 return -ENOMEM;
814         }
815
816         port = 0;
817         asic = 0;
818         for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
819                 int byte_no;
820
821                 s = dev->subdevices + sdev_no;
822                 s->private = devpriv->sprivs + sdev_no;
823                 s->maxdata = 1;
824                 s->range_table = &range_digital;
825                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
826                 s->type = COMEDI_SUBD_DIO;
827                 s->insn_bits = pcmuio_dio_insn_bits;
828                 s->insn_config = pcmuio_dio_insn_config;
829                 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
830                 subpriv->intr.asic = -1;
831                 subpriv->intr.first_chan = -1;
832                 subpriv->intr.asic_chan = -1;
833                 subpriv->intr.num_asic_chans = -1;
834                 subpriv->intr.active = 0;
835                 s->len_chanlist = 1;
836
837                 /* save the ioport address for each 'port' of 8 channels in the
838                    subdevice */
839                 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
840                         if (port >= PORTS_PER_ASIC) {
841                                 port = 0;
842                                 ++asic;
843                                 thisasic_chanct = 0;
844                         }
845                         subpriv->iobases[byte_no] =
846                             devpriv->asics[asic].iobase + port;
847
848                         if (thisasic_chanct <
849                             CHANS_PER_PORT * INTR_PORTS_PER_ASIC
850                             && subpriv->intr.asic < 0) {
851                                 /* this is an interrupt subdevice, so setup the struct */
852                                 subpriv->intr.asic = asic;
853                                 subpriv->intr.active = 0;
854                                 subpriv->intr.stop_count = 0;
855                                 subpriv->intr.first_chan = byte_no * 8;
856                                 subpriv->intr.asic_chan = thisasic_chanct;
857                                 subpriv->intr.num_asic_chans =
858                                     s->n_chan - subpriv->intr.first_chan;
859                                 dev->read_subdev = s;
860                                 s->subdev_flags |= SDF_CMD_READ;
861                                 s->cancel = pcmuio_cancel;
862                                 s->do_cmd = pcmuio_cmd;
863                                 s->do_cmdtest = pcmuio_cmdtest;
864                                 s->len_chanlist = subpriv->intr.num_asic_chans;
865                         }
866                         thisasic_chanct += CHANS_PER_PORT;
867                 }
868                 spin_lock_init(&subpriv->intr.spinlock);
869
870                 chans_left -= s->n_chan;
871
872                 if (!chans_left) {
873                         asic = 0;       /* reset the asic to our first asic, to do intr subdevs */
874                         port = 0;
875                 }
876
877         }
878
879         init_asics(dev);        /* clear out all the registers, basically */
880
881         for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
882                 if (irq[asic]
883                     && request_irq(irq[asic], interrupt_pcmuio,
884                                    IRQF_SHARED, thisboard->name, dev)) {
885                         int i;
886                         /* unroll the allocated irqs.. */
887                         for (i = asic - 1; i >= 0; --i) {
888                                 free_irq(irq[i], dev);
889                                 devpriv->asics[i].irq = irq[i] = 0;
890                         }
891                         irq[asic] = 0;
892                 }
893                 devpriv->asics[asic].irq = irq[asic];
894         }
895
896         dev->irq = irq[0];      /* grr.. wish comedi dev struct supported multiple
897                                    irqs.. */
898
899         if (irq[0]) {
900                 dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
901                 if (irq[1] && thisboard->num_asics == 2)
902                         dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
903         } else {
904                 dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
905         }
906
907
908         return 1;
909 }
910
911 static void pcmuio_detach(struct comedi_device *dev)
912 {
913         int i;
914
915         if (dev->iobase)
916                 release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
917         for (i = 0; i < MAX_ASICS; ++i) {
918                 if (devpriv->asics[i].irq)
919                         free_irq(devpriv->asics[i].irq, dev);
920         }
921         if (devpriv && devpriv->sprivs)
922                 kfree(devpriv->sprivs);
923 }
924
925 static const struct pcmuio_board pcmuio_boards[] = {
926         {
927                 .name           = "pcmuio48",
928                 .num_asics      = 1,
929                 .num_ports      = 6,
930         }, {
931                 .name           = "pcmuio96",
932                 .num_asics      = 2,
933                 .num_ports      = 12,
934         },
935 };
936
937 static struct comedi_driver pcmuio_driver = {
938         .driver_name    = "pcmuio",
939         .module         = THIS_MODULE,
940         .attach         = pcmuio_attach,
941         .detach         = pcmuio_detach,
942         .board_name     = &pcmuio_boards[0].name,
943         .offset         = sizeof(struct pcmuio_board),
944         .num_names      = ARRAY_SIZE(pcmuio_boards),
945 };
946 module_comedi_driver(pcmuio_driver);
947
948 MODULE_AUTHOR("Comedi http://www.comedi.org");
949 MODULE_DESCRIPTION("Comedi low-level driver");
950 MODULE_LICENSE("GPL");