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