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