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