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