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