📄 cb_pcidas.c
字号:
static int cb_pcidas_ai_cmd(comedi_device *dev,comedi_subdevice *s);static int cb_pcidas_ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);static int cb_pcidas_ao_cmd(comedi_device *dev,comedi_subdevice *s);static int cb_pcidas_ao_inttrig(comedi_device *dev, comedi_subdevice *subdev, unsigned int trig_num);static int cb_pcidas_ao_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);static void cb_pcidas_interrupt(int irq, void *d, struct pt_regs *regs);static void handle_ao_interrupt(comedi_device *dev, unsigned int status);static int cb_pcidas_cancel(comedi_device *dev, comedi_subdevice *s);static int cb_pcidas_ao_cancel(comedi_device *dev, comedi_subdevice *s);static void cb_pcidas_load_counters(comedi_device *dev, unsigned int *ns, int round_flags);static int eeprom_read_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data );static int caldac_read_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data );static int caldac_write_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data );static int trimpot_read_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data );static int cb_pcidas_trimpot_write( comedi_device *dev, unsigned int channel, lsampl_t value );static int trimpot_write_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data );static int dac08_read_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data );static int dac08_write( comedi_device *dev, lsampl_t value );static int dac08_write_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data );static int caldac_8800_write(comedi_device *dev, unsigned int address, uint8_t value);static int trimpot_7376_write(comedi_device *dev, uint8_t value);static int trimpot_8402_write(comedi_device *dev, unsigned int channel, uint8_t value);static int nvram_read( comedi_device *dev, unsigned int address, uint8_t *data );/* * Attach is called by the Comedi core to configure the driver * for a particular board. */static int cb_pcidas_attach(comedi_device *dev, comedi_devconfig *it){ comedi_subdevice *s; struct pci_dev* pcidev; int index; unsigned long s5933_config, control_status, adc_fifo, pacer_counter_dio, ao_registers; int err; int i; printk("comedi%d: cb_pcidas: ",dev->minor);/* * Allocate the private structure area. */ if(alloc_private(dev,sizeof(cb_pcidas_private))<0) return -ENOMEM;/* * Probe the device to determine what device in the series it is. */ printk("\n"); pci_for_each_dev(pcidev) { // is it not a computer boards card? if(pcidev->vendor != PCI_VENDOR_ID_CB) continue; // loop through cards supported by this driver for(index = 0; index < N_BOARDS; index++) { if(cb_pcidas_boards[index].device_id != pcidev->device) continue; // was a particular bus/slot requested? if(it->options[0] || it->options[1]) { // are we on the wrong bus/slot? if(pcidev->bus->number != it->options[0] || PCI_SLOT(pcidev->devfn) != it->options[1]) { continue; } } devpriv->pci_dev = pcidev; dev->board_ptr = cb_pcidas_boards + index; goto found; } } printk("No supported ComputerBoards/MeasurementComputing card found on " "requested position\n"); return -EIO;found: printk("Found %s on bus %i, slot %i\n", cb_pcidas_boards[index].name, devpriv->pci_dev->bus->number, PCI_SLOT(devpriv->pci_dev->devfn)); /* * Initialize devpriv->control_status and devpriv->adc_fifo to point to * their base address. */ if(pci_enable_device(devpriv->pci_dev)) return -EIO; s5933_config = pci_resource_start(devpriv->pci_dev, S5933_BADRINDEX); control_status = pci_resource_start(devpriv->pci_dev, CONT_STAT_BADRINDEX); adc_fifo = pci_resource_start(devpriv->pci_dev, ADC_FIFO_BADRINDEX); pacer_counter_dio = pci_resource_start(devpriv->pci_dev, PACER_BADRINDEX); ao_registers = pci_resource_start(devpriv->pci_dev, AO_BADRINDEX); // reserve io ports err = 0; if(check_region(s5933_config, AMCC_OP_REG_SIZE) < 0) err++; if(check_region(control_status, CONT_STAT_SIZE) < 0) err++; if(check_region(adc_fifo, ADC_FIFO_SIZE) < 0) err++; if(check_region(pacer_counter_dio, PACER_SIZE) < 0) err++; if(thisboard->ao_nchan) if(check_region(ao_registers, AO_SIZE) < 0) err++; if(err) { printk(" I/O port conflict\n"); return -EIO; } request_region(s5933_config, AMCC_OP_REG_SIZE, "cb_pcidas"); devpriv->s5933_config = s5933_config; request_region(control_status, CONT_STAT_SIZE, "cb_pcidas"); devpriv->control_status = control_status; request_region(adc_fifo, ADC_FIFO_SIZE, "cb_pcidas"); devpriv->adc_fifo = adc_fifo; request_region(pacer_counter_dio, PACER_SIZE, "cb_pcidas"); devpriv->pacer_counter_dio = pacer_counter_dio; if(thisboard->ao_nchan) { request_region(ao_registers, AO_SIZE, "cb_pcidas"); devpriv->ao_registers = ao_registers; } // get irq if(comedi_request_irq(devpriv->pci_dev->irq, cb_pcidas_interrupt, SA_SHIRQ, "cb_pcidas", dev )) { printk(" unable to allocate irq %d\n", devpriv->pci_dev->irq); return -EINVAL; } dev->irq = devpriv->pci_dev->irq; //Initialize dev->board_name dev->board_name = thisboard->name;/* * Allocate the subdevice structures. */ if(alloc_subdevices(dev, 7) < 0) return -ENOMEM; s = dev->subdevices + 0; /* analog input subdevice */ dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; /* WARNING: Number of inputs in differential mode is ignored */ s->n_chan = thisboard->ai_se_chans; s->len_chanlist = thisboard->ai_se_chans; s->maxdata = (1 << thisboard->ai_bits) - 1; s->range_table = thisboard->ranges; s->insn_read = cb_pcidas_ai_rinsn; s->insn_config = ai_config_insn; s->do_cmd = cb_pcidas_ai_cmd; s->do_cmdtest = cb_pcidas_ai_cmdtest; s->cancel = cb_pcidas_cancel; /* analog output subdevice */ s = dev->subdevices + 1; if(thisboard->ao_nchan) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; s->n_chan = thisboard->ao_nchan; // analog out resolution is the same as analog input resolution, so use ai_bits s->maxdata = (1 << thisboard->ai_bits) - 1; s->range_table = &cb_pcidas_ao_ranges; s->insn_read = cb_pcidas_ao_readback_insn; if(thisboard->has_ao_fifo) { dev->write_subdev = s; s->insn_write = cb_pcidas_ao_fifo_winsn; s->do_cmdtest = cb_pcidas_ao_cmdtest; s->do_cmd = cb_pcidas_ao_cmd; s->cancel = cb_pcidas_ao_cancel; }else { s->insn_write = cb_pcidas_ao_nofifo_winsn; } }else { s->type = COMEDI_SUBD_UNUSED; } /* 8255 */ s = dev->subdevices + 2; subdev_8255_init(dev, s, NULL, (unsigned long)(devpriv->pacer_counter_dio + DIO_8255)); // serial EEPROM, s = dev->subdevices + 3; s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; s->n_chan = 256; s->maxdata = 0xff; s->insn_read = eeprom_read_insn; // 8800 caldac s = dev->subdevices + 4; s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = NUM_CHANNELS_8800; s->maxdata = 0xff; s->insn_read = caldac_read_insn; s->insn_write = caldac_write_insn; for( i = 0; i < s->n_chan; i++ ) caldac_8800_write( dev, i, s->maxdata / 2 ); // trim potentiometer s = dev->subdevices + 5; s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; if( thisboard->trimpot == AD7376 ) { s->n_chan = NUM_CHANNELS_7376; s->maxdata = 0x7f; }else { s->n_chan = NUM_CHANNELS_8402; s->maxdata = 0xff; } s->insn_read = trimpot_read_insn; s->insn_write = trimpot_write_insn; for( i = 0; i < s->n_chan; i++ ) cb_pcidas_trimpot_write( dev, i, s->maxdata / 2 ); // dac08 caldac s = dev->subdevices + 6; if( thisboard->has_dac08 ) { s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = NUM_CHANNELS_DAC08; s->insn_read = dac08_read_insn; s->insn_write = dac08_write_insn; s->maxdata = 0xff; dac08_write( dev, s->maxdata / 2 ); }else s->type = COMEDI_SUBD_UNUSED; // make sure mailbox 4 is empty inl(devpriv->s5933_config + AMCC_OP_REG_IMB4 ); /* Set bits to enable incoming mailbox interrupts on amcc s5933. */ devpriv->s5933_intcsr_bits = INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | INTCSR_INBOX_FULL_INT; // clear and enable interrupt on amcc s5933 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); return 1;}/* * cb_pcidas_detach is called to deconfigure a device. It should deallocate * resources. * This function is also called when _attach() fails, so it should be * careful not to release resources that were not necessarily * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */static int cb_pcidas_detach(comedi_device *dev){ printk("comedi%d: cb_pcidas: remove\n",dev->minor); if(devpriv) { if(devpriv->s5933_config) { // disable and clear interrupts on amcc s5933 outl(INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR);#ifdef CB_PCIDAS_DEBUG rt_printk("detaching, incsr is 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR));#endif release_region(devpriv->s5933_config, AMCC_OP_REG_SIZE); } if(devpriv->control_status) release_region(devpriv->control_status, CONT_STAT_SIZE); if(devpriv->adc_fifo) release_region(devpriv->adc_fifo, ADC_FIFO_SIZE); if(devpriv->pacer_counter_dio) release_region(devpriv->pacer_counter_dio, PACER_SIZE); if(devpriv->ao_registers) release_region(devpriv->ao_registers, AO_SIZE); } if(dev->irq) comedi_free_irq(dev->irq, dev); if(dev->subdevices) subdev_8255_cleanup(dev,dev->subdevices + 2); return 0;}/* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */static int cb_pcidas_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int n,i; unsigned int bits; static const int timeout = 10000; // enable calibration input if appropriate if( insn->chanspec & CR_ALT_SOURCE ) outw( CAL_EN_BIT | CAL_SRC_BITS( devpriv->calibration_source ), devpriv->control_status + CALIBRATION_REG); else outw( 0, devpriv->control_status + CALIBRATION_REG); // set mux limits and gain bits = BEGIN_SCAN(CR_CHAN(insn->chanspec)) | END_SCAN(CR_CHAN(insn->chanspec)) | GAIN_BITS(CR_RANGE(insn->chanspec)); // set unipolar/bipolar if(CR_RANGE(insn->chanspec) & IS_UNIPOLAR) bits |= UNIP; // set singleended/differential if(CR_AREF(insn->chanspec) != AREF_DIFF) bits |= SE; outw(bits, devpriv->control_status + ADCMUX_CONT); /* clear fifo */ outw(0, devpriv->adc_fifo + ADCFIFOCLR); /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ outw(0, devpriv->adc_fifo + ADCDATA); /* wait for conversion to end */ /* return -ETIMEDOUT if there is a timeout */ for(i = 0; i < timeout; i++) { if (inw(devpriv->control_status + ADCMUX_CONT) & EOC) break; } if(i == timeout) return -ETIMEDOUT; /* read data */ data[n] = inw(devpriv->adc_fifo + ADCDATA); } /* return the number of samples read/written */ return n;}static int ai_config_calibration_source( comedi_device *dev, lsampl_t *data ){ static const int num_calibration_sources = 8; lsampl_t source = data[1]; if(source >= num_calibration_sources) { printk( "invalid calibration source: %i\n", source ); return -EINVAL; } devpriv->calibration_source = source; return 2;}static int ai_config_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int id = data[0]; switch( id ) { case INSN_CONFIG_ALT_SOURCE: return ai_config_calibration_source( dev, data ); break; default: return -EINVAL; break; } return -EINVAL;}// analog output insn for pcidas-1000 and 1200 seriesstatic int cb_pcidas_ao_nofifo_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int channel; unsigned long flags; // set channel and range channel = CR_CHAN(insn->chanspec); comedi_spin_lock_irqsave( &dev->spinlock, flags ); devpriv->ao_control_bits &= ~DAC_MODE_UPDATE_BOTH & ~DAC_RANGE_MASK( channel ); devpriv->ao_control_bits |= DACEN | DAC_RANGE( channel, CR_RANGE( insn->chanspec ) ); outw( devpriv->ao_control_bits, devpriv->control_status + DAC_CSR ); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); // remember value for readback devpriv->ao_value[channel] = data[0]; // send data outw(data[0], devpriv->ao_registers + DAC_DATA_REG(channel)); return 1;}// analog output insn for pcidas-1602 seriesstatic int cb_pcidas_ao_fifo_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int bits, channel; // clear dac fifo outw(0, devpriv->ao_registers + DACFIFOCLR); // set channel and range channel = CR_CHAN(insn->chanspec); bits = DACEN; bits |= DAC_RANGE(channel, CR_RANGE(insn->chanspec)); bits |= DAC_CHAN_EN(channel); bits |= DAC_START; // not sure if this is necessary outw(bits, devpriv->control_status + DAC_CSR); // remember value for readback devpriv->ao_value[channel] = data[0]; // send data outw(data[0], devpriv->ao_registers + DACDATA); return 1;}// analog output readback insn// XXX loses track of analog output value back after an analog ouput command is executedstatic int cb_pcidas_ao_readback_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; return 1;}static int eeprom_read_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data ){ uint8_t nvram_data; int retval; retval = nvram_read( dev, CR_CHAN( insn->chanspec ), &nvram_data );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -