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