static int dmm32at_ai_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); unsigned int range0 = CR_RANGE(cmd->chanlist[0]); int i; for (i = 1; i < cmd->chanlist_len; i++) { unsigned int chan = CR_CHAN(cmd->chanlist[i]); unsigned int range = CR_RANGE(cmd->chanlist[i]); if (chan != (chan0 + i) % s->n_chan) { dev_dbg(dev->class_dev, "entries in chanlist must be consecutive channels, counting upwards\n"); return -EINVAL; } if (range != range0) { dev_dbg(dev->class_dev, "entries in chanlist must all have the same gain\n"); return -EINVAL; } } return 0; }
static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct das08_board_struct *thisboard = comedi_board(dev); struct das08_private_struct *devpriv = dev->private; int i, n; int chan; int range; int lsb, msb; chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); /* clear crap */ inb(dev->iobase + DAS08_LSB); inb(dev->iobase + DAS08_MSB); /* set multiplexer */ /* lock to prevent race with digital output */ spin_lock(&dev->spinlock); devpriv->do_mux_bits &= ~DAS08_MUX_MASK; devpriv->do_mux_bits |= DAS08_MUX(chan); outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); spin_unlock(&dev->spinlock); if (s->range_table->length > 1) { /* set gain/range */ range = CR_RANGE(insn->chanspec); outb(devpriv->pg_gainlist[range], dev->iobase + DAS08AO_GAIN_CONTROL); } for (n = 0; n < insn->n; n++) { /* clear over-range bits for 16-bit boards */ if (thisboard->ai_nbits == 16) if (inb(dev->iobase + DAS08_MSB) & 0x80) dev_info(dev->class_dev, "over-range\n"); /* trigger conversion */ outb_p(0, dev->iobase + DAS08_TRIG_12BIT); for (i = 0; i < TIMEOUT; i++) { if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC)) break; } if (i == TIMEOUT) { dev_err(dev->class_dev, "timeout\n"); return -ETIME; } msb = inb(dev->iobase + DAS08_MSB); lsb = inb(dev->iobase + DAS08_LSB); if (thisboard->ai_encoding == das08_encode12) { data[n] = (lsb >> 4) | (msb << 4); } else if (thisboard->ai_encoding == das08_pcm_encode12) {
static int dac02_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); unsigned int val; int i; for (i = 0; i < insn->n; i++) { val = data[i]; s->readback[chan] = val; /* * Unipolar outputs are true binary encoding. * Bipolar outputs are complementary offset binary * (that is, 0 = +full scale, maxdata = -full scale). */ if (comedi_range_is_bipolar(s, range)) val = s->maxdata - val; /* * DACs are double-buffered. * Write LSB then MSB to latch output. */ outb((val << 4) & 0xf0, dev->iobase + DAC02_AO_LSB(chan)); outb((val >> 4) & 0xff, dev->iobase + DAC02_AO_MSB(chan)); } return insn->n; }
static void pcl711_set_changain(struct comedi_device *dev, int chan) { int chan_register; outb(CR_RANGE(chan), dev->iobase + PCL711_GAIN); chan_register = CR_CHAN(chan); if (this_board->is_8112) { /* * Set the correct channel. The two channel banks are switched * using the mask value. * NB: To use differential channels, you should use * mask = 0x30, but I haven't written the support for this * yet. /JJ */ if (chan_register >= 8) chan_register = 0x20 | (chan_register & 0x7); else chan_register |= 0x10; } else { outb(chan_register, dev->iobase + PCL711_MUX); } }
static int pci1720_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); unsigned int val; int i; /* set the channel range and polarity */ val = inb(dev->iobase + PCI1720_AO_RANGE_REG); val &= ~PCI1720_AO_RANGE_MASK(chan); val |= PCI1720_AO_RANGE(chan, range); outb(val, dev->iobase + PCI1720_AO_RANGE_REG); val = s->readback[chan]; for (i = 0; i < insn->n; i++) { val = data[i]; outb(val & 0xff, dev->iobase + PCI1720_AO_LSB_REG(chan)); outb((val >> 8) & 0xff, dev->iobase + PCI1720_AO_MSB_REG(chan)); /* conversion time is 2us (500 kHz throughput) */ usleep_range(2, 100); } s->readback[chan] = val; return insn->n; }
static int daq700_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int n; int d; int ret; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); unsigned int r3_bits = 0; /* set channel input modes */ if (aref == AREF_DIFF) r3_bits |= CMD_R3_DIFF; /* write channel mode/range */ if (range >= 1) range++; /* convert range to hardware value */ outb(r3_bits | (range & 0x03), dev->iobase + CMD_R3); /* write channel to multiplexer */ /* set mask scan bit high to disable scanning */ outb(chan | 0x80, dev->iobase + CMD_R1); /* mux needs 2us to really settle [Fred Brooks]. */ udelay(2); /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion with out0 L to H */ outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */ outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */ outb(0x00, dev->iobase + ADCLEAR_R); /* clear the ADC FIFO */ /* read 16bit junk from FIFO to clear */ inw(dev->iobase + ADFIFO_R); /* mode 1 out0 H, L to H, start conversion */ outb(0x32, dev->iobase + CMO_R); /* wait for conversion to end */ ret = comedi_timeout(dev, s, insn, daq700_ai_eoc, 0); if (ret) return ret; /* read data */ d = inw(dev->iobase + ADFIFO_R); /* mangle the data as necessary */ /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */ d &= 0x0fff; d ^= 0x0800; data[n] = d; } return n; }
static void generic_prep_adc_for_dac( calibration_setup_t *setup, comedi_calibration_t *calibration, int observable ) { unsigned int adc_channel, adc_range; int chanspec; if( observable < 0 ) return; chanspec = setup->observables[ observable ].observe_insn.chanspec; adc_channel = CR_CHAN( chanspec ); adc_range = CR_RANGE( chanspec ); comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev, adc_channel, adc_range, 0, calibration ); }
static int apci3501_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); unsigned int cfg = APCI3501_AO_DATA_CHAN(chan); int ret; int i; /* * All analog output channels have the same output range. * 14-bit bipolar: 0-10V * 13-bit unipolar: +/-10V * Changing the range of one channel changes all of them! */ if (range) { outl(0, dev->iobase + APCI3501_AO_CTRL_STATUS_REG); } else { cfg |= APCI3501_AO_DATA_BIPOLAR; outl(APCI3501_AO_CTRL_BIPOLAR, dev->iobase + APCI3501_AO_CTRL_STATUS_REG); } for (i = 0; i < insn->n; i++) { unsigned int val = data[i]; if (range == 1) { if (data[i] > 0x1fff) { dev_err(dev->class_dev, "Unipolar resolution is only 13-bits\n"); return -EINVAL; } } ret = apci3501_wait_for_dac(dev); if (ret) return ret; outl(cfg | APCI3501_AO_DATA_VAL(val), dev->iobase + APCI3501_AO_DATA_REG); s->readback[chan] = val; } return insn->n; }
static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct das16_board *board = comedi_board(dev); int i, n; int range; int chan; int msb, lsb; /* disable interrupts and pacing */ devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK; outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); /* set multiplexer */ chan = CR_CHAN(insn->chanspec); chan |= CR_CHAN(insn->chanspec) << 4; outb(chan, dev->iobase + DAS16_MUX); /* set gain */ if (board->ai_pg != das16_pg_none) { range = CR_RANGE(insn->chanspec); outb((das16_gainlists[board->ai_pg])[range], dev->iobase + DAS16_GAIN); } for (n = 0; n < insn->n; n++) { /* trigger conversion */ outb_p(0, dev->iobase + DAS16_TRIG); for (i = 0; i < DAS16_TIMEOUT; i++) { if (!(inb(dev->iobase + DAS16_STATUS) & BUSY)) break; } if (i == DAS16_TIMEOUT) { printk("das16: timeout\n"); return -ETIME; } msb = inb(dev->iobase + DAS16_AI_MSB); lsb = inb(dev->iobase + DAS16_AI_LSB); if (board->ai_nbits == 12) data[n] = ((lsb >> 4) & 0xf) | (msb << 4); else data[n] = lsb | (msb << 8); }
static void dmm32at_ai_set_chanspec(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int chanspec, int nchan) { unsigned int chan = CR_CHAN(chanspec); unsigned int range = CR_RANGE(chanspec); unsigned int last_chan = (chan + nchan - 1) % s->n_chan; outb(DMM32AT_FIFO_CTRL_FIFORST, dev->iobase + DMM32AT_FIFO_CTRL_REG); if (nchan > 1) outb(DMM32AT_FIFO_CTRL_SCANEN, dev->iobase + DMM32AT_FIFO_CTRL_REG); outb(chan, dev->iobase + DMM32AT_AI_LO_CHAN_REG); outb(last_chan, dev->iobase + DMM32AT_AI_HI_CHAN_REG); outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AI_CFG_REG); }
/* analog output callback */ static int dyna_pci10xx_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct dyna_pci10xx_private *devpriv = dev->private; int n; unsigned int chan, range; chan = CR_CHAN(insn->chanspec); range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; mutex_lock(&devpriv->mutex); for (n = 0; n < insn->n; n++) { smp_mb(); /* trigger conversion and write data */ outw_p(data[n], dev->iobase); udelay(10); } mutex_unlock(&devpriv->mutex); return n; }
static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct dyna_pci10xx_private *devpriv = dev->private; int n; u16 d = 0; int ret = 0; unsigned int chan, range; /* get the channel number and range */ chan = CR_CHAN(insn->chanspec); range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; mutex_lock(&devpriv->mutex); /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ smp_mb(); outw_p(0x0000 + range + chan, dev->iobase + 2); udelay(10); ret = comedi_timeout(dev, s, insn, dyna_pci10xx_ai_eoc, 0); if (ret) break; /* read data */ d = inw_p(dev->iobase); /* mask the first 4 bits - EOC bits */ d &= 0x0FFF; data[n] = d; } mutex_unlock(&devpriv->mutex); /* return the number of samples read/written */ return ret ? ret : n; }
static int atmio16d_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct atmio16d_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int timer, base_clock; unsigned int sample_count, tmp, chan, gain; int i; /* This is slowly becoming a working command interface. * * It is still uber-experimental */ reset_counters(dev); s->async->cur_chan = 0; /* check if scanning multiple channels */ if (cmd->chanlist_len < 2) { devpriv->com_reg_1_state &= ~COMREG1_SCANEN; outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); } else { devpriv->com_reg_1_state |= COMREG1_SCANEN; devpriv->com_reg_2_state |= COMREG2_SCN2; outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2); } /* Setup the Mux-Gain Counter */ for (i = 0; i < cmd->chanlist_len; ++i) { chan = CR_CHAN(cmd->chanlist[i]); gain = CR_RANGE(cmd->chanlist[i]); outw(i, dev->iobase + MUX_CNTR_REG); tmp = chan | (gain << 6); if (i == cmd->scan_end_arg - 1) tmp |= 0x0010; /* set LASTONE bit */ outw(tmp, dev->iobase + MUX_GAIN_REG); } /* Now program the sample interval timer */ /* Figure out which clock to use then get an * appropriate timer value */ if (cmd->convert_arg < 65536000) { base_clock = CLOCK_1_MHZ; timer = cmd->convert_arg / 1000; } else if (cmd->convert_arg < 655360000) { base_clock = CLOCK_100_KHZ; timer = cmd->convert_arg / 10000; } else if (cmd->convert_arg <= 0xffffffff /* 6553600000 */) { base_clock = CLOCK_10_KHZ; timer = cmd->convert_arg / 100000; } else if (cmd->convert_arg <= 0xffffffff /* 65536000000 */) { base_clock = CLOCK_1_KHZ; timer = cmd->convert_arg / 1000000; } outw(0xFF03, dev->iobase + AM9513A_COM_REG); outw(base_clock, dev->iobase + AM9513A_DATA_REG); outw(0xFF0B, dev->iobase + AM9513A_COM_REG); outw(0x2, dev->iobase + AM9513A_DATA_REG); outw(0xFF44, dev->iobase + AM9513A_COM_REG); outw(0xFFF3, dev->iobase + AM9513A_COM_REG); outw(timer, dev->iobase + AM9513A_DATA_REG); outw(0xFF24, dev->iobase + AM9513A_COM_REG); /* Now figure out how many samples to get */ /* and program the sample counter */ sample_count = cmd->stop_arg * cmd->scan_end_arg; outw(0xFF04, dev->iobase + AM9513A_COM_REG); outw(0x1025, dev->iobase + AM9513A_DATA_REG); outw(0xFF0C, dev->iobase + AM9513A_COM_REG); if (sample_count < 65536) { /* use only Counter 4 */ outw(sample_count, dev->iobase + AM9513A_DATA_REG); outw(0xFF48, dev->iobase + AM9513A_COM_REG); outw(0xFFF4, dev->iobase + AM9513A_COM_REG); outw(0xFF28, dev->iobase + AM9513A_COM_REG); devpriv->com_reg_1_state &= ~COMREG1_1632CNT; outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); } else { /* Counter 4 and 5 are needed */ tmp = sample_count & 0xFFFF; if (tmp) outw(tmp - 1, dev->iobase + AM9513A_DATA_REG); else outw(0xFFFF, dev->iobase + AM9513A_DATA_REG); outw(0xFF48, dev->iobase + AM9513A_COM_REG); outw(0, dev->iobase + AM9513A_DATA_REG); outw(0xFF28, dev->iobase + AM9513A_COM_REG); outw(0xFF05, dev->iobase + AM9513A_COM_REG); outw(0x25, dev->iobase + AM9513A_DATA_REG); outw(0xFF0D, dev->iobase + AM9513A_COM_REG); tmp = sample_count & 0xFFFF; if ((tmp == 0) || (tmp == 1)) { outw((sample_count >> 16) & 0xFFFF, dev->iobase + AM9513A_DATA_REG); } else {
static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { const struct das16_board *board = comedi_board(dev); struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int byte; unsigned long flags; int range; if (devpriv->dma_chan == 0 || (dev->irq == 0 && devpriv->timer_mode == 0)) { comedi_error(dev, "irq (or use of 'timer mode') dma required to " "execute comedi_cmd"); return -1; } if (cmd->flags & TRIG_RT) { comedi_error(dev, "isa dma transfers cannot be performed with " "TRIG_RT, aborting"); return -1; } devpriv->adc_byte_count = cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t); /* disable conversions for das1600 mode */ if (board->size > 0x400) outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV); /* set scan limits */ byte = CR_CHAN(cmd->chanlist[0]); byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4; outb(byte, dev->iobase + DAS16_MUX); /* set gain (this is also burst rate register but according to * computer boards manual, burst rate does nothing, even on * keithley cards) */ if (board->ai_pg != das16_pg_none) { range = CR_RANGE(cmd->chanlist[0]); outb((das16_gainlists[board->ai_pg])[range], dev->iobase + DAS16_GAIN); } /* set counter mode and counts */ cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); DEBUG_PRINT("pacer period: %d ns\n", cmd->convert_arg); /* enable counters */ byte = 0; /* Enable burst mode if appropriate. */ if (board->size > 0x400) { if (cmd->convert_src == TRIG_NOW) { outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST); /* set burst length */ byte |= BURST_LEN_BITS(cmd->chanlist_len - 1); } else { outb(0, dev->iobase + DAS1600_BURST); } } outb(byte, dev->iobase + DAS16_PACER); /* set up dma transfer */ flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); /* clear flip-flop to make sure 2-byte registers for * count and address get set correctly */ clear_dma_ff(devpriv->dma_chan); devpriv->current_buffer = 0; set_dma_addr(devpriv->dma_chan, devpriv->dma_buffer_addr[devpriv->current_buffer]); /* set appropriate size of transfer */ devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, *cmd); set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); enable_dma(devpriv->dma_chan); release_dma_lock(flags); /* set up interrupt */ if (devpriv->timer_mode) { devpriv->timer_running = 1; devpriv->timer.expires = jiffies + timer_period(); add_timer(&devpriv->timer); devpriv->control_state &= ~DAS16_INTE; } else { /* clear interrupt bit */ outb(0x00, dev->iobase + DAS16_STATUS); /* enable interrupts */ devpriv->control_state |= DAS16_INTE; } devpriv->control_state |= DMA_ENABLE; devpriv->control_state &= ~PACING_MASK; if (cmd->convert_src == TRIG_EXT) devpriv->control_state |= EXT_PACER; else devpriv->control_state |= INT_PACER; outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); /* Enable conversions if using das1600 mode */ if (board->size > 0x400) outb(0, dev->iobase + DAS1600_CONV); return 0; }
static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct das16_board *board = comedi_board(dev); int err = 0, tmp; int gain, start_chan, i; int mask; /* make sure triggers are valid */ tmp = cmd->start_src; cmd->start_src &= TRIG_NOW; if (!cmd->start_src || tmp != cmd->start_src) err++; tmp = cmd->scan_begin_src; mask = TRIG_FOLLOW; /* if board supports burst mode */ if (board->size > 0x400) mask |= TRIG_TIMER | TRIG_EXT; cmd->scan_begin_src &= mask; if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; tmp = cmd->convert_src; mask = TRIG_TIMER | TRIG_EXT; /* if board supports burst mode */ if (board->size > 0x400) mask |= TRIG_NOW; cmd->convert_src &= mask; 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->scan_begin_src != TRIG_TIMER && cmd->scan_begin_src != TRIG_EXT && cmd->scan_begin_src != TRIG_FOLLOW) err++; if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) err++; if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) err++; /* make sure scan_begin_src and convert_src dont conflict */ if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) err++; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) 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->scan_begin_src == TRIG_FOLLOW) { /* internal trigger */ if (cmd->scan_begin_arg != 0) { cmd->scan_begin_arg = 0; err++; } } if (cmd->scan_end_arg != cmd->chanlist_len) { cmd->scan_end_arg = cmd->chanlist_len; err++; } /* check against maximum frequency */ if (cmd->scan_begin_src == TRIG_TIMER) { if (cmd->scan_begin_arg < board->ai_speed * cmd->chanlist_len) { cmd->scan_begin_arg = board->ai_speed * cmd->chanlist_len; err++; } } if (cmd->convert_src == TRIG_TIMER) { if (cmd->convert_arg < board->ai_speed) { cmd->convert_arg = board->ai_speed; err++; } } if (cmd->stop_src == TRIG_NONE) { if (cmd->stop_arg != 0) { cmd->stop_arg = 0; err++; } } if (err) return 3; /* step 4: fix up arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { unsigned int tmp = cmd->scan_begin_arg; /* set divisors, correct timing arguments */ i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->scan_begin_arg), cmd->flags & TRIG_ROUND_MASK); err += (tmp != cmd->scan_begin_arg); } if (cmd->convert_src == TRIG_TIMER) { unsigned int tmp = cmd->convert_arg; /* set divisors, correct timing arguments */ i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK); err += (tmp != cmd->convert_arg); } if (err) return 4; /* check channel/gain list against card's limitations */ if (cmd->chanlist) { gain = CR_RANGE(cmd->chanlist[0]); start_chan = CR_CHAN(cmd->chanlist[0]); for (i = 1; i < cmd->chanlist_len; i++) { if (CR_CHAN(cmd->chanlist[i]) != (start_chan + i) % s->n_chan) { comedi_error(dev, "entries in chanlist must be " "consecutive channels, " "counting upwards\n"); err++; } if (CR_RANGE(cmd->chanlist[i]) != gain) { comedi_error(dev, "entries in chanlist must all " "have the same gain\n"); err++; } } } if (err) return 5; return 0; }
int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int i_ReturnValue = 0; unsigned char b_Cpt; unsigned char b_Length; unsigned char b_Schift; unsigned char b_SSICpt; unsigned int dw_And; unsigned int dw_And1; unsigned int dw_And2; unsigned int dw_StatusReg; unsigned int dw_CounterValue; unsigned char b_ModulNbr; unsigned char b_SelectedSSI; unsigned char b_ReadType; unsigned int *pul_Position; unsigned int *pul_TurnCpt; unsigned int *pul_Position1; unsigned int *pul_TurnCpt1; i_ReturnValue = insn->n; pul_Position1 = (unsigned int *) &data[0]; /* For Read1 */ pul_TurnCpt1 = (unsigned int *) &data[1]; /* For Read all */ pul_Position = (unsigned int *) &data[0]; /* 0-2 */ pul_TurnCpt = (unsigned int *) &data[3]; /* 3-5 */ b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); /**************************/ /* Test the module number */ /**************************/ if (b_ModulNbr < 4) { /***********************/ /* Test if SSI counter */ /***********************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { /***************************/ /* Test if SSI initialised */ /***************************/ if (devpriv->s_ModuleInfo[b_ModulNbr]. s_SSICounterInfo.b_SSIInit == 1) { switch (b_ReadType) { case APCI1710_SSI_READ1VALUE: /****************************************/ /* Test the selected SSI counter number */ /****************************************/ if (b_SelectedSSI < 3) { /************************/ /* Start the conversion */ /************************/ outl(0, devpriv->s_BoardInfos. ui_Address + 8 + (64 * b_ModulNbr)); do { /*******************/ /* Read the status */ /*******************/ dw_StatusReg = inl(devpriv-> s_BoardInfos. ui_Address + (64 * b_ModulNbr)); } while ((dw_StatusReg & 0x1) != 0); /******************************/ /* Read the SSI counter value */ /******************************/ dw_CounterValue = inl(devpriv-> s_BoardInfos. ui_Address + 4 + (b_SelectedSSI * 4) + (64 * b_ModulNbr)); b_Length = devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile / 2; if ((b_Length * 2) != devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile) { b_Length++; } b_Schift = b_Length - devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength; *pul_Position1 = dw_CounterValue >> b_Schift; dw_And = 1; for (b_Cpt = 0; b_Cpt < devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength; b_Cpt++) { dw_And = dw_And * 2; } *pul_Position1 = *pul_Position1 & ((dw_And) - 1); *pul_TurnCpt1 = dw_CounterValue >> b_Length; dw_And = 1; for (b_Cpt = 0; b_Cpt < devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_TurnCptLength; b_Cpt++) { dw_And = dw_And * 2; } *pul_TurnCpt1 = *pul_TurnCpt1 & ((dw_And) - 1); } else { /*****************************/ /* The selected SSI is wrong */ /*****************************/ DPRINTK("The selected SSI is wrong\n"); i_ReturnValue = -5; } break; case APCI1710_SSI_READALLVALUE: dw_And1 = 1; for (b_Cpt = 0; b_Cpt < devpriv-> s_ModuleInfo[b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength; b_Cpt++) { dw_And1 = dw_And1 * 2; } dw_And2 = 1; for (b_Cpt = 0; b_Cpt < devpriv-> s_ModuleInfo[b_ModulNbr]. s_SSICounterInfo. b_TurnCptLength; b_Cpt++) { dw_And2 = dw_And2 * 2; } /************************/ /* Start the conversion */ /************************/ outl(0, devpriv->s_BoardInfos. ui_Address + 8 + (64 * b_ModulNbr)); do { /*******************/ /* Read the status */ /*******************/ dw_StatusReg = inl(devpriv-> s_BoardInfos. ui_Address + (64 * b_ModulNbr)); } while ((dw_StatusReg & 0x1) != 0); for (b_SSICpt = 0; b_SSICpt < 3; b_SSICpt++) { /******************************/ /* Read the SSI counter value */ /******************************/ dw_CounterValue = inl(devpriv-> s_BoardInfos. ui_Address + 4 + (b_SSICpt * 4) + (64 * b_ModulNbr)); b_Length = devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile / 2; if ((b_Length * 2) != devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile) { b_Length++; } b_Schift = b_Length - devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength; pul_Position[b_SSICpt] = dw_CounterValue >> b_Schift; pul_Position[b_SSICpt] = pul_Position[b_SSICpt] & ((dw_And1) - 1); pul_TurnCpt[b_SSICpt] = dw_CounterValue >> b_Length; pul_TurnCpt[b_SSICpt] = pul_TurnCpt[b_SSICpt] & ((dw_And2) - 1); } break; default: printk("Read Type Inputs Wrong\n"); } /* switch ending */ } else {
/* analogue IN - interrupt service routine */ static void usbduxsub_ai_isoc_irq(struct urb *urb) { struct comedi_device *dev = urb->context; struct comedi_subdevice *s = dev->read_subdev; struct usbdux_private *devpriv = dev->private; int i, err, n; /* first we test if something unusual has just happened */ switch (urb->status) { case 0: /* copy the result in the transfer buffer */ memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); break; case -EILSEQ: /* error in the ISOchronous data */ /* we don't copy the data into the transfer buffer */ /* and recycle the last data byte */ dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ if (devpriv->ai_cmd_running) { s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; comedi_event(dev, s); /* stop the transfer w/o unlink */ usbdux_ai_stop(dev, 0); } return; default: /* a real error on the bus */ /* pass error to comedi if we are really running a command */ if (devpriv->ai_cmd_running) { dev_err(dev->class_dev, "Non-zero urb status received in ai intr context: %d\n", urb->status); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; comedi_event(dev, s); /* don't do an unlink here */ usbdux_ai_stop(dev, 0); } return; } /* * at this point we are reasonably sure that nothing dodgy has happened * are we running a command? */ if (unlikely(!devpriv->ai_cmd_running)) { /* * not running a command, do not continue execution if no * asynchronous command is running in particular not resubmit */ return; } urb->dev = comedi_to_usb_dev(dev); /* resubmit the urb */ err = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(err < 0)) { dev_err(dev->class_dev, "urb resubmit failed in int-context! err=%d\n", err); if (err == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handler!\n"); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; comedi_event(dev, s); /* don't do an unlink here */ usbdux_ai_stop(dev, 0); return; } devpriv->ai_counter--; if (likely(devpriv->ai_counter > 0)) return; /* timer zero, transfer measurements to comedi */ devpriv->ai_counter = devpriv->ai_timer; /* test, if we transmit only a fixed number of samples */ if (!devpriv->ai_continous) { /* not continuous, fixed number of samples */ devpriv->ai_sample_count--; /* all samples received? */ if (devpriv->ai_sample_count < 0) { /* prevent a resubmit next time */ usbdux_ai_stop(dev, 0); /* say comedi that the acquistion is over */ s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); return; } } /* get the data from the USB bus and hand it over to comedi */ n = s->async->cmd.chanlist_len; for (i = 0; i < n; i++) { unsigned int range = CR_RANGE(s->async->cmd.chanlist[i]); int16_t val = le16_to_cpu(devpriv->in_buf[i]); /* bipolar data is two's-complement */ if (comedi_range_is_bipolar(s, range)) val ^= ((s->maxdata + 1) >> 1); /* transfer data */ err = comedi_buf_put(s->async, val); if (unlikely(err == 0)) { /* buffer overflow */ usbdux_ai_stop(dev, 0); return; } } /* tell comedi that data is there */ s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); }