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