dt2817.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
1/*
2    comedi/drivers/dt2817.c
3    Hardware driver for Data Translation DT2817
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 1998 David A. Schleef <ds@schleef.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23/*
24Driver: dt2817
25Description: Data Translation DT2817
26Author: ds
27Status: complete
28Devices: [Data Translation] DT2817 (dt2817)
29
30A very simple digital I/O card.  Four banks of 8 lines, each bank
31is configurable for input or output.  One wonders why it takes a
3250 page manual to describe this thing.
33
34The driver (which, btw, is much less than 50 pages) has 1 subdevice
35with 32 channels, configurable in groups of 8.
36
37Configuration options:
38  [0] - I/O port base base address
39*/
40
41#include "../comedidev.h"
42
43#include <linux/ioport.h>
44
45#define DT2817_SIZE 5
46
47#define DT2817_CR 0
48#define DT2817_DATA 1
49
50static int dt2817_attach(struct comedi_device *dev,
51			 struct comedi_devconfig *it);
52static int dt2817_detach(struct comedi_device *dev);
53static struct comedi_driver driver_dt2817 = {
54	.driver_name = "dt2817",
55	.module = THIS_MODULE,
56	.attach = dt2817_attach,
57	.detach = dt2817_detach,
58};
59
60COMEDI_INITCLEANUP(driver_dt2817);
61
62static int dt2817_dio_insn_config(struct comedi_device *dev,
63				  struct comedi_subdevice *s,
64				  struct comedi_insn *insn, unsigned int *data)
65{
66	int mask;
67	int chan;
68	int oe = 0;
69
70	if (insn->n != 1)
71		return -EINVAL;
72
73	chan = CR_CHAN(insn->chanspec);
74	if (chan < 8) {
75		mask = 0xff;
76	} else if (chan < 16) {
77		mask = 0xff00;
78	} else if (chan < 24) {
79		mask = 0xff0000;
80	} else
81		mask = 0xff000000;
82	if (data[0])
83		s->io_bits |= mask;
84	else
85		s->io_bits &= ~mask;
86
87	if (s->io_bits & 0x000000ff)
88		oe |= 0x1;
89	if (s->io_bits & 0x0000ff00)
90		oe |= 0x2;
91	if (s->io_bits & 0x00ff0000)
92		oe |= 0x4;
93	if (s->io_bits & 0xff000000)
94		oe |= 0x8;
95
96	outb(oe, dev->iobase + DT2817_CR);
97
98	return 1;
99}
100
101static int dt2817_dio_insn_bits(struct comedi_device *dev,
102				struct comedi_subdevice *s,
103				struct comedi_insn *insn, unsigned int *data)
104{
105	unsigned int changed;
106
107	/* It's questionable whether it is more important in
108	 * a driver like this to be deterministic or fast.
109	 * We choose fast. */
110
111	if (data[0]) {
112		changed = s->state;
113		s->state &= ~data[0];
114		s->state |= (data[0] & data[1]);
115		changed ^= s->state;
116		changed &= s->io_bits;
117		if (changed & 0x000000ff)
118			outb(s->state & 0xff, dev->iobase + DT2817_DATA + 0);
119		if (changed & 0x0000ff00)
120			outb((s->state >> 8) & 0xff,
121			     dev->iobase + DT2817_DATA + 1);
122		if (changed & 0x00ff0000)
123			outb((s->state >> 16) & 0xff,
124			     dev->iobase + DT2817_DATA + 2);
125		if (changed & 0xff000000)
126			outb((s->state >> 24) & 0xff,
127			     dev->iobase + DT2817_DATA + 3);
128	}
129	data[1] = inb(dev->iobase + DT2817_DATA + 0);
130	data[1] |= (inb(dev->iobase + DT2817_DATA + 1) << 8);
131	data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16);
132	data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24);
133
134	return 2;
135}
136
137static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
138{
139	int ret;
140	struct comedi_subdevice *s;
141	unsigned long iobase;
142
143	iobase = it->options[0];
144	printk("comedi%d: dt2817: 0x%04lx ", dev->minor, iobase);
145	if (!request_region(iobase, DT2817_SIZE, "dt2817")) {
146		printk("I/O port conflict\n");
147		return -EIO;
148	}
149	dev->iobase = iobase;
150	dev->board_name = "dt2817";
151
152	ret = alloc_subdevices(dev, 1);
153	if (ret < 0)
154		return ret;
155
156	s = dev->subdevices + 0;
157
158	s->n_chan = 32;
159	s->type = COMEDI_SUBD_DIO;
160	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
161	s->range_table = &range_digital;
162	s->maxdata = 1;
163	s->insn_bits = dt2817_dio_insn_bits;
164	s->insn_config = dt2817_dio_insn_config;
165
166	s->state = 0;
167	outb(0, dev->iobase + DT2817_CR);
168
169	printk("\n");
170
171	return 0;
172}
173
174static int dt2817_detach(struct comedi_device *dev)
175{
176	printk("comedi%d: dt2817: remove\n", dev->minor);
177
178	if (dev->iobase)
179		release_region(dev->iobase, DT2817_SIZE);
180
181	return 0;
182}
183