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