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