]> Pileus Git - ~andy/linux/blob - drivers/staging/comedi/drivers/pcmmio.c
Merge tag 'stable/for-linus-3.8-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel...
[~andy/linux] / drivers / staging / comedi / drivers / pcmmio.c
1 /*
2     comedi/drivers/pcmmio.c
3     Driver for Winsystems PC-104 based multifunction IO board.
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2007 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: pcmmio
24 Description: A driver for the PCM-MIO multifunction board
25 Devices: [Winsystems] PCM-MIO (pcmmio)
26 Author: Calin Culianu <calin@ajvar.org>
27 Updated: Wed, May 16 2007 16:21:10 -0500
28 Status: works
29
30 A driver for the relatively new PCM-MIO multifunction board from
31 Winsystems.  This board is a PC-104 based I/O board.  It contains
32 four subdevices:
33   subdevice 0 - 16 channels of 16-bit AI
34   subdevice 1 - 8 channels of 16-bit AO
35   subdevice 2 - first 24 channels of the 48 channel of DIO
36         (with edge-triggered interrupt support)
37   subdevice 3 - last 24 channels of the 48 channel DIO
38         (no interrupt support for this bank of channels)
39
40   Some notes:
41
42   Synchronous reads and writes are the only things implemented for AI and AO,
43   even though the hardware itself can do streaming acquisition, etc.  Anyone
44   want to add asynchronous I/O for AI/AO as a feature?  Be my guest...
45
46   Asynchronous I/O for the DIO subdevices *is* implemented, however!  They are
47   basically edge-triggered interrupts for any configuration of the first
48   24 DIO-lines.
49
50   Also note that this interrupt support is untested.
51
52   A few words about edge-detection IRQ support (commands on DIO):
53
54   * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
55     of the board to the comedi_config command.  The board IRQ is not jumpered
56     but rather configured through software, so any IRQ from 1-15 is OK.
57
58   * Due to the genericity of the comedi API, you need to create a special
59     comedi_command in order to use edge-triggered interrupts for DIO.
60
61   * Use comedi_commands with TRIG_NOW.  Your callback will be called each
62     time an edge is detected on the specified DIO line(s), and the data
63     values will be two sample_t's, which should be concatenated to form
64     one 32-bit unsigned int.  This value is the mask of channels that had
65     edges detected from your channel list.  Note that the bits positions
66     in the mask correspond to positions in your chanlist when you
67     specified the command and *not* channel id's!
68
69  *  To set the polarity of the edge-detection interrupts pass a nonzero value
70     for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
71     value for both CR_RANGE and CR_AREF if you want edge-down polarity.
72
73 Configuration Options:
74   [0] - I/O port base address
75   [1] - IRQ (optional -- for edge-detect interrupt support only,
76         leave out if you don't need this feature)
77 */
78
79 #include <linux/interrupt.h>
80 #include <linux/slab.h>
81 #include "../comedidev.h"
82 #include "pcm_common.h"
83 #include <linux/pci.h>          /* for PCI devices */
84
85 /* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
86 #define CHANS_PER_PORT   8
87 #define PORTS_PER_ASIC   6
88 #define INTR_PORTS_PER_ASIC   3
89 #define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
90 #define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
91 #define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
92 #define INTR_CHANS_PER_ASIC 24
93 #define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
94 #define MAX_DIO_CHANS   (PORTS_PER_ASIC*1*CHANS_PER_PORT)
95 #define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
96 #define SDEV_NO ((int)(s - dev->subdevices))
97 #define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
98 /* IO Memory sizes */
99 #define ASIC_IOSIZE (0x0B)
100 #define PCMMIO48_IOSIZE ASIC_IOSIZE
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        /*
123                                  * page selector register, upper 2 bits select
124                                  * a page and bits 0-5 are used to 'lock down'
125                                  * a particular port above to make it readonly.
126                                  */
127 #define REG_POL0 0x8
128 #define REG_POL1 0x9
129 #define REG_POL2 0xA
130 #define REG_ENAB0 0x8
131 #define REG_ENAB1 0x9
132 #define REG_ENAB2 0xA
133 #define REG_INT_ID0 0x8
134 #define REG_INT_ID1 0x9
135 #define REG_INT_ID2 0xA
136
137 #define NUM_PAGED_REGS 3
138 #define NUM_PAGES 4
139 #define FIRST_PAGED_REG 0x8
140 #define REG_PAGE_BITOFFSET 6
141 #define REG_LOCK_BITOFFSET 0
142 #define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
143 #define REG_LOCK_MASK (~(REG_PAGE_MASK))
144 #define PAGE_POL 1
145 #define PAGE_ENAB 2
146 #define PAGE_INT_ID 3
147
148 static const struct comedi_lrange ranges_ai = {
149         4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
150 };
151
152 static const struct comedi_lrange ranges_ao = {
153         6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
154           RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
155 };
156
157 /* this structure is for data unique to this subdevice.  */
158 struct pcmmio_subdev_private {
159
160         union {
161                 /* for DIO: mapping of halfwords (bytes)
162                    in port/chanarray to iobase */
163                 unsigned long iobases[PORTS_PER_SUBDEV];
164
165                 /* for AI/AO */
166                 unsigned long iobase;
167         };
168         union {
169                 struct {
170
171                         /* The below is only used for intr subdevices */
172                         struct {
173                                 /*
174                                  * if non-negative, this subdev has an
175                                  * interrupt asic
176                                  */
177                                 int asic;
178                                 /*
179                                  * if nonnegative, the first channel id for
180                                  * interrupts.
181                                  */
182                                 int first_chan;
183                                 /*
184                                  * the number of asic channels in this subdev
185                                  * that have interrutps
186                                  */
187                                 int num_asic_chans;
188                                 /*
189                                  * if nonnegative, the first channel id with
190                                  * respect to the asic that has interrupts
191                                  */
192                                 int asic_chan;
193                                 /*
194                                  * subdev-relative channel mask for channels
195                                  * we are interested in
196                                  */
197                                 int enabled_mask;
198                                 int active;
199                                 int stop_count;
200                                 int continuous;
201                                 spinlock_t spinlock;
202                         } intr;
203                 } dio;
204                 struct {
205                         /* the last unsigned int data written */
206                         unsigned int shadow_samples[8];
207                 } ao;
208         };
209 };
210
211 /*
212  * this structure is for data unique to this hardware driver.  If
213  * several hardware drivers keep similar information in this structure,
214  * feel free to suggest moving the variable to the struct comedi_device struct.
215  */
216 struct pcmmio_private {
217         /* stuff for DIO */
218         struct {
219                 unsigned char pagelock; /* current page and lock */
220                 /* shadow of POLx registers */
221                 unsigned char pol[NUM_PAGED_REGS];
222                 /* shadow of ENABx registers */
223                 unsigned char enab[NUM_PAGED_REGS];
224                 int num;
225                 unsigned long iobase;
226                 unsigned int irq;
227                 spinlock_t spinlock;
228         } asics[MAX_ASICS];
229         struct pcmmio_subdev_private *sprivs;
230 };
231
232 #define subpriv ((struct pcmmio_subdev_private *)s->private)
233
234 /* DIO devices are slightly special.  Although it is possible to
235  * implement the insn_read/insn_write interface, it is much more
236  * useful to applications if you implement the insn_bits interface.
237  * This allows packed reading/writing of the DIO channels.  The
238  * comedi core can convert between insn_bits and insn_read/write */
239 static int pcmmio_dio_insn_bits(struct comedi_device *dev,
240                                 struct comedi_subdevice *s,
241                                 struct comedi_insn *insn, unsigned int *data)
242 {
243         int byte_no;
244
245         /* NOTE:
246            reading a 0 means this channel was high
247            writine a 0 sets the channel high
248            reading a 1 means this channel was low
249            writing a 1 means set this channel low
250
251            Therefore everything is always inverted. */
252
253         /* The insn data is a mask in data[0] and the new data
254          * in data[1], each channel cooresponding to a bit. */
255
256 #ifdef DAMMIT_ITS_BROKEN
257         /* DEBUG */
258         printk(KERN_DEBUG "write mask: %08x  data: %08x\n", data[0], data[1]);
259 #endif
260
261         s->state = 0;
262
263         for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
264                 /* address of 8-bit port */
265                 unsigned long ioaddr = subpriv->iobases[byte_no],
266                     /* bit offset of port in 32-bit doubleword */
267                     offset = byte_no * 8;
268                 /* this 8-bit port's data */
269                 unsigned char byte = 0,
270                     /* The write mask for this port (if any) */
271                     write_mask_byte = (data[0] >> offset) & 0xff,
272                     /* The data byte for this port */
273                     data_byte = (data[1] >> offset) & 0xff;
274
275                 byte = inb(ioaddr);     /* read all 8-bits for this port */
276
277 #ifdef DAMMIT_ITS_BROKEN
278                 /* DEBUG */
279                 printk
280                     (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
281                      " data_in %02x ", byte_no, (unsigned)write_mask_byte,
282                      (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
283 #endif
284
285                 if (write_mask_byte) {
286                         /*
287                          * this byte has some write_bits
288                          * -- so set the output lines
289                          */
290                         /* clear bits for write mask */
291                         byte &= ~write_mask_byte;
292                         /* set to inverted data_byte */
293                         byte |= ~data_byte & write_mask_byte;
294                         /* Write out the new digital output state */
295                         outb(byte, ioaddr);
296                 }
297 #ifdef DAMMIT_ITS_BROKEN
298                 /* DEBUG */
299                 printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
300 #endif
301                 /* save the digital input lines for this byte.. */
302                 s->state |= ((unsigned int)byte) << offset;
303         }
304
305         /* now return the DIO lines to data[1] - note they came inverted! */
306         data[1] = ~s->state;
307
308 #ifdef DAMMIT_ITS_BROKEN
309         /* DEBUG */
310         printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
311 #endif
312
313         return insn->n;
314 }
315
316 /* The input or output configuration of each digital line is
317  * configured by a special insn_config instruction.  chanspec
318  * contains the channel to be changed, and data[0] contains the
319  * value COMEDI_INPUT or COMEDI_OUTPUT. */
320 static int pcmmio_dio_insn_config(struct comedi_device *dev,
321                                   struct comedi_subdevice *s,
322                                   struct comedi_insn *insn, unsigned int *data)
323 {
324         int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
325             chan % 8;
326         unsigned long ioaddr;
327         unsigned char byte;
328
329         /* Compute ioaddr for this channel */
330         ioaddr = subpriv->iobases[byte_no];
331
332         /* NOTE:
333            writing a 0 an IO channel's bit sets the channel to INPUT
334            and pulls the line high as well
335
336            writing a 1 to an IO channel's  bit pulls the line low
337
338            All channels are implicitly always in OUTPUT mode -- but when
339            they are high they can be considered to be in INPUT mode..
340
341            Thus, we only force channels low if the config request was INPUT,
342            otherwise we do nothing to the hardware.    */
343
344         switch (data[0]) {
345         case INSN_CONFIG_DIO_OUTPUT:
346                 /* save to io_bits -- don't actually do anything since
347                    all input channels are also output channels... */
348                 s->io_bits |= 1 << chan;
349                 break;
350         case INSN_CONFIG_DIO_INPUT:
351                 /* write a 0 to the actual register representing the channel
352                    to set it to 'input'.  0 means "float high". */
353                 byte = inb(ioaddr);
354                 byte &= ~(1 << bit_no);
355                                 /**< set input channel to '0' */
356
357                 /*
358                  * write out byte -- this is the only time we actually affect
359                  * the hardware as all channels are implicitly output
360                  * -- but input channels are set to float-high
361                  */
362                 outb(byte, ioaddr);
363
364                 /* save to io_bits */
365                 s->io_bits &= ~(1 << chan);
366                 break;
367
368         case INSN_CONFIG_DIO_QUERY:
369                 /* retrieve from shadow register */
370                 data[1] =
371                     (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
372                 return insn->n;
373                 break;
374
375         default:
376                 return -EINVAL;
377                 break;
378         }
379
380         return insn->n;
381 }
382
383 static void switch_page(struct comedi_device *dev, int asic, int page)
384 {
385         struct pcmmio_private *devpriv = dev->private;
386
387         if (asic < 0 || asic >= 1)
388                 return;         /* paranoia */
389         if (page < 0 || page >= NUM_PAGES)
390                 return;         /* more paranoia */
391
392         devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
393         devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
394
395         /* now write out the shadow register */
396         outb(devpriv->asics[asic].pagelock,
397              devpriv->asics[asic].iobase + REG_PAGELOCK);
398 }
399
400 static void init_asics(struct comedi_device *dev)
401 {                               /* sets up an
402                                    ASIC chip to defaults */
403         struct pcmmio_private *devpriv = dev->private;
404         int asic;
405
406         for (asic = 0; asic < 1; ++asic) {
407                 int port, page;
408                 unsigned long baseaddr = devpriv->asics[asic].iobase;
409
410                 switch_page(dev, asic, 0);      /* switch back to page 0 */
411
412                 /* first, clear all the DIO port bits */
413                 for (port = 0; port < PORTS_PER_ASIC; ++port)
414                         outb(0, baseaddr + REG_PORT0 + port);
415
416                 /* Next, clear all the paged registers for each page */
417                 for (page = 1; page < NUM_PAGES; ++page) {
418                         int reg;
419                         /* now clear all the paged registers */
420                         switch_page(dev, asic, page);
421                         for (reg = FIRST_PAGED_REG;
422                              reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
423                                 outb(0, baseaddr + reg);
424                 }
425
426                 /* DEBUG  set rising edge interrupts on port0 of both asics */
427                 /*switch_page(dev, asic, PAGE_POL);
428                    outb(0xff, baseaddr + REG_POL0);
429                    switch_page(dev, asic, PAGE_ENAB);
430                    outb(0xff, baseaddr + REG_ENAB0); */
431                 /* END DEBUG */
432
433                 /* switch back to default page 0 */
434                 switch_page(dev, asic, 0);
435         }
436 }
437
438 #ifdef notused
439 static void lock_port(struct comedi_device *dev, int asic, int port)
440 {
441         struct pcmmio_private *devpriv = dev->private;
442
443         if (asic < 0 || asic >= 1)
444                 return;         /* paranoia */
445         if (port < 0 || port >= PORTS_PER_ASIC)
446                 return;         /* more paranoia */
447
448         devpriv->asics[asic].pagelock |= 0x1 << port;
449         /* now write out the shadow register */
450         outb(devpriv->asics[asic].pagelock,
451              devpriv->asics[asic].iobase + REG_PAGELOCK);
452         return;
453 }
454
455 static void unlock_port(struct comedi_device *dev, int asic, int port)
456 {
457         struct pcmmio_private *devpriv = dev->private;
458
459         if (asic < 0 || asic >= 1)
460                 return;         /* paranoia */
461         if (port < 0 || port >= PORTS_PER_ASIC)
462                 return;         /* more paranoia */
463         devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
464         /* now write out the shadow register */
465         outb(devpriv->asics[asic].pagelock,
466              devpriv->asics[asic].iobase + REG_PAGELOCK);
467 }
468 #endif /* notused */
469
470 static void pcmmio_stop_intr(struct comedi_device *dev,
471                              struct comedi_subdevice *s)
472 {
473         struct pcmmio_private *devpriv = dev->private;
474         int nports, firstport, asic, port;
475
476         asic = subpriv->dio.intr.asic;
477         if (asic < 0)
478                 return;         /* not an interrupt subdev */
479
480         subpriv->dio.intr.enabled_mask = 0;
481         subpriv->dio.intr.active = 0;
482         s->async->inttrig = NULL;
483         nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
484         firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
485         switch_page(dev, asic, PAGE_ENAB);
486         for (port = firstport; port < firstport + nports; ++port) {
487                 /* disable all intrs for this subdev.. */
488                 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
489         }
490 }
491
492 static irqreturn_t interrupt_pcmmio(int irq, void *d)
493 {
494         int asic, got1 = 0;
495         struct comedi_device *dev = (struct comedi_device *)d;
496         struct pcmmio_private *devpriv = dev->private;
497         int i;
498
499         for (asic = 0; asic < MAX_ASICS; ++asic) {
500                 if (irq == devpriv->asics[asic].irq) {
501                         unsigned long flags;
502                         unsigned triggered = 0;
503                         unsigned long iobase = devpriv->asics[asic].iobase;
504                         /* it is an interrupt for ASIC #asic */
505                         unsigned char int_pend;
506
507                         spin_lock_irqsave(&devpriv->asics[asic].spinlock,
508                                           flags);
509
510                         int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
511
512                         if (int_pend) {
513                                 int port;
514                                 for (port = 0; port < INTR_PORTS_PER_ASIC;
515                                      ++port) {
516                                         if (int_pend & (0x1 << port)) {
517                                                 unsigned char
518                                                     io_lines_with_edges = 0;
519                                                 switch_page(dev, asic,
520                                                             PAGE_INT_ID);
521                                                 io_lines_with_edges =
522                                                     inb(iobase +
523                                                         REG_INT_ID0 + port);
524
525                                                 if (io_lines_with_edges)
526                                                         /*
527                                                          * clear pending
528                                                          * interrupt
529                                                          */
530                                                         outb(0, iobase +
531                                                              REG_INT_ID0 +
532                                                              port);
533
534                                                 triggered |=
535                                                     io_lines_with_edges <<
536                                                     port * 8;
537                                         }
538                                 }
539
540                                 ++got1;
541                         }
542
543                         spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
544                                                flags);
545
546                         if (triggered) {
547                                 struct comedi_subdevice *s;
548                                 /*
549                                  * TODO here: dispatch io lines to subdevs
550                                  * with commands..
551                                  */
552                                 printk
553                                     (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
554                                      irq, asic, triggered);
555                                 for (i = 2; i < dev->n_subdevices; i++) {
556                                         s = &dev->subdevices[i];
557                                         /*
558                                          * this is an interrupt subdev,
559                                          * and it matches this asic!
560                                          */
561                                         if (subpriv->dio.intr.asic == asic) {
562                                                 unsigned long flags;
563                                                 unsigned oldevents;
564
565                                                 spin_lock_irqsave(&subpriv->dio.
566                                                                   intr.spinlock,
567                                                                   flags);
568
569                                                 oldevents = s->async->events;
570
571                                                 if (subpriv->dio.intr.active) {
572                                                         unsigned mytrig =
573                                                             ((triggered >>
574                                                               subpriv->dio.intr.asic_chan)
575                                                              &
576                                                              ((0x1 << subpriv->
577                                                                dio.intr.
578                                                                num_asic_chans) -
579                                                               1)) << subpriv->
580                                                             dio.intr.first_chan;
581                                                         if (mytrig &
582                                                             subpriv->dio.
583                                                             intr.enabled_mask) {
584                                                                 unsigned int val
585                                                                     = 0;
586                                                                 unsigned int n,
587                                                                     ch, len;
588
589                                                                 len =
590                                                                     s->
591                                                                     async->cmd.chanlist_len;
592                                                                 for (n = 0;
593                                                                      n < len;
594                                                                      n++) {
595                                                                         ch = CR_CHAN(s->async->cmd.chanlist[n]);
596                                                                         if (mytrig & (1U << ch))
597                                                                                 val |= (1U << n);
598                                                                 }
599                                                                 /* Write the scan to the buffer. */
600                                                                 if (comedi_buf_put(s->async, ((short *)&val)[0])
601                                                                     &&
602                                                                     comedi_buf_put
603                                                                     (s->async,
604                                                                      ((short *)
605                                                                       &val)[1])) {
606                                                                         s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
607                                                                 } else {
608                                                                         /* Overflow! Stop acquisition!! */
609                                                                         /* TODO: STOP_ACQUISITION_CALL_HERE!! */
610                                                                         pcmmio_stop_intr
611                                                                             (dev,
612                                                                              s);
613                                                                 }
614
615                                                                 /* Check for end of acquisition. */
616                                                                 if (!subpriv->dio.intr.continuous) {
617                                                                         /* stop_src == TRIG_COUNT */
618                                                                         if (subpriv->dio.intr.stop_count > 0) {
619                                                                                 subpriv->dio.intr.stop_count--;
620                                                                                 if (subpriv->dio.intr.stop_count == 0) {
621                                                                                         s->async->events |= COMEDI_CB_EOA;
622                                                                                         /* TODO: STOP_ACQUISITION_CALL_HERE!! */
623                                                                                         pcmmio_stop_intr
624                                                                                             (dev,
625                                                                                              s);
626                                                                                 }
627                                                                         }
628                                                                 }
629                                                         }
630                                                 }
631
632                                                 spin_unlock_irqrestore
633                                                     (&subpriv->dio.intr.
634                                                      spinlock, flags);
635
636                                                 if (oldevents !=
637                                                     s->async->events) {
638                                                         comedi_event(dev, s);
639                                                 }
640
641                                         }
642
643                                 }
644                         }
645
646                 }
647         }
648         if (!got1)
649                 return IRQ_NONE;        /* interrupt from other source */
650         return IRQ_HANDLED;
651 }
652
653 static int pcmmio_start_intr(struct comedi_device *dev,
654                              struct comedi_subdevice *s)
655 {
656         struct pcmmio_private *devpriv = dev->private;
657
658         if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
659                 /* An empty acquisition! */
660                 s->async->events |= COMEDI_CB_EOA;
661                 subpriv->dio.intr.active = 0;
662                 return 1;
663         } else {
664                 unsigned bits = 0, pol_bits = 0, n;
665                 int nports, firstport, asic, port;
666                 struct comedi_cmd *cmd = &s->async->cmd;
667
668                 asic = subpriv->dio.intr.asic;
669                 if (asic < 0)
670                         return 1;       /* not an interrupt
671                                            subdev */
672                 subpriv->dio.intr.enabled_mask = 0;
673                 subpriv->dio.intr.active = 1;
674                 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
675                 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
676                 if (cmd->chanlist) {
677                         for (n = 0; n < cmd->chanlist_len; n++) {
678                                 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
679                                 pol_bits |= (CR_AREF(cmd->chanlist[n])
680                                              || CR_RANGE(cmd->
681                                                          chanlist[n]) ? 1U : 0U)
682                                     << CR_CHAN(cmd->chanlist[n]);
683                         }
684                 }
685                 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
686                          1) << subpriv->dio.intr.first_chan;
687                 subpriv->dio.intr.enabled_mask = bits;
688
689                 {
690                         /*
691                          * the below code configures the board
692                          * to use a specific IRQ from 0-15.
693                          */
694                         unsigned char b;
695                         /*
696                          * set resource enable register
697                          * to enable IRQ operation
698                          */
699                         outb(1 << 4, dev->iobase + 3);
700                         /* set bits 0-3 of b to the irq number from 0-15 */
701                         b = dev->irq & ((1 << 4) - 1);
702                         outb(b, dev->iobase + 2);
703                         /* done, we told the board what irq to use */
704                 }
705
706                 switch_page(dev, asic, PAGE_ENAB);
707                 for (port = firstport; port < firstport + nports; ++port) {
708                         unsigned enab =
709                             bits >> (subpriv->dio.intr.first_chan + (port -
710                                                                      firstport)
711                                      * 8) & 0xff, pol =
712                             pol_bits >> (subpriv->dio.intr.first_chan +
713                                          (port - firstport) * 8) & 0xff;
714                         /* set enab intrs for this subdev.. */
715                         outb(enab,
716                              devpriv->asics[asic].iobase + REG_ENAB0 + port);
717                         switch_page(dev, asic, PAGE_POL);
718                         outb(pol,
719                              devpriv->asics[asic].iobase + REG_ENAB0 + port);
720                 }
721         }
722         return 0;
723 }
724
725 static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
726 {
727         unsigned long flags;
728
729         spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
730         if (subpriv->dio.intr.active)
731                 pcmmio_stop_intr(dev, s);
732         spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
733
734         return 0;
735 }
736
737 /*
738  * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
739  */
740 static int
741 pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
742                           unsigned int trignum)
743 {
744         unsigned long flags;
745         int event = 0;
746
747         if (trignum != 0)
748                 return -EINVAL;
749
750         spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
751         s->async->inttrig = NULL;
752         if (subpriv->dio.intr.active)
753                 event = pcmmio_start_intr(dev, s);
754         spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
755
756         if (event)
757                 comedi_event(dev, s);
758
759         return 1;
760 }
761
762 /*
763  * 'do_cmd' function for an 'INTERRUPT' subdevice.
764  */
765 static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
766 {
767         struct comedi_cmd *cmd = &s->async->cmd;
768         unsigned long flags;
769         int event = 0;
770
771         spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
772         subpriv->dio.intr.active = 1;
773
774         /* Set up end of acquisition. */
775         switch (cmd->stop_src) {
776         case TRIG_COUNT:
777                 subpriv->dio.intr.continuous = 0;
778                 subpriv->dio.intr.stop_count = cmd->stop_arg;
779                 break;
780         default:
781                 /* TRIG_NONE */
782                 subpriv->dio.intr.continuous = 1;
783                 subpriv->dio.intr.stop_count = 0;
784                 break;
785         }
786
787         /* Set up start of acquisition. */
788         switch (cmd->start_src) {
789         case TRIG_INT:
790                 s->async->inttrig = pcmmio_inttrig_start_intr;
791                 break;
792         default:
793                 /* TRIG_NOW */
794                 event = pcmmio_start_intr(dev, s);
795                 break;
796         }
797         spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
798
799         if (event)
800                 comedi_event(dev, s);
801
802         return 0;
803 }
804
805 static int
806 pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
807                struct comedi_cmd *cmd)
808 {
809         return comedi_pcm_cmdtest(dev, s, cmd);
810 }
811
812 static int adc_wait_ready(unsigned long iobase)
813 {
814         unsigned long retry = 100000;
815         while (retry--)
816                 if (inb(iobase + 3) & 0x80)
817                         return 0;
818         return 1;
819 }
820
821 /* All this is for AI and AO */
822 static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
823                     struct comedi_insn *insn, unsigned int *data)
824 {
825         int n;
826         unsigned long iobase = subpriv->iobase;
827
828         /*
829            1. write the CMD byte (to BASE+2)
830            2. read junk lo byte (BASE+0)
831            3. read junk hi byte (BASE+1)
832            4. (mux settled so) write CMD byte again (BASE+2)
833            5. read valid lo byte(BASE+0)
834            6. read valid hi byte(BASE+1)
835
836            Additionally note that the BASE += 4 if the channel >= 8
837          */
838
839         /* convert n samples */
840         for (n = 0; n < insn->n; n++) {
841                 unsigned chan = CR_CHAN(insn->chanspec), range =
842                     CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
843                 unsigned char command_byte = 0;
844                 unsigned iooffset = 0;
845                 short sample, adc_adjust = 0;
846
847                 if (chan > 7)
848                         chan -= 8, iooffset = 4;        /*
849                                                          * use the second dword
850                                                          * for channels > 7
851                                                          */
852
853                 if (aref != AREF_DIFF) {
854                         aref = AREF_GROUND;
855                         command_byte |= 1 << 7; /*
856                                                  * set bit 7 to indicate
857                                                  * single-ended
858                                                  */
859                 }
860                 if (range < 2)
861                         adc_adjust = 0x8000;    /*
862                                                  * bipolar ranges
863                                                  * (-5,5 .. -10,10 need to be
864                                                  * adjusted -- that is.. they
865                                                  * need to wrap around by
866                                                  * adding 0x8000
867                                                  */
868
869                 if (chan % 2) {
870                         command_byte |= 1 << 6; /*
871                                                  * odd-numbered channels
872                                                  * have bit 6 set
873                                                  */
874                 }
875
876                 /* select the channel, bits 4-5 == chan/2 */
877                 command_byte |= ((chan / 2) & 0x3) << 4;
878
879                 /* set the range, bits 2-3 */
880                 command_byte |= (range & 0x3) << 2;
881
882                 /* need to do this twice to make sure mux settled */
883                 /* chan/range/aref select */
884                 outb(command_byte, iobase + iooffset + 2);
885
886                 /* wait for the adc to say it finised the conversion */
887                 adc_wait_ready(iobase + iooffset);
888
889                 /* select the chan/range/aref AGAIN */
890                 outb(command_byte, iobase + iooffset + 2);
891
892                 adc_wait_ready(iobase + iooffset);
893
894                 /* read data lo byte */
895                 sample = inb(iobase + iooffset + 0);
896
897                 /* read data hi byte */
898                 sample |= inb(iobase + iooffset + 1) << 8;
899                 sample += adc_adjust;   /* adjustment .. munge data */
900                 data[n] = sample;
901         }
902         /* return the number of samples read/written */
903         return n;
904 }
905
906 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
907                     struct comedi_insn *insn, unsigned int *data)
908 {
909         int n;
910         for (n = 0; n < insn->n; n++) {
911                 unsigned chan = CR_CHAN(insn->chanspec);
912                 if (chan < s->n_chan)
913                         data[n] = subpriv->ao.shadow_samples[chan];
914         }
915         return n;
916 }
917
918 static int wait_dac_ready(unsigned long iobase)
919 {
920         unsigned long retry = 100000L;
921
922         /* This may seem like an absurd way to handle waiting and violates the
923            "no busy waiting" policy. The fact is that the hardware is
924            normally so fast that we usually only need one time through the loop
925            anyway. The longer timeout is for rare occasions and for detecting
926            non-existent hardware.  */
927
928         while (retry--) {
929                 if (inb(iobase + 3) & 0x80)
930                         return 0;
931
932         }
933         return 1;
934 }
935
936 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
937                     struct comedi_insn *insn, unsigned int *data)
938 {
939         int n;
940         unsigned iobase = subpriv->iobase, iooffset = 0;
941
942         for (n = 0; n < insn->n; n++) {
943                 unsigned chan = CR_CHAN(insn->chanspec), range =
944                     CR_RANGE(insn->chanspec);
945                 if (chan < s->n_chan) {
946                         unsigned char command_byte = 0, range_byte =
947                             range & ((1 << 4) - 1);
948                         if (chan >= 4)
949                                 chan -= 4, iooffset += 4;
950                         /* set the range.. */
951                         outb(range_byte, iobase + iooffset + 0);
952                         outb(0, iobase + iooffset + 1);
953
954                         /* tell it to begin */
955                         command_byte = (chan << 1) | 0x60;
956                         outb(command_byte, iobase + iooffset + 2);
957
958                         wait_dac_ready(iobase + iooffset);
959
960                         /* low order byte */
961                         outb(data[n] & 0xff, iobase + iooffset + 0);
962
963                         /* high order byte */
964                         outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
965
966                         /*
967                          * set bit 4 of command byte to indicate
968                          * data is loaded and trigger conversion
969                          */
970                         command_byte = 0x70 | (chan << 1);
971                         /* trigger converion */
972                         outb(command_byte, iobase + iooffset + 2);
973
974                         wait_dac_ready(iobase + iooffset);
975
976                         /* save to shadow register for ao_rinsn */
977                         subpriv->ao.shadow_samples[chan] = data[n];
978                 }
979         }
980         return n;
981 }
982
983 static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
984 {
985         struct pcmmio_private *devpriv;
986         struct comedi_subdevice *s;
987         int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
988             thisasic_chanct = 0;
989         unsigned long iobase;
990         unsigned int irq[MAX_ASICS];
991         int ret;
992
993         dev->board_name = dev->driver->driver_name;
994
995         iobase = it->options[0];
996         irq[0] = it->options[1];
997
998         printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
999                         dev->board_name, iobase);
1000
1001         dev->iobase = iobase;
1002
1003         if (!iobase || !request_region(iobase, 32, dev->board_name)) {
1004                 printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
1005                 return -EIO;
1006         }
1007
1008         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1009         if (!devpriv)
1010                 return -ENOMEM;
1011         dev->private = devpriv;
1012
1013         for (asic = 0; asic < MAX_ASICS; ++asic) {
1014                 devpriv->asics[asic].num = asic;
1015                 devpriv->asics[asic].iobase =
1016                     dev->iobase + 16 + asic * ASIC_IOSIZE;
1017                 /*
1018                  * this gets actually set at the end of this function when we
1019                  * request_irqs
1020                  */
1021                 devpriv->asics[asic].irq = 0;
1022                 spin_lock_init(&devpriv->asics[asic].spinlock);
1023         }
1024
1025         chans_left = CHANS_PER_ASIC * 1;
1026         n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
1027         n_subdevs = n_dio_subdevs + 2;
1028         devpriv->sprivs =
1029             kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
1030                     GFP_KERNEL);
1031         if (!devpriv->sprivs) {
1032                 printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
1033                                 dev->minor);
1034                 return -ENOMEM;
1035         }
1036
1037         ret = comedi_alloc_subdevices(dev, n_subdevs);
1038         if (ret)
1039                 return ret;
1040
1041         /* First, AI */
1042         s = &dev->subdevices[0];
1043         s->private = &devpriv->sprivs[0];
1044         s->maxdata = 0xffff;
1045         s->range_table = &ranges_ai;
1046         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
1047         s->type = COMEDI_SUBD_AI;
1048         s->n_chan = 16;
1049         s->len_chanlist = s->n_chan;
1050         s->insn_read = ai_rinsn;
1051         subpriv->iobase = dev->iobase + 0;
1052         /* initialize the resource enable register by clearing it */
1053         outb(0, subpriv->iobase + 3);
1054         outb(0, subpriv->iobase + 4 + 3);
1055
1056         /* Next, AO */
1057         s = &dev->subdevices[1];
1058         s->private = &devpriv->sprivs[1];
1059         s->maxdata = 0xffff;
1060         s->range_table = &ranges_ao;
1061         s->subdev_flags = SDF_READABLE;
1062         s->type = COMEDI_SUBD_AO;
1063         s->n_chan = 8;
1064         s->len_chanlist = s->n_chan;
1065         s->insn_read = ao_rinsn;
1066         s->insn_write = ao_winsn;
1067         subpriv->iobase = dev->iobase + 8;
1068         /* initialize the resource enable register by clearing it */
1069         outb(0, subpriv->iobase + 3);
1070         outb(0, subpriv->iobase + 4 + 3);
1071
1072         port = 0;
1073         asic = 0;
1074         for (sdev_no = 2; sdev_no < dev->n_subdevices; ++sdev_no) {
1075                 int byte_no;
1076
1077                 s = &dev->subdevices[sdev_no];
1078                 s->private = &devpriv->sprivs[sdev_no];
1079                 s->maxdata = 1;
1080                 s->range_table = &range_digital;
1081                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1082                 s->type = COMEDI_SUBD_DIO;
1083                 s->insn_bits = pcmmio_dio_insn_bits;
1084                 s->insn_config = pcmmio_dio_insn_config;
1085                 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
1086                 subpriv->dio.intr.asic = -1;
1087                 subpriv->dio.intr.first_chan = -1;
1088                 subpriv->dio.intr.asic_chan = -1;
1089                 subpriv->dio.intr.num_asic_chans = -1;
1090                 subpriv->dio.intr.active = 0;
1091                 s->len_chanlist = 1;
1092
1093                 /* save the ioport address for each 'port' of 8 channels in the
1094                    subdevice */
1095                 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
1096                         if (port >= PORTS_PER_ASIC) {
1097                                 port = 0;
1098                                 ++asic;
1099                                 thisasic_chanct = 0;
1100                         }
1101                         subpriv->iobases[byte_no] =
1102                             devpriv->asics[asic].iobase + port;
1103
1104                         if (thisasic_chanct <
1105                             CHANS_PER_PORT * INTR_PORTS_PER_ASIC
1106                             && subpriv->dio.intr.asic < 0) {
1107                                 /*
1108                                  * this is an interrupt subdevice,
1109                                  * so setup the struct
1110                                  */
1111                                 subpriv->dio.intr.asic = asic;
1112                                 subpriv->dio.intr.active = 0;
1113                                 subpriv->dio.intr.stop_count = 0;
1114                                 subpriv->dio.intr.first_chan = byte_no * 8;
1115                                 subpriv->dio.intr.asic_chan = thisasic_chanct;
1116                                 subpriv->dio.intr.num_asic_chans =
1117                                     s->n_chan - subpriv->dio.intr.first_chan;
1118                                 s->cancel = pcmmio_cancel;
1119                                 s->do_cmd = pcmmio_cmd;
1120                                 s->do_cmdtest = pcmmio_cmdtest;
1121                                 s->len_chanlist =
1122                                     subpriv->dio.intr.num_asic_chans;
1123                         }
1124                         thisasic_chanct += CHANS_PER_PORT;
1125                 }
1126                 spin_lock_init(&subpriv->dio.intr.spinlock);
1127
1128                 chans_left -= s->n_chan;
1129
1130                 if (!chans_left) {
1131                         /*
1132                          * reset the asic to our first asic,
1133                          * to do intr subdevs
1134                          */
1135                         asic = 0;
1136                         port = 0;
1137                 }
1138
1139         }
1140
1141         init_asics(dev);        /* clear out all the registers, basically */
1142
1143         for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
1144                 if (irq[asic]
1145                     && request_irq(irq[asic], interrupt_pcmmio,
1146                                    IRQF_SHARED, dev->board_name, dev)) {
1147                         int i;
1148                         /* unroll the allocated irqs.. */
1149                         for (i = asic - 1; i >= 0; --i) {
1150                                 free_irq(irq[i], dev);
1151                                 devpriv->asics[i].irq = irq[i] = 0;
1152                         }
1153                         irq[asic] = 0;
1154                 }
1155                 devpriv->asics[asic].irq = irq[asic];
1156         }
1157
1158         dev->irq = irq[0];      /*
1159                                  * grr.. wish comedi dev struct supported
1160                                  * multiple irqs..
1161                                  */
1162
1163         printk(KERN_INFO "comedi%d: attached\n", dev->minor);
1164
1165         return 1;
1166 }
1167
1168 static void pcmmio_detach(struct comedi_device *dev)
1169 {
1170         struct pcmmio_private *devpriv = dev->private;
1171         int i;
1172
1173         if (dev->iobase)
1174                 release_region(dev->iobase, 32);
1175         for (i = 0; i < MAX_ASICS; ++i) {
1176                 if (devpriv && devpriv->asics[i].irq)
1177                         free_irq(devpriv->asics[i].irq, dev);
1178         }
1179         if (devpriv && devpriv->sprivs)
1180                 kfree(devpriv->sprivs);
1181 }
1182
1183 static struct comedi_driver pcmmio_driver = {
1184         .driver_name    = "pcmmio",
1185         .module         = THIS_MODULE,
1186         .attach         = pcmmio_attach,
1187         .detach         = pcmmio_detach,
1188 };
1189 module_comedi_driver(pcmmio_driver);
1190
1191 MODULE_AUTHOR("Comedi http://www.comedi.org");
1192 MODULE_DESCRIPTION("Comedi low-level driver");
1193 MODULE_LICENSE("GPL");