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