linux/drivers/staging/comedi/drivers/dt282x.c
<<
>>
Prefs
   1/*
   2   comedi/drivers/dt282x.c
   3   Hardware driver for Data Translation DT2821 series
   4
   5   COMEDI - Linux Control and Measurement Device Interface
   6   Copyright (C) 1997-8 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: dt282x
  25Description: Data Translation DT2821 series (including DT-EZ)
  26Author: ds
  27Devices: [Data Translation] DT2821 (dt2821),
  28  DT2821-F-16SE (dt2821-f), DT2821-F-8DI (dt2821-f),
  29  DT2821-G-16SE (dt2821-f), DT2821-G-8DI (dt2821-g),
  30  DT2823 (dt2823),
  31  DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825),
  32  DT2827 (dt2827), DT2828 (dt2828), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
  33  DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
  34Status: complete
  35Updated: Wed, 22 Aug 2001 17:11:34 -0700
  36
  37Configuration options:
  38  [0] - I/O port base address
  39  [1] - IRQ
  40  [2] - DMA 1
  41  [3] - DMA 2
  42  [4] - AI jumpered for 0=single ended, 1=differential
  43  [5] - AI jumpered for 0=straight binary, 1=2's complement
  44  [6] - AO 0 jumpered for 0=straight binary, 1=2's complement
  45  [7] - AO 1 jumpered for 0=straight binary, 1=2's complement
  46  [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
  47  [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
  48        4=[-2.5,2.5]
  49  [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
  50        4=[-2.5,2.5]
  51
  52Notes:
  53  - AO commands might be broken.
  54  - If you try to run a command on both the AI and AO subdevices
  55    simultaneously, bad things will happen.  The driver needs to
  56    be fixed to check for this situation and return an error.
  57*/
  58
  59#include "../comedidev.h"
  60
  61#include <linux/gfp.h>
  62#include <linux/ioport.h>
  63#include <linux/interrupt.h>
  64#include <linux/io.h>
  65#include <asm/dma.h>
  66#include "comedi_fc.h"
  67
  68#define DEBUG
  69
  70#define DT2821_TIMEOUT          100     /* 500 us */
  71#define DT2821_SIZE 0x10
  72
  73/*
  74 *    Registers in the DT282x
  75 */
  76
  77#define DT2821_ADCSR    0x00    /* A/D Control/Status             */
  78#define DT2821_CHANCSR  0x02    /* Channel Control/Status */
  79#define DT2821_ADDAT    0x04    /* A/D data                       */
  80#define DT2821_DACSR    0x06    /* D/A Control/Status             */
  81#define DT2821_DADAT    0x08    /* D/A data                       */
  82#define DT2821_DIODAT   0x0a    /* digital data                   */
  83#define DT2821_SUPCSR   0x0c    /* Supervisor Control/Status      */
  84#define DT2821_TMRCTR   0x0e    /* Timer/Counter          */
  85
  86/*
  87 *  At power up, some registers are in a well-known state.  The
  88 *  masks and values are as follows:
  89 */
  90
  91#define DT2821_ADCSR_MASK 0xfff0
  92#define DT2821_ADCSR_VAL 0x7c00
  93
  94#define DT2821_CHANCSR_MASK 0xf0f0
  95#define DT2821_CHANCSR_VAL 0x70f0
  96
  97#define DT2821_DACSR_MASK 0x7c93
  98#define DT2821_DACSR_VAL 0x7c90
  99
 100#define DT2821_SUPCSR_MASK 0xf8ff
 101#define DT2821_SUPCSR_VAL 0x0000
 102
 103#define DT2821_TMRCTR_MASK 0xff00
 104#define DT2821_TMRCTR_VAL 0xf000
 105
 106/*
 107 *    Bit fields of each register
 108 */
 109
 110/* ADCSR */
 111
 112#define DT2821_ADERR    0x8000  /* (R)   1 for A/D error  */
 113#define DT2821_ADCLK    0x0200  /* (R/W) A/D clock enable */
 114                /*      0x7c00           read as 1's            */
 115#define DT2821_MUXBUSY  0x0100  /* (R)   multiplexer busy */
 116#define DT2821_ADDONE   0x0080  /* (R)   A/D done         */
 117#define DT2821_IADDONE  0x0040  /* (R/W) interrupt on A/D done    */
 118                /*      0x0030           gain select            */
 119                /*      0x000f           channel select         */
 120
 121/* CHANCSR */
 122
 123#define DT2821_LLE      0x8000  /* (R/W) Load List Enable */
 124                /*      0x7000           read as 1's            */
 125                /*      0x0f00     (R)   present address        */
 126                /*      0x00f0           read as 1's            */
 127                /*      0x000f     (R)   number of entries - 1  */
 128
 129/* DACSR */
 130
 131#define DT2821_DAERR    0x8000  /* (R)   D/A error                */
 132#define DT2821_YSEL     0x0200  /* (R/W) DAC 1 select             */
 133#define DT2821_SSEL     0x0100  /* (R/W) single channel select    */
 134#define DT2821_DACRDY   0x0080  /* (R)   DAC ready                */
 135#define DT2821_IDARDY   0x0040  /* (R/W) interrupt on DAC ready   */
 136#define DT2821_DACLK    0x0020  /* (R/W) D/A clock enable */
 137#define DT2821_HBOE     0x0002  /* (R/W) DIO high byte output enable      */
 138#define DT2821_LBOE     0x0001  /* (R/W) DIO low byte output enable       */
 139
 140/* SUPCSR */
 141
 142#define DT2821_DMAD     0x8000  /* (R)   DMA done                 */
 143#define DT2821_ERRINTEN 0x4000  /* (R/W) interrupt on error               */
 144#define DT2821_CLRDMADNE 0x2000 /* (W)   clear DMA done                   */
 145#define DT2821_DDMA     0x1000  /* (R/W) dual DMA                 */
 146#define DT2821_DS1      0x0800  /* (R/W) DMA select 1                     */
 147#define DT2821_DS0      0x0400  /* (R/W) DMA select 0                     */
 148#define DT2821_BUFFB    0x0200  /* (R/W) buffer B selected                */
 149#define DT2821_SCDN     0x0100  /* (R)   scan done                        */
 150#define DT2821_DACON    0x0080  /* (W)   DAC single conversion            */
 151#define DT2821_ADCINIT  0x0040  /* (W)   A/D initialize                   */
 152#define DT2821_DACINIT  0x0020  /* (W)   D/A initialize                   */
 153#define DT2821_PRLD     0x0010  /* (W)   preload multiplexer              */
 154#define DT2821_STRIG    0x0008  /* (W)   software trigger         */
 155#define DT2821_XTRIG    0x0004  /* (R/W) external trigger enable  */
 156#define DT2821_XCLK     0x0002  /* (R/W) external clock enable            */
 157#define DT2821_BDINIT   0x0001  /* (W)   initialize board         */
 158
 159static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
 160        4, {
 161                RANGE(-10, 10),
 162                RANGE(-5, 5),
 163                RANGE(-2.5, 2.5),
 164                RANGE(-1.25, 1.25)
 165        }
 166};
 167
 168static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
 169        4, {
 170                RANGE(0, 10),
 171                RANGE(0, 5),
 172                RANGE(0, 2.5),
 173                RANGE(0, 1.25)
 174        }
 175};
 176
 177static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
 178        4, {
 179                RANGE(-5, 5),
 180                RANGE(-2.5, 2.5),
 181                RANGE(-1.25, 1.25),
 182                RANGE(-0.625, 0.625)
 183        }
 184};
 185
 186static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
 187        4, {
 188                RANGE(0, 5),
 189                RANGE(0, 2.5),
 190                RANGE(0, 1.25),
 191                RANGE(0, 0.625),
 192        }
 193};
 194
 195static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
 196        4, {
 197                RANGE(-10, 10),
 198                RANGE(-1, 1),
 199                RANGE(-0.1, 0.1),
 200                RANGE(-0.02, 0.02)
 201        }
 202};
 203
 204static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
 205        4, {
 206                RANGE(0, 10),
 207                RANGE(0, 1),
 208                RANGE(0, 0.1),
 209                RANGE(0, 0.02)
 210        }
 211};
 212
 213struct dt282x_board {
 214        const char *name;
 215        int adbits;
 216        int adchan_se;
 217        int adchan_di;
 218        int ai_speed;
 219        int ispgl;
 220        int dachan;
 221        int dabits;
 222};
 223
 224struct dt282x_private {
 225        int ad_2scomp;          /* we have 2's comp jumper set  */
 226        int da0_2scomp;         /* same, for DAC0               */
 227        int da1_2scomp;         /* same, for DAC1               */
 228
 229        const struct comedi_lrange *darangelist[2];
 230
 231        short ao[2];
 232
 233        volatile int dacsr;     /* software copies of registers */
 234        volatile int adcsr;
 235        volatile int supcsr;
 236
 237        volatile int ntrig;
 238        volatile int nread;
 239
 240        struct {
 241                int chan;
 242                short *buf;     /* DMA buffer */
 243                volatile int size;      /* size of current transfer */
 244        } dma[2];
 245        int dma_maxsize;        /* max size of DMA transfer (in bytes) */
 246        int usedma;             /* driver uses DMA              */
 247        volatile int current_dma_index;
 248        int dma_dir;
 249};
 250
 251/*
 252 *    Some useless abstractions
 253 */
 254#define chan_to_DAC(a)  ((a)&1)
 255#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
 256#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
 257
 258/*
 259 *    danger! macro abuse... a is the expression to wait on, and b is
 260 *      the statement(s) to execute if it doesn't happen.
 261 */
 262#define wait_for(a, b)                                          \
 263        do {                                                    \
 264                int _i;                                         \
 265                for (_i = 0; _i < DT2821_TIMEOUT; _i++) {       \
 266                        if (a) {                                \
 267                                _i = 0;                         \
 268                                break;                          \
 269                        }                                       \
 270                        udelay(5);                              \
 271                }                                               \
 272                if (_i) {                                       \
 273                        b                                       \
 274                }                                               \
 275        } while (0)
 276
 277static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
 278static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
 279static int dt282x_ai_cancel(struct comedi_device *dev,
 280                            struct comedi_subdevice *s);
 281static int dt282x_ao_cancel(struct comedi_device *dev,
 282                            struct comedi_subdevice *s);
 283static int dt282x_ns_to_timer(int *nanosec, int round_mode);
 284static void dt282x_disable_dma(struct comedi_device *dev);
 285
 286static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
 287
 288static void dt282x_munge(struct comedi_device *dev, short *buf,
 289                         unsigned int nbytes)
 290{
 291        const struct dt282x_board *board = comedi_board(dev);
 292        struct dt282x_private *devpriv = dev->private;
 293        unsigned int i;
 294        unsigned short mask = (1 << board->adbits) - 1;
 295        unsigned short sign = 1 << (board->adbits - 1);
 296        int n;
 297
 298        if (devpriv->ad_2scomp)
 299                sign = 1 << (board->adbits - 1);
 300        else
 301                sign = 0;
 302
 303        if (nbytes % 2)
 304                comedi_error(dev, "bug! odd number of bytes from dma xfer");
 305        n = nbytes / 2;
 306        for (i = 0; i < n; i++)
 307                buf[i] = (buf[i] & mask) ^ sign;
 308}
 309
 310static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
 311{
 312        struct dt282x_private *devpriv = dev->private;
 313        void *ptr;
 314        int size;
 315        int i;
 316        struct comedi_subdevice *s = &dev->subdevices[1];
 317
 318        outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
 319
 320        if (!s->async->prealloc_buf) {
 321                printk(KERN_ERR "async->data disappeared.  dang!\n");
 322                return;
 323        }
 324
 325        i = devpriv->current_dma_index;
 326        ptr = devpriv->dma[i].buf;
 327
 328        disable_dma(devpriv->dma[i].chan);
 329
 330        devpriv->current_dma_index = 1 - i;
 331
 332        size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
 333        if (size == 0) {
 334                printk(KERN_ERR "dt282x: AO underrun\n");
 335                dt282x_ao_cancel(dev, s);
 336                s->async->events |= COMEDI_CB_OVERFLOW;
 337                return;
 338        }
 339        prep_ao_dma(dev, i, size);
 340        return;
 341}
 342
 343static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
 344{
 345        struct dt282x_private *devpriv = dev->private;
 346        void *ptr;
 347        int size;
 348        int i;
 349        int ret;
 350        struct comedi_subdevice *s = &dev->subdevices[0];
 351
 352        outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
 353
 354        if (!s->async->prealloc_buf) {
 355                printk(KERN_ERR "async->data disappeared.  dang!\n");
 356                return;
 357        }
 358
 359        i = devpriv->current_dma_index;
 360        ptr = devpriv->dma[i].buf;
 361        size = devpriv->dma[i].size;
 362
 363        disable_dma(devpriv->dma[i].chan);
 364
 365        devpriv->current_dma_index = 1 - i;
 366
 367        dt282x_munge(dev, ptr, size);
 368        ret = cfc_write_array_to_buffer(s, ptr, size);
 369        if (ret != size) {
 370                dt282x_ai_cancel(dev, s);
 371                return;
 372        }
 373        devpriv->nread -= size / 2;
 374
 375        if (devpriv->nread < 0) {
 376                printk(KERN_INFO "dt282x: off by one\n");
 377                devpriv->nread = 0;
 378        }
 379        if (!devpriv->nread) {
 380                dt282x_ai_cancel(dev, s);
 381                s->async->events |= COMEDI_CB_EOA;
 382                return;
 383        }
 384#if 0
 385        /* clear the dual dma flag, making this the last dma segment */
 386        /* XXX probably wrong */
 387        if (!devpriv->ntrig) {
 388                devpriv->supcsr &= ~(DT2821_DDMA);
 389                outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
 390        }
 391#endif
 392        /* restart the channel */
 393        prep_ai_dma(dev, i, 0);
 394}
 395
 396static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
 397{
 398        struct dt282x_private *devpriv = dev->private;
 399        int dma_chan;
 400        unsigned long dma_ptr;
 401        unsigned long flags;
 402
 403        if (!devpriv->ntrig)
 404                return 0;
 405
 406        if (n == 0)
 407                n = devpriv->dma_maxsize;
 408        if (n > devpriv->ntrig * 2)
 409                n = devpriv->ntrig * 2;
 410        devpriv->ntrig -= n / 2;
 411
 412        devpriv->dma[dma_index].size = n;
 413        dma_chan = devpriv->dma[dma_index].chan;
 414        dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
 415
 416        set_dma_mode(dma_chan, DMA_MODE_READ);
 417        flags = claim_dma_lock();
 418        clear_dma_ff(dma_chan);
 419        set_dma_addr(dma_chan, dma_ptr);
 420        set_dma_count(dma_chan, n);
 421        release_dma_lock(flags);
 422
 423        enable_dma(dma_chan);
 424
 425        return n;
 426}
 427
 428static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
 429{
 430        struct dt282x_private *devpriv = dev->private;
 431        int dma_chan;
 432        unsigned long dma_ptr;
 433        unsigned long flags;
 434
 435        devpriv->dma[dma_index].size = n;
 436        dma_chan = devpriv->dma[dma_index].chan;
 437        dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
 438
 439        set_dma_mode(dma_chan, DMA_MODE_WRITE);
 440        flags = claim_dma_lock();
 441        clear_dma_ff(dma_chan);
 442        set_dma_addr(dma_chan, dma_ptr);
 443        set_dma_count(dma_chan, n);
 444        release_dma_lock(flags);
 445
 446        enable_dma(dma_chan);
 447
 448        return n;
 449}
 450
 451static irqreturn_t dt282x_interrupt(int irq, void *d)
 452{
 453        struct comedi_device *dev = d;
 454        struct dt282x_private *devpriv = dev->private;
 455        struct comedi_subdevice *s;
 456        struct comedi_subdevice *s_ao;
 457        unsigned int supcsr, adcsr, dacsr;
 458        int handled = 0;
 459
 460        if (!dev->attached) {
 461                comedi_error(dev, "spurious interrupt");
 462                return IRQ_HANDLED;
 463        }
 464
 465        s = &dev->subdevices[0];
 466        s_ao = &dev->subdevices[1];
 467        adcsr = inw(dev->iobase + DT2821_ADCSR);
 468        dacsr = inw(dev->iobase + DT2821_DACSR);
 469        supcsr = inw(dev->iobase + DT2821_SUPCSR);
 470        if (supcsr & DT2821_DMAD) {
 471                if (devpriv->dma_dir == DMA_MODE_READ)
 472                        dt282x_ai_dma_interrupt(dev);
 473                else
 474                        dt282x_ao_dma_interrupt(dev);
 475                handled = 1;
 476        }
 477        if (adcsr & DT2821_ADERR) {
 478                if (devpriv->nread != 0) {
 479                        comedi_error(dev, "A/D error");
 480                        dt282x_ai_cancel(dev, s);
 481                        s->async->events |= COMEDI_CB_ERROR;
 482                }
 483                handled = 1;
 484        }
 485        if (dacsr & DT2821_DAERR) {
 486#if 0
 487                static int warn = 5;
 488                if (--warn <= 0) {
 489                        disable_irq(dev->irq);
 490                        printk(KERN_INFO "disabling irq\n");
 491                }
 492#endif
 493                comedi_error(dev, "D/A error");
 494                dt282x_ao_cancel(dev, s_ao);
 495                s->async->events |= COMEDI_CB_ERROR;
 496                handled = 1;
 497        }
 498#if 0
 499        if (adcsr & DT2821_ADDONE) {
 500                int ret;
 501                short data;
 502
 503                data = (short)inw(dev->iobase + DT2821_ADDAT);
 504                data &= (1 << board->adbits) - 1;
 505
 506                if (devpriv->ad_2scomp)
 507                        data ^= 1 << (board->adbits - 1);
 508                ret = comedi_buf_put(s->async, data);
 509
 510                if (ret == 0)
 511                        s->async->events |= COMEDI_CB_OVERFLOW;
 512
 513                devpriv->nread--;
 514                if (!devpriv->nread) {
 515                        s->async->events |= COMEDI_CB_EOA;
 516                } else {
 517                        if (supcsr & DT2821_SCDN)
 518                                outw(devpriv->supcsr | DT2821_STRIG,
 519                                        dev->iobase + DT2821_SUPCSR);
 520                }
 521                handled = 1;
 522        }
 523#endif
 524        comedi_event(dev, s);
 525        /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
 526                adcsr, dacsr, supcsr); */
 527        return IRQ_RETVAL(handled);
 528}
 529
 530static void dt282x_load_changain(struct comedi_device *dev, int n,
 531                                 unsigned int *chanlist)
 532{
 533        struct dt282x_private *devpriv = dev->private;
 534        unsigned int i;
 535        unsigned int chan, range;
 536
 537        outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
 538        for (i = 0; i < n; i++) {
 539                chan = CR_CHAN(chanlist[i]);
 540                range = CR_RANGE(chanlist[i]);
 541                outw(devpriv->adcsr | (range << 4) | chan,
 542                        dev->iobase + DT2821_ADCSR);
 543        }
 544        outw(n - 1, dev->iobase + DT2821_CHANCSR);
 545}
 546
 547/*
 548 *    Performs a single A/D conversion.
 549 *      - Put channel/gain into channel-gain list
 550 *      - preload multiplexer
 551 *      - trigger conversion and wait for it to finish
 552 */
 553static int dt282x_ai_insn_read(struct comedi_device *dev,
 554                               struct comedi_subdevice *s,
 555                               struct comedi_insn *insn, unsigned int *data)
 556{
 557        const struct dt282x_board *board = comedi_board(dev);
 558        struct dt282x_private *devpriv = dev->private;
 559        int i;
 560
 561        /* XXX should we really be enabling the ad clock here? */
 562        devpriv->adcsr = DT2821_ADCLK;
 563        outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
 564
 565        dt282x_load_changain(dev, 1, &insn->chanspec);
 566
 567        outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
 568        wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
 569
 570        for (i = 0; i < insn->n; i++) {
 571                outw(devpriv->supcsr | DT2821_STRIG,
 572                        dev->iobase + DT2821_SUPCSR);
 573                wait_for(ad_done(), comedi_error(dev, "timeout\n");
 574                         return -ETIME;);
 575
 576                data[i] =
 577                    inw(dev->iobase +
 578                        DT2821_ADDAT) & ((1 << board->adbits) - 1);
 579                if (devpriv->ad_2scomp)
 580                        data[i] ^= (1 << (board->adbits - 1));
 581        }
 582
 583        return i;
 584}
 585
 586static int dt282x_ai_cmdtest(struct comedi_device *dev,
 587                             struct comedi_subdevice *s, struct comedi_cmd *cmd)
 588{
 589        const struct dt282x_board *board = comedi_board(dev);
 590        int err = 0;
 591        int tmp;
 592
 593        /* Step 1 : check if triggers are trivially valid */
 594
 595        err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
 596        err |= cfc_check_trigger_src(&cmd->scan_begin_src,
 597                                        TRIG_FOLLOW | TRIG_EXT);
 598        err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
 599        err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 600        err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 601
 602        if (err)
 603                return 1;
 604
 605        /* Step 2a : make sure trigger sources are unique */
 606
 607        err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
 608        err |= cfc_check_trigger_is_unique(cmd->stop_src);
 609
 610        /* Step 2b : and mutually compatible */
 611
 612        if (err)
 613                return 2;
 614
 615        /* Step 3: check if arguments are trivially valid */
 616
 617        err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
 618
 619        if (cmd->scan_begin_src == TRIG_FOLLOW) {
 620                /* internal trigger */
 621                err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 622        } else {
 623                /* external trigger */
 624                /* should be level/edge, hi/lo specification here */
 625                err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 626        }
 627
 628        err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
 629
 630#define SLOWEST_TIMER   (250*(1<<15)*255)
 631        err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
 632        err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
 633        err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
 634
 635        if (cmd->stop_src == TRIG_COUNT) {
 636                /* any count is allowed */
 637        } else {        /* TRIG_NONE */
 638                err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
 639        }
 640
 641        if (err)
 642                return 3;
 643
 644        /* step 4: fix up any arguments */
 645
 646        tmp = cmd->convert_arg;
 647        dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
 648        if (tmp != cmd->convert_arg)
 649                err++;
 650
 651        if (err)
 652                return 4;
 653
 654        return 0;
 655}
 656
 657static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 658{
 659        const struct dt282x_board *board = comedi_board(dev);
 660        struct dt282x_private *devpriv = dev->private;
 661        struct comedi_cmd *cmd = &s->async->cmd;
 662        int timer;
 663
 664        if (devpriv->usedma == 0) {
 665                comedi_error(dev,
 666                             "driver requires 2 dma channels"
 667                                                " to execute command");
 668                return -EIO;
 669        }
 670
 671        dt282x_disable_dma(dev);
 672
 673        if (cmd->convert_arg < board->ai_speed)
 674                cmd->convert_arg = board->ai_speed;
 675        timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
 676        outw(timer, dev->iobase + DT2821_TMRCTR);
 677
 678        if (cmd->scan_begin_src == TRIG_FOLLOW) {
 679                /* internal trigger */
 680                devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
 681        } else {
 682                /* external trigger */
 683                devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
 684        }
 685        outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT,
 686                dev->iobase + DT2821_SUPCSR);
 687
 688        devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
 689        devpriv->nread = devpriv->ntrig;
 690
 691        devpriv->dma_dir = DMA_MODE_READ;
 692        devpriv->current_dma_index = 0;
 693        prep_ai_dma(dev, 0, 0);
 694        if (devpriv->ntrig) {
 695                prep_ai_dma(dev, 1, 0);
 696                devpriv->supcsr |= DT2821_DDMA;
 697                outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
 698        }
 699
 700        devpriv->adcsr = 0;
 701
 702        dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
 703
 704        devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
 705        outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
 706
 707        outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
 708        wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
 709
 710        if (cmd->scan_begin_src == TRIG_FOLLOW) {
 711                outw(devpriv->supcsr | DT2821_STRIG,
 712                        dev->iobase + DT2821_SUPCSR);
 713        } else {
 714                devpriv->supcsr |= DT2821_XTRIG;
 715                outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
 716        }
 717
 718        return 0;
 719}
 720
 721static void dt282x_disable_dma(struct comedi_device *dev)
 722{
 723        struct dt282x_private *devpriv = dev->private;
 724
 725        if (devpriv->usedma) {
 726                disable_dma(devpriv->dma[0].chan);
 727                disable_dma(devpriv->dma[1].chan);
 728        }
 729}
 730
 731static int dt282x_ai_cancel(struct comedi_device *dev,
 732                            struct comedi_subdevice *s)
 733{
 734        struct dt282x_private *devpriv = dev->private;
 735
 736        dt282x_disable_dma(dev);
 737
 738        devpriv->adcsr = 0;
 739        outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
 740
 741        devpriv->supcsr = 0;
 742        outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR);
 743
 744        return 0;
 745}
 746
 747static int dt282x_ns_to_timer(int *nanosec, int round_mode)
 748{
 749        int prescale, base, divider;
 750
 751        for (prescale = 0; prescale < 16; prescale++) {
 752                if (prescale == 1)
 753                        continue;
 754                base = 250 * (1 << prescale);
 755                switch (round_mode) {
 756                case TRIG_ROUND_NEAREST:
 757                default:
 758                        divider = (*nanosec + base / 2) / base;
 759                        break;
 760                case TRIG_ROUND_DOWN:
 761                        divider = (*nanosec) / base;
 762                        break;
 763                case TRIG_ROUND_UP:
 764                        divider = (*nanosec + base - 1) / base;
 765                        break;
 766                }
 767                if (divider < 256) {
 768                        *nanosec = divider * base;
 769                        return (prescale << 8) | (255 - divider);
 770                }
 771        }
 772        base = 250 * (1 << 15);
 773        divider = 255;
 774        *nanosec = divider * base;
 775        return (15 << 8) | (255 - divider);
 776}
 777
 778/*
 779 *    Analog output routine.  Selects single channel conversion,
 780 *      selects correct channel, converts from 2's compliment to
 781 *      offset binary if necessary, loads the data into the DAC
 782 *      data register, and performs the conversion.
 783 */
 784static int dt282x_ao_insn_read(struct comedi_device *dev,
 785                               struct comedi_subdevice *s,
 786                               struct comedi_insn *insn, unsigned int *data)
 787{
 788        struct dt282x_private *devpriv = dev->private;
 789
 790        data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
 791
 792        return 1;
 793}
 794
 795static int dt282x_ao_insn_write(struct comedi_device *dev,
 796                                struct comedi_subdevice *s,
 797                                struct comedi_insn *insn, unsigned int *data)
 798{
 799        const struct dt282x_board *board = comedi_board(dev);
 800        struct dt282x_private *devpriv = dev->private;
 801        short d;
 802        unsigned int chan;
 803
 804        chan = CR_CHAN(insn->chanspec);
 805        d = data[0];
 806        d &= (1 << board->dabits) - 1;
 807        devpriv->ao[chan] = d;
 808
 809        devpriv->dacsr |= DT2821_SSEL;
 810
 811        if (chan) {
 812                /* select channel */
 813                devpriv->dacsr |= DT2821_YSEL;
 814                if (devpriv->da0_2scomp)
 815                        d ^= (1 << (board->dabits - 1));
 816        } else {
 817                devpriv->dacsr &= ~DT2821_YSEL;
 818                if (devpriv->da1_2scomp)
 819                        d ^= (1 << (board->dabits - 1));
 820        }
 821
 822        outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
 823
 824        outw(d, dev->iobase + DT2821_DADAT);
 825
 826        outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR);
 827
 828        return 1;
 829}
 830
 831static int dt282x_ao_cmdtest(struct comedi_device *dev,
 832                             struct comedi_subdevice *s, struct comedi_cmd *cmd)
 833{
 834        int err = 0;
 835        int tmp;
 836
 837        /* Step 1 : check if triggers are trivially valid */
 838
 839        err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
 840        err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
 841        err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
 842        err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 843        err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 844
 845        if (err)
 846                return 1;
 847
 848        /* Step 2a : make sure trigger sources are unique */
 849
 850        err |= cfc_check_trigger_is_unique(cmd->stop_src);
 851
 852        /* Step 2b : and mutually compatible */
 853
 854        if (err)
 855                return 2;
 856
 857        /* Step 3: check if arguments are trivially valid */
 858
 859        err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
 860        err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
 861        err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
 862        err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2);
 863
 864        if (cmd->stop_src == TRIG_COUNT) {
 865                /* any count is allowed */
 866        } else {        /* TRIG_NONE */
 867                err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
 868        }
 869
 870        if (err)
 871                return 3;
 872
 873        /* step 4: fix up any arguments */
 874
 875        tmp = cmd->scan_begin_arg;
 876        dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
 877        if (tmp != cmd->scan_begin_arg)
 878                err++;
 879
 880        if (err)
 881                return 4;
 882
 883        return 0;
 884
 885}
 886
 887static int dt282x_ao_inttrig(struct comedi_device *dev,
 888                             struct comedi_subdevice *s, unsigned int x)
 889{
 890        struct dt282x_private *devpriv = dev->private;
 891        int size;
 892
 893        if (x != 0)
 894                return -EINVAL;
 895
 896        size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
 897                                          devpriv->dma_maxsize);
 898        if (size == 0) {
 899                printk(KERN_ERR "dt282x: AO underrun\n");
 900                return -EPIPE;
 901        }
 902        prep_ao_dma(dev, 0, size);
 903
 904        size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
 905                                          devpriv->dma_maxsize);
 906        if (size == 0) {
 907                printk(KERN_ERR "dt282x: AO underrun\n");
 908                return -EPIPE;
 909        }
 910        prep_ao_dma(dev, 1, size);
 911
 912        outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR);
 913        s->async->inttrig = NULL;
 914
 915        return 1;
 916}
 917
 918static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 919{
 920        struct dt282x_private *devpriv = dev->private;
 921        int timer;
 922        struct comedi_cmd *cmd = &s->async->cmd;
 923
 924        if (devpriv->usedma == 0) {
 925                comedi_error(dev,
 926                             "driver requires 2 dma channels"
 927                                                " to execute command");
 928                return -EIO;
 929        }
 930
 931        dt282x_disable_dma(dev);
 932
 933        devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
 934        outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT,
 935                dev->iobase + DT2821_SUPCSR);
 936
 937        devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
 938        devpriv->nread = devpriv->ntrig;
 939
 940        devpriv->dma_dir = DMA_MODE_WRITE;
 941        devpriv->current_dma_index = 0;
 942
 943        timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
 944        outw(timer, dev->iobase + DT2821_TMRCTR);
 945
 946        devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
 947        outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
 948
 949        s->async->inttrig = dt282x_ao_inttrig;
 950
 951        return 0;
 952}
 953
 954static int dt282x_ao_cancel(struct comedi_device *dev,
 955                            struct comedi_subdevice *s)
 956{
 957        struct dt282x_private *devpriv = dev->private;
 958
 959        dt282x_disable_dma(dev);
 960
 961        devpriv->dacsr = 0;
 962        outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
 963
 964        devpriv->supcsr = 0;
 965        outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR);
 966
 967        return 0;
 968}
 969
 970static int dt282x_dio_insn_bits(struct comedi_device *dev,
 971                                struct comedi_subdevice *s,
 972                                struct comedi_insn *insn, unsigned int *data)
 973{
 974        if (data[0]) {
 975                s->state &= ~data[0];
 976                s->state |= (data[0] & data[1]);
 977
 978                outw(s->state, dev->iobase + DT2821_DIODAT);
 979        }
 980        data[1] = inw(dev->iobase + DT2821_DIODAT);
 981
 982        return insn->n;
 983}
 984
 985static int dt282x_dio_insn_config(struct comedi_device *dev,
 986                                  struct comedi_subdevice *s,
 987                                  struct comedi_insn *insn, unsigned int *data)
 988{
 989        struct dt282x_private *devpriv = dev->private;
 990        int mask;
 991
 992        mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
 993        if (data[0])
 994                s->io_bits |= mask;
 995        else
 996                s->io_bits &= ~mask;
 997
 998        if (s->io_bits & 0x00ff)
 999                devpriv->dacsr |= DT2821_LBOE;
1000        else
1001                devpriv->dacsr &= ~DT2821_LBOE;
1002        if (s->io_bits & 0xff00)
1003                devpriv->dacsr |= DT2821_HBOE;
1004        else
1005                devpriv->dacsr &= ~DT2821_HBOE;
1006
1007        outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1008
1009        return 1;
1010}
1011
1012static const struct comedi_lrange *const ai_range_table[] = {
1013        &range_dt282x_ai_lo_bipolar,
1014        &range_dt282x_ai_lo_unipolar,
1015        &range_dt282x_ai_5_bipolar,
1016        &range_dt282x_ai_5_unipolar
1017};
1018
1019static const struct comedi_lrange *const ai_range_pgl_table[] = {
1020        &range_dt282x_ai_hi_bipolar,
1021        &range_dt282x_ai_hi_unipolar
1022};
1023
1024static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1025{
1026        if (ispgl) {
1027                if (x < 0 || x >= 2)
1028                        x = 0;
1029                return ai_range_pgl_table[x];
1030        } else {
1031                if (x < 0 || x >= 4)
1032                        x = 0;
1033                return ai_range_table[x];
1034        }
1035}
1036
1037static const struct comedi_lrange *const ao_range_table[] = {
1038        &range_bipolar10,
1039        &range_unipolar10,
1040        &range_bipolar5,
1041        &range_unipolar5,
1042        &range_bipolar2_5
1043};
1044
1045static const struct comedi_lrange *opt_ao_range_lkup(int x)
1046{
1047        if (x < 0 || x >= 5)
1048                x = 0;
1049        return ao_range_table[x];
1050}
1051
1052enum {  /* i/o base, irq, dma channels */
1053        opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1054        opt_diff,               /* differential */
1055        opt_ai_twos, opt_ao0_twos, opt_ao1_twos,        /* twos comp */
1056        opt_ai_range, opt_ao0_range, opt_ao1_range,     /* range */
1057};
1058
1059static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1060{
1061        struct dt282x_private *devpriv = dev->private;
1062        int ret;
1063
1064        devpriv->usedma = 0;
1065
1066        if (!dma1 && !dma2) {
1067                printk(KERN_ERR " (no dma)");
1068                return 0;
1069        }
1070
1071        if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1072                return -EINVAL;
1073
1074        if (dma2 < dma1) {
1075                int i;
1076                i = dma1;
1077                dma1 = dma2;
1078                dma2 = i;
1079        }
1080
1081        ret = request_dma(dma1, "dt282x A");
1082        if (ret)
1083                return -EBUSY;
1084        devpriv->dma[0].chan = dma1;
1085
1086        ret = request_dma(dma2, "dt282x B");
1087        if (ret)
1088                return -EBUSY;
1089        devpriv->dma[1].chan = dma2;
1090
1091        devpriv->dma_maxsize = PAGE_SIZE;
1092        devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1093        devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1094        if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1095                printk(KERN_ERR " can't get DMA memory");
1096                return -ENOMEM;
1097        }
1098
1099        printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1100
1101        devpriv->usedma = 1;
1102
1103        return 0;
1104}
1105
1106/*
1107   options:
1108   0    i/o base
1109   1    irq
1110   2    dma1
1111   3    dma2
1112   4    0=single ended, 1=differential
1113   5    ai 0=straight binary, 1=2's comp
1114   6    ao0 0=straight binary, 1=2's comp
1115   7    ao1 0=straight binary, 1=2's comp
1116   8    ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1117   9    ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1118   10   ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1119 */
1120static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1121{
1122        const struct dt282x_board *board = comedi_board(dev);
1123        struct dt282x_private *devpriv;
1124        int i, irq;
1125        int ret;
1126        struct comedi_subdevice *s;
1127
1128        ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
1129        if (ret)
1130                return ret;
1131
1132        outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1133        i = inw(dev->iobase + DT2821_ADCSR);
1134#ifdef DEBUG
1135        printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1136               inw(dev->iobase + DT2821_ADCSR),
1137               inw(dev->iobase + DT2821_CHANCSR),
1138               inw(dev->iobase + DT2821_DACSR),
1139               inw(dev->iobase + DT2821_SUPCSR),
1140               inw(dev->iobase + DT2821_TMRCTR));
1141#endif
1142
1143        if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1144             != DT2821_ADCSR_VAL) ||
1145            ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1146             != DT2821_CHANCSR_VAL) ||
1147            ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1148             != DT2821_DACSR_VAL) ||
1149            ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1150             != DT2821_SUPCSR_VAL) ||
1151            ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1152             != DT2821_TMRCTR_VAL)) {
1153                printk(KERN_ERR " board not found");
1154                return -EIO;
1155        }
1156        /* should do board test */
1157
1158        irq = it->options[opt_irq];
1159#if 0
1160        if (irq < 0) {
1161                unsigned long flags;
1162                int irqs;
1163
1164                save_flags(flags);
1165                sti();
1166                irqs = probe_irq_on();
1167
1168                /* trigger interrupt */
1169
1170                udelay(100);
1171
1172                irq = probe_irq_off(irqs);
1173                restore_flags(flags);
1174                if (0 /* error */)
1175                        printk(KERN_ERR " error probing irq (bad)");
1176        }
1177#endif
1178        if (irq > 0) {
1179                printk(KERN_INFO " ( irq = %d )", irq);
1180                ret = request_irq(irq, dt282x_interrupt, 0,
1181                                  dev->board_name, dev);
1182                if (ret < 0) {
1183                        printk(KERN_ERR " failed to get irq\n");
1184                        return -EIO;
1185                }
1186                dev->irq = irq;
1187        } else if (irq == 0) {
1188                printk(KERN_INFO " (no irq)");
1189        } else {
1190#if 0
1191                printk(KERN_INFO " (probe returned multiple irqs--bad)");
1192#else
1193                printk(KERN_INFO " (irq probe not implemented)");
1194#endif
1195        }
1196
1197        devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1198        if (!devpriv)
1199                return -ENOMEM;
1200        dev->private = devpriv;
1201
1202        ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1203                              it->options[opt_dma2]);
1204        if (ret < 0)
1205                return ret;
1206
1207        ret = comedi_alloc_subdevices(dev, 3);
1208        if (ret)
1209                return ret;
1210
1211        s = &dev->subdevices[0];
1212
1213        dev->read_subdev = s;
1214        /* ai subdevice */
1215        s->type = COMEDI_SUBD_AI;
1216        s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1217            ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1218        s->n_chan =
1219            (it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
1220        s->insn_read = dt282x_ai_insn_read;
1221        s->do_cmdtest = dt282x_ai_cmdtest;
1222        s->do_cmd = dt282x_ai_cmd;
1223        s->cancel = dt282x_ai_cancel;
1224        s->maxdata = (1 << board->adbits) - 1;
1225        s->len_chanlist = 16;
1226        s->range_table =
1227            opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
1228        devpriv->ad_2scomp = it->options[opt_ai_twos];
1229
1230        s = &dev->subdevices[1];
1231
1232        s->n_chan = board->dachan;
1233        if (s->n_chan) {
1234                /* ao subsystem */
1235                s->type = COMEDI_SUBD_AO;
1236                dev->write_subdev = s;
1237                s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1238                s->insn_read = dt282x_ao_insn_read;
1239                s->insn_write = dt282x_ao_insn_write;
1240                s->do_cmdtest = dt282x_ao_cmdtest;
1241                s->do_cmd = dt282x_ao_cmd;
1242                s->cancel = dt282x_ao_cancel;
1243                s->maxdata = (1 << board->dabits) - 1;
1244                s->len_chanlist = 2;
1245                s->range_table_list = devpriv->darangelist;
1246                devpriv->darangelist[0] =
1247                    opt_ao_range_lkup(it->options[opt_ao0_range]);
1248                devpriv->darangelist[1] =
1249                    opt_ao_range_lkup(it->options[opt_ao1_range]);
1250                devpriv->da0_2scomp = it->options[opt_ao0_twos];
1251                devpriv->da1_2scomp = it->options[opt_ao1_twos];
1252        } else {
1253                s->type = COMEDI_SUBD_UNUSED;
1254        }
1255
1256        s = &dev->subdevices[2];
1257        /* dio subsystem */
1258        s->type = COMEDI_SUBD_DIO;
1259        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1260        s->n_chan = 16;
1261        s->insn_bits = dt282x_dio_insn_bits;
1262        s->insn_config = dt282x_dio_insn_config;
1263        s->maxdata = 1;
1264        s->range_table = &range_digital;
1265
1266        printk(KERN_INFO "\n");
1267
1268        return 0;
1269}
1270
1271static void dt282x_detach(struct comedi_device *dev)
1272{
1273        struct dt282x_private *devpriv = dev->private;
1274
1275        if (dev->private) {
1276                if (devpriv->dma[0].chan)
1277                        free_dma(devpriv->dma[0].chan);
1278                if (devpriv->dma[1].chan)
1279                        free_dma(devpriv->dma[1].chan);
1280                if (devpriv->dma[0].buf)
1281                        free_page((unsigned long)devpriv->dma[0].buf);
1282                if (devpriv->dma[1].buf)
1283                        free_page((unsigned long)devpriv->dma[1].buf);
1284        }
1285        comedi_legacy_detach(dev);
1286}
1287
1288static const struct dt282x_board boardtypes[] = {
1289        {
1290                .name           = "dt2821",
1291                .adbits         = 12,
1292                .adchan_se      = 16,
1293                .adchan_di      = 8,
1294                .ai_speed       = 20000,
1295                .ispgl          = 0,
1296                .dachan         = 2,
1297                .dabits         = 12,
1298        }, {
1299                .name           = "dt2821-f",
1300                .adbits         = 12,
1301                .adchan_se      = 16,
1302                .adchan_di      = 8,
1303                .ai_speed       = 6500,
1304                .ispgl          = 0,
1305                .dachan         = 2,
1306                .dabits         = 12,
1307        }, {
1308                .name           = "dt2821-g",
1309                .adbits         = 12,
1310                .adchan_se      = 16,
1311                .adchan_di      = 8,
1312                .ai_speed       = 4000,
1313                .ispgl          = 0,
1314                .dachan         = 2,
1315                .dabits         = 12,
1316        }, {
1317                .name           = "dt2823",
1318                .adbits         = 16,
1319                .adchan_se      = 0,
1320                .adchan_di      = 4,
1321                .ai_speed       = 10000,
1322                .ispgl          = 0,
1323                .dachan         = 2,
1324                .dabits         = 16,
1325        }, {
1326                .name           = "dt2824-pgh",
1327                .adbits         = 12,
1328                .adchan_se      = 16,
1329                .adchan_di      = 8,
1330                .ai_speed       = 20000,
1331                .ispgl          = 0,
1332                .dachan         = 0,
1333                .dabits         = 0,
1334        }, {
1335                .name           = "dt2824-pgl",
1336                .adbits         = 12,
1337                .adchan_se      = 16,
1338                .adchan_di      = 8,
1339                .ai_speed       = 20000,
1340                .ispgl          = 1,
1341                .dachan         = 0,
1342                .dabits         = 0,
1343        }, {
1344                .name           = "dt2825",
1345                .adbits         = 12,
1346                .adchan_se      = 16,
1347                .adchan_di      = 8,
1348                .ai_speed       = 20000,
1349                .ispgl          = 1,
1350                .dachan         = 2,
1351                .dabits         = 12,
1352        }, {
1353                .name           = "dt2827",
1354                .adbits         = 16,
1355                .adchan_se      = 0,
1356                .adchan_di      = 4,
1357                .ai_speed       = 10000,
1358                .ispgl          = 0,
1359                .dachan         = 2,
1360                .dabits         = 12,
1361        }, {
1362                .name           = "dt2828",
1363                .adbits         = 12,
1364                .adchan_se      = 4,
1365                .adchan_di      = 0,
1366                .ai_speed       = 10000,
1367                .ispgl          = 0,
1368                .dachan         = 2,
1369                .dabits         = 12,
1370        }, {
1371                .name           = "dt2829",
1372                .adbits         = 16,
1373                .adchan_se      = 8,
1374                .adchan_di      = 0,
1375                .ai_speed       = 33250,
1376                .ispgl          = 0,
1377                .dachan         = 2,
1378                .dabits         = 16,
1379        }, {
1380                .name           = "dt21-ez",
1381                .adbits         = 12,
1382                .adchan_se      = 16,
1383                .adchan_di      = 8,
1384                .ai_speed       = 10000,
1385                .ispgl          = 0,
1386                .dachan         = 2,
1387                .dabits         = 12,
1388        }, {
1389                .name           = "dt23-ez",
1390                .adbits         = 16,
1391                .adchan_se      = 16,
1392                .adchan_di      = 8,
1393                .ai_speed       = 10000,
1394                .ispgl          = 0,
1395                .dachan         = 0,
1396                .dabits         = 0,
1397        }, {
1398                .name           = "dt24-ez",
1399                .adbits         = 12,
1400                .adchan_se      = 16,
1401                .adchan_di      = 8,
1402                .ai_speed       = 10000,
1403                .ispgl          = 0,
1404                .dachan         = 0,
1405                .dabits         = 0,
1406        }, {
1407                .name           = "dt24-ez-pgl",
1408                .adbits         = 12,
1409                .adchan_se      = 16,
1410                .adchan_di      = 8,
1411                .ai_speed       = 10000,
1412                .ispgl          = 1,
1413                .dachan         = 0,
1414                .dabits         = 0,
1415        },
1416};
1417
1418static struct comedi_driver dt282x_driver = {
1419        .driver_name    = "dt282x",
1420        .module         = THIS_MODULE,
1421        .attach         = dt282x_attach,
1422        .detach         = dt282x_detach,
1423        .board_name     = &boardtypes[0].name,
1424        .num_names      = ARRAY_SIZE(boardtypes),
1425        .offset         = sizeof(struct dt282x_board),
1426};
1427module_comedi_driver(dt282x_driver);
1428
1429MODULE_AUTHOR("Comedi http://www.comedi.org");
1430MODULE_DESCRIPTION("Comedi low-level driver");
1431MODULE_LICENSE("GPL");
1432