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