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