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