dt2817.c revision 790c55415aa31f4c732729f94d2c3a54f7d3bfc2
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(comedi_device * dev, comedi_devconfig * it);
51static int dt2817_detach(comedi_device * dev);
52static comedi_driver driver_dt2817 = {
53      driver_name:"dt2817",
54      module:THIS_MODULE,
55      attach:dt2817_attach,
56      detach:dt2817_detach,
57};
58
59COMEDI_INITCLEANUP(driver_dt2817);
60
61static int dt2817_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
62	comedi_insn * insn, unsigned int * data)
63{
64	int mask;
65	int chan;
66	int oe = 0;
67
68	if (insn->n != 1)
69		return -EINVAL;
70
71	chan = CR_CHAN(insn->chanspec);
72	if (chan < 8) {
73		mask = 0xff;
74	} else if (chan < 16) {
75		mask = 0xff00;
76	} else if (chan < 24) {
77		mask = 0xff0000;
78	} else
79		mask = 0xff000000;
80	if (data[0])
81		s->io_bits |= mask;
82	else
83		s->io_bits &= ~mask;
84
85	if (s->io_bits & 0x000000ff)
86		oe |= 0x1;
87	if (s->io_bits & 0x0000ff00)
88		oe |= 0x2;
89	if (s->io_bits & 0x00ff0000)
90		oe |= 0x4;
91	if (s->io_bits & 0xff000000)
92		oe |= 0x8;
93
94	outb(oe, dev->iobase + DT2817_CR);
95
96	return 1;
97}
98
99static int dt2817_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
100	comedi_insn * insn, unsigned int * data)
101{
102	unsigned int changed;
103
104	/* It's questionable whether it is more important in
105	 * a driver like this to be deterministic or fast.
106	 * We choose fast. */
107
108	if (data[0]) {
109		changed = s->state;
110		s->state &= ~data[0];
111		s->state |= (data[0] & data[1]);
112		changed ^= s->state;
113		changed &= s->io_bits;
114		if (changed & 0x000000ff)
115			outb(s->state & 0xff, dev->iobase + DT2817_DATA + 0);
116		if (changed & 0x0000ff00)
117			outb((s->state >> 8) & 0xff,
118				dev->iobase + DT2817_DATA + 1);
119		if (changed & 0x00ff0000)
120			outb((s->state >> 16) & 0xff,
121				dev->iobase + DT2817_DATA + 2);
122		if (changed & 0xff000000)
123			outb((s->state >> 24) & 0xff,
124				dev->iobase + DT2817_DATA + 3);
125	}
126	data[1] = inb(dev->iobase + DT2817_DATA + 0);
127	data[1] |= (inb(dev->iobase + DT2817_DATA + 1) << 8);
128	data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16);
129	data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24);
130
131	return 2;
132}
133
134static int dt2817_attach(comedi_device * dev, comedi_devconfig * it)
135{
136	int ret;
137	comedi_subdevice *s;
138	unsigned long iobase;
139
140	iobase = it->options[0];
141	printk("comedi%d: dt2817: 0x%04lx ", dev->minor, iobase);
142	if (!request_region(iobase, DT2817_SIZE, "dt2817")) {
143		printk("I/O port conflict\n");
144		return -EIO;
145	}
146	dev->iobase = iobase;
147	dev->board_name = "dt2817";
148
149	if ((ret = alloc_subdevices(dev, 1)) < 0)
150		return ret;
151
152	s = dev->subdevices + 0;
153
154	s->n_chan = 32;
155	s->type = COMEDI_SUBD_DIO;
156	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
157	s->range_table = &range_digital;
158	s->maxdata = 1;
159	s->insn_bits = dt2817_dio_insn_bits;
160	s->insn_config = dt2817_dio_insn_config;
161
162	s->state = 0;
163	outb(0, dev->iobase + DT2817_CR);
164
165	printk("\n");
166
167	return 0;
168}
169
170static int dt2817_detach(comedi_device * dev)
171{
172	printk("comedi%d: dt2817: remove\n", dev->minor);
173
174	if (dev->iobase)
175		release_region(dev->iobase, DT2817_SIZE);
176
177	return 0;
178}
179