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