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