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