poc.c revision 139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88
1/*
2    comedi/drivers/poc.c
3    Mini-drivers for POC (Piece of Crap) boards
4    Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
5    Copyright (C) 2001 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/*
22Driver: poc
23Description: Generic driver for very simple devices
24Author: ds
25Devices: [Keithley Metrabyte] DAC-02 (dac02), [Advantech] PCL-733 (pcl733),
26  PCL-734 (pcl734)
27Updated: Sat, 16 Mar 2002 17:34:48 -0800
28Status: unknown
29
30This driver is indended to support very simple ISA-based devices,
31including:
32  dac02 - Keithley DAC-02 analog output board
33  pcl733 - Advantech PCL-733
34  pcl734 - Advantech PCL-734
35
36Configuration options:
37  [0] - I/O port base
38*/
39
40#include "../comedidev.h"
41
42#include <linux/ioport.h>
43
44static int poc_attach(struct comedi_device * dev, comedi_devconfig * it);
45static int poc_detach(struct comedi_device * dev);
46static int readback_insn(struct comedi_device * dev, struct comedi_subdevice * s,
47	comedi_insn * insn, unsigned int * data);
48
49static int dac02_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
50	comedi_insn * insn, unsigned int * data);
51static int pcl733_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
52	comedi_insn * insn, unsigned int * data);
53static int pcl734_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
54	comedi_insn * insn, unsigned int * data);
55
56struct boarddef_struct {
57	const char *name;
58	unsigned int iosize;
59	int (*setup) (struct comedi_device *);
60	int type;
61	int n_chan;
62	int n_bits;
63	int (*winsn) (struct comedi_device *, struct comedi_subdevice *, comedi_insn *,
64		unsigned int *);
65	int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, comedi_insn *,
66		unsigned int *);
67	int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, comedi_insn *,
68		unsigned int *);
69	const comedi_lrange *range;
70};
71static const struct boarddef_struct boards[] = {
72	{
73	      name:	"dac02",
74	      iosize:	8,
75			//setup:                dac02_setup,
76	      type:	COMEDI_SUBD_AO,
77	      n_chan:	2,
78	      n_bits:	12,
79	      winsn:	dac02_ao_winsn,
80	      rinsn:	readback_insn,
81	      range:	&range_unknown,
82		},
83	{
84	      name:	"pcl733",
85	      iosize:	4,
86	      type:	COMEDI_SUBD_DI,
87	      n_chan:	32,
88	      n_bits:	1,
89	      insnbits:pcl733_insn_bits,
90	      range:	&range_digital,
91		},
92	{
93	      name:	"pcl734",
94	      iosize:	4,
95	      type:	COMEDI_SUBD_DO,
96	      n_chan:	32,
97	      n_bits:	1,
98	      insnbits:pcl734_insn_bits,
99	      range:	&range_digital,
100		},
101};
102
103#define n_boards (sizeof(boards)/sizeof(boards[0]))
104#define this_board ((const struct boarddef_struct *)dev->board_ptr)
105
106static struct comedi_driver driver_poc = {
107      driver_name:"poc",
108      module:THIS_MODULE,
109      attach:poc_attach,
110      detach:poc_detach,
111      board_name:&boards[0].name,
112      num_names:n_boards,
113      offset:sizeof(boards[0]),
114};
115
116static int poc_attach(struct comedi_device * dev, comedi_devconfig * it)
117{
118	struct comedi_subdevice *s;
119	unsigned long iobase;
120	unsigned int iosize;
121
122	iobase = it->options[0];
123	printk("comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
124		this_board->name, iobase);
125
126	dev->board_name = this_board->name;
127
128	if (iobase == 0) {
129		printk("io base address required\n");
130		return -EINVAL;
131	}
132
133	iosize = this_board->iosize;
134	/* check if io addresses are available */
135	if (!request_region(iobase, iosize, "dac02")) {
136		printk("I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
137		return -EIO;
138	}
139	dev->iobase = iobase;
140
141	if (alloc_subdevices(dev, 1) < 0)
142		return -ENOMEM;
143	if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
144		return -ENOMEM;
145
146	/* analog output subdevice */
147	s = dev->subdevices + 0;
148	s->type = this_board->type;
149	s->n_chan = this_board->n_chan;
150	s->maxdata = (1 << this_board->n_bits) - 1;
151	s->range_table = this_board->range;
152	s->insn_write = this_board->winsn;
153	s->insn_read = this_board->rinsn;
154	s->insn_bits = this_board->insnbits;
155	if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) {
156		s->subdev_flags = SDF_WRITABLE;
157	}
158
159	return 0;
160}
161
162static int poc_detach(struct comedi_device * dev)
163{
164	/* only free stuff if it has been allocated by _attach */
165	if (dev->iobase)
166		release_region(dev->iobase, this_board->iosize);
167
168	printk("comedi%d: dac02: remove\n", dev->minor);
169
170	return 0;
171}
172
173static int readback_insn(struct comedi_device * dev, struct comedi_subdevice * s,
174	comedi_insn * insn, unsigned int * data)
175{
176	int chan;
177
178	chan = CR_CHAN(insn->chanspec);
179	data[0] = ((unsigned int *) dev->private)[chan];
180
181	return 1;
182}
183
184/* DAC-02 registers */
185#define DAC02_LSB(a)	(2 * a)
186#define DAC02_MSB(a)	(2 * a + 1)
187
188static int dac02_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
189	comedi_insn * insn, unsigned int * data)
190{
191	int temp;
192	int chan;
193	int output;
194
195	chan = CR_CHAN(insn->chanspec);
196	((unsigned int *) dev->private)[chan] = data[0];
197	output = data[0];
198#ifdef wrong
199	// convert to complementary binary if range is bipolar
200	if ((CR_RANGE(insn->chanspec) & 0x2) == 0)
201		output = ~output;
202#endif
203	temp = (output << 4) & 0xf0;
204	outb(temp, dev->iobase + DAC02_LSB(chan));
205	temp = (output >> 4) & 0xff;
206	outb(temp, dev->iobase + DAC02_MSB(chan));
207
208	return 1;
209}
210
211static int pcl733_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
212	comedi_insn * insn, unsigned int * data)
213{
214	if (insn->n != 2)
215		return -EINVAL;
216
217	data[1] = inb(dev->iobase + 0);
218	data[1] |= (inb(dev->iobase + 1) << 8);
219	data[1] |= (inb(dev->iobase + 2) << 16);
220	data[1] |= (inb(dev->iobase + 3) << 24);
221
222	return 2;
223}
224
225static int pcl734_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
226	comedi_insn * insn, unsigned int * data)
227{
228	if (insn->n != 2)
229		return -EINVAL;
230	if (data[0]) {
231		s->state &= ~data[0];
232		s->state |= (data[0] & data[1]);
233		if ((data[0] >> 0) & 0xff)
234			outb((s->state >> 0) & 0xff, dev->iobase + 0);
235		if ((data[0] >> 8) & 0xff)
236			outb((s->state >> 8) & 0xff, dev->iobase + 1);
237		if ((data[0] >> 16) & 0xff)
238			outb((s->state >> 16) & 0xff, dev->iobase + 2);
239		if ((data[0] >> 24) & 0xff)
240			outb((s->state >> 24) & 0xff, dev->iobase + 3);
241	}
242	data[1] = s->state;
243
244	return 2;
245}
246
247COMEDI_INITCLEANUP(driver_poc);
248