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