root/drivers/staging/comedi/drivers/amplc_pci224.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pci224_clk_config
  2. pci224_gat_config
  3. pci224_ao_set_data
  4. pci224_ao_insn_write
  5. pci224_ao_stop
  6. pci224_ao_start
  7. pci224_ao_handle_fifo
  8. pci224_ao_inttrig_start
  9. pci224_ao_check_chanlist
  10. pci224_ao_cmdtest
  11. pci224_ao_start_pacer
  12. pci224_ao_cmd
  13. pci224_ao_cancel
  14. pci224_ao_munge
  15. pci224_interrupt
  16. pci224_auto_attach
  17. pci224_detach
  18. amplc_pci224_pci_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * comedi/drivers/amplc_pci224.c
   4  * Driver for Amplicon PCI224 and PCI234 AO boards.
   5  *
   6  * Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/>
   7  *
   8  * COMEDI - Linux Control and Measurement Device Interface
   9  * Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
  10  */
  11 
  12 /*
  13  * Driver: amplc_pci224
  14  * Description: Amplicon PCI224, PCI234
  15  * Author: Ian Abbott <abbotti@mev.co.uk>
  16  * Devices: [Amplicon] PCI224 (amplc_pci224), PCI234
  17  * Updated: Thu, 31 Jul 2014 11:08:03 +0000
  18  * Status: works, but see caveats
  19  *
  20  * Supports:
  21  *
  22  *   - ao_insn read/write
  23  *   - ao_do_cmd mode with the following sources:
  24  *
  25  *     - start_src         TRIG_INT        TRIG_EXT
  26  *     - scan_begin_src    TRIG_TIMER      TRIG_EXT
  27  *     - convert_src       TRIG_NOW
  28  *     - scan_end_src      TRIG_COUNT
  29  *     - stop_src          TRIG_COUNT      TRIG_EXT        TRIG_NONE
  30  *
  31  *     The channel list must contain at least one channel with no repeated
  32  *     channels.  The scan end count must equal the number of channels in
  33  *     the channel list.
  34  *
  35  *     There is only one external trigger source so only one of start_src,
  36  *     scan_begin_src or stop_src may use TRIG_EXT.
  37  *
  38  * Configuration options:
  39  *   none
  40  *
  41  * Manual configuration of PCI cards is not supported; they are configured
  42  * automatically.
  43  *
  44  * Output range selection - PCI224:
  45  *
  46  *   Output ranges on PCI224 are partly software-selectable and partly
  47  *   hardware-selectable according to jumper LK1.  All channels are set
  48  *   to the same range:
  49  *
  50  *   - LK1 position 1-2 (factory default) corresponds to the following
  51  *     comedi ranges:
  52  *
  53  *       0: [-10V,+10V]; 1: [-5V,+5V]; 2: [-2.5V,+2.5V], 3: [-1.25V,+1.25V],
  54  *       4: [0,+10V],    5: [0,+5V],   6: [0,+2.5V],     7: [0,+1.25V]
  55  *
  56  *   - LK1 position 2-3 corresponds to the following Comedi ranges, using
  57  *     an external voltage reference:
  58  *
  59  *       0: [-Vext,+Vext],
  60  *       1: [0,+Vext]
  61  *
  62  * Output range selection - PCI234:
  63  *
  64  *   Output ranges on PCI234 are hardware-selectable according to jumper
  65  *   LK1 which affects all channels, and jumpers LK2, LK3, LK4 and LK5
  66  *   which affect channels 0, 1, 2 and 3 individually.  LK1 chooses between
  67  *   an internal 5V reference and an external voltage reference (Vext).
  68  *   LK2/3/4/5 choose (per channel) to double the reference or not according
  69  *   to the following table:
  70  *
  71  *     LK1 position   LK2/3/4/5 pos  Comedi range
  72  *     -------------  -------------  --------------
  73  *     2-3 (factory)  1-2 (factory)  0: [-10V,+10V]
  74  *     2-3 (factory)  2-3            1: [-5V,+5V]
  75  *     1-2            1-2 (factory)  2: [-2*Vext,+2*Vext]
  76  *     1-2            2-3            3: [-Vext,+Vext]
  77  *
  78  * Caveats:
  79  *
  80  *   1) All channels on the PCI224 share the same range.  Any change to the
  81  *      range as a result of insn_write or a streaming command will affect
  82  *      the output voltages of all channels, including those not specified
  83  *      by the instruction or command.
  84  *
  85  *   2) For the analog output command,  the first scan may be triggered
  86  *      falsely at the start of acquisition.  This occurs when the DAC scan
  87  *      trigger source is switched from 'none' to 'timer' (scan_begin_src =
  88  *      TRIG_TIMER) or 'external' (scan_begin_src == TRIG_EXT) at the start
  89  *      of acquisition and the trigger source is at logic level 1 at the
  90  *      time of the switch.  This is very likely for TRIG_TIMER.  For
  91  *      TRIG_EXT, it depends on the state of the external line and whether
  92  *      the CR_INVERT flag has been set.  The remaining scans are triggered
  93  *      correctly.
  94  */
  95 
  96 #include <linux/module.h>
  97 #include <linux/interrupt.h>
  98 #include <linux/slab.h>
  99 
 100 #include "../comedi_pci.h"
 101 
 102 #include "comedi_8254.h"
 103 
 104 /*
 105  * PCI224/234 i/o space 1 (PCIBAR2) registers.
 106  */
 107 #define PCI224_Z2_BASE  0x14    /* 82C54 counter/timer */
 108 #define PCI224_ZCLK_SCE 0x1A    /* Group Z Clock Configuration Register */
 109 #define PCI224_ZGAT_SCE 0x1D    /* Group Z Gate Configuration Register */
 110 #define PCI224_INT_SCE  0x1E    /* ISR Interrupt source mask register */
 111                                 /* /Interrupt status */
 112 
 113 /*
 114  * PCI224/234 i/o space 2 (PCIBAR3) 16-bit registers.
 115  */
 116 #define PCI224_DACDATA  0x00    /* (w-o) DAC FIFO data. */
 117 #define PCI224_SOFTTRIG 0x00    /* (r-o) DAC software scan trigger. */
 118 #define PCI224_DACCON   0x02    /* (r/w) DAC status/configuration. */
 119 #define PCI224_FIFOSIZ  0x04    /* (w-o) FIFO size for wraparound mode. */
 120 #define PCI224_DACCEN   0x06    /* (w-o) DAC channel enable register. */
 121 
 122 /*
 123  * DACCON values.
 124  */
 125 /* (r/w) Scan trigger. */
 126 #define PCI224_DACCON_TRIG(x)           (((x) & 0x7) << 0)
 127 #define PCI224_DACCON_TRIG_MASK         PCI224_DACCON_TRIG(7)
 128 #define PCI224_DACCON_TRIG_NONE         PCI224_DACCON_TRIG(0)   /* none */
 129 #define PCI224_DACCON_TRIG_SW           PCI224_DACCON_TRIG(1)   /* soft trig */
 130 #define PCI224_DACCON_TRIG_EXTP         PCI224_DACCON_TRIG(2)   /* ext + edge */
 131 #define PCI224_DACCON_TRIG_EXTN         PCI224_DACCON_TRIG(3)   /* ext - edge */
 132 #define PCI224_DACCON_TRIG_Z2CT0        PCI224_DACCON_TRIG(4)   /* Z2 CT0 out */
 133 #define PCI224_DACCON_TRIG_Z2CT1        PCI224_DACCON_TRIG(5)   /* Z2 CT1 out */
 134 #define PCI224_DACCON_TRIG_Z2CT2        PCI224_DACCON_TRIG(6)   /* Z2 CT2 out */
 135 /* (r/w) Polarity (PCI224 only, PCI234 always bipolar!). */
 136 #define PCI224_DACCON_POLAR(x)          (((x) & 0x1) << 3)
 137 #define PCI224_DACCON_POLAR_MASK        PCI224_DACCON_POLAR(1)
 138 #define PCI224_DACCON_POLAR_UNI         PCI224_DACCON_POLAR(0)  /* [0,+V] */
 139 #define PCI224_DACCON_POLAR_BI          PCI224_DACCON_POLAR(1)  /* [-V,+V] */
 140 /* (r/w) Internal Vref (PCI224 only, when LK1 in position 1-2). */
 141 #define PCI224_DACCON_VREF(x)           (((x) & 0x3) << 4)
 142 #define PCI224_DACCON_VREF_MASK         PCI224_DACCON_VREF(3)
 143 #define PCI224_DACCON_VREF_1_25         PCI224_DACCON_VREF(0)   /* 1.25V */
 144 #define PCI224_DACCON_VREF_2_5          PCI224_DACCON_VREF(1)   /* 2.5V */
 145 #define PCI224_DACCON_VREF_5            PCI224_DACCON_VREF(2)   /* 5V */
 146 #define PCI224_DACCON_VREF_10           PCI224_DACCON_VREF(3)   /* 10V */
 147 /* (r/w) Wraparound mode enable (to play back stored waveform). */
 148 #define PCI224_DACCON_FIFOWRAP          BIT(7)
 149 /* (r/w) FIFO enable.  It MUST be set! */
 150 #define PCI224_DACCON_FIFOENAB          BIT(8)
 151 /* (r/w) FIFO interrupt trigger level (most values are not very useful). */
 152 #define PCI224_DACCON_FIFOINTR(x)       (((x) & 0x7) << 9)
 153 #define PCI224_DACCON_FIFOINTR_MASK     PCI224_DACCON_FIFOINTR(7)
 154 #define PCI224_DACCON_FIFOINTR_EMPTY    PCI224_DACCON_FIFOINTR(0) /* empty */
 155 #define PCI224_DACCON_FIFOINTR_NEMPTY   PCI224_DACCON_FIFOINTR(1) /* !empty */
 156 #define PCI224_DACCON_FIFOINTR_NHALF    PCI224_DACCON_FIFOINTR(2) /* !half */
 157 #define PCI224_DACCON_FIFOINTR_HALF     PCI224_DACCON_FIFOINTR(3) /* half */
 158 #define PCI224_DACCON_FIFOINTR_NFULL    PCI224_DACCON_FIFOINTR(4) /* !full */
 159 #define PCI224_DACCON_FIFOINTR_FULL     PCI224_DACCON_FIFOINTR(5) /* full */
 160 /* (r-o) FIFO fill level. */
 161 #define PCI224_DACCON_FIFOFL(x)         (((x) & 0x7) << 12)
 162 #define PCI224_DACCON_FIFOFL_MASK       PCI224_DACCON_FIFOFL(7)
 163 #define PCI224_DACCON_FIFOFL_EMPTY      PCI224_DACCON_FIFOFL(1) /* 0 */
 164 #define PCI224_DACCON_FIFOFL_ONETOHALF  PCI224_DACCON_FIFOFL(0) /* 1-2048 */
 165 #define PCI224_DACCON_FIFOFL_HALFTOFULL PCI224_DACCON_FIFOFL(4) /* 2049-4095 */
 166 #define PCI224_DACCON_FIFOFL_FULL       PCI224_DACCON_FIFOFL(6) /* 4096 */
 167 /* (r-o) DAC busy flag. */
 168 #define PCI224_DACCON_BUSY              BIT(15)
 169 /* (w-o) FIFO reset. */
 170 #define PCI224_DACCON_FIFORESET         BIT(12)
 171 /* (w-o) Global reset (not sure what it does). */
 172 #define PCI224_DACCON_GLOBALRESET       BIT(13)
 173 
 174 /*
 175  * DAC FIFO size.
 176  */
 177 #define PCI224_FIFO_SIZE        4096
 178 
 179 /*
 180  * DAC FIFO guaranteed minimum room available, depending on reported fill level.
 181  * The maximum room available depends on the reported fill level and how much
 182  * has been written!
 183  */
 184 #define PCI224_FIFO_ROOM_EMPTY          PCI224_FIFO_SIZE
 185 #define PCI224_FIFO_ROOM_ONETOHALF      (PCI224_FIFO_SIZE / 2)
 186 #define PCI224_FIFO_ROOM_HALFTOFULL     1
 187 #define PCI224_FIFO_ROOM_FULL           0
 188 
 189 /*
 190  * Counter/timer clock input configuration sources.
 191  */
 192 #define CLK_CLK         0       /* reserved (channel-specific clock) */
 193 #define CLK_10MHZ       1       /* internal 10 MHz clock */
 194 #define CLK_1MHZ        2       /* internal 1 MHz clock */
 195 #define CLK_100KHZ      3       /* internal 100 kHz clock */
 196 #define CLK_10KHZ       4       /* internal 10 kHz clock */
 197 #define CLK_1KHZ        5       /* internal 1 kHz clock */
 198 #define CLK_OUTNM1      6       /* output of channel-1 modulo total */
 199 #define CLK_EXT         7       /* external clock */
 200 
 201 static unsigned int pci224_clk_config(unsigned int chan, unsigned int src)
 202 {
 203         return ((chan & 3) << 3) | (src & 7);
 204 }
 205 
 206 /*
 207  * Counter/timer gate input configuration sources.
 208  */
 209 #define GAT_VCC         0       /* VCC (i.e. enabled) */
 210 #define GAT_GND         1       /* GND (i.e. disabled) */
 211 #define GAT_EXT         2       /* reserved (external gate input) */
 212 #define GAT_NOUTNM2     3       /* inverted output of channel-2 modulo total */
 213 
 214 static unsigned int pci224_gat_config(unsigned int chan, unsigned int src)
 215 {
 216         return ((chan & 3) << 3) | (src & 7);
 217 }
 218 
 219 /*
 220  * Summary of CLK_OUTNM1 and GAT_NOUTNM2 connections for PCI224 and PCI234:
 221  *
 222  *              Channel's       Channel's
 223  *              clock input     gate input
 224  * Channel      CLK_OUTNM1      GAT_NOUTNM2
 225  * -------      ----------      -----------
 226  * Z2-CT0       Z2-CT2-OUT      /Z2-CT1-OUT
 227  * Z2-CT1       Z2-CT0-OUT      /Z2-CT2-OUT
 228  * Z2-CT2       Z2-CT1-OUT      /Z2-CT0-OUT
 229  */
 230 
 231 /*
 232  * Interrupt enable/status bits
 233  */
 234 #define PCI224_INTR_EXT         0x01    /* rising edge on external input */
 235 #define PCI224_INTR_DAC         0x04    /* DAC (FIFO) interrupt */
 236 #define PCI224_INTR_Z2CT1       0x20    /* rising edge on Z2-CT1 output */
 237 
 238 #define PCI224_INTR_EDGE_BITS   (PCI224_INTR_EXT | PCI224_INTR_Z2CT1)
 239 #define PCI224_INTR_LEVEL_BITS  PCI224_INTR_DACFIFO
 240 
 241 /*
 242  * Handy macros.
 243  */
 244 
 245 /* Combine old and new bits. */
 246 #define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
 247 
 248 /* Current CPU.  XXX should this be hard_smp_processor_id()? */
 249 #define THISCPU         smp_processor_id()
 250 
 251 /* State bits for use with atomic bit operations. */
 252 #define AO_CMD_STARTED  0
 253 
 254 /*
 255  * Range tables.
 256  */
 257 
 258 /*
 259  * The ranges for PCI224.
 260  *
 261  * These are partly hardware-selectable by jumper LK1 and partly
 262  * software-selectable.
 263  *
 264  * All channels share the same hardware range.
 265  */
 266 static const struct comedi_lrange range_pci224 = {
 267         10, {
 268                 /* jumper LK1 in position 1-2 (factory default) */
 269                 BIP_RANGE(10),
 270                 BIP_RANGE(5),
 271                 BIP_RANGE(2.5),
 272                 BIP_RANGE(1.25),
 273                 UNI_RANGE(10),
 274                 UNI_RANGE(5),
 275                 UNI_RANGE(2.5),
 276                 UNI_RANGE(1.25),
 277                 /* jumper LK1 in position 2-3 */
 278                 RANGE_ext(-1, 1),       /* bipolar [-Vext,+Vext] */
 279                 RANGE_ext(0, 1),        /* unipolar [0,+Vext] */
 280         }
 281 };
 282 
 283 static const unsigned short hwrange_pci224[10] = {
 284         /* jumper LK1 in position 1-2 (factory default) */
 285         PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_10,
 286         PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_5,
 287         PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_2_5,
 288         PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_1_25,
 289         PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_10,
 290         PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_5,
 291         PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_2_5,
 292         PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_1_25,
 293         /* jumper LK1 in position 2-3 */
 294         PCI224_DACCON_POLAR_BI,
 295         PCI224_DACCON_POLAR_UNI,
 296 };
 297 
 298 /* Used to check all channels set to the same range on PCI224. */
 299 static const unsigned char range_check_pci224[10] = {
 300         0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
 301 };
 302 
 303 /*
 304  * The ranges for PCI234.
 305  *
 306  * These are all hardware-selectable by jumper LK1 affecting all channels,
 307  * and jumpers LK2, LK3, LK4 and LK5 affecting channels 0, 1, 2 and 3
 308  * individually.
 309  */
 310 static const struct comedi_lrange range_pci234 = {
 311         4, {
 312                 /* LK1: 1-2 (fact def), LK2/3/4/5: 2-3 (fac def) */
 313                 BIP_RANGE(10),
 314                 /* LK1: 1-2 (fact def), LK2/3/4/5: 1-2 */
 315                 BIP_RANGE(5),
 316                 /* LK1: 2-3, LK2/3/4/5: 2-3 (fac def) */
 317                 RANGE_ext(-2, 2),       /* bipolar [-2*Vext,+2*Vext] */
 318                 /* LK1: 2-3, LK2/3/4/5: 1-2 */
 319                 RANGE_ext(-1, 1),       /* bipolar [-Vext,+Vext] */
 320         }
 321 };
 322 
 323 /* N.B. PCI234 ignores the polarity bit, but software uses it. */
 324 static const unsigned short hwrange_pci234[4] = {
 325         PCI224_DACCON_POLAR_BI,
 326         PCI224_DACCON_POLAR_BI,
 327         PCI224_DACCON_POLAR_BI,
 328         PCI224_DACCON_POLAR_BI,
 329 };
 330 
 331 /* Used to check all channels use same LK1 setting on PCI234. */
 332 static const unsigned char range_check_pci234[4] = {
 333         0, 0, 1, 1,
 334 };
 335 
 336 /*
 337  * Board descriptions.
 338  */
 339 
 340 enum pci224_model { pci224_model, pci234_model };
 341 
 342 struct pci224_board {
 343         const char *name;
 344         unsigned int ao_chans;
 345         unsigned int ao_bits;
 346         const struct comedi_lrange *ao_range;
 347         const unsigned short *ao_hwrange;
 348         const unsigned char *ao_range_check;
 349 };
 350 
 351 static const struct pci224_board pci224_boards[] = {
 352         [pci224_model] = {
 353                 .name           = "pci224",
 354                 .ao_chans       = 16,
 355                 .ao_bits        = 12,
 356                 .ao_range       = &range_pci224,
 357                 .ao_hwrange     = &hwrange_pci224[0],
 358                 .ao_range_check = &range_check_pci224[0],
 359         },
 360         [pci234_model] = {
 361                 .name           = "pci234",
 362                 .ao_chans       = 4,
 363                 .ao_bits        = 16,
 364                 .ao_range       = &range_pci234,
 365                 .ao_hwrange     = &hwrange_pci234[0],
 366                 .ao_range_check = &range_check_pci234[0],
 367         },
 368 };
 369 
 370 struct pci224_private {
 371         unsigned long iobase1;
 372         unsigned long state;
 373         spinlock_t ao_spinlock; /* spinlock for AO command handling */
 374         unsigned short *ao_scan_vals;
 375         unsigned char *ao_scan_order;
 376         int intr_cpuid;
 377         short intr_running;
 378         unsigned short daccon;
 379         unsigned short ao_enab; /* max 16 channels so 'short' will do */
 380         unsigned char intsce;
 381 };
 382 
 383 /*
 384  * Called from the 'insn_write' function to perform a single write.
 385  */
 386 static void
 387 pci224_ao_set_data(struct comedi_device *dev, int chan, int range,
 388                    unsigned int data)
 389 {
 390         const struct pci224_board *board = dev->board_ptr;
 391         struct pci224_private *devpriv = dev->private;
 392         unsigned short mangled;
 393 
 394         /* Enable the channel. */
 395         outw(1 << chan, dev->iobase + PCI224_DACCEN);
 396         /* Set range and reset FIFO. */
 397         devpriv->daccon = COMBINE(devpriv->daccon, board->ao_hwrange[range],
 398                                   PCI224_DACCON_POLAR_MASK |
 399                                   PCI224_DACCON_VREF_MASK);
 400         outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
 401              dev->iobase + PCI224_DACCON);
 402         /*
 403          * Mangle the data.  The hardware expects:
 404          * - bipolar: 16-bit 2's complement
 405          * - unipolar: 16-bit unsigned
 406          */
 407         mangled = (unsigned short)data << (16 - board->ao_bits);
 408         if ((devpriv->daccon & PCI224_DACCON_POLAR_MASK) ==
 409             PCI224_DACCON_POLAR_BI) {
 410                 mangled ^= 0x8000;
 411         }
 412         /* Write mangled data to the FIFO. */
 413         outw(mangled, dev->iobase + PCI224_DACDATA);
 414         /* Trigger the conversion. */
 415         inw(dev->iobase + PCI224_SOFTTRIG);
 416 }
 417 
 418 static int pci224_ao_insn_write(struct comedi_device *dev,
 419                                 struct comedi_subdevice *s,
 420                                 struct comedi_insn *insn,
 421                                 unsigned int *data)
 422 {
 423         unsigned int chan = CR_CHAN(insn->chanspec);
 424         unsigned int range = CR_RANGE(insn->chanspec);
 425         unsigned int val = s->readback[chan];
 426         int i;
 427 
 428         for (i = 0; i < insn->n; i++) {
 429                 val = data[i];
 430                 pci224_ao_set_data(dev, chan, range, val);
 431         }
 432         s->readback[chan] = val;
 433 
 434         return insn->n;
 435 }
 436 
 437 /*
 438  * Kills a command running on the AO subdevice.
 439  */
 440 static void pci224_ao_stop(struct comedi_device *dev,
 441                            struct comedi_subdevice *s)
 442 {
 443         struct pci224_private *devpriv = dev->private;
 444         unsigned long flags;
 445 
 446         if (!test_and_clear_bit(AO_CMD_STARTED, &devpriv->state))
 447                 return;
 448 
 449         spin_lock_irqsave(&devpriv->ao_spinlock, flags);
 450         /* Kill the interrupts. */
 451         devpriv->intsce = 0;
 452         outb(0, devpriv->iobase1 + PCI224_INT_SCE);
 453         /*
 454          * Interrupt routine may or may not be running.  We may or may not
 455          * have been called from the interrupt routine (directly or
 456          * indirectly via a comedi_events() callback routine).  It's highly
 457          * unlikely that we've been called from some other interrupt routine
 458          * but who knows what strange things coders get up to!
 459          *
 460          * If the interrupt routine is currently running, wait for it to
 461          * finish, unless we appear to have been called via the interrupt
 462          * routine.
 463          */
 464         while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
 465                 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
 466                 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
 467         }
 468         spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
 469         /* Reconfigure DAC for insn_write usage. */
 470         outw(0, dev->iobase + PCI224_DACCEN);   /* Disable channels. */
 471         devpriv->daccon =
 472              COMBINE(devpriv->daccon,
 473                      PCI224_DACCON_TRIG_SW | PCI224_DACCON_FIFOINTR_EMPTY,
 474                      PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK);
 475         outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
 476              dev->iobase + PCI224_DACCON);
 477 }
 478 
 479 /*
 480  * Handles start of acquisition for the AO subdevice.
 481  */
 482 static void pci224_ao_start(struct comedi_device *dev,
 483                             struct comedi_subdevice *s)
 484 {
 485         struct pci224_private *devpriv = dev->private;
 486         struct comedi_cmd *cmd = &s->async->cmd;
 487         unsigned long flags;
 488 
 489         set_bit(AO_CMD_STARTED, &devpriv->state);
 490 
 491         /* Enable interrupts. */
 492         spin_lock_irqsave(&devpriv->ao_spinlock, flags);
 493         if (cmd->stop_src == TRIG_EXT)
 494                 devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC;
 495         else
 496                 devpriv->intsce = PCI224_INTR_DAC;
 497 
 498         outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
 499         spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
 500 }
 501 
 502 /*
 503  * Handles interrupts from the DAC FIFO.
 504  */
 505 static void pci224_ao_handle_fifo(struct comedi_device *dev,
 506                                   struct comedi_subdevice *s)
 507 {
 508         struct pci224_private *devpriv = dev->private;
 509         struct comedi_cmd *cmd = &s->async->cmd;
 510         unsigned int num_scans = comedi_nscans_left(s, 0);
 511         unsigned int room;
 512         unsigned short dacstat;
 513         unsigned int i, n;
 514 
 515         /* Determine how much room is in the FIFO (in samples). */
 516         dacstat = inw(dev->iobase + PCI224_DACCON);
 517         switch (dacstat & PCI224_DACCON_FIFOFL_MASK) {
 518         case PCI224_DACCON_FIFOFL_EMPTY:
 519                 room = PCI224_FIFO_ROOM_EMPTY;
 520                 if (cmd->stop_src == TRIG_COUNT &&
 521                     s->async->scans_done >= cmd->stop_arg) {
 522                         /* FIFO empty at end of counted acquisition. */
 523                         s->async->events |= COMEDI_CB_EOA;
 524                         comedi_handle_events(dev, s);
 525                         return;
 526                 }
 527                 break;
 528         case PCI224_DACCON_FIFOFL_ONETOHALF:
 529                 room = PCI224_FIFO_ROOM_ONETOHALF;
 530                 break;
 531         case PCI224_DACCON_FIFOFL_HALFTOFULL:
 532                 room = PCI224_FIFO_ROOM_HALFTOFULL;
 533                 break;
 534         default:
 535                 room = PCI224_FIFO_ROOM_FULL;
 536                 break;
 537         }
 538         if (room >= PCI224_FIFO_ROOM_ONETOHALF) {
 539                 /* FIFO is less than half-full. */
 540                 if (num_scans == 0) {
 541                         /* Nothing left to put in the FIFO. */
 542                         dev_err(dev->class_dev, "AO buffer underrun\n");
 543                         s->async->events |= COMEDI_CB_OVERFLOW;
 544                 }
 545         }
 546         /* Determine how many new scans can be put in the FIFO. */
 547         room /= cmd->chanlist_len;
 548 
 549         /* Determine how many scans to process. */
 550         if (num_scans > room)
 551                 num_scans = room;
 552 
 553         /* Process scans. */
 554         for (n = 0; n < num_scans; n++) {
 555                 comedi_buf_read_samples(s, &devpriv->ao_scan_vals[0],
 556                                         cmd->chanlist_len);
 557                 for (i = 0; i < cmd->chanlist_len; i++) {
 558                         outw(devpriv->ao_scan_vals[devpriv->ao_scan_order[i]],
 559                              dev->iobase + PCI224_DACDATA);
 560                 }
 561         }
 562         if (cmd->stop_src == TRIG_COUNT &&
 563             s->async->scans_done >= cmd->stop_arg) {
 564                 /*
 565                  * Change FIFO interrupt trigger level to wait
 566                  * until FIFO is empty.
 567                  */
 568                 devpriv->daccon = COMBINE(devpriv->daccon,
 569                                           PCI224_DACCON_FIFOINTR_EMPTY,
 570                                           PCI224_DACCON_FIFOINTR_MASK);
 571                 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
 572         }
 573         if ((devpriv->daccon & PCI224_DACCON_TRIG_MASK) ==
 574             PCI224_DACCON_TRIG_NONE) {
 575                 unsigned short trig;
 576 
 577                 /*
 578                  * This is the initial DAC FIFO interrupt at the
 579                  * start of the acquisition.  The DAC's scan trigger
 580                  * has been set to 'none' up until now.
 581                  *
 582                  * Now that data has been written to the FIFO, the
 583                  * DAC's scan trigger source can be set to the
 584                  * correct value.
 585                  *
 586                  * BUG: The first scan will be triggered immediately
 587                  * if the scan trigger source is at logic level 1.
 588                  */
 589                 if (cmd->scan_begin_src == TRIG_TIMER) {
 590                         trig = PCI224_DACCON_TRIG_Z2CT0;
 591                 } else {
 592                         /* cmd->scan_begin_src == TRIG_EXT */
 593                         if (cmd->scan_begin_arg & CR_INVERT)
 594                                 trig = PCI224_DACCON_TRIG_EXTN;
 595                         else
 596                                 trig = PCI224_DACCON_TRIG_EXTP;
 597                 }
 598                 devpriv->daccon =
 599                     COMBINE(devpriv->daccon, trig, PCI224_DACCON_TRIG_MASK);
 600                 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
 601         }
 602 
 603         comedi_handle_events(dev, s);
 604 }
 605 
 606 static int pci224_ao_inttrig_start(struct comedi_device *dev,
 607                                    struct comedi_subdevice *s,
 608                                    unsigned int trig_num)
 609 {
 610         struct comedi_cmd *cmd = &s->async->cmd;
 611 
 612         if (trig_num != cmd->start_arg)
 613                 return -EINVAL;
 614 
 615         s->async->inttrig = NULL;
 616         pci224_ao_start(dev, s);
 617 
 618         return 1;
 619 }
 620 
 621 static int pci224_ao_check_chanlist(struct comedi_device *dev,
 622                                     struct comedi_subdevice *s,
 623                                     struct comedi_cmd *cmd)
 624 {
 625         const struct pci224_board *board = dev->board_ptr;
 626         unsigned int range_check_0;
 627         unsigned int chan_mask = 0;
 628         int i;
 629 
 630         range_check_0 = board->ao_range_check[CR_RANGE(cmd->chanlist[0])];
 631         for (i = 0; i < cmd->chanlist_len; i++) {
 632                 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
 633 
 634                 if (chan_mask & (1 << chan)) {
 635                         dev_dbg(dev->class_dev,
 636                                 "%s: entries in chanlist must contain no duplicate channels\n",
 637                                 __func__);
 638                         return -EINVAL;
 639                 }
 640                 chan_mask |= 1 << chan;
 641 
 642                 if (board->ao_range_check[CR_RANGE(cmd->chanlist[i])] !=
 643                     range_check_0) {
 644                         dev_dbg(dev->class_dev,
 645                                 "%s: entries in chanlist have incompatible ranges\n",
 646                                 __func__);
 647                         return -EINVAL;
 648                 }
 649         }
 650 
 651         return 0;
 652 }
 653 
 654 #define MAX_SCAN_PERIOD         0xFFFFFFFFU
 655 #define MIN_SCAN_PERIOD         2500
 656 #define CONVERT_PERIOD          625
 657 
 658 /*
 659  * 'do_cmdtest' function for AO subdevice.
 660  */
 661 static int
 662 pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 663                   struct comedi_cmd *cmd)
 664 {
 665         int err = 0;
 666         unsigned int arg;
 667 
 668         /* Step 1 : check if triggers are trivially valid */
 669 
 670         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
 671         err |= comedi_check_trigger_src(&cmd->scan_begin_src,
 672                                         TRIG_EXT | TRIG_TIMER);
 673         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
 674         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 675         err |= comedi_check_trigger_src(&cmd->stop_src,
 676                                         TRIG_COUNT | TRIG_EXT | TRIG_NONE);
 677 
 678         if (err)
 679                 return 1;
 680 
 681         /* Step 2a : make sure trigger sources are unique */
 682 
 683         err |= comedi_check_trigger_is_unique(cmd->start_src);
 684         err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
 685         err |= comedi_check_trigger_is_unique(cmd->stop_src);
 686 
 687         /* Step 2b : and mutually compatible */
 688 
 689         /*
 690          * There's only one external trigger signal (which makes these
 691          * tests easier).  Only one thing can use it.
 692          */
 693         arg = 0;
 694         if (cmd->start_src & TRIG_EXT)
 695                 arg++;
 696         if (cmd->scan_begin_src & TRIG_EXT)
 697                 arg++;
 698         if (cmd->stop_src & TRIG_EXT)
 699                 arg++;
 700         if (arg > 1)
 701                 err |= -EINVAL;
 702 
 703         if (err)
 704                 return 2;
 705 
 706         /* Step 3: check if arguments are trivially valid */
 707 
 708         switch (cmd->start_src) {
 709         case TRIG_INT:
 710                 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 711                 break;
 712         case TRIG_EXT:
 713                 /* Force to external trigger 0. */
 714                 if (cmd->start_arg & ~CR_FLAGS_MASK) {
 715                         cmd->start_arg =
 716                             COMBINE(cmd->start_arg, 0, ~CR_FLAGS_MASK);
 717                         err |= -EINVAL;
 718                 }
 719                 /* The only flag allowed is CR_EDGE, which is ignored. */
 720                 if (cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) {
 721                         cmd->start_arg = COMBINE(cmd->start_arg, 0,
 722                                                  CR_FLAGS_MASK & ~CR_EDGE);
 723                         err |= -EINVAL;
 724                 }
 725                 break;
 726         }
 727 
 728         switch (cmd->scan_begin_src) {
 729         case TRIG_TIMER:
 730                 err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
 731                                                     MAX_SCAN_PERIOD);
 732 
 733                 arg = cmd->chanlist_len * CONVERT_PERIOD;
 734                 if (arg < MIN_SCAN_PERIOD)
 735                         arg = MIN_SCAN_PERIOD;
 736                 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, arg);
 737                 break;
 738         case TRIG_EXT:
 739                 /* Force to external trigger 0. */
 740                 if (cmd->scan_begin_arg & ~CR_FLAGS_MASK) {
 741                         cmd->scan_begin_arg =
 742                             COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK);
 743                         err |= -EINVAL;
 744                 }
 745                 /* Only allow flags CR_EDGE and CR_INVERT.  Ignore CR_EDGE. */
 746                 if (cmd->scan_begin_arg & CR_FLAGS_MASK &
 747                     ~(CR_EDGE | CR_INVERT)) {
 748                         cmd->scan_begin_arg =
 749                             COMBINE(cmd->scan_begin_arg, 0,
 750                                     CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
 751                         err |= -EINVAL;
 752                 }
 753                 break;
 754         }
 755 
 756         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
 757         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 758                                            cmd->chanlist_len);
 759 
 760         switch (cmd->stop_src) {
 761         case TRIG_COUNT:
 762                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
 763                 break;
 764         case TRIG_EXT:
 765                 /* Force to external trigger 0. */
 766                 if (cmd->stop_arg & ~CR_FLAGS_MASK) {
 767                         cmd->stop_arg =
 768                             COMBINE(cmd->stop_arg, 0, ~CR_FLAGS_MASK);
 769                         err |= -EINVAL;
 770                 }
 771                 /* The only flag allowed is CR_EDGE, which is ignored. */
 772                 if (cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) {
 773                         cmd->stop_arg =
 774                             COMBINE(cmd->stop_arg, 0, CR_FLAGS_MASK & ~CR_EDGE);
 775                 }
 776                 break;
 777         case TRIG_NONE:
 778                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 779                 break;
 780         }
 781 
 782         if (err)
 783                 return 3;
 784 
 785         /* Step 4: fix up any arguments. */
 786 
 787         if (cmd->scan_begin_src == TRIG_TIMER) {
 788                 arg = cmd->scan_begin_arg;
 789                 /* Use two timers. */
 790                 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
 791                 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
 792         }
 793 
 794         if (err)
 795                 return 4;
 796 
 797         /* Step 5: check channel list if it exists */
 798         if (cmd->chanlist && cmd->chanlist_len > 0)
 799                 err |= pci224_ao_check_chanlist(dev, s, cmd);
 800 
 801         if (err)
 802                 return 5;
 803 
 804         return 0;
 805 }
 806 
 807 static void pci224_ao_start_pacer(struct comedi_device *dev,
 808                                   struct comedi_subdevice *s)
 809 {
 810         struct pci224_private *devpriv = dev->private;
 811 
 812         /*
 813          * The output of timer Z2-0 will be used as the scan trigger
 814          * source.
 815          */
 816         /* Make sure Z2-0 is gated on.  */
 817         outb(pci224_gat_config(0, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
 818         /* Cascading with Z2-2. */
 819         /* Make sure Z2-2 is gated on.  */
 820         outb(pci224_gat_config(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
 821         /* Z2-2 needs 10 MHz clock. */
 822         outb(pci224_clk_config(2, CLK_10MHZ),
 823              devpriv->iobase1 + PCI224_ZCLK_SCE);
 824         /* Z2-0 is clocked from Z2-2's output. */
 825         outb(pci224_clk_config(0, CLK_OUTNM1),
 826              devpriv->iobase1 + PCI224_ZCLK_SCE);
 827 
 828         comedi_8254_pacer_enable(dev->pacer, 2, 0, false);
 829 }
 830 
 831 static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 832 {
 833         const struct pci224_board *board = dev->board_ptr;
 834         struct pci224_private *devpriv = dev->private;
 835         struct comedi_cmd *cmd = &s->async->cmd;
 836         int range;
 837         unsigned int i, j;
 838         unsigned int ch;
 839         unsigned int rank;
 840         unsigned long flags;
 841 
 842         /* Cannot handle null/empty chanlist. */
 843         if (!cmd->chanlist || cmd->chanlist_len == 0)
 844                 return -EINVAL;
 845 
 846         /* Determine which channels are enabled and their load order.  */
 847         devpriv->ao_enab = 0;
 848 
 849         for (i = 0; i < cmd->chanlist_len; i++) {
 850                 ch = CR_CHAN(cmd->chanlist[i]);
 851                 devpriv->ao_enab |= 1U << ch;
 852                 rank = 0;
 853                 for (j = 0; j < cmd->chanlist_len; j++) {
 854                         if (CR_CHAN(cmd->chanlist[j]) < ch)
 855                                 rank++;
 856                 }
 857                 devpriv->ao_scan_order[rank] = i;
 858         }
 859 
 860         /* Set enabled channels. */
 861         outw(devpriv->ao_enab, dev->iobase + PCI224_DACCEN);
 862 
 863         /* Determine range and polarity.  All channels the same.  */
 864         range = CR_RANGE(cmd->chanlist[0]);
 865 
 866         /*
 867          * Set DAC range and polarity.
 868          * Set DAC scan trigger source to 'none'.
 869          * Set DAC FIFO interrupt trigger level to 'not half full'.
 870          * Reset DAC FIFO.
 871          *
 872          * N.B. DAC FIFO interrupts are currently disabled.
 873          */
 874         devpriv->daccon =
 875             COMBINE(devpriv->daccon,
 876                     board->ao_hwrange[range] | PCI224_DACCON_TRIG_NONE |
 877                     PCI224_DACCON_FIFOINTR_NHALF,
 878                     PCI224_DACCON_POLAR_MASK | PCI224_DACCON_VREF_MASK |
 879                     PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK);
 880         outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
 881              dev->iobase + PCI224_DACCON);
 882 
 883         if (cmd->scan_begin_src == TRIG_TIMER) {
 884                 comedi_8254_update_divisors(dev->pacer);
 885                 pci224_ao_start_pacer(dev, s);
 886         }
 887 
 888         spin_lock_irqsave(&devpriv->ao_spinlock, flags);
 889         if (cmd->start_src == TRIG_INT) {
 890                 s->async->inttrig = pci224_ao_inttrig_start;
 891         } else {        /* TRIG_EXT */
 892                 /* Enable external interrupt trigger to start acquisition. */
 893                 devpriv->intsce |= PCI224_INTR_EXT;
 894                 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
 895         }
 896         spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
 897 
 898         return 0;
 899 }
 900 
 901 /*
 902  * 'cancel' function for AO subdevice.
 903  */
 904 static int pci224_ao_cancel(struct comedi_device *dev,
 905                             struct comedi_subdevice *s)
 906 {
 907         pci224_ao_stop(dev, s);
 908         return 0;
 909 }
 910 
 911 /*
 912  * 'munge' data for AO command.
 913  */
 914 static void
 915 pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
 916                 void *data, unsigned int num_bytes, unsigned int chan_index)
 917 {
 918         const struct pci224_board *board = dev->board_ptr;
 919         struct comedi_cmd *cmd = &s->async->cmd;
 920         unsigned short *array = data;
 921         unsigned int length = num_bytes / sizeof(*array);
 922         unsigned int offset;
 923         unsigned int shift;
 924         unsigned int i;
 925 
 926         /* The hardware expects 16-bit numbers. */
 927         shift = 16 - board->ao_bits;
 928         /* Channels will be all bipolar or all unipolar. */
 929         if ((board->ao_hwrange[CR_RANGE(cmd->chanlist[0])] &
 930              PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) {
 931                 /* Unipolar */
 932                 offset = 0;
 933         } else {
 934                 /* Bipolar */
 935                 offset = 32768;
 936         }
 937         /* Munge the data. */
 938         for (i = 0; i < length; i++)
 939                 array[i] = (array[i] << shift) - offset;
 940 }
 941 
 942 /*
 943  * Interrupt handler.
 944  */
 945 static irqreturn_t pci224_interrupt(int irq, void *d)
 946 {
 947         struct comedi_device *dev = d;
 948         struct pci224_private *devpriv = dev->private;
 949         struct comedi_subdevice *s = dev->write_subdev;
 950         struct comedi_cmd *cmd;
 951         unsigned char intstat, valid_intstat;
 952         unsigned char curenab;
 953         int retval = 0;
 954         unsigned long flags;
 955 
 956         intstat = inb(devpriv->iobase1 + PCI224_INT_SCE) & 0x3F;
 957         if (intstat) {
 958                 retval = 1;
 959                 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
 960                 valid_intstat = devpriv->intsce & intstat;
 961                 /* Temporarily disable interrupt sources. */
 962                 curenab = devpriv->intsce & ~intstat;
 963                 outb(curenab, devpriv->iobase1 + PCI224_INT_SCE);
 964                 devpriv->intr_running = 1;
 965                 devpriv->intr_cpuid = THISCPU;
 966                 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
 967                 if (valid_intstat) {
 968                         cmd = &s->async->cmd;
 969                         if (valid_intstat & PCI224_INTR_EXT) {
 970                                 devpriv->intsce &= ~PCI224_INTR_EXT;
 971                                 if (cmd->start_src == TRIG_EXT)
 972                                         pci224_ao_start(dev, s);
 973                                 else if (cmd->stop_src == TRIG_EXT)
 974                                         pci224_ao_stop(dev, s);
 975                         }
 976                         if (valid_intstat & PCI224_INTR_DAC)
 977                                 pci224_ao_handle_fifo(dev, s);
 978                 }
 979                 /* Reenable interrupt sources. */
 980                 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
 981                 if (curenab != devpriv->intsce) {
 982                         outb(devpriv->intsce,
 983                              devpriv->iobase1 + PCI224_INT_SCE);
 984                 }
 985                 devpriv->intr_running = 0;
 986                 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
 987         }
 988         return IRQ_RETVAL(retval);
 989 }
 990 
 991 static int
 992 pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
 993 {
 994         struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
 995         const struct pci224_board *board = NULL;
 996         struct pci224_private *devpriv;
 997         struct comedi_subdevice *s;
 998         unsigned int irq;
 999         int ret;
1000 
1001         if (context_model < ARRAY_SIZE(pci224_boards))
1002                 board = &pci224_boards[context_model];
1003         if (!board || !board->name) {
1004                 dev_err(dev->class_dev,
1005                         "amplc_pci224: BUG! cannot determine board type!\n");
1006                 return -EINVAL;
1007         }
1008         dev->board_ptr = board;
1009         dev->board_name = board->name;
1010 
1011         dev_info(dev->class_dev, "amplc_pci224: attach pci %s - %s\n",
1012                  pci_name(pci_dev), dev->board_name);
1013 
1014         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1015         if (!devpriv)
1016                 return -ENOMEM;
1017 
1018         ret = comedi_pci_enable(dev);
1019         if (ret)
1020                 return ret;
1021 
1022         spin_lock_init(&devpriv->ao_spinlock);
1023 
1024         devpriv->iobase1 = pci_resource_start(pci_dev, 2);
1025         dev->iobase = pci_resource_start(pci_dev, 3);
1026         irq = pci_dev->irq;
1027 
1028         /* Allocate buffer to hold values for AO channel scan. */
1029         devpriv->ao_scan_vals = kmalloc_array(board->ao_chans,
1030                                               sizeof(devpriv->ao_scan_vals[0]),
1031                                               GFP_KERNEL);
1032         if (!devpriv->ao_scan_vals)
1033                 return -ENOMEM;
1034 
1035         /* Allocate buffer to hold AO channel scan order. */
1036         devpriv->ao_scan_order =
1037                                 kmalloc_array(board->ao_chans,
1038                                               sizeof(devpriv->ao_scan_order[0]),
1039                                               GFP_KERNEL);
1040         if (!devpriv->ao_scan_order)
1041                 return -ENOMEM;
1042 
1043         /* Disable interrupt sources. */
1044         devpriv->intsce = 0;
1045         outb(0, devpriv->iobase1 + PCI224_INT_SCE);
1046 
1047         /* Initialize the DAC hardware. */
1048         outw(PCI224_DACCON_GLOBALRESET, dev->iobase + PCI224_DACCON);
1049         outw(0, dev->iobase + PCI224_DACCEN);
1050         outw(0, dev->iobase + PCI224_FIFOSIZ);
1051         devpriv->daccon = PCI224_DACCON_TRIG_SW | PCI224_DACCON_POLAR_BI |
1052                           PCI224_DACCON_FIFOENAB | PCI224_DACCON_FIFOINTR_EMPTY;
1053         outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
1054              dev->iobase + PCI224_DACCON);
1055 
1056         dev->pacer = comedi_8254_init(devpriv->iobase1 + PCI224_Z2_BASE,
1057                                       I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
1058         if (!dev->pacer)
1059                 return -ENOMEM;
1060 
1061         ret = comedi_alloc_subdevices(dev, 1);
1062         if (ret)
1063                 return ret;
1064 
1065         s = &dev->subdevices[0];
1066         /* Analog output subdevice. */
1067         s->type = COMEDI_SUBD_AO;
1068         s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
1069         s->n_chan = board->ao_chans;
1070         s->maxdata = (1 << board->ao_bits) - 1;
1071         s->range_table = board->ao_range;
1072         s->insn_write = pci224_ao_insn_write;
1073         s->len_chanlist = s->n_chan;
1074         dev->write_subdev = s;
1075         s->do_cmd = pci224_ao_cmd;
1076         s->do_cmdtest = pci224_ao_cmdtest;
1077         s->cancel = pci224_ao_cancel;
1078         s->munge = pci224_ao_munge;
1079 
1080         ret = comedi_alloc_subdev_readback(s);
1081         if (ret)
1082                 return ret;
1083 
1084         if (irq) {
1085                 ret = request_irq(irq, pci224_interrupt, IRQF_SHARED,
1086                                   dev->board_name, dev);
1087                 if (ret < 0) {
1088                         dev_err(dev->class_dev,
1089                                 "error! unable to allocate irq %u\n", irq);
1090                         return ret;
1091                 }
1092                 dev->irq = irq;
1093         }
1094 
1095         return 0;
1096 }
1097 
1098 static void pci224_detach(struct comedi_device *dev)
1099 {
1100         struct pci224_private *devpriv = dev->private;
1101 
1102         comedi_pci_detach(dev);
1103         if (devpriv) {
1104                 kfree(devpriv->ao_scan_vals);
1105                 kfree(devpriv->ao_scan_order);
1106         }
1107 }
1108 
1109 static struct comedi_driver amplc_pci224_driver = {
1110         .driver_name    = "amplc_pci224",
1111         .module         = THIS_MODULE,
1112         .detach         = pci224_detach,
1113         .auto_attach    = pci224_auto_attach,
1114         .board_name     = &pci224_boards[0].name,
1115         .offset         = sizeof(struct pci224_board),
1116         .num_names      = ARRAY_SIZE(pci224_boards),
1117 };
1118 
1119 static int amplc_pci224_pci_probe(struct pci_dev *dev,
1120                                   const struct pci_device_id *id)
1121 {
1122         return comedi_pci_auto_config(dev, &amplc_pci224_driver,
1123                                       id->driver_data);
1124 }
1125 
1126 static const struct pci_device_id amplc_pci224_pci_table[] = {
1127         { PCI_VDEVICE(AMPLICON, 0x0007), pci224_model },
1128         { PCI_VDEVICE(AMPLICON, 0x0008), pci234_model },
1129         { 0 }
1130 };
1131 MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table);
1132 
1133 static struct pci_driver amplc_pci224_pci_driver = {
1134         .name           = "amplc_pci224",
1135         .id_table       = amplc_pci224_pci_table,
1136         .probe          = amplc_pci224_pci_probe,
1137         .remove         = comedi_pci_auto_unconfig,
1138 };
1139 module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver);
1140 
1141 MODULE_AUTHOR("Comedi http://www.comedi.org");
1142 MODULE_DESCRIPTION("Comedi driver for Amplicon PCI224 and PCI234 AO boards");
1143 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */