1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * dt3000.c 4 * Data Translation DT3000 series driver 5 * 6 * COMEDI - Linux Control and Measurement Device Interface 7 * Copyright (C) 1999 David A. Schleef <ds@schleef.org> 8 */ 9 10 /* 11 * Driver: dt3000 12 * Description: Data Translation DT3000 series 13 * Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003, 14 * DT3003-PGL, DT3004, DT3005, DT3004-200 15 * Author: ds 16 * Updated: Mon, 14 Apr 2008 15:41:24 +0100 17 * Status: works 18 * 19 * Configuration Options: not applicable, uses PCI auto config 20 * 21 * There is code to support AI commands, but it may not work. 22 * 23 * AO commands are not supported. 24 */ 25 26 /* 27 * The DT3000 series is Data Translation's attempt to make a PCI 28 * data acquisition board. The design of this series is very nice, 29 * since each board has an on-board DSP (Texas Instruments TMS320C52). 30 * However, a few details are a little annoying. The boards lack 31 * bus-mastering DMA, which eliminates them from serious work. 32 * They also are not capable of autocalibration, which is a common 33 * feature in modern hardware. The default firmware is pretty bad, 34 * making it nearly impossible to write an RT compatible driver. 35 * It would make an interesting project to write a decent firmware 36 * for these boards. 37 * 38 * Data Translation originally wanted an NDA for the documentation 39 * for the 3k series. However, if you ask nicely, they might send 40 * you the docs without one, also. 41 */ 42 43 #include <linux/module.h> 44 #include <linux/delay.h> 45 #include <linux/interrupt.h> 46 #include <linux/comedi/comedi_pci.h> 47 48 /* 49 * PCI BAR0 - dual-ported RAM location definitions (dev->mmio) 50 */ 51 #define DPR_DAC_BUFFER (4 * 0x000) 52 #define DPR_ADC_BUFFER (4 * 0x800) 53 #define DPR_COMMAND (4 * 0xfd3) 54 #define DPR_SUBSYS (4 * 0xfd3) 55 #define DPR_SUBSYS_AI 0 56 #define DPR_SUBSYS_AO 1 57 #define DPR_SUBSYS_DIN 2 58 #define DPR_SUBSYS_DOUT 3 59 #define DPR_SUBSYS_MEM 4 60 #define DPR_SUBSYS_CT 5 61 #define DPR_ENCODE (4 * 0xfd4) 62 #define DPR_PARAMS(x) (4 * (0xfd5 + (x))) 63 #define DPR_TICK_REG_LO (4 * 0xff5) 64 #define DPR_TICK_REG_HI (4 * 0xff6) 65 #define DPR_DA_BUF_FRONT (4 * 0xff7) 66 #define DPR_DA_BUF_REAR (4 * 0xff8) 67 #define DPR_AD_BUF_FRONT (4 * 0xff9) 68 #define DPR_AD_BUF_REAR (4 * 0xffa) 69 #define DPR_INT_MASK (4 * 0xffb) 70 #define DPR_INTR_FLAG (4 * 0xffc) 71 #define DPR_INTR_CMDONE BIT(7) 72 #define DPR_INTR_CTDONE BIT(6) 73 #define DPR_INTR_DAHWERR BIT(5) 74 #define DPR_INTR_DASWERR BIT(4) 75 #define DPR_INTR_DAEMPTY BIT(3) 76 #define DPR_INTR_ADHWERR BIT(2) 77 #define DPR_INTR_ADSWERR BIT(1) 78 #define DPR_INTR_ADFULL BIT(0) 79 #define DPR_RESPONSE_MBX (4 * 0xffe) 80 #define DPR_CMD_MBX (4 * 0xfff) 81 #define DPR_CMD_COMPLETION(x) ((x) << 8) 82 #define DPR_CMD_NOTPROCESSED DPR_CMD_COMPLETION(0x00) 83 #define DPR_CMD_NOERROR DPR_CMD_COMPLETION(0x55) 84 #define DPR_CMD_ERROR DPR_CMD_COMPLETION(0xaa) 85 #define DPR_CMD_NOTSUPPORTED DPR_CMD_COMPLETION(0xff) 86 #define DPR_CMD_COMPLETION_MASK DPR_CMD_COMPLETION(0xff) 87 #define DPR_CMD(x) ((x) << 0) 88 #define DPR_CMD_GETBRDINFO DPR_CMD(0) 89 #define DPR_CMD_CONFIG DPR_CMD(1) 90 #define DPR_CMD_GETCONFIG DPR_CMD(2) 91 #define DPR_CMD_START DPR_CMD(3) 92 #define DPR_CMD_STOP DPR_CMD(4) 93 #define DPR_CMD_READSINGLE DPR_CMD(5) 94 #define DPR_CMD_WRITESINGLE DPR_CMD(6) 95 #define DPR_CMD_CALCCLOCK DPR_CMD(7) 96 #define DPR_CMD_READEVENTS DPR_CMD(8) 97 #define DPR_CMD_WRITECTCTRL DPR_CMD(16) 98 #define DPR_CMD_READCTCTRL DPR_CMD(17) 99 #define DPR_CMD_WRITECT DPR_CMD(18) 100 #define DPR_CMD_READCT DPR_CMD(19) 101 #define DPR_CMD_WRITEDATA DPR_CMD(32) 102 #define DPR_CMD_READDATA DPR_CMD(33) 103 #define DPR_CMD_WRITEIO DPR_CMD(34) 104 #define DPR_CMD_READIO DPR_CMD(35) 105 #define DPR_CMD_WRITECODE DPR_CMD(36) 106 #define DPR_CMD_READCODE DPR_CMD(37) 107 #define DPR_CMD_EXECUTE DPR_CMD(38) 108 #define DPR_CMD_HALT DPR_CMD(48) 109 #define DPR_CMD_MASK DPR_CMD(0xff) 110 111 #define DPR_PARAM5_AD_TRIG(x) (((x) & 0x7) << 2) 112 #define DPR_PARAM5_AD_TRIG_INT DPR_PARAM5_AD_TRIG(0) 113 #define DPR_PARAM5_AD_TRIG_EXT DPR_PARAM5_AD_TRIG(1) 114 #define DPR_PARAM5_AD_TRIG_INT_RETRIG DPR_PARAM5_AD_TRIG(2) 115 #define DPR_PARAM5_AD_TRIG_EXT_RETRIG DPR_PARAM5_AD_TRIG(3) 116 #define DPR_PARAM5_AD_TRIG_INT_RETRIG2 DPR_PARAM5_AD_TRIG(4) 117 118 #define DPR_PARAM6_AD_DIFF BIT(0) 119 120 #define DPR_AI_FIFO_DEPTH 2003 121 #define DPR_AO_FIFO_DEPTH 2048 122 123 #define DPR_EXTERNAL_CLOCK 1 124 #define DPR_RISING_EDGE 2 125 126 #define DPR_TMODE_MASK 0x1c 127 128 #define DPR_CMD_TIMEOUT 100 129 130 static const struct comedi_lrange range_dt3000_ai = { 131 4, { 132 BIP_RANGE(10), 133 BIP_RANGE(5), 134 BIP_RANGE(2.5), 135 BIP_RANGE(1.25) 136 } 137 }; 138 139 static const struct comedi_lrange range_dt3000_ai_pgl = { 140 4, { 141 BIP_RANGE(10), 142 BIP_RANGE(1), 143 BIP_RANGE(0.1), 144 BIP_RANGE(0.02) 145 } 146 }; 147 148 enum dt3k_boardid { 149 BOARD_DT3001, 150 BOARD_DT3001_PGL, 151 BOARD_DT3002, 152 BOARD_DT3003, 153 BOARD_DT3003_PGL, 154 BOARD_DT3004, 155 BOARD_DT3005, 156 }; 157 158 struct dt3k_boardtype { 159 const char *name; 160 int adchan; 161 int ai_speed; 162 const struct comedi_lrange *adrange; 163 unsigned int ai_is_16bit:1; 164 unsigned int has_ao:1; 165 }; 166 167 static const struct dt3k_boardtype dt3k_boardtypes[] = { 168 [BOARD_DT3001] = { 169 .name = "dt3001", 170 .adchan = 16, 171 .adrange = &range_dt3000_ai, 172 .ai_speed = 3000, 173 .has_ao = 1, 174 }, 175 [BOARD_DT3001_PGL] = { 176 .name = "dt3001-pgl", 177 .adchan = 16, 178 .adrange = &range_dt3000_ai_pgl, 179 .ai_speed = 3000, 180 .has_ao = 1, 181 }, 182 [BOARD_DT3002] = { 183 .name = "dt3002", 184 .adchan = 32, 185 .adrange = &range_dt3000_ai, 186 .ai_speed = 3000, 187 }, 188 [BOARD_DT3003] = { 189 .name = "dt3003", 190 .adchan = 64, 191 .adrange = &range_dt3000_ai, 192 .ai_speed = 3000, 193 .has_ao = 1, 194 }, 195 [BOARD_DT3003_PGL] = { 196 .name = "dt3003-pgl", 197 .adchan = 64, 198 .adrange = &range_dt3000_ai_pgl, 199 .ai_speed = 3000, 200 .has_ao = 1, 201 }, 202 [BOARD_DT3004] = { 203 .name = "dt3004", 204 .adchan = 16, 205 .adrange = &range_dt3000_ai, 206 .ai_speed = 10000, 207 .ai_is_16bit = 1, 208 .has_ao = 1, 209 }, 210 [BOARD_DT3005] = { 211 .name = "dt3005", /* a.k.a. 3004-200 */ 212 .adchan = 16, 213 .adrange = &range_dt3000_ai, 214 .ai_speed = 5000, 215 .ai_is_16bit = 1, 216 .has_ao = 1, 217 }, 218 }; 219 220 struct dt3k_private { 221 unsigned int lock; 222 unsigned int ai_front; 223 unsigned int ai_rear; 224 }; 225 226 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) 227 { 228 int i; 229 unsigned int status = 0; 230 231 writew(cmd, dev->mmio + DPR_CMD_MBX); 232 233 for (i = 0; i < DPR_CMD_TIMEOUT; i++) { 234 status = readw(dev->mmio + DPR_CMD_MBX); 235 status &= DPR_CMD_COMPLETION_MASK; 236 if (status != DPR_CMD_NOTPROCESSED) 237 break; 238 udelay(1); 239 } 240 241 if (status != DPR_CMD_NOERROR) 242 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n", 243 __func__, status); 244 } 245 246 static unsigned int dt3k_readsingle(struct comedi_device *dev, 247 unsigned int subsys, unsigned int chan, 248 unsigned int gain) 249 { 250 writew(subsys, dev->mmio + DPR_SUBSYS); 251 252 writew(chan, dev->mmio + DPR_PARAMS(0)); 253 writew(gain, dev->mmio + DPR_PARAMS(1)); 254 255 dt3k_send_cmd(dev, DPR_CMD_READSINGLE); 256 257 return readw(dev->mmio + DPR_PARAMS(2)); 258 } 259 260 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, 261 unsigned int chan, unsigned int data) 262 { 263 writew(subsys, dev->mmio + DPR_SUBSYS); 264 265 writew(chan, dev->mmio + DPR_PARAMS(0)); 266 writew(0, dev->mmio + DPR_PARAMS(1)); 267 writew(data, dev->mmio + DPR_PARAMS(2)); 268 269 dt3k_send_cmd(dev, DPR_CMD_WRITESINGLE); 270 } 271 272 static void dt3k_ai_empty_fifo(struct comedi_device *dev, 273 struct comedi_subdevice *s) 274 { 275 struct dt3k_private *devpriv = dev->private; 276 int front; 277 int rear; 278 int count; 279 int i; 280 unsigned short data; 281 282 front = readw(dev->mmio + DPR_AD_BUF_FRONT); 283 count = front - devpriv->ai_front; 284 if (count < 0) 285 count += DPR_AI_FIFO_DEPTH; 286 287 rear = devpriv->ai_rear; 288 289 for (i = 0; i < count; i++) { 290 data = readw(dev->mmio + DPR_ADC_BUFFER + rear); 291 comedi_buf_write_samples(s, &data, 1); 292 rear++; 293 if (rear >= DPR_AI_FIFO_DEPTH) 294 rear = 0; 295 } 296 297 devpriv->ai_rear = rear; 298 writew(rear, dev->mmio + DPR_AD_BUF_REAR); 299 } 300 301 static int dt3k_ai_cancel(struct comedi_device *dev, 302 struct comedi_subdevice *s) 303 { 304 writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); 305 dt3k_send_cmd(dev, DPR_CMD_STOP); 306 307 writew(0, dev->mmio + DPR_INT_MASK); 308 309 return 0; 310 } 311 312 static int debug_n_ints; 313 314 /* FIXME! Assumes shared interrupt is for this card. */ 315 /* What's this debug_n_ints stuff? Obviously needs some work... */ 316 static irqreturn_t dt3k_interrupt(int irq, void *d) 317 { 318 struct comedi_device *dev = d; 319 struct comedi_subdevice *s = dev->read_subdev; 320 unsigned int status; 321 322 if (!dev->attached) 323 return IRQ_NONE; 324 325 status = readw(dev->mmio + DPR_INTR_FLAG); 326 327 if (status & DPR_INTR_ADFULL) 328 dt3k_ai_empty_fifo(dev, s); 329 330 if (status & (DPR_INTR_ADSWERR | DPR_INTR_ADHWERR)) 331 s->async->events |= COMEDI_CB_ERROR; 332 333 debug_n_ints++; 334 if (debug_n_ints >= 10) 335 s->async->events |= COMEDI_CB_EOA; 336 337 comedi_handle_events(dev, s); 338 return IRQ_HANDLED; 339 } 340 341 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec, 342 unsigned int flags) 343 { 344 unsigned int divider, base, prescale; 345 346 /* This function needs improvement */ 347 /* Don't know if divider==0 works. */ 348 349 for (prescale = 0; prescale < 16; prescale++) { 350 base = timer_base * (prescale + 1); 351 switch (flags & CMDF_ROUND_MASK) { 352 case CMDF_ROUND_NEAREST: 353 default: 354 divider = DIV_ROUND_CLOSEST(*nanosec, base); 355 break; 356 case CMDF_ROUND_DOWN: 357 divider = (*nanosec) / base; 358 break; 359 case CMDF_ROUND_UP: 360 divider = DIV_ROUND_UP(*nanosec, base); 361 break; 362 } 363 if (divider < 65536) { 364 *nanosec = divider * base; 365 return (prescale << 16) | (divider); 366 } 367 } 368 369 prescale = 15; 370 base = timer_base * (prescale + 1); 371 divider = 65535; 372 *nanosec = divider * base; 373 return (prescale << 16) | (divider); 374 } 375 376 static int dt3k_ai_cmdtest(struct comedi_device *dev, 377 struct comedi_subdevice *s, struct comedi_cmd *cmd) 378 { 379 const struct dt3k_boardtype *board = dev->board_ptr; 380 int err = 0; 381 unsigned int arg; 382 383 /* Step 1 : check if triggers are trivially valid */ 384 385 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); 386 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); 387 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER); 388 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 389 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT); 390 391 if (err) 392 return 1; 393 394 /* Step 2a : make sure trigger sources are unique */ 395 /* Step 2b : and mutually compatible */ 396 397 /* Step 3: check if arguments are trivially valid */ 398 399 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); 400 401 if (cmd->scan_begin_src == TRIG_TIMER) { 402 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 403 board->ai_speed); 404 err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg, 405 100 * 16 * 65535); 406 } 407 408 if (cmd->convert_src == TRIG_TIMER) { 409 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 410 board->ai_speed); 411 err |= comedi_check_trigger_arg_max(&cmd->convert_arg, 412 50 * 16 * 65535); 413 } 414 415 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, 416 cmd->chanlist_len); 417 418 if (cmd->stop_src == TRIG_COUNT) 419 err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); 420 else /* TRIG_NONE */ 421 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); 422 423 if (err) 424 return 3; 425 426 /* step 4: fix up any arguments */ 427 428 if (cmd->scan_begin_src == TRIG_TIMER) { 429 arg = cmd->scan_begin_arg; 430 dt3k_ns_to_timer(100, &arg, cmd->flags); 431 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); 432 } 433 434 if (cmd->convert_src == TRIG_TIMER) { 435 arg = cmd->convert_arg; 436 dt3k_ns_to_timer(50, &arg, cmd->flags); 437 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); 438 439 if (cmd->scan_begin_src == TRIG_TIMER) { 440 arg = cmd->convert_arg * cmd->scan_end_arg; 441 err |= comedi_check_trigger_arg_min( 442 &cmd->scan_begin_arg, arg); 443 } 444 } 445 446 if (err) 447 return 4; 448 449 return 0; 450 } 451 452 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 453 { 454 struct comedi_cmd *cmd = &s->async->cmd; 455 int i; 456 unsigned int chan, range, aref; 457 unsigned int divider; 458 unsigned int tscandiv; 459 460 for (i = 0; i < cmd->chanlist_len; i++) { 461 chan = CR_CHAN(cmd->chanlist[i]); 462 range = CR_RANGE(cmd->chanlist[i]); 463 464 writew((range << 6) | chan, dev->mmio + DPR_ADC_BUFFER + i); 465 } 466 aref = CR_AREF(cmd->chanlist[0]); 467 468 writew(cmd->scan_end_arg, dev->mmio + DPR_PARAMS(0)); 469 470 if (cmd->convert_src == TRIG_TIMER) { 471 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags); 472 writew((divider >> 16), dev->mmio + DPR_PARAMS(1)); 473 writew((divider & 0xffff), dev->mmio + DPR_PARAMS(2)); 474 } 475 476 if (cmd->scan_begin_src == TRIG_TIMER) { 477 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg, 478 cmd->flags); 479 writew((tscandiv >> 16), dev->mmio + DPR_PARAMS(3)); 480 writew((tscandiv & 0xffff), dev->mmio + DPR_PARAMS(4)); 481 } 482 483 writew(DPR_PARAM5_AD_TRIG_INT_RETRIG, dev->mmio + DPR_PARAMS(5)); 484 writew((aref == AREF_DIFF) ? DPR_PARAM6_AD_DIFF : 0, 485 dev->mmio + DPR_PARAMS(6)); 486 487 writew(DPR_AI_FIFO_DEPTH / 2, dev->mmio + DPR_PARAMS(7)); 488 489 writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); 490 dt3k_send_cmd(dev, DPR_CMD_CONFIG); 491 492 writew(DPR_INTR_ADFULL | DPR_INTR_ADSWERR | DPR_INTR_ADHWERR, 493 dev->mmio + DPR_INT_MASK); 494 495 debug_n_ints = 0; 496 497 writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); 498 dt3k_send_cmd(dev, DPR_CMD_START); 499 500 return 0; 501 } 502 503 static int dt3k_ai_insn_read(struct comedi_device *dev, 504 struct comedi_subdevice *s, 505 struct comedi_insn *insn, 506 unsigned int *data) 507 { 508 int i; 509 unsigned int chan, gain; 510 511 chan = CR_CHAN(insn->chanspec); 512 gain = CR_RANGE(insn->chanspec); 513 /* XXX docs don't explain how to select aref */ 514 515 for (i = 0; i < insn->n; i++) 516 data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain); 517 518 return i; 519 } 520 521 static int dt3k_ao_insn_write(struct comedi_device *dev, 522 struct comedi_subdevice *s, 523 struct comedi_insn *insn, 524 unsigned int *data) 525 { 526 unsigned int chan = CR_CHAN(insn->chanspec); 527 unsigned int val = s->readback[chan]; 528 int i; 529 530 for (i = 0; i < insn->n; i++) { 531 val = data[i]; 532 dt3k_writesingle(dev, DPR_SUBSYS_AO, chan, val); 533 } 534 s->readback[chan] = val; 535 536 return insn->n; 537 } 538 539 static void dt3k_dio_config(struct comedi_device *dev, int bits) 540 { 541 /* XXX */ 542 writew(DPR_SUBSYS_DOUT, dev->mmio + DPR_SUBSYS); 543 544 writew(bits, dev->mmio + DPR_PARAMS(0)); 545 546 /* XXX write 0 to DPR_PARAMS(1) and DPR_PARAMS(2) ? */ 547 548 dt3k_send_cmd(dev, DPR_CMD_CONFIG); 549 } 550 551 static int dt3k_dio_insn_config(struct comedi_device *dev, 552 struct comedi_subdevice *s, 553 struct comedi_insn *insn, 554 unsigned int *data) 555 { 556 unsigned int chan = CR_CHAN(insn->chanspec); 557 unsigned int mask; 558 int ret; 559 560 if (chan < 4) 561 mask = 0x0f; 562 else 563 mask = 0xf0; 564 565 ret = comedi_dio_insn_config(dev, s, insn, data, mask); 566 if (ret) 567 return ret; 568 569 dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3)); 570 571 return insn->n; 572 } 573 574 static int dt3k_dio_insn_bits(struct comedi_device *dev, 575 struct comedi_subdevice *s, 576 struct comedi_insn *insn, 577 unsigned int *data) 578 { 579 if (comedi_dio_update_state(s, data)) 580 dt3k_writesingle(dev, DPR_SUBSYS_DOUT, 0, s->state); 581 582 data[1] = dt3k_readsingle(dev, DPR_SUBSYS_DIN, 0, 0); 583 584 return insn->n; 585 } 586 587 static int dt3k_mem_insn_read(struct comedi_device *dev, 588 struct comedi_subdevice *s, 589 struct comedi_insn *insn, 590 unsigned int *data) 591 { 592 unsigned int addr = CR_CHAN(insn->chanspec); 593 int i; 594 595 for (i = 0; i < insn->n; i++) { 596 writew(DPR_SUBSYS_MEM, dev->mmio + DPR_SUBSYS); 597 writew(addr, dev->mmio + DPR_PARAMS(0)); 598 writew(1, dev->mmio + DPR_PARAMS(1)); 599 600 dt3k_send_cmd(dev, DPR_CMD_READCODE); 601 602 data[i] = readw(dev->mmio + DPR_PARAMS(2)); 603 } 604 605 return i; 606 } 607 608 static int dt3000_auto_attach(struct comedi_device *dev, 609 unsigned long context) 610 { 611 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 612 const struct dt3k_boardtype *board = NULL; 613 struct dt3k_private *devpriv; 614 struct comedi_subdevice *s; 615 int ret = 0; 616 617 if (context < ARRAY_SIZE(dt3k_boardtypes)) 618 board = &dt3k_boardtypes[context]; 619 if (!board) 620 return -ENODEV; 621 dev->board_ptr = board; 622 dev->board_name = board->name; 623 624 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); 625 if (!devpriv) 626 return -ENOMEM; 627 628 ret = comedi_pci_enable(dev); 629 if (ret < 0) 630 return ret; 631 632 dev->mmio = pci_ioremap_bar(pcidev, 0); 633 if (!dev->mmio) 634 return -ENOMEM; 635 636 if (pcidev->irq) { 637 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED, 638 dev->board_name, dev); 639 if (ret == 0) 640 dev->irq = pcidev->irq; 641 } 642 643 ret = comedi_alloc_subdevices(dev, 4); 644 if (ret) 645 return ret; 646 647 /* Analog Input subdevice */ 648 s = &dev->subdevices[0]; 649 s->type = COMEDI_SUBD_AI; 650 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; 651 s->n_chan = board->adchan; 652 s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff; 653 s->range_table = &range_dt3000_ai; /* XXX */ 654 s->insn_read = dt3k_ai_insn_read; 655 if (dev->irq) { 656 dev->read_subdev = s; 657 s->subdev_flags |= SDF_CMD_READ; 658 s->len_chanlist = 512; 659 s->do_cmd = dt3k_ai_cmd; 660 s->do_cmdtest = dt3k_ai_cmdtest; 661 s->cancel = dt3k_ai_cancel; 662 } 663 664 /* Analog Output subdevice */ 665 s = &dev->subdevices[1]; 666 if (board->has_ao) { 667 s->type = COMEDI_SUBD_AO; 668 s->subdev_flags = SDF_WRITABLE; 669 s->n_chan = 2; 670 s->maxdata = 0x0fff; 671 s->range_table = &range_bipolar10; 672 s->insn_write = dt3k_ao_insn_write; 673 674 ret = comedi_alloc_subdev_readback(s); 675 if (ret) 676 return ret; 677 678 } else { 679 s->type = COMEDI_SUBD_UNUSED; 680 } 681 682 /* Digital I/O subdevice */ 683 s = &dev->subdevices[2]; 684 s->type = COMEDI_SUBD_DIO; 685 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 686 s->n_chan = 8; 687 s->maxdata = 1; 688 s->range_table = &range_digital; 689 s->insn_config = dt3k_dio_insn_config; 690 s->insn_bits = dt3k_dio_insn_bits; 691 692 /* Memory subdevice */ 693 s = &dev->subdevices[3]; 694 s->type = COMEDI_SUBD_MEMORY; 695 s->subdev_flags = SDF_READABLE; 696 s->n_chan = 0x1000; 697 s->maxdata = 0xff; 698 s->range_table = &range_unknown; 699 s->insn_read = dt3k_mem_insn_read; 700 701 return 0; 702 } 703 704 static struct comedi_driver dt3000_driver = { 705 .driver_name = "dt3000", 706 .module = THIS_MODULE, 707 .auto_attach = dt3000_auto_attach, 708 .detach = comedi_pci_detach, 709 }; 710 711 static int dt3000_pci_probe(struct pci_dev *dev, 712 const struct pci_device_id *id) 713 { 714 return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data); 715 } 716 717 static const struct pci_device_id dt3000_pci_table[] = { 718 { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 }, 719 { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 }, 720 { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 }, 721 { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 }, 722 { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 }, 723 { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL }, 724 { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL }, 725 { 0 } 726 }; 727 MODULE_DEVICE_TABLE(pci, dt3000_pci_table); 728 729 static struct pci_driver dt3000_pci_driver = { 730 .name = "dt3000", 731 .id_table = dt3000_pci_table, 732 .probe = dt3000_pci_probe, 733 .remove = comedi_pci_auto_unconfig, 734 }; 735 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver); 736 737 MODULE_AUTHOR("Comedi https://www.comedi.org"); 738 MODULE_DESCRIPTION("Comedi driver for Data Translation DT3000 series boards"); 739 MODULE_LICENSE("GPL"); 740