fl512.c revision 0707bb04be89b18ee83b5a997e36cc585f0b988d
1/*
2    comedi/drivers/fl512.c
3    Anders Gnistrup <ex18@kalman.iau.dtu.dk>
4*/
5
6/*
7Driver: fl512
8Description: unknown
9Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk>
10Devices: [unknown] FL512 (fl512)
11Status: unknown
12
13Digital I/O is not supported.
14
15Configuration options:
16  [0] - I/O port base address
17*/
18
19#define DEBUG 0
20
21#include "../comedidev.h"
22
23#include <linux/delay.h>
24#include <linux/ioport.h>
25
26#define FL512_SIZE 16		/* the size of the used memory */
27typedef struct {
28	short ao_readback[2];
29} fl512_private;
30#define devpriv ((fl512_private *) dev->private)
31
32static const struct comedi_lrange range_fl512 = { 4, {
33			BIP_RANGE(0.5),
34			BIP_RANGE(1),
35			BIP_RANGE(5),
36			BIP_RANGE(10),
37			UNI_RANGE(1),
38			UNI_RANGE(5),
39			UNI_RANGE(10),
40	}
41};
42
43static int fl512_attach(struct comedi_device * dev, struct comedi_devconfig * it);
44static int fl512_detach(struct comedi_device * dev);
45
46static struct comedi_driver driver_fl512 = {
47      driver_name:"fl512",
48      module:THIS_MODULE,
49      attach:fl512_attach,
50      detach:fl512_detach,
51};
52
53COMEDI_INITCLEANUP(driver_fl512);
54
55static int fl512_ai_insn(struct comedi_device * dev,
56	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data);
57static int fl512_ao_insn(struct comedi_device * dev,
58	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data);
59static int fl512_ao_insn_readback(struct comedi_device * dev,
60	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data);
61
62/*
63 * fl512_ai_insn : this is the analog input function
64 */
65static int fl512_ai_insn(struct comedi_device * dev,
66	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
67{
68	int n;
69	unsigned int lo_byte, hi_byte;
70	char chan = CR_CHAN(insn->chanspec);
71	unsigned long iobase = dev->iobase;
72
73	for (n = 0; n < insn->n; n++) {	/* sample n times on selected channel */
74		/* XXX probably can move next step out of for() loop -- will make
75		 * AI a little bit faster. */
76		outb(chan, iobase + 2);	/* select chan */
77		outb(0, iobase + 3);	/* start conversion */
78		/* XXX should test "done" flag instead of delay */
79		comedi_udelay(30);	/* sleep 30 usec */
80		lo_byte = inb(iobase + 2);	/* low 8 byte */
81		hi_byte = inb(iobase + 3) & 0xf;	/* high 4 bit and mask */
82		data[n] = lo_byte + (hi_byte << 8);
83	}
84	return n;
85}
86
87/*
88 * fl512_ao_insn : used to write to a DA port n times
89 */
90static int fl512_ao_insn(struct comedi_device * dev,
91	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
92{
93	int n;
94	int chan = CR_CHAN(insn->chanspec);	/* get chan to write */
95	unsigned long iobase = dev->iobase;	/* get base address  */
96
97	for (n = 0; n < insn->n; n++) {	/* write n data set */
98		outb(data[n] & 0x0ff, iobase + 4 + 2 * chan);	/* write low byte   */
99		outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan);	/* write high byte  */
100		inb(iobase + 4 + 2 * chan);	/* trig */
101
102		devpriv->ao_readback[chan] = data[n];
103	}
104	return n;
105}
106
107/*
108 * fl512_ao_insn_readback : used to read previous values written to
109 * DA port
110 */
111static int fl512_ao_insn_readback(struct comedi_device * dev,
112	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
113{
114	int n;
115	int chan = CR_CHAN(insn->chanspec);
116
117	for (n = 0; n < insn->n; n++) {
118		data[n] = devpriv->ao_readback[chan];
119	}
120
121	return n;
122}
123
124/*
125 * start attach
126 */
127static int fl512_attach(struct comedi_device * dev, struct comedi_devconfig * it)
128{
129	unsigned long iobase;
130	struct comedi_subdevice *s;	/* pointer to the subdevice:
131				   Analog in, Analog out, ( not made ->and Digital IO) */
132
133	iobase = it->options[0];
134	printk("comedi:%d fl512: 0x%04lx", dev->minor, iobase);
135	if (!request_region(iobase, FL512_SIZE, "fl512")) {
136		printk(" I/O port conflict\n");
137		return -EIO;
138	}
139	dev->iobase = iobase;
140	dev->board_name = "fl512";
141	if (alloc_private(dev, sizeof(fl512_private)) < 0)
142		return -ENOMEM;
143
144#if DEBUG
145	printk("malloc ok\n");
146#endif
147
148	if (alloc_subdevices(dev, 2) < 0)
149		return -ENOMEM;
150
151	/*
152	 * this if the definitions of the supdevices, 2 have been defined
153	 */
154	/* Analog indput */
155	s = dev->subdevices + 0;
156	s->type = COMEDI_SUBD_AI;	/* define subdevice as Analog In   */
157	s->subdev_flags = SDF_READABLE | SDF_GROUND;	/* you can read it from userspace  */
158	s->n_chan = 16;		/* Number of Analog input channels */
159	s->maxdata = 0x0fff;	/* accept only 12 bits of data     */
160	s->range_table = &range_fl512;	/* device use one of the ranges    */
161	s->insn_read = fl512_ai_insn;	/* function to call when read AD   */
162	printk("comedi: fl512: subdevice 0 initialized\n");
163
164	/* Analog output */
165	s = dev->subdevices + 1;
166	s->type = COMEDI_SUBD_AO;	/* define subdevice as Analog OUT   */
167	s->subdev_flags = SDF_WRITABLE;	/* you can write it from userspace  */
168	s->n_chan = 2;		/* Number of Analog output channels */
169	s->maxdata = 0x0fff;	/* accept only 12 bits of data      */
170	s->range_table = &range_fl512;	/* device use one of the ranges     */
171	s->insn_write = fl512_ao_insn;	/* function to call when write DA   */
172	s->insn_read = fl512_ao_insn_readback;	/* function to call when reading DA   */
173	printk("comedi: fl512: subdevice 1 initialized\n");
174
175	return 1;
176}
177
178static int fl512_detach(struct comedi_device * dev)
179{
180	if (dev->iobase)
181		release_region(dev->iobase, FL512_SIZE);
182	printk("comedi%d: fl512: dummy i detach\n", dev->minor);
183	return 0;
184}
185