addi_apci_3xxx.c revision 1867add98e44d4bec01572b4cfd4becd11297e5d
1#include <linux/pci.h> 2#include <linux/interrupt.h> 3#include <linux/sched.h> 4 5#include "../comedidev.h" 6#include "comedi_fc.h" 7#include "amcc_s5933.h" 8 9#ifndef COMEDI_SUBD_TTLIO 10#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ 11#endif 12 13static const struct comedi_lrange apci3xxx_ai_range = { 14 8, { 15 BIP_RANGE(10), 16 BIP_RANGE(5), 17 BIP_RANGE(2), 18 BIP_RANGE(1), 19 UNI_RANGE(10), 20 UNI_RANGE(5), 21 UNI_RANGE(2), 22 UNI_RANGE(1) 23 } 24}; 25 26static const struct comedi_lrange apci3xxx_ao_range = { 27 2, { 28 BIP_RANGE(10), 29 UNI_RANGE(10) 30 } 31}; 32 33enum apci3xxx_boardid { 34 BOARD_APCI3000_16, 35 BOARD_APCI3000_8, 36 BOARD_APCI3000_4, 37 BOARD_APCI3006_16, 38 BOARD_APCI3006_8, 39 BOARD_APCI3006_4, 40 BOARD_APCI3010_16, 41 BOARD_APCI3010_8, 42 BOARD_APCI3010_4, 43 BOARD_APCI3016_16, 44 BOARD_APCI3016_8, 45 BOARD_APCI3016_4, 46 BOARD_APCI3100_16_4, 47 BOARD_APCI3100_8_4, 48 BOARD_APCI3106_16_4, 49 BOARD_APCI3106_8_4, 50 BOARD_APCI3110_16_4, 51 BOARD_APCI3110_8_4, 52 BOARD_APCI3116_16_4, 53 BOARD_APCI3116_8_4, 54 BOARD_APCI3003, 55 BOARD_APCI3002_16, 56 BOARD_APCI3002_8, 57 BOARD_APCI3002_4, 58 BOARD_APCI3500, 59}; 60 61struct apci3xxx_boardinfo { 62 const char *pc_DriverName; 63 int i_IorangeBase1; 64 int i_NbrAiChannel; 65 int i_NbrAiChannelDiff; 66 int i_AiChannelList; 67 int i_NbrAoChannel; 68 int i_AiMaxdata; 69 int i_AoMaxdata; 70 int i_NbrDiChannel; 71 int i_NbrDoChannel; 72 int i_NbrTTLChannel; 73 unsigned char b_AvailableConvertUnit; 74 unsigned int ui_MinAcquisitiontimeNs; 75}; 76 77static const struct apci3xxx_boardinfo apci3xxx_boardtypes[] = { 78 [BOARD_APCI3000_16] = { 79 .pc_DriverName = "apci3000-16", 80 .i_IorangeBase1 = 256, 81 .i_NbrAiChannel = 16, 82 .i_NbrAiChannelDiff = 8, 83 .i_AiChannelList = 16, 84 .i_AiMaxdata = 4095, 85 .i_NbrTTLChannel = 24, 86 .b_AvailableConvertUnit = 6, 87 .ui_MinAcquisitiontimeNs = 10000, 88 }, 89 [BOARD_APCI3000_8] = { 90 .pc_DriverName = "apci3000-8", 91 .i_IorangeBase1 = 256, 92 .i_NbrAiChannel = 8, 93 .i_NbrAiChannelDiff = 4, 94 .i_AiChannelList = 8, 95 .i_AiMaxdata = 4095, 96 .i_NbrTTLChannel = 24, 97 .b_AvailableConvertUnit = 6, 98 .ui_MinAcquisitiontimeNs = 10000, 99 }, 100 [BOARD_APCI3000_4] = { 101 .pc_DriverName = "apci3000-4", 102 .i_IorangeBase1 = 256, 103 .i_NbrAiChannel = 4, 104 .i_NbrAiChannelDiff = 2, 105 .i_AiChannelList = 4, 106 .i_AiMaxdata = 4095, 107 .i_NbrTTLChannel = 24, 108 .b_AvailableConvertUnit = 6, 109 .ui_MinAcquisitiontimeNs = 10000, 110 }, 111 [BOARD_APCI3006_16] = { 112 .pc_DriverName = "apci3006-16", 113 .i_IorangeBase1 = 256, 114 .i_NbrAiChannel = 16, 115 .i_NbrAiChannelDiff = 8, 116 .i_AiChannelList = 16, 117 .i_AiMaxdata = 65535, 118 .i_NbrTTLChannel = 24, 119 .b_AvailableConvertUnit = 6, 120 .ui_MinAcquisitiontimeNs = 10000, 121 }, 122 [BOARD_APCI3006_8] = { 123 .pc_DriverName = "apci3006-8", 124 .i_IorangeBase1 = 256, 125 .i_NbrAiChannel = 8, 126 .i_NbrAiChannelDiff = 4, 127 .i_AiChannelList = 8, 128 .i_AiMaxdata = 65535, 129 .i_NbrTTLChannel = 24, 130 .b_AvailableConvertUnit = 6, 131 .ui_MinAcquisitiontimeNs = 10000, 132 }, 133 [BOARD_APCI3006_4] = { 134 .pc_DriverName = "apci3006-4", 135 .i_IorangeBase1 = 256, 136 .i_NbrAiChannel = 4, 137 .i_NbrAiChannelDiff = 2, 138 .i_AiChannelList = 4, 139 .i_AiMaxdata = 65535, 140 .i_NbrTTLChannel = 24, 141 .b_AvailableConvertUnit = 6, 142 .ui_MinAcquisitiontimeNs = 10000, 143 }, 144 [BOARD_APCI3010_16] = { 145 .pc_DriverName = "apci3010-16", 146 .i_IorangeBase1 = 256, 147 .i_NbrAiChannel = 16, 148 .i_NbrAiChannelDiff = 8, 149 .i_AiChannelList = 16, 150 .i_AiMaxdata = 4095, 151 .i_NbrDiChannel = 4, 152 .i_NbrDoChannel = 4, 153 .i_NbrTTLChannel = 24, 154 .b_AvailableConvertUnit = 6, 155 .ui_MinAcquisitiontimeNs = 5000, 156 }, 157 [BOARD_APCI3010_8] = { 158 .pc_DriverName = "apci3010-8", 159 .i_IorangeBase1 = 256, 160 .i_NbrAiChannel = 8, 161 .i_NbrAiChannelDiff = 4, 162 .i_AiChannelList = 8, 163 .i_AiMaxdata = 4095, 164 .i_NbrDiChannel = 4, 165 .i_NbrDoChannel = 4, 166 .i_NbrTTLChannel = 24, 167 .b_AvailableConvertUnit = 6, 168 .ui_MinAcquisitiontimeNs = 5000, 169 }, 170 [BOARD_APCI3010_4] = { 171 .pc_DriverName = "apci3010-4", 172 .i_IorangeBase1 = 256, 173 .i_NbrAiChannel = 4, 174 .i_NbrAiChannelDiff = 2, 175 .i_AiChannelList = 4, 176 .i_AiMaxdata = 4095, 177 .i_NbrDiChannel = 4, 178 .i_NbrDoChannel = 4, 179 .i_NbrTTLChannel = 24, 180 .b_AvailableConvertUnit = 6, 181 .ui_MinAcquisitiontimeNs = 5000, 182 }, 183 [BOARD_APCI3016_16] = { 184 .pc_DriverName = "apci3016-16", 185 .i_IorangeBase1 = 256, 186 .i_NbrAiChannel = 16, 187 .i_NbrAiChannelDiff = 8, 188 .i_AiChannelList = 16, 189 .i_AiMaxdata = 65535, 190 .i_NbrDiChannel = 4, 191 .i_NbrDoChannel = 4, 192 .i_NbrTTLChannel = 24, 193 .b_AvailableConvertUnit = 6, 194 .ui_MinAcquisitiontimeNs = 5000, 195 }, 196 [BOARD_APCI3016_8] = { 197 .pc_DriverName = "apci3016-8", 198 .i_IorangeBase1 = 256, 199 .i_NbrAiChannel = 8, 200 .i_NbrAiChannelDiff = 4, 201 .i_AiChannelList = 8, 202 .i_AiMaxdata = 65535, 203 .i_NbrDiChannel = 4, 204 .i_NbrDoChannel = 4, 205 .i_NbrTTLChannel = 24, 206 .b_AvailableConvertUnit = 6, 207 .ui_MinAcquisitiontimeNs = 5000, 208 }, 209 [BOARD_APCI3016_4] = { 210 .pc_DriverName = "apci3016-4", 211 .i_IorangeBase1 = 256, 212 .i_NbrAiChannel = 4, 213 .i_NbrAiChannelDiff = 2, 214 .i_AiChannelList = 4, 215 .i_AiMaxdata = 65535, 216 .i_NbrDiChannel = 4, 217 .i_NbrDoChannel = 4, 218 .i_NbrTTLChannel = 24, 219 .b_AvailableConvertUnit = 6, 220 .ui_MinAcquisitiontimeNs = 5000, 221 }, 222 [BOARD_APCI3100_16_4] = { 223 .pc_DriverName = "apci3100-16-4", 224 .i_IorangeBase1 = 256, 225 .i_NbrAiChannel = 16, 226 .i_NbrAiChannelDiff = 8, 227 .i_AiChannelList = 16, 228 .i_NbrAoChannel = 4, 229 .i_AiMaxdata = 4095, 230 .i_AoMaxdata = 4095, 231 .i_NbrTTLChannel = 24, 232 .b_AvailableConvertUnit = 6, 233 .ui_MinAcquisitiontimeNs = 10000, 234 }, 235 [BOARD_APCI3100_8_4] = { 236 .pc_DriverName = "apci3100-8-4", 237 .i_IorangeBase1 = 256, 238 .i_NbrAiChannel = 8, 239 .i_NbrAiChannelDiff = 4, 240 .i_AiChannelList = 8, 241 .i_NbrAoChannel = 4, 242 .i_AiMaxdata = 4095, 243 .i_AoMaxdata = 4095, 244 .i_NbrTTLChannel = 24, 245 .b_AvailableConvertUnit = 6, 246 .ui_MinAcquisitiontimeNs = 10000, 247 }, 248 [BOARD_APCI3106_16_4] = { 249 .pc_DriverName = "apci3106-16-4", 250 .i_IorangeBase1 = 256, 251 .i_NbrAiChannel = 16, 252 .i_NbrAiChannelDiff = 8, 253 .i_AiChannelList = 16, 254 .i_NbrAoChannel = 4, 255 .i_AiMaxdata = 65535, 256 .i_AoMaxdata = 4095, 257 .i_NbrTTLChannel = 24, 258 .b_AvailableConvertUnit = 6, 259 .ui_MinAcquisitiontimeNs = 10000, 260 }, 261 [BOARD_APCI3106_8_4] = { 262 .pc_DriverName = "apci3106-8-4", 263 .i_IorangeBase1 = 256, 264 .i_NbrAiChannel = 8, 265 .i_NbrAiChannelDiff = 4, 266 .i_AiChannelList = 8, 267 .i_NbrAoChannel = 4, 268 .i_AiMaxdata = 65535, 269 .i_AoMaxdata = 4095, 270 .i_NbrTTLChannel = 24, 271 .b_AvailableConvertUnit = 6, 272 .ui_MinAcquisitiontimeNs = 10000, 273 }, 274 [BOARD_APCI3110_16_4] = { 275 .pc_DriverName = "apci3110-16-4", 276 .i_IorangeBase1 = 256, 277 .i_NbrAiChannel = 16, 278 .i_NbrAiChannelDiff = 8, 279 .i_AiChannelList = 16, 280 .i_NbrAoChannel = 4, 281 .i_AiMaxdata = 4095, 282 .i_AoMaxdata = 4095, 283 .i_NbrDiChannel = 4, 284 .i_NbrDoChannel = 4, 285 .i_NbrTTLChannel = 24, 286 .b_AvailableConvertUnit = 6, 287 .ui_MinAcquisitiontimeNs = 5000, 288 }, 289 [BOARD_APCI3110_8_4] = { 290 .pc_DriverName = "apci3110-8-4", 291 .i_IorangeBase1 = 256, 292 .i_NbrAiChannel = 8, 293 .i_NbrAiChannelDiff = 4, 294 .i_AiChannelList = 8, 295 .i_NbrAoChannel = 4, 296 .i_AiMaxdata = 4095, 297 .i_AoMaxdata = 4095, 298 .i_NbrDiChannel = 4, 299 .i_NbrDoChannel = 4, 300 .i_NbrTTLChannel = 24, 301 .b_AvailableConvertUnit = 6, 302 .ui_MinAcquisitiontimeNs = 5000, 303 }, 304 [BOARD_APCI3116_16_4] = { 305 .pc_DriverName = "apci3116-16-4", 306 .i_IorangeBase1 = 256, 307 .i_NbrAiChannel = 16, 308 .i_NbrAiChannelDiff = 8, 309 .i_AiChannelList = 16, 310 .i_NbrAoChannel = 4, 311 .i_AiMaxdata = 65535, 312 .i_AoMaxdata = 4095, 313 .i_NbrDiChannel = 4, 314 .i_NbrDoChannel = 4, 315 .i_NbrTTLChannel = 24, 316 .b_AvailableConvertUnit = 6, 317 .ui_MinAcquisitiontimeNs = 5000, 318 }, 319 [BOARD_APCI3116_8_4] = { 320 .pc_DriverName = "apci3116-8-4", 321 .i_IorangeBase1 = 256, 322 .i_NbrAiChannel = 8, 323 .i_NbrAiChannelDiff = 4, 324 .i_AiChannelList = 8, 325 .i_NbrAoChannel = 4, 326 .i_AiMaxdata = 65535, 327 .i_AoMaxdata = 4095, 328 .i_NbrDiChannel = 4, 329 .i_NbrDoChannel = 4, 330 .i_NbrTTLChannel = 24, 331 .b_AvailableConvertUnit = 6, 332 .ui_MinAcquisitiontimeNs = 5000, 333 }, 334 [BOARD_APCI3003] = { 335 .pc_DriverName = "apci3003", 336 .i_IorangeBase1 = 256, 337 .i_NbrAiChannelDiff = 4, 338 .i_AiChannelList = 4, 339 .i_AiMaxdata = 65535, 340 .i_NbrDiChannel = 4, 341 .i_NbrDoChannel = 4, 342 .b_AvailableConvertUnit = 7, 343 .ui_MinAcquisitiontimeNs = 2500, 344 }, 345 [BOARD_APCI3002_16] = { 346 .pc_DriverName = "apci3002-16", 347 .i_IorangeBase1 = 256, 348 .i_NbrAiChannelDiff = 16, 349 .i_AiChannelList = 16, 350 .i_AiMaxdata = 65535, 351 .i_NbrDiChannel = 4, 352 .i_NbrDoChannel = 4, 353 .b_AvailableConvertUnit = 6, 354 .ui_MinAcquisitiontimeNs = 5000, 355 }, 356 [BOARD_APCI3002_8] = { 357 .pc_DriverName = "apci3002-8", 358 .i_IorangeBase1 = 256, 359 .i_NbrAiChannelDiff = 8, 360 .i_AiChannelList = 8, 361 .i_AiMaxdata = 65535, 362 .i_NbrDiChannel = 4, 363 .i_NbrDoChannel = 4, 364 .b_AvailableConvertUnit = 6, 365 .ui_MinAcquisitiontimeNs = 5000, 366 }, 367 [BOARD_APCI3002_4] = { 368 .pc_DriverName = "apci3002-4", 369 .i_IorangeBase1 = 256, 370 .i_NbrAiChannelDiff = 4, 371 .i_AiChannelList = 4, 372 .i_AiMaxdata = 65535, 373 .i_NbrDiChannel = 4, 374 .i_NbrDoChannel = 4, 375 .b_AvailableConvertUnit = 6, 376 .ui_MinAcquisitiontimeNs = 5000, 377 }, 378 [BOARD_APCI3500] = { 379 .pc_DriverName = "apci3500", 380 .i_IorangeBase1 = 256, 381 .i_NbrAoChannel = 4, 382 .i_AoMaxdata = 4095, 383 .i_NbrTTLChannel = 24, 384 }, 385}; 386 387struct apci3xxx_private { 388 int iobase; 389 int i_IobaseReserved; 390 void __iomem *dw_AiBase; 391 unsigned char b_AiInitialisation; 392 unsigned int ui_AiNbrofChannels; /* how many channels is measured */ 393 unsigned int ui_AiReadData[32]; 394 unsigned char b_EocEosInterrupt; 395 unsigned int ui_EocEosConversionTime; 396 unsigned char b_EocEosConversionTimeBase; 397 unsigned char b_SingelDiff; 398 struct task_struct *tsk_Current; 399 unsigned int ul_TTLPortConfiguration[10]; 400}; 401 402#include "addi-data/hwdrv_apci3xxx.c" 403 404static irqreturn_t apci3xxx_irq_handler(int irq, void *d) 405{ 406 struct comedi_device *dev = d; 407 struct apci3xxx_private *devpriv = dev->private; 408 unsigned int status; 409 int i; 410 411 /* Test if interrupt occur */ 412 status = readl(devpriv->dw_AiBase + 16); 413 if ((status & 0x2) == 0x2) { 414 /* Reset the interrupt */ 415 writel(status, devpriv->dw_AiBase + 16); 416 417 /* Test if interrupt enabled */ 418 if (devpriv->b_EocEosInterrupt == 1) { 419 /* Read all analog inputs value */ 420 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) { 421 unsigned int val; 422 423 val = readl(devpriv->dw_AiBase + 28); 424 devpriv->ui_AiReadData[i] = val; 425 } 426 427 /* Set the interrupt flag */ 428 devpriv->b_EocEosInterrupt = 2; 429 430 /* Send a signal to from kernel to user space */ 431 send_sig(SIGIO, devpriv->tsk_Current, 0); 432 } 433 } 434 return IRQ_RETVAL(1); 435} 436 437static int apci3xxx_di_insn_bits(struct comedi_device *dev, 438 struct comedi_subdevice *s, 439 struct comedi_insn *insn, 440 unsigned int *data) 441{ 442 struct apci3xxx_private *devpriv = dev->private; 443 444 data[1] = inl(devpriv->iobase + 32) & 0xf; 445 446 return insn->n; 447} 448 449static int apci3xxx_do_insn_bits(struct comedi_device *dev, 450 struct comedi_subdevice *s, 451 struct comedi_insn *insn, 452 unsigned int *data) 453{ 454 struct apci3xxx_private *devpriv = dev->private; 455 unsigned int mask = data[0]; 456 unsigned int bits = data[1]; 457 458 s->state = inl(devpriv->iobase + 48) & 0xf; 459 if (mask) { 460 s->state &= ~mask; 461 s->state |= (bits & mask); 462 463 outl(s->state, devpriv->iobase + 48); 464 } 465 466 data[1] = s->state; 467 468 return insn->n; 469} 470 471static int apci3xxx_reset(struct comedi_device *dev) 472{ 473 struct apci3xxx_private *devpriv = dev->private; 474 unsigned int val; 475 int i; 476 477 /* Disable the interrupt */ 478 disable_irq(dev->irq); 479 480 /* Reset the interrupt flag */ 481 devpriv->b_EocEosInterrupt = 0; 482 483 /* Clear the start command */ 484 writel(0, devpriv->dw_AiBase + 8); 485 486 /* Reset the interrupt flags */ 487 val = readl(devpriv->dw_AiBase + 16); 488 writel(val, devpriv->dw_AiBase + 16); 489 490 /* clear the EOS */ 491 readl(devpriv->dw_AiBase + 20); 492 493 /* Clear the FIFO */ 494 for (i = 0; i < 16; i++) 495 val = readl(devpriv->dw_AiBase + 28); 496 497 /* Enable the interrupt */ 498 enable_irq(dev->irq); 499 500 return 0; 501} 502 503static int apci3xxx_auto_attach(struct comedi_device *dev, 504 unsigned long context) 505{ 506 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 507 const struct apci3xxx_boardinfo *board = NULL; 508 struct apci3xxx_private *devpriv; 509 struct comedi_subdevice *s; 510 int ret, n_subdevices; 511 512 if (context < ARRAY_SIZE(apci3xxx_boardtypes)) 513 board = &apci3xxx_boardtypes[context]; 514 if (!board) 515 return -ENODEV; 516 dev->board_ptr = board; 517 dev->board_name = board->pc_DriverName; 518 519 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); 520 if (!devpriv) 521 return -ENOMEM; 522 dev->private = devpriv; 523 524 ret = comedi_pci_enable(dev); 525 if (ret) 526 return ret; 527 528 /* board has an ADDIDATA_9054 eeprom */ 529 dev->iobase = pci_resource_start(pcidev, 2); 530 devpriv->iobase = pci_resource_start(pcidev, 2); 531 devpriv->dw_AiBase = pci_ioremap_bar(pcidev, 3); 532 devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); 533 534 if (pcidev->irq > 0) { 535 ret = request_irq(pcidev->irq, apci3xxx_irq_handler, 536 IRQF_SHARED, dev->board_name, dev); 537 if (ret == 0) 538 dev->irq = pcidev->irq; 539 } 540 541 n_subdevices = 7; 542 ret = comedi_alloc_subdevices(dev, n_subdevices); 543 if (ret) 544 return ret; 545 546 /* Allocate and Initialise AI Subdevice Structures */ 547 s = &dev->subdevices[0]; 548 if (board->i_NbrAiChannel || board->i_NbrAiChannelDiff) { 549 dev->read_subdev = s; 550 s->type = COMEDI_SUBD_AI; 551 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | 552 SDF_DIFF; 553 if (board->i_NbrAiChannel) { 554 s->n_chan = board->i_NbrAiChannel; 555 devpriv->b_SingelDiff = 0; 556 } else { 557 s->n_chan = board->i_NbrAiChannelDiff; 558 devpriv->b_SingelDiff = 1; 559 } 560 s->maxdata = board->i_AiMaxdata; 561 s->len_chanlist = board->i_AiChannelList; 562 s->range_table = &apci3xxx_ai_range; 563 564 /* Set the initialisation flag */ 565 devpriv->b_AiInitialisation = 1; 566 567 s->insn_config = i_APCI3XXX_InsnConfigAnalogInput; 568 s->insn_read = i_APCI3XXX_InsnReadAnalogInput; 569 570 } else { 571 s->type = COMEDI_SUBD_UNUSED; 572 } 573 574 /* Allocate and Initialise AO Subdevice Structures */ 575 s = &dev->subdevices[1]; 576 if (board->i_NbrAoChannel) { 577 s->type = COMEDI_SUBD_AO; 578 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; 579 s->n_chan = board->i_NbrAoChannel; 580 s->maxdata = board->i_AoMaxdata; 581 s->range_table = &apci3xxx_ao_range; 582 s->insn_write = i_APCI3XXX_InsnWriteAnalogOutput; 583 } else { 584 s->type = COMEDI_SUBD_UNUSED; 585 } 586 /* Allocate and Initialise DI Subdevice Structures */ 587 s = &dev->subdevices[2]; 588 if (board->i_NbrDiChannel) { 589 s->type = COMEDI_SUBD_DI; 590 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; 591 s->n_chan = board->i_NbrDiChannel; 592 s->maxdata = 1; 593 s->range_table = &range_digital; 594 s->io_bits = 0; /* all bits input */ 595 s->insn_bits = apci3xxx_di_insn_bits; 596 } else { 597 s->type = COMEDI_SUBD_UNUSED; 598 } 599 /* Allocate and Initialise DO Subdevice Structures */ 600 s = &dev->subdevices[3]; 601 if (board->i_NbrDoChannel) { 602 s->type = COMEDI_SUBD_DO; 603 s->subdev_flags = 604 SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; 605 s->n_chan = board->i_NbrDoChannel; 606 s->maxdata = 1; 607 s->range_table = &range_digital; 608 s->io_bits = 0xf; /* all bits output */ 609 s->insn_bits = apci3xxx_do_insn_bits; 610 } else { 611 s->type = COMEDI_SUBD_UNUSED; 612 } 613 614 /* Allocate and Initialise Timer Subdevice Structures */ 615 s = &dev->subdevices[4]; 616 s->type = COMEDI_SUBD_UNUSED; 617 618 /* Allocate and Initialise TTL */ 619 s = &dev->subdevices[5]; 620 if (board->i_NbrTTLChannel) { 621 s->type = COMEDI_SUBD_TTLIO; 622 s->subdev_flags = 623 SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; 624 s->n_chan = board->i_NbrTTLChannel; 625 s->maxdata = 1; 626 s->io_bits = 0; /* all bits input */ 627 s->len_chanlist = board->i_NbrTTLChannel; 628 s->range_table = &range_digital; 629 s->insn_config = i_APCI3XXX_InsnConfigInitTTLIO; 630 s->insn_bits = i_APCI3XXX_InsnBitsTTLIO; 631 s->insn_read = i_APCI3XXX_InsnReadTTLIO; 632 s->insn_write = i_APCI3XXX_InsnWriteTTLIO; 633 } else { 634 s->type = COMEDI_SUBD_UNUSED; 635 } 636 637 /* EEPROM */ 638 s = &dev->subdevices[6]; 639 s->type = COMEDI_SUBD_UNUSED; 640 641 apci3xxx_reset(dev); 642 return 0; 643} 644 645static void apci3xxx_detach(struct comedi_device *dev) 646{ 647 struct apci3xxx_private *devpriv = dev->private; 648 649 if (devpriv) { 650 if (dev->iobase) 651 apci3xxx_reset(dev); 652 if (dev->irq) 653 free_irq(dev->irq, dev); 654 if (devpriv->dw_AiBase) 655 iounmap(devpriv->dw_AiBase); 656 } 657 comedi_pci_disable(dev); 658} 659 660static struct comedi_driver apci3xxx_driver = { 661 .driver_name = "addi_apci_3xxx", 662 .module = THIS_MODULE, 663 .auto_attach = apci3xxx_auto_attach, 664 .detach = apci3xxx_detach, 665}; 666 667static int apci3xxx_pci_probe(struct pci_dev *dev, 668 const struct pci_device_id *id) 669{ 670 return comedi_pci_auto_config(dev, &apci3xxx_driver, id->driver_data); 671} 672 673static DEFINE_PCI_DEVICE_TABLE(apci3xxx_pci_table) = { 674 { PCI_VDEVICE(ADDIDATA, 0x3010), BOARD_APCI3000_16 }, 675 { PCI_VDEVICE(ADDIDATA, 0x300f), BOARD_APCI3000_8 }, 676 { PCI_VDEVICE(ADDIDATA, 0x300e), BOARD_APCI3000_4 }, 677 { PCI_VDEVICE(ADDIDATA, 0x3013), BOARD_APCI3006_16 }, 678 { PCI_VDEVICE(ADDIDATA, 0x3014), BOARD_APCI3006_8 }, 679 { PCI_VDEVICE(ADDIDATA, 0x3015), BOARD_APCI3006_4 }, 680 { PCI_VDEVICE(ADDIDATA, 0x3016), BOARD_APCI3010_16 }, 681 { PCI_VDEVICE(ADDIDATA, 0x3017), BOARD_APCI3010_8 }, 682 { PCI_VDEVICE(ADDIDATA, 0x3018), BOARD_APCI3010_4 }, 683 { PCI_VDEVICE(ADDIDATA, 0x3019), BOARD_APCI3016_16 }, 684 { PCI_VDEVICE(ADDIDATA, 0x301a), BOARD_APCI3016_8 }, 685 { PCI_VDEVICE(ADDIDATA, 0x301b), BOARD_APCI3016_4 }, 686 { PCI_VDEVICE(ADDIDATA, 0x301c), BOARD_APCI3100_16_4 }, 687 { PCI_VDEVICE(ADDIDATA, 0x301d), BOARD_APCI3100_8_4 }, 688 { PCI_VDEVICE(ADDIDATA, 0x301e), BOARD_APCI3106_16_4 }, 689 { PCI_VDEVICE(ADDIDATA, 0x301f), BOARD_APCI3106_8_4 }, 690 { PCI_VDEVICE(ADDIDATA, 0x3020), BOARD_APCI3110_16_4 }, 691 { PCI_VDEVICE(ADDIDATA, 0x3021), BOARD_APCI3110_8_4 }, 692 { PCI_VDEVICE(ADDIDATA, 0x3022), BOARD_APCI3116_16_4 }, 693 { PCI_VDEVICE(ADDIDATA, 0x3023), BOARD_APCI3116_8_4 }, 694 { PCI_VDEVICE(ADDIDATA, 0x300B), BOARD_APCI3003 }, 695 { PCI_VDEVICE(ADDIDATA, 0x3002), BOARD_APCI3002_16 }, 696 { PCI_VDEVICE(ADDIDATA, 0x3003), BOARD_APCI3002_8 }, 697 { PCI_VDEVICE(ADDIDATA, 0x3004), BOARD_APCI3002_4 }, 698 { PCI_VDEVICE(ADDIDATA, 0x3024), BOARD_APCI3500 }, 699 { 0 } 700}; 701MODULE_DEVICE_TABLE(pci, apci3xxx_pci_table); 702 703static struct pci_driver apci3xxx_pci_driver = { 704 .name = "addi_apci_3xxx", 705 .id_table = apci3xxx_pci_table, 706 .probe = apci3xxx_pci_probe, 707 .remove = comedi_pci_auto_unconfig, 708}; 709module_comedi_pci_driver(apci3xxx_driver, apci3xxx_pci_driver); 710 711MODULE_AUTHOR("Comedi http://www.comedi.org"); 712MODULE_DESCRIPTION("Comedi low-level driver"); 713MODULE_LICENSE("GPL"); 714