linux/drivers/staging/comedi/drivers/pcl812.c
<<
>>
Prefs
   1/*
   2 * comedi/drivers/pcl812.c
   3 *
   4 * Author: Michal Dobes <dobes@tesnet.cz>
   5 *
   6 * hardware driver for Advantech cards
   7 *  card:   PCL-812, PCL-812PG, PCL-813, PCL-813B
   8 *  driver: pcl812,  pcl812pg,  pcl813,  pcl813b
   9 * and for ADlink cards
  10 *  card:   ACL-8112DG, ACL-8112HG, ACL-8112PG, ACL-8113, ACL-8216
  11 *  driver: acl8112dg,  acl8112hg,  acl8112pg,  acl8113,  acl8216
  12 * and for ICP DAS cards
  13 *  card:   ISO-813, A-821PGH, A-821PGL, A-821PGL-NDA, A-822PGH, A-822PGL,
  14 *  driver: iso813,  a821pgh,  a-821pgl, a-821pglnda,  a822pgh,  a822pgl,
  15 *  card:   A-823PGH, A-823PGL, A-826PG
  16 * driver:  a823pgh,  a823pgl,  a826pg
  17 */
  18
  19/*
  20 * Driver: pcl812
  21 * Description: Advantech PCL-812/PG, PCL-813/B,
  22 *           ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216,
  23 *           ICP DAS A-821PGH/PGL/PGL-NDA, A-822PGH/PGL, A-823PGH/PGL, A-826PG,
  24 *           ICP DAS ISO-813
  25 * Author: Michal Dobes <dobes@tesnet.cz>
  26 * Devices: [Advantech] PCL-812 (pcl812), PCL-812PG (pcl812pg),
  27 *      PCL-813 (pcl813), PCL-813B (pcl813b), [ADLink] ACL-8112DG (acl8112dg),
  28 *      ACL-8112HG (acl8112hg), ACL-8113 (acl-8113), ACL-8216 (acl8216),
  29 *      [ICP] ISO-813 (iso813), A-821PGH (a821pgh), A-821PGL (a821pgl),
  30 *      A-821PGL-NDA (a821pclnda), A-822PGH (a822pgh), A-822PGL (a822pgl),
  31 *      A-823PGH (a823pgh), A-823PGL (a823pgl), A-826PG (a826pg)
  32 * Updated: Mon, 06 Aug 2007 12:03:15 +0100
  33 * Status: works (I hope. My board fire up under my hands
  34 *             and I cann't test all features.)
  35 *
  36 * This driver supports insn and cmd interfaces. Some boards support only insn
  37 * because their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813).
  38 * Data transfer over DMA is supported only when you measure only one
  39 * channel, this is too hardware limitation of these boards.
  40 *
  41 * Options for PCL-812:
  42 *   [0] - IO Base
  43 *   [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
  44 *   [2] - DMA  (0=disable, 1, 3)
  45 *   [3] - 0=trigger source is internal 8253 with 2MHz clock
  46 *         1=trigger source is external
  47 *   [4] - 0=A/D input range is +/-10V
  48 *         1=A/D input range is +/-5V
  49 *         2=A/D input range is +/-2.5V
  50 *         3=A/D input range is +/-1.25V
  51 *         4=A/D input range is +/-0.625V
  52 *         5=A/D input range is +/-0.3125V
  53 *   [5] - 0=D/A outputs 0-5V  (internal reference -5V)
  54 *         1=D/A outputs 0-10V (internal reference -10V)
  55 *         2=D/A outputs unknown (external reference)
  56 *
  57 * Options for PCL-812PG, ACL-8112PG:
  58 *   [0] - IO Base
  59 *   [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
  60 *   [2] - DMA  (0=disable, 1, 3)
  61 *   [3] - 0=trigger source is internal 8253 with 2MHz clock
  62 *         1=trigger source is external
  63 *   [4] - 0=A/D have max +/-5V input
  64 *         1=A/D have max +/-10V input
  65 *   [5] - 0=D/A outputs 0-5V  (internal reference -5V)
  66 *         1=D/A outputs 0-10V (internal reference -10V)
  67 *         2=D/A outputs unknown (external reference)
  68 *
  69 * Options for ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH, ACL-8216, A-826PG:
  70 *   [0] - IO Base
  71 *   [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
  72 *   [2] - DMA  (0=disable, 1, 3)
  73 *   [3] - 0=trigger source is internal 8253 with 2MHz clock
  74 *         1=trigger source is external
  75 *   [4] - 0=A/D channels are S.E.
  76 *         1=A/D channels are DIFF
  77 *   [5] - 0=D/A outputs 0-5V  (internal reference -5V)
  78 *         1=D/A outputs 0-10V (internal reference -10V)
  79 *         2=D/A outputs unknown (external reference)
  80 *
  81 * Options for A-821PGL/PGH:
  82 *   [0] - IO Base
  83 *   [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7)
  84 *   [2] - 0=A/D channels are S.E.
  85 *         1=A/D channels are DIFF
  86 *   [3] - 0=D/A output 0-5V  (internal reference -5V)
  87 *         1=D/A output 0-10V (internal reference -10V)
  88 *
  89 * Options for A-821PGL-NDA:
  90 *   [0] - IO Base
  91 *   [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7)
  92 *   [2] - 0=A/D channels are S.E.
  93 *         1=A/D channels are DIFF
  94 *
  95 * Options for PCL-813:
  96 *   [0] - IO Base
  97 *
  98 * Options for PCL-813B:
  99 *   [0] - IO Base
 100 *   [1] - 0= bipolar inputs
 101 *         1= unipolar inputs
 102 *
 103 * Options for ACL-8113, ISO-813:
 104 *   [0] - IO Base
 105 *   [1] - 0= 10V bipolar inputs
 106 *         1= 10V unipolar inputs
 107 *         2= 20V bipolar inputs
 108 *         3= 20V unipolar inputs
 109 */
 110
 111#include <linux/interrupt.h>
 112#include <linux/gfp.h>
 113#include "../comedidev.h"
 114
 115#include <linux/delay.h>
 116#include <linux/ioport.h>
 117#include <linux/io.h>
 118#include <asm/dma.h>
 119
 120#include "8253.h"
 121
 122/* if this is defined then a lot of messages is printed */
 123#undef PCL812_EXTDEBUG
 124
 125/* hardware types of the cards */
 126#define boardPCL812PG         0 /* and ACL-8112PG */
 127#define boardPCL813B          1
 128#define boardPCL812           2
 129#define boardPCL813           3
 130#define boardISO813           5
 131#define boardACL8113          6
 132#define boardACL8112          7 /* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */
 133#define boardACL8216          8 /* and ICP DAS A-826PG */
 134#define boardA821             9 /* PGH, PGL, PGL/NDA versions */
 135
 136#define PCLx1x_IORANGE       16
 137
 138#define PCL812_CTR0           0
 139#define PCL812_CTR1           1
 140#define PCL812_CTR2           2
 141#define PCL812_CTRCTL         3
 142#define PCL812_AD_LO          4
 143#define PCL812_DA1_LO         4
 144#define PCL812_AD_HI          5
 145#define PCL812_DA1_HI         5
 146#define PCL812_DA2_LO         6
 147#define PCL812_DI_LO          6
 148#define PCL812_DA2_HI         7
 149#define PCL812_DI_HI          7
 150#define PCL812_CLRINT         8
 151#define PCL812_GAIN           9
 152#define PCL812_MUX           10
 153#define PCL812_MODE          11
 154#define PCL812_CNTENABLE     10
 155#define PCL812_SOFTTRIG      12
 156#define PCL812_DO_LO         13
 157#define PCL812_DO_HI         14
 158
 159#define PCL812_DRDY        0x10 /* =0 data ready */
 160
 161#define ACL8216_STATUS        8 /* 5. bit signalize data ready */
 162
 163#define ACL8216_DRDY       0x20 /* =0 data ready */
 164
 165#define MAX_CHANLIST_LEN    256 /* length of scan list */
 166
 167static const struct comedi_lrange range_pcl812pg_ai = { 5, {
 168                                                            BIP_RANGE(5),
 169                                                            BIP_RANGE(2.5),
 170                                                            BIP_RANGE(1.25),
 171                                                            BIP_RANGE(0.625),
 172                                                            BIP_RANGE(0.3125),
 173                                                            }
 174};
 175
 176static const struct comedi_lrange range_pcl812pg2_ai = { 5, {
 177                                                             BIP_RANGE(10),
 178                                                             BIP_RANGE(5),
 179                                                             BIP_RANGE(2.5),
 180                                                             BIP_RANGE(1.25),
 181                                                             BIP_RANGE(0.625),
 182                                                             }
 183};
 184
 185static const struct comedi_lrange range812_bipolar1_25 = { 1, {
 186                                                               BIP_RANGE(1.25),
 187                                                               }
 188};
 189
 190static const struct comedi_lrange range812_bipolar0_625 = { 1, {
 191                                                                BIP_RANGE
 192                                                                (0.625),
 193                                                                }
 194};
 195
 196static const struct comedi_lrange range812_bipolar0_3125 = { 1, {
 197                                                                 BIP_RANGE
 198                                                                 (0.3125),
 199                                                                 }
 200};
 201
 202static const struct comedi_lrange range_pcl813b_ai = { 4, {
 203                                                           BIP_RANGE(5),
 204                                                           BIP_RANGE(2.5),
 205                                                           BIP_RANGE(1.25),
 206                                                           BIP_RANGE(0.625),
 207                                                           }
 208};
 209
 210static const struct comedi_lrange range_pcl813b2_ai = { 4, {
 211                                                            UNI_RANGE(10),
 212                                                            UNI_RANGE(5),
 213                                                            UNI_RANGE(2.5),
 214                                                            UNI_RANGE(1.25),
 215                                                            }
 216};
 217
 218static const struct comedi_lrange range_iso813_1_ai = { 5, {
 219                                                            BIP_RANGE(5),
 220                                                            BIP_RANGE(2.5),
 221                                                            BIP_RANGE(1.25),
 222                                                            BIP_RANGE(0.625),
 223                                                            BIP_RANGE(0.3125),
 224                                                            }
 225};
 226
 227static const struct comedi_lrange range_iso813_1_2_ai = { 5, {
 228                                                              UNI_RANGE(10),
 229                                                              UNI_RANGE(5),
 230                                                              UNI_RANGE(2.5),
 231                                                              UNI_RANGE(1.25),
 232                                                              UNI_RANGE(0.625),
 233                                                              }
 234};
 235
 236static const struct comedi_lrange range_iso813_2_ai = { 4, {
 237                                                            BIP_RANGE(5),
 238                                                            BIP_RANGE(2.5),
 239                                                            BIP_RANGE(1.25),
 240                                                            BIP_RANGE(0.625),
 241                                                            }
 242};
 243
 244static const struct comedi_lrange range_iso813_2_2_ai = { 4, {
 245                                                              UNI_RANGE(10),
 246                                                              UNI_RANGE(5),
 247                                                              UNI_RANGE(2.5),
 248                                                              UNI_RANGE(1.25),
 249                                                              }
 250};
 251
 252static const struct comedi_lrange range_acl8113_1_ai = { 4, {
 253                                                             BIP_RANGE(5),
 254                                                             BIP_RANGE(2.5),
 255                                                             BIP_RANGE(1.25),
 256                                                             BIP_RANGE(0.625),
 257                                                             }
 258};
 259
 260static const struct comedi_lrange range_acl8113_1_2_ai = { 4, {
 261                                                               UNI_RANGE(10),
 262                                                               UNI_RANGE(5),
 263                                                               UNI_RANGE(2.5),
 264                                                               UNI_RANGE(1.25),
 265                                                               }
 266};
 267
 268static const struct comedi_lrange range_acl8113_2_ai = { 3, {
 269                                                             BIP_RANGE(5),
 270                                                             BIP_RANGE(2.5),
 271                                                             BIP_RANGE(1.25),
 272                                                             }
 273};
 274
 275static const struct comedi_lrange range_acl8113_2_2_ai = { 3, {
 276                                                               UNI_RANGE(10),
 277                                                               UNI_RANGE(5),
 278                                                               UNI_RANGE(2.5),
 279                                                               }
 280};
 281
 282static const struct comedi_lrange range_acl8112dg_ai = { 9, {
 283                                                             BIP_RANGE(5),
 284                                                             BIP_RANGE(2.5),
 285                                                             BIP_RANGE(1.25),
 286                                                             BIP_RANGE(0.625),
 287                                                             UNI_RANGE(10),
 288                                                             UNI_RANGE(5),
 289                                                             UNI_RANGE(2.5),
 290                                                             UNI_RANGE(1.25),
 291                                                             BIP_RANGE(10),
 292                                                             }
 293};
 294
 295static const struct comedi_lrange range_acl8112hg_ai = { 12, {
 296                                                              BIP_RANGE(5),
 297                                                              BIP_RANGE(0.5),
 298                                                              BIP_RANGE(0.05),
 299                                                              BIP_RANGE(0.005),
 300                                                              UNI_RANGE(10),
 301                                                              UNI_RANGE(1),
 302                                                              UNI_RANGE(0.1),
 303                                                              UNI_RANGE(0.01),
 304                                                              BIP_RANGE(10),
 305                                                              BIP_RANGE(1),
 306                                                              BIP_RANGE(0.1),
 307                                                              BIP_RANGE(0.01),
 308                                                              }
 309};
 310
 311static const struct comedi_lrange range_a821pgh_ai = { 4, {
 312                                                           BIP_RANGE(5),
 313                                                           BIP_RANGE(0.5),
 314                                                           BIP_RANGE(0.05),
 315                                                           BIP_RANGE(0.005),
 316                                                           }
 317};
 318
 319struct pcl812_board {
 320
 321        const char *name;       /*  board name */
 322        int board_type;         /*  type of this board */
 323        int n_aichan;           /*  num of AI chans in S.E. */
 324        int n_aichan_diff;      /*  DIFF num of chans */
 325        int n_aochan;           /*  num of DA chans */
 326        int n_dichan;           /*  DI and DO chans */
 327        int n_dochan;
 328        int ai_maxdata;         /*  AI resolution */
 329        unsigned int ai_ns_min; /*  max sample speed of card v ns */
 330        unsigned int i8254_osc_base;    /*  clock base */
 331        const struct comedi_lrange *rangelist_ai;       /*  rangelist for A/D */
 332        const struct comedi_lrange *rangelist_ao;       /*  rangelist for D/A */
 333        unsigned int IRQbits;   /*  allowed IRQ */
 334        unsigned char DMAbits;  /*  allowed DMA chans */
 335        unsigned char io_range; /*  iorange for this board */
 336        unsigned char haveMPC508;       /*  1=board use MPC508A multiplexor */
 337};
 338
 339#define this_board ((const struct pcl812_board *)dev->board_ptr)
 340
 341struct pcl812_private {
 342
 343        unsigned char valid;    /*  =1 device is OK */
 344        unsigned char dma;      /*  >0 use dma ( usedDMA channel) */
 345        unsigned char use_diff; /*  =1 diff inputs */
 346        unsigned char use_MPC;  /*  1=board uses MPC508A multiplexor */
 347        unsigned char use_ext_trg;      /*  1=board uses external trigger */
 348        unsigned char range_correction; /*  =1 we must add 1 to range number */
 349        unsigned char old_chan_reg;     /*  lastly used chan/gain pair */
 350        unsigned char old_gain_reg;
 351        unsigned char mode_reg_int;     /*  there is stored INT number for some card */
 352        unsigned char ai_neverending;   /*  =1 we do unlimited AI */
 353        unsigned char ai_eos;   /*  1=EOS wake up */
 354        unsigned char ai_dma;   /*  =1 we use DMA */
 355        unsigned int ai_poll_ptr;       /*  how many sampes transfer poll */
 356        unsigned int ai_scans;  /*  len of scanlist */
 357        unsigned int ai_act_scan;       /*  how many scans we finished */
 358        unsigned int ai_chanlist[MAX_CHANLIST_LEN];     /*  our copy of channel/range list */
 359        unsigned int ai_n_chan; /*  how many channels is measured */
 360        unsigned int ai_flags;  /*  flaglist */
 361        unsigned int ai_data_len;       /*  len of data buffer */
 362        short *ai_data;         /*  data buffer */
 363        unsigned int ai_is16b;  /*  =1 we have 16 bit card */
 364        unsigned long dmabuf[2];        /*  PTR to DMA buf */
 365        unsigned int dmapages[2];       /*  how many pages we have allocated */
 366        unsigned int hwdmaptr[2];       /*  HW PTR to DMA buf */
 367        unsigned int hwdmasize[2];      /*  DMA buf size in bytes */
 368        unsigned int dmabytestomove[2]; /*  how many bytes DMA transfer */
 369        int next_dma_buf;       /*  which buffer is next to use */
 370        unsigned int dma_runs_to_end;   /*  how many times we must switch DMA buffers */
 371        unsigned int last_dma_run;      /*  how many bytes to transfer on last DMA buffer */
 372        unsigned int max_812_ai_mode0_rangewait;        /*  setling time for gain */
 373        unsigned int ao_readback[2];    /*  data for AO readback */
 374};
 375
 376#define devpriv ((struct pcl812_private *)dev->private)
 377
 378/*
 379==============================================================================
 380*/
 381static void start_pacer(struct comedi_device *dev, int mode,
 382                        unsigned int divisor1, unsigned int divisor2);
 383static void setup_range_channel(struct comedi_device *dev,
 384                                struct comedi_subdevice *s,
 385                                unsigned int rangechan, char wait);
 386static int pcl812_ai_cancel(struct comedi_device *dev,
 387                            struct comedi_subdevice *s);
 388/*
 389==============================================================================
 390*/
 391static int pcl812_ai_insn_read(struct comedi_device *dev,
 392                               struct comedi_subdevice *s,
 393                               struct comedi_insn *insn, unsigned int *data)
 394{
 395        int n;
 396        int timeout, hi;
 397
 398        /* select software trigger */
 399        outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE);
 400        /*  select channel and renge */
 401        setup_range_channel(dev, s, insn->chanspec, 1);
 402        for (n = 0; n < insn->n; n++) {
 403                /* start conversion */
 404                outb(255, dev->iobase + PCL812_SOFTTRIG);
 405                udelay(5);
 406                timeout = 50;   /* wait max 50us, it must finish under 33us */
 407                while (timeout--) {
 408                        hi = inb(dev->iobase + PCL812_AD_HI);
 409                        if (!(hi & PCL812_DRDY))
 410                                goto conv_finish;
 411                        udelay(1);
 412                }
 413                printk
 414                    ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
 415                     dev->minor, dev->board_name, dev->iobase);
 416                outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
 417                return -ETIME;
 418
 419conv_finish:
 420                data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO);
 421        }
 422        outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
 423        return n;
 424}
 425
 426/*
 427==============================================================================
 428*/
 429static int acl8216_ai_insn_read(struct comedi_device *dev,
 430                                struct comedi_subdevice *s,
 431                                struct comedi_insn *insn, unsigned int *data)
 432{
 433        int n;
 434        int timeout;
 435
 436        /* select software trigger */
 437        outb(1, dev->iobase + PCL812_MODE);
 438        /*  select channel and renge */
 439        setup_range_channel(dev, s, insn->chanspec, 1);
 440        for (n = 0; n < insn->n; n++) {
 441                /* start conversion */
 442                outb(255, dev->iobase + PCL812_SOFTTRIG);
 443                udelay(5);
 444                timeout = 50;   /* wait max 50us, it must finish under 33us */
 445                while (timeout--) {
 446                        if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY))
 447                                goto conv_finish;
 448                        udelay(1);
 449                }
 450                printk
 451                    ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
 452                     dev->minor, dev->board_name, dev->iobase);
 453                outb(0, dev->iobase + PCL812_MODE);
 454                return -ETIME;
 455
 456conv_finish:
 457                data[n] =
 458                    (inb(dev->iobase +
 459                         PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO);
 460        }
 461        outb(0, dev->iobase + PCL812_MODE);
 462        return n;
 463}
 464
 465/*
 466==============================================================================
 467*/
 468static int pcl812_ao_insn_write(struct comedi_device *dev,
 469                                struct comedi_subdevice *s,
 470                                struct comedi_insn *insn, unsigned int *data)
 471{
 472        int chan = CR_CHAN(insn->chanspec);
 473        int i;
 474
 475        for (i = 0; i < insn->n; i++) {
 476                outb((data[i] & 0xff),
 477                     dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO));
 478                outb((data[i] >> 8) & 0x0f,
 479                     dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI));
 480                devpriv->ao_readback[chan] = data[i];
 481        }
 482
 483        return i;
 484}
 485
 486/*
 487==============================================================================
 488*/
 489static int pcl812_ao_insn_read(struct comedi_device *dev,
 490                               struct comedi_subdevice *s,
 491                               struct comedi_insn *insn, unsigned int *data)
 492{
 493        int chan = CR_CHAN(insn->chanspec);
 494        int i;
 495
 496        for (i = 0; i < insn->n; i++)
 497                data[i] = devpriv->ao_readback[chan];
 498
 499        return i;
 500}
 501
 502/*
 503==============================================================================
 504*/
 505static int pcl812_di_insn_bits(struct comedi_device *dev,
 506                               struct comedi_subdevice *s,
 507                               struct comedi_insn *insn, unsigned int *data)
 508{
 509        if (insn->n != 2)
 510                return -EINVAL;
 511
 512        data[1] = inb(dev->iobase + PCL812_DI_LO);
 513        data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8;
 514
 515        return 2;
 516}
 517
 518/*
 519==============================================================================
 520*/
 521static int pcl812_do_insn_bits(struct comedi_device *dev,
 522                               struct comedi_subdevice *s,
 523                               struct comedi_insn *insn, unsigned int *data)
 524{
 525        if (insn->n != 2)
 526                return -EINVAL;
 527
 528        if (data[0]) {
 529                s->state &= ~data[0];
 530                s->state |= data[0] & data[1];
 531                outb(s->state & 0xff, dev->iobase + PCL812_DO_LO);
 532                outb((s->state >> 8), dev->iobase + PCL812_DO_HI);
 533        }
 534        data[1] = s->state;
 535
 536        return 2;
 537}
 538
 539#ifdef PCL812_EXTDEBUG
 540/*
 541==============================================================================
 542*/
 543static void pcl812_cmdtest_out(int e, struct comedi_cmd *cmd)
 544{
 545        printk(KERN_INFO "pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
 546               cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
 547        printk(KERN_INFO "pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
 548               cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
 549        printk(KERN_INFO "pcl812 e=%d stopsrc=%x scanend=%x\n", e,
 550               cmd->stop_src, cmd->scan_end_src);
 551        printk(KERN_INFO "pcl812 e=%d stoparg=%d scanendarg=%d "
 552               "chanlistlen=%d\n", e, cmd->stop_arg, cmd->scan_end_arg,
 553               cmd->chanlist_len);
 554}
 555#endif
 556
 557/*
 558==============================================================================
 559*/
 560static int pcl812_ai_cmdtest(struct comedi_device *dev,
 561                             struct comedi_subdevice *s, struct comedi_cmd *cmd)
 562{
 563        int err = 0;
 564        int tmp, divisor1, divisor2;
 565
 566#ifdef PCL812_EXTDEBUG
 567        printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n");
 568        pcl812_cmdtest_out(-1, cmd);
 569#endif
 570        /* step 1: make sure trigger sources are trivially valid */
 571
 572        tmp = cmd->start_src;
 573        cmd->start_src &= TRIG_NOW;
 574        if (!cmd->start_src || tmp != cmd->start_src)
 575                err++;
 576
 577        tmp = cmd->scan_begin_src;
 578        cmd->scan_begin_src &= TRIG_FOLLOW;
 579        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 580                err++;
 581
 582        tmp = cmd->convert_src;
 583        if (devpriv->use_ext_trg)
 584                cmd->convert_src &= TRIG_EXT;
 585        else
 586                cmd->convert_src &= TRIG_TIMER;
 587
 588        if (!cmd->convert_src || tmp != cmd->convert_src)
 589                err++;
 590
 591        tmp = cmd->scan_end_src;
 592        cmd->scan_end_src &= TRIG_COUNT;
 593        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 594                err++;
 595
 596        tmp = cmd->stop_src;
 597        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 598        if (!cmd->stop_src || tmp != cmd->stop_src)
 599                err++;
 600
 601        if (err) {
 602#ifdef PCL812_EXTDEBUG
 603                pcl812_cmdtest_out(1, cmd);
 604                printk
 605                    ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n",
 606                     err);
 607#endif
 608                return 1;
 609        }
 610
 611        /*
 612         * step 2: make sure trigger sources are
 613         * unique and mutually compatible
 614         */
 615
 616        if (cmd->start_src != TRIG_NOW) {
 617                cmd->start_src = TRIG_NOW;
 618                err++;
 619        }
 620
 621        if (cmd->scan_begin_src != TRIG_FOLLOW) {
 622                cmd->scan_begin_src = TRIG_FOLLOW;
 623                err++;
 624        }
 625
 626        if (devpriv->use_ext_trg) {
 627                if (cmd->convert_src != TRIG_EXT) {
 628                        cmd->convert_src = TRIG_EXT;
 629                        err++;
 630                }
 631        } else {
 632                if (cmd->convert_src != TRIG_TIMER) {
 633                        cmd->convert_src = TRIG_TIMER;
 634                        err++;
 635                }
 636        }
 637
 638        if (cmd->scan_end_src != TRIG_COUNT) {
 639                cmd->scan_end_src = TRIG_COUNT;
 640                err++;
 641        }
 642
 643        if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
 644                err++;
 645
 646        if (err) {
 647#ifdef PCL812_EXTDEBUG
 648                pcl812_cmdtest_out(2, cmd);
 649                printk
 650                    ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n",
 651                     err);
 652#endif
 653                return 2;
 654        }
 655
 656        /* step 3: make sure arguments are trivially compatible */
 657
 658        if (cmd->start_arg != 0) {
 659                cmd->start_arg = 0;
 660                err++;
 661        }
 662
 663        if (cmd->scan_begin_arg != 0) {
 664                cmd->scan_begin_arg = 0;
 665                err++;
 666        }
 667
 668        if (cmd->convert_src == TRIG_TIMER) {
 669                if (cmd->convert_arg < this_board->ai_ns_min) {
 670                        cmd->convert_arg = this_board->ai_ns_min;
 671                        err++;
 672                }
 673        } else {                /* TRIG_EXT */
 674                if (cmd->convert_arg != 0) {
 675                        cmd->convert_arg = 0;
 676                        err++;
 677                }
 678        }
 679
 680        if (!cmd->chanlist_len) {
 681                cmd->chanlist_len = 1;
 682                err++;
 683        }
 684        if (cmd->chanlist_len > MAX_CHANLIST_LEN) {
 685                cmd->chanlist_len = this_board->n_aichan;
 686                err++;
 687        }
 688        if (cmd->scan_end_arg != cmd->chanlist_len) {
 689                cmd->scan_end_arg = cmd->chanlist_len;
 690                err++;
 691        }
 692        if (cmd->stop_src == TRIG_COUNT) {
 693                if (!cmd->stop_arg) {
 694                        cmd->stop_arg = 1;
 695                        err++;
 696                }
 697        } else {                /* TRIG_NONE */
 698                if (cmd->stop_arg != 0) {
 699                        cmd->stop_arg = 0;
 700                        err++;
 701                }
 702        }
 703
 704        if (err) {
 705#ifdef PCL812_EXTDEBUG
 706                pcl812_cmdtest_out(3, cmd);
 707                printk
 708                    ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n",
 709                     err);
 710#endif
 711                return 3;
 712        }
 713
 714        /* step 4: fix up any arguments */
 715
 716        if (cmd->convert_src == TRIG_TIMER) {
 717                tmp = cmd->convert_arg;
 718                i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
 719                                          &divisor2, &cmd->convert_arg,
 720                                          cmd->flags & TRIG_ROUND_MASK);
 721                if (cmd->convert_arg < this_board->ai_ns_min)
 722                        cmd->convert_arg = this_board->ai_ns_min;
 723                if (tmp != cmd->convert_arg)
 724                        err++;
 725        }
 726
 727        if (err) {
 728#ifdef PCL812_EXTDEBUG
 729                printk
 730                    ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n",
 731                     err);
 732#endif
 733                return 4;
 734        }
 735
 736        return 0;
 737}
 738
 739/*
 740==============================================================================
 741*/
 742static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 743{
 744        unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes;
 745        struct comedi_cmd *cmd = &s->async->cmd;
 746
 747#ifdef PCL812_EXTDEBUG
 748        printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n");
 749#endif
 750
 751        if (cmd->start_src != TRIG_NOW)
 752                return -EINVAL;
 753        if (cmd->scan_begin_src != TRIG_FOLLOW)
 754                return -EINVAL;
 755        if (devpriv->use_ext_trg) {
 756                if (cmd->convert_src != TRIG_EXT)
 757                        return -EINVAL;
 758        } else {
 759                if (cmd->convert_src != TRIG_TIMER)
 760                        return -EINVAL;
 761        }
 762        if (cmd->scan_end_src != TRIG_COUNT)
 763                return -EINVAL;
 764        if (cmd->scan_end_arg != cmd->chanlist_len)
 765                return -EINVAL;
 766        if (cmd->chanlist_len > MAX_CHANLIST_LEN)
 767                return -EINVAL;
 768
 769        if (cmd->convert_src == TRIG_TIMER) {
 770                if (cmd->convert_arg < this_board->ai_ns_min)
 771                        cmd->convert_arg = this_board->ai_ns_min;
 772                i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
 773                                          &divisor1, &divisor2,
 774                                          &cmd->convert_arg,
 775                                          cmd->flags & TRIG_ROUND_MASK);
 776        }
 777
 778        start_pacer(dev, -1, 0, 0);     /*  stop pacer */
 779
 780        devpriv->ai_n_chan = cmd->chanlist_len;
 781        memcpy(devpriv->ai_chanlist, cmd->chanlist,
 782               sizeof(unsigned int) * cmd->scan_end_arg);
 783        /*  select first channel and range */
 784        setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1);
 785
 786        if (devpriv->dma) {     /*  check if we can use DMA transfer */
 787                devpriv->ai_dma = 1;
 788                for (i = 1; i < devpriv->ai_n_chan; i++)
 789                        if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) {
 790                                /*  we cann't use DMA :-( */
 791                                devpriv->ai_dma = 0;
 792                                break;
 793                        }
 794        } else
 795                devpriv->ai_dma = 0;
 796
 797        devpriv->ai_flags = cmd->flags;
 798        devpriv->ai_data_len = s->async->prealloc_bufsz;
 799        devpriv->ai_data = s->async->prealloc_buf;
 800        if (cmd->stop_src == TRIG_COUNT) {
 801                devpriv->ai_scans = cmd->stop_arg;
 802                devpriv->ai_neverending = 0;
 803        } else {
 804                devpriv->ai_scans = 0;
 805                devpriv->ai_neverending = 1;
 806        }
 807
 808        devpriv->ai_act_scan = 0;
 809        devpriv->ai_poll_ptr = 0;
 810        s->async->cur_chan = 0;
 811
 812        /*  don't we want wake up every scan? */
 813        if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
 814                devpriv->ai_eos = 1;
 815
 816                /*  DMA is useless for this situation */
 817                if (devpriv->ai_n_chan == 1)
 818                        devpriv->ai_dma = 0;
 819        }
 820
 821        if (devpriv->ai_dma) {
 822                /*  we use EOS, so adapt DMA buffer to one scan */
 823                if (devpriv->ai_eos) {
 824                        devpriv->dmabytestomove[0] =
 825                            devpriv->ai_n_chan * sizeof(short);
 826                        devpriv->dmabytestomove[1] =
 827                            devpriv->ai_n_chan * sizeof(short);
 828                        devpriv->dma_runs_to_end = 1;
 829                } else {
 830                        devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
 831                        devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
 832                        if (devpriv->ai_data_len < devpriv->hwdmasize[0])
 833                                devpriv->dmabytestomove[0] =
 834                                    devpriv->ai_data_len;
 835                        if (devpriv->ai_data_len < devpriv->hwdmasize[1])
 836                                devpriv->dmabytestomove[1] =
 837                                    devpriv->ai_data_len;
 838                        if (devpriv->ai_neverending) {
 839                                devpriv->dma_runs_to_end = 1;
 840                        } else {
 841                                /*  how many samples we must transfer? */
 842                                bytes = devpriv->ai_n_chan *
 843                                        devpriv->ai_scans * sizeof(short);
 844
 845                                /*  how many DMA pages we must fill */
 846                                devpriv->dma_runs_to_end =
 847                                        bytes / devpriv->dmabytestomove[0];
 848
 849                                /* on last dma transfer must be moved */
 850                                devpriv->last_dma_run =
 851                                        bytes % devpriv->dmabytestomove[0];
 852                                if (devpriv->dma_runs_to_end == 0)
 853                                        devpriv->dmabytestomove[0] =
 854                                            devpriv->last_dma_run;
 855                                devpriv->dma_runs_to_end--;
 856                        }
 857                }
 858                if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) {
 859                        devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
 860                        devpriv->ai_eos = 0;
 861                }
 862                if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) {
 863                        devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
 864                        devpriv->ai_eos = 0;
 865                }
 866                devpriv->next_dma_buf = 0;
 867                set_dma_mode(devpriv->dma, DMA_MODE_READ);
 868                dma_flags = claim_dma_lock();
 869                clear_dma_ff(devpriv->dma);
 870                set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
 871                set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
 872                release_dma_lock(dma_flags);
 873                enable_dma(devpriv->dma);
 874#ifdef PCL812_EXTDEBUG
 875                printk
 876                    ("pcl812 EDBG:   DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n",
 877                     devpriv->dma, devpriv->hwdmaptr[0],
 878                     devpriv->hwdmaptr[1], devpriv->dmabytestomove[0],
 879                     devpriv->dmabytestomove[1], devpriv->ai_eos);
 880#endif
 881        }
 882
 883        switch (cmd->convert_src) {
 884        case TRIG_TIMER:
 885                start_pacer(dev, 1, divisor1, divisor2);
 886                break;
 887        }
 888
 889        if (devpriv->ai_dma)                                    /*  let's go! */
 890                outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE);
 891        else                                                    /*  let's go! */
 892                outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE);
 893
 894#ifdef PCL812_EXTDEBUG
 895        printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cmd(...)\n");
 896#endif
 897
 898        return 0;
 899}
 900
 901/*
 902==============================================================================
 903*/
 904static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
 905{
 906        char err = 1;
 907        unsigned int mask, timeout;
 908        struct comedi_device *dev = d;
 909        struct comedi_subdevice *s = dev->subdevices + 0;
 910        unsigned int next_chan;
 911
 912        s->async->events = 0;
 913
 914        timeout = 50;           /* wait max 50us, it must finish under 33us */
 915        if (devpriv->ai_is16b) {
 916                mask = 0xffff;
 917                while (timeout--) {
 918                        if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) {
 919                                err = 0;
 920                                break;
 921                        }
 922                        udelay(1);
 923                }
 924        } else {
 925                mask = 0x0fff;
 926                while (timeout--) {
 927                        if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) {
 928                                err = 0;
 929                                break;
 930                        }
 931                        udelay(1);
 932                }
 933        }
 934
 935        if (err) {
 936                printk
 937                    ("comedi%d: pcl812: (%s at 0x%lx) "
 938                     "A/D cmd IRQ without DRDY!\n",
 939                     dev->minor, dev->board_name, dev->iobase);
 940                pcl812_ai_cancel(dev, s);
 941                s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
 942                comedi_event(dev, s);
 943                return IRQ_HANDLED;
 944        }
 945
 946        comedi_buf_put(s->async,
 947                       ((inb(dev->iobase + PCL812_AD_HI) << 8) |
 948                        inb(dev->iobase + PCL812_AD_LO)) & mask);
 949
 950        /* Set up next channel. Added by abbotti 2010-01-20, but untested. */
 951        next_chan = s->async->cur_chan + 1;
 952        if (next_chan >= devpriv->ai_n_chan)
 953                next_chan = 0;
 954        if (devpriv->ai_chanlist[s->async->cur_chan] !=
 955                        devpriv->ai_chanlist[next_chan])
 956                setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0);
 957
 958        outb(0, dev->iobase + PCL812_CLRINT);   /* clear INT request */
 959
 960        s->async->cur_chan = next_chan;
 961        if (next_chan == 0) {   /* one scan done */
 962                devpriv->ai_act_scan++;
 963                if (!(devpriv->ai_neverending))
 964                                                        /* all data sampled */
 965                        if (devpriv->ai_act_scan >= devpriv->ai_scans) {
 966                                pcl812_ai_cancel(dev, s);
 967                                s->async->events |= COMEDI_CB_EOA;
 968                        }
 969        }
 970
 971        comedi_event(dev, s);
 972        return IRQ_HANDLED;
 973}
 974
 975/*
 976==============================================================================
 977*/
 978static void transfer_from_dma_buf(struct comedi_device *dev,
 979                                  struct comedi_subdevice *s, short *ptr,
 980                                  unsigned int bufptr, unsigned int len)
 981{
 982        unsigned int i;
 983
 984        s->async->events = 0;
 985        for (i = len; i; i--) {
 986                                                        /*  get one sample */
 987                comedi_buf_put(s->async, ptr[bufptr++]);
 988
 989                s->async->cur_chan++;
 990                if (s->async->cur_chan >= devpriv->ai_n_chan) {
 991                        s->async->cur_chan = 0;
 992                        devpriv->ai_act_scan++;
 993                        if (!devpriv->ai_neverending)
 994                                                        /* all data sampled */
 995                                if (devpriv->ai_act_scan >= devpriv->ai_scans) {
 996                                        pcl812_ai_cancel(dev, s);
 997                                        s->async->events |= COMEDI_CB_EOA;
 998                                        break;
 999                                }
1000                }
1001        }
1002
1003        comedi_event(dev, s);
1004}
1005
1006/*
1007==============================================================================
1008*/
1009static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
1010{
1011        struct comedi_device *dev = d;
1012        struct comedi_subdevice *s = dev->subdevices + 0;
1013        unsigned long dma_flags;
1014        int len, bufptr;
1015        short *ptr;
1016
1017#ifdef PCL812_EXTDEBUG
1018        printk(KERN_DEBUG "pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
1019#endif
1020        ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf];
1021        len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
1022            devpriv->ai_poll_ptr;
1023
1024        devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
1025        disable_dma(devpriv->dma);
1026        set_dma_mode(devpriv->dma, DMA_MODE_READ);
1027        dma_flags = claim_dma_lock();
1028        set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
1029        if (devpriv->ai_eos) {
1030                set_dma_count(devpriv->dma,
1031                              devpriv->dmabytestomove[devpriv->next_dma_buf]);
1032        } else {
1033                if (devpriv->dma_runs_to_end) {
1034                        set_dma_count(devpriv->dma,
1035                                      devpriv->dmabytestomove[devpriv->
1036                                                              next_dma_buf]);
1037                } else {
1038                        set_dma_count(devpriv->dma, devpriv->last_dma_run);
1039                }
1040                devpriv->dma_runs_to_end--;
1041        }
1042        release_dma_lock(dma_flags);
1043        enable_dma(devpriv->dma);
1044
1045        outb(0, dev->iobase + PCL812_CLRINT);   /* clear INT request */
1046
1047        bufptr = devpriv->ai_poll_ptr;
1048        devpriv->ai_poll_ptr = 0;
1049
1050        transfer_from_dma_buf(dev, s, ptr, bufptr, len);
1051
1052#ifdef PCL812_EXTDEBUG
1053        printk(KERN_DEBUG "pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
1054#endif
1055        return IRQ_HANDLED;
1056}
1057
1058/*
1059==============================================================================
1060*/
1061static irqreturn_t interrupt_pcl812(int irq, void *d)
1062{
1063        struct comedi_device *dev = d;
1064
1065        if (!dev->attached) {
1066                comedi_error(dev, "spurious interrupt");
1067                return IRQ_HANDLED;
1068        }
1069        if (devpriv->ai_dma)
1070                return interrupt_pcl812_ai_dma(irq, d);
1071        else
1072                return interrupt_pcl812_ai_int(irq, d);
1073}
1074
1075/*
1076==============================================================================
1077*/
1078static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
1079{
1080        unsigned long flags;
1081        unsigned int top1, top2, i;
1082
1083        if (!devpriv->ai_dma)
1084                return 0;       /*  poll is valid only for DMA transfer */
1085
1086        spin_lock_irqsave(&dev->spinlock, flags);
1087
1088        for (i = 0; i < 10; i++) {
1089                /*  where is now DMA */
1090                top1 = get_dma_residue(devpriv->ai_dma);
1091                top2 = get_dma_residue(devpriv->ai_dma);
1092                if (top1 == top2)
1093                        break;
1094        }
1095
1096        if (top1 != top2) {
1097                spin_unlock_irqrestore(&dev->spinlock, flags);
1098                return 0;
1099        }
1100        /*  where is now DMA in buffer */
1101        top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1;
1102        top1 >>= 1;             /*  sample position */
1103        top2 = top1 - devpriv->ai_poll_ptr;
1104        if (top2 < 1) {         /*  no new samples */
1105                spin_unlock_irqrestore(&dev->spinlock, flags);
1106                return 0;
1107        }
1108
1109        transfer_from_dma_buf(dev, s,
1110                              (void *)devpriv->dmabuf[1 -
1111                                                      devpriv->next_dma_buf],
1112                              devpriv->ai_poll_ptr, top2);
1113
1114        devpriv->ai_poll_ptr = top1;    /*  new buffer position */
1115
1116        spin_unlock_irqrestore(&dev->spinlock, flags);
1117
1118        return s->async->buf_write_count - s->async->buf_read_count;
1119}
1120
1121/*
1122==============================================================================
1123*/
1124static void setup_range_channel(struct comedi_device *dev,
1125                                struct comedi_subdevice *s,
1126                                unsigned int rangechan, char wait)
1127{
1128        unsigned char chan_reg = CR_CHAN(rangechan);    /*  normal board */
1129                                                        /*  gain index */
1130        unsigned char gain_reg = CR_RANGE(rangechan) +
1131                                 devpriv->range_correction;
1132
1133        if ((chan_reg == devpriv->old_chan_reg)
1134            && (gain_reg == devpriv->old_gain_reg))
1135                return;         /*  we can return, no change */
1136
1137        devpriv->old_chan_reg = chan_reg;
1138        devpriv->old_gain_reg = gain_reg;
1139
1140        if (devpriv->use_MPC) {
1141                if (devpriv->use_diff) {
1142                        chan_reg = chan_reg | 0x30;     /*  DIFF inputs */
1143                } else {
1144                        if (chan_reg & 0x80)
1145                                                        /*  SE inputs 8-15 */
1146                                chan_reg = chan_reg | 0x20;
1147                        else
1148                                                        /*  SE inputs 0-7 */
1149                                chan_reg = chan_reg | 0x10;
1150                }
1151        }
1152
1153        outb(chan_reg, dev->iobase + PCL812_MUX);       /* select channel */
1154        outb(gain_reg, dev->iobase + PCL812_GAIN);      /* select gain */
1155
1156
1157        if (wait)
1158                /*
1159                 * XXX this depends on selected range and can be very long for
1160                 * some high gain ranges!
1161                 */
1162                udelay(devpriv->max_812_ai_mode0_rangewait);
1163}
1164
1165/*
1166==============================================================================
1167*/
1168static void start_pacer(struct comedi_device *dev, int mode,
1169                        unsigned int divisor1, unsigned int divisor2)
1170{
1171#ifdef PCL812_EXTDEBUG
1172        printk(KERN_DEBUG "pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1173               divisor1, divisor2);
1174#endif
1175        outb(0xb4, dev->iobase + PCL812_CTRCTL);
1176        outb(0x74, dev->iobase + PCL812_CTRCTL);
1177        udelay(1);
1178
1179        if (mode == 1) {
1180                outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2);
1181                outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);
1182                outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1);
1183                outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
1184        }
1185#ifdef PCL812_EXTDEBUG
1186        printk(KERN_DEBUG "pcl812 EDBG: END: start_pacer(...)\n");
1187#endif
1188}
1189
1190/*
1191==============================================================================
1192*/
1193static void free_resources(struct comedi_device *dev)
1194{
1195
1196        if (dev->private) {
1197                if (devpriv->dmabuf[0])
1198                        free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1199                if (devpriv->dmabuf[1])
1200                        free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1201                if (devpriv->dma)
1202                        free_dma(devpriv->dma);
1203        }
1204        if (dev->irq)
1205                free_irq(dev->irq, dev);
1206        if (dev->iobase)
1207                release_region(dev->iobase, this_board->io_range);
1208}
1209
1210/*
1211==============================================================================
1212*/
1213static int pcl812_ai_cancel(struct comedi_device *dev,
1214                            struct comedi_subdevice *s)
1215{
1216#ifdef PCL812_EXTDEBUG
1217        printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
1218#endif
1219        if (devpriv->ai_dma)
1220                disable_dma(devpriv->dma);
1221        outb(0, dev->iobase + PCL812_CLRINT);   /* clear INT request */
1222                                                        /* Stop A/D */
1223        outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
1224        start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1225        outb(0, dev->iobase + PCL812_CLRINT);   /* clear INT request */
1226#ifdef PCL812_EXTDEBUG
1227        printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
1228#endif
1229        return 0;
1230}
1231
1232/*
1233==============================================================================
1234*/
1235static void pcl812_reset(struct comedi_device *dev)
1236{
1237#ifdef PCL812_EXTDEBUG
1238        printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_reset(...)\n");
1239#endif
1240        outb(0, dev->iobase + PCL812_MUX);
1241        outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN);
1242        devpriv->old_chan_reg = -1;     /*  invalidate chain/gain memory */
1243        devpriv->old_gain_reg = -1;
1244
1245        switch (this_board->board_type) {
1246        case boardPCL812PG:
1247        case boardPCL812:
1248        case boardACL8112:
1249        case boardACL8216:
1250                outb(0, dev->iobase + PCL812_DA2_LO);
1251                outb(0, dev->iobase + PCL812_DA2_HI);
1252        case boardA821:
1253                outb(0, dev->iobase + PCL812_DA1_LO);
1254                outb(0, dev->iobase + PCL812_DA1_HI);
1255                start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1256                outb(0, dev->iobase + PCL812_DO_HI);
1257                outb(0, dev->iobase + PCL812_DO_LO);
1258                outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
1259                outb(0, dev->iobase + PCL812_CLRINT);
1260                break;
1261        case boardPCL813B:
1262        case boardPCL813:
1263        case boardISO813:
1264        case boardACL8113:
1265                udelay(5);
1266                break;
1267        }
1268        udelay(5);
1269#ifdef PCL812_EXTDEBUG
1270        printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_reset(...)\n");
1271#endif
1272}
1273
1274static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1275{
1276        int ret, subdev;
1277        unsigned long iobase;
1278        unsigned int irq;
1279        unsigned int dma;
1280        unsigned long pages;
1281        struct comedi_subdevice *s;
1282        int n_subdevices;
1283
1284        iobase = it->options[0];
1285        printk(KERN_INFO "comedi%d: pcl812:  board=%s, ioport=0x%03lx",
1286               dev->minor, this_board->name, iobase);
1287
1288        if (!request_region(iobase, this_board->io_range, "pcl812")) {
1289                printk("I/O port conflict\n");
1290                return -EIO;
1291        }
1292        dev->iobase = iobase;
1293
1294        ret = alloc_private(dev, sizeof(struct pcl812_private));
1295        if (ret < 0) {
1296                free_resources(dev);
1297                return ret;     /* Can't alloc mem */
1298        }
1299
1300        dev->board_name = this_board->name;
1301
1302        irq = 0;
1303        if (this_board->IRQbits != 0) { /* board support IRQ */
1304                irq = it->options[1];
1305                if (irq) {      /* we want to use IRQ */
1306                        if (((1 << irq) & this_board->IRQbits) == 0) {
1307                                printk
1308                                    (", IRQ %u is out of allowed range, "
1309                                     "DISABLING IT", irq);
1310                                irq = 0;        /* Bad IRQ */
1311                        } else {
1312                                if (request_irq
1313                                    (irq, interrupt_pcl812, 0, "pcl812", dev)) {
1314                                        printk
1315                                            (", unable to allocate IRQ %u, "
1316                                             "DISABLING IT", irq);
1317                                        irq = 0;        /* Can't use IRQ */
1318                                } else {
1319                                        printk(KERN_INFO ", irq=%u", irq);
1320                                }
1321                        }
1322                }
1323        }
1324
1325        dev->irq = irq;
1326
1327        dma = 0;
1328        devpriv->dma = dma;
1329        if (!dev->irq)
1330                goto no_dma;    /* if we haven't IRQ, we can't use DMA */
1331        if (this_board->DMAbits != 0) { /* board support DMA */
1332                dma = it->options[2];
1333                if (((1 << dma) & this_board->DMAbits) == 0) {
1334                        printk(", DMA is out of allowed range, FAIL!\n");
1335                        return -EINVAL; /* Bad DMA */
1336                }
1337                ret = request_dma(dma, "pcl812");
1338                if (ret) {
1339                        printk(KERN_ERR ", unable to allocate DMA %u, FAIL!\n",
1340                               dma);
1341                        return -EBUSY;  /* DMA isn't free */
1342                }
1343                devpriv->dma = dma;
1344                printk(KERN_INFO ", dma=%u", dma);
1345                pages = 1;      /* we want 8KB */
1346                devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1347                if (!devpriv->dmabuf[0]) {
1348                        printk(", unable to allocate DMA buffer, FAIL!\n");
1349                        /*
1350                         * maybe experiment with try_to_free_pages()
1351                         * will help ....
1352                         */
1353                        free_resources(dev);
1354                        return -EBUSY;  /* no buffer :-( */
1355                }
1356                devpriv->dmapages[0] = pages;
1357                devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1358                devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages);
1359                devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1360                if (!devpriv->dmabuf[1]) {
1361                        printk(KERN_ERR ", unable to allocate DMA buffer, FAIL!\n");
1362                        free_resources(dev);
1363                        return -EBUSY;
1364                }
1365                devpriv->dmapages[1] = pages;
1366                devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1367                devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages);
1368        }
1369no_dma:
1370
1371        n_subdevices = 0;
1372        if (this_board->n_aichan > 0)
1373                n_subdevices++;
1374        if (this_board->n_aochan > 0)
1375                n_subdevices++;
1376        if (this_board->n_dichan > 0)
1377                n_subdevices++;
1378        if (this_board->n_dochan > 0)
1379                n_subdevices++;
1380
1381        ret = alloc_subdevices(dev, n_subdevices);
1382        if (ret < 0) {
1383                free_resources(dev);
1384                return ret;
1385        }
1386
1387        subdev = 0;
1388
1389        /* analog input */
1390        if (this_board->n_aichan > 0) {
1391                s = dev->subdevices + subdev;
1392                s->type = COMEDI_SUBD_AI;
1393                s->subdev_flags = SDF_READABLE;
1394                switch (this_board->board_type) {
1395                case boardA821:
1396                        if (it->options[2] == 1) {
1397                                s->n_chan = this_board->n_aichan_diff;
1398                                s->subdev_flags |= SDF_DIFF;
1399                                devpriv->use_diff = 1;
1400                        } else {
1401                                s->n_chan = this_board->n_aichan;
1402                                s->subdev_flags |= SDF_GROUND;
1403                        }
1404                        break;
1405                case boardACL8112:
1406                case boardACL8216:
1407                        if (it->options[4] == 1) {
1408                                s->n_chan = this_board->n_aichan_diff;
1409                                s->subdev_flags |= SDF_DIFF;
1410                                devpriv->use_diff = 1;
1411                        } else {
1412                                s->n_chan = this_board->n_aichan;
1413                                s->subdev_flags |= SDF_GROUND;
1414                        }
1415                        break;
1416                default:
1417                        s->n_chan = this_board->n_aichan;
1418                        s->subdev_flags |= SDF_GROUND;
1419                        break;
1420                }
1421                s->maxdata = this_board->ai_maxdata;
1422                s->len_chanlist = MAX_CHANLIST_LEN;
1423                s->range_table = this_board->rangelist_ai;
1424                if (this_board->board_type == boardACL8216)
1425                        s->insn_read = acl8216_ai_insn_read;
1426                else
1427                        s->insn_read = pcl812_ai_insn_read;
1428
1429                devpriv->use_MPC = this_board->haveMPC508;
1430                s->cancel = pcl812_ai_cancel;
1431                if (dev->irq) {
1432                        dev->read_subdev = s;
1433                        s->subdev_flags |= SDF_CMD_READ;
1434                        s->do_cmdtest = pcl812_ai_cmdtest;
1435                        s->do_cmd = pcl812_ai_cmd;
1436                        s->poll = pcl812_ai_poll;
1437                }
1438                switch (this_board->board_type) {
1439                case boardPCL812PG:
1440                        if (it->options[4] == 1)
1441                                s->range_table = &range_pcl812pg2_ai;
1442                        break;
1443                case boardPCL812:
1444                        switch (it->options[4]) {
1445                        case 0:
1446                                s->range_table = &range_bipolar10;
1447                                break;
1448                        case 1:
1449                                s->range_table = &range_bipolar5;
1450                                break;
1451                        case 2:
1452                                s->range_table = &range_bipolar2_5;
1453                                break;
1454                        case 3:
1455                                s->range_table = &range812_bipolar1_25;
1456                                break;
1457                        case 4:
1458                                s->range_table = &range812_bipolar0_625;
1459                                break;
1460                        case 5:
1461                                s->range_table = &range812_bipolar0_3125;
1462                                break;
1463                        default:
1464                                s->range_table = &range_bipolar10;
1465                                break;
1466                                printk
1467                                    (", incorrect range number %d, changing "
1468                                     "to 0 (+/-10V)", it->options[4]);
1469                                break;
1470                        }
1471                        break;
1472                        break;
1473                case boardPCL813B:
1474                        if (it->options[1] == 1)
1475                                s->range_table = &range_pcl813b2_ai;
1476                        break;
1477                case boardISO813:
1478                        switch (it->options[1]) {
1479                        case 0:
1480                                s->range_table = &range_iso813_1_ai;
1481                                break;
1482                        case 1:
1483                                s->range_table = &range_iso813_1_2_ai;
1484                                break;
1485                        case 2:
1486                                s->range_table = &range_iso813_2_ai;
1487                                devpriv->range_correction = 1;
1488                                break;
1489                        case 3:
1490                                s->range_table = &range_iso813_2_2_ai;
1491                                devpriv->range_correction = 1;
1492                                break;
1493                        default:
1494                                s->range_table = &range_iso813_1_ai;
1495                                break;
1496                                printk
1497                                    (", incorrect range number %d, "
1498                                     "changing to 0 ", it->options[1]);
1499                                break;
1500                        }
1501                        break;
1502                case boardACL8113:
1503                        switch (it->options[1]) {
1504                        case 0:
1505                                s->range_table = &range_acl8113_1_ai;
1506                                break;
1507                        case 1:
1508                                s->range_table = &range_acl8113_1_2_ai;
1509                                break;
1510                        case 2:
1511                                s->range_table = &range_acl8113_2_ai;
1512                                devpriv->range_correction = 1;
1513                                break;
1514                        case 3:
1515                                s->range_table = &range_acl8113_2_2_ai;
1516                                devpriv->range_correction = 1;
1517                                break;
1518                        default:
1519                                s->range_table = &range_acl8113_1_ai;
1520                                break;
1521                                printk
1522                                    (", incorrect range number %d, "
1523                                     "changing to 0 ", it->options[1]);
1524                                break;
1525                        }
1526                        break;
1527                }
1528                subdev++;
1529        }
1530
1531        /* analog output */
1532        if (this_board->n_aochan > 0) {
1533                s = dev->subdevices + subdev;
1534                s->type = COMEDI_SUBD_AO;
1535                s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1536                s->n_chan = this_board->n_aochan;
1537                s->maxdata = 0xfff;
1538                s->len_chanlist = 1;
1539                s->range_table = this_board->rangelist_ao;
1540                s->insn_read = pcl812_ao_insn_read;
1541                s->insn_write = pcl812_ao_insn_write;
1542                switch (this_board->board_type) {
1543                case boardA821:
1544                        if (it->options[3] == 1)
1545                                s->range_table = &range_unipolar10;
1546                        break;
1547                case boardPCL812:
1548                case boardACL8112:
1549                case boardPCL812PG:
1550                case boardACL8216:
1551                        if (it->options[5] == 1)
1552                                s->range_table = &range_unipolar10;
1553                        if (it->options[5] == 2)
1554                                s->range_table = &range_unknown;
1555                        break;
1556                }
1557                subdev++;
1558        }
1559
1560        /* digital input */
1561        if (this_board->n_dichan > 0) {
1562                s = dev->subdevices + subdev;
1563                s->type = COMEDI_SUBD_DI;
1564                s->subdev_flags = SDF_READABLE;
1565                s->n_chan = this_board->n_dichan;
1566                s->maxdata = 1;
1567                s->len_chanlist = this_board->n_dichan;
1568                s->range_table = &range_digital;
1569                s->insn_bits = pcl812_di_insn_bits;
1570                subdev++;
1571        }
1572
1573        /* digital output */
1574        if (this_board->n_dochan > 0) {
1575                s = dev->subdevices + subdev;
1576                s->type = COMEDI_SUBD_DO;
1577                s->subdev_flags = SDF_WRITABLE;
1578                s->n_chan = this_board->n_dochan;
1579                s->maxdata = 1;
1580                s->len_chanlist = this_board->n_dochan;
1581                s->range_table = &range_digital;
1582                s->insn_bits = pcl812_do_insn_bits;
1583                subdev++;
1584        }
1585
1586        switch (this_board->board_type) {
1587        case boardACL8216:
1588                devpriv->ai_is16b = 1;
1589        case boardPCL812PG:
1590        case boardPCL812:
1591        case boardACL8112:
1592                devpriv->max_812_ai_mode0_rangewait = 1;
1593                if (it->options[3] > 0)
1594                                                /*  we use external trigger */
1595                        devpriv->use_ext_trg = 1;
1596        case boardA821:
1597                devpriv->max_812_ai_mode0_rangewait = 1;
1598                devpriv->mode_reg_int = (irq << 4) & 0xf0;
1599                break;
1600        case boardPCL813B:
1601        case boardPCL813:
1602        case boardISO813:
1603        case boardACL8113:
1604                /* maybe there must by greatest timeout */
1605                devpriv->max_812_ai_mode0_rangewait = 5;
1606                break;
1607        }
1608
1609        printk(KERN_INFO "\n");
1610        devpriv->valid = 1;
1611
1612        pcl812_reset(dev);
1613
1614        return 0;
1615}
1616
1617static void pcl812_detach(struct comedi_device *dev)
1618{
1619        free_resources(dev);
1620}
1621
1622static const struct pcl812_board boardtypes[] = {
1623        {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
1624         33000, 500, &range_bipolar10, &range_unipolar5,
1625         0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1626        {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
1627         33000, 500, &range_pcl812pg_ai, &range_unipolar5,
1628         0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1629        {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
1630         10000, 500, &range_pcl812pg_ai, &range_unipolar5,
1631         0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1632        {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1633         10000, 500, &range_acl8112dg_ai, &range_unipolar5,
1634         0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
1635        {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1636         10000, 500, &range_acl8112hg_ai, &range_unipolar5,
1637         0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
1638        {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
1639         10000, 500, &range_pcl813b_ai, &range_unipolar5,
1640         0x000c, 0x00, PCLx1x_IORANGE, 0},
1641        {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
1642         10000, 500, &range_pcl813b_ai, NULL,
1643         0x000c, 0x00, PCLx1x_IORANGE, 0},
1644        {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
1645         10000, 500, &range_a821pgh_ai, &range_unipolar5,
1646         0x000c, 0x00, PCLx1x_IORANGE, 0},
1647        {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1648         10000, 500, &range_acl8112dg_ai, &range_unipolar5,
1649         0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1650        {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1651         10000, 500, &range_acl8112hg_ai, &range_unipolar5,
1652         0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1653        {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1654         8000, 500, &range_acl8112dg_ai, &range_unipolar5,
1655         0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1656        {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1657         8000, 500, &range_acl8112hg_ai, &range_unipolar5,
1658         0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1659        {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
1660         0, 0, &range_pcl813b_ai, NULL,
1661         0x0000, 0x00, PCLx1x_IORANGE, 0},
1662        {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
1663         0, 0, &range_pcl813b_ai, NULL,
1664         0x0000, 0x00, PCLx1x_IORANGE, 0},
1665        {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
1666         0, 0, &range_acl8113_1_ai, NULL,
1667         0x0000, 0x00, PCLx1x_IORANGE, 0},
1668        {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
1669         0, 0, &range_iso813_1_ai, NULL,
1670         0x0000, 0x00, PCLx1x_IORANGE, 0},
1671        {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
1672         10000, 500, &range_pcl813b2_ai, &range_unipolar5,
1673         0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
1674        {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
1675         10000, 500, &range_pcl813b2_ai, &range_unipolar5,
1676         0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1677};
1678
1679static struct comedi_driver pcl812_driver = {
1680        .driver_name    = "pcl812",
1681        .module         = THIS_MODULE,
1682        .attach         = pcl812_attach,
1683        .detach         = pcl812_detach,
1684        .board_name     = &boardtypes[0].name,
1685        .num_names      = ARRAY_SIZE(boardtypes),
1686        .offset         = sizeof(struct pcl812_board),
1687};
1688module_comedi_driver(pcl812_driver);
1689
1690MODULE_AUTHOR("Comedi http://www.comedi.org");
1691MODULE_DESCRIPTION("Comedi low-level driver");
1692MODULE_LICENSE("GPL");
1693