pcl818.c revision 90f703d30dd3e0c16ff80f35e34e511385a05ad5
1/* 2 comedi/drivers/pcl818.c 3 4 Author: Michal Dobes <dobes@tesnet.cz> 5 6 hardware driver for Advantech cards: 7 card: PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718 8 driver: pcl818l, pcl818h, pcl818hd, pcl818hg, pcl818, pcl718 9*/ 10/* 11Driver: pcl818 12Description: Advantech PCL-818 cards, PCL-718 13Author: Michal Dobes <dobes@tesnet.cz> 14Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h), 15 PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818), 16 PCL-718 (pcl718) 17Status: works 18 19All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO. 20Differences are only at maximal sample speed, range list and FIFO 21support. 22The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support 23only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0. 24PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO 25but this code is untested. 26A word or two about DMA. Driver support DMA operations at two ways: 271) DMA uses two buffers and after one is filled then is generated 28 INT and DMA restart with second buffer. With this mode I'm unable run 29 more that 80Ksamples/secs without data dropouts on K6/233. 302) DMA uses one buffer and run in autoinit mode and the data are 31 from DMA buffer moved on the fly with 2kHz interrupts from RTC. 32 This mode is used if the interrupt 8 is available for allocation. 33 If not, then first DMA mode is used. With this I can run at 34 full speed one card (100ksamples/secs) or two cards with 35 60ksamples/secs each (more is problem on account of ISA limitations). 36 To use this mode you must have compiled kernel with disabled 37 "Enhanced Real Time Clock Support". 38 Maybe you can have problems if you use xntpd or similar. 39 If you've data dropouts with DMA mode 2 then: 40 a) disable IDE DMA 41 b) switch text mode console to fb. 42 43 Options for PCL-818L: 44 [0] - IO Base 45 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) 46 [2] - DMA (0=disable, 1, 3) 47 [3] - 0, 10=10MHz clock for 8254 48 1= 1MHz clock for 8254 49 [4] - 0, 5=A/D input -5V.. +5V 50 1, 10=A/D input -10V..+10V 51 [5] - 0, 5=D/A output 0-5V (internal reference -5V) 52 1, 10=D/A output 0-10V (internal reference -10V) 53 2 =D/A output unknown (external reference) 54 55 Options for PCL-818, PCL-818H: 56 [0] - IO Base 57 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) 58 [2] - DMA (0=disable, 1, 3) 59 [3] - 0, 10=10MHz clock for 8254 60 1= 1MHz clock for 8254 61 [4] - 0, 5=D/A output 0-5V (internal reference -5V) 62 1, 10=D/A output 0-10V (internal reference -10V) 63 2 =D/A output unknown (external reference) 64 65 Options for PCL-818HD, PCL-818HG: 66 [0] - IO Base 67 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) 68 [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA, 69 1=use DMA ch 1, 3=use DMA ch 3) 70 [3] - 0, 10=10MHz clock for 8254 71 1= 1MHz clock for 8254 72 [4] - 0, 5=D/A output 0-5V (internal reference -5V) 73 1, 10=D/A output 0-10V (internal reference -10V) 74 2 =D/A output unknown (external reference) 75 76 Options for PCL-718: 77 [0] - IO Base 78 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) 79 [2] - DMA (0=disable, 1, 3) 80 [3] - 0, 10=10MHz clock for 8254 81 1= 1MHz clock for 8254 82 [4] - 0=A/D Range is +/-10V 83 1= +/-5V 84 2= +/-2.5V 85 3= +/-1V 86 4= +/-0.5V 87 5= user defined bipolar 88 6= 0-10V 89 7= 0-5V 90 8= 0-2V 91 9= 0-1V 92 10= user defined unipolar 93 [5] - 0, 5=D/A outputs 0-5V (internal reference -5V) 94 1, 10=D/A outputs 0-10V (internal reference -10V) 95 2=D/A outputs unknown (external reference) 96 [6] - 0, 60=max 60kHz A/D sampling 97 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed) 98 99*/ 100 101#include "../comedidev.h" 102 103#include <linux/ioport.h> 104#include <linux/mc146818rtc.h> 105#include <linux/gfp.h> 106#include <linux/delay.h> 107#include <asm/dma.h> 108 109#include "8253.h" 110 111/* #define PCL818_MODE13_AO 1 */ 112 113/* boards constants */ 114 115#define boardPCL818L 0 116#define boardPCL818H 1 117#define boardPCL818HD 2 118#define boardPCL818HG 3 119#define boardPCL818 4 120#define boardPCL718 5 121 122/* IO space len */ 123#define PCLx1x_RANGE 16 124/* IO space len if we use FIFO */ 125#define PCLx1xFIFO_RANGE 32 126 127/* W: clear INT request */ 128#define PCL818_CLRINT 8 129/* R: return status byte */ 130#define PCL818_STATUS 8 131/* R: A/D high byte W: A/D range control */ 132#define PCL818_RANGE 1 133/* R: next mux scan channel W: mux scan channel & range control pointer */ 134#define PCL818_MUX 2 135/* R/W: operation control register */ 136#define PCL818_CONTROL 9 137/* W: counter enable */ 138#define PCL818_CNTENABLE 10 139 140/* R: low byte of A/D W: soft A/D trigger */ 141#define PCL818_AD_LO 0 142/* R: high byte of A/D W: A/D range control */ 143#define PCL818_AD_HI 1 144/* W: D/A low&high byte */ 145#define PCL818_DA_LO 4 146#define PCL818_DA_HI 5 147/* R: low&high byte of DI */ 148#define PCL818_DI_LO 3 149#define PCL818_DI_HI 11 150/* W: low&high byte of DO */ 151#define PCL818_DO_LO 3 152#define PCL818_DO_HI 11 153/* W: PCL718 second D/A */ 154#define PCL718_DA2_LO 6 155#define PCL718_DA2_HI 7 156/* counters */ 157#define PCL818_CTR0 12 158#define PCL818_CTR1 13 159#define PCL818_CTR2 14 160/* W: counter control */ 161#define PCL818_CTRCTL 15 162 163/* W: fifo enable/disable */ 164#define PCL818_FI_ENABLE 6 165/* W: fifo interrupt clear */ 166#define PCL818_FI_INTCLR 20 167/* W: fifo interrupt clear */ 168#define PCL818_FI_FLUSH 25 169/* R: fifo status */ 170#define PCL818_FI_STATUS 25 171/* R: one record from FIFO */ 172#define PCL818_FI_DATALO 23 173#define PCL818_FI_DATAHI 23 174 175/* type of interrupt handler */ 176#define INT_TYPE_AI1_INT 1 177#define INT_TYPE_AI1_DMA 2 178#define INT_TYPE_AI1_FIFO 3 179#define INT_TYPE_AI3_INT 4 180#define INT_TYPE_AI3_DMA 5 181#define INT_TYPE_AI3_FIFO 6 182#ifdef PCL818_MODE13_AO 183#define INT_TYPE_AO1_INT 7 184#define INT_TYPE_AO3_INT 8 185#endif 186 187#ifdef unused 188/* RTC stuff... */ 189#define INT_TYPE_AI1_DMA_RTC 9 190#define INT_TYPE_AI3_DMA_RTC 10 191 192#define RTC_IRQ 8 193#define RTC_IO_EXTENT 0x10 194#endif 195 196#define MAGIC_DMA_WORD 0x5a5a 197 198static const struct comedi_lrange range_pcl818h_ai = { 9, { 199 BIP_RANGE(5), 200 BIP_RANGE(2.5), 201 BIP_RANGE(1.25), 202 BIP_RANGE(0.625), 203 UNI_RANGE(10), 204 UNI_RANGE(5), 205 UNI_RANGE(2.5), 206 UNI_RANGE(1.25), 207 BIP_RANGE(10), 208 } 209}; 210 211static const struct comedi_lrange range_pcl818hg_ai = { 10, { 212 BIP_RANGE(5), 213 BIP_RANGE(0.5), 214 BIP_RANGE(0.05), 215 BIP_RANGE(0.005), 216 UNI_RANGE(10), 217 UNI_RANGE(1), 218 UNI_RANGE(0.1), 219 UNI_RANGE(0.01), 220 BIP_RANGE(10), 221 BIP_RANGE(1), 222 BIP_RANGE(0.1), 223 BIP_RANGE(0.01), 224 } 225}; 226 227static const struct comedi_lrange range_pcl818l_l_ai = { 4, { 228 BIP_RANGE(5), 229 BIP_RANGE(2.5), 230 BIP_RANGE(1.25), 231 BIP_RANGE(0.625), 232 } 233}; 234 235static const struct comedi_lrange range_pcl818l_h_ai = { 4, { 236 BIP_RANGE(10), 237 BIP_RANGE(5), 238 BIP_RANGE(2.5), 239 BIP_RANGE(1.25), 240 } 241}; 242 243static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} }; 244static const struct comedi_lrange range718_bipolar0_5 = 245 { 1, {BIP_RANGE(0.5),} }; 246static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} }; 247static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} }; 248 249static int pcl818_attach(struct comedi_device *dev, 250 struct comedi_devconfig *it); 251static int pcl818_detach(struct comedi_device *dev); 252 253#ifdef unused 254static int RTC_lock = 0; /* RTC lock */ 255static int RTC_timer_lock = 0; /* RTC int lock */ 256#endif 257 258struct pcl818_board { 259 260 const char *name; /* driver name */ 261 int n_ranges; /* len of range list */ 262 int n_aichan_se; /* num of A/D chans in single ended mode */ 263 int n_aichan_diff; /* num of A/D chans in diferencial mode */ 264 unsigned int ns_min; /* minimal alllowed delay between samples (in ns) */ 265 int n_aochan; /* num of D/A chans */ 266 int n_dichan; /* num of DI chans */ 267 int n_dochan; /* num of DO chans */ 268 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ 269 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ 270 unsigned int io_range; /* len of IO space */ 271 unsigned int IRQbits; /* allowed interrupts */ 272 unsigned int DMAbits; /* allowed DMA chans */ 273 int ai_maxdata; /* maxdata for A/D */ 274 int ao_maxdata; /* maxdata for D/A */ 275 unsigned char fifo; /* 1=board has FIFO */ 276 int is_818; 277}; 278 279static const struct pcl818_board boardtypes[] = { 280 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, 281 &range_unipolar5, PCLx1x_RANGE, 0x00fc, 282 0x0a, 0xfff, 0xfff, 0, 1}, 283 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, 284 &range_unipolar5, PCLx1x_RANGE, 0x00fc, 285 0x0a, 0xfff, 0xfff, 0, 1}, 286 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, 287 &range_unipolar5, PCLx1x_RANGE, 0x00fc, 288 0x0a, 0xfff, 0xfff, 1, 1}, 289 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, 290 &range_unipolar5, PCLx1x_RANGE, 0x00fc, 291 0x0a, 0xfff, 0xfff, 1, 1}, 292 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, 293 &range_unipolar5, PCLx1x_RANGE, 0x00fc, 294 0x0a, 0xfff, 0xfff, 0, 1}, 295 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, 296 &range_unipolar5, PCLx1x_RANGE, 0x00fc, 297 0x0a, 0xfff, 0xfff, 0, 0}, 298 /* pcm3718 */ 299 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, 300 &range_unipolar5, PCLx1x_RANGE, 0x00fc, 301 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ }, 302}; 303 304#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board)) 305 306static struct comedi_driver driver_pcl818 = { 307 .driver_name = "pcl818", 308 .module = THIS_MODULE, 309 .attach = pcl818_attach, 310 .detach = pcl818_detach, 311 .board_name = &boardtypes[0].name, 312 .num_names = n_boardtypes, 313 .offset = sizeof(struct pcl818_board), 314}; 315 316COMEDI_INITCLEANUP(driver_pcl818); 317 318struct pcl818_private { 319 320 unsigned int dma; /* used DMA, 0=don't use DMA */ 321 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */ 322 unsigned int io_range; 323#ifdef unused 324 unsigned long rtc_iobase; /* RTC port region */ 325 unsigned int rtc_iosize; 326 unsigned int rtc_irq; 327 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */ 328 unsigned long rtc_freq; /* RTC int freq */ 329 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */ 330#endif 331 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ 332 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ 333 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ 334 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ 335 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ 336 unsigned int last_top_dma; /* DMA pointer in last RTC int */ 337 int next_dma_buf; /* which DMA buffer will be used next round */ 338 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ 339 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ 340 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */ 341 unsigned int ns_min; /* manimal alllowed delay between samples (in us) for actual card */ 342 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ 343 int irq_free; /* 1=have allocated IRQ */ 344 int irq_blocked; /* 1=IRQ now uses any subdev */ 345 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */ 346 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ 347 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ 348 int ai_act_scan; /* how many scans we finished */ 349 int ai_act_chan; /* actual position in actual scan */ 350 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */ 351 unsigned int act_chanlist_len; /* how long is actual MUX list */ 352 unsigned int act_chanlist_pos; /* actual position in MUX list */ 353 unsigned int ai_scans; /* len of scanlist */ 354 unsigned int ai_n_chan; /* how many channels is measured */ 355 unsigned int *ai_chanlist; /* actaul chanlist */ 356 unsigned int ai_flags; /* flaglist */ 357 unsigned int ai_data_len; /* len of data buffer */ 358 short *ai_data; /* data buffer */ 359 unsigned int ai_timer1; /* timers */ 360 unsigned int ai_timer2; 361 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ 362 unsigned char usefifo; /* 1=use fifo */ 363 unsigned int ao_readback[2]; 364}; 365 366static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */ 367 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff 368}; 369 370#define devpriv ((struct pcl818_private *)dev->private) 371#define this_board ((const struct pcl818_board *)dev->board_ptr) 372 373/* 374============================================================================== 375*/ 376static void setup_channel_list(struct comedi_device *dev, 377 struct comedi_subdevice *s, 378 unsigned int *chanlist, unsigned int n_chan, 379 unsigned int seglen); 380static int check_channel_list(struct comedi_device *dev, 381 struct comedi_subdevice *s, 382 unsigned int *chanlist, unsigned int n_chan); 383 384static int pcl818_ai_cancel(struct comedi_device *dev, 385 struct comedi_subdevice *s); 386static void start_pacer(struct comedi_device *dev, int mode, 387 unsigned int divisor1, unsigned int divisor2); 388 389#ifdef unused 390static int set_rtc_irq_bit(unsigned char bit); 391static void rtc_dropped_irq(unsigned long data); 392static int rtc_setfreq_irq(int freq); 393#endif 394 395/* 396============================================================================== 397 ANALOG INPUT MODE0, 818 cards, slow version 398*/ 399static int pcl818_ai_insn_read(struct comedi_device *dev, 400 struct comedi_subdevice *s, 401 struct comedi_insn *insn, unsigned int *data) 402{ 403 int n; 404 int timeout; 405 406 /* software trigger, DMA and INT off */ 407 outb(0, dev->iobase + PCL818_CONTROL); 408 409 /* select channel */ 410 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX); 411 412 /* select gain */ 413 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE); 414 415 for (n = 0; n < insn->n; n++) { 416 417 /* clear INT (conversion end) flag */ 418 outb(0, dev->iobase + PCL818_CLRINT); 419 420 /* start conversion */ 421 outb(0, dev->iobase + PCL818_AD_LO); 422 423 timeout = 100; 424 while (timeout--) { 425 if (inb(dev->iobase + PCL818_STATUS) & 0x10) 426 goto conv_finish; 427 udelay(1); 428 } 429 comedi_error(dev, "A/D insn timeout"); 430 /* clear INT (conversion end) flag */ 431 outb(0, dev->iobase + PCL818_CLRINT); 432 return -EIO; 433 434conv_finish: 435 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) | 436 (inb(dev->iobase + PCL818_AD_LO) >> 4)); 437 } 438 439 return n; 440} 441 442/* 443============================================================================== 444 ANALOG OUTPUT MODE0, 818 cards 445 only one sample per call is supported 446*/ 447static int pcl818_ao_insn_read(struct comedi_device *dev, 448 struct comedi_subdevice *s, 449 struct comedi_insn *insn, unsigned int *data) 450{ 451 int n; 452 int chan = CR_CHAN(insn->chanspec); 453 454 for (n = 0; n < insn->n; n++) { 455 data[n] = devpriv->ao_readback[chan]; 456 } 457 458 return n; 459} 460 461static int pcl818_ao_insn_write(struct comedi_device *dev, 462 struct comedi_subdevice *s, 463 struct comedi_insn *insn, unsigned int *data) 464{ 465 int n; 466 int chan = CR_CHAN(insn->chanspec); 467 468 for (n = 0; n < insn->n; n++) { 469 devpriv->ao_readback[chan] = data[n]; 470 outb((data[n] & 0x000f) << 4, dev->iobase + 471 (chan ? PCL718_DA2_LO : PCL818_DA_LO)); 472 outb((data[n] & 0x0ff0) >> 4, dev->iobase + 473 (chan ? PCL718_DA2_HI : PCL818_DA_HI)); 474 } 475 476 return n; 477} 478 479/* 480============================================================================== 481 DIGITAL INPUT MODE0, 818 cards 482 483 only one sample per call is supported 484*/ 485static int pcl818_di_insn_bits(struct comedi_device *dev, 486 struct comedi_subdevice *s, 487 struct comedi_insn *insn, unsigned int *data) 488{ 489 if (insn->n != 2) 490 return -EINVAL; 491 492 data[1] = inb(dev->iobase + PCL818_DI_LO) | 493 (inb(dev->iobase + PCL818_DI_HI) << 8); 494 495 return 2; 496} 497 498/* 499============================================================================== 500 DIGITAL OUTPUT MODE0, 818 cards 501 502 only one sample per call is supported 503*/ 504static int pcl818_do_insn_bits(struct comedi_device *dev, 505 struct comedi_subdevice *s, 506 struct comedi_insn *insn, unsigned int *data) 507{ 508 if (insn->n != 2) 509 return -EINVAL; 510 511 s->state &= ~data[0]; 512 s->state |= (data[0] & data[1]); 513 514 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO); 515 outb((s->state >> 8), dev->iobase + PCL818_DO_HI); 516 517 data[1] = s->state; 518 519 return 2; 520} 521 522/* 523============================================================================== 524 analog input interrupt mode 1 & 3, 818 cards 525 one sample per interrupt version 526*/ 527static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) 528{ 529 struct comedi_device *dev = d; 530 struct comedi_subdevice *s = dev->subdevices + 0; 531 int low; 532 int timeout = 50; /* wait max 50us */ 533 534 while (timeout--) { 535 if (inb(dev->iobase + PCL818_STATUS) & 0x10) 536 goto conv_finish; 537 udelay(1); 538 } 539 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */ 540 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); 541 pcl818_ai_cancel(dev, s); 542 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 543 comedi_event(dev, s); 544 return IRQ_HANDLED; 545 546conv_finish: 547 low = inb(dev->iobase + PCL818_AD_LO); 548 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */ 549 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ 550 551 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ 552 printk 553 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n", 554 (low & 0xf), 555 devpriv->act_chanlist[devpriv->act_chanlist_pos]); 556 pcl818_ai_cancel(dev, s); 557 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 558 comedi_event(dev, s); 559 return IRQ_HANDLED; 560 } 561 devpriv->act_chanlist_pos++; 562 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { 563 devpriv->act_chanlist_pos = 0; 564 } 565 s->async->cur_chan++; 566 if (s->async->cur_chan >= devpriv->ai_n_chan) { 567 /* printk("E"); */ 568 s->async->cur_chan = 0; 569 devpriv->ai_act_scan--; 570 } 571 572 if (!devpriv->neverending_ai) { 573 if (devpriv->ai_act_scan == 0) { /* all data sampled */ 574 pcl818_ai_cancel(dev, s); 575 s->async->events |= COMEDI_CB_EOA; 576 } 577 } 578 comedi_event(dev, s); 579 return IRQ_HANDLED; 580} 581 582/* 583============================================================================== 584 analog input dma mode 1 & 3, 818 cards 585*/ 586static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) 587{ 588 struct comedi_device *dev = d; 589 struct comedi_subdevice *s = dev->subdevices + 0; 590 int i, len, bufptr; 591 unsigned long flags; 592 short *ptr; 593 594 disable_dma(devpriv->dma); 595 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; 596 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */ 597 set_dma_mode(devpriv->dma, DMA_MODE_READ); 598 flags = claim_dma_lock(); 599 set_dma_addr(devpriv->dma, 600 devpriv->hwdmaptr[devpriv->next_dma_buf]); 601 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) { 602 set_dma_count(devpriv->dma, 603 devpriv->hwdmasize[devpriv-> 604 next_dma_buf]); 605 } else { 606 set_dma_count(devpriv->dma, devpriv->last_dma_run); 607 } 608 release_dma_lock(flags); 609 enable_dma(devpriv->dma); 610 } 611 printk("comedi: A/D mode1/3 IRQ \n"); 612 613 devpriv->dma_runs_to_end--; 614 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ 615 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; 616 617 len = devpriv->hwdmasize[0] >> 1; 618 bufptr = 0; 619 620 for (i = 0; i < len; i++) { 621 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ 622 printk 623 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n", 624 (ptr[bufptr] & 0xf), 625 devpriv->act_chanlist[devpriv->act_chanlist_pos], 626 devpriv->act_chanlist_pos); 627 pcl818_ai_cancel(dev, s); 628 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 629 comedi_event(dev, s); 630 return IRQ_HANDLED; 631 } 632 633 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */ 634 635 devpriv->act_chanlist_pos++; 636 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { 637 devpriv->act_chanlist_pos = 0; 638 } 639 s->async->cur_chan++; 640 if (s->async->cur_chan >= devpriv->ai_n_chan) { 641 s->async->cur_chan = 0; 642 devpriv->ai_act_scan--; 643 } 644 645 if (!devpriv->neverending_ai) 646 if (devpriv->ai_act_scan == 0) { /* all data sampled */ 647 pcl818_ai_cancel(dev, s); 648 s->async->events |= COMEDI_CB_EOA; 649 comedi_event(dev, s); 650 /* printk("done int ai13 dma\n"); */ 651 return IRQ_HANDLED; 652 } 653 } 654 655 if (len > 0) 656 comedi_event(dev, s); 657 return IRQ_HANDLED; 658} 659 660#ifdef unused 661/* 662============================================================================== 663 analog input dma mode 1 & 3 over RTC, 818 cards 664*/ 665static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) 666{ 667 struct comedi_device *dev = d; 668 struct comedi_subdevice *s = dev->subdevices + 0; 669 unsigned long tmp; 670 unsigned int top1, top2, i, bufptr; 671 long ofs_dats; 672 short *dmabuf = (short *)devpriv->dmabuf[0]; 673 674 /* outb(2,0x378); */ 675 switch (devpriv->ai_mode) { 676 case INT_TYPE_AI1_DMA_RTC: 677 case INT_TYPE_AI3_DMA_RTC: 678 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); 679 mod_timer(&devpriv->rtc_irq_timer, 680 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100); 681 682 for (i = 0; i < 10; i++) { 683 top1 = get_dma_residue(devpriv->dma); 684 top2 = get_dma_residue(devpriv->dma); 685 if (top1 == top2) 686 break; 687 } 688 689 if (top1 != top2) 690 return IRQ_HANDLED; 691 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */ 692 top1 >>= 1; 693 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */ 694 if (ofs_dats < 0) 695 ofs_dats = (devpriv->dmasamplsize) + ofs_dats; 696 if (!ofs_dats) 697 return IRQ_HANDLED; /* exit=no new samples from last call */ 698 /* obsluz data */ 699 i = devpriv->last_top_dma - 1; 700 i &= (devpriv->dmasamplsize - 1); 701 702 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */ 703 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!"); 704 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */ 705 pcl818_ai_cancel(dev, s); 706 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 707 comedi_event(dev, s); 708 return IRQ_HANDLED; 709 } 710 /* printk("r %ld ",ofs_dats); */ 711 712 bufptr = devpriv->last_top_dma; 713 714 for (i = 0; i < ofs_dats; i++) { 715 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ 716 printk 717 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n", 718 (dmabuf[bufptr] & 0xf), 719 devpriv-> 720 act_chanlist[devpriv->act_chanlist_pos]); 721 pcl818_ai_cancel(dev, s); 722 s->async->events |= 723 COMEDI_CB_EOA | COMEDI_CB_ERROR; 724 comedi_event(dev, s); 725 return IRQ_HANDLED; 726 } 727 728 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */ 729 bufptr &= (devpriv->dmasamplsize - 1); 730 731 devpriv->act_chanlist_pos++; 732 if (devpriv->act_chanlist_pos >= 733 devpriv->act_chanlist_len) { 734 devpriv->act_chanlist_pos = 0; 735 } 736 s->async->cur_chan++; 737 if (s->async->cur_chan >= devpriv->ai_n_chan) { 738 s->async->cur_chan = 0; 739 devpriv->ai_act_scan--; 740 } 741 742 if (!devpriv->neverending_ai) 743 if (devpriv->ai_act_scan == 0) { /* all data sampled */ 744 pcl818_ai_cancel(dev, s); 745 s->async->events |= COMEDI_CB_EOA; 746 comedi_event(dev, s); 747 /* printk("done int ai13 dma\n"); */ 748 return IRQ_HANDLED; 749 } 750 } 751 752 devpriv->last_top_dma = bufptr; 753 bufptr--; 754 bufptr &= (devpriv->dmasamplsize - 1); 755 dmabuf[bufptr] = MAGIC_DMA_WORD; 756 comedi_event(dev, s); 757 /* outb(0,0x378); */ 758 return IRQ_HANDLED; 759 } 760 761 /* outb(0,0x378); */ 762 return IRQ_HANDLED; 763} 764#endif 765 766/* 767============================================================================== 768 analog input interrupt mode 1 & 3, 818HD/HG cards 769*/ 770static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) 771{ 772 struct comedi_device *dev = d; 773 struct comedi_subdevice *s = dev->subdevices + 0; 774 int i, len, lo; 775 776 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ 777 778 lo = inb(dev->iobase + PCL818_FI_STATUS); 779 780 if (lo & 4) { 781 comedi_error(dev, "A/D mode1/3 FIFO overflow!"); 782 pcl818_ai_cancel(dev, s); 783 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 784 comedi_event(dev, s); 785 return IRQ_HANDLED; 786 } 787 788 if (lo & 1) { 789 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!"); 790 pcl818_ai_cancel(dev, s); 791 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 792 comedi_event(dev, s); 793 return IRQ_HANDLED; 794 } 795 796 if (lo & 2) { 797 len = 512; 798 } else { 799 len = 0; 800 } 801 802 for (i = 0; i < len; i++) { 803 lo = inb(dev->iobase + PCL818_FI_DATALO); 804 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ 805 printk 806 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n", 807 (lo & 0xf), 808 devpriv->act_chanlist[devpriv->act_chanlist_pos]); 809 pcl818_ai_cancel(dev, s); 810 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 811 comedi_event(dev, s); 812 return IRQ_HANDLED; 813 } 814 815 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */ 816 817 devpriv->act_chanlist_pos++; 818 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { 819 devpriv->act_chanlist_pos = 0; 820 } 821 s->async->cur_chan++; 822 if (s->async->cur_chan >= devpriv->ai_n_chan) { 823 s->async->cur_chan = 0; 824 devpriv->ai_act_scan--; 825 } 826 827 if (!devpriv->neverending_ai) 828 if (devpriv->ai_act_scan == 0) { /* all data sampled */ 829 pcl818_ai_cancel(dev, s); 830 s->async->events |= COMEDI_CB_EOA; 831 comedi_event(dev, s); 832 return IRQ_HANDLED; 833 } 834 } 835 836 if (len > 0) 837 comedi_event(dev, s); 838 return IRQ_HANDLED; 839} 840 841/* 842============================================================================== 843 INT procedure 844*/ 845static irqreturn_t interrupt_pcl818(int irq, void *d) 846{ 847 struct comedi_device *dev = d; 848 849 if (!dev->attached) { 850 comedi_error(dev, "premature interrupt"); 851 return IRQ_HANDLED; 852 } 853 /* printk("I\n"); */ 854 855 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) { 856 if ((devpriv->neverending_ai || (!devpriv->neverending_ai && 857 devpriv->ai_act_scan > 0)) && 858 (devpriv->ai_mode == INT_TYPE_AI1_DMA || 859 devpriv->ai_mode == INT_TYPE_AI3_DMA)) { 860 /* The cleanup from ai_cancel() has been delayed 861 until now because the card doesn't seem to like 862 being reprogrammed while a DMA transfer is in 863 progress. 864 */ 865 struct comedi_subdevice *s = dev->subdevices + 0; 866 devpriv->ai_act_scan = 0; 867 devpriv->neverending_ai = 0; 868 pcl818_ai_cancel(dev, s); 869 } 870 871 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ 872 873 return IRQ_HANDLED; 874 } 875 876 switch (devpriv->ai_mode) { 877 case INT_TYPE_AI1_DMA: 878 case INT_TYPE_AI3_DMA: 879 return interrupt_pcl818_ai_mode13_dma(irq, d); 880 case INT_TYPE_AI1_INT: 881 case INT_TYPE_AI3_INT: 882 return interrupt_pcl818_ai_mode13_int(irq, d); 883 case INT_TYPE_AI1_FIFO: 884 case INT_TYPE_AI3_FIFO: 885 return interrupt_pcl818_ai_mode13_fifo(irq, d); 886#ifdef PCL818_MODE13_AO 887 case INT_TYPE_AO1_INT: 888 case INT_TYPE_AO3_INT: 889 return interrupt_pcl818_ao_mode13_int(irq, d); 890#endif 891 default: 892 break; 893 } 894 895 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ 896 897 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked) 898 || (!devpriv->ai_mode)) { 899 comedi_error(dev, "bad IRQ!"); 900 return IRQ_NONE; 901 } 902 903 comedi_error(dev, "IRQ from unknown source!"); 904 return IRQ_NONE; 905} 906 907/* 908============================================================================== 909 ANALOG INPUT MODE 1 or 3 DMA , 818 cards 910*/ 911static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev, 912 struct comedi_subdevice *s) 913{ 914 unsigned int flags; 915 unsigned int bytes; 916 917 printk("mode13dma_int, mode: %d\n", mode); 918 disable_dma(devpriv->dma); /* disable dma */ 919 bytes = devpriv->hwdmasize[0]; 920 if (!devpriv->neverending_ai) { 921 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */ 922 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */ 923 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ 924 devpriv->dma_runs_to_end--; 925 if (devpriv->dma_runs_to_end >= 0) 926 bytes = devpriv->hwdmasize[0]; 927 } 928 929 devpriv->next_dma_buf = 0; 930 set_dma_mode(devpriv->dma, DMA_MODE_READ); 931 flags = claim_dma_lock(); 932 clear_dma_ff(devpriv->dma); 933 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); 934 set_dma_count(devpriv->dma, bytes); 935 release_dma_lock(flags); 936 enable_dma(devpriv->dma); 937 938 if (mode == 1) { 939 devpriv->ai_mode = INT_TYPE_AI1_DMA; 940 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */ 941 } else { 942 devpriv->ai_mode = INT_TYPE_AI3_DMA; 943 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */ 944 }; 945} 946 947#ifdef unused 948/* 949============================================================================== 950 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards 951*/ 952static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev, 953 struct comedi_subdevice *s) 954{ 955 unsigned int flags; 956 short *pole; 957 958 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT); 959 flags = claim_dma_lock(); 960 clear_dma_ff(devpriv->dma); 961 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); 962 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]); 963 release_dma_lock(flags); 964 enable_dma(devpriv->dma); 965 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */ 966 pole = (short *)devpriv->dmabuf[0]; 967 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2; 968 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD; 969#ifdef unused 970 devpriv->rtc_freq = rtc_setfreq_irq(2048); 971 devpriv->rtc_irq_timer.expires = 972 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100; 973 devpriv->rtc_irq_timer.data = (unsigned long)dev; 974 devpriv->rtc_irq_timer.function = rtc_dropped_irq; 975 976 add_timer(&devpriv->rtc_irq_timer); 977#endif 978 979 if (mode == 1) { 980 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC; 981 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */ 982 } else { 983 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC; 984 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */ 985 }; 986} 987#endif 988 989/* 990============================================================================== 991 ANALOG INPUT MODE 1 or 3, 818 cards 992*/ 993static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, 994 struct comedi_subdevice *s) 995{ 996 struct comedi_cmd *cmd = &s->async->cmd; 997 int divisor1 = 0, divisor2 = 0; 998 unsigned int seglen; 999 1000 printk("pcl818_ai_cmd_mode()\n"); 1001 if ((!dev->irq) && (!devpriv->dma_rtc)) { 1002 comedi_error(dev, "IRQ not defined!"); 1003 return -EINVAL; 1004 } 1005 1006 if (devpriv->irq_blocked) 1007 return -EBUSY; 1008 1009 start_pacer(dev, -1, 0, 0); /* stop pacer */ 1010 1011 seglen = check_channel_list(dev, s, devpriv->ai_chanlist, 1012 devpriv->ai_n_chan); 1013 if (seglen < 1) 1014 return -EINVAL; 1015 setup_channel_list(dev, s, devpriv->ai_chanlist, 1016 devpriv->ai_n_chan, seglen); 1017 1018 udelay(1); 1019 1020 devpriv->ai_act_scan = devpriv->ai_scans; 1021 devpriv->ai_act_chan = 0; 1022 devpriv->irq_blocked = 1; 1023 devpriv->irq_was_now_closed = 0; 1024 devpriv->neverending_ai = 0; 1025 devpriv->act_chanlist_pos = 0; 1026 devpriv->dma_runs_to_end = 0; 1027 1028 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) 1029 devpriv->neverending_ai = 1; /* well, user want neverending */ 1030 1031 if (mode == 1) { 1032 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, 1033 &divisor2, &cmd->convert_arg, 1034 TRIG_ROUND_NEAREST); 1035 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */ 1036 divisor1 = 2; 1037 divisor2 /= 2; 1038 } 1039 if (divisor2 == 1) { 1040 divisor2 = 2; 1041 divisor1 /= 2; 1042 } 1043 } 1044 1045 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ 1046 1047 switch (devpriv->dma) { 1048 case 1: /* DMA */ 1049 case 3: 1050 if (devpriv->dma_rtc == 0) { 1051 pcl818_ai_mode13dma_int(mode, dev, s); 1052 } 1053#ifdef unused 1054 else { 1055 pcl818_ai_mode13dma_rtc(mode, dev, s); 1056 } 1057#else 1058 else { 1059 return -EINVAL; 1060 } 1061#endif 1062 break; 1063 case 0: 1064 if (!devpriv->usefifo) { 1065 /* IRQ */ 1066 /* printk("IRQ\n"); */ 1067 if (mode == 1) { 1068 devpriv->ai_mode = INT_TYPE_AI1_INT; 1069 /* Pacer+IRQ */ 1070 outb(0x83 | (dev->irq << 4), 1071 dev->iobase + PCL818_CONTROL); 1072 } else { 1073 devpriv->ai_mode = INT_TYPE_AI3_INT; 1074 /* Ext trig+IRQ */ 1075 outb(0x82 | (dev->irq << 4), 1076 dev->iobase + PCL818_CONTROL); 1077 } 1078 } else { 1079 /* FIFO */ 1080 /* enable FIFO */ 1081 outb(1, dev->iobase + PCL818_FI_ENABLE); 1082 if (mode == 1) { 1083 devpriv->ai_mode = INT_TYPE_AI1_FIFO; 1084 /* Pacer */ 1085 outb(0x03, dev->iobase + PCL818_CONTROL); 1086 } else { 1087 devpriv->ai_mode = INT_TYPE_AI3_FIFO; 1088 outb(0x02, dev->iobase + PCL818_CONTROL); 1089 } 1090 } 1091 } 1092 1093 start_pacer(dev, mode, divisor1, divisor2); 1094 1095#ifdef unused 1096 switch (devpriv->ai_mode) { 1097 case INT_TYPE_AI1_DMA_RTC: 1098 case INT_TYPE_AI3_DMA_RTC: 1099 set_rtc_irq_bit(1); /* start RTC */ 1100 break; 1101 } 1102#endif 1103 printk("pcl818_ai_cmd_mode() end\n"); 1104 return 0; 1105} 1106 1107#ifdef unused 1108/* 1109============================================================================== 1110 ANALOG OUTPUT MODE 1 or 3, 818 cards 1111*/ 1112#ifdef PCL818_MODE13_AO 1113static int pcl818_ao_mode13(int mode, struct comedi_device *dev, 1114 struct comedi_subdevice *s, comedi_trig * it) 1115{ 1116 int divisor1 = 0, divisor2 = 0; 1117 1118 if (!dev->irq) { 1119 comedi_error(dev, "IRQ not defined!"); 1120 return -EINVAL; 1121 } 1122 1123 if (devpriv->irq_blocked) 1124 return -EBUSY; 1125 1126 start_pacer(dev, -1, 0, 0); /* stop pacer */ 1127 1128 devpriv->int13_act_scan = it->n; 1129 devpriv->int13_act_chan = 0; 1130 devpriv->irq_blocked = 1; 1131 devpriv->irq_was_now_closed = 0; 1132 devpriv->neverending_ai = 0; 1133 devpriv->act_chanlist_pos = 0; 1134 1135 if (mode == 1) { 1136 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, 1137 &divisor2, &it->trigvar, 1138 TRIG_ROUND_NEAREST); 1139 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */ 1140 divisor1 = 2; 1141 divisor2 /= 2; 1142 } 1143 if (divisor2 == 1) { 1144 divisor2 = 2; 1145 divisor1 /= 2; 1146 } 1147 } 1148 1149 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ 1150 if (mode == 1) { 1151 devpriv->int818_mode = INT_TYPE_AO1_INT; 1152 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */ 1153 } else { 1154 devpriv->int818_mode = INT_TYPE_AO3_INT; 1155 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */ 1156 }; 1157 1158 start_pacer(dev, mode, divisor1, divisor2); 1159 1160 return 0; 1161} 1162 1163/* 1164============================================================================== 1165 ANALOG OUTPUT MODE 1, 818 cards 1166*/ 1167static int pcl818_ao_mode1(struct comedi_device *dev, 1168 struct comedi_subdevice *s, comedi_trig * it) 1169{ 1170 return pcl818_ao_mode13(1, dev, s, it); 1171} 1172 1173/* 1174============================================================================== 1175 ANALOG OUTPUT MODE 3, 818 cards 1176*/ 1177static int pcl818_ao_mode3(struct comedi_device *dev, 1178 struct comedi_subdevice *s, comedi_trig * it) 1179{ 1180 return pcl818_ao_mode13(3, dev, s, it); 1181} 1182#endif 1183#endif 1184 1185/* 1186============================================================================== 1187 Start/stop pacer onboard pacer 1188*/ 1189static void start_pacer(struct comedi_device *dev, int mode, 1190 unsigned int divisor1, unsigned int divisor2) 1191{ 1192 outb(0xb4, dev->iobase + PCL818_CTRCTL); 1193 outb(0x74, dev->iobase + PCL818_CTRCTL); 1194 udelay(1); 1195 1196 if (mode == 1) { 1197 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2); 1198 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2); 1199 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1); 1200 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1); 1201 } 1202} 1203 1204/* 1205============================================================================== 1206 Check if channel list from user is builded correctly 1207 If it's ok, then program scan/gain logic 1208*/ 1209static int check_channel_list(struct comedi_device *dev, 1210 struct comedi_subdevice *s, 1211 unsigned int *chanlist, unsigned int n_chan) 1212{ 1213 unsigned int chansegment[16]; 1214 unsigned int i, nowmustbechan, seglen, segpos; 1215 1216 /* correct channel and range number check itself comedi/range.c */ 1217 if (n_chan < 1) { 1218 comedi_error(dev, "range/channel list is empty!"); 1219 return 0; 1220 } 1221 1222 if (n_chan > 1) { 1223 /* first channel is everytime ok */ 1224 chansegment[0] = chanlist[0]; 1225 /* build part of chanlist */ 1226 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { 1227 1228 /* printk("%d. %d * %d\n",i, 1229 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/ 1230 1231 /* we detect loop, this must by finish */ 1232 1233 if (chanlist[0] == chanlist[i]) 1234 break; 1235 nowmustbechan = 1236 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; 1237 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */ 1238 printk 1239 ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", 1240 dev->minor, i, CR_CHAN(chanlist[i]), 1241 nowmustbechan, CR_CHAN(chanlist[0])); 1242 return 0; 1243 } 1244 /* well, this is next correct channel in list */ 1245 chansegment[i] = chanlist[i]; 1246 } 1247 1248 /* check whole chanlist */ 1249 for (i = 0, segpos = 0; i < n_chan; i++) { 1250 /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); */ 1251 if (chanlist[i] != chansegment[i % seglen]) { 1252 printk 1253 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", 1254 dev->minor, i, CR_CHAN(chansegment[i]), 1255 CR_RANGE(chansegment[i]), 1256 CR_AREF(chansegment[i]), 1257 CR_CHAN(chanlist[i % seglen]), 1258 CR_RANGE(chanlist[i % seglen]), 1259 CR_AREF(chansegment[i % seglen])); 1260 return 0; /* chan/gain list is strange */ 1261 } 1262 } 1263 } else { 1264 seglen = 1; 1265 } 1266 printk("check_channel_list: seglen %d\n", seglen); 1267 return seglen; 1268} 1269 1270static void setup_channel_list(struct comedi_device *dev, 1271 struct comedi_subdevice *s, 1272 unsigned int *chanlist, unsigned int n_chan, 1273 unsigned int seglen) 1274{ 1275 int i; 1276 1277 devpriv->act_chanlist_len = seglen; 1278 devpriv->act_chanlist_pos = 0; 1279 1280 for (i = 0; i < seglen; i++) { /* store range list to card */ 1281 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); 1282 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */ 1283 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */ 1284 } 1285 1286 udelay(1); 1287 1288 /* select channel interval to scan */ 1289 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen - 1290 1] << 4), 1291 dev->iobase + PCL818_MUX); 1292} 1293 1294/* 1295============================================================================== 1296 Check if board is switched to SE (1) or DIFF(0) mode 1297*/ 1298static int check_single_ended(unsigned int port) 1299{ 1300 if (inb(port + PCL818_STATUS) & 0x20) { 1301 return 1; 1302 } else { 1303 return 0; 1304 } 1305} 1306 1307/* 1308============================================================================== 1309*/ 1310static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, 1311 struct comedi_cmd *cmd) 1312{ 1313 int err = 0; 1314 int tmp, divisor1 = 0, divisor2 = 0; 1315 1316 /* step 1: make sure trigger sources are trivially valid */ 1317 1318 tmp = cmd->start_src; 1319 cmd->start_src &= TRIG_NOW; 1320 if (!cmd->start_src || tmp != cmd->start_src) 1321 err++; 1322 1323 tmp = cmd->scan_begin_src; 1324 cmd->scan_begin_src &= TRIG_FOLLOW; 1325 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 1326 err++; 1327 1328 tmp = cmd->convert_src; 1329 cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 1330 if (!cmd->convert_src || tmp != cmd->convert_src) 1331 err++; 1332 1333 tmp = cmd->scan_end_src; 1334 cmd->scan_end_src &= TRIG_COUNT; 1335 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 1336 err++; 1337 1338 tmp = cmd->stop_src; 1339 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 1340 if (!cmd->stop_src || tmp != cmd->stop_src) 1341 err++; 1342 1343 if (err) { 1344 return 1; 1345 } 1346 1347 /* step 2: make sure trigger sources are unique and mutually compatible */ 1348 1349 if (cmd->start_src != TRIG_NOW) { 1350 cmd->start_src = TRIG_NOW; 1351 err++; 1352 } 1353 if (cmd->scan_begin_src != TRIG_FOLLOW) { 1354 cmd->scan_begin_src = TRIG_FOLLOW; 1355 err++; 1356 } 1357 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 1358 err++; 1359 1360 if (cmd->scan_end_src != TRIG_COUNT) { 1361 cmd->scan_end_src = TRIG_COUNT; 1362 err++; 1363 } 1364 1365 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) 1366 err++; 1367 1368 if (err) { 1369 return 2; 1370 } 1371 1372 /* step 3: make sure arguments are trivially compatible */ 1373 1374 if (cmd->start_arg != 0) { 1375 cmd->start_arg = 0; 1376 err++; 1377 } 1378 1379 if (cmd->scan_begin_arg != 0) { 1380 cmd->scan_begin_arg = 0; 1381 err++; 1382 } 1383 1384 if (cmd->convert_src == TRIG_TIMER) { 1385 if (cmd->convert_arg < this_board->ns_min) { 1386 cmd->convert_arg = this_board->ns_min; 1387 err++; 1388 } 1389 } else { /* TRIG_EXT */ 1390 if (cmd->convert_arg != 0) { 1391 cmd->convert_arg = 0; 1392 err++; 1393 } 1394 } 1395 1396 if (cmd->scan_end_arg != cmd->chanlist_len) { 1397 cmd->scan_end_arg = cmd->chanlist_len; 1398 err++; 1399 } 1400 if (cmd->stop_src == TRIG_COUNT) { 1401 if (!cmd->stop_arg) { 1402 cmd->stop_arg = 1; 1403 err++; 1404 } 1405 } else { /* TRIG_NONE */ 1406 if (cmd->stop_arg != 0) { 1407 cmd->stop_arg = 0; 1408 err++; 1409 } 1410 } 1411 1412 if (err) { 1413 return 3; 1414 } 1415 1416 /* step 4: fix up any arguments */ 1417 1418 if (cmd->convert_src == TRIG_TIMER) { 1419 tmp = cmd->convert_arg; 1420 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, 1421 &divisor2, &cmd->convert_arg, 1422 cmd->flags & TRIG_ROUND_MASK); 1423 if (cmd->convert_arg < this_board->ns_min) 1424 cmd->convert_arg = this_board->ns_min; 1425 if (tmp != cmd->convert_arg) 1426 err++; 1427 } 1428 1429 if (err) { 1430 return 4; 1431 } 1432 1433 /* step 5: complain about special chanlist considerations */ 1434 1435 if (cmd->chanlist) { 1436 if (!check_channel_list(dev, s, cmd->chanlist, 1437 cmd->chanlist_len)) 1438 return 5; /* incorrect channels list */ 1439 } 1440 1441 return 0; 1442} 1443 1444/* 1445============================================================================== 1446*/ 1447static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 1448{ 1449 struct comedi_cmd *cmd = &s->async->cmd; 1450 int retval; 1451 1452 printk("pcl818_ai_cmd()\n"); 1453 devpriv->ai_n_chan = cmd->chanlist_len; 1454 devpriv->ai_chanlist = cmd->chanlist; 1455 devpriv->ai_flags = cmd->flags; 1456 devpriv->ai_data_len = s->async->prealloc_bufsz; 1457 devpriv->ai_data = s->async->prealloc_buf; 1458 devpriv->ai_timer1 = 0; 1459 devpriv->ai_timer2 = 0; 1460 1461 if (cmd->stop_src == TRIG_COUNT) { 1462 devpriv->ai_scans = cmd->stop_arg; 1463 } else { 1464 devpriv->ai_scans = 0; 1465 } 1466 1467 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */ 1468 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */ 1469 devpriv->ai_timer1 = cmd->convert_arg; 1470 retval = pcl818_ai_cmd_mode(1, dev, s); 1471 printk("pcl818_ai_cmd() end\n"); 1472 return retval; 1473 } 1474 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ 1475 return pcl818_ai_cmd_mode(3, dev, s); 1476 } 1477 } 1478 1479 return -1; 1480} 1481 1482/* 1483============================================================================== 1484 cancel any mode 1-4 AI 1485*/ 1486static int pcl818_ai_cancel(struct comedi_device *dev, 1487 struct comedi_subdevice *s) 1488{ 1489 if (devpriv->irq_blocked > 0) { 1490 printk("pcl818_ai_cancel()\n"); 1491 devpriv->irq_was_now_closed = 1; 1492 1493 switch (devpriv->ai_mode) { 1494#ifdef unused 1495 case INT_TYPE_AI1_DMA_RTC: 1496 case INT_TYPE_AI3_DMA_RTC: 1497 set_rtc_irq_bit(0); /* stop RTC */ 1498 del_timer(&devpriv->rtc_irq_timer); 1499#endif 1500 case INT_TYPE_AI1_DMA: 1501 case INT_TYPE_AI3_DMA: 1502 if (devpriv->neverending_ai || 1503 (!devpriv->neverending_ai && 1504 devpriv->ai_act_scan > 0)) { 1505 /* wait for running dma transfer to end, do cleanup in interrupt */ 1506 goto end; 1507 } 1508 disable_dma(devpriv->dma); 1509 case INT_TYPE_AI1_INT: 1510 case INT_TYPE_AI3_INT: 1511 case INT_TYPE_AI1_FIFO: 1512 case INT_TYPE_AI3_FIFO: 1513#ifdef PCL818_MODE13_AO 1514 case INT_TYPE_AO1_INT: 1515 case INT_TYPE_AO3_INT: 1516#endif 1517 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */ 1518 udelay(1); 1519 start_pacer(dev, -1, 0, 0); 1520 outb(0, dev->iobase + PCL818_AD_LO); 1521 inb(dev->iobase + PCL818_AD_LO); 1522 inb(dev->iobase + PCL818_AD_HI); 1523 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ 1524 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */ 1525 if (devpriv->usefifo) { /* FIFO shutdown */ 1526 outb(0, dev->iobase + PCL818_FI_INTCLR); 1527 outb(0, dev->iobase + PCL818_FI_FLUSH); 1528 outb(0, dev->iobase + PCL818_FI_ENABLE); 1529 } 1530 devpriv->irq_blocked = 0; 1531 devpriv->last_int_sub = s; 1532 devpriv->neverending_ai = 0; 1533 devpriv->ai_mode = 0; 1534 devpriv->irq_was_now_closed = 0; 1535 break; 1536 } 1537 } 1538 1539end: 1540 printk("pcl818_ai_cancel() end\n"); 1541 return 0; 1542} 1543 1544/* 1545============================================================================== 1546 chech for PCL818 1547*/ 1548static int pcl818_check(unsigned long iobase) 1549{ 1550 outb(0x00, iobase + PCL818_MUX); 1551 udelay(1); 1552 if (inb(iobase + PCL818_MUX) != 0x00) 1553 return 1; /* there isn't card */ 1554 outb(0x55, iobase + PCL818_MUX); 1555 udelay(1); 1556 if (inb(iobase + PCL818_MUX) != 0x55) 1557 return 1; /* there isn't card */ 1558 outb(0x00, iobase + PCL818_MUX); 1559 udelay(1); 1560 outb(0x18, iobase + PCL818_CONTROL); 1561 udelay(1); 1562 if (inb(iobase + PCL818_CONTROL) != 0x18) 1563 return 1; /* there isn't card */ 1564 return 0; /* ok, card exist */ 1565} 1566 1567/* 1568============================================================================== 1569 reset whole PCL-818 cards 1570*/ 1571static void pcl818_reset(struct comedi_device *dev) 1572{ 1573 if (devpriv->usefifo) { /* FIFO shutdown */ 1574 outb(0, dev->iobase + PCL818_FI_INTCLR); 1575 outb(0, dev->iobase + PCL818_FI_FLUSH); 1576 outb(0, dev->iobase + PCL818_FI_ENABLE); 1577 } 1578 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */ 1579 outb(0, dev->iobase + PCL818_DA_HI); 1580 udelay(1); 1581 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */ 1582 outb(0, dev->iobase + PCL818_DO_LO); 1583 udelay(1); 1584 outb(0, dev->iobase + PCL818_CONTROL); 1585 outb(0, dev->iobase + PCL818_CNTENABLE); 1586 outb(0, dev->iobase + PCL818_MUX); 1587 outb(0, dev->iobase + PCL818_CLRINT); 1588 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */ 1589 outb(0x70, dev->iobase + PCL818_CTRCTL); 1590 outb(0x30, dev->iobase + PCL818_CTRCTL); 1591 if (this_board->is_818) { 1592 outb(0, dev->iobase + PCL818_RANGE); 1593 } else { 1594 outb(0, dev->iobase + PCL718_DA2_LO); 1595 outb(0, dev->iobase + PCL718_DA2_HI); 1596 } 1597} 1598 1599#ifdef unused 1600/* 1601============================================================================== 1602 Enable(1)/disable(0) periodic interrupts from RTC 1603*/ 1604static int set_rtc_irq_bit(unsigned char bit) 1605{ 1606 unsigned char val; 1607 unsigned long flags; 1608 1609 if (bit == 1) { 1610 RTC_timer_lock++; 1611 if (RTC_timer_lock > 1) 1612 return 0; 1613 } else { 1614 RTC_timer_lock--; 1615 if (RTC_timer_lock < 0) 1616 RTC_timer_lock = 0; 1617 if (RTC_timer_lock > 0) 1618 return 0; 1619 } 1620 1621 save_flags(flags); 1622 cli(); 1623 val = CMOS_READ(RTC_CONTROL); 1624 if (bit) { 1625 val |= RTC_PIE; 1626 } else { 1627 val &= ~RTC_PIE; 1628 } 1629 CMOS_WRITE(val, RTC_CONTROL); 1630 CMOS_READ(RTC_INTR_FLAGS); 1631 restore_flags(flags); 1632 return 0; 1633} 1634 1635/* 1636============================================================================== 1637 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers) 1638*/ 1639static void rtc_dropped_irq(unsigned long data) 1640{ 1641 struct comedi_device *dev = (void *)data; 1642 unsigned long flags, tmp; 1643 1644 switch (devpriv->int818_mode) { 1645 case INT_TYPE_AI1_DMA_RTC: 1646 case INT_TYPE_AI3_DMA_RTC: 1647 mod_timer(&devpriv->rtc_irq_timer, 1648 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100); 1649 save_flags(flags); 1650 cli(); 1651 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ 1652 restore_flags(flags); 1653 break; 1654 }; 1655} 1656 1657/* 1658============================================================================== 1659 Set frequency of interrupts from RTC 1660*/ 1661static int rtc_setfreq_irq(int freq) 1662{ 1663 int tmp = 0; 1664 int rtc_freq; 1665 unsigned char val; 1666 unsigned long flags; 1667 1668 if (freq < 2) 1669 freq = 2; 1670 if (freq > 8192) 1671 freq = 8192; 1672 1673 while (freq > (1 << tmp)) 1674 tmp++; 1675 1676 rtc_freq = 1 << tmp; 1677 1678 save_flags(flags); 1679 cli(); 1680 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; 1681 val |= (16 - tmp); 1682 CMOS_WRITE(val, RTC_FREQ_SELECT); 1683 restore_flags(flags); 1684 return rtc_freq; 1685} 1686#endif 1687 1688/* 1689============================================================================== 1690 Free any resources that we have claimed 1691*/ 1692static void free_resources(struct comedi_device *dev) 1693{ 1694 /* printk("free_resource()\n"); */ 1695 if (dev->private) { 1696 pcl818_ai_cancel(dev, devpriv->sub_ai); 1697 pcl818_reset(dev); 1698 if (devpriv->dma) 1699 free_dma(devpriv->dma); 1700 if (devpriv->dmabuf[0]) 1701 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); 1702 if (devpriv->dmabuf[1]) 1703 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); 1704#ifdef unused 1705 if (devpriv->rtc_irq) 1706 free_irq(devpriv->rtc_irq, dev); 1707 if ((devpriv->dma_rtc) && (RTC_lock == 1)) { 1708 if (devpriv->rtc_iobase) 1709 release_region(devpriv->rtc_iobase, 1710 devpriv->rtc_iosize); 1711 } 1712 if (devpriv->dma_rtc) 1713 RTC_lock--; 1714#endif 1715 } 1716 1717 if (dev->irq) 1718 free_irq(dev->irq, dev); 1719 if (dev->iobase) 1720 release_region(dev->iobase, devpriv->io_range); 1721 /* printk("free_resource() end\n"); */ 1722} 1723 1724/* 1725============================================================================== 1726 1727 Initialization 1728 1729*/ 1730static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) 1731{ 1732 int ret; 1733 unsigned long iobase; 1734 unsigned int irq; 1735 int dma; 1736 unsigned long pages; 1737 struct comedi_subdevice *s; 1738 1739 ret = alloc_private(dev, sizeof(struct pcl818_private)); 1740 if (ret < 0) 1741 return ret; /* Can't alloc mem */ 1742 1743 /* claim our I/O space */ 1744 iobase = it->options[0]; 1745 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx", 1746 dev->minor, this_board->name, iobase); 1747 devpriv->io_range = this_board->io_range; 1748 if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */ 1749 devpriv->io_range = PCLx1xFIFO_RANGE; 1750 devpriv->usefifo = 1; 1751 } 1752 if (!request_region(iobase, devpriv->io_range, "pcl818")) { 1753 printk("I/O port conflict\n"); 1754 return -EIO; 1755 } 1756 1757 dev->iobase = iobase; 1758 1759 if (pcl818_check(iobase)) { 1760 printk(", I can't detect board. FAIL!\n"); 1761 return -EIO; 1762 } 1763 1764 /* set up some name stuff */ 1765 dev->board_name = this_board->name; 1766 /* grab our IRQ */ 1767 irq = 0; 1768 if (this_board->IRQbits != 0) { /* board support IRQ */ 1769 irq = it->options[1]; 1770 if (irq) { /* we want to use IRQ */ 1771 if (((1 << irq) & this_board->IRQbits) == 0) { 1772 printk 1773 (", IRQ %u is out of allowed range, DISABLING IT", 1774 irq); 1775 irq = 0; /* Bad IRQ */ 1776 } else { 1777 if (request_irq 1778 (irq, interrupt_pcl818, 0, "pcl818", dev)) { 1779 printk 1780 (", unable to allocate IRQ %u, DISABLING IT", 1781 irq); 1782 irq = 0; /* Can't use IRQ */ 1783 } else { 1784 printk(", irq=%u", irq); 1785 } 1786 } 1787 } 1788 } 1789 1790 dev->irq = irq; 1791 if (irq) { 1792 devpriv->irq_free = 1; 1793 } /* 1=we have allocated irq */ 1794 else { 1795 devpriv->irq_free = 0; 1796 } 1797 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ 1798 devpriv->ai_mode = 0; /* mode of irq */ 1799 1800#ifdef unused 1801 /* grab RTC for DMA operations */ 1802 devpriv->dma_rtc = 0; 1803 if (it->options[2] > 0) { /* we want to use DMA */ 1804 if (RTC_lock == 0) { 1805 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, 1806 "pcl818 (RTC)")) 1807 goto no_rtc; 1808 } 1809 devpriv->rtc_iobase = RTC_PORT(0); 1810 devpriv->rtc_iosize = RTC_IO_EXTENT; 1811 RTC_lock++; 1812 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0, 1813 "pcl818 DMA (RTC)", dev)) { 1814 devpriv->dma_rtc = 1; 1815 devpriv->rtc_irq = RTC_IRQ; 1816 printk(", dma_irq=%u", devpriv->rtc_irq); 1817 } else { 1818 RTC_lock--; 1819 if (RTC_lock == 0) { 1820 if (devpriv->rtc_iobase) 1821 release_region(devpriv->rtc_iobase, 1822 devpriv->rtc_iosize); 1823 } 1824 devpriv->rtc_iobase = 0; 1825 devpriv->rtc_iosize = 0; 1826 } 1827 } 1828 1829no_rtc: 1830#endif 1831 /* grab our DMA */ 1832 dma = 0; 1833 devpriv->dma = dma; 1834 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0)) 1835 goto no_dma; /* if we haven't IRQ, we can't use DMA */ 1836 if (this_board->DMAbits != 0) { /* board support DMA */ 1837 dma = it->options[2]; 1838 if (dma < 1) 1839 goto no_dma; /* DMA disabled */ 1840 if (((1 << dma) & this_board->DMAbits) == 0) { 1841 printk(", DMA is out of allowed range, FAIL!\n"); 1842 return -EINVAL; /* Bad DMA */ 1843 } 1844 ret = request_dma(dma, "pcl818"); 1845 if (ret) { 1846 printk(", unable to allocate DMA %u, FAIL!\n", dma); 1847 return -EBUSY; /* DMA isn't free */ 1848 } 1849 devpriv->dma = dma; 1850 printk(", dma=%u", dma); 1851 pages = 2; /* we need 16KB */ 1852 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); 1853 if (!devpriv->dmabuf[0]) { 1854 printk(", unable to allocate DMA buffer, FAIL!\n"); 1855 /* maybe experiment with try_to_free_pages() will help .... */ 1856 return -EBUSY; /* no buffer :-( */ 1857 } 1858 devpriv->dmapages[0] = pages; 1859 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); 1860 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; 1861 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ 1862 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */ 1863 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); 1864 if (!devpriv->dmabuf[1]) { 1865 printk 1866 (", unable to allocate DMA buffer, FAIL!\n"); 1867 return -EBUSY; 1868 } 1869 devpriv->dmapages[1] = pages; 1870 devpriv->hwdmaptr[1] = 1871 virt_to_bus((void *)devpriv->dmabuf[1]); 1872 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; 1873 } 1874 } 1875 1876no_dma: 1877 1878 ret = alloc_subdevices(dev, 4); 1879 if (ret < 0) 1880 return ret; 1881 1882 s = dev->subdevices + 0; 1883 if (!this_board->n_aichan_se) { 1884 s->type = COMEDI_SUBD_UNUSED; 1885 } else { 1886 s->type = COMEDI_SUBD_AI; 1887 devpriv->sub_ai = s; 1888 s->subdev_flags = SDF_READABLE; 1889 if (check_single_ended(dev->iobase)) { 1890 s->n_chan = this_board->n_aichan_se; 1891 s->subdev_flags |= SDF_COMMON | SDF_GROUND; 1892 printk(", %dchans S.E. DAC", s->n_chan); 1893 } else { 1894 s->n_chan = this_board->n_aichan_diff; 1895 s->subdev_flags |= SDF_DIFF; 1896 printk(", %dchans DIFF DAC", s->n_chan); 1897 } 1898 s->maxdata = this_board->ai_maxdata; 1899 s->len_chanlist = s->n_chan; 1900 s->range_table = this_board->ai_range_type; 1901 s->cancel = pcl818_ai_cancel; 1902 s->insn_read = pcl818_ai_insn_read; 1903 if ((irq) || (devpriv->dma_rtc)) { 1904 dev->read_subdev = s; 1905 s->subdev_flags |= SDF_CMD_READ; 1906 s->do_cmdtest = ai_cmdtest; 1907 s->do_cmd = ai_cmd; 1908 } 1909 if (this_board->is_818) { 1910 if ((it->options[4] == 1) || (it->options[4] == 10)) 1911 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */ 1912 } else { 1913 switch (it->options[4]) { 1914 case 0: 1915 s->range_table = &range_bipolar10; 1916 break; 1917 case 1: 1918 s->range_table = &range_bipolar5; 1919 break; 1920 case 2: 1921 s->range_table = &range_bipolar2_5; 1922 break; 1923 case 3: 1924 s->range_table = &range718_bipolar1; 1925 break; 1926 case 4: 1927 s->range_table = &range718_bipolar0_5; 1928 break; 1929 case 6: 1930 s->range_table = &range_unipolar10; 1931 break; 1932 case 7: 1933 s->range_table = &range_unipolar5; 1934 break; 1935 case 8: 1936 s->range_table = &range718_unipolar2; 1937 break; 1938 case 9: 1939 s->range_table = &range718_unipolar1; 1940 break; 1941 default: 1942 s->range_table = &range_unknown; 1943 break; 1944 } 1945 } 1946 } 1947 1948 s = dev->subdevices + 1; 1949 if (!this_board->n_aochan) { 1950 s->type = COMEDI_SUBD_UNUSED; 1951 } else { 1952 s->type = COMEDI_SUBD_AO; 1953 s->subdev_flags = SDF_WRITABLE | SDF_GROUND; 1954 s->n_chan = this_board->n_aochan; 1955 s->maxdata = this_board->ao_maxdata; 1956 s->len_chanlist = this_board->n_aochan; 1957 s->range_table = this_board->ao_range_type; 1958 s->insn_read = pcl818_ao_insn_read; 1959 s->insn_write = pcl818_ao_insn_write; 1960#ifdef unused 1961#ifdef PCL818_MODE13_AO 1962 if (irq) { 1963 s->trig[1] = pcl818_ao_mode1; 1964 s->trig[3] = pcl818_ao_mode3; 1965 } 1966#endif 1967#endif 1968 if (this_board->is_818) { 1969 if ((it->options[4] == 1) || (it->options[4] == 10)) 1970 s->range_table = &range_unipolar10; 1971 if (it->options[4] == 2) 1972 s->range_table = &range_unknown; 1973 } else { 1974 if ((it->options[5] == 1) || (it->options[5] == 10)) 1975 s->range_table = &range_unipolar10; 1976 if (it->options[5] == 2) 1977 s->range_table = &range_unknown; 1978 } 1979 } 1980 1981 s = dev->subdevices + 2; 1982 if (!this_board->n_dichan) { 1983 s->type = COMEDI_SUBD_UNUSED; 1984 } else { 1985 s->type = COMEDI_SUBD_DI; 1986 s->subdev_flags = SDF_READABLE; 1987 s->n_chan = this_board->n_dichan; 1988 s->maxdata = 1; 1989 s->len_chanlist = this_board->n_dichan; 1990 s->range_table = &range_digital; 1991 s->insn_bits = pcl818_di_insn_bits; 1992 } 1993 1994 s = dev->subdevices + 3; 1995 if (!this_board->n_dochan) { 1996 s->type = COMEDI_SUBD_UNUSED; 1997 } else { 1998 s->type = COMEDI_SUBD_DO; 1999 s->subdev_flags = SDF_WRITABLE; 2000 s->n_chan = this_board->n_dochan; 2001 s->maxdata = 1; 2002 s->len_chanlist = this_board->n_dochan; 2003 s->range_table = &range_digital; 2004 s->insn_bits = pcl818_do_insn_bits; 2005 } 2006 2007 /* select 1/10MHz oscilator */ 2008 if ((it->options[3] == 0) || (it->options[3] == 10)) { 2009 devpriv->i8253_osc_base = 100; 2010 } else { 2011 devpriv->i8253_osc_base = 1000; 2012 } 2013 2014 /* max sampling speed */ 2015 devpriv->ns_min = this_board->ns_min; 2016 2017 if (!this_board->is_818) { 2018 if ((it->options[6] == 1) || (it->options[6] == 100)) 2019 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */ 2020 } 2021 2022 pcl818_reset(dev); 2023 2024 printk("\n"); 2025 2026 return 0; 2027} 2028 2029/* 2030============================================================================== 2031 Removes device 2032 */ 2033static int pcl818_detach(struct comedi_device *dev) 2034{ 2035 /* printk("comedi%d: pcl818: remove\n", dev->minor); */ 2036 free_resources(dev); 2037 return 0; 2038} 2039 2040MODULE_AUTHOR("Comedi http://www.comedi.org"); 2041MODULE_DESCRIPTION("Comedi low-level driver"); 2042MODULE_LICENSE("GPL"); 2043