dt3000.c revision a471eace7baa40cdf16d3f26b2f78ddce613ca8f
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: not applicable, uses PCI auto config 33 34There is code to support AI commands, but it may not work. 35 36AO commands are not supported. 37*/ 38 39/* 40 The DT3000 series is Data Translation's attempt to make a PCI 41 data acquisition board. The design of this series is very nice, 42 since each board has an on-board DSP (Texas Instruments TMS320C52). 43 However, a few details are a little annoying. The boards lack 44 bus-mastering DMA, which eliminates them from serious work. 45 They also are not capable of autocalibration, which is a common 46 feature in modern hardware. The default firmware is pretty bad, 47 making it nearly impossible to write an RT compatible driver. 48 It would make an interesting project to write a decent firmware 49 for these boards. 50 51 Data Translation originally wanted an NDA for the documentation 52 for the 3k series. However, if you ask nicely, they might send 53 you the docs without one, also. 54*/ 55 56#define DEBUG 1 57 58#include <linux/interrupt.h> 59#include "../comedidev.h" 60#include <linux/delay.h> 61 62#include "comedi_fc.h" 63 64/* 65 * PCI device id's supported by this driver 66 */ 67#define PCI_DEVICE_ID_DT3001 0x0022 68#define PCI_DEVICE_ID_DT3002 0x0023 69#define PCI_DEVICE_ID_DT3003 0x0024 70#define PCI_DEVICE_ID_DT3004 0x0025 71#define PCI_DEVICE_ID_DT3005 0x0026 72#define PCI_DEVICE_ID_DT3001_PGL 0x0027 73#define PCI_DEVICE_ID_DT3003_PGL 0x0028 74 75static const struct comedi_lrange range_dt3000_ai = { 76 4, { 77 BIP_RANGE(10), 78 BIP_RANGE(5), 79 BIP_RANGE(2.5), 80 BIP_RANGE(1.25) 81 } 82}; 83 84static const struct comedi_lrange range_dt3000_ai_pgl = { 85 4, { 86 BIP_RANGE(10), 87 BIP_RANGE(1), 88 BIP_RANGE(0.1), 89 BIP_RANGE(0.02) 90 } 91}; 92 93struct dt3k_boardtype { 94 const char *name; 95 unsigned int device_id; 96 int adchan; 97 int adbits; 98 int ai_speed; 99 const struct comedi_lrange *adrange; 100 int dachan; 101 int dabits; 102}; 103 104static const struct dt3k_boardtype dt3k_boardtypes[] = { 105 { 106 .name = "dt3001", 107 .device_id = PCI_DEVICE_ID_DT3001, 108 .adchan = 16, 109 .adbits = 12, 110 .adrange = &range_dt3000_ai, 111 .ai_speed = 3000, 112 .dachan = 2, 113 .dabits = 12, 114 }, { 115 .name = "dt3001-pgl", 116 .device_id = PCI_DEVICE_ID_DT3001_PGL, 117 .adchan = 16, 118 .adbits = 12, 119 .adrange = &range_dt3000_ai_pgl, 120 .ai_speed = 3000, 121 .dachan = 2, 122 .dabits = 12, 123 }, { 124 .name = "dt3002", 125 .device_id = PCI_DEVICE_ID_DT3002, 126 .adchan = 32, 127 .adbits = 12, 128 .adrange = &range_dt3000_ai, 129 .ai_speed = 3000, 130 }, { 131 .name = "dt3003", 132 .device_id = PCI_DEVICE_ID_DT3003, 133 .adchan = 64, 134 .adbits = 12, 135 .adrange = &range_dt3000_ai, 136 .ai_speed = 3000, 137 .dachan = 2, 138 .dabits = 12, 139 }, { 140 .name = "dt3003-pgl", 141 .device_id = PCI_DEVICE_ID_DT3003_PGL, 142 .adchan = 64, 143 .adbits = 12, 144 .adrange = &range_dt3000_ai_pgl, 145 .ai_speed = 3000, 146 .dachan = 2, 147 .dabits = 12, 148 }, { 149 .name = "dt3004", 150 .device_id = PCI_DEVICE_ID_DT3004, 151 .adchan = 16, 152 .adbits = 16, 153 .adrange = &range_dt3000_ai, 154 .ai_speed = 10000, 155 .dachan = 2, 156 .dabits = 12, 157 }, { 158 .name = "dt3005", /* a.k.a. 3004-200 */ 159 .device_id = PCI_DEVICE_ID_DT3005, 160 .adchan = 16, 161 .adbits = 16, 162 .adrange = &range_dt3000_ai, 163 .ai_speed = 5000, 164 .dachan = 2, 165 .dabits = 12, 166 }, 167}; 168 169#define DT3000_SIZE (4*0x1000) 170 171/* dual-ported RAM location definitions */ 172 173#define DPR_DAC_buffer (4*0x000) 174#define DPR_ADC_buffer (4*0x800) 175#define DPR_Command (4*0xfd3) 176#define DPR_SubSys (4*0xfd3) 177#define DPR_Encode (4*0xfd4) 178#define DPR_Params(a) (4*(0xfd5+(a))) 179#define DPR_Tick_Reg_Lo (4*0xff5) 180#define DPR_Tick_Reg_Hi (4*0xff6) 181#define DPR_DA_Buf_Front (4*0xff7) 182#define DPR_DA_Buf_Rear (4*0xff8) 183#define DPR_AD_Buf_Front (4*0xff9) 184#define DPR_AD_Buf_Rear (4*0xffa) 185#define DPR_Int_Mask (4*0xffb) 186#define DPR_Intr_Flag (4*0xffc) 187#define DPR_Response_Mbx (4*0xffe) 188#define DPR_Command_Mbx (4*0xfff) 189 190#define AI_FIFO_DEPTH 2003 191#define AO_FIFO_DEPTH 2048 192 193/* command list */ 194 195#define CMD_GETBRDINFO 0 196#define CMD_CONFIG 1 197#define CMD_GETCONFIG 2 198#define CMD_START 3 199#define CMD_STOP 4 200#define CMD_READSINGLE 5 201#define CMD_WRITESINGLE 6 202#define CMD_CALCCLOCK 7 203#define CMD_READEVENTS 8 204#define CMD_WRITECTCTRL 16 205#define CMD_READCTCTRL 17 206#define CMD_WRITECT 18 207#define CMD_READCT 19 208#define CMD_WRITEDATA 32 209#define CMD_READDATA 33 210#define CMD_WRITEIO 34 211#define CMD_READIO 35 212#define CMD_WRITECODE 36 213#define CMD_READCODE 37 214#define CMD_EXECUTE 38 215#define CMD_HALT 48 216 217#define SUBS_AI 0 218#define SUBS_AO 1 219#define SUBS_DIN 2 220#define SUBS_DOUT 3 221#define SUBS_MEM 4 222#define SUBS_CT 5 223 224/* interrupt flags */ 225#define DT3000_CMDONE 0x80 226#define DT3000_CTDONE 0x40 227#define DT3000_DAHWERR 0x20 228#define DT3000_DASWERR 0x10 229#define DT3000_DAEMPTY 0x08 230#define DT3000_ADHWERR 0x04 231#define DT3000_ADSWERR 0x02 232#define DT3000_ADFULL 0x01 233 234#define DT3000_COMPLETION_MASK 0xff00 235#define DT3000_COMMAND_MASK 0x00ff 236#define DT3000_NOTPROCESSED 0x0000 237#define DT3000_NOERROR 0x5500 238#define DT3000_ERROR 0xaa00 239#define DT3000_NOTSUPPORTED 0xff00 240 241#define DT3000_EXTERNAL_CLOCK 1 242#define DT3000_RISING_EDGE 2 243 244#define TMODE_MASK 0x1c 245 246#define DT3000_AD_TRIG_INTERNAL (0<<2) 247#define DT3000_AD_TRIG_EXTERNAL (1<<2) 248#define DT3000_AD_RETRIG_INTERNAL (2<<2) 249#define DT3000_AD_RETRIG_EXTERNAL (3<<2) 250#define DT3000_AD_EXTRETRIG (4<<2) 251 252#define DT3000_CHANNEL_MODE_SE 0 253#define DT3000_CHANNEL_MODE_DI 1 254 255struct dt3k_private { 256 void __iomem *io_addr; 257 unsigned int lock; 258 unsigned int ao_readback[2]; 259 unsigned int ai_front; 260 unsigned int ai_rear; 261}; 262 263#ifdef DEBUG 264static char *intr_flags[] = { 265 "AdFull", "AdSwError", "AdHwError", "DaEmpty", 266 "DaSwError", "DaHwError", "CtDone", "CmDone", 267}; 268 269static void debug_intr_flags(unsigned int flags) 270{ 271 int i; 272 printk(KERN_DEBUG "dt3k: intr_flags:"); 273 for (i = 0; i < 8; i++) { 274 if (flags & (1 << i)) 275 printk(KERN_CONT " %s", intr_flags[i]); 276 } 277 printk(KERN_CONT "\n"); 278} 279#endif 280 281#define TIMEOUT 100 282 283static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) 284{ 285 struct dt3k_private *devpriv = dev->private; 286 int i; 287 unsigned int status = 0; 288 289 writew(cmd, devpriv->io_addr + DPR_Command_Mbx); 290 291 for (i = 0; i < TIMEOUT; i++) { 292 status = readw(devpriv->io_addr + DPR_Command_Mbx); 293 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED) 294 break; 295 udelay(1); 296 } 297 298 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR) 299 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n", 300 __func__, status); 301} 302 303static unsigned int dt3k_readsingle(struct comedi_device *dev, 304 unsigned int subsys, unsigned int chan, 305 unsigned int gain) 306{ 307 struct dt3k_private *devpriv = dev->private; 308 309 writew(subsys, devpriv->io_addr + DPR_SubSys); 310 311 writew(chan, devpriv->io_addr + DPR_Params(0)); 312 writew(gain, devpriv->io_addr + DPR_Params(1)); 313 314 dt3k_send_cmd(dev, CMD_READSINGLE); 315 316 return readw(devpriv->io_addr + DPR_Params(2)); 317} 318 319static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, 320 unsigned int chan, unsigned int data) 321{ 322 struct dt3k_private *devpriv = dev->private; 323 324 writew(subsys, devpriv->io_addr + DPR_SubSys); 325 326 writew(chan, devpriv->io_addr + DPR_Params(0)); 327 writew(0, devpriv->io_addr + DPR_Params(1)); 328 writew(data, devpriv->io_addr + DPR_Params(2)); 329 330 dt3k_send_cmd(dev, CMD_WRITESINGLE); 331} 332 333static void dt3k_ai_empty_fifo(struct comedi_device *dev, 334 struct comedi_subdevice *s) 335{ 336 struct dt3k_private *devpriv = dev->private; 337 int front; 338 int rear; 339 int count; 340 int i; 341 short data; 342 343 front = readw(devpriv->io_addr + DPR_AD_Buf_Front); 344 count = front - devpriv->ai_front; 345 if (count < 0) 346 count += AI_FIFO_DEPTH; 347 348 rear = devpriv->ai_rear; 349 350 for (i = 0; i < count; i++) { 351 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear); 352 comedi_buf_put(s->async, data); 353 rear++; 354 if (rear >= AI_FIFO_DEPTH) 355 rear = 0; 356 } 357 358 devpriv->ai_rear = rear; 359 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear); 360} 361 362static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 363{ 364 struct dt3k_private *devpriv = dev->private; 365 366 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys); 367 dt3k_send_cmd(dev, CMD_STOP); 368 369 writew(0, devpriv->io_addr + DPR_Int_Mask); 370 371 return 0; 372} 373 374static int debug_n_ints; 375 376/* FIXME! Assumes shared interrupt is for this card. */ 377/* What's this debug_n_ints stuff? Obviously needs some work... */ 378static irqreturn_t dt3k_interrupt(int irq, void *d) 379{ 380 struct comedi_device *dev = d; 381 struct dt3k_private *devpriv = dev->private; 382 struct comedi_subdevice *s; 383 unsigned int status; 384 385 if (!dev->attached) 386 return IRQ_NONE; 387 388 s = &dev->subdevices[0]; 389 status = readw(devpriv->io_addr + DPR_Intr_Flag); 390#ifdef DEBUG 391 debug_intr_flags(status); 392#endif 393 394 if (status & DT3000_ADFULL) { 395 dt3k_ai_empty_fifo(dev, s); 396 s->async->events |= COMEDI_CB_BLOCK; 397 } 398 399 if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) 400 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 401 402 debug_n_ints++; 403 if (debug_n_ints >= 10) { 404 dt3k_ai_cancel(dev, s); 405 s->async->events |= COMEDI_CB_EOA; 406 } 407 408 comedi_event(dev, s); 409 return IRQ_HANDLED; 410} 411 412static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec, 413 unsigned int round_mode) 414{ 415 int divider, base, prescale; 416 417 /* This function needs improvment */ 418 /* Don't know if divider==0 works. */ 419 420 for (prescale = 0; prescale < 16; prescale++) { 421 base = timer_base * (prescale + 1); 422 switch (round_mode) { 423 case TRIG_ROUND_NEAREST: 424 default: 425 divider = (*nanosec + base / 2) / base; 426 break; 427 case TRIG_ROUND_DOWN: 428 divider = (*nanosec) / base; 429 break; 430 case TRIG_ROUND_UP: 431 divider = (*nanosec) / base; 432 break; 433 } 434 if (divider < 65536) { 435 *nanosec = divider * base; 436 return (prescale << 16) | (divider); 437 } 438 } 439 440 prescale = 15; 441 base = timer_base * (1 << prescale); 442 divider = 65535; 443 *nanosec = divider * base; 444 return (prescale << 16) | (divider); 445} 446 447static int dt3k_ai_cmdtest(struct comedi_device *dev, 448 struct comedi_subdevice *s, struct comedi_cmd *cmd) 449{ 450 const struct dt3k_boardtype *this_board = comedi_board(dev); 451 int err = 0; 452 int tmp; 453 454 /* Step 1 : check if triggers are trivially valid */ 455 456 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); 457 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); 458 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); 459 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 460 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT); 461 462 if (err) 463 return 1; 464 465 /* Step 2a : make sure trigger sources are unique */ 466 /* Step 2b : and mutually compatible */ 467 468 if (err) 469 return 2; 470 471 /* Step 3: check if arguments are trivially valid */ 472 473 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 474 475 if (cmd->scan_begin_src == TRIG_TIMER) { 476 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 477 this_board->ai_speed); 478 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 479 100 * 16 * 65535); 480 } 481 482 if (cmd->convert_src == TRIG_TIMER) { 483 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 484 this_board->ai_speed); 485 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 486 50 * 16 * 65535); 487 } 488 489 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 490 491 if (cmd->stop_src == TRIG_COUNT) 492 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); 493 else /* TRIG_NONE */ 494 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 495 496 if (err) 497 return 3; 498 499 /* step 4: fix up any arguments */ 500 501 if (cmd->scan_begin_src == TRIG_TIMER) { 502 tmp = cmd->scan_begin_arg; 503 dt3k_ns_to_timer(100, &cmd->scan_begin_arg, 504 cmd->flags & TRIG_ROUND_MASK); 505 if (tmp != cmd->scan_begin_arg) 506 err++; 507 } 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 } 523 524 if (err) 525 return 4; 526 527 return 0; 528} 529 530static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 531{ 532 struct dt3k_private *devpriv = dev->private; 533 struct comedi_cmd *cmd = &s->async->cmd; 534 int i; 535 unsigned int chan, range, aref; 536 unsigned int divider; 537 unsigned int tscandiv; 538 unsigned int mode; 539 540 for (i = 0; i < cmd->chanlist_len; i++) { 541 chan = CR_CHAN(cmd->chanlist[i]); 542 range = CR_RANGE(cmd->chanlist[i]); 543 544 writew((range << 6) | chan, 545 devpriv->io_addr + DPR_ADC_buffer + i); 546 } 547 aref = CR_AREF(cmd->chanlist[0]); 548 549 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0)); 550 551 if (cmd->convert_src == TRIG_TIMER) { 552 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, 553 cmd->flags & TRIG_ROUND_MASK); 554 writew((divider >> 16), devpriv->io_addr + DPR_Params(1)); 555 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2)); 556 } 557 558 if (cmd->scan_begin_src == TRIG_TIMER) { 559 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg, 560 cmd->flags & TRIG_ROUND_MASK); 561 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3)); 562 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4)); 563 } 564 565 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0; 566 writew(mode, devpriv->io_addr + DPR_Params(5)); 567 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6)); 568 569 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7)); 570 571 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys); 572 dt3k_send_cmd(dev, CMD_CONFIG); 573 574 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR, 575 devpriv->io_addr + DPR_Int_Mask); 576 577 debug_n_ints = 0; 578 579 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys); 580 dt3k_send_cmd(dev, CMD_START); 581 582 return 0; 583} 584 585static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, 586 struct comedi_insn *insn, unsigned int *data) 587{ 588 int i; 589 unsigned int chan, gain, aref; 590 591 chan = CR_CHAN(insn->chanspec); 592 gain = CR_RANGE(insn->chanspec); 593 /* XXX docs don't explain how to select aref */ 594 aref = CR_AREF(insn->chanspec); 595 596 for (i = 0; i < insn->n; i++) 597 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain); 598 599 return i; 600} 601 602static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, 603 struct comedi_insn *insn, unsigned int *data) 604{ 605 struct dt3k_private *devpriv = dev->private; 606 int i; 607 unsigned int chan; 608 609 chan = CR_CHAN(insn->chanspec); 610 for (i = 0; i < insn->n; i++) { 611 dt3k_writesingle(dev, SUBS_AO, chan, data[i]); 612 devpriv->ao_readback[chan] = data[i]; 613 } 614 615 return i; 616} 617 618static int dt3k_ao_insn_read(struct comedi_device *dev, 619 struct comedi_subdevice *s, 620 struct comedi_insn *insn, unsigned int *data) 621{ 622 struct dt3k_private *devpriv = dev->private; 623 int i; 624 unsigned int chan; 625 626 chan = CR_CHAN(insn->chanspec); 627 for (i = 0; i < insn->n; i++) 628 data[i] = devpriv->ao_readback[chan]; 629 630 return i; 631} 632 633static void dt3k_dio_config(struct comedi_device *dev, int bits) 634{ 635 struct dt3k_private *devpriv = dev->private; 636 637 /* XXX */ 638 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys); 639 640 writew(bits, devpriv->io_addr + DPR_Params(0)); 641#if 0 642 /* don't know */ 643 writew(0, devpriv->io_addr + DPR_Params(1)); 644 writew(0, devpriv->io_addr + DPR_Params(2)); 645#endif 646 647 dt3k_send_cmd(dev, CMD_CONFIG); 648} 649 650static int dt3k_dio_insn_config(struct comedi_device *dev, 651 struct comedi_subdevice *s, 652 struct comedi_insn *insn, unsigned int *data) 653{ 654 int mask; 655 656 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0; 657 658 switch (data[0]) { 659 case INSN_CONFIG_DIO_OUTPUT: 660 s->io_bits |= mask; 661 break; 662 case INSN_CONFIG_DIO_INPUT: 663 s->io_bits &= ~mask; 664 break; 665 case INSN_CONFIG_DIO_QUERY: 666 data[1] = 667 (s-> 668 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : 669 COMEDI_INPUT; 670 return insn->n; 671 break; 672 default: 673 return -EINVAL; 674 break; 675 } 676 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3); 677 dt3k_dio_config(dev, mask); 678 679 return insn->n; 680} 681 682static int dt3k_dio_insn_bits(struct comedi_device *dev, 683 struct comedi_subdevice *s, 684 struct comedi_insn *insn, unsigned int *data) 685{ 686 if (data[0]) { 687 s->state &= ~data[0]; 688 s->state |= data[1] & data[0]; 689 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state); 690 } 691 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0); 692 693 return insn->n; 694} 695 696static int dt3k_mem_insn_read(struct comedi_device *dev, 697 struct comedi_subdevice *s, 698 struct comedi_insn *insn, unsigned int *data) 699{ 700 struct dt3k_private *devpriv = dev->private; 701 unsigned int addr = CR_CHAN(insn->chanspec); 702 int i; 703 704 for (i = 0; i < insn->n; i++) { 705 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys); 706 writew(addr, devpriv->io_addr + DPR_Params(0)); 707 writew(1, devpriv->io_addr + DPR_Params(1)); 708 709 dt3k_send_cmd(dev, CMD_READCODE); 710 711 data[i] = readw(devpriv->io_addr + DPR_Params(2)); 712 } 713 714 return i; 715} 716 717static const void *dt3000_find_boardinfo(struct comedi_device *dev, 718 struct pci_dev *pcidev) 719{ 720 const struct dt3k_boardtype *this_board; 721 int i; 722 723 for (i = 0; i < ARRAY_SIZE(dt3k_boardtypes); i++) { 724 this_board = &dt3k_boardtypes[i]; 725 if (this_board->device_id == pcidev->device) 726 return this_board; 727 } 728 return NULL; 729} 730 731static int __devinit dt3000_auto_attach(struct comedi_device *dev, 732 unsigned long context_unused) 733{ 734 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 735 const struct dt3k_boardtype *this_board; 736 struct dt3k_private *devpriv; 737 struct comedi_subdevice *s; 738 resource_size_t pci_base; 739 int ret = 0; 740 741 this_board = dt3000_find_boardinfo(dev, pcidev); 742 if (!this_board) 743 return -ENODEV; 744 dev->board_ptr = this_board; 745 dev->board_name = this_board->name; 746 747 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); 748 if (!devpriv) 749 return -ENOMEM; 750 dev->private = devpriv; 751 752 ret = comedi_pci_enable(pcidev, dev->board_name); 753 if (ret < 0) 754 return ret; 755 dev->iobase = 1; /* the "detach" needs this */ 756 757 pci_base = pci_resource_start(pcidev, 0); 758 devpriv->io_addr = ioremap(pci_base, DT3000_SIZE); 759 if (!devpriv->io_addr) 760 return -ENOMEM; 761 762 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED, 763 dev->board_name, dev); 764 if (ret) 765 return ret; 766 dev->irq = pcidev->irq; 767 768 ret = comedi_alloc_subdevices(dev, 4); 769 if (ret) 770 return ret; 771 772 s = &dev->subdevices[0]; 773 dev->read_subdev = s; 774 /* ai subdevice */ 775 s->type = COMEDI_SUBD_AI; 776 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; 777 s->n_chan = this_board->adchan; 778 s->insn_read = dt3k_ai_insn; 779 s->maxdata = (1 << this_board->adbits) - 1; 780 s->len_chanlist = 512; 781 s->range_table = &range_dt3000_ai; /* XXX */ 782 s->do_cmd = dt3k_ai_cmd; 783 s->do_cmdtest = dt3k_ai_cmdtest; 784 s->cancel = dt3k_ai_cancel; 785 786 s = &dev->subdevices[1]; 787 /* ao subsystem */ 788 s->type = COMEDI_SUBD_AO; 789 s->subdev_flags = SDF_WRITABLE; 790 s->n_chan = 2; 791 s->insn_read = dt3k_ao_insn_read; 792 s->insn_write = dt3k_ao_insn; 793 s->maxdata = (1 << this_board->dabits) - 1; 794 s->len_chanlist = 1; 795 s->range_table = &range_bipolar10; 796 797 s = &dev->subdevices[2]; 798 /* dio subsystem */ 799 s->type = COMEDI_SUBD_DIO; 800 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 801 s->n_chan = 8; 802 s->insn_config = dt3k_dio_insn_config; 803 s->insn_bits = dt3k_dio_insn_bits; 804 s->maxdata = 1; 805 s->len_chanlist = 8; 806 s->range_table = &range_digital; 807 808 s = &dev->subdevices[3]; 809 /* mem subsystem */ 810 s->type = COMEDI_SUBD_MEMORY; 811 s->subdev_flags = SDF_READABLE; 812 s->n_chan = 0x1000; 813 s->insn_read = dt3k_mem_insn_read; 814 s->maxdata = 0xff; 815 s->len_chanlist = 1; 816 s->range_table = &range_unknown; 817 818#if 0 819 s = &dev->subdevices[4]; 820 /* proc subsystem */ 821 s->type = COMEDI_SUBD_PROC; 822#endif 823 824 dev_info(dev->class_dev, "%s attached\n", dev->board_name); 825 826 return 0; 827} 828 829static void dt3000_detach(struct comedi_device *dev) 830{ 831 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 832 struct dt3k_private *devpriv = dev->private; 833 834 if (dev->irq) 835 free_irq(dev->irq, dev); 836 if (devpriv) { 837 if (devpriv->io_addr) 838 iounmap(devpriv->io_addr); 839 } 840 if (pcidev) { 841 if (dev->iobase) 842 comedi_pci_disable(pcidev); 843 } 844} 845 846static struct comedi_driver dt3000_driver = { 847 .driver_name = "dt3000", 848 .module = THIS_MODULE, 849 .auto_attach = dt3000_auto_attach, 850 .detach = dt3000_detach, 851}; 852 853static int __devinit dt3000_pci_probe(struct pci_dev *dev, 854 const struct pci_device_id *ent) 855{ 856 return comedi_pci_auto_config(dev, &dt3000_driver); 857} 858 859static void __devexit dt3000_pci_remove(struct pci_dev *dev) 860{ 861 comedi_pci_auto_unconfig(dev); 862} 863 864static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = { 865 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001) }, 866 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001_PGL) }, 867 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3002) }, 868 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003) }, 869 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003_PGL) }, 870 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3004) }, 871 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3005) }, 872 { 0 } 873}; 874MODULE_DEVICE_TABLE(pci, dt3000_pci_table); 875 876static struct pci_driver dt3000_pci_driver = { 877 .name = "dt3000", 878 .id_table = dt3000_pci_table, 879 .probe = dt3000_pci_probe, 880 .remove = dt3000_pci_remove, 881}; 882module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver); 883 884MODULE_AUTHOR("Comedi http://www.comedi.org"); 885MODULE_DESCRIPTION("Comedi low-level driver"); 886MODULE_LICENSE("GPL"); 887