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