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