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