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