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