root/drivers/staging/comedi/drivers/dt282x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dt282x_prep_ai_dma
  2. dt282x_prep_ao_dma
  3. dt282x_disable_dma
  4. dt282x_ns_to_timer
  5. dt282x_munge
  6. dt282x_ao_setup_dma
  7. dt282x_ao_dma_interrupt
  8. dt282x_ai_dma_interrupt
  9. dt282x_interrupt
  10. dt282x_load_changain
  11. dt282x_ai_timeout
  12. dt282x_ai_insn_read
  13. dt282x_ai_cmdtest
  14. dt282x_ai_cmd
  15. dt282x_ai_cancel
  16. dt282x_ao_insn_write
  17. dt282x_ao_cmdtest
  18. dt282x_ao_inttrig
  19. dt282x_ao_cmd
  20. dt282x_ao_cancel
  21. dt282x_dio_insn_bits
  22. dt282x_dio_insn_config
  23. opt_ai_range_lkup
  24. dt282x_alloc_dma
  25. dt282x_free_dma
  26. dt282x_initialize
  27. dt282x_attach
  28. dt282x_detach

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * dt282x.c
   4  * Comedi driver for Data Translation DT2821 series
   5  *
   6  * COMEDI - Linux Control and Measurement Device Interface
   7  * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
   8  */
   9 
  10 /*
  11  * Driver: dt282x
  12  * Description: Data Translation DT2821 series (including DT-EZ)
  13  * Author: ds
  14  * Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f),
  15  *   DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g),
  16  *   DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh),
  17  *   DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827),
  18  *   DT2828 (dt2828), DT2928 (dt2829), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
  19  *   DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
  20  * Status: complete
  21  * Updated: Wed, 22 Aug 2001 17:11:34 -0700
  22  *
  23  * Configuration options:
  24  *   [0] - I/O port base address
  25  *   [1] - IRQ (optional, required for async command support)
  26  *   [2] - DMA 1 (optional, required for async command support)
  27  *   [3] - DMA 2 (optional, required for async command support)
  28  *   [4] - AI jumpered for 0=single ended, 1=differential
  29  *   [5] - AI jumpered for 0=straight binary, 1=2's complement
  30  *   [6] - AO 0 data format (deprecated, see below)
  31  *   [7] - AO 1 data format (deprecated, see below)
  32  *   [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
  33  *   [9] - AO channel 0 range (deprecated, see below)
  34  *   [10]- AO channel 1 range (deprecated, see below)
  35  *
  36  * Notes:
  37  *   - AO commands might be broken.
  38  *   - If you try to run a command on both the AI and AO subdevices
  39  *     simultaneously, bad things will happen.  The driver needs to
  40  *     be fixed to check for this situation and return an error.
  41  *   - AO range is not programmable. The AO subdevice has a range_table
  42  *     containing all the possible analog output ranges. Use the range
  43  *     that matches your board configuration to convert between data
  44  *     values and physical units. The format of the data written to the
  45  *     board is handled automatically based on the unipolar/bipolar
  46  *     range that is selected.
  47  */
  48 
  49 #include <linux/module.h>
  50 #include <linux/delay.h>
  51 #include <linux/gfp.h>
  52 #include <linux/interrupt.h>
  53 #include <linux/io.h>
  54 
  55 #include "../comedidev.h"
  56 
  57 #include "comedi_isadma.h"
  58 
  59 /*
  60  * Register map
  61  */
  62 #define DT2821_ADCSR_REG                0x00
  63 #define DT2821_ADCSR_ADERR              BIT(15)
  64 #define DT2821_ADCSR_ADCLK              BIT(9)
  65 #define DT2821_ADCSR_MUXBUSY            BIT(8)
  66 #define DT2821_ADCSR_ADDONE             BIT(7)
  67 #define DT2821_ADCSR_IADDONE            BIT(6)
  68 #define DT2821_ADCSR_GS(x)              (((x) & 0x3) << 4)
  69 #define DT2821_ADCSR_CHAN(x)            (((x) & 0xf) << 0)
  70 #define DT2821_CHANCSR_REG              0x02
  71 #define DT2821_CHANCSR_LLE              BIT(15)
  72 #define DT2821_CHANCSR_TO_PRESLA(x)     (((x) >> 8) & 0xf)
  73 #define DT2821_CHANCSR_NUMB(x)          ((((x) - 1) & 0xf) << 0)
  74 #define DT2821_ADDAT_REG                0x04
  75 #define DT2821_DACSR_REG                0x06
  76 #define DT2821_DACSR_DAERR              BIT(15)
  77 #define DT2821_DACSR_YSEL(x)            ((x) << 9)
  78 #define DT2821_DACSR_SSEL               BIT(8)
  79 #define DT2821_DACSR_DACRDY             BIT(7)
  80 #define DT2821_DACSR_IDARDY             BIT(6)
  81 #define DT2821_DACSR_DACLK              BIT(5)
  82 #define DT2821_DACSR_HBOE               BIT(1)
  83 #define DT2821_DACSR_LBOE               BIT(0)
  84 #define DT2821_DADAT_REG                0x08
  85 #define DT2821_DIODAT_REG               0x0a
  86 #define DT2821_SUPCSR_REG               0x0c
  87 #define DT2821_SUPCSR_DMAD              BIT(15)
  88 #define DT2821_SUPCSR_ERRINTEN          BIT(14)
  89 #define DT2821_SUPCSR_CLRDMADNE         BIT(13)
  90 #define DT2821_SUPCSR_DDMA              BIT(12)
  91 #define DT2821_SUPCSR_DS(x)             (((x) & 0x3) << 10)
  92 #define DT2821_SUPCSR_DS_PIO            DT2821_SUPCSR_DS(0)
  93 #define DT2821_SUPCSR_DS_AD_CLK         DT2821_SUPCSR_DS(1)
  94 #define DT2821_SUPCSR_DS_DA_CLK         DT2821_SUPCSR_DS(2)
  95 #define DT2821_SUPCSR_DS_AD_TRIG        DT2821_SUPCSR_DS(3)
  96 #define DT2821_SUPCSR_BUFFB             BIT(9)
  97 #define DT2821_SUPCSR_SCDN              BIT(8)
  98 #define DT2821_SUPCSR_DACON             BIT(7)
  99 #define DT2821_SUPCSR_ADCINIT           BIT(6)
 100 #define DT2821_SUPCSR_DACINIT           BIT(5)
 101 #define DT2821_SUPCSR_PRLD              BIT(4)
 102 #define DT2821_SUPCSR_STRIG             BIT(3)
 103 #define DT2821_SUPCSR_XTRIG             BIT(2)
 104 #define DT2821_SUPCSR_XCLK              BIT(1)
 105 #define DT2821_SUPCSR_BDINIT            BIT(0)
 106 #define DT2821_TMRCTR_REG               0x0e
 107 #define DT2821_TMRCTR_PRESCALE(x)       (((x) & 0xf) << 8)
 108 #define DT2821_TMRCTR_DIVIDER(x)        ((255 - ((x) & 0xff)) << 0)
 109 
 110 /* Pacer Clock */
 111 #define DT2821_OSC_BASE         250     /* 4 MHz (in nanoseconds) */
 112 #define DT2821_PRESCALE(x)      BIT(x)
 113 #define DT2821_PRESCALE_MAX     15
 114 #define DT2821_DIVIDER_MAX      255
 115 #define DT2821_OSC_MAX          (DT2821_OSC_BASE *                      \
 116                                  DT2821_PRESCALE(DT2821_PRESCALE_MAX) * \
 117                                  DT2821_DIVIDER_MAX)
 118 
 119 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
 120         4, {
 121                 BIP_RANGE(10),
 122                 BIP_RANGE(5),
 123                 BIP_RANGE(2.5),
 124                 BIP_RANGE(1.25)
 125         }
 126 };
 127 
 128 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
 129         4, {
 130                 UNI_RANGE(10),
 131                 UNI_RANGE(5),
 132                 UNI_RANGE(2.5),
 133                 UNI_RANGE(1.25)
 134         }
 135 };
 136 
 137 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
 138         4, {
 139                 BIP_RANGE(5),
 140                 BIP_RANGE(2.5),
 141                 BIP_RANGE(1.25),
 142                 BIP_RANGE(0.625)
 143         }
 144 };
 145 
 146 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
 147         4, {
 148                 UNI_RANGE(5),
 149                 UNI_RANGE(2.5),
 150                 UNI_RANGE(1.25),
 151                 UNI_RANGE(0.625)
 152         }
 153 };
 154 
 155 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
 156         4, {
 157                 BIP_RANGE(10),
 158                 BIP_RANGE(1),
 159                 BIP_RANGE(0.1),
 160                 BIP_RANGE(0.02)
 161         }
 162 };
 163 
 164 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
 165         4, {
 166                 UNI_RANGE(10),
 167                 UNI_RANGE(1),
 168                 UNI_RANGE(0.1),
 169                 UNI_RANGE(0.02)
 170         }
 171 };
 172 
 173 /*
 174  * The Analog Output range is set per-channel using jumpers on the board.
 175  * All of these ranges may not be available on some DT2821 series boards.
 176  * The default jumper setting has both channels set for +/-10V output.
 177  */
 178 static const struct comedi_lrange dt282x_ao_range = {
 179         5, {
 180                 BIP_RANGE(10),
 181                 BIP_RANGE(5),
 182                 BIP_RANGE(2.5),
 183                 UNI_RANGE(10),
 184                 UNI_RANGE(5),
 185         }
 186 };
 187 
 188 struct dt282x_board {
 189         const char *name;
 190         unsigned int ai_maxdata;
 191         int adchan_se;
 192         int adchan_di;
 193         int ai_speed;
 194         int ispgl;
 195         int dachan;
 196         unsigned int ao_maxdata;
 197 };
 198 
 199 static const struct dt282x_board boardtypes[] = {
 200         {
 201                 .name           = "dt2821",
 202                 .ai_maxdata     = 0x0fff,
 203                 .adchan_se      = 16,
 204                 .adchan_di      = 8,
 205                 .ai_speed       = 20000,
 206                 .dachan         = 2,
 207                 .ao_maxdata     = 0x0fff,
 208         }, {
 209                 .name           = "dt2821-f",
 210                 .ai_maxdata     = 0x0fff,
 211                 .adchan_se      = 16,
 212                 .adchan_di      = 8,
 213                 .ai_speed       = 6500,
 214                 .dachan         = 2,
 215                 .ao_maxdata     = 0x0fff,
 216         }, {
 217                 .name           = "dt2821-g",
 218                 .ai_maxdata     = 0x0fff,
 219                 .adchan_se      = 16,
 220                 .adchan_di      = 8,
 221                 .ai_speed       = 4000,
 222                 .dachan         = 2,
 223                 .ao_maxdata     = 0x0fff,
 224         }, {
 225                 .name           = "dt2823",
 226                 .ai_maxdata     = 0xffff,
 227                 .adchan_di      = 4,
 228                 .ai_speed       = 10000,
 229                 .dachan         = 2,
 230                 .ao_maxdata     = 0xffff,
 231         }, {
 232                 .name           = "dt2824-pgh",
 233                 .ai_maxdata     = 0x0fff,
 234                 .adchan_se      = 16,
 235                 .adchan_di      = 8,
 236                 .ai_speed       = 20000,
 237         }, {
 238                 .name           = "dt2824-pgl",
 239                 .ai_maxdata     = 0x0fff,
 240                 .adchan_se      = 16,
 241                 .adchan_di      = 8,
 242                 .ai_speed       = 20000,
 243                 .ispgl          = 1,
 244         }, {
 245                 .name           = "dt2825",
 246                 .ai_maxdata     = 0x0fff,
 247                 .adchan_se      = 16,
 248                 .adchan_di      = 8,
 249                 .ai_speed       = 20000,
 250                 .ispgl          = 1,
 251                 .dachan         = 2,
 252                 .ao_maxdata     = 0x0fff,
 253         }, {
 254                 .name           = "dt2827",
 255                 .ai_maxdata     = 0xffff,
 256                 .adchan_di      = 4,
 257                 .ai_speed       = 10000,
 258                 .dachan         = 2,
 259                 .ao_maxdata     = 0x0fff,
 260         }, {
 261                 .name           = "dt2828",
 262                 .ai_maxdata     = 0x0fff,
 263                 .adchan_se      = 4,
 264                 .ai_speed       = 10000,
 265                 .dachan         = 2,
 266                 .ao_maxdata     = 0x0fff,
 267         }, {
 268                 .name           = "dt2829",
 269                 .ai_maxdata     = 0xffff,
 270                 .adchan_se      = 8,
 271                 .ai_speed       = 33250,
 272                 .dachan         = 2,
 273                 .ao_maxdata     = 0xffff,
 274         }, {
 275                 .name           = "dt21-ez",
 276                 .ai_maxdata     = 0x0fff,
 277                 .adchan_se      = 16,
 278                 .adchan_di      = 8,
 279                 .ai_speed       = 10000,
 280                 .dachan         = 2,
 281                 .ao_maxdata     = 0x0fff,
 282         }, {
 283                 .name           = "dt23-ez",
 284                 .ai_maxdata     = 0xffff,
 285                 .adchan_se      = 16,
 286                 .adchan_di      = 8,
 287                 .ai_speed       = 10000,
 288         }, {
 289                 .name           = "dt24-ez",
 290                 .ai_maxdata     = 0x0fff,
 291                 .adchan_se      = 16,
 292                 .adchan_di      = 8,
 293                 .ai_speed       = 10000,
 294         }, {
 295                 .name           = "dt24-ez-pgl",
 296                 .ai_maxdata     = 0x0fff,
 297                 .adchan_se      = 16,
 298                 .adchan_di      = 8,
 299                 .ai_speed       = 10000,
 300                 .ispgl          = 1,
 301         },
 302 };
 303 
 304 struct dt282x_private {
 305         struct comedi_isadma *dma;
 306         unsigned int ad_2scomp:1;
 307         unsigned int divisor;
 308         int dacsr;      /* software copies of registers */
 309         int adcsr;
 310         int supcsr;
 311         int ntrig;
 312         int nread;
 313         int dma_dir;
 314 };
 315 
 316 static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
 317 {
 318         struct dt282x_private *devpriv = dev->private;
 319         struct comedi_isadma *dma = devpriv->dma;
 320         struct comedi_isadma_desc *desc = &dma->desc[dma_index];
 321 
 322         if (!devpriv->ntrig)
 323                 return 0;
 324 
 325         if (n == 0)
 326                 n = desc->maxsize;
 327         if (n > devpriv->ntrig * 2)
 328                 n = devpriv->ntrig * 2;
 329         devpriv->ntrig -= n / 2;
 330 
 331         desc->size = n;
 332         comedi_isadma_set_mode(desc, devpriv->dma_dir);
 333 
 334         comedi_isadma_program(desc);
 335 
 336         return n;
 337 }
 338 
 339 static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
 340 {
 341         struct dt282x_private *devpriv = dev->private;
 342         struct comedi_isadma *dma = devpriv->dma;
 343         struct comedi_isadma_desc *desc = &dma->desc[dma_index];
 344 
 345         desc->size = n;
 346         comedi_isadma_set_mode(desc, devpriv->dma_dir);
 347 
 348         comedi_isadma_program(desc);
 349 
 350         return n;
 351 }
 352 
 353 static void dt282x_disable_dma(struct comedi_device *dev)
 354 {
 355         struct dt282x_private *devpriv = dev->private;
 356         struct comedi_isadma *dma = devpriv->dma;
 357         struct comedi_isadma_desc *desc;
 358         int i;
 359 
 360         for (i = 0; i < 2; i++) {
 361                 desc = &dma->desc[i];
 362                 comedi_isadma_disable(desc->chan);
 363         }
 364 }
 365 
 366 static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
 367 {
 368         unsigned int prescale, base, divider;
 369 
 370         for (prescale = 0; prescale <= DT2821_PRESCALE_MAX; prescale++) {
 371                 if (prescale == 1)      /* 0 and 1 are both divide by 1 */
 372                         continue;
 373                 base = DT2821_OSC_BASE * DT2821_PRESCALE(prescale);
 374                 switch (flags & CMDF_ROUND_MASK) {
 375                 case CMDF_ROUND_NEAREST:
 376                 default:
 377                         divider = DIV_ROUND_CLOSEST(*ns, base);
 378                         break;
 379                 case CMDF_ROUND_DOWN:
 380                         divider = (*ns) / base;
 381                         break;
 382                 case CMDF_ROUND_UP:
 383                         divider = DIV_ROUND_UP(*ns, base);
 384                         break;
 385                 }
 386                 if (divider <= DT2821_DIVIDER_MAX)
 387                         break;
 388         }
 389         if (divider > DT2821_DIVIDER_MAX) {
 390                 prescale = DT2821_PRESCALE_MAX;
 391                 divider = DT2821_DIVIDER_MAX;
 392                 base = DT2821_OSC_BASE * DT2821_PRESCALE(prescale);
 393         }
 394         *ns = divider * base;
 395         return DT2821_TMRCTR_PRESCALE(prescale) |
 396                DT2821_TMRCTR_DIVIDER(divider);
 397 }
 398 
 399 static void dt282x_munge(struct comedi_device *dev,
 400                          struct comedi_subdevice *s,
 401                          unsigned short *buf,
 402                          unsigned int nbytes)
 403 {
 404         struct dt282x_private *devpriv = dev->private;
 405         unsigned int val;
 406         int i;
 407 
 408         if (nbytes % 2)
 409                 dev_err(dev->class_dev,
 410                         "bug! odd number of bytes from dma xfer\n");
 411 
 412         for (i = 0; i < nbytes / 2; i++) {
 413                 val = buf[i];
 414                 val &= s->maxdata;
 415                 if (devpriv->ad_2scomp)
 416                         val = comedi_offset_munge(s, val);
 417 
 418                 buf[i] = val;
 419         }
 420 }
 421 
 422 static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev,
 423                                         struct comedi_subdevice *s,
 424                                         int cur_dma)
 425 {
 426         struct dt282x_private *devpriv = dev->private;
 427         struct comedi_isadma *dma = devpriv->dma;
 428         struct comedi_isadma_desc *desc = &dma->desc[cur_dma];
 429         unsigned int nsamples = comedi_bytes_to_samples(s, desc->maxsize);
 430         unsigned int nbytes;
 431 
 432         nbytes = comedi_buf_read_samples(s, desc->virt_addr, nsamples);
 433         if (nbytes)
 434                 dt282x_prep_ao_dma(dev, cur_dma, nbytes);
 435         else
 436                 dev_err(dev->class_dev, "AO underrun\n");
 437 
 438         return nbytes;
 439 }
 440 
 441 static void dt282x_ao_dma_interrupt(struct comedi_device *dev,
 442                                     struct comedi_subdevice *s)
 443 {
 444         struct dt282x_private *devpriv = dev->private;
 445         struct comedi_isadma *dma = devpriv->dma;
 446         struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 447 
 448         outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
 449              dev->iobase + DT2821_SUPCSR_REG);
 450 
 451         comedi_isadma_disable(desc->chan);
 452 
 453         if (!dt282x_ao_setup_dma(dev, s, dma->cur_dma))
 454                 s->async->events |= COMEDI_CB_OVERFLOW;
 455 
 456         dma->cur_dma = 1 - dma->cur_dma;
 457 }
 458 
 459 static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
 460                                     struct comedi_subdevice *s)
 461 {
 462         struct dt282x_private *devpriv = dev->private;
 463         struct comedi_isadma *dma = devpriv->dma;
 464         struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 465         unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
 466         int ret;
 467 
 468         outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
 469              dev->iobase + DT2821_SUPCSR_REG);
 470 
 471         comedi_isadma_disable(desc->chan);
 472 
 473         dt282x_munge(dev, s, desc->virt_addr, desc->size);
 474         ret = comedi_buf_write_samples(s, desc->virt_addr, nsamples);
 475         if (ret != desc->size)
 476                 return;
 477 
 478         devpriv->nread -= nsamples;
 479         if (devpriv->nread < 0) {
 480                 dev_info(dev->class_dev, "nread off by one\n");
 481                 devpriv->nread = 0;
 482         }
 483         if (!devpriv->nread) {
 484                 s->async->events |= COMEDI_CB_EOA;
 485                 return;
 486         }
 487 #if 0
 488         /* clear the dual dma flag, making this the last dma segment */
 489         /* XXX probably wrong */
 490         if (!devpriv->ntrig) {
 491                 devpriv->supcsr &= ~DT2821_SUPCSR_DDMA;
 492                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
 493         }
 494 #endif
 495         /* restart the channel */
 496         dt282x_prep_ai_dma(dev, dma->cur_dma, 0);
 497 
 498         dma->cur_dma = 1 - dma->cur_dma;
 499 }
 500 
 501 static irqreturn_t dt282x_interrupt(int irq, void *d)
 502 {
 503         struct comedi_device *dev = d;
 504         struct dt282x_private *devpriv = dev->private;
 505         struct comedi_subdevice *s = dev->read_subdev;
 506         struct comedi_subdevice *s_ao = dev->write_subdev;
 507         unsigned int supcsr, adcsr, dacsr;
 508         int handled = 0;
 509 
 510         if (!dev->attached) {
 511                 dev_err(dev->class_dev, "spurious interrupt\n");
 512                 return IRQ_HANDLED;
 513         }
 514 
 515         adcsr = inw(dev->iobase + DT2821_ADCSR_REG);
 516         dacsr = inw(dev->iobase + DT2821_DACSR_REG);
 517         supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
 518         if (supcsr & DT2821_SUPCSR_DMAD) {
 519                 if (devpriv->dma_dir == COMEDI_ISADMA_READ)
 520                         dt282x_ai_dma_interrupt(dev, s);
 521                 else
 522                         dt282x_ao_dma_interrupt(dev, s_ao);
 523                 handled = 1;
 524         }
 525         if (adcsr & DT2821_ADCSR_ADERR) {
 526                 if (devpriv->nread != 0) {
 527                         dev_err(dev->class_dev, "A/D error\n");
 528                         s->async->events |= COMEDI_CB_ERROR;
 529                 }
 530                 handled = 1;
 531         }
 532         if (dacsr & DT2821_DACSR_DAERR) {
 533                 dev_err(dev->class_dev, "D/A error\n");
 534                 s_ao->async->events |= COMEDI_CB_ERROR;
 535                 handled = 1;
 536         }
 537 #if 0
 538         if (adcsr & DT2821_ADCSR_ADDONE) {
 539                 unsigned short data;
 540 
 541                 data = inw(dev->iobase + DT2821_ADDAT_REG);
 542                 data &= s->maxdata;
 543                 if (devpriv->ad_2scomp)
 544                         data = comedi_offset_munge(s, data);
 545 
 546                 comedi_buf_write_samples(s, &data, 1);
 547 
 548                 devpriv->nread--;
 549                 if (!devpriv->nread) {
 550                         s->async->events |= COMEDI_CB_EOA;
 551                 } else {
 552                         if (supcsr & DT2821_SUPCSR_SCDN)
 553                                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
 554                                      dev->iobase + DT2821_SUPCSR_REG);
 555                 }
 556                 handled = 1;
 557         }
 558 #endif
 559         comedi_handle_events(dev, s);
 560         if (s_ao)
 561                 comedi_handle_events(dev, s_ao);
 562 
 563         return IRQ_RETVAL(handled);
 564 }
 565 
 566 static void dt282x_load_changain(struct comedi_device *dev, int n,
 567                                  unsigned int *chanlist)
 568 {
 569         struct dt282x_private *devpriv = dev->private;
 570         int i;
 571 
 572         outw(DT2821_CHANCSR_LLE | DT2821_CHANCSR_NUMB(n),
 573              dev->iobase + DT2821_CHANCSR_REG);
 574         for (i = 0; i < n; i++) {
 575                 unsigned int chan = CR_CHAN(chanlist[i]);
 576                 unsigned int range = CR_RANGE(chanlist[i]);
 577 
 578                 outw(devpriv->adcsr |
 579                      DT2821_ADCSR_GS(range) |
 580                      DT2821_ADCSR_CHAN(chan),
 581                      dev->iobase + DT2821_ADCSR_REG);
 582         }
 583         outw(DT2821_CHANCSR_NUMB(n), dev->iobase + DT2821_CHANCSR_REG);
 584 }
 585 
 586 static int dt282x_ai_timeout(struct comedi_device *dev,
 587                              struct comedi_subdevice *s,
 588                              struct comedi_insn *insn,
 589                              unsigned long context)
 590 {
 591         unsigned int status;
 592 
 593         status = inw(dev->iobase + DT2821_ADCSR_REG);
 594         switch (context) {
 595         case DT2821_ADCSR_MUXBUSY:
 596                 if ((status & DT2821_ADCSR_MUXBUSY) == 0)
 597                         return 0;
 598                 break;
 599         case DT2821_ADCSR_ADDONE:
 600                 if (status & DT2821_ADCSR_ADDONE)
 601                         return 0;
 602                 break;
 603         default:
 604                 return -EINVAL;
 605         }
 606         return -EBUSY;
 607 }
 608 
 609 /*
 610  *    Performs a single A/D conversion.
 611  *      - Put channel/gain into channel-gain list
 612  *      - preload multiplexer
 613  *      - trigger conversion and wait for it to finish
 614  */
 615 static int dt282x_ai_insn_read(struct comedi_device *dev,
 616                                struct comedi_subdevice *s,
 617                                struct comedi_insn *insn,
 618                                unsigned int *data)
 619 {
 620         struct dt282x_private *devpriv = dev->private;
 621         unsigned int val;
 622         int ret;
 623         int i;
 624 
 625         /* XXX should we really be enabling the ad clock here? */
 626         devpriv->adcsr = DT2821_ADCSR_ADCLK;
 627         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
 628 
 629         dt282x_load_changain(dev, 1, &insn->chanspec);
 630 
 631         outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
 632              dev->iobase + DT2821_SUPCSR_REG);
 633         ret = comedi_timeout(dev, s, insn,
 634                              dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
 635         if (ret)
 636                 return ret;
 637 
 638         for (i = 0; i < insn->n; i++) {
 639                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
 640                      dev->iobase + DT2821_SUPCSR_REG);
 641 
 642                 ret = comedi_timeout(dev, s, insn,
 643                                      dt282x_ai_timeout, DT2821_ADCSR_ADDONE);
 644                 if (ret)
 645                         return ret;
 646 
 647                 val = inw(dev->iobase + DT2821_ADDAT_REG);
 648                 val &= s->maxdata;
 649                 if (devpriv->ad_2scomp)
 650                         val = comedi_offset_munge(s, val);
 651 
 652                 data[i] = val;
 653         }
 654 
 655         return i;
 656 }
 657 
 658 static int dt282x_ai_cmdtest(struct comedi_device *dev,
 659                              struct comedi_subdevice *s,
 660                              struct comedi_cmd *cmd)
 661 {
 662         const struct dt282x_board *board = dev->board_ptr;
 663         struct dt282x_private *devpriv = dev->private;
 664         int err = 0;
 665         unsigned int arg;
 666 
 667         /* Step 1 : check if triggers are trivially valid */
 668 
 669         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
 670         err |= comedi_check_trigger_src(&cmd->scan_begin_src,
 671                                         TRIG_FOLLOW | TRIG_EXT);
 672         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
 673         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 674         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 675 
 676         if (err)
 677                 return 1;
 678 
 679         /* Step 2a : make sure trigger sources are unique */
 680 
 681         err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
 682         err |= comedi_check_trigger_is_unique(cmd->stop_src);
 683 
 684         /* Step 2b : and mutually compatible */
 685 
 686         if (err)
 687                 return 2;
 688 
 689         /* Step 3: check if arguments are trivially valid */
 690 
 691         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 692         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 693         err |= comedi_check_trigger_arg_max(&cmd->convert_arg, DT2821_OSC_MAX);
 694         err |= comedi_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
 695         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 696                                            cmd->chanlist_len);
 697 
 698         if (cmd->stop_src == TRIG_COUNT)
 699                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
 700         else    /* TRIG_EXT | TRIG_NONE */
 701                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 702 
 703         if (err)
 704                 return 3;
 705 
 706         /* step 4: fix up any arguments */
 707 
 708         arg = cmd->convert_arg;
 709         devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
 710         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
 711 
 712         if (err)
 713                 return 4;
 714 
 715         return 0;
 716 }
 717 
 718 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 719 {
 720         struct dt282x_private *devpriv = dev->private;
 721         struct comedi_isadma *dma = devpriv->dma;
 722         struct comedi_cmd *cmd = &s->async->cmd;
 723         int ret;
 724 
 725         dt282x_disable_dma(dev);
 726 
 727         outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
 728 
 729         devpriv->supcsr = DT2821_SUPCSR_ERRINTEN;
 730         if (cmd->scan_begin_src == TRIG_FOLLOW)
 731                 devpriv->supcsr = DT2821_SUPCSR_DS_AD_CLK;
 732         else
 733                 devpriv->supcsr = DT2821_SUPCSR_DS_AD_TRIG;
 734         outw(devpriv->supcsr |
 735              DT2821_SUPCSR_CLRDMADNE |
 736              DT2821_SUPCSR_BUFFB |
 737              DT2821_SUPCSR_ADCINIT,
 738              dev->iobase + DT2821_SUPCSR_REG);
 739 
 740         devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
 741         devpriv->nread = devpriv->ntrig;
 742 
 743         devpriv->dma_dir = COMEDI_ISADMA_READ;
 744         dma->cur_dma = 0;
 745         dt282x_prep_ai_dma(dev, 0, 0);
 746         if (devpriv->ntrig) {
 747                 dt282x_prep_ai_dma(dev, 1, 0);
 748                 devpriv->supcsr |= DT2821_SUPCSR_DDMA;
 749                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
 750         }
 751 
 752         devpriv->adcsr = 0;
 753 
 754         dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
 755 
 756         devpriv->adcsr = DT2821_ADCSR_ADCLK | DT2821_ADCSR_IADDONE;
 757         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
 758 
 759         outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
 760              dev->iobase + DT2821_SUPCSR_REG);
 761         ret = comedi_timeout(dev, s, NULL,
 762                              dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
 763         if (ret)
 764                 return ret;
 765 
 766         if (cmd->scan_begin_src == TRIG_FOLLOW) {
 767                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
 768                      dev->iobase + DT2821_SUPCSR_REG);
 769         } else {
 770                 devpriv->supcsr |= DT2821_SUPCSR_XTRIG;
 771                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
 772         }
 773 
 774         return 0;
 775 }
 776 
 777 static int dt282x_ai_cancel(struct comedi_device *dev,
 778                             struct comedi_subdevice *s)
 779 {
 780         struct dt282x_private *devpriv = dev->private;
 781 
 782         dt282x_disable_dma(dev);
 783 
 784         devpriv->adcsr = 0;
 785         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
 786 
 787         devpriv->supcsr = 0;
 788         outw(devpriv->supcsr | DT2821_SUPCSR_ADCINIT,
 789              dev->iobase + DT2821_SUPCSR_REG);
 790 
 791         return 0;
 792 }
 793 
 794 static int dt282x_ao_insn_write(struct comedi_device *dev,
 795                                 struct comedi_subdevice *s,
 796                                 struct comedi_insn *insn,
 797                                 unsigned int *data)
 798 {
 799         struct dt282x_private *devpriv = dev->private;
 800         unsigned int chan = CR_CHAN(insn->chanspec);
 801         unsigned int range = CR_RANGE(insn->chanspec);
 802         int i;
 803 
 804         devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan);
 805 
 806         for (i = 0; i < insn->n; i++) {
 807                 unsigned int val = data[i];
 808 
 809                 s->readback[chan] = val;
 810 
 811                 if (comedi_range_is_bipolar(s, range))
 812                         val = comedi_offset_munge(s, val);
 813 
 814                 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
 815 
 816                 outw(val, dev->iobase + DT2821_DADAT_REG);
 817 
 818                 outw(devpriv->supcsr | DT2821_SUPCSR_DACON,
 819                      dev->iobase + DT2821_SUPCSR_REG);
 820         }
 821 
 822         return insn->n;
 823 }
 824 
 825 static int dt282x_ao_cmdtest(struct comedi_device *dev,
 826                              struct comedi_subdevice *s,
 827                              struct comedi_cmd *cmd)
 828 {
 829         struct dt282x_private *devpriv = dev->private;
 830         int err = 0;
 831         unsigned int arg;
 832 
 833         /* Step 1 : check if triggers are trivially valid */
 834 
 835         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT);
 836         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
 837         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
 838         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 839         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 840 
 841         if (err)
 842                 return 1;
 843 
 844         /* Step 2a : make sure trigger sources are unique */
 845 
 846         err |= comedi_check_trigger_is_unique(cmd->stop_src);
 847 
 848         /* Step 2b : and mutually compatible */
 849 
 850         if (err)
 851                 return 2;
 852 
 853         /* Step 3: check if arguments are trivially valid */
 854 
 855         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 856         err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
 857         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
 858         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 859                                            cmd->chanlist_len);
 860 
 861         if (cmd->stop_src == TRIG_COUNT)
 862                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
 863         else    /* TRIG_EXT | TRIG_NONE */
 864                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 865 
 866         if (err)
 867                 return 3;
 868 
 869         /* step 4: fix up any arguments */
 870 
 871         arg = cmd->scan_begin_arg;
 872         devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
 873         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
 874 
 875         if (err)
 876                 return 4;
 877 
 878         return 0;
 879 }
 880 
 881 static int dt282x_ao_inttrig(struct comedi_device *dev,
 882                              struct comedi_subdevice *s,
 883                              unsigned int trig_num)
 884 {
 885         struct dt282x_private *devpriv = dev->private;
 886         struct comedi_cmd *cmd = &s->async->cmd;
 887 
 888         if (trig_num != cmd->start_src)
 889                 return -EINVAL;
 890 
 891         if (!dt282x_ao_setup_dma(dev, s, 0))
 892                 return -EPIPE;
 893 
 894         if (!dt282x_ao_setup_dma(dev, s, 1))
 895                 return -EPIPE;
 896 
 897         outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
 898              dev->iobase + DT2821_SUPCSR_REG);
 899         s->async->inttrig = NULL;
 900 
 901         return 1;
 902 }
 903 
 904 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 905 {
 906         struct dt282x_private *devpriv = dev->private;
 907         struct comedi_isadma *dma = devpriv->dma;
 908         struct comedi_cmd *cmd = &s->async->cmd;
 909 
 910         dt282x_disable_dma(dev);
 911 
 912         devpriv->supcsr = DT2821_SUPCSR_ERRINTEN |
 913                           DT2821_SUPCSR_DS_DA_CLK |
 914                           DT2821_SUPCSR_DDMA;
 915         outw(devpriv->supcsr |
 916              DT2821_SUPCSR_CLRDMADNE |
 917              DT2821_SUPCSR_BUFFB |
 918              DT2821_SUPCSR_DACINIT,
 919              dev->iobase + DT2821_SUPCSR_REG);
 920 
 921         devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
 922         devpriv->nread = devpriv->ntrig;
 923 
 924         devpriv->dma_dir = COMEDI_ISADMA_WRITE;
 925         dma->cur_dma = 0;
 926 
 927         outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
 928 
 929         /* clear all bits but the DIO direction bits */
 930         devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
 931 
 932         devpriv->dacsr |= (DT2821_DACSR_SSEL |
 933                            DT2821_DACSR_DACLK |
 934                            DT2821_DACSR_IDARDY);
 935         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
 936 
 937         s->async->inttrig = dt282x_ao_inttrig;
 938 
 939         return 0;
 940 }
 941 
 942 static int dt282x_ao_cancel(struct comedi_device *dev,
 943                             struct comedi_subdevice *s)
 944 {
 945         struct dt282x_private *devpriv = dev->private;
 946 
 947         dt282x_disable_dma(dev);
 948 
 949         /* clear all bits but the DIO direction bits */
 950         devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
 951 
 952         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
 953 
 954         devpriv->supcsr = 0;
 955         outw(devpriv->supcsr | DT2821_SUPCSR_DACINIT,
 956              dev->iobase + DT2821_SUPCSR_REG);
 957 
 958         return 0;
 959 }
 960 
 961 static int dt282x_dio_insn_bits(struct comedi_device *dev,
 962                                 struct comedi_subdevice *s,
 963                                 struct comedi_insn *insn,
 964                                 unsigned int *data)
 965 {
 966         if (comedi_dio_update_state(s, data))
 967                 outw(s->state, dev->iobase + DT2821_DIODAT_REG);
 968 
 969         data[1] = inw(dev->iobase + DT2821_DIODAT_REG);
 970 
 971         return insn->n;
 972 }
 973 
 974 static int dt282x_dio_insn_config(struct comedi_device *dev,
 975                                   struct comedi_subdevice *s,
 976                                   struct comedi_insn *insn,
 977                                   unsigned int *data)
 978 {
 979         struct dt282x_private *devpriv = dev->private;
 980         unsigned int chan = CR_CHAN(insn->chanspec);
 981         unsigned int mask;
 982         int ret;
 983 
 984         if (chan < 8)
 985                 mask = 0x00ff;
 986         else
 987                 mask = 0xff00;
 988 
 989         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
 990         if (ret)
 991                 return ret;
 992 
 993         devpriv->dacsr &= ~(DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
 994         if (s->io_bits & 0x00ff)
 995                 devpriv->dacsr |= DT2821_DACSR_LBOE;
 996         if (s->io_bits & 0xff00)
 997                 devpriv->dacsr |= DT2821_DACSR_HBOE;
 998 
 999         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
1000 
1001         return insn->n;
1002 }
1003 
1004 static const struct comedi_lrange *const ai_range_table[] = {
1005         &range_dt282x_ai_lo_bipolar,
1006         &range_dt282x_ai_lo_unipolar,
1007         &range_dt282x_ai_5_bipolar,
1008         &range_dt282x_ai_5_unipolar
1009 };
1010 
1011 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1012         &range_dt282x_ai_hi_bipolar,
1013         &range_dt282x_ai_hi_unipolar
1014 };
1015 
1016 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1017 {
1018         if (ispgl) {
1019                 if (x < 0 || x >= 2)
1020                         x = 0;
1021                 return ai_range_pgl_table[x];
1022         }
1023 
1024         if (x < 0 || x >= 4)
1025                 x = 0;
1026         return ai_range_table[x];
1027 }
1028 
1029 static void dt282x_alloc_dma(struct comedi_device *dev,
1030                              struct comedi_devconfig *it)
1031 {
1032         struct dt282x_private *devpriv = dev->private;
1033         unsigned int irq_num = it->options[1];
1034         unsigned int dma_chan[2];
1035 
1036         if (it->options[2] < it->options[3]) {
1037                 dma_chan[0] = it->options[2];
1038                 dma_chan[1] = it->options[3];
1039         } else {
1040                 dma_chan[0] = it->options[3];
1041                 dma_chan[1] = it->options[2];
1042         }
1043 
1044         if (!irq_num || dma_chan[0] == dma_chan[1] ||
1045             dma_chan[0] < 5 || dma_chan[0] > 7 ||
1046             dma_chan[1] < 5 || dma_chan[1] > 7)
1047                 return;
1048 
1049         if (request_irq(irq_num, dt282x_interrupt, 0, dev->board_name, dev))
1050                 return;
1051 
1052         /* DMA uses two 4K buffers with separate DMA channels */
1053         devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan[0], dma_chan[1],
1054                                            PAGE_SIZE, 0);
1055         if (!devpriv->dma)
1056                 free_irq(irq_num, dev);
1057         else
1058                 dev->irq = irq_num;
1059 }
1060 
1061 static void dt282x_free_dma(struct comedi_device *dev)
1062 {
1063         struct dt282x_private *devpriv = dev->private;
1064 
1065         if (devpriv)
1066                 comedi_isadma_free(devpriv->dma);
1067 }
1068 
1069 static int dt282x_initialize(struct comedi_device *dev)
1070 {
1071         /* Initialize board */
1072         outw(DT2821_SUPCSR_BDINIT, dev->iobase + DT2821_SUPCSR_REG);
1073         inw(dev->iobase + DT2821_ADCSR_REG);
1074 
1075         /*
1076          * At power up, some registers are in a well-known state.
1077          * Check them to see if a DT2821 series board is present.
1078          */
1079         if (((inw(dev->iobase + DT2821_ADCSR_REG) & 0xfff0) != 0x7c00) ||
1080             ((inw(dev->iobase + DT2821_CHANCSR_REG) & 0xf0f0) != 0x70f0) ||
1081             ((inw(dev->iobase + DT2821_DACSR_REG) & 0x7c93) != 0x7c90) ||
1082             ((inw(dev->iobase + DT2821_SUPCSR_REG) & 0xf8ff) != 0x0000) ||
1083             ((inw(dev->iobase + DT2821_TMRCTR_REG) & 0xff00) != 0xf000)) {
1084                 dev_err(dev->class_dev, "board not found\n");
1085                 return -EIO;
1086         }
1087         return 0;
1088 }
1089 
1090 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1091 {
1092         const struct dt282x_board *board = dev->board_ptr;
1093         struct dt282x_private *devpriv;
1094         struct comedi_subdevice *s;
1095         int ret;
1096 
1097         ret = comedi_request_region(dev, it->options[0], 0x10);
1098         if (ret)
1099                 return ret;
1100 
1101         ret = dt282x_initialize(dev);
1102         if (ret)
1103                 return ret;
1104 
1105         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1106         if (!devpriv)
1107                 return -ENOMEM;
1108 
1109         /* an IRQ and 2 DMA channels are required for async command support */
1110         dt282x_alloc_dma(dev, it);
1111 
1112         ret = comedi_alloc_subdevices(dev, 3);
1113         if (ret)
1114                 return ret;
1115 
1116         /* Analog Input subdevice */
1117         s = &dev->subdevices[0];
1118         s->type         = COMEDI_SUBD_AI;
1119         s->subdev_flags = SDF_READABLE;
1120         if ((it->options[4] && board->adchan_di) || board->adchan_se == 0) {
1121                 s->subdev_flags |= SDF_DIFF;
1122                 s->n_chan       = board->adchan_di;
1123         } else {
1124                 s->subdev_flags |= SDF_COMMON;
1125                 s->n_chan       = board->adchan_se;
1126         }
1127         s->maxdata      = board->ai_maxdata;
1128 
1129         s->range_table = opt_ai_range_lkup(board->ispgl, it->options[8]);
1130         devpriv->ad_2scomp = it->options[5] ? 1 : 0;
1131 
1132         s->insn_read    = dt282x_ai_insn_read;
1133         if (dev->irq) {
1134                 dev->read_subdev = s;
1135                 s->subdev_flags |= SDF_CMD_READ;
1136                 s->len_chanlist = s->n_chan;
1137                 s->do_cmdtest   = dt282x_ai_cmdtest;
1138                 s->do_cmd       = dt282x_ai_cmd;
1139                 s->cancel       = dt282x_ai_cancel;
1140         }
1141 
1142         /* Analog Output subdevice */
1143         s = &dev->subdevices[1];
1144         if (board->dachan) {
1145                 s->type         = COMEDI_SUBD_AO;
1146                 s->subdev_flags = SDF_WRITABLE;
1147                 s->n_chan       = board->dachan;
1148                 s->maxdata      = board->ao_maxdata;
1149                 /* ranges are per-channel, set by jumpers on the board */
1150                 s->range_table  = &dt282x_ao_range;
1151                 s->insn_write   = dt282x_ao_insn_write;
1152                 if (dev->irq) {
1153                         dev->write_subdev = s;
1154                         s->subdev_flags |= SDF_CMD_WRITE;
1155                         s->len_chanlist = s->n_chan;
1156                         s->do_cmdtest   = dt282x_ao_cmdtest;
1157                         s->do_cmd       = dt282x_ao_cmd;
1158                         s->cancel       = dt282x_ao_cancel;
1159                 }
1160 
1161                 ret = comedi_alloc_subdev_readback(s);
1162                 if (ret)
1163                         return ret;
1164         } else {
1165                 s->type         = COMEDI_SUBD_UNUSED;
1166         }
1167 
1168         /* Digital I/O subdevice */
1169         s = &dev->subdevices[2];
1170         s->type         = COMEDI_SUBD_DIO;
1171         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1172         s->n_chan       = 16;
1173         s->maxdata      = 1;
1174         s->range_table  = &range_digital;
1175         s->insn_bits    = dt282x_dio_insn_bits;
1176         s->insn_config  = dt282x_dio_insn_config;
1177 
1178         return 0;
1179 }
1180 
1181 static void dt282x_detach(struct comedi_device *dev)
1182 {
1183         dt282x_free_dma(dev);
1184         comedi_legacy_detach(dev);
1185 }
1186 
1187 static struct comedi_driver dt282x_driver = {
1188         .driver_name    = "dt282x",
1189         .module         = THIS_MODULE,
1190         .attach         = dt282x_attach,
1191         .detach         = dt282x_detach,
1192         .board_name     = &boardtypes[0].name,
1193         .num_names      = ARRAY_SIZE(boardtypes),
1194         .offset         = sizeof(struct dt282x_board),
1195 };
1196 module_comedi_driver(dt282x_driver);
1197 
1198 MODULE_AUTHOR("Comedi http://www.comedi.org");
1199 MODULE_DESCRIPTION("Comedi driver for Data Translation DT2821 series");
1200 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */