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