adl_pci9111.c revision c50a39824d350c3f9c3ba5edc2ffdf0b3b743cb7
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_check_chanlist(struct comedi_device *dev, 318 struct comedi_subdevice *s, 319 struct comedi_cmd *cmd) 320{ 321 unsigned int range0 = CR_RANGE(cmd->chanlist[0]); 322 unsigned int aref0 = CR_AREF(cmd->chanlist[0]); 323 int i; 324 325 for (i = 1; i < cmd->chanlist_len; i++) { 326 unsigned int chan = CR_CHAN(cmd->chanlist[i]); 327 unsigned int range = CR_RANGE(cmd->chanlist[i]); 328 unsigned int aref = CR_AREF(cmd->chanlist[i]); 329 330 if (chan != i) { 331 dev_dbg(dev->class_dev, 332 "entries in chanlist must be consecutive channels,counting upwards from 0\n"); 333 return -EINVAL; 334 } 335 336 if (range != range0) { 337 dev_dbg(dev->class_dev, 338 "entries in chanlist must all have the same gain\n"); 339 return -EINVAL; 340 } 341 342 if (aref != aref0) { 343 dev_dbg(dev->class_dev, 344 "entries in chanlist must all have the same reference\n"); 345 return -EINVAL; 346 } 347 } 348 349 return 0; 350} 351 352static int pci9111_ai_do_cmd_test(struct comedi_device *dev, 353 struct comedi_subdevice *s, 354 struct comedi_cmd *cmd) 355{ 356 struct pci9111_private_data *dev_private = dev->private; 357 int err = 0; 358 int tmp; 359 360 /* Step 1 : check if triggers are trivially valid */ 361 362 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); 363 err |= cfc_check_trigger_src(&cmd->scan_begin_src, 364 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); 365 err |= cfc_check_trigger_src(&cmd->convert_src, 366 TRIG_TIMER | TRIG_EXT); 367 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 368 err |= cfc_check_trigger_src(&cmd->stop_src, 369 TRIG_COUNT | TRIG_NONE); 370 371 if (err) 372 return 1; 373 374 /* Step 2a : make sure trigger sources are unique */ 375 376 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); 377 err |= cfc_check_trigger_is_unique(cmd->convert_src); 378 err |= cfc_check_trigger_is_unique(cmd->stop_src); 379 380 /* Step 2b : and mutually compatible */ 381 382 if ((cmd->convert_src == TRIG_TIMER) && 383 !((cmd->scan_begin_src == TRIG_TIMER) || 384 (cmd->scan_begin_src == TRIG_FOLLOW))) 385 err |= -EINVAL; 386 if ((cmd->convert_src == TRIG_EXT) && 387 !((cmd->scan_begin_src == TRIG_EXT) || 388 (cmd->scan_begin_src == TRIG_FOLLOW))) 389 err |= -EINVAL; 390 391 if (err) 392 return 2; 393 394 /* Step 3: check if arguments are trivially valid */ 395 396 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 397 398 if (cmd->convert_src == TRIG_TIMER) 399 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 400 PCI9111_AI_ACQUISITION_PERIOD_MIN_NS); 401 else /* TRIG_EXT */ 402 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); 403 404 if (cmd->scan_begin_src == TRIG_TIMER) 405 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 406 PCI9111_AI_ACQUISITION_PERIOD_MIN_NS); 407 else /* TRIG_FOLLOW || TRIG_EXT */ 408 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 409 410 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 411 412 if (cmd->stop_src == TRIG_COUNT) 413 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); 414 else /* TRIG_NONE */ 415 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 416 417 if (err) 418 return 3; 419 420 /* Step 4 : fix up any arguments */ 421 422 if (cmd->convert_src == TRIG_TIMER) { 423 tmp = cmd->convert_arg; 424 i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, 425 &dev_private->div1, 426 &dev_private->div2, 427 &cmd->convert_arg, cmd->flags); 428 if (tmp != cmd->convert_arg) 429 err |= -EINVAL; 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 err |= -EINVAL; 450 } 451 } else { 452 cmd->scan_begin_arg = scan_begin_min; 453 err |= -EINVAL; 454 } 455 } 456 } 457 458 if (err) 459 return 4; 460 461 /* Step 5: check channel list if it exists */ 462 if (cmd->chanlist && cmd->chanlist_len > 0) 463 err |= pci9111_ai_check_chanlist(dev, s, cmd); 464 465 if (err) 466 return 5; 467 468 return 0; 469 470} 471 472static int pci9111_ai_do_cmd(struct comedi_device *dev, 473 struct comedi_subdevice *s) 474{ 475 struct pci9111_private_data *dev_private = dev->private; 476 struct comedi_cmd *async_cmd = &s->async->cmd; 477 478 /* Set channel scan limit */ 479 /* PCI9111 allows only scanning from channel 0 to channel n */ 480 /* TODO: handle the case of an external multiplexer */ 481 482 if (async_cmd->chanlist_len > 1) { 483 outb(async_cmd->chanlist_len - 1, 484 dev->iobase + PCI9111_AI_CHANNEL_REG); 485 pci9111_autoscan_set(dev, true); 486 } else { 487 outb(CR_CHAN(async_cmd->chanlist[0]), 488 dev->iobase + PCI9111_AI_CHANNEL_REG); 489 pci9111_autoscan_set(dev, false); 490 } 491 492 /* Set gain */ 493 /* This is the same gain on every channel */ 494 495 outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, 496 dev->iobase + PCI9111_AI_RANGE_STAT_REG); 497 498 /* Set counter */ 499 if (async_cmd->stop_src == TRIG_COUNT) { 500 dev_private->stop_counter = 501 async_cmd->stop_arg * async_cmd->chanlist_len; 502 dev_private->stop_is_none = 0; 503 } else { /* TRIG_NONE */ 504 dev_private->stop_counter = 0; 505 dev_private->stop_is_none = 1; 506 } 507 508 /* Set timer pacer */ 509 dev_private->scan_delay = 0; 510 if (async_cmd->convert_src == TRIG_TIMER) { 511 pci9111_trigger_source_set(dev, software); 512 pci9111_timer_set(dev); 513 pci9111_fifo_reset(dev); 514 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, 515 irq_on_timer_tick); 516 pci9111_trigger_source_set(dev, timer_pacer); 517 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, 518 false, true, true); 519 520 if (async_cmd->scan_begin_src == TRIG_TIMER) { 521 dev_private->scan_delay = 522 (async_cmd->scan_begin_arg / 523 (async_cmd->convert_arg * 524 async_cmd->chanlist_len)) - 1; 525 } 526 } else { /* TRIG_EXT */ 527 pci9111_trigger_source_set(dev, external); 528 pci9111_fifo_reset(dev); 529 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, 530 irq_on_timer_tick); 531 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, 532 false, true, true); 533 534 } 535 536 dev_private->stop_counter *= (1 + dev_private->scan_delay); 537 dev_private->chanlist_len = async_cmd->chanlist_len; 538 dev_private->chunk_counter = 0; 539 dev_private->chunk_num_samples = 540 dev_private->chanlist_len * (1 + dev_private->scan_delay); 541 542 return 0; 543} 544 545static void pci9111_ai_munge(struct comedi_device *dev, 546 struct comedi_subdevice *s, void *data, 547 unsigned int num_bytes, 548 unsigned int start_chan_index) 549{ 550 unsigned short *array = data; 551 unsigned int maxdata = s->maxdata; 552 unsigned int invert = (maxdata + 1) >> 1; 553 unsigned int shift = (maxdata == 0xffff) ? 0 : 4; 554 unsigned int num_samples = num_bytes / sizeof(short); 555 unsigned int i; 556 557 for (i = 0; i < num_samples; i++) 558 array[i] = ((array[i] >> shift) & maxdata) ^ invert; 559} 560 561static irqreturn_t pci9111_interrupt(int irq, void *p_device) 562{ 563 struct comedi_device *dev = p_device; 564 struct pci9111_private_data *dev_private = dev->private; 565 struct comedi_subdevice *s = dev->read_subdev; 566 struct comedi_async *async; 567 unsigned int status; 568 unsigned long irq_flags; 569 unsigned char intcsr; 570 571 if (!dev->attached) { 572 /* Ignore interrupt before device fully attached. */ 573 /* Might not even have allocated subdevices yet! */ 574 return IRQ_NONE; 575 } 576 577 async = s->async; 578 579 spin_lock_irqsave(&dev->spinlock, irq_flags); 580 581 /* Check if we are source of interrupt */ 582 intcsr = inb(dev_private->lcr_io_base + PLX9052_INTCSR); 583 if (!(((intcsr & PLX9052_INTCSR_PCIENAB) != 0) && 584 (((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) || 585 ((intcsr & PCI9111_LI2_ACTIVE) == PCI9111_LI2_ACTIVE)))) { 586 /* Not the source of the interrupt. */ 587 /* (N.B. not using PLX9052_INTCSR_SOFTINT) */ 588 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 589 return IRQ_NONE; 590 } 591 592 if ((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) { 593 /* Interrupt comes from fifo_half-full signal */ 594 595 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); 596 597 /* '0' means FIFO is full, data may have been lost */ 598 if (!(status & PCI9111_AI_STAT_FF_FF)) { 599 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 600 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); 601 outb(0, dev->iobase + PCI9111_INT_CLR_REG); 602 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 603 cfc_handle_events(dev, s); 604 605 return IRQ_HANDLED; 606 } 607 608 /* '0' means FIFO is half-full */ 609 if (!(status & PCI9111_AI_STAT_FF_HF)) { 610 unsigned int num_samples; 611 unsigned int bytes_written = 0; 612 613 num_samples = 614 PCI9111_FIFO_HALF_SIZE > 615 dev_private->stop_counter 616 && !dev_private-> 617 stop_is_none ? dev_private->stop_counter : 618 PCI9111_FIFO_HALF_SIZE; 619 insw(dev->iobase + PCI9111_AI_FIFO_REG, 620 dev_private->ai_bounce_buffer, num_samples); 621 622 if (dev_private->scan_delay < 1) { 623 bytes_written = 624 cfc_write_array_to_buffer(s, 625 dev_private-> 626 ai_bounce_buffer, 627 num_samples * 628 sizeof(short)); 629 } else { 630 int position = 0; 631 int to_read; 632 633 while (position < num_samples) { 634 if (dev_private->chunk_counter < 635 dev_private->chanlist_len) { 636 to_read = 637 dev_private->chanlist_len - 638 dev_private->chunk_counter; 639 640 if (to_read > 641 num_samples - position) 642 to_read = 643 num_samples - 644 position; 645 646 bytes_written += 647 cfc_write_array_to_buffer 648 (s, 649 dev_private->ai_bounce_buffer 650 + position, 651 to_read * sizeof(short)); 652 } else { 653 to_read = 654 dev_private->chunk_num_samples 655 - 656 dev_private->chunk_counter; 657 if (to_read > 658 num_samples - position) 659 to_read = 660 num_samples - 661 position; 662 663 bytes_written += 664 sizeof(short) * to_read; 665 } 666 667 position += to_read; 668 dev_private->chunk_counter += to_read; 669 670 if (dev_private->chunk_counter >= 671 dev_private->chunk_num_samples) 672 dev_private->chunk_counter = 0; 673 } 674 } 675 676 dev_private->stop_counter -= 677 bytes_written / sizeof(short); 678 } 679 } 680 681 if (dev_private->stop_counter == 0 && !dev_private->stop_is_none) 682 async->events |= COMEDI_CB_EOA; 683 684 outb(0, dev->iobase + PCI9111_INT_CLR_REG); 685 686 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 687 688 cfc_handle_events(dev, s); 689 690 return IRQ_HANDLED; 691} 692 693static int pci9111_ai_eoc(struct comedi_device *dev, 694 struct comedi_subdevice *s, 695 struct comedi_insn *insn, 696 unsigned long context) 697{ 698 unsigned int status; 699 700 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); 701 if (status & PCI9111_AI_STAT_FF_EF) 702 return 0; 703 return -EBUSY; 704} 705 706static int pci9111_ai_insn_read(struct comedi_device *dev, 707 struct comedi_subdevice *s, 708 struct comedi_insn *insn, unsigned int *data) 709{ 710 unsigned int chan = CR_CHAN(insn->chanspec); 711 unsigned int range = CR_RANGE(insn->chanspec); 712 unsigned int maxdata = s->maxdata; 713 unsigned int invert = (maxdata + 1) >> 1; 714 unsigned int shift = (maxdata == 0xffff) ? 0 : 4; 715 unsigned int status; 716 int ret; 717 int i; 718 719 outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG); 720 721 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); 722 if ((status & PCI9111_AI_RANGE_MASK) != range) { 723 outb(range & PCI9111_AI_RANGE_MASK, 724 dev->iobase + PCI9111_AI_RANGE_STAT_REG); 725 } 726 727 pci9111_fifo_reset(dev); 728 729 for (i = 0; i < insn->n; i++) { 730 /* Generate a software trigger */ 731 outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG); 732 733 ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0); 734 if (ret) { 735 pci9111_fifo_reset(dev); 736 return ret; 737 } 738 739 data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG); 740 data[i] = ((data[i] >> shift) & maxdata) ^ invert; 741 } 742 743 return i; 744} 745 746static int pci9111_ao_insn_write(struct comedi_device *dev, 747 struct comedi_subdevice *s, 748 struct comedi_insn *insn, 749 unsigned int *data) 750{ 751 struct pci9111_private_data *dev_private = dev->private; 752 unsigned int val = 0; 753 int i; 754 755 for (i = 0; i < insn->n; i++) { 756 val = data[i]; 757 outw(val, dev->iobase + PCI9111_AO_REG); 758 } 759 dev_private->ao_readback = val; 760 761 return insn->n; 762} 763 764static int pci9111_ao_insn_read(struct comedi_device *dev, 765 struct comedi_subdevice *s, 766 struct comedi_insn *insn, 767 unsigned int *data) 768{ 769 struct pci9111_private_data *dev_private = dev->private; 770 int i; 771 772 for (i = 0; i < insn->n; i++) 773 data[i] = dev_private->ao_readback; 774 775 return insn->n; 776} 777 778static int pci9111_di_insn_bits(struct comedi_device *dev, 779 struct comedi_subdevice *s, 780 struct comedi_insn *insn, 781 unsigned int *data) 782{ 783 data[1] = inw(dev->iobase + PCI9111_DIO_REG); 784 785 return insn->n; 786} 787 788static int pci9111_do_insn_bits(struct comedi_device *dev, 789 struct comedi_subdevice *s, 790 struct comedi_insn *insn, 791 unsigned int *data) 792{ 793 if (comedi_dio_update_state(s, data)) 794 outw(s->state, dev->iobase + PCI9111_DIO_REG); 795 796 data[1] = s->state; 797 798 return insn->n; 799} 800 801static int pci9111_reset(struct comedi_device *dev) 802{ 803 struct pci9111_private_data *dev_private = dev->private; 804 805 /* Set trigger source to software */ 806 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, 807 true, false); 808 809 pci9111_trigger_source_set(dev, software); 810 pci9111_pretrigger_set(dev, false); 811 pci9111_autoscan_set(dev, false); 812 813 /* Reset 8254 chip */ 814 dev_private->div1 = 0; 815 dev_private->div2 = 0; 816 pci9111_timer_set(dev); 817 818 return 0; 819} 820 821static int pci9111_auto_attach(struct comedi_device *dev, 822 unsigned long context_unused) 823{ 824 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 825 struct pci9111_private_data *dev_private; 826 struct comedi_subdevice *s; 827 int ret; 828 829 dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private)); 830 if (!dev_private) 831 return -ENOMEM; 832 833 ret = comedi_pci_enable(dev); 834 if (ret) 835 return ret; 836 dev_private->lcr_io_base = pci_resource_start(pcidev, 1); 837 dev->iobase = pci_resource_start(pcidev, 2); 838 839 pci9111_reset(dev); 840 841 if (pcidev->irq) { 842 ret = request_irq(pcidev->irq, pci9111_interrupt, 843 IRQF_SHARED, dev->board_name, dev); 844 if (ret == 0) 845 dev->irq = pcidev->irq; 846 } 847 848 ret = comedi_alloc_subdevices(dev, 4); 849 if (ret) 850 return ret; 851 852 s = &dev->subdevices[0]; 853 s->type = COMEDI_SUBD_AI; 854 s->subdev_flags = SDF_READABLE | SDF_COMMON; 855 s->n_chan = 16; 856 s->maxdata = 0xffff; 857 s->range_table = &pci9111_ai_range; 858 s->insn_read = pci9111_ai_insn_read; 859 if (dev->irq) { 860 dev->read_subdev = s; 861 s->subdev_flags |= SDF_CMD_READ; 862 s->len_chanlist = s->n_chan; 863 s->do_cmdtest = pci9111_ai_do_cmd_test; 864 s->do_cmd = pci9111_ai_do_cmd; 865 s->cancel = pci9111_ai_cancel; 866 s->munge = pci9111_ai_munge; 867 } 868 869 s = &dev->subdevices[1]; 870 s->type = COMEDI_SUBD_AO; 871 s->subdev_flags = SDF_WRITABLE | SDF_COMMON; 872 s->n_chan = 1; 873 s->maxdata = 0x0fff; 874 s->len_chanlist = 1; 875 s->range_table = &range_bipolar10; 876 s->insn_write = pci9111_ao_insn_write; 877 s->insn_read = pci9111_ao_insn_read; 878 879 s = &dev->subdevices[2]; 880 s->type = COMEDI_SUBD_DI; 881 s->subdev_flags = SDF_READABLE; 882 s->n_chan = 16; 883 s->maxdata = 1; 884 s->range_table = &range_digital; 885 s->insn_bits = pci9111_di_insn_bits; 886 887 s = &dev->subdevices[3]; 888 s->type = COMEDI_SUBD_DO; 889 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 890 s->n_chan = 16; 891 s->maxdata = 1; 892 s->range_table = &range_digital; 893 s->insn_bits = pci9111_do_insn_bits; 894 895 return 0; 896} 897 898static void pci9111_detach(struct comedi_device *dev) 899{ 900 if (dev->iobase) 901 pci9111_reset(dev); 902 if (dev->irq != 0) 903 free_irq(dev->irq, dev); 904 comedi_pci_disable(dev); 905} 906 907static struct comedi_driver adl_pci9111_driver = { 908 .driver_name = "adl_pci9111", 909 .module = THIS_MODULE, 910 .auto_attach = pci9111_auto_attach, 911 .detach = pci9111_detach, 912}; 913 914static int pci9111_pci_probe(struct pci_dev *dev, 915 const struct pci_device_id *id) 916{ 917 return comedi_pci_auto_config(dev, &adl_pci9111_driver, 918 id->driver_data); 919} 920 921static const struct pci_device_id pci9111_pci_table[] = { 922 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, 923 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ 924 { 0 } 925}; 926MODULE_DEVICE_TABLE(pci, pci9111_pci_table); 927 928static struct pci_driver adl_pci9111_pci_driver = { 929 .name = "adl_pci9111", 930 .id_table = pci9111_pci_table, 931 .probe = pci9111_pci_probe, 932 .remove = comedi_pci_auto_unconfig, 933}; 934module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver); 935 936MODULE_AUTHOR("Comedi http://www.comedi.org"); 937MODULE_DESCRIPTION("Comedi low-level driver"); 938MODULE_LICENSE("GPL"); 939