linux/drivers/staging/comedi/drivers/adv_pci1710.c
<<
>>
Prefs
   1/*
   2 * comedi/drivers/adv_pci1710.c
   3 *
   4 * Author: Michal Dobes <dobes@tesnet.cz>
   5 *
   6 * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
   7 * for testing and informations.
   8 *
   9 *  hardware driver for Advantech cards:
  10 *   card:   PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731
  11 *   driver: pci1710,  pci1710hg,  pci1711,  pci1713,  pci1720,  pci1731
  12 *
  13 * Options:
  14 *  [0] - PCI bus number - if bus number and slot number are 0,
  15 *                         then driver search for first unused card
  16 *  [1] - PCI slot number
  17 *
  18*/
  19/*
  20Driver: adv_pci1710
  21Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
  22             Advantech PCI-1720, PCI-1731
  23Author: Michal Dobes <dobes@tesnet.cz>
  24Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
  25  PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
  26  PCI-1731
  27Status: works
  28
  29This driver supports AI, AO, DI and DO subdevices.
  30AI subdevice supports cmd and insn interface,
  31other subdevices support only insn interface.
  32
  33The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
  34driver cannot distinguish between them, as would be normal for a
  35PCI driver.
  36
  37Configuration options:
  38  [0] - PCI bus of device (optional)
  39  [1] - PCI slot of device (optional)
  40          If bus/slot is not specified, the first available PCI
  41          device will be used.
  42*/
  43
  44#include <linux/interrupt.h>
  45
  46#include "../comedidev.h"
  47
  48#include "comedi_pci.h"
  49
  50#include "8253.h"
  51#include "amcc_s5933.h"
  52
  53#define PCI171x_PARANOIDCHECK   /* if defined, then is used code which control correct channel number on every 12 bit sample */
  54
  55#undef PCI171X_EXTDEBUG
  56
  57#define DRV_NAME "adv_pci1710"
  58
  59#undef DPRINTK
  60#ifdef PCI171X_EXTDEBUG
  61#define DPRINTK(fmt, args...) printk(fmt, ## args)
  62#else
  63#define DPRINTK(fmt, args...)
  64#endif
  65
  66/* hardware types of the cards */
  67#define TYPE_PCI171X    0
  68#define TYPE_PCI1713    2
  69#define TYPE_PCI1720    3
  70
  71#define IORANGE_171x    32
  72#define IORANGE_1720    16
  73
  74#define PCI171x_AD_DATA  0      /* R:   A/D data */
  75#define PCI171x_SOFTTRG  0      /* W:   soft trigger for A/D */
  76#define PCI171x_RANGE    2      /* W:   A/D gain/range register */
  77#define PCI171x_MUX      4      /* W:   A/D multiplexor control */
  78#define PCI171x_STATUS   6      /* R:   status register */
  79#define PCI171x_CONTROL  6      /* W:   control register */
  80#define PCI171x_CLRINT   8      /* W:   clear interrupts request */
  81#define PCI171x_CLRFIFO  9      /* W:   clear FIFO */
  82#define PCI171x_DA1     10      /* W:   D/A register */
  83#define PCI171x_DA2     12      /* W:   D/A register */
  84#define PCI171x_DAREF   14      /* W:   D/A reference control */
  85#define PCI171x_DI      16      /* R:   digi inputs */
  86#define PCI171x_DO      16      /* R:   digi inputs */
  87#define PCI171x_CNT0    24      /* R/W: 8254 couter 0 */
  88#define PCI171x_CNT1    26      /* R/W: 8254 couter 1 */
  89#define PCI171x_CNT2    28      /* R/W: 8254 couter 2 */
  90#define PCI171x_CNTCTRL 30      /* W:   8254 counter control */
  91
  92/* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */
  93#define Status_FE       0x0100  /* 1=FIFO is empty */
  94#define Status_FH       0x0200  /* 1=FIFO is half full */
  95#define Status_FF       0x0400  /* 1=FIFO is full, fatal error */
  96#define Status_IRQ      0x0800  /* 1=IRQ occured */
  97/* bits from control register (PCI171x_CONTROL) */
  98#define Control_CNT0    0x0040  /* 1=CNT0 have external source, 0=have internal 100kHz source */
  99#define Control_ONEFH   0x0020  /* 1=IRQ on FIFO is half full, 0=every sample */
 100#define Control_IRQEN   0x0010  /* 1=enable IRQ */
 101#define Control_GATE    0x0008  /* 1=enable external trigger GATE (8254?) */
 102#define Control_EXT     0x0004  /* 1=external trigger source */
 103#define Control_PACER   0x0002  /* 1=enable internal 8254 trigger source */
 104#define Control_SW      0x0001  /* 1=enable software trigger source */
 105/* bits from counter control register (PCI171x_CNTCTRL) */
 106#define Counter_BCD     0x0001  /* 0 = binary counter, 1 = BCD counter */
 107#define Counter_M0      0x0002  /* M0-M2 select modes 0-5 */
 108#define Counter_M1      0x0004  /* 000 = mode 0, 010 = mode 2 ... */
 109#define Counter_M2      0x0008
 110#define Counter_RW0     0x0010  /* RW0/RW1 select read/write mode */
 111#define Counter_RW1     0x0020
 112#define Counter_SC0     0x0040  /* Select Counter. Only 00 or 11 may */
 113#define Counter_SC1     0x0080  /* be used, 00 for CNT0, 11 for read-back command */
 114
 115#define PCI1720_DA0      0      /* W:   D/A register 0 */
 116#define PCI1720_DA1      2      /* W:   D/A register 1 */
 117#define PCI1720_DA2      4      /* W:   D/A register 2 */
 118#define PCI1720_DA3      6      /* W:   D/A register 3 */
 119#define PCI1720_RANGE    8      /* R/W: D/A range register */
 120#define PCI1720_SYNCOUT  9      /* W:   D/A synchronized output register */
 121#define PCI1720_SYNCONT 15      /* R/W: D/A synchronized control */
 122
 123/* D/A synchronized control (PCI1720_SYNCONT) */
 124#define Syncont_SC0      1      /* set synchronous output mode */
 125
 126static const struct comedi_lrange range_pci1710_3 = { 9, {
 127                                                          BIP_RANGE(5),
 128                                                          BIP_RANGE(2.5),
 129                                                          BIP_RANGE(1.25),
 130                                                          BIP_RANGE(0.625),
 131                                                          BIP_RANGE(10),
 132                                                          UNI_RANGE(10),
 133                                                          UNI_RANGE(5),
 134                                                          UNI_RANGE(2.5),
 135                                                          UNI_RANGE(1.25)
 136                                                          }
 137};
 138
 139static const char range_codes_pci1710_3[] =
 140    { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 };
 141
 142static const struct comedi_lrange range_pci1710hg = { 12, {
 143                                                           BIP_RANGE(5),
 144                                                           BIP_RANGE(0.5),
 145                                                           BIP_RANGE(0.05),
 146                                                           BIP_RANGE(0.005),
 147                                                           BIP_RANGE(10),
 148                                                           BIP_RANGE(1),
 149                                                           BIP_RANGE(0.1),
 150                                                           BIP_RANGE(0.01),
 151                                                           UNI_RANGE(10),
 152                                                           UNI_RANGE(1),
 153                                                           UNI_RANGE(0.1),
 154                                                           UNI_RANGE(0.01)
 155                                                           }
 156};
 157
 158static const char range_codes_pci1710hg[] =
 159    { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12,
 160        0x13
 161};
 162
 163static const struct comedi_lrange range_pci17x1 = { 5, {
 164                                                        BIP_RANGE(10),
 165                                                        BIP_RANGE(5),
 166                                                        BIP_RANGE(2.5),
 167                                                        BIP_RANGE(1.25),
 168                                                        BIP_RANGE(0.625)
 169                                                        }
 170};
 171
 172static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
 173
 174static const struct comedi_lrange range_pci1720 = { 4, {
 175                                                        UNI_RANGE(5),
 176                                                        UNI_RANGE(10),
 177                                                        BIP_RANGE(5),
 178                                                        BIP_RANGE(10)
 179                                                        }
 180};
 181
 182static const struct comedi_lrange range_pci171x_da = { 2, {
 183                                                           UNI_RANGE(5),
 184                                                           UNI_RANGE(10),
 185                                                           }
 186};
 187
 188static int pci1710_attach(struct comedi_device *dev,
 189                          struct comedi_devconfig *it);
 190static int pci1710_detach(struct comedi_device *dev);
 191
 192struct boardtype {
 193        const char *name;       /*  board name */
 194        int device_id;
 195        int iorange;            /*  I/O range len */
 196        char have_irq;          /*  1=card support IRQ */
 197        char cardtype;          /*  0=1710& co. 2=1713, ... */
 198        int n_aichan;           /*  num of A/D chans */
 199        int n_aichand;          /*  num of A/D chans in diff mode */
 200        int n_aochan;           /*  num of D/A chans */
 201        int n_dichan;           /*  num of DI chans */
 202        int n_dochan;           /*  num of DO chans */
 203        int n_counter;          /*  num of counters */
 204        int ai_maxdata;         /*  resolution of A/D */
 205        int ao_maxdata;         /*  resolution of D/A */
 206        const struct comedi_lrange *rangelist_ai;       /*  rangelist for A/D */
 207        const char *rangecode_ai;       /*  range codes for programming */
 208        const struct comedi_lrange *rangelist_ao;       /*  rangelist for D/A */
 209        unsigned int ai_ns_min; /*  max sample speed of card v ns */
 210        unsigned int fifo_half_size;    /*  size of FIFO/2 */
 211};
 212
 213static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
 214        {
 215        PCI_VENDOR_ID_ADVANTECH, 0x1710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 216        PCI_VENDOR_ID_ADVANTECH, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 217        PCI_VENDOR_ID_ADVANTECH, 0x1713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 218        PCI_VENDOR_ID_ADVANTECH, 0x1720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 219        PCI_VENDOR_ID_ADVANTECH, 0x1731, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 220        0}
 221};
 222
 223MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
 224
 225static const struct boardtype boardtypes[] = {
 226        {"pci1710", 0x1710,
 227         IORANGE_171x, 1, TYPE_PCI171X,
 228         16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
 229         &range_pci1710_3, range_codes_pci1710_3,
 230         &range_pci171x_da,
 231         10000, 2048},
 232        {"pci1710hg", 0x1710,
 233         IORANGE_171x, 1, TYPE_PCI171X,
 234         16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
 235         &range_pci1710hg, range_codes_pci1710hg,
 236         &range_pci171x_da,
 237         10000, 2048},
 238        {"pci1711", 0x1711,
 239         IORANGE_171x, 1, TYPE_PCI171X,
 240         16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
 241         &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
 242         10000, 512},
 243        {"pci1713", 0x1713,
 244         IORANGE_171x, 1, TYPE_PCI1713,
 245         32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
 246         &range_pci1710_3, range_codes_pci1710_3, NULL,
 247         10000, 2048},
 248        {"pci1720", 0x1720,
 249         IORANGE_1720, 0, TYPE_PCI1720,
 250         0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
 251         NULL, NULL, &range_pci1720,
 252         0, 0},
 253        {"pci1731", 0x1731,
 254         IORANGE_171x, 1, TYPE_PCI171X,
 255         16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
 256         &range_pci17x1, range_codes_pci17x1, NULL,
 257         10000, 512},
 258        /*  dummy entry corresponding to driver name */
 259        {.name = DRV_NAME},
 260};
 261
 262#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
 263
 264static struct comedi_driver driver_pci1710 = {
 265        .driver_name = DRV_NAME,
 266        .module = THIS_MODULE,
 267        .attach = pci1710_attach,
 268        .detach = pci1710_detach,
 269        .num_names = n_boardtypes,
 270        .board_name = &boardtypes[0].name,
 271        .offset = sizeof(struct boardtype),
 272};
 273
 274struct pci1710_private {
 275        struct pci_dev *pcidev; /*  ptr to PCI device */
 276        char valid;             /*  card is usable */
 277        char neverending_ai;    /*  we do unlimited AI */
 278        unsigned int CntrlReg;  /*  Control register */
 279        unsigned int i8254_osc_base;    /*  frequence of onboard oscilator */
 280        unsigned int ai_do;     /*  what do AI? 0=nothing, 1 to 4 mode */
 281        unsigned int ai_act_scan;       /*  how many scans we finished */
 282        unsigned int ai_act_chan;       /*  actual position in actual scan */
 283        unsigned int ai_buf_ptr;        /*  data buffer ptr in samples */
 284        unsigned char ai_eos;   /*  1=EOS wake up */
 285        unsigned char ai_et;
 286        unsigned int ai_et_CntrlReg;
 287        unsigned int ai_et_MuxVal;
 288        unsigned int ai_et_div1, ai_et_div2;
 289        unsigned int act_chanlist[32];  /*  list of scaned channel */
 290        unsigned char act_chanlist_len; /*  len of scanlist */
 291        unsigned char act_chanlist_pos; /*  actual position in MUX list */
 292        unsigned char da_ranges;        /*  copy of D/A outpit range register */
 293        unsigned int ai_scans;  /*  len of scanlist */
 294        unsigned int ai_n_chan; /*  how many channels is measured */
 295        unsigned int *ai_chanlist;      /*  actaul chanlist */
 296        unsigned int ai_flags;  /*  flaglist */
 297        unsigned int ai_data_len;       /*  len of data buffer */
 298        short *ai_data;         /*  data buffer */
 299        unsigned int ai_timer1; /*  timers */
 300        unsigned int ai_timer2;
 301        short ao_data[4];       /*  data output buffer */
 302        unsigned int cnt0_write_wait;   /*  after a write, wait for update of the internal state */
 303};
 304
 305#define devpriv ((struct pci1710_private *)dev->private)
 306#define this_board ((const struct boardtype *)dev->board_ptr)
 307
 308/*
 309==============================================================================
 310*/
 311
 312static int check_channel_list(struct comedi_device *dev,
 313                              struct comedi_subdevice *s,
 314                              unsigned int *chanlist, unsigned int n_chan);
 315static void setup_channel_list(struct comedi_device *dev,
 316                               struct comedi_subdevice *s,
 317                               unsigned int *chanlist, unsigned int n_chan,
 318                               unsigned int seglen);
 319static void start_pacer(struct comedi_device *dev, int mode,
 320                        unsigned int divisor1, unsigned int divisor2);
 321static int pci1710_reset(struct comedi_device *dev);
 322static int pci171x_ai_cancel(struct comedi_device *dev,
 323                             struct comedi_subdevice *s);
 324
 325static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,      /*  used for gain list programming */
 326        0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
 327        0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
 328        0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
 329};
 330
 331/*
 332==============================================================================
 333*/
 334static int pci171x_insn_read_ai(struct comedi_device *dev,
 335                                struct comedi_subdevice *s,
 336                                struct comedi_insn *insn, unsigned int *data)
 337{
 338        int n, timeout;
 339#ifdef PCI171x_PARANOIDCHECK
 340        unsigned int idata;
 341#endif
 342
 343        DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
 344        devpriv->CntrlReg &= Control_CNT0;
 345        devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
 346        outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 347        outb(0, dev->iobase + PCI171x_CLRFIFO);
 348        outb(0, dev->iobase + PCI171x_CLRINT);
 349
 350        setup_channel_list(dev, s, &insn->chanspec, 1, 1);
 351
 352        DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
 353                inw(dev->iobase + PCI171x_STATUS),
 354                dev->iobase + PCI171x_STATUS);
 355        for (n = 0; n < insn->n; n++) {
 356                outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
 357                DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
 358                        inw(dev->iobase + PCI171x_STATUS));
 359                /* udelay(1); */
 360                DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
 361                        inw(dev->iobase + PCI171x_STATUS));
 362                timeout = 100;
 363                while (timeout--) {
 364                        if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
 365                                goto conv_finish;
 366                        if (!(timeout % 10))
 367                                DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
 368                                        timeout,
 369                                        inw(dev->iobase + PCI171x_STATUS));
 370                }
 371                comedi_error(dev, "A/D insn timeout");
 372                outb(0, dev->iobase + PCI171x_CLRFIFO);
 373                outb(0, dev->iobase + PCI171x_CLRINT);
 374                data[n] = 0;
 375                DPRINTK
 376                    ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
 377                     n);
 378                return -ETIME;
 379
 380conv_finish:
 381#ifdef PCI171x_PARANOIDCHECK
 382                idata = inw(dev->iobase + PCI171x_AD_DATA);
 383                if (this_board->cardtype != TYPE_PCI1713)
 384                        if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
 385                                comedi_error(dev, "A/D insn data droput!");
 386                                return -ETIME;
 387                        }
 388                data[n] = idata & 0x0fff;
 389#else
 390                data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
 391#endif
 392
 393        }
 394
 395        outb(0, dev->iobase + PCI171x_CLRFIFO);
 396        outb(0, dev->iobase + PCI171x_CLRINT);
 397
 398        DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
 399        return n;
 400}
 401
 402/*
 403==============================================================================
 404*/
 405static int pci171x_insn_write_ao(struct comedi_device *dev,
 406                                 struct comedi_subdevice *s,
 407                                 struct comedi_insn *insn, unsigned int *data)
 408{
 409        int n, chan, range, ofs;
 410
 411        chan = CR_CHAN(insn->chanspec);
 412        range = CR_RANGE(insn->chanspec);
 413        if (chan) {
 414                devpriv->da_ranges &= 0xfb;
 415                devpriv->da_ranges |= (range << 2);
 416                outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
 417                ofs = PCI171x_DA2;
 418        } else {
 419                devpriv->da_ranges &= 0xfe;
 420                devpriv->da_ranges |= range;
 421                outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
 422                ofs = PCI171x_DA1;
 423        }
 424
 425        for (n = 0; n < insn->n; n++)
 426                outw(data[n], dev->iobase + ofs);
 427
 428        devpriv->ao_data[chan] = data[n];
 429
 430        return n;
 431
 432}
 433
 434/*
 435==============================================================================
 436*/
 437static int pci171x_insn_read_ao(struct comedi_device *dev,
 438                                struct comedi_subdevice *s,
 439                                struct comedi_insn *insn, unsigned int *data)
 440{
 441        int n, chan;
 442
 443        chan = CR_CHAN(insn->chanspec);
 444        for (n = 0; n < insn->n; n++)
 445                data[n] = devpriv->ao_data[chan];
 446
 447        return n;
 448}
 449
 450/*
 451==============================================================================
 452*/
 453static int pci171x_insn_bits_di(struct comedi_device *dev,
 454                                struct comedi_subdevice *s,
 455                                struct comedi_insn *insn, unsigned int *data)
 456{
 457        data[1] = inw(dev->iobase + PCI171x_DI);
 458
 459        return 2;
 460}
 461
 462/*
 463==============================================================================
 464*/
 465static int pci171x_insn_bits_do(struct comedi_device *dev,
 466                                struct comedi_subdevice *s,
 467                                struct comedi_insn *insn, unsigned int *data)
 468{
 469        if (data[0]) {
 470                s->state &= ~data[0];
 471                s->state |= (data[0] & data[1]);
 472                outw(s->state, dev->iobase + PCI171x_DO);
 473        }
 474        data[1] = s->state;
 475
 476        return 2;
 477}
 478
 479/*
 480==============================================================================
 481*/
 482static int pci171x_insn_counter_read(struct comedi_device *dev,
 483                                     struct comedi_subdevice *s,
 484                                     struct comedi_insn *insn,
 485                                     unsigned int *data)
 486{
 487        unsigned int msb, lsb, ccntrl;
 488        int i;
 489
 490        ccntrl = 0xD2;          /* count only */
 491        for (i = 0; i < insn->n; i++) {
 492                outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
 493
 494                lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
 495                msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
 496
 497                data[0] = lsb | (msb << 8);
 498        }
 499
 500        return insn->n;
 501}
 502
 503/*
 504==============================================================================
 505*/
 506static int pci171x_insn_counter_write(struct comedi_device *dev,
 507                                      struct comedi_subdevice *s,
 508                                      struct comedi_insn *insn,
 509                                      unsigned int *data)
 510{
 511        uint msb, lsb, ccntrl, status;
 512
 513        lsb = data[0] & 0x00FF;
 514        msb = (data[0] & 0xFF00) >> 8;
 515
 516        /* write lsb, then msb */
 517        outw(lsb, dev->iobase + PCI171x_CNT0);
 518        outw(msb, dev->iobase + PCI171x_CNT0);
 519
 520        if (devpriv->cnt0_write_wait) {
 521                /* wait for the new count to be loaded */
 522                ccntrl = 0xE2;
 523                do {
 524                        outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
 525                        status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
 526                } while (status & 0x40);
 527        }
 528
 529        return insn->n;
 530}
 531
 532/*
 533==============================================================================
 534*/
 535static int pci171x_insn_counter_config(struct comedi_device *dev,
 536                                       struct comedi_subdevice *s,
 537                                       struct comedi_insn *insn,
 538                                       unsigned int *data)
 539{
 540#ifdef unused
 541        /* This doesn't work like a normal Comedi counter config */
 542        uint ccntrl = 0;
 543
 544        devpriv->cnt0_write_wait = data[0] & 0x20;
 545
 546        /* internal or external clock? */
 547        if (!(data[0] & 0x10)) {        /* internal */
 548                devpriv->CntrlReg &= ~Control_CNT0;
 549        } else {
 550                devpriv->CntrlReg |= Control_CNT0;
 551        }
 552        outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 553
 554        if (data[0] & 0x01)
 555                ccntrl |= Counter_M0;
 556        if (data[0] & 0x02)
 557                ccntrl |= Counter_M1;
 558        if (data[0] & 0x04)
 559                ccntrl |= Counter_M2;
 560        if (data[0] & 0x08)
 561                ccntrl |= Counter_BCD;
 562        ccntrl |= Counter_RW0;  /* set read/write mode */
 563        ccntrl |= Counter_RW1;
 564        outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
 565#endif
 566
 567        return 1;
 568}
 569
 570/*
 571==============================================================================
 572*/
 573static int pci1720_insn_write_ao(struct comedi_device *dev,
 574                                 struct comedi_subdevice *s,
 575                                 struct comedi_insn *insn, unsigned int *data)
 576{
 577        int n, rangereg, chan;
 578
 579        chan = CR_CHAN(insn->chanspec);
 580        rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
 581        rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
 582        if (rangereg != devpriv->da_ranges) {
 583                outb(rangereg, dev->iobase + PCI1720_RANGE);
 584                devpriv->da_ranges = rangereg;
 585        }
 586
 587        for (n = 0; n < insn->n; n++) {
 588                outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
 589                outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
 590        }
 591
 592        devpriv->ao_data[chan] = data[n];
 593
 594        return n;
 595}
 596
 597/*
 598==============================================================================
 599*/
 600static void interrupt_pci1710_every_sample(void *d)
 601{
 602        struct comedi_device *dev = d;
 603        struct comedi_subdevice *s = dev->subdevices + 0;
 604        int m;
 605#ifdef PCI171x_PARANOIDCHECK
 606        short sampl;
 607#endif
 608
 609        DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
 610        m = inw(dev->iobase + PCI171x_STATUS);
 611        if (m & Status_FE) {
 612                printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
 613                pci171x_ai_cancel(dev, s);
 614                s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
 615                comedi_event(dev, s);
 616                return;
 617        }
 618        if (m & Status_FF) {
 619                printk
 620                    ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
 621                     dev->minor, m);
 622                pci171x_ai_cancel(dev, s);
 623                s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
 624                comedi_event(dev, s);
 625                return;
 626        }
 627
 628        outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
 629
 630        DPRINTK("FOR ");
 631        for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
 632#ifdef PCI171x_PARANOIDCHECK
 633                sampl = inw(dev->iobase + PCI171x_AD_DATA);
 634                DPRINTK("%04x:", sampl);
 635                if (this_board->cardtype != TYPE_PCI1713)
 636                        if ((sampl & 0xf000) !=
 637                            devpriv->act_chanlist[s->async->cur_chan]) {
 638                                printk
 639                                    ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
 640                                     (sampl & 0xf000) >> 12,
 641                                     (devpriv->
 642                                      act_chanlist[s->
 643                                                   async->cur_chan] & 0xf000) >>
 644                                     12);
 645                                pci171x_ai_cancel(dev, s);
 646                                s->async->events |=
 647                                    COMEDI_CB_EOA | COMEDI_CB_ERROR;
 648                                comedi_event(dev, s);
 649                                return;
 650                        }
 651                DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
 652                        s->async->cur_chan, s->async->buf_int_count);
 653                comedi_buf_put(s->async, sampl & 0x0fff);
 654#else
 655                comedi_buf_put(s->async,
 656                               inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
 657#endif
 658                ++s->async->cur_chan;
 659
 660                if (s->async->cur_chan >= devpriv->ai_n_chan) {
 661                        s->async->cur_chan = 0;
 662                }
 663
 664                if (s->async->cur_chan == 0) {  /*  one scan done */
 665                        devpriv->ai_act_scan++;
 666                        DPRINTK
 667                            ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
 668                             s->async->buf_int_count, s->async->buf_int_ptr,
 669                             s->async->buf_user_count, s->async->buf_user_ptr);
 670                        DPRINTK("adv_pci1710 EDBG: EOS2\n");
 671                        if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) {        /*  all data sampled */
 672                                pci171x_ai_cancel(dev, s);
 673                                s->async->events |= COMEDI_CB_EOA;
 674                                comedi_event(dev, s);
 675                                return;
 676                        }
 677                }
 678        }
 679
 680        outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
 681        DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
 682
 683        comedi_event(dev, s);
 684}
 685
 686/*
 687==============================================================================
 688*/
 689static int move_block_from_fifo(struct comedi_device *dev,
 690                                struct comedi_subdevice *s, int n, int turn)
 691{
 692        int i, j;
 693#ifdef PCI171x_PARANOIDCHECK
 694        int sampl;
 695#endif
 696        DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
 697                turn);
 698        j = s->async->cur_chan;
 699        for (i = 0; i < n; i++) {
 700#ifdef PCI171x_PARANOIDCHECK
 701                sampl = inw(dev->iobase + PCI171x_AD_DATA);
 702                if (this_board->cardtype != TYPE_PCI1713)
 703                        if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
 704                                printk
 705                                    ("comedi%d: A/D  FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
 706                                     dev->minor, (sampl & 0xf000) >> 12,
 707                                     (devpriv->act_chanlist[j] & 0xf000) >> 12,
 708                                     i, j, devpriv->ai_act_scan, n, turn,
 709                                     sampl);
 710                                pci171x_ai_cancel(dev, s);
 711                                s->async->events |=
 712                                    COMEDI_CB_EOA | COMEDI_CB_ERROR;
 713                                comedi_event(dev, s);
 714                                return 1;
 715                        }
 716                comedi_buf_put(s->async, sampl & 0x0fff);
 717#else
 718                comedi_buf_put(s->async,
 719                               inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
 720#endif
 721                j++;
 722                if (j >= devpriv->ai_n_chan) {
 723                        j = 0;
 724                        devpriv->ai_act_scan++;
 725                }
 726        }
 727        DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
 728        return 0;
 729}
 730
 731/*
 732==============================================================================
 733*/
 734static void interrupt_pci1710_half_fifo(void *d)
 735{
 736        struct comedi_device *dev = d;
 737        struct comedi_subdevice *s = dev->subdevices + 0;
 738        int m, samplesinbuf;
 739
 740        DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
 741        m = inw(dev->iobase + PCI171x_STATUS);
 742        if (!(m & Status_FH)) {
 743                printk("comedi%d: A/D FIFO not half full! (%4x)\n",
 744                       dev->minor, m);
 745                pci171x_ai_cancel(dev, s);
 746                s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
 747                comedi_event(dev, s);
 748                return;
 749        }
 750        if (m & Status_FF) {
 751                printk
 752                    ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
 753                     dev->minor, m);
 754                pci171x_ai_cancel(dev, s);
 755                s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
 756                comedi_event(dev, s);
 757                return;
 758        }
 759
 760        samplesinbuf = this_board->fifo_half_size;
 761        if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
 762                m = devpriv->ai_data_len / sizeof(short);
 763                if (move_block_from_fifo(dev, s, m, 0))
 764                        return;
 765                samplesinbuf -= m;
 766        }
 767
 768        if (samplesinbuf) {
 769                if (move_block_from_fifo(dev, s, samplesinbuf, 1))
 770                        return;
 771        }
 772
 773        if (!devpriv->neverending_ai)
 774                if (devpriv->ai_act_scan >= devpriv->ai_scans) {        /* all data sampled */
 775                        pci171x_ai_cancel(dev, s);
 776                        s->async->events |= COMEDI_CB_EOA;
 777                        comedi_event(dev, s);
 778                        return;
 779                }
 780        outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
 781        DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
 782
 783        comedi_event(dev, s);
 784}
 785
 786/*
 787==============================================================================
 788*/
 789static irqreturn_t interrupt_service_pci1710(int irq, void *d)
 790{
 791        struct comedi_device *dev = d;
 792
 793        DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
 794                irq);
 795        if (!dev->attached)     /*  is device attached? */
 796                return IRQ_NONE;        /*  no, exit */
 797
 798        if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))  /*  is this interrupt from our board? */
 799                return IRQ_NONE;        /*  no, exit */
 800
 801        DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
 802                inw(dev->iobase + PCI171x_STATUS));
 803
 804        if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
 805                devpriv->ai_et = 0;
 806                devpriv->CntrlReg &= Control_CNT0;
 807                devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
 808                outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 809                devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
 810                outb(0, dev->iobase + PCI171x_CLRFIFO);
 811                outb(0, dev->iobase + PCI171x_CLRINT);
 812                outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
 813                outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 814                /*  start pacer */
 815                start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
 816                return IRQ_HANDLED;
 817        }
 818        if (devpriv->ai_eos) {  /*  We use FIFO half full INT or not? */
 819                interrupt_pci1710_every_sample(d);
 820        } else {
 821                interrupt_pci1710_half_fifo(d);
 822        }
 823        DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
 824        return IRQ_HANDLED;
 825}
 826
 827/*
 828==============================================================================
 829*/
 830static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
 831                                     struct comedi_subdevice *s)
 832{
 833        unsigned int divisor1, divisor2;
 834        unsigned int seglen;
 835
 836        DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
 837                mode);
 838        start_pacer(dev, -1, 0, 0);     /*  stop pacer */
 839
 840        seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
 841                                    devpriv->ai_n_chan);
 842        if (seglen < 1)
 843                return -EINVAL;
 844        setup_channel_list(dev, s, devpriv->ai_chanlist,
 845                           devpriv->ai_n_chan, seglen);
 846
 847        outb(0, dev->iobase + PCI171x_CLRFIFO);
 848        outb(0, dev->iobase + PCI171x_CLRINT);
 849
 850        devpriv->ai_do = mode;
 851
 852        devpriv->ai_act_scan = 0;
 853        s->async->cur_chan = 0;
 854        devpriv->ai_buf_ptr = 0;
 855        devpriv->neverending_ai = 0;
 856
 857        devpriv->CntrlReg &= Control_CNT0;
 858        if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {      /*  don't we want wake up every scan?            devpriv->ai_eos=1; */
 859                devpriv->ai_eos = 1;
 860        } else {
 861                devpriv->CntrlReg |= Control_ONEFH;
 862                devpriv->ai_eos = 0;
 863        }
 864
 865        if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) {
 866                devpriv->neverending_ai = 1;
 867        } /* well, user want neverending */
 868        else {
 869                devpriv->neverending_ai = 0;
 870        }
 871        switch (mode) {
 872        case 1:
 873        case 2:
 874                if (devpriv->ai_timer1 < this_board->ai_ns_min)
 875                        devpriv->ai_timer1 = this_board->ai_ns_min;
 876                devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
 877                if (mode == 2) {
 878                        devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
 879                        devpriv->CntrlReg &=
 880                            ~(Control_PACER | Control_ONEFH | Control_GATE);
 881                        devpriv->CntrlReg |= Control_EXT;
 882                        devpriv->ai_et = 1;
 883                } else {
 884                        devpriv->ai_et = 0;
 885                }
 886                i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
 887                                          &divisor2, &devpriv->ai_timer1,
 888                                          devpriv->ai_flags & TRIG_ROUND_MASK);
 889                DPRINTK
 890                    ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
 891                     devpriv->i8254_osc_base, divisor1, divisor2,
 892                     devpriv->ai_timer1);
 893                outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 894                if (mode != 2) {
 895                        /*  start pacer */
 896                        start_pacer(dev, mode, divisor1, divisor2);
 897                } else {
 898                        devpriv->ai_et_div1 = divisor1;
 899                        devpriv->ai_et_div2 = divisor2;
 900                }
 901                break;
 902        case 3:
 903                devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
 904                outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
 905                break;
 906        }
 907
 908        DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
 909        return 0;
 910}
 911
 912#ifdef PCI171X_EXTDEBUG
 913/*
 914==============================================================================
 915*/
 916static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
 917{
 918        printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
 919               cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
 920        printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
 921               cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
 922        printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
 923               cmd->scan_end_src);
 924        printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
 925               e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
 926}
 927#endif
 928
 929/*
 930==============================================================================
 931*/
 932static int pci171x_ai_cmdtest(struct comedi_device *dev,
 933                              struct comedi_subdevice *s,
 934                              struct comedi_cmd *cmd)
 935{
 936        int err = 0;
 937        int tmp, divisor1, divisor2;
 938
 939        DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
 940#ifdef PCI171X_EXTDEBUG
 941        pci171x_cmdtest_out(-1, cmd);
 942#endif
 943        /* step 1: make sure trigger sources are trivially valid */
 944
 945        tmp = cmd->start_src;
 946        cmd->start_src &= TRIG_NOW | TRIG_EXT;
 947        if (!cmd->start_src || tmp != cmd->start_src)
 948                err++;
 949
 950        tmp = cmd->scan_begin_src;
 951        cmd->scan_begin_src &= TRIG_FOLLOW;
 952        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 953                err++;
 954
 955        tmp = cmd->convert_src;
 956        cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
 957        if (!cmd->convert_src || tmp != cmd->convert_src)
 958                err++;
 959
 960        tmp = cmd->scan_end_src;
 961        cmd->scan_end_src &= TRIG_COUNT;
 962        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 963                err++;
 964
 965        tmp = cmd->stop_src;
 966        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 967        if (!cmd->stop_src || tmp != cmd->stop_src)
 968                err++;
 969
 970        if (err) {
 971#ifdef PCI171X_EXTDEBUG
 972                pci171x_cmdtest_out(1, cmd);
 973#endif
 974                DPRINTK
 975                    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
 976                     err);
 977                return 1;
 978        }
 979
 980        /* step 2: make sure trigger sources are unique and mutually compatible */
 981
 982        if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
 983                cmd->start_src = TRIG_NOW;
 984                err++;
 985        }
 986
 987        if (cmd->scan_begin_src != TRIG_FOLLOW) {
 988                cmd->scan_begin_src = TRIG_FOLLOW;
 989                err++;
 990        }
 991
 992        if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
 993                err++;
 994
 995        if (cmd->scan_end_src != TRIG_COUNT) {
 996                cmd->scan_end_src = TRIG_COUNT;
 997                err++;
 998        }
 999
