das800.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
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, 247 struct comedi_devconfig *it); 248static int das800_detach(struct comedi_device *dev); 249static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s); 250 251static struct comedi_driver driver_das800 = { 252 .driver_name = "das800", 253 .module = THIS_MODULE, 254 .attach = das800_attach, 255 .detach = das800_detach, 256 .num_names = ARRAY_SIZE(das800_boards), 257 .board_name = &das800_boards[0].name, 258 .offset = sizeof(struct das800_board), 259}; 260 261static irqreturn_t das800_interrupt(int irq, void *d); 262static void enable_das800(struct comedi_device *dev); 263static void disable_das800(struct comedi_device *dev); 264static int das800_ai_do_cmdtest(struct comedi_device *dev, 265 struct comedi_subdevice *s, 266 struct comedi_cmd *cmd); 267static int das800_ai_do_cmd(struct comedi_device *dev, 268 struct comedi_subdevice *s); 269static int das800_ai_rinsn(struct comedi_device *dev, 270 struct comedi_subdevice *s, struct comedi_insn *insn, 271 unsigned int *data); 272static int das800_di_rbits(struct comedi_device *dev, 273 struct comedi_subdevice *s, struct comedi_insn *insn, 274 unsigned int *data); 275static int das800_do_wbits(struct comedi_device *dev, 276 struct comedi_subdevice *s, struct comedi_insn *insn, 277 unsigned int *data); 278static int das800_probe(struct comedi_device *dev); 279static int das800_set_frequency(struct comedi_device *dev); 280 281/* checks and probes das-800 series board type */ 282static int das800_probe(struct comedi_device *dev) 283{ 284 int id_bits; 285 unsigned long irq_flags; 286 int board; 287 288 /* 'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */ 289 spin_lock_irqsave(&dev->spinlock, irq_flags); 290 outb(ID, dev->iobase + DAS800_GAIN); /* select base address + 7 to be ID register */ 291 id_bits = inb(dev->iobase + DAS800_ID) & 0x3; /* get id bits */ 292 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 293 294 board = thisboard - das800_boards; 295 296 switch (id_bits) { 297 case 0x0: 298 if (board == das800) { 299 printk(" Board model: DAS-800\n"); 300 return board; 301 } 302 if (board == ciodas800) { 303 printk(" Board model: CIO-DAS800\n"); 304 return board; 305 } 306 printk(" Board model (probed): DAS-800\n"); 307 return das800; 308 break; 309 case 0x2: 310 if (board == das801) { 311 printk(" Board model: DAS-801\n"); 312 return board; 313 } 314 if (board == ciodas801) { 315 printk(" Board model: CIO-DAS801\n"); 316 return board; 317 } 318 printk(" Board model (probed): DAS-801\n"); 319 return das801; 320 break; 321 case 0x3: 322 if (board == das802) { 323 printk(" Board model: DAS-802\n"); 324 return board; 325 } 326 if (board == ciodas802) { 327 printk(" Board model: CIO-DAS802\n"); 328 return board; 329 } 330 if (board == ciodas80216) { 331 printk(" Board model: CIO-DAS802/16\n"); 332 return board; 333 } 334 printk(" Board model (probed): DAS-802\n"); 335 return das802; 336 break; 337 default: 338 printk(" Board model: probe returned 0x%x (unknown)\n", 339 id_bits); 340 return board; 341 break; 342 } 343 return -1; 344} 345 346/* 347 * A convenient macro that defines init_module() and cleanup_module(), 348 * as necessary. 349 */ 350COMEDI_INITCLEANUP(driver_das800); 351 352/* interrupt service routine */ 353static irqreturn_t das800_interrupt(int irq, void *d) 354{ 355 short i; /* loop index */ 356 short dataPoint = 0; 357 struct comedi_device *dev = d; 358 struct comedi_subdevice *s = dev->read_subdev; /* analog input subdevice */ 359 struct comedi_async *async; 360 int status; 361 unsigned long irq_flags; 362 static const int max_loops = 128; /* half-fifo size for cio-das802/16 */ 363 /* flags */ 364 int fifo_empty = 0; 365 int fifo_overflow = 0; 366 367 status = inb(dev->iobase + DAS800_STATUS); 368 /* if interrupt was not generated by board or driver not attached, quit */ 369 if (!(status & IRQ)) 370 return IRQ_NONE; 371 if (!(dev->attached)) 372 return IRQ_HANDLED; 373 374 /* wait until here to initialize async, since we will get null dereference 375 * if interrupt occurs before driver is fully attached! 376 */ 377 async = s->async; 378 379 /* if hardware conversions are not enabled, then quit */ 380 spin_lock_irqsave(&dev->spinlock, irq_flags); 381 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */ 382 status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN; 383 /* don't release spinlock yet since we want to make sure noone else disables hardware conversions */ 384 if (status == 0) { 385 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 386 return IRQ_HANDLED; 387 } 388 389 /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */ 390 for (i = 0; i < max_loops; i++) { 391 /* read 16 bits from dev->iobase and dev->iobase + 1 */ 392 dataPoint = inb(dev->iobase + DAS800_LSB); 393 dataPoint += inb(dev->iobase + DAS800_MSB) << 8; 394 if (thisboard->resolution == 12) { 395 fifo_empty = dataPoint & FIFO_EMPTY; 396 fifo_overflow = dataPoint & FIFO_OVF; 397 if (fifo_overflow) 398 break; 399 } else { 400 fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */ 401 } 402 if (fifo_empty) { 403 break; 404 } 405 /* strip off extraneous bits for 12 bit cards */ 406 if (thisboard->resolution == 12) 407 dataPoint = (dataPoint >> 4) & 0xfff; 408 /* if there are more data points to collect */ 409 if (devpriv->count > 0 || devpriv->forever == 1) { 410 /* write data point to buffer */ 411 cfc_write_to_buffer(s, dataPoint); 412 if (devpriv->count > 0) 413 devpriv->count--; 414 } 415 } 416 async->events |= COMEDI_CB_BLOCK; 417 /* check for fifo overflow */ 418 if (thisboard->resolution == 12) { 419 fifo_overflow = dataPoint & FIFO_OVF; 420 /* else cio-das802/16 */ 421 } else { 422 fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV; 423 } 424 if (fifo_overflow) { 425 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 426 comedi_error(dev, "DAS800 FIFO overflow"); 427 das800_cancel(dev, dev->subdevices + 0); 428 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 429 comedi_event(dev, s); 430 async->events = 0; 431 return IRQ_HANDLED; 432 } 433 if (devpriv->count > 0 || devpriv->forever == 1) { 434 /* Re-enable card's interrupt. 435 * We already have spinlock, so indirect addressing is safe */ 436 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 437 outb(CONTROL1_INTE | devpriv->do_bits, 438 dev->iobase + DAS800_CONTROL1); 439 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 440 /* otherwise, stop taking data */ 441 } else { 442 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 443 disable_das800(dev); /* diable hardware triggered conversions */ 444 async->events |= COMEDI_CB_EOA; 445 } 446 comedi_event(dev, s); 447 async->events = 0; 448 return IRQ_HANDLED; 449} 450 451static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) 452{ 453 struct comedi_subdevice *s; 454 unsigned long iobase = it->options[0]; 455 unsigned int irq = it->options[1]; 456 unsigned long irq_flags; 457 int board; 458 459 printk("comedi%d: das800: io 0x%lx", dev->minor, iobase); 460 if (irq) { 461 printk(", irq %u", irq); 462 } 463 printk("\n"); 464 465 /* allocate and initialize dev->private */ 466 if (alloc_private(dev, sizeof(struct das800_private)) < 0) 467 return -ENOMEM; 468 469 if (iobase == 0) { 470 printk("io base address required for das800\n"); 471 return -EINVAL; 472 } 473 474 /* check if io addresses are available */ 475 if (!request_region(iobase, DAS800_SIZE, "das800")) { 476 printk("I/O port conflict\n"); 477 return -EIO; 478 } 479 dev->iobase = iobase; 480 481 board = das800_probe(dev); 482 if (board < 0) { 483 printk("unable to determine board type\n"); 484 return -ENODEV; 485 } 486 dev->board_ptr = das800_boards + board; 487 488 /* grab our IRQ */ 489 if (irq == 1 || irq > 7) { 490 printk("irq out of range\n"); 491 return -EINVAL; 492 } 493 if (irq) { 494 if (request_irq(irq, das800_interrupt, 0, "das800", dev)) { 495 printk("unable to allocate irq %u\n", irq); 496 return -EINVAL; 497 } 498 } 499 dev->irq = irq; 500 501 dev->board_name = thisboard->name; 502 503 if (alloc_subdevices(dev, 3) < 0) 504 return -ENOMEM; 505 506 /* analog input subdevice */ 507 s = dev->subdevices + 0; 508 dev->read_subdev = s; 509 s->type = COMEDI_SUBD_AI; 510 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; 511 s->n_chan = 8; 512 s->len_chanlist = 8; 513 s->maxdata = (1 << thisboard->resolution) - 1; 514 s->range_table = thisboard->ai_range; 515 s->do_cmd = das800_ai_do_cmd; 516 s->do_cmdtest = das800_ai_do_cmdtest; 517 s->insn_read = das800_ai_rinsn; 518 s->cancel = das800_cancel; 519 520 /* di */ 521 s = dev->subdevices + 1; 522 s->type = COMEDI_SUBD_DI; 523 s->subdev_flags = SDF_READABLE; 524 s->n_chan = 3; 525 s->maxdata = 1; 526 s->range_table = &range_digital; 527 s->insn_bits = das800_di_rbits; 528 529 /* do */ 530 s = dev->subdevices + 2; 531 s->type = COMEDI_SUBD_DO; 532 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 533 s->n_chan = 4; 534 s->maxdata = 1; 535 s->range_table = &range_digital; 536 s->insn_bits = das800_do_wbits; 537 538 disable_das800(dev); 539 540 /* initialize digital out channels */ 541 spin_lock_irqsave(&dev->spinlock, irq_flags); 542 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 543 outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); 544 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 545 546 return 0; 547}; 548 549static int das800_detach(struct comedi_device *dev) 550{ 551 printk("comedi%d: das800: remove\n", dev->minor); 552 553 /* only free stuff if it has been allocated by _attach */ 554 if (dev->iobase) 555 release_region(dev->iobase, DAS800_SIZE); 556 if (dev->irq) 557 free_irq(dev->irq, dev); 558 return 0; 559}; 560 561static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 562{ 563 devpriv->forever = 0; 564 devpriv->count = 0; 565 disable_das800(dev); 566 return 0; 567} 568 569/* enable_das800 makes the card start taking hardware triggered conversions */ 570static void enable_das800(struct comedi_device *dev) 571{ 572 unsigned long irq_flags; 573 spin_lock_irqsave(&dev->spinlock, irq_flags); 574 /* enable fifo-half full interrupts for cio-das802/16 */ 575 if (thisboard->resolution == 16) 576 outb(CIO_ENHF, dev->iobase + DAS800_GAIN); 577 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 578 outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL); /* enable hardware triggering */ 579 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 580 outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); /* enable card's interrupt */ 581 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 582} 583 584/* disable_das800 stops hardware triggered conversions */ 585static void disable_das800(struct comedi_device *dev) 586{ 587 unsigned long irq_flags; 588 spin_lock_irqsave(&dev->spinlock, irq_flags); 589 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 590 outb(0x0, dev->iobase + DAS800_CONV_CONTROL); /* disable hardware triggering of conversions */ 591 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 592} 593 594static int das800_ai_do_cmdtest(struct comedi_device *dev, 595 struct comedi_subdevice *s, 596 struct comedi_cmd *cmd) 597{ 598 int err = 0; 599 int tmp; 600 int gain, startChan; 601 int i; 602 603 /* step 1: make sure trigger sources are trivially valid */ 604 605 tmp = cmd->start_src; 606 cmd->start_src &= TRIG_NOW | TRIG_EXT; 607 if (!cmd->start_src || tmp != cmd->start_src) 608 err++; 609 610 tmp = cmd->scan_begin_src; 611 cmd->scan_begin_src &= TRIG_FOLLOW; 612 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 613 err++; 614 615 tmp = cmd->convert_src; 616 cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 617 if (!cmd->convert_src || tmp != cmd->convert_src) 618 err++; 619 620 tmp = cmd->scan_end_src; 621 cmd->scan_end_src &= TRIG_COUNT; 622 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 623 err++; 624 625 tmp = cmd->stop_src; 626 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 627 if (!cmd->stop_src || tmp != cmd->stop_src) 628 err++; 629 630 if (err) 631 return 1; 632 633 /* step 2: make sure trigger sources are unique and mutually compatible */ 634 635 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) 636 err++; 637 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 638 err++; 639 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 640 err++; 641 642 if (err) 643 return 2; 644 645 /* step 3: make sure arguments are trivially compatible */ 646 647 if (cmd->start_arg != 0) { 648 cmd->start_arg = 0; 649 err++; 650 } 651 if (cmd->convert_src == TRIG_TIMER) { 652 if (cmd->convert_arg < thisboard->ai_speed) { 653 cmd->convert_arg = thisboard->ai_speed; 654 err++; 655 } 656 } 657 if (!cmd->chanlist_len) { 658 cmd->chanlist_len = 1; 659 err++; 660 } 661 if (cmd->scan_end_arg != cmd->chanlist_len) { 662 cmd->scan_end_arg = cmd->chanlist_len; 663 err++; 664 } 665 if (cmd->stop_src == TRIG_COUNT) { 666 if (!cmd->stop_arg) { 667 cmd->stop_arg = 1; 668 err++; 669 } 670 } else { /* TRIG_NONE */ 671 if (cmd->stop_arg != 0) { 672 cmd->stop_arg = 0; 673 err++; 674 } 675 } 676 677 if (err) 678 return 3; 679 680 /* step 4: fix up any arguments */ 681 682 if (cmd->convert_src == TRIG_TIMER) { 683 tmp = cmd->convert_arg; 684 /* calculate counter values that give desired timing */ 685 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), 686 &(devpriv->divisor2), 687 &(cmd->convert_arg), 688 cmd->flags & TRIG_ROUND_MASK); 689 if (tmp != cmd->convert_arg) 690 err++; 691 } 692 693 if (err) 694 return 4; 695 696 /* check channel/gain list against card's limitations */ 697 if (cmd->chanlist) { 698 gain = CR_RANGE(cmd->chanlist[0]); 699 startChan = CR_CHAN(cmd->chanlist[0]); 700 for (i = 1; i < cmd->chanlist_len; i++) { 701 if (CR_CHAN(cmd->chanlist[i]) != 702 (startChan + i) % N_CHAN_AI) { 703 comedi_error(dev, 704 "entries in chanlist must be consecutive channels, counting upwards\n"); 705 err++; 706 } 707 if (CR_RANGE(cmd->chanlist[i]) != gain) { 708 comedi_error(dev, 709 "entries in chanlist must all have the same gain\n"); 710 err++; 711 } 712 } 713 } 714 715 if (err) 716 return 5; 717 718 return 0; 719} 720 721static int das800_ai_do_cmd(struct comedi_device *dev, 722 struct comedi_subdevice *s) 723{ 724 int startChan, endChan, scan, gain; 725 int conv_bits; 726 unsigned long irq_flags; 727 struct comedi_async *async = s->async; 728 729 if (!dev->irq) { 730 comedi_error(dev, 731 "no irq assigned for das-800, cannot do hardware conversions"); 732 return -1; 733 } 734 735 disable_das800(dev); 736 737 /* set channel scan limits */ 738 startChan = CR_CHAN(async->cmd.chanlist[0]); 739 endChan = (startChan + async->cmd.chanlist_len - 1) % 8; 740 scan = (endChan << 3) | startChan; 741 742 spin_lock_irqsave(&dev->spinlock, irq_flags); 743 outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN); /* select base address + 2 to be scan limits register */ 744 outb(scan, dev->iobase + DAS800_SCAN_LIMITS); /* set scan limits */ 745 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 746 747 /* set gain */ 748 gain = CR_RANGE(async->cmd.chanlist[0]); 749 if (thisboard->resolution == 12 && gain > 0) 750 gain += 0x7; 751 gain &= 0xf; 752 outb(gain, dev->iobase + DAS800_GAIN); 753 754 switch (async->cmd.stop_src) { 755 case TRIG_COUNT: 756 devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len; 757 devpriv->forever = 0; 758 break; 759 case TRIG_NONE: 760 devpriv->forever = 1; 761 devpriv->count = 0; 762 break; 763 default: 764 break; 765 } 766 767 /* enable auto channel scan, send interrupts on end of conversion 768 * and set clock source to internal or external 769 */ 770 conv_bits = 0; 771 conv_bits |= EACS | IEOC; 772 if (async->cmd.start_src == TRIG_EXT) 773 conv_bits |= DTEN; 774 switch (async->cmd.convert_src) { 775 case TRIG_TIMER: 776 conv_bits |= CASC | ITE; 777 /* set conversion frequency */ 778 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), 779 &(devpriv->divisor2), 780 &(async->cmd.convert_arg), 781 async->cmd. 782 flags & TRIG_ROUND_MASK); 783 if (das800_set_frequency(dev) < 0) { 784 comedi_error(dev, "Error setting up counters"); 785 return -1; 786 } 787 break; 788 case TRIG_EXT: 789 break; 790 default: 791 break; 792 } 793 794 spin_lock_irqsave(&dev->spinlock, irq_flags); 795 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 796 outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL); 797 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 798 async->events = 0; 799 enable_das800(dev); 800 return 0; 801} 802 803static int das800_ai_rinsn(struct comedi_device *dev, 804 struct comedi_subdevice *s, struct comedi_insn *insn, 805 unsigned int *data) 806{ 807 int i, n; 808 int chan; 809 int range; 810 int lsb, msb; 811 int timeout = 1000; 812 unsigned long irq_flags; 813 814 disable_das800(dev); /* disable hardware conversions (enables software conversions) */ 815 816 /* set multiplexer */ 817 chan = CR_CHAN(insn->chanspec); 818 819 spin_lock_irqsave(&dev->spinlock, irq_flags); 820 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 821 outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); 822 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 823 824 /* set gain / range */ 825 range = CR_RANGE(insn->chanspec); 826 if (thisboard->resolution == 12 && range) 827 range += 0x7; 828 range &= 0xf; 829 outb(range, dev->iobase + DAS800_GAIN); 830 831 udelay(5); 832 833 for (n = 0; n < insn->n; n++) { 834 /* trigger conversion */ 835 outb_p(0, dev->iobase + DAS800_MSB); 836 837 for (i = 0; i < timeout; i++) { 838 if (!(inb(dev->iobase + DAS800_STATUS) & BUSY)) 839 break; 840 } 841 if (i == timeout) { 842 comedi_error(dev, "timeout"); 843 return -ETIME; 844 } 845 lsb = inb(dev->iobase + DAS800_LSB); 846 msb = inb(dev->iobase + DAS800_MSB); 847 if (thisboard->resolution == 12) { 848 data[n] = (lsb >> 4) & 0xff; 849 data[n] |= (msb << 4); 850 } else { 851 data[n] = (msb << 8) | lsb; 852 } 853 } 854 855 return n; 856} 857 858static int das800_di_rbits(struct comedi_device *dev, 859 struct comedi_subdevice *s, struct comedi_insn *insn, 860 unsigned int *data) 861{ 862 unsigned int bits; 863 864 bits = inb(dev->iobase + DAS800_STATUS) >> 4; 865 bits &= 0x7; 866 data[1] = bits; 867 data[0] = 0; 868 869 return 2; 870} 871 872static int das800_do_wbits(struct comedi_device *dev, 873 struct comedi_subdevice *s, struct comedi_insn *insn, 874 unsigned int *data) 875{ 876 int wbits; 877 unsigned long irq_flags; 878 879 /* only set bits that have been masked */ 880 data[0] &= 0xf; 881 wbits = devpriv->do_bits >> 4; 882 wbits &= ~data[0]; 883 wbits |= data[0] & data[1]; 884 devpriv->do_bits = wbits << 4; 885 886 spin_lock_irqsave(&dev->spinlock, irq_flags); 887 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 888 outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1); 889 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 890 891 data[1] = wbits; 892 893 return 2; 894} 895 896/* loads counters with divisor1, divisor2 from private structure */ 897static int das800_set_frequency(struct comedi_device *dev) 898{ 899 int err = 0; 900 901 if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2)) 902 err++; 903 if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2)) 904 err++; 905 if (err) 906 return -1; 907 908 return 0; 909} 910