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