📄 pcl816.c
字号:
}/*============================================================================== Start/stop pacer onboard pacer*/static voidstart_pacer (comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2){ outb (0x32, dev->iobase + PCL816_CTRCTL); outb (0xff, dev->iobase + PCL816_CTR0); outb (0x00, dev->iobase + PCL816_CTR0); comedi_udelay (1); outb(0xb4, dev->iobase + PCL816_CTRCTL); // set counter 2 as mode 3 outb(0x74, dev->iobase + PCL816_CTRCTL); // set counter 1 as mode 3 comedi_udelay(1); if (mode == 1) { DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1, divisor2); outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2); outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2); outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1); outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1); } /* clear pending interrupts (just in case) */// outb(0, dev->iobase + PCL816_CLRINT);}/*============================================================================== Check if channel list from user is builded correctly If it's ok, then program scan/gain logic*/static intcheck_and_setup_channel_list (comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, int chanlen){ unsigned int chansegment[16]; unsigned int i, nowmustbechan, seglen, segpos; // correct channel and range number check itself comedi/range.c if (chanlen < 1) { comedi_error (dev, "range/channel list is empty!"); return 0; } if (chanlen > 1) { chansegment[0] = chanlist[0]; // first channel is everytime ok for (i = 1, seglen = 1; i < chanlen; i++, seglen++) { // build part of chanlist DEBUG(rt_printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i]));) if (chanlist[0] == chanlist[i]) break; // we detect loop, this must by finish nowmustbechan = (CR_CHAN (chansegment[i - 1]) + 1) % chanlen; if (nowmustbechan != CR_CHAN (chanlist[i])) { // channel list isn't continous :-( rt_printk("comedi%d: pcl816: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", dev->minor, i, CR_CHAN (chanlist[i]), nowmustbechan, CR_CHAN (chanlist[0])); return 0; } chansegment[i] = chanlist[i]; // well, this is next correct channel in list } for (i = 0, segpos = 0; i < chanlen; i++) { // check whole chanlist DEBUG(rt_printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i]));) if (chanlist[i] != chansegment[i % seglen]) { rt_printk("comedi%d: pcl816: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", dev->minor, i, CR_CHAN (chansegment[i]), CR_RANGE (chansegment[i]), CR_AREF (chansegment[i]), CR_CHAN (chanlist[i % seglen]), CR_RANGE(chanlist[i % seglen]), CR_AREF (chansegment[i % seglen])); return 0; // chan/gain list is strange } } } else { seglen = 1; } devpriv->ai_act_chanlist_len = seglen; devpriv->ai_act_chanlist_pos = 0; for (i = 0; i < seglen; i++) { // store range list to card devpriv->ai_act_chanlist[i] = CR_CHAN (chanlist[i]); outb (CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX); outb (CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); /* select gain */ } comedi_udelay (1); outb (devpriv->ai_act_chanlist[0] | (devpriv->ai_act_chanlist[seglen - 1] << 4), dev->iobase + PCL816_MUX); /* select channel interval to scan */ return 1; // we can serve this with MUX logic}/* ============================================================================== Enable(1)/disable(0) periodic interrupts from RTC*/static int set_rtc_irq_bit(unsigned char bit){ unsigned char val; unsigned long flags; if (bit==1) { RTC_timer_lock++; if (RTC_timer_lock>1) return 0; } else { RTC_timer_lock--; if (RTC_timer_lock<0) RTC_timer_lock=0; if (RTC_timer_lock>0) return 0; } save_flags(flags); cli(); val = CMOS_READ(RTC_CONTROL); if (bit) { val |= RTC_PIE; } else { val &= ~RTC_PIE; } CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); restore_flags(flags); return 0;}/* ============================================================================== Free any resources that we have claimed */static voidfree_resources (comedi_device * dev){ //rt_printk("free_resource()\n"); if (dev->private) { pcl816_ai_cancel (dev, devpriv->sub_ai); pcl816_reset (dev); if (devpriv->dma) free_dma (devpriv->dma); 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->rtc_irq) comedi_free_irq (devpriv->rtc_irq, dev); if ((devpriv->dma_rtc) && (RTC_lock == 1)) { if (devpriv->rtc_iobase) release_region (devpriv->rtc_iobase, devpriv->rtc_iosize); } } if (dev->irq) free_irq (dev->irq, dev); if (dev->iobase) release_region (dev->iobase, this_board->io_range); //rt_printk("free_resource() end\n");}/* ============================================================================== Initialization */static intpcl816_attach (comedi_device * dev, comedi_devconfig * it){ int ret; int iobase; int irq, dma; unsigned long pages; //int i; comedi_subdevice *s; /* claim our I/O space */ iobase = it->options[0]; printk("comedi%d: pcl816: board=%s, ioport=0x%03x", dev->minor, this_board->name, iobase); if (check_region (iobase, this_board->io_range) < 0) { rt_printk ("I/O port conflict\n"); return -EIO; } request_region (iobase, this_board->io_range, "pcl816"); dev->iobase = iobase; if (pcl816_check (iobase)) { rt_printk (", I cann't detect board. FAIL!\n"); return -EIO; } if ((ret = alloc_private (dev, sizeof (pcl816_private))) < 0) return ret; /* Can't alloc mem */ /* set up some name stuff */ dev->board_name = this_board->name; /* grab our IRQ */ irq = 0; if (this_board->IRQbits != 0) { /* board support IRQ */ irq = it->options[1]; if (irq > 0) { /* we want to use IRQ */ if (((1 << irq) & this_board->IRQbits) == 0) { rt_printk (", IRQ %d is out of allowed range, DISABLING IT", irq); irq = 0; /* Bad IRQ */ } else { if (comedi_request_irq(irq, interrupt_pcl816, 0, "pcl816", dev)) { rt_printk (", unable to allocate IRQ %d, DISABLING IT",irq); irq = 0; /* Can't use IRQ */ } else { rt_printk (", irq=%d", irq); } } } } dev->irq = irq; if (irq) { devpriv->irq_free = 1; } /* 1=we have allocated irq */ else { devpriv->irq_free = 0; } devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ devpriv->int816_mode = 0; /* mode of irq */ /* grab RTC for DMA operations */ devpriv->dma_rtc = 0; if (it->options[2] > 0) { // we want to use DMA if (RTC_lock == 0) { if (check_region (RTC_PORT (0), RTC_IO_EXTENT) < 0) goto no_rtc; request_region (RTC_PORT (0), RTC_IO_EXTENT, "pcl816 (RTC)"); } devpriv->rtc_iobase = RTC_PORT (0); devpriv->rtc_iosize = RTC_IO_EXTENT; RTC_lock++;#ifdef UNTESTED_CODE if (!comedi_request_irq (RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0, "pcl816 DMA (RTC)", dev)) { devpriv->dma_rtc = 1; devpriv->rtc_irq = RTC_IRQ; rt_printk (", dma_irq=%d", devpriv->rtc_irq); } else { RTC_lock--; if (RTC_lock == 0) { if (devpriv->rtc_iobase) release_region (devpriv->rtc_iobase, devpriv->rtc_iosize); } devpriv->rtc_iobase = 0; devpriv->rtc_iosize = 0; }#else printk("pcl816: RTC code missing");#endif }no_rtc: /* grab our DMA */ dma = 0; devpriv->dma = dma; if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0)) 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 (dma < 1) goto no_dma; /* DMA disabled */ if (((1 << dma) & this_board->DMAbits) == 0) { rt_printk (", DMA is out of allowed range, FAIL!\n"); return -EINVAL; /* Bad DMA */ } ret = request_dma (dma, "pcl816"); if (ret) { rt_printk (", unable to allocate DMA %d, FAIL!\n", dma); return -EBUSY; /* DMA isn't free */ } devpriv->dma = dma; rt_printk (", dma=%d", dma); pages = 2; /* we need 16KB */ devpriv->dmabuf[0] = __get_dma_pages (GFP_KERNEL, pages); if (!devpriv->dmabuf[0]) { rt_printk (", unable to allocate DMA buffer, FAIL!\n"); /* maybe experiment with try_to_free_pages() will help .... */ return -EBUSY; /* no buffer :-( */ } devpriv->dmapages[0] = pages; devpriv->hwdmaptr[0] = virt_to_bus ((void *) devpriv->dmabuf[0]); devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; //rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); if (devpriv->dma_rtc == 0) { // we must do duble buff :-( devpriv->dmabuf[1] = __get_dma_pages (GFP_KERNEL, pages); if (!devpriv->dmabuf[1]) { rt_printk (", unable to allocate DMA buffer, FAIL!\n"); return -EBUSY; } devpriv->dmapages[1] = pages; devpriv->hwdmaptr[1] = virt_to_bus ((void *) devpriv->dmabuf[1]); devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; } }no_dma:/* if (this_board->n_aochan > 0) subdevs[1] = COMEDI_SUBD_AO; if (this_board->n_dichan > 0) subdevs[2] = COMEDI_SUBD_DI; if (this_board->n_dochan > 0) subdevs[3] = COMEDI_SUBD_DO;*/ if ((ret = alloc_subdevices (dev, 1)) < 0) return ret; s = dev->subdevices + 0; if (this_board->n_aichan > 0){ s->type = COMEDI_SUBD_AI; devpriv->sub_ai = s; dev->read_subdev = s; s->subdev_flags = SDF_READABLE; s->n_chan = this_board->n_aichan; s->subdev_flags |= SDF_DIFF; //printk (", %dchans DIFF DAC - %d", s->n_chan, i); s->maxdata = this_board->ai_maxdata; s->len_chanlist = this_board->ai_chanlist; s->range_table = this_board->ai_range_type; s->cancel = pcl816_ai_cancel; s->do_cmdtest = pcl816_ai_cmdtest; s->do_cmd = pcl816_ai_cmd; s->poll = pcl816_ai_poll; s->insn_read = pcl816_ai_insn_read; }else{ s->type = COMEDI_SUBD_UNUSED; }#if 0 case COMEDI_SUBD_AO: s->subdev_flags = SDF_WRITABLE | SDF_GROUND; s->n_chan = this_board->n_aochan; s->maxdata = this_board->ao_maxdata; s->len_chanlist = this_board->ao_chanlist; s->range_table = this_board->ao_range_type; break; case 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; break; case 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; break; } s++; }#endif pcl816_reset (dev); rt_printk ("\n"); return 0;}/*============================================================================== Removes device */static intpcl816_detach (comedi_device * dev){ DEBUG(rt_printk("comedi%d: pcl816: remove\n", dev->minor);) free_resources (dev); if (devpriv->dma_rtc) RTC_lock--; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -