Version:  2.0.40 2.2.26 2.4.37 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1

Linux/drivers/staging/comedi/drivers/amplc_pci224.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us