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.
122 #ifdef CONFIG_COMEDI_PCI
123 struct pc263_private
{
125 struct pci_dev
*pci_dev
;
128 #define devpriv ((struct pc263_private *)dev->private)
129 #endif /* CONFIG_COMEDI_PCI */
132 * The struct comedi_driver structure tells the Comedi core module
133 * which functions to call to configure/deconfigure (attach/detach)
134 * the board, and also about the kernel module that contains
137 static int pc263_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
);
138 static int pc263_detach(struct comedi_device
*dev
);
139 static struct comedi_driver driver_amplc_pc263
= {
140 .driver_name
= PC263_DRIVER_NAME
,
141 .module
= THIS_MODULE
,
142 .attach
= pc263_attach
,
143 .detach
= pc263_detach
,
144 .board_name
= &pc263_boards
[0].name
,
145 .offset
= sizeof(struct pc263_board
),
146 .num_names
= ARRAY_SIZE(pc263_boards
),
149 static int pc263_request_region(unsigned minor
, unsigned long from
,
150 unsigned long extent
);
151 static int pc263_dio_insn_bits(struct comedi_device
*dev
,
152 struct comedi_subdevice
*s
,
153 struct comedi_insn
*insn
, unsigned int *data
);
154 static int pc263_dio_insn_config(struct comedi_device
*dev
,
155 struct comedi_subdevice
*s
,
156 struct comedi_insn
*insn
, unsigned int *data
);
159 * This function looks for a PCI device matching the requested board name,
162 #ifdef CONFIG_COMEDI_PCI
164 pc263_find_pci(struct comedi_device
*dev
, int bus
, int slot
,
165 struct pci_dev
**pci_dev_p
)
167 struct pci_dev
*pci_dev
= NULL
;
171 /* Look for matching PCI device. */
172 for (pci_dev
= pci_get_device(PCI_VENDOR_ID_AMPLICON
, PCI_ANY_ID
, NULL
);
174 pci_dev
= pci_get_device(PCI_VENDOR_ID_AMPLICON
,
175 PCI_ANY_ID
, pci_dev
)) {
176 /* If bus/slot specified, check them. */
178 if (bus
!= pci_dev
->bus
->number
179 || slot
!= PCI_SLOT(pci_dev
->devfn
))
182 if (thisboard
->model
== anypci_model
) {
183 /* Match any supported model. */
186 for (i
= 0; i
< ARRAY_SIZE(pc263_boards
); i
++) {
187 if (pc263_boards
[i
].bustype
!= pci_bustype
)
189 if (pci_dev
->device
== pc263_boards
[i
].devid
) {
190 /* Change board_ptr to matched board. */
191 dev
->board_ptr
= &pc263_boards
[i
];
195 if (i
== ARRAY_SIZE(pc263_boards
))
198 /* Match specific model name. */
199 if (pci_dev
->device
!= thisboard
->devid
)
204 *pci_dev_p
= pci_dev
;
207 /* No match found. */
210 "comedi%d: error! no %s found at pci %02x:%02x!\n",
211 dev
->minor
, thisboard
->name
, bus
, slot
);
213 printk(KERN_ERR
"comedi%d: error! no %s found!\n",
214 dev
->minor
, thisboard
->name
);
221 * Attach is called by the Comedi core to configure the driver
222 * for a particular board. If you specified a board_name array
223 * in the driver structure, dev->board_ptr contains that
226 static int pc263_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
228 struct comedi_subdevice
*s
;
229 unsigned long iobase
= 0;
230 #ifdef CONFIG_COMEDI_PCI
231 struct pci_dev
*pci_dev
= NULL
;
232 int bus
= 0, slot
= 0;
236 printk(KERN_DEBUG
"comedi%d: %s: attach\n", dev
->minor
,
239 * Allocate the private structure area. alloc_private() is a
240 * convenient macro defined in comedidev.h.
242 #ifdef CONFIG_COMEDI_PCI
243 ret
= alloc_private(dev
, sizeof(struct pc263_private
));
245 printk(KERN_ERR
"comedi%d: error! out of memory!\n",
250 /* Process options. */
251 switch (thisboard
->bustype
) {
253 iobase
= it
->options
[0];
255 #ifdef CONFIG_COMEDI_PCI
257 bus
= it
->options
[0];
258 slot
= it
->options
[1];
260 ret
= pc263_find_pci(dev
, bus
, slot
, &pci_dev
);
263 devpriv
->pci_dev
= pci_dev
;
265 #endif /* CONFIG_COMEDI_PCI */
268 "comedi%d: %s: BUG! cannot determine board type!\n",
269 dev
->minor
, PC263_DRIVER_NAME
);
275 * Initialize dev->board_name.
277 dev
->board_name
= thisboard
->name
;
279 /* Enable device and reserve I/O spaces. */
280 #ifdef CONFIG_COMEDI_PCI
282 ret
= comedi_pci_enable(pci_dev
, PC263_DRIVER_NAME
);
285 "comedi%d: error! cannot enable PCI device and "
286 "request regions!\n",
290 iobase
= pci_resource_start(pci_dev
, 2);
294 ret
= pc263_request_region(dev
->minor
, iobase
, PC263_IO_SIZE
);
298 dev
->iobase
= iobase
;
301 * Allocate the subdevice structures. alloc_subdevice() is a
302 * convenient macro defined in comedidev.h.
304 ret
= alloc_subdevices(dev
, 1);
306 printk(KERN_ERR
"comedi%d: error! out of memory!\n",
311 s
= dev
->subdevices
+ 0;
312 /* digital i/o subdevice */
313 s
->type
= COMEDI_SUBD_DIO
;
314 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
317 s
->range_table
= &range_digital
;
318 s
->insn_bits
= pc263_dio_insn_bits
;
319 s
->insn_config
= pc263_dio_insn_config
;
322 /* read initial relay state */
323 s
->state
= inb(dev
->iobase
);
324 s
->state
= s
->state
| (inb(dev
->iobase
) << 8);
326 printk(KERN_INFO
"comedi%d: %s ", dev
->minor
, dev
->board_name
);
327 if (thisboard
->bustype
== isa_bustype
) {
328 printk("(base %#lx) ", iobase
);
330 #ifdef CONFIG_COMEDI_PCI
331 printk("(pci %s) ", pci_name(pci_dev
));
335 printk("attached\n");
341 * _detach is called to deconfigure a device. It should deallocate
343 * This function is also called when _attach() fails, so it should be
344 * careful not to release resources that were not necessarily
345 * allocated by _attach(). dev->private and dev->subdevices are
346 * deallocated automatically by the core.
348 static int pc263_detach(struct comedi_device
*dev
)
350 printk(KERN_DEBUG
"comedi%d: %s: detach\n", dev
->minor
,
353 #ifdef CONFIG_COMEDI_PCI
356 #ifdef CONFIG_COMEDI_PCI
357 if (devpriv
->pci_dev
) {
359 comedi_pci_disable(devpriv
->pci_dev
);
360 pci_dev_put(devpriv
->pci_dev
);
365 release_region(dev
->iobase
, PC263_IO_SIZE
);
368 if (dev
->board_name
) {
369 printk(KERN_INFO
"comedi%d: %s removed\n",
370 dev
->minor
, dev
->board_name
);
376 * This function checks and requests an I/O region, reporting an error
377 * if there is a conflict.
379 static int pc263_request_region(unsigned minor
, unsigned long from
,
380 unsigned long extent
)
382 if (!from
|| !request_region(from
, extent
, PC263_DRIVER_NAME
)) {
383 printk(KERN_ERR
"comedi%d: I/O port conflict (%#lx,%lu)!\n",
384 minor
, from
, extent
);
390 /* DIO devices are slightly special. Although it is possible to
391 * implement the insn_read/insn_write interface, it is much more
392 * useful to applications if you implement the insn_bits interface.
393 * This allows packed reading/writing of the DIO channels. The
394 * comedi core can convert between insn_bits and insn_read/write */
395 static int pc263_dio_insn_bits(struct comedi_device
*dev
,
396 struct comedi_subdevice
*s
,
397 struct comedi_insn
*insn
, unsigned int *data
)
402 /* The insn data is a mask in data[0] and the new data
403 * in data[1], each channel cooresponding to a bit. */
405 s
->state
&= ~data
[0];
406 s
->state
|= data
[0] & data
[1];
407 /* Write out the new digital output lines */
408 outb(s
->state
& 0xFF, dev
->iobase
);
409 outb(s
->state
>> 8, dev
->iobase
+ 1);
412 /* on return, data[1] contains the value of the digital
413 * input and output lines. */
414 /* or we could just return the software copy of the output values if
415 * it was a purely digital output subdevice */
421 static int pc263_dio_insn_config(struct comedi_device
*dev
,
422 struct comedi_subdevice
*s
,
423 struct comedi_insn
*insn
, unsigned int *data
)
431 * A convenient macro that defines init_module() and cleanup_module(),
434 #ifdef CONFIG_COMEDI_PCI
435 static int __devinit
driver_amplc_pc263_pci_probe(struct pci_dev
*dev
,
436 const struct pci_device_id
439 return comedi_pci_auto_config(dev
, driver_amplc_pc263
.driver_name
);
442 static void __devexit
driver_amplc_pc263_pci_remove(struct pci_dev
*dev
)
444 comedi_pci_auto_unconfig(dev
);
447 static struct pci_driver driver_amplc_pc263_pci_driver
= {
448 .id_table
= pc263_pci_table
,
449 .probe
= &driver_amplc_pc263_pci_probe
,
450 .remove
= __devexit_p(&driver_amplc_pc263_pci_remove
)
453 static int __init
driver_amplc_pc263_init_module(void)
457 retval
= comedi_driver_register(&driver_amplc_pc263
);
461 driver_amplc_pc263_pci_driver
.name
=
462 (char *)driver_amplc_pc263
.driver_name
;
463 return pci_register_driver(&driver_amplc_pc263_pci_driver
);
466 static void __exit
driver_amplc_pc263_cleanup_module(void)
468 pci_unregister_driver(&driver_amplc_pc263_pci_driver
);
469 comedi_driver_unregister(&driver_amplc_pc263
);
472 module_init(driver_amplc_pc263_init_module
);
473 module_exit(driver_amplc_pc263_cleanup_module
);
475 static int __init
driver_amplc_pc263_init_module(void)
477 return comedi_driver_register(&driver_amplc_pc263
);
480 static void __exit
driver_amplc_pc263_cleanup_module(void)
482 comedi_driver_unregister(&driver_amplc_pc263
);
485 module_init(driver_amplc_pc263_init_module
);
486 module_exit(driver_amplc_pc263_cleanup_module
);
489 MODULE_AUTHOR("Comedi http://www.comedi.org");
490 MODULE_DESCRIPTION("Comedi low-level driver");
491 MODULE_LICENSE("GPL");