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