adl_pci9111.c revision 27020ffed9166d65ce1e5b523051d13bfa2329b0
1/* 2 3comedi/drivers/adl_pci9111.c 4 5Hardware driver for PCI9111 ADLink cards: 6 7PCI-9111HR 8 9Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr> 10 11This program is free software; you can redistribute it and/or modify 12it under the terms of the GNU General Public License as published by 13the Free Software Foundation; either version 2 of the License, or 14(at your option) any later version. 15 16This program is distributed in the hope that it will be useful, 17but WITHOUT ANY WARRANTY; without even the implied warranty of 18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19GNU General Public License for more details. 20 21You should have received a copy of the GNU General Public License 22along with this program; if not, write to the Free Software 23Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24*/ 25 26/* 27Driver: adl_pci9111 28Description: Adlink PCI-9111HR 29Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr> 30Devices: [ADLink] PCI-9111HR (adl_pci9111) 31Status: experimental 32 33Supports: 34 35 - ai_insn read 36 - ao_insn read/write 37 - di_insn read 38 - do_insn read/write 39 - ai_do_cmd mode with the following sources: 40 41 - start_src TRIG_NOW 42 - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT 43 - convert_src TRIG_TIMER TRIG_EXT 44 - scan_end_src TRIG_COUNT 45 - stop_src TRIG_COUNT TRIG_NONE 46 47The scanned channels must be consecutive and start from 0. They must 48all have the same range and aref. 49 50Configuration options: not applicable, uses PCI auto config 51*/ 52 53/* 54CHANGELOG: 55 562005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be 57a multiple of chanlist_len*convert_arg. 582002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data. 592002/02/18 Added external trigger support for analog input. 60 61TODO: 62 63 - Really test implemented functionality. 64 - Add support for the PCI-9111DG with a probe routine to identify 65 the card type (perhaps with the help of the channel number readback 66 of the A/D Data register). 67 - Add external multiplexer support. 68 69*/ 70 71#include "../comedidev.h" 72 73#include <linux/delay.h> 74#include <linux/interrupt.h> 75 76#include "8253.h" 77#include "comedi_fc.h" 78 79#define PCI9111_DRIVER_NAME "adl_pci9111" 80#define PCI9111_HR_DEVICE_ID 0x9111 81 82#define PCI9111_FIFO_HALF_SIZE 512 83 84#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000 85 86#define PCI9111_RANGE_SETTING_DELAY 10 87#define PCI9111_AI_INSTANT_READ_UDELAY_US 2 88#define PCI9111_AI_INSTANT_READ_TIMEOUT 100 89 90#define PCI9111_8254_CLOCK_PERIOD_NS 500 91 92/* 93 * IO address map and bit defines 94 */ 95#define PCI9111_AI_FIFO_REG 0x00 96#define PCI9111_AO_REG 0x00 97#define PCI9111_DIO_REG 0x02 98#define PCI9111_EDIO_REG 0x04 99#define PCI9111_AI_CHANNEL_REG 0x06 100#define PCI9111_AI_RANGE_STAT_REG 0x08 101#define PCI9111_AI_STAT_AD_BUSY (1 << 7) 102#define PCI9111_AI_STAT_FF_FF (1 << 6) 103#define PCI9111_AI_STAT_FF_HF (1 << 5) 104#define PCI9111_AI_STAT_FF_EF (1 << 4) 105#define PCI9111_AI_RANGE_MASK (7 << 0) 106#define PCI9111_AI_TRIG_CTRL_REG 0x0a 107#define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5) 108#define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4) 109#define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3) 110#define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2) 111#define PCI9111_AI_TRIG_CTRL_TPST (1 << 1) 112#define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0) 113#define PCI9111_INT_CTRL_REG 0x0c 114#define PCI9111_INT_CTRL_ISC2 (1 << 3) 115#define PCI9111_INT_CTRL_FFEN (1 << 2) 116#define PCI9111_INT_CTRL_ISC1 (1 << 1) 117#define PCI9111_INT_CTRL_ISC0 (1 << 0) 118#define PCI9111_SOFT_TRIG_REG 0x0e 119#define PCI9111_8254_BASE_REG 0x40 120#define PCI9111_INT_CLR_REG 0x48 121 122static const struct comedi_lrange pci9111_ai_range = { 123 5, 124 { 125 BIP_RANGE(10), 126 BIP_RANGE(5), 127 BIP_RANGE(2.5), 128 BIP_RANGE(1.25), 129 BIP_RANGE(0.625) 130 } 131}; 132 133struct pci9111_private_data { 134 unsigned long lcr_io_base; 135 136 int stop_counter; 137 int stop_is_none; 138 139 unsigned int scan_delay; 140 unsigned int chanlist_len; 141 unsigned int chunk_counter; 142 unsigned int chunk_num_samples; 143 144 int ao_readback; 145 146 unsigned int div1; 147 unsigned int div2; 148 149 short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; 150}; 151 152#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c 153 154#define PLX9050_LINTI1_ENABLE (1 << 0) 155#define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1) 156#define PLX9050_LINTI1_STATUS (1 << 2) 157#define PLX9050_LINTI2_ENABLE (1 << 3) 158#define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4) 159#define PLX9050_LINTI2_STATUS (1 << 5) 160#define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6) 161#define PLX9050_SOFTWARE_INTERRUPT (1 << 7) 162 163static void plx9050_interrupt_control(unsigned long io_base, 164 bool LINTi1_enable, 165 bool LINTi1_active_high, 166 bool LINTi2_enable, 167 bool LINTi2_active_high, 168 bool interrupt_enable) 169{ 170 int flags = 0; 171 172 if (LINTi1_enable) 173 flags |= PLX9050_LINTI1_ENABLE; 174 if (LINTi1_active_high) 175 flags |= PLX9050_LINTI1_ACTIVE_HIGH; 176 if (LINTi2_enable) 177 flags |= PLX9050_LINTI2_ENABLE; 178 if (LINTi2_active_high) 179 flags |= PLX9050_LINTI2_ACTIVE_HIGH; 180 181 if (interrupt_enable) 182 flags |= PLX9050_PCI_INTERRUPT_ENABLE; 183 184 outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL); 185} 186 187static void pci9111_timer_set(struct comedi_device *dev) 188{ 189 struct pci9111_private_data *dev_private = dev->private; 190 unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG; 191 192 i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY); 193 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY); 194 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY); 195 196 udelay(1); 197 198 i8254_write(timer_base, 1, 2, dev_private->div2); 199 i8254_write(timer_base, 1, 1, dev_private->div1); 200} 201 202enum pci9111_trigger_sources { 203 software, 204 timer_pacer, 205 external 206}; 207 208static void pci9111_trigger_source_set(struct comedi_device *dev, 209 enum pci9111_trigger_sources source) 210{ 211 int flags; 212 213 /* Read the current trigger mode control bits */ 214 flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); 215 /* Mask off the EITS and TPST bits */ 216 flags &= 0x9; 217 218 switch (source) { 219 case software: 220 break; 221 222 case timer_pacer: 223 flags |= PCI9111_AI_TRIG_CTRL_TPST; 224 break; 225 226 case external: 227 flags |= PCI9111_AI_TRIG_CTRL_ETIS; 228 break; 229 } 230 231 outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); 232} 233 234static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger) 235{ 236 int flags; 237 238 /* Read the current trigger mode control bits */ 239 flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); 240 /* Mask off the PTRG bit */ 241 flags &= 0x7; 242 243 if (pretrigger) 244 flags |= PCI9111_AI_TRIG_CTRL_PTRG; 245 246 outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); 247} 248 249static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan) 250{ 251 int flags; 252 253 /* Read the current trigger mode control bits */ 254 flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); 255 /* Mask off the ASCAN bit */ 256 flags &= 0xe; 257 258 if (autoscan) 259 flags |= PCI9111_AI_TRIG_CTRL_ASCAN; 260 261 outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); 262} 263 264enum pci9111_ISC0_sources { 265 irq_on_eoc, 266 irq_on_fifo_half_full 267}; 268 269enum pci9111_ISC1_sources { 270 irq_on_timer_tick, 271 irq_on_external_trigger 272}; 273 274static void pci9111_interrupt_source_set(struct comedi_device *dev, 275 enum pci9111_ISC0_sources irq_0_source, 276 enum pci9111_ISC1_sources irq_1_source) 277{ 278 int flags; 279 280 /* Read the current interrupt control bits */ 281 flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); 282 /* Shift the bits so they are compatible with the write register */ 283 flags >>= 4; 284 /* Mask off the ISCx bits */ 285 flags &= 0xc0; 286 287 /* Now set the new ISCx bits */ 288 if (irq_0_source == irq_on_fifo_half_full) 289 flags |= PCI9111_INT_CTRL_ISC0; 290 291 if (irq_1_source == irq_on_external_trigger) 292 flags |= PCI9111_INT_CTRL_ISC1; 293 294 outb(flags, dev->iobase + PCI9111_INT_CTRL_REG); 295} 296 297static void pci9111_fifo_reset(struct comedi_device *dev) 298{ 299 unsigned long int_ctrl_reg = dev->iobase + PCI9111_INT_CTRL_REG; 300 301 /* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */ 302 outb(0, int_ctrl_reg); 303 outb(PCI9111_INT_CTRL_FFEN, int_ctrl_reg); 304 outb(0, int_ctrl_reg); 305} 306 307static int pci9111_ai_cancel(struct comedi_device *dev, 308 struct comedi_subdevice *s) 309{ 310 struct pci9111_private_data *dev_private = dev->private; 311 312 /* Disable interrupts */ 313 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, 314 true, false); 315 316 pci9111_trigger_source_set(dev, software); 317 318 pci9111_autoscan_set(dev, false); 319 320 pci9111_fifo_reset(dev); 321 322 return 0; 323} 324 325static int pci9111_ai_do_cmd_test(struct comedi_device *dev, 326 struct comedi_subdevice *s, 327 struct comedi_cmd *cmd) 328{ 329 struct pci9111_private_data *dev_private = dev->private; 330 int tmp; 331 int error = 0; 332 int range, reference; 333 int i; 334 335 /* Step 1 : check if triggers are trivially valid */ 336 337 error |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); 338 error |= cfc_check_trigger_src(&cmd->scan_begin_src, 339 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); 340 error |= cfc_check_trigger_src(&cmd->convert_src, 341 TRIG_TIMER | TRIG_EXT); 342 error |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 343 error |= cfc_check_trigger_src(&cmd->stop_src, 344 TRIG_COUNT | TRIG_NONE); 345 346 if (error) 347 return 1; 348 349 /* Step 2a : make sure trigger sources are unique */ 350 351 error |= cfc_check_trigger_is_unique(cmd->scan_begin_src); 352 error |= cfc_check_trigger_is_unique(cmd->convert_src); 353 error |= cfc_check_trigger_is_unique(cmd->stop_src); 354 355 /* Step 2b : and mutually compatible */ 356 357 if ((cmd->convert_src == TRIG_TIMER) && 358 !((cmd->scan_begin_src == TRIG_TIMER) || 359 (cmd->scan_begin_src == TRIG_FOLLOW))) 360 error |= -EINVAL; 361 if ((cmd->convert_src == TRIG_EXT) && 362 !((cmd->scan_begin_src == TRIG_EXT) || 363 (cmd->scan_begin_src == TRIG_FOLLOW))) 364 error |= -EINVAL; 365 366 if (error) 367 return 2; 368 369 /* Step 3 : make sure arguments are trivialy compatible */ 370 371 if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) { 372 cmd->start_arg = 0; 373 error++; 374 } 375 376 if ((cmd->convert_src == TRIG_TIMER) && 377 (cmd->convert_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) { 378 cmd->convert_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS; 379 error++; 380 } 381 if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) { 382 cmd->convert_arg = 0; 383 error++; 384 } 385 386 if ((cmd->scan_begin_src == TRIG_TIMER) && 387 (cmd->scan_begin_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) { 388 cmd->scan_begin_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS; 389 error++; 390 } 391 if ((cmd->scan_begin_src == TRIG_FOLLOW) 392 && (cmd->scan_begin_arg != 0)) { 393 cmd->scan_begin_arg = 0; 394 error++; 395 } 396 if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) { 397 cmd->scan_begin_arg = 0; 398 error++; 399 } 400 401 if ((cmd->scan_end_src == TRIG_COUNT) && 402 (cmd->scan_end_arg != cmd->chanlist_len)) { 403 cmd->scan_end_arg = cmd->chanlist_len; 404 error++; 405 } 406 407 if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) { 408 cmd->stop_arg = 1; 409 error++; 410 } 411 if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) { 412 cmd->stop_arg = 0; 413 error++; 414 } 415 416 if (error) 417 return 3; 418 419 /* Step 4 : fix up any arguments */ 420 421 if (cmd->convert_src == TRIG_TIMER) { 422 tmp = cmd->convert_arg; 423 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, 424 &dev_private->div1, 425 &dev_private->div2, 426 &cmd->convert_arg, 427 cmd->flags & TRIG_ROUND_MASK); 428 if (tmp != cmd->convert_arg) 429 error++; 430 } 431 /* There's only one timer on this card, so the scan_begin timer must */ 432 /* be a multiple of chanlist_len*convert_arg */ 433 434 if (cmd->scan_begin_src == TRIG_TIMER) { 435 436 unsigned int scan_begin_min; 437 unsigned int scan_begin_arg; 438 unsigned int scan_factor; 439 440 scan_begin_min = cmd->chanlist_len * cmd->convert_arg; 441 442 if (cmd->scan_begin_arg != scan_begin_min) { 443 if (scan_begin_min < cmd->scan_begin_arg) { 444 scan_factor = 445 cmd->scan_begin_arg / scan_begin_min; 446 scan_begin_arg = scan_factor * scan_begin_min; 447 if (cmd->scan_begin_arg != scan_begin_arg) { 448 cmd->scan_begin_arg = scan_begin_arg; 449 error++; 450 } 451 } else { 452 cmd->scan_begin_arg = scan_begin_min; 453 error++; 454 } 455 } 456 } 457 458 if (error) 459 return 4; 460 461 /* Step 5 : check channel list */ 462 463 if (cmd->chanlist) { 464 465 range = CR_RANGE(cmd->chanlist[0]); 466 reference = CR_AREF(cmd->chanlist[0]); 467 468 if (cmd->chanlist_len > 1) { 469 for (i = 0; i < cmd->chanlist_len; i++) { 470 if (CR_CHAN(cmd->chanlist[i]) != i) { 471 comedi_error(dev, 472 "entries in chanlist must be consecutive " 473 "channels,counting upwards from 0\n"); 474 error++; 475 } 476 if (CR_RANGE(cmd->chanlist[i]) != range) { 477 comedi_error(dev, 478 "entries in chanlist must all have the same gain\n"); 479 error++; 480 } 481 if (CR_AREF(cmd->chanlist[i]) != reference) { 482 comedi_error(dev, 483 "entries in chanlist must all have the same reference\n"); 484 error++; 485 } 486 } 487 } 488 } 489 490 if (error) 491 return 5; 492 493 return 0; 494 495} 496 497static int pci9111_ai_do_cmd(struct comedi_device *dev, 498 struct comedi_subdevice *s) 499{ 500 struct pci9111_private_data *dev_private = dev->private; 501 struct comedi_cmd *async_cmd = &s->async->cmd; 502 503 if (!dev->irq) { 504 comedi_error(dev, 505 "no irq assigned for PCI9111, cannot do hardware conversion"); 506 return -1; 507 } 508 /* Set channel scan limit */ 509 /* PCI9111 allows only scanning from channel 0 to channel n */ 510 /* TODO: handle the case of an external multiplexer */ 511 512 if (async_cmd->chanlist_len > 1) { 513 outb(async_cmd->chanlist_len - 1, 514 dev->iobase + PCI9111_AI_CHANNEL_REG); 515 pci9111_autoscan_set(dev, true); 516 } else { 517 outb(CR_CHAN(async_cmd->chanlist[0]), 518 dev->iobase + PCI9111_AI_CHANNEL_REG); 519 pci9111_autoscan_set(dev, false); 520 } 521 522 /* Set gain */ 523 /* This is the same gain on every channel */ 524 525 outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, 526 dev->iobase + PCI9111_AI_RANGE_STAT_REG); 527 528 /* Set counter */ 529 530 switch (async_cmd->stop_src) { 531 case TRIG_COUNT: 532 dev_private->stop_counter = 533 async_cmd->stop_arg * async_cmd->chanlist_len; 534 dev_private->stop_is_none = 0; 535 break; 536 537 case TRIG_NONE: 538 dev_private->stop_counter = 0; 539 dev_private->stop_is_none = 1; 540 break; 541 542 default: 543 comedi_error(dev, "Invalid stop trigger"); 544 return -1; 545 } 546 547 /* Set timer pacer */ 548 549 dev_private->scan_delay = 0; 550 switch (async_cmd->convert_src) { 551 case TRIG_TIMER: 552 pci9111_trigger_source_set(dev, software); 553 pci9111_timer_set(dev); 554 pci9111_fifo_reset(dev); 555 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, 556 irq_on_timer_tick); 557 pci9111_trigger_source_set(dev, timer_pacer); 558 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, 559 false, true, true); 560 561 if (async_cmd->scan_begin_src == TRIG_TIMER) { 562 dev_private->scan_delay = 563 (async_cmd->scan_begin_arg / 564 (async_cmd->convert_arg * 565 async_cmd->chanlist_len)) - 1; 566 } 567 568 break; 569 570 case TRIG_EXT: 571 572 pci9111_trigger_source_set(dev, external); 573 pci9111_fifo_reset(dev); 574 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, 575 irq_on_timer_tick); 576 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, 577 false, true, true); 578 579 break; 580 581 default: 582 comedi_error(dev, "Invalid convert trigger"); 583 return -1; 584 } 585 586 dev_private->stop_counter *= (1 + dev_private->scan_delay); 587 dev_private->chanlist_len = async_cmd->chanlist_len; 588 dev_private->chunk_counter = 0; 589 dev_private->chunk_num_samples = 590 dev_private->chanlist_len * (1 + dev_private->scan_delay); 591 592 return 0; 593} 594 595static void pci9111_ai_munge(struct comedi_device *dev, 596 struct comedi_subdevice *s, void *data, 597 unsigned int num_bytes, 598 unsigned int start_chan_index) 599{ 600 short *array = data; 601 unsigned int maxdata = s->maxdata; 602 unsigned int invert = (maxdata + 1) >> 1; 603 unsigned int shift = (maxdata == 0xffff) ? 0 : 4; 604 unsigned int num_samples = num_bytes / sizeof(short); 605 unsigned int i; 606 607 for (i = 0; i < num_samples; i++) 608 array[i] = ((array[i] >> shift) & maxdata) ^ invert; 609} 610 611static irqreturn_t pci9111_interrupt(int irq, void *p_device) 612{ 613 struct comedi_device *dev = p_device; 614 struct pci9111_private_data *dev_private = dev->private; 615 struct comedi_subdevice *s = dev->read_subdev; 616 struct comedi_async *async; 617 unsigned int status; 618 unsigned long irq_flags; 619 unsigned char intcsr; 620 621 if (!dev->attached) { 622 /* Ignore interrupt before device fully attached. */ 623 /* Might not even have allocated subdevices yet! */ 624 return IRQ_NONE; 625 } 626 627 async = s->async; 628 629 spin_lock_irqsave(&dev->spinlock, irq_flags); 630 631 /* Check if we are source of interrupt */ 632 intcsr = inb(dev_private->lcr_io_base + 633 PLX9050_REGISTER_INTERRUPT_CONTROL); 634 if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0) 635 && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) 636 == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) 637 || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS)) 638 == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) { 639 /* Not the source of the interrupt. */ 640 /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */ 641 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 642 return IRQ_NONE; 643 } 644 645 if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) == 646 (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) { 647 /* Interrupt comes from fifo_half-full signal */ 648 649 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); 650 651 /* '0' means FIFO is full, data may have been lost */ 652 if (!(status & PCI9111_AI_STAT_FF_FF)) { 653 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 654 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); 655 outb(0, dev->iobase + PCI9111_INT_CLR_REG); 656 pci9111_ai_cancel(dev, s); 657 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 658 comedi_event(dev, s); 659 660 return IRQ_HANDLED; 661 } 662 663 /* '0' means FIFO is half-full */ 664 if (!(status & PCI9111_AI_STAT_FF_HF)) { 665 unsigned int num_samples; 666 unsigned int bytes_written = 0; 667 668 num_samples = 669 PCI9111_FIFO_HALF_SIZE > 670 dev_private->stop_counter 671 && !dev_private-> 672 stop_is_none ? dev_private->stop_counter : 673 PCI9111_FIFO_HALF_SIZE; 674 insw(dev->iobase + PCI9111_AI_FIFO_REG, 675 dev_private->ai_bounce_buffer, num_samples); 676 677 if (dev_private->scan_delay < 1) { 678 bytes_written = 679 cfc_write_array_to_buffer(s, 680 dev_private-> 681 ai_bounce_buffer, 682 num_samples * 683 sizeof(short)); 684 } else { 685 int position = 0; 686 int to_read; 687 688 while (position < num_samples) { 689 if (dev_private->chunk_counter < 690 dev_private->chanlist_len) { 691 to_read = 692 dev_private->chanlist_len - 693 dev_private->chunk_counter; 694 695 if (to_read > 696 num_samples - position) 697 to_read = 698 num_samples - 699 position; 700 701 bytes_written += 702 cfc_write_array_to_buffer 703 (s, 704 dev_private->ai_bounce_buffer 705 + position, 706 to_read * sizeof(short)); 707 } else { 708 to_read = 709 dev_private->chunk_num_samples 710 - 711 dev_private->chunk_counter; 712 if (to_read > 713 num_samples - position) 714 to_read = 715 num_samples - 716 position; 717 718 bytes_written += 719 sizeof(short) * to_read; 720 } 721 722 position += to_read; 723 dev_private->chunk_counter += to_read; 724 725 if (dev_private->chunk_counter >= 726 dev_private->chunk_num_samples) 727 dev_private->chunk_counter = 0; 728 } 729 } 730 731 dev_private->stop_counter -= 732 bytes_written / sizeof(short); 733 } 734 } 735 736 if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) { 737 async->events |= COMEDI_CB_EOA; 738 pci9111_ai_cancel(dev, s); 739 } 740 741 outb(0, dev->iobase + PCI9111_INT_CLR_REG); 742 743 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 744 745 comedi_event(dev, s); 746 747 return IRQ_HANDLED; 748} 749 750static int pci9111_ai_insn_read(struct comedi_device *dev, 751 struct comedi_subdevice *s, 752 struct comedi_insn *insn, unsigned int *data) 753{ 754 unsigned int chan = CR_CHAN(insn->chanspec); 755 unsigned int range = CR_RANGE(insn->chanspec); 756 unsigned int maxdata = s->maxdata; 757 unsigned int invert = (maxdata + 1) >> 1; 758 unsigned int shift = (maxdata == 0xffff) ? 0 : 4; 759 unsigned int status; 760 int timeout; 761 int i; 762 763 outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG); 764 765 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); 766 if ((status & PCI9111_AI_RANGE_MASK) != range) { 767 outb(range & PCI9111_AI_RANGE_MASK, 768 dev->iobase + PCI9111_AI_RANGE_STAT_REG); 769 } 770 771 pci9111_fifo_reset(dev); 772 773 for (i = 0; i < insn->n; i++) { 774 /* Generate a software trigger */ 775 outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG); 776 777 timeout = PCI9111_AI_INSTANT_READ_TIMEOUT; 778 779 while (timeout--) { 780 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); 781 /* '1' means FIFO is not empty */ 782 if (status & PCI9111_AI_STAT_FF_EF) 783 goto conversion_done; 784 } 785 786 comedi_error(dev, "A/D read timeout"); 787 data[i] = 0; 788 pci9111_fifo_reset(dev); 789 return -ETIME; 790 791conversion_done: 792 793 data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG); 794 data[i] = ((data[i] >> shift) & maxdata) ^ invert; 795 } 796 797 return i; 798} 799 800static int pci9111_ao_insn_write(struct comedi_device *dev, 801 struct comedi_subdevice *s, 802 struct comedi_insn *insn, 803 unsigned int *data) 804{ 805 struct pci9111_private_data *dev_private = dev->private; 806 unsigned int val = 0; 807 int i; 808 809 for (i = 0; i < insn->n; i++) { 810 val = data[i]; 811 outw(val, dev->iobase + PCI9111_AO_REG); 812 } 813 dev_private->ao_readback = val; 814 815 return insn->n; 816} 817 818static int pci9111_ao_insn_read(struct comedi_device *dev, 819 struct comedi_subdevice *s, 820 struct comedi_insn *insn, 821 unsigned int *data) 822{ 823 struct pci9111_private_data *dev_private = dev->private; 824 int i; 825 826 for (i = 0; i < insn->n; i++) 827 data[i] = dev_private->ao_readback; 828 829 return insn->n; 830} 831 832static int pci9111_di_insn_bits(struct comedi_device *dev, 833 struct comedi_subdevice *s, 834 struct comedi_insn *insn, 835 unsigned int *data) 836{ 837 data[1] = inw(dev->iobase + PCI9111_DIO_REG); 838 839 return insn->n; 840} 841 842static int pci9111_do_insn_bits(struct comedi_device *dev, 843 struct comedi_subdevice *s, 844 struct comedi_insn *insn, 845 unsigned int *data) 846{ 847 unsigned int mask = data[0]; 848 unsigned int bits = data[1]; 849 850 if (mask) { 851 s->state &= ~mask; 852 s->state |= (bits & mask); 853 854 outw(s->state, dev->iobase + PCI9111_DIO_REG); 855 } 856 857 data[1] = s->state; 858 859 return insn->n; 860} 861 862static int pci9111_reset(struct comedi_device *dev) 863{ 864 struct pci9111_private_data *dev_private = dev->private; 865 866 /* Set trigger source to software */ 867 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, 868 true, false); 869 870 pci9111_trigger_source_set(dev, software); 871 pci9111_pretrigger_set(dev, false); 872 pci9111_autoscan_set(dev, false); 873 874 /* Reset 8254 chip */ 875 dev_private->div1 = 0; 876 dev_private->div2 = 0; 877 pci9111_timer_set(dev); 878 879 return 0; 880} 881 882static int pci9111_attach_pci(struct comedi_device *dev, 883 struct pci_dev *pcidev) 884{ 885 struct pci9111_private_data *dev_private; 886 struct comedi_subdevice *s; 887 int ret; 888 889 comedi_set_hw_dev(dev, &pcidev->dev); 890 dev->board_name = dev->driver->driver_name; 891 892 ret = alloc_private(dev, sizeof(*dev_private)); 893 if (ret) 894 return ret; 895 dev_private = dev->private; 896 897 ret = comedi_pci_enable(pcidev, dev->board_name); 898 if (ret) 899 return ret; 900 dev_private->lcr_io_base = pci_resource_start(pcidev, 1); 901 dev->iobase = pci_resource_start(pcidev, 2); 902 903 pci9111_reset(dev); 904 905 if (pcidev->irq > 0) { 906 ret = request_irq(dev->irq, pci9111_interrupt, 907 IRQF_SHARED, dev->board_name, dev); 908 if (ret) 909 return ret; 910 dev->irq = pcidev->irq; 911 } 912 913 ret = comedi_alloc_subdevices(dev, 4); 914 if (ret) 915 return ret; 916 917 s = &dev->subdevices[0]; 918 dev->read_subdev = s; 919 s->type = COMEDI_SUBD_AI; 920 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; 921 s->n_chan = 16; 922 s->maxdata = 0xffff; 923 s->len_chanlist = 16; 924 s->range_table = &pci9111_ai_range; 925 s->cancel = pci9111_ai_cancel; 926 s->insn_read = pci9111_ai_insn_read; 927 s->do_cmdtest = pci9111_ai_do_cmd_test; 928 s->do_cmd = pci9111_ai_do_cmd; 929 s->munge = pci9111_ai_munge; 930 931 s = &dev->subdevices[1]; 932 s->type = COMEDI_SUBD_AO; 933 s->subdev_flags = SDF_WRITABLE | SDF_COMMON; 934 s->n_chan = 1; 935 s->maxdata = 0x0fff; 936 s->len_chanlist = 1; 937 s->range_table = &range_bipolar10; 938 s->insn_write = pci9111_ao_insn_write; 939 s->insn_read = pci9111_ao_insn_read; 940 941 s = &dev->subdevices[2]; 942 s->type = COMEDI_SUBD_DI; 943 s->subdev_flags = SDF_READABLE; 944 s->n_chan = 16; 945 s->maxdata = 1; 946 s->range_table = &range_digital; 947 s->insn_bits = pci9111_di_insn_bits; 948 949 s = &dev->subdevices[3]; 950 s->type = COMEDI_SUBD_DO; 951 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 952 s->n_chan = 16; 953 s->maxdata = 1; 954 s->range_table = &range_digital; 955 s->insn_bits = pci9111_do_insn_bits; 956 957 dev_info(dev->class_dev, "%s attached\n", dev->board_name); 958 959 return 0; 960} 961 962static void pci9111_detach(struct comedi_device *dev) 963{ 964 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 965 966 if (dev->iobase) 967 pci9111_reset(dev); 968 if (dev->irq != 0) 969 free_irq(dev->irq, dev); 970 if (pcidev) { 971 if (dev->iobase) 972 comedi_pci_disable(pcidev); 973 } 974} 975 976static struct comedi_driver adl_pci9111_driver = { 977 .driver_name = "adl_pci9111", 978 .module = THIS_MODULE, 979 .attach_pci = pci9111_attach_pci, 980 .detach = pci9111_detach, 981}; 982 983static int __devinit pci9111_pci_probe(struct pci_dev *dev, 984 const struct pci_device_id *ent) 985{ 986 return comedi_pci_auto_config(dev, &adl_pci9111_driver); 987} 988 989static void __devexit pci9111_pci_remove(struct pci_dev *dev) 990{ 991 comedi_pci_auto_unconfig(dev); 992} 993 994static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = { 995 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, 996 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ 997 { 0 } 998}; 999MODULE_DEVICE_TABLE(pci, pci9111_pci_table); 1000 1001static struct pci_driver adl_pci9111_pci_driver = { 1002 .name = "adl_pci9111", 1003 .id_table = pci9111_pci_table, 1004 .probe = pci9111_pci_probe, 1005 .remove = __devexit_p(pci9111_pci_remove), 1006}; 1007module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver); 1008 1009MODULE_AUTHOR("Comedi http://www.comedi.org"); 1010MODULE_DESCRIPTION("Comedi low-level driver"); 1011MODULE_LICENSE("GPL"); 1012