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