icp_multi.c revision fafe91a8b2ea372b76e0cbad995cea8afd77b5da
1/* 2 comedi/drivers/icp_multi.c 3 4 COMEDI - Linux Control and Measurement Device Interface 5 Copyright (C) 1997-2002 David A. Schleef <ds@schleef.org> 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 21*/ 22 23/* 24Driver: icp_multi 25Description: Inova ICP_MULTI 26Author: Anne Smorthit <anne.smorthit@sfwte.ch> 27Devices: [Inova] ICP_MULTI (icp_multi) 28Status: works 29 30The driver works for analog input and output and digital input and output. 31It does not work with interrupts or with the counters. Currently no support 32for DMA. 33 34It has 16 single-ended or 8 differential Analogue Input channels with 12-bit 35resolution. Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA. Input 36ranges can be individually programmed for each channel. Voltage or current 37measurement is selected by jumper. 38 39There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V 40 4116 x Digital Inputs, 24V 42 438 x Digital Outputs, 24V, 1A 44 454 x 16-bit counters 46 47Options: 48 [0] - PCI bus number - if bus number and slot number are 0, 49 then driver search for first unused card 50 [1] - PCI slot number 51*/ 52 53#include <linux/interrupt.h> 54#include "../comedidev.h" 55 56#include <linux/delay.h> 57#include <linux/pci.h> 58 59#include "icp_multi.h" 60 61#define PCI_DEVICE_ID_ICP_MULTI 0x8000 62 63/* Hardware types of the cards */ 64#define TYPE_ICP_MULTI 0 65 66#define IORANGE_ICP_MULTI 32 67 68#define ICP_MULTI_ADC_CSR 0 /* R/W: ADC command/status register */ 69#define ICP_MULTI_AI 2 /* R: Analogue input data */ 70#define ICP_MULTI_DAC_CSR 4 /* R/W: DAC command/status register */ 71#define ICP_MULTI_AO 6 /* R/W: Analogue output data */ 72#define ICP_MULTI_DI 8 /* R/W: Digital inouts */ 73#define ICP_MULTI_DO 0x0A /* R/W: Digital outputs */ 74#define ICP_MULTI_INT_EN 0x0C /* R/W: Interrupt enable register */ 75#define ICP_MULTI_INT_STAT 0x0E /* R/W: Interrupt status register */ 76#define ICP_MULTI_CNTR0 0x10 /* R/W: Counter 0 */ 77#define ICP_MULTI_CNTR1 0x12 /* R/W: counter 1 */ 78#define ICP_MULTI_CNTR2 0x14 /* R/W: Counter 2 */ 79#define ICP_MULTI_CNTR3 0x16 /* R/W: Counter 3 */ 80 81#define ICP_MULTI_SIZE 0x20 /* 32 bytes */ 82 83/* Define bits from ADC command/status register */ 84#define ADC_ST 0x0001 /* Start ADC */ 85#define ADC_BSY 0x0001 /* ADC busy */ 86#define ADC_BI 0x0010 /* Bipolar input range 1 = bipolar */ 87#define ADC_RA 0x0020 /* Input range 0 = 5V, 1 = 10V */ 88#define ADC_DI 0x0040 /* Differential input mode 1 = differential */ 89 90/* Define bits from DAC command/status register */ 91#define DAC_ST 0x0001 /* Start DAC */ 92#define DAC_BSY 0x0001 /* DAC busy */ 93#define DAC_BI 0x0010 /* Bipolar input range 1 = bipolar */ 94#define DAC_RA 0x0020 /* Input range 0 = 5V, 1 = 10V */ 95 96/* Define bits from interrupt enable/status registers */ 97#define ADC_READY 0x0001 /* A/d conversion ready interrupt */ 98#define DAC_READY 0x0002 /* D/a conversion ready interrupt */ 99#define DOUT_ERROR 0x0004 /* Digital output error interrupt */ 100#define DIN_STATUS 0x0008 /* Digital input status change interrupt */ 101#define CIE0 0x0010 /* Counter 0 overrun interrupt */ 102#define CIE1 0x0020 /* Counter 1 overrun interrupt */ 103#define CIE2 0x0040 /* Counter 2 overrun interrupt */ 104#define CIE3 0x0080 /* Counter 3 overrun interrupt */ 105 106/* Useful definitions */ 107#define Status_IRQ 0x00ff /* All interrupts */ 108 109/* Define analogue range */ 110static const struct comedi_lrange range_analog = { 4, { 111 UNI_RANGE(5), 112 UNI_RANGE(10), 113 BIP_RANGE(5), 114 BIP_RANGE(10) 115 } 116}; 117 118static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; 119 120/* 121============================================================================== 122 Data & Structure declarations 123============================================================================== 124*/ 125static unsigned short pci_list_builded; /*>0 list of card is known */ 126 127struct boardtype { 128 const char *name; /* driver name */ 129 int device_id; 130 int iorange; /* I/O range len */ 131 char have_irq; /* 1=card support IRQ */ 132 char cardtype; /* 0=ICP Multi */ 133 int n_aichan; /* num of A/D chans */ 134 int n_aichand; /* num of A/D chans in diff mode */ 135 int ai_maxdata; /* resolution of A/D */ 136 int ao_maxdata; /* resolution of D/A */ 137 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ 138 const char *rangecode; /* range codes for programming */ 139 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ 140}; 141 142struct icp_multi_private { 143 struct pcilst_struct *card; /* pointer to card */ 144 char valid; /* card is usable */ 145 void __iomem *io_addr; /* Pointer to mapped io address */ 146 resource_size_t phys_iobase; /* Physical io address */ 147 unsigned int AdcCmdStatus; /* ADC Command/Status register */ 148 unsigned int DacCmdStatus; /* DAC Command/Status register */ 149 unsigned int IntEnable; /* Interrupt Enable register */ 150 unsigned int IntStatus; /* Interrupt Status register */ 151 unsigned int act_chanlist[32]; /* list of scaned channel */ 152 unsigned char act_chanlist_len; /* len of scanlist */ 153 unsigned char act_chanlist_pos; /* actual position in MUX list */ 154 unsigned int *ai_chanlist; /* actaul chanlist */ 155 short *ai_data; /* data buffer */ 156 short ao_data[4]; /* data output buffer */ 157 short di_data; /* Digital input data */ 158 unsigned int do_data; /* Remember digital output data */ 159}; 160 161#define devpriv ((struct icp_multi_private *)dev->private) 162#define this_board ((const struct boardtype *)dev->board_ptr) 163 164/* 165============================================================================== 166 167Name: setup_channel_list 168 169Description: 170 This function sets the appropriate channel selection, 171 differential input mode and range bits in the ADC Command/ 172 Status register. 173 174Parameters: 175 struct comedi_device *dev Pointer to current service structure 176 struct comedi_subdevice *s Pointer to current subdevice structure 177 unsigned int *chanlist Pointer to packed channel list 178 unsigned int n_chan Number of channels to scan 179 180Returns:Void 181 182============================================================================== 183*/ 184static void setup_channel_list(struct comedi_device *dev, 185 struct comedi_subdevice *s, 186 unsigned int *chanlist, unsigned int n_chan) 187{ 188 unsigned int i, range, chanprog; 189 unsigned int diff; 190 191 devpriv->act_chanlist_len = n_chan; 192 devpriv->act_chanlist_pos = 0; 193 194 for (i = 0; i < n_chan; i++) { 195 /* Get channel */ 196 chanprog = CR_CHAN(chanlist[i]); 197 198 /* Determine if it is a differential channel (Bit 15 = 1) */ 199 if (CR_AREF(chanlist[i]) == AREF_DIFF) { 200 diff = 1; 201 chanprog &= 0x0007; 202 } else { 203 diff = 0; 204 chanprog &= 0x000f; 205 } 206 207 /* Clear channel, range and input mode bits 208 * in A/D command/status register */ 209 devpriv->AdcCmdStatus &= 0xf00f; 210 211 /* Set channel number and differential mode status bit */ 212 if (diff) { 213 /* Set channel number, bits 9-11 & mode, bit 6 */ 214 devpriv->AdcCmdStatus |= (chanprog << 9); 215 devpriv->AdcCmdStatus |= ADC_DI; 216 } else 217 /* Set channel number, bits 8-11 */ 218 devpriv->AdcCmdStatus |= (chanprog << 8); 219 220 /* Get range for current channel */ 221 range = this_board->rangecode[CR_RANGE(chanlist[i])]; 222 /* Set range. bits 4-5 */ 223 devpriv->AdcCmdStatus |= range; 224 225 /* Output channel, range, mode to ICP Multi */ 226 writew(devpriv->AdcCmdStatus, 227 devpriv->io_addr + ICP_MULTI_ADC_CSR); 228 } 229} 230 231/* 232============================================================================== 233 234Name: icp_multi_insn_read_ai 235 236Description: 237 This function reads a single analogue input. 238 239Parameters: 240 struct comedi_device *dev Pointer to current device structure 241 struct comedi_subdevice *s Pointer to current subdevice structure 242 struct comedi_insn *insn Pointer to current comedi instruction 243 unsigned int *data Pointer to analogue input data 244 245Returns:int Nmuber of instructions executed 246 247============================================================================== 248*/ 249static int icp_multi_insn_read_ai(struct comedi_device *dev, 250 struct comedi_subdevice *s, 251 struct comedi_insn *insn, unsigned int *data) 252{ 253 int n, timeout; 254 255 /* Disable A/D conversion ready interrupt */ 256 devpriv->IntEnable &= ~ADC_READY; 257 writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); 258 259 /* Clear interrupt status */ 260 devpriv->IntStatus |= ADC_READY; 261 writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); 262 263 /* Set up appropriate channel, mode and range data, for specified ch */ 264 setup_channel_list(dev, s, &insn->chanspec, 1); 265 266 for (n = 0; n < insn->n; n++) { 267 /* Set start ADC bit */ 268 devpriv->AdcCmdStatus |= ADC_ST; 269 writew(devpriv->AdcCmdStatus, 270 devpriv->io_addr + ICP_MULTI_ADC_CSR); 271 devpriv->AdcCmdStatus &= ~ADC_ST; 272 273 udelay(1); 274 275 /* Wait for conversion to complete, or get fed up waiting */ 276 timeout = 100; 277 while (timeout--) { 278 if (!(readw(devpriv->io_addr + 279 ICP_MULTI_ADC_CSR) & ADC_BSY)) 280 goto conv_finish; 281 282 udelay(1); 283 } 284 285 /* If we reach here, a timeout has occurred */ 286 comedi_error(dev, "A/D insn timeout"); 287 288 /* Disable interrupt */ 289 devpriv->IntEnable &= ~ADC_READY; 290 writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); 291 292 /* Clear interrupt status */ 293 devpriv->IntStatus |= ADC_READY; 294 writew(devpriv->IntStatus, 295 devpriv->io_addr + ICP_MULTI_INT_STAT); 296 297 /* Clear data received */ 298 data[n] = 0; 299 300 return -ETIME; 301 302conv_finish: 303 data[n] = 304 (readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff; 305 } 306 307 /* Disable interrupt */ 308 devpriv->IntEnable &= ~ADC_READY; 309 writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); 310 311 /* Clear interrupt status */ 312 devpriv->IntStatus |= ADC_READY; 313 writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); 314 315 return n; 316} 317 318/* 319============================================================================== 320 321Name: icp_multi_insn_write_ao 322 323Description: 324 This function writes a single analogue output. 325 326Parameters: 327 struct comedi_device *dev Pointer to current device structure 328 struct comedi_subdevice *s Pointer to current subdevice structure 329 struct comedi_insn *insn Pointer to current comedi instruction 330 unsigned int *data Pointer to analogue output data 331 332Returns:int Nmuber of instructions executed 333 334============================================================================== 335*/ 336static int icp_multi_insn_write_ao(struct comedi_device *dev, 337 struct comedi_subdevice *s, 338 struct comedi_insn *insn, unsigned int *data) 339{ 340 int n, chan, range, timeout; 341 342 /* Disable D/A conversion ready interrupt */ 343 devpriv->IntEnable &= ~DAC_READY; 344 writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); 345 346 /* Clear interrupt status */ 347 devpriv->IntStatus |= DAC_READY; 348 writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); 349 350 /* Get channel number and range */ 351 chan = CR_CHAN(insn->chanspec); 352 range = CR_RANGE(insn->chanspec); 353 354 /* Set up range and channel data */ 355 /* Bit 4 = 1 : Bipolar */ 356 /* Bit 5 = 0 : 5V */ 357 /* Bit 5 = 1 : 10V */ 358 /* Bits 8-9 : Channel number */ 359 devpriv->DacCmdStatus &= 0xfccf; 360 devpriv->DacCmdStatus |= this_board->rangecode[range]; 361 devpriv->DacCmdStatus |= (chan << 8); 362 363 writew(devpriv->DacCmdStatus, devpriv->io_addr + ICP_MULTI_DAC_CSR); 364 365 for (n = 0; n < insn->n; n++) { 366 /* Wait for analogue output data register to be 367 * ready for new data, or get fed up waiting */ 368 timeout = 100; 369 while (timeout--) { 370 if (!(readw(devpriv->io_addr + 371 ICP_MULTI_DAC_CSR) & DAC_BSY)) 372 goto dac_ready; 373 374 udelay(1); 375 } 376 377 /* If we reach here, a timeout has occurred */ 378 comedi_error(dev, "D/A insn timeout"); 379 380 /* Disable interrupt */ 381 devpriv->IntEnable &= ~DAC_READY; 382 writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); 383 384 /* Clear interrupt status */ 385 devpriv->IntStatus |= DAC_READY; 386 writew(devpriv->IntStatus, 387 devpriv->io_addr + ICP_MULTI_INT_STAT); 388 389 /* Clear data received */ 390 devpriv->ao_data[chan] = 0; 391 392 return -ETIME; 393 394dac_ready: 395 /* Write data to analogue output data register */ 396 writew(data[n], devpriv->io_addr + ICP_MULTI_AO); 397 398 /* Set DAC_ST bit to write the data to selected channel */ 399 devpriv->DacCmdStatus |= DAC_ST; 400 writew(devpriv->DacCmdStatus, 401 devpriv->io_addr + ICP_MULTI_DAC_CSR); 402 devpriv->DacCmdStatus &= ~DAC_ST; 403 404 /* Save analogue output data */ 405 devpriv->ao_data[chan] = data[n]; 406 } 407 408 return n; 409} 410 411/* 412============================================================================== 413 414Name: icp_multi_insn_read_ao 415 416Description: 417 This function reads a single analogue output. 418 419Parameters: 420 struct comedi_device *dev Pointer to current device structure 421 struct comedi_subdevice *s Pointer to current subdevice structure 422 struct comedi_insn *insn Pointer to current comedi instruction 423 unsigned int *data Pointer to analogue output data 424 425Returns:int Nmuber of instructions executed 426 427============================================================================== 428*/ 429static int icp_multi_insn_read_ao(struct comedi_device *dev, 430 struct comedi_subdevice *s, 431 struct comedi_insn *insn, unsigned int *data) 432{ 433 int n, chan; 434 435 /* Get channel number */ 436 chan = CR_CHAN(insn->chanspec); 437 438 /* Read analogue outputs */ 439 for (n = 0; n < insn->n; n++) 440 data[n] = devpriv->ao_data[chan]; 441 442 return n; 443} 444 445/* 446============================================================================== 447 448Name: icp_multi_insn_bits_di 449 450Description: 451 This function reads the digital inputs. 452 453Parameters: 454 struct comedi_device *dev Pointer to current device structure 455 struct comedi_subdevice *s Pointer to current subdevice structure 456 struct comedi_insn *insn Pointer to current comedi instruction 457 unsigned int *data Pointer to analogue output data 458 459Returns:int Nmuber of instructions executed 460 461============================================================================== 462*/ 463static int icp_multi_insn_bits_di(struct comedi_device *dev, 464 struct comedi_subdevice *s, 465 struct comedi_insn *insn, unsigned int *data) 466{ 467 data[1] = readw(devpriv->io_addr + ICP_MULTI_DI); 468 469 return insn->n; 470} 471 472/* 473============================================================================== 474 475Name: icp_multi_insn_bits_do 476 477Description: 478 This function writes the appropriate digital outputs. 479 480Parameters: 481 struct comedi_device *dev Pointer to current device structure 482 struct comedi_subdevice *s Pointer to current subdevice structure 483 struct comedi_insn *insn Pointer to current comedi instruction 484 unsigned int *data Pointer to analogue output data 485 486Returns:int Nmuber of instructions executed 487 488============================================================================== 489*/ 490static int icp_multi_insn_bits_do(struct comedi_device *dev, 491 struct comedi_subdevice *s, 492 struct comedi_insn *insn, unsigned int *data) 493{ 494 if (data[0]) { 495 s->state &= ~data[0]; 496 s->state |= (data[0] & data[1]); 497 498 printk(KERN_DEBUG "Digital outputs = %4x \n", s->state); 499 500 writew(s->state, devpriv->io_addr + ICP_MULTI_DO); 501 } 502 503 data[1] = readw(devpriv->io_addr + ICP_MULTI_DI); 504 505 return insn->n; 506} 507 508/* 509============================================================================== 510 511Name: icp_multi_insn_read_ctr 512 513Description: 514 This function reads the specified counter. 515 516Parameters: 517 struct comedi_device *dev Pointer to current device structure 518 struct comedi_subdevice *s Pointer to current subdevice structure 519 struct comedi_insn *insn Pointer to current comedi instruction 520 unsigned int *data Pointer to counter data 521 522Returns:int Nmuber of instructions executed 523 524============================================================================== 525*/ 526static int icp_multi_insn_read_ctr(struct comedi_device *dev, 527 struct comedi_subdevice *s, 528 struct comedi_insn *insn, unsigned int *data) 529{ 530 return 0; 531} 532 533/* 534============================================================================== 535 536Name: icp_multi_insn_write_ctr 537 538Description: 539 This function write to the specified counter. 540 541Parameters: 542 struct comedi_device *dev Pointer to current device structure 543 struct comedi_subdevice *s Pointer to current subdevice structure 544 struct comedi_insn *insn Pointer to current comedi instruction 545 unsigned int *data Pointer to counter data 546 547Returns:int Nmuber of instructions executed 548 549============================================================================== 550*/ 551static int icp_multi_insn_write_ctr(struct comedi_device *dev, 552 struct comedi_subdevice *s, 553 struct comedi_insn *insn, 554 unsigned int *data) 555{ 556 return 0; 557} 558 559/* 560============================================================================== 561 562Name: interrupt_service_icp_multi 563 564Description: 565 This function is the interrupt service routine for all 566 interrupts generated by the icp multi board. 567 568Parameters: 569 int irq 570 void *d Pointer to current device 571 572============================================================================== 573*/ 574static irqreturn_t interrupt_service_icp_multi(int irq, void *d) 575{ 576 struct comedi_device *dev = d; 577 int int_no; 578 579 /* Is this interrupt from our board? */ 580 int_no = readw(devpriv->io_addr + ICP_MULTI_INT_STAT) & Status_IRQ; 581 if (!int_no) 582 /* No, exit */ 583 return IRQ_NONE; 584 585 /* Determine which interrupt is active & handle it */ 586 switch (int_no) { 587 case ADC_READY: 588 break; 589 case DAC_READY: 590 break; 591 case DOUT_ERROR: 592 break; 593 case DIN_STATUS: 594 break; 595 case CIE0: 596 break; 597 case CIE1: 598 break; 599 case CIE2: 600 break; 601 case CIE3: 602 break; 603 default: 604 break; 605 606 } 607 608 return IRQ_HANDLED; 609} 610 611#if 0 612/* 613============================================================================== 614 615Name: check_channel_list 616 617Description: 618 This function checks if the channel list, provided by user 619 is built correctly 620 621Parameters: 622 struct comedi_device *dev Pointer to current service structure 623 struct comedi_subdevice *s Pointer to current subdevice structure 624 unsigned int *chanlist Pointer to packed channel list 625 unsigned int n_chan Number of channels to scan 626 627Returns:int 0 = failure 628 1 = success 629 630============================================================================== 631*/ 632static int check_channel_list(struct comedi_device *dev, 633 struct comedi_subdevice *s, 634 unsigned int *chanlist, unsigned int n_chan) 635{ 636 unsigned int i; 637 638 /* Check that we at least have one channel to check */ 639 if (n_chan < 1) { 640 comedi_error(dev, "range/channel list is empty!"); 641 return 0; 642 } 643 /* Check all channels */ 644 for (i = 0; i < n_chan; i++) { 645 /* Check that channel number is < maximum */ 646 if (CR_AREF(chanlist[i]) == AREF_DIFF) { 647 if (CR_CHAN(chanlist[i]) > this_board->n_aichand) { 648 comedi_error(dev, 649 "Incorrect differential ai ch-nr"); 650 return 0; 651 } 652 } else { 653 if (CR_CHAN(chanlist[i]) > this_board->n_aichan) { 654 comedi_error(dev, 655 "Incorrect ai channel number"); 656 return 0; 657 } 658 } 659 } 660 return 1; 661} 662#endif 663 664/* 665============================================================================== 666 667Name: icp_multi_reset 668 669Description: 670 This function resets the icp multi device to a 'safe' state 671 672Parameters: 673 struct comedi_device *dev Pointer to current service structure 674 675Returns:int 0 = success 676 677============================================================================== 678*/ 679static int icp_multi_reset(struct comedi_device *dev) 680{ 681 unsigned int i; 682 683 /* Clear INT enables and requests */ 684 writew(0, devpriv->io_addr + ICP_MULTI_INT_EN); 685 writew(0x00ff, devpriv->io_addr + ICP_MULTI_INT_STAT); 686 687 /* Set DACs to 0..5V range and 0V output */ 688 for (i = 0; i < 4; i++) { 689 devpriv->DacCmdStatus &= 0xfcce; 690 691 /* Set channel number */ 692 devpriv->DacCmdStatus |= (i << 8); 693 694 /* Output 0V */ 695 writew(0, devpriv->io_addr + ICP_MULTI_AO); 696 697 /* Set start conversion bit */ 698 devpriv->DacCmdStatus |= DAC_ST; 699 700 /* Output to command / status register */ 701 writew(devpriv->DacCmdStatus, 702 devpriv->io_addr + ICP_MULTI_DAC_CSR); 703 704 /* Delay to allow DAC time to recover */ 705 udelay(1); 706 } 707 708 /* Digital outputs to 0 */ 709 writew(0, devpriv->io_addr + ICP_MULTI_DO); 710 711 return 0; 712} 713 714static int icp_multi_attach(struct comedi_device *dev, 715 struct comedi_devconfig *it) 716{ 717 struct comedi_subdevice *s; 718 int ret, subdev, n_subdevices; 719 unsigned int irq; 720 struct pcilst_struct *card = NULL; 721 resource_size_t io_addr[5], iobase; 722 unsigned char pci_bus, pci_slot, pci_func; 723 724 printk(KERN_WARNING 725 "icp_multi EDBG: BGN: icp_multi_attach(...)\n"); 726 727 /* Allocate private data storage space */ 728 ret = alloc_private(dev, sizeof(struct icp_multi_private)); 729 if (ret < 0) 730 return ret; 731 732 /* Initialise list of PCI cards in system, if not already done so */ 733 if (pci_list_builded++ == 0) 734 pci_card_list_init(PCI_VENDOR_ID_ICP, 0); 735 736 printk(KERN_WARNING 737 "Anne's comedi%d: icp_multi: board=%s", dev->minor, 738 this_board->name); 739 740 card = select_and_alloc_pci_card(PCI_VENDOR_ID_ICP, 741 this_board->device_id, it->options[0], 742 it->options[1]); 743 744 if (card == NULL) 745 return -EIO; 746 747 devpriv->card = card; 748 749 if ((pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0], 750 &irq)) < 0) { 751 printk(KERN_WARNING " - Can't get configuration data!\n"); 752 return -EIO; 753 } 754 755 iobase = io_addr[2]; 756 devpriv->phys_iobase = iobase; 757 758 printk(KERN_WARNING 759 ", b:s:f=%d:%d:%d, io=0x%8llx \n", pci_bus, pci_slot, pci_func, 760 (unsigned long long)iobase); 761 762 devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE); 763 764 if (devpriv->io_addr == NULL) { 765 printk(KERN_WARNING "ioremap failed.\n"); 766 return -ENOMEM; 767 } 768 769 dev->board_name = this_board->name; 770 771 n_subdevices = 0; 772 if (this_board->n_aichan) 773 n_subdevices++; 774 n_subdevices++; 775 n_subdevices++; 776 n_subdevices++; 777 n_subdevices++; 778 779 ret = comedi_alloc_subdevices(dev, n_subdevices); 780 if (ret) 781 return ret; 782 783 icp_multi_reset(dev); 784 785 if (this_board->have_irq) { 786 if (irq) { 787 if (request_irq(irq, interrupt_service_icp_multi, 788 IRQF_SHARED, "Inova Icp Multi", dev)) { 789 printk(KERN_WARNING 790 "unable to allocate IRQ %u, DISABLING IT", 791 irq); 792 irq = 0; /* Can't use IRQ */ 793 } else 794 printk(KERN_WARNING ", irq=%u", irq); 795 } else 796 printk(KERN_WARNING ", IRQ disabled"); 797 } else 798 irq = 0; 799 800 dev->irq = irq; 801 802 printk(KERN_WARNING ".\n"); 803 804 subdev = 0; 805 806 if (this_board->n_aichan) { 807 s = &dev->subdevices[subdev]; 808 dev->read_subdev = s; 809 s->type = COMEDI_SUBD_AI; 810 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; 811 if (this_board->n_aichand) 812 s->subdev_flags |= SDF_DIFF; 813 s->n_chan = this_board->n_aichan; 814 s->maxdata = this_board->ai_maxdata; 815 s->len_chanlist = this_board->n_aichan; 816 s->range_table = this_board->rangelist_ai; 817 s->insn_read = icp_multi_insn_read_ai; 818 subdev++; 819 } 820 821 s = &dev->subdevices[subdev]; 822 s->type = COMEDI_SUBD_AO; 823 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 824 s->n_chan = 4; 825 s->maxdata = this_board->ao_maxdata; 826 s->len_chanlist = 4; 827 s->range_table = &range_analog; 828 s->insn_write = icp_multi_insn_write_ao; 829 s->insn_read = icp_multi_insn_read_ao; 830 subdev++; 831 832 s = &dev->subdevices[subdev]; 833 s->type = COMEDI_SUBD_DI; 834 s->subdev_flags = SDF_READABLE; 835 s->n_chan = 16; 836 s->maxdata = 1; 837 s->len_chanlist = 16; 838 s->range_table = &range_digital; 839 s->io_bits = 0; 840 s->insn_bits = icp_multi_insn_bits_di; 841 subdev++; 842 843 s = &dev->subdevices[subdev]; 844 s->type = COMEDI_SUBD_DO; 845 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 846 s->n_chan = 8; 847 s->maxdata = 1; 848 s->len_chanlist = 8; 849 s->range_table = &range_digital; 850 s->io_bits = 0xff; 851 s->state = 0; 852 s->insn_bits = icp_multi_insn_bits_do; 853 subdev++; 854 855 s = &dev->subdevices[subdev]; 856 s->type = COMEDI_SUBD_COUNTER; 857 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 858 s->n_chan = 4; 859 s->maxdata = 0xffff; 860 s->len_chanlist = 4; 861 s->state = 0; 862 s->insn_read = icp_multi_insn_read_ctr; 863 s->insn_write = icp_multi_insn_write_ctr; 864 subdev++; 865 866 devpriv->valid = 1; 867 868 return 0; 869} 870 871static void icp_multi_detach(struct comedi_device *dev) 872{ 873 if (dev->private) 874 if (devpriv->valid) 875 icp_multi_reset(dev); 876 if (dev->irq) 877 free_irq(dev->irq, dev); 878 if (dev->private && devpriv->io_addr) 879 iounmap(devpriv->io_addr); 880 if (dev->private && devpriv->card) 881 pci_card_free(devpriv->card); 882 if (--pci_list_builded == 0) 883 pci_card_list_cleanup(PCI_VENDOR_ID_ICP); 884} 885 886static const struct boardtype boardtypes[] = { 887 { 888 .name = "icp_multi", 889 .device_id = PCI_DEVICE_ID_ICP_MULTI, 890 .iorange = IORANGE_ICP_MULTI, 891 .have_irq = 1, 892 .cardtype = TYPE_ICP_MULTI, 893 .n_aichan = 16, 894 .n_aichand = 8, 895 .ai_maxdata = 0x0fff, 896 .ao_maxdata = 0x0fff, 897 .rangelist_ai = &range_analog, 898 .rangecode = range_codes_analog, 899 .rangelist_ao = &range_analog, 900 }, 901}; 902 903static struct comedi_driver icp_multi_driver = { 904 .driver_name = "icp_multi", 905 .module = THIS_MODULE, 906 .attach = icp_multi_attach, 907 .detach = icp_multi_detach, 908 .num_names = ARRAY_SIZE(boardtypes), 909 .board_name = &boardtypes[0].name, 910 .offset = sizeof(struct boardtype), 911}; 912 913static int __devinit icp_multi_pci_probe(struct pci_dev *dev, 914 const struct pci_device_id *ent) 915{ 916 return comedi_pci_auto_config(dev, &icp_multi_driver); 917} 918 919static void __devexit icp_multi_pci_remove(struct pci_dev *dev) 920{ 921 comedi_pci_auto_unconfig(dev); 922} 923 924static DEFINE_PCI_DEVICE_TABLE(icp_multi_pci_table) = { 925 { PCI_DEVICE(PCI_VENDOR_ID_ICP, PCI_DEVICE_ID_ICP_MULTI) }, 926 { 0 } 927}; 928MODULE_DEVICE_TABLE(pci, icp_multi_pci_table); 929 930static struct pci_driver icp_multi_pci_driver = { 931 .name = "icp_multi", 932 .id_table = icp_multi_pci_table, 933 .probe = icp_multi_pci_probe, 934 .remove = __devexit_p(icp_multi_pci_remove), 935}; 936module_comedi_pci_driver(icp_multi_driver, icp_multi_pci_driver); 937 938MODULE_AUTHOR("Comedi http://www.comedi.org"); 939MODULE_DESCRIPTION("Comedi low-level driver"); 940MODULE_LICENSE("GPL"); 941