2 comedi/drivers/amplc_pc263.c
3 Driver for Amplicon PC263 and PCI263 relay boards.
5 Copyright (C) 2002 MEV Ltd. <http://www.mev.co.uk/>
7 COMEDI - Linux Control and Measurement Device Interface
8 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
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.
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.
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.
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
33 Configuration options - PC263:
34 [0] - I/O port base address
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
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.
47 #include "../comedidev.h"
49 #include "comedi_pci.h"
51 #define PC263_DRIVER_NAME "amplc_pc263"
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
58 /* PC263 / PCI263 registers */
59 #define PC263_IO_SIZE 2
62 * Board descriptions for Amplicon PC263 / PCI263.
65 enum pc263_bustype { isa_bustype, pci_bustype };
66 enum pc263_model { pc263_model, pci263_model, anypci_model };
70 const char *fancy_name;
72 enum pc263_bustype bustype;
73 enum pc263_model model;
75 static const struct pc263_board pc263_boards[] = {
78 .fancy_name = "PC263",
79 .bustype = isa_bustype,
82 #ifdef CONFIG_COMEDI_PCI
85 .fancy_name = "PCI263",
86 .devid = PCI_DEVICE_ID_AMPLICON_PCI263,
87 .bustype = pci_bustype,
88 .model = pci263_model,
91 #ifdef CONFIG_COMEDI_PCI
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 */
102 #ifdef CONFIG_COMEDI_PCI
103 static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
105 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263,
106 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
110 MODULE_DEVICE_TABLE(pci, pc263_pci_table);
111 #endif /* CONFIG_COMEDI_PCI */
114 * Useful for shorthand access to the particular board structure
116 #define thisboard ((const struct pc263_board *)dev->board_ptr)
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 {
124 struct pci_dev *pci_dev;
127 #define devpriv ((struct pc263_private *)dev->private)
128 #endif /* CONFIG_COMEDI_PCI */
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
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),
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);
158 * This function looks for a PCI device matching the requested board name,
161 #ifdef CONFIG_COMEDI_PCI
163 pc263_find_pci(struct comedi_device *dev, int bus, int slot,
164 struct pci_dev **pci_dev_p)
166 struct pci_dev *pci_dev = NULL;
170 /* Look for matching PCI device. */
171 for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
173 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
174 PCI_ANY_ID, pci_dev)) {
175 /* If bus/slot specified, check them. */
177 if (bus != pci_dev->bus->number
178 || slot != PCI_SLOT(pci_dev->devfn))
181 if (thisboard->model == anypci_model) {
182 /* Match any supported model. */
185 for (i = 0; i < ARRAY_SIZE(pc263_boards); i++) {
186 if (pc263_boards[i].bustype != pci_bustype)
188 if (pci_dev->device == pc263_boards[i].devid) {
189 /* Change board_ptr to matched board. */
190 dev->board_ptr = &pc263_boards[i];
194 if (i == ARRAY_SIZE(pc263_boards))
197 /* Match specific model name. */
198 if (pci_dev->device != thisboard->devid)
203 *pci_dev_p = pci_dev;
206 /* No match found. */
209 "comedi%d: error! no %s found at pci %02x:%02x!\n",
210 dev->minor, thisboard->name, bus, slot);
212 printk(KERN_ERR "comedi%d: error! no %s found!\n",
213 dev->minor, thisboard->name);
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
225 static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
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;
235 printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
238 * Allocate the private structure area. alloc_private() is a
239 * convenient macro defined in comedidev.h.
241 #ifdef CONFIG_COMEDI_PCI
242 ret = alloc_private(dev, sizeof(struct pc263_private));
244 printk(KERN_ERR "comedi%d: error! out of memory!\n",
249 /* Process options. */
250 switch (thisboard->bustype) {
252 iobase = it->options[0];
254 #ifdef CONFIG_COMEDI_PCI
256 bus = it->options[0];
257 slot = it->options[1];
259 ret = pc263_find_pci(dev, bus, slot, &pci_dev);
262 devpriv->pci_dev = pci_dev;
264 #endif /* CONFIG_COMEDI_PCI */
267 "comedi%d: %s: BUG! cannot determine board type!\n",
268 dev->minor, PC263_DRIVER_NAME);
274 * Initialize dev->board_name.
276 dev->board_name = thisboard->name;
278 /* Enable device and reserve I/O spaces. */
279 #ifdef CONFIG_COMEDI_PCI
281 ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
284 "comedi%d: error! cannot enable PCI device and request regions!\n",
288 iobase = pci_resource_start(pci_dev, 2);
292 ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE);
297 dev->iobase = iobase;
300 * Allocate the subdevice structures. alloc_subdevice() is a
301 * convenient macro defined in comedidev.h.
303 ret = alloc_subdevices(dev, 1);
305 printk(KERN_ERR "comedi%d: error! out of memory!\n",
310 s = dev->subdevices + 0;
311 /* digital i/o subdevice */
312 s->type = COMEDI_SUBD_DIO;
313 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
316 s->range_table = &range_digital;
317 s->insn_bits = pc263_dio_insn_bits;
318 s->insn_config = pc263_dio_insn_config;
321 /* read initial relay state */
322 s->state = inb(dev->iobase);
323 s->state = s->state | (inb(dev->iobase) << 8);
325 printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
326 if (thisboard->bustype == isa_bustype) {
327 printk("(base %#lx) ", iobase);
329 #ifdef CONFIG_COMEDI_PCI
330 printk("(pci %s) ", pci_name(pci_dev));
334 printk("attached\n");
340 * _detach is called to deconfigure a device. It should deallocate
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.
347 static int pc263_detach(struct comedi_device *dev)
349 printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
352 #ifdef CONFIG_COMEDI_PCI
356 #ifdef CONFIG_COMEDI_PCI
357 if (devpriv->pci_dev) {
359 comedi_pci_disable(devpriv->pci_dev);
361 pci_dev_put(devpriv->pci_dev);
366 release_region(dev->iobase, PC263_IO_SIZE);
370 if (dev->board_name) {
371 printk(KERN_INFO "comedi%d: %s removed\n",
372 dev->minor, dev->board_name);
378 * This function checks and requests an I/O region, reporting an error
379 * if there is a conflict.
381 static int pc263_request_region(unsigned minor, unsigned long from,
382 unsigned long extent)
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);
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)
404 /* The insn data is a mask in data[0] and the new data
405 * in data[1], each channel cooresponding to a bit. */
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);
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 */
423 static int pc263_dio_insn_config(struct comedi_device *dev,
424 struct comedi_subdevice *s,
425 struct comedi_insn *insn, unsigned int *data)
433 * A convenient macro that defines init_module() and cleanup_module(),
436 #ifdef CONFIG_COMEDI_PCI
437 COMEDI_PCI_INITCLEANUP(driver_amplc_pc263, pc263_pci_table);
439 COMEDI_INITCLEANUP(driver_amplc_pc263);