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