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/*
  19Driver: dt3000
  20Description: Data Translation DT3000 series
  21Author: ds
  22Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
  23  DT3003-PGL, DT3004, DT3005, DT3004-200
  24Updated: Mon, 14 Apr 2008 15:41:24 +0100
  25Status: works
  26
  27Configuration Options: not applicable, uses PCI auto config
  28
  29There is code to support AI commands, but it may not work.
  30
  31AO commands are not supported.
  32*/
  33
  34/*
  35   The DT3000 series is Data Translation's attempt to make a PCI
  36   data acquisition board.  The design of this series is very nice,
  37   since each board has an on-board DSP (Texas Instruments TMS320C52).
  38   However, a few details are a little annoying.  The boards lack
  39   bus-mastering DMA, which eliminates them from serious work.
  40   They also are not capable of autocalibration, which is a common
  41   feature in modern hardware.  The default firmware is pretty bad,
  42   making it nearly impossible to write an RT compatible driver.
  43   It would make an interesting project to write a decent firmware
  44   for these boards.
  45
  46   Data Translation originally wanted an NDA for the documentation
  47   for the 3k series.  However, if you ask nicely, they might send
  48   you the docs without one, also.
  49*/
  50
  51#include <linux/module.h>
  52#include <linux/pci.h>
  53#include <linux/delay.h>
  54#include <linux/interrupt.h>
  55
  56#include "../comedidev.h"
  57
  58#include "comedi_fc.h"
  59
  60static const struct comedi_lrange range_dt3000_ai = {
  61        4, {
  62                BIP_RANGE(10),
  63                BIP_RANGE(5),
  64                BIP_RANGE(2.5),
  65                BIP_RANGE(1.25)
  66        }
  67};
  68
  69static const struct comedi_lrange range_dt3000_ai_pgl = {
  70        4, {
  71                BIP_RANGE(10),
  72                BIP_RANGE(1),
  73                BIP_RANGE(0.1),
  74                BIP_RANGE(0.02)
  75        }
  76};
  77
  78enum dt3k_boardid {
  79        BOARD_DT3001,
  80        BOARD_DT3001_PGL,
  81        BOARD_DT3002,
  82        BOARD_DT3003,
  83        BOARD_DT3003_PGL,
  84        BOARD_DT3004,
  85        BOARD_DT3005,
  86};
  87
  88struct dt3k_boardtype {
  89        const char *name;
  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        [BOARD_DT3001] = {
 100                .name           = "dt3001",
 101                .adchan         = 16,
 102                .adbits         = 12,
 103                .adrange        = &range_dt3000_ai,
 104                .ai_speed       = 3000,
 105                .dachan         = 2,
 106                .dabits         = 12,
 107        },
 108        [BOARD_DT3001_PGL] = {
 109                .name           = "dt3001-pgl",
 110                .adchan         = 16,
 111                .adbits         = 12,
 112                .adrange        = &range_dt3000_ai_pgl,
 113                .ai_speed       = 3000,
 114                .dachan         = 2,
 115                .dabits         = 12,
 116        },
 117        [BOARD_DT3002] = {
 118                .name           = "dt3002",
 119                .adchan         = 32,
 120                .adbits         = 12,
 121                .adrange        = &range_dt3000_ai,
 122                .ai_speed       = 3000,
 123        },
 124        [BOARD_DT3003] = {
 125                .name           = "dt3003",
 126                .adchan         = 64,
 127                .adbits         = 12,
 128                .adrange        = &range_dt3000_ai,
 129                .ai_speed       = 3000,
 130                .dachan         = 2,
 131                .dabits         = 12,
 132        },
 133        [BOARD_DT3003_PGL] = {
 134                .name           = "dt3003-pgl",
 135                .adchan         = 64,
 136                .adbits         = 12,
 137                .adrange        = &range_dt3000_ai_pgl,
 138                .ai_speed       = 3000,
 139                .dachan         = 2,
 140                .dabits         = 12,
 141        },
 142        [BOARD_DT3004] = {
 143                .name           = "dt3004",
 144                .adchan         = 16,
 145                .adbits         = 16,
 146                .adrange        = &range_dt3000_ai,
 147                .ai_speed       = 10000,
 148                .dachan         = 2,
 149                .dabits         = 12,
 150        },
 151        [BOARD_DT3005] = {
 152                .name           = "dt3005",     /* a.k.a. 3004-200 */
 153                .adchan         = 16,
 154                .adbits         = 16,
 155                .adrange        = &range_dt3000_ai,
 156                .ai_speed       = 5000,
 157                .dachan         = 2,
 158                .dabits         = 12,
 159        },
 160};
 161
 162/* dual-ported RAM location definitions */
 163
 164#define DPR_DAC_buffer          (4*0x000)
 165#define DPR_ADC_buffer          (4*0x800)
 166#define DPR_Command             (4*0xfd3)
 167#define DPR_SubSys              (4*0xfd3)
 168#define DPR_Encode              (4*0xfd4)
 169#define DPR_Params(a)           (4*(0xfd5+(a)))
 170#define DPR_Tick_Reg_Lo         (4*0xff5)
 171#define DPR_Tick_Reg_Hi         (4*0xff6)
 172#define DPR_DA_Buf_Front        (4*0xff7)
 173#define DPR_DA_Buf_Rear         (4*0xff8)
 174#define DPR_AD_Buf_Front        (4*0xff9)
 175#define DPR_AD_Buf_Rear         (4*0xffa)
 176#define DPR_Int_Mask            (4*0xffb)
 177#define DPR_Intr_Flag           (4*0xffc)
 178#define DPR_Response_Mbx        (4*0xffe)
 179#define DPR_Command_Mbx         (4*0xfff)
 180
 181#define AI_FIFO_DEPTH   2003
 182#define AO_FIFO_DEPTH   2048
 183
 184/* command list */
 185
 186#define CMD_GETBRDINFO          0
 187#define CMD_CONFIG              1
 188#define CMD_GETCONFIG           2
 189#define CMD_START               3
 190#define CMD_STOP                4
 191#define CMD_READSINGLE          5
 192#define CMD_WRITESINGLE         6
 193#define CMD_CALCCLOCK           7
 194#define CMD_READEVENTS          8
 195#define CMD_WRITECTCTRL         16
 196#define CMD_READCTCTRL          17
 197#define CMD_WRITECT             18
 198#define CMD_READCT              19
 199#define CMD_WRITEDATA           32
 200#define CMD_READDATA            33
 201#define CMD_WRITEIO             34
 202#define CMD_READIO              35
 203#define CMD_WRITECODE           36
 204#define CMD_READCODE            37
 205#define CMD_EXECUTE             38
 206#define CMD_HALT                48
 207
 208#define SUBS_AI         0
 209#define SUBS_AO         1
 210#define SUBS_DIN        2
 211#define SUBS_DOUT       3
 212#define SUBS_MEM        4
 213#define SUBS_CT         5
 214
 215/* interrupt flags */
 216#define DT3000_CMDONE           0x80
 217#define DT3000_CTDONE           0x40
 218#define DT3000_DAHWERR          0x20
 219#define DT3000_DASWERR          0x10
 220#define DT3000_DAEMPTY          0x08
 221#define DT3000_ADHWERR          0x04
 222#define DT3000_ADSWERR          0x02
 223#define DT3000_ADFULL           0x01
 224
 225#define DT3000_COMPLETION_MASK  0xff00
 226#define DT3000_COMMAND_MASK     0x00ff
 227#define DT3000_NOTPROCESSED     0x0000
 228#define DT3000_NOERROR          0x5500
 229#define DT3000_ERROR            0xaa00
 230#define DT3000_NOTSUPPORTED     0xff00
 231
 232#define DT3000_EXTERNAL_CLOCK   1
 233#define DT3000_RISING_EDGE      2
 234
 235#define TMODE_MASK              0x1c
 236
 237#define DT3000_AD_TRIG_INTERNAL         (0<<2)
 238#define DT3000_AD_TRIG_EXTERNAL         (1<<2)
 239#define DT3000_AD_RETRIG_INTERNAL       (2<<2)
 240#define DT3000_AD_RETRIG_EXTERNAL       (3<<2)
 241#define DT3000_AD_EXTRETRIG             (4<<2)
 242
 243#define DT3000_CHANNEL_MODE_SE          0
 244#define DT3000_CHANNEL_MODE_DI          1
 245
 246struct dt3k_private {
 247        unsigned int lock;
 248        unsigned int ai_front;
 249        unsigned int ai_rear;
 250};
 251
 252#define TIMEOUT 100
 253
 254static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
 255{
 256        int i;
 257        unsigned int status = 0;
 258
 259        writew(cmd, dev->mmio + DPR_Command_Mbx);
 260
 261        for (i = 0; i < TIMEOUT; i++) {
 262                status = readw(dev->mmio + DPR_Command_Mbx);
 263                if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
 264                        break;
 265                udelay(1);
 266        }
 267
 268        if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
 269                dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
 270                        __func__, status);
 271}
 272
 273static unsigned int dt3k_readsingle(struct comedi_device *dev,
 274                                    unsigned int subsys, unsigned int chan,
 275                                    unsigned int gain)
 276{
 277        writew(subsys, dev->mmio + DPR_SubSys);
 278
 279        writew(chan, dev->mmio + DPR_Params(0));
 280        writew(gain, dev->mmio + DPR_Params(1));
 281
 282        dt3k_send_cmd(dev, CMD_READSINGLE);
 283
 284        return readw(dev->mmio + DPR_Params(2));
 285}
 286
 287static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
 288                             unsigned int chan, unsigned int data)
 289{
 290        writew(subsys, dev->mmio + DPR_SubSys);
 291
 292        writew(chan, dev->mmio + DPR_Params(0));
 293        writew(0, dev->mmio + DPR_Params(1));
 294        writew(data, dev->mmio + DPR_Params(2));
 295
 296        dt3k_send_cmd(dev, CMD_WRITESINGLE);
 297}
 298
 299static void dt3k_ai_empty_fifo(struct comedi_device *dev,
 300                               struct comedi_subdevice *s)
 301{
 302        struct dt3k_private *devpriv = dev->private;
 303        int front;
 304        int rear;
 305        int count;
 306        int i;
 307        unsigned short data;
 308
 309        front = readw(dev->mmio + DPR_AD_Buf_Front);
 310        count = front - devpriv->ai_front;
 311        if (count < 0)
 312                count += AI_FIFO_DEPTH;
 313
 314        rear = devpriv->ai_rear;
 315
 316        for (i = 0; i < count; i++) {
 317                data = readw(dev->mmio + DPR_ADC_buffer + rear);
 318                comedi_buf_write_samples(s, &data, 1);
 319                rear++;
 320                if (rear >= AI_FIFO_DEPTH)
 321                        rear = 0;
 322        }
 323
 324        devpriv->ai_rear = rear;
 325        writew(rear, dev->mmio + DPR_AD_Buf_Rear);
 326}
 327
 328static int dt3k_ai_cancel(struct comedi_device *dev,
 329                          struct comedi_subdevice *s)
 330{
 331        writew(SUBS_AI, dev->mmio + DPR_SubSys);
 332        dt3k_send_cmd(dev, CMD_STOP);
 333
 334        writew(0, dev->mmio + DPR_Int_Mask);
 335
 336        return 0;
 337}
 338
 339static int debug_n_ints;
 340
 341/* FIXME! Assumes shared interrupt is for this card. */
 342/* What's this debug_n_ints stuff? Obviously needs some work... */
 343static irqreturn_t dt3k_interrupt(int irq, void *d)
 344{
 345        struct comedi_device *dev = d;
 346        struct comedi_subdevice *s = dev->read_subdev;
 347        unsigned int status;
 348
 349        if (!dev->attached)
 350                return IRQ_NONE;
 351
 352        status = readw(dev->mmio + DPR_Intr_Flag);
 353
 354        if (status & DT3000_ADFULL)
 355                dt3k_ai_empty_fifo(dev, s);
 356
 357        if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
 358                s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 359
 360        debug_n_ints++;
 361        if (debug_n_ints >= 10)
 362                s->async->events |= COMEDI_CB_EOA;
 363
 364        comedi_handle_events(dev, s);
 365        return IRQ_HANDLED;
 366}
 367
 368static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
 369                            unsigned int flags)
 370{
 371        int divider, base, prescale;
 372
 373        /* This function needs improvment */
 374        /* Don't know if divider==0 works. */
 375
 376        for (prescale = 0; prescale < 16; prescale++) {
 377                base = timer_base * (prescale + 1);
 378                switch (flags & CMDF_ROUND_MASK) {
 379                case CMDF_ROUND_NEAREST:
 380                default:
 381                        divider = (*nanosec + base / 2) / base;
 382                        break;
 383                case CMDF_ROUND_DOWN:
 384                        divider = (*nanosec) / base;
 385                        break;
 386                case CMDF_ROUND_UP:
 387                        divider = (*nanosec) / base;
 388                        break;
 389                }
 390                if (divider < 65536) {
 391                        *nanosec = divider * base;
 392                        return (prescale << 16) | (divider);
 393                }
 394        }
 395
 396        prescale = 15;
 397        base = timer_base * (1 << prescale);
 398        divider = 65535;
 399        *nanosec = divider * base;
 400        return (prescale << 16) | (divider);
 401}
 402
 403static int dt3k_ai_cmdtest(struct comedi_device *dev,
 404                           struct comedi_subdevice *s, struct comedi_cmd *cmd)
 405{
 406        const struct dt3k_boardtype *this_board = dev->board_ptr;
 407        int err = 0;
 408        unsigned int arg;
 409
 410        /* Step 1 : check if triggers are trivially valid */
 411
 412        err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
 413        err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
 414        err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
 415        err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 416        err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
 417
 418        if (err)
 419                return 1;
 420
 421        /* Step 2a : make sure trigger sources are unique */
 422        /* Step 2b : and mutually compatible */
 423
 424        /* Step 3: check if arguments are trivially valid */
 425
 426        err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
 427
 428        if (cmd->scan_begin_src == TRIG_TIMER) {
 429                err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
 430                                                 this_board->ai_speed);
 431                err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
 432                                                 100 * 16 * 65535);
 433        }
 434
 435        if (cmd->convert_src == TRIG_TIMER) {
 436                err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
 437                                                 this_board->ai_speed);
 438                err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
 439                                                 50 * 16 * 65535);
 440        }
 441
 442        err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
 443
 444        if (cmd->stop_src == TRIG_COUNT)
 445                err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
 446        else    /* TRIG_NONE */
 447                err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
 448
 449        if (err)
 450                return 3;
 451
 452        /* step 4: fix up any arguments */
 453
 454        if (cmd->scan_begin_src == TRIG_TIMER) {
 455                arg = cmd->scan_begin_arg;
 456                dt3k_ns_to_timer(100, &arg, cmd->flags);
 457                err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
 458        }
 459
 460        if (cmd->convert_src == TRIG_TIMER) {
 461                arg = cmd->convert_arg;
 462                dt3k_ns_to_timer(50, &arg, cmd->flags);
 463                err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
 464
 465                if (cmd->scan_begin_src == TRIG_TIMER) {
 466                        arg = cmd->convert_arg * cmd->scan_end_arg;
 467                        err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
 468                                                         arg);
 469                }
 470        }
 471
 472        if (err)
 473                return 4;
 474
 475        return 0;
 476}
 477
 478static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 479{
 480        struct comedi_cmd *cmd = &s->async->cmd;
 481        int i;
 482        unsigned int chan, range, aref;
 483        unsigned int divider;
 484        unsigned int tscandiv;
 485
 486        for (i = 0; i < cmd->chanlist_len; i++) {
 487                chan = CR_CHAN(cmd->chanlist[i]);
 488                range = CR_RANGE(cmd->chanlist[i]);
 489
 490                writew((range << 6) | chan, dev->mmio + DPR_ADC_buffer + i);
 491        }
 492        aref = CR_AREF(cmd->chanlist[0]);
 493
 494        writew(cmd->scan_end_arg, dev->mmio + DPR_Params(0));
 495
 496        if (cmd->convert_src == TRIG_TIMER) {
 497                divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
 498                writew((divider >> 16), dev->mmio + DPR_Params(1));
 499                writew((divider & 0xffff), dev->mmio + DPR_Params(2));
 500        }
 501
 502        if (cmd->scan_begin_src == TRIG_TIMER) {
 503                tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
 504                                            cmd->flags);
 505                writew((tscandiv >> 16), dev->mmio + DPR_Params(3));
 506                writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4));
 507        }
 508
 509        writew(DT3000_AD_RETRIG_INTERNAL, dev->mmio + DPR_Params(5));
 510        writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6));
 511
 512        writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7));
 513
 514        writew(SUBS_AI, dev->mmio + DPR_SubSys);
 515        dt3k_send_cmd(dev, CMD_CONFIG);
 516
 517        writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
 518               dev->mmio + DPR_Int_Mask);
 519
 520        debug_n_ints = 0;
 521
 522        writew(SUBS_AI, dev->mmio + DPR_SubSys);
 523        dt3k_send_cmd(dev, CMD_START);
 524
 525        return 0;
 526}
 527
 528static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 529                        struct comedi_insn *insn, unsigned int *data)
 530{
 531        int i;
 532        unsigned int chan, gain, aref;
 533
 534        chan = CR_CHAN(insn->chanspec);
 535        gain = CR_RANGE(insn->chanspec);
 536        /* XXX docs don't explain how to select aref */
 537        aref = CR_AREF(insn->chanspec);
 538
 539        for (i = 0; i < insn->n; i++)
 540                data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
 541
 542        return i;
 543}
 544
 545static int dt3k_ao_insn_write(struct comedi_device *dev,
 546                              struct comedi_subdevice *s,
 547                              struct comedi_insn *insn,
 548                              unsigned int *data)
 549{
 550        unsigned int chan = CR_CHAN(insn->chanspec);
 551        unsigned int val = s->readback[chan];
 552        int i;
 553
 554        for (i = 0; i < insn->n; i++) {
 555                val = data[i];
 556                dt3k_writesingle(dev, SUBS_AO, chan, val);
 557        }
 558        s->readback[chan] = val;
 559
 560        return insn->n;
 561}
 562
 563static void dt3k_dio_config(struct comedi_device *dev, int bits)
 564{
 565        /* XXX */
 566        writew(SUBS_DOUT, dev->mmio + DPR_SubSys);
 567
 568        writew(bits, dev->mmio + DPR_Params(0));
 569#if 0
 570        /* don't know */
 571        writew(0, dev->mmio + DPR_Params(1));
 572        writew(0, dev->mmio + DPR_Params(2));
 573#endif
 574
 575        dt3k_send_cmd(dev, CMD_CONFIG);
 576}
 577
 578static int dt3k_dio_insn_config(struct comedi_device *dev,
 579                                struct comedi_subdevice *s,
 580                                struct comedi_insn *insn,
 581                                unsigned int *data)
 582{
 583        unsigned int chan = CR_CHAN(insn->chanspec);
 584        unsigned int mask;
 585        int ret;
 586
 587        if (chan < 4)
 588                mask = 0x0f;
 589        else
 590                mask = 0xf0;
 591
 592        ret = comedi_dio_insn_config(dev, s, insn, data, mask);
 593        if (ret)
 594                return ret;
 595
 596        dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
 597
 598        return insn->n;
 599}
 600
 601static int dt3k_dio_insn_bits(struct comedi_device *dev,
 602                              struct comedi_subdevice *s,
 603                              struct comedi_insn *insn,
 604                              unsigned int *data)
 605{
 606        if (comedi_dio_update_state(s, data))
 607                dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
 608
 609        data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
 610
 611        return insn->n;
 612}
 613
 614static int dt3k_mem_insn_read(struct comedi_device *dev,
 615                              struct comedi_subdevice *s,
 616                              struct comedi_insn *insn,
 617                              unsigned int *data)
 618{
 619        unsigned int addr = CR_CHAN(insn->chanspec);
 620        int i;
 621
 622        for (i = 0; i < insn->n; i++) {
 623                writew(SUBS_MEM, dev->mmio + DPR_SubSys);
 624                writew(addr, dev->mmio + DPR_Params(0));
 625                writew(1, dev->mmio + DPR_Params(1));
 626
 627                dt3k_send_cmd(dev, CMD_READCODE);
 628
 629                data[i] = readw(dev->mmio + DPR_Params(2));
 630        }
 631
 632        return i;
 633}
 634
 635static int dt3000_auto_attach(struct comedi_device *dev,
 636                              unsigned long context)
 637{
 638        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 639        const struct dt3k_boardtype *this_board = NULL;
 640        struct dt3k_private *devpriv;
 641        struct comedi_subdevice *s;
 642        int ret = 0;
 643
 644        if (context < ARRAY_SIZE(dt3k_boardtypes))
 645                this_board = &dt3k_boardtypes[context];
 646        if (!this_board)
 647                return -ENODEV;
 648        dev->board_ptr = this_board;
 649        dev->board_name = this_board->name;
 650
 651        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 652        if (!devpriv)
 653                return -ENOMEM;
 654
 655        ret = comedi_pci_enable(dev);
 656        if (ret < 0)
 657                return ret;
 658
 659        dev->mmio = pci_ioremap_bar(pcidev, 0);
 660        if (!dev->mmio)
 661                return -ENOMEM;
 662
 663        if (pcidev->irq) {
 664                ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
 665                                  dev->board_name, dev);
 666                if (ret == 0)
 667                        dev->irq = pcidev->irq;
 668        }
 669
 670        ret = comedi_alloc_subdevices(dev, 4);
 671        if (ret)
 672                return ret;
 673
 674        s = &dev->subdevices[0];
 675        /* ai subdevice */
 676        s->type         = COMEDI_SUBD_AI;
 677        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
 678        s->n_chan       = this_board->adchan;
 679        s->insn_read    = dt3k_ai_insn;
 680        s->maxdata      = (1 << this_board->adbits) - 1;
 681        s->range_table  = &range_dt3000_ai;     /* XXX */
 682        if (dev->irq) {
 683                dev->read_subdev = s;
 684                s->subdev_flags |= SDF_CMD_READ;
 685                s->len_chanlist = 512;
 686                s->do_cmd       = dt3k_ai_cmd;
 687                s->do_cmdtest   = dt3k_ai_cmdtest;
 688                s->cancel       = dt3k_ai_cancel;
 689        }
 690
 691        s = &dev->subdevices[1];
 692        /* ao subsystem */
 693        s->type         = COMEDI_SUBD_AO;
 694        s->subdev_flags = SDF_WRITABLE;
 695        s->n_chan       = 2;
 696        s->maxdata      = (1 << this_board->dabits) - 1;
 697        s->len_chanlist = 1;
 698        s->range_table  = &range_bipolar10;
 699        s->insn_write   = dt3k_ao_insn_write;
 700
 701        ret = comedi_alloc_subdev_readback(s);
 702        if (ret)
 703                return ret;
 704
 705        s = &dev->subdevices[2];
 706        /* dio subsystem */
 707        s->type         = COMEDI_SUBD_DIO;
 708        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 709        s->n_chan       = 8;
 710        s->insn_config  = dt3k_dio_insn_config;
 711        s->insn_bits    = dt3k_dio_insn_bits;
 712        s->maxdata      = 1;
 713        s->len_chanlist = 8;
 714        s->range_table  = &range_digital;
 715
 716        s = &dev->subdevices[3];
 717        /* mem subsystem */
 718        s->type         = COMEDI_SUBD_MEMORY;
 719        s->subdev_flags = SDF_READABLE;
 720        s->n_chan       = 0x1000;
 721        s->insn_read    = dt3k_mem_insn_read;
 722        s->maxdata      = 0xff;
 723        s->len_chanlist = 1;
 724        s->range_table  = &range_unknown;
 725
 726#if 0
 727        s = &dev->subdevices[4];
 728        /* proc subsystem */
 729        s->type = COMEDI_SUBD_PROC;
 730#endif
 731
 732        return 0;
 733}
 734
 735static struct comedi_driver dt3000_driver = {
 736        .driver_name    = "dt3000",
 737        .module         = THIS_MODULE,
 738        .auto_attach    = dt3000_auto_attach,
 739        .detach         = comedi_pci_detach,
 740};
 741
 742static int dt3000_pci_probe(struct pci_dev *dev,
 743                            const struct pci_device_id *id)
 744{
 745        return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
 746}
 747
 748static const struct pci_device_id dt3000_pci_table[] = {
 749        { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
 750        { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
 751        { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
 752        { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
 753        { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
 754        { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
 755        { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
 756        { 0 }
 757};
 758MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
 759
 760static struct pci_driver dt3000_pci_driver = {
 761        .name           = "dt3000",
 762        .id_table       = dt3000_pci_table,
 763        .probe          = dt3000_pci_probe,
 764        .remove         = comedi_pci_auto_unconfig,
 765};
 766module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
 767
 768MODULE_AUTHOR("Comedi http://www.comedi.org");
 769MODULE_DESCRIPTION("Comedi low-level driver");
 770MODULE_LICENSE("GPL");
 771
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.