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