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