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