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