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