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