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