1000        if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1001                err++;
1002
1003        if (err) {
1004#ifdef PCI171X_EXTDEBUG
1005                pci171x_cmdtest_out(2, cmd);
1006#endif
1007                DPRINTK
1008                    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1009                     err);
1010                return 2;
1011        }
1012
1013        /* step 3: make sure arguments are trivially compatible */
1014
1015        if (cmd->start_arg != 0) {
1016                cmd->start_arg = 0;
1017                err++;
1018        }
1019
1020        if (cmd->scan_begin_arg != 0) {
1021                cmd->scan_begin_arg = 0;
1022                err++;
1023        }
1024
1025        if (cmd->convert_src == TRIG_TIMER) {
1026                if (cmd->convert_arg < this_board->ai_ns_min) {
1027                        cmd->convert_arg = this_board->ai_ns_min;
1028                        err++;
1029                }
1030        } else {                /* TRIG_FOLLOW */
1031                if (cmd->convert_arg != 0) {
1032                        cmd->convert_arg = 0;
1033                        err++;
1034                }
1035        }
1036
1037        if (!cmd->chanlist_len) {
1038                cmd->chanlist_len = 1;
1039                err++;
1040        }
1041        if (cmd->chanlist_len > this_board->n_aichan) {
1042                cmd->chanlist_len = this_board->n_aichan;
1043                err++;
1044        }
1045        if (cmd->scan_end_arg != cmd->chanlist_len) {
1046                cmd->scan_end_arg = cmd->chanlist_len;
1047                err++;
1048        }
1049        if (cmd->stop_src == TRIG_COUNT) {
1050                if (!cmd->stop_arg) {
1051                        cmd->stop_arg = 1;
1052                        err++;
1053                }
1054        } else {                /* TRIG_NONE */
1055                if (cmd->stop_arg != 0) {
1056                        cmd->stop_arg = 0;
1057                        err++;
1058                }
1059        }
1060
1061        if (err) {
1062#ifdef PCI171X_EXTDEBUG
1063                pci171x_cmdtest_out(3, cmd);
1064#endif
1065                DPRINTK
1066                    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1067                     err);
1068                return 3;
1069        }
1070
1071        /* step 4: fix up any arguments */
1072
1073        if (cmd->convert_src == TRIG_TIMER) {
1074                tmp = cmd->convert_arg;
1075                i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1076                                          &divisor2, &cmd->convert_arg,
1077                                          cmd->flags & TRIG_ROUND_MASK);
1078                if (cmd->convert_arg < this_board->ai_ns_min)
1079                        cmd->convert_arg = this_board->ai_ns_min;
1080                if (tmp != cmd->convert_arg)
1081                        err++;
1082        }
1083
1084        if (err) {
1085                DPRINTK
1086                    ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1087                     err);
1088                return 4;
1089        }
1090
1091        /* step 5: complain about special chanlist considerations */
1092
1093        if (cmd->chanlist) {
1094                if (!check_channel_list(dev, s, cmd->chanlist,
1095                                        cmd->chanlist_len))
1096                        return 5;       /*  incorrect channels list */
1097        }
1098
1099        DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1100        return 0;
1101}
1102
1103/*
1104==============================================================================
1105*/
1106static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1107{
1108        struct comedi_cmd *cmd = &s->async->cmd;
1109
1110        DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1111        devpriv->ai_n_chan = cmd->chanlist_len;
1112        devpriv->ai_chanlist = cmd->chanlist;
1113        devpriv->ai_flags = cmd->flags;
1114        devpriv->ai_data_len = s->async->prealloc_bufsz;
1115        devpriv->ai_data = s->async->prealloc_buf;
1116        devpriv->ai_timer1 = 0;
1117        devpriv->ai_timer2 = 0;
1118
1119        if (cmd->stop_src == TRIG_COUNT) {
1120                devpriv->ai_scans = cmd->stop_arg;
1121        } else {
1122                devpriv->ai_scans = 0;
1123        }
1124
1125        if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 2, 3 */
1126                if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 and 2 */
1127                        devpriv->ai_timer1 = cmd->convert_arg;
1128                        return pci171x_ai_docmd_and_mode(cmd->start_src ==
1129                                                         TRIG_EXT ? 2 : 1, dev,
1130                                                         s);
1131                }
1132                if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1133                        return pci171x_ai_docmd_and_mode(3, dev, s);
1134                }
1135        }
1136
1137        return -1;
1138}
1139
1140/*
1141==============================================================================
1142 Check if channel list from user is builded correctly
1143 If it's ok, then program scan/gain logic.
1144 This works for all cards.
1145*/
1146static int check_channel_list(struct comedi_device *dev,
1147                              struct comedi_subdevice *s,
1148                              unsigned int *chanlist, unsigned int n_chan)
1149{
1150        unsigned int chansegment[32];
1151        unsigned int i, nowmustbechan, seglen, segpos;
1152
1153        DPRINTK("adv_pci1710 EDBG:  check_channel_list(...,%d)\n", n_chan);
1154        /* correct channel and range number check itself comedi/range.c */
1155        if (n_chan < 1) {
1156                comedi_error(dev, "range/channel list is empty!");
1157                return 0;
1158        }
1159
1160        if (n_chan > 1) {
1161                chansegment[0] = chanlist[0];   /*  first channel is everytime ok */
1162                for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {    /*  build part of chanlist */
1163                        /*  printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1164                        if (chanlist[0] == chanlist[i])
1165                                break;  /*  we detect loop, this must by finish */
1166                        if (CR_CHAN(chanlist[i]) & 1)   /*  odd channel cann't by differencial */
1167                                if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1168                                        comedi_error(dev,
1169                                                     "Odd channel can't be differential input!\n");
1170                                        return 0;
1171                                }
1172                        nowmustbechan =
1173                            (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1174                        if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1175                                nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1176                        if (nowmustbechan != CR_CHAN(chanlist[i])) {    /*  channel list isn't continous :-( */
1177                                printk
1178                                    ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1179                                     i, CR_CHAN(chanlist[i]), nowmustbechan,
1180                                     CR_CHAN(chanlist[0]));
1181                                return 0;
1182                        }
1183                        chansegment[i] = chanlist[i];   /*  well, this is next correct channel in list */
1184                }
1185
1186                for (i = 0, segpos = 0; i < n_chan; i++) {      /*  check whole chanlist */
1187                        /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1188                        if (chanlist[i] != chansegment[i % seglen]) {
1189                                printk
1190                                    ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1191                                     i, CR_CHAN(chansegment[i]),
1192                                     CR_RANGE(chansegment[i]),
1193                                     CR_AREF(chansegment[i]),
1194                                     CR_CHAN(chanlist[i % seglen]),
1195                                     CR_RANGE(chanlist[i % seglen]),
1196                                     CR_AREF(chansegment[i % seglen]));
1197                                return 0;       /*  chan/gain list is strange */
1198                        }
1199                }
1200        } else {
1201                seglen = 1;
1202        }
1203        return seglen;
1204}
1205
1206static void setup_channel_list(struct comedi_device *dev,
1207                               struct comedi_subdevice *s,
1208                               unsigned int *chanlist, unsigned int n_chan,
1209                               unsigned int seglen)
1210{
1211        unsigned int i, range, chanprog;
1212
1213        DPRINTK("adv_pci1710 EDBG:  setup_channel_list(...,%d,%d)\n", n_chan,
1214                seglen);
1215        devpriv->act_chanlist_len = seglen;
1216        devpriv->act_chanlist_pos = 0;
1217
1218        DPRINTK("SegLen: %d\n", seglen);
1219        for (i = 0; i < seglen; i++) {  /*  store range list to card */
1220                chanprog = muxonechan[CR_CHAN(chanlist[i])];
1221                outw(chanprog, dev->iobase + PCI171x_MUX);      /* select channel */
1222                range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1223                if (CR_AREF(chanlist[i]) == AREF_DIFF)
1224                        range |= 0x0020;
1225                outw(range, dev->iobase + PCI171x_RANGE);       /* select gain */
1226#ifdef PCI171x_PARANOIDCHECK
1227                devpriv->act_chanlist[i] =
1228                    (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1229#endif
1230                DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1231                        devpriv->act_chanlist[i]);
1232        }
1233
1234        devpriv->ai_et_MuxVal =
1235            CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1236        outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
1237        DPRINTK("MUX: %4x L%4x.H%4x\n",
1238                CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1239                CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1240}
1241
1242/*
1243==============================================================================
1244*/
1245static void start_pacer(struct comedi_device *dev, int mode,
1246                        unsigned int divisor1, unsigned int divisor2)
1247{
1248        DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1249                divisor1, divisor2);
1250        outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1251        outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1252
1253        if (mode == 1) {
1254                outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1255                outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1256                outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1257                outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1258        }
1259        DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1260}
1261
1262/*
1263==============================================================================
1264*/
1265static int pci171x_ai_cancel(struct comedi_device *dev,
1266                             struct comedi_subdevice *s)
1267{
1268        DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1269
1270        switch (this_board->cardtype) {
1271        default:
1272                devpriv->CntrlReg &= Control_CNT0;
1273                devpriv->CntrlReg |= Control_SW;
1274
1275                outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1276                start_pacer(dev, -1, 0, 0);
1277                outb(0, dev->iobase + PCI171x_CLRFIFO);
1278                outb(0, dev->iobase + PCI171x_CLRINT);
1279                break;
1280        }
1281
1282        devpriv->ai_do = 0;
1283        devpriv->ai_act_scan = 0;
1284        s->async->cur_chan = 0;
1285        devpriv->ai_buf_ptr = 0;
1286        devpriv->neverending_ai = 0;
1287
1288        DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1289        return 0;
1290}
1291
1292/*
1293==============================================================================
1294*/
1295static int pci171x_reset(struct comedi_device *dev)
1296{
1297        DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1298        outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1299        devpriv->CntrlReg = Control_SW | Control_CNT0;  /*  Software trigger, CNT0=external */
1300        outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1301        outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1302        outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1303        start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1304        devpriv->da_ranges = 0;
1305        if (this_board->n_aochan) {
1306                outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);  /*  set DACs to 0..5V */
1307                outw(0, dev->iobase + PCI171x_DA1);     /*  set DA outputs to 0V */
1308                devpriv->ao_data[0] = 0x0000;
1309                if (this_board->n_aochan > 1) {
1310                        outw(0, dev->iobase + PCI171x_DA2);
1311                        devpriv->ao_data[1] = 0x0000;
1312                }
1313        }
1314        outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1315        outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1316        outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1317
1318        DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1319        return 0;
1320}
1321
1322/*
1323==============================================================================
1324*/
1325static int pci1720_reset(struct comedi_device *dev)
1326{
1327        DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1328        outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);       /*  set synchronous output mode */
1329        devpriv->da_ranges = 0xAA;
1330        outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);  /*  set all ranges to +/-5V */
1331        outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1332        outw(0x0800, dev->iobase + PCI1720_DA1);
1333        outw(0x0800, dev->iobase + PCI1720_DA2);
1334        outw(0x0800, dev->iobase + PCI1720_DA3);
1335        outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1336        devpriv->ao_data[0] = 0x0800;
1337        devpriv->ao_data[1] = 0x0800;
1338        devpriv->ao_data[2] = 0x0800;
1339        devpriv->ao_data[3] = 0x0800;
1340        DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1341        return 0;
1342}
1343
1344/*
1345==============================================================================
1346*/
1347static int pci1710_reset(struct comedi_device *dev)
1348{
1349        DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1350        switch (this_board->cardtype) {
1351        case TYPE_PCI1720:
1352                return pci1720_reset(dev);
1353        default:
1354                return pci171x_reset(dev);
1355        }
1356        DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1357}
1358
1359/*
1360==============================================================================
1361*/
1362static int pci1710_attach(struct comedi_device *dev,
1363                          struct comedi_devconfig *it)
1364{
1365        struct comedi_subdevice *s;
1366        int ret, subdev, n_subdevices;
1367        unsigned int irq;
1368        unsigned long iobase;
1369        struct pci_dev *pcidev;
1370        int opt_bus, opt_slot;
1371        const char *errstr;
1372        unsigned char pci_bus, pci_slot, pci_func;
1373        int i;
1374        int board_index;
1375
1376        printk("comedi%d: adv_pci1710: ", dev->minor);
1377
1378        opt_bus = it->options[0];
1379        opt_slot = it->options[1];
1380
1381        ret = alloc_private(dev, sizeof(struct pci1710_private));
1382        if (ret < 0) {
1383                printk(" - Allocation failed!\n");
1384                return -ENOMEM;
1385        }
1386
1387        /* Look for matching PCI device */
1388        errstr = "not found!";
1389        pcidev = NULL;
1390        board_index = this_board - boardtypes;
1391        while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1392                                                PCI_ANY_ID, pcidev))) {
1393                if (strcmp(this_board->name, DRV_NAME) == 0) {
1394                        for (i = 0; i < n_boardtypes; ++i) {
1395                                if (pcidev->device == boardtypes[i].device_id) {
1396                                        board_index = i;
1397                                        break;
1398                                }
1399                        }
1400                        if (i == n_boardtypes)
1401                                continue;
1402                } else {
1403                        if (pcidev->device != boardtypes[board_index].device_id)
1404                                continue;
1405                }
1406
1407                /* Found matching vendor/device. */
1408                if (opt_bus || opt_slot) {
1409                        /* Check bus/slot. */
1410                        if (opt_bus != pcidev->bus->number
1411                            || opt_slot != PCI_SLOT(pcidev->devfn))
1412                                continue;       /* no match */
1413                }
1414                /*
1415                 * Look for device that isn't in use.
1416                 * Enable PCI device and request regions.
1417                 */
1418                if (comedi_pci_enable(pcidev, DRV_NAME)) {
1419                        errstr =
1420                            "failed to enable PCI device and request regions!";
1421                        continue;
1422                }
1423                /*  fixup board_ptr in case we were using the dummy entry with the driver name */
1424                dev->board_ptr = &boardtypes[board_index];
1425                break;
1426        }
1427
1428        if (!pcidev) {
1429                if (opt_bus || opt_slot) {
1430                        printk(" - Card at b:s %d:%d %s\n",
1431                               opt_bus, opt_slot, errstr);
1432                } else {
1433                        printk(" - Card %s\n", errstr);
1434                }
1435                return -EIO;
1436        }
1437
1438        pci_bus = pcidev->bus->number;
1439        pci_slot = PCI_SLOT(pcidev->devfn);
1440        pci_func = PCI_FUNC(pcidev->devfn);
1441        irq = pcidev->irq;
1442        iobase = pci_resource_start(pcidev, 2);
1443
1444        printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
1445               iobase);
1446
1447        dev->iobase = iobase;
1448
1449        dev->board_name = this_board->name;
1450        devpriv->pcidev = pcidev;
1451
1452        n_subdevices = 0;
1453        if (this_board->n_aichan)
1454                n_subdevices++;
1455        if (this_board->n_aochan)
1456                n_subdevices++;
1457        if (this_board->n_dichan)
1458                n_subdevices++;
1459        if (this_board->n_dochan)
1460                n_subdevices++;
1461        if (this_board->n_counter)
1462                n_subdevices++;
1463
1464        ret = alloc_subdevices(dev, n_subdevices);
1465        if (ret < 0) {
1466                printk(" - Allocation failed!\n");
1467                return ret;
1468        }
1469
1470        pci1710_reset(dev);
1471
1472        if (this_board->have_irq) {
1473                if (irq) {
1474                        if (request_irq(irq, interrupt_service_pci1710,
1475                                        IRQF_SHARED, "Advantech PCI-1710",
1476                                        dev)) {
1477                                printk
1478                                    (", unable to allocate IRQ %d, DISABLING IT",
1479                                     irq);
1480                                irq = 0;        /* Can't use IRQ */
1481                        } else {
1482                                printk(", irq=%u", irq);
1483                        }
1484                } else {
1485                        printk(", IRQ disabled");
1486                }
1487        } else {
1488                irq = 0;
1489        }
1490
1491        dev->irq = irq;
1492
1493        printk(".\n");
1494
1495        subdev = 0;
1496
1497        if (this_board->n_aichan) {
1498                s = dev->subdevices + subdev;
1499                dev->read_subdev = s;
1500                s->type = COMEDI_SUBD_AI;
1501                s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1502                if (this_board->n_aichand)
1503                        s->subdev_flags |= SDF_DIFF;
1504                s->n_chan = this_board->n_aichan;
1505                s->maxdata = this_board->ai_maxdata;
1506                s->len_chanlist = this_board->n_aichan;
1507                s->range_table = this_board->rangelist_ai;
1508                s->cancel = pci171x_ai_cancel;
1509                s->insn_read = pci171x_insn_read_ai;
1510                if (irq) {
1511                        s->subdev_flags |= SDF_CMD_READ;
1512                        s->do_cmdtest = pci171x_ai_cmdtest;
1513                        s->do_cmd = pci171x_ai_cmd;
1514                }
1515                devpriv->i8254_osc_base = 100;  /*  100ns=10MHz */
1516                subdev++;
1517        }
1518
1519        if (this_board->n_aochan) {
1520                s = dev->subdevices + subdev;
1521                s->type = COMEDI_SUBD_AO;
1522                s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1523                s->n_chan = this_board->n_aochan;
1524                s->maxdata = this_board->ao_maxdata;
1525                s->len_chanlist = this_board->n_aochan;
1526                s->range_table = this_board->rangelist_ao;
1527                switch (this_board->cardtype) {
1528                case TYPE_PCI1720:
1529                        s->insn_write = pci1720_insn_write_ao;
1530                        break;
1531                default:
1532                        s->insn_write = pci171x_insn_write_ao;
1533                        break;
1534                }
1535                s->insn_read = pci171x_insn_read_ao;
1536                subdev++;
1537        }
1538
1539        if (this_board->n_dichan) {
1540                s = dev->subdevices + subdev;
1541                s->type = COMEDI_SUBD_DI;
1542                s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1543                s->n_chan = this_board->n_dichan;
1544                s->maxdata = 1;
1545                s->len_chanlist = this_board->n_dichan;
1546                s->range_table = &range_digital;
1547                s->io_bits = 0; /* all bits input */
1548                s->insn_bits = pci171x_insn_bits_di;
1549                subdev++;
1550        }
1551
1552        if (this_board->n_dochan) {
1553                s = dev->subdevices + subdev;
1554                s->type = COMEDI_SUBD_DO;
1555                s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1556                s->n_chan = this_board->n_dochan;
1557                s->maxdata = 1;
1558                s->len_chanlist = this_board->n_dochan;
1559                s->range_table = &range_digital;
1560                s->io_bits = (1 << this_board->n_dochan) - 1;   /* all bits output */
1561                s->state = 0;
1562                s->insn_bits = pci171x_insn_bits_do;
1563                subdev++;
1564        }
1565
1566        if (this_board->n_counter) {
1567                s = dev->subdevices + subdev;
1568                s->type = COMEDI_SUBD_COUNTER;
1569                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1570                s->n_chan = this_board->n_counter;
1571                s->len_chanlist = this_board->n_counter;
1572                s->maxdata = 0xffff;
1573                s->range_table = &range_unknown;
1574                s->insn_read = pci171x_insn_counter_read;
1575                s->insn_write = pci171x_insn_counter_write;
1576                s->insn_config = pci171x_insn_counter_config;
1577                subdev++;
1578        }
1579
1580        devpriv->valid = 1;
1581
1582        return 0;
1583}
1584
1585/*
1586==============================================================================
1587*/
1588static int pci1710_detach(struct comedi_device *dev)
1589{
1590
1591        if (dev->private) {
1592                if (devpriv->valid)
1593                        pci1710_reset(dev);
1594                if (dev->irq)
1595                        free_irq(dev->irq, dev);
1596                if (devpriv->pcidev) {
1597                        if (dev->iobase) {
1598                                comedi_pci_disable(devpriv->pcidev);
1599                        }
1600                        pci_dev_put(devpriv->pcidev);
1601                }
1602        }
1603
1604        return 0;
1605}
1606
1607/*
1608==============================================================================
1609*/
1610COMEDI_PCI_INITCLEANUP(driver_pci1710, pci1710_pci_table);
1611/*
1612==============================================================================
1613*/
1614