adl_pci9111.c revision b3450faf38294faea229fb9353498ae05b6e2075
1/* 2 3comedi/drivers/adl_pci9111.c 4 5Hardware driver for PCI9111 ADLink cards: 6 7PCI-9111HR 8 9Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr> 10 11This program is free software; you can redistribute it and/or modify 12it under the terms of the GNU General Public License as published by 13the Free Software Foundation; either version 2 of the License, or 14(at your option) any later version. 15 16This program is distributed in the hope that it will be useful, 17but WITHOUT ANY WARRANTY; without even the implied warranty of 18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19GNU General Public License for more details. 20 21You should have received a copy of the GNU General Public License 22along with this program; if not, write to the Free Software 23Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24*/ 25 26/* 27Driver: adl_pci9111 28Description: Adlink PCI-9111HR 29Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr> 30Devices: [ADLink] PCI-9111HR (adl_pci9111) 31Status: experimental 32 33Supports: 34 35 - ai_insn read 36 - ao_insn read/write 37 - di_insn read 38 - do_insn read/write 39 - ai_do_cmd mode with the following sources: 40 41 - start_src TRIG_NOW 42 - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT 43 - convert_src TRIG_TIMER TRIG_EXT 44 - scan_end_src TRIG_COUNT 45 - stop_src TRIG_COUNT TRIG_NONE 46 47The scanned channels must be consecutive and start from 0. They must 48all have the same range and aref. 49 50Configuration options: 51 52 [0] - PCI bus number (optional) 53 [1] - PCI slot number (optional) 54 55If bus/slot is not specified, the first available PCI 56device will be used. 57 58*/ 59 60/* 61CHANGELOG: 62 632005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be 64a multiple of chanlist_len*convert_arg. 652002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data. 662002/02/18 Added external trigger support for analog input. 67 68TODO: 69 70 - Really test implemented functionality. 71 - Add support for the PCI-9111DG with a probe routine to identify 72 the card type (perhaps with the help of the channel number readback 73 of the A/D Data register). 74 - Add external multiplexer support. 75 76*/ 77 78#include "../comedidev.h" 79 80#include <linux/delay.h> 81#include <linux/interrupt.h> 82 83#include "8253.h" 84#include "comedi_fc.h" 85 86#define PCI9111_DRIVER_NAME "adl_pci9111" 87#define PCI9111_HR_DEVICE_ID 0x9111 88 89/* TODO: Add other pci9111 board id */ 90 91#define PCI9111_IO_RANGE 0x0100 92 93#define PCI9111_FIFO_HALF_SIZE 512 94 95#define PCI9111_AI_CHANNEL_NBR 16 96 97#define PCI9111_AI_RESOLUTION 12 98#define PCI9111_AI_RESOLUTION_MASK 0x0FFF 99#define PCI9111_AI_RESOLUTION_2_CMP_BIT 0x0800 100 101#define PCI9111_HR_AI_RESOLUTION 16 102#define PCI9111_HR_AI_RESOLUTION_MASK 0xFFFF 103#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT 0x8000 104 105#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000 106#define PCI9111_AO_CHANNEL_NBR 1 107#define PCI9111_AO_RESOLUTION 12 108#define PCI9111_AO_RESOLUTION_MASK 0x0FFF 109#define PCI9111_DI_CHANNEL_NBR 16 110#define PCI9111_DO_CHANNEL_NBR 16 111 112#define PCI9111_RANGE_SETTING_DELAY 10 113#define PCI9111_AI_INSTANT_READ_UDELAY_US 2 114#define PCI9111_AI_INSTANT_READ_TIMEOUT 100 115 116#define PCI9111_8254_CLOCK_PERIOD_NS 500 117 118/* IO address map */ 119 120#define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 /* AD Data stored 121 in FIFO */ 122#define PCI9111_AO_REG 0x00 123#define PCI9111_DIO_REG 0x02 124#define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04 125#define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 /* Channel 126 selection */ 127#define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06 128#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08 129#define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08 130#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A 131#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A 132#define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E 133#define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C 134#define PCI9111_8254_BASE_REG 0x40 135#define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48 136 137#define PCI9111_TRIGGER_MASK 0x0F 138#define PCI9111_PTRG_OFF (0 << 3) 139#define PCI9111_PTRG_ON (1 << 3) 140#define PCI9111_EITS_EXTERNAL (1 << 2) 141#define PCI9111_EITS_INTERNAL (0 << 2) 142#define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1) 143#define PCI9111_TPST_TIMER_PACER (1 << 1) 144#define PCI9111_ASCAN_ON (1 << 0) 145#define PCI9111_ASCAN_OFF (0 << 0) 146 147#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0) 148#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0) 149#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1) 150#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1) 151#define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2) 152#define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2) 153 154#define PCI9111_CHANNEL_MASK 0x0F 155 156#define PCI9111_RANGE_MASK 0x07 157#define PCI9111_FIFO_EMPTY_MASK 0x10 158#define PCI9111_FIFO_HALF_FULL_MASK 0x20 159#define PCI9111_FIFO_FULL_MASK 0x40 160#define PCI9111_AD_BUSY_MASK 0x80 161 162/* 163 * Define inlined function 164 */ 165 166#define pci9111_trigger_and_autoscan_get() \ 167 (inb(dev->iobase + PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F) 168 169#define pci9111_trigger_and_autoscan_set(flags) \ 170 outb(flags, dev->iobase + PCI9111_REGISTER_TRIGGER_MODE_CONTROL) 171 172#define pci9111_interrupt_and_fifo_get() \ 173 ((inb(dev->iobase + PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) \ 174 >> 4) & 0x03) 175 176#define pci9111_interrupt_and_fifo_set(flags) \ 177 outb(flags, dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL) 178 179#define pci9111_interrupt_clear() \ 180 outb(0, dev->iobase + PCI9111_REGISTER_INTERRUPT_CLEAR) 181 182#define pci9111_software_trigger() \ 183 outb(0, dev->iobase + PCI9111_REGISTER_SOFTWARE_TRIGGER) 184 185#define pci9111_fifo_reset() do { \ 186 outb(PCI9111_FFEN_SET_FIFO_ENABLE, \ 187 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \ 188 outb(PCI9111_FFEN_SET_FIFO_DISABLE, \ 189 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \ 190 outb(PCI9111_FFEN_SET_FIFO_ENABLE, \ 191 dev->iobase + PCI9111_REGISTER_INTERRUPT_CONTROL); \ 192 } while (0) 193 194#define pci9111_is_fifo_full() \ 195 ((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ 196 PCI9111_FIFO_FULL_MASK) == 0) 197 198#define pci9111_is_fifo_half_full() \ 199 ((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ 200 PCI9111_FIFO_HALF_FULL_MASK) == 0) 201 202#define pci9111_is_fifo_empty() \ 203 ((inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ 204 PCI9111_FIFO_EMPTY_MASK) == 0) 205 206#define pci9111_ai_channel_set(channel) \ 207 outb((channel)&PCI9111_CHANNEL_MASK, \ 208 dev->iobase + PCI9111_REGISTER_AD_CHANNEL_CONTROL) 209 210#define pci9111_ai_channel_get() \ 211 (inb(dev->iobase + PCI9111_REGISTER_AD_CHANNEL_READBACK) \ 212 &PCI9111_CHANNEL_MASK) 213 214#define pci9111_ai_range_set(range) \ 215 outb((range)&PCI9111_RANGE_MASK, \ 216 dev->iobase + PCI9111_REGISTER_INPUT_SIGNAL_RANGE) 217 218#define pci9111_ai_range_get() \ 219 (inb(dev->iobase + PCI9111_REGISTER_RANGE_STATUS_READBACK) \ 220 &PCI9111_RANGE_MASK) 221 222#define pci9111_ai_get_data() \ 223 (((inw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE)>>4) \ 224 &PCI9111_AI_RESOLUTION_MASK) \ 225 ^ PCI9111_AI_RESOLUTION_2_CMP_BIT) 226 227#define pci9111_hr_ai_get_data() \ 228 ((inw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE) \ 229 &PCI9111_HR_AI_RESOLUTION_MASK) \ 230 ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT) 231 232static const struct comedi_lrange pci9111_hr_ai_range = { 233 5, 234 { 235 BIP_RANGE(10), 236 BIP_RANGE(5), 237 BIP_RANGE(2.5), 238 BIP_RANGE(1.25), 239 BIP_RANGE(0.625) 240 } 241}; 242 243/* */ 244/* Board specification structure */ 245/* */ 246 247struct pci9111_board { 248 const char *name; /* driver name */ 249 int device_id; 250 int ai_channel_nbr; /* num of A/D chans */ 251 int ao_channel_nbr; /* num of D/A chans */ 252 int ai_resolution; /* resolution of A/D */ 253 int ai_resolution_mask; 254 int ao_resolution; /* resolution of D/A */ 255 int ao_resolution_mask; 256 const struct comedi_lrange *ai_range_list; /* rangelist for A/D */ 257 const struct comedi_lrange *ao_range_list; /* rangelist for D/A */ 258 unsigned int ai_acquisition_period_min_ns; 259}; 260 261static const struct pci9111_board pci9111_boards[] = { 262 { 263 .name = "pci9111_hr", 264 .device_id = PCI9111_HR_DEVICE_ID, 265 .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR, 266 .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR, 267 .ai_resolution = PCI9111_HR_AI_RESOLUTION, 268 .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK, 269 .ao_resolution = PCI9111_AO_RESOLUTION, 270 .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK, 271 .ai_range_list = &pci9111_hr_ai_range, 272 .ao_range_list = &range_bipolar10, 273 .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS} 274}; 275 276/* Private data structure */ 277 278struct pci9111_private_data { 279 unsigned long io_range; /* PCI6503 io range */ 280 281 unsigned long lcr_io_base; /* Local configuration register base 282 * address */ 283 unsigned long lcr_io_range; 284 285 int stop_counter; 286 int stop_is_none; 287 288 unsigned int scan_delay; 289 unsigned int chanlist_len; 290 unsigned int chunk_counter; 291 unsigned int chunk_num_samples; 292 293 int ao_readback; /* Last written analog output data */ 294 295 unsigned int timer_divisor_1; /* Divisor values for the 8254 timer 296 * pacer */ 297 unsigned int timer_divisor_2; 298 299 int is_valid; /* Is device valid */ 300 301 short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; 302}; 303 304/* ------------------------------------------------------------------ */ 305/* PLX9050 SECTION */ 306/* ------------------------------------------------------------------ */ 307 308#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c 309 310#define PLX9050_LINTI1_ENABLE (1 << 0) 311#define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1) 312#define PLX9050_LINTI1_STATUS (1 << 2) 313#define PLX9050_LINTI2_ENABLE (1 << 3) 314#define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4) 315#define PLX9050_LINTI2_STATUS (1 << 5) 316#define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6) 317#define PLX9050_SOFTWARE_INTERRUPT (1 << 7) 318 319static void plx9050_interrupt_control(unsigned long io_base, 320 bool LINTi1_enable, 321 bool LINTi1_active_high, 322 bool LINTi2_enable, 323 bool LINTi2_active_high, 324 bool interrupt_enable) 325{ 326 int flags = 0; 327 328 if (LINTi1_enable) 329 flags |= PLX9050_LINTI1_ENABLE; 330 if (LINTi1_active_high) 331 flags |= PLX9050_LINTI1_ACTIVE_HIGH; 332 if (LINTi2_enable) 333 flags |= PLX9050_LINTI2_ENABLE; 334 if (LINTi2_active_high) 335 flags |= PLX9050_LINTI2_ACTIVE_HIGH; 336 337 if (interrupt_enable) 338 flags |= PLX9050_PCI_INTERRUPT_ENABLE; 339 340 outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL); 341} 342 343/* ------------------------------------------------------------------ */ 344/* MISCELLANEOUS SECTION */ 345/* ------------------------------------------------------------------ */ 346 347/* 8254 timer */ 348 349static void pci9111_timer_set(struct comedi_device *dev) 350{ 351 struct pci9111_private_data *dev_private = dev->private; 352 unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG; 353 354 i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY); 355 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY); 356 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY); 357 358 udelay(1); 359 360 i8254_write(timer_base, 1, 2, dev_private->timer_divisor_2); 361 i8254_write(timer_base, 1, 1, dev_private->timer_divisor_1); 362} 363 364enum pci9111_trigger_sources { 365 software, 366 timer_pacer, 367 external 368}; 369 370static void pci9111_trigger_source_set(struct comedi_device *dev, 371 enum pci9111_trigger_sources source) 372{ 373 int flags; 374 375 flags = pci9111_trigger_and_autoscan_get() & 0x09; 376 377 switch (source) { 378 case software: 379 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER; 380 break; 381 382 case timer_pacer: 383 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER; 384 break; 385 386 case external: 387 flags |= PCI9111_EITS_EXTERNAL; 388 break; 389 } 390 391 pci9111_trigger_and_autoscan_set(flags); 392} 393 394static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger) 395{ 396 int flags; 397 398 flags = pci9111_trigger_and_autoscan_get() & 0x07; 399 400 if (pretrigger) 401 flags |= PCI9111_PTRG_ON; 402 403 pci9111_trigger_and_autoscan_set(flags); 404} 405 406static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan) 407{ 408 int flags; 409 410 flags = pci9111_trigger_and_autoscan_get() & 0x0e; 411 412 if (autoscan) 413 flags |= PCI9111_ASCAN_ON; 414 415 pci9111_trigger_and_autoscan_set(flags); 416} 417 418enum pci9111_ISC0_sources { 419 irq_on_eoc, 420 irq_on_fifo_half_full 421}; 422 423enum pci9111_ISC1_sources { 424 irq_on_timer_tick, 425 irq_on_external_trigger 426}; 427 428static void pci9111_interrupt_source_set(struct comedi_device *dev, 429 enum pci9111_ISC0_sources irq_0_source, 430 enum pci9111_ISC1_sources irq_1_source) 431{ 432 int flags; 433 434 flags = pci9111_interrupt_and_fifo_get() & 0x04; 435 436 if (irq_0_source == irq_on_fifo_half_full) 437 flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL; 438 439 if (irq_1_source == irq_on_external_trigger) 440 flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG; 441 442 pci9111_interrupt_and_fifo_set(flags); 443} 444 445/* ------------------------------------------------------------------ */ 446/* HARDWARE TRIGGERED ANALOG INPUT SECTION */ 447/* ------------------------------------------------------------------ */ 448 449/* Cancel analog input autoscan */ 450 451#undef AI_DO_CMD_DEBUG 452 453static int pci9111_ai_cancel(struct comedi_device *dev, 454 struct comedi_subdevice *s) 455{ 456 struct pci9111_private_data *dev_private = dev->private; 457 458 /* Disable interrupts */ 459 460 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, 461 true, false); 462 463 pci9111_trigger_source_set(dev, software); 464 465 pci9111_autoscan_set(dev, false); 466 467 pci9111_fifo_reset(); 468 469#ifdef AI_DO_CMD_DEBUG 470 printk(PCI9111_DRIVER_NAME ": ai_cancel\n"); 471#endif 472 473 return 0; 474} 475 476/* Test analog input command */ 477 478#define pci9111_check_trigger_src(src, flags) do { \ 479 tmp = src; \ 480 src &= flags; \ 481 if (!src || tmp != src) \ 482 error++; \ 483 } while (false); 484 485static int 486pci9111_ai_do_cmd_test(struct comedi_device *dev, 487 struct comedi_subdevice *s, struct comedi_cmd *cmd) 488{ 489 struct pci9111_private_data *dev_private = dev->private; 490 int tmp; 491 int error = 0; 492 int range, reference; 493 int i; 494 struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr; 495 496 /* Step 1 : check if trigger are trivialy valid */ 497 498 pci9111_check_trigger_src(cmd->start_src, TRIG_NOW); 499 pci9111_check_trigger_src(cmd->scan_begin_src, 500 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); 501 pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT); 502 pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT); 503 pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE); 504 505 if (error) 506 return 1; 507 508 /* step 2 : make sure trigger sources are unique and mutually 509 * compatible */ 510 511 if (cmd->start_src != TRIG_NOW) 512 error++; 513 514 if ((cmd->scan_begin_src != TRIG_TIMER) && 515 (cmd->scan_begin_src != TRIG_FOLLOW) && 516 (cmd->scan_begin_src != TRIG_EXT)) 517 error++; 518 519 if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT)) 520 error++; 521 if ((cmd->convert_src == TRIG_TIMER) && 522 !((cmd->scan_begin_src == TRIG_TIMER) || 523 (cmd->scan_begin_src == TRIG_FOLLOW))) 524 error++; 525 if ((cmd->convert_src == TRIG_EXT) && 526 !((cmd->scan_begin_src == TRIG_EXT) || 527 (cmd->scan_begin_src == TRIG_FOLLOW))) 528 error++; 529 530 531 if (cmd->scan_end_src != TRIG_COUNT) 532 error++; 533 if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE)) 534 error++; 535 536 if (error) 537 return 2; 538 539 /* Step 3 : make sure arguments are trivialy compatible */ 540 541 if (cmd->chanlist_len < 1) { 542 cmd->chanlist_len = 1; 543 error++; 544 } 545 546 if (cmd->chanlist_len > board->ai_channel_nbr) { 547 cmd->chanlist_len = board->ai_channel_nbr; 548 error++; 549 } 550 551 if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) { 552 cmd->start_arg = 0; 553 error++; 554 } 555 556 if ((cmd->convert_src == TRIG_TIMER) && 557 (cmd->convert_arg < board->ai_acquisition_period_min_ns)) { 558 cmd->convert_arg = board->ai_acquisition_period_min_ns; 559 error++; 560 } 561 if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) { 562 cmd->convert_arg = 0; 563 error++; 564 } 565 566 if ((cmd->scan_begin_src == TRIG_TIMER) && 567 (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) { 568 cmd->scan_begin_arg = board->ai_acquisition_period_min_ns; 569 error++; 570 } 571 if ((cmd->scan_begin_src == TRIG_FOLLOW) 572 && (cmd->scan_begin_arg != 0)) { 573 cmd->scan_begin_arg = 0; 574 error++; 575 } 576 if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) { 577 cmd->scan_begin_arg = 0; 578 error++; 579 } 580 581 if ((cmd->scan_end_src == TRIG_COUNT) && 582 (cmd->scan_end_arg != cmd->chanlist_len)) { 583 cmd->scan_end_arg = cmd->chanlist_len; 584 error++; 585 } 586 587 if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) { 588 cmd->stop_arg = 1; 589 error++; 590 } 591 if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) { 592 cmd->stop_arg = 0; 593 error++; 594 } 595 596 if (error) 597 return 3; 598 599 /* Step 4 : fix up any arguments */ 600 601 if (cmd->convert_src == TRIG_TIMER) { 602 tmp = cmd->convert_arg; 603 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, 604 &(dev_private->timer_divisor_1), 605 &(dev_private->timer_divisor_2), 606 &(cmd->convert_arg), 607 cmd->flags & TRIG_ROUND_MASK); 608 if (tmp != cmd->convert_arg) 609 error++; 610 } 611 /* There's only one timer on this card, so the scan_begin timer must */ 612 /* be a multiple of chanlist_len*convert_arg */ 613 614 if (cmd->scan_begin_src == TRIG_TIMER) { 615 616 unsigned int scan_begin_min; 617 unsigned int scan_begin_arg; 618 unsigned int scan_factor; 619 620 scan_begin_min = cmd->chanlist_len * cmd->convert_arg; 621 622 if (cmd->scan_begin_arg != scan_begin_min) { 623 if (scan_begin_min < cmd->scan_begin_arg) { 624 scan_factor = 625 cmd->scan_begin_arg / scan_begin_min; 626 scan_begin_arg = scan_factor * scan_begin_min; 627 if (cmd->scan_begin_arg != scan_begin_arg) { 628 cmd->scan_begin_arg = scan_begin_arg; 629 error++; 630 } 631 } else { 632 cmd->scan_begin_arg = scan_begin_min; 633 error++; 634 } 635 } 636 } 637 638 if (error) 639 return 4; 640 641 /* Step 5 : check channel list */ 642 643 if (cmd->chanlist) { 644 645 range = CR_RANGE(cmd->chanlist[0]); 646 reference = CR_AREF(cmd->chanlist[0]); 647 648 if (cmd->chanlist_len > 1) { 649 for (i = 0; i < cmd->chanlist_len; i++) { 650 if (CR_CHAN(cmd->chanlist[i]) != i) { 651 comedi_error(dev, 652 "entries in chanlist must be consecutive " 653 "channels,counting upwards from 0\n"); 654 error++; 655 } 656 if (CR_RANGE(cmd->chanlist[i]) != range) { 657 comedi_error(dev, 658 "entries in chanlist must all have the same gain\n"); 659 error++; 660 } 661 if (CR_AREF(cmd->chanlist[i]) != reference) { 662 comedi_error(dev, 663 "entries in chanlist must all have the same reference\n"); 664 error++; 665 } 666 } 667 } else { 668 if ((CR_CHAN(cmd->chanlist[0]) > 669 (board->ai_channel_nbr - 1)) 670 || (CR_CHAN(cmd->chanlist[0]) < 0)) { 671 comedi_error(dev, 672 "channel number is out of limits\n"); 673 error++; 674 } 675 } 676 } 677 678 if (error) 679 return 5; 680 681 return 0; 682 683} 684 685/* Analog input command */ 686 687static int pci9111_ai_do_cmd(struct comedi_device *dev, 688 struct comedi_subdevice *s) 689{ 690 struct pci9111_private_data *dev_private = dev->private; 691 struct comedi_cmd *async_cmd = &s->async->cmd; 692 693 if (!dev->irq) { 694 comedi_error(dev, 695 "no irq assigned for PCI9111, cannot do hardware conversion"); 696 return -1; 697 } 698 /* Set channel scan limit */ 699 /* PCI9111 allows only scanning from channel 0 to channel n */ 700 /* TODO: handle the case of an external multiplexer */ 701 702 if (async_cmd->chanlist_len > 1) { 703 pci9111_ai_channel_set((async_cmd->chanlist_len) - 1); 704 pci9111_autoscan_set(dev, true); 705 } else { 706 pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0])); 707 pci9111_autoscan_set(dev, false); 708 } 709 710 /* Set gain */ 711 /* This is the same gain on every channel */ 712 713 pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0])); 714 715 /* Set counter */ 716 717 switch (async_cmd->stop_src) { 718 case TRIG_COUNT: 719 dev_private->stop_counter = 720 async_cmd->stop_arg * async_cmd->chanlist_len; 721 dev_private->stop_is_none = 0; 722 break; 723 724 case TRIG_NONE: 725 dev_private->stop_counter = 0; 726 dev_private->stop_is_none = 1; 727 break; 728 729 default: 730 comedi_error(dev, "Invalid stop trigger"); 731 return -1; 732 } 733 734 /* Set timer pacer */ 735 736 dev_private->scan_delay = 0; 737 switch (async_cmd->convert_src) { 738 case TRIG_TIMER: 739 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, 740 &(dev_private->timer_divisor_1), 741 &(dev_private->timer_divisor_2), 742 &(async_cmd->convert_arg), 743 async_cmd-> 744 flags & TRIG_ROUND_MASK); 745#ifdef AI_DO_CMD_DEBUG 746 printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n", 747 dev_private->timer_divisor_1, 748 dev_private->timer_divisor_2); 749#endif 750 751 pci9111_trigger_source_set(dev, software); 752 pci9111_timer_set(dev); 753 pci9111_fifo_reset(); 754 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, 755 irq_on_timer_tick); 756 pci9111_trigger_source_set(dev, timer_pacer); 757 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, 758 false, true, true); 759 760 if (async_cmd->scan_begin_src == TRIG_TIMER) { 761 dev_private->scan_delay = 762 (async_cmd->scan_begin_arg / 763 (async_cmd->convert_arg * 764 async_cmd->chanlist_len)) - 1; 765 } 766 767 break; 768 769 case TRIG_EXT: 770 771 pci9111_trigger_source_set(dev, external); 772 pci9111_fifo_reset(); 773 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, 774 irq_on_timer_tick); 775 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, 776 false, true, true); 777 778 break; 779 780 default: 781 comedi_error(dev, "Invalid convert trigger"); 782 return -1; 783 } 784 785 dev_private->stop_counter *= (1 + dev_private->scan_delay); 786 dev_private->chanlist_len = async_cmd->chanlist_len; 787 dev_private->chunk_counter = 0; 788 dev_private->chunk_num_samples = 789 dev_private->chanlist_len * (1 + dev_private->scan_delay); 790 791#ifdef AI_DO_CMD_DEBUG 792 printk(PCI9111_DRIVER_NAME ": start interruptions!\n"); 793 printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n", 794 pci9111_trigger_and_autoscan_get()); 795 printk(PCI9111_DRIVER_NAME ": irq source = %2x\n", 796 pci9111_interrupt_and_fifo_get()); 797 printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n"); 798 printk(PCI9111_DRIVER_NAME ": stop counter = %d\n", 799 dev_private->stop_counter); 800 printk(PCI9111_DRIVER_NAME ": scan delay = %d\n", 801 dev_private->scan_delay); 802 printk(PCI9111_DRIVER_NAME ": chanlist_len = %d\n", 803 dev_private->chanlist_len); 804 printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n", 805 dev_private->chunk_num_samples); 806#endif 807 808 return 0; 809} 810 811static void pci9111_ai_munge(struct comedi_device *dev, 812 struct comedi_subdevice *s, void *data, 813 unsigned int num_bytes, 814 unsigned int start_chan_index) 815{ 816 unsigned int i, num_samples = num_bytes / sizeof(short); 817 short *array = data; 818 int resolution = 819 ((struct pci9111_board *)dev->board_ptr)->ai_resolution; 820 821 for (i = 0; i < num_samples; i++) { 822 if (resolution == PCI9111_HR_AI_RESOLUTION) 823 array[i] = 824 (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^ 825 PCI9111_HR_AI_RESOLUTION_2_CMP_BIT; 826 else 827 array[i] = 828 ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^ 829 PCI9111_AI_RESOLUTION_2_CMP_BIT; 830 } 831} 832 833/* ------------------------------------------------------------------ */ 834/* INTERRUPT SECTION */ 835/* ------------------------------------------------------------------ */ 836 837#undef INTERRUPT_DEBUG 838 839static irqreturn_t pci9111_interrupt(int irq, void *p_device) 840{ 841 struct comedi_device *dev = p_device; 842 struct pci9111_private_data *dev_private = dev->private; 843 struct comedi_subdevice *s = dev->read_subdev; 844 struct comedi_async *async; 845 unsigned long irq_flags; 846 unsigned char intcsr; 847 848 if (!dev->attached) { 849 /* Ignore interrupt before device fully attached. */ 850 /* Might not even have allocated subdevices yet! */ 851 return IRQ_NONE; 852 } 853 854 async = s->async; 855 856 spin_lock_irqsave(&dev->spinlock, irq_flags); 857 858 /* Check if we are source of interrupt */ 859 intcsr = inb(dev_private->lcr_io_base + 860 PLX9050_REGISTER_INTERRUPT_CONTROL); 861 if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0) 862 && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) 863 == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) 864 || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS)) 865 == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) { 866 /* Not the source of the interrupt. */ 867 /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */ 868 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 869 return IRQ_NONE; 870 } 871 872 if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) == 873 (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) { 874 /* Interrupt comes from fifo_half-full signal */ 875 876 if (pci9111_is_fifo_full()) { 877 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 878 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); 879 pci9111_interrupt_clear(); 880 pci9111_ai_cancel(dev, s); 881 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 882 comedi_event(dev, s); 883 884 return IRQ_HANDLED; 885 } 886 887 if (pci9111_is_fifo_half_full()) { 888 unsigned int num_samples; 889 unsigned int bytes_written = 0; 890 891#ifdef INTERRUPT_DEBUG 892 printk(PCI9111_DRIVER_NAME ": fifo is half full\n"); 893#endif 894 895 num_samples = 896 PCI9111_FIFO_HALF_SIZE > 897 dev_private->stop_counter 898 && !dev_private-> 899 stop_is_none ? dev_private->stop_counter : 900 PCI9111_FIFO_HALF_SIZE; 901 insw(dev->iobase + PCI9111_REGISTER_AD_FIFO_VALUE, 902 dev_private->ai_bounce_buffer, num_samples); 903 904 if (dev_private->scan_delay < 1) { 905 bytes_written = 906 cfc_write_array_to_buffer(s, 907 dev_private-> 908 ai_bounce_buffer, 909 num_samples * 910 sizeof(short)); 911 } else { 912 int position = 0; 913 int to_read; 914 915 while (position < num_samples) { 916 if (dev_private->chunk_counter < 917 dev_private->chanlist_len) { 918 to_read = 919 dev_private->chanlist_len - 920 dev_private->chunk_counter; 921 922 if (to_read > 923 num_samples - position) 924 to_read = 925 num_samples - 926 position; 927 928 bytes_written += 929 cfc_write_array_to_buffer 930 (s, 931 dev_private->ai_bounce_buffer 932 + position, 933 to_read * sizeof(short)); 934 } else { 935 to_read = 936 dev_private->chunk_num_samples 937 - 938 dev_private->chunk_counter; 939 if (to_read > 940 num_samples - position) 941 to_read = 942 num_samples - 943 position; 944 945 bytes_written += 946 sizeof(short) * to_read; 947 } 948 949 position += to_read; 950 dev_private->chunk_counter += to_read; 951 952 if (dev_private->chunk_counter >= 953 dev_private->chunk_num_samples) 954 dev_private->chunk_counter = 0; 955 } 956 } 957 958 dev_private->stop_counter -= 959 bytes_written / sizeof(short); 960 } 961 } 962 963 if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) { 964 async->events |= COMEDI_CB_EOA; 965 pci9111_ai_cancel(dev, s); 966 } 967 968 /* Very important, otherwise another interrupt request will be inserted 969 * and will cause driver hangs on processing interrupt event. */ 970 971 pci9111_interrupt_clear(); 972 973 spin_unlock_irqrestore(&dev->spinlock, irq_flags); 974 975 comedi_event(dev, s); 976 977 return IRQ_HANDLED; 978} 979 980/* ------------------------------------------------------------------ */ 981/* INSTANT ANALOG INPUT OUTPUT SECTION */ 982/* ------------------------------------------------------------------ */ 983 984/* analog instant input */ 985 986#undef AI_INSN_DEBUG 987 988static int pci9111_ai_insn_read(struct comedi_device *dev, 989 struct comedi_subdevice *s, 990 struct comedi_insn *insn, unsigned int *data) 991{ 992 int resolution = 993 ((struct pci9111_board *)dev->board_ptr)->ai_resolution; 994 995 int timeout, i; 996 997#ifdef AI_INSN_DEBUG 998 printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n", 999 CR_CHAN((&insn->chanspec)[0]), 1000 CR_RANGE((&insn->chanspec)[0]), insn->n); 1001#endif 1002 1003 pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0])); 1004 1005 if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0])) 1006 pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0])); 1007 1008 pci9111_fifo_reset(); 1009 1010 for (i = 0; i < insn->n; i++) { 1011 pci9111_software_trigger(); 1012 1013 timeout = PCI9111_AI_INSTANT_READ_TIMEOUT; 1014 1015 while (timeout--) { 1016 if (!pci9111_is_fifo_empty()) 1017 goto conversion_done; 1018 } 1019 1020 comedi_error(dev, "A/D read timeout"); 1021 data[i] = 0; 1022 pci9111_fifo_reset(); 1023 return -ETIME; 1024 1025conversion_done: 1026 1027 if (resolution == PCI9111_HR_AI_RESOLUTION) 1028 data[i] = pci9111_hr_ai_get_data(); 1029 else 1030 data[i] = pci9111_ai_get_data(); 1031 } 1032 1033#ifdef AI_INSN_DEBUG 1034 printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n", 1035 pci9111_ai_channel_get(), 1036 pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get()); 1037#endif 1038 1039 return i; 1040} 1041 1042/* Analog instant output */ 1043 1044static int 1045pci9111_ao_insn_write(struct comedi_device *dev, 1046 struct comedi_subdevice *s, struct comedi_insn *insn, 1047 unsigned int *data) 1048{ 1049 struct pci9111_private_data *dev_private = dev->private; 1050 int i; 1051 1052 for (i = 0; i < insn->n; i++) { 1053 outw(data[i] & PCI9111_AO_RESOLUTION_MASK, 1054 dev->iobase + PCI9111_AO_REG); 1055 dev_private->ao_readback = data[i]; 1056 } 1057 1058 return i; 1059} 1060 1061static int pci9111_ao_insn_read(struct comedi_device *dev, 1062 struct comedi_subdevice *s, 1063 struct comedi_insn *insn, 1064 unsigned int *data) 1065{ 1066 struct pci9111_private_data *dev_private = dev->private; 1067 int i; 1068 1069 for (i = 0; i < insn->n; i++) 1070 data[i] = dev_private->ao_readback; 1071 1072 return insn->n; 1073} 1074 1075static int pci9111_di_insn_bits(struct comedi_device *dev, 1076 struct comedi_subdevice *s, 1077 struct comedi_insn *insn, 1078 unsigned int *data) 1079{ 1080 data[1] = inw(dev->iobase + PCI9111_DIO_REG); 1081 1082 return insn->n; 1083} 1084 1085static int pci9111_do_insn_bits(struct comedi_device *dev, 1086 struct comedi_subdevice *s, 1087 struct comedi_insn *insn, 1088 unsigned int *data) 1089{ 1090 unsigned int mask = data[0]; 1091 unsigned int bits = data[1]; 1092 1093 if (mask) { 1094 s->state &= ~mask; 1095 s->state |= (bits & mask); 1096 1097 outw(s->state, dev->iobase + PCI9111_DIO_REG); 1098 } 1099 1100 data[1] = s->state; 1101 1102 return insn->n; 1103} 1104 1105/* ------------------------------------------------------------------ */ 1106/* INITIALISATION SECTION */ 1107/* ------------------------------------------------------------------ */ 1108 1109/* Reset device */ 1110 1111static int pci9111_reset(struct comedi_device *dev) 1112{ 1113 struct pci9111_private_data *dev_private = dev->private; 1114 1115 /* Set trigger source to software */ 1116 1117 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, 1118 true, false); 1119 1120 pci9111_trigger_source_set(dev, software); 1121 pci9111_pretrigger_set(dev, false); 1122 pci9111_autoscan_set(dev, false); 1123 1124 /* Reset 8254 chip */ 1125 1126 dev_private->timer_divisor_1 = 0; 1127 dev_private->timer_divisor_2 = 0; 1128 1129 pci9111_timer_set(dev); 1130 1131 return 0; 1132} 1133 1134static struct pci_dev *pci9111_find_pci(struct comedi_device *dev, 1135 struct comedi_devconfig *it) 1136{ 1137 struct pci_dev *pcidev = NULL; 1138 int bus = it->options[0]; 1139 int slot = it->options[1]; 1140 int i; 1141 1142 for_each_pci_dev(pcidev) { 1143 if (pcidev->vendor != PCI_VENDOR_ID_ADLINK) 1144 continue; 1145 for (i = 0; i < ARRAY_SIZE(pci9111_boards); i++) { 1146 if (pcidev->device != pci9111_boards[i].device_id) 1147 continue; 1148 if (bus || slot) { 1149 /* requested particular bus/slot */ 1150 if (pcidev->bus->number != bus || 1151 PCI_SLOT(pcidev->devfn) != slot) 1152 continue; 1153 } 1154 dev->board_ptr = pci9111_boards + i; 1155 printk(KERN_ERR 1156 "comedi%d: found %s (b:s:f=%d:%d:%d), irq=%d\n", 1157 dev->minor, pci9111_boards[i].name, 1158 pcidev->bus->number, PCI_SLOT(pcidev->devfn), 1159 PCI_FUNC(pcidev->devfn), pcidev->irq); 1160 return pcidev; 1161 } 1162 } 1163 printk(KERN_ERR 1164 "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", 1165 dev->minor, bus, slot); 1166 return NULL; 1167} 1168 1169static int pci9111_attach(struct comedi_device *dev, 1170 struct comedi_devconfig *it) 1171{ 1172 struct pci9111_private_data *dev_private; 1173 struct pci_dev *pcidev; 1174 struct comedi_subdevice *s; 1175 unsigned long io_base, io_range, lcr_io_base, lcr_io_range; 1176 int ret; 1177 const struct pci9111_board *board; 1178 1179 ret = alloc_private(dev, sizeof(*dev_private)); 1180 if (ret) 1181 return ret; 1182 dev_private = dev->private; 1183 1184 /* Probe the device to determine what device in the series it is. */ 1185 1186 printk(KERN_ERR "comedi%d: " PCI9111_DRIVER_NAME " driver\n", 1187 dev->minor); 1188 1189 pcidev = pci9111_find_pci(dev, it); 1190 if (!pcidev) 1191 return -EIO; 1192 comedi_set_hw_dev(dev, &pcidev->dev); 1193 board = (struct pci9111_board *)dev->board_ptr; 1194 1195 /* TODO: Warn about non-tested boards. */ 1196 1197 /* Read local configuration register base address 1198 * [PCI_BASE_ADDRESS #1]. */ 1199 1200 lcr_io_base = pci_resource_start(pcidev, 1); 1201 lcr_io_range = pci_resource_len(pcidev, 1); 1202 1203 printk 1204 ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n", 1205 dev->minor, lcr_io_base, lcr_io_range); 1206 1207 /* Enable PCI device and request regions */ 1208 if (comedi_pci_enable(pcidev, PCI9111_DRIVER_NAME) < 0) { 1209 printk 1210 ("comedi%d: Failed to enable PCI device and request regions\n", 1211 dev->minor); 1212 return -EIO; 1213 } 1214 /* Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */ 1215 1216 io_base = pci_resource_start(pcidev, 2); 1217 io_range = pci_resource_len(pcidev, 2); 1218 1219 printk(KERN_ERR "comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n", 1220 dev->minor, io_base, io_range); 1221 1222 dev->iobase = io_base; 1223 dev->board_name = board->name; 1224 dev_private->io_range = io_range; 1225 dev_private->is_valid = 0; 1226 dev_private->lcr_io_base = lcr_io_base; 1227 dev_private->lcr_io_range = lcr_io_range; 1228 1229 pci9111_reset(dev); 1230 1231 /* Irq setup */ 1232 1233 dev->irq = 0; 1234 if (pcidev->irq > 0) { 1235 dev->irq = pcidev->irq; 1236 1237 if (request_irq(dev->irq, pci9111_interrupt, 1238 IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) { 1239 printk(KERN_ERR 1240 "comedi%d: unable to allocate irq %u\n", 1241 dev->minor, dev->irq); 1242 return -EINVAL; 1243 } 1244 } 1245 1246 /* TODO: Add external multiplexer setup (according to option[2]). */ 1247 1248 ret = comedi_alloc_subdevices(dev, 4); 1249 if (ret) 1250 return ret; 1251 1252 s = &dev->subdevices[0]; 1253 dev->read_subdev = s; 1254 1255 s->type = COMEDI_SUBD_AI; 1256 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; 1257 1258 /* TODO: Add external multiplexer data */ 1259 /* if (devpriv->usemux) { s->n_chan = devpriv->usemux; } */ 1260 /* else { s->n_chan = this_board->n_aichan; } */ 1261 1262 s->n_chan = board->ai_channel_nbr; 1263 s->maxdata = board->ai_resolution_mask; 1264 s->len_chanlist = board->ai_channel_nbr; 1265 s->range_table = board->ai_range_list; 1266 s->cancel = pci9111_ai_cancel; 1267 s->insn_read = pci9111_ai_insn_read; 1268 s->do_cmdtest = pci9111_ai_do_cmd_test; 1269 s->do_cmd = pci9111_ai_do_cmd; 1270 s->munge = pci9111_ai_munge; 1271 1272 s = &dev->subdevices[1]; 1273 s->type = COMEDI_SUBD_AO; 1274 s->subdev_flags = SDF_WRITABLE | SDF_COMMON; 1275 s->n_chan = board->ao_channel_nbr; 1276 s->maxdata = board->ao_resolution_mask; 1277 s->len_chanlist = board->ao_channel_nbr; 1278 s->range_table = board->ao_range_list; 1279 s->insn_write = pci9111_ao_insn_write; 1280 s->insn_read = pci9111_ao_insn_read; 1281 1282 s = &dev->subdevices[2]; 1283 s->type = COMEDI_SUBD_DI; 1284 s->subdev_flags = SDF_READABLE; 1285 s->n_chan = PCI9111_DI_CHANNEL_NBR; 1286 s->maxdata = 1; 1287 s->range_table = &range_digital; 1288 s->insn_bits = pci9111_di_insn_bits; 1289 1290 s = &dev->subdevices[3]; 1291 s->type = COMEDI_SUBD_DO; 1292 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 1293 s->n_chan = PCI9111_DO_CHANNEL_NBR; 1294 s->maxdata = 1; 1295 s->range_table = &range_digital; 1296 s->insn_bits = pci9111_do_insn_bits; 1297 1298 dev_private->is_valid = 1; 1299 1300 return 0; 1301} 1302 1303static void pci9111_detach(struct comedi_device *dev) 1304{ 1305 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 1306 struct pci9111_private_data *dev_private = dev->private; 1307 1308 if (dev_private) { 1309 if (dev_private->is_valid) 1310 pci9111_reset(dev); 1311 } 1312 if (dev->irq != 0) 1313 free_irq(dev->irq, dev); 1314 if (pcidev) { 1315 if (dev->iobase) 1316 comedi_pci_disable(pcidev); 1317 pci_dev_put(pcidev); 1318 } 1319} 1320 1321static struct comedi_driver adl_pci9111_driver = { 1322 .driver_name = "adl_pci9111", 1323 .module = THIS_MODULE, 1324 .attach = pci9111_attach, 1325 .detach = pci9111_detach, 1326}; 1327 1328static int __devinit pci9111_pci_probe(struct pci_dev *dev, 1329 const struct pci_device_id *ent) 1330{ 1331 return comedi_pci_auto_config(dev, &adl_pci9111_driver); 1332} 1333 1334static void __devexit pci9111_pci_remove(struct pci_dev *dev) 1335{ 1336 comedi_pci_auto_unconfig(dev); 1337} 1338 1339static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = { 1340 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, 1341 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ 1342 { 0 } 1343}; 1344MODULE_DEVICE_TABLE(pci, pci9111_pci_table); 1345 1346static struct pci_driver adl_pci9111_pci_driver = { 1347 .name = "adl_pci9111", 1348 .id_table = pci9111_pci_table, 1349 .probe = pci9111_pci_probe, 1350 .remove = __devexit_p(pci9111_pci_remove), 1351}; 1352module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver); 1353 1354MODULE_AUTHOR("Comedi http://www.comedi.org"); 1355MODULE_DESCRIPTION("Comedi low-level driver"); 1356MODULE_LICENSE("GPL"); 1357