dt3000.c revision 68c3dbff9fc9f25872408d0e95980d41733d48d0
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 ret = alloc_private(dev, sizeof(struct dt3k_private)); 815 if (ret < 0) 816 return ret; 817 818 ret = dt_pci_probe(dev, bus, slot); 819 if (ret < 0) 820 return ret; 821 if (ret == 0) { 822 printk(" no DT board found\n"); 823 return -ENODEV; 824 } 825 826 dev->board_name = this_board->name; 827 828 if (comedi_request_irq(devpriv->pci_dev->irq, dt3k_interrupt, 829 IRQF_SHARED, "dt3000", dev)) { 830 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq); 831 return -EINVAL; 832 } 833 dev->irq = devpriv->pci_dev->irq; 834 835 ret = alloc_subdevices(dev, 4); 836 if (ret < 0) 837 return ret; 838 839 s = dev->subdevices; 840 dev->read_subdev = s; 841 842 /* ai subdevice */ 843 s->type = COMEDI_SUBD_AI; 844 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; 845 s->n_chan = this_board->adchan; 846 s->insn_read = dt3k_ai_insn; 847 s->maxdata = (1 << this_board->adbits) - 1; 848 s->len_chanlist = 512; 849 s->range_table = &range_dt3000_ai; /* XXX */ 850 s->do_cmd = dt3k_ai_cmd; 851 s->do_cmdtest = dt3k_ai_cmdtest; 852 s->cancel = dt3k_ai_cancel; 853 854 s++; 855 /* ao subsystem */ 856 s->type = COMEDI_SUBD_AO; 857 s->subdev_flags = SDF_WRITABLE; 858 s->n_chan = 2; 859 s->insn_read = dt3k_ao_insn_read; 860 s->insn_write = dt3k_ao_insn; 861 s->maxdata = (1 << this_board->dabits) - 1; 862 s->len_chanlist = 1; 863 s->range_table = &range_bipolar10; 864 865 s++; 866 /* dio subsystem */ 867 s->type = COMEDI_SUBD_DIO; 868 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 869 s->n_chan = 8; 870 s->insn_config = dt3k_dio_insn_config; 871 s->insn_bits = dt3k_dio_insn_bits; 872 s->maxdata = 1; 873 s->len_chanlist = 8; 874 s->range_table = &range_digital; 875 876 s++; 877 /* mem subsystem */ 878 s->type = COMEDI_SUBD_MEMORY; 879 s->subdev_flags = SDF_READABLE; 880 s->n_chan = 0x1000; 881 s->insn_read = dt3k_mem_insn_read; 882 s->maxdata = 0xff; 883 s->len_chanlist = 1; 884 s->range_table = &range_unknown; 885 886#if 0 887 s++; 888 /* proc subsystem */ 889 s->type = COMEDI_SUBD_PROC; 890#endif 891 892 return 0; 893} 894 895static int dt3000_detach(struct comedi_device *dev) 896{ 897 if (dev->irq) 898 comedi_free_irq(dev->irq, dev); 899 900 if (devpriv) { 901 if (devpriv->pci_dev) { 902 if (devpriv->phys_addr) { 903 comedi_pci_disable(devpriv->pci_dev); 904 } 905 pci_dev_put(devpriv->pci_dev); 906 } 907 if (devpriv->io_addr) 908 iounmap(devpriv->io_addr); 909 } 910 /* XXX */ 911 912 return 0; 913} 914 915static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board); 916static int setup_pci(struct comedi_device *dev); 917 918static int dt_pci_probe(struct comedi_device *dev, int bus, int slot) 919{ 920 int board; 921 int ret; 922 struct pci_dev *pcidev; 923 924 pcidev = NULL; 925 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) { 926 if ((bus == 0 && slot == 0) || 927 (pcidev->bus->number == bus && 928 PCI_SLOT(pcidev->devfn) == slot)) { 929 break; 930 } 931 } 932 devpriv->pci_dev = pcidev; 933 934 if (board >= 0) 935 dev->board_ptr = dt3k_boardtypes + board; 936 937 if (!devpriv->pci_dev) 938 return 0; 939 940 ret = setup_pci(dev); 941 if (ret < 0) 942 return ret; 943 944 return 1; 945} 946 947static int setup_pci(struct comedi_device *dev) 948{ 949 resource_size_t addr; 950 int ret; 951 952 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000"); 953 if (ret < 0) 954 return ret; 955 956 addr = pci_resource_start(devpriv->pci_dev, 0); 957 devpriv->phys_addr = addr; 958 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE); 959 if (!devpriv->io_addr) 960 return -ENOMEM; 961#if DEBUG 962 printk("0x%08llx mapped to %p, ", 963 (unsigned long long)devpriv->phys_addr, devpriv->io_addr); 964#endif 965 966 return 0; 967} 968 969static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board) 970{ 971 int i; 972 973 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from); 974 from != NULL; 975 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) { 976 for (i = 0; i < n_dt3k_boards; i++) { 977 if (from->device == dt3k_boardtypes[i].device_id) { 978 *board = i; 979 return from; 980 } 981 } 982 printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device); 983 } 984 *board = -1; 985 return from; 986} 987