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