das800.c revision 25436dc9d84f1be60ff549c9ab712bba2835f284
1/* 2 comedi/drivers/das800.c 3 Driver for Keitley das800 series boards and compatibles 4 Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> 5 6 COMEDI - Linux Control and Measurement Device Interface 7 Copyright (C) 2000 David A. Schleef <ds@schleef.org> 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 23************************************************************************ 24*/ 25/* 26Driver: das800 27Description: Keithley Metrabyte DAS800 (& compatibles) 28Author: Frank Mori Hess <fmhess@users.sourceforge.net> 29Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801), 30 DAS-802 (das-802), 31 [Measurement Computing] CIO-DAS800 (cio-das800), 32 CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802), 33 CIO-DAS802/16 (cio-das802/16) 34Status: works, cio-das802/16 untested - email me if you have tested it 35 36Configuration options: 37 [0] - I/O port base address 38 [1] - IRQ (optional, required for timed or externally triggered conversions) 39 40Notes: 41 IRQ can be omitted, although the cmd interface will not work without it. 42 43 All entries in the channel/gain list must use the same gain and be 44 consecutive channels counting upwards in channel number (these are 45 hardware limitations.) 46 47 I've never tested the gain setting stuff since I only have a 48 DAS-800 board with fixed gain. 49 50 The cio-das802/16 does not have a fifo-empty status bit! Therefore 51 only fifo-half-full transfers are possible with this card. 52*/ 53/* 54 55cmd triggers supported: 56 start_src: TRIG_NOW | TRIG_EXT 57 scan_begin_src: TRIG_FOLLOW 58 scan_end_src: TRIG_COUNT 59 convert_src: TRIG_TIMER | TRIG_EXT 60 stop_src: TRIG_NONE | TRIG_COUNT 61 62 63*/ 64 65#include <linux/interrupt.h> 66#include "../comedidev.h" 67 68#include <linux/ioport.h> 69#include <linux/delay.h> 70 71#include "8253.h" 72#include "comedi_fc.h" 73 74#define DAS800_SIZE 8 75#define TIMER_BASE 1000 76#define N_CHAN_AI 8 /* number of analog input channels */ 77 78/* Registers for the das800 */ 79 80#define DAS800_LSB 0 81#define FIFO_EMPTY 0x1 82#define FIFO_OVF 0x2 83#define DAS800_MSB 1 84#define DAS800_CONTROL1 2 85#define CONTROL1_INTE 0x8 86#define DAS800_CONV_CONTROL 2 87#define ITE 0x1 88#define CASC 0x2 89#define DTEN 0x4 90#define IEOC 0x8 91#define EACS 0x10 92#define CONV_HCEN 0x80 93#define DAS800_SCAN_LIMITS 2 94#define DAS800_STATUS 2 95#define IRQ 0x8 96#define BUSY 0x80 97#define DAS800_GAIN 3 98#define CIO_FFOV 0x8 /* fifo overflow for cio-das802/16 */ 99#define CIO_ENHF 0x90 /* interrupt fifo half full for cio-das802/16 */ 100#define CONTROL1 0x80 101#define CONV_CONTROL 0xa0 102#define SCAN_LIMITS 0xc0 103#define ID 0xe0 104#define DAS800_8254 4 105#define DAS800_STATUS2 7 106#define STATUS2_HCEN 0x80 107#define STATUS2_INTE 0X20 108#define DAS800_ID 7 109 110struct das800_board { 111 const char *name; 112 int ai_speed; 113 const struct comedi_lrange *ai_range; 114 int resolution; 115}; 116 117/* analog input ranges */ 118static const struct comedi_lrange range_das800_ai = { 119 1, 120 { 121 RANGE(-5, 5), 122 } 123}; 124 125static const struct comedi_lrange range_das801_ai = { 126 9, 127 { 128 RANGE(-5, 5), 129 RANGE(-10, 10), 130 RANGE(0, 10), 131 RANGE(-0.5, 0.5), 132 RANGE(0, 1), 133 RANGE(-0.05, 0.05), 134 RANGE(0, 0.1), 135 RANGE(-0.01, 0.01), 136 RANGE(0, 0.02), 137 } 138}; 139 140static const struct comedi_lrange range_cio_das801_ai = { 141 9, 142 { 143 RANGE(-5, 5), 144 RANGE(-10, 10), 145 RANGE(0, 10), 146 RANGE(-0.5, 0.5), 147 RANGE(0, 1), 148 RANGE(-0.05, 0.05), 149 RANGE(0, 0.1), 150 RANGE(-0.005, 0.005), 151 RANGE(0, 0.01), 152 } 153}; 154 155static const struct comedi_lrange range_das802_ai = { 156 9, 157 { 158 RANGE(-5, 5), 159 RANGE(-10, 10), 160 RANGE(0, 10), 161 RANGE(-2.5, 2.5), 162 RANGE(0, 5), 163 RANGE(-1.25, 1.25), 164 RANGE(0, 2.5), 165 RANGE(-0.625, 0.625), 166 RANGE(0, 1.25), 167 } 168}; 169 170static const struct comedi_lrange range_das80216_ai = { 171 8, 172 { 173 RANGE(-10, 10), 174 RANGE(0, 10), 175 RANGE(-5, 5), 176 RANGE(0, 5), 177 RANGE(-2.5, 2.5), 178 RANGE(0, 2.5), 179 RANGE(-1.25, 1.25), 180 RANGE(0, 1.25), 181 } 182}; 183 184enum { das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 }; 185 186static const struct das800_board das800_boards[] = { 187 { 188 .name = "das-800", 189 .ai_speed = 25000, 190 .ai_range = &range_das800_ai, 191 .resolution = 12, 192 }, 193 { 194 .name = "cio-das800", 195 .ai_speed = 20000, 196 .ai_range = &range_das800_ai, 197 .resolution = 12, 198 }, 199 { 200 .name = "das-801", 201 .ai_speed = 25000, 202 .ai_range = &range_das801_ai, 203 .resolution = 12, 204 }, 205 { 206 .name = "cio-das801", 207 .ai_speed = 20000, 208 .ai_range = &range_cio_das801_ai, 209 .resolution = 12, 210 }, 211 { 212 .name = "das-802", 213 .ai_speed = 25000, 214 .ai_range = &range_das802_ai, 215 .resolution = 12, 216 }, 217 { 218 .name = "cio-das802", 219 .ai_speed = 20000, 220 .ai_range = &range_das802_ai, 221 .resolution = 12, 222 }, 223 { 224 .name = "cio-das802/16", 225 .ai_speed = 10000, 226 .ai_range = &range_das80216_ai, 227 .resolution = 16, 228 }, 229}; 230 231/* 232 * Useful for shorthand access to the particular board structure 233 */ 234#define thisboard ((const struct das800_board *)dev->board_ptr) 235 236struct das800_private { 237 volatile unsigned int count; /* number of data points left to be taken */ 238 volatile int forever; /* flag indicating whether we should take data forever */ 239 unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */ 240 unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */ 241 volatile int do_bits; /* digital output bits */ 242}; 243 244#define devpriv ((struct das800_private *)dev->private) 245 246static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it); 247static int das800_detach(struct comedi_device *dev); 248static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s); 249 250static struct comedi_driver driver_das800 = { 251 .driver_name = "das800", 252 .module = THIS_MODULE, 253 .attach = das800_attach, 254 .detach = das800_detach, 255 .num_names = ARRAY_SIZE(das800_boards), 256 .board_name = &das800_boards[0].name, 257 .offset = sizeof(struct das800_board), 258}; 259 260static irqreturn_t das800_interrupt(int irq, void *d); 261static void enable_das800(struct comedi_device *dev); 262static void disable_das800(struct comedi_device *dev); 263static int das800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, 264 struct comedi_cmd *cmd); 265static int das800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s); 266static int das800_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 267 struct comedi_insn *insn, unsigned int *data); 268static int das800_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, 269 struct comedi_insn *insn, unsigned int *data); 270static int das800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, 271 struct comedi_insn *insn, unsigned int *data); 272static int das800_probe(struct comedi_device *dev); 273static int das800_set_frequency(struct comedi_device *dev); 274 275/* checks and probes das-800 series board type */ 276static int das800_probe(struct comedi_device *dev) 277{ 278 int id_bits; 279 unsigned long irq_flags; 280 int board; 281 282 /* 'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */ 283 spin_lock_irqsave(&dev->spinlock, irq_flags); 284 outb(ID, dev->iobase + DAS800_GAIN); /* select base address + 7 to be ID register */ 285 id_bits = inb(dev->iobase + DAS800_ID) & 0x3; /* get id bits */ 286 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 287 288 board = thisboard - das800_boards; 289 290 switch (id_bits) { 291 case 0x0: 292 if (board == das800) { 293 printk(" Board model: DAS-800\n"); 294 return board; 295 } 296 if (board == ciodas800) { 297 printk(" Board model: CIO-DAS800\n"); 298 return board; 299 } 300 printk(" Board model (probed): DAS-800\n"); 301 return das800; 302 break; 303 case 0x2: 304 if (board == das801) { 305 printk(" Board model: DAS-801\n"); 306 return board; 307 } 308 if (board == ciodas801) { 309 printk(" Board model: CIO-DAS801\n"); 310 return board; 311 } 312 printk(" Board model (probed): DAS-801\n"); 313 return das801; 314 break; 315 case 0x3: 316 if (board == das802) { 317 printk(" Board model: DAS-802\n"); 318 return board; 319 } 320 if (board == ciodas802) { 321 printk(" Board model: CIO-DAS802\n"); 322 return board; 323 } 324 if (board == ciodas80216) { 325 printk(" Board model: CIO-DAS802/16\n"); 326 return board; 327 } 328 printk(" Board model (probed): DAS-802\n"); 329 return das802; 330 break; 331 default: 332 printk(" Board model: probe returned 0x%x (unknown)\n", 333 id_bits); 334 return board; 335 break; 336 } 337 return -1; 338} 339 340/* 341 * A convenient macro that defines init_module() and cleanup_module(), 342 * as necessary. 343 */ 344COMEDI_INITCLEANUP(driver_das800); 345 346/* interrupt service routine */ 347static irqreturn_t das800_interrupt(int irq, void *d) 348{ 349 short i; /* loop index */ 350 short dataPoint = 0; 351 struct comedi_device *dev = d; 352 struct comedi_subdevice *s = dev->read_subdev; /* analog input subdevice */ 353 struct comedi_async *async; 354 int status; 355 unsigned long irq_flags; 356 static const int max_loops = 128; /* half-fifo size for cio-das802/16 */ 357 /* flags */ 358 int fifo_empty = 0; 359 int fifo_overflow = 0; 360 361 status = inb(dev->iobase + DAS800_STATUS); 362 /* if interrupt was not generated by board or driver not attached, quit */ 363 if (!(status & IRQ)) 364 return IRQ_NONE; 365 if (!(dev->attached)) 366 return IRQ_HANDLED; 367 368 /* wait until here to initialize async, since we will get null dereference 369 * if interrupt occurs before driver is fully attached! 370 */ 371 async = s->async; 372 373 /* if hardware conversions are not enabled, then quit */ 374 spin_lock_irqsave(&dev->spinlock, irq_flags); 375 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */ 376 status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN; 377 /* don't release spinlock yet since we want to make sure noone else disables hardware conversions */ 378 if (status == 0) { 379 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 380 return IRQ_HANDLED; 381 } 382 383 /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */ 384 for (i = 0; i < max_loops; i++) { 385 /* read 16 bits from dev->iobase and dev->iobase + 1 */ 386 dataPoint = inb(dev->iobase + DAS800_LSB); 387 dataPoint += inb(dev->iobase + DAS800_MSB) << 8; 388 if (thisboard->resolution == 12) { 389 fifo_empty = dataPoint & FIFO_EMPTY; 390 fifo_overflow = dataPoint & FIFO_OVF; 391 if (fifo_overflow) 392 break; 393 } else { 394 fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */ 395 } 396 if (fifo_empty) { 397 break; 398 } 399 /* strip off extraneous bits for 12 bit cards */ 400 if (thisboard->resolution == 12) 401 dataPoint = (dataPoint >> 4) & 0xfff; 402 /* if there are more data points to collect */ 403 if (devpriv->count > 0 || devpriv->forever == 1) { 404 /* write data point to buffer */ 405 cfc_write_to_buffer(s, dataPoint); 406 if (devpriv->count > 0) 407 devpriv->count--; 408 } 409 } 410 async->events |= COMEDI_CB_BLOCK; 411 /* check for fifo overflow */ 412 if (thisboard->resolution == 12) { 413 fifo_overflow = dataPoint & FIFO_OVF; 414 /* else cio-das802/16 */ 415 } else { 416 fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV; 417 } 418 if (fifo_overflow) { 419 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 420 comedi_error(dev, "DAS800 FIFO overflow"); 421 das800_cancel(dev, dev->subdevices + 0); 422 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 423 comedi_event(dev, s); 424 async->events = 0; 425 return IRQ_HANDLED; 426 } 427 if (devpriv->count > 0 || devpriv->forever == 1) { 428 /* Re-enable card's interrupt. 429 * We already have spinlock, so indirect addressing is safe */ 430 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 431 outb(CONTROL1_INTE | devpriv->do_bits, 432 dev->iobase + DAS800_CONTROL1); 433 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 434 /* otherwise, stop taking data */ 435 } else { 436 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 437 disable_das800(dev); /* diable hardware triggered conversions */ 438 async->events |= COMEDI_CB_EOA; 439 } 440 comedi_event(dev, s); 441 async->events = 0; 442 return IRQ_HANDLED; 443} 444 445static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) 446{ 447 struct comedi_subdevice *s; 448 unsigned long iobase = it->options[0]; 449 unsigned int irq = it->options[1]; 450 unsigned long irq_flags; 451 int board; 452 453 printk("comedi%d: das800: io 0x%lx", dev->minor, iobase); 454 if (irq) { 455 printk(", irq %u", irq); 456 } 457 printk("\n"); 458 459 /* allocate and initialize dev->private */ 460 if (alloc_private(dev, sizeof(struct das800_private)) < 0) 461 return -ENOMEM; 462 463 if (iobase == 0) { 464 printk("io base address required for das800\n"); 465 return -EINVAL; 466 } 467 468 /* check if io addresses are available */ 469 if (!request_region(iobase, DAS800_SIZE, "das800")) { 470 printk("I/O port conflict\n"); 471 return -EIO; 472 } 473 dev->iobase = iobase; 474 475 board = das800_probe(dev); 476 if (board < 0) { 477 printk("unable to determine board type\n"); 478 return -ENODEV; 479 } 480 dev->board_ptr = das800_boards + board; 481 482 /* grab our IRQ */ 483 if (irq == 1 || irq > 7) { 484 printk("irq out of range\n"); 485 return -EINVAL; 486 } 487 if (irq) { 488 if (request_irq(irq, das800_interrupt, 0, "das800", dev)) { 489 printk("unable to allocate irq %u\n", irq); 490 return -EINVAL; 491 } 492 } 493 dev->irq = irq; 494 495 dev->board_name = thisboard->name; 496 497 if (alloc_subdevices(dev, 3) < 0) 498 return -ENOMEM; 499 500 /* analog input subdevice */ 501 s = dev->subdevices + 0; 502 dev->read_subdev = s; 503 s->type = COMEDI_SUBD_AI; 504 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; 505 s->n_chan = 8; 506 s->len_chanlist = 8; 507 s->maxdata = (1 << thisboard->resolution) - 1; 508 s->range_table = thisboard->ai_range; 509 s->do_cmd = das800_ai_do_cmd; 510 s->do_cmdtest = das800_ai_do_cmdtest; 511 s->insn_read = das800_ai_rinsn; 512 s->cancel = das800_cancel; 513 514 /* di */ 515 s = dev->subdevices + 1; 516 s->type = COMEDI_SUBD_DI; 517 s->subdev_flags = SDF_READABLE; 518 s->n_chan = 3; 519 s->maxdata = 1; 520 s->range_table = &range_digital; 521 s->insn_bits = das800_di_rbits; 522 523 /* do */ 524 s = dev->subdevices + 2; 525 s->type = COMEDI_SUBD_DO; 526 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 527 s->n_chan = 4; 528 s->maxdata = 1; 529 s->range_table = &range_digital; 530 s->insn_bits = das800_do_wbits; 531 532 disable_das800(dev); 533 534 /* initialize digital out channels */ 535 spin_lock_irqsave(&dev->spinlock, irq_flags); 536 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 537 outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); 538 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 539 540 return 0; 541}; 542 543static int das800_detach(struct comedi_device *dev) 544{ 545 printk("comedi%d: das800: remove\n", dev->minor); 546 547 /* only free stuff if it has been allocated by _attach */ 548 if (dev->iobase) 549 release_region(dev->iobase, DAS800_SIZE); 550 if (dev->irq) 551 free_irq(dev->irq, dev); 552 return 0; 553}; 554 555static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 556{ 557 devpriv->forever = 0; 558 devpriv->count = 0; 559 disable_das800(dev); 560 return 0; 561} 562 563/* enable_das800 makes the card start taking hardware triggered conversions */ 564static void enable_das800(struct comedi_device *dev) 565{ 566 unsigned long irq_flags; 567 spin_lock_irqsave(&dev->spinlock, irq_flags); 568 /* enable fifo-half full interrupts for cio-das802/16 */ 569 if (thisboard->resolution == 16) 570 outb(CIO_ENHF, dev->iobase + DAS800_GAIN); 571 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 572 outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL); /* enable hardware triggering */ 573 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 574 outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); /* enable card's interrupt */ 575 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 576} 577 578/* disable_das800 stops hardware triggered conversions */ 579static void disable_das800(struct comedi_device *dev) 580{ 581 unsigned long irq_flags; 582 spin_lock_irqsave(&dev->spinlock, irq_flags); 583 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 584 outb(0x0, dev->iobase + DAS800_CONV_CONTROL); /* disable hardware triggering of conversions */ 585 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 586} 587 588static int das800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, 589 struct comedi_cmd *cmd) 590{ 591 int err = 0; 592 int tmp; 593 int gain, startChan; 594 int i; 595 596 /* step 1: make sure trigger sources are trivially valid */ 597 598 tmp = cmd->start_src; 599 cmd->start_src &= TRIG_NOW | TRIG_EXT; 600 if (!cmd->start_src || tmp != cmd->start_src) 601 err++; 602 603 tmp = cmd->scan_begin_src; 604 cmd->scan_begin_src &= TRIG_FOLLOW; 605 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 606 err++; 607 608 tmp = cmd->convert_src; 609 cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 610 if (!cmd->convert_src || tmp != cmd->convert_src) 611 err++; 612 613 tmp = cmd->scan_end_src; 614 cmd->scan_end_src &= TRIG_COUNT; 615 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 616 err++; 617 618 tmp = cmd->stop_src; 619 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 620 if (!cmd->stop_src || tmp != cmd->stop_src) 621 err++; 622 623 if (err) 624 return 1; 625 626 /* step 2: make sure trigger sources are unique and mutually compatible */ 627 628 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) 629 err++; 630 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 631 err++; 632 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 633 err++; 634 635 if (err) 636 return 2; 637 638 /* step 3: make sure arguments are trivially compatible */ 639 640 if (cmd->start_arg != 0) { 641 cmd->start_arg = 0; 642 err++; 643 } 644 if (cmd->convert_src == TRIG_TIMER) { 645 if (cmd->convert_arg < thisboard->ai_speed) { 646 cmd->convert_arg = thisboard->ai_speed; 647 err++; 648 } 649 } 650 if (!cmd->chanlist_len) { 651 cmd->chanlist_len = 1; 652 err++; 653 } 654 if (cmd->scan_end_arg != cmd->chanlist_len) { 655 cmd->scan_end_arg = cmd->chanlist_len; 656 err++; 657 } 658 if (cmd->stop_src == TRIG_COUNT) { 659 if (!cmd->stop_arg) { 660 cmd->stop_arg = 1; 661 err++; 662 } 663 } else { /* TRIG_NONE */ 664 if (cmd->stop_arg != 0) { 665 cmd->stop_arg = 0; 666 err++; 667 } 668 } 669 670 if (err) 671 return 3; 672 673 /* step 4: fix up any arguments */ 674 675 if (cmd->convert_src == TRIG_TIMER) { 676 tmp = cmd->convert_arg; 677 /* calculate counter values that give desired timing */ 678 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), 679 &(devpriv->divisor2), &(cmd->convert_arg), 680 cmd->flags & TRIG_ROUND_MASK); 681 if (tmp != cmd->convert_arg) 682 err++; 683 } 684 685 if (err) 686 return 4; 687 688 /* check channel/gain list against card's limitations */ 689 if (cmd->chanlist) { 690 gain = CR_RANGE(cmd->chanlist[0]); 691 startChan = CR_CHAN(cmd->chanlist[0]); 692 for (i = 1; i < cmd->chanlist_len; i++) { 693 if (CR_CHAN(cmd->chanlist[i]) != 694 (startChan + i) % N_CHAN_AI) { 695 comedi_error(dev, 696 "entries in chanlist must be consecutive channels, counting upwards\n"); 697 err++; 698 } 699 if (CR_RANGE(cmd->chanlist[i]) != gain) { 700 comedi_error(dev, 701 "entries in chanlist must all have the same gain\n"); 702 err++; 703 } 704 } 705 } 706 707 if (err) 708 return 5; 709 710 return 0; 711} 712 713static int das800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 714{ 715 int startChan, endChan, scan, gain; 716 int conv_bits; 717 unsigned long irq_flags; 718 struct comedi_async *async = s->async; 719 720 if (!dev->irq) { 721 comedi_error(dev, 722 "no irq assigned for das-800, cannot do hardware conversions"); 723 return -1; 724 } 725 726 disable_das800(dev); 727 728 /* set channel scan limits */ 729 startChan = CR_CHAN(async->cmd.chanlist[0]); 730 endChan = (startChan + async->cmd.chanlist_len - 1) % 8; 731 scan = (endChan << 3) | startChan; 732 733 spin_lock_irqsave(&dev->spinlock, irq_flags); 734 outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN); /* select base address + 2 to be scan limits register */ 735 outb(scan, dev->iobase + DAS800_SCAN_LIMITS); /* set scan limits */ 736 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 737 738 /* set gain */ 739 gain = CR_RANGE(async->cmd.chanlist[0]); 740 if (thisboard->resolution == 12 && gain > 0) 741 gain += 0x7; 742 gain &= 0xf; 743 outb(gain, dev->iobase + DAS800_GAIN); 744 745 switch (async->cmd.stop_src) { 746 case TRIG_COUNT: 747 devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len; 748 devpriv->forever = 0; 749 break; 750 case TRIG_NONE: 751 devpriv->forever = 1; 752 devpriv->count = 0; 753 break; 754 default: 755 break; 756 } 757 758 /* enable auto channel scan, send interrupts on end of conversion 759 * and set clock source to internal or external 760 */ 761 conv_bits = 0; 762 conv_bits |= EACS | IEOC; 763 if (async->cmd.start_src == TRIG_EXT) 764 conv_bits |= DTEN; 765 switch (async->cmd.convert_src) { 766 case TRIG_TIMER: 767 conv_bits |= CASC | ITE; 768 /* set conversion frequency */ 769 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), 770 &(devpriv->divisor2), &(async->cmd.convert_arg), 771 async->cmd.flags & TRIG_ROUND_MASK); 772 if (das800_set_frequency(dev) < 0) { 773 comedi_error(dev, "Error setting up counters"); 774 return -1; 775 } 776 break; 777 case TRIG_EXT: 778 break; 779 default: 780 break; 781 } 782 783 spin_lock_irqsave(&dev->spinlock, irq_flags); 784 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 785 outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL); 786 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 787 async->events = 0; 788 enable_das800(dev); 789 return 0; 790} 791 792static int das800_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 793 struct comedi_insn *insn, unsigned int *data) 794{ 795 int i, n; 796 int chan; 797 int range; 798 int lsb, msb; 799 int timeout = 1000; 800 unsigned long irq_flags; 801 802 disable_das800(dev); /* disable hardware conversions (enables software conversions) */ 803 804 /* set multiplexer */ 805 chan = CR_CHAN(insn->chanspec); 806 807 spin_lock_irqsave(&dev->spinlock, irq_flags); 808 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 809 outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); 810 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 811 812 /* set gain / range */ 813 range = CR_RANGE(insn->chanspec); 814 if (thisboard->resolution == 12 && range) 815 range += 0x7; 816 range &= 0xf; 817 outb(range, dev->iobase + DAS800_GAIN); 818 819 udelay(5); 820 821 for (n = 0; n < insn->n; n++) { 822 /* trigger conversion */ 823 outb_p(0, dev->iobase + DAS800_MSB); 824 825 for (i = 0; i < timeout; i++) { 826 if (!(inb(dev->iobase + DAS800_STATUS) & BUSY)) 827 break; 828 } 829 if (i == timeout) { 830 comedi_error(dev, "timeout"); 831 return -ETIME; 832 } 833 lsb = inb(dev->iobase + DAS800_LSB); 834 msb = inb(dev->iobase + DAS800_MSB); 835 if (thisboard->resolution == 12) { 836 data[n] = (lsb >> 4) & 0xff; 837 data[n] |= (msb << 4); 838 } else { 839 data[n] = (msb << 8) | lsb; 840 } 841 } 842 843 return n; 844} 845 846static int das800_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, 847 struct comedi_insn *insn, unsigned int *data) 848{ 849 unsigned int bits; 850 851 bits = inb(dev->iobase + DAS800_STATUS) >> 4; 852 bits &= 0x7; 853 data[1] = bits; 854 data[0] = 0; 855 856 return 2; 857} 858 859static int das800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, 860 struct comedi_insn *insn, unsigned int *data) 861{ 862 int wbits; 863 unsigned long irq_flags; 864 865 /* only set bits that have been masked */ 866 data[0] &= 0xf; 867 wbits = devpriv->do_bits >> 4; 868 wbits &= ~data[0]; 869 wbits |= data[0] & data[1]; 870 devpriv->do_bits = wbits << 4; 871 872 spin_lock_irqsave(&dev->spinlock, irq_flags); 873 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 874 outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1); 875 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 876 877 data[1] = wbits; 878 879 return 2; 880} 881 882/* loads counters with divisor1, divisor2 from private structure */ 883static int das800_set_frequency(struct comedi_device *dev) 884{ 885 int err = 0; 886 887 if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2)) 888 err++; 889 if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2)) 890 err++; 891 if (err) 892 return -1; 893 894 return 0; 895} 896