Merge branch 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/git...
[deliverable/linux.git] / drivers / staging / comedi / drivers / dt3000.c
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 /*
24 Driver: dt3000
25 Description: Data Translation DT3000 series
26 Author: ds
27 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
28 DT3003-PGL, DT3004, DT3005, DT3004-200
29 Updated: Mon, 14 Apr 2008 15:41:24 +0100
30 Status: works
31
32 Configuration 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
38 There is code to support AI commands, but it may not work.
39
40 AO 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 <linux/interrupt.h>
63 #include "../comedidev.h"
64 #include <linux/delay.h>
65
66 #include "comedi_pci.h"
67
68 #define PCI_VENDOR_ID_DT 0x1116
69
70 static const struct comedi_lrange range_dt3000_ai = { 4, {
71 RANGE(-10, 10),
72 RANGE(-5, 5),
73 RANGE(-2.5, 2.5),
74 RANGE(-1.25, 1.25)
75 }
76 };
77
78 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
79 RANGE(-10, 10),
80 RANGE(-1, 1),
81 RANGE(-0.1, 0.1),
82 RANGE(-0.02, 0.02)
83 }
84 };
85
86 struct dt3k_boardtype {
87
88 const char *name;
89 unsigned int device_id;
90 int adchan;
91 int adbits;
92 int ai_speed;
93 const struct comedi_lrange *adrange;
94 int dachan;
95 int dabits;
96 };
97
98 static const struct dt3k_boardtype dt3k_boardtypes[] = {
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,
107 },
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,
116 },
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,
125 },
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,
134 },
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,
143 },
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,
152 },
153 {.name = "dt3005", /* a.k.a. 3004-200 */
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,
161 },
162 };
163
164 #define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
165 #define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
166
167 static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
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}
177 };
178
179 MODULE_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
267 struct dt3k_private {
268
269 struct pci_dev *pci_dev;
270 resource_size_t phys_addr;
271 void *io_addr;
272 unsigned int lock;
273 unsigned int ao_readback[2];
274 unsigned int ai_front;
275 unsigned int ai_rear;
276 };
277
278 #define devpriv ((struct dt3k_private *)dev->private)
279
280 static int dt3000_attach(struct comedi_device *dev,
281 struct comedi_devconfig *it);
282 static int dt3000_detach(struct comedi_device *dev);
283 static struct comedi_driver driver_dt3000 = {
284 .driver_name = "dt3000",
285 .module = THIS_MODULE,
286 .attach = dt3000_attach,
287 .detach = dt3000_detach,
288 };
289
290 COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
291
292 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
293 struct comedi_subdevice *s);
294 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
295 unsigned int round_mode);
296 static int dt3k_ai_cancel(struct comedi_device *dev,
297 struct comedi_subdevice *s);
298 #ifdef DEBUG
299 static void debug_intr_flags(unsigned int flags);
300 #endif
301
302 #define TIMEOUT 100
303
304 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
305 {
306 int i;
307 unsigned int status = 0;
308
309 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
310
311 for (i = 0; i < TIMEOUT; i++) {
312 status = readw(devpriv->io_addr + DPR_Command_Mbx);
313 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
314 break;
315 udelay(1);
316 }
317 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
318 return 0;
319 }
320
321 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
322
323 return -ETIME;
324 }
325
326 static unsigned int dt3k_readsingle(struct comedi_device *dev,
327 unsigned int subsys, unsigned int chan,
328 unsigned int gain)
329 {
330 writew(subsys, devpriv->io_addr + DPR_SubSys);
331
332 writew(chan, devpriv->io_addr + DPR_Params(0));
333 writew(gain, devpriv->io_addr + DPR_Params(1));
334
335 dt3k_send_cmd(dev, CMD_READSINGLE);
336
337 return readw(devpriv->io_addr + DPR_Params(2));
338 }
339
340 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
341 unsigned int chan, unsigned int data)
342 {
343 writew(subsys, devpriv->io_addr + DPR_SubSys);
344
345 writew(chan, devpriv->io_addr + DPR_Params(0));
346 writew(0, devpriv->io_addr + DPR_Params(1));
347 writew(data, devpriv->io_addr + DPR_Params(2));
348
349 dt3k_send_cmd(dev, CMD_WRITESINGLE);
350 }
351
352 static int debug_n_ints = 0;
353
354 /* FIXME! Assumes shared interrupt is for this card. */
355 /* What's this debug_n_ints stuff? Obviously needs some work... */
356 static irqreturn_t dt3k_interrupt(int irq, void *d)
357 {
358 struct comedi_device *dev = d;
359 struct comedi_subdevice *s;
360 unsigned int status;
361
362 if (!dev->attached) {
363 return IRQ_NONE;
364 }
365
366 s = dev->subdevices + 0;
367 status = readw(devpriv->io_addr + DPR_Intr_Flag);
368 #ifdef DEBUG
369 debug_intr_flags(status);
370 #endif
371
372 if (status & DT3000_ADFULL) {
373 dt3k_ai_empty_fifo(dev, s);
374 s->async->events |= COMEDI_CB_BLOCK;
375 }
376
377 if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
378 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
379 }
380
381 debug_n_ints++;
382 if (debug_n_ints >= 10) {
383 dt3k_ai_cancel(dev, s);
384 s->async->events |= COMEDI_CB_EOA;
385 }
386
387 comedi_event(dev, s);
388 return IRQ_HANDLED;
389 }
390
391 #ifdef DEBUG
392 static char *intr_flags[] = {
393 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
394 "DaSwError", "DaHwError", "CtDone", "CmDone",
395 };
396
397 static void debug_intr_flags(unsigned int flags)
398 {
399 int i;
400 printk("dt3k: intr_flags:");
401 for (i = 0; i < 8; i++) {
402 if (flags & (1 << i)) {
403 printk(" %s", intr_flags[i]);
404 }
405 }
406 printk("\n");
407 }
408 #endif
409
410 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
411 struct comedi_subdevice *s)
412 {
413 int front;
414 int rear;
415 int count;
416 int i;
417 short data;
418
419 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
420 count = front - devpriv->ai_front;
421 if (count < 0)
422 count += AI_FIFO_DEPTH;
423
424 printk("reading %d samples\n", count);
425
426 rear = devpriv->ai_rear;
427
428 for (i = 0; i < count; i++) {
429 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
430 comedi_buf_put(s->async, data);
431 rear++;
432 if (rear >= AI_FIFO_DEPTH)
433 rear = 0;
434 }
435
436 devpriv->ai_rear = rear;
437 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
438 }
439
440 static int dt3k_ai_cmdtest(struct comedi_device *dev,
441 struct comedi_subdevice *s, struct comedi_cmd *cmd)
442 {
443 int err = 0;
444 int tmp;
445
446 /* step 1: make sure trigger sources are trivially valid */
447
448 tmp = cmd->start_src;
449 cmd->start_src &= TRIG_NOW;
450 if (!cmd->start_src || tmp != cmd->start_src)
451 err++;
452
453 tmp = cmd->scan_begin_src;
454 cmd->scan_begin_src &= TRIG_TIMER;
455 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
456 err++;
457
458 tmp = cmd->convert_src;
459 cmd->convert_src &= TRIG_TIMER;
460 if (!cmd->convert_src || tmp != cmd->convert_src)
461 err++;
462
463 tmp = cmd->scan_end_src;
464 cmd->scan_end_src &= TRIG_COUNT;
465 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
466 err++;
467
468 tmp = cmd->stop_src;
469 cmd->stop_src &= TRIG_COUNT;
470 if (!cmd->stop_src || tmp != cmd->stop_src)
471 err++;
472
473 if (err)
474 return 1;
475
476 /* step 2: make sure trigger sources are unique and mutually compatible */
477
478 if (err)
479 return 2;
480
481 /* step 3: make sure arguments are trivially compatible */
482
483 if (cmd->start_arg != 0) {
484 cmd->start_arg = 0;
485 err++;
486 }
487
488 if (cmd->scan_begin_src == TRIG_TIMER) {
489 if (cmd->scan_begin_arg < this_board->ai_speed) {
490 cmd->scan_begin_arg = this_board->ai_speed;
491 err++;
492 }
493 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
494 cmd->scan_begin_arg = 100 * 16 * 65535;
495 err++;
496 }
497 } else {
498 /* not supported */
499 }
500 if (cmd->convert_src == TRIG_TIMER) {
501 if (cmd->convert_arg < this_board->ai_speed) {
502 cmd->convert_arg = this_board->ai_speed;
503 err++;
504 }
505 if (cmd->convert_arg > 50 * 16 * 65535) {
506 cmd->convert_arg = 50 * 16 * 65535;
507 err++;
508 }
509 } else {
510 /* not supported */
511 }
512
513 if (cmd->scan_end_arg != cmd->chanlist_len) {
514 cmd->scan_end_arg = cmd->chanlist_len;
515 err++;
516 }
517 if (cmd->stop_src == TRIG_COUNT) {
518 if (cmd->stop_arg > 0x00ffffff) {
519 cmd->stop_arg = 0x00ffffff;
520 err++;
521 }
522 } else {
523 /* TRIG_NONE */
524 if (cmd->stop_arg != 0) {
525 cmd->stop_arg = 0;
526 err++;
527 }
528 }
529
530 if (err)
531 return 3;
532
533 /* step 4: fix up any arguments */
534
535 if (cmd->scan_begin_src == TRIG_TIMER) {
536 tmp = cmd->scan_begin_arg;
537 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
538 cmd->flags & TRIG_ROUND_MASK);
539 if (tmp != cmd->scan_begin_arg)
540 err++;
541 } else {
542 /* not supported */
543 }
544 if (cmd->convert_src == TRIG_TIMER) {
545 tmp = cmd->convert_arg;
546 dt3k_ns_to_timer(50, &cmd->convert_arg,
547 cmd->flags & TRIG_ROUND_MASK);
548 if (tmp != cmd->convert_arg)
549 err++;
550 if (cmd->scan_begin_src == TRIG_TIMER &&
551 cmd->scan_begin_arg <
552 cmd->convert_arg * cmd->scan_end_arg) {
553 cmd->scan_begin_arg =
554 cmd->convert_arg * cmd->scan_end_arg;
555 err++;
556 }
557 } else {
558 /* not supported */
559 }
560
561 if (err)
562 return 4;
563
564 return 0;
565 }
566
567 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
568 unsigned int round_mode)
569 {
570 int divider, base, prescale;
571
572 /* This function needs improvment */
573 /* Don't know if divider==0 works. */
574
575 for (prescale = 0; prescale < 16; prescale++) {
576 base = timer_base * (prescale + 1);
577 switch (round_mode) {
578 case TRIG_ROUND_NEAREST:
579 default:
580 divider = (*nanosec + base / 2) / base;
581 break;
582 case TRIG_ROUND_DOWN:
583 divider = (*nanosec) / base;
584 break;
585 case TRIG_ROUND_UP:
586 divider = (*nanosec) / base;
587 break;
588 }
589 if (divider < 65536) {
590 *nanosec = divider * base;
591 return (prescale << 16) | (divider);
592 }
593 }
594
595 prescale = 15;
596 base = timer_base * (1 << prescale);
597 divider = 65535;
598 *nanosec = divider * base;
599 return (prescale << 16) | (divider);
600 }
601
602 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
603 {
604 struct comedi_cmd *cmd = &s->async->cmd;
605 int i;
606 unsigned int chan, range, aref;
607 unsigned int divider;
608 unsigned int tscandiv;
609 int ret;
610 unsigned int mode;
611
612 printk("dt3k_ai_cmd:\n");
613 for (i = 0; i < cmd->chanlist_len; i++) {
614 chan = CR_CHAN(cmd->chanlist[i]);
615 range = CR_RANGE(cmd->chanlist[i]);
616
617 writew((range << 6) | chan,
618 devpriv->io_addr + DPR_ADC_buffer + i);
619 }
620 aref = CR_AREF(cmd->chanlist[0]);
621
622 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
623 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
624
625 if (cmd->convert_src == TRIG_TIMER) {
626 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
627 cmd->flags & TRIG_ROUND_MASK);
628 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
629 printk("param[1]=0x%04x\n", divider >> 16);
630 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
631 printk("param[2]=0x%04x\n", divider & 0xffff);
632 } else {
633 /* not supported */
634 }
635
636 if (cmd->scan_begin_src == TRIG_TIMER) {
637 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
638 cmd->flags & TRIG_ROUND_MASK);
639 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
640 printk("param[3]=0x%04x\n", tscandiv >> 16);
641 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
642 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
643 } else {
644 /* not supported */
645 }
646
647 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
648 writew(mode, devpriv->io_addr + DPR_Params(5));
649 printk("param[5]=0x%04x\n", mode);
650 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
651 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
652
653 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
654 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
655
656 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
657 ret = dt3k_send_cmd(dev, CMD_CONFIG);
658
659 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
660 devpriv->io_addr + DPR_Int_Mask);
661
662 debug_n_ints = 0;
663
664 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
665 ret = dt3k_send_cmd(dev, CMD_START);
666
667 return 0;
668 }
669
670 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
671 {
672 int ret;
673
674 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
675 ret = dt3k_send_cmd(dev, CMD_STOP);
676
677 writew(0, devpriv->io_addr + DPR_Int_Mask);
678
679 return 0;
680 }
681
682 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
683 struct comedi_insn *insn, unsigned int *data)
684 {
685 int i;
686 unsigned int chan, gain, aref;
687
688 chan = CR_CHAN(insn->chanspec);
689 gain = CR_RANGE(insn->chanspec);
690 /* XXX docs don't explain how to select aref */
691 aref = CR_AREF(insn->chanspec);
692
693 for (i = 0; i < insn->n; i++) {
694 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
695 }
696
697 return i;
698 }
699
700 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
701 struct comedi_insn *insn, unsigned int *data)
702 {
703 int i;
704 unsigned int chan;
705
706 chan = CR_CHAN(insn->chanspec);
707 for (i = 0; i < insn->n; i++) {
708 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
709 devpriv->ao_readback[chan] = data[i];
710 }
711
712 return i;
713 }
714
715 static int dt3k_ao_insn_read(struct comedi_device *dev,
716 struct comedi_subdevice *s,
717 struct comedi_insn *insn, unsigned int *data)
718 {
719 int i;
720 unsigned int chan;
721
722 chan = CR_CHAN(insn->chanspec);
723 for (i = 0; i < insn->n; i++) {
724 data[i] = devpriv->ao_readback[chan];
725 }
726
727 return i;
728 }
729
730 static void dt3k_dio_config(struct comedi_device *dev, int bits)
731 {
732 /* XXX */
733 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
734
735 writew(bits, devpriv->io_addr + DPR_Params(0));
736 #if 0
737 /* don't know */
738 writew(0, devpriv->io_addr + DPR_Params(1));
739 writew(0, devpriv->io_addr + DPR_Params(2));
740 #endif
741
742 dt3k_send_cmd(dev, CMD_CONFIG);
743 }
744
745 static int dt3k_dio_insn_config(struct comedi_device *dev,
746 struct comedi_subdevice *s,
747 struct comedi_insn *insn, unsigned int *data)
748 {
749 int mask;
750
751 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
752
753 switch (data[0]) {
754 case INSN_CONFIG_DIO_OUTPUT:
755 s->io_bits |= mask;
756 break;
757 case INSN_CONFIG_DIO_INPUT:
758 s->io_bits &= ~mask;
759 break;
760 case INSN_CONFIG_DIO_QUERY:
761 data[1] =
762 (s->
763 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
764 COMEDI_INPUT;
765 return insn->n;
766 break;
767 default:
768 return -EINVAL;
769 break;
770 }
771 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
772 dt3k_dio_config(dev, mask);
773
774 return insn->n;
775 }
776
777 static int dt3k_dio_insn_bits(struct comedi_device *dev,
778 struct comedi_subdevice *s,
779 struct comedi_insn *insn, unsigned int *data)
780 {
781 if (insn->n != 2)
782 return -EINVAL;
783
784 if (data[0]) {
785 s->state &= ~data[0];
786 s->state |= data[1] & data[0];
787 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
788 }
789 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
790
791 return 2;
792 }
793
794 static int dt3k_mem_insn_read(struct comedi_device *dev,
795 struct comedi_subdevice *s,
796 struct comedi_insn *insn, unsigned int *data)
797 {
798 unsigned int addr = CR_CHAN(insn->chanspec);
799 int i;
800
801 for (i = 0; i < insn->n; i++) {
802 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
803 writew(addr, devpriv->io_addr + DPR_Params(0));
804 writew(1, devpriv->io_addr + DPR_Params(1));
805
806 dt3k_send_cmd(dev, CMD_READCODE);
807
808 data[i] = readw(devpriv->io_addr + DPR_Params(2));
809 }
810
811 return i;
812 }
813
814 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
815
816 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
817 {
818 struct comedi_subdevice *s;
819 int bus, slot;
820 int ret = 0;
821
822 printk("dt3000:");
823 bus = it->options[0];
824 slot = it->options[1];
825
826 ret = alloc_private(dev, sizeof(struct dt3k_private));
827 if (ret < 0)
828 return ret;
829
830 ret = dt_pci_probe(dev, bus, slot);
831 if (ret < 0)
832 return ret;
833 if (ret == 0) {
834 printk(" no DT board found\n");
835 return -ENODEV;
836 }
837
838 dev->board_name = this_board->name;
839
840 if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
841 "dt3000", dev)) {
842 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
843 return -EINVAL;
844 }
845 dev->irq = devpriv->pci_dev->irq;
846
847 ret = alloc_subdevices(dev, 4);
848 if (ret < 0)
849 return ret;
850
851 s = dev->subdevices;
852 dev->read_subdev = s;
853
854 /* ai subdevice */
855 s->type = COMEDI_SUBD_AI;
856 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
857 s->n_chan = this_board->adchan;
858 s->insn_read = dt3k_ai_insn;
859 s->maxdata = (1 << this_board->adbits) - 1;
860 s->len_chanlist = 512;
861 s->range_table = &range_dt3000_ai; /* XXX */
862 s->do_cmd = dt3k_ai_cmd;
863 s->do_cmdtest = dt3k_ai_cmdtest;
864 s->cancel = dt3k_ai_cancel;
865
866 s++;
867 /* ao subsystem */
868 s->type = COMEDI_SUBD_AO;
869 s->subdev_flags = SDF_WRITABLE;
870 s->n_chan = 2;
871 s->insn_read = dt3k_ao_insn_read;
872 s->insn_write = dt3k_ao_insn;
873 s->maxdata = (1 << this_board->dabits) - 1;
874 s->len_chanlist = 1;
875 s->range_table = &range_bipolar10;
876
877 s++;
878 /* dio subsystem */
879 s->type = COMEDI_SUBD_DIO;
880 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
881 s->n_chan = 8;
882 s->insn_config = dt3k_dio_insn_config;
883 s->insn_bits = dt3k_dio_insn_bits;
884 s->maxdata = 1;
885 s->len_chanlist = 8;
886 s->range_table = &range_digital;
887
888 s++;
889 /* mem subsystem */
890 s->type = COMEDI_SUBD_MEMORY;
891 s->subdev_flags = SDF_READABLE;
892 s->n_chan = 0x1000;
893 s->insn_read = dt3k_mem_insn_read;
894 s->maxdata = 0xff;
895 s->len_chanlist = 1;
896 s->range_table = &range_unknown;
897
898 #if 0
899 s++;
900 /* proc subsystem */
901 s->type = COMEDI_SUBD_PROC;
902 #endif
903
904 return 0;
905 }
906
907 static int dt3000_detach(struct comedi_device *dev)
908 {
909 if (dev->irq)
910 free_irq(dev->irq, dev);
911
912 if (devpriv) {
913 if (devpriv->pci_dev) {
914 if (devpriv->phys_addr) {
915 comedi_pci_disable(devpriv->pci_dev);
916 }
917 pci_dev_put(devpriv->pci_dev);
918 }
919 if (devpriv->io_addr)
920 iounmap(devpriv->io_addr);
921 }
922 /* XXX */
923
924 return 0;
925 }
926
927 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
928 static int setup_pci(struct comedi_device *dev);
929
930 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
931 {
932 int board;
933 int ret;
934 struct pci_dev *pcidev;
935
936 pcidev = NULL;
937 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
938 if ((bus == 0 && slot == 0) ||
939 (pcidev->bus->number == bus &&
940 PCI_SLOT(pcidev->devfn) == slot)) {
941 break;
942 }
943 }
944 devpriv->pci_dev = pcidev;
945
946 if (board >= 0)
947 dev->board_ptr = dt3k_boardtypes + board;
948
949 if (!devpriv->pci_dev)
950 return 0;
951
952 ret = setup_pci(dev);
953 if (ret < 0)
954 return ret;
955
956 return 1;
957 }
958
959 static int setup_pci(struct comedi_device *dev)
960 {
961 resource_size_t addr;
962 int ret;
963
964 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
965 if (ret < 0)
966 return ret;
967
968 addr = pci_resource_start(devpriv->pci_dev, 0);
969 devpriv->phys_addr = addr;
970 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
971 if (!devpriv->io_addr)
972 return -ENOMEM;
973 #if DEBUG
974 printk("0x%08llx mapped to %p, ",
975 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
976 #endif
977
978 return 0;
979 }
980
981 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
982 {
983 int i;
984
985 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
986 from != NULL;
987 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
988 for (i = 0; i < n_dt3k_boards; i++) {
989 if (from->device == dt3k_boardtypes[i].device_id) {
990 *board = i;
991 return from;
992 }
993 }
994 printk
995 ("unknown Data Translation PCI device found with device_id=0x%04x\n",
996 from->device);
997 }
998 *board = -1;
999 return from;
1000 }
This page took 0.064912 seconds and 6 git commands to generate.