in drivers/ni_mio_common.c [5970:6333]
static int ni_E_init(struct comedi_device *dev,
unsigned int interrupt_pin, unsigned int irq_polarity)
{
const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
struct comedi_subdevice *s;
int ret;
int i;
const char *dev_family = devpriv->is_m_series ? "ni_mseries"
: "ni_eseries";
/* prepare the device for globally-named routes. */
if (ni_assign_device_routes(dev_family, board->name,
board->alt_route_name,
&devpriv->routing_tables) < 0) {
dev_warn(dev->class_dev, "%s: %s device has no signal routing table.\n",
__func__, board->name);
dev_warn(dev->class_dev, "%s: High level NI signal names will not be available for this %s board.\n",
__func__, board->name);
} else {
/*
* only(?) assign insn_device_config if we have global names for
* this device.
*/
dev->insn_device_config = ni_global_insn_config;
dev->get_valid_routes = _ni_get_valid_routes;
}
if (board->n_aochan > MAX_N_AO_CHAN) {
dev_err(dev->class_dev, "bug! n_aochan > MAX_N_AO_CHAN\n");
return -EINVAL;
}
/* initialize clock dividers */
devpriv->clock_and_fout = NISTC_CLK_FOUT_SLOW_DIV2 |
NISTC_CLK_FOUT_SLOW_TIMEBASE |
NISTC_CLK_FOUT_TO_BOARD_DIV2 |
NISTC_CLK_FOUT_TO_BOARD;
if (!devpriv->is_6xxx) {
/* BEAM is this needed for PCI-6143 ?? */
devpriv->clock_and_fout |= (NISTC_CLK_FOUT_AI_OUT_DIV2 |
NISTC_CLK_FOUT_AO_OUT_DIV2);
}
ni_stc_writew(dev, devpriv->clock_and_fout, NISTC_CLK_FOUT_REG);
ret = comedi_alloc_subdevices(dev, NI_NUM_SUBDEVICES);
if (ret)
return ret;
/* Analog Input subdevice */
s = &dev->subdevices[NI_AI_SUBDEV];
if (board->n_adchan) {
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_DITHER;
if (!devpriv->is_611x)
s->subdev_flags |= SDF_GROUND | SDF_COMMON | SDF_OTHER;
if (board->ai_maxdata > 0xffff)
s->subdev_flags |= SDF_LSAMPL;
if (devpriv->is_m_series)
s->subdev_flags |= SDF_SOFT_CALIBRATED;
s->n_chan = board->n_adchan;
s->maxdata = board->ai_maxdata;
s->range_table = ni_range_lkup[board->gainlkup];
s->insn_read = ni_ai_insn_read;
s->insn_config = ni_ai_insn_config;
if (dev->irq) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->len_chanlist = 512;
s->do_cmdtest = ni_ai_cmdtest;
s->do_cmd = ni_ai_cmd;
s->cancel = ni_ai_reset;
s->poll = ni_ai_poll;
s->munge = ni_ai_munge;
if (devpriv->mite)
s->async_dma_dir = DMA_FROM_DEVICE;
}
/* reset the analog input configuration */
ni_ai_reset(dev, s);
} else {
s->type = COMEDI_SUBD_UNUSED;
}
/* Analog Output subdevice */
s = &dev->subdevices[NI_AO_SUBDEV];
if (board->n_aochan) {
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_DEGLITCH | SDF_GROUND;
if (devpriv->is_m_series)
s->subdev_flags |= SDF_SOFT_CALIBRATED;
s->n_chan = board->n_aochan;
s->maxdata = board->ao_maxdata;
s->range_table = board->ao_range_table;
s->insn_config = ni_ao_insn_config;
s->insn_write = ni_ao_insn_write;
ret = comedi_alloc_subdev_readback(s);
if (ret)
return ret;
/*
* Along with the IRQ we need either a FIFO or DMA for
* async command support.
*/
if (dev->irq && (board->ao_fifo_depth || devpriv->mite)) {
dev->write_subdev = s;
s->subdev_flags |= SDF_CMD_WRITE;
s->len_chanlist = s->n_chan;
s->do_cmdtest = ni_ao_cmdtest;
s->do_cmd = ni_ao_cmd;
s->cancel = ni_ao_reset;
if (!devpriv->is_m_series)
s->munge = ni_ao_munge;
if (devpriv->mite)
s->async_dma_dir = DMA_TO_DEVICE;
}
if (devpriv->is_67xx)
init_ao_67xx(dev, s);
/* reset the analog output configuration */
ni_ao_reset(dev, s);
} else {
s->type = COMEDI_SUBD_UNUSED;
}
/* Digital I/O subdevice */
s = &dev->subdevices[NI_DIO_SUBDEV];
s->type = COMEDI_SUBD_DIO;
s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
s->n_chan = board->has_32dio_chan ? 32 : 8;
s->maxdata = 1;
s->range_table = &range_digital;
if (devpriv->is_m_series) {
#ifdef PCIDMA
s->subdev_flags |= SDF_LSAMPL;
s->insn_bits = ni_m_series_dio_insn_bits;
s->insn_config = ni_m_series_dio_insn_config;
if (dev->irq) {
s->subdev_flags |= SDF_CMD_WRITE /* | SDF_CMD_READ */;
s->len_chanlist = s->n_chan;
s->do_cmdtest = ni_cdio_cmdtest;
s->do_cmd = ni_cdio_cmd;
s->cancel = ni_cdio_cancel;
/* M-series boards use DMA */
s->async_dma_dir = DMA_BIDIRECTIONAL;
}
/* reset DIO and set all channels to inputs */
ni_writel(dev, NI_M_CDO_CMD_RESET |
NI_M_CDI_CMD_RESET,
NI_M_CDIO_CMD_REG);
ni_writel(dev, s->io_bits, NI_M_DIO_DIR_REG);
#endif /* PCIDMA */
} else {
s->insn_bits = ni_dio_insn_bits;
s->insn_config = ni_dio_insn_config;
/* set all channels to inputs */
devpriv->dio_control = NISTC_DIO_CTRL_DIR(s->io_bits);
ni_writew(dev, devpriv->dio_control, NISTC_DIO_CTRL_REG);
}
/* 8255 device */
s = &dev->subdevices[NI_8255_DIO_SUBDEV];
if (board->has_8255) {
ret = subdev_8255_init(dev, s, ni_8255_callback,
NI_E_8255_BASE);
if (ret)
return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
/* formerly general purpose counter/timer device, but no longer used */
s = &dev->subdevices[NI_UNUSED_SUBDEV];
s->type = COMEDI_SUBD_UNUSED;
/* Calibration subdevice */
s = &dev->subdevices[NI_CALIBRATION_SUBDEV];
s->type = COMEDI_SUBD_CALIB;
s->subdev_flags = SDF_INTERNAL;
s->n_chan = 1;
s->maxdata = 0;
if (devpriv->is_m_series) {
/* internal PWM output used for AI nonlinearity calibration */
s->insn_config = ni_m_series_pwm_config;
ni_writel(dev, 0x0, NI_M_CAL_PWM_REG);
} else if (devpriv->is_6143) {
/* internal PWM output used for AI nonlinearity calibration */
s->insn_config = ni_6143_pwm_config;
} else {
s->subdev_flags |= SDF_WRITABLE;
s->insn_read = ni_calib_insn_read;
s->insn_write = ni_calib_insn_write;
/* setup the caldacs and find the real n_chan and maxdata */
caldac_setup(dev, s);
}
/* EEPROM subdevice */
s = &dev->subdevices[NI_EEPROM_SUBDEV];
s->type = COMEDI_SUBD_MEMORY;
s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
s->maxdata = 0xff;
if (devpriv->is_m_series) {
s->n_chan = M_SERIES_EEPROM_SIZE;
s->insn_read = ni_m_series_eeprom_insn_read;
} else {
s->n_chan = 512;
s->insn_read = ni_eeprom_insn_read;
}
/* Digital I/O (PFI) subdevice */
s = &dev->subdevices[NI_PFI_DIO_SUBDEV];
s->type = COMEDI_SUBD_DIO;
s->maxdata = 1;
if (devpriv->is_m_series) {
s->n_chan = 16;
s->insn_bits = ni_pfi_insn_bits;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
ni_writew(dev, s->state, NI_M_PFI_DO_REG);
for (i = 0; i < NUM_PFI_OUTPUT_SELECT_REGS; ++i) {
ni_writew(dev, devpriv->pfi_output_select_reg[i],
NI_M_PFI_OUT_SEL_REG(i));
}
} else {
s->n_chan = 10;
s->subdev_flags = SDF_INTERNAL;
}
s->insn_config = ni_pfi_insn_config;
ni_set_bits(dev, NISTC_IO_BIDIR_PIN_REG, ~0, 0);
/* cs5529 calibration adc */
s = &dev->subdevices[NI_CS5529_CALIBRATION_SUBDEV];
if (devpriv->is_67xx) {
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL;
/* one channel for each analog output channel */
s->n_chan = board->n_aochan;
s->maxdata = BIT(16) - 1;
s->range_table = &range_unknown; /* XXX */
s->insn_read = cs5529_ai_insn_read;
s->insn_config = NULL;
init_cs5529(dev);
} else {
s->type = COMEDI_SUBD_UNUSED;
}
/* Serial */
s = &dev->subdevices[NI_SERIAL_SUBDEV];
s->type = COMEDI_SUBD_SERIAL;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
s->n_chan = 1;
s->maxdata = 0xff;
s->insn_config = ni_serial_insn_config;
devpriv->serial_interval_ns = 0;
devpriv->serial_hw_mode = 0;
/* RTSI */
s = &dev->subdevices[NI_RTSI_SUBDEV];
s->type = COMEDI_SUBD_DIO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
s->n_chan = 8;
s->maxdata = 1;
s->insn_bits = ni_rtsi_insn_bits;
s->insn_config = ni_rtsi_insn_config;
ni_rtsi_init(dev);
/* allocate and initialize the gpct counter device */
devpriv->counter_dev = ni_gpct_device_construct(dev,
ni_gpct_write_register,
ni_gpct_read_register,
(devpriv->is_m_series)
? ni_gpct_variant_m_series
: ni_gpct_variant_e_series,
NUM_GPCT,
NUM_GPCT,
&devpriv->routing_tables);
if (!devpriv->counter_dev)
return -ENOMEM;
/* Counter (gpct) subdevices */
for (i = 0; i < NUM_GPCT; ++i) {
struct ni_gpct *gpct = &devpriv->counter_dev->counters[i];
/* setup and initialize the counter */
ni_tio_init_counter(gpct);
s = &dev->subdevices[NI_GPCT_SUBDEV(i)];
s->type = COMEDI_SUBD_COUNTER;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
s->n_chan = 3;
s->maxdata = (devpriv->is_m_series) ? 0xffffffff
: 0x00ffffff;
s->insn_read = ni_tio_insn_read;
s->insn_write = ni_tio_insn_write;
s->insn_config = ni_tio_insn_config;
#ifdef PCIDMA
if (dev->irq && devpriv->mite) {
s->subdev_flags |= SDF_CMD_READ /* | SDF_CMD_WRITE */;
s->len_chanlist = 1;
s->do_cmdtest = ni_tio_cmdtest;
s->do_cmd = ni_gpct_cmd;
s->cancel = ni_gpct_cancel;
s->async_dma_dir = DMA_BIDIRECTIONAL;
}
#endif
s->private = gpct;
}
/* Initialize GPFO_{0,1} to produce output of counters */
ni_set_gout_routing(0, 0, dev); /* output of counter 0; DAQ STC, p338 */
ni_set_gout_routing(0, 1, dev); /* output of counter 1; DAQ STC, p338 */
/* Frequency output subdevice */
s = &dev->subdevices[NI_FREQ_OUT_SUBDEV];
s->type = COMEDI_SUBD_COUNTER;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
s->n_chan = 1;
s->maxdata = 0xf;
s->insn_read = ni_freq_out_insn_read;
s->insn_write = ni_freq_out_insn_write;
s->insn_config = ni_freq_out_insn_config;
if (dev->irq) {
ni_stc_writew(dev,
(irq_polarity ? NISTC_INT_CTRL_INT_POL : 0) |
(NISTC_INT_CTRL_3PIN_INT & 0) |
NISTC_INT_CTRL_INTA_ENA |
NISTC_INT_CTRL_INTB_ENA |
NISTC_INT_CTRL_INTA_SEL(interrupt_pin) |
NISTC_INT_CTRL_INTB_SEL(interrupt_pin),
NISTC_INT_CTRL_REG);
}
/* DMA setup */
ni_writeb(dev, devpriv->ai_ao_select_reg, NI_E_DMA_AI_AO_SEL_REG);
ni_writeb(dev, devpriv->g0_g1_select_reg, NI_E_DMA_G0_G1_SEL_REG);
if (devpriv->is_6xxx) {
ni_writeb(dev, 0, NI611X_MAGIC_REG);
} else if (devpriv->is_m_series) {
int channel;
for (channel = 0; channel < board->n_aochan; ++channel) {
ni_writeb(dev, 0xf,
NI_M_AO_WAVEFORM_ORDER_REG(channel));
ni_writeb(dev, 0x0,
NI_M_AO_REF_ATTENUATION_REG(channel));
}
ni_writeb(dev, 0x0, NI_M_AO_CALIB_REG);
}
return 0;
}