Staging: Comedi: Lindent changes to comdi driver in staging tree
[safe/jmp/linux-2.6] / drivers / staging / comedi / drivers / amplc_pc263.c
1 /*
2     comedi/drivers/amplc_pc263.c
3     Driver for Amplicon PC263 and PCI263 relay boards.
4
5     Copyright (C) 2002 MEV Ltd. <http://www.mev.co.uk/>
6
7     COMEDI - Linux Control and Measurement Device Interface
8     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
9
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 */
25 /*
26 Driver: amplc_pc263
27 Description: Amplicon PC263, PCI263
28 Author: Ian Abbott <abbotti@mev.co.uk>
29 Devices: [Amplicon] PC263 (pc263), PCI263 (pci263 or amplc_pc263)
30 Updated: Wed, 22 Oct 2008 14:10:53 +0100
31 Status: works
32
33 Configuration options - PC263:
34   [0] - I/O port base address
35
36 Configuration options - PCI263:
37   [0] - PCI bus of device (optional)
38   [1] - PCI slot of device (optional)
39   If bus/slot is not specified, the first available PCI device will be
40   used.
41
42 Each board appears as one subdevice, with 16 digital outputs, each
43 connected to a reed-relay. Relay contacts are closed when output is 1.
44 The state of the outputs can be read.
45 */
46
47 #include "../comedidev.h"
48
49 #include "comedi_pci.h"
50
51 #define PC263_DRIVER_NAME       "amplc_pc263"
52
53 /* PCI263 PCI configuration register information */
54 #define PCI_VENDOR_ID_AMPLICON 0x14dc
55 #define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
56 #define PCI_DEVICE_ID_INVALID 0xffff
57
58 /* PC263 / PCI263 registers */
59 #define PC263_IO_SIZE   2
60
61 /*
62  * Board descriptions for Amplicon PC263 / PCI263.
63  */
64
65 enum pc263_bustype { isa_bustype, pci_bustype };
66 enum pc263_model { pc263_model, pci263_model, anypci_model };
67
68 struct pc263_board {
69         const char *name;
70         const char *fancy_name;
71         unsigned short devid;
72         enum pc263_bustype bustype;
73         enum pc263_model model;
74 };
75 static const struct pc263_board pc263_boards[] = {
76         {
77          .name = "pc263",
78          .fancy_name = "PC263",
79          .bustype = isa_bustype,
80          .model = pc263_model,
81          },
82 #ifdef CONFIG_COMEDI_PCI
83         {
84          .name = "pci263",
85          .fancy_name = "PCI263",
86          .devid = PCI_DEVICE_ID_AMPLICON_PCI263,
87          .bustype = pci_bustype,
88          .model = pci263_model,
89          },
90 #endif
91 #ifdef CONFIG_COMEDI_PCI
92         {
93          .name = PC263_DRIVER_NAME,
94          .fancy_name = PC263_DRIVER_NAME,
95          .devid = PCI_DEVICE_ID_INVALID,
96          .bustype = pci_bustype,
97          .model = anypci_model, /* wildcard */
98          },
99 #endif
100 };
101
102 #ifdef CONFIG_COMEDI_PCI
103 static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
104         {
105         PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263,
106                     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
107         0}
108 };
109
110 MODULE_DEVICE_TABLE(pci, pc263_pci_table);
111 #endif /* CONFIG_COMEDI_PCI */
112
113 /*
114  * Useful for shorthand access to the particular board structure
115  */
116 #define thisboard ((const struct pc263_board *)dev->board_ptr)
117
118 /* this structure is for data unique to this hardware driver.  If
119    several hardware drivers keep similar information in this structure,
120    feel free to suggest moving the variable to the struct comedi_device struct.  */
121 #ifdef CONFIG_COMEDI_PCI
122 struct pc263_private {
123         /* PCI device. */
124         struct pci_dev *pci_dev;
125 };
126
127 #define devpriv ((struct pc263_private *)dev->private)
128 #endif /* CONFIG_COMEDI_PCI */
129
130 /*
131  * The struct comedi_driver structure tells the Comedi core module
132  * which functions to call to configure/deconfigure (attach/detach)
133  * the board, and also about the kernel module that contains
134  * the device code.
135  */
136 static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it);
137 static int pc263_detach(struct comedi_device *dev);
138 static struct comedi_driver driver_amplc_pc263 = {
139         .driver_name = PC263_DRIVER_NAME,
140         .module = THIS_MODULE,
141         .attach = pc263_attach,
142         .detach = pc263_detach,
143         .board_name = &pc263_boards[0].name,
144         .offset = sizeof(struct pc263_board),
145         .num_names = ARRAY_SIZE(pc263_boards),
146 };
147
148 static int pc263_request_region(unsigned minor, unsigned long from,
149                                 unsigned long extent);
150 static int pc263_dio_insn_bits(struct comedi_device *dev,
151                                struct comedi_subdevice *s,
152                                struct comedi_insn *insn, unsigned int *data);
153 static int pc263_dio_insn_config(struct comedi_device *dev,
154                                  struct comedi_subdevice *s,
155                                  struct comedi_insn *insn, unsigned int *data);
156
157 /*
158  * This function looks for a PCI device matching the requested board name,
159  * bus and slot.
160  */
161 #ifdef CONFIG_COMEDI_PCI
162 static int
163 pc263_find_pci(struct comedi_device *dev, int bus, int slot,
164                struct pci_dev **pci_dev_p)
165 {
166         struct pci_dev *pci_dev = NULL;
167
168         *pci_dev_p = NULL;
169
170         /* Look for matching PCI device. */
171         for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
172              pci_dev != NULL;
173              pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
174                                       PCI_ANY_ID, pci_dev)) {
175                 /* If bus/slot specified, check them. */
176                 if (bus || slot) {
177                         if (bus != pci_dev->bus->number
178                             || slot != PCI_SLOT(pci_dev->devfn))
179                                 continue;
180                 }
181                 if (thisboard->model == anypci_model) {
182                         /* Match any supported model. */
183                         int i;
184
185                         for (i = 0; i < ARRAY_SIZE(pc263_boards); i++) {
186                                 if (pc263_boards[i].bustype != pci_bustype)
187                                         continue;
188                                 if (pci_dev->device == pc263_boards[i].devid) {
189                                         /* Change board_ptr to matched board. */
190                                         dev->board_ptr = &pc263_boards[i];
191                                         break;
192                                 }
193                         }
194                         if (i == ARRAY_SIZE(pc263_boards))
195                                 continue;
196                 } else {
197                         /* Match specific model name. */
198                         if (pci_dev->device != thisboard->devid)
199                                 continue;
200                 }
201
202                 /* Found a match. */
203                 *pci_dev_p = pci_dev;
204                 return 0;
205         }
206         /* No match found. */
207         if (bus || slot) {
208                 printk(KERN_ERR
209                        "comedi%d: error! no %s found at pci %02x:%02x!\n",
210                        dev->minor, thisboard->name, bus, slot);
211         } else {
212                 printk(KERN_ERR "comedi%d: error! no %s found!\n",
213                        dev->minor, thisboard->name);
214         }
215         return -EIO;
216 }
217 #endif
218
219 /*
220  * Attach is called by the Comedi core to configure the driver
221  * for a particular board.  If you specified a board_name array
222  * in the driver structure, dev->board_ptr contains that
223  * address.
224  */
225 static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
226 {
227         struct comedi_subdevice *s;
228         unsigned long iobase = 0;
229 #ifdef CONFIG_COMEDI_PCI
230         struct pci_dev *pci_dev = NULL;
231         int bus = 0, slot = 0;
232 #endif
233         int ret;
234
235         printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
236                PC263_DRIVER_NAME);
237 /*
238  * Allocate the private structure area.  alloc_private() is a
239  * convenient macro defined in comedidev.h.
240  */
241 #ifdef CONFIG_COMEDI_PCI
242         ret = alloc_private(dev, sizeof(struct pc263_private));
243         if (ret < 0) {
244                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
245                        dev->minor);
246                 return ret;
247         }
248 #endif
249         /* Process options. */
250         switch (thisboard->bustype) {
251         case isa_bustype:
252                 iobase = it->options[0];
253                 break;
254 #ifdef CONFIG_COMEDI_PCI
255         case pci_bustype:
256                 bus = it->options[0];
257                 slot = it->options[1];
258
259                 ret = pc263_find_pci(dev, bus, slot, &pci_dev);
260                 if (ret < 0)
261                         return ret;
262                 devpriv->pci_dev = pci_dev;
263                 break;
264 #endif /* CONFIG_COMEDI_PCI */
265         default:
266                 printk(KERN_ERR
267                        "comedi%d: %s: BUG! cannot determine board type!\n",
268                        dev->minor, PC263_DRIVER_NAME);
269                 return -EINVAL;
270                 break;
271         }
272
273 /*
274  * Initialize dev->board_name.
275  */
276         dev->board_name = thisboard->name;
277
278         /* Enable device and reserve I/O spaces. */
279 #ifdef CONFIG_COMEDI_PCI
280         if (pci_dev) {
281                 ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
282                 if (ret < 0) {
283                         printk(KERN_ERR
284                                "comedi%d: error! cannot enable PCI device and request regions!\n",
285                                dev->minor);
286                         return ret;
287                 }
288                 iobase = pci_resource_start(pci_dev, 2);
289         } else
290 #endif
291         {
292                 ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE);
293                 if (ret < 0) {
294                         return ret;
295                 }
296         }
297         dev->iobase = iobase;
298
299 /*
300  * Allocate the subdevice structures.  alloc_subdevice() is a
301  * convenient macro defined in comedidev.h.
302  */
303         ret = alloc_subdevices(dev, 1);
304         if (ret < 0) {
305                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
306                        dev->minor);
307                 return ret;
308         }
309
310         s = dev->subdevices + 0;
311         /* digital i/o subdevice */
312         s->type = COMEDI_SUBD_DIO;
313         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
314         s->n_chan = 16;
315         s->maxdata = 1;
316         s->range_table = &range_digital;
317         s->insn_bits = pc263_dio_insn_bits;
318         s->insn_config = pc263_dio_insn_config;
319         /* all outputs */
320         s->io_bits = 0xffff;
321         /* read initial relay state */
322         s->state = inb(dev->iobase);
323         s->state = s->state | (inb(dev->iobase) << 8);
324
325         printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
326         if (thisboard->bustype == isa_bustype) {
327                 printk("(base %#lx) ", iobase);
328         } else {
329 #ifdef CONFIG_COMEDI_PCI
330                 printk("(pci %s) ", pci_name(pci_dev));
331 #endif
332         }
333
334         printk("attached\n");
335
336         return 1;
337 }
338
339 /*
340  * _detach is called to deconfigure a device.  It should deallocate
341  * resources.
342  * This function is also called when _attach() fails, so it should be
343  * careful not to release resources that were not necessarily
344  * allocated by _attach().  dev->private and dev->subdevices are
345  * deallocated automatically by the core.
346  */
347 static int pc263_detach(struct comedi_device *dev)
348 {
349         printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
350                PC263_DRIVER_NAME);
351
352 #ifdef CONFIG_COMEDI_PCI
353         if (devpriv)
354 #endif
355         {
356 #ifdef CONFIG_COMEDI_PCI
357                 if (devpriv->pci_dev) {
358                         if (dev->iobase) {
359                                 comedi_pci_disable(devpriv->pci_dev);
360                         }
361                         pci_dev_put(devpriv->pci_dev);
362                 } else
363 #endif
364                 {
365                         if (dev->iobase) {
366                                 release_region(dev->iobase, PC263_IO_SIZE);
367                         }
368                 }
369         }
370         if (dev->board_name) {
371                 printk(KERN_INFO "comedi%d: %s removed\n",
372                        dev->minor, dev->board_name);
373         }
374         return 0;
375 }
376
377 /*
378  * This function checks and requests an I/O region, reporting an error
379  * if there is a conflict.
380  */
381 static int pc263_request_region(unsigned minor, unsigned long from,
382                                 unsigned long extent)
383 {
384         if (!from || !request_region(from, extent, PC263_DRIVER_NAME)) {
385                 printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
386                        minor, from, extent);
387                 return -EIO;
388         }
389         return 0;
390 }
391
392 /* DIO devices are slightly special.  Although it is possible to
393  * implement the insn_read/insn_write interface, it is much more
394  * useful to applications if you implement the insn_bits interface.
395  * This allows packed reading/writing of the DIO channels.  The
396  * comedi core can convert between insn_bits and insn_read/write */
397 static int pc263_dio_insn_bits(struct comedi_device *dev,
398                                struct comedi_subdevice *s,
399                                struct comedi_insn *insn, unsigned int *data)
400 {
401         if (insn->n != 2)
402                 return -EINVAL;
403
404         /* The insn data is a mask in data[0] and the new data
405          * in data[1], each channel cooresponding to a bit. */
406         if (data[0]) {
407                 s->state &= ~data[0];
408                 s->state |= data[0] & data[1];
409                 /* Write out the new digital output lines */
410                 outb(s->state & 0xFF, dev->iobase);
411                 outb(s->state >> 8, dev->iobase + 1);
412         }
413
414         /* on return, data[1] contains the value of the digital
415          * input and output lines. */
416         /* or we could just return the software copy of the output values if
417          * it was a purely digital output subdevice */
418         data[1] = s->state;
419
420         return 2;
421 }
422
423 static int pc263_dio_insn_config(struct comedi_device *dev,
424                                  struct comedi_subdevice *s,
425                                  struct comedi_insn *insn, unsigned int *data)
426 {
427         if (insn->n != 1)
428                 return -EINVAL;
429         return 1;
430 }
431
432 /*
433  * A convenient macro that defines init_module() and cleanup_module(),
434  * as necessary.
435  */
436 #ifdef CONFIG_COMEDI_PCI
437 COMEDI_PCI_INITCLEANUP(driver_amplc_pc263, pc263_pci_table);
438 #else
439 COMEDI_INITCLEANUP(driver_amplc_pc263);
440 #endif