linux/drivers/staging/comedi/drivers/dmm32at.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/dmm32at.c
   3    Diamond Systems mm32at code for a Comedi driver
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   7
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 2 of the License, or
  11    (at your option) any later version.
  12
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17
  18    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21
  22*/
  23/*
  24Driver: dmm32at
  25Description: Diamond Systems mm32at driver.
  26Devices:
  27Author: Perry J. Piplani <perry.j.piplani@nasa.gov>
  28Updated: Fri Jun  4 09:13:24 CDT 2004
  29Status: experimental
  30
  31This driver is for the Diamond Systems MM-32-AT board
  32http://www.diamondsystems.com/products/diamondmm32at It is being used
  33on serveral projects inside NASA, without problems so far. For analog
  34input commands, TRIG_EXT is not yet supported at all..
  35
  36Configuration Options:
  37  comedi_config /dev/comedi0 dmm32at baseaddr,irq
  38*/
  39
  40/*
  41 * The previous block comment is used to automatically generate
  42 * documentation in Comedi and Comedilib.  The fields:
  43 *
  44 * Driver: the name of the driver
  45 * Description: a short phrase describing the driver.  Don't list boards.
  46 * Devices: a full list of the boards that attempt to be supported by
  47 *   the driver.  Format is "(manufacturer) board name [comedi name]",
  48 *   where comedi_name is the name that is used to configure the board.
  49 *   See the comment near board_name: in the struct comedi_driver structure
  50 *   below.  If (manufacturer) or [comedi name] is missing, the previous
  51 *   value is used.
  52 * Author: you
  53 * Updated: date when the _documentation_ was last updated.  Use 'date -R'
  54 *   to get a value for this.
  55 * Status: a one-word description of the status.  Valid values are:
  56 *   works - driver works correctly on most boards supported, and
  57 *     passes comedi_test.
  58 *   unknown - unknown.  Usually put there by ds.
  59 *   experimental - may not work in any particular release.  Author
  60 *     probably wants assistance testing it.
  61 *   bitrotten - driver has not been update in a long time, probably
  62 *     doesn't work, and probably is missing support for significant
  63 *     Comedi interface features.
  64 *   untested - author probably wrote it "blind", and is believed to
  65 *     work, but no confirmation.
  66 *
  67 * These headers should be followed by a blank line, and any comments
  68 * you wish to say about the driver.  The comment area is the place
  69 * to put any known bugs, limitations, unsupported features, supported
  70 * command triggers, whether or not commands are supported on particular
  71 * subdevices, etc.
  72 *
  73 * Somewhere in the comment should be information about configuration
  74 * options that are used with comedi_config.
  75 */
  76
  77#include <linux/interrupt.h>
  78#include "../comedidev.h"
  79#include <linux/ioport.h>
  80
  81/* Board register addresses */
  82
  83#define DMM32AT_MEMSIZE 0x10
  84
  85#define DMM32AT_CONV 0x00
  86#define DMM32AT_AILSB 0x00
  87#define DMM32AT_AUXDOUT 0x01
  88#define DMM32AT_AIMSB 0x01
  89#define DMM32AT_AILOW 0x02
  90#define DMM32AT_AIHIGH 0x03
  91
  92#define DMM32AT_DACLSB 0x04
  93#define DMM32AT_DACSTAT 0x04
  94#define DMM32AT_DACMSB 0x05
  95
  96#define DMM32AT_FIFOCNTRL 0x07
  97#define DMM32AT_FIFOSTAT 0x07
  98
  99#define DMM32AT_CNTRL 0x08
 100#define DMM32AT_AISTAT 0x08
 101
 102#define DMM32AT_INTCLOCK 0x09
 103
 104#define DMM32AT_CNTRDIO 0x0a
 105
 106#define DMM32AT_AICONF 0x0b
 107#define DMM32AT_AIRBACK 0x0b
 108
 109#define DMM32AT_CLK1 0x0d
 110#define DMM32AT_CLK2 0x0e
 111#define DMM32AT_CLKCT 0x0f
 112
 113#define DMM32AT_DIOA 0x0c
 114#define DMM32AT_DIOB 0x0d
 115#define DMM32AT_DIOC 0x0e
 116#define DMM32AT_DIOCONF 0x0f
 117
 118#define dmm_inb(cdev, reg) inb((cdev->iobase)+reg)
 119#define dmm_outb(cdev, reg, valu) outb(valu, (cdev->iobase)+reg)
 120
 121/* Board register values. */
 122
 123/* DMM32AT_DACSTAT 0x04 */
 124#define DMM32AT_DACBUSY 0x80
 125
 126/* DMM32AT_FIFOCNTRL 0x07 */
 127#define DMM32AT_FIFORESET 0x02
 128#define DMM32AT_SCANENABLE 0x04
 129
 130/* DMM32AT_CNTRL 0x08 */
 131#define DMM32AT_RESET 0x20
 132#define DMM32AT_INTRESET 0x08
 133#define DMM32AT_CLKACC 0x00
 134#define DMM32AT_DIOACC 0x01
 135
 136/* DMM32AT_AISTAT 0x08 */
 137#define DMM32AT_STATUS 0x80
 138
 139/* DMM32AT_INTCLOCK 0x09 */
 140#define DMM32AT_ADINT 0x80
 141#define DMM32AT_CLKSEL 0x03
 142
 143/* DMM32AT_CNTRDIO 0x0a */
 144#define DMM32AT_FREQ12 0x80
 145
 146/* DMM32AT_AICONF 0x0b */
 147#define DMM32AT_RANGE_U10 0x0c
 148#define DMM32AT_RANGE_U5 0x0d
 149#define DMM32AT_RANGE_B10 0x08
 150#define DMM32AT_RANGE_B5 0x00
 151#define DMM32AT_SCINT_20 0x00
 152#define DMM32AT_SCINT_15 0x10
 153#define DMM32AT_SCINT_10 0x20
 154#define DMM32AT_SCINT_5 0x30
 155
 156/* DMM32AT_CLKCT 0x0f */
 157#define DMM32AT_CLKCT1 0x56     /* mode3 counter 1 - write low byte only */
 158#define DMM32AT_CLKCT2 0xb6     /*  mode3 counter 2 - write high and low byte */
 159
 160/* DMM32AT_DIOCONF 0x0f */
 161#define DMM32AT_DIENABLE 0x80
 162#define DMM32AT_DIRA 0x10
 163#define DMM32AT_DIRB 0x02
 164#define DMM32AT_DIRCL 0x01
 165#define DMM32AT_DIRCH 0x08
 166
 167/* board AI ranges in comedi structure */
 168static const struct comedi_lrange dmm32at_airanges = {
 169        4,
 170        {
 171         UNI_RANGE(10),
 172         UNI_RANGE(5),
 173         BIP_RANGE(10),
 174         BIP_RANGE(5),
 175         }
 176};
 177
 178/* register values for above ranges */
 179static const unsigned char dmm32at_rangebits[] = {
 180        DMM32AT_RANGE_U10,
 181        DMM32AT_RANGE_U5,
 182        DMM32AT_RANGE_B10,
 183        DMM32AT_RANGE_B5,
 184};
 185
 186/* only one of these ranges is valid, as set by a jumper on the
 187 * board. The application should only use the range set by the jumper
 188 */
 189static const struct comedi_lrange dmm32at_aoranges = {
 190        4,
 191        {
 192         UNI_RANGE(10),
 193         UNI_RANGE(5),
 194         BIP_RANGE(10),
 195         BIP_RANGE(5),
 196         }
 197};
 198
 199/*
 200 * Board descriptions for two imaginary boards.  Describing the
 201 * boards in this way is optional, and completely driver-dependent.
 202 * Some drivers use arrays such as this, other do not.
 203 */
 204struct dmm32at_board {
 205        const char *name;
 206        int ai_chans;
 207        int ai_bits;
 208        const struct comedi_lrange *ai_ranges;
 209        int ao_chans;
 210        int ao_bits;
 211        const struct comedi_lrange *ao_ranges;
 212        int have_dio;
 213        int dio_chans;
 214};
 215static const struct dmm32at_board dmm32at_boards[] = {
 216        {
 217         .name = "dmm32at",
 218         .ai_chans = 32,
 219         .ai_bits = 16,
 220         .ai_ranges = &dmm32at_airanges,
 221         .ao_chans = 4,
 222         .ao_bits = 12,
 223         .ao_ranges = &dmm32at_aoranges,
 224         .have_dio = 1,
 225         .dio_chans = 24,
 226         },
 227};
 228
 229/*
 230 * Useful for shorthand access to the particular board structure
 231 */
 232#define thisboard ((const struct dmm32at_board *)dev->board_ptr)
 233
 234/* this structure is for data unique to this hardware driver.  If
 235 * several hardware drivers keep similar information in this structure,
 236 * feel free to suggest moving the variable to the struct comedi_device struct.
 237 */
 238struct dmm32at_private {
 239
 240        int data;
 241        int ai_inuse;
 242        unsigned int ai_scans_left;
 243
 244        /* Used for AO readback */
 245        unsigned int ao_readback[4];
 246        unsigned char dio_config;
 247
 248};
 249
 250/*
 251 * most drivers define the following macro to make it easy to
 252 * access the private structure.
 253 */
 254#define devpriv ((struct dmm32at_private *)dev->private)
 255
 256/*
 257 * The struct comedi_driver structure tells the Comedi core module
 258 * which functions to call to configure/deconfigure (attach/detach)
 259 * the board, and also about the kernel module that contains
 260 * the device code.
 261 */
 262static int dmm32at_attach(struct comedi_device *dev,
 263                          struct comedi_devconfig *it);
 264static int dmm32at_detach(struct comedi_device *dev);
 265static struct comedi_driver driver_dmm32at = {
 266        .driver_name = "dmm32at",
 267        .module = THIS_MODULE,
 268        .attach = dmm32at_attach,
 269        .detach = dmm32at_detach,
 270/* It is not necessary to implement the following members if you are
 271 * writing a driver for a ISA PnP or PCI card */
 272/* Most drivers will support multiple types of boards by
 273 * having an array of board structures.  These were defined
 274 * in dmm32at_boards[] above.  Note that the element 'name'
 275 * was first in the structure -- Comedi uses this fact to
 276 * extract the name of the board without knowing any details
 277 * about the structure except for its length.
 278 * When a device is attached (by comedi_config), the name
 279 * of the device is given to Comedi, and Comedi tries to
 280 * match it by going through the list of board names.  If
 281 * there is a match, the address of the pointer is put
 282 * into dev->board_ptr and driver->attach() is called.
 283 *
 284 * Note that these are not necessary if you can determine
 285 * the type of board in software.  ISA PnP, PCI, and PCMCIA
 286 * devices are such boards.
 287 */
 288        .board_name = &dmm32at_boards[0].name,
 289        .offset = sizeof(struct dmm32at_board),
 290        .num_names = ARRAY_SIZE(dmm32at_boards),
 291};
 292
 293/* prototypes for driver functions below */
 294static int dmm32at_ai_rinsn(struct comedi_device *dev,
 295                            struct comedi_subdevice *s,
 296                            struct comedi_insn *insn, unsigned int *data);
 297static int dmm32at_ao_winsn(struct comedi_device *dev,
 298                            struct comedi_subdevice *s,
 299                            struct comedi_insn *insn, unsigned int *data);
 300static int dmm32at_ao_rinsn(struct comedi_device *dev,
 301                            struct comedi_subdevice *s,
 302                            struct comedi_insn *insn, unsigned int *data);
 303static int dmm32at_dio_insn_bits(struct comedi_device *dev,
 304                                 struct comedi_subdevice *s,
 305                                 struct comedi_insn *insn, unsigned int *data);
 306static int dmm32at_dio_insn_config(struct comedi_device *dev,
 307                                   struct comedi_subdevice *s,
 308                                   struct comedi_insn *insn,
 309                                   unsigned int *data);
 310static int dmm32at_ai_cmdtest(struct comedi_device *dev,
 311                              struct comedi_subdevice *s,
 312                              struct comedi_cmd *cmd);
 313static int dmm32at_ai_cmd(struct comedi_device *dev,
 314                          struct comedi_subdevice *s);
 315static int dmm32at_ai_cancel(struct comedi_device *dev,
 316                             struct comedi_subdevice *s);
 317static int dmm32at_ns_to_timer(unsigned int *ns, int round);
 318static irqreturn_t dmm32at_isr(int irq, void *d);
 319void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec);
 320
 321/*
 322 * Attach is called by the Comedi core to configure the driver
 323 * for a particular board.  If you specified a board_name array
 324 * in the driver structure, dev->board_ptr contains that
 325 * address.
 326 */
 327static int dmm32at_attach(struct comedi_device *dev,
 328                          struct comedi_devconfig *it)
 329{
 330        int ret;
 331        struct comedi_subdevice *s;
 332        unsigned char aihi, ailo, fifostat, aistat, intstat, airback;
 333        unsigned long iobase;
 334        unsigned int irq;
 335
 336        iobase = it->options[0];
 337        irq = it->options[1];
 338
 339        printk("comedi%d: dmm32at: attaching\n", dev->minor);
 340        printk("dmm32at: probing at address 0x%04lx, irq %u\n", iobase, irq);
 341
 342        /* register address space */
 343        if (!request_region(iobase, DMM32AT_MEMSIZE, thisboard->name)) {
 344                printk("I/O port conflict\n");
 345                return -EIO;
 346        }
 347        dev->iobase = iobase;
 348
 349        /* the following just makes sure the board is there and gets
 350           it to a known state */
 351
 352        /* reset the board */
 353        dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_RESET);
 354
 355        /* allow a millisecond to reset */
 356        udelay(1000);
 357
 358        /* zero scan and fifo control */
 359        dmm_outb(dev, DMM32AT_FIFOCNTRL, 0x0);
 360
 361        /* zero interrupt and clock control */
 362        dmm_outb(dev, DMM32AT_INTCLOCK, 0x0);
 363
 364        /* write a test channel range, the high 3 bits should drop */
 365        dmm_outb(dev, DMM32AT_AILOW, 0x80);
 366        dmm_outb(dev, DMM32AT_AIHIGH, 0xff);
 367
 368        /* set the range at 10v unipolar */
 369        dmm_outb(dev, DMM32AT_AICONF, DMM32AT_RANGE_U10);
 370
 371        /* should take 10 us to settle, here's a hundred */
 372        udelay(100);
 373
 374        /* read back the values */
 375        ailo = dmm_inb(dev, DMM32AT_AILOW);
 376        aihi = dmm_inb(dev, DMM32AT_AIHIGH);
 377        fifostat = dmm_inb(dev, DMM32AT_FIFOSTAT);
 378        aistat = dmm_inb(dev, DMM32AT_AISTAT);
 379        intstat = dmm_inb(dev, DMM32AT_INTCLOCK);
 380        airback = dmm_inb(dev, DMM32AT_AIRBACK);
 381
 382        printk("dmm32at: lo=0x%02x hi=0x%02x fifostat=0x%02x\n",
 383               ailo, aihi, fifostat);
 384        printk("dmm32at: aistat=0x%02x intstat=0x%02x airback=0x%02x\n",
 385               aistat, intstat, airback);
 386
 387        if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) ||
 388            (aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) {
 389                printk("dmmat32: board detection failed\n");
 390                return -EIO;
 391        }
 392
 393        /* board is there, register interrupt */
 394        if (irq) {
 395                ret = request_irq(irq, dmm32at_isr, 0, thisboard->name, dev);
 396                if (ret < 0) {
 397                        printk("irq conflict\n");
 398                        return ret;
 399                }
 400                dev->irq = irq;
 401        }
 402
 403/*
 404 * If you can probe the device to determine what device in a series
 405 * it is, this is the place to do it.  Otherwise, dev->board_ptr
 406 * should already be initialized.
 407 */
 408        /* dev->board_ptr = dmm32at_probe(dev); */
 409
 410/*
 411 * Initialize dev->board_name.  Note that we can use the "thisboard"
 412 * macro now, since we just initialized it in the last line.
 413 */
 414        dev->board_name = thisboard->name;
 415
 416/*
 417 * Allocate the private structure area.  alloc_private() is a
 418 * convenient macro defined in comedidev.h.
 419 */
 420        if (alloc_private(dev, sizeof(struct dmm32at_private)) < 0)
 421                return -ENOMEM;
 422
 423/*
 424 * Allocate the subdevice structures.  alloc_subdevice() is a
 425 * convenient macro defined in comedidev.h.
 426 */
 427        if (alloc_subdevices(dev, 3) < 0)
 428                return -ENOMEM;
 429
 430        s = dev->subdevices + 0;
 431        dev->read_subdev = s;
 432        /* analog input subdevice */
 433        s->type = COMEDI_SUBD_AI;
 434        /* we support single-ended (ground) and differential */
 435        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
 436        s->n_chan = thisboard->ai_chans;
 437        s->maxdata = (1 << thisboard->ai_bits) - 1;
 438        s->range_table = thisboard->ai_ranges;
 439        s->len_chanlist = 32;   /* This is the maximum chanlist length that
 440                                   the board can handle */
 441        s->insn_read = dmm32at_ai_rinsn;
 442        s->do_cmd = dmm32at_ai_cmd;
 443        s->do_cmdtest = dmm32at_ai_cmdtest;
 444        s->cancel = dmm32at_ai_cancel;
 445
 446        s = dev->subdevices + 1;
 447        /* analog output subdevice */
 448        s->type = COMEDI_SUBD_AO;
 449        s->subdev_flags = SDF_WRITABLE;
 450        s->n_chan = thisboard->ao_chans;
 451        s->maxdata = (1 << thisboard->ao_bits) - 1;
 452        s->range_table = thisboard->ao_ranges;
 453        s->insn_write = dmm32at_ao_winsn;
 454        s->insn_read = dmm32at_ao_rinsn;
 455
 456        s = dev->subdevices + 2;
 457        /* digital i/o subdevice */
 458        if (thisboard->have_dio) {
 459
 460                /* get access to the DIO regs */
 461                dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC);
 462                /* set the DIO's to the defualt input setting */
 463                devpriv->dio_config = DMM32AT_DIRA | DMM32AT_DIRB |
 464                    DMM32AT_DIRCL | DMM32AT_DIRCH | DMM32AT_DIENABLE;
 465                dmm_outb(dev, DMM32AT_DIOCONF, devpriv->dio_config);
 466
 467                /* set up the subdevice */
 468                s->type = COMEDI_SUBD_DIO;
 469                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 470                s->n_chan = thisboard->dio_chans;
 471                s->maxdata = 1;
 472                s->state = 0;
 473                s->range_table = &range_digital;
 474                s->insn_bits = dmm32at_dio_insn_bits;
 475                s->insn_config = dmm32at_dio_insn_config;
 476        } else {
 477                s->type = COMEDI_SUBD_UNUSED;
 478        }
 479
 480        /* success */
 481        printk("comedi%d: dmm32at: attached\n", dev->minor);
 482
 483        return 1;
 484
 485}
 486
 487/*
 488 * _detach is called to deconfigure a device.  It should deallocate
 489 * resources.
 490 * This function is also called when _attach() fails, so it should be
 491 * careful not to release resources that were not necessarily
 492 * allocated by _attach().  dev->private and dev->subdevices are
 493 * deallocated automatically by the core.
 494 */
 495static int dmm32at_detach(struct comedi_device *dev)
 496{
 497        printk("comedi%d: dmm32at: remove\n", dev->minor);
 498        if (dev->irq)
 499                free_irq(dev->irq, dev);
 500        if (dev->iobase)
 501                release_region(dev->iobase, DMM32AT_MEMSIZE);
 502
 503        return 0;
 504}
 505
 506/*
 507 * "instructions" read/write data in "one-shot" or "software-triggered"
 508 * mode.
 509 */
 510
 511static int dmm32at_ai_rinsn(struct comedi_device *dev,
 512                            struct comedi_subdevice *s,
 513                            struct comedi_insn *insn, unsigned int *data)
 514{
 515        int n, i;
 516        unsigned int d;
 517        unsigned char status;
 518        unsigned short msb, lsb;
 519        unsigned char chan;
 520        int range;
 521
 522        /* get the channel and range number */
 523
 524        chan = CR_CHAN(insn->chanspec) & (s->n_chan - 1);
 525        range = CR_RANGE(insn->chanspec);
 526
 527        /* printk("channel=0x%02x, range=%d\n",chan,range); */
 528
 529        /* zero scan and fifo control and reset fifo */
 530        dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET);
 531
 532        /* write the ai channel range regs */
 533        dmm_outb(dev, DMM32AT_AILOW, chan);
 534        dmm_outb(dev, DMM32AT_AIHIGH, chan);
 535        /* set the range bits */
 536        dmm_outb(dev, DMM32AT_AICONF, dmm32at_rangebits[range]);
 537
 538        /* wait for circuit to settle */
 539        for (i = 0; i < 40000; i++) {
 540                status = dmm_inb(dev, DMM32AT_AIRBACK);
 541                if ((status & DMM32AT_STATUS) == 0)
 542                        break;
 543        }
 544        if (i == 40000) {
 545                printk("timeout\n");
 546                return -ETIMEDOUT;
 547        }
 548
 549        /* convert n samples */
 550        for (n = 0; n < insn->n; n++) {
 551                /* trigger conversion */
 552                dmm_outb(dev, DMM32AT_CONV, 0xff);
 553                /* wait for conversion to end */
 554                for (i = 0; i < 40000; i++) {
 555                        status = dmm_inb(dev, DMM32AT_AISTAT);
 556                        if ((status & DMM32AT_STATUS) == 0)
 557                                break;
 558                }
 559                if (i == 40000) {
 560                        printk("timeout\n");
 561                        return -ETIMEDOUT;
 562                }
 563
 564                /* read data */
 565                lsb = dmm_inb(dev, DMM32AT_AILSB);
 566                msb = dmm_inb(dev, DMM32AT_AIMSB);
 567
 568                /* invert sign bit to make range unsigned, this is an
 569                   idiosyncracy of the diamond board, it return
 570                   conversions as a signed value, i.e. -32768 to
 571                   32767, flipping the bit and interpreting it as
 572                   signed gives you a range of 0 to 65535 which is
 573                   used by comedi */
 574                d = ((msb ^ 0x0080) << 8) + lsb;
 575
 576                data[n] = d;
 577        }
 578
 579        /* return the number of samples read/written */
 580        return n;
 581}
 582
 583static int dmm32at_ai_cmdtest(struct comedi_device *dev,
 584                              struct comedi_subdevice *s,
 585                              struct comedi_cmd *cmd)
 586{
 587        int err = 0;
 588        int tmp;
 589        int start_chan, gain, i;
 590
 591        /* printk("dmmat32 in command test\n"); */
 592
 593        /* cmdtest tests a particular command to see if it is valid.
 594         * Using the cmdtest ioctl, a user can create a valid cmd
 595         * and then have it executes by the cmd ioctl.
 596         *
 597         * cmdtest returns 1,2,3,4 or 0, depending on which tests
 598         * the command passes. */
 599
 600        /* step 1: make sure trigger sources are trivially valid */
 601
 602        tmp = cmd->start_src;
 603        cmd->start_src &= TRIG_NOW;
 604        if (!cmd->start_src || tmp != cmd->start_src)
 605                err++;
 606
 607        tmp = cmd->scan_begin_src;
 608        cmd->scan_begin_src &= TRIG_TIMER /*| TRIG_EXT */ ;
 609        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 610                err++;
 611
 612        tmp = cmd->convert_src;
 613        cmd->convert_src &= TRIG_TIMER /*| TRIG_EXT */ ;
 614        if (!cmd->convert_src || tmp != cmd->convert_src)
 615                err++;
 616
 617        tmp = cmd->scan_end_src;
 618        cmd->scan_end_src &= TRIG_COUNT;
 619        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 620                err++;
 621
 622        tmp = cmd->stop_src;
 623        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 624        if (!cmd->stop_src || tmp != cmd->stop_src)
 625                err++;
 626
 627        if (err)
 628                return 1;
 629
 630        /* step 2: make sure trigger sources are unique and mutually compatible */
 631
 632        /* note that mutual compatiblity is not an issue here */
 633        if (cmd->scan_begin_src != TRIG_TIMER &&
 634            cmd->scan_begin_src != TRIG_EXT)
 635                err++;
 636        if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
 637                err++;
 638        if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
 639                err++;
 640
 641        if (err)
 642                return 2;
 643
 644        /* step 3: make sure arguments are trivially compatible */
 645
 646        if (cmd->start_arg != 0) {
 647                cmd->start_arg = 0;
 648                err++;
 649        }
 650#define MAX_SCAN_SPEED  1000000 /* in nanoseconds */
 651#define MIN_SCAN_SPEED  1000000000      /* in nanoseconds */
 652
 653        if (cmd->scan_begin_src == TRIG_TIMER) {
 654                if (cmd->scan_begin_arg < MAX_SCAN_SPEED) {
 655                        cmd->scan_begin_arg = MAX_SCAN_SPEED;
 656                        err++;
 657                }
 658                if (cmd->scan_begin_arg > MIN_SCAN_SPEED) {
 659                        cmd->scan_begin_arg = MIN_SCAN_SPEED;
 660                        err++;
 661                }
 662        } else {
 663                /* external trigger */
 664                /* should be level/edge, hi/lo specification here */
 665                /* should specify multiple external triggers */
 666                if (cmd->scan_begin_arg > 9) {
 667                        cmd->scan_begin_arg = 9;
 668                        err++;
 669                }
 670        }
 671        if (cmd->convert_src == TRIG_TIMER) {
 672                if (cmd->convert_arg >= 17500)
 673                        cmd->convert_arg = 20000;
 674                else if (cmd->convert_arg >= 12500)
 675                        cmd->convert_arg = 15000;
 676                else if (cmd->convert_arg >= 7500)
 677                        cmd->convert_arg = 10000;
 678                else
 679                        cmd->convert_arg = 5000;
 680
 681        } else {
 682                /* external trigger */
 683                /* see above */
 684                if (cmd->convert_arg > 9) {
 685                        cmd->convert_arg = 9;
 686                        err++;
 687                }
 688        }
 689
 690        if (cmd->scan_end_arg != cmd->chanlist_len) {
 691                cmd->scan_end_arg = cmd->chanlist_len;
 692                err++;
 693        }
 694        if (cmd->stop_src == TRIG_COUNT) {
 695                if (cmd->stop_arg > 0xfffffff0) {
 696                        cmd->stop_arg = 0xfffffff0;
 697                        err++;
 698                }
 699                if (cmd->stop_arg == 0) {
 700                        cmd->stop_arg = 1;
 701                        err++;
 702                }
 703        } else {
 704                /* TRIG_NONE */
 705                if (cmd->stop_arg != 0) {
 706                        cmd->stop_arg = 0;
 707                        err++;
 708                }
 709        }
 710
 711        if (err)
 712                return 3;
 713
 714        /* step 4: fix up any arguments */
 715
 716        if (cmd->scan_begin_src == TRIG_TIMER) {
 717                tmp = cmd->scan_begin_arg;
 718                dmm32at_ns_to_timer(&cmd->scan_begin_arg,
 719                                    cmd->flags & TRIG_ROUND_MASK);
 720                if (tmp != cmd->scan_begin_arg)
 721                        err++;
 722        }
 723        if (cmd->convert_src == TRIG_TIMER) {
 724                tmp = cmd->convert_arg;
 725                dmm32at_ns_to_timer(&cmd->convert_arg,
 726                                    cmd->flags & TRIG_ROUND_MASK);
 727                if (tmp != cmd->convert_arg)
 728                        err++;
 729                if (cmd->scan_begin_src == TRIG_TIMER &&
 730                    cmd->scan_begin_arg <
 731                    cmd->convert_arg * cmd->scan_end_arg) {
 732                        cmd->scan_begin_arg =
 733                            cmd->convert_arg * cmd->scan_end_arg;
 734                        err++;
 735                }
 736        }
 737
 738        if (err)
 739                return 4;
 740
 741        /* step 5 check the channel list, the channel list for this
 742           board must be consecutive and gains must be the same */
 743
 744        if (cmd->chanlist) {
 745                gain = CR_RANGE(cmd->chanlist[0]);
 746                start_chan = CR_CHAN(cmd->chanlist[0]);
 747                for (i = 1; i < cmd->chanlist_len; i++) {
 748                        if (CR_CHAN(cmd->chanlist[i]) !=
 749                            (start_chan + i) % s->n_chan) {
 750                                comedi_error(dev,
 751                                             "entries in chanlist must be consecutive channels, counting upwards\n");
 752                                err++;
 753                        }
 754                        if (CR_RANGE(cmd->chanlist[i]) != gain) {
 755                                comedi_error(dev,
 756                                             "entries in chanlist must all have the same gain\n");
 757                                err++;
 758                        }
 759                }
 760        }
 761
 762        if (err)
 763                return 5;
 764
 765        return 0;
 766}
 767
 768static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 769{
 770        struct comedi_cmd *cmd = &s->async->cmd;
 771        int i, range;
 772        unsigned char chanlo, chanhi, status;
 773
 774        if (!cmd->chanlist)
 775                return -EINVAL;
 776
 777        /* get the channel list and range */
 778        chanlo = CR_CHAN(cmd->chanlist[0]) & (s->n_chan - 1);
 779        chanhi = chanlo + cmd->chanlist_len - 1;
 780        if (chanhi >= s->n_chan)
 781                return -EINVAL;
 782        range = CR_RANGE(cmd->chanlist[0]);
 783
 784        /* reset fifo */
 785        dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET);
 786
 787        /* set scan enable */
 788        dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_SCANENABLE);
 789
 790        /* write the ai channel range regs */
 791        dmm_outb(dev, DMM32AT_AILOW, chanlo);
 792        dmm_outb(dev, DMM32AT_AIHIGH, chanhi);
 793
 794        /* set the range bits */
 795        dmm_outb(dev, DMM32AT_AICONF, dmm32at_rangebits[range]);
 796
 797        /* reset the interrupt just in case */
 798        dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_INTRESET);
 799
 800        if (cmd->stop_src == TRIG_COUNT)
 801                devpriv->ai_scans_left = cmd->stop_arg;
 802        else {                  /* TRIG_NONE */
 803                devpriv->ai_scans_left = 0xffffffff;    /* indicates TRIG_NONE to isr */
 804        }
 805
 806        /* wait for circuit to settle */
 807        for (i = 0; i < 40000; i++) {
 808                status = dmm_inb(dev, DMM32AT_AIRBACK);
 809                if ((status & DMM32AT_STATUS) == 0)
 810                        break;
 811        }
 812        if (i == 40000) {
 813                printk("timeout\n");
 814                return -ETIMEDOUT;
 815        }
 816
 817        if (devpriv->ai_scans_left > 1) {
 818                /* start the clock and enable the interrupts */
 819                dmm32at_setaitimer(dev, cmd->scan_begin_arg);
 820        } else {
 821                /* start the interrups and initiate a single scan */
 822                dmm_outb(dev, DMM32AT_INTCLOCK, DMM32AT_ADINT);
 823                dmm_outb(dev, DMM32AT_CONV, 0xff);
 824        }
 825
 826/*      printk("dmmat32 in command\n"); */
 827
 828/*      for(i=0;i<cmd->chanlist_len;i++) */
 829/*              comedi_buf_put(s->async,i*100); */
 830
 831/*      s->async->events |= COMEDI_CB_EOA; */
 832/*      comedi_event(dev, s); */
 833
 834        return 0;
 835
 836}
 837
 838static int dmm32at_ai_cancel(struct comedi_device *dev,
 839                             struct comedi_subdevice *s)
 840{
 841        devpriv->ai_scans_left = 1;
 842        return 0;
 843}
 844
 845static irqreturn_t dmm32at_isr(int irq, void *d)
 846{
 847        unsigned char intstat;
 848        unsigned int samp;
 849        unsigned short msb, lsb;
 850        int i;
 851        struct comedi_device *dev = d;
 852
 853        if (!dev->attached) {
 854                comedi_error(dev, "spurious interrupt");
 855                return IRQ_HANDLED;
 856        }
 857
 858        intstat = dmm_inb(dev, DMM32AT_INTCLOCK);
 859
 860        if (intstat & DMM32AT_ADINT) {
 861                struct comedi_subdevice *s = dev->read_subdev;
 862                struct comedi_cmd *cmd = &s->async->cmd;
 863
 864                for (i = 0; i < cmd->chanlist_len; i++) {
 865                        /* read data */
 866                        lsb = dmm_inb(dev, DMM32AT_AILSB);
 867                        msb = dmm_inb(dev, DMM32AT_AIMSB);
 868
 869                        /* invert sign bit to make range unsigned */
 870                        samp = ((msb ^ 0x0080) << 8) + lsb;
 871                        comedi_buf_put(s->async, samp);
 872                }
 873
 874                if (devpriv->ai_scans_left != 0xffffffff) {     /* TRIG_COUNT */
 875                        devpriv->ai_scans_left--;
 876                        if (devpriv->ai_scans_left == 0) {
 877                                /* disable further interrupts and clocks */
 878                                dmm_outb(dev, DMM32AT_INTCLOCK, 0x0);
 879                                /* set the buffer to be flushed with an EOF */
 880                                s->async->events |= COMEDI_CB_EOA;
 881                        }
 882
 883                }
 884                /* flush the buffer */
 885                comedi_event(dev, s);
 886        }
 887
 888        /* reset the interrupt */
 889        dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_INTRESET);
 890        return IRQ_HANDLED;
 891}
 892
 893/* This function doesn't require a particular form, this is just
 894 * what happens to be used in some of the drivers.  It should
 895 * convert ns nanoseconds to a counter value suitable for programming
 896 * the device.  Also, it should adjust ns so that it cooresponds to
 897 * the actual time that the device will use. */
 898static int dmm32at_ns_to_timer(unsigned int *ns, int round)
 899{
 900        /* trivial timer */
 901        /* if your timing is done through two cascaded timers, the
 902         * i8253_cascade_ns_to_timer() function in 8253.h can be
 903         * very helpful.  There are also i8254_load() and i8254_mm_load()
 904         * which can be used to load values into the ubiquitous 8254 counters
 905         */
 906
 907        return *ns;
 908}
 909
 910static int dmm32at_ao_winsn(struct comedi_device *dev,
 911                            struct comedi_subdevice *s,
 912                            struct comedi_insn *insn, unsigned int *data)
 913{
 914        int i;
 915        int chan = CR_CHAN(insn->chanspec);
 916        unsigned char hi, lo, status;
 917
 918        /* Writing a list of values to an AO channel is probably not
 919         * very useful, but that's how the interface is defined. */
 920        for (i = 0; i < insn->n; i++) {
 921
 922                devpriv->ao_readback[chan] = data[i];
 923
 924                /* get the low byte */
 925                lo = data[i] & 0x00ff;
 926                /* high byte also contains channel number */
 927                hi = (data[i] >> 8) + chan * (1 << 6);
 928                /* printk("writing 0x%02x  0x%02x\n",hi,lo); */
 929                /* write the low and high values to the board */
 930                dmm_outb(dev, DMM32AT_DACLSB, lo);
 931                dmm_outb(dev, DMM32AT_DACMSB, hi);
 932
 933                /* wait for circuit to settle */
 934                for (i = 0; i < 40000; i++) {
 935                        status = dmm_inb(dev, DMM32AT_DACSTAT);
 936                        if ((status & DMM32AT_DACBUSY) == 0)
 937                                break;
 938                }
 939                if (i == 40000) {
 940                        printk("timeout\n");
 941                        return -ETIMEDOUT;
 942                }
 943                /* dummy read to update trigger the output */
 944                status = dmm_inb(dev, DMM32AT_DACMSB);
 945
 946        }
 947
 948        /* return the number of samples read/written */
 949        return i;
 950}
 951
 952/* AO subdevices should have a read insn as well as a write insn.
 953 * Usually this means copying a value stored in devpriv. */
 954static int dmm32at_ao_rinsn(struct comedi_device *dev,
 955                            struct comedi_subdevice *s,
 956                            struct comedi_insn *insn, unsigned int *data)
 957{
 958        int i;
 959        int chan = CR_CHAN(insn->chanspec);
 960
 961        for (i = 0; i < insn->n; i++)
 962                data[i] = devpriv->ao_readback[chan];
 963
 964        return i;
 965}
 966
 967/* DIO devices are slightly special.  Although it is possible to
 968 * implement the insn_read/insn_write interface, it is much more
 969 * useful to applications if you implement the insn_bits interface.
 970 * This allows packed reading/writing of the DIO channels.  The
 971 * comedi core can convert between insn_bits and insn_read/write */
 972static int dmm32at_dio_insn_bits(struct comedi_device *dev,
 973                                 struct comedi_subdevice *s,
 974                                 struct comedi_insn *insn, unsigned int *data)
 975{
 976        unsigned char diobits;
 977
 978        if (insn->n != 2)
 979                return -EINVAL;
 980
 981        /* The insn data is a mask in data[0] and the new data
 982         * in data[1], each channel cooresponding to a bit. */
 983        if (data[0]) {
 984                s->state &= ~data[0];
 985                s->state |= data[0] & data[1];
 986                /* Write out the new digital output lines */
 987                /* outw(s->state,dev->iobase + DMM32AT_DIO); */
 988        }
 989
 990        /* get access to the DIO regs */
 991        dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC);
 992
 993        /* if either part of dio is set for output */
 994        if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) ||
 995            ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) {
 996                diobits = (s->state & 0x00ff0000) >> 16;
 997                dmm_outb(dev, DMM32AT_DIOC, diobits);
 998        }
 999        if ((devpriv->dio_config & DMM32AT_DIRB) == 0) {
1000                diobits = (s->state & 0x0000ff00) >> 8;
1001                dmm_outb(dev, DMM32AT_DIOB, diobits);
1002        }
1003        if ((devpriv->dio_config & DMM32AT_DIRA) == 0) {
1004                diobits = (s->state & 0x000000ff);
1005                dmm_outb(dev, DMM32AT_DIOA, diobits);
1006        }
1007
1008        /* now read the state back in */
1009        s->state = dmm_inb(dev, DMM32AT_DIOC);
1010        s->state <<= 8;
1011        s->state |= dmm_inb(dev, DMM32AT_DIOB);
1012        s->state <<= 8;
1013        s->state |= dmm_inb(dev, DMM32AT_DIOA);
1014        data[1] = s->state;
1015
1016        /* on return, data[1] contains the value of the digital
1017         * input and output lines. */
1018        /* data[1]=inw(dev->iobase + DMM32AT_DIO); */
1019        /* or we could just return the software copy of the output values if
1020         * it was a purely digital output subdevice */
1021        /* data[1]=s->state; */
1022
1023        return 2;
1024}
1025
1026static int dmm32at_dio_insn_config(struct comedi_device *dev,
1027                                   struct comedi_subdevice *s,
1028                                   struct comedi_insn *insn, unsigned int *data)
1029{
1030        unsigned char chanbit;
1031        int chan = CR_CHAN(insn->chanspec);
1032
1033        if (insn->n != 1)
1034                return -EINVAL;
1035
1036        if (chan < 8)
1037                chanbit = DMM32AT_DIRA;
1038        else if (chan < 16)
1039                chanbit = DMM32AT_DIRB;
1040        else if (chan < 20)
1041                chanbit = DMM32AT_DIRCL;
1042        else
1043                chanbit = DMM32AT_DIRCH;
1044
1045        /* The input or output configuration of each digital line is
1046         * configured by a special insn_config instruction.  chanspec
1047         * contains the channel to be changed, and data[0] contains the
1048         * value COMEDI_INPUT or COMEDI_OUTPUT. */
1049
1050        /* if output clear the bit, otherwise set it */
1051        if (data[0] == COMEDI_OUTPUT) {
1052                devpriv->dio_config &= ~chanbit;
1053        } else {
1054                devpriv->dio_config |= chanbit;
1055        }
1056        /* get access to the DIO regs */
1057        dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC);
1058        /* set the DIO's to the new configuration setting */
1059        dmm_outb(dev, DMM32AT_DIOCONF, devpriv->dio_config);
1060
1061        return 1;
1062}
1063
1064void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
1065{
1066        unsigned char lo1, lo2, hi2;
1067        unsigned short both2;
1068
1069        /* based on 10mhz clock */
1070        lo1 = 200;
1071        both2 = nansec / 20000;
1072        hi2 = (both2 & 0xff00) >> 8;
1073        lo2 = both2 & 0x00ff;
1074
1075        /* set the counter frequency to 10mhz */
1076        dmm_outb(dev, DMM32AT_CNTRDIO, 0);
1077
1078        /* get access to the clock regs */
1079        dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_CLKACC);
1080
1081        /* write the counter 1 control word and low byte to counter */
1082        dmm_outb(dev, DMM32AT_CLKCT, DMM32AT_CLKCT1);
1083        dmm_outb(dev, DMM32AT_CLK1, lo1);
1084
1085        /* write the counter 2 control word and low byte then to counter */
1086        dmm_outb(dev, DMM32AT_CLKCT, DMM32AT_CLKCT2);
1087        dmm_outb(dev, DMM32AT_CLK2, lo2);
1088        dmm_outb(dev, DMM32AT_CLK2, hi2);
1089
1090        /* enable the ai conversion interrupt and the clock to start scans */
1091        dmm_outb(dev, DMM32AT_INTCLOCK, DMM32AT_ADINT | DMM32AT_CLKSEL);
1092
1093}
1094
1095/*
1096 * A convenient macro that defines init_module() and cleanup_module(),
1097 * as necessary.
1098 */
1099COMEDI_INITCLEANUP(driver_dmm32at);
1100