📄 ni_at_a2150.c
字号:
if(dev->iobase) { // put board in power-down mode outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG); release_region(dev->iobase, A2150_SIZE); } if(dev->irq) comedi_free_irq(dev->irq, dev); if(devpriv) { if(devpriv->dma) free_dma(devpriv->dma); if(devpriv->dma_buffer) kfree(devpriv->dma_buffer); } return 0;};static int a2150_cancel(comedi_device *dev, comedi_subdevice *s){ // disable dma on card devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT; outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); // disable computer's dma disable_dma(devpriv->dma); // clear fifo and reset triggering circuitry outw(0, dev->iobase + FIFO_RESET_REG); return 0;}static int a2150_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd){ int err = 0; int tmp; int startChan; int i; /* step 1: make sure trigger sources are trivially valid */ tmp = cmd->start_src; cmd->start_src &= TRIG_NOW | TRIG_EXT; if(!cmd->start_src || tmp != cmd->start_src) err++; tmp = cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_TIMER; if(!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; tmp = cmd->convert_src; cmd->convert_src &= TRIG_NOW; if(!cmd->convert_src || tmp != cmd->convert_src) err++; tmp = cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if(!cmd->scan_end_src || tmp != cmd->scan_end_src) err++; tmp=cmd->stop_src; cmd->stop_src &= TRIG_COUNT | TRIG_NONE; if(!cmd->stop_src || tmp!=cmd->stop_src) err++; if(err) return 1; /* step 2: make sure trigger sources are unique and mutually compatible */ if(cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) err++; if(cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) err++; if(err)return 2; /* step 3: make sure arguments are trivially compatible */ if(cmd->start_arg != 0) { cmd->start_arg = 0; err++; } if(cmd->convert_src == TRIG_TIMER) { if(cmd->convert_arg < thisboard->ai_speed) { cmd->convert_arg = thisboard->ai_speed; err++; } } if(!cmd->chanlist_len) { cmd->chanlist_len = 1; err++; } if(cmd->scan_end_arg != cmd->chanlist_len) { cmd->scan_end_arg = cmd->chanlist_len; err++; } if(cmd->stop_src == TRIG_COUNT) { if(!cmd->stop_arg) { cmd->stop_arg = 1; err++; } } else { /* TRIG_NONE */ if(cmd->stop_arg != 0) { cmd->stop_arg = 0; err++; } } if(err)return 3; /* step 4: fix up any arguments */ if(cmd->scan_begin_src == TRIG_TIMER) { tmp = cmd->scan_begin_arg; a2150_get_timing(dev, &cmd->scan_begin_arg, cmd->flags); if(tmp != cmd->scan_begin_arg) err++; } if(err)return 4; // check channel/gain list against card's limitations if(cmd->chanlist) { startChan = CR_CHAN(cmd->chanlist[0]); for(i = 1; i < cmd->chanlist_len; i++) { if(CR_CHAN(cmd->chanlist[i]) != (startChan + i)) { comedi_error(dev, "entries in chanlist must be consecutive channels, counting upwards\n"); err++; } } if(cmd->chanlist_len == 2 && CR_CHAN(cmd->chanlist[0]) == 1) { comedi_error(dev, "length 2 chanlist must be channels 0,1 or channels 2,3"); err++; } if(cmd->chanlist_len == 3) { comedi_error(dev, "chanlist must have 1,2 or 4 channels"); err++; } if(CR_AREF(cmd->chanlist[0]) != CR_AREF(cmd->chanlist[1]) || CR_AREF(cmd->chanlist[2]) != CR_AREF(cmd->chanlist[3])) { comedi_error(dev, "channels 0/1 and 2/3 must have the same analog reference"); err++; } } if(err)return 5; return 0;}static int a2150_ai_cmd(comedi_device *dev, comedi_subdevice *s){ comedi_async *async = s->async; comedi_cmd *cmd = &async->cmd; unsigned long lock_flags; unsigned int old_config_bits = devpriv->config_bits; unsigned int trigger_bits; if(!dev->irq || !devpriv->dma) { comedi_error(dev, " irq and dma required, cannot do hardware conversions"); return -1; } if(cmd->flags & TRIG_RT) { comedi_error(dev, " dma incompatible with hard real-time interrupt (TRIG_RT), aborting"); return -1; } // clear fifo and reset triggering circuitry outw(0, dev->iobase + FIFO_RESET_REG); /* setup chanlist */ if(a2150_set_chanlist(dev, CR_CHAN(cmd->chanlist[0]), cmd->chanlist_len) < 0) return -1; // setup ac/dc coupling if(CR_AREF(cmd->chanlist[0]) == AREF_OTHER) devpriv->config_bits |= AC0_BIT; else devpriv->config_bits &= ~AC0_BIT; if(CR_AREF(cmd->chanlist[2]) == AREF_OTHER) devpriv->config_bits |= AC1_BIT; else devpriv->config_bits &= ~AC1_BIT; // setup timing a2150_get_timing(dev, &cmd->scan_begin_arg, cmd->flags); // send timing, channel, config bits outw(devpriv->config_bits, dev->iobase + CONFIG_REG); // initialize number of samples remaining devpriv->count = cmd->stop_arg * cmd->chanlist_len; // enable computer's dma lock_flags = claim_dma_lock(); disable_dma(devpriv->dma); /* clear flip-flop to make sure 2-byte registers for * count and address get set correctly */ clear_dma_ff(devpriv->dma); set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer)); // set size of transfer to fill in 1/3 second#define ONE_THIRD_SECOND 333333333 devpriv->dma_transfer_size = sizeof(devpriv->dma_buffer[0]) * cmd->chanlist_len * ONE_THIRD_SECOND / cmd->scan_begin_arg; if(devpriv->dma_transfer_size > A2150_DMA_BUFFER_SIZE) devpriv->dma_transfer_size = A2150_DMA_BUFFER_SIZE; if(devpriv->dma_transfer_size < sizeof(devpriv->dma_buffer[0])) devpriv->dma_transfer_size = sizeof(devpriv->dma_buffer[0]); devpriv->dma_transfer_size -= devpriv->dma_transfer_size % sizeof(devpriv->dma_buffer[0]); set_dma_count(devpriv->dma, devpriv->dma_transfer_size); enable_dma(devpriv->dma); release_dma_lock(lock_flags); /* clear dma interrupt before enabling it, to try and get rid of that * one spurious interrupt that has been happening */ outw(0x00, dev->iobase + DMA_TC_CLEAR_REG); // enable dma on card devpriv->irq_dma_bits |= DMA_INTR_EN_BIT | DMA_EN_BIT; outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); // may need to wait 72 sampling periods if timing was changed i8254_load(dev->iobase + I8253_BASE_REG, 2, 72, 0); // setup start triggering trigger_bits = 0; // decide if we need to wait 72 periods for valid data if(cmd->start_src == TRIG_NOW && (old_config_bits & CLOCK_MASK) != (devpriv->config_bits & CLOCK_MASK)) { // set trigger source to delay trigger trigger_bits |= DELAY_TRIGGER_BITS; }else { // otherwise no delay trigger_bits |= POST_TRIGGER_BITS; } // enable external hardware trigger if(cmd->start_src == TRIG_EXT) { trigger_bits |= HW_TRIG_EN; }else if(cmd->start_src == TRIG_OTHER) { // XXX add support for level/slope start trigger using TRIG_OTHER comedi_error(dev, "you shouldn't see this?"); } // send trigger config bits outw(trigger_bits, dev->iobase + TRIGGER_REG); // start aquisition for soft trigger if(cmd->start_src == TRIG_NOW) { outw(0, dev->iobase + FIFO_START_REG); }#ifdef A2150_DEBUG ni_dump_regs(dev);#endif return 0;}static int a2150_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ unsigned int i, n; static const int timeout = 100000; static const int filter_delay = 36; // clear fifo and reset triggering circuitry outw(0, dev->iobase + FIFO_RESET_REG); /* setup chanlist */ if(a2150_set_chanlist(dev, CR_CHAN(insn->chanspec), 1) < 0) return -1; // set dc coupling devpriv->config_bits &= ~AC0_BIT; devpriv->config_bits &= ~AC1_BIT; // send timing, channel, config bits outw(devpriv->config_bits, dev->iobase + CONFIG_REG); // disable dma on card devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT; outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); // setup start triggering outw(0, dev->iobase + TRIGGER_REG); // start aquisition for soft trigger outw(0, dev->iobase + FIFO_START_REG); /* there is a 35.6 sample delay for data to get through the antialias filter */ for(n = 0; n < filter_delay; n++) { for(i = 0; i < timeout; i++) { if(inw(dev->iobase + STATUS_REG) & FNE_BIT) break; comedi_udelay(1); } if(i == timeout) { comedi_error(dev, "timeout"); return -ETIME; } inw(dev->iobase + FIFO_DATA_REG); } // read data for(n = 0; n < insn->n; n++) { for(i = 0; i < timeout; i++) { if(inw(dev->iobase + STATUS_REG) & FNE_BIT) break; comedi_udelay(1); } if(i == timeout) { comedi_error(dev, "timeout"); return -ETIME; }#ifdef A2150_DEBUG ni_dump_regs(dev);#endif data[n] = inw(dev->iobase + FIFO_DATA_REG);#ifdef A2150_DEBUG rt_printk(" data is %i\n", data[n]);#endif data[n] ^= 0x8000; } // clear fifo and reset triggering circuitry outw(0, dev->iobase + FIFO_RESET_REG); return n;}/* sets bits in devpriv->clock_bits to nearest approximation of requested period, * adjusts requested period to actual timing. */static int a2150_get_timing(comedi_device *dev, unsigned int *period, int flags){ int lub, glb, temp; int lub_divisor_shift, lub_index, glb_divisor_shift, glb_index; int i, j; // initialize greatest lower and least upper bounds lub_divisor_shift = 3; lub_index = 0; lub = thisboard->clock[lub_index] * (1 << lub_divisor_shift); glb_divisor_shift = 0; glb_index = thisboard->num_clocks - 1; glb = thisboard->clock[glb_index] * (1 << glb_divisor_shift); // make sure period is in available range if(*period < glb) *period = glb; if(*period > lub) *period = lub; // we can multiply period by 1, 2, 4, or 8, using (1 << i) for(i = 0; i < 4; i = i++) { // there are a maximum of 4 master clocks for(j = 0; j < thisboard->num_clocks; j++) { // temp is the period in nanosec we are evaluating temp = thisboard->clock[j] * (1 << i); // if it is the best match yet if(temp < lub && temp >= *period) { lub_divisor_shift = i; lub_index = j; lub = temp; } if(temp > glb && temp <= *period) { glb_divisor_shift = i; glb_index = j; glb = temp; } } } flags &= TRIG_ROUND_MASK; switch (flags) { case TRIG_ROUND_NEAREST: default: // if least upper bound is better approximation if(lub - *period < *period - glb) { *period = lub; }else { *period = glb; } break; case TRIG_ROUND_UP: *period = lub; break; case TRIG_ROUND_DOWN: *period = glb; break; } // set clock bits for config register appropriately devpriv->config_bits &= ~CLOCK_MASK; if(*period == lub) { devpriv->config_bits |= CLOCK_SELECT_BITS(lub_index) | CLOCK_DIVISOR_BITS(lub_divisor_shift); }else { devpriv->config_bits |= CLOCK_SELECT_BITS(glb_index) | CLOCK_DIVISOR_BITS(glb_divisor_shift); } return 0;}static int a2150_set_chanlist(comedi_device *dev, unsigned int start_channel, unsigned int num_channels){ if(start_channel + num_channels > 4) return -1; devpriv->config_bits &= ~CHANNEL_MASK; switch(num_channels) { case 1: devpriv->config_bits |= CHANNEL_BITS(0x4 | start_channel); break; case 2: if(start_channel == 0) { devpriv->config_bits |= CHANNEL_BITS(0x2); }else if(start_channel == 2) { devpriv->config_bits |= CHANNEL_BITS(0x3); }else { return -1; } break; case 4: devpriv->config_bits |= CHANNEL_BITS(0x1); break; default: return -1; break; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -