Merge tag 'for-v3.7' of git://git.infradead.org/battery-2.6
[deliverable/linux.git] / drivers / staging / comedi / drivers / dt3000.c
1 /*
2 comedi/drivers/dt3000.c
3 Data Translation DT3000 series driver
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1999 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 /*
24 Driver: dt3000
25 Description: Data Translation DT3000 series
26 Author: ds
27 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
28 DT3003-PGL, DT3004, DT3005, DT3004-200
29 Updated: Mon, 14 Apr 2008 15:41:24 +0100
30 Status: works
31
32 Configuration Options:
33 [0] - PCI bus of device (optional)
34 [1] - PCI slot of device (optional)
35 If bus/slot is not specified, the first supported
36 PCI device found will be used.
37
38 There is code to support AI commands, but it may not work.
39
40 AO commands are not supported.
41 */
42
43 /*
44 The DT3000 series is Data Translation's attempt to make a PCI
45 data acquisition board. The design of this series is very nice,
46 since each board has an on-board DSP (Texas Instruments TMS320C52).
47 However, a few details are a little annoying. The boards lack
48 bus-mastering DMA, which eliminates them from serious work.
49 They also are not capable of autocalibration, which is a common
50 feature in modern hardware. The default firmware is pretty bad,
51 making it nearly impossible to write an RT compatible driver.
52 It would make an interesting project to write a decent firmware
53 for these boards.
54
55 Data Translation originally wanted an NDA for the documentation
56 for the 3k series. However, if you ask nicely, they might send
57 you the docs without one, also.
58 */
59
60 #define DEBUG 1
61
62 #include <linux/interrupt.h>
63 #include "../comedidev.h"
64 #include <linux/delay.h>
65
66 #include "comedi_fc.h"
67
68 #define PCI_VENDOR_ID_DT 0x1116
69
70 static const struct comedi_lrange range_dt3000_ai = { 4, {
71 RANGE(-10, 10),
72 RANGE(-5, 5),
73 RANGE(-2.5, 2.5),
74 RANGE(-1.25, 1.25)
75 }
76 };
77
78 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
79 RANGE(-10, 10),
80 RANGE(-1, 1),
81 RANGE(-0.1, 0.1),
82 RANGE(-0.02, 0.02)
83 }
84 };
85
86 struct dt3k_boardtype {
87
88 const char *name;
89 unsigned int device_id;
90 int adchan;
91 int adbits;
92 int ai_speed;
93 const struct comedi_lrange *adrange;
94 int dachan;
95 int dabits;
96 };
97
98 static const struct dt3k_boardtype dt3k_boardtypes[] = {
99 {.name = "dt3001",
100 .device_id = 0x22,
101 .adchan = 16,
102 .adbits = 12,
103 .adrange = &range_dt3000_ai,
104 .ai_speed = 3000,
105 .dachan = 2,
106 .dabits = 12,
107 },
108 {.name = "dt3001-pgl",
109 .device_id = 0x27,
110 .adchan = 16,
111 .adbits = 12,
112 .adrange = &range_dt3000_ai_pgl,
113 .ai_speed = 3000,
114 .dachan = 2,
115 .dabits = 12,
116 },
117 {.name = "dt3002",
118 .device_id = 0x23,
119 .adchan = 32,
120 .adbits = 12,
121 .adrange = &range_dt3000_ai,
122 .ai_speed = 3000,
123 .dachan = 0,
124 .dabits = 0,
125 },
126 {.name = "dt3003",
127 .device_id = 0x24,
128 .adchan = 64,
129 .adbits = 12,
130 .adrange = &range_dt3000_ai,
131 .ai_speed = 3000,
132 .dachan = 2,
133 .dabits = 12,
134 },
135 {.name = "dt3003-pgl",
136 .device_id = 0x28,
137 .adchan = 64,
138 .adbits = 12,
139 .adrange = &range_dt3000_ai_pgl,
140 .ai_speed = 3000,
141 .dachan = 2,
142 .dabits = 12,
143 },
144 {.name = "dt3004",
145 .device_id = 0x25,
146 .adchan = 16,
147 .adbits = 16,
148 .adrange = &range_dt3000_ai,
149 .ai_speed = 10000,
150 .dachan = 2,
151 .dabits = 12,
152 },
153 {.name = "dt3005", /* a.k.a. 3004-200 */
154 .device_id = 0x26,
155 .adchan = 16,
156 .adbits = 16,
157 .adrange = &range_dt3000_ai,
158 .ai_speed = 5000,
159 .dachan = 2,
160 .dabits = 12,
161 },
162 };
163
164 #define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
165
166 #define DT3000_SIZE (4*0x1000)
167
168 /* dual-ported RAM location definitions */
169
170 #define DPR_DAC_buffer (4*0x000)
171 #define DPR_ADC_buffer (4*0x800)
172 #define DPR_Command (4*0xfd3)
173 #define DPR_SubSys (4*0xfd3)
174 #define DPR_Encode (4*0xfd4)
175 #define DPR_Params(a) (4*(0xfd5+(a)))
176 #define DPR_Tick_Reg_Lo (4*0xff5)
177 #define DPR_Tick_Reg_Hi (4*0xff6)
178 #define DPR_DA_Buf_Front (4*0xff7)
179 #define DPR_DA_Buf_Rear (4*0xff8)
180 #define DPR_AD_Buf_Front (4*0xff9)
181 #define DPR_AD_Buf_Rear (4*0xffa)
182 #define DPR_Int_Mask (4*0xffb)
183 #define DPR_Intr_Flag (4*0xffc)
184 #define DPR_Response_Mbx (4*0xffe)
185 #define DPR_Command_Mbx (4*0xfff)
186
187 #define AI_FIFO_DEPTH 2003
188 #define AO_FIFO_DEPTH 2048
189
190 /* command list */
191
192 #define CMD_GETBRDINFO 0
193 #define CMD_CONFIG 1
194 #define CMD_GETCONFIG 2
195 #define CMD_START 3
196 #define CMD_STOP 4
197 #define CMD_READSINGLE 5
198 #define CMD_WRITESINGLE 6
199 #define CMD_CALCCLOCK 7
200 #define CMD_READEVENTS 8
201 #define CMD_WRITECTCTRL 16
202 #define CMD_READCTCTRL 17
203 #define CMD_WRITECT 18
204 #define CMD_READCT 19
205 #define CMD_WRITEDATA 32
206 #define CMD_READDATA 33
207 #define CMD_WRITEIO 34
208 #define CMD_READIO 35
209 #define CMD_WRITECODE 36
210 #define CMD_READCODE 37
211 #define CMD_EXECUTE 38
212 #define CMD_HALT 48
213
214 #define SUBS_AI 0
215 #define SUBS_AO 1
216 #define SUBS_DIN 2
217 #define SUBS_DOUT 3
218 #define SUBS_MEM 4
219 #define SUBS_CT 5
220
221 /* interrupt flags */
222 #define DT3000_CMDONE 0x80
223 #define DT3000_CTDONE 0x40
224 #define DT3000_DAHWERR 0x20
225 #define DT3000_DASWERR 0x10
226 #define DT3000_DAEMPTY 0x08
227 #define DT3000_ADHWERR 0x04
228 #define DT3000_ADSWERR 0x02
229 #define DT3000_ADFULL 0x01
230
231 #define DT3000_COMPLETION_MASK 0xff00
232 #define DT3000_COMMAND_MASK 0x00ff
233 #define DT3000_NOTPROCESSED 0x0000
234 #define DT3000_NOERROR 0x5500
235 #define DT3000_ERROR 0xaa00
236 #define DT3000_NOTSUPPORTED 0xff00
237
238 #define DT3000_EXTERNAL_CLOCK 1
239 #define DT3000_RISING_EDGE 2
240
241 #define TMODE_MASK 0x1c
242
243 #define DT3000_AD_TRIG_INTERNAL (0<<2)
244 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
245 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
246 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
247 #define DT3000_AD_EXTRETRIG (4<<2)
248
249 #define DT3000_CHANNEL_MODE_SE 0
250 #define DT3000_CHANNEL_MODE_DI 1
251
252 struct dt3k_private {
253 void __iomem *io_addr;
254 unsigned int lock;
255 unsigned int ao_readback[2];
256 unsigned int ai_front;
257 unsigned int ai_rear;
258 };
259
260 #define devpriv ((struct dt3k_private *)dev->private)
261
262 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
263 struct comedi_subdevice *s);
264 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
265 unsigned int round_mode);
266 static int dt3k_ai_cancel(struct comedi_device *dev,
267 struct comedi_subdevice *s);
268 #ifdef DEBUG
269 static void debug_intr_flags(unsigned int flags);
270 #endif
271
272 #define TIMEOUT 100
273
274 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
275 {
276 int i;
277 unsigned int status = 0;
278
279 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
280
281 for (i = 0; i < TIMEOUT; i++) {
282 status = readw(devpriv->io_addr + DPR_Command_Mbx);
283 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
284 break;
285 udelay(1);
286 }
287 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR)
288 return 0;
289
290 dev_dbg(dev->class_dev, "dt3k_send_cmd() timeout/error status=0x%04x\n",
291 status);
292
293 return -ETIME;
294 }
295
296 static unsigned int dt3k_readsingle(struct comedi_device *dev,
297 unsigned int subsys, unsigned int chan,
298 unsigned int gain)
299 {
300 writew(subsys, devpriv->io_addr + DPR_SubSys);
301
302 writew(chan, devpriv->io_addr + DPR_Params(0));
303 writew(gain, devpriv->io_addr + DPR_Params(1));
304
305 dt3k_send_cmd(dev, CMD_READSINGLE);
306
307 return readw(devpriv->io_addr + DPR_Params(2));
308 }
309
310 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
311 unsigned int chan, unsigned int data)
312 {
313 writew(subsys, devpriv->io_addr + DPR_SubSys);
314
315 writew(chan, devpriv->io_addr + DPR_Params(0));
316 writew(0, devpriv->io_addr + DPR_Params(1));
317 writew(data, devpriv->io_addr + DPR_Params(2));
318
319 dt3k_send_cmd(dev, CMD_WRITESINGLE);
320 }
321
322 static int debug_n_ints;
323
324 /* FIXME! Assumes shared interrupt is for this card. */
325 /* What's this debug_n_ints stuff? Obviously needs some work... */
326 static irqreturn_t dt3k_interrupt(int irq, void *d)
327 {
328 struct comedi_device *dev = d;
329 struct comedi_subdevice *s;
330 unsigned int status;
331
332 if (!dev->attached)
333 return IRQ_NONE;
334
335 s = &dev->subdevices[0];
336 status = readw(devpriv->io_addr + DPR_Intr_Flag);
337 #ifdef DEBUG
338 debug_intr_flags(status);
339 #endif
340
341 if (status & DT3000_ADFULL) {
342 dt3k_ai_empty_fifo(dev, s);
343 s->async->events |= COMEDI_CB_BLOCK;
344 }
345
346 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
347 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
348
349 debug_n_ints++;
350 if (debug_n_ints >= 10) {
351 dt3k_ai_cancel(dev, s);
352 s->async->events |= COMEDI_CB_EOA;
353 }
354
355 comedi_event(dev, s);
356 return IRQ_HANDLED;
357 }
358
359 #ifdef DEBUG
360 static char *intr_flags[] = {
361 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
362 "DaSwError", "DaHwError", "CtDone", "CmDone",
363 };
364
365 static void debug_intr_flags(unsigned int flags)
366 {
367 int i;
368 printk(KERN_DEBUG "dt3k: intr_flags:");
369 for (i = 0; i < 8; i++) {
370 if (flags & (1 << i))
371 printk(KERN_CONT " %s", intr_flags[i]);
372 }
373 printk(KERN_CONT "\n");
374 }
375 #endif
376
377 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
378 struct comedi_subdevice *s)
379 {
380 int front;
381 int rear;
382 int count;
383 int i;
384 short data;
385
386 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
387 count = front - devpriv->ai_front;
388 if (count < 0)
389 count += AI_FIFO_DEPTH;
390
391 dev_dbg(dev->class_dev, "reading %d samples\n", count);
392
393 rear = devpriv->ai_rear;
394
395 for (i = 0; i < count; i++) {
396 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
397 comedi_buf_put(s->async, data);
398 rear++;
399 if (rear >= AI_FIFO_DEPTH)
400 rear = 0;
401 }
402
403 devpriv->ai_rear = rear;
404 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
405 }
406
407 static int dt3k_ai_cmdtest(struct comedi_device *dev,
408 struct comedi_subdevice *s, struct comedi_cmd *cmd)
409 {
410 int err = 0;
411 int tmp;
412
413 /* Step 1 : check if triggers are trivially valid */
414
415 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
416 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
417 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
418 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
419 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
420
421 if (err)
422 return 1;
423
424 /* Step 2a : make sure trigger sources are unique */
425 /* Step 2b : and mutually compatible */
426
427 if (err)
428 return 2;
429
430 /* step 3: make sure arguments are trivially compatible */
431
432 if (cmd->start_arg != 0) {
433 cmd->start_arg = 0;
434 err++;
435 }
436
437 if (cmd->scan_begin_src == TRIG_TIMER) {
438 if (cmd->scan_begin_arg < this_board->ai_speed) {
439 cmd->scan_begin_arg = this_board->ai_speed;
440 err++;
441 }
442 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
443 cmd->scan_begin_arg = 100 * 16 * 65535;
444 err++;
445 }
446 } else {
447 /* not supported */
448 }
449 if (cmd->convert_src == TRIG_TIMER) {
450 if (cmd->convert_arg < this_board->ai_speed) {
451 cmd->convert_arg = this_board->ai_speed;
452 err++;
453 }
454 if (cmd->convert_arg > 50 * 16 * 65535) {
455 cmd->convert_arg = 50 * 16 * 65535;
456 err++;
457 }
458 } else {
459 /* not supported */
460 }
461
462 if (cmd->scan_end_arg != cmd->chanlist_len) {
463 cmd->scan_end_arg = cmd->chanlist_len;
464 err++;
465 }
466 if (cmd->stop_src == TRIG_COUNT) {
467 if (cmd->stop_arg > 0x00ffffff) {
468 cmd->stop_arg = 0x00ffffff;
469 err++;
470 }
471 } else {
472 /* TRIG_NONE */
473 if (cmd->stop_arg != 0) {
474 cmd->stop_arg = 0;
475 err++;
476 }
477 }
478
479 if (err)
480 return 3;
481
482 /* step 4: fix up any arguments */
483
484 if (cmd->scan_begin_src == TRIG_TIMER) {
485 tmp = cmd->scan_begin_arg;
486 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
487 cmd->flags & TRIG_ROUND_MASK);
488 if (tmp != cmd->scan_begin_arg)
489 err++;
490 } else {
491 /* not supported */
492 }
493 if (cmd->convert_src == TRIG_TIMER) {
494 tmp = cmd->convert_arg;
495 dt3k_ns_to_timer(50, &cmd->convert_arg,
496 cmd->flags & TRIG_ROUND_MASK);
497 if (tmp != cmd->convert_arg)
498 err++;
499 if (cmd->scan_begin_src == TRIG_TIMER &&
500 cmd->scan_begin_arg <
501 cmd->convert_arg * cmd->scan_end_arg) {
502 cmd->scan_begin_arg =
503 cmd->convert_arg * cmd->scan_end_arg;
504 err++;
505 }
506 } else {
507 /* not supported */
508 }
509
510 if (err)
511 return 4;
512
513 return 0;
514 }
515
516 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
517 unsigned int round_mode)
518 {
519 int divider, base, prescale;
520
521 /* This function needs improvment */
522 /* Don't know if divider==0 works. */
523
524 for (prescale = 0; prescale < 16; prescale++) {
525 base = timer_base * (prescale + 1);
526 switch (round_mode) {
527 case TRIG_ROUND_NEAREST:
528 default:
529 divider = (*nanosec + base / 2) / base;
530 break;
531 case TRIG_ROUND_DOWN:
532 divider = (*nanosec) / base;
533 break;
534 case TRIG_ROUND_UP:
535 divider = (*nanosec) / base;
536 break;
537 }
538 if (divider < 65536) {
539 *nanosec = divider * base;
540 return (prescale << 16) | (divider);
541 }
542 }
543
544 prescale = 15;
545 base = timer_base * (1 << prescale);
546 divider = 65535;
547 *nanosec = divider * base;
548 return (prescale << 16) | (divider);
549 }
550
551 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
552 {
553 struct comedi_cmd *cmd = &s->async->cmd;
554 int i;
555 unsigned int chan, range, aref;
556 unsigned int divider;
557 unsigned int tscandiv;
558 int ret;
559 unsigned int mode;
560
561 dev_dbg(dev->class_dev, "dt3k_ai_cmd:\n");
562 for (i = 0; i < cmd->chanlist_len; i++) {
563 chan = CR_CHAN(cmd->chanlist[i]);
564 range = CR_RANGE(cmd->chanlist[i]);
565
566 writew((range << 6) | chan,
567 devpriv->io_addr + DPR_ADC_buffer + i);
568 }
569 aref = CR_AREF(cmd->chanlist[0]);
570
571 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
572 dev_dbg(dev->class_dev, "param[0]=0x%04x\n", cmd->scan_end_arg);
573
574 if (cmd->convert_src == TRIG_TIMER) {
575 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
576 cmd->flags & TRIG_ROUND_MASK);
577 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
578 dev_dbg(dev->class_dev, "param[1]=0x%04x\n", divider >> 16);
579 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
580 dev_dbg(dev->class_dev, "param[2]=0x%04x\n", divider & 0xffff);
581 } else {
582 /* not supported */
583 }
584
585 if (cmd->scan_begin_src == TRIG_TIMER) {
586 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
587 cmd->flags & TRIG_ROUND_MASK);
588 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
589 dev_dbg(dev->class_dev, "param[3]=0x%04x\n", tscandiv >> 16);
590 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
591 dev_dbg(dev->class_dev, "param[4]=0x%04x\n", tscandiv & 0xffff);
592 } else {
593 /* not supported */
594 }
595
596 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
597 writew(mode, devpriv->io_addr + DPR_Params(5));
598 dev_dbg(dev->class_dev, "param[5]=0x%04x\n", mode);
599 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
600 dev_dbg(dev->class_dev, "param[6]=0x%04x\n", aref == AREF_DIFF);
601
602 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
603 dev_dbg(dev->class_dev, "param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
604
605 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
606 ret = dt3k_send_cmd(dev, CMD_CONFIG);
607
608 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
609 devpriv->io_addr + DPR_Int_Mask);
610
611 debug_n_ints = 0;
612
613 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
614 ret = dt3k_send_cmd(dev, CMD_START);
615
616 return 0;
617 }
618
619 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
620 {
621 int ret;
622
623 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
624 ret = dt3k_send_cmd(dev, CMD_STOP);
625
626 writew(0, devpriv->io_addr + DPR_Int_Mask);
627
628 return 0;
629 }
630
631 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
632 struct comedi_insn *insn, unsigned int *data)
633 {
634 int i;
635 unsigned int chan, gain, aref;
636
637 chan = CR_CHAN(insn->chanspec);
638 gain = CR_RANGE(insn->chanspec);
639 /* XXX docs don't explain how to select aref */
640 aref = CR_AREF(insn->chanspec);
641
642 for (i = 0; i < insn->n; i++)
643 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
644
645 return i;
646 }
647
648 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
649 struct comedi_insn *insn, unsigned int *data)
650 {
651 int i;
652 unsigned int chan;
653
654 chan = CR_CHAN(insn->chanspec);
655 for (i = 0; i < insn->n; i++) {
656 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
657 devpriv->ao_readback[chan] = data[i];
658 }
659
660 return i;
661 }
662
663 static int dt3k_ao_insn_read(struct comedi_device *dev,
664 struct comedi_subdevice *s,
665 struct comedi_insn *insn, unsigned int *data)
666 {
667 int i;
668 unsigned int chan;
669
670 chan = CR_CHAN(insn->chanspec);
671 for (i = 0; i < insn->n; i++)
672 data[i] = devpriv->ao_readback[chan];
673
674 return i;
675 }
676
677 static void dt3k_dio_config(struct comedi_device *dev, int bits)
678 {
679 /* XXX */
680 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
681
682 writew(bits, devpriv->io_addr + DPR_Params(0));
683 #if 0
684 /* don't know */
685 writew(0, devpriv->io_addr + DPR_Params(1));
686 writew(0, devpriv->io_addr + DPR_Params(2));
687 #endif
688
689 dt3k_send_cmd(dev, CMD_CONFIG);
690 }
691
692 static int dt3k_dio_insn_config(struct comedi_device *dev,
693 struct comedi_subdevice *s,
694 struct comedi_insn *insn, unsigned int *data)
695 {
696 int mask;
697
698 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
699
700 switch (data[0]) {
701 case INSN_CONFIG_DIO_OUTPUT:
702 s->io_bits |= mask;
703 break;
704 case INSN_CONFIG_DIO_INPUT:
705 s->io_bits &= ~mask;
706 break;
707 case INSN_CONFIG_DIO_QUERY:
708 data[1] =
709 (s->
710 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
711 COMEDI_INPUT;
712 return insn->n;
713 break;
714 default:
715 return -EINVAL;
716 break;
717 }
718 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
719 dt3k_dio_config(dev, mask);
720
721 return insn->n;
722 }
723
724 static int dt3k_dio_insn_bits(struct comedi_device *dev,
725 struct comedi_subdevice *s,
726 struct comedi_insn *insn, unsigned int *data)
727 {
728 if (data[0]) {
729 s->state &= ~data[0];
730 s->state |= data[1] & data[0];
731 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
732 }
733 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
734
735 return insn->n;
736 }
737
738 static int dt3k_mem_insn_read(struct comedi_device *dev,
739 struct comedi_subdevice *s,
740 struct comedi_insn *insn, unsigned int *data)
741 {
742 unsigned int addr = CR_CHAN(insn->chanspec);
743 int i;
744
745 for (i = 0; i < insn->n; i++) {
746 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
747 writew(addr, devpriv->io_addr + DPR_Params(0));
748 writew(1, devpriv->io_addr + DPR_Params(1));
749
750 dt3k_send_cmd(dev, CMD_READCODE);
751
752 data[i] = readw(devpriv->io_addr + DPR_Params(2));
753 }
754
755 return i;
756 }
757
758 static struct pci_dev *dt3000_find_pci_dev(struct comedi_device *dev,
759 struct comedi_devconfig *it)
760 {
761 struct pci_dev *pcidev = NULL;
762 int bus = it->options[0];
763 int slot = it->options[1];
764 int i;
765
766 for_each_pci_dev(pcidev) {
767 if (bus || slot) {
768 if (bus != pcidev->bus->number ||
769 slot != PCI_SLOT(pcidev->devfn))
770 continue;
771 }
772 if (pcidev->vendor != PCI_VENDOR_ID_DT)
773 continue;
774 for (i = 0; i < ARRAY_SIZE(dt3k_boardtypes); i++) {
775 if (dt3k_boardtypes[i].device_id != pcidev->device)
776 continue;
777 dev->board_ptr = dt3k_boardtypes + i;
778 return pcidev;
779 }
780 }
781 dev_err(dev->class_dev,
782 "No supported board found! (req. bus %d, slot %d)\n",
783 bus, slot);
784 return NULL;
785 }
786
787 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
788 {
789 struct pci_dev *pcidev;
790 struct comedi_subdevice *s;
791 resource_size_t pci_base;
792 int ret = 0;
793
794 dev_dbg(dev->class_dev, "dt3000:\n");
795
796 ret = alloc_private(dev, sizeof(struct dt3k_private));
797 if (ret < 0)
798 return ret;
799
800 pcidev = dt3000_find_pci_dev(dev, it);
801 if (!pcidev)
802 return -EIO;
803 comedi_set_hw_dev(dev, &pcidev->dev);
804
805 ret = comedi_pci_enable(pcidev, "dt3000");
806 if (ret < 0)
807 return ret;
808 dev->iobase = 1; /* the "detach" needs this */
809
810 pci_base = pci_resource_start(pcidev, 0);
811 devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
812 if (!devpriv->io_addr)
813 return -ENOMEM;
814
815 dev->board_name = this_board->name;
816
817 if (request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
818 "dt3000", dev)) {
819 dev_err(dev->class_dev, "unable to allocate IRQ %u\n",
820 pcidev->irq);
821 return -EINVAL;
822 }
823 dev->irq = pcidev->irq;
824
825 ret = comedi_alloc_subdevices(dev, 4);
826 if (ret)
827 return ret;
828
829 s = &dev->subdevices[0];
830 dev->read_subdev = s;
831
832 /* ai subdevice */
833 s->type = COMEDI_SUBD_AI;
834 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
835 s->n_chan = this_board->adchan;
836 s->insn_read = dt3k_ai_insn;
837 s->maxdata = (1 << this_board->adbits) - 1;
838 s->len_chanlist = 512;
839 s->range_table = &range_dt3000_ai; /* XXX */
840 s->do_cmd = dt3k_ai_cmd;
841 s->do_cmdtest = dt3k_ai_cmdtest;
842 s->cancel = dt3k_ai_cancel;
843
844 s = &dev->subdevices[1];
845 /* ao subsystem */
846 s->type = COMEDI_SUBD_AO;
847 s->subdev_flags = SDF_WRITABLE;
848 s->n_chan = 2;
849 s->insn_read = dt3k_ao_insn_read;
850 s->insn_write = dt3k_ao_insn;
851 s->maxdata = (1 << this_board->dabits) - 1;
852 s->len_chanlist = 1;
853 s->range_table = &range_bipolar10;
854
855 s = &dev->subdevices[2];
856 /* dio subsystem */
857 s->type = COMEDI_SUBD_DIO;
858 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
859 s->n_chan = 8;
860 s->insn_config = dt3k_dio_insn_config;
861 s->insn_bits = dt3k_dio_insn_bits;
862 s->maxdata = 1;
863 s->len_chanlist = 8;
864 s->range_table = &range_digital;
865
866 s = &dev->subdevices[3];
867 /* mem subsystem */
868 s->type = COMEDI_SUBD_MEMORY;
869 s->subdev_flags = SDF_READABLE;
870 s->n_chan = 0x1000;
871 s->insn_read = dt3k_mem_insn_read;
872 s->maxdata = 0xff;
873 s->len_chanlist = 1;
874 s->range_table = &range_unknown;
875
876 #if 0
877 s = &dev->subdevices[4];
878 /* proc subsystem */
879 s->type = COMEDI_SUBD_PROC;
880 #endif
881
882 return 0;
883 }
884
885 static void dt3000_detach(struct comedi_device *dev)
886 {
887 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
888
889 if (dev->irq)
890 free_irq(dev->irq, dev);
891 if (devpriv) {
892 if (devpriv->io_addr)
893 iounmap(devpriv->io_addr);
894 }
895 if (pcidev) {
896 if (dev->iobase)
897 comedi_pci_disable(pcidev);
898 pci_dev_put(pcidev);
899 }
900 }
901
902 static struct comedi_driver dt3000_driver = {
903 .driver_name = "dt3000",
904 .module = THIS_MODULE,
905 .attach = dt3000_attach,
906 .detach = dt3000_detach,
907 };
908
909 static int __devinit dt3000_pci_probe(struct pci_dev *dev,
910 const struct pci_device_id *ent)
911 {
912 return comedi_pci_auto_config(dev, &dt3000_driver);
913 }
914
915 static void __devexit dt3000_pci_remove(struct pci_dev *dev)
916 {
917 comedi_pci_auto_unconfig(dev);
918 }
919
920 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
921 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
922 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
923 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
924 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
925 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
926 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
927 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
928 { 0 }
929 };
930 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
931
932 static struct pci_driver dt3000_pci_driver = {
933 .name = "dt3000",
934 .id_table = dt3000_pci_table,
935 .probe = dt3000_pci_probe,
936 .remove = __devexit_p(dt3000_pci_remove),
937 };
938 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
939
940 MODULE_AUTHOR("Comedi http://www.comedi.org");
941 MODULE_DESCRIPTION("Comedi low-level driver");
942 MODULE_LICENSE("GPL");
This page took 0.054937 seconds and 6 git commands to generate.