pcl816.c revision efdf83c1763156220a74c8f2755c1a6fa1e1c26b
1/* 2 comedi/drivers/pcl816.c 3 4 Author: Juan Grigera <juan@grigera.com.ar> 5 based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812 6 7 hardware driver for Advantech cards: 8 card: PCL-816, PCL814B 9 driver: pcl816 10*/ 11/* 12Driver: pcl816 13Description: Advantech PCL-816 cards, PCL-814 14Author: Juan Grigera <juan@grigera.com.ar> 15Devices: [Advantech] PCL-816 (pcl816), PCL-814B (pcl814b) 16Status: works 17Updated: Tue, 2 Apr 2002 23:15:21 -0800 18 19PCL 816 and 814B have 16 SE/DIFF ADCs, 16 DACs, 16 DI and 16 DO. 20Differences are at resolution (16 vs 12 bits). 21 22The driver support AI command mode, other subdevices not written. 23 24Analog output and digital input and output are not supported. 25 26Configuration Options: 27 [0] - IO Base 28 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) 29 [2] - DMA (0=disable, 1, 3) 30 [3] - 0, 10=10MHz clock for 8254 31 1= 1MHz clock for 8254 32 33*/ 34 35#include "../comedidev.h" 36 37#include <linux/ioport.h> 38#include <linux/mc146818rtc.h> 39#include <linux/delay.h> 40#include <asm/dma.h> 41 42#include "8253.h" 43 44#define DEBUG(x) x 45 46/* boards constants */ 47/* IO space len */ 48#define PCLx1x_RANGE 16 49 50/* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */ 51 52/* INTEL 8254 counters */ 53#define PCL816_CTR0 4 54#define PCL816_CTR1 5 55#define PCL816_CTR2 6 56/* R: counter read-back register W: counter control */ 57#define PCL816_CTRCTL 7 58 59/* R: A/D high byte W: A/D range control */ 60#define PCL816_RANGE 9 61/* W: clear INT request */ 62#define PCL816_CLRINT 10 63/* R: next mux scan channel W: mux scan channel & range control pointer */ 64#define PCL816_MUX 11 65/* R/W: operation control register */ 66#define PCL816_CONTROL 12 67 68/* R: return status byte W: set DMA/IRQ */ 69#define PCL816_STATUS 13 70#define PCL816_STATUS_DRDY_MASK 0x80 71 72/* R: low byte of A/D W: soft A/D trigger */ 73#define PCL816_AD_LO 8 74/* R: high byte of A/D W: A/D range control */ 75#define PCL816_AD_HI 9 76 77/* type of interrupt handler */ 78#define INT_TYPE_AI1_INT 1 79#define INT_TYPE_AI1_DMA 2 80#define INT_TYPE_AI3_INT 4 81#define INT_TYPE_AI3_DMA 5 82#ifdef unused 83#define INT_TYPE_AI1_DMA_RTC 9 84#define INT_TYPE_AI3_DMA_RTC 10 85 86/* RTC stuff... */ 87#define RTC_IRQ 8 88#define RTC_IO_EXTENT 0x10 89#endif 90 91#define MAGIC_DMA_WORD 0x5a5a 92 93static const struct comedi_lrange range_pcl816 = { 8, { 94 BIP_RANGE(10), 95 BIP_RANGE(5), 96 BIP_RANGE(2.5), 97 BIP_RANGE(1.25), 98 UNI_RANGE(10), 99 UNI_RANGE(5), 100 UNI_RANGE(2.5), 101 UNI_RANGE(1.25), 102 } 103}; 104 105struct pcl816_board { 106 107 const char *name; /* board name */ 108 int n_ranges; /* len of range list */ 109 int n_aichan; /* num of A/D chans in diferencial mode */ 110 unsigned int ai_ns_min; /* minimal alllowed delay between samples (in ns) */ 111 int n_aochan; /* num of D/A chans */ 112 int n_dichan; /* num of DI chans */ 113 int n_dochan; /* num of DO chans */ 114 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ 115 const struct comedi_lrange *ao_range_type; /* dafault D/A rangelist */ 116 unsigned int io_range; /* len of IO space */ 117 unsigned int IRQbits; /* allowed interrupts */ 118 unsigned int DMAbits; /* allowed DMA chans */ 119 int ai_maxdata; /* maxdata for A/D */ 120 int ao_maxdata; /* maxdata for D/A */ 121 int ai_chanlist; /* allowed len of channel list A/D */ 122 int ao_chanlist; /* allowed len of channel list D/A */ 123 int i8254_osc_base; /* 1/frequency of on board oscilator in ns */ 124}; 125 126static const struct pcl816_board boardtypes[] = { 127 {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, 128 &range_pcl816, PCLx1x_RANGE, 129 0x00fc, /* IRQ mask */ 130 0x0a, /* DMA mask */ 131 0xffff, /* 16-bit card */ 132 0xffff, /* D/A maxdata */ 133 1024, 134 1, /* ao chan list */ 135 100}, 136 {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, 137 &range_pcl816, PCLx1x_RANGE, 138 0x00fc, 139 0x0a, 140 0x3fff, /* 14 bit card */ 141 0x3fff, 142 1024, 143 1, 144 100}, 145}; 146 147#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board)) 148#define devpriv ((struct pcl816_private *)dev->private) 149#define this_board ((const struct pcl816_board *)dev->board_ptr) 150 151static int pcl816_attach(struct comedi_device *dev, 152 struct comedi_devconfig *it); 153static int pcl816_detach(struct comedi_device *dev); 154 155#ifdef unused 156static int RTC_lock = 0; /* RTC lock */ 157static int RTC_timer_lock = 0; /* RTC int lock */ 158#endif 159 160static struct comedi_driver driver_pcl816 = { 161 .driver_name = "pcl816", 162 .module = THIS_MODULE, 163 .attach = pcl816_attach, 164 .detach = pcl816_detach, 165 .board_name = &boardtypes[0].name, 166 .num_names = n_boardtypes, 167 .offset = sizeof(struct pcl816_board), 168}; 169 170COMEDI_INITCLEANUP(driver_pcl816); 171 172struct pcl816_private { 173 174 unsigned int dma; /* used DMA, 0=don't use DMA */ 175 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */ 176#ifdef unused 177 unsigned long rtc_iobase; /* RTC port region */ 178 unsigned int rtc_iosize; 179 unsigned int rtc_irq; 180#endif 181 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ 182 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ 183 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ 184 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ 185 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ 186 unsigned int last_top_dma; /* DMA pointer in last RTC int */ 187 int next_dma_buf; /* which DMA buffer will be used next round */ 188 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ 189 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ 190 191 unsigned int ai_scans; /* len of scanlist */ 192 unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */ 193 int irq_free; /* 1=have allocated IRQ */ 194 int irq_blocked; /* 1=IRQ now uses any subdev */ 195#ifdef unused 196 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */ 197#endif 198 int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */ 199 int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ 200 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ 201 int ai_act_scan; /* how many scans we finished */ 202 unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */ 203 unsigned int ai_act_chanlist_len; /* how long is actual MUX list */ 204 unsigned int ai_act_chanlist_pos; /* actual position in MUX list */ 205 unsigned int ai_poll_ptr; /* how many sampes transfer poll */ 206 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ 207#ifdef unused 208 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */ 209 unsigned long rtc_freq; /* RTC int freq */ 210#endif 211}; 212 213/* 214============================================================================== 215*/ 216static int check_and_setup_channel_list(struct comedi_device *dev, 217 struct comedi_subdevice *s, 218 unsigned int *chanlist, int chanlen); 219static int pcl816_ai_cancel(struct comedi_device *dev, 220 struct comedi_subdevice *s); 221static void start_pacer(struct comedi_device *dev, int mode, 222 unsigned int divisor1, unsigned int divisor2); 223#ifdef unused 224static int set_rtc_irq_bit(unsigned char bit); 225#endif 226 227static int pcl816_ai_cmdtest(struct comedi_device *dev, 228 struct comedi_subdevice *s, 229 struct comedi_cmd *cmd); 230static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); 231 232/* 233============================================================================== 234 ANALOG INPUT MODE0, 816 cards, slow version 235*/ 236static int pcl816_ai_insn_read(struct comedi_device *dev, 237 struct comedi_subdevice *s, 238 struct comedi_insn *insn, unsigned int *data) 239{ 240 int n; 241 int timeout; 242 243 DPRINTK("mode 0 analog input\n"); 244 /* software trigger, DMA and INT off */ 245 outb(0, dev->iobase + PCL816_CONTROL); 246 /* clear INT (conversion end) flag */ 247 outb(0, dev->iobase + PCL816_CLRINT); 248 249 /* Set the input channel */ 250 outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX); 251 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE); /* select gain */ 252 253 for (n = 0; n < insn->n; n++) { 254 255 outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */ 256 257 timeout = 100; 258 while (timeout--) { 259 if (!(inb(dev->iobase + PCL816_STATUS) & 260 PCL816_STATUS_DRDY_MASK)) { 261 /* return read value */ 262 data[n] = 263 ((inb(dev->iobase + 264 PCL816_AD_HI) << 8) | 265 (inb(dev->iobase + PCL816_AD_LO))); 266 267 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT (conversion end) flag */ 268 break; 269 } 270 udelay(1); 271 } 272 /* Return timeout error */ 273 if (!timeout) { 274 comedi_error(dev, "A/D insn timeout\n"); 275 data[0] = 0; 276 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT (conversion end) flag */ 277 return -EIO; 278 } 279 280 } 281 return n; 282} 283 284/* 285============================================================================== 286 analog input interrupt mode 1 & 3, 818 cards 287 one sample per interrupt version 288*/ 289static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) 290{ 291 struct comedi_device *dev = d; 292 struct comedi_subdevice *s = dev->subdevices + 0; 293 int low, hi; 294 int timeout = 50; /* wait max 50us */ 295 296 while (timeout--) { 297 if (!(inb(dev->iobase + PCL816_STATUS) & 298 PCL816_STATUS_DRDY_MASK)) 299 break; 300 udelay(1); 301 } 302 if (!timeout) { /* timeout, bail error */ 303 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ 304 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); 305 pcl816_ai_cancel(dev, s); 306 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 307 comedi_event(dev, s); 308 return IRQ_HANDLED; 309 310 } 311 312 /* get the sample */ 313 low = inb(dev->iobase + PCL816_AD_LO); 314 hi = inb(dev->iobase + PCL816_AD_HI); 315 316 comedi_buf_put(s->async, (hi << 8) | low); 317 318 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ 319 320 if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len) 321 devpriv->ai_act_chanlist_pos = 0; 322 323 if (s->async->cur_chan == 0) { 324 devpriv->ai_act_scan++; 325 } 326 327 if (!devpriv->ai_neverending) 328 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 329 /* all data sampled */ 330 pcl816_ai_cancel(dev, s); 331 s->async->events |= COMEDI_CB_EOA; 332 } 333 comedi_event(dev, s); 334 return IRQ_HANDLED; 335} 336 337/* 338============================================================================== 339 analog input dma mode 1 & 3, 816 cards 340*/ 341static void transfer_from_dma_buf(struct comedi_device *dev, 342 struct comedi_subdevice *s, short *ptr, 343 unsigned int bufptr, unsigned int len) 344{ 345 int i; 346 347 s->async->events = 0; 348 349 for (i = 0; i < len; i++) { 350 351 comedi_buf_put(s->async, ptr[bufptr++]); 352 353 if (++devpriv->ai_act_chanlist_pos >= 354 devpriv->ai_act_chanlist_len) { 355 devpriv->ai_act_chanlist_pos = 0; 356 devpriv->ai_act_scan++; 357 } 358 359 if (!devpriv->ai_neverending) 360 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 361 pcl816_ai_cancel(dev, s); 362 s->async->events |= COMEDI_CB_EOA; 363 s->async->events |= COMEDI_CB_BLOCK; 364 break; 365 } 366 } 367 368 comedi_event(dev, s); 369} 370 371static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) 372{ 373 struct comedi_device *dev = d; 374 struct comedi_subdevice *s = dev->subdevices + 0; 375 int len, bufptr, this_dma_buf; 376 unsigned long dma_flags; 377 short *ptr; 378 379 disable_dma(devpriv->dma); 380 this_dma_buf = devpriv->next_dma_buf; 381 382 if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { /* switch dma bufs */ 383 384 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; 385 set_dma_mode(devpriv->dma, DMA_MODE_READ); 386 dma_flags = claim_dma_lock(); 387/* clear_dma_ff (devpriv->dma); */ 388 set_dma_addr(devpriv->dma, 389 devpriv->hwdmaptr[devpriv->next_dma_buf]); 390 if (devpriv->dma_runs_to_end) { 391 set_dma_count(devpriv->dma, 392 devpriv->hwdmasize[devpriv-> 393 next_dma_buf]); 394 } else { 395 set_dma_count(devpriv->dma, devpriv->last_dma_run); 396 } 397 release_dma_lock(dma_flags); 398 enable_dma(devpriv->dma); 399 } 400 401 devpriv->dma_runs_to_end--; 402 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ 403 404 ptr = (short *)devpriv->dmabuf[this_dma_buf]; 405 406 len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr; 407 bufptr = devpriv->ai_poll_ptr; 408 devpriv->ai_poll_ptr = 0; 409 410 transfer_from_dma_buf(dev, s, ptr, bufptr, len); 411 return IRQ_HANDLED; 412} 413 414/* 415============================================================================== 416 INT procedure 417*/ 418static irqreturn_t interrupt_pcl816(int irq, void *d) 419{ 420 struct comedi_device *dev = d; 421 DPRINTK("<I>"); 422 423 if (!dev->attached) { 424 comedi_error(dev, "premature interrupt"); 425 return IRQ_HANDLED; 426 } 427 428 switch (devpriv->int816_mode) { 429 case INT_TYPE_AI1_DMA: 430 case INT_TYPE_AI3_DMA: 431 return interrupt_pcl816_ai_mode13_dma(irq, d); 432 case INT_TYPE_AI1_INT: 433 case INT_TYPE_AI3_INT: 434 return interrupt_pcl816_ai_mode13_int(irq, d); 435 } 436 437 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ 438 if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) | 439 (!devpriv->int816_mode)) { 440 if (devpriv->irq_was_now_closed) { 441 devpriv->irq_was_now_closed = 0; 442 /* comedi_error(dev,"last IRQ.."); */ 443 return IRQ_HANDLED; 444 } 445 comedi_error(dev, "bad IRQ!"); 446 return IRQ_NONE; 447 } 448 comedi_error(dev, "IRQ from unknow source!"); 449 return IRQ_NONE; 450} 451 452/* 453============================================================================== 454 COMMAND MODE 455*/ 456static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd) 457{ 458 printk("pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, 459 cmd->start_src, cmd->scan_begin_src, cmd->convert_src); 460 printk("pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e, 461 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); 462 printk("pcl816 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, 463 cmd->scan_end_src); 464 printk("pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e, 465 cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); 466} 467 468/* 469============================================================================== 470*/ 471static int pcl816_ai_cmdtest(struct comedi_device *dev, 472 struct comedi_subdevice *s, struct comedi_cmd *cmd) 473{ 474 int err = 0; 475 int tmp, divisor1 = 0, divisor2 = 0; 476 477 DEBUG(printk("pcl816 pcl812_ai_cmdtest\n"); pcl816_cmdtest_out(-1, cmd); 478 ); 479 480 /* step 1: make sure trigger sources are trivially valid */ 481 tmp = cmd->start_src; 482 cmd->start_src &= TRIG_NOW; 483 if (!cmd->start_src || tmp != cmd->start_src) 484 err++; 485 486 tmp = cmd->scan_begin_src; 487 cmd->scan_begin_src &= TRIG_FOLLOW; 488 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 489 err++; 490 491 tmp = cmd->convert_src; 492 cmd->convert_src &= TRIG_EXT | TRIG_TIMER; 493 if (!cmd->convert_src || tmp != cmd->convert_src) 494 err++; 495 496 tmp = cmd->scan_end_src; 497 cmd->scan_end_src &= TRIG_COUNT; 498 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 499 err++; 500 501 tmp = cmd->stop_src; 502 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 503 if (!cmd->stop_src || tmp != cmd->stop_src) 504 err++; 505 506 if (err) { 507 return 1; 508 } 509 510 /* step 2: make sure trigger sources are unique and mutually compatible */ 511 512 if (cmd->start_src != TRIG_NOW) { 513 cmd->start_src = TRIG_NOW; 514 err++; 515 } 516 517 if (cmd->scan_begin_src != TRIG_FOLLOW) { 518 cmd->scan_begin_src = TRIG_FOLLOW; 519 err++; 520 } 521 522 if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) { 523 cmd->convert_src = TRIG_TIMER; 524 err++; 525 } 526 527 if (cmd->scan_end_src != TRIG_COUNT) { 528 cmd->scan_end_src = TRIG_COUNT; 529 err++; 530 } 531 532 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) 533 err++; 534 535 if (err) { 536 return 2; 537 } 538 539 /* step 3: make sure arguments are trivially compatible */ 540 if (cmd->start_arg != 0) { 541 cmd->start_arg = 0; 542 err++; 543 } 544 545 if (cmd->scan_begin_arg != 0) { 546 cmd->scan_begin_arg = 0; 547 err++; 548 } 549 if (cmd->convert_src == TRIG_TIMER) { 550 if (cmd->convert_arg < this_board->ai_ns_min) { 551 cmd->convert_arg = this_board->ai_ns_min; 552 err++; 553 } 554 } else { /* TRIG_EXT */ 555 if (cmd->convert_arg != 0) { 556 cmd->convert_arg = 0; 557 err++; 558 } 559 } 560 561 if (!cmd->chanlist_len) { 562 cmd->chanlist_len = 1; 563 err++; 564 } 565 if (cmd->chanlist_len > this_board->n_aichan) { 566 cmd->chanlist_len = this_board->n_aichan; 567 err++; 568 } 569 if (cmd->scan_end_arg != cmd->chanlist_len) { 570 cmd->scan_end_arg = cmd->chanlist_len; 571 err++; 572 } 573 if (cmd->stop_src == TRIG_COUNT) { 574 if (!cmd->stop_arg) { 575 cmd->stop_arg = 1; 576 err++; 577 } 578 } else { /* TRIG_NONE */ 579 if (cmd->stop_arg != 0) { 580 cmd->stop_arg = 0; 581 err++; 582 } 583 } 584 585 if (err) { 586 return 3; 587 } 588 589 /* step 4: fix up any arguments */ 590 if (cmd->convert_src == TRIG_TIMER) { 591 tmp = cmd->convert_arg; 592 i8253_cascade_ns_to_timer(this_board->i8254_osc_base, 593 &divisor1, &divisor2, 594 &cmd->convert_arg, 595 cmd->flags & TRIG_ROUND_MASK); 596 if (cmd->convert_arg < this_board->ai_ns_min) 597 cmd->convert_arg = this_board->ai_ns_min; 598 if (tmp != cmd->convert_arg) 599 err++; 600 } 601 602 if (err) { 603 return 4; 604 } 605 606 return 0; 607} 608 609static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 610{ 611 unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq; 612 struct comedi_cmd *cmd = &s->async->cmd; 613 614 if (cmd->start_src != TRIG_NOW) 615 return -EINVAL; 616 if (cmd->scan_begin_src != TRIG_FOLLOW) 617 return -EINVAL; 618 if (cmd->scan_end_src != TRIG_COUNT) 619 return -EINVAL; 620 if (cmd->scan_end_arg != cmd->chanlist_len) 621 return -EINVAL; 622/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */ 623 if (devpriv->irq_blocked) 624 return -EBUSY; 625 626 if (cmd->convert_src == TRIG_TIMER) { 627 if (cmd->convert_arg < this_board->ai_ns_min) 628 cmd->convert_arg = this_board->ai_ns_min; 629 630 i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1, 631 &divisor2, &cmd->convert_arg, 632 cmd->flags & TRIG_ROUND_MASK); 633 if (divisor1 == 1) { /* PCL816 crash if any divisor is set to 1 */ 634 divisor1 = 2; 635 divisor2 /= 2; 636 } 637 if (divisor2 == 1) { 638 divisor2 = 2; 639 divisor1 /= 2; 640 } 641 } 642 643 start_pacer(dev, -1, 0, 0); /* stop pacer */ 644 645 if (!check_and_setup_channel_list(dev, s, cmd->chanlist, 646 cmd->chanlist_len)) 647 return -EINVAL; 648 udelay(1); 649 650 devpriv->ai_act_scan = 0; 651 s->async->cur_chan = 0; 652 devpriv->irq_blocked = 1; 653 devpriv->ai_poll_ptr = 0; 654 devpriv->irq_was_now_closed = 0; 655 656 if (cmd->stop_src == TRIG_COUNT) { 657 devpriv->ai_scans = cmd->stop_arg; 658 devpriv->ai_neverending = 0; 659 } else { 660 devpriv->ai_scans = 0; 661 devpriv->ai_neverending = 1; 662 } 663 664 if ((cmd->flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? */ 665 printk("pl816: You wankt WAKE_EOS but I dont want handle it"); 666 /* devpriv->ai_eos=1; */ 667 /* if (devpriv->ai_n_chan==1) */ 668 /* devpriv->dma=0; // DMA is useless for this situation */ 669 } 670 671 if (devpriv->dma) { 672 bytes = devpriv->hwdmasize[0]; 673 if (!devpriv->ai_neverending) { 674 bytes = s->async->cmd.chanlist_len * s->async->cmd.chanlist_len * sizeof(short); /* how many */ 675 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fill */ 676 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ 677 devpriv->dma_runs_to_end--; 678 if (devpriv->dma_runs_to_end >= 0) 679 bytes = devpriv->hwdmasize[0]; 680 } else 681 devpriv->dma_runs_to_end = -1; 682 683 devpriv->next_dma_buf = 0; 684 set_dma_mode(devpriv->dma, DMA_MODE_READ); 685 dma_flags = claim_dma_lock(); 686 clear_dma_ff(devpriv->dma); 687 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); 688 set_dma_count(devpriv->dma, bytes); 689 release_dma_lock(dma_flags); 690 enable_dma(devpriv->dma); 691 } 692 693 start_pacer(dev, 1, divisor1, divisor2); 694 dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7); 695 696 switch (cmd->convert_src) { 697 case TRIG_TIMER: 698 devpriv->int816_mode = INT_TYPE_AI1_DMA; 699 outb(0x32, dev->iobase + PCL816_CONTROL); /* Pacer+IRQ+DMA */ 700 outb(dmairq, dev->iobase + PCL816_STATUS); /* write irq and DMA to card */ 701 break; 702 703 default: 704 devpriv->int816_mode = INT_TYPE_AI3_DMA; 705 outb(0x34, dev->iobase + PCL816_CONTROL); /* Ext trig+IRQ+DMA */ 706 outb(dmairq, dev->iobase + PCL816_STATUS); /* write irq to card */ 707 break; 708 } 709 710 DPRINTK("pcl816 END: pcl812_ai_cmd()\n"); 711 return 0; 712} 713 714static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) 715{ 716 unsigned long flags; 717 unsigned int top1, top2, i; 718 719 if (!devpriv->dma) 720 return 0; /* poll is valid only for DMA transfer */ 721 722 spin_lock_irqsave(&dev->spinlock, flags); 723 724 for (i = 0; i < 20; i++) { 725 top1 = get_dma_residue(devpriv->dma); /* where is now DMA */ 726 top2 = get_dma_residue(devpriv->dma); 727 if (top1 == top2) 728 break; 729 } 730 if (top1 != top2) { 731 spin_unlock_irqrestore(&dev->spinlock, flags); 732 return 0; 733 } 734 735 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */ 736 top1 >>= 1; /* sample position */ 737 top2 = top1 - devpriv->ai_poll_ptr; 738 if (top2 < 1) { /* no new samples */ 739 spin_unlock_irqrestore(&dev->spinlock, flags); 740 return 0; 741 } 742 743 transfer_from_dma_buf(dev, s, 744 (short *)devpriv->dmabuf[devpriv->next_dma_buf], 745 devpriv->ai_poll_ptr, top2); 746 747 devpriv->ai_poll_ptr = top1; /* new buffer position */ 748 spin_unlock_irqrestore(&dev->spinlock, flags); 749 750 return s->async->buf_write_count - s->async->buf_read_count; 751} 752 753/* 754============================================================================== 755 cancel any mode 1-4 AI 756*/ 757static int pcl816_ai_cancel(struct comedi_device *dev, 758 struct comedi_subdevice *s) 759{ 760/* DEBUG(printk("pcl816_ai_cancel()\n");) */ 761 762 if (devpriv->irq_blocked > 0) { 763 switch (devpriv->int816_mode) { 764#ifdef unused 765 case INT_TYPE_AI1_DMA_RTC: 766 case INT_TYPE_AI3_DMA_RTC: 767 set_rtc_irq_bit(0); /* stop RTC */ 768 del_timer(&devpriv->rtc_irq_timer); 769#endif 770 case INT_TYPE_AI1_DMA: 771 case INT_TYPE_AI3_DMA: 772 disable_dma(devpriv->dma); 773 case INT_TYPE_AI1_INT: 774 case INT_TYPE_AI3_INT: 775 outb(inb(dev->iobase + PCL816_CONTROL) & 0x73, dev->iobase + PCL816_CONTROL); /* Stop A/D */ 776 udelay(1); 777 outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ 778 outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ 779 outb(0x70, dev->iobase + PCL816_CTRCTL); 780 outb(0, dev->iobase + PCL816_AD_LO); 781 inb(dev->iobase + PCL816_AD_LO); 782 inb(dev->iobase + PCL816_AD_HI); 783 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ 784 outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ 785 devpriv->irq_blocked = 0; 786 devpriv->irq_was_now_closed = devpriv->int816_mode; 787 devpriv->int816_mode = 0; 788 devpriv->last_int_sub = s; 789/* s->busy = 0; */ 790 break; 791 } 792 } 793 794 DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");) 795 return 0; 796} 797 798/* 799============================================================================== 800 chech for PCL816 801*/ 802static int pcl816_check(unsigned long iobase) 803{ 804 outb(0x00, iobase + PCL816_MUX); 805 udelay(1); 806 if (inb(iobase + PCL816_MUX) != 0x00) 807 return 1; /* there isn't card */ 808 outb(0x55, iobase + PCL816_MUX); 809 udelay(1); 810 if (inb(iobase + PCL816_MUX) != 0x55) 811 return 1; /* there isn't card */ 812 outb(0x00, iobase + PCL816_MUX); 813 udelay(1); 814 outb(0x18, iobase + PCL816_CONTROL); 815 udelay(1); 816 if (inb(iobase + PCL816_CONTROL) != 0x18) 817 return 1; /* there isn't card */ 818 return 0; /* ok, card exist */ 819} 820 821/* 822============================================================================== 823 reset whole PCL-816 cards 824*/ 825static void pcl816_reset(struct comedi_device *dev) 826{ 827/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */ 828/* outb (0, dev->iobase + PCL818_DA_HI); */ 829/* udelay (1); */ 830/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */ 831/* outb (0, dev->iobase + PCL818_DO_LO); */ 832/* udelay (1); */ 833 outb(0, dev->iobase + PCL816_CONTROL); 834 outb(0, dev->iobase + PCL816_MUX); 835 outb(0, dev->iobase + PCL816_CLRINT); 836 outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ 837 outb(0x70, dev->iobase + PCL816_CTRCTL); 838 outb(0x30, dev->iobase + PCL816_CTRCTL); 839 outb(0, dev->iobase + PCL816_RANGE); 840} 841 842/* 843============================================================================== 844 Start/stop pacer onboard pacer 845*/ 846static void 847start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, 848 unsigned int divisor2) 849{ 850 outb(0x32, dev->iobase + PCL816_CTRCTL); 851 outb(0xff, dev->iobase + PCL816_CTR0); 852 outb(0x00, dev->iobase + PCL816_CTR0); 853 udelay(1); 854 outb(0xb4, dev->iobase + PCL816_CTRCTL); /* set counter 2 as mode 3 */ 855 outb(0x74, dev->iobase + PCL816_CTRCTL); /* set counter 1 as mode 3 */ 856 udelay(1); 857 858 if (mode == 1) { 859 DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1, 860 divisor2); 861 outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2); 862 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2); 863 outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1); 864 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1); 865 } 866 867 /* clear pending interrupts (just in case) */ 868/* outb(0, dev->iobase + PCL816_CLRINT); */ 869} 870 871/* 872============================================================================== 873 Check if channel list from user is builded correctly 874 If it's ok, then program scan/gain logic 875*/ 876static int 877check_and_setup_channel_list(struct comedi_device *dev, 878 struct comedi_subdevice *s, unsigned int *chanlist, 879 int chanlen) 880{ 881 unsigned int chansegment[16]; 882 unsigned int i, nowmustbechan, seglen, segpos; 883 884 /* correct channel and range number check itself comedi/range.c */ 885 if (chanlen < 1) { 886 comedi_error(dev, "range/channel list is empty!"); 887 return 0; 888 } 889 890 if (chanlen > 1) { 891 chansegment[0] = chanlist[0]; /* first channel is everytime ok */ 892 for (i = 1, seglen = 1; i < chanlen; i++, seglen++) { 893 /* build part of chanlist */ 894 DEBUG(printk("%d. %d %d\n", i, CR_CHAN(chanlist[i]), 895 CR_RANGE(chanlist[i]));) 896 if (chanlist[0] == chanlist[i]) 897 break; /* we detect loop, this must by finish */ 898 nowmustbechan = 899 (CR_CHAN(chansegment[i - 1]) + 1) % chanlen; 900 if (nowmustbechan != CR_CHAN(chanlist[i])) { 901 /* channel list isn't continous :-( */ 902 printk 903 ("comedi%d: pcl816: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", 904 dev->minor, i, CR_CHAN(chanlist[i]), 905 nowmustbechan, CR_CHAN(chanlist[0])); 906 return 0; 907 } 908 chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */ 909 } 910 911 for (i = 0, segpos = 0; i < chanlen; i++) { /* check whole chanlist */ 912 DEBUG(printk("%d %d=%d %d\n", 913 CR_CHAN(chansegment[i % seglen]), 914 CR_RANGE(chansegment[i % seglen]), 915 CR_CHAN(chanlist[i]), 916 CR_RANGE(chanlist[i]));) 917 if (chanlist[i] != chansegment[i % seglen]) { 918 printk 919 ("comedi%d: pcl816: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", 920 dev->minor, i, CR_CHAN(chansegment[i]), 921 CR_RANGE(chansegment[i]), 922 CR_AREF(chansegment[i]), 923 CR_CHAN(chanlist[i % seglen]), 924 CR_RANGE(chanlist[i % seglen]), 925 CR_AREF(chansegment[i % seglen])); 926 return 0; /* chan/gain list is strange */ 927 } 928 } 929 } else { 930 seglen = 1; 931 } 932 933 devpriv->ai_act_chanlist_len = seglen; 934 devpriv->ai_act_chanlist_pos = 0; 935 936 for (i = 0; i < seglen; i++) { /* store range list to card */ 937 devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]); 938 outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX); 939 outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); /* select gain */ 940 } 941 942 udelay(1); 943 944 outb(devpriv->ai_act_chanlist[0] | (devpriv->ai_act_chanlist[seglen - 1] << 4), dev->iobase + PCL816_MUX); /* select channel interval to scan */ 945 946 return 1; /* we can serve this with MUX logic */ 947} 948 949#ifdef unused 950/* 951============================================================================== 952 Enable(1)/disable(0) periodic interrupts from RTC 953*/ 954static int set_rtc_irq_bit(unsigned char bit) 955{ 956 unsigned char val; 957 unsigned long flags; 958 959 if (bit == 1) { 960 RTC_timer_lock++; 961 if (RTC_timer_lock > 1) 962 return 0; 963 } else { 964 RTC_timer_lock--; 965 if (RTC_timer_lock < 0) 966 RTC_timer_lock = 0; 967 if (RTC_timer_lock > 0) 968 return 0; 969 } 970 971 save_flags(flags); 972 cli(); 973 val = CMOS_READ(RTC_CONTROL); 974 if (bit) { 975 val |= RTC_PIE; 976 } else { 977 val &= ~RTC_PIE; 978 } 979 CMOS_WRITE(val, RTC_CONTROL); 980 CMOS_READ(RTC_INTR_FLAGS); 981 restore_flags(flags); 982 return 0; 983} 984#endif 985 986/* 987============================================================================== 988 Free any resources that we have claimed 989*/ 990static void free_resources(struct comedi_device *dev) 991{ 992 /* printk("free_resource()\n"); */ 993 if (dev->private) { 994 pcl816_ai_cancel(dev, devpriv->sub_ai); 995 pcl816_reset(dev); 996 if (devpriv->dma) 997 free_dma(devpriv->dma); 998 if (devpriv->dmabuf[0]) 999 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); 1000 if (devpriv->dmabuf[1]) 1001 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); 1002#ifdef unused 1003 if (devpriv->rtc_irq) 1004 free_irq(devpriv->rtc_irq, dev); 1005 if ((devpriv->dma_rtc) && (RTC_lock == 1)) { 1006 if (devpriv->rtc_iobase) 1007 release_region(devpriv->rtc_iobase, 1008 devpriv->rtc_iosize); 1009 } 1010#endif 1011 } 1012 1013 if (dev->irq) 1014 free_irq(dev->irq, dev); 1015 if (dev->iobase) 1016 release_region(dev->iobase, this_board->io_range); 1017 /* printk("free_resource() end\n"); */ 1018} 1019 1020/* 1021============================================================================== 1022 1023 Initialization 1024 1025*/ 1026static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) 1027{ 1028 int ret; 1029 unsigned long iobase; 1030 unsigned int irq, dma; 1031 unsigned long pages; 1032 /* int i; */ 1033 struct comedi_subdevice *s; 1034 1035 /* claim our I/O space */ 1036 iobase = it->options[0]; 1037 printk("comedi%d: pcl816: board=%s, ioport=0x%03lx", dev->minor, 1038 this_board->name, iobase); 1039 1040 if (!request_region(iobase, this_board->io_range, "pcl816")) { 1041 printk("I/O port conflict\n"); 1042 return -EIO; 1043 } 1044 1045 dev->iobase = iobase; 1046 1047 if (pcl816_check(iobase)) { 1048 printk(", I cann't detect board. FAIL!\n"); 1049 return -EIO; 1050 } 1051 1052 ret = alloc_private(dev, sizeof(struct pcl816_private)); 1053 if (ret < 0) 1054 return ret; /* Can't alloc mem */ 1055 1056 /* set up some name stuff */ 1057 dev->board_name = this_board->name; 1058 1059 /* grab our IRQ */ 1060 irq = 0; 1061 if (this_board->IRQbits != 0) { /* board support IRQ */ 1062 irq = it->options[1]; 1063 if (irq) { /* we want to use IRQ */ 1064 if (((1 << irq) & this_board->IRQbits) == 0) { 1065 printk 1066 (", IRQ %u is out of allowed range, DISABLING IT", 1067 irq); 1068 irq = 0; /* Bad IRQ */ 1069 } else { 1070 if (request_irq 1071 (irq, interrupt_pcl816, 0, "pcl816", dev)) { 1072 printk 1073 (", unable to allocate IRQ %u, DISABLING IT", 1074 irq); 1075 irq = 0; /* Can't use IRQ */ 1076 } else { 1077 printk(", irq=%u", irq); 1078 } 1079 } 1080 } 1081 } 1082 1083 dev->irq = irq; 1084 if (irq) { 1085 devpriv->irq_free = 1; 1086 } /* 1=we have allocated irq */ 1087 else { 1088 devpriv->irq_free = 0; 1089 } 1090 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ 1091 devpriv->int816_mode = 0; /* mode of irq */ 1092 1093#ifdef unused 1094 /* grab RTC for DMA operations */ 1095 devpriv->dma_rtc = 0; 1096 if (it->options[2] > 0) { /* we want to use DMA */ 1097 if (RTC_lock == 0) { 1098 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, 1099 "pcl816 (RTC)")) 1100 goto no_rtc; 1101 } 1102 devpriv->rtc_iobase = RTC_PORT(0); 1103 devpriv->rtc_iosize = RTC_IO_EXTENT; 1104 RTC_lock++; 1105#ifdef UNTESTED_CODE 1106 if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0, 1107 "pcl816 DMA (RTC)", dev)) { 1108 devpriv->dma_rtc = 1; 1109 devpriv->rtc_irq = RTC_IRQ; 1110 printk(", dma_irq=%u", devpriv->rtc_irq); 1111 } else { 1112 RTC_lock--; 1113 if (RTC_lock == 0) { 1114 if (devpriv->rtc_iobase) 1115 release_region(devpriv->rtc_iobase, 1116 devpriv->rtc_iosize); 1117 } 1118 devpriv->rtc_iobase = 0; 1119 devpriv->rtc_iosize = 0; 1120 } 1121#else 1122 printk("pcl816: RTC code missing"); 1123#endif 1124 1125 } 1126 1127no_rtc: 1128#endif 1129 /* grab our DMA */ 1130 dma = 0; 1131 devpriv->dma = dma; 1132 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0)) 1133 goto no_dma; /* if we haven't IRQ, we can't use DMA */ 1134 1135 if (this_board->DMAbits != 0) { /* board support DMA */ 1136 dma = it->options[2]; 1137 if (dma < 1) 1138 goto no_dma; /* DMA disabled */ 1139 1140 if (((1 << dma) & this_board->DMAbits) == 0) { 1141 printk(", DMA is out of allowed range, FAIL!\n"); 1142 return -EINVAL; /* Bad DMA */ 1143 } 1144 ret = request_dma(dma, "pcl816"); 1145 if (ret) { 1146 printk(", unable to allocate DMA %u, FAIL!\n", dma); 1147 return -EBUSY; /* DMA isn't free */ 1148 } 1149 1150 devpriv->dma = dma; 1151 printk(", dma=%u", dma); 1152 pages = 2; /* we need 16KB */ 1153 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); 1154 1155 if (!devpriv->dmabuf[0]) { 1156 printk(", unable to allocate DMA buffer, FAIL!\n"); 1157 /* maybe experiment with try_to_free_pages() will help .... */ 1158 return -EBUSY; /* no buffer :-( */ 1159 } 1160 devpriv->dmapages[0] = pages; 1161 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); 1162 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; 1163 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ 1164 1165 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */ 1166 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); 1167 if (!devpriv->dmabuf[1]) { 1168 printk 1169 (", unable to allocate DMA buffer, FAIL!\n"); 1170 return -EBUSY; 1171 } 1172 devpriv->dmapages[1] = pages; 1173 devpriv->hwdmaptr[1] = 1174 virt_to_bus((void *)devpriv->dmabuf[1]); 1175 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; 1176 } 1177 } 1178 1179no_dma: 1180 1181/* if (this_board->n_aochan > 0) 1182 subdevs[1] = COMEDI_SUBD_AO; 1183 if (this_board->n_dichan > 0) 1184 subdevs[2] = COMEDI_SUBD_DI; 1185 if (this_board->n_dochan > 0) 1186 subdevs[3] = COMEDI_SUBD_DO; 1187*/ 1188 1189 ret = alloc_subdevices(dev, 1); 1190 if (ret < 0) 1191 return ret; 1192 1193 s = dev->subdevices + 0; 1194 if (this_board->n_aichan > 0) { 1195 s->type = COMEDI_SUBD_AI; 1196 devpriv->sub_ai = s; 1197 dev->read_subdev = s; 1198 s->subdev_flags = SDF_READABLE | SDF_CMD_READ; 1199 s->n_chan = this_board->n_aichan; 1200 s->subdev_flags |= SDF_DIFF; 1201 /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */ 1202 s->maxdata = this_board->ai_maxdata; 1203 s->len_chanlist = this_board->ai_chanlist; 1204 s->range_table = this_board->ai_range_type; 1205 s->cancel = pcl816_ai_cancel; 1206 s->do_cmdtest = pcl816_ai_cmdtest; 1207 s->do_cmd = pcl816_ai_cmd; 1208 s->poll = pcl816_ai_poll; 1209 s->insn_read = pcl816_ai_insn_read; 1210 } else { 1211 s->type = COMEDI_SUBD_UNUSED; 1212 } 1213 1214#if 0 1215case COMEDI_SUBD_AO: 1216 s->subdev_flags = SDF_WRITABLE | SDF_GROUND; 1217 s->n_chan = this_board->n_aochan; 1218 s->maxdata = this_board->ao_maxdata; 1219 s->len_chanlist = this_board->ao_chanlist; 1220 s->range_table = this_board->ao_range_type; 1221 break; 1222 1223case COMEDI_SUBD_DI: 1224 s->subdev_flags = SDF_READABLE; 1225 s->n_chan = this_board->n_dichan; 1226 s->maxdata = 1; 1227 s->len_chanlist = this_board->n_dichan; 1228 s->range_table = &range_digital; 1229 break; 1230 1231case COMEDI_SUBD_DO: 1232 s->subdev_flags = SDF_WRITABLE; 1233 s->n_chan = this_board->n_dochan; 1234 s->maxdata = 1; 1235 s->len_chanlist = this_board->n_dochan; 1236 s->range_table = &range_digital; 1237 break; 1238#endif 1239 1240 pcl816_reset(dev); 1241 1242 printk("\n"); 1243 1244 return 0; 1245} 1246 1247/* 1248============================================================================== 1249 Removes device 1250 */ 1251static int pcl816_detach(struct comedi_device *dev) 1252{ 1253 DEBUG(printk("comedi%d: pcl816: remove\n", dev->minor);) 1254 free_resources(dev); 1255#ifdef unused 1256 if (devpriv->dma_rtc) 1257 RTC_lock--; 1258#endif 1259 return 0; 1260} 1261