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