1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
27struct fl512_private {
28
29 short ao_readback[2];
30};
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
43
44
45
46static int fl512_ai_insn(struct comedi_device *dev,
47 struct comedi_subdevice *s, struct comedi_insn *insn,
48 unsigned int *data)
49{
50 int n;
51 unsigned int lo_byte, hi_byte;
52 char chan = CR_CHAN(insn->chanspec);
53 unsigned long iobase = dev->iobase;
54
55 for (n = 0; n < insn->n; n++) {
56
57
58 outb(chan, iobase + 2);
59 outb(0, iobase + 3);
60
61 udelay(30);
62 lo_byte = inb(iobase + 2);
63 hi_byte = inb(iobase + 3) & 0xf;
64 data[n] = lo_byte + (hi_byte << 8);
65 }
66 return n;
67}
68
69
70
71
72static int fl512_ao_insn(struct comedi_device *dev,
73 struct comedi_subdevice *s, struct comedi_insn *insn,
74 unsigned int *data)
75{
76 struct fl512_private *devpriv = dev->private;
77 int n;
78 int chan = CR_CHAN(insn->chanspec);
79 unsigned long iobase = dev->iobase;
80
81 for (n = 0; n < insn->n; n++) {
82
83 outb(data[n] & 0x0ff, iobase + 4 + 2 * chan);
84
85 outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan);
86 inb(iobase + 4 + 2 * chan);
87
88 devpriv->ao_readback[chan] = data[n];
89 }
90 return n;
91}
92
93
94
95
96
97static int fl512_ao_insn_readback(struct comedi_device *dev,
98 struct comedi_subdevice *s,
99 struct comedi_insn *insn, unsigned int *data)
100{
101 struct fl512_private *devpriv = dev->private;
102 int n;
103 int chan = CR_CHAN(insn->chanspec);
104
105 for (n = 0; n < insn->n; n++)
106 data[n] = devpriv->ao_readback[chan];
107
108 return n;
109}
110
111static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
112{
113 struct fl512_private *devpriv;
114 unsigned long iobase;
115 int ret;
116
117
118
119 struct comedi_subdevice *s;
120
121 iobase = it->options[0];
122 printk(KERN_INFO "comedi:%d fl512: 0x%04lx", dev->minor, iobase);
123 if (!request_region(iobase, FL512_SIZE, "fl512")) {
124 printk(KERN_WARNING " I/O port conflict\n");
125 return -EIO;
126 }
127 dev->iobase = iobase;
128 dev->board_name = "fl512";
129
130 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
131 if (!devpriv)
132 return -ENOMEM;
133 dev->private = devpriv;
134
135#if DEBUG
136 printk(KERN_DEBUG "malloc ok\n");
137#endif
138
139 ret = comedi_alloc_subdevices(dev, 2);
140 if (ret)
141 return ret;
142
143
144
145
146
147 s = &dev->subdevices[0];
148
149 s->type = COMEDI_SUBD_AI;
150
151 s->subdev_flags = SDF_READABLE | SDF_GROUND;
152
153 s->n_chan = 16;
154
155 s->maxdata = 0x0fff;
156
157 s->range_table = &range_fl512;
158
159 s->insn_read = fl512_ai_insn;
160 printk(KERN_INFO "comedi: fl512: subdevice 0 initialized\n");
161
162
163 s = &dev->subdevices[1];
164
165 s->type = COMEDI_SUBD_AO;
166
167 s->subdev_flags = SDF_WRITABLE;
168
169 s->n_chan = 2;
170
171 s->maxdata = 0x0fff;
172
173 s->range_table = &range_fl512;
174
175 s->insn_write = fl512_ao_insn;
176
177 s->insn_read = fl512_ao_insn_readback;
178 printk(KERN_INFO "comedi: fl512: subdevice 1 initialized\n");
179
180 return 1;
181}
182
183static void fl512_detach(struct comedi_device *dev)
184{
185 if (dev->iobase)
186 release_region(dev->iobase, FL512_SIZE);
187}
188
189static struct comedi_driver fl512_driver = {
190 .driver_name = "fl512",
191 .module = THIS_MODULE,
192 .attach = fl512_attach,
193 .detach = fl512_detach,
194};
195module_comedi_driver(fl512_driver);
196
197MODULE_AUTHOR("Comedi http://www.comedi.org");
198MODULE_DESCRIPTION("Comedi low-level driver");
199MODULE_LICENSE("GPL");
200