1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/sched.h>
41#include <linux/mm.h>
42#include <linux/errno.h>
43#include <linux/ioport.h>
44#include <linux/delay.h>
45#include <linux/interrupt.h>
46#include <linux/timex.h>
47#include <linux/timer.h>
48#include <linux/io.h>
49#include <linux/pnp.h>
50
51#include "../comedidev.h"
52
53static u8 ReadByteFromHwPort(unsigned long addr)
54{
55 u8 result = inb(addr);
56 return result;
57}
58
59static void WriteByteToHwPort(unsigned long addr, u8 val)
60{
61 outb_p(val, addr);
62}
63
64#define C6XDIGIO_SIZE 3
65
66
67
68
69#define C6XDIGIO_PARALLEL_DATA 0
70#define C6XDIGIO_PARALLEL_STATUS 1
71#define C6XDIGIO_PARALLEL_CONTROL 2
72struct pwmbitstype {
73 unsigned sb0:2;
74 unsigned sb1:2;
75 unsigned sb2:2;
76 unsigned sb3:2;
77 unsigned sb4:2;
78};
79union pwmcmdtype {
80 unsigned cmd;
81 struct pwmbitstype bits;
82};
83struct encbitstype {
84 unsigned sb0:3;
85 unsigned sb1:3;
86 unsigned sb2:3;
87 unsigned sb3:3;
88 unsigned sb4:3;
89 unsigned sb5:3;
90 unsigned sb6:3;
91 unsigned sb7:3;
92};
93union encvaluetype {
94 unsigned value;
95 struct encbitstype bits;
96};
97
98#define C6XDIGIO_TIME_OUT 20
99
100static void C6X_pwmInit(unsigned long baseAddr)
101{
102 int timeout = 0;
103
104
105
106 WriteByteToHwPort(baseAddr, 0x70);
107 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
108 && (timeout < C6XDIGIO_TIME_OUT)) {
109 timeout++;
110 }
111
112 WriteByteToHwPort(baseAddr, 0x74);
113 timeout = 0;
114 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
115 && (timeout < C6XDIGIO_TIME_OUT)) {
116 timeout++;
117 }
118
119 WriteByteToHwPort(baseAddr, 0x70);
120 timeout = 0;
121 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
122 && (timeout < C6XDIGIO_TIME_OUT)) {
123 timeout++;
124 }
125
126 WriteByteToHwPort(baseAddr, 0x0);
127 timeout = 0;
128 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
129 && (timeout < C6XDIGIO_TIME_OUT)) {
130 timeout++;
131 }
132
133}
134
135static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value)
136{
137 unsigned ppcmd;
138 union pwmcmdtype pwm;
139 int timeout = 0;
140 unsigned tmp;
141
142
143
144 pwm.cmd = value;
145 if (pwm.cmd > 498)
146 pwm.cmd = 498;
147 if (pwm.cmd < 2)
148 pwm.cmd = 2;
149
150 if (channel == 0) {
151 ppcmd = 0x28;
152 } else {
153 ppcmd = 0x30;
154 }
155
156 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0);
157 tmp = ReadByteFromHwPort(baseAddr + 1);
158 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
159 tmp = ReadByteFromHwPort(baseAddr + 1);
160 timeout++;
161 }
162
163 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4);
164 timeout = 0;
165 tmp = ReadByteFromHwPort(baseAddr + 1);
166 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
167 tmp = ReadByteFromHwPort(baseAddr + 1);
168 timeout++;
169 }
170
171 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2);
172 tmp = ReadByteFromHwPort(baseAddr + 1);
173 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
174 tmp = ReadByteFromHwPort(baseAddr + 1);
175 timeout++;
176 }
177
178 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4);
179 timeout = 0;
180 tmp = ReadByteFromHwPort(baseAddr + 1);
181 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
182 tmp = ReadByteFromHwPort(baseAddr + 1);
183 timeout++;
184 }
185
186 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4);
187 tmp = ReadByteFromHwPort(baseAddr + 1);
188 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
189 tmp = ReadByteFromHwPort(baseAddr + 1);
190 timeout++;
191 }
192
193 WriteByteToHwPort(baseAddr, 0x0);
194 timeout = 0;
195 tmp = ReadByteFromHwPort(baseAddr + 1);
196 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
197 tmp = ReadByteFromHwPort(baseAddr + 1);
198 timeout++;
199 }
200
201}
202
203static int C6X_encInput(unsigned long baseAddr, unsigned channel)
204{
205 unsigned ppcmd;
206 union encvaluetype enc;
207 int timeout = 0;
208 int tmp;
209
210
211
212 enc.value = 0;
213 if (channel == 0)
214 ppcmd = 0x48;
215 else
216 ppcmd = 0x50;
217
218 WriteByteToHwPort(baseAddr, ppcmd);
219 tmp = ReadByteFromHwPort(baseAddr + 1);
220 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
221 tmp = ReadByteFromHwPort(baseAddr + 1);
222 timeout++;
223 }
224
225 enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
226 WriteByteToHwPort(baseAddr, ppcmd + 0x4);
227 timeout = 0;
228 tmp = ReadByteFromHwPort(baseAddr + 1);
229 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
230 tmp = ReadByteFromHwPort(baseAddr + 1);
231 timeout++;
232 }
233 enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
234 WriteByteToHwPort(baseAddr, ppcmd);
235 timeout = 0;
236 tmp = ReadByteFromHwPort(baseAddr + 1);
237 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
238 tmp = ReadByteFromHwPort(baseAddr + 1);
239 timeout++;
240 }
241 enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
242 WriteByteToHwPort(baseAddr, ppcmd + 0x4);
243 timeout = 0;
244 tmp = ReadByteFromHwPort(baseAddr + 1);
245 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
246 tmp = ReadByteFromHwPort(baseAddr + 1);
247 timeout++;
248 }
249 enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
250 WriteByteToHwPort(baseAddr, ppcmd);
251 timeout = 0;
252 tmp = ReadByteFromHwPort(baseAddr + 1);
253 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
254 tmp = ReadByteFromHwPort(baseAddr + 1);
255 timeout++;
256 }
257 enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
258 WriteByteToHwPort(baseAddr, ppcmd + 0x4);
259 timeout = 0;
260 tmp = ReadByteFromHwPort(baseAddr + 1);
261 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
262 tmp = ReadByteFromHwPort(baseAddr + 1);
263 timeout++;
264 }
265 enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
266 WriteByteToHwPort(baseAddr, ppcmd);
267 timeout = 0;
268 tmp = ReadByteFromHwPort(baseAddr + 1);
269 while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) {
270 tmp = ReadByteFromHwPort(baseAddr + 1);
271 timeout++;
272 }
273 enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
274 WriteByteToHwPort(baseAddr, ppcmd + 0x4);
275 timeout = 0;
276 tmp = ReadByteFromHwPort(baseAddr + 1);
277 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
278 tmp = ReadByteFromHwPort(baseAddr + 1);
279 timeout++;
280 }
281 enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
282 WriteByteToHwPort(baseAddr, ppcmd);
283 timeout = 0;
284 tmp = ReadByteFromHwPort(baseAddr + 1);
285 while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) {
286 tmp = ReadByteFromHwPort(baseAddr + 1);
287 timeout++;
288 }
289
290 WriteByteToHwPort(baseAddr, 0x0);
291 timeout = 0;
292 tmp = ReadByteFromHwPort(baseAddr + 1);
293 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
294 tmp = ReadByteFromHwPort(baseAddr + 1);
295 timeout++;
296 }
297
298 return enc.value ^ 0x800000;
299}
300
301static void C6X_encResetAll(unsigned long baseAddr)
302{
303 unsigned timeout = 0;
304
305
306
307 WriteByteToHwPort(baseAddr, 0x68);
308 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
309 && (timeout < C6XDIGIO_TIME_OUT)) {
310 timeout++;
311 }
312 WriteByteToHwPort(baseAddr, 0x6C);
313 timeout = 0;
314 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
315 && (timeout < C6XDIGIO_TIME_OUT)) {
316 timeout++;
317 }
318 WriteByteToHwPort(baseAddr, 0x68);
319 timeout = 0;
320 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
321 && (timeout < C6XDIGIO_TIME_OUT)) {
322 timeout++;
323 }
324 WriteByteToHwPort(baseAddr, 0x0);
325 timeout = 0;
326 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
327 && (timeout < C6XDIGIO_TIME_OUT)) {
328 timeout++;
329 }
330}
331
332static int c6xdigio_pwmo_insn_read(struct comedi_device *dev,
333 struct comedi_subdevice *s,
334 struct comedi_insn *insn, unsigned int *data)
335{
336 printk(KERN_DEBUG "c6xdigio_pwmo_insn_read %x\n", insn->n);
337 return insn->n;
338}
339
340static int c6xdigio_pwmo_insn_write(struct comedi_device *dev,
341 struct comedi_subdevice *s,
342 struct comedi_insn *insn,
343 unsigned int *data)
344{
345 int i;
346 int chan = CR_CHAN(insn->chanspec);
347
348
349 for (i = 0; i < insn->n; i++) {
350 C6X_pwmOutput(dev->iobase, chan, data[i]);
351
352 }
353 return i;
354}
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376static int c6xdigio_ei_insn_read(struct comedi_device *dev,
377 struct comedi_subdevice *s,
378 struct comedi_insn *insn, unsigned int *data)
379{
380
381 int n;
382 int chan = CR_CHAN(insn->chanspec);
383
384 for (n = 0; n < insn->n; n++)
385 data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff);
386
387 return n;
388}
389
390static void board_init(struct comedi_device *dev)
391{
392
393
394
395 C6X_pwmInit(dev->iobase);
396 C6X_encResetAll(dev->iobase);
397
398}
399
400
401
402
403
404
405
406static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
407
408 {.id = "PNP0400", .driver_data = 0},
409
410 {.id = "PNP0401", .driver_data = 0},
411 {}
412};
413
414static struct pnp_driver c6xdigio_pnp_driver = {
415 .name = "c6xdigio",
416 .id_table = c6xdigio_pnp_tbl,
417};
418
419static int c6xdigio_attach(struct comedi_device *dev,
420 struct comedi_devconfig *it)
421{
422 int result = 0;
423 unsigned long iobase;
424 unsigned int irq;
425 struct comedi_subdevice *s;
426
427 iobase = it->options[0];
428 printk(KERN_DEBUG "comedi%d: c6xdigio: 0x%04lx\n", dev->minor, iobase);
429 if (!request_region(iobase, C6XDIGIO_SIZE, "c6xdigio")) {
430 printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
431 return -EIO;
432 }
433 dev->iobase = iobase;
434 dev->board_name = "c6xdigio";
435
436 result = comedi_alloc_subdevices(dev, 2);
437 if (result)
438 return result;
439
440
441 pnp_register_driver(&c6xdigio_pnp_driver);
442
443 irq = it->options[1];
444 if (irq > 0)
445 printk(KERN_DEBUG "comedi%d: irq = %u ignored\n",
446 dev->minor, irq);
447 else if (irq == 0)
448 printk(KERN_DEBUG "comedi%d: no irq\n", dev->minor);
449
450 s = &dev->subdevices[0];
451
452 s->type = COMEDI_SUBD_AO;
453 s->subdev_flags = SDF_WRITEABLE;
454 s->n_chan = 2;
455
456 s->insn_read = c6xdigio_pwmo_insn_read;
457 s->insn_write = c6xdigio_pwmo_insn_write;
458 s->maxdata = 500;
459 s->range_table = &range_bipolar10;
460
461 s = &dev->subdevices[1];
462
463 s->type = COMEDI_SUBD_COUNTER;
464 s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
465 s->n_chan = 2;
466
467 s->insn_read = c6xdigio_ei_insn_read;
468 s->maxdata = 0xffffff;
469 s->range_table = &range_unknown;
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484 board_init(dev);
485
486 return 0;
487}
488
489static void c6xdigio_detach(struct comedi_device *dev)
490{
491 if (dev->iobase)
492 release_region(dev->iobase, C6XDIGIO_SIZE);
493 if (dev->irq)
494 free_irq(dev->irq, dev);
495 pnp_unregister_driver(&c6xdigio_pnp_driver);
496}
497
498static struct comedi_driver c6xdigio_driver = {
499 .driver_name = "c6xdigio",
500 .module = THIS_MODULE,
501 .attach = c6xdigio_attach,
502 .detach = c6xdigio_detach,
503};
504module_comedi_driver(c6xdigio_driver);
505
506MODULE_AUTHOR("Comedi http://www.comedi.org");
507MODULE_DESCRIPTION("Comedi low-level driver");
508MODULE_LICENSE("GPL");
509