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