adv_pci1710.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
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/interrupt.h> 45 46#include "../comedidev.h" 47 48#include "comedi_pci.h" 49 50#include "8253.h" 51#include "amcc_s5933.h" 52 53#define PCI171x_PARANOIDCHECK /* if defined, then is used code which control correct channel number on every 12 bit sample */ 54 55#undef PCI171X_EXTDEBUG 56 57#define DRV_NAME "adv_pci1710" 58 59#undef DPRINTK 60#ifdef PCI171X_EXTDEBUG 61#define DPRINTK(fmt, args...) printk(fmt, ## args) 62#else 63#define DPRINTK(fmt, args...) 64#endif 65 66/* hardware types of the cards */ 67#define TYPE_PCI171X 0 68#define TYPE_PCI1713 2 69#define TYPE_PCI1720 3 70 71#define IORANGE_171x 32 72#define IORANGE_1720 16 73 74#define PCI171x_AD_DATA 0 /* R: A/D data */ 75#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */ 76#define PCI171x_RANGE 2 /* W: A/D gain/range register */ 77#define PCI171x_MUX 4 /* W: A/D multiplexor control */ 78#define PCI171x_STATUS 6 /* R: status register */ 79#define PCI171x_CONTROL 6 /* W: control register */ 80#define PCI171x_CLRINT 8 /* W: clear interrupts request */ 81#define PCI171x_CLRFIFO 9 /* W: clear FIFO */ 82#define PCI171x_DA1 10 /* W: D/A register */ 83#define PCI171x_DA2 12 /* W: D/A register */ 84#define PCI171x_DAREF 14 /* W: D/A reference control */ 85#define PCI171x_DI 16 /* R: digi inputs */ 86#define PCI171x_DO 16 /* R: digi inputs */ 87#define PCI171x_CNT0 24 /* R/W: 8254 couter 0 */ 88#define PCI171x_CNT1 26 /* R/W: 8254 couter 1 */ 89#define PCI171x_CNT2 28 /* R/W: 8254 couter 2 */ 90#define PCI171x_CNTCTRL 30 /* W: 8254 counter control */ 91 92/* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */ 93#define Status_FE 0x0100 /* 1=FIFO is empty */ 94#define Status_FH 0x0200 /* 1=FIFO is half full */ 95#define Status_FF 0x0400 /* 1=FIFO is full, fatal error */ 96#define Status_IRQ 0x0800 /* 1=IRQ occured */ 97/* bits from control register (PCI171x_CONTROL) */ 98#define Control_CNT0 0x0040 /* 1=CNT0 have external source, 0=have internal 100kHz source */ 99#define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */ 100#define Control_IRQEN 0x0010 /* 1=enable IRQ */ 101#define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */ 102#define Control_EXT 0x0004 /* 1=external trigger source */ 103#define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */ 104#define Control_SW 0x0001 /* 1=enable software trigger source */ 105/* bits from counter control register (PCI171x_CNTCTRL) */ 106#define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */ 107#define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */ 108#define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */ 109#define Counter_M2 0x0008 110#define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */ 111#define Counter_RW1 0x0020 112#define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */ 113#define Counter_SC1 0x0080 /* be used, 00 for CNT0, 11 for read-back command */ 114 115#define PCI1720_DA0 0 /* W: D/A register 0 */ 116#define PCI1720_DA1 2 /* W: D/A register 1 */ 117#define PCI1720_DA2 4 /* W: D/A register 2 */ 118#define PCI1720_DA3 6 /* W: D/A register 3 */ 119#define PCI1720_RANGE 8 /* R/W: D/A range register */ 120#define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */ 121#define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */ 122 123/* D/A synchronized control (PCI1720_SYNCONT) */ 124#define Syncont_SC0 1 /* set synchronous output mode */ 125 126static const struct comedi_lrange range_pci1710_3 = { 9, { 127 BIP_RANGE(5), 128 BIP_RANGE(2.5), 129 BIP_RANGE(1.25), 130 BIP_RANGE(0.625), 131 BIP_RANGE(10), 132 UNI_RANGE(10), 133 UNI_RANGE(5), 134 UNI_RANGE(2.5), 135 UNI_RANGE(1.25) 136 } 137}; 138 139static const char range_codes_pci1710_3[] = 140 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 }; 141 142static const struct comedi_lrange range_pci1710hg = { 12, { 143 BIP_RANGE(5), 144 BIP_RANGE(0.5), 145 BIP_RANGE(0.05), 146 BIP_RANGE(0.005), 147 BIP_RANGE(10), 148 BIP_RANGE(1), 149 BIP_RANGE(0.1), 150 BIP_RANGE(0.01), 151 UNI_RANGE(10), 152 UNI_RANGE(1), 153 UNI_RANGE(0.1), 154 UNI_RANGE(0.01) 155 } 156}; 157 158static const char range_codes_pci1710hg[] = 159 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 160 0x13 161}; 162 163static const struct comedi_lrange range_pci17x1 = { 5, { 164 BIP_RANGE(10), 165 BIP_RANGE(5), 166 BIP_RANGE(2.5), 167 BIP_RANGE(1.25), 168 BIP_RANGE(0.625) 169 } 170}; 171 172static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 }; 173 174static const struct comedi_lrange range_pci1720 = { 4, { 175 UNI_RANGE(5), 176 UNI_RANGE(10), 177 BIP_RANGE(5), 178 BIP_RANGE(10) 179 } 180}; 181 182static const struct comedi_lrange range_pci171x_da = { 2, { 183 UNI_RANGE(5), 184 UNI_RANGE(10), 185 } 186}; 187 188static int pci1710_attach(struct comedi_device *dev, 189 struct comedi_devconfig *it); 190static int pci1710_detach(struct comedi_device *dev); 191 192struct boardtype { 193 const char *name; /* board name */ 194 int device_id; 195 int iorange; /* I/O range len */ 196 char have_irq; /* 1=card support IRQ */ 197 char cardtype; /* 0=1710& co. 2=1713, ... */ 198 int n_aichan; /* num of A/D chans */ 199 int n_aichand; /* num of A/D chans in diff mode */ 200 int n_aochan; /* num of D/A chans */ 201 int n_dichan; /* num of DI chans */ 202 int n_dochan; /* num of DO chans */ 203 int n_counter; /* num of counters */ 204 int ai_maxdata; /* resolution of A/D */ 205 int ao_maxdata; /* resolution of D/A */ 206 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ 207 const char *rangecode_ai; /* range codes for programming */ 208 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ 209 unsigned int ai_ns_min; /* max sample speed of card v ns */ 210 unsigned int fifo_half_size; /* size of FIFO/2 */ 211}; 212 213static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = { 214 { 215 PCI_VENDOR_ID_ADVANTECH, 0x1710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 216 PCI_VENDOR_ID_ADVANTECH, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 217 PCI_VENDOR_ID_ADVANTECH, 0x1713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 218 PCI_VENDOR_ID_ADVANTECH, 0x1720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 219 PCI_VENDOR_ID_ADVANTECH, 0x1731, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 220 0} 221}; 222 223MODULE_DEVICE_TABLE(pci, pci1710_pci_table); 224 225static const struct boardtype boardtypes[] = { 226 {"pci1710", 0x1710, 227 IORANGE_171x, 1, TYPE_PCI171X, 228 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff, 229 &range_pci1710_3, range_codes_pci1710_3, 230 &range_pci171x_da, 231 10000, 2048}, 232 {"pci1710hg", 0x1710, 233 IORANGE_171x, 1, TYPE_PCI171X, 234 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff, 235 &range_pci1710hg, range_codes_pci1710hg, 236 &range_pci171x_da, 237 10000, 2048}, 238 {"pci1711", 0x1711, 239 IORANGE_171x, 1, TYPE_PCI171X, 240 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff, 241 &range_pci17x1, range_codes_pci17x1, &range_pci171x_da, 242 10000, 512}, 243 {"pci1713", 0x1713, 244 IORANGE_171x, 1, TYPE_PCI1713, 245 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000, 246 &range_pci1710_3, range_codes_pci1710_3, NULL, 247 10000, 2048}, 248 {"pci1720", 0x1720, 249 IORANGE_1720, 0, TYPE_PCI1720, 250 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff, 251 NULL, NULL, &range_pci1720, 252 0, 0}, 253 {"pci1731", 0x1731, 254 IORANGE_171x, 1, TYPE_PCI171X, 255 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000, 256 &range_pci17x1, range_codes_pci17x1, NULL, 257 10000, 512}, 258 /* dummy entry corresponding to driver name */ 259 {.name = DRV_NAME}, 260}; 261 262#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) 263 264static struct comedi_driver driver_pci1710 = { 265 .driver_name = DRV_NAME, 266 .module = THIS_MODULE, 267 .attach = pci1710_attach, 268 .detach = pci1710_detach, 269 .num_names = n_boardtypes, 270 .board_name = &boardtypes[0].name, 271 .offset = sizeof(struct boardtype), 272}; 273 274struct pci1710_private { 275 struct pci_dev *pcidev; /* ptr to PCI device */ 276 char valid; /* card is usable */ 277 char neverending_ai; /* we do unlimited AI */ 278 unsigned int CntrlReg; /* Control register */ 279 unsigned int i8254_osc_base; /* frequence of onboard oscilator */ 280 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ 281 unsigned int ai_act_scan; /* how many scans we finished */ 282 unsigned int ai_act_chan; /* actual position in actual scan */ 283 unsigned int ai_buf_ptr; /* data buffer ptr in samples */ 284 unsigned char ai_eos; /* 1=EOS wake up */ 285 unsigned char ai_et; 286 unsigned int ai_et_CntrlReg; 287 unsigned int ai_et_MuxVal; 288 unsigned int ai_et_div1, ai_et_div2; 289 unsigned int act_chanlist[32]; /* list of scaned channel */ 290 unsigned char act_chanlist_len; /* len of scanlist */ 291 unsigned char act_chanlist_pos; /* actual position in MUX list */ 292 unsigned char da_ranges; /* copy of D/A outpit range register */ 293 unsigned int ai_scans; /* len of scanlist */ 294 unsigned int ai_n_chan; /* how many channels is measured */ 295 unsigned int *ai_chanlist; /* actaul chanlist */ 296 unsigned int ai_flags; /* flaglist */ 297 unsigned int ai_data_len; /* len of data buffer */ 298 short *ai_data; /* data buffer */ 299 unsigned int ai_timer1; /* timers */ 300 unsigned int ai_timer2; 301 short ao_data[4]; /* data output buffer */ 302 unsigned int cnt0_write_wait; /* after a write, wait for update of the internal state */ 303}; 304 305#define devpriv ((struct pci1710_private *)dev->private) 306#define this_board ((const struct boardtype *)dev->board_ptr) 307 308/* 309============================================================================== 310*/ 311 312static int check_channel_list(struct comedi_device *dev, 313 struct comedi_subdevice *s, 314 unsigned int *chanlist, unsigned int n_chan); 315static void setup_channel_list(struct comedi_device *dev, 316 struct comedi_subdevice *s, 317 unsigned int *chanlist, unsigned int n_chan, 318 unsigned int seglen); 319static void start_pacer(struct comedi_device *dev, int mode, 320 unsigned int divisor1, unsigned int divisor2); 321static int pci1710_reset(struct comedi_device *dev); 322static int pci171x_ai_cancel(struct comedi_device *dev, 323 struct comedi_subdevice *s); 324 325static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, /* used for gain list programming */ 326 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, 327 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, 328 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f 329}; 330 331/* 332============================================================================== 333*/ 334static int pci171x_insn_read_ai(struct comedi_device *dev, 335 struct comedi_subdevice *s, 336 struct comedi_insn *insn, unsigned int *data) 337{ 338 int n, timeout; 339#ifdef PCI171x_PARANOIDCHECK 340 unsigned int idata; 341#endif 342 343 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n"); 344 devpriv->CntrlReg &= Control_CNT0; 345 devpriv->CntrlReg |= Control_SW; /* set software trigger */ 346 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 347 outb(0, dev->iobase + PCI171x_CLRFIFO); 348 outb(0, dev->iobase + PCI171x_CLRINT); 349 350 setup_channel_list(dev, s, &insn->chanspec, 1, 1); 351 352 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n", 353 inw(dev->iobase + PCI171x_STATUS), 354 dev->iobase + PCI171x_STATUS); 355 for (n = 0; n < insn->n; n++) { 356 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ 357 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n, 358 inw(dev->iobase + PCI171x_STATUS)); 359 /* udelay(1); */ 360 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n, 361 inw(dev->iobase + PCI171x_STATUS)); 362 timeout = 100; 363 while (timeout--) { 364 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE)) 365 goto conv_finish; 366 if (!(timeout % 10)) 367 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n, 368 timeout, 369 inw(dev->iobase + PCI171x_STATUS)); 370 } 371 comedi_error(dev, "A/D insn timeout"); 372 outb(0, dev->iobase + PCI171x_CLRFIFO); 373 outb(0, dev->iobase + PCI171x_CLRINT); 374 data[n] = 0; 375 DPRINTK 376 ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", 377 n); 378 return -ETIME; 379 380conv_finish: 381#ifdef PCI171x_PARANOIDCHECK 382 idata = inw(dev->iobase + PCI171x_AD_DATA); 383 if (this_board->cardtype != TYPE_PCI1713) 384 if ((idata & 0xf000) != devpriv->act_chanlist[0]) { 385 comedi_error(dev, "A/D insn data droput!"); 386 return -ETIME; 387 } 388 data[n] = idata & 0x0fff; 389#else 390 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff; 391#endif 392 393 } 394 395 outb(0, dev->iobase + PCI171x_CLRFIFO); 396 outb(0, dev->iobase + PCI171x_CLRINT); 397 398 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n); 399 return n; 400} 401 402/* 403============================================================================== 404*/ 405static int pci171x_insn_write_ao(struct comedi_device *dev, 406 struct comedi_subdevice *s, 407 struct comedi_insn *insn, unsigned int *data) 408{ 409 int n, chan, range, ofs; 410 411 chan = CR_CHAN(insn->chanspec); 412 range = CR_RANGE(insn->chanspec); 413 if (chan) { 414 devpriv->da_ranges &= 0xfb; 415 devpriv->da_ranges |= (range << 2); 416 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); 417 ofs = PCI171x_DA2; 418 } else { 419 devpriv->da_ranges &= 0xfe; 420 devpriv->da_ranges |= range; 421 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); 422 ofs = PCI171x_DA1; 423 } 424 425 for (n = 0; n < insn->n; n++) 426 outw(data[n], dev->iobase + ofs); 427 428 devpriv->ao_data[chan] = data[n]; 429 430 return n; 431 432} 433 434/* 435============================================================================== 436*/ 437static int pci171x_insn_read_ao(struct comedi_device *dev, 438 struct comedi_subdevice *s, 439 struct comedi_insn *insn, unsigned int *data) 440{ 441 int n, chan; 442 443 chan = CR_CHAN(insn->chanspec); 444 for (n = 0; n < insn->n; n++) 445 data[n] = devpriv->ao_data[chan]; 446 447 return n; 448} 449 450/* 451============================================================================== 452*/ 453static int pci171x_insn_bits_di(struct comedi_device *dev, 454 struct comedi_subdevice *s, 455 struct comedi_insn *insn, unsigned int *data) 456{ 457 data[1] = inw(dev->iobase + PCI171x_DI); 458 459 return 2; 460} 461 462/* 463============================================================================== 464*/ 465static int pci171x_insn_bits_do(struct comedi_device *dev, 466 struct comedi_subdevice *s, 467 struct comedi_insn *insn, unsigned int *data) 468{ 469 if (data[0]) { 470 s->state &= ~data[0]; 471 s->state |= (data[0] & data[1]); 472 outw(s->state, dev->iobase + PCI171x_DO); 473 } 474 data[1] = s->state; 475 476 return 2; 477} 478 479/* 480============================================================================== 481*/ 482static int pci171x_insn_counter_read(struct comedi_device *dev, 483 struct comedi_subdevice *s, 484 struct comedi_insn *insn, 485 unsigned int *data) 486{ 487 unsigned int msb, lsb, ccntrl; 488 int i; 489 490 ccntrl = 0xD2; /* count only */ 491 for (i = 0; i < insn->n; i++) { 492 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL); 493 494 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF; 495 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF; 496 497 data[0] = lsb | (msb << 8); 498 } 499 500 return insn->n; 501} 502 503/* 504============================================================================== 505*/ 506static int pci171x_insn_counter_write(struct comedi_device *dev, 507 struct comedi_subdevice *s, 508 struct comedi_insn *insn, 509 unsigned int *data) 510{ 511 uint msb, lsb, ccntrl, status; 512 513 lsb = data[0] & 0x00FF; 514 msb = (data[0] & 0xFF00) >> 8; 515 516 /* write lsb, then msb */ 517 outw(lsb, dev->iobase + PCI171x_CNT0); 518 outw(msb, dev->iobase + PCI171x_CNT0); 519 520 if (devpriv->cnt0_write_wait) { 521 /* wait for the new count to be loaded */ 522 ccntrl = 0xE2; 523 do { 524 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL); 525 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF; 526 } while (status & 0x40); 527 } 528 529 return insn->n; 530} 531 532/* 533============================================================================== 534*/ 535static int pci171x_insn_counter_config(struct comedi_device *dev, 536 struct comedi_subdevice *s, 537 struct comedi_insn *insn, 538 unsigned int *data) 539{ 540#ifdef unused 541 /* This doesn't work like a normal Comedi counter config */ 542 uint ccntrl = 0; 543 544 devpriv->cnt0_write_wait = data[0] & 0x20; 545 546 /* internal or external clock? */ 547 if (!(data[0] & 0x10)) { /* internal */ 548 devpriv->CntrlReg &= ~Control_CNT0; 549 } else { 550 devpriv->CntrlReg |= Control_CNT0; 551 } 552 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 553 554 if (data[0] & 0x01) 555 ccntrl |= Counter_M0; 556 if (data[0] & 0x02) 557 ccntrl |= Counter_M1; 558 if (data[0] & 0x04) 559 ccntrl |= Counter_M2; 560 if (data[0] & 0x08) 561 ccntrl |= Counter_BCD; 562 ccntrl |= Counter_RW0; /* set read/write mode */ 563 ccntrl |= Counter_RW1; 564 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL); 565#endif 566 567 return 1; 568} 569 570/* 571============================================================================== 572*/ 573static int pci1720_insn_write_ao(struct comedi_device *dev, 574 struct comedi_subdevice *s, 575 struct comedi_insn *insn, unsigned int *data) 576{ 577 int n, rangereg, chan; 578 579 chan = CR_CHAN(insn->chanspec); 580 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1))); 581 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1)); 582 if (rangereg != devpriv->da_ranges) { 583 outb(rangereg, dev->iobase + PCI1720_RANGE); 584 devpriv->da_ranges = rangereg; 585 } 586 587 for (n = 0; n < insn->n; n++) { 588 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1)); 589 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ 590 } 591 592 devpriv->ao_data[chan] = data[n]; 593 594 return n; 595} 596 597/* 598============================================================================== 599*/ 600static void interrupt_pci1710_every_sample(void *d) 601{ 602 struct comedi_device *dev = d; 603 struct comedi_subdevice *s = dev->subdevices + 0; 604 int m; 605#ifdef PCI171x_PARANOIDCHECK 606 short sampl; 607#endif 608 609 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n"); 610 m = inw(dev->iobase + PCI171x_STATUS); 611 if (m & Status_FE) { 612 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m); 613 pci171x_ai_cancel(dev, s); 614 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 615 comedi_event(dev, s); 616 return; 617 } 618 if (m & Status_FF) { 619 printk 620 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n", 621 dev->minor, m); 622 pci171x_ai_cancel(dev, s); 623 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 624 comedi_event(dev, s); 625 return; 626 } 627 628 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ 629 630 DPRINTK("FOR "); 631 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { 632#ifdef PCI171x_PARANOIDCHECK 633 sampl = inw(dev->iobase + PCI171x_AD_DATA); 634 DPRINTK("%04x:", sampl); 635 if (this_board->cardtype != TYPE_PCI1713) 636 if ((sampl & 0xf000) != 637 devpriv->act_chanlist[s->async->cur_chan]) { 638 printk 639 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n", 640 (sampl & 0xf000) >> 12, 641 (devpriv-> 642 act_chanlist[s-> 643 async->cur_chan] & 0xf000) >> 644 12); 645 pci171x_ai_cancel(dev, s); 646 s->async->events |= 647 COMEDI_CB_EOA | COMEDI_CB_ERROR; 648 comedi_event(dev, s); 649 return; 650 } 651 DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr, 652 s->async->cur_chan, s->async->buf_int_count); 653 comedi_buf_put(s->async, sampl & 0x0fff); 654#else 655 comedi_buf_put(s->async, 656 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff); 657#endif 658 ++s->async->cur_chan; 659 660 if (s->async->cur_chan >= devpriv->ai_n_chan) { 661 s->async->cur_chan = 0; 662 } 663 664 if (s->async->cur_chan == 0) { /* one scan done */ 665 devpriv->ai_act_scan++; 666 DPRINTK 667 ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n", 668 s->async->buf_int_count, s->async->buf_int_ptr, 669 s->async->buf_user_count, s->async->buf_user_ptr); 670 DPRINTK("adv_pci1710 EDBG: EOS2\n"); 671 if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */ 672 pci171x_ai_cancel(dev, s); 673 s->async->events |= COMEDI_CB_EOA; 674 comedi_event(dev, s); 675 return; 676 } 677 } 678 } 679 680 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ 681 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n"); 682 683 comedi_event(dev, s); 684} 685 686/* 687============================================================================== 688*/ 689static int move_block_from_fifo(struct comedi_device *dev, 690 struct comedi_subdevice *s, int n, int turn) 691{ 692 int i, j; 693#ifdef PCI171x_PARANOIDCHECK 694 int sampl; 695#endif 696 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n, 697 turn); 698 j = s->async->cur_chan; 699 for (i = 0; i < n; i++) { 700#ifdef PCI171x_PARANOIDCHECK 701 sampl = inw(dev->iobase + PCI171x_AD_DATA); 702 if (this_board->cardtype != TYPE_PCI1713) 703 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) { 704 printk 705 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n", 706 dev->minor, (sampl & 0xf000) >> 12, 707 (devpriv->act_chanlist[j] & 0xf000) >> 12, 708 i, j, devpriv->ai_act_scan, n, turn, 709 sampl); 710 pci171x_ai_cancel(dev, s); 711 s->async->events |= 712 COMEDI_CB_EOA | COMEDI_CB_ERROR; 713 comedi_event(dev, s); 714 return 1; 715 } 716 comedi_buf_put(s->async, sampl & 0x0fff); 717#else 718 comedi_buf_put(s->async, 719 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff); 720#endif 721 j++; 722 if (j >= devpriv->ai_n_chan) { 723 j = 0; 724 devpriv->ai_act_scan++; 725 } 726 } 727 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n"); 728 return 0; 729} 730 731/* 732============================================================================== 733*/ 734static void interrupt_pci1710_half_fifo(void *d) 735{ 736 struct comedi_device *dev = d; 737 struct comedi_subdevice *s = dev->subdevices + 0; 738 int m, samplesinbuf; 739 740 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n"); 741 m = inw(dev->iobase + PCI171x_STATUS); 742 if (!(m & Status_FH)) { 743 printk("comedi%d: A/D FIFO not half full! (%4x)\n", 744 dev->minor, m); 745 pci171x_ai_cancel(dev, s); 746 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 747 comedi_event(dev, s); 748 return; 749 } 750 if (m & Status_FF) { 751 printk 752 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n", 753 dev->minor, m); 754 pci171x_ai_cancel(dev, s); 755 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 756 comedi_event(dev, s); 757 return; 758 } 759 760 samplesinbuf = this_board->fifo_half_size; 761 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) { 762 m = devpriv->ai_data_len / sizeof(short); 763 if (move_block_from_fifo(dev, s, m, 0)) 764 return; 765 samplesinbuf -= m; 766 } 767 768 if (samplesinbuf) { 769 if (move_block_from_fifo(dev, s, samplesinbuf, 1)) 770 return; 771 } 772 773 if (!devpriv->neverending_ai) 774 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 775 pci171x_ai_cancel(dev, s); 776 s->async->events |= COMEDI_CB_EOA; 777 comedi_event(dev, s); 778 return; 779 } 780 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ 781 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n"); 782 783 comedi_event(dev, s); 784} 785 786/* 787============================================================================== 788*/ 789static irqreturn_t interrupt_service_pci1710(int irq, void *d) 790{ 791 struct comedi_device *dev = d; 792 793 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n", 794 irq); 795 if (!dev->attached) /* is device attached? */ 796 return IRQ_NONE; /* no, exit */ 797 798 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */ 799 return IRQ_NONE; /* no, exit */ 800 801 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n", 802 inw(dev->iobase + PCI171x_STATUS)); 803 804 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ 805 devpriv->ai_et = 0; 806 devpriv->CntrlReg &= Control_CNT0; 807 devpriv->CntrlReg |= Control_SW; /* set software trigger */ 808 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 809 devpriv->CntrlReg = devpriv->ai_et_CntrlReg; 810 outb(0, dev->iobase + PCI171x_CLRFIFO); 811 outb(0, dev->iobase + PCI171x_CLRINT); 812 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); 813 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 814 /* start pacer */ 815 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2); 816 return IRQ_HANDLED; 817 } 818 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */ 819 interrupt_pci1710_every_sample(d); 820 } else { 821 interrupt_pci1710_half_fifo(d); 822 } 823 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n"); 824 return IRQ_HANDLED; 825} 826 827/* 828============================================================================== 829*/ 830static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, 831 struct comedi_subdevice *s) 832{ 833 unsigned int divisor1, divisor2; 834 unsigned int seglen; 835 836 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n", 837 mode); 838 start_pacer(dev, -1, 0, 0); /* stop pacer */ 839 840 seglen = check_channel_list(dev, s, devpriv->ai_chanlist, 841 devpriv->ai_n_chan); 842 if (seglen < 1) 843 return -EINVAL; 844 setup_channel_list(dev, s, devpriv->ai_chanlist, 845 devpriv->ai_n_chan, seglen); 846 847 outb(0, dev->iobase + PCI171x_CLRFIFO); 848 outb(0, dev->iobase + PCI171x_CLRINT); 849 850 devpriv->ai_do = mode; 851 852 devpriv->ai_act_scan = 0; 853 s->async->cur_chan = 0; 854 devpriv->ai_buf_ptr = 0; 855 devpriv->neverending_ai = 0; 856 857 devpriv->CntrlReg &= Control_CNT0; 858 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */ 859 devpriv->ai_eos = 1; 860 } else { 861 devpriv->CntrlReg |= Control_ONEFH; 862 devpriv->ai_eos = 0; 863 } 864 865 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) { 866 devpriv->neverending_ai = 1; 867 } /* well, user want neverending */ 868 else { 869 devpriv->neverending_ai = 0; 870 } 871 switch (mode) { 872 case 1: 873 case 2: 874 if (devpriv->ai_timer1 < this_board->ai_ns_min) 875 devpriv->ai_timer1 = this_board->ai_ns_min; 876 devpriv->CntrlReg |= Control_PACER | Control_IRQEN; 877 if (mode == 2) { 878 devpriv->ai_et_CntrlReg = devpriv->CntrlReg; 879 devpriv->CntrlReg &= 880 ~(Control_PACER | Control_ONEFH | Control_GATE); 881 devpriv->CntrlReg |= Control_EXT; 882 devpriv->ai_et = 1; 883 } else { 884 devpriv->ai_et = 0; 885 } 886 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, 887 &divisor2, &devpriv->ai_timer1, 888 devpriv->ai_flags & TRIG_ROUND_MASK); 889 DPRINTK 890 ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n", 891 devpriv->i8254_osc_base, divisor1, divisor2, 892 devpriv->ai_timer1); 893 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 894 if (mode != 2) { 895 /* start pacer */ 896 start_pacer(dev, mode, divisor1, divisor2); 897 } else { 898 devpriv->ai_et_div1 = divisor1; 899 devpriv->ai_et_div2 = divisor2; 900 } 901 break; 902 case 3: 903 devpriv->CntrlReg |= Control_EXT | Control_IRQEN; 904 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); 905 break; 906 } 907 908 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n"); 909 return 0; 910} 911 912#ifdef PCI171X_EXTDEBUG 913/* 914============================================================================== 915*/ 916static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd) 917{ 918 printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, 919 cmd->start_src, cmd->scan_begin_src, cmd->convert_src); 920 printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e, 921 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); 922 printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, 923 cmd->scan_end_src); 924 printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", 925 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); 926} 927#endif 928 929/* 930============================================================================== 931*/ 932static int pci171x_ai_cmdtest(struct comedi_device *dev, 933 struct comedi_subdevice *s, 934 struct comedi_cmd *cmd) 935{ 936 int err = 0; 937 int tmp, divisor1, divisor2; 938 939 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n"); 940#ifdef PCI171X_EXTDEBUG 941 pci171x_cmdtest_out(-1, cmd); 942#endif 943 /* step 1: make sure trigger sources are trivially valid */ 944 945 tmp = cmd->start_src; 946 cmd->start_src &= TRIG_NOW | TRIG_EXT; 947 if (!cmd->start_src || tmp != cmd->start_src) 948 err++; 949 950 tmp = cmd->scan_begin_src; 951 cmd->scan_begin_src &= TRIG_FOLLOW; 952 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 953 err++; 954 955 tmp = cmd->convert_src; 956 cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 957 if (!cmd->convert_src || tmp != cmd->convert_src) 958 err++; 959 960 tmp = cmd->scan_end_src; 961 cmd->scan_end_src &= TRIG_COUNT; 962 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 963 err++; 964 965 tmp = cmd->stop_src; 966 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 967 if (!cmd->stop_src || tmp != cmd->stop_src) 968 err++; 969 970 if (err) { 971#ifdef PCI171X_EXTDEBUG 972 pci171x_cmdtest_out(1, cmd); 973#endif 974 DPRINTK 975 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n", 976 err); 977 return 1; 978 } 979 980 /* step 2: make sure trigger sources are unique and mutually compatible */ 981 982 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) { 983 cmd->start_src = TRIG_NOW; 984 err++; 985 } 986 987 if (cmd->scan_begin_src != TRIG_FOLLOW) { 988 cmd->scan_begin_src = TRIG_FOLLOW; 989 err++; 990 } 991 992 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 993 err++; 994 995 if (cmd->scan_end_src != TRIG_COUNT) { 996 cmd->scan_end_src = TRIG_COUNT; 997 err++; 998 } 999 1000 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) 1001 err++; 1002 1003 if (err) { 1004#ifdef PCI171X_EXTDEBUG 1005 pci171x_cmdtest_out(2, cmd); 1006#endif 1007 DPRINTK 1008 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n", 1009 err); 1010 return 2; 1011 } 1012 1013 /* step 3: make sure arguments are trivially compatible */ 1014 1015 if (cmd->start_arg != 0) { 1016 cmd->start_arg = 0; 1017 err++; 1018 } 1019 1020 if (cmd->scan_begin_arg != 0) { 1021 cmd->scan_begin_arg = 0; 1022 err++; 1023 } 1024 1025 if (cmd->convert_src == TRIG_TIMER) { 1026 if (cmd->convert_arg < this_board->ai_ns_min) { 1027 cmd->convert_arg = this_board->ai_ns_min; 1028 err++; 1029 } 1030 } else { /* TRIG_FOLLOW */ 1031 if (cmd->convert_arg != 0) { 1032 cmd->convert_arg = 0; 1033 err++; 1034 } 1035 } 1036 1037 if (!cmd->chanlist_len) { 1038 cmd->chanlist_len = 1; 1039 err++; 1040 } 1041 if (cmd->chanlist_len > this_board->n_aichan) { 1042 cmd->chanlist_len = this_board->n_aichan; 1043 err++; 1044 } 1045 if (cmd->scan_end_arg != cmd->chanlist_len) { 1046 cmd->scan_end_arg = cmd->chanlist_len; 1047 err++; 1048 } 1049 if (cmd->stop_src == TRIG_COUNT) { 1050 if (!cmd->stop_arg) { 1051 cmd->stop_arg = 1; 1052 err++; 1053 } 1054 } else { /* TRIG_NONE */ 1055 if (cmd->stop_arg != 0) { 1056 cmd->stop_arg = 0; 1057 err++; 1058 } 1059 } 1060 1061 if (err) { 1062#ifdef PCI171X_EXTDEBUG 1063 pci171x_cmdtest_out(3, cmd); 1064#endif 1065 DPRINTK 1066 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n", 1067 err); 1068 return 3; 1069 } 1070 1071 /* step 4: fix up any arguments */ 1072 1073 if (cmd->convert_src == TRIG_TIMER) { 1074 tmp = cmd->convert_arg; 1075 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, 1076 &divisor2, &cmd->convert_arg, 1077 cmd->flags & TRIG_ROUND_MASK); 1078 if (cmd->convert_arg < this_board->ai_ns_min) 1079 cmd->convert_arg = this_board->ai_ns_min; 1080 if (tmp != cmd->convert_arg) 1081 err++; 1082 } 1083 1084 if (err) { 1085 DPRINTK 1086 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n", 1087 err); 1088 return 4; 1089 } 1090 1091 /* step 5: complain about special chanlist considerations */ 1092 1093 if (cmd->chanlist) { 1094 if (!check_channel_list(dev, s, cmd->chanlist, 1095 cmd->chanlist_len)) 1096 return 5; /* incorrect channels list */ 1097 } 1098 1099 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n"); 1100 return 0; 1101} 1102 1103/* 1104============================================================================== 1105*/ 1106static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 1107{ 1108 struct comedi_cmd *cmd = &s->async->cmd; 1109 1110 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n"); 1111 devpriv->ai_n_chan = cmd->chanlist_len; 1112 devpriv->ai_chanlist = cmd->chanlist; 1113 devpriv->ai_flags = cmd->flags; 1114 devpriv->ai_data_len = s->async->prealloc_bufsz; 1115 devpriv->ai_data = s->async->prealloc_buf; 1116 devpriv->ai_timer1 = 0; 1117 devpriv->ai_timer2 = 0; 1118 1119 if (cmd->stop_src == TRIG_COUNT) { 1120 devpriv->ai_scans = cmd->stop_arg; 1121 } else { 1122 devpriv->ai_scans = 0; 1123 } 1124 1125 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */ 1126 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */ 1127 devpriv->ai_timer1 = cmd->convert_arg; 1128 return pci171x_ai_docmd_and_mode(cmd->start_src == 1129 TRIG_EXT ? 2 : 1, dev, 1130 s); 1131 } 1132 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ 1133 return pci171x_ai_docmd_and_mode(3, dev, s); 1134 } 1135 } 1136 1137 return -1; 1138} 1139 1140/* 1141============================================================================== 1142 Check if channel list from user is builded correctly 1143 If it's ok, then program scan/gain logic. 1144 This works for all cards. 1145*/ 1146static int check_channel_list(struct comedi_device *dev, 1147 struct comedi_subdevice *s, 1148 unsigned int *chanlist, unsigned int n_chan) 1149{ 1150 unsigned int chansegment[32]; 1151 unsigned int i, nowmustbechan, seglen, segpos; 1152 1153 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan); 1154 /* correct channel and range number check itself comedi/range.c */ 1155 if (n_chan < 1) { 1156 comedi_error(dev, "range/channel list is empty!"); 1157 return 0; 1158 } 1159 1160 if (n_chan > 1) { 1161 chansegment[0] = chanlist[0]; /* first channel is everytime ok */ 1162 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */ 1163 /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */ 1164 if (chanlist[0] == chanlist[i]) 1165 break; /* we detect loop, this must by finish */ 1166 if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */ 1167 if (CR_AREF(chanlist[i]) == AREF_DIFF) { 1168 comedi_error(dev, 1169 "Odd channel can't be differential input!\n"); 1170 return 0; 1171 } 1172 nowmustbechan = 1173 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; 1174 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF) 1175 nowmustbechan = (nowmustbechan + 1) % s->n_chan; 1176 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */ 1177 printk 1178 ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", 1179 i, CR_CHAN(chanlist[i]), nowmustbechan, 1180 CR_CHAN(chanlist[0])); 1181 return 0; 1182 } 1183 chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */ 1184 } 1185 1186 for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */ 1187 /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */ 1188 if (chanlist[i] != chansegment[i % seglen]) { 1189 printk 1190 ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", 1191 i, CR_CHAN(chansegment[i]), 1192 CR_RANGE(chansegment[i]), 1193 CR_AREF(chansegment[i]), 1194 CR_CHAN(chanlist[i % seglen]), 1195 CR_RANGE(chanlist[i % seglen]), 1196 CR_AREF(chansegment[i % seglen])); 1197 return 0; /* chan/gain list is strange */ 1198 } 1199 } 1200 } else { 1201 seglen = 1; 1202 } 1203 return seglen; 1204} 1205 1206static void setup_channel_list(struct comedi_device *dev, 1207 struct comedi_subdevice *s, 1208 unsigned int *chanlist, unsigned int n_chan, 1209 unsigned int seglen) 1210{ 1211 unsigned int i, range, chanprog; 1212 1213 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan, 1214 seglen); 1215 devpriv->act_chanlist_len = seglen; 1216 devpriv->act_chanlist_pos = 0; 1217 1218 DPRINTK("SegLen: %d\n", seglen); 1219 for (i = 0; i < seglen; i++) { /* store range list to card */ 1220 chanprog = muxonechan[CR_CHAN(chanlist[i])]; 1221 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ 1222 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; 1223 if (CR_AREF(chanlist[i]) == AREF_DIFF) 1224 range |= 0x0020; 1225 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ 1226#ifdef PCI171x_PARANOIDCHECK 1227 devpriv->act_chanlist[i] = 1228 (CR_CHAN(chanlist[i]) << 12) & 0xf000; 1229#endif 1230 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, 1231 devpriv->act_chanlist[i]); 1232 } 1233 1234 devpriv->ai_et_MuxVal = 1235 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); 1236 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */ 1237 DPRINTK("MUX: %4x L%4x.H%4x\n", 1238 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8), 1239 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1])); 1240} 1241 1242/* 1243============================================================================== 1244*/ 1245static void start_pacer(struct comedi_device *dev, int mode, 1246 unsigned int divisor1, unsigned int divisor2) 1247{ 1248 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, 1249 divisor1, divisor2); 1250 outw(0xb4, dev->iobase + PCI171x_CNTCTRL); 1251 outw(0x74, dev->iobase + PCI171x_CNTCTRL); 1252 1253 if (mode == 1) { 1254 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2); 1255 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2); 1256 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1); 1257 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1); 1258 } 1259 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n"); 1260} 1261 1262/* 1263============================================================================== 1264*/ 1265static int pci171x_ai_cancel(struct comedi_device *dev, 1266 struct comedi_subdevice *s) 1267{ 1268 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n"); 1269 1270 switch (this_board->cardtype) { 1271 default: 1272 devpriv->CntrlReg &= Control_CNT0; 1273 devpriv->CntrlReg |= Control_SW; 1274 1275 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ 1276 start_pacer(dev, -1, 0, 0); 1277 outb(0, dev->iobase + PCI171x_CLRFIFO); 1278 outb(0, dev->iobase + PCI171x_CLRINT); 1279 break; 1280 } 1281 1282 devpriv->ai_do = 0; 1283 devpriv->ai_act_scan = 0; 1284 s->async->cur_chan = 0; 1285 devpriv->ai_buf_ptr = 0; 1286 devpriv->neverending_ai = 0; 1287 1288 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n"); 1289 return 0; 1290} 1291 1292/* 1293============================================================================== 1294*/ 1295static int pci171x_reset(struct comedi_device *dev) 1296{ 1297 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n"); 1298 outw(0x30, dev->iobase + PCI171x_CNTCTRL); 1299 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */ 1300 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ 1301 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ 1302 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ 1303 start_pacer(dev, -1, 0, 0); /* stop 8254 */ 1304 devpriv->da_ranges = 0; 1305 if (this_board->n_aochan) { 1306 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */ 1307 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */ 1308 devpriv->ao_data[0] = 0x0000; 1309 if (this_board->n_aochan > 1) { 1310 outw(0, dev->iobase + PCI171x_DA2); 1311 devpriv->ao_data[1] = 0x0000; 1312 } 1313 } 1314 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */ 1315 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ 1316 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ 1317 1318 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n"); 1319 return 0; 1320} 1321 1322/* 1323============================================================================== 1324*/ 1325static int pci1720_reset(struct comedi_device *dev) 1326{ 1327 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n"); 1328 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */ 1329 devpriv->da_ranges = 0xAA; 1330 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */ 1331 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */ 1332 outw(0x0800, dev->iobase + PCI1720_DA1); 1333 outw(0x0800, dev->iobase + PCI1720_DA2); 1334 outw(0x0800, dev->iobase + PCI1720_DA3); 1335 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ 1336 devpriv->ao_data[0] = 0x0800; 1337 devpriv->ao_data[1] = 0x0800; 1338 devpriv->ao_data[2] = 0x0800; 1339 devpriv->ao_data[3] = 0x0800; 1340 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n"); 1341 return 0; 1342} 1343 1344/* 1345============================================================================== 1346*/ 1347static int pci1710_reset(struct comedi_device *dev) 1348{ 1349 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n"); 1350 switch (this_board->cardtype) { 1351 case TYPE_PCI1720: 1352 return pci1720_reset(dev); 1353 default: 1354 return pci171x_reset(dev); 1355 } 1356 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n"); 1357} 1358 1359/* 1360============================================================================== 1361*/ 1362static int pci1710_attach(struct comedi_device *dev, 1363 struct comedi_devconfig *it) 1364{ 1365 struct comedi_subdevice *s; 1366 int ret, subdev, n_subdevices; 1367 unsigned int irq; 1368 unsigned long iobase; 1369 struct pci_dev *pcidev; 1370 int opt_bus, opt_slot; 1371 const char *errstr; 1372 unsigned char pci_bus, pci_slot, pci_func; 1373 int i; 1374 int board_index; 1375 1376 printk("comedi%d: adv_pci1710: ", dev->minor); 1377 1378 opt_bus = it->options[0]; 1379 opt_slot = it->options[1]; 1380 1381 ret = alloc_private(dev, sizeof(struct pci1710_private)); 1382 if (ret < 0) { 1383 printk(" - Allocation failed!\n"); 1384 return -ENOMEM; 1385 } 1386 1387 /* Look for matching PCI device */ 1388 errstr = "not found!"; 1389 pcidev = NULL; 1390 board_index = this_board - boardtypes; 1391 while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH, 1392 PCI_ANY_ID, pcidev))) { 1393 if (strcmp(this_board->name, DRV_NAME) == 0) { 1394 for (i = 0; i < n_boardtypes; ++i) { 1395 if (pcidev->device == boardtypes[i].device_id) { 1396 board_index = i; 1397 break; 1398 } 1399 } 1400 if (i == n_boardtypes) 1401 continue; 1402 } else { 1403 if (pcidev->device != boardtypes[board_index].device_id) 1404 continue; 1405 } 1406 1407 /* Found matching vendor/device. */ 1408 if (opt_bus || opt_slot) { 1409 /* Check bus/slot. */ 1410 if (opt_bus != pcidev->bus->number 1411 || opt_slot != PCI_SLOT(pcidev->devfn)) 1412 continue; /* no match */ 1413 } 1414 /* 1415 * Look for device that isn't in use. 1416 * Enable PCI device and request regions. 1417 */ 1418 if (comedi_pci_enable(pcidev, DRV_NAME)) { 1419 errstr = 1420 "failed to enable PCI device and request regions!"; 1421 continue; 1422 } 1423 /* fixup board_ptr in case we were using the dummy entry with the driver name */ 1424 dev->board_ptr = &boardtypes[board_index]; 1425 break; 1426 } 1427 1428 if (!pcidev) { 1429 if (opt_bus || opt_slot) { 1430 printk(" - Card at b:s %d:%d %s\n", 1431 opt_bus, opt_slot, errstr); 1432 } else { 1433 printk(" - Card %s\n", errstr); 1434 } 1435 return -EIO; 1436 } 1437 1438 pci_bus = pcidev->bus->number; 1439 pci_slot = PCI_SLOT(pcidev->devfn); 1440 pci_func = PCI_FUNC(pcidev->devfn); 1441 irq = pcidev->irq; 1442 iobase = pci_resource_start(pcidev, 2); 1443 1444 printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func, 1445 iobase); 1446 1447 dev->iobase = iobase; 1448 1449 dev->board_name = this_board->name; 1450 devpriv->pcidev = pcidev; 1451 1452 n_subdevices = 0; 1453 if (this_board->n_aichan) 1454 n_subdevices++; 1455 if (this_board->n_aochan) 1456 n_subdevices++; 1457 if (this_board->n_dichan) 1458 n_subdevices++; 1459 if (this_board->n_dochan) 1460 n_subdevices++; 1461 if (this_board->n_counter) 1462 n_subdevices++; 1463 1464 ret = alloc_subdevices(dev, n_subdevices); 1465 if (ret < 0) { 1466 printk(" - Allocation failed!\n"); 1467 return ret; 1468 } 1469 1470 pci1710_reset(dev); 1471 1472 if (this_board->have_irq) { 1473 if (irq) { 1474 if (request_irq(irq, interrupt_service_pci1710, 1475 IRQF_SHARED, "Advantech PCI-1710", 1476 dev)) { 1477 printk 1478 (", unable to allocate IRQ %d, DISABLING IT", 1479 irq); 1480 irq = 0; /* Can't use IRQ */ 1481 } else { 1482 printk(", irq=%u", irq); 1483 } 1484 } else { 1485 printk(", IRQ disabled"); 1486 } 1487 } else { 1488 irq = 0; 1489 } 1490 1491 dev->irq = irq; 1492 1493 printk(".\n"); 1494 1495 subdev = 0; 1496 1497 if (this_board->n_aichan) { 1498 s = dev->subdevices + subdev; 1499 dev->read_subdev = s; 1500 s->type = COMEDI_SUBD_AI; 1501 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; 1502 if (this_board->n_aichand) 1503 s->subdev_flags |= SDF_DIFF; 1504 s->n_chan = this_board->n_aichan; 1505 s->maxdata = this_board->ai_maxdata; 1506 s->len_chanlist = this_board->n_aichan; 1507 s->range_table = this_board->rangelist_ai; 1508 s->cancel = pci171x_ai_cancel; 1509 s->insn_read = pci171x_insn_read_ai; 1510 if (irq) { 1511 s->subdev_flags |= SDF_CMD_READ; 1512 s->do_cmdtest = pci171x_ai_cmdtest; 1513 s->do_cmd = pci171x_ai_cmd; 1514 } 1515 devpriv->i8254_osc_base = 100; /* 100ns=10MHz */ 1516 subdev++; 1517 } 1518 1519 if (this_board->n_aochan) { 1520 s = dev->subdevices + subdev; 1521 s->type = COMEDI_SUBD_AO; 1522 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 1523 s->n_chan = this_board->n_aochan; 1524 s->maxdata = this_board->ao_maxdata; 1525 s->len_chanlist = this_board->n_aochan; 1526 s->range_table = this_board->rangelist_ao; 1527 switch (this_board->cardtype) { 1528 case TYPE_PCI1720: 1529 s->insn_write = pci1720_insn_write_ao; 1530 break; 1531 default: 1532 s->insn_write = pci171x_insn_write_ao; 1533 break; 1534 } 1535 s->insn_read = pci171x_insn_read_ao; 1536 subdev++; 1537 } 1538 1539 if (this_board->n_dichan) { 1540 s = dev->subdevices + subdev; 1541 s->type = COMEDI_SUBD_DI; 1542 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; 1543 s->n_chan = this_board->n_dichan; 1544 s->maxdata = 1; 1545 s->len_chanlist = this_board->n_dichan; 1546 s->range_table = &range_digital; 1547 s->io_bits = 0; /* all bits input */ 1548 s->insn_bits = pci171x_insn_bits_di; 1549 subdev++; 1550 } 1551 1552 if (this_board->n_dochan) { 1553 s = dev->subdevices + subdev; 1554 s->type = COMEDI_SUBD_DO; 1555 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 1556 s->n_chan = this_board->n_dochan; 1557 s->maxdata = 1; 1558 s->len_chanlist = this_board->n_dochan; 1559 s->range_table = &range_digital; 1560 s->io_bits = (1 << this_board->n_dochan) - 1; /* all bits output */ 1561 s->state = 0; 1562 s->insn_bits = pci171x_insn_bits_do; 1563 subdev++; 1564 } 1565 1566 if (this_board->n_counter) { 1567 s = dev->subdevices + subdev; 1568 s->type = COMEDI_SUBD_COUNTER; 1569 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 1570 s->n_chan = this_board->n_counter; 1571 s->len_chanlist = this_board->n_counter; 1572 s->maxdata = 0xffff; 1573 s->range_table = &range_unknown; 1574 s->insn_read = pci171x_insn_counter_read; 1575 s->insn_write = pci171x_insn_counter_write; 1576 s->insn_config = pci171x_insn_counter_config; 1577 subdev++; 1578 } 1579 1580 devpriv->valid = 1; 1581 1582 return 0; 1583} 1584 1585/* 1586============================================================================== 1587*/ 1588static int pci1710_detach(struct comedi_device *dev) 1589{ 1590 1591 if (dev->private) { 1592 if (devpriv->valid) 1593 pci1710_reset(dev); 1594 if (dev->irq) 1595 free_irq(dev->irq, dev); 1596 if (devpriv->pcidev) { 1597 if (dev->iobase) { 1598 comedi_pci_disable(devpriv->pcidev); 1599 } 1600 pci_dev_put(devpriv->pcidev); 1601 } 1602 } 1603 1604 return 0; 1605} 1606 1607/* 1608============================================================================== 1609*/ 1610COMEDI_PCI_INITCLEANUP(driver_pci1710, pci1710_pci_table); 1611/* 1612============================================================================== 1613*/ 1614