1/* 2 * comedi/drivers/adv_pci1710.c 3 * 4 * Author: Michal Dobes <dobes@tesnet.cz> 5 * 6 * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn> 7 * for testing and informations. 8 * 9 * hardware driver for Advantech cards: 10 * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731 11 * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731 12 * 13 * Options: 14 * [0] - PCI bus number - if bus number and slot number are 0, 15 * then driver search for first unused card 16 * [1] - PCI slot number 17 * 18*/ 19/* 20Driver: adv_pci1710 21Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, 22 Advantech PCI-1720, PCI-1731 23Author: Michal Dobes <dobes@tesnet.cz> 24Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg), 25 PCI-1711 (adv_pci1710), PCI-1713, PCI-1720, 26 PCI-1731 27Status: works 28 29This driver supports AI, AO, DI and DO subdevices. 30AI subdevice supports cmd and insn interface, 31other subdevices support only insn interface. 32 33The PCI-1710 and PCI-1710HG have the same PCI device ID, so the 34driver cannot distinguish between them, as would be normal for a 35PCI driver. 36 37Configuration options: 38 [0] - PCI bus of device (optional) 39 [1] - PCI slot of device (optional) 40 If bus/slot is not specified, the first available PCI 41 device will be used. 42*/ 43 44#include <linux/module.h> 45#include <linux/pci.h> 46#include <linux/interrupt.h> 47 48#include "../comedidev.h" 49 50#include "comedi_fc.h" 51#include "8253.h" 52#include "amcc_s5933.h" 53 54/* hardware types of the cards */ 55#define TYPE_PCI171X 0 56#define TYPE_PCI1713 2 57#define TYPE_PCI1720 3 58 59#define PCI171x_AD_DATA 0 /* R: A/D data */ 60#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */ 61#define PCI171x_RANGE 2 /* W: A/D gain/range register */ 62#define PCI171x_MUX 4 /* W: A/D multiplexor control */ 63#define PCI171x_STATUS 6 /* R: status register */ 64#define PCI171x_CONTROL 6 /* W: control register */ 65#define PCI171x_CLRINT 8 /* W: clear interrupts request */ 66#define PCI171x_CLRFIFO 9 /* W: clear FIFO */ 67#define PCI171x_DA1 10 /* W: D/A register */ 68#define PCI171x_DA2 12 /* W: D/A register */ 69#define PCI171x_DAREF 14 /* W: D/A reference control */ 70#define PCI171x_DI 16 /* R: digi inputs */ 71#define PCI171x_DO 16 /* R: digi inputs */ 72 73#define PCI171X_TIMER_BASE 0x18 74 75#define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */ 76#define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */ 77#define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */ 78#define PCI171x_CNTCTRL 30 /* W: 8254 counter control */ 79 80/* upper bits from status register (PCI171x_STATUS) (lower is same with control 81 * reg) */ 82#define Status_FE 0x0100 /* 1=FIFO is empty */ 83#define Status_FH 0x0200 /* 1=FIFO is half full */ 84#define Status_FF 0x0400 /* 1=FIFO is full, fatal error */ 85#define Status_IRQ 0x0800 /* 1=IRQ occurred */ 86/* bits from control register (PCI171x_CONTROL) */ 87#define Control_CNT0 0x0040 /* 1=CNT0 have external source, 88 * 0=have internal 100kHz source */ 89#define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */ 90#define Control_IRQEN 0x0010 /* 1=enable IRQ */ 91#define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */ 92#define Control_EXT 0x0004 /* 1=external trigger source */ 93#define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */ 94#define Control_SW 0x0001 /* 1=enable software trigger source */ 95/* bits from counter control register (PCI171x_CNTCTRL) */ 96#define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */ 97#define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */ 98#define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */ 99#define Counter_M2 0x0008 100#define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */ 101#define Counter_RW1 0x0020 102#define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */ 103#define Counter_SC1 0x0080 /* be used, 00 for CNT0, 104 * 11 for read-back command */ 105 106#define PCI1720_DA0 0 /* W: D/A register 0 */ 107#define PCI1720_DA1 2 /* W: D/A register 1 */ 108#define PCI1720_DA2 4 /* W: D/A register 2 */ 109#define PCI1720_DA3 6 /* W: D/A register 3 */ 110#define PCI1720_RANGE 8 /* R/W: D/A range register */ 111#define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */ 112#define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */ 113 114/* D/A synchronized control (PCI1720_SYNCONT) */ 115#define Syncont_SC0 1 /* set synchronous output mode */ 116 117static const struct comedi_lrange range_pci1710_3 = { 118 9, { 119 BIP_RANGE(5), 120 BIP_RANGE(2.5), 121 BIP_RANGE(1.25), 122 BIP_RANGE(0.625), 123 BIP_RANGE(10), 124 UNI_RANGE(10), 125 UNI_RANGE(5), 126 UNI_RANGE(2.5), 127 UNI_RANGE(1.25) 128 } 129}; 130 131static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 132 0x10, 0x11, 0x12, 0x13 }; 133 134static const struct comedi_lrange range_pci1710hg = { 135 12, { 136 BIP_RANGE(5), 137 BIP_RANGE(0.5), 138 BIP_RANGE(0.05), 139 BIP_RANGE(0.005), 140 BIP_RANGE(10), 141 BIP_RANGE(1), 142 BIP_RANGE(0.1), 143 BIP_RANGE(0.01), 144 UNI_RANGE(10), 145 UNI_RANGE(1), 146 UNI_RANGE(0.1), 147 UNI_RANGE(0.01) 148 } 149}; 150 151static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 152 0x05, 0x06, 0x07, 0x10, 0x11, 153 0x12, 0x13 }; 154 155static const struct comedi_lrange range_pci17x1 = { 156 5, { 157 BIP_RANGE(10), 158 BIP_RANGE(5), 159 BIP_RANGE(2.5), 160 BIP_RANGE(1.25), 161 BIP_RANGE(0.625) 162 } 163}; 164 165static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 }; 166 167static const struct comedi_lrange range_pci1720 = { 168 4, { 169 UNI_RANGE(5), 170 UNI_RANGE(10), 171 BIP_RANGE(5), 172 BIP_RANGE(10) 173 } 174}; 175 176static const struct comedi_lrange range_pci171x_da = { 177 2, { 178 UNI_RANGE(5), 179 UNI_RANGE(10) 180 } 181}; 182 183enum pci1710_boardid { 184 BOARD_PCI1710, 185 BOARD_PCI1710HG, 186 BOARD_PCI1711, 187 BOARD_PCI1713, 188 BOARD_PCI1720, 189 BOARD_PCI1731, 190}; 191 192struct boardtype { 193 const char *name; /* board name */ 194 char have_irq; /* 1=card support IRQ */ 195 char cardtype; /* 0=1710& co. 2=1713, ... */ 196 int n_aichan; /* num of A/D chans */ 197 int n_aichand; /* num of A/D chans in diff mode */ 198 int n_aochan; /* num of D/A chans */ 199 int n_dichan; /* num of DI chans */ 200 int n_dochan; /* num of DO chans */ 201 int n_counter; /* num of counters */ 202 int ai_maxdata; /* resolution of A/D */ 203 int ao_maxdata; /* resolution of D/A */ 204 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ 205 const char *rangecode_ai; /* range codes for programming */ 206 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ 207 unsigned int ai_ns_min; /* max sample speed of card v ns */ 208 unsigned int fifo_half_size; /* size of FIFO/2 */ 209}; 210 211static const struct boardtype boardtypes[] = { 212 [BOARD_PCI1710] = { 213 .name = "pci1710", 214 .have_irq = 1, 215 .cardtype = TYPE_PCI171X, 216 .n_aichan = 16, 217 .n_aichand = 8, 218 .n_aochan = 2, 219 .n_dichan = 16, 220 .n_dochan = 16, 221 .n_counter = 1, 222 .ai_maxdata = 0x0fff, 223 .ao_maxdata = 0x0fff, 224 .rangelist_ai = &range_pci1710_3, 225 .rangecode_ai = range_codes_pci1710_3, 226 .rangelist_ao = &range_pci171x_da, 227 .ai_ns_min = 10000, 228 .fifo_half_size = 2048, 229 }, 230 [BOARD_PCI1710HG] = { 231 .name = "pci1710hg", 232 .have_irq = 1, 233 .cardtype = TYPE_PCI171X, 234 .n_aichan = 16, 235 .n_aichand = 8, 236 .n_aochan = 2, 237 .n_dichan = 16, 238 .n_dochan = 16, 239 .n_counter = 1, 240 .ai_maxdata = 0x0fff, 241 .ao_maxdata = 0x0fff, 242 .rangelist_ai = &range_pci1710hg, 243 .rangecode_ai = range_codes_pci1710hg, 244 .rangelist_ao = &range_pci171x_da, 245 .ai_ns_min = 10000, 246 .fifo_half_size = 2048, 247 }, 248 [BOARD_PCI1711] = { 249 .name = "pci1711", 250 .have_irq = 1, 251 .cardtype = TYPE_PCI171X, 252 .n_aichan = 16, 253 .n_aochan = 2, 254 .n_dichan = 16, 255 .n_dochan = 16, 256 .n_counter = 1, 257 .ai_maxdata = 0x0fff, 258 .ao_maxdata = 0x0fff, 259 .rangelist_ai = &range_pci17x1, 260 .rangecode_ai = range_codes_pci17x1, 261 .rangelist_ao = &range_pci171x_da, 262 .ai_ns_min = 10000, 263 .fifo_half_size = 512, 264 }, 265 [BOARD_PCI1713] = { 266 .name = "pci1713", 267 .have_irq = 1, 268 .cardtype = TYPE_PCI1713, 269 .n_aichan = 32, 270 .n_aichand = 16, 271 .ai_maxdata = 0x0fff, 272 .rangelist_ai = &range_pci1710_3, 273 .rangecode_ai = range_codes_pci1710_3, 274 .ai_ns_min = 10000, 275 .fifo_half_size = 2048, 276 }, 277 [BOARD_PCI1720] = { 278 .name = "pci1720", 279 .cardtype = TYPE_PCI1720, 280 .n_aochan = 4, 281 .ao_maxdata = 0x0fff, 282 .rangelist_ao = &range_pci1720, 283 }, 284 [BOARD_PCI1731] = { 285 .name = "pci1731", 286 .have_irq = 1, 287 .cardtype = TYPE_PCI171X, 288 .n_aichan = 16, 289 .n_dichan = 16, 290 .n_dochan = 16, 291 .ai_maxdata = 0x0fff, 292 .rangelist_ai = &range_pci17x1, 293 .rangecode_ai = range_codes_pci17x1, 294 .ai_ns_min = 10000, 295 .fifo_half_size = 512, 296 }, 297}; 298 299struct pci1710_private { 300 unsigned int CntrlReg; /* Control register */ 301 unsigned int ai_act_scan; /* how many scans we finished */ 302 unsigned char ai_et; 303 unsigned int ai_et_CntrlReg; 304 unsigned int ai_et_MuxVal; 305 unsigned int next_divisor1; 306 unsigned int next_divisor2; 307 unsigned int divisor1; 308 unsigned int divisor2; 309 unsigned int act_chanlist[32]; /* list of scanned channel */ 310 unsigned char saved_seglen; /* len of the non-repeating chanlist */ 311 unsigned char da_ranges; /* copy of D/A outpit range register */ 312 unsigned short ao_data[4]; /* data output buffer */ 313 unsigned int cnt0_write_wait; /* after a write, wait for update of the 314 * internal state */ 315}; 316 317/* used for gain list programming */ 318static const unsigned int muxonechan[] = { 319 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, 320 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, 321 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, 322 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f 323}; 324 325static int pci171x_ai_dropout(struct comedi_device *dev, 326 struct comedi_subdevice *s, 327 unsigned int chan, 328 unsigned int val) 329{ 330 const struct boardtype *board = dev->board_ptr; 331 struct pci1710_private *devpriv = dev->private; 332 333 if (board->cardtype != TYPE_PCI1713) { 334 if ((val & 0xf000) != devpriv->act_chanlist[chan]) { 335 dev_err(dev->class_dev, 336 "A/D data droput: received from channel %d, expected %d\n", 337 (val >> 12) & 0xf, 338 (devpriv->act_chanlist[chan] >> 12) & 0xf); 339 return -ENODATA; 340 } 341 } 342 return 0; 343} 344 345static int pci171x_ai_check_chanlist(struct comedi_device *dev, 346 struct comedi_subdevice *s, 347 struct comedi_cmd *cmd) 348{ 349 struct pci1710_private *devpriv = dev->private; 350 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); 351 unsigned int last_aref = CR_AREF(cmd->chanlist[0]); 352 unsigned int next_chan = (chan0 + 1) % s->n_chan; 353 unsigned int chansegment[32]; 354 unsigned int seglen; 355 int i; 356 357 if (cmd->chanlist_len == 1) { 358 devpriv->saved_seglen = cmd->chanlist_len; 359 return 0; 360 } 361 362 /* first channel is always ok */ 363 chansegment[0] = cmd->chanlist[0]; 364 365 for (i = 1; i < cmd->chanlist_len; i++) { 366 unsigned int chan = CR_CHAN(cmd->chanlist[i]); 367 unsigned int aref = CR_AREF(cmd->chanlist[i]); 368 369 if (cmd->chanlist[0] == cmd->chanlist[i]) 370 break; /* we detected a loop, stop */ 371 372 if (aref == AREF_DIFF && (chan & 1)) { 373 dev_err(dev->class_dev, 374 "Odd channel cannot be differential input!\n"); 375 return -EINVAL; 376 } 377 378 if (last_aref == AREF_DIFF) 379 next_chan = (next_chan + 1) % s->n_chan; 380 if (chan != next_chan) { 381 dev_err(dev->class_dev, 382 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", 383 i, chan, next_chan, chan0); 384 return -EINVAL; 385 } 386 387 /* next correct channel in list */ 388 chansegment[i] = cmd->chanlist[i]; 389 last_aref = aref; 390 } 391 seglen = i; 392 393 for (i = 0; i < cmd->chanlist_len; i++) { 394 if (cmd->chanlist[i] != chansegment[i % seglen]) { 395 dev_err(dev->class_dev, 396 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", 397 i, CR_CHAN(chansegment[i]), 398 CR_RANGE(chansegment[i]), 399 CR_AREF(chansegment[i]), 400 CR_CHAN(cmd->chanlist[i % seglen]), 401 CR_RANGE(cmd->chanlist[i % seglen]), 402 CR_AREF(chansegment[i % seglen])); 403 return -EINVAL; 404 } 405 } 406 devpriv->saved_seglen = seglen; 407 408 return 0; 409} 410 411static void setup_channel_list(struct comedi_device *dev, 412 struct comedi_subdevice *s, 413 unsigned int *chanlist, unsigned int n_chan, 414 unsigned int seglen) 415{ 416 const struct boardtype *this_board = dev->board_ptr; 417 struct pci1710_private *devpriv = dev->private; 418 unsigned int i, range, chanprog; 419 420 for (i = 0; i < seglen; i++) { /* store range list to card */ 421 chanprog = muxonechan[CR_CHAN(chanlist[i])]; 422 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ 423 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; 424 if (CR_AREF(chanlist[i]) == AREF_DIFF) 425 range |= 0x0020; 426 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ 427 devpriv->act_chanlist[i] = 428 (CR_CHAN(chanlist[i]) << 12) & 0xf000; 429 } 430 for ( ; i < n_chan; i++) { /* store remainder of channel list */ 431 devpriv->act_chanlist[i] = 432 (CR_CHAN(chanlist[i]) << 12) & 0xf000; 433 } 434 435 devpriv->ai_et_MuxVal = 436 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); 437 /* select channel interval to scan */ 438 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); 439} 440 441static int pci171x_ai_eoc(struct comedi_device *dev, 442 struct comedi_subdevice *s, 443 struct comedi_insn *insn, 444 unsigned long context) 445{ 446 unsigned int status; 447 448 status = inw(dev->iobase + PCI171x_STATUS); 449 if ((status & Status_FE) == 0) 450 return 0; 451 return -EBUSY; 452} 453 454static int pci171x_insn_read_ai(struct comedi_device *dev, 455 struct comedi_subdevice *s, 456 struct comedi_insn *insn, unsigned int *data) 457{ 458 struct pci1710_private *devpriv = dev->private; 459 unsigned int chan = CR_CHAN(insn->chanspec); 460 int ret = 0; 461 int i; 462 463 devpriv->CntrlReg &= Control_CNT0; 464 devpriv->CntrlReg |= Control_SW; /* set software trigger */ 465 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 466 outb(0, dev->iobase + PCI171x_CLRFIFO); 467 outb(0, dev->iobase + PCI171x_CLRINT); 468 469 setup_channel_list(dev, s, &insn->chanspec, 1, 1); 470 471 for (i = 0; i < insn->n; i++) { 472 unsigned int val; 473 474 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ 475 476 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0); 477 if (ret) 478 break; 479 480 val = inw(dev->iobase + PCI171x_AD_DATA); 481 ret = pci171x_ai_dropout(dev, s, chan, val); 482 if (ret) 483 break; 484 485 data[i] = val & s->maxdata; 486 } 487 488 outb(0, dev->iobase + PCI171x_CLRFIFO); 489 outb(0, dev->iobase + PCI171x_CLRINT); 490 491 return ret ? ret : insn->n; 492} 493 494/* 495============================================================================== 496*/ 497static int pci171x_insn_write_ao(struct comedi_device *dev, 498 struct comedi_subdevice *s, 499 struct comedi_insn *insn, unsigned int *data) 500{ 501 struct pci1710_private *devpriv = dev->private; 502 unsigned int val; 503 int n, chan, range, ofs; 504 505 chan = CR_CHAN(insn->chanspec); 506 range = CR_RANGE(insn->chanspec); 507 if (chan) { 508 devpriv->da_ranges &= 0xfb; 509 devpriv->da_ranges |= (range << 2); 510 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); 511 ofs = PCI171x_DA2; 512 } else { 513 devpriv->da_ranges &= 0xfe; 514 devpriv->da_ranges |= range; 515 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); 516 ofs = PCI171x_DA1; 517 } 518 val = devpriv->ao_data[chan]; 519 520 for (n = 0; n < insn->n; n++) { 521 val = data[n]; 522 outw(val, dev->iobase + ofs); 523 } 524 525 devpriv->ao_data[chan] = val; 526 527 return n; 528 529} 530 531/* 532============================================================================== 533*/ 534static int pci171x_insn_read_ao(struct comedi_device *dev, 535 struct comedi_subdevice *s, 536 struct comedi_insn *insn, unsigned int *data) 537{ 538 struct pci1710_private *devpriv = dev->private; 539 int n, chan; 540 541 chan = CR_CHAN(insn->chanspec); 542 for (n = 0; n < insn->n; n++) 543 data[n] = devpriv->ao_data[chan]; 544 545 return n; 546} 547 548/* 549============================================================================== 550*/ 551static int pci171x_insn_bits_di(struct comedi_device *dev, 552 struct comedi_subdevice *s, 553 struct comedi_insn *insn, unsigned int *data) 554{ 555 data[1] = inw(dev->iobase + PCI171x_DI); 556 557 return insn->n; 558} 559 560static int pci171x_insn_bits_do(struct comedi_device *dev, 561 struct comedi_subdevice *s, 562 struct comedi_insn *insn, 563 unsigned int *data) 564{ 565 if (comedi_dio_update_state(s, data)) 566 outw(s->state, dev->iobase + PCI171x_DO); 567 568 data[1] = s->state; 569 570 return insn->n; 571} 572 573static void pci171x_start_pacer(struct comedi_device *dev, 574 bool load_counters) 575{ 576 struct pci1710_private *devpriv = dev->private; 577 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE; 578 579 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY); 580 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY); 581 582 if (load_counters) { 583 i8254_write(timer_base, 1, 2, devpriv->divisor2); 584 i8254_write(timer_base, 1, 1, devpriv->divisor1); 585 } 586} 587 588/* 589============================================================================== 590*/ 591static int pci171x_insn_counter_read(struct comedi_device *dev, 592 struct comedi_subdevice *s, 593 struct comedi_insn *insn, 594 unsigned int *data) 595{ 596 unsigned int msb, lsb, ccntrl; 597 int i; 598 599 ccntrl = 0xD2; /* count only */ 600 for (i = 0; i < insn->n; i++) { 601 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL); 602 603 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF; 604 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF; 605 606 data[0] = lsb | (msb << 8); 607 } 608 609 return insn->n; 610} 611 612/* 613============================================================================== 614*/ 615static int pci171x_insn_counter_write(struct comedi_device *dev, 616 struct comedi_subdevice *s, 617 struct comedi_insn *insn, 618 unsigned int *data) 619{ 620 struct pci1710_private *devpriv = dev->private; 621 uint msb, lsb, ccntrl, status; 622 623 lsb = data[0] & 0x00FF; 624 msb = (data[0] & 0xFF00) >> 8; 625 626 /* write lsb, then msb */ 627 outw(lsb, dev->iobase + PCI171x_CNT0); 628 outw(msb, dev->iobase + PCI171x_CNT0); 629 630 if (devpriv->cnt0_write_wait) { 631 /* wait for the new count to be loaded */ 632 ccntrl = 0xE2; 633 do { 634 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL); 635 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF; 636 } while (status & 0x40); 637 } 638 639 return insn->n; 640} 641 642/* 643============================================================================== 644*/ 645static int pci171x_insn_counter_config(struct comedi_device *dev, 646 struct comedi_subdevice *s, 647 struct comedi_insn *insn, 648 unsigned int *data) 649{ 650#ifdef unused 651 /* This doesn't work like a normal Comedi counter config */ 652 struct pci1710_private *devpriv = dev->private; 653 uint ccntrl = 0; 654 655 devpriv->cnt0_write_wait = data[0] & 0x20; 656 657 /* internal or external clock? */ 658 if (!(data[0] & 0x10)) { /* internal */ 659 devpriv->CntrlReg &= ~Control_CNT0; 660 } else { 661 devpriv->CntrlReg |= Control_CNT0; 662 } 663 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 664 665 if (data[0] & 0x01) 666 ccntrl |= Counter_M0; 667 if (data[0] & 0x02) 668 ccntrl |= Counter_M1; 669 if (data[0] & 0x04) 670 ccntrl |= Counter_M2; 671 if (data[0] & 0x08) 672 ccntrl |= Counter_BCD; 673 ccntrl |= Counter_RW0; /* set read/write mode */ 674 ccntrl |= Counter_RW1; 675 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL); 676#endif 677 678 return 1; 679} 680 681/* 682============================================================================== 683*/ 684static int pci1720_insn_write_ao(struct comedi_device *dev, 685 struct comedi_subdevice *s, 686 struct comedi_insn *insn, unsigned int *data) 687{ 688 struct pci1710_private *devpriv = dev->private; 689 unsigned int val; 690 int n, rangereg, chan; 691 692 chan = CR_CHAN(insn->chanspec); 693 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1))); 694 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1)); 695 if (rangereg != devpriv->da_ranges) { 696 outb(rangereg, dev->iobase + PCI1720_RANGE); 697 devpriv->da_ranges = rangereg; 698 } 699 val = devpriv->ao_data[chan]; 700 701 for (n = 0; n < insn->n; n++) { 702 val = data[n]; 703 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); 704 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ 705 } 706 707 devpriv->ao_data[chan] = val; 708 709 return n; 710} 711 712/* 713============================================================================== 714*/ 715static int pci171x_ai_cancel(struct comedi_device *dev, 716 struct comedi_subdevice *s) 717{ 718 const struct boardtype *this_board = dev->board_ptr; 719 struct pci1710_private *devpriv = dev->private; 720 721 switch (this_board->cardtype) { 722 default: 723 devpriv->CntrlReg &= Control_CNT0; 724 devpriv->CntrlReg |= Control_SW; 725 /* reset any operations */ 726 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 727 pci171x_start_pacer(dev, false); 728 outb(0, dev->iobase + PCI171x_CLRFIFO); 729 outb(0, dev->iobase + PCI171x_CLRINT); 730 break; 731 } 732 733 devpriv->ai_act_scan = 0; 734 s->async->cur_chan = 0; 735 736 return 0; 737} 738 739static void pci1710_handle_every_sample(struct comedi_device *dev, 740 struct comedi_subdevice *s) 741{ 742 struct pci1710_private *devpriv = dev->private; 743 struct comedi_cmd *cmd = &s->async->cmd; 744 unsigned int status; 745 unsigned int val; 746 int ret; 747 748 status = inw(dev->iobase + PCI171x_STATUS); 749 if (status & Status_FE) { 750 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status); 751 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 752 cfc_handle_events(dev, s); 753 return; 754 } 755 if (status & Status_FF) { 756 dev_dbg(dev->class_dev, 757 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status); 758 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 759 cfc_handle_events(dev, s); 760 return; 761 } 762 763 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ 764 765 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { 766 val = inw(dev->iobase + PCI171x_AD_DATA); 767 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); 768 if (ret) { 769 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 770 break; 771 } 772 773 comedi_buf_put(s, val & s->maxdata); 774 775 s->async->cur_chan++; 776 if (s->async->cur_chan >= cmd->chanlist_len) 777 s->async->cur_chan = 0; 778 779 780 if (s->async->cur_chan == 0) { /* one scan done */ 781 devpriv->ai_act_scan++; 782 if (cmd->stop_src == TRIG_COUNT && 783 devpriv->ai_act_scan >= cmd->stop_arg) { 784 /* all data sampled */ 785 s->async->events |= COMEDI_CB_EOA; 786 break; 787 } 788 } 789 } 790 791 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ 792 793 cfc_handle_events(dev, s); 794} 795 796/* 797============================================================================== 798*/ 799static int move_block_from_fifo(struct comedi_device *dev, 800 struct comedi_subdevice *s, int n, int turn) 801{ 802 struct pci1710_private *devpriv = dev->private; 803 struct comedi_cmd *cmd = &s->async->cmd; 804 unsigned int val; 805 int ret; 806 int i; 807 808 for (i = 0; i < n; i++) { 809 val = inw(dev->iobase + PCI171x_AD_DATA); 810 811 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); 812 if (ret) { 813 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 814 return ret; 815 } 816 817 comedi_buf_put(s, val & s->maxdata); 818 819 s->async->cur_chan++; 820 if (s->async->cur_chan >= cmd->chanlist_len) { 821 s->async->cur_chan = 0; 822 devpriv->ai_act_scan++; 823 } 824 } 825 return 0; 826} 827 828static void pci1710_handle_fifo(struct comedi_device *dev, 829 struct comedi_subdevice *s) 830{ 831 const struct boardtype *this_board = dev->board_ptr; 832 struct pci1710_private *devpriv = dev->private; 833 struct comedi_cmd *cmd = &s->async->cmd; 834 int m, samplesinbuf; 835 836 m = inw(dev->iobase + PCI171x_STATUS); 837 if (!(m & Status_FH)) { 838 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m); 839 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 840 cfc_handle_events(dev, s); 841 return; 842 } 843 if (m & Status_FF) { 844 dev_dbg(dev->class_dev, 845 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); 846 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 847 cfc_handle_events(dev, s); 848 return; 849 } 850 851 samplesinbuf = this_board->fifo_half_size; 852 if (samplesinbuf * sizeof(short) >= s->async->prealloc_bufsz) { 853 m = s->async->prealloc_bufsz / sizeof(short); 854 if (move_block_from_fifo(dev, s, m, 0)) 855 return; 856 samplesinbuf -= m; 857 } 858 859 if (samplesinbuf) { 860 if (move_block_from_fifo(dev, s, samplesinbuf, 1)) 861 return; 862 } 863 864 if (cmd->stop_src == TRIG_COUNT && 865 devpriv->ai_act_scan >= cmd->stop_arg) { 866 /* all data sampled */ 867 s->async->events |= COMEDI_CB_EOA; 868 cfc_handle_events(dev, s); 869 return; 870 } 871 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ 872 873 cfc_handle_events(dev, s); 874} 875 876/* 877============================================================================== 878*/ 879static irqreturn_t interrupt_service_pci1710(int irq, void *d) 880{ 881 struct comedi_device *dev = d; 882 struct pci1710_private *devpriv = dev->private; 883 struct comedi_subdevice *s; 884 struct comedi_cmd *cmd; 885 886 if (!dev->attached) /* is device attached? */ 887 return IRQ_NONE; /* no, exit */ 888 889 s = dev->read_subdev; 890 cmd = &s->async->cmd; 891 892 /* is this interrupt from our board? */ 893 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) 894 return IRQ_NONE; /* no, exit */ 895 896 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ 897 devpriv->ai_et = 0; 898 devpriv->CntrlReg &= Control_CNT0; 899 devpriv->CntrlReg |= Control_SW; /* set software trigger */ 900 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 901 devpriv->CntrlReg = devpriv->ai_et_CntrlReg; 902 outb(0, dev->iobase + PCI171x_CLRFIFO); 903 outb(0, dev->iobase + PCI171x_CLRINT); 904 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); 905 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 906 pci171x_start_pacer(dev, true); 907 return IRQ_HANDLED; 908 } 909 910 if (cmd->flags & CMDF_WAKE_EOS) 911 pci1710_handle_every_sample(dev, s); 912 else 913 pci1710_handle_fifo(dev, s); 914 915 return IRQ_HANDLED; 916} 917 918static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 919{ 920 struct pci1710_private *devpriv = dev->private; 921 struct comedi_cmd *cmd = &s->async->cmd; 922 923 pci171x_start_pacer(dev, false); 924 925 setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len, 926 devpriv->saved_seglen); 927 928 outb(0, dev->iobase + PCI171x_CLRFIFO); 929 outb(0, dev->iobase + PCI171x_CLRINT); 930 931 devpriv->ai_act_scan = 0; 932 s->async->cur_chan = 0; 933 934 devpriv->CntrlReg &= Control_CNT0; 935 if ((cmd->flags & CMDF_WAKE_EOS) == 0) 936 devpriv->CntrlReg |= Control_ONEFH; 937 938 devpriv->divisor1 = devpriv->next_divisor1; 939 devpriv->divisor2 = devpriv->next_divisor2; 940 941 if (cmd->convert_src == TRIG_TIMER) { 942 devpriv->CntrlReg |= Control_PACER | Control_IRQEN; 943 if (cmd->start_src == TRIG_EXT) { 944 devpriv->ai_et_CntrlReg = devpriv->CntrlReg; 945 devpriv->CntrlReg &= 946 ~(Control_PACER | Control_ONEFH | Control_GATE); 947 devpriv->CntrlReg |= Control_EXT; 948 devpriv->ai_et = 1; 949 } else { /* TRIG_NOW */ 950 devpriv->ai_et = 0; 951 } 952 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 953 954 if (cmd->start_src == TRIG_NOW) 955 pci171x_start_pacer(dev, true); 956 } else { /* TRIG_EXT */ 957 devpriv->CntrlReg |= Control_EXT | Control_IRQEN; 958 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 959 } 960 961 return 0; 962} 963 964/* 965============================================================================== 966*/ 967static int pci171x_ai_cmdtest(struct comedi_device *dev, 968 struct comedi_subdevice *s, 969 struct comedi_cmd *cmd) 970{ 971 const struct boardtype *this_board = dev->board_ptr; 972 struct pci1710_private *devpriv = dev->private; 973 int err = 0; 974 unsigned int arg; 975 976 /* Step 1 : check if triggers are trivially valid */ 977 978 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); 979 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); 980 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); 981 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 982 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); 983 984 if (err) 985 return 1; 986 987 /* step 2a: make sure trigger sources are unique */ 988 989 err |= cfc_check_trigger_is_unique(cmd->start_src); 990 err |= cfc_check_trigger_is_unique(cmd->convert_src); 991 err |= cfc_check_trigger_is_unique(cmd->stop_src); 992 993 /* step 2b: and mutually compatible */ 994 995 if (err) 996 return 2; 997 998 /* Step 3: check if arguments are trivially valid */ 999 1000 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 1001 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 1002 1003 if (cmd->convert_src == TRIG_TIMER) 1004 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 1005 this_board->ai_ns_min); 1006 else /* TRIG_FOLLOW */ 1007 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); 1008 1009 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 1010 1011 if (cmd->stop_src == TRIG_COUNT) 1012 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); 1013 else /* TRIG_NONE */ 1014 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 1015 1016 if (err) 1017 return 3; 1018 1019 /* step 4: fix up any arguments */ 1020 1021 if (cmd->convert_src == TRIG_TIMER) { 1022 arg = cmd->convert_arg; 1023 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, 1024 &devpriv->next_divisor1, 1025 &devpriv->next_divisor2, 1026 &arg, cmd->flags); 1027 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); 1028 } 1029 1030 if (err) 1031 return 4; 1032 1033 /* Step 5: check channel list */ 1034 1035 err |= pci171x_ai_check_chanlist(dev, s, cmd); 1036 1037 if (err) 1038 return 5; 1039 1040 return 0; 1041} 1042 1043/* 1044============================================================================== 1045*/ 1046static int pci171x_reset(struct comedi_device *dev) 1047{ 1048 const struct boardtype *this_board = dev->board_ptr; 1049 struct pci1710_private *devpriv = dev->private; 1050 1051 outw(0x30, dev->iobase + PCI171x_CNTCTRL); 1052 /* Software trigger, CNT0=external */ 1053 devpriv->CntrlReg = Control_SW | Control_CNT0; 1054 /* reset any operations */ 1055 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 1056 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ 1057 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ 1058 pci171x_start_pacer(dev, false); 1059 devpriv->da_ranges = 0; 1060 if (this_board->n_aochan) { 1061 /* set DACs to 0..5V */ 1062 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); 1063 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */ 1064 devpriv->ao_data[0] = 0x0000; 1065 if (this_board->n_aochan > 1) { 1066 outw(0, dev->iobase + PCI171x_DA2); 1067 devpriv->ao_data[1] = 0x0000; 1068 } 1069 } 1070 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */ 1071 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ 1072 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ 1073 1074 return 0; 1075} 1076 1077/* 1078============================================================================== 1079*/ 1080static int pci1720_reset(struct comedi_device *dev) 1081{ 1082 struct pci1710_private *devpriv = dev->private; 1083 /* set synchronous output mode */ 1084 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); 1085 devpriv->da_ranges = 0xAA; 1086 /* set all ranges to +/-5V */ 1087 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); 1088 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */ 1089 outw(0x0800, dev->iobase + PCI1720_DA1); 1090 outw(0x0800, dev->iobase + PCI1720_DA2); 1091 outw(0x0800, dev->iobase + PCI1720_DA3); 1092 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ 1093 devpriv->ao_data[0] = 0x0800; 1094 devpriv->ao_data[1] = 0x0800; 1095 devpriv->ao_data[2] = 0x0800; 1096 devpriv->ao_data[3] = 0x0800; 1097 return 0; 1098} 1099 1100/* 1101============================================================================== 1102*/ 1103static int pci1710_reset(struct comedi_device *dev) 1104{ 1105 const struct boardtype *this_board = dev->board_ptr; 1106 1107 switch (this_board->cardtype) { 1108 case TYPE_PCI1720: 1109 return pci1720_reset(dev); 1110 default: 1111 return pci171x_reset(dev); 1112 } 1113} 1114 1115static int pci1710_auto_attach(struct comedi_device *dev, 1116 unsigned long context) 1117{ 1118 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 1119 const struct boardtype *this_board = NULL; 1120 struct pci1710_private *devpriv; 1121 struct comedi_subdevice *s; 1122 int ret, subdev, n_subdevices; 1123 1124 if (context < ARRAY_SIZE(boardtypes)) 1125 this_board = &boardtypes[context]; 1126 if (!this_board) 1127 return -ENODEV; 1128 dev->board_ptr = this_board; 1129 dev->board_name = this_board->name; 1130 1131 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); 1132 if (!devpriv) 1133 return -ENOMEM; 1134 1135 ret = comedi_pci_enable(dev); 1136 if (ret) 1137 return ret; 1138 dev->iobase = pci_resource_start(pcidev, 2); 1139 1140 n_subdevices = 0; 1141 if (this_board->n_aichan) 1142 n_subdevices++; 1143 if (this_board->n_aochan) 1144 n_subdevices++; 1145 if (this_board->n_dichan) 1146 n_subdevices++; 1147 if (this_board->n_dochan) 1148 n_subdevices++; 1149 if (this_board->n_counter) 1150 n_subdevices++; 1151 1152 ret = comedi_alloc_subdevices(dev, n_subdevices); 1153 if (ret) 1154 return ret; 1155 1156 pci1710_reset(dev); 1157 1158 if (this_board->have_irq && pcidev->irq) { 1159 ret = request_irq(pcidev->irq, interrupt_service_pci1710, 1160 IRQF_SHARED, dev->board_name, dev); 1161 if (ret == 0) 1162 dev->irq = pcidev->irq; 1163 } 1164 1165 subdev = 0; 1166 1167 if (this_board->n_aichan) { 1168 s = &dev->subdevices[subdev]; 1169 s->type = COMEDI_SUBD_AI; 1170 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; 1171 if (this_board->n_aichand) 1172 s->subdev_flags |= SDF_DIFF; 1173 s->n_chan = this_board->n_aichan; 1174 s->maxdata = this_board->ai_maxdata; 1175 s->range_table = this_board->rangelist_ai; 1176 s->insn_read = pci171x_insn_read_ai; 1177 if (dev->irq) { 1178 dev->read_subdev = s; 1179 s->subdev_flags |= SDF_CMD_READ; 1180 s->len_chanlist = s->n_chan; 1181 s->do_cmdtest = pci171x_ai_cmdtest; 1182 s->do_cmd = pci171x_ai_cmd; 1183 s->cancel = pci171x_ai_cancel; 1184 } 1185 subdev++; 1186 } 1187 1188 if (this_board->n_aochan) { 1189 s = &dev->subdevices[subdev]; 1190 s->type = COMEDI_SUBD_AO; 1191 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 1192 s->n_chan = this_board->n_aochan; 1193 s->maxdata = this_board->ao_maxdata; 1194 s->len_chanlist = this_board->n_aochan; 1195 s->range_table = this_board->rangelist_ao; 1196 switch (this_board->cardtype) { 1197 case TYPE_PCI1720: 1198 s->insn_write = pci1720_insn_write_ao; 1199 break; 1200 default: 1201 s->insn_write = pci171x_insn_write_ao; 1202 break; 1203 } 1204 s->insn_read = pci171x_insn_read_ao; 1205 subdev++; 1206 } 1207 1208 if (this_board->n_dichan) { 1209 s = &dev->subdevices[subdev]; 1210 s->type = COMEDI_SUBD_DI; 1211 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; 1212 s->n_chan = this_board->n_dichan; 1213 s->maxdata = 1; 1214 s->len_chanlist = this_board->n_dichan; 1215 s->range_table = &range_digital; 1216 s->insn_bits = pci171x_insn_bits_di; 1217 subdev++; 1218 } 1219 1220 if (this_board->n_dochan) { 1221 s = &dev->subdevices[subdev]; 1222 s->type = COMEDI_SUBD_DO; 1223 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 1224 s->n_chan = this_board->n_dochan; 1225 s->maxdata = 1; 1226 s->len_chanlist = this_board->n_dochan; 1227 s->range_table = &range_digital; 1228 s->insn_bits = pci171x_insn_bits_do; 1229 subdev++; 1230 } 1231 1232 if (this_board->n_counter) { 1233 s = &dev->subdevices[subdev]; 1234 s->type = COMEDI_SUBD_COUNTER; 1235 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 1236 s->n_chan = this_board->n_counter; 1237 s->len_chanlist = this_board->n_counter; 1238 s->maxdata = 0xffff; 1239 s->range_table = &range_unknown; 1240 s->insn_read = pci171x_insn_counter_read; 1241 s->insn_write = pci171x_insn_counter_write; 1242 s->insn_config = pci171x_insn_counter_config; 1243 subdev++; 1244 } 1245 1246 return 0; 1247} 1248 1249static void pci1710_detach(struct comedi_device *dev) 1250{ 1251 if (dev->iobase) 1252 pci1710_reset(dev); 1253 comedi_pci_detach(dev); 1254} 1255 1256static struct comedi_driver adv_pci1710_driver = { 1257 .driver_name = "adv_pci1710", 1258 .module = THIS_MODULE, 1259 .auto_attach = pci1710_auto_attach, 1260 .detach = pci1710_detach, 1261}; 1262 1263static int adv_pci1710_pci_probe(struct pci_dev *dev, 1264 const struct pci_device_id *id) 1265{ 1266 return comedi_pci_auto_config(dev, &adv_pci1710_driver, 1267 id->driver_data); 1268} 1269 1270static const struct pci_device_id adv_pci1710_pci_table[] = { 1271 { 1272 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1273 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050), 1274 .driver_data = BOARD_PCI1710, 1275 }, { 1276 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1277 PCI_VENDOR_ID_ADVANTECH, 0x0000), 1278 .driver_data = BOARD_PCI1710, 1279 }, { 1280 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1281 PCI_VENDOR_ID_ADVANTECH, 0xb100), 1282 .driver_data = BOARD_PCI1710, 1283 }, { 1284 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1285 PCI_VENDOR_ID_ADVANTECH, 0xb200), 1286 .driver_data = BOARD_PCI1710, 1287 }, { 1288 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1289 PCI_VENDOR_ID_ADVANTECH, 0xc100), 1290 .driver_data = BOARD_PCI1710, 1291 }, { 1292 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1293 PCI_VENDOR_ID_ADVANTECH, 0xc200), 1294 .driver_data = BOARD_PCI1710, 1295 }, { 1296 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100), 1297 .driver_data = BOARD_PCI1710, 1298 }, { 1299 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1300 PCI_VENDOR_ID_ADVANTECH, 0x0002), 1301 .driver_data = BOARD_PCI1710HG, 1302 }, { 1303 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1304 PCI_VENDOR_ID_ADVANTECH, 0xb102), 1305 .driver_data = BOARD_PCI1710HG, 1306 }, { 1307 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1308 PCI_VENDOR_ID_ADVANTECH, 0xb202), 1309 .driver_data = BOARD_PCI1710HG, 1310 }, { 1311 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1312 PCI_VENDOR_ID_ADVANTECH, 0xc102), 1313 .driver_data = BOARD_PCI1710HG, 1314 }, { 1315 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 1316 PCI_VENDOR_ID_ADVANTECH, 0xc202), 1317 .driver_data = BOARD_PCI1710HG, 1318 }, { 1319 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102), 1320 .driver_data = BOARD_PCI1710HG, 1321 }, 1322 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 }, 1323 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 }, 1324 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 }, 1325 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 }, 1326 { 0 } 1327}; 1328MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table); 1329 1330static struct pci_driver adv_pci1710_pci_driver = { 1331 .name = "adv_pci1710", 1332 .id_table = adv_pci1710_pci_table, 1333 .probe = adv_pci1710_pci_probe, 1334 .remove = comedi_pci_auto_unconfig, 1335}; 1336module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver); 1337 1338MODULE_AUTHOR("Comedi http://www.comedi.org"); 1339MODULE_DESCRIPTION("Comedi low-level driver"); 1340MODULE_LICENSE("GPL"); 1341