contec_pci_dio.c revision 3256837311344ef7efa41c717a280f95207e5140
1/*
2    comedi/drivers/contec_pci_dio.c
3
4    COMEDI - Linux Control and Measurement Device Interface
5    Copyright (C) 2000 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/*
23Driver: contec_pci_dio
24Description: Contec PIO1616L digital I/O board
25Devices: [Contec] PIO1616L (contec_pci_dio)
26Author: Stefano Rivoir <s.rivoir@gts.it>
27Updated: Wed, 27 Jun 2007 13:00:06 +0100
28Status: works
29
30Configuration Options:
31  [0] - PCI bus of device (optional)
32  [1] - PCI slot of device (optional)
33  If bus/slot is not specified, the first supported
34  PCI device found will be used.
35*/
36
37#include "../comedidev.h"
38
39#define PCI_DEVICE_ID_PIO1616L 0x8172
40
41/*
42 * Register map
43 */
44#define PIO1616L_DI_REG		0x00
45#define PIO1616L_DO_REG		0x02
46
47static int contec_do_insn_bits(struct comedi_device *dev,
48			       struct comedi_subdevice *s,
49			       struct comedi_insn *insn, unsigned int *data)
50{
51	if (data[0]) {
52		s->state &= ~data[0];
53		s->state |= data[0] & data[1];
54
55		outw(s->state, dev->iobase + PIO1616L_DO_REG);
56	}
57	return insn->n;
58}
59
60static int contec_di_insn_bits(struct comedi_device *dev,
61			       struct comedi_subdevice *s,
62			       struct comedi_insn *insn, unsigned int *data)
63{
64	data[1] = inw(dev->iobase + PIO1616L_DI_REG);
65
66	return insn->n;
67}
68
69static struct pci_dev *contec_find_pci_dev(struct comedi_device *dev,
70					   struct comedi_devconfig *it)
71{
72	struct pci_dev *pcidev = NULL;
73	int bus = it->options[0];
74	int slot = it->options[1];
75
76	for_each_pci_dev(pcidev) {
77		if (bus || slot) {
78			if (bus != pcidev->bus->number ||
79				slot != PCI_SLOT(pcidev->devfn))
80				continue;
81		}
82		if (pcidev->vendor != PCI_VENDOR_ID_CONTEC ||
83		    pcidev->device != PCI_DEVICE_ID_PIO1616L)
84			continue;
85
86		return pcidev;
87	}
88	dev_err(dev->class_dev,
89		"No supported board found! (req. bus %d, slot %d)\n",
90		bus, slot);
91	return NULL;
92}
93
94static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
95{
96	struct pci_dev *pcidev;
97	struct comedi_subdevice *s;
98	int ret;
99
100	printk("comedi%d: contec: ", dev->minor);
101
102	ret = comedi_alloc_subdevices(dev, 2);
103	if (ret)
104		return ret;
105
106	pcidev = contec_find_pci_dev(dev, it);
107	if (!pcidev)
108		return -EIO;
109	comedi_set_hw_dev(dev, &pcidev->dev);
110	dev->board_name = dev->driver->driver_name;
111
112	if (comedi_pci_enable(pcidev, "contec_pci_dio")) {
113		printk("error enabling PCI device and request regions!\n");
114		return -EIO;
115	}
116	dev->iobase = pci_resource_start(pcidev, 0);
117	printk(" base addr %lx ", dev->iobase);
118
119	s = dev->subdevices + 0;
120
121	s->type = COMEDI_SUBD_DI;
122	s->subdev_flags = SDF_READABLE;
123	s->n_chan = 16;
124	s->maxdata = 1;
125	s->range_table = &range_digital;
126	s->insn_bits = contec_di_insn_bits;
127
128	s = dev->subdevices + 1;
129	s->type = COMEDI_SUBD_DO;
130	s->subdev_flags = SDF_WRITABLE;
131	s->n_chan = 16;
132	s->maxdata = 1;
133	s->range_table = &range_digital;
134	s->insn_bits = contec_do_insn_bits;
135
136	printk("attached\n");
137
138	return 1;
139}
140
141static void contec_detach(struct comedi_device *dev)
142{
143	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
144
145	if (pcidev) {
146		if (dev->iobase)
147			comedi_pci_disable(pcidev);
148		pci_dev_put(pcidev);
149	}
150}
151
152static struct comedi_driver contec_pci_dio_driver = {
153	.driver_name	= "contec_pci_dio",
154	.module		= THIS_MODULE,
155	.attach		= contec_attach,
156	.detach		= contec_detach,
157};
158
159static int __devinit contec_pci_dio_pci_probe(struct pci_dev *dev,
160					      const struct pci_device_id *ent)
161{
162	return comedi_pci_auto_config(dev, &contec_pci_dio_driver);
163}
164
165static void __devexit contec_pci_dio_pci_remove(struct pci_dev *dev)
166{
167	comedi_pci_auto_unconfig(dev);
168}
169
170static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = {
171	{ PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L) },
172	{ 0 }
173};
174MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table);
175
176static struct pci_driver contec_pci_dio_pci_driver = {
177	.name		= "contec_pci_dio",
178	.id_table	= contec_pci_dio_pci_table,
179	.probe		= contec_pci_dio_pci_probe,
180	.remove		= __devexit_p(contec_pci_dio_pci_remove),
181};
182module_comedi_pci_driver(contec_pci_dio_driver, contec_pci_dio_pci_driver);
183
184MODULE_AUTHOR("Comedi http://www.comedi.org");
185MODULE_DESCRIPTION("Comedi low-level driver");
186MODULE_LICENSE("GPL");
187