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/*
18Driver: contec_pci_dio
19Description: Contec PIO1616L digital I/O board
20Devices: [Contec] PIO1616L (contec_pci_dio)
21Author: Stefano Rivoir <s.rivoir@gts.it>
22Updated: Wed, 27 Jun 2007 13:00:06 +0100
23Status: works
24
25Configuration Options: not applicable, uses comedi PCI auto config
26*/
27
28#include <linux/module.h>
29#include <linux/pci.h>
30
31#include "../comedidev.h"
32
33/*
34 * Register map
35 */
36#define PIO1616L_DI_REG		0x00
37#define PIO1616L_DO_REG		0x02
38
39static int contec_do_insn_bits(struct comedi_device *dev,
40			       struct comedi_subdevice *s,
41			       struct comedi_insn *insn,
42			       unsigned int *data)
43{
44	if (comedi_dio_update_state(s, data))
45		outw(s->state, dev->iobase + PIO1616L_DO_REG);
46
47	data[1] = s->state;
48
49	return insn->n;
50}
51
52static int contec_di_insn_bits(struct comedi_device *dev,
53			       struct comedi_subdevice *s,
54			       struct comedi_insn *insn, unsigned int *data)
55{
56	data[1] = inw(dev->iobase + PIO1616L_DI_REG);
57
58	return insn->n;
59}
60
61static int contec_auto_attach(struct comedi_device *dev,
62					unsigned long context_unused)
63{
64	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
65	struct comedi_subdevice *s;
66	int ret;
67
68	ret = comedi_pci_enable(dev);
69	if (ret)
70		return ret;
71	dev->iobase = pci_resource_start(pcidev, 0);
72
73	ret = comedi_alloc_subdevices(dev, 2);
74	if (ret)
75		return ret;
76
77	s = &dev->subdevices[0];
78	s->type		= COMEDI_SUBD_DI;
79	s->subdev_flags	= SDF_READABLE;
80	s->n_chan	= 16;
81	s->maxdata	= 1;
82	s->range_table	= &range_digital;
83	s->insn_bits	= contec_di_insn_bits;
84
85	s = &dev->subdevices[1];
86	s->type		= COMEDI_SUBD_DO;
87	s->subdev_flags	= SDF_WRITABLE;
88	s->n_chan	= 16;
89	s->maxdata	= 1;
90	s->range_table	= &range_digital;
91	s->insn_bits	= contec_do_insn_bits;
92
93	return 0;
94}
95
96static struct comedi_driver contec_pci_dio_driver = {
97	.driver_name	= "contec_pci_dio",
98	.module		= THIS_MODULE,
99	.auto_attach	= contec_auto_attach,
100	.detach		= comedi_pci_detach,
101};
102
103static int contec_pci_dio_pci_probe(struct pci_dev *dev,
104				    const struct pci_device_id *id)
105{
106	return comedi_pci_auto_config(dev, &contec_pci_dio_driver,
107				      id->driver_data);
108}
109
110static const struct pci_device_id contec_pci_dio_pci_table[] = {
111	{ PCI_DEVICE(PCI_VENDOR_ID_CONTEC, 0x8172) },
112	{ 0 }
113};
114MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table);
115
116static struct pci_driver contec_pci_dio_pci_driver = {
117	.name		= "contec_pci_dio",
118	.id_table	= contec_pci_dio_pci_table,
119	.probe		= contec_pci_dio_pci_probe,
120	.remove		= comedi_pci_auto_unconfig,
121};
122module_comedi_pci_driver(contec_pci_dio_driver, contec_pci_dio_pci_driver);
123
124MODULE_AUTHOR("Comedi http://www.comedi.org");
125MODULE_DESCRIPTION("Comedi low-level driver");
126MODULE_LICENSE("GPL");
127