root/drivers/staging/comedi/drivers/das800.c

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

DEFINITIONS

This source file includes following definitions.
  1. das800_ind_write
  2. das800_ind_read
  3. das800_enable
  4. das800_disable
  5. das800_cancel
  6. das800_ai_check_chanlist
  7. das800_ai_do_cmdtest
  8. das800_ai_do_cmd
  9. das800_ai_get_sample
  10. das800_interrupt
  11. das800_ai_eoc
  12. das800_ai_insn_read
  13. das800_di_insn_bits
  14. das800_do_insn_bits
  15. das800_probe
  16. das800_attach

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * comedi/drivers/das800.c
   4  * Driver for Keitley das800 series boards and compatibles
   5  * Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
   6  *
   7  * COMEDI - Linux Control and Measurement Device Interface
   8  * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   9  */
  10 /*
  11  * Driver: das800
  12  * Description: Keithley Metrabyte DAS800 (& compatibles)
  13  * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
  14  * Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801),
  15  * DAS-802 (das-802),
  16  * [Measurement Computing] CIO-DAS800 (cio-das800),
  17  * CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802),
  18  * CIO-DAS802/16 (cio-das802/16)
  19  * Status: works, cio-das802/16 untested - email me if you have tested it
  20  *
  21  * Configuration options:
  22  * [0] - I/O port base address
  23  * [1] - IRQ (optional, required for timed or externally triggered conversions)
  24  *
  25  * Notes:
  26  *      IRQ can be omitted, although the cmd interface will not work without it.
  27  *
  28  *      All entries in the channel/gain list must use the same gain and be
  29  *      consecutive channels counting upwards in channel number (these are
  30  *      hardware limitations.)
  31  *
  32  *      I've never tested the gain setting stuff since I only have a
  33  *      DAS-800 board with fixed gain.
  34  *
  35  *      The cio-das802/16 does not have a fifo-empty status bit!  Therefore
  36  *      only fifo-half-full transfers are possible with this card.
  37  *
  38  * cmd triggers supported:
  39  *      start_src:      TRIG_NOW | TRIG_EXT
  40  *      scan_begin_src: TRIG_FOLLOW
  41  *      scan_end_src:   TRIG_COUNT
  42  *      convert_src:    TRIG_TIMER | TRIG_EXT
  43  *      stop_src:       TRIG_NONE | TRIG_COUNT
  44  */
  45 
  46 #include <linux/module.h>
  47 #include <linux/interrupt.h>
  48 #include <linux/delay.h>
  49 
  50 #include "../comedidev.h"
  51 
  52 #include "comedi_8254.h"
  53 
  54 #define N_CHAN_AI             8 /*  number of analog input channels */
  55 
  56 /* Registers for the das800 */
  57 
  58 #define DAS800_LSB            0
  59 #define   FIFO_EMPTY            0x1
  60 #define   FIFO_OVF              0x2
  61 #define DAS800_MSB            1
  62 #define DAS800_CONTROL1       2
  63 #define   CONTROL1_INTE         0x8
  64 #define DAS800_CONV_CONTROL   2
  65 #define   ITE                   0x1
  66 #define   CASC                  0x2
  67 #define   DTEN                  0x4
  68 #define   IEOC                  0x8
  69 #define   EACS                  0x10
  70 #define   CONV_HCEN             0x80
  71 #define DAS800_SCAN_LIMITS    2
  72 #define DAS800_STATUS         2
  73 #define   IRQ                   0x8
  74 #define   BUSY                  0x80
  75 #define DAS800_GAIN           3
  76 #define   CIO_FFOV              0x8   /* cio-das802/16 fifo overflow */
  77 #define   CIO_ENHF              0x90  /* cio-das802/16 fifo half full int ena */
  78 #define   CONTROL1              0x80
  79 #define   CONV_CONTROL          0xa0
  80 #define   SCAN_LIMITS           0xc0
  81 #define   ID                    0xe0
  82 #define DAS800_8254           4
  83 #define DAS800_STATUS2        7
  84 #define   STATUS2_HCEN          0x80
  85 #define   STATUS2_INTE          0X20
  86 #define DAS800_ID             7
  87 
  88 #define DAS802_16_HALF_FIFO_SZ  128
  89 
  90 struct das800_board {
  91         const char *name;
  92         int ai_speed;
  93         const struct comedi_lrange *ai_range;
  94         int resolution;
  95 };
  96 
  97 static const struct comedi_lrange range_das801_ai = {
  98         9, {
  99                 BIP_RANGE(5),
 100                 BIP_RANGE(10),
 101                 UNI_RANGE(10),
 102                 BIP_RANGE(0.5),
 103                 UNI_RANGE(1),
 104                 BIP_RANGE(0.05),
 105                 UNI_RANGE(0.1),
 106                 BIP_RANGE(0.01),
 107                 UNI_RANGE(0.02)
 108         }
 109 };
 110 
 111 static const struct comedi_lrange range_cio_das801_ai = {
 112         9, {
 113                 BIP_RANGE(5),
 114                 BIP_RANGE(10),
 115                 UNI_RANGE(10),
 116                 BIP_RANGE(0.5),
 117                 UNI_RANGE(1),
 118                 BIP_RANGE(0.05),
 119                 UNI_RANGE(0.1),
 120                 BIP_RANGE(0.005),
 121                 UNI_RANGE(0.01)
 122         }
 123 };
 124 
 125 static const struct comedi_lrange range_das802_ai = {
 126         9, {
 127                 BIP_RANGE(5),
 128                 BIP_RANGE(10),
 129                 UNI_RANGE(10),
 130                 BIP_RANGE(2.5),
 131                 UNI_RANGE(5),
 132                 BIP_RANGE(1.25),
 133                 UNI_RANGE(2.5),
 134                 BIP_RANGE(0.625),
 135                 UNI_RANGE(1.25)
 136         }
 137 };
 138 
 139 static const struct comedi_lrange range_das80216_ai = {
 140         8, {
 141                 BIP_RANGE(10),
 142                 UNI_RANGE(10),
 143                 BIP_RANGE(5),
 144                 UNI_RANGE(5),
 145                 BIP_RANGE(2.5),
 146                 UNI_RANGE(2.5),
 147                 BIP_RANGE(1.25),
 148                 UNI_RANGE(1.25)
 149         }
 150 };
 151 
 152 enum das800_boardinfo {
 153         BOARD_DAS800,
 154         BOARD_CIODAS800,
 155         BOARD_DAS801,
 156         BOARD_CIODAS801,
 157         BOARD_DAS802,
 158         BOARD_CIODAS802,
 159         BOARD_CIODAS80216,
 160 };
 161 
 162 static const struct das800_board das800_boards[] = {
 163         [BOARD_DAS800] = {
 164                 .name           = "das-800",
 165                 .ai_speed       = 25000,
 166                 .ai_range       = &range_bipolar5,
 167                 .resolution     = 12,
 168         },
 169         [BOARD_CIODAS800] = {
 170                 .name           = "cio-das800",
 171                 .ai_speed       = 20000,
 172                 .ai_range       = &range_bipolar5,
 173                 .resolution     = 12,
 174         },
 175         [BOARD_DAS801] = {
 176                 .name           = "das-801",
 177                 .ai_speed       = 25000,
 178                 .ai_range       = &range_das801_ai,
 179                 .resolution     = 12,
 180         },
 181         [BOARD_CIODAS801] = {
 182                 .name           = "cio-das801",
 183                 .ai_speed       = 20000,
 184                 .ai_range       = &range_cio_das801_ai,
 185                 .resolution     = 12,
 186         },
 187         [BOARD_DAS802] = {
 188                 .name           = "das-802",
 189                 .ai_speed       = 25000,
 190                 .ai_range       = &range_das802_ai,
 191                 .resolution     = 12,
 192         },
 193         [BOARD_CIODAS802] = {
 194                 .name           = "cio-das802",
 195                 .ai_speed       = 20000,
 196                 .ai_range       = &range_das802_ai,
 197                 .resolution     = 12,
 198         },
 199         [BOARD_CIODAS80216] = {
 200                 .name           = "cio-das802/16",
 201                 .ai_speed       = 10000,
 202                 .ai_range       = &range_das80216_ai,
 203                 .resolution     = 16,
 204         },
 205 };
 206 
 207 struct das800_private {
 208         unsigned int do_bits;   /* digital output bits */
 209 };
 210 
 211 static void das800_ind_write(struct comedi_device *dev,
 212                              unsigned int val, unsigned int reg)
 213 {
 214         /*
 215          * Select dev->iobase + 2 to be desired register
 216          * then write to that register.
 217          */
 218         outb(reg, dev->iobase + DAS800_GAIN);
 219         outb(val, dev->iobase + 2);
 220 }
 221 
 222 static unsigned int das800_ind_read(struct comedi_device *dev, unsigned int reg)
 223 {
 224         /*
 225          * Select dev->iobase + 7 to be desired register
 226          * then read from that register.
 227          */
 228         outb(reg, dev->iobase + DAS800_GAIN);
 229         return inb(dev->iobase + 7);
 230 }
 231 
 232 static void das800_enable(struct comedi_device *dev)
 233 {
 234         const struct das800_board *board = dev->board_ptr;
 235         struct das800_private *devpriv = dev->private;
 236         unsigned long irq_flags;
 237 
 238         spin_lock_irqsave(&dev->spinlock, irq_flags);
 239         /*  enable fifo-half full interrupts for cio-das802/16 */
 240         if (board->resolution == 16)
 241                 outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
 242         /* enable hardware triggering */
 243         das800_ind_write(dev, CONV_HCEN, CONV_CONTROL);
 244         /* enable card's interrupt */
 245         das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
 246         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 247 }
 248 
 249 static void das800_disable(struct comedi_device *dev)
 250 {
 251         unsigned long irq_flags;
 252 
 253         spin_lock_irqsave(&dev->spinlock, irq_flags);
 254         /* disable hardware triggering of conversions */
 255         das800_ind_write(dev, 0x0, CONV_CONTROL);
 256         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 257 }
 258 
 259 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 260 {
 261         das800_disable(dev);
 262         return 0;
 263 }
 264 
 265 static int das800_ai_check_chanlist(struct comedi_device *dev,
 266                                     struct comedi_subdevice *s,
 267                                     struct comedi_cmd *cmd)
 268 {
 269         unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
 270         unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
 271         int i;
 272 
 273         for (i = 1; i < cmd->chanlist_len; i++) {
 274                 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
 275                 unsigned int range = CR_RANGE(cmd->chanlist[i]);
 276 
 277                 if (chan != (chan0 + i) % s->n_chan) {
 278                         dev_dbg(dev->class_dev,
 279                                 "chanlist must be consecutive, counting upwards\n");
 280                         return -EINVAL;
 281                 }
 282 
 283                 if (range != range0) {
 284                         dev_dbg(dev->class_dev,
 285                                 "chanlist must all have the same gain\n");
 286                         return -EINVAL;
 287                 }
 288         }
 289 
 290         return 0;
 291 }
 292 
 293 static int das800_ai_do_cmdtest(struct comedi_device *dev,
 294                                 struct comedi_subdevice *s,
 295                                 struct comedi_cmd *cmd)
 296 {
 297         const struct das800_board *board = dev->board_ptr;
 298         int err = 0;
 299 
 300         /* Step 1 : check if triggers are trivially valid */
 301 
 302         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
 303         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
 304         err |= comedi_check_trigger_src(&cmd->convert_src,
 305                                         TRIG_TIMER | TRIG_EXT);
 306         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 307         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 308 
 309         if (err)
 310                 return 1;
 311 
 312         /* Step 2a : make sure trigger sources are unique */
 313 
 314         err |= comedi_check_trigger_is_unique(cmd->start_src);
 315         err |= comedi_check_trigger_is_unique(cmd->convert_src);
 316         err |= comedi_check_trigger_is_unique(cmd->stop_src);
 317 
 318         /* Step 2b : and mutually compatible */
 319 
 320         if (err)
 321                 return 2;
 322 
 323         /* Step 3: check if arguments are trivially valid */
 324 
 325         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 326 
 327         if (cmd->convert_src == TRIG_TIMER) {
 328                 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
 329                                                     board->ai_speed);
 330         }
 331 
 332         err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1);
 333         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 334                                            cmd->chanlist_len);
 335 
 336         if (cmd->stop_src == TRIG_COUNT)
 337                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
 338         else    /* TRIG_NONE */
 339                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 340 
 341         if (err)
 342                 return 3;
 343 
 344         /* step 4: fix up any arguments */
 345 
 346         if (cmd->convert_src == TRIG_TIMER) {
 347                 unsigned int arg = cmd->convert_arg;
 348 
 349                 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
 350                 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
 351         }
 352 
 353         if (err)
 354                 return 4;
 355 
 356         /* Step 5: check channel list if it exists */
 357         if (cmd->chanlist && cmd->chanlist_len > 0)
 358                 err |= das800_ai_check_chanlist(dev, s, cmd);
 359 
 360         if (err)
 361                 return 5;
 362 
 363         return 0;
 364 }
 365 
 366 static int das800_ai_do_cmd(struct comedi_device *dev,
 367                             struct comedi_subdevice *s)
 368 {
 369         const struct das800_board *board = dev->board_ptr;
 370         struct comedi_async *async = s->async;
 371         struct comedi_cmd *cmd = &async->cmd;
 372         unsigned int gain = CR_RANGE(cmd->chanlist[0]);
 373         unsigned int start_chan = CR_CHAN(cmd->chanlist[0]);
 374         unsigned int end_chan = (start_chan + cmd->chanlist_len - 1) % 8;
 375         unsigned int scan_chans = (end_chan << 3) | start_chan;
 376         int conv_bits;
 377         unsigned long irq_flags;
 378 
 379         das800_disable(dev);
 380 
 381         spin_lock_irqsave(&dev->spinlock, irq_flags);
 382         /* set scan limits */
 383         das800_ind_write(dev, scan_chans, SCAN_LIMITS);
 384         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 385 
 386         /* set gain */
 387         if (board->resolution == 12 && gain > 0)
 388                 gain += 0x7;
 389         gain &= 0xf;
 390         outb(gain, dev->iobase + DAS800_GAIN);
 391 
 392         /* enable auto channel scan, send interrupts on end of conversion
 393          * and set clock source to internal or external
 394          */
 395         conv_bits = 0;
 396         conv_bits |= EACS | IEOC;
 397         if (cmd->start_src == TRIG_EXT)
 398                 conv_bits |= DTEN;
 399         if (cmd->convert_src == TRIG_TIMER) {
 400                 conv_bits |= CASC | ITE;
 401                 comedi_8254_update_divisors(dev->pacer);
 402                 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
 403         }
 404 
 405         spin_lock_irqsave(&dev->spinlock, irq_flags);
 406         das800_ind_write(dev, conv_bits, CONV_CONTROL);
 407         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 408 
 409         das800_enable(dev);
 410         return 0;
 411 }
 412 
 413 static unsigned int das800_ai_get_sample(struct comedi_device *dev)
 414 {
 415         unsigned int lsb = inb(dev->iobase + DAS800_LSB);
 416         unsigned int msb = inb(dev->iobase + DAS800_MSB);
 417 
 418         return (msb << 8) | lsb;
 419 }
 420 
 421 static irqreturn_t das800_interrupt(int irq, void *d)
 422 {
 423         struct comedi_device *dev = d;
 424         struct das800_private *devpriv = dev->private;
 425         struct comedi_subdevice *s = dev->read_subdev;
 426         struct comedi_async *async;
 427         struct comedi_cmd *cmd;
 428         unsigned long irq_flags;
 429         unsigned int status;
 430         unsigned int val;
 431         bool fifo_empty;
 432         bool fifo_overflow;
 433         int i;
 434 
 435         status = inb(dev->iobase + DAS800_STATUS);
 436         if (!(status & IRQ))
 437                 return IRQ_NONE;
 438         if (!dev->attached)
 439                 return IRQ_HANDLED;
 440 
 441         async = s->async;
 442         cmd = &async->cmd;
 443 
 444         spin_lock_irqsave(&dev->spinlock, irq_flags);
 445         status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN;
 446         /*
 447          * Don't release spinlock yet since we want to make sure
 448          * no one else disables hardware conversions.
 449          */
 450 
 451         /* if hardware conversions are not enabled, then quit */
 452         if (status == 0) {
 453                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 454                 return IRQ_HANDLED;
 455         }
 456 
 457         for (i = 0; i < DAS802_16_HALF_FIFO_SZ; i++) {
 458                 val = das800_ai_get_sample(dev);
 459                 if (s->maxdata == 0x0fff) {
 460                         fifo_empty = !!(val & FIFO_EMPTY);
 461                         fifo_overflow = !!(val & FIFO_OVF);
 462                 } else {
 463                         /* cio-das802/16 has no fifo empty status bit */
 464                         fifo_empty = false;
 465                         fifo_overflow = !!(inb(dev->iobase + DAS800_GAIN) &
 466                                                 CIO_FFOV);
 467                 }
 468                 if (fifo_empty || fifo_overflow)
 469                         break;
 470 
 471                 if (s->maxdata == 0x0fff)
 472                         val >>= 4;      /* 12-bit sample */
 473 
 474                 val &= s->maxdata;
 475                 comedi_buf_write_samples(s, &val, 1);
 476 
 477                 if (cmd->stop_src == TRIG_COUNT &&
 478                     async->scans_done >= cmd->stop_arg) {
 479                         async->events |= COMEDI_CB_EOA;
 480                         break;
 481                 }
 482         }
 483 
 484         if (fifo_overflow) {
 485                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 486                 async->events |= COMEDI_CB_ERROR;
 487                 comedi_handle_events(dev, s);
 488                 return IRQ_HANDLED;
 489         }
 490 
 491         if (!(async->events & COMEDI_CB_CANCEL_MASK)) {
 492                 /*
 493                  * Re-enable card's interrupt.
 494                  * We already have spinlock, so indirect addressing is safe
 495                  */
 496                 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
 497                                  CONTROL1);
 498                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 499         } else {
 500                 /* otherwise, stop taking data */
 501                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 502                 das800_disable(dev);
 503         }
 504         comedi_handle_events(dev, s);
 505         return IRQ_HANDLED;
 506 }
 507 
 508 static int das800_ai_eoc(struct comedi_device *dev,
 509                          struct comedi_subdevice *s,
 510                          struct comedi_insn *insn,
 511                          unsigned long context)
 512 {
 513         unsigned int status;
 514 
 515         status = inb(dev->iobase + DAS800_STATUS);
 516         if ((status & BUSY) == 0)
 517                 return 0;
 518         return -EBUSY;
 519 }
 520 
 521 static int das800_ai_insn_read(struct comedi_device *dev,
 522                                struct comedi_subdevice *s,
 523                                struct comedi_insn *insn,
 524                                unsigned int *data)
 525 {
 526         struct das800_private *devpriv = dev->private;
 527         unsigned int chan = CR_CHAN(insn->chanspec);
 528         unsigned int range = CR_RANGE(insn->chanspec);
 529         unsigned long irq_flags;
 530         unsigned int val;
 531         int ret;
 532         int i;
 533 
 534         das800_disable(dev);
 535 
 536         /* set multiplexer */
 537         spin_lock_irqsave(&dev->spinlock, irq_flags);
 538         das800_ind_write(dev, chan | devpriv->do_bits, CONTROL1);
 539         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 540 
 541         /* set gain / range */
 542         if (s->maxdata == 0x0fff && range)
 543                 range += 0x7;
 544         range &= 0xf;
 545         outb(range, dev->iobase + DAS800_GAIN);
 546 
 547         udelay(5);
 548 
 549         for (i = 0; i < insn->n; i++) {
 550                 /* trigger conversion */
 551                 outb_p(0, dev->iobase + DAS800_MSB);
 552 
 553                 ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0);
 554                 if (ret)
 555                         return ret;
 556 
 557                 val = das800_ai_get_sample(dev);
 558                 if (s->maxdata == 0x0fff)
 559                         val >>= 4;      /* 12-bit sample */
 560                 data[i] = val & s->maxdata;
 561         }
 562 
 563         return insn->n;
 564 }
 565 
 566 static int das800_di_insn_bits(struct comedi_device *dev,
 567                                struct comedi_subdevice *s,
 568                                struct comedi_insn *insn,
 569                                unsigned int *data)
 570 {
 571         data[1] = (inb(dev->iobase + DAS800_STATUS) >> 4) & 0x7;
 572 
 573         return insn->n;
 574 }
 575 
 576 static int das800_do_insn_bits(struct comedi_device *dev,
 577                                struct comedi_subdevice *s,
 578                                struct comedi_insn *insn,
 579                                unsigned int *data)
 580 {
 581         struct das800_private *devpriv = dev->private;
 582         unsigned long irq_flags;
 583 
 584         if (comedi_dio_update_state(s, data)) {
 585                 devpriv->do_bits = s->state << 4;
 586 
 587                 spin_lock_irqsave(&dev->spinlock, irq_flags);
 588                 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
 589                                  CONTROL1);
 590                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 591         }
 592 
 593         data[1] = s->state;
 594 
 595         return insn->n;
 596 }
 597 
 598 static const struct das800_board *das800_probe(struct comedi_device *dev)
 599 {
 600         const struct das800_board *board = dev->board_ptr;
 601         int index = board ? board - das800_boards : -EINVAL;
 602         int id_bits;
 603         unsigned long irq_flags;
 604 
 605         /*
 606          * The dev->board_ptr will be set by comedi_device_attach() if the
 607          * board name provided by the user matches a board->name in this
 608          * driver. If so, this function sanity checks the id_bits to verify
 609          * that the board is correct.
 610          *
 611          * If the dev->board_ptr is not set, the user is trying to attach
 612          * an unspecified board to this driver. In this case the id_bits
 613          * are used to 'probe' for the correct dev->board_ptr.
 614          */
 615         spin_lock_irqsave(&dev->spinlock, irq_flags);
 616         id_bits = das800_ind_read(dev, ID) & 0x3;
 617         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 618 
 619         switch (id_bits) {
 620         case 0x0:
 621                 if (index == BOARD_DAS800 || index == BOARD_CIODAS800)
 622                         return board;
 623                 index = BOARD_DAS800;
 624                 break;
 625         case 0x2:
 626                 if (index == BOARD_DAS801 || index == BOARD_CIODAS801)
 627                         return board;
 628                 index = BOARD_DAS801;
 629                 break;
 630         case 0x3:
 631                 if (index == BOARD_DAS802 || index == BOARD_CIODAS802 ||
 632                     index == BOARD_CIODAS80216)
 633                         return board;
 634                 index = BOARD_DAS802;
 635                 break;
 636         default:
 637                 dev_dbg(dev->class_dev, "Board model: 0x%x (unknown)\n",
 638                         id_bits);
 639                 return NULL;
 640         }
 641         dev_dbg(dev->class_dev, "Board model (probed): %s series\n",
 642                 das800_boards[index].name);
 643 
 644         return &das800_boards[index];
 645 }
 646 
 647 static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 648 {
 649         const struct das800_board *board;
 650         struct das800_private *devpriv;
 651         struct comedi_subdevice *s;
 652         unsigned int irq = it->options[1];
 653         unsigned long irq_flags;
 654         int ret;
 655 
 656         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 657         if (!devpriv)
 658                 return -ENOMEM;
 659 
 660         ret = comedi_request_region(dev, it->options[0], 0x8);
 661         if (ret)
 662                 return ret;
 663 
 664         board = das800_probe(dev);
 665         if (!board)
 666                 return -ENODEV;
 667         dev->board_ptr = board;
 668         dev->board_name = board->name;
 669 
 670         if (irq > 1 && irq <= 7) {
 671                 ret = request_irq(irq, das800_interrupt, 0, dev->board_name,
 672                                   dev);
 673                 if (ret == 0)
 674                         dev->irq = irq;
 675         }
 676 
 677         dev->pacer = comedi_8254_init(dev->iobase + DAS800_8254,
 678                                       I8254_OSC_BASE_1MHZ, I8254_IO8, 0);
 679         if (!dev->pacer)
 680                 return -ENOMEM;
 681 
 682         ret = comedi_alloc_subdevices(dev, 3);
 683         if (ret)
 684                 return ret;
 685 
 686         /* Analog Input subdevice */
 687         s = &dev->subdevices[0];
 688         dev->read_subdev = s;
 689         s->type         = COMEDI_SUBD_AI;
 690         s->subdev_flags = SDF_READABLE | SDF_GROUND;
 691         s->n_chan       = 8;
 692         s->maxdata      = (1 << board->resolution) - 1;
 693         s->range_table  = board->ai_range;
 694         s->insn_read    = das800_ai_insn_read;
 695         if (dev->irq) {
 696                 s->subdev_flags |= SDF_CMD_READ;
 697                 s->len_chanlist = 8;
 698                 s->do_cmdtest   = das800_ai_do_cmdtest;
 699                 s->do_cmd       = das800_ai_do_cmd;
 700                 s->cancel       = das800_cancel;
 701         }
 702 
 703         /* Digital Input subdevice */
 704         s = &dev->subdevices[1];
 705         s->type         = COMEDI_SUBD_DI;
 706         s->subdev_flags = SDF_READABLE;
 707         s->n_chan       = 3;
 708         s->maxdata      = 1;
 709         s->range_table  = &range_digital;
 710         s->insn_bits    = das800_di_insn_bits;
 711 
 712         /* Digital Output subdevice */
 713         s = &dev->subdevices[2];
 714         s->type         = COMEDI_SUBD_DO;
 715         s->subdev_flags = SDF_WRITABLE;
 716         s->n_chan       = 4;
 717         s->maxdata      = 1;
 718         s->range_table  = &range_digital;
 719         s->insn_bits    = das800_do_insn_bits;
 720 
 721         das800_disable(dev);
 722 
 723         /* initialize digital out channels */
 724         spin_lock_irqsave(&dev->spinlock, irq_flags);
 725         das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
 726         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 727 
 728         return 0;
 729 };
 730 
 731 static struct comedi_driver driver_das800 = {
 732         .driver_name    = "das800",
 733         .module         = THIS_MODULE,
 734         .attach         = das800_attach,
 735         .detach         = comedi_legacy_detach,
 736         .num_names      = ARRAY_SIZE(das800_boards),
 737         .board_name     = &das800_boards[0].name,
 738         .offset         = sizeof(struct das800_board),
 739 };
 740 module_comedi_driver(driver_das800);
 741 
 742 MODULE_AUTHOR("Comedi http://www.comedi.org");
 743 MODULE_DESCRIPTION("Comedi low-level driver");
 744 MODULE_LICENSE("GPL");

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