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