📄 ni_mio_common.c
字号:
#if 0static void ni_handle_block_dma(comedi_device *dev){ comedi_subdevice *s = dev->subdevices + 0; MDPRINTK("ni_handle_block_dma\n"); mite_dma_disarm(devpriv->mite); ni_set_bits(dev, Interrupt_A_Enable_Register, AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable| AI_START2_Interrupt_Enable| AI_START_Interrupt_Enable| AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable| AI_FIFO_Interrupt_Enable,0); ni_ai_reset(dev,dev->subdevices); s->async->events |= COMEDI_CB_EOA; MDPRINTK("exit ni_handle_block_dma\n");}#endifstatic void ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd){ struct mite_struct *mite = devpriv->mite; struct mite_channel *mite_chan = &mite->channels[ AI_DMA_CHAN ]; comedi_subdevice *s = dev->subdevices + 0; /* write alloc the entire buffer */ comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); mite_chan->current_link = 0; mite_chan->dir = COMEDI_INPUT; if( boardtype.reg_611x ) mite_prep_dma(mite, AI_DMA_CHAN, 32, 16); else mite_prep_dma(mite, AI_DMA_CHAN, 16, 16); /*start the MITE*/ mite_dma_arm(mite, AI_DMA_CHAN);}static void ni_ao_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd){ struct mite_struct *mite = devpriv->mite; struct mite_channel *mite_chan = &mite->channels[ AO_DMA_CHAN ]; comedi_subdevice *s = dev->subdevices + 1; devpriv->last_buf_write_count = s->async->buf_write_count; mite_chan->current_link = 0; mite_chan->dir = COMEDI_OUTPUT; if( boardtype.ao_671x ) mite_prep_dma(mite, AO_DMA_CHAN, 32, 32); else mite_prep_dma(mite, AO_DMA_CHAN, 16, 16); /*start the MITE*/ mite_dma_arm(mite, AO_DMA_CHAN);}#endif // PCIDMA/* used for both cancel ioctl and board initialization this is pretty harsh for a cancel, but it works... */static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s){#ifdef PCIDMA mite_dma_disarm(devpriv->mite, AI_DMA_CHAN);#endif /* ai configuration */ win_out( AI_Configuration_Start | AI_Reset, Joint_Reset_Register ); ni_set_bits(dev, Interrupt_A_Enable_Register, AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable| AI_START2_Interrupt_Enable| AI_START_Interrupt_Enable| AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable| AI_FIFO_Interrupt_Enable,0); win_out(1,ADC_FIFO_Clear); ni_writeb(0, Misc_Command); win_out(AI_Disarm, AI_Command_1_Register); /* reset pulses */ win_out(AI_Start_Stop | AI_Mode_1_Reserved /*| AI_Trigger_Once */, AI_Mode_1_Register); win_out(0x0000,AI_Mode_2_Register);#if 0 /* generate FIFO interrupts on half full */ win_out((1<<6)|0x0000,AI_Mode_3_Register);#else /* generate FIFO interrupts on non-empty */ win_out((0<<6)|0x0000,AI_Mode_3_Register);#endif if(!boardtype.reg_611x){ win_out(AI_SHIFTIN_Pulse_Width | AI_SOC_Polarity | AI_CONVERT_Pulse_Width | AI_LOCALMUX_CLK_Pulse_Width, AI_Personal_Register); win_out(AI_SCAN_IN_PROG_Output_Select(3) | AI_EXTMUX_CLK_Output_Select(0) | AI_LOCALMUX_CLK_Output_Select(2) | AI_SC_TC_Output_Select(3) | AI_CONVERT_Output_Select(2),AI_Output_Control_Register); }else{ win_out(AI_SHIFTIN_Pulse_Width | AI_SOC_Polarity | AI_LOCALMUX_CLK_Pulse_Width, AI_Personal_Register); win_out(AI_SCAN_IN_PROG_Output_Select(3) | AI_EXTMUX_CLK_Output_Select(0) | AI_LOCALMUX_CLK_Output_Select(2) | AI_SC_TC_Output_Select(3) | AI_CONVERT_Output_Select(3),AI_Output_Control_Register); } /* the following registers should not be changed, because there * are no backup registers in devpriv. If you want to change * any of these, add a backup register and other appropriate code: * Clock_and_FOUT_Register * AI_Mode_1_Register * AI_Mode_3_Register * AI_Personal_Register * AI_Output_Control_Register */ win_out(0x3f80,Interrupt_A_Ack_Register); /* clear interrupts */ win_out(AI_Configuration_End,Joint_Reset_Register); return 0;}static int ni_ai_poll(comedi_device *dev,comedi_subdevice *s){#ifndef PCIDMA ni_handle_fifo_dregs(dev); //comedi_event(dev,s,s->async->events); return s->async->buf_write_count - s->async->buf_read_count;#else /* XXX we don't support this yet. */ return -EINVAL;#endif}static int ni_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i,n; unsigned int mask; unsigned short signbits; unsigned short d; ni_load_channelgain_list(dev,1,&insn->chanspec); win_out(1,ADC_FIFO_Clear); mask=(1<<boardtype.adbits)-1; signbits=devpriv->ai_offset[0]; if(boardtype.reg_611x){ for(n=0; n < num_adc_stages_611x; n++){ win_out(AI_CONVERT_Pulse, AI_Command_1_Register); comedi_udelay(1); } for(n=0; n<insn->n; n++){ win_out(AI_CONVERT_Pulse, AI_Command_1_Register); /* The 611x has screwy 32-bit FIFOs. */ d = 0; for(i=0; i<NI_TIMEOUT; i++){ if(ni_readb(XXX_Status)&0x80) { d = ( ni_readl(ADC_FIFO_Data_611x) >> 16 ) & 0xffff; break; } if(!(win_in(AI_Status_1_Register)&AI_FIFO_Empty_St)) { d = ni_readl(ADC_FIFO_Data_611x) & 0xffff; break; } } if(i==NI_TIMEOUT){ rt_printk("ni_mio_common: timeout in 611x ni_ai_insn_read\n"); return -ETIME; } d += signbits; /* subtle: needs to be short addition */ data[ n ] = d; } }else{ for(n=0;n<insn->n;n++){ win_out(AI_CONVERT_Pulse, AI_Command_1_Register); for(i=0;i<NI_TIMEOUT;i++){ if(!(win_in(AI_Status_1_Register)&AI_FIFO_Empty_St)) break; } if(i==NI_TIMEOUT){ rt_printk("ni_mio_common: timeout in ni_ai_insn_read\n"); return -ETIME; } d = ni_readw(ADC_FIFO_Data_Register); d += signbits; /* subtle: needs to be short addition */ data[n] = d; } } return insn->n;}/* * Notes on the 6110 and 6111: * These boards a slightly different than the rest of the series, since * they have multiple A/D converters. Register level documentation is * not written down for these boards, other than what is here. If you * have any questions, ask Tim Ousley. * From the driver side, it is only the configuration memory that is a * little different. * Configuration Memory Low: * bits 15-9: same * bit 8: unipolar/bipolar (should be 0 for bipolar) * bits 0-3: gain. This is 4 bits instead of 3 for the other boards * 1001 gain=0.1 (+/- 50) * 1010 0.2 * 1011 0.1 * 0001 1 * 0010 2 * 0011 5 * 0100 10 * 0101 20 * 0110 50 * Configuration Memory High: * bits 12-14: Channel Type * 001 for differential * 000 for calibration * bit 11: coupling (this is not currently handled) * 1 AC coupling * 0 DC coupling * bits 0-2: channel * valid channels are 0-3 */static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan, unsigned int *list){ unsigned int chan,range,aref; unsigned int i; unsigned int hi,lo; unsigned short offset; unsigned int dither; if(n_chan == 1 && boardtype.reg_611x == 0){ if(devpriv->changain_state && devpriv->changain_spec==list[0]){ // ready to go. return; } devpriv->changain_state=1; devpriv->changain_spec=list[0]; }else{ devpriv->changain_state=0; } win_out(1,Configuration_Memory_Clear); offset=1<<(boardtype.adbits-1); for(i=0;i<n_chan;i++){ if(list[i]&CR_ALT_SOURCE){ chan=devpriv->ai_calib_source; }else{ chan=CR_CHAN(list[i]); } aref=CR_AREF(list[i]); range=CR_RANGE(list[i]); dither=((list[i]&CR_ALT_FILTER)!=0); /* fix the external/internal range differences */ range = ni_gainlkup[boardtype.gainlkup][range]; if( boardtype.reg_611x ) devpriv->ai_offset[i] = offset; else devpriv->ai_offset[i] = (range&0x100)?0:offset; hi = 0; if( ( list[i] & CR_ALT_SOURCE ) ) { if( boardtype.reg_611x ) ni_writew(CR_CHAN(list[i])&0x0003, Calibration_Channel_Select_611x); }else { if( boardtype.reg_611x ) aref = AREF_DIFF; switch( aref ) { case AREF_DIFF: hi |= AI_DIFFERENTIAL; break; case AREF_COMMON: hi |= AI_COMMON; break; case AREF_GROUND: hi |= AI_GROUND; break; case AREF_OTHER: break; } } hi |= AI_CONFIG_CHANNEL( chan ); ni_writew(hi,Configuration_Memory_High); lo = range; if(i == n_chan - 1) lo |= AI_LAST_CHANNEL; if( dither ) lo |= AI_DITHER; ni_writew(lo,Configuration_Memory_Low); } /* prime the channel/gain list */ if(boardtype.reg_611x == 0){ win_out(AI_CONVERT_Pulse, AI_Command_1_Register); for(i=0;i<NI_TIMEOUT;i++){ if(!(win_in(AI_Status_1_Register)&AI_FIFO_Empty_St)){ win_out(1,ADC_FIFO_Clear); return; } comedi_udelay(1); } rt_printk("ni_mio_common: timeout loading channel/gain list\n"); }}#define TIMER_BASE 50 /* 20 Mhz base */static int ni_ns_to_timer(int *nanosec,int round_mode){ int divider,base; base=TIMER_BASE; switch(round_mode){ case TRIG_ROUND_NEAREST: default: divider=(*nanosec+base/2)/base; break; case TRIG_ROUND_DOWN: divider=(*nanosec)/base; break; case TRIG_ROUND_UP: divider=(*nanosec+base-1)/base; break; } *nanosec=base*divider; return divider-1;}static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd){ int err=0; int tmp; int sources; /* step 1: make sure trigger sources are trivially valid */ tmp=cmd->start_src; cmd->start_src &= TRIG_NOW|TRIG_INT|TRIG_EXT; if(!cmd->start_src || tmp!=cmd->start_src)err++; tmp=cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_TIMER|TRIG_EXT; if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; tmp=cmd->convert_src; sources = TRIG_TIMER | TRIG_EXT; if( boardtype.reg_611x ) sources |= TRIG_NOW; cmd->convert_src &= sources; 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 */ /* note that mutual compatiblity is not an issue here */ if(cmd->start_src!=TRIG_NOW && cmd->start_src!=TRIG_INT && cmd->start_src!=TRIG_EXT)err++; if(cmd->scan_begin_src!=TRIG_TIMER && cmd->scan_begin_src!=TRIG_EXT && cmd->scan_begin_src!=TRIG_OTHER)err++; if(cmd->convert_src!=TRIG_TIMER && cmd->convert_src!=TRIG_EXT && cmd->convert_src!=TRIG_NOW)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_src==TRIG_EXT){ /* external trigger */ unsigned int tmp = CR_CHAN(cmd->start_arg); if(tmp>9)tmp=9; /* XXX for now, use the top bit to invert the signal */ tmp |= (cmd->start_arg&0x80000000); if(cmd->start_arg!=tmp){ cmd->start_arg = tmp; err++; } }else{ if(cmd->start_arg!=0){ /* true for both TRIG_NOW and TRIG_INT */ cmd->start_arg=0; err++; } } if(cmd->scan_begin_src==TRIG_TIMER){ if(cmd->scan_begin_arg<boardtype.ai_speed){ cmd->scan_begin_arg=boardtype.ai_speed; err++; } if(cmd->scan_begin_arg>TIMER_BASE*0xffffff){ cmd->scan_begin_arg=TIMER_BASE*0xffffff; err++; } }else if(cmd->scan_begin_src==TRIG_EXT){ /* external trigger */ unsigned int tmp = CR_CHAN(cmd->scan_begin_arg); if(tmp>9)tmp=9; /* XXX for now, use the top bit to invert the signal */ tmp |= (cmd->scan_begin_arg&0x80000000); if(cmd->scan_begin_arg!=tmp){ cmd->scan_begin_arg = tmp; err++; } }else{ /* TRIG_OTHER */ if(cmd->scan_begin_arg){ cmd->scan_begin_arg=0; err++; } } if(cmd->convert_src==TRIG_TIMER){ if( boardtype.reg_611x ){ if(cmd->convert_arg != 0){ cmd->convert_arg = 0; err++; } }else{ if(cmd->convert_arg<boardtype.ai_speed){ cmd->convert_arg=boardtype.ai_speed; err++; } if(cmd->convert_arg>TIMER_BASE*0xffff){ cmd->convert_arg=TIMER_BASE*0xffff; err++; } } }else if(cmd->convert_src == TRIG_EXT){ /* external trigger */ unsigned int tmp = CR_CHAN(cmd->convert_arg); if(tmp>9)tmp=9; tmp |= (cmd->convert_arg&(CR_ALT_FILTER|CR_INVERT)); if(cmd->convert_arg!=tmp){ cmd->convert_arg = tmp; err++; } }else if(cmd->convert_src == TRIG_NOW){ if(cmd->convert_arg != 0){ cmd->convert_arg = 0; err++; } } if(cmd->scan_end_arg!=cmd->chanlist_len){ cmd->scan_end_arg=cmd->chanlist_len; err++; } if(cmd->stop_src==TRIG_COUNT){ unsigned int max_count = 0x01000000; if( boardtype.reg_611x ) max_count -= num_adc_stages_611x; if(cmd->stop_arg > max_count){ cmd->stop_arg = max_count; err++; } }else{ /* TRIG_NONE */ if(cmd->stop_arg!=0){ cmd->stop_arg=0; err++; } } if(err)return 3; /* step 4: fix up any arguments */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -