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