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