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