linux/drivers/staging/comedi/drivers/cb_pcidas.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/cb_pcidas.c
   3
   4    Developed by Ivan Martinez and Frank Mori Hess, with valuable help from
   5    David Schleef and the rest of the Comedi developers comunity.
   6
   7    Copyright (C) 2001-2003 Ivan Martinez <imr@oersted.dtu.dk>
   8    Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
   9
  10    COMEDI - Linux Control and Measurement Device Interface
  11    Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
  12
  13    This program is free software; you can redistribute it and/or modify
  14    it under the terms of the GNU General Public License as published by
  15    the Free Software Foundation; either version 2 of the License, or
  16    (at your option) any later version.
  17
  18    This program is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22
  23    You should have received a copy of the GNU General Public License
  24    along with this program; if not, write to the Free Software
  25    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26
  27************************************************************************
  28*/
  29/*
  30Driver: cb_pcidas
  31Description: MeasurementComputing PCI-DAS series
  32  with the AMCC S5933 PCI controller
  33Author: Ivan Martinez <imr@oersted.dtu.dk>,
  34  Frank Mori Hess <fmhess@users.sourceforge.net>
  35Updated: 2003-3-11
  36Devices: [Measurement Computing] PCI-DAS1602/16 (cb_pcidas),
  37  PCI-DAS1602/16jr, PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr,
  38  PCI-DAS1000, PCI-DAS1001, PCI_DAS1002
  39
  40Status:
  41  There are many reports of the driver being used with most of the
  42  supported cards. Despite no detailed log is maintained, it can
  43  be said that the driver is quite tested and stable.
  44
  45  The boards may be autocalibrated using the comedi_calibrate
  46  utility.
  47
  48Configuration options:
  49  [0] - PCI bus of device (optional)
  50  [1] - PCI slot of device (optional)
  51  If bus/slot is not specified, the first supported
  52  PCI device found will be used.
  53
  54For commands, the scanned channels must be consecutive
  55(i.e. 4-5-6-7, 2-3-4,...), and must all have the same
  56range and aref.
  57
  58AI Triggering:
  59   For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used.
  60   For 1602 series, the start_arg is interpreted as follows:
  61     start_arg == 0                   => gated trigger (level high)
  62     start_arg == CR_INVERT           => gated trigger (level low)
  63     start_arg == CR_EDGE             => Rising edge
  64     start_arg == CR_EDGE | CR_INVERT => Falling edge
  65   For the other boards the trigger will be done on rising edge
  66*/
  67/*
  68
  69TODO:
  70
  71analog triggering on 1602 series
  72*/
  73
  74#include "../comedidev.h"
  75#include <linux/delay.h>
  76#include <linux/interrupt.h>
  77
  78#include "8253.h"
  79#include "8255.h"
  80#include "amcc_s5933.h"
  81#include "comedi_fc.h"
  82
  83/* PCI vendor number of ComputerBoards/MeasurementComputing */
  84#define PCI_VENDOR_ID_CB        0x1307
  85
  86#define TIMER_BASE              100     /* 10MHz master clock */
  87#define AI_BUFFER_SIZE          1024    /* max ai fifo size */
  88#define AO_BUFFER_SIZE          1024    /* max ao fifo size */
  89#define NUM_CHANNELS_8800       8
  90#define NUM_CHANNELS_7376       1
  91#define NUM_CHANNELS_8402       2
  92#define NUM_CHANNELS_DAC08      1
  93
  94/* Control/Status registers */
  95#define INT_ADCFIFO             0       /* INTERRUPT / ADC FIFO register */
  96#define   INT_EOS               0x1     /* int end of scan */
  97#define   INT_FHF               0x2     /* int fifo half full */
  98#define   INT_FNE               0x3     /* int fifo not empty */
  99#define   INT_MASK              0x3     /* mask of int select bits */
 100#define   INTE                  0x4     /* int enable */
 101#define   DAHFIE                0x8     /* dac half full int enable */
 102#define   EOAIE                 0x10    /* end of acq. int enable */
 103#define   DAHFI                 0x20    /* dac half full status / clear */
 104#define   EOAI                  0x40    /* end of acq. int status / clear */
 105#define   INT                   0x80    /* int status / clear */
 106#define   EOBI                  0x200   /* end of burst int status */
 107#define   ADHFI                 0x400   /* half-full int status */
 108#define   ADNEI                 0x800   /* fifo not empty int status (latch) */
 109#define   ADNE                  0x1000  /* fifo not empty status (realtime) */
 110#define   DAEMIE                0x1000  /* dac empty int enable */
 111#define   LADFUL                0x2000  /* fifo overflow / clear */
 112#define   DAEMI                 0x4000  /* dac fifo empty int status / clear */
 113
 114#define ADCMUX_CONT             2       /* ADC CHANNEL MUX AND CONTROL reg */
 115#define   BEGIN_SCAN(x)         ((x) & 0xf)
 116#define   END_SCAN(x)           (((x) & 0xf) << 4)
 117#define   GAIN_BITS(x)          (((x) & 0x3) << 8)
 118#define   UNIP                  0x800   /* Analog front-end unipolar mode */
 119#define   SE                    0x400   /* Inputs in single-ended mode */
 120#define   PACER_MASK            0x3000  /* pacer source bits */
 121#define   PACER_INT             0x1000  /* int. pacer */
 122#define   PACER_EXT_FALL        0x2000  /* ext. falling edge */
 123#define   PACER_EXT_RISE        0x3000  /* ext. rising edge */
 124#define   EOC                   0x4000  /* adc not busy */
 125
 126#define TRIG_CONTSTAT            4      /* TRIGGER CONTROL/STATUS register */
 127#define   SW_TRIGGER            0x1     /* software start trigger */
 128#define   EXT_TRIGGER           0x2     /* ext. start trigger */
 129#define   ANALOG_TRIGGER        0x3     /* ext. analog trigger */
 130#define   TRIGGER_MASK          0x3     /* start trigger mask */
 131#define   TGPOL                 0x04    /* invert trigger (1602 only) */
 132#define   TGSEL                 0x08    /* edge/level trigerred (1602 only) */
 133#define   TGEN                  0x10    /* enable external start trigger */
 134#define   BURSTE                0x20    /* burst mode enable */
 135#define   XTRCL                 0x80    /* clear external trigger */
 136
 137#define CALIBRATION_REG         6       /* CALIBRATION register */
 138#define   SELECT_8800_BIT       0x100   /* select 8800 caldac */
 139#define   SELECT_TRIMPOT_BIT    0x200   /* select ad7376 trim pot */
 140#define   SELECT_DAC08_BIT      0x400   /* select dac08 caldac */
 141#define   CAL_SRC_BITS(x)       (((x) & 0x7) << 11)
 142#define   CAL_EN_BIT            0x4000  /* calibration source enable */
 143#define   SERIAL_DATA_IN_BIT    0x8000  /* serial data bit going to caldac */
 144
 145#define DAC_CSR                 0x8     /* dac control and status register */
 146#define   DACEN                 0x02    /* dac enable */
 147#define   DAC_MODE_UPDATE_BOTH  0x80    /* update both dacs */
 148
 149static inline unsigned int DAC_RANGE(unsigned int channel, unsigned int range)
 150{
 151        return (range & 0x3) << (8 + 2 * (channel & 0x1));
 152}
 153
 154static inline unsigned int DAC_RANGE_MASK(unsigned int channel)
 155{
 156        return 0x3 << (8 + 2 * (channel & 0x1));
 157};
 158
 159/* bits for 1602 series only */
 160#define   DAC_EMPTY             0x1     /* fifo empty, read, write clear */
 161#define   DAC_START             0x4     /* start/arm fifo operations */
 162#define   DAC_PACER_MASK        0x18    /* bits that set pacer source */
 163#define   DAC_PACER_INT         0x8     /* int. pacing */
 164#define   DAC_PACER_EXT_FALL    0x10    /* ext. pacing, falling edge */
 165#define   DAC_PACER_EXT_RISE    0x18    /* ext. pacing, rising edge */
 166
 167static inline unsigned int DAC_CHAN_EN(unsigned int channel)
 168{
 169        return 1 << (5 + (channel & 0x1));      /*  enable channel 0 or 1 */
 170};
 171
 172/* analog input fifo */
 173#define ADCDATA                 0       /* ADC DATA register */
 174#define ADCFIFOCLR              2       /* ADC FIFO CLEAR */
 175
 176/* pacer, counter, dio registers */
 177#define ADC8254                 0
 178#define DIO_8255                4
 179#define DAC8254                 8
 180
 181/* analog output registers for 100x, 1200 series */
 182static inline unsigned int DAC_DATA_REG(unsigned int channel)
 183{
 184        return 2 * (channel & 0x1);
 185}
 186
 187/* analog output registers for 1602 series*/
 188#define DACDATA                 0       /* DAC DATA register */
 189#define DACFIFOCLR              2       /* DAC FIFO CLEAR */
 190
 191#define IS_UNIPOLAR             0x4     /* unipolar range mask */
 192
 193/* analog input ranges for most boards */
 194static const struct comedi_lrange cb_pcidas_ranges = {
 195        8,
 196        {
 197         BIP_RANGE(10),
 198         BIP_RANGE(5),
 199         BIP_RANGE(2.5),
 200         BIP_RANGE(1.25),
 201         UNI_RANGE(10),
 202         UNI_RANGE(5),
 203         UNI_RANGE(2.5),
 204         UNI_RANGE(1.25)
 205         }
 206};
 207
 208/* pci-das1001 input ranges */
 209static const struct comedi_lrange cb_pcidas_alt_ranges = {
 210        8,
 211        {
 212         BIP_RANGE(10),
 213         BIP_RANGE(1),
 214         BIP_RANGE(0.1),
 215         BIP_RANGE(0.01),
 216         UNI_RANGE(10),
 217         UNI_RANGE(1),
 218         UNI_RANGE(0.1),
 219         UNI_RANGE(0.01)
 220         }
 221};
 222
 223/* analog output ranges */
 224static const struct comedi_lrange cb_pcidas_ao_ranges = {
 225        4,
 226        {
 227         BIP_RANGE(5),
 228         BIP_RANGE(10),
 229         UNI_RANGE(5),
 230         UNI_RANGE(10),
 231         }
 232};
 233
 234enum trimpot_model {
 235        AD7376,
 236        AD8402,
 237};
 238
 239struct cb_pcidas_board {
 240        const char *name;
 241        unsigned short device_id;
 242        int ai_nchan;           /*  Inputs in single-ended mode */
 243        int ai_bits;            /*  analog input resolution */
 244        int ai_speed;           /*  fastest conversion period in ns */
 245        int ao_nchan;           /*  number of analog out channels */
 246        int has_ao_fifo;        /*  analog output has fifo */
 247        int ao_scan_speed;      /*  analog output scan speed for 1602 series */
 248        int fifo_size;          /*  number of samples fifo can hold */
 249        const struct comedi_lrange *ranges;
 250        enum trimpot_model trimpot;
 251        unsigned has_dac08:1;
 252        unsigned is_1602:1;
 253};
 254
 255static const struct cb_pcidas_board cb_pcidas_boards[] = {
 256        {
 257                .name           = "pci-das1602/16",
 258                .device_id      = 0x1,
 259                .ai_nchan       = 16,
 260                .ai_bits        = 16,
 261                .ai_speed       = 5000,
 262                .ao_nchan       = 2,
 263                .has_ao_fifo    = 1,
 264                .ao_scan_speed  = 10000,
 265                .fifo_size      = 512,
 266                .ranges         = &cb_pcidas_ranges,
 267                .trimpot        = AD8402,
 268                .has_dac08      = 1,
 269                .is_1602        = 1,
 270        }, {
 271                .name           = "pci-das1200",
 272                .device_id      = 0xF,
 273                .ai_nchan       = 16,
 274                .ai_bits        = 12,
 275                .ai_speed       = 3200,
 276                .ao_nchan       = 2,
 277                .fifo_size      = 1024,
 278                .ranges         = &cb_pcidas_ranges,
 279                .trimpot        = AD7376,
 280        }, {
 281                .name           = "pci-das1602/12",
 282                .device_id      = 0x10,
 283                .ai_nchan       = 16,
 284                .ai_bits        = 12,
 285                .ai_speed       = 3200,
 286                .ao_nchan       = 2,
 287                .has_ao_fifo    = 1,
 288                .ao_scan_speed  = 4000,
 289                .fifo_size      = 1024,
 290                .ranges         = &cb_pcidas_ranges,
 291                .trimpot        = AD7376,
 292                .is_1602        = 1,
 293        }, {
 294                .name           = "pci-das1200/jr",
 295                .device_id      = 0x19,
 296                .ai_nchan       = 16,
 297                .ai_bits        = 12,
 298                .ai_speed       = 3200,
 299                .fifo_size      = 1024,
 300                .ranges         = &cb_pcidas_ranges,
 301                .trimpot        = AD7376,
 302        }, {
 303                .name           = "pci-das1602/16/jr",
 304                .device_id      = 0x1C,
 305                .ai_nchan       = 16,
 306                .ai_bits        = 16,
 307                .ai_speed       = 5000,
 308                .fifo_size      = 512,
 309                .ranges         = &cb_pcidas_ranges,
 310                .trimpot        = AD8402,
 311                .has_dac08      = 1,
 312                .is_1602        = 1,
 313        }, {
 314                .name           = "pci-das1000",
 315                .device_id      = 0x4C,
 316                .ai_nchan       = 16,
 317                .ai_bits        = 12,
 318                .ai_speed       = 4000,
 319                .fifo_size      = 1024,
 320                .ranges         = &cb_pcidas_ranges,
 321                .trimpot        = AD7376,
 322        }, {
 323                .name           = "pci-das1001",
 324                .device_id      = 0x1a,
 325                .ai_nchan       = 16,
 326                .ai_bits        = 12,
 327                .ai_speed       = 6800,
 328                .ao_nchan       = 2,
 329                .fifo_size      = 1024,
 330                .ranges         = &cb_pcidas_alt_ranges,
 331                .trimpot        = AD7376,
 332        }, {
 333                .name           = "pci-das1002",
 334                .device_id      = 0x1b,
 335                .ai_nchan       = 16,
 336                .ai_bits        = 12,
 337                .ai_speed       = 6800,
 338                .ao_nchan       = 2,
 339                .fifo_size      = 1024,
 340                .ranges         = &cb_pcidas_ranges,
 341                .trimpot        = AD7376,
 342        },
 343};
 344
 345struct cb_pcidas_private {
 346        /* base addresses */
 347        unsigned long s5933_config;
 348        unsigned long control_status;
 349        unsigned long adc_fifo;
 350        unsigned long pacer_counter_dio;
 351        unsigned long ao_registers;
 352        /* divisors of master clock for analog input pacing */
 353        unsigned int divisor1;
 354        unsigned int divisor2;
 355        /* number of analog input samples remaining */
 356        unsigned int count;
 357        /* bits to write to registers */
 358        unsigned int adc_fifo_bits;
 359        unsigned int s5933_intcsr_bits;
 360        unsigned int ao_control_bits;
 361        /* fifo buffers */
 362        short ai_buffer[AI_BUFFER_SIZE];
 363        short ao_buffer[AO_BUFFER_SIZE];
 364        /* divisors of master clock for analog output pacing */
 365        unsigned int ao_divisor1;
 366        unsigned int ao_divisor2;
 367        /* number of analog output samples remaining */
 368        unsigned int ao_count;
 369        /* cached values for readback */
 370        int ao_value[2];
 371        unsigned int caldac_value[NUM_CHANNELS_8800];
 372        unsigned int trimpot_value[NUM_CHANNELS_8402];
 373        unsigned int dac08_value;
 374        unsigned int calibration_source;
 375};
 376
 377static inline unsigned int cal_enable_bits(struct comedi_device *dev)
 378{
 379        struct cb_pcidas_private *devpriv = dev->private;
 380
 381        return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source);
 382}
 383
 384static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
 385                              struct comedi_subdevice *s,
 386                              struct comedi_insn *insn, unsigned int *data)
 387{
 388        struct cb_pcidas_private *devpriv = dev->private;
 389        unsigned int chan = CR_CHAN(insn->chanspec);
 390        unsigned int range = CR_RANGE(insn->chanspec);
 391        unsigned int aref = CR_AREF(insn->chanspec);
 392        unsigned int bits;
 393        int n, i;
 394
 395        /* enable calibration input if appropriate */
 396        if (insn->chanspec & CR_ALT_SOURCE) {
 397                outw(cal_enable_bits(dev),
 398                     devpriv->control_status + CALIBRATION_REG);
 399                chan = 0;
 400        } else {
 401                outw(0, devpriv->control_status + CALIBRATION_REG);
 402        }
 403
 404        /* set mux limits and gain */
 405        bits = BEGIN_SCAN(chan) | END_SCAN(chan) | GAIN_BITS(range);
 406        /* set unipolar/bipolar */
 407        if (range & IS_UNIPOLAR)
 408                bits |= UNIP;
 409        /* set single-ended/differential */
 410        if (aref != AREF_DIFF)
 411                bits |= SE;
 412        outw(bits, devpriv->control_status + ADCMUX_CONT);
 413
 414        /* clear fifo */
 415        outw(0, devpriv->adc_fifo + ADCFIFOCLR);
 416
 417        /* convert n samples */
 418        for (n = 0; n < insn->n; n++) {
 419                /* trigger conversion */
 420                outw(0, devpriv->adc_fifo + ADCDATA);
 421
 422                /* wait for conversion to end */
 423                /* return -ETIMEDOUT if there is a timeout */
 424                for (i = 0; i < 10000; i++) {
 425                        if (inw(devpriv->control_status + ADCMUX_CONT) & EOC)
 426                                break;
 427                }
 428                if (i == 10000)
 429                        return -ETIMEDOUT;
 430
 431                /* read data */
 432                data[n] = inw(devpriv->adc_fifo + ADCDATA);
 433        }
 434
 435        /* return the number of samples read/written */
 436        return n;
 437}
 438
 439static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 440                          struct comedi_insn *insn, unsigned int *data)
 441{
 442        struct cb_pcidas_private *devpriv = dev->private;
 443        int id = data[0];
 444        unsigned int source = data[1];
 445
 446        switch (id) {
 447        case INSN_CONFIG_ALT_SOURCE:
 448                if (source >= 8) {
 449                        dev_err(dev->class_dev,
 450                                "invalid calibration source: %i\n",
 451                                source);
 452                        return -EINVAL;
 453                }
 454                devpriv->calibration_source = source;
 455                break;
 456        default:
 457                return -EINVAL;
 458                break;
 459        }
 460        return insn->n;
 461}
 462
 463/* analog output insn for pcidas-1000 and 1200 series */
 464static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev,
 465                                     struct comedi_subdevice *s,
 466                                     struct comedi_insn *insn,
 467                                     unsigned int *data)
 468{
 469        struct cb_pcidas_private *devpriv = dev->private;
 470        unsigned int chan = CR_CHAN(insn->chanspec);
 471        unsigned int range = CR_RANGE(insn->chanspec);
 472        unsigned long flags;
 473
 474        /* set channel and range */
 475        spin_lock_irqsave(&dev->spinlock, flags);
 476        devpriv->ao_control_bits &= (~DAC_MODE_UPDATE_BOTH &
 477                                     ~DAC_RANGE_MASK(chan));
 478        devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range));
 479        outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
 480        spin_unlock_irqrestore(&dev->spinlock, flags);
 481
 482        /* remember value for readback */
 483        devpriv->ao_value[chan] = data[0];
 484
 485        /* send data */
 486        outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan));
 487
 488        return insn->n;
 489}
 490
 491/* analog output insn for pcidas-1602 series */
 492static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev,
 493                                   struct comedi_subdevice *s,
 494                                   struct comedi_insn *insn, unsigned int *data)
 495{
 496        struct cb_pcidas_private *devpriv = dev->private;
 497        unsigned int chan = CR_CHAN(insn->chanspec);
 498        unsigned int range = CR_RANGE(insn->chanspec);
 499        unsigned long flags;
 500
 501        /* clear dac fifo */
 502        outw(0, devpriv->ao_registers + DACFIFOCLR);
 503
 504        /* set channel and range */
 505        spin_lock_irqsave(&dev->spinlock, flags);
 506        devpriv->ao_control_bits &= (~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) &
 507                                     ~DAC_RANGE_MASK(chan) & ~DAC_PACER_MASK);
 508        devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range) |
 509                                     DAC_CHAN_EN(chan) | DAC_START);
 510        outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
 511        spin_unlock_irqrestore(&dev->spinlock, flags);
 512
 513        /* remember value for readback */
 514        devpriv->ao_value[chan] = data[0];
 515
 516        /* send data */
 517        outw(data[0], devpriv->ao_registers + DACDATA);
 518
 519        return insn->n;
 520}
 521
 522static int cb_pcidas_ao_readback_insn(struct comedi_device *dev,
 523                                      struct comedi_subdevice *s,
 524                                      struct comedi_insn *insn,
 525                                      unsigned int *data)
 526{
 527        struct cb_pcidas_private *devpriv = dev->private;
 528
 529        data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
 530
 531        return 1;
 532}
 533
 534static int wait_for_nvram_ready(unsigned long s5933_base_addr)
 535{
 536        static const int timeout = 1000;
 537        unsigned int i;
 538
 539        for (i = 0; i < timeout; i++) {
 540                if ((inb(s5933_base_addr +
 541                         AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY)
 542                    == 0)
 543                        return 0;
 544                udelay(1);
 545        }
 546        return -1;
 547}
 548
 549static int nvram_read(struct comedi_device *dev, unsigned int address,
 550                        uint8_t *data)
 551{
 552        struct cb_pcidas_private *devpriv = dev->private;
 553        unsigned long iobase = devpriv->s5933_config;
 554
 555        if (wait_for_nvram_ready(iobase) < 0)
 556                return -ETIMEDOUT;
 557
 558        outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR,
 559             iobase + AMCC_OP_REG_MCSR_NVCMD);
 560        outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
 561        outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR,
 562             iobase + AMCC_OP_REG_MCSR_NVCMD);
 563        outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
 564        outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
 565
 566        if (wait_for_nvram_ready(iobase) < 0)
 567                return -ETIMEDOUT;
 568
 569        *data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
 570
 571        return 0;
 572}
 573
 574static int eeprom_read_insn(struct comedi_device *dev,
 575                            struct comedi_subdevice *s,
 576                            struct comedi_insn *insn, unsigned int *data)
 577{
 578        uint8_t nvram_data;
 579        int retval;
 580
 581        retval = nvram_read(dev, CR_CHAN(insn->chanspec), &nvram_data);
 582        if (retval < 0)
 583                return retval;
 584
 585        data[0] = nvram_data;
 586
 587        return 1;
 588}
 589
 590static void write_calibration_bitstream(struct comedi_device *dev,
 591                                        unsigned int register_bits,
 592                                        unsigned int bitstream,
 593                                        unsigned int bitstream_length)
 594{
 595        struct cb_pcidas_private *devpriv = dev->private;
 596        static const int write_delay = 1;
 597        unsigned int bit;
 598
 599        for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
 600                if (bitstream & bit)
 601                        register_bits |= SERIAL_DATA_IN_BIT;
 602                else
 603                        register_bits &= ~SERIAL_DATA_IN_BIT;
 604                udelay(write_delay);
 605                outw(register_bits, devpriv->control_status + CALIBRATION_REG);
 606        }
 607}
 608
 609static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
 610                             uint8_t value)
 611{
 612        struct cb_pcidas_private *devpriv = dev->private;
 613        static const int num_caldac_channels = 8;
 614        static const int bitstream_length = 11;
 615        unsigned int bitstream = ((address & 0x7) << 8) | value;
 616        static const int caldac_8800_udelay = 1;
 617
 618        if (address >= num_caldac_channels) {
 619                comedi_error(dev, "illegal caldac channel");
 620                return -1;
 621        }
 622
 623        if (value == devpriv->caldac_value[address])
 624                return 1;
 625
 626        devpriv->caldac_value[address] = value;
 627
 628        write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream,
 629                                    bitstream_length);
 630
 631        udelay(caldac_8800_udelay);
 632        outw(cal_enable_bits(dev) | SELECT_8800_BIT,
 633             devpriv->control_status + CALIBRATION_REG);
 634        udelay(caldac_8800_udelay);
 635        outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
 636
 637        return 1;
 638}
 639
 640static int caldac_write_insn(struct comedi_device *dev,
 641                             struct comedi_subdevice *s,
 642                             struct comedi_insn *insn, unsigned int *data)
 643{
 644        const unsigned int channel = CR_CHAN(insn->chanspec);
 645
 646        return caldac_8800_write(dev, channel, data[0]);
 647}
 648
 649static int caldac_read_insn(struct comedi_device *dev,
 650                            struct comedi_subdevice *s,
 651                            struct comedi_insn *insn, unsigned int *data)
 652{
 653        struct cb_pcidas_private *devpriv = dev->private;
 654
 655        data[0] = devpriv->caldac_value[CR_CHAN(insn->chanspec)];
 656
 657        return 1;
 658}
 659
 660/* 1602/16 pregain offset */
 661static void dac08_write(struct comedi_device *dev, unsigned int value)
 662{
 663        struct cb_pcidas_private *devpriv = dev->private;
 664        unsigned long cal_reg;
 665
 666        if (devpriv->dac08_value != value) {
 667                devpriv->dac08_value = value;
 668
 669                cal_reg = devpriv->control_status + CALIBRATION_REG;
 670
 671                value &= 0xff;
 672                value |= cal_enable_bits(dev);
 673
 674                /* latch the new value into the caldac */
 675                outw(value, cal_reg);
 676                udelay(1);
 677                outw(value | SELECT_DAC08_BIT, cal_reg);
 678                udelay(1);
 679                outw(value, cal_reg);
 680                udelay(1);
 681        }
 682}
 683
 684static int dac08_write_insn(struct comedi_device *dev,
 685                            struct comedi_subdevice *s,
 686                            struct comedi_insn *insn, unsigned int *data)
 687{
 688        int i;
 689
 690        for (i = 0; i < insn->n; i++)
 691                dac08_write(dev, data[i]);
 692
 693        return insn->n;
 694}
 695
 696static int dac08_read_insn(struct comedi_device *dev,
 697                           struct comedi_subdevice *s, struct comedi_insn *insn,
 698                           unsigned int *data)
 699{
 700        struct cb_pcidas_private *devpriv = dev->private;
 701
 702        data[0] = devpriv->dac08_value;
 703
 704        return 1;
 705}
 706
 707static int trimpot_7376_write(struct comedi_device *dev, uint8_t value)
 708{
 709        struct cb_pcidas_private *devpriv = dev->private;
 710        static const int bitstream_length = 7;
 711        unsigned int bitstream = value & 0x7f;
 712        unsigned int register_bits;
 713        static const int ad7376_udelay = 1;
 714
 715        register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
 716        udelay(ad7376_udelay);
 717        outw(register_bits, devpriv->control_status + CALIBRATION_REG);
 718
 719        write_calibration_bitstream(dev, register_bits, bitstream,
 720                                    bitstream_length);
 721
 722        udelay(ad7376_udelay);
 723        outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
 724
 725        return 0;
 726}
 727
 728/* For 1602/16 only
 729 * ch 0 : adc gain
 730 * ch 1 : adc postgain offset */
 731static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel,
 732                              uint8_t value)
 733{
 734        struct cb_pcidas_private *devpriv = dev->private;
 735        static const int bitstream_length = 10;
 736        unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff);
 737        unsigned int register_bits;
 738        static const int ad8402_udelay = 1;
 739
 740        register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
 741        udelay(ad8402_udelay);
 742        outw(register_bits, devpriv->control_status + CALIBRATION_REG);
 743
 744        write_calibration_bitstream(dev, register_bits, bitstream,
 745                                    bitstream_length);
 746
 747        udelay(ad8402_udelay);
 748        outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
 749
 750        return 0;
 751}
 752
 753static int cb_pcidas_trimpot_write(struct comedi_device *dev,
 754                                   unsigned int channel, unsigned int value)
 755{
 756        const struct cb_pcidas_board *thisboard = comedi_board(dev);
 757        struct cb_pcidas_private *devpriv = dev->private;
 758
 759        if (devpriv->trimpot_value[channel] == value)
 760                return 1;
 761
 762        devpriv->trimpot_value[channel] = value;
 763        switch (thisboard->trimpot) {
 764        case AD7376:
 765                trimpot_7376_write(dev, value);
 766                break;
 767        case AD8402:
 768                trimpot_8402_write(dev, channel, value);
 769                break;
 770        default:
 771                comedi_error(dev, "driver bug?");
 772                return -1;
 773                break;
 774        }
 775
 776        return 1;
 777}
 778
 779static int trimpot_write_insn(struct comedi_device *dev,
 780                              struct comedi_subdevice *s,
 781                              struct comedi_insn *insn, unsigned int *data)
 782{
 783        unsigned int channel = CR_CHAN(insn->chanspec);
 784
 785        return cb_pcidas_trimpot_write(dev, channel, data[0]);
 786}
 787
 788static int trimpot_read_insn(struct comedi_device *dev,
 789                             struct comedi_subdevice *s,
 790                             struct comedi_insn *insn, unsigned int *data)
 791{
 792        struct cb_pcidas_private *devpriv = dev->private;
 793        unsigned int channel = CR_CHAN(insn->chanspec);
 794
 795        data[0] = devpriv->trimpot_value[channel];
 796
 797        return 1;
 798}
 799
 800static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
 801                                struct comedi_subdevice *s,
 802                                struct comedi_cmd *cmd)
 803{
 804        const struct cb_pcidas_board *thisboard = comedi_board(dev);
 805        struct cb_pcidas_private *devpriv = dev->private;
 806        int err = 0;
 807        int tmp;
 808        int i, gain, start_chan;
 809
 810        /* step 1: trigger sources are trivially valid */
 811
 812        tmp = cmd->start_src;
 813        cmd->start_src &= TRIG_NOW | TRIG_EXT;
 814        if (!cmd->start_src || tmp != cmd->start_src)
 815                err++;
 816
 817        tmp = cmd->scan_begin_src;
 818        cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT;
 819        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 820                err++;
 821
 822        tmp = cmd->convert_src;
 823        cmd->convert_src &= TRIG_TIMER | TRIG_NOW | TRIG_EXT;
 824        if (!cmd->convert_src || tmp != cmd->convert_src)
 825                err++;
 826
 827        tmp = cmd->scan_end_src;
 828        cmd->scan_end_src &= TRIG_COUNT;
 829        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 830                err++;
 831
 832        tmp = cmd->stop_src;
 833        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 834        if (!cmd->stop_src || tmp != cmd->stop_src)
 835                err++;
 836
 837        if (err)
 838                return 1;
 839
 840        /* step 2: trigger sources are unique and mutually compatible */
 841
 842        if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
 843                err++;
 844        if (cmd->scan_begin_src != TRIG_FOLLOW &&
 845            cmd->scan_begin_src != TRIG_TIMER &&
 846            cmd->scan_begin_src != TRIG_EXT)
 847                err++;
 848        if (cmd->convert_src != TRIG_TIMER &&
 849            cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
 850                err++;
 851        if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
 852                err++;
 853
 854        /*  make sure trigger sources are compatible with each other */
 855        if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
 856                err++;
 857        if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
 858                err++;
 859        if (cmd->start_src == TRIG_EXT &&
 860            (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT))
 861                err++;
 862
 863        if (err)
 864                return 2;
 865
 866        /* step 3: arguments are trivially compatible */
 867
 868        switch (cmd->start_src) {
 869        case TRIG_EXT:
 870                /* External trigger, only CR_EDGE and CR_INVERT flags allowed */
 871                if ((cmd->start_arg
 872                     & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) {
 873                        cmd->start_arg &=
 874                            ~(CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
 875                        err++;
 876                }
 877                if (!thisboard->is_1602 && (cmd->start_arg & CR_INVERT)) {
 878                        cmd->start_arg &= (CR_FLAGS_MASK & ~CR_INVERT);
 879                        err++;
 880                }
 881                break;
 882        default:
 883                if (cmd->start_arg != 0) {
 884                        cmd->start_arg = 0;
 885                        err++;
 886                }
 887                break;
 888        }
 889
 890        if (cmd->scan_begin_src == TRIG_TIMER) {
 891                if (cmd->scan_begin_arg <
 892                    thisboard->ai_speed * cmd->chanlist_len) {
 893                        cmd->scan_begin_arg =
 894                            thisboard->ai_speed * cmd->chanlist_len;
 895                        err++;
 896                }
 897        }
 898        if (cmd->convert_src == TRIG_TIMER) {
 899                if (cmd->convert_arg < thisboard->ai_speed) {
 900                        cmd->convert_arg = thisboard->ai_speed;
 901                        err++;
 902                }
 903        }
 904
 905        if (cmd->scan_end_arg != cmd->chanlist_len) {
 906                cmd->scan_end_arg = cmd->chanlist_len;
 907                err++;
 908        }
 909        if (cmd->stop_src == TRIG_NONE) {
 910                /* TRIG_NONE */
 911                if (cmd->stop_arg != 0) {
 912                        cmd->stop_arg = 0;
 913                        err++;
 914                }
 915        }
 916
 917        if (err)
 918                return 3;
 919
 920        /* step 4: fix up any arguments */
 921
 922        if (cmd->scan_begin_src == TRIG_TIMER) {
 923                tmp = cmd->scan_begin_arg;
 924                i8253_cascade_ns_to_timer_2div(TIMER_BASE,
 925                                               &(devpriv->divisor1),
 926                                               &(devpriv->divisor2),
 927                                               &(cmd->scan_begin_arg),
 928                                               cmd->flags & TRIG_ROUND_MASK);
 929                if (tmp != cmd->scan_begin_arg)
 930                        err++;
 931        }
 932        if (cmd->convert_src == TRIG_TIMER) {
 933                tmp = cmd->convert_arg;
 934                i8253_cascade_ns_to_timer_2div(TIMER_BASE,
 935                                               &(devpriv->divisor1),
 936                                               &(devpriv->divisor2),
 937                                               &(cmd->convert_arg),
 938                                               cmd->flags & TRIG_ROUND_MASK);
 939                if (tmp != cmd->convert_arg)
 940                        err++;
 941        }
 942
 943        if (err)
 944                return 4;
 945
 946        /*  check channel/gain list against card's limitations */
 947        if (cmd->chanlist) {
 948                gain = CR_RANGE(cmd->chanlist[0]);
 949                start_chan = CR_CHAN(cmd->chanlist[0]);
 950                for (i = 1; i < cmd->chanlist_len; i++) {
 951                        if (CR_CHAN(cmd->chanlist[i]) !=
 952                            (start_chan + i) % s->n_chan) {
 953                                comedi_error(dev,
 954                                             "entries in chanlist must be consecutive channels, counting upwards\n");
 955                                err++;
 956                        }
 957                        if (CR_RANGE(cmd->chanlist[i]) != gain) {
 958                                comedi_error(dev,
 959                                             "entries in chanlist must all have the same gain\n");
 960                                err++;
 961                        }
 962                }
 963        }
 964
 965        if (err)
 966                return 5;
 967
 968        return 0;
 969}
 970
 971static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns,
 972                                    int rounding_flags)
 973{
 974        struct cb_pcidas_private *devpriv = dev->private;
 975
 976        i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
 977                                       &(devpriv->divisor2), ns,
 978                                       rounding_flags & TRIG_ROUND_MASK);
 979
 980        /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
 981        i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 1,
 982                   devpriv->divisor1, 2);
 983        i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 2,
 984                   devpriv->divisor2, 2);
 985}
 986
 987static int cb_pcidas_ai_cmd(struct comedi_device *dev,
 988                            struct comedi_subdevice *s)
 989{
 990        const struct cb_pcidas_board *thisboard = comedi_board(dev);
 991        struct cb_pcidas_private *devpriv = dev->private;
 992        struct comedi_async *async = s->async;
 993        struct comedi_cmd *cmd = &async->cmd;
 994        unsigned int bits;
 995        unsigned long flags;
 996
 997        /*  make sure CAL_EN_BIT is disabled */
 998        outw(0, devpriv->control_status + CALIBRATION_REG);
 999        /*  initialize before settings pacer source and count values */
1000        outw(0, devpriv->control_status + TRIG_CONTSTAT);
1001        /*  clear fifo */
1002        outw(0, devpriv->adc_fifo + ADCFIFOCLR);
1003
1004        /*  set mux limits, gain and pacer source */
1005        bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) |
1006            END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) |
1007            GAIN_BITS(CR_RANGE(cmd->chanlist[0]));
1008        /*  set unipolar/bipolar */
1009        if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR)
1010                bits |= UNIP;
1011        /*  set singleended/differential */
1012        if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF)
1013                bits |= SE;
1014        /*  set pacer source */
1015        if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)
1016                bits |= PACER_EXT_RISE;
1017        else
1018                bits |= PACER_INT;
1019        outw(bits, devpriv->control_status + ADCMUX_CONT);
1020
1021        /*  load counters */
1022        if (cmd->convert_src == TRIG_TIMER)
1023                cb_pcidas_load_counters(dev, &cmd->convert_arg,
1024                                        cmd->flags & TRIG_ROUND_MASK);
1025        else if (cmd->scan_begin_src == TRIG_TIMER)
1026                cb_pcidas_load_counters(dev, &cmd->scan_begin_arg,
1027                                        cmd->flags & TRIG_ROUND_MASK);
1028
1029        /*  set number of conversions */
1030        if (cmd->stop_src == TRIG_COUNT)
1031                devpriv->count = cmd->chanlist_len * cmd->stop_arg;
1032        /*  enable interrupts */
1033        spin_lock_irqsave(&dev->spinlock, flags);
1034        devpriv->adc_fifo_bits |= INTE;
1035        devpriv->adc_fifo_bits &= ~INT_MASK;
1036        if (cmd->flags & TRIG_WAKE_EOS) {
1037                if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) {
1038                        /* interrupt end of burst */
1039                        devpriv->adc_fifo_bits |= INT_EOS;
1040                } else {
1041                        /* interrupt fifo not empty */
1042                        devpriv->adc_fifo_bits |= INT_FNE;
1043                }
1044        } else {
1045                /* interrupt fifo half full */
1046                devpriv->adc_fifo_bits |= INT_FHF;
1047        }
1048
1049        /*  enable (and clear) interrupts */
1050        outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL,
1051             devpriv->control_status + INT_ADCFIFO);
1052        spin_unlock_irqrestore(&dev->spinlock, flags);
1053
1054        /*  set start trigger and burst mode */
1055        bits = 0;
1056        if (cmd->start_src == TRIG_NOW)
1057                bits |= SW_TRIGGER;
1058        else if (cmd->start_src == TRIG_EXT) {
1059                bits |= EXT_TRIGGER | TGEN | XTRCL;
1060                if (thisboard->is_1602) {
1061                        if (cmd->start_arg & CR_INVERT)
1062                                bits |= TGPOL;
1063                        if (cmd->start_arg & CR_EDGE)
1064                                bits |= TGSEL;
1065                }
1066        } else {
1067                comedi_error(dev, "bug!");
1068                return -1;
1069        }
1070        if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
1071                bits |= BURSTE;
1072        outw(bits, devpriv->control_status + TRIG_CONTSTAT);
1073
1074        return 0;
1075}
1076
1077static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
1078                                struct comedi_subdevice *s,
1079                                struct comedi_cmd *cmd)
1080{
1081        const struct cb_pcidas_board *thisboard = comedi_board(dev);
1082        struct cb_pcidas_private *devpriv = dev->private;
1083        int err = 0;
1084        int tmp;
1085
1086        /* step 1: trigger sources are trivially valid */
1087
1088        tmp = cmd->start_src;
1089        cmd->start_src &= TRIG_INT;
1090        if (!cmd->start_src || tmp != cmd->start_src)
1091                err++;
1092
1093        tmp = cmd->scan_begin_src;
1094        cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
1095        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1096                err++;
1097
1098        tmp = cmd->convert_src;
1099        cmd->convert_src &= TRIG_NOW;
1100        if (!cmd->convert_src || tmp != cmd->convert_src)
1101                err++;
1102
1103        tmp = cmd->scan_end_src;
1104        cmd->scan_end_src &= TRIG_COUNT;
1105        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1106                err++;
1107
1108        tmp = cmd->stop_src;
1109        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1110        if (!cmd->stop_src || tmp != cmd->stop_src)
1111                err++;
1112
1113        if (err)
1114                return 1;
1115
1116        /* step 2: trigger sources are unique and mutually compatible */
1117
1118        if (cmd->scan_begin_src != TRIG_TIMER &&
1119            cmd->scan_begin_src != TRIG_EXT)
1120                err++;
1121        if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1122                err++;
1123
1124        if (err)
1125                return 2;
1126
1127        /* step 3: arguments are trivially compatible */
1128
1129        if (cmd->start_arg != 0) {
1130                cmd->start_arg = 0;
1131                err++;
1132        }
1133
1134        if (cmd->scan_begin_src == TRIG_TIMER) {
1135                if (cmd->scan_begin_arg < thisboard->ao_scan_speed) {
1136                        cmd->scan_begin_arg = thisboard->ao_scan_speed;
1137                        err++;
1138                }
1139        }
1140
1141        if (cmd->scan_end_arg != cmd->chanlist_len) {
1142                cmd->scan_end_arg = cmd->chanlist_len;
1143                err++;
1144        }
1145        if (cmd->stop_src == TRIG_NONE) {
1146                /* TRIG_NONE */
1147                if (cmd->stop_arg != 0) {
1148                        cmd->stop_arg = 0;
1149                        err++;
1150                }
1151        }
1152
1153        if (err)
1154                return 3;
1155
1156        /* step 4: fix up any arguments */
1157
1158        if (cmd->scan_begin_src == TRIG_TIMER) {
1159                tmp = cmd->scan_begin_arg;
1160                i8253_cascade_ns_to_timer_2div(TIMER_BASE,
1161                                               &(devpriv->ao_divisor1),
1162                                               &(devpriv->ao_divisor2),
1163                                               &(cmd->scan_begin_arg),
1164                                               cmd->flags & TRIG_ROUND_MASK);
1165                if (tmp != cmd->scan_begin_arg)
1166                        err++;
1167        }
1168
1169        if (err)
1170                return 4;
1171
1172        /*  check channel/gain list against card's limitations */
1173        if (cmd->chanlist && cmd->chanlist_len > 1) {
1174                if (CR_CHAN(cmd->chanlist[0]) != 0 ||
1175                    CR_CHAN(cmd->chanlist[1]) != 1) {
1176                        comedi_error(dev,
1177                                     "channels must be ordered channel 0, channel 1 in chanlist\n");
1178                        err++;
1179                }
1180        }
1181
1182        if (err)
1183                return 5;
1184
1185        return 0;
1186}
1187
1188/* cancel analog input command */
1189static int cb_pcidas_cancel(struct comedi_device *dev,
1190                            struct comedi_subdevice *s)
1191{
1192        struct cb_pcidas_private *devpriv = dev->private;
1193        unsigned long flags;
1194
1195        spin_lock_irqsave(&dev->spinlock, flags);
1196        /*  disable interrupts */
1197        devpriv->adc_fifo_bits &= ~INTE & ~EOAIE;
1198        outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1199        spin_unlock_irqrestore(&dev->spinlock, flags);
1200
1201        /*  disable start trigger source and burst mode */
1202        outw(0, devpriv->control_status + TRIG_CONTSTAT);
1203        /*  software pacer source */
1204        outw(0, devpriv->control_status + ADCMUX_CONT);
1205
1206        return 0;
1207}
1208
1209static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
1210                                struct comedi_subdevice *s,
1211                                unsigned int trig_num)
1212{
1213        const struct cb_pcidas_board *thisboard = comedi_board(dev);
1214        struct cb_pcidas_private *devpriv = dev->private;
1215        unsigned int num_bytes, num_points = thisboard->fifo_size;
1216        struct comedi_async *async = s->async;
1217        struct comedi_cmd *cmd = &s->async->cmd;
1218        unsigned long flags;
1219
1220        if (trig_num != 0)
1221                return -EINVAL;
1222
1223        /*  load up fifo */
1224        if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points)
1225                num_points = devpriv->ao_count;
1226
1227        num_bytes = cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1228                                               num_points * sizeof(short));
1229        num_points = num_bytes / sizeof(short);
1230
1231        if (cmd->stop_src == TRIG_COUNT)
1232                devpriv->ao_count -= num_points;
1233        /*  write data to board's fifo */
1234        outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes);
1235
1236        /*  enable dac half-full and empty interrupts */
1237        spin_lock_irqsave(&dev->spinlock, flags);
1238        devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
1239
1240        /*  enable and clear interrupts */
1241        outw(devpriv->adc_fifo_bits | DAEMI | DAHFI,
1242             devpriv->control_status + INT_ADCFIFO);
1243
1244        /*  start dac */
1245        devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;
1246        outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
1247
1248        spin_unlock_irqrestore(&dev->spinlock, flags);
1249
1250        async->inttrig = NULL;
1251
1252        return 0;
1253}
1254
1255static int cb_pcidas_ao_cmd(struct comedi_device *dev,
1256                            struct comedi_subdevice *s)
1257{
1258        struct cb_pcidas_private *devpriv = dev->private;
1259        struct comedi_async *async = s->async;
1260        struct comedi_cmd *cmd = &async->cmd;
1261        unsigned int i;
1262        unsigned long flags;
1263
1264        /*  set channel limits, gain */
1265        spin_lock_irqsave(&dev->spinlock, flags);
1266        for (i = 0; i < cmd->chanlist_len; i++) {
1267                /*  enable channel */
1268                devpriv->ao_control_bits |=
1269                    DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i]));
1270                /*  set range */
1271                devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]),
1272                                                      CR_RANGE(cmd->
1273                                                               chanlist[i]));
1274        }
1275
1276        /*  disable analog out before settings pacer source and count values */
1277        outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
1278        spin_unlock_irqrestore(&dev->spinlock, flags);
1279
1280        /*  clear fifo */
1281        outw(0, devpriv->ao_registers + DACFIFOCLR);
1282
1283        /*  load counters */
1284        if (cmd->scan_begin_src == TRIG_TIMER) {
1285                i8253_cascade_ns_to_timer_2div(TIMER_BASE,
1286                                               &(devpriv->ao_divisor1),
1287                                               &(devpriv->ao_divisor2),
1288                                               &(cmd->scan_begin_arg),
1289                                               cmd->flags);
1290
1291                /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
1292                i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1,
1293                           devpriv->ao_divisor1, 2);
1294                i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2,
1295                           devpriv->ao_divisor2, 2);
1296        }
1297        /*  set number of conversions */
1298        if (cmd->stop_src == TRIG_COUNT)
1299                devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg;
1300        /*  set pacer source */
1301        spin_lock_irqsave(&dev->spinlock, flags);
1302        switch (cmd->scan_begin_src) {
1303        case TRIG_TIMER:
1304                devpriv->ao_control_bits |= DAC_PACER_INT;
1305                break;
1306        case TRIG_EXT:
1307                devpriv->ao_control_bits |= DAC_PACER_EXT_RISE;
1308                break;
1309        default:
1310                spin_unlock_irqrestore(&dev->spinlock, flags);
1311                comedi_error(dev, "error setting dac pacer source");
1312                return -1;
1313                break;
1314        }
1315        spin_unlock_irqrestore(&dev->spinlock, flags);
1316
1317        async->inttrig = cb_pcidas_ao_inttrig;
1318
1319        return 0;
1320}
1321
1322/* cancel analog output command */
1323static int cb_pcidas_ao_cancel(struct comedi_device *dev,
1324                               struct comedi_subdevice *s)
1325{
1326        struct cb_pcidas_private *devpriv = dev->private;
1327        unsigned long flags;
1328
1329        spin_lock_irqsave(&dev->spinlock, flags);
1330        /*  disable interrupts */
1331        devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE;
1332        outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1333
1334        /*  disable output */
1335        devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK;
1336        outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
1337        spin_unlock_irqrestore(&dev->spinlock, flags);
1338
1339        return 0;
1340}
1341
1342static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
1343{
1344        const struct cb_pcidas_board *thisboard = comedi_board(dev);
1345        struct cb_pcidas_private *devpriv = dev->private;
1346        struct comedi_subdevice *s = dev->write_subdev;
1347        struct comedi_async *async = s->async;
1348        struct comedi_cmd *cmd = &async->cmd;
1349        unsigned int half_fifo = thisboard->fifo_size / 2;
1350        unsigned int num_points;
1351        unsigned long flags;
1352
1353        async->events = 0;
1354
1355        if (status & DAEMI) {
1356                /*  clear dac empty interrupt latch */
1357                spin_lock_irqsave(&dev->spinlock, flags);
1358                outw(devpriv->adc_fifo_bits | DAEMI,
1359                     devpriv->control_status + INT_ADCFIFO);
1360                spin_unlock_irqrestore(&dev->spinlock, flags);
1361                if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) {
1362                        if (cmd->stop_src == TRIG_NONE ||
1363                            (cmd->stop_src == TRIG_COUNT
1364                             && devpriv->ao_count)) {
1365                                comedi_error(dev, "dac fifo underflow");
1366                                cb_pcidas_ao_cancel(dev, s);
1367                                async->events |= COMEDI_CB_ERROR;
1368                        }
1369                        async->events |= COMEDI_CB_EOA;
1370                }
1371        } else if (status & DAHFI) {
1372                unsigned int num_bytes;
1373
1374                /*  figure out how many points we are writing to fifo */
1375                num_points = half_fifo;
1376                if (cmd->stop_src == TRIG_COUNT &&
1377                    devpriv->ao_count < num_points)
1378                        num_points = devpriv->ao_count;
1379                num_bytes =
1380                    cfc_read_array_from_buffer(s, devpriv->ao_buffer,
1381                                               num_points * sizeof(short));
1382                num_points = num_bytes / sizeof(short);
1383
1384                if (async->cmd.stop_src == TRIG_COUNT)
1385                        devpriv->ao_count -= num_points;
1386                /*  write data to board's fifo */
1387                outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer,
1388                      num_points);
1389                /*  clear half-full interrupt latch */
1390                spin_lock_irqsave(&dev->spinlock, flags);
1391                outw(devpriv->adc_fifo_bits | DAHFI,
1392                     devpriv->control_status + INT_ADCFIFO);
1393                spin_unlock_irqrestore(&dev->spinlock, flags);
1394        }
1395
1396        comedi_event(dev, s);
1397}
1398
1399static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
1400{
1401        struct comedi_device *dev = (struct comedi_device *)d;
1402        const struct cb_pcidas_board *thisboard = comedi_board(dev);
1403        struct cb_pcidas_private *devpriv = dev->private;
1404        struct comedi_subdevice *s = dev->read_subdev;
1405        struct comedi_async *async;
1406        int status, s5933_status;
1407        int half_fifo = thisboard->fifo_size / 2;
1408        unsigned int num_samples, i;
1409        static const int timeout = 10000;
1410        unsigned long flags;
1411
1412        if (dev->attached == 0)
1413                return IRQ_NONE;
1414
1415        async = s->async;
1416        async->events = 0;
1417
1418        s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1419
1420        if ((INTCSR_INTR_ASSERTED & s5933_status) == 0)
1421                return IRQ_NONE;
1422
1423        /*  make sure mailbox 4 is empty */
1424        inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4);
1425        /*  clear interrupt on amcc s5933 */
1426        outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
1427             devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1428
1429        status = inw(devpriv->control_status + INT_ADCFIFO);
1430
1431        /*  check for analog output interrupt */
1432        if (status & (DAHFI | DAEMI))
1433                handle_ao_interrupt(dev, status);
1434        /*  check for analog input interrupts */
1435        /*  if fifo half-full */
1436        if (status & ADHFI) {
1437                /*  read data */
1438                num_samples = half_fifo;
1439                if (async->cmd.stop_src == TRIG_COUNT &&
1440                    num_samples > devpriv->count) {
1441                        num_samples = devpriv->count;
1442                }
1443                insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer,
1444                     num_samples);
1445                cfc_write_array_to_buffer(s, devpriv->ai_buffer,
1446                                          num_samples * sizeof(short));
1447                devpriv->count -= num_samples;
1448                if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) {
1449                        async->events |= COMEDI_CB_EOA;
1450                        cb_pcidas_cancel(dev, s);
1451                }
1452                /*  clear half-full interrupt latch */
1453                spin_lock_irqsave(&dev->spinlock, flags);
1454                outw(devpriv->adc_fifo_bits | INT,
1455                     devpriv->control_status + INT_ADCFIFO);
1456                spin_unlock_irqrestore(&dev->spinlock, flags);
1457                /*  else if fifo not empty */
1458        } else if (status & (ADNEI | EOBI)) {
1459                for (i = 0; i < timeout; i++) {
1460                        /*  break if fifo is empty */
1461                        if ((ADNE & inw(devpriv->control_status +
1462                                        INT_ADCFIFO)) == 0)
1463                                break;
1464                        cfc_write_to_buffer(s, inw(devpriv->adc_fifo));
1465                        if (async->cmd.stop_src == TRIG_COUNT &&
1466                            --devpriv->count == 0) {
1467                                /* end of acquisition */
1468                                cb_pcidas_cancel(dev, s);
1469                                async->events |= COMEDI_CB_EOA;
1470                                break;
1471                        }
1472                }
1473                /*  clear not-empty interrupt latch */
1474                spin_lock_irqsave(&dev->spinlock, flags);
1475                outw(devpriv->adc_fifo_bits | INT,
1476                     devpriv->control_status + INT_ADCFIFO);
1477                spin_unlock_irqrestore(&dev->spinlock, flags);
1478        } else if (status & EOAI) {
1479                comedi_error(dev,
1480                             "bug! encountered end of acquisition interrupt?");
1481                /*  clear EOA interrupt latch */
1482                spin_lock_irqsave(&dev->spinlock, flags);
1483                outw(devpriv->adc_fifo_bits | EOAI,
1484                     devpriv->control_status + INT_ADCFIFO);
1485                spin_unlock_irqrestore(&dev->spinlock, flags);
1486        }
1487        /* check for fifo overflow */
1488        if (status & LADFUL) {
1489                comedi_error(dev, "fifo overflow");
1490                /*  clear overflow interrupt latch */
1491                spin_lock_irqsave(&dev->spinlock, flags);
1492                outw(devpriv->adc_fifo_bits | LADFUL,
1493                     devpriv->control_status + INT_ADCFIFO);
1494                spin_unlock_irqrestore(&dev->spinlock, flags);
1495                cb_pcidas_cancel(dev, s);
1496                async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
1497        }
1498
1499        comedi_event(dev, s);
1500
1501        return IRQ_HANDLED;
1502}
1503
1504static struct pci_dev *cb_pcidas_find_pci_device(struct comedi_device *dev,
1505                                                 struct comedi_devconfig *it)
1506{
1507        const struct cb_pcidas_board *thisboard;
1508        struct pci_dev *pcidev = NULL;
1509        int bus = it->options[0];
1510        int slot = it->options[1];
1511        int i;
1512
1513        for_each_pci_dev(pcidev) {
1514                /*  is it not a computer boards card? */
1515                if (pcidev->vendor != PCI_VENDOR_ID_CB)
1516                        continue;
1517                /*  loop through cards supported by this driver */
1518                for (i = 0; i < ARRAY_SIZE(cb_pcidas_boards); i++) {
1519                        thisboard = &cb_pcidas_boards[i];
1520                        if (thisboard->device_id != pcidev->device)
1521                                continue;
1522                        /*  was a particular bus/slot requested? */
1523                        if (bus || slot) {
1524                                /*  are we on the wrong bus/slot? */
1525                                if (pcidev->bus->number != bus ||
1526                                    PCI_SLOT(pcidev->devfn) != slot) {
1527                                        continue;
1528                                }
1529                        }
1530                        dev_dbg(dev->class_dev,
1531                                "Found %s on bus %i, slot %i\n",
1532                                thisboard->name,
1533                                pcidev->bus->number, PCI_SLOT(pcidev->devfn));
1534                        dev->board_ptr = thisboard;
1535                        return pcidev;
1536                }
1537        }
1538        dev_err(dev->class_dev, "No supported card found\n");
1539        return NULL;
1540}
1541
1542static int cb_pcidas_attach(struct comedi_device *dev,
1543                            struct comedi_devconfig *it)
1544{
1545        const struct cb_pcidas_board *thisboard;
1546        struct cb_pcidas_private *devpriv;
1547        struct pci_dev *pcidev;
1548        struct comedi_subdevice *s;
1549        int i;
1550        int ret;
1551
1552        if (alloc_private(dev, sizeof(struct cb_pcidas_private)) < 0)
1553                return -ENOMEM;
1554        devpriv = dev->private;
1555
1556        pcidev = cb_pcidas_find_pci_device(dev, it);
1557        if (!pcidev)
1558                return -EIO;
1559        comedi_set_hw_dev(dev, &pcidev->dev);
1560        thisboard = comedi_board(dev);
1561
1562        if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
1563                dev_err(dev->class_dev,
1564                        "Failed to enable PCI device and request regions\n");
1565                return -EIO;
1566        }
1567
1568        devpriv->s5933_config = pci_resource_start(pcidev, 0);
1569        devpriv->control_status = pci_resource_start(pcidev, 1);
1570        devpriv->adc_fifo = pci_resource_start(pcidev, 2);
1571        devpriv->pacer_counter_dio = pci_resource_start(pcidev, 3);
1572        if (thisboard->ao_nchan)
1573                devpriv->ao_registers = pci_resource_start(pcidev, 4);
1574
1575        /*  disable and clear interrupts on amcc s5933 */
1576        outl(INTCSR_INBOX_INTR_STATUS,
1577             devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1578
1579        if (request_irq(pcidev->irq, cb_pcidas_interrupt,
1580                        IRQF_SHARED, dev->driver->driver_name, dev)) {
1581                dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
1582                        pcidev->irq);
1583                return -EINVAL;
1584        }
1585        dev->irq = pcidev->irq;
1586
1587        dev->board_name = thisboard->name;
1588
1589        ret = comedi_alloc_subdevices(dev, 7);
1590        if (ret)
1591                return ret;
1592
1593        s = dev->subdevices + 0;
1594        /* analog input subdevice */
1595        dev->read_subdev = s;
1596        s->type = COMEDI_SUBD_AI;
1597        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
1598        /* WARNING: Number of inputs in differential mode is ignored */
1599        s->n_chan = thisboard->ai_nchan;
1600        s->len_chanlist = thisboard->ai_nchan;
1601        s->maxdata = (1 << thisboard->ai_bits) - 1;
1602        s->range_table = thisboard->ranges;
1603        s->insn_read = cb_pcidas_ai_rinsn;
1604        s->insn_config = ai_config_insn;
1605        s->do_cmd = cb_pcidas_ai_cmd;
1606        s->do_cmdtest = cb_pcidas_ai_cmdtest;
1607        s->cancel = cb_pcidas_cancel;
1608
1609        /* analog output subdevice */
1610        s = dev->subdevices + 1;
1611        if (thisboard->ao_nchan) {
1612                s->type = COMEDI_SUBD_AO;
1613                s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
1614                s->n_chan = thisboard->ao_nchan;
1615                /*
1616                 * analog out resolution is the same as
1617                 * analog input resolution, so use ai_bits
1618                 */
1619                s->maxdata = (1 << thisboard->ai_bits) - 1;
1620                s->range_table = &cb_pcidas_ao_ranges;
1621                s->insn_read = cb_pcidas_ao_readback_insn;
1622                if (thisboard->has_ao_fifo) {
1623                        dev->write_subdev = s;
1624                        s->subdev_flags |= SDF_CMD_WRITE;
1625                        s->insn_write = cb_pcidas_ao_fifo_winsn;
1626                        s->do_cmdtest = cb_pcidas_ao_cmdtest;
1627                        s->do_cmd = cb_pcidas_ao_cmd;
1628                        s->cancel = cb_pcidas_ao_cancel;
1629                } else {
1630                        s->insn_write = cb_pcidas_ao_nofifo_winsn;
1631                }
1632        } else {
1633                s->type = COMEDI_SUBD_UNUSED;
1634        }
1635
1636        /* 8255 */
1637        s = dev->subdevices + 2;
1638        ret = subdev_8255_init(dev, s, NULL,
1639                               devpriv->pacer_counter_dio + DIO_8255);
1640        if (ret)
1641                return ret;
1642
1643        /*  serial EEPROM, */
1644        s = dev->subdevices + 3;
1645        s->type = COMEDI_SUBD_MEMORY;
1646        s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
1647        s->n_chan = 256;
1648        s->maxdata = 0xff;
1649        s->insn_read = eeprom_read_insn;
1650
1651        /*  8800 caldac */
1652        s = dev->subdevices + 4;
1653        s->type = COMEDI_SUBD_CALIB;
1654        s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1655        s->n_chan = NUM_CHANNELS_8800;
1656        s->maxdata = 0xff;
1657        s->insn_read = caldac_read_insn;
1658        s->insn_write = caldac_write_insn;
1659        for (i = 0; i < s->n_chan; i++)
1660                caldac_8800_write(dev, i, s->maxdata / 2);
1661
1662        /*  trim potentiometer */
1663        s = dev->subdevices + 5;
1664        s->type = COMEDI_SUBD_CALIB;
1665        s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1666        if (thisboard->trimpot == AD7376) {
1667                s->n_chan = NUM_CHANNELS_7376;
1668                s->maxdata = 0x7f;
1669        } else {
1670                s->n_chan = NUM_CHANNELS_8402;
1671                s->maxdata = 0xff;
1672        }
1673        s->insn_read = trimpot_read_insn;
1674        s->insn_write = trimpot_write_insn;
1675        for (i = 0; i < s->n_chan; i++)
1676                cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
1677
1678        /*  dac08 caldac */
1679        s = dev->subdevices + 6;
1680        if (thisboard->has_dac08) {
1681                s->type = COMEDI_SUBD_CALIB;
1682                s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1683                s->n_chan = NUM_CHANNELS_DAC08;
1684                s->insn_read = dac08_read_insn;
1685                s->insn_write = dac08_write_insn;
1686                s->maxdata = 0xff;
1687                dac08_write(dev, s->maxdata / 2);
1688        } else
1689                s->type = COMEDI_SUBD_UNUSED;
1690
1691        /*  make sure mailbox 4 is empty */
1692        inl(devpriv->s5933_config + AMCC_OP_REG_IMB4);
1693        /* Set bits to enable incoming mailbox interrupts on amcc s5933. */
1694        devpriv->s5933_intcsr_bits =
1695            INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) |
1696            INTCSR_INBOX_FULL_INT;
1697        /*  clear and enable interrupt on amcc s5933 */
1698        outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
1699             devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1700
1701        return 1;
1702}
1703
1704static void cb_pcidas_detach(struct comedi_device *dev)
1705{
1706        struct cb_pcidas_private *devpriv = dev->private;
1707        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1708
1709        if (devpriv) {
1710                if (devpriv->s5933_config) {
1711                        outl(INTCSR_INBOX_INTR_STATUS,
1712                             devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1713                }
1714        }
1715        if (dev->irq)
1716                free_irq(dev->irq, dev);
1717        if (dev->subdevices)
1718                subdev_8255_cleanup(dev, dev->subdevices + 2);
1719        if (pcidev) {
1720                if (devpriv->s5933_config)
1721                        comedi_pci_disable(pcidev);
1722                pci_dev_put(pcidev);
1723        }
1724}
1725
1726static struct comedi_driver cb_pcidas_driver = {
1727        .driver_name    = "cb_pcidas",
1728        .module         = THIS_MODULE,
1729        .attach         = cb_pcidas_attach,
1730        .detach         = cb_pcidas_detach,
1731};
1732
1733static int __devinit cb_pcidas_pci_probe(struct pci_dev *dev,
1734                                         const struct pci_device_id *ent)
1735{
1736        return comedi_pci_auto_config(dev, &cb_pcidas_driver);
1737}
1738
1739static void __devexit cb_pcidas_pci_remove(struct pci_dev *dev)
1740{
1741        comedi_pci_auto_unconfig(dev);
1742}
1743
1744static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
1745        { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) },
1746        { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) },
1747        { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) },
1748        { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) },
1749        { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) },
1750        { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) },
1751        { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) },
1752        { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) },
1753        { 0 }
1754};
1755MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
1756
1757static struct pci_driver cb_pcidas_pci_driver = {
1758        .name           = "cb_pcidas",
1759        .id_table       = cb_pcidas_pci_table,
1760        .probe          = cb_pcidas_pci_probe,
1761        .remove         = __devexit_p(cb_pcidas_pci_remove)
1762};
1763module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
1764
1765MODULE_AUTHOR("Comedi http://www.comedi.org");
1766MODULE_DESCRIPTION("Comedi low-level driver");
1767MODULE_LICENSE("GPL");
1768