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