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