📄 cb_pcidas.c
字号:
comedi_cmd *cmd = &async->cmd; unsigned int i; unsigned long flags; // set channel limits, gain comedi_spin_lock_irqsave( &dev->spinlock, flags ); for(i = 0; i < cmd->chanlist_len; i++) { // enable channel devpriv->ao_control_bits |= DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i])); // set range devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]), CR_RANGE(cmd->chanlist[i])); } // disable analog out before settings pacer source and count values outw( devpriv->ao_control_bits, devpriv->control_status + DAC_CSR ); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); // clear fifo outw(0, devpriv->ao_registers + DACFIFOCLR); // load counters if(cmd->scan_begin_src == TRIG_TIMER) { i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->ao_divisor1), &(devpriv->ao_divisor2), &(cmd->scan_begin_arg), cmd->flags); /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ i8254_load(devpriv->pacer_counter_dio + DAC8254, 1, devpriv->ao_divisor1, 2); i8254_load(devpriv->pacer_counter_dio + DAC8254, 2, devpriv->ao_divisor2, 2); } // set number of conversions if(cmd->stop_src == TRIG_COUNT) { devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg; } // set pacer source comedi_spin_lock_irqsave( &dev->spinlock, flags ); switch(cmd->scan_begin_src) { case TRIG_TIMER: devpriv->ao_control_bits |= DAC_PACER_INT; break; case TRIG_EXT: devpriv->ao_control_bits |= DAC_PACER_EXT_RISE; break; default: comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); comedi_error(dev, "error setting dac pacer source"); return -1; break; } comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); async->inttrig = cb_pcidas_ao_inttrig; return 0;}static int cb_pcidas_ao_inttrig(comedi_device *dev, comedi_subdevice *s, unsigned int trig_num){ unsigned int num_bytes, num_points = thisboard->fifo_size; comedi_async *async = s->async; comedi_cmd *cmd = &s->async->cmd; unsigned long flags; if(trig_num != 0) return -EINVAL; // load up fifo if( cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points ) num_points = devpriv->ao_count; num_bytes = cfc_read_array_from_buffer( s, devpriv->ao_buffer, num_points * sizeof( sampl_t ) ); num_points = num_bytes / sizeof( sampl_t ); if(cmd->stop_src == TRIG_COUNT) { devpriv->ao_count -= num_points; } // write data to board's fifo outsw( devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes ); // enable dac half-full and empty interrupts comedi_spin_lock_irqsave( &dev->spinlock, flags ); devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;#ifdef CB_PCIDAS_DEBUG rt_printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits);#endif // enable and clear interrupts outw(devpriv->adc_fifo_bits | DAEMI | DAHFI, devpriv->control_status + INT_ADCFIFO); // start dac devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY; outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);#ifdef CB_PCIDAS_DEBUG rt_printk("comedi: sent 0x%x to dac control\n", devpriv->ao_control_bits);#endif comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); async->inttrig = NULL; return 0;}static void cb_pcidas_interrupt(int irq, void *d, struct pt_regs *regs){ comedi_device *dev = (comedi_device*) d; comedi_subdevice *s = dev->read_subdev; comedi_async *async; int status, s5933_status; int half_fifo = thisboard->fifo_size / 2; unsigned int num_samples, i; static const int timeout = 10000; unsigned long flags; if(dev->attached == 0) { comedi_error(dev, "premature interrupt"); } async = s->async; async->events = 0; s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);#ifdef CB_PCIDAS_DEBUG rt_printk("intcsr 0x%x\n", s5933_status); rt_printk("mbef 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_MBEF));#endif if( ( INTCSR_INTR_ASSERTED & s5933_status ) == 0 ) return; // make sure mailbox 4 is empty inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4); // clear interrupt on amcc s5933 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); status = inw(devpriv->control_status + INT_ADCFIFO);#ifdef CB_PCIDAS_DEBUG if((status & (INT | EOAI | LADFUL | DAHFI | DAEMI)) == 0) { comedi_error(dev, "spurious interrupt"); }#endif // check for analog output interrupt if(status & (DAHFI | DAEMI)) { handle_ao_interrupt(dev, status); } // check for analog input interrupts // if fifo half-full if(status & ADHFI) { // read data num_samples = half_fifo; if(async->cmd.stop_src == TRIG_COUNT && num_samples > devpriv->count) { num_samples = devpriv->count; } insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer, num_samples); cfc_write_array_to_buffer( s, devpriv->ai_buffer, num_samples * sizeof( sampl_t ) ); devpriv->count -= num_samples; if(async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) { async->events |= COMEDI_CB_EOA; cb_pcidas_cancel(dev, s); } // clear half-full interrupt latch comedi_spin_lock_irqsave( &dev->spinlock, flags ); outw(devpriv->adc_fifo_bits | INT, devpriv->control_status + INT_ADCFIFO); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); // else if fifo not empty }else if(status & (ADNEI | EOBI)) { for(i = 0; i < timeout; i++) { // break if fifo is empty if((ADNE & inw(devpriv->control_status + INT_ADCFIFO)) == 0) break; cfc_write_to_buffer( s, inw( devpriv->adc_fifo ) ); if(async->cmd.stop_src == TRIG_COUNT && --devpriv->count == 0) { /* end of acquisition */ cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } } // clear not-empty interrupt latch comedi_spin_lock_irqsave( &dev->spinlock, flags ); outw(devpriv->adc_fifo_bits | INT, devpriv->control_status + INT_ADCFIFO); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); }else if(status & EOAI) { comedi_error(dev, "bug! encountered end of aquisition interrupt?"); // clear EOA interrupt latch comedi_spin_lock_irqsave( &dev->spinlock, flags ); outw(devpriv->adc_fifo_bits | EOAI, devpriv->control_status + INT_ADCFIFO); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); } //check for fifo overflow if(status & LADFUL) { comedi_error(dev, "fifo overflow"); // clear overflow interrupt latch comedi_spin_lock_irqsave( &dev->spinlock, flags ); outw(devpriv->adc_fifo_bits | LADFUL, devpriv->control_status + INT_ADCFIFO); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } comedi_event(dev, s, async->events); return;}static void handle_ao_interrupt(comedi_device *dev, unsigned int status){ comedi_subdevice *s = dev->write_subdev; comedi_async *async = s->async; comedi_cmd *cmd = &async->cmd; unsigned int half_fifo = thisboard->fifo_size / 2; unsigned int num_points; unsigned int flags; async->events = 0; if(status & DAEMI) { // clear dac empty interrupt latch comedi_spin_lock_irqsave( &dev->spinlock, flags ); outw(devpriv->adc_fifo_bits | DAEMI, devpriv->control_status + INT_ADCFIFO); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); if(inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) { if(cmd->stop_src == TRIG_NONE || (cmd->stop_src == TRIG_COUNT && devpriv->ao_count)) { comedi_error(dev, "dac fifo underflow"); cb_pcidas_ao_cancel(dev, s); async->events |= COMEDI_CB_ERROR; } async->events |= COMEDI_CB_EOA; } }else if(status & DAHFI) { unsigned int num_bytes; // figure out how many points we are writing to fifo num_points = half_fifo; if(cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points) num_points = devpriv->ao_count; num_bytes = cfc_read_array_from_buffer( s, devpriv->ao_buffer, num_points * sizeof( sampl_t ) ); num_points = num_bytes / sizeof( sampl_t ); if(async->cmd.stop_src == TRIG_COUNT) { devpriv->ao_count -= num_points; } // write data to board's fifo outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_points); // clear half-full interrupt latch comedi_spin_lock_irqsave( &dev->spinlock, flags ); outw(devpriv->adc_fifo_bits | DAHFI, devpriv->control_status + INT_ADCFIFO); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); } comedi_event(dev, s, async->events);}// cancel analog input commandstatic int cb_pcidas_cancel(comedi_device *dev, comedi_subdevice *s){ unsigned long flags; comedi_spin_lock_irqsave( &dev->spinlock, flags ); // disable interrupts devpriv->adc_fifo_bits &= ~INTE & ~EOAIE; outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); // disable start trigger source and burst mode outw(0, devpriv->control_status + TRIG_CONTSTAT); // software pacer source outw(0, devpriv->control_status + ADCMUX_CONT); return 0;}// cancel analog output commandstatic int cb_pcidas_ao_cancel(comedi_device *dev, comedi_subdevice *s){ unsigned long flags; comedi_spin_lock_irqsave( &dev->spinlock, flags ); // disable interrupts devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE; outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); // disable output devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK; outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); return 0;}static void cb_pcidas_load_counters(comedi_device *dev, unsigned int *ns, int rounding_flags){ i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2), ns, rounding_flags & TRIG_ROUND_MASK); /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ i8254_load(devpriv->pacer_counter_dio + ADC8254, 1, devpriv->divisor1, 2); i8254_load(devpriv->pacer_counter_dio + ADC8254, 2, devpriv->divisor2, 2);}static void write_calibration_bitstream( comedi_device *dev, unsigned int register_bits, unsigned int bitstream, unsigned int bitstream_length ){ static const int write_delay = 1; unsigned int bit; for( bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { if(bitstream & bit) register_bits |= SERIAL_DATA_IN_BIT; else register_bits &= ~SERIAL_DATA_IN_BIT; comedi_udelay( write_delay ); outw( register_bits, devpriv->control_status + CALIBRATION_REG); }}static int caldac_8800_write(comedi_device *dev, unsigned int address, uint8_t value){ static const int num_caldac_channels = 8; static const int bitstream_length = 11; unsigned int bitstream = ((address & 0x7) << 8) | value; static const int caldac_8800_comedi_udelay = 1; if(address >= num_caldac_channels) { comedi_error(dev, "illegal caldac channel"); return -1; } if( value == devpriv->caldac_value[ address ] ) return 1; devpriv->caldac_value[ address ] = value; write_calibration_bitstream( dev, 0, bitstream, bitstream_length ); comedi_udelay(caldac_8800_comedi_udelay); outw(SELECT_8800_BIT, devpriv->control_status + CALIBRATION_REG); comedi_udelay(caldac_8800_comedi_udelay); outw(0, devpriv->control_status + CALIBRATION_REG); return 1;}static int trimpot_7376_write(comedi_device *dev, uint8_t value){ static const int bitstream_length = 7; unsigned int bitstream = value & 0x7f; unsigned int register_bits; static const int ad7376_comedi_udelay = 1; register_bits = SELECT_TRIMPOT_BIT; comedi_udelay( ad7376_comedi_udelay ); outw( register_bits, devpriv->control_status + CALIBRATION_REG); write_calibration_bitstream( dev, register_bits, bitstream, bitstream_length ); comedi_udelay(ad7376_comedi_udelay); outw(0, devpriv->control_status + CALIBRATION_REG); return 0;}/* For 1602/16 only * ch 0 : adc gain * ch 1 : adc postgain offset */static int trimpot_8402_write(comedi_device *dev, unsigned int channel, uint8_t value){ // XXX check docs, this function is just a guess static const int bitstream_length = 10; unsigned int bitstream = ( ( channel & 0x1 ) << 8 ) | ( value & 0xff ); unsigned int register_bits; static const int ad8402_comedi_udelay = 1; register_bits = SELECT_TRIMPOT_BIT; comedi_udelay( ad8402_comedi_udelay ); outw( register_bits, devpriv->control_status + CALIBRATION_REG); write_calibration_bitstream( dev, register_bits, bitstream, bitstream_length ); comedi_udelay(ad8402_comedi_udelay); outw(0, devpriv->control_status + CALIBRATION_REG); return 0;}static int wait_for_nvram_ready( unsigned long s5933_base_addr ){ static const int timeout = 1000; unsigned int i; for( i = 0; i < timeout; i++) { if( ( inb( s5933_base_addr + AMCC_OP_REG_MCSR_NVCMD ) & MCSR_NV_BUSY ) == 0 ) return 0; comedi_udelay( 1 ); } return -1;}static int nvram_read( comedi_device *dev, unsigned int address, uint8_t *data ){ unsigned long iobase = devpriv->s5933_config; if( wait_for_nvram_ready( iobase ) < 0 ) return -ETIMEDOUT; outb( MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR, iobase + AMCC_OP_REG_MCSR_NVCMD ); outb( address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA ); outb( MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR, iobase + AMCC_OP_REG_MCSR_NVCMD ); outb( ( address >> 8 ) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA ); outb( MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD ); if( wait_for_nvram_ready( iobase ) < 0 ) return -ETIMEDOUT; *data = inb( iobase + AMCC_OP_REG_MCSR_NVDATA ); return 0;}/* * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */COMEDI_INITCLEANUP(driver_cb_pcidas);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -