linux/drivers/staging/comedi/drivers/dt3000.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/dt3000.c
   3    Data Translation DT3000 series driver
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 1999 David A. Schleef <ds@schleef.org>
   7
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 2 of the License, or
  11    (at your option) any later version.
  12
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17
  18    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21
  22*/
  23/*
  24Driver: dt3000
  25Description: Data Translation DT3000 series
  26Author: ds
  27Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
  28  DT3003-PGL, DT3004, DT3005, DT3004-200
  29Updated: Mon, 14 Apr 2008 15:41:24 +0100
  30Status: works
  31
  32Configuration Options:
  33  [0] - PCI bus of device (optional)
  34  [1] - PCI slot of device (optional)
  35  If bus/slot is not specified, the first supported
  36  PCI device found will be used.
  37
  38There is code to support AI commands, but it may not work.
  39
  40AO commands are not supported.
  41*/
  42
  43/*
  44   The DT3000 series is Data Translation's attempt to make a PCI
  45   data acquisition board.  The design of this series is very nice,
  46   since each board has an on-board DSP (Texas Instruments TMS320C52).
  47   However, a few details are a little annoying.  The boards lack
  48   bus-mastering DMA, which eliminates them from serious work.
  49   They also are not capable of autocalibration, which is a common
  50   feature in modern hardware.  The default firmware is pretty bad,
  51   making it nearly impossible to write an RT compatible driver.
  52   It would make an interesting project to write a decent firmware
  53   for these boards.
  54
  55   Data Translation originally wanted an NDA for the documentation
  56   for the 3k series.  However, if you ask nicely, they might send
  57   you the docs without one, also.
  58*/
  59
  60#define DEBUG 1
  61
  62#include <linux/interrupt.h>
  63#include "../comedidev.h"
  64#include <linux/delay.h>
  65
  66#include "comedi_pci.h"
  67
  68#define PCI_VENDOR_ID_DT        0x1116
  69
  70static const struct comedi_lrange range_dt3000_ai = { 4, {
  71                                                          RANGE(-10, 10),
  72                                                          RANGE(-5, 5),
  73                                                          RANGE(-2.5, 2.5),
  74                                                          RANGE(-1.25, 1.25)
  75                                                          }
  76};
  77
  78static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
  79                                                              RANGE(-10, 10),
  80                                                              RANGE(-1, 1),
  81                                                              RANGE(-0.1, 0.1),
  82                                                              RANGE(-0.02, 0.02)
  83                                                              }
  84};
  85
  86struct dt3k_boardtype {
  87
  88        const char *name;
  89        unsigned int device_id;
  90        int adchan;
  91        int adbits;
  92        int ai_speed;
  93        const struct comedi_lrange *adrange;
  94        int dachan;
  95        int dabits;
  96};
  97
  98static const struct dt3k_boardtype dt3k_boardtypes[] = {
  99        {.name = "dt3001",
 100         .device_id = 0x22,
 101         .adchan = 16,
 102         .adbits = 12,
 103         .adrange = &range_dt3000_ai,
 104         .ai_speed = 3000,
 105         .dachan = 2,
 106         .dabits = 12,
 107         },
 108        {.name = "dt3001-pgl",
 109         .device_id = 0x27,
 110         .adchan = 16,
 111         .adbits = 12,
 112         .adrange = &range_dt3000_ai_pgl,
 113         .ai_speed = 3000,
 114         .dachan = 2,
 115         .dabits = 12,
 116         },
 117        {.name = "dt3002",
 118         .device_id = 0x23,
 119         .adchan = 32,
 120         .adbits = 12,
 121         .adrange = &range_dt3000_ai,
 122         .ai_speed = 3000,
 123         .dachan = 0,
 124         .dabits = 0,
 125         },
 126        {.name = "dt3003",
 127         .device_id = 0x24,
 128         .adchan = 64,
 129         .adbits = 12,
 130         .adrange = &range_dt3000_ai,
 131         .ai_speed = 3000,
 132         .dachan = 2,
 133         .dabits = 12,
 134         },
 135        {.name = "dt3003-pgl",
 136         .device_id = 0x28,
 137         .adchan = 64,
 138         .adbits = 12,
 139         .adrange = &range_dt3000_ai_pgl,
 140         .ai_speed = 3000,
 141         .dachan = 2,
 142         .dabits = 12,
 143         },
 144        {.name = "dt3004",
 145         .device_id = 0x25,
 146         .adchan = 16,
 147         .adbits = 16,
 148         .adrange = &range_dt3000_ai,
 149         .ai_speed = 10000,
 150         .dachan = 2,
 151         .dabits = 12,
 152         },
 153        {.name = "dt3005",      /* a.k.a. 3004-200 */
 154         .device_id = 0x26,
 155         .adchan = 16,
 156         .adbits = 16,
 157         .adrange = &range_dt3000_ai,
 158         .ai_speed = 5000,
 159         .dachan = 2,
 160         .dabits = 12,
 161         },
 162};
 163
 164#define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
 165#define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
 166
 167static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
 168        {
 169        PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 170        PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 171        PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 172        PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 173        PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 174        PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 175        PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
 176        0}
 177};
 178
 179MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
 180
 181#define DT3000_SIZE             (4*0x1000)
 182
 183/* dual-ported RAM location definitions */
 184
 185#define DPR_DAC_buffer          (4*0x000)
 186#define DPR_ADC_buffer          (4*0x800)
 187#define DPR_Command             (4*0xfd3)
 188#define DPR_SubSys              (4*0xfd3)
 189#define DPR_Encode              (4*0xfd4)
 190#define DPR_Params(a)           (4*(0xfd5+(a)))
 191#define DPR_Tick_Reg_Lo         (4*0xff5)
 192#define DPR_Tick_Reg_Hi         (4*0xff6)
 193#define DPR_DA_Buf_Front        (4*0xff7)
 194#define DPR_DA_Buf_Rear         (4*0xff8)
 195#define DPR_AD_Buf_Front        (4*0xff9)
 196#define DPR_AD_Buf_Rear         (4*0xffa)
 197#define DPR_Int_Mask            (4*0xffb)
 198#define DPR_Intr_Flag           (4*0xffc)
 199#define DPR_Response_Mbx        (4*0xffe)
 200#define DPR_Command_Mbx         (4*0xfff)
 201
 202#define AI_FIFO_DEPTH   2003
 203#define AO_FIFO_DEPTH   2048
 204
 205/* command list */
 206
 207#define CMD_GETBRDINFO          0
 208#define CMD_CONFIG              1
 209#define CMD_GETCONFIG           2
 210#define CMD_START               3
 211#define CMD_STOP                4
 212#define CMD_READSINGLE          5
 213#define CMD_WRITESINGLE         6
 214#define CMD_CALCCLOCK           7
 215#define CMD_READEVENTS          8
 216#define CMD_WRITECTCTRL         16
 217#define CMD_READCTCTRL          17
 218#define CMD_WRITECT             18
 219#define CMD_READCT              19
 220#define CMD_WRITEDATA           32
 221#define CMD_READDATA            33
 222#define CMD_WRITEIO             34
 223#define CMD_READIO              35
 224#define CMD_WRITECODE           36
 225#define CMD_READCODE            37
 226#define CMD_EXECUTE             38
 227#define CMD_HALT                48
 228
 229#define SUBS_AI         0
 230#define SUBS_AO         1
 231#define SUBS_DIN        2
 232#define SUBS_DOUT       3
 233#define SUBS_MEM        4
 234#define SUBS_CT         5
 235
 236/* interrupt flags */
 237#define DT3000_CMDONE           0x80
 238#define DT3000_CTDONE           0x40
 239#define DT3000_DAHWERR          0x20
 240#define DT3000_DASWERR          0x10
 241#define DT3000_DAEMPTY          0x08
 242#define DT3000_ADHWERR          0x04
 243#define DT3000_ADSWERR          0x02
 244#define DT3000_ADFULL           0x01
 245
 246#define DT3000_COMPLETION_MASK  0xff00
 247#define DT3000_COMMAND_MASK     0x00ff
 248#define DT3000_NOTPROCESSED     0x0000
 249#define DT3000_NOERROR          0x5500
 250#define DT3000_ERROR            0xaa00
 251#define DT3000_NOTSUPPORTED     0xff00
 252
 253#define DT3000_EXTERNAL_CLOCK   1
 254#define DT3000_RISING_EDGE      2
 255
 256#define TMODE_MASK              0x1c
 257
 258#define DT3000_AD_TRIG_INTERNAL         (0<<2)
 259#define DT3000_AD_TRIG_EXTERNAL         (1<<2)
 260#define DT3000_AD_RETRIG_INTERNAL       (2<<2)
 261#define DT3000_AD_RETRIG_EXTERNAL       (3<<2)
 262#define DT3000_AD_EXTRETRIG             (4<<2)
 263
 264#define DT3000_CHANNEL_MODE_SE          0
 265#define DT3000_CHANNEL_MODE_DI          1
 266
 267struct dt3k_private {
 268
 269        struct pci_dev *pci_dev;
 270        resource_size_t phys_addr;
 271        void *io_addr;
 272        unsigned int lock;
 273        unsigned int ao_readback[2];
 274        unsigned int ai_front;
 275        unsigned int ai_rear;
 276};
 277
 278#define devpriv ((struct dt3k_private *)dev->private)
 279
 280static int dt3000_attach(struct comedi_device *dev,
 281                         struct comedi_devconfig *it);
 282static int dt3000_detach(struct comedi_device *dev);
 283static struct comedi_driver driver_dt3000 = {
 284        .driver_name = "dt3000",
 285        .module = THIS_MODULE,
 286        .attach = dt3000_attach,
 287        .detach = dt3000_detach,
 288};
 289
 290COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
 291
 292static void dt3k_ai_empty_fifo(struct comedi_device *dev,
 293                               struct comedi_subdevice *s);
 294static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
 295                            unsigned int round_mode);
 296static int dt3k_ai_cancel(struct comedi_device *dev,
 297                          struct comedi_subdevice *s);
 298#ifdef DEBUG
 299static void debug_intr_flags(unsigned int flags);
 300#endif
 301
 302#define TIMEOUT 100
 303
 304static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
 305{
 306        int i;
 307        unsigned int status = 0;
 308
 309        writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
 310
 311        for (i = 0; i < TIMEOUT; i++) {
 312                status = readw(devpriv->io_addr + DPR_Command_Mbx);
 313                if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
 314                        break;
 315                udelay(1);
 316        }
 317        if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
 318                return 0;
 319        }
 320
 321        printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
 322
 323        return -ETIME;
 324}
 325
 326static unsigned int dt3k_readsingle(struct comedi_device *dev,
 327                                    unsigned int subsys, unsigned int chan,
 328                                    unsigned int gain)
 329{
 330        writew(subsys, devpriv->io_addr + DPR_SubSys);
 331
 332        writew(chan, devpriv->io_addr + DPR_Params(0));
 333        writew(gain, devpriv->io_addr + DPR_Params(1));
 334
 335        dt3k_send_cmd(dev, CMD_READSINGLE);
 336
 337        return readw(devpriv->io_addr + DPR_Params(2));
 338}
 339
 340static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
 341                             unsigned int chan, unsigned int data)
 342{
 343        writew(subsys, devpriv->io_addr + DPR_SubSys);
 344
 345        writew(chan, devpriv->io_addr + DPR_Params(0));
 346        writew(0, devpriv->io_addr + DPR_Params(1));
 347        writew(data, devpriv->io_addr + DPR_Params(2));
 348
 349        dt3k_send_cmd(dev, CMD_WRITESINGLE);
 350}
 351
 352static int debug_n_ints = 0;
 353
 354/* FIXME! Assumes shared interrupt is for this card. */
 355/* What's this debug_n_ints stuff? Obviously needs some work... */
 356static irqreturn_t dt3k_interrupt(int irq, void *d)
 357{
 358        struct comedi_device *dev = d;
 359        struct comedi_subdevice *s;
 360        unsigned int status;
 361
 362        if (!dev->attached) {
 363                return IRQ_NONE;
 364        }
 365
 366        s = dev->subdevices + 0;
 367        status = readw(devpriv->io_addr + DPR_Intr_Flag);
 368#ifdef DEBUG
 369        debug_intr_flags(status);
 370#endif
 371
 372        if (status & DT3000_ADFULL) {
 373                dt3k_ai_empty_fifo(dev, s);
 374                s->async->events |= COMEDI_CB_BLOCK;
 375        }
 376
 377        if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
 378                s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 379        }
 380
 381        debug_n_ints++;
 382        if (debug_n_ints >= 10) {
 383                dt3k_ai_cancel(dev, s);
 384                s->async->events |= COMEDI_CB_EOA;
 385        }
 386
 387        comedi_event(dev, s);
 388        return IRQ_HANDLED;
 389}
 390
 391#ifdef DEBUG
 392static char *intr_flags[] = {
 393        "AdFull", "AdSwError", "AdHwError", "DaEmpty",
 394        "DaSwError", "DaHwError", "CtDone", "CmDone",
 395};
 396
 397static void debug_intr_flags(unsigned int flags)
 398{
 399        int i;
 400        printk("dt3k: intr_flags:");
 401        for (i = 0; i < 8; i++) {
 402                if (flags & (1 << i)) {
 403                        printk(" %s", intr_flags[i]);
 404                }
 405        }
 406        printk("\n");
 407}
 408#endif
 409
 410static void dt3k_ai_empty_fifo(struct comedi_device *dev,
 411                               struct comedi_subdevice *s)
 412{
 413        int front;
 414        int rear;
 415        int count;
 416        int i;
 417        short data;
 418
 419        front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
 420        count = front - devpriv->ai_front;
 421        if (count < 0)
 422                count += AI_FIFO_DEPTH;
 423
 424        printk("reading %d samples\n", count);
 425
 426        rear = devpriv->ai_rear;
 427
 428        for (i = 0; i < count; i++) {
 429                data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
 430                comedi_buf_put(s->async, data);
 431                rear++;
 432                if (rear >= AI_FIFO_DEPTH)
 433                        rear = 0;
 434        }
 435
 436        devpriv->ai_rear = rear;
 437        writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
 438}
 439
 440static int dt3k_ai_cmdtest(struct comedi_device *dev,
 441                           struct comedi_subdevice *s, struct comedi_cmd *cmd)
 442{
 443        int err = 0;
 444        int tmp;
 445
 446        /* step 1: make sure trigger sources are trivially valid */
 447
 448        tmp = cmd->start_src;
 449        cmd->start_src &= TRIG_NOW;
 450        if (!cmd->start_src || tmp != cmd->start_src)
 451                err++;
 452
 453        tmp = cmd->scan_begin_src;
 454        cmd->scan_begin_src &= TRIG_TIMER;
 455        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 456                err++;
 457
 458        tmp = cmd->convert_src;
 459        cmd->convert_src &= TRIG_TIMER;
 460        if (!cmd->convert_src || tmp != cmd->convert_src)
 461                err++;
 462
 463        tmp = cmd->scan_end_src;
 464        cmd->scan_end_src &= TRIG_COUNT;
 465        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 466                err++;
 467
 468        tmp = cmd->stop_src;
 469        cmd->stop_src &= TRIG_COUNT;
 470        if (!cmd->stop_src || tmp != cmd->stop_src)
 471                err++;
 472
 473        if (err)
 474                return 1;
 475
 476        /* step 2: make sure trigger sources are unique and mutually compatible */
 477
 478        if (err)
 479                return 2;
 480
 481        /* step 3: make sure arguments are trivially compatible */
 482
 483        if (cmd->start_arg != 0) {
 484                cmd->start_arg = 0;
 485                err++;
 486        }
 487
 488        if (cmd->scan_begin_src == TRIG_TIMER) {
 489                if (cmd->scan_begin_arg < this_board->ai_speed) {
 490                        cmd->scan_begin_arg = this_board->ai_speed;
 491                        err++;
 492                }
 493                if (cmd->scan_begin_arg > 100 * 16 * 65535) {
 494                        cmd->scan_begin_arg = 100 * 16 * 65535;
 495                        err++;
 496                }
 497        } else {
 498                /* not supported */
 499        }
 500        if (cmd->convert_src == TRIG_TIMER) {
 501                if (cmd->convert_arg < this_board->ai_speed) {
 502                        cmd->convert_arg = this_board->ai_speed;
 503                        err++;
 504                }
 505                if (cmd->convert_arg > 50 * 16 * 65535) {
 506                        cmd->convert_arg = 50 * 16 * 65535;
 507                        err++;
 508                }
 509        } else {
 510                /* not supported */
 511        }
 512
 513        if (cmd->scan_end_arg != cmd->chanlist_len) {
 514                cmd->scan_end_arg = cmd->chanlist_len;
 515                err++;
 516        }
 517        if (cmd->stop_src == TRIG_COUNT) {
 518                if (cmd->stop_arg > 0x00ffffff) {
 519                        cmd->stop_arg = 0x00ffffff;
 520                        err++;
 521                }
 522        } else {
 523                /* TRIG_NONE */
 524                if (cmd->stop_arg != 0) {
 525                        cmd->stop_arg = 0;
 526                        err++;
 527                }
 528        }
 529
 530        if (err)
 531                return 3;
 532
 533        /* step 4: fix up any arguments */
 534
 535        if (cmd->scan_begin_src == TRIG_TIMER) {
 536                tmp = cmd->scan_begin_arg;
 537                dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
 538                                 cmd->flags & TRIG_ROUND_MASK);
 539                if (tmp != cmd->scan_begin_arg)
 540                        err++;
 541        } else {
 542                /* not supported */
 543        }
 544        if (cmd->convert_src == TRIG_TIMER) {
 545                tmp = cmd->convert_arg;
 546                dt3k_ns_to_timer(50, &cmd->convert_arg,
 547                                 cmd->flags & TRIG_ROUND_MASK);
 548                if (tmp != cmd->convert_arg)
 549                        err++;
 550                if (cmd->scan_begin_src == TRIG_TIMER &&
 551                    cmd->scan_begin_arg <
 552                    cmd->convert_arg * cmd->scan_end_arg) {
 553                        cmd->scan_begin_arg =
 554                            cmd->convert_arg * cmd->scan_end_arg;
 555                        err++;
 556                }
 557        } else {
 558                /* not supported */
 559        }
 560
 561        if (err)
 562                return 4;
 563
 564        return 0;
 565}
 566
 567static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
 568                            unsigned int round_mode)
 569{
 570        int divider, base, prescale;
 571
 572        /* This function needs improvment */
 573        /* Don't know if divider==0 works. */
 574
 575        for (prescale = 0; prescale < 16; prescale++) {
 576                base = timer_base * (prescale + 1);
 577                switch (round_mode) {
 578                case TRIG_ROUND_NEAREST:
 579                default:
 580                        divider = (*nanosec + base / 2) / base;
 581                        break;
 582                case TRIG_ROUND_DOWN:
 583                        divider = (*nanosec) / base;
 584                        break;
 585                case TRIG_ROUND_UP:
 586                        divider = (*nanosec) / base;
 587                        break;
 588                }
 589                if (divider < 65536) {
 590                        *nanosec = divider * base;
 591                        return (prescale << 16) | (divider);
 592                }
 593        }
 594
 595        prescale = 15;
 596        base = timer_base * (1 << prescale);
 597        divider = 65535;
 598        *nanosec = divider * base;
 599        return (prescale << 16) | (divider);
 600}
 601
 602static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 603{
 604        struct comedi_cmd *cmd = &s->async->cmd;
 605        int i;
 606        unsigned int chan, range, aref;
 607        unsigned int divider;
 608        unsigned int tscandiv;
 609        int ret;
 610        unsigned int mode;
 611
 612        printk("dt3k_ai_cmd:\n");
 613        for (i = 0; i < cmd->chanlist_len; i++) {
 614                chan = CR_CHAN(cmd->chanlist[i]);
 615                range = CR_RANGE(cmd->chanlist[i]);
 616
 617                writew((range << 6) | chan,
 618                       devpriv->io_addr + DPR_ADC_buffer + i);
 619        }
 620        aref = CR_AREF(cmd->chanlist[0]);
 621
 622        writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
 623        printk("param[0]=0x%04x\n", cmd->scan_end_arg);
 624
 625        if (cmd->convert_src == TRIG_TIMER) {
 626                divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
 627                                           cmd->flags & TRIG_ROUND_MASK);
 628                writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
 629                printk("param[1]=0x%04x\n", divider >> 16);
 630                writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
 631                printk("param[2]=0x%04x\n", divider & 0xffff);
 632        } else {
 633                /* not supported */
 634        }
 635
 636        if (cmd->scan_begin_src == TRIG_TIMER) {
 637                tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
 638                                            cmd->flags & TRIG_ROUND_MASK);
 639                writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
 640                printk("param[3]=0x%04x\n", tscandiv >> 16);
 641                writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
 642                printk("param[4]=0x%04x\n", tscandiv & 0xffff);
 643        } else {
 644                /* not supported */
 645        }
 646
 647        mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
 648        writew(mode, devpriv->io_addr + DPR_Params(5));
 649        printk("param[5]=0x%04x\n", mode);
 650        writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
 651        printk("param[6]=0x%04x\n", aref == AREF_DIFF);
 652
 653        writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
 654        printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
 655
 656        writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
 657        ret = dt3k_send_cmd(dev, CMD_CONFIG);
 658
 659        writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
 660               devpriv->io_addr + DPR_Int_Mask);
 661
 662        debug_n_ints = 0;
 663
 664        writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
 665        ret = dt3k_send_cmd(dev, CMD_START);
 666
 667        return 0;
 668}
 669
 670static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 671{
 672        int ret;
 673
 674        writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
 675        ret = dt3k_send_cmd(dev, CMD_STOP);
 676
 677        writew(0, devpriv->io_addr + DPR_Int_Mask);
 678
 679        return 0;
 680}
 681
 682static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 683                        struct comedi_insn *insn, unsigned int *data)
 684{
 685        int i;
 686        unsigned int chan, gain, aref;
 687
 688        chan = CR_CHAN(insn->chanspec);
 689        gain = CR_RANGE(insn->chanspec);
 690        /* XXX docs don't explain how to select aref */
 691        aref = CR_AREF(insn->chanspec);
 692
 693        for (i = 0; i < insn->n; i++) {
 694                data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
 695        }
 696
 697        return i;
 698}
 699
 700static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 701                        struct comedi_insn *insn, unsigned int *data)
 702{
 703        int i;
 704        unsigned int chan;
 705
 706        chan = CR_CHAN(insn->chanspec);
 707        for (i = 0; i < insn->n; i++) {
 708                dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
 709                devpriv->ao_readback[chan] = data[i];
 710        }
 711
 712        return i;
 713}
 714
 715static int dt3k_ao_insn_read(struct comedi_device *dev,
 716                             struct comedi_subdevice *s,
 717                             struct comedi_insn *insn, unsigned int *data)
 718{
 719        int i;
 720        unsigned int chan;
 721
 722        chan = CR_CHAN(insn->chanspec);
 723        for (i = 0; i < insn->n; i++) {
 724                data[i] = devpriv->ao_readback[chan];
 725        }
 726
 727        return i;
 728}
 729
 730static void dt3k_dio_config(struct comedi_device *dev, int bits)
 731{
 732        /* XXX */
 733        writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
 734
 735        writew(bits, devpriv->io_addr + DPR_Params(0));
 736#if 0
 737        /* don't know */
 738        writew(0, devpriv->io_addr + DPR_Params(1));
 739        writew(0, devpriv->io_addr + DPR_Params(2));
 740#endif
 741
 742        dt3k_send_cmd(dev, CMD_CONFIG);
 743}
 744
 745static int dt3k_dio_insn_config(struct comedi_device *dev,
 746                                struct comedi_subdevice *s,
 747                                struct comedi_insn *insn, unsigned int *data)
 748{
 749        int mask;
 750
 751        mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
 752
 753        switch (data[0]) {
 754        case INSN_CONFIG_DIO_OUTPUT:
 755                s->io_bits |= mask;
 756                break;
 757        case INSN_CONFIG_DIO_INPUT:
 758                s->io_bits &= ~mask;
 759                break;
 760        case INSN_CONFIG_DIO_QUERY:
 761                data[1] =
 762                    (s->
 763                     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
 764                    COMEDI_INPUT;
 765                return insn->n;
 766                break;
 767        default:
 768                return -EINVAL;
 769                break;
 770        }
 771        mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
 772        dt3k_dio_config(dev, mask);
 773
 774        return insn->n;
 775}
 776
 777static int dt3k_dio_insn_bits(struct comedi_device *dev,
 778                              struct comedi_subdevice *s,
 779                              struct comedi_insn *insn, unsigned int *data)
 780{
 781        if (insn->n != 2)
 782                return -EINVAL;
 783
 784        if (data[0]) {
 785                s->state &= ~data[0];
 786                s->state |= data[1] & data[0];
 787                dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
 788        }
 789        data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
 790
 791        return 2;
 792}
 793
 794static int dt3k_mem_insn_read(struct comedi_device *dev,
 795                              struct comedi_subdevice *s,
 796                              struct comedi_insn *insn, unsigned int *data)
 797{
 798        unsigned int addr = CR_CHAN(insn->chanspec);
 799        int i;
 800
 801        for (i = 0; i < insn->n; i++) {
 802                writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
 803                writew(addr, devpriv->io_addr + DPR_Params(0));
 804                writew(1, devpriv->io_addr + DPR_Params(1));
 805
 806                dt3k_send_cmd(dev, CMD_READCODE);
 807
 808                data[i] = readw(devpriv->io_addr + DPR_Params(2));
 809        }
 810
 811        return i;
 812}
 813
 814static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
 815
 816static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 817{
 818        struct comedi_subdevice *s;
 819        int bus, slot;
 820        int ret = 0;
 821
 822        printk("dt3000:");
 823        bus = it->options[0];
 824        slot = it->options[1];
 825
 826        ret = alloc_private(dev, sizeof(struct dt3k_private));
 827        if (ret < 0)
 828                return ret;
 829
 830        ret = dt_pci_probe(dev, bus, slot);
 831        if (ret < 0)
 832                return ret;
 833        if (ret == 0) {
 834                printk(" no DT board found\n");
 835                return -ENODEV;
 836        }
 837
 838        dev->board_name = this_board->name;
 839
 840        if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
 841                        "dt3000", dev)) {
 842                printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
 843                return -EINVAL;
 844        }
 845        dev->irq = devpriv->pci_dev->irq;
 846
 847        ret = alloc_subdevices(dev, 4);
 848        if (ret < 0)
 849                return ret;
 850
 851        s = dev->subdevices;
 852        dev->read_subdev = s;
 853
 854        /* ai subdevice */
 855        s->type = COMEDI_SUBD_AI;
 856        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
 857        s->n_chan = this_board->adchan;
 858        s->insn_read = dt3k_ai_insn;
 859        s->maxdata = (1 << this_board->adbits) - 1;
 860        s->len_chanlist = 512;
 861        s->range_table = &range_dt3000_ai;      /* XXX */
 862        s->do_cmd = dt3k_ai_cmd;
 863        s->do_cmdtest = dt3k_ai_cmdtest;
 864        s->cancel = dt3k_ai_cancel;
 865
 866        s++;
 867        /* ao subsystem */
 868        s->type = COMEDI_SUBD_AO;
 869        s->subdev_flags = SDF_WRITABLE;
 870        s->n_chan = 2;
 871        s->insn_read = dt3k_ao_insn_read;
 872        s->insn_write = dt3k_ao_insn;
 873        s->maxdata = (1 << this_board->dabits) - 1;
 874        s->len_chanlist = 1;
 875        s->range_table = &range_bipolar10;
 876
 877        s++;
 878        /* dio subsystem */
 879        s->type = COMEDI_SUBD_DIO;
 880        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 881        s->n_chan = 8;
 882        s->insn_config = dt3k_dio_insn_config;
 883        s->insn_bits = dt3k_dio_insn_bits;
 884        s->maxdata = 1;
 885        s->len_chanlist = 8;
 886        s->range_table = &range_digital;
 887
 888        s++;
 889        /* mem subsystem */
 890        s->type = COMEDI_SUBD_MEMORY;
 891        s->subdev_flags = SDF_READABLE;
 892        s->n_chan = 0x1000;
 893        s->insn_read = dt3k_mem_insn_read;
 894        s->maxdata = 0xff;
 895        s->len_chanlist = 1;
 896        s->range_table = &range_unknown;
 897
 898#if 0
 899        s++;
 900        /* proc subsystem */
 901        s->type = COMEDI_SUBD_PROC;
 902#endif
 903
 904        return 0;
 905}
 906
 907static int dt3000_detach(struct comedi_device *dev)
 908{
 909        if (dev->irq)
 910                free_irq(dev->irq, dev);
 911
 912        if (devpriv) {
 913                if (devpriv->pci_dev) {
 914                        if (devpriv->phys_addr) {
 915                                comedi_pci_disable(devpriv->pci_dev);
 916                        }
 917                        pci_dev_put(devpriv->pci_dev);
 918                }
 919                if (devpriv->io_addr)
 920                        iounmap(devpriv->io_addr);
 921        }
 922        /* XXX */
 923
 924        return 0;
 925}
 926
 927static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
 928static int setup_pci(struct comedi_device *dev);
 929
 930static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
 931{
 932        int board;
 933        int ret;
 934        struct pci_dev *pcidev;
 935
 936        pcidev = NULL;
 937        while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
 938                if ((bus == 0 && slot == 0) ||
 939                    (pcidev->bus->number == bus &&
 940                     PCI_SLOT(pcidev->devfn) == slot)) {
 941                        break;
 942                }
 943        }
 944        devpriv->pci_dev = pcidev;
 945
 946        if (board >= 0)
 947                dev->board_ptr = dt3k_boardtypes + board;
 948
 949        if (!devpriv->pci_dev)
 950                return 0;
 951
 952        ret = setup_pci(dev);
 953        if (ret < 0)
 954                return ret;
 955
 956        return 1;
 957}
 958
 959static int setup_pci(struct comedi_device *dev)
 960{
 961        resource_size_t addr;
 962        int ret;
 963
 964        ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
 965        if (ret < 0)
 966                return ret;
 967
 968        addr = pci_resource_start(devpriv->pci_dev, 0);
 969        devpriv->phys_addr = addr;
 970        devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
 971        if (!devpriv->io_addr)
 972                return -ENOMEM;
 973#if DEBUG
 974        printk("0x%08llx mapped to %p, ",
 975               (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
 976#endif
 977
 978        return 0;
 979}
 980
 981static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
 982{
 983        int i;
 984
 985        for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
 986             from != NULL;
 987             from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
 988                for (i = 0; i < n_dt3k_boards; i++) {
 989                        if (from->device == dt3k_boardtypes[i].device_id) {
 990                                *board = i;
 991                                return from;
 992                        }
 993                }
 994                printk
 995                    ("unknown Data Translation PCI device found with device_id=0x%04x\n",
 996                     from->device);
 997        }
 998        *board = -1;
 999        return from;
1000}
1001