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