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