]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/addi-data/addi_common.c
staging: comedi_pci: make comedi_pci_disable() safe to call
[karo-tx-linux.git] / drivers / staging / comedi / drivers / addi-data / addi_common.c
1 /**
2 @verbatim
3
4 Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
5
6         ADDI-DATA GmbH
7         Dieselstrasse 3
8         D-77833 Ottersweier
9         Tel: +19(0)7223/9493-0
10         Fax: +49(0)7223/9493-92
11         http://www.addi-data.com
12         info@addi-data.com
13
14 This program is free software; you can redistribute it and/or modify it under
15 the terms of the GNU General Public License as published by the Free Software
16 Foundation; either version 2 of the License, or (at your option) any later
17 version.
18
19 This program is distributed in the hope that it will be useful, but WITHOUT ANY
20 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 PARTICULAR PURPOSE. See the GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License along with
24 this program; if not, write to the Free Software Foundation, Inc.,
25 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
27 You should also find the complete GPL in the COPYING file accompanying this
28 source code.
29
30 @endverbatim
31 */
32 /*
33
34   +-----------------------------------------------------------------------+
35   | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
36   +-----------------------------------------------------------------------+
37   | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
38   | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
39   +-----------------------------------------------------------------------+
40   | Project   : ADDI DATA         | Compiler : GCC                        |
41   | Modulname : addi_common.c     | Version  : 2.96                       |
42   +-------------------------------+---------------------------------------+
43   | Author    :           | Date     :                                    |
44   +-----------------------------------------------------------------------+
45   | Description : ADDI COMMON Main Module                                 |
46   +-----------------------------------------------------------------------+
47 */
48
49 #ifndef COMEDI_SUBD_TTLIO
50 #define COMEDI_SUBD_TTLIO   11  /* Digital Input Output But TTL */
51 #endif
52
53 static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev,
54                                      struct comedi_subdevice *s,
55                                      struct comedi_insn *insn,
56                                      unsigned int *data)
57 {
58         const struct addi_board *this_board = comedi_board(dev);
59         struct addi_private *devpriv = dev->private;
60         unsigned short w_Address = CR_CHAN(insn->chanspec);
61         unsigned short w_Data;
62
63         w_Data = addi_eeprom_readw(devpriv->i_IobaseAmcc,
64                 this_board->pc_EepromChip, 2 * w_Address);
65         data[0] = w_Data;
66
67         return insn->n;
68 }
69
70 static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
71 {
72         struct comedi_device *dev = d;
73         const struct addi_board *this_board = comedi_board(dev);
74
75         this_board->interrupt(irq, d);
76         return IRQ_RETVAL(1);
77 }
78
79 static int i_ADDI_Reset(struct comedi_device *dev)
80 {
81         const struct addi_board *this_board = comedi_board(dev);
82
83         this_board->reset(dev);
84         return 0;
85 }
86
87 static int addi_auto_attach(struct comedi_device *dev,
88                                       unsigned long context_unused)
89 {
90         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
91         const struct addi_board *this_board = comedi_board(dev);
92         struct addi_private *devpriv;
93         struct comedi_subdevice *s;
94         int ret, n_subdevices;
95         unsigned int dw_Dummy;
96
97         dev->board_name = this_board->pc_DriverName;
98
99         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
100         if (!devpriv)
101                 return -ENOMEM;
102         dev->private = devpriv;
103
104         ret = comedi_pci_enable(pcidev, dev->board_name);
105         if (ret)
106                 return ret;
107
108         if (!this_board->pc_EepromChip ||
109             strcmp(this_board->pc_EepromChip, ADDIDATA_9054)) {
110                 /* board does not have an eeprom or is not ADDIDATA_9054 */
111                 if (this_board->i_IorangeBase1)
112                         dev->iobase = pci_resource_start(pcidev, 1);
113                 else
114                         dev->iobase = pci_resource_start(pcidev, 0);
115
116                 devpriv->iobase = dev->iobase;
117                 devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0);
118                 devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2);
119         } else {
120                 /* board has an ADDIDATA_9054 eeprom */
121                 dev->iobase = pci_resource_start(pcidev, 2);
122                 devpriv->iobase = pci_resource_start(pcidev, 2);
123                 devpriv->dw_AiBase = ioremap(pci_resource_start(pcidev, 3),
124                                              this_board->i_IorangeBase3);
125         }
126         devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3);
127
128         /* Initialize parameters that can be overridden in EEPROM */
129         devpriv->s_EeParameters.i_NbrAiChannel = this_board->i_NbrAiChannel;
130         devpriv->s_EeParameters.i_NbrAoChannel = this_board->i_NbrAoChannel;
131         devpriv->s_EeParameters.i_AiMaxdata = this_board->i_AiMaxdata;
132         devpriv->s_EeParameters.i_AoMaxdata = this_board->i_AoMaxdata;
133         devpriv->s_EeParameters.i_NbrDiChannel = this_board->i_NbrDiChannel;
134         devpriv->s_EeParameters.i_NbrDoChannel = this_board->i_NbrDoChannel;
135         devpriv->s_EeParameters.i_DoMaxdata = this_board->i_DoMaxdata;
136         devpriv->s_EeParameters.i_Dma = this_board->i_Dma;
137         devpriv->s_EeParameters.i_Timer = this_board->i_Timer;
138         devpriv->s_EeParameters.ui_MinAcquisitiontimeNs =
139                 this_board->ui_MinAcquisitiontimeNs;
140         devpriv->s_EeParameters.ui_MinDelaytimeNs =
141                 this_board->ui_MinDelaytimeNs;
142
143         /* ## */
144
145         if (pcidev->irq > 0) {
146                 ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED,
147                                   dev->board_name, dev);
148                 if (ret == 0)
149                         dev->irq = pcidev->irq;
150         }
151
152         /*  Read eepeom and fill addi_board Structure */
153
154         if (this_board->i_PCIEeprom) {
155                 if (!(strcmp(this_board->pc_EepromChip, "S5920"))) {
156                         /*  Set 3 wait stait */
157                         if (!(strcmp(dev->board_name, "apci035")))
158                                 outl(0x80808082, devpriv->i_IobaseAmcc + 0x60);
159                         else
160                                 outl(0x83838383, devpriv->i_IobaseAmcc + 0x60);
161
162                         /*  Enable the interrupt for the controller */
163                         dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38);
164                         outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38);
165                 }
166                 addi_eeprom_read_info(dev, pci_resource_start(pcidev, 0));
167         }
168
169         n_subdevices = 7;
170         ret = comedi_alloc_subdevices(dev, n_subdevices);
171         if (ret)
172                 return ret;
173
174         /*  Allocate and Initialise AI Subdevice Structures */
175         s = &dev->subdevices[0];
176         if ((devpriv->s_EeParameters.i_NbrAiChannel)
177                 || (this_board->i_NbrAiChannelDiff)) {
178                 dev->read_subdev = s;
179                 s->type = COMEDI_SUBD_AI;
180                 s->subdev_flags =
181                         SDF_READABLE | SDF_COMMON | SDF_GROUND
182                         | SDF_DIFF;
183                 if (devpriv->s_EeParameters.i_NbrAiChannel) {
184                         s->n_chan =
185                                 devpriv->s_EeParameters.i_NbrAiChannel;
186                         devpriv->b_SingelDiff = 0;
187                 } else {
188                         s->n_chan = this_board->i_NbrAiChannelDiff;
189                         devpriv->b_SingelDiff = 1;
190                 }
191                 s->maxdata = devpriv->s_EeParameters.i_AiMaxdata;
192                 s->len_chanlist = this_board->i_AiChannelList;
193                 s->range_table = this_board->pr_AiRangelist;
194
195                 /* Set the initialisation flag */
196                 devpriv->b_AiInitialisation = 1;
197
198                 s->insn_config = this_board->ai_config;
199                 s->insn_read = this_board->ai_read;
200                 s->insn_write = this_board->ai_write;
201                 s->insn_bits = this_board->ai_bits;
202                 s->do_cmdtest = this_board->ai_cmdtest;
203                 s->do_cmd = this_board->ai_cmd;
204                 s->cancel = this_board->ai_cancel;
205
206         } else {
207                 s->type = COMEDI_SUBD_UNUSED;
208         }
209
210         /*  Allocate and Initialise AO Subdevice Structures */
211         s = &dev->subdevices[1];
212         if (devpriv->s_EeParameters.i_NbrAoChannel) {
213                 s->type = COMEDI_SUBD_AO;
214                 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
215                 s->n_chan = devpriv->s_EeParameters.i_NbrAoChannel;
216                 s->maxdata = devpriv->s_EeParameters.i_AoMaxdata;
217                 s->len_chanlist =
218                         devpriv->s_EeParameters.i_NbrAoChannel;
219                 s->range_table = this_board->pr_AoRangelist;
220                 s->insn_config = this_board->ao_config;
221                 s->insn_write = this_board->ao_write;
222         } else {
223                 s->type = COMEDI_SUBD_UNUSED;
224         }
225         /*  Allocate and Initialise DI Subdevice Structures */
226         s = &dev->subdevices[2];
227         if (devpriv->s_EeParameters.i_NbrDiChannel) {
228                 s->type = COMEDI_SUBD_DI;
229                 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
230                 s->n_chan = devpriv->s_EeParameters.i_NbrDiChannel;
231                 s->maxdata = 1;
232                 s->len_chanlist =
233                         devpriv->s_EeParameters.i_NbrDiChannel;
234                 s->range_table = &range_digital;
235                 s->io_bits = 0; /* all bits input */
236                 s->insn_config = this_board->di_config;
237                 s->insn_read = this_board->di_read;
238                 s->insn_write = this_board->di_write;
239                 s->insn_bits = this_board->di_bits;
240         } else {
241                 s->type = COMEDI_SUBD_UNUSED;
242         }
243         /*  Allocate and Initialise DO Subdevice Structures */
244         s = &dev->subdevices[3];
245         if (devpriv->s_EeParameters.i_NbrDoChannel) {
246                 s->type = COMEDI_SUBD_DO;
247                 s->subdev_flags =
248                         SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
249                 s->n_chan = devpriv->s_EeParameters.i_NbrDoChannel;
250                 s->maxdata = devpriv->s_EeParameters.i_DoMaxdata;
251                 s->len_chanlist =
252                         devpriv->s_EeParameters.i_NbrDoChannel;
253                 s->range_table = &range_digital;
254                 s->io_bits = 0xf;       /* all bits output */
255
256                 /* insn_config - for digital output memory */
257                 s->insn_config = this_board->do_config;
258                 s->insn_write = this_board->do_write;
259                 s->insn_bits = this_board->do_bits;
260                 s->insn_read = this_board->do_read;
261         } else {
262                 s->type = COMEDI_SUBD_UNUSED;
263         }
264
265         /*  Allocate and Initialise Timer Subdevice Structures */
266         s = &dev->subdevices[4];
267         if (devpriv->s_EeParameters.i_Timer) {
268                 s->type = COMEDI_SUBD_TIMER;
269                 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
270                 s->n_chan = 1;
271                 s->maxdata = 0;
272                 s->len_chanlist = 1;
273                 s->range_table = &range_digital;
274
275                 s->insn_write = this_board->timer_write;
276                 s->insn_read = this_board->timer_read;
277                 s->insn_config = this_board->timer_config;
278                 s->insn_bits = this_board->timer_bits;
279         } else {
280                 s->type = COMEDI_SUBD_UNUSED;
281         }
282
283         /*  Allocate and Initialise TTL */
284         s = &dev->subdevices[5];
285         if (this_board->i_NbrTTLChannel) {
286                 s->type = COMEDI_SUBD_TTLIO;
287                 s->subdev_flags =
288                         SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
289                 s->n_chan = this_board->i_NbrTTLChannel;
290                 s->maxdata = 1;
291                 s->io_bits = 0; /* all bits input */
292                 s->len_chanlist = this_board->i_NbrTTLChannel;
293                 s->range_table = &range_digital;
294                 s->insn_config = this_board->ttl_config;
295                 s->insn_bits = this_board->ttl_bits;
296                 s->insn_read = this_board->ttl_read;
297                 s->insn_write = this_board->ttl_write;
298         } else {
299                 s->type = COMEDI_SUBD_UNUSED;
300         }
301
302         /* EEPROM */
303         s = &dev->subdevices[6];
304         if (this_board->i_PCIEeprom) {
305                 s->type = COMEDI_SUBD_MEMORY;
306                 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
307                 s->n_chan = 256;
308                 s->maxdata = 0xffff;
309                 s->insn_read = i_ADDIDATA_InsnReadEeprom;
310         } else {
311                 s->type = COMEDI_SUBD_UNUSED;
312         }
313
314         i_ADDI_Reset(dev);
315         return 0;
316 }
317
318 static void i_ADDI_Detach(struct comedi_device *dev)
319 {
320         struct addi_private *devpriv = dev->private;
321
322         if (devpriv) {
323                 if (dev->iobase)
324                         i_ADDI_Reset(dev);
325                 if (dev->irq)
326                         free_irq(dev->irq, dev);
327                 if (devpriv->dw_AiBase)
328                         iounmap(devpriv->dw_AiBase);
329         }
330         comedi_pci_disable(dev);
331 }