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