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