das800.c revision 882e5b32b5d68960f46331215fc3c301df508110
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 /* strip off extraneous bits for 12 bit cards */ 405 if (thisboard->resolution == 12) 406 dataPoint = (dataPoint >> 4) & 0xfff; 407 /* if there are more data points to collect */ 408 if (devpriv->count > 0 || devpriv->forever == 1) { 409 /* write data point to buffer */ 410 cfc_write_to_buffer(s, dataPoint); 411 if (devpriv->count > 0) 412 devpriv->count--; 413 } 414 } 415 async->events |= COMEDI_CB_BLOCK; 416 /* check for fifo overflow */ 417 if (thisboard->resolution == 12) { 418 fifo_overflow = dataPoint & FIFO_OVF; 419 /* else cio-das802/16 */ 420 } else { 421 fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV; 422 } 423 if (fifo_overflow) { 424 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 425 comedi_error(dev, "DAS800 FIFO overflow"); 426 das800_cancel(dev, dev->subdevices + 0); 427 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 428 comedi_event(dev, s); 429 async->events = 0; 430 return IRQ_HANDLED; 431 } 432 if (devpriv->count > 0 || devpriv->forever == 1) { 433 /* Re-enable card's interrupt. 434 * We already have spinlock, so indirect addressing is safe */ 435 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 436 outb(CONTROL1_INTE | devpriv->do_bits, 437 dev->iobase + DAS800_CONTROL1); 438 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 439 /* otherwise, stop taking data */ 440 } else { 441 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 442 disable_das800(dev); /* diable hardware triggered conversions */ 443 async->events |= COMEDI_CB_EOA; 444 } 445 comedi_event(dev, s); 446 async->events = 0; 447 return IRQ_HANDLED; 448} 449 450static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) 451{ 452 struct comedi_subdevice *s; 453 unsigned long iobase = it->options[0]; 454 unsigned int irq = it->options[1]; 455 unsigned long irq_flags; 456 int board; 457 458 printk("comedi%d: das800: io 0x%lx", dev->minor, iobase); 459 if (irq) 460 printk(", irq %u", irq); 461 printk("\n"); 462 463 /* allocate and initialize dev->private */ 464 if (alloc_private(dev, sizeof(struct das800_private)) < 0) 465 return -ENOMEM; 466 467 if (iobase == 0) { 468 printk("io base address required for das800\n"); 469 return -EINVAL; 470 } 471 472 /* check if io addresses are available */ 473 if (!request_region(iobase, DAS800_SIZE, "das800")) { 474 printk("I/O port conflict\n"); 475 return -EIO; 476 } 477 dev->iobase = iobase; 478 479 board = das800_probe(dev); 480 if (board < 0) { 481 printk("unable to determine board type\n"); 482 return -ENODEV; 483 } 484 dev->board_ptr = das800_boards + board; 485 486 /* grab our IRQ */ 487 if (irq == 1 || irq > 7) { 488 printk("irq out of range\n"); 489 return -EINVAL; 490 } 491 if (irq) { 492 if (request_irq(irq, das800_interrupt, 0, "das800", dev)) { 493 printk("unable to allocate irq %u\n", irq); 494 return -EINVAL; 495 } 496 } 497 dev->irq = irq; 498 499 dev->board_name = thisboard->name; 500 501 if (alloc_subdevices(dev, 3) < 0) 502 return -ENOMEM; 503 504 /* analog input subdevice */ 505 s = dev->subdevices + 0; 506 dev->read_subdev = s; 507 s->type = COMEDI_SUBD_AI; 508 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; 509 s->n_chan = 8; 510 s->len_chanlist = 8; 511 s->maxdata = (1 << thisboard->resolution) - 1; 512 s->range_table = thisboard->ai_range; 513 s->do_cmd = das800_ai_do_cmd; 514 s->do_cmdtest = das800_ai_do_cmdtest; 515 s->insn_read = das800_ai_rinsn; 516 s->cancel = das800_cancel; 517 518 /* di */ 519 s = dev->subdevices + 1; 520 s->type = COMEDI_SUBD_DI; 521 s->subdev_flags = SDF_READABLE; 522 s->n_chan = 3; 523 s->maxdata = 1; 524 s->range_table = &range_digital; 525 s->insn_bits = das800_di_rbits; 526 527 /* do */ 528 s = dev->subdevices + 2; 529 s->type = COMEDI_SUBD_DO; 530 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 531 s->n_chan = 4; 532 s->maxdata = 1; 533 s->range_table = &range_digital; 534 s->insn_bits = das800_do_wbits; 535 536 disable_das800(dev); 537 538 /* initialize digital out channels */ 539 spin_lock_irqsave(&dev->spinlock, irq_flags); 540 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 541 outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); 542 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 543 544 return 0; 545}; 546 547static int das800_detach(struct comedi_device *dev) 548{ 549 printk("comedi%d: das800: remove\n", dev->minor); 550 551 /* only free stuff if it has been allocated by _attach */ 552 if (dev->iobase) 553 release_region(dev->iobase, DAS800_SIZE); 554 if (dev->irq) 555 free_irq(dev->irq, dev); 556 return 0; 557}; 558 559static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 560{ 561 devpriv->forever = 0; 562 devpriv->count = 0; 563 disable_das800(dev); 564 return 0; 565} 566 567/* enable_das800 makes the card start taking hardware triggered conversions */ 568static void enable_das800(struct comedi_device *dev) 569{ 570 unsigned long irq_flags; 571 spin_lock_irqsave(&dev->spinlock, irq_flags); 572 /* enable fifo-half full interrupts for cio-das802/16 */ 573 if (thisboard->resolution == 16) 574 outb(CIO_ENHF, dev->iobase + DAS800_GAIN); 575 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 576 outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL); /* enable hardware triggering */ 577 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 578 outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); /* enable card's interrupt */ 579 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 580} 581 582/* disable_das800 stops hardware triggered conversions */ 583static void disable_das800(struct comedi_device *dev) 584{ 585 unsigned long irq_flags; 586 spin_lock_irqsave(&dev->spinlock, irq_flags); 587 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 588 outb(0x0, dev->iobase + DAS800_CONV_CONTROL); /* disable hardware triggering of conversions */ 589 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 590} 591 592static int das800_ai_do_cmdtest(struct comedi_device *dev, 593 struct comedi_subdevice *s, 594 struct comedi_cmd *cmd) 595{ 596 int err = 0; 597 int tmp; 598 int gain, startChan; 599 int i; 600 601 /* step 1: make sure trigger sources are trivially valid */ 602 603 tmp = cmd->start_src; 604 cmd->start_src &= TRIG_NOW | TRIG_EXT; 605 if (!cmd->start_src || tmp != cmd->start_src) 606 err++; 607 608 tmp = cmd->scan_begin_src; 609 cmd->scan_begin_src &= TRIG_FOLLOW; 610 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 611 err++; 612 613 tmp = cmd->convert_src; 614 cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 615 if (!cmd->convert_src || tmp != cmd->convert_src) 616 err++; 617 618 tmp = cmd->scan_end_src; 619 cmd->scan_end_src &= TRIG_COUNT; 620 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 621 err++; 622 623 tmp = cmd->stop_src; 624 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 625 if (!cmd->stop_src || tmp != cmd->stop_src) 626 err++; 627 628 if (err) 629 return 1; 630 631 /* step 2: make sure trigger sources are unique and mutually compatible */ 632 633 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) 634 err++; 635 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 636 err++; 637 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 638 err++; 639 640 if (err) 641 return 2; 642 643 /* step 3: make sure arguments are trivially compatible */ 644 645 if (cmd->start_arg != 0) { 646 cmd->start_arg = 0; 647 err++; 648 } 649 if (cmd->convert_src == TRIG_TIMER) { 650 if (cmd->convert_arg < thisboard->ai_speed) { 651 cmd->convert_arg = thisboard->ai_speed; 652 err++; 653 } 654 } 655 if (!cmd->chanlist_len) { 656 cmd->chanlist_len = 1; 657 err++; 658 } 659 if (cmd->scan_end_arg != cmd->chanlist_len) { 660 cmd->scan_end_arg = cmd->chanlist_len; 661 err++; 662 } 663 if (cmd->stop_src == TRIG_COUNT) { 664 if (!cmd->stop_arg) { 665 cmd->stop_arg = 1; 666 err++; 667 } 668 } else { /* TRIG_NONE */ 669 if (cmd->stop_arg != 0) { 670 cmd->stop_arg = 0; 671 err++; 672 } 673 } 674 675 if (err) 676 return 3; 677 678 /* step 4: fix up any arguments */ 679 680 if (cmd->convert_src == TRIG_TIMER) { 681 tmp = cmd->convert_arg; 682 /* calculate counter values that give desired timing */ 683 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), 684 &(devpriv->divisor2), 685 &(cmd->convert_arg), 686 cmd->flags & TRIG_ROUND_MASK); 687 if (tmp != cmd->convert_arg) 688 err++; 689 } 690 691 if (err) 692 return 4; 693 694 /* check channel/gain list against card's limitations */ 695 if (cmd->chanlist) { 696 gain = CR_RANGE(cmd->chanlist[0]); 697 startChan = CR_CHAN(cmd->chanlist[0]); 698 for (i = 1; i < cmd->chanlist_len; i++) { 699 if (CR_CHAN(cmd->chanlist[i]) != 700 (startChan + i) % N_CHAN_AI) { 701 comedi_error(dev, 702 "entries in chanlist must be consecutive channels, counting upwards\n"); 703 err++; 704 } 705 if (CR_RANGE(cmd->chanlist[i]) != gain) { 706 comedi_error(dev, 707 "entries in chanlist must all have the same gain\n"); 708 err++; 709 } 710 } 711 } 712 713 if (err) 714 return 5; 715 716 return 0; 717} 718 719static int das800_ai_do_cmd(struct comedi_device *dev, 720 struct comedi_subdevice *s) 721{ 722 int startChan, endChan, scan, gain; 723 int conv_bits; 724 unsigned long irq_flags; 725 struct comedi_async *async = s->async; 726 727 if (!dev->irq) { 728 comedi_error(dev, 729 "no irq assigned for das-800, cannot do hardware conversions"); 730 return -1; 731 } 732 733 disable_das800(dev); 734 735 /* set channel scan limits */ 736 startChan = CR_CHAN(async->cmd.chanlist[0]); 737 endChan = (startChan + async->cmd.chanlist_len - 1) % 8; 738 scan = (endChan << 3) | startChan; 739 740 spin_lock_irqsave(&dev->spinlock, irq_flags); 741 outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN); /* select base address + 2 to be scan limits register */ 742 outb(scan, dev->iobase + DAS800_SCAN_LIMITS); /* set scan limits */ 743 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 744 745 /* set gain */ 746 gain = CR_RANGE(async->cmd.chanlist[0]); 747 if (thisboard->resolution == 12 && gain > 0) 748 gain += 0x7; 749 gain &= 0xf; 750 outb(gain, dev->iobase + DAS800_GAIN); 751 752 switch (async->cmd.stop_src) { 753 case TRIG_COUNT: 754 devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len; 755 devpriv->forever = 0; 756 break; 757 case TRIG_NONE: 758 devpriv->forever = 1; 759 devpriv->count = 0; 760 break; 761 default: 762 break; 763 } 764 765 /* enable auto channel scan, send interrupts on end of conversion 766 * and set clock source to internal or external 767 */ 768 conv_bits = 0; 769 conv_bits |= EACS | IEOC; 770 if (async->cmd.start_src == TRIG_EXT) 771 conv_bits |= DTEN; 772 switch (async->cmd.convert_src) { 773 case TRIG_TIMER: 774 conv_bits |= CASC | ITE; 775 /* set conversion frequency */ 776 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), 777 &(devpriv->divisor2), 778 &(async->cmd.convert_arg), 779 async->cmd. 780 flags & TRIG_ROUND_MASK); 781 if (das800_set_frequency(dev) < 0) { 782 comedi_error(dev, "Error setting up counters"); 783 return -1; 784 } 785 break; 786 case TRIG_EXT: 787 break; 788 default: 789 break; 790 } 791 792 spin_lock_irqsave(&dev->spinlock, irq_flags); 793 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ 794 outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL); 795 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 796 async->events = 0; 797 enable_das800(dev); 798 return 0; 799} 800 801static int das800_ai_rinsn(struct comedi_device *dev, 802 struct comedi_subdevice *s, struct comedi_insn *insn, 803 unsigned int *data) 804{ 805 int i, n; 806 int chan; 807 int range; 808 int lsb, msb; 809 int timeout = 1000; 810 unsigned long irq_flags; 811 812 disable_das800(dev); /* disable hardware conversions (enables software conversions) */ 813 814 /* set multiplexer */ 815 chan = CR_CHAN(insn->chanspec); 816 817 spin_lock_irqsave(&dev->spinlock, irq_flags); 818 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 819 outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); 820 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 821 822 /* set gain / range */ 823 range = CR_RANGE(insn->chanspec); 824 if (thisboard->resolution == 12 && range) 825 range += 0x7; 826 range &= 0xf; 827 outb(range, dev->iobase + DAS800_GAIN); 828 829 udelay(5); 830 831 for (n = 0; n < insn->n; n++) { 832 /* trigger conversion */ 833 outb_p(0, dev->iobase + DAS800_MSB); 834 835 for (i = 0; i < timeout; i++) { 836 if (!(inb(dev->iobase + DAS800_STATUS) & BUSY)) 837 break; 838 } 839 if (i == timeout) { 840 comedi_error(dev, "timeout"); 841 return -ETIME; 842 } 843 lsb = inb(dev->iobase + DAS800_LSB); 844 msb = inb(dev->iobase + DAS800_MSB); 845 if (thisboard->resolution == 12) { 846 data[n] = (lsb >> 4) & 0xff; 847 data[n] |= (msb << 4); 848 } else { 849 data[n] = (msb << 8) | lsb; 850 } 851 } 852 853 return n; 854} 855 856static int das800_di_rbits(struct comedi_device *dev, 857 struct comedi_subdevice *s, struct comedi_insn *insn, 858 unsigned int *data) 859{ 860 unsigned int bits; 861 862 bits = inb(dev->iobase + DAS800_STATUS) >> 4; 863 bits &= 0x7; 864 data[1] = bits; 865 data[0] = 0; 866 867 return 2; 868} 869 870static int das800_do_wbits(struct comedi_device *dev, 871 struct comedi_subdevice *s, struct comedi_insn *insn, 872 unsigned int *data) 873{ 874 int wbits; 875 unsigned long irq_flags; 876 877 /* only set bits that have been masked */ 878 data[0] &= 0xf; 879 wbits = devpriv->do_bits >> 4; 880 wbits &= ~data[0]; 881 wbits |= data[0] & data[1]; 882 devpriv->do_bits = wbits << 4; 883 884 spin_lock_irqsave(&dev->spinlock, irq_flags); 885 outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ 886 outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1); 887 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 888 889 data[1] = wbits; 890 891 return 2; 892} 893 894/* loads counters with divisor1, divisor2 from private structure */ 895static int das800_set_frequency(struct comedi_device *dev) 896{ 897 int err = 0; 898 899 if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2)) 900 err++; 901 if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2)) 902 err++; 903 if (err) 904 return -1; 905 906 return 0; 907} 908