📄 pcl812.c
字号:
if (devpriv->ai_dma) { interrupt_pcl812_ai_dma(irq, d, regs); } else { interrupt_pcl812_ai_int(irq, d, regs); };}/*==============================================================================*/static int pcl812_ai_poll(comedi_device *dev,comedi_subdevice *s){ unsigned long flags; unsigned int top1,top2,i; if (!devpriv->ai_dma) return 0; // poll is valid only for DMA transfer comedi_spin_lock_irqsave(&dev->spinlock,flags); for (i=0; i<10; i++) { top1=get_dma_residue(devpriv->ai_dma); // where is now DMA top2=get_dma_residue(devpriv->ai_dma); if (top1==top2) break; } if (top1!=top2) { comedi_spin_unlock_irqrestore(&dev->spinlock,flags); return 0; } top1=devpriv->dmabytestomove[1-devpriv->next_dma_buf]-top1; // where is now DMA in buffer top1>>=1; // sample position top2=top1-devpriv->ai_poll_ptr; if (top2<1) { // no new samples comedi_spin_unlock_irqrestore(&dev->spinlock,flags); return 0; } transfer_from_dma_buf(dev, s, (void *)devpriv->dmabuf[1-devpriv->next_dma_buf], devpriv->ai_poll_ptr, top2); devpriv->ai_poll_ptr=top1; // new buffer position comedi_spin_unlock_irqrestore(&dev->spinlock,flags); return s->async->buf_write_count-s->async->buf_read_count;}/*==============================================================================*/static void setup_range_channel(comedi_device * dev, comedi_subdevice * s, unsigned int rangechan, char wait){ unsigned char chan_reg=CR_CHAN(rangechan); // normal board unsigned char gain_reg=CR_RANGE(rangechan)+devpriv->range_correction; // gain index if ((chan_reg==devpriv->old_chan_reg)&&(gain_reg==devpriv->old_gain_reg)) return; // we can return, no change devpriv->old_chan_reg=chan_reg; devpriv->old_gain_reg=gain_reg; if (devpriv->use_MPC) { if (devpriv->use_diff) { chan_reg=chan_reg | 0x30; // DIFF inputs } else { if (chan_reg&0x80) { chan_reg=chan_reg | 0x20; // SE inputs 8-15 } else { chan_reg=chan_reg | 0x10; // SE inputs 0-7 } } } outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */ outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */ if (wait) { comedi_udelay(devpriv->max_812_ai_mode0_rangewait); // XXX this depends on selected range and can be very long for some high gain ranges! }}/*==============================================================================*/static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2) {#ifdef PCL812_EXTDEBUG rt_printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n",mode,divisor1,divisor2);#endif outb(0xb4, dev->iobase + PCL812_CTRCTL); outb(0x74, dev->iobase + PCL812_CTRCTL); comedi_udelay(1); if (mode==1) { outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2); outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2); outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1); outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1); }#ifdef PCL812_EXTDEBUG rt_printk("pcl812 EDBG: END: start_pacer(...)\n");#endif}/* ==============================================================================*/static void free_resources(comedi_device * dev){ if (dev->private) { if (devpriv->dmabuf[0]) free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); if (devpriv->dmabuf[1]) free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); if (devpriv->dma) free_dma(devpriv->dma); } if (dev->irq) comedi_free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, this_board->io_range);}/* ==============================================================================*/static int pcl812_ai_cancel(comedi_device * dev, comedi_subdevice * s){#ifdef PCL812_EXTDEBUG rt_printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");#endif if (devpriv->ai_dma) disable_dma(devpriv->dma); outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ outb(devpriv->mode_reg_int|0, dev->iobase + PCL812_MODE); /* Stop A/D */ start_pacer(dev,-1,0,0); // stop 8254 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */#ifdef PCL812_EXTDEBUG rt_printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n");#endif return 0;}/* ==============================================================================*/static void pcl812_reset(comedi_device * dev){#ifdef PCL812_EXTDEBUG rt_printk("pcl812 EDBG: BGN: pcl812_reset(...)\n");#endif outb(0, dev->iobase + PCL812_MUX); outb(0+devpriv->range_correction, dev->iobase + PCL812_GAIN); devpriv->old_chan_reg=-1; // invalidate chain/gain memory devpriv->old_gain_reg=-1; switch (this_board->board_type) { case boardPCL812PG: case boardPCL812: case boardACL8112: case boardACL8216: outb(0, dev->iobase + PCL812_DA2_LO); outb(0, dev->iobase + PCL812_DA2_HI); case boardA821: outb(0, dev->iobase + PCL812_DA1_LO); outb(0, dev->iobase + PCL812_DA1_HI); start_pacer(dev,-1,0,0); // stop 8254 outb(0, dev->iobase + PCL812_DO_HI); outb(0, dev->iobase + PCL812_DO_LO); outb(devpriv->mode_reg_int|0, dev->iobase + PCL812_MODE); outb(0, dev->iobase + PCL812_CLRINT); break; case boardPCL813B: case boardPCL813: case boardISO813: case boardACL8113: comedi_udelay(5); break; } comedi_udelay(5);#ifdef PCL812_EXTDEBUG rt_printk("pcl812 EDBG: END: pcl812_reset(...)\n");#endif}/*==============================================================================*/static int pcl812_attach(comedi_device * dev, comedi_devconfig * it){ int ret,subdev; int iobase; int irq; int dma; unsigned long pages; comedi_subdevice *s; int n_subdevices; iobase = it->options[0]; printk("comedi%d: pcl812: board=%s, ioport=0x%03x", dev->minor, this_board->name, iobase); if (check_region(iobase, this_board->io_range) < 0) { printk("I/O port conflict\n"); return -EIO; } request_region(iobase, this_board->io_range, "pcl812"); dev->iobase = iobase; if ((ret = alloc_private(dev, sizeof(pcl812_private))) < 0) { free_resources(dev); return ret; /* Can't alloc mem */ } dev->board_name = this_board->name; irq = 0; if (this_board->IRQbits != 0) { /* board support IRQ */ irq = it->options[1]; if (irq) { /* we want to use IRQ */ if (((1 << irq) & this_board->IRQbits) == 0) { printk(", IRQ %d is out of allowed range, DISABLING IT", irq); irq = 0; /* Bad IRQ */ } else { if (comedi_request_irq(irq, interrupt_pcl812, 0, "pcl812", dev)) { printk(", unable to allocate IRQ %d, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { printk(", irq=%d", irq); } } } } dev->irq = irq; dma = 0; devpriv->dma = dma; if (!dev->irq) goto no_dma; /* if we haven't IRQ, we can't use DMA */ if (this_board->DMAbits != 0) { /* board support DMA */ dma = it->options[2]; if (((1 << dma) & this_board->DMAbits) == 0) { printk(", DMA is out of allowed range, FAIL!\n"); return -EINVAL; /* Bad DMA */ } ret = request_dma(dma, "pcl812"); if (ret) { printk(", unable to allocate DMA %d, FAIL!\n", dma); return -EBUSY; /* DMA isn't free */ } devpriv->dma = dma; printk(", dma=%d", dma); pages = 1; /* we want 8KB */ devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); if (!devpriv->dmabuf[0]) { printk(", unable to allocate DMA buffer, FAIL!\n"); /* maybe experiment with try_to_free_pages() will help .... */ free_resources(dev); return -EBUSY; /* no buffer :-( */ } devpriv->dmapages[0] = pages; devpriv->hwdmaptr[0] = virt_to_bus((void *) devpriv->dmabuf[0]); devpriv->hwdmasize[0] = PAGE_SIZE * (1<<pages); devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); if (!devpriv->dmabuf[1]) { printk(", unable to allocate DMA buffer, FAIL!\n"); free_resources(dev); return -EBUSY; } devpriv->dmapages[1] = pages; devpriv->hwdmaptr[1] = virt_to_bus((void *) devpriv->dmabuf[1]); devpriv->hwdmasize[1] = PAGE_SIZE * (1<<pages); } no_dma: n_subdevices=0; if (this_board->n_aichan > 0) n_subdevices++; if (this_board->n_aochan > 0) n_subdevices++; if (this_board->n_dichan > 0) n_subdevices++; if (this_board->n_dochan > 0) n_subdevices++; if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) { free_resources(dev); return ret; } subdev=0; /* analog input */ if (this_board->n_aichan>0) { s = dev->subdevices + subdev; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE; switch (this_board->board_type) { case boardA821: if (it->options[2] == 1) { s->n_chan = this_board->n_aichan_diff; s->subdev_flags |= SDF_DIFF; devpriv->use_diff=1; } else { s->n_chan = this_board->n_aichan; s->subdev_flags |= SDF_GROUND; } break; case boardACL8112: case boardACL8216: if (it->options[4] == 1) { s->n_chan = this_board->n_aichan_diff; s->subdev_flags |= SDF_DIFF; devpriv->use_diff=1; } else { s->n_chan = this_board->n_aichan; s->subdev_flags |= SDF_GROUND; } break; default: s->n_chan = this_board->n_aichan; s->subdev_flags |= SDF_GROUND; break; } s->maxdata = this_board->ai_maxdata; s->len_chanlist = MAX_CHANLIST_LEN; s->range_table = this_board->rangelist_ai; if (this_board->board_type==boardACL8216) { s->insn_read = acl8216_ai_insn_read; } else { s->insn_read = pcl812_ai_insn_read; } devpriv->use_MPC = this_board->haveMPC508; s->cancel = pcl812_ai_cancel; if (dev->irq) { s->do_cmdtest = pcl812_ai_cmdtest; s->do_cmd = pcl812_ai_cmd; s->poll = pcl812_ai_poll; } switch (this_board->board_type) { case boardPCL812PG: if (it->options[4] == 1) s->range_table = &range_pcl812pg2_ai; break; case boardPCL812: switch (it->options[4]) { case 0: s->range_table = &range_bipolar10; break; case 1: s->range_table = &range_bipolar5; break; case 2: s->range_table = &range_bipolar2_5; break; case 3: s->range_table = &range812_bipolar1_25; break; case 4: s->range_table = &range812_bipolar0_625; break; case 5: s->range_table = &range812_bipolar0_3125; break; default: s->range_table = &range_bipolar10; break; printk(", incorrect range number %d, changing to 0 (+/-10V)", it->options[4]); break; } break; break; case boardPCL813B: if (it->options[1] == 1) s->range_table = &range_pcl813b2_ai; break; case boardISO813: switch (it->options[1]) { case 0: s->range_table = &range_iso813_1_ai; break; case 1: s->range_table = &range_iso813_1_2_ai; break; case 2: s->range_table = &range_iso813_2_ai; devpriv->range_correction=1; break; case 3: s->range_table = &range_iso813_2_2_ai; devpriv->range_correction=1; break; default: s->range_table = &range_iso813_1_ai; break; printk(", incorrect range number %d, changing to 0 ", it->options[1]); break; } break; case boardACL8113: switch (it->options[1]) { case 0: s->range_table = &range_acl8113_1_ai; break; case 1: s->range_table = &range_acl8113_1_2_ai; break; case 2: s->range_table = &range_acl8113_2_ai; devpriv->range_correction=1; break; case 3: s->range_table = &range_acl8113_2_2_ai; devpriv->range_correction=1; break; default: s->range_table = &range_acl8113_1_ai; break; printk(", incorrect range number %d, changing to 0 ", it->options[1]); break; } break; } subdev++; } /* analog output */ if (this_board->n_aochan>0) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE|SDF_GROUND; s->n_chan = this_board->n_aochan; s->maxdata = 0xfff; s->len_chanlist = 1; s->range_table = this_board->rangelist_ao; s->insn_read = pcl812_ao_insn_read; s->insn_write = pcl812_ao_insn_write; switch (this_board->board_type) { case boardA821: if (it->options[3] == 1) s->range_table = &range_unipolar10; break; case boardPCL812: case boardACL8112: case boardPCL812PG: case boardACL8216: if (it->options[5] == 1) s->range_table = &range_unipolar10; if (it->options[5] == 2) s->range_table = &range_unknown; break; } subdev++; } /* digital input */ if (this_board->n_dichan>0) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = this_board->n_dichan; s->maxdata = 1; s->len_chanlist = this_board->n_dichan; s->range_table = &range_digital; s->insn_bits = pcl812_di_insn_bits; subdev++; } /* digital output */ if (this_board->n_dochan>0) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; s->n_chan = this_board->n_dochan; s->maxdata = 1; s->len_chanlist = this_board->n_dochan; s->range_table = &range_digital; s->insn_bits = pcl812_do_insn_bits; subdev++; } switch (this_board->board_type) { case boardACL8216: devpriv->ai_is16b=1; case boardPCL812PG: case boardPCL812: case boardACL8112: devpriv->max_812_ai_mode0_rangewait = 1; if (it->options[3] > 0) devpriv->use_ext_trg=1; // we use external trigger case boardA821: devpriv->max_812_ai_mode0_rangewait = 1; devpriv->mode_reg_int=(irq<<4) & 0xf0; break; case boardPCL813B: case boardPCL813: case boardISO813: case boardACL8113: devpriv->max_812_ai_mode0_rangewait = 5; /* maybe there must by greatest timeout */ break; } printk("\n"); devpriv->valid=1; pcl812_reset(dev); return 0;}/*============================================================================== */static int pcl812_detach(comedi_device * dev){#ifdef PCL812_EXTDEBUG rt_printk("comedi%d: pcl812: remove\n", dev->minor);#endif free_resources(dev); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -