linux/drivers/staging/comedi/drivers/das16.c
<<
>>
Prefs
   1/*
   2 * das16.c
   3 * DAS16 driver
   4 *
   5 * COMEDI - Linux Control and Measurement Device Interface
   6 * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   7 * Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
   8 * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 */
  20
  21/*
  22 * Driver: das16
  23 * Description: DAS16 compatible boards
  24 * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
  25 * Devices: (Keithley Metrabyte) DAS-16 [das-16]
  26 *          (Keithley Metrabyte) DAS-16G [das-16g]
  27 *          (Keithley Metrabyte) DAS-16F [das-16f]
  28 *          (Keithley Metrabyte) DAS-1201 [das-1201]
  29 *          (Keithley Metrabyte) DAS-1202 [das-1202]
  30 *          (Keithley Metrabyte) DAS-1401 [das-1401]
  31 *          (Keithley Metrabyte) DAS-1402 [das-1402]
  32 *          (Keithley Metrabyte) DAS-1601 [das-1601]
  33 *          (Keithley Metrabyte) DAS-1602 [das-1602]
  34 *          (ComputerBoards) PC104-DAS16/JR [pc104-das16jr]
  35 *          (ComputerBoards) PC104-DAS16JR/16 [pc104-das16jr/16]
  36 *          (ComputerBoards) CIO-DAS16 [cio-das16]
  37 *          (ComputerBoards) CIO-DAS16F [cio-das16/f]
  38 *          (ComputerBoards) CIO-DAS16/JR [cio-das16/jr]
  39 *          (ComputerBoards) CIO-DAS16JR/16 [cio-das16jr/16]
  40 *          (ComputerBoards) CIO-DAS1401/12 [cio-das1401/12]
  41 *          (ComputerBoards) CIO-DAS1402/12 [cio-das1402/12]
  42 *          (ComputerBoards) CIO-DAS1402/16 [cio-das1402/16]
  43 *          (ComputerBoards) CIO-DAS1601/12 [cio-das1601/12]
  44 *          (ComputerBoards) CIO-DAS1602/12 [cio-das1602/12]
  45 *          (ComputerBoards) CIO-DAS1602/16 [cio-das1602/16]
  46 *          (ComputerBoards) CIO-DAS16/330 [cio-das16/330]
  47 * Status: works
  48 * Updated: 2003-10-12
  49 *
  50 * A rewrite of the das16 and das1600 drivers.
  51 *
  52 * Options:
  53 *      [0] - base io address
  54 *      [1] - irq (does nothing, irq is not used anymore)
  55 *      [2] - dma channel (optional, required for comedi_command support)
  56 *      [3] - master clock speed in MHz (optional, 1 or 10, ignored if
  57 *              board can probe clock, defaults to 1)
  58 *      [4] - analog input range lowest voltage in microvolts (optional,
  59 *              only useful if your board does not have software
  60 *              programmable gain)
  61 *      [5] - analog input range highest voltage in microvolts (optional,
  62 *              only useful if board does not have software programmable
  63 *              gain)
  64 *      [6] - analog output range lowest voltage in microvolts (optional)
  65 *      [7] - analog output range highest voltage in microvolts (optional)
  66 *
  67 * Passing a zero for an option is the same as leaving it unspecified.
  68 */
  69
  70/*
  71 * Testing and debugging help provided by Daniel Koch.
  72 *
  73 * Keithley Manuals:
  74 *      2309.PDF (das16)
  75 *      4919.PDF (das1400, 1600)
  76 *      4922.PDF (das-1400)
  77 *      4923.PDF (das1200, 1400, 1600)
  78 *
  79 * Computer boards manuals also available from their website
  80 * www.measurementcomputing.com
  81 */
  82
  83#include <linux/module.h>
  84#include <linux/slab.h>
  85#include <linux/delay.h>
  86#include <linux/pci.h>
  87#include <linux/interrupt.h>
  88
  89#include <asm/dma.h>
  90
  91#include "../comedidev.h"
  92
  93#include "8253.h"
  94#include "8255.h"
  95#include "comedi_fc.h"
  96
  97#define DAS16_DMA_SIZE 0xff00   /*  size in bytes of allocated dma buffer */
  98
  99/*
 100 * Register I/O map
 101 */
 102#define DAS16_TRIG_REG                  0x00
 103#define DAS16_AI_LSB_REG                0x00
 104#define DAS16_AI_MSB_REG                0x01
 105#define DAS16_MUX_REG                   0x02
 106#define DAS16_DIO_REG                   0x03
 107#define DAS16_AO_LSB_REG(x)             ((x) ? 0x06 : 0x04)
 108#define DAS16_AO_MSB_REG(x)             ((x) ? 0x07 : 0x05)
 109#define DAS16_STATUS_REG                0x08
 110#define DAS16_STATUS_BUSY               (1 << 7)
 111#define DAS16_STATUS_UNIPOLAR           (1 << 6)
 112#define DAS16_STATUS_MUXBIT             (1 << 5)
 113#define DAS16_STATUS_INT                (1 << 4)
 114#define DAS16_CTRL_REG                  0x09
 115#define DAS16_CTRL_INTE                 (1 << 7)
 116#define DAS16_CTRL_IRQ(x)               (((x) & 0x7) << 4)
 117#define DAS16_CTRL_DMAE                 (1 << 2)
 118#define DAS16_CTRL_PACING_MASK          (3 << 0)
 119#define DAS16_CTRL_INT_PACER            (3 << 0)
 120#define DAS16_CTRL_EXT_PACER            (2 << 0)
 121#define DAS16_CTRL_SOFT_PACER           (0 << 0)
 122#define DAS16_PACER_REG                 0x0a
 123#define DAS16_PACER_BURST_LEN(x)        (((x) & 0xf) << 4)
 124#define DAS16_PACER_CTR0                (1 << 1)
 125#define DAS16_PACER_TRIG0               (1 << 0)
 126#define DAS16_GAIN_REG                  0x0b
 127#define DAS16_TIMER_BASE_REG            0x0c    /* to 0x0f */
 128
 129#define DAS1600_CONV_REG                0x404
 130#define DAS1600_CONV_DISABLE            (1 << 6)
 131#define DAS1600_BURST_REG               0x405
 132#define DAS1600_BURST_VAL               (1 << 6)
 133#define DAS1600_ENABLE_REG              0x406
 134#define DAS1600_ENABLE_VAL              (1 << 6)
 135#define DAS1600_STATUS_REG              0x407
 136#define DAS1600_STATUS_BME              (1 << 6)
 137#define DAS1600_STATUS_ME               (1 << 5)
 138#define DAS1600_STATUS_CD               (1 << 4)
 139#define DAS1600_STATUS_WS               (1 << 1)
 140#define DAS1600_STATUS_CLK_10MHZ        (1 << 0)
 141
 142static const struct comedi_lrange range_das1x01_bip = {
 143        4, {
 144                BIP_RANGE(10),
 145                BIP_RANGE(1),
 146                BIP_RANGE(0.1),
 147                BIP_RANGE(0.01)
 148        }
 149};
 150
 151static const struct comedi_lrange range_das1x01_unip = {
 152        4, {
 153                UNI_RANGE(10),
 154                UNI_RANGE(1),
 155                UNI_RANGE(0.1),
 156                UNI_RANGE(0.01)
 157        }
 158};
 159
 160static const struct comedi_lrange range_das1x02_bip = {
 161        4, {
 162                BIP_RANGE(10),
 163                BIP_RANGE(5),
 164                BIP_RANGE(2.5),
 165                BIP_RANGE(1.25)
 166        }
 167};
 168
 169static const struct comedi_lrange range_das1x02_unip = {
 170        4, {
 171                UNI_RANGE(10),
 172                UNI_RANGE(5),
 173                UNI_RANGE(2.5),
 174                UNI_RANGE(1.25)
 175        }
 176};
 177
 178static const struct comedi_lrange range_das16jr = {
 179        9, {
 180                BIP_RANGE(10),
 181                BIP_RANGE(5),
 182                BIP_RANGE(2.5),
 183                BIP_RANGE(1.25),
 184                BIP_RANGE(0.625),
 185                UNI_RANGE(10),
 186                UNI_RANGE(5),
 187                UNI_RANGE(2.5),
 188                UNI_RANGE(1.25)
 189        }
 190};
 191
 192static const struct comedi_lrange range_das16jr_16 = {
 193        8, {
 194                BIP_RANGE(10),
 195                BIP_RANGE(5),
 196                BIP_RANGE(2.5),
 197                BIP_RANGE(1.25),
 198                UNI_RANGE(10),
 199                UNI_RANGE(5),
 200                UNI_RANGE(2.5),
 201                UNI_RANGE(1.25)
 202        }
 203};
 204
 205static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
 206static const int das16jr_16_gainlist[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
 207static const int das1600_gainlist[] = { 0, 1, 2, 3 };
 208
 209enum {
 210        das16_pg_none = 0,
 211        das16_pg_16jr,
 212        das16_pg_16jr_16,
 213        das16_pg_1601,
 214        das16_pg_1602,
 215};
 216static const int *const das16_gainlists[] = {
 217        NULL,
 218        das16jr_gainlist,
 219        das16jr_16_gainlist,
 220        das1600_gainlist,
 221        das1600_gainlist,
 222};
 223
 224static const struct comedi_lrange *const das16_ai_uni_lranges[] = {
 225        &range_unknown,
 226        &range_das16jr,
 227        &range_das16jr_16,
 228        &range_das1x01_unip,
 229        &range_das1x02_unip,
 230};
 231
 232static const struct comedi_lrange *const das16_ai_bip_lranges[] = {
 233        &range_unknown,
 234        &range_das16jr,
 235        &range_das16jr_16,
 236        &range_das1x01_bip,
 237        &range_das1x02_bip,
 238};
 239
 240struct das16_board {
 241        const char *name;
 242        unsigned int ai_maxdata;
 243        unsigned int ai_speed;  /*  max conversion speed in nanosec */
 244        unsigned int ai_pg;
 245        unsigned int has_ao:1;
 246        unsigned int has_8255:1;
 247
 248        unsigned int i8255_offset;
 249
 250        unsigned int size;
 251        unsigned int id;
 252};
 253
 254static const struct das16_board das16_boards[] = {
 255        {
 256                .name           = "das-16",
 257                .ai_maxdata     = 0x0fff,
 258                .ai_speed       = 15000,
 259                .ai_pg          = das16_pg_none,
 260                .has_ao         = 1,
 261                .has_8255       = 1,
 262                .i8255_offset   = 0x10,
 263                .size           = 0x14,
 264                .id             = 0x00,
 265        }, {
 266                .name           = "das-16g",
 267                .ai_maxdata     = 0x0fff,
 268                .ai_speed       = 15000,
 269                .ai_pg          = das16_pg_none,
 270                .has_ao         = 1,
 271                .has_8255       = 1,
 272                .i8255_offset   = 0x10,
 273                .size           = 0x14,
 274                .id             = 0x00,
 275        }, {
 276                .name           = "das-16f",
 277                .ai_maxdata     = 0x0fff,
 278                .ai_speed       = 8500,
 279                .ai_pg          = das16_pg_none,
 280                .has_ao         = 1,
 281                .has_8255       = 1,
 282                .i8255_offset   = 0x10,
 283                .size           = 0x14,
 284                .id             = 0x00,
 285        }, {
 286                .name           = "cio-das16",
 287                .ai_maxdata     = 0x0fff,
 288                .ai_speed       = 20000,
 289                .ai_pg          = das16_pg_none,
 290                .has_ao         = 1,
 291                .has_8255       = 1,
 292                .i8255_offset   = 0x10,
 293                .size           = 0x14,
 294                .id             = 0x80,
 295        }, {
 296                .name           = "cio-das16/f",
 297                .ai_maxdata     = 0x0fff,
 298                .ai_speed       = 10000,
 299                .ai_pg          = das16_pg_none,
 300                .has_ao         = 1,
 301                .has_8255       = 1,
 302                .i8255_offset   = 0x10,
 303                .size           = 0x14,
 304                .id             = 0x80,
 305        }, {
 306                .name           = "cio-das16/jr",
 307                .ai_maxdata     = 0x0fff,
 308                .ai_speed       = 7692,
 309                .ai_pg          = das16_pg_16jr,
 310                .size           = 0x10,
 311                .id             = 0x00,
 312        }, {
 313                .name           = "pc104-das16jr",
 314                .ai_maxdata     = 0x0fff,
 315                .ai_speed       = 3300,
 316                .ai_pg          = das16_pg_16jr,
 317                .size           = 0x10,
 318                .id             = 0x00,
 319        }, {
 320                .name           = "cio-das16jr/16",
 321                .ai_maxdata     = 0xffff,
 322                .ai_speed       = 10000,
 323                .ai_pg          = das16_pg_16jr_16,
 324                .size           = 0x10,
 325                .id             = 0x00,
 326        }, {
 327                .name           = "pc104-das16jr/16",
 328                .ai_maxdata     = 0xffff,
 329                .ai_speed       = 10000,
 330                .ai_pg          = das16_pg_16jr_16,
 331                .size           = 0x10,
 332                .id             = 0x00,
 333        }, {
 334                .name           = "das-1201",
 335                .ai_maxdata     = 0x0fff,
 336                .ai_speed       = 20000,
 337                .ai_pg          = das16_pg_none,
 338                .has_8255       = 1,
 339                .i8255_offset   = 0x400,
 340                .size           = 0x408,
 341                .id             = 0x20,
 342        }, {
 343                .name           = "das-1202",
 344                .ai_maxdata     = 0x0fff,
 345                .ai_speed       = 10000,
 346                .ai_pg          = das16_pg_none,
 347                .has_8255       = 1,
 348                .i8255_offset   = 0x400,
 349                .size           = 0x408,
 350                .id             = 0x20,
 351        }, {
 352                .name           = "das-1401",
 353                .ai_maxdata     = 0x0fff,
 354                .ai_speed       = 10000,
 355                .ai_pg          = das16_pg_1601,
 356                .size           = 0x408,
 357                .id             = 0xc0,
 358        }, {
 359                .name           = "das-1402",
 360                .ai_maxdata     = 0x0fff,
 361                .ai_speed       = 10000,
 362                .ai_pg          = das16_pg_1602,
 363                .size           = 0x408,
 364                .id             = 0xc0,
 365        }, {
 366                .name           = "das-1601",
 367                .ai_maxdata     = 0x0fff,
 368                .ai_speed       = 10000,
 369                .ai_pg          = das16_pg_1601,
 370                .has_ao         = 1,
 371                .has_8255       = 1,
 372                .i8255_offset   = 0x400,
 373                .size           = 0x408,
 374                .id             = 0xc0,
 375        }, {
 376                .name           = "das-1602",
 377                .ai_maxdata     = 0x0fff,
 378                .ai_speed       = 10000,
 379                .ai_pg          = das16_pg_1602,
 380                .has_ao         = 1,
 381                .has_8255       = 1,
 382                .i8255_offset   = 0x400,
 383                .size           = 0x408,
 384                .id             = 0xc0,
 385        }, {
 386                .name           = "cio-das1401/12",
 387                .ai_maxdata     = 0x0fff,
 388                .ai_speed       = 6250,
 389                .ai_pg          = das16_pg_1601,
 390                .size           = 0x408,
 391                .id             = 0xc0,
 392        }, {
 393                .name           = "cio-das1402/12",
 394                .ai_maxdata     = 0x0fff,
 395                .ai_speed       = 6250,
 396                .ai_pg          = das16_pg_1602,
 397                .size           = 0x408,
 398                .id             = 0xc0,
 399        }, {
 400                .name           = "cio-das1402/16",
 401                .ai_maxdata     = 0xffff,
 402                .ai_speed       = 10000,
 403                .ai_pg          = das16_pg_1602,
 404                .size           = 0x408,
 405                .id             = 0xc0,
 406        }, {
 407                .name           = "cio-das1601/12",
 408                .ai_maxdata     = 0x0fff,
 409                .ai_speed       = 6250,
 410                .ai_pg          = das16_pg_1601,
 411                .has_ao         = 1,
 412                .has_8255       = 1,
 413                .i8255_offset   = 0x400,
 414                .size           = 0x408,
 415                .id             = 0xc0,
 416        }, {
 417                .name           = "cio-das1602/12",
 418                .ai_maxdata     = 0x0fff,
 419                .ai_speed       = 10000,
 420                .ai_pg          = das16_pg_1602,
 421                .has_ao         = 1,
 422                .has_8255       = 1,
 423                .i8255_offset   = 0x400,
 424                .size           = 0x408,
 425                .id             = 0xc0,
 426        }, {
 427                .name           = "cio-das1602/16",
 428                .ai_maxdata     = 0xffff,
 429                .ai_speed       = 10000,
 430                .ai_pg          = das16_pg_1602,
 431                .has_ao         = 1,
 432                .has_8255       = 1,
 433                .i8255_offset   = 0x400,
 434                .size           = 0x408,
 435                .id             = 0xc0,
 436        }, {
 437                .name           = "cio-das16/330",
 438                .ai_maxdata     = 0x0fff,
 439                .ai_speed       = 3030,
 440                .ai_pg          = das16_pg_16jr,
 441                .size           = 0x14,
 442                .id             = 0xf0,
 443        },
 444};
 445
 446/* Period for timer interrupt in jiffies.  It's a function
 447 * to deal with possibility of dynamic HZ patches  */
 448static inline int timer_period(void)
 449{
 450        return HZ / 20;
 451}
 452
 453struct das16_private_struct {
 454        unsigned int            clockbase;
 455        unsigned int            ctrl_reg;
 456        unsigned long           adc_byte_count;
 457        unsigned int            divisor1;
 458        unsigned int            divisor2;
 459        unsigned int            dma_chan;
 460        uint16_t                *dma_buffer[2];
 461        dma_addr_t              dma_buffer_addr[2];
 462        unsigned int            current_buffer;
 463        unsigned int            dma_transfer_size;
 464        struct comedi_lrange    *user_ai_range_table;
 465        struct comedi_lrange    *user_ao_range_table;
 466        struct timer_list       timer;
 467        short                   timer_running;
 468        unsigned long           extra_iobase;
 469        unsigned int            can_burst:1;
 470};
 471
 472static void das16_ai_enable(struct comedi_device *dev,
 473                            unsigned int mode, unsigned int src)
 474{
 475        struct das16_private_struct *devpriv = dev->private;
 476
 477        devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
 478                               DAS16_CTRL_DMAE |
 479                               DAS16_CTRL_PACING_MASK);
 480        devpriv->ctrl_reg |= mode;
 481
 482        if (src == TRIG_EXT)
 483                devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
 484        else
 485                devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
 486        outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
 487}
 488
 489static void das16_ai_disable(struct comedi_device *dev)
 490{
 491        struct das16_private_struct *devpriv = dev->private;
 492
 493        /* disable interrupts, dma and pacer clocked conversions */
 494        devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
 495                               DAS16_CTRL_DMAE |
 496                               DAS16_CTRL_PACING_MASK);
 497        outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
 498}
 499
 500/* the pc104-das16jr (at least) has problems if the dma
 501        transfer is interrupted in the middle of transferring
 502        a 16 bit sample, so this function takes care to get
 503        an even transfer count after disabling dma
 504        channel.
 505*/
 506static int disable_dma_on_even(struct comedi_device *dev)
 507{
 508        struct das16_private_struct *devpriv = dev->private;
 509        int residue;
 510        int i;
 511        static const int disable_limit = 100;
 512        static const int enable_timeout = 100;
 513
 514        disable_dma(devpriv->dma_chan);
 515        residue = get_dma_residue(devpriv->dma_chan);
 516        for (i = 0; i < disable_limit && (residue % 2); ++i) {
 517                int j;
 518                enable_dma(devpriv->dma_chan);
 519                for (j = 0; j < enable_timeout; ++j) {
 520                        int new_residue;
 521                        udelay(2);
 522                        new_residue = get_dma_residue(devpriv->dma_chan);
 523                        if (new_residue != residue)
 524                                break;
 525                }
 526                disable_dma(devpriv->dma_chan);
 527                residue = get_dma_residue(devpriv->dma_chan);
 528        }
 529        if (i == disable_limit) {
 530                dev_err(dev->class_dev,
 531                        "failed to get an even dma transfer, could be trouble\n");
 532        }
 533        return residue;
 534}
 535
 536static void das16_interrupt(struct comedi_device *dev)
 537{
 538        struct das16_private_struct *devpriv = dev->private;
 539        struct comedi_subdevice *s = dev->read_subdev;
 540        struct comedi_async *async = s->async;
 541        struct comedi_cmd *cmd = &async->cmd;
 542        unsigned long spin_flags;
 543        unsigned long dma_flags;
 544        int num_bytes, residue;
 545        int buffer_index;
 546
 547        spin_lock_irqsave(&dev->spinlock, spin_flags);
 548        if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) {
 549                spin_unlock_irqrestore(&dev->spinlock, spin_flags);
 550                return;
 551        }
 552
 553        dma_flags = claim_dma_lock();
 554        clear_dma_ff(devpriv->dma_chan);
 555        residue = disable_dma_on_even(dev);
 556
 557        /*  figure out how many points to read */
 558        if (residue > devpriv->dma_transfer_size) {
 559                dev_err(dev->class_dev, "residue > transfer size!\n");
 560                async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 561                num_bytes = 0;
 562        } else
 563                num_bytes = devpriv->dma_transfer_size - residue;
 564
 565        if (cmd->stop_src == TRIG_COUNT &&
 566                                        num_bytes >= devpriv->adc_byte_count) {
 567                num_bytes = devpriv->adc_byte_count;
 568                async->events |= COMEDI_CB_EOA;
 569        }
 570
 571        buffer_index = devpriv->current_buffer;
 572        devpriv->current_buffer = (devpriv->current_buffer + 1) % 2;
 573        devpriv->adc_byte_count -= num_bytes;
 574
 575        /*  re-enable  dma */
 576        if ((async->events & COMEDI_CB_EOA) == 0) {
 577                set_dma_addr(devpriv->dma_chan,
 578                             devpriv->dma_buffer_addr[devpriv->current_buffer]);
 579                set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
 580                enable_dma(devpriv->dma_chan);
 581        }
 582        release_dma_lock(dma_flags);
 583
 584        spin_unlock_irqrestore(&dev->spinlock, spin_flags);
 585
 586        cfc_write_array_to_buffer(s,
 587                                  devpriv->dma_buffer[buffer_index], num_bytes);
 588
 589        cfc_handle_events(dev, s);
 590}
 591
 592static void das16_timer_interrupt(unsigned long arg)
 593{
 594        struct comedi_device *dev = (struct comedi_device *)arg;
 595        struct das16_private_struct *devpriv = dev->private;
 596
 597        das16_interrupt(dev);
 598
 599        if (devpriv->timer_running)
 600                mod_timer(&devpriv->timer, jiffies + timer_period());
 601}
 602
 603static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
 604                          struct comedi_cmd *cmd)
 605{
 606        const struct das16_board *board = comedi_board(dev);
 607        struct das16_private_struct *devpriv = dev->private;
 608        int err = 0, tmp;
 609        int gain, start_chan, i;
 610        int mask;
 611
 612        /* Step 1 : check if triggers are trivially valid */
 613
 614        err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
 615
 616        mask = TRIG_FOLLOW;
 617        if (devpriv->can_burst)
 618                mask |= TRIG_TIMER | TRIG_EXT;
 619        err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask);
 620
 621        tmp = cmd->convert_src;
 622        mask = TRIG_TIMER | TRIG_EXT;
 623        if (devpriv->can_burst)
 624                mask |= TRIG_NOW;
 625        err |= cfc_check_trigger_src(&cmd->convert_src, mask);
 626
 627        err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 628        err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 629
 630        if (err)
 631                return 1;
 632
 633        /* Step 2a : make sure trigger sources are unique */
 634
 635        err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
 636        err |= cfc_check_trigger_is_unique(cmd->convert_src);
 637        err |= cfc_check_trigger_is_unique(cmd->stop_src);
 638
 639        /* Step 2b : and mutually compatible */
 640
 641        /*  make sure scan_begin_src and convert_src dont conflict */
 642        if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
 643                err |= -EINVAL;
 644        if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
 645                err |= -EINVAL;
 646
 647        if (err)
 648                return 2;
 649
 650        /* Step 3: check if arguments are trivially valid */
 651
 652        err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
 653
 654        if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */
 655                err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 656
 657        err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
 658
 659        /* check against maximum frequency */
 660        if (cmd->scan_begin_src == TRIG_TIMER)
 661                err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
 662                                        board->ai_speed * cmd->chanlist_len);
 663
 664        if (cmd->convert_src == TRIG_TIMER)
 665                err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
 666                                                 board->ai_speed);
 667
 668        if (cmd->stop_src == TRIG_NONE)
 669                err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
 670
 671        if (err)
 672                return 3;
 673
 674        /*  step 4: fix up arguments */
 675        if (cmd->scan_begin_src == TRIG_TIMER) {
 676                unsigned int tmp = cmd->scan_begin_arg;
 677                /*  set divisors, correct timing arguments */
 678                i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
 679                                               &devpriv->divisor1,
 680                                               &devpriv->divisor2,
 681                                               &cmd->scan_begin_arg,
 682                                               cmd->flags & TRIG_ROUND_MASK);
 683                err += (tmp != cmd->scan_begin_arg);
 684        }
 685        if (cmd->convert_src == TRIG_TIMER) {
 686                unsigned int tmp = cmd->convert_arg;
 687                /*  set divisors, correct timing arguments */
 688                i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
 689                                               &devpriv->divisor1,
 690                                               &devpriv->divisor2,
 691                                               &cmd->convert_arg,
 692                                               cmd->flags & TRIG_ROUND_MASK);
 693                err += (tmp != cmd->convert_arg);
 694        }
 695        if (err)
 696                return 4;
 697
 698        /*  check channel/gain list against card's limitations */
 699        if (cmd->chanlist) {
 700                gain = CR_RANGE(cmd->chanlist[0]);
 701                start_chan = CR_CHAN(cmd->chanlist[0]);
 702                for (i = 1; i < cmd->chanlist_len; i++) {
 703                        if (CR_CHAN(cmd->chanlist[i]) !=
 704                            (start_chan + i) % s->n_chan) {
 705                                dev_err(dev->class_dev,
 706                                        "entries in chanlist must be consecutive channels, counting upwards\n");
 707                                err++;
 708                        }
 709                        if (CR_RANGE(cmd->chanlist[i]) != gain) {
 710                                dev_err(dev->class_dev,
 711                                        "entries in chanlist must all have the same gain\n");
 712                                err++;
 713                        }
 714                }
 715        }
 716        if (err)
 717                return 5;
 718
 719        return 0;
 720}
 721
 722static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
 723                                    int rounding_flags)
 724{
 725        struct das16_private_struct *devpriv = dev->private;
 726        unsigned long timer_base = dev->iobase + DAS16_TIMER_BASE_REG;
 727
 728        i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
 729                                       &devpriv->divisor1,
 730                                       &devpriv->divisor2,
 731                                       &ns,
 732                                       rounding_flags & TRIG_ROUND_MASK);
 733
 734        /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
 735        i8254_load(timer_base, 0, 1, devpriv->divisor1, 2);
 736        i8254_load(timer_base, 0, 2, devpriv->divisor2, 2);
 737
 738        return ns;
 739}
 740
 741static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 742{
 743        const struct das16_board *board = comedi_board(dev);
 744        struct das16_private_struct *devpriv = dev->private;
 745        struct comedi_async *async = s->async;
 746        struct comedi_cmd *cmd = &async->cmd;
 747        unsigned int byte;
 748        unsigned long flags;
 749        int range;
 750
 751        if (cmd->flags & TRIG_RT) {
 752                dev_err(dev->class_dev,
 753                         "isa dma transfers cannot be performed with TRIG_RT, aborting\n");
 754                return -1;
 755        }
 756
 757        devpriv->adc_byte_count =
 758            cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t);
 759
 760        if (devpriv->can_burst)
 761                outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG);
 762
 763        /*  set scan limits */
 764        byte = CR_CHAN(cmd->chanlist[0]);
 765        byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4;
 766        outb(byte, dev->iobase + DAS16_MUX_REG);
 767
 768        /* set gain (this is also burst rate register but according to
 769         * computer boards manual, burst rate does nothing, even on
 770         * keithley cards) */
 771        if (board->ai_pg != das16_pg_none) {
 772                range = CR_RANGE(cmd->chanlist[0]);
 773                outb((das16_gainlists[board->ai_pg])[range],
 774                     dev->iobase + DAS16_GAIN_REG);
 775        }
 776
 777        /* set counter mode and counts */
 778        cmd->convert_arg =
 779            das16_set_pacer(dev, cmd->convert_arg,
 780                            cmd->flags & TRIG_ROUND_MASK);
 781
 782        /* enable counters */
 783        byte = 0;
 784        if (devpriv->can_burst) {
 785                if (cmd->convert_src == TRIG_NOW) {
 786                        outb(DAS1600_BURST_VAL,
 787                             dev->iobase + DAS1600_BURST_REG);
 788                        /*  set burst length */
 789                        byte |= DAS16_PACER_BURST_LEN(cmd->chanlist_len - 1);
 790                } else {
 791                        outb(0, dev->iobase + DAS1600_BURST_REG);
 792                }
 793        }
 794        outb(byte, dev->iobase + DAS16_PACER_REG);
 795
 796        /*  set up dma transfer */
 797        flags = claim_dma_lock();
 798        disable_dma(devpriv->dma_chan);
 799        /* clear flip-flop to make sure 2-byte registers for
 800         * count and address get set correctly */
 801        clear_dma_ff(devpriv->dma_chan);
 802        devpriv->current_buffer = 0;
 803        set_dma_addr(devpriv->dma_chan,
 804                     devpriv->dma_buffer_addr[devpriv->current_buffer]);
 805        devpriv->dma_transfer_size = DAS16_DMA_SIZE;
 806        set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
 807        enable_dma(devpriv->dma_chan);
 808        release_dma_lock(flags);
 809
 810        /*  set up interrupt */
 811        devpriv->timer_running = 1;
 812        devpriv->timer.expires = jiffies + timer_period();
 813        add_timer(&devpriv->timer);
 814
 815        das16_ai_enable(dev, DAS16_CTRL_DMAE, cmd->convert_src);
 816
 817        if (devpriv->can_burst)
 818                outb(0, dev->iobase + DAS1600_CONV_REG);
 819
 820        return 0;
 821}
 822
 823static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 824{
 825        struct das16_private_struct *devpriv = dev->private;
 826        unsigned long flags;
 827
 828        spin_lock_irqsave(&dev->spinlock, flags);
 829
 830        das16_ai_disable(dev);
 831        disable_dma(devpriv->dma_chan);
 832
 833        /*  disable SW timer */
 834        if (devpriv->timer_running) {
 835                devpriv->timer_running = 0;
 836                del_timer(&devpriv->timer);
 837        }
 838
 839        if (devpriv->can_burst)
 840                outb(0, dev->iobase + DAS1600_BURST_REG);
 841
 842        spin_unlock_irqrestore(&dev->spinlock, flags);
 843
 844        return 0;
 845}
 846
 847static void das16_ai_munge(struct comedi_device *dev,
 848                           struct comedi_subdevice *s, void *array,
 849                           unsigned int num_bytes,
 850                           unsigned int start_chan_index)
 851{
 852        unsigned int i, num_samples = num_bytes / sizeof(short);
 853        short *data = array;
 854
 855        for (i = 0; i < num_samples; i++) {
 856                data[i] = le16_to_cpu(data[i]);
 857                if (s->maxdata == 0x0fff)
 858                        data[i] >>= 4;
 859                data[i] &= s->maxdata;
 860        }
 861}
 862
 863static int das16_ai_wait_for_conv(struct comedi_device *dev,
 864                                  unsigned int timeout)
 865{
 866        unsigned int status;
 867        int i;
 868
 869        for (i = 0; i < timeout; i++) {
 870                status = inb(dev->iobase + DAS16_STATUS_REG);
 871                if (!(status & DAS16_STATUS_BUSY))
 872                        return 0;
 873        }
 874        return -ETIME;
 875}
 876
 877static int das16_ai_insn_read(struct comedi_device *dev,
 878                              struct comedi_subdevice *s,
 879                              struct comedi_insn *insn,
 880                              unsigned int *data)
 881{
 882        const struct das16_board *board = comedi_board(dev);
 883        unsigned int chan = CR_CHAN(insn->chanspec);
 884        unsigned int range = CR_RANGE(insn->chanspec);
 885        unsigned int val;
 886        int ret;
 887        int i;
 888
 889        das16_ai_disable(dev);
 890
 891        /* set multiplexer */
 892        outb(chan | (chan << 4), dev->iobase + DAS16_MUX_REG);
 893
 894        /* set gain */
 895        if (board->ai_pg != das16_pg_none) {
 896                outb((das16_gainlists[board->ai_pg])[range],
 897                     dev->iobase + DAS16_GAIN_REG);
 898        }
 899
 900        for (i = 0; i < insn->n; i++) {
 901                /* trigger conversion */
 902                outb_p(0, dev->iobase + DAS16_TRIG_REG);
 903
 904                ret = das16_ai_wait_for_conv(dev, 1000);
 905                if (ret)
 906                        return ret;
 907
 908                val = inb(dev->iobase + DAS16_AI_MSB_REG) << 8;
 909                val |= inb(dev->iobase + DAS16_AI_LSB_REG);
 910                if (s->maxdata == 0x0fff)
 911                        val >>= 4;
 912                val &= s->maxdata;
 913
 914                data[i] = val;
 915        }
 916
 917        return insn->n;
 918}
 919
 920static int das16_ao_insn_write(struct comedi_device *dev,
 921                               struct comedi_subdevice *s,
 922                               struct comedi_insn *insn,
 923                               unsigned int *data)
 924{
 925        unsigned int chan = CR_CHAN(insn->chanspec);
 926        unsigned int val;
 927        int i;
 928
 929        for (i = 0; i < insn->n; i++) {
 930                val = data[i];
 931                val <<= 4;
 932
 933                outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan));
 934                outb((val >> 8) & 0xff, dev->iobase + DAS16_AO_MSB_REG(chan));
 935        }
 936
 937        return insn->n;
 938}
 939
 940static int das16_di_insn_bits(struct comedi_device *dev,
 941                              struct comedi_subdevice *s,
 942                              struct comedi_insn *insn,
 943                              unsigned int *data)
 944{
 945        data[1] = inb(dev->iobase + DAS16_DIO_REG) & 0xf;
 946
 947        return insn->n;
 948}
 949
 950static int das16_do_insn_bits(struct comedi_device *dev,
 951                              struct comedi_subdevice *s,
 952                              struct comedi_insn *insn,
 953                              unsigned int *data)
 954{
 955        unsigned int mask = data[0];
 956        unsigned int bits = data[1];
 957
 958        if (mask) {
 959                s->state &= ~mask;
 960                s->state |= (bits & mask);
 961
 962                outb(s->state, dev->iobase + DAS16_DIO_REG);
 963        }
 964
 965        data[1] = s->state;
 966
 967        return insn->n;
 968}
 969
 970static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
 971{
 972        const struct das16_board *board = comedi_board(dev);
 973        int diobits;
 974
 975        /* diobits indicates boards */
 976        diobits = inb(dev->iobase + DAS16_DIO_REG) & 0xf0;
 977        if (board->id != diobits) {
 978                dev_err(dev->class_dev,
 979                        "requested board's id bits are incorrect (0x%x != 0x%x)\n",
 980                        board->id, diobits);
 981                return -EINVAL;
 982        }
 983
 984        return 0;
 985}
 986
 987static void das16_reset(struct comedi_device *dev)
 988{
 989        outb(0, dev->iobase + DAS16_STATUS_REG);
 990        outb(0, dev->iobase + DAS16_CTRL_REG);
 991        outb(0, dev->iobase + DAS16_PACER_REG);
 992        outb(0, dev->iobase + DAS16_TIMER_BASE_REG + i8254_control_reg);
 993}
 994
 995static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 996{
 997        const struct das16_board *board = comedi_board(dev);
 998        struct das16_private_struct *devpriv;
 999        struct comedi_subdevice *s;
1000        struct comedi_lrange *lrange;
1001        struct comedi_krange *krange;
1002        unsigned int dma_chan = it->options[2];
1003        unsigned int status;
1004        int ret;
1005
1006        /*  check that clock setting is valid */
1007        if (it->options[3]) {
1008                if (it->options[3] != 0 &&
1009                    it->options[3] != 1 && it->options[3] != 10) {
1010                        dev_err(dev->class_dev,
1011                                "Invalid option. Master clock must be set to 1 or 10 (MHz)\n");
1012                        return -EINVAL;
1013                }
1014        }
1015
1016        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1017        if (!devpriv)
1018                return -ENOMEM;
1019
1020        if (board->size < 0x400) {
1021                ret = comedi_request_region(dev, it->options[0], board->size);
1022                if (ret)
1023                        return ret;
1024        } else {
1025                ret = comedi_request_region(dev, it->options[0], 0x10);
1026                if (ret)
1027                        return ret;
1028                /* Request an additional region for the 8255 */
1029                ret = __comedi_request_region(dev, dev->iobase + 0x400,
1030                                              board->size & 0x3ff);
1031                if (ret)
1032                        return ret;
1033                devpriv->extra_iobase = dev->iobase + 0x400;
1034                devpriv->can_burst = 1;
1035        }
1036
1037        /*  probe id bits to make sure they are consistent */
1038        if (das16_probe(dev, it))
1039                return -EINVAL;
1040
1041        /*  get master clock speed */
1042        if (devpriv->can_burst) {
1043                status = inb(dev->iobase + DAS1600_STATUS_REG);
1044
1045                if (status & DAS1600_STATUS_CLK_10MHZ)
1046                        devpriv->clockbase = 100;
1047                else
1048                        devpriv->clockbase = 1000;
1049        } else {
1050                if (it->options[3])
1051                        devpriv->clockbase = 1000 / it->options[3];
1052                else
1053                        devpriv->clockbase = 1000;      /*  1 MHz default */
1054        }
1055
1056        /* initialize dma */
1057        if (dma_chan == 1 || dma_chan == 3) {
1058                unsigned long flags;
1059                int i;
1060
1061                if (request_dma(dma_chan, dev->board_name)) {
1062                        dev_err(dev->class_dev,
1063                                "failed to request dma channel %i\n",
1064                                dma_chan);
1065                        return -EINVAL;
1066                }
1067                devpriv->dma_chan = dma_chan;
1068
1069                /* allocate dma buffers */
1070                for (i = 0; i < 2; i++) {
1071                        void *p;
1072
1073                        p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE,
1074                                                 &devpriv->dma_buffer_addr[i]);
1075                        if (!p)
1076                                return -ENOMEM;
1077                        devpriv->dma_buffer[i] = p;
1078                }
1079
1080                flags = claim_dma_lock();
1081                disable_dma(devpriv->dma_chan);
1082                set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
1083                release_dma_lock(flags);
1084
1085                init_timer(&devpriv->timer);
1086                devpriv->timer.function = das16_timer_interrupt;
1087                devpriv->timer.data = (unsigned long)dev;
1088        }
1089
1090        /* get any user-defined input range */
1091        if (board->ai_pg == das16_pg_none &&
1092            (it->options[4] || it->options[5])) {
1093                /* allocate single-range range table */
1094                lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
1095                if (!lrange)
1096                        return -ENOMEM;
1097
1098                /* initialize ai range */
1099                devpriv->user_ai_range_table = lrange;
1100                lrange->length = 1;
1101                krange = devpriv->user_ai_range_table->range;
1102                krange->min = it->options[4];
1103                krange->max = it->options[5];
1104                krange->flags = UNIT_volt;
1105        }
1106
1107        /* get any user-defined output range */
1108        if (it->options[6] || it->options[7]) {
1109                /* allocate single-range range table */
1110                lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
1111                if (!lrange)
1112                        return -ENOMEM;
1113
1114                /* initialize ao range */
1115                devpriv->user_ao_range_table = lrange;
1116                lrange->length = 1;
1117                krange = devpriv->user_ao_range_table->range;
1118                krange->min = it->options[6];
1119                krange->max = it->options[7];
1120                krange->flags = UNIT_volt;
1121        }
1122
1123        ret = comedi_alloc_subdevices(dev, 4 + board->has_8255);
1124        if (ret)
1125                return ret;
1126
1127        status = inb(dev->iobase + DAS16_STATUS_REG);
1128
1129        /* Analog Input subdevice */
1130        s = &dev->subdevices[0];
1131        s->type         = COMEDI_SUBD_AI;
1132        s->subdev_flags = SDF_READABLE;
1133        if (status & DAS16_STATUS_MUXBIT) {
1134                s->subdev_flags |= SDF_GROUND;
1135                s->n_chan       = 16;
1136        } else {
1137                s->subdev_flags |= SDF_DIFF;
1138                s->n_chan       = 8;
1139        }
1140        s->len_chanlist = s->n_chan;
1141        s->maxdata      = board->ai_maxdata;
1142        if (devpriv->user_ai_range_table) { /*  user defined ai range */
1143                s->range_table  = devpriv->user_ai_range_table;
1144        } else if (status & DAS16_STATUS_UNIPOLAR) {
1145                s->range_table  = das16_ai_uni_lranges[board->ai_pg];
1146        } else {
1147                s->range_table  = das16_ai_bip_lranges[board->ai_pg];
1148        }
1149        s->insn_read    = das16_ai_insn_read;
1150        if (devpriv->dma_chan) {
1151                dev->read_subdev = s;
1152                s->subdev_flags |= SDF_CMD_READ;
1153                s->do_cmdtest   = das16_cmd_test;
1154                s->do_cmd       = das16_cmd_exec;
1155                s->cancel       = das16_cancel;
1156                s->munge        = das16_ai_munge;
1157        }
1158
1159        /* Analog Output subdevice */
1160        s = &dev->subdevices[1];
1161        if (board->has_ao) {
1162                s->type         = COMEDI_SUBD_AO;
1163                s->subdev_flags = SDF_WRITABLE;
1164                s->n_chan       = 2;
1165                s->maxdata      = 0x0fff;
1166                s->range_table  = devpriv->user_ao_range_table;
1167                s->insn_write   = das16_ao_insn_write;
1168        } else {
1169                s->type         = COMEDI_SUBD_UNUSED;
1170        }
1171
1172        /* Digital Input subdevice */
1173        s = &dev->subdevices[2];
1174        s->type         = COMEDI_SUBD_DI;
1175        s->subdev_flags = SDF_READABLE;
1176        s->n_chan       = 4;
1177        s->maxdata      = 1;
1178        s->range_table  = &range_digital;
1179        s->insn_bits    = das16_di_insn_bits;
1180
1181        /* Digital Output subdevice */
1182        s = &dev->subdevices[3];
1183        s->type         = COMEDI_SUBD_DO;
1184        s->subdev_flags = SDF_WRITABLE;
1185        s->n_chan       = 4;
1186        s->maxdata      = 1;
1187        s->range_table  = &range_digital;
1188        s->insn_bits    = das16_do_insn_bits;
1189
1190        /* initialize digital output lines */
1191        outb(s->state, dev->iobase + DAS16_DIO_REG);
1192
1193        /* 8255 Digital I/O subdevice */
1194        if (board->has_8255) {
1195                s = &dev->subdevices[4];
1196                ret = subdev_8255_init(dev, s, NULL,
1197                                       dev->iobase + board->i8255_offset);
1198                if (ret)
1199                        return ret;
1200        }
1201
1202        das16_reset(dev);
1203        /* set the interrupt level */
1204        devpriv->ctrl_reg = DAS16_CTRL_IRQ(dev->irq);
1205        outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
1206
1207        if (devpriv->can_burst) {
1208                outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE_REG);
1209                outb(0, dev->iobase + DAS1600_CONV_REG);
1210                outb(0, dev->iobase + DAS1600_BURST_REG);
1211        }
1212
1213        return 0;
1214}
1215
1216static void das16_detach(struct comedi_device *dev)
1217{
1218        const struct das16_board *board = comedi_board(dev);
1219        struct das16_private_struct *devpriv = dev->private;
1220        int i;
1221
1222        if (devpriv) {
1223                if (dev->iobase)
1224                        das16_reset(dev);
1225
1226                for (i = 0; i < 2; i++) {
1227                        if (devpriv->dma_buffer[i])
1228                                pci_free_consistent(NULL, DAS16_DMA_SIZE,
1229                                                    devpriv->dma_buffer[i],
1230                                                    devpriv->
1231                                                    dma_buffer_addr[i]);
1232                }
1233                if (devpriv->dma_chan)
1234                        free_dma(devpriv->dma_chan);
1235                kfree(devpriv->user_ai_range_table);
1236                kfree(devpriv->user_ao_range_table);
1237
1238                if (devpriv->extra_iobase)
1239                        release_region(devpriv->extra_iobase,
1240                                       board->size & 0x3ff);
1241        }
1242
1243        comedi_legacy_detach(dev);
1244}
1245
1246static struct comedi_driver das16_driver = {
1247        .driver_name    = "das16",
1248        .module         = THIS_MODULE,
1249        .attach         = das16_attach,
1250        .detach         = das16_detach,
1251        .board_name     = &das16_boards[0].name,
1252        .num_names      = ARRAY_SIZE(das16_boards),
1253        .offset         = sizeof(das16_boards[0]),
1254};
1255module_comedi_driver(das16_driver);
1256
1257MODULE_AUTHOR("Comedi http://www.comedi.org");
1258MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards");
1259MODULE_LICENSE("GPL");
1260