MODE_MULT_CHAN_DOWN,
};
-static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static irqreturn_t labpc_interrupt(int irq, void *d);
-static int labpc_drain_fifo(struct comedi_device *dev);
-#ifdef CONFIG_ISA_DMA_API
-static void labpc_drain_dma(struct comedi_device *dev);
-static void handle_isa_dma(struct comedi_device *dev);
-#endif
-static void labpc_drain_dregs(struct comedi_device *dev);
-static int labpc_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_calib_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_calib_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_eeprom_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_eeprom_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
- enum scan_mode scan_mode);
-#ifdef CONFIG_ISA_DMA_API
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd);
-#endif
-static int labpc_dio_mem_callback(int dir, int port, int data,
- unsigned long arg);
-static void labpc_serial_out(struct comedi_device *dev, unsigned int value,
- unsigned int num_bits);
-static unsigned int labpc_serial_in(struct comedi_device *dev);
-static unsigned int labpc_eeprom_read(struct comedi_device *dev,
- unsigned int address);
-static unsigned int labpc_eeprom_read_status(struct comedi_device *dev);
-static int labpc_eeprom_write(struct comedi_device *dev,
- unsigned int address,
- unsigned int value);
-static void write_caldac(struct comedi_device *dev, unsigned int channel,
- unsigned int value);
-
/* analog input ranges */
#define NUM_LABPC_PLUS_AI_RANGES 16
/* indicates unipolar ranges */
writeb(byte, (void __iomem *)address);
}
-static const struct labpc_board_struct labpc_boards[] = {
- {
- .name = "lab-pc-1200",
- .ai_speed = 10000,
- .bustype = isa_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 0,
- },
+static const struct labpc_boardinfo labpc_boards[] = {
{
- .name = "lab-pc-1200ai",
- .ai_speed = 10000,
- .bustype = isa_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 0,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 0,
- },
- {
- .name = "lab-pc+",
- .ai_speed = 12000,
- .bustype = isa_bustype,
- .register_layout = labpc_plus_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_plus_ai,
- .ai_range_code = labpc_plus_ai_gain_bits,
- .ai_range_is_unipolar = labpc_plus_is_unipolar,
- .ai_scan_up = 0,
- .memory_mapped_io = 0,
- },
+ .name = "lab-pc-1200",
+ .ai_speed = 10000,
+ .bustype = isa_bustype,
+ .register_layout = labpc_1200_layout,
+ .has_ao = 1,
+ .ai_range_table = &range_labpc_1200_ai,
+ .ai_range_code = labpc_1200_ai_gain_bits,
+ .ai_range_is_unipolar = labpc_1200_is_unipolar,
+ .ai_scan_up = 1,
+ }, {
+ .name = "lab-pc-1200ai",
+ .ai_speed = 10000,
+ .bustype = isa_bustype,
+ .register_layout = labpc_1200_layout,
+ .ai_range_table = &range_labpc_1200_ai,
+ .ai_range_code = labpc_1200_ai_gain_bits,
+ .ai_range_is_unipolar = labpc_1200_is_unipolar,
+ .ai_scan_up = 1,
+ }, {
+ .name = "lab-pc+",
+ .ai_speed = 12000,
+ .bustype = isa_bustype,
+ .register_layout = labpc_plus_layout,
+ .has_ao = 1,
+ .ai_range_table = &range_labpc_plus_ai,
+ .ai_range_code = labpc_plus_ai_gain_bits,
+ .ai_range_is_unipolar = labpc_plus_is_unipolar,
+ },
#ifdef CONFIG_COMEDI_PCI_DRIVERS
{
- .name = "pci-1200",
- .device_id = 0x161,
- .ai_speed = 10000,
- .bustype = pci_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 1,
- },
-/* dummy entry so pci board works when comedi_config is passed driver name */
- {
- .name = DRV_NAME,
- .bustype = pci_bustype,
- },
+ .name = "pci-1200",
+ .device_id = 0x161,
+ .ai_speed = 10000,
+ .bustype = pci_bustype,
+ .register_layout = labpc_1200_layout,
+ .has_ao = 1,
+ .ai_range_table = &range_labpc_1200_ai,
+ .ai_range_code = labpc_1200_ai_gain_bits,
+ .ai_range_is_unipolar = labpc_1200_is_unipolar,
+ .ai_scan_up = 1,
+ .memory_mapped_io = 1,
+ },
#endif
};
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((struct labpc_board_struct *)dev->board_ptr)
-
/* size in bytes of dma buffer */
static const int dma_buffer_size = 0xff00;
/* 2 bytes per sample */
static const int sample_size = 2;
-static inline int labpc_counter_load(struct comedi_device *dev,
- unsigned long base_address,
- unsigned int counter_number,
- unsigned int count, unsigned int mode)
+static void labpc_clear_adc_fifo(const struct comedi_device *dev)
{
- if (thisboard->memory_mapped_io)
- return i8254_mm_load((void __iomem *)base_address, 0,
- counter_number, count, mode);
- else
- return i8254_load(base_address, 0, counter_number, count, mode);
+ struct labpc_private *devpriv = dev->private;
+
+ devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
+ devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+ devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
}
-int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
- unsigned int irq, unsigned int dma_chan)
+static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
{
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- int i;
- unsigned long isr_flags;
-#ifdef CONFIG_ISA_DMA_API
- unsigned long dma_flags;
-#endif
- short lsb, msb;
- int ret;
-
- dev_info(dev->class_dev, "ni_labpc: %s\n", thisboard->name);
- if (iobase == 0) {
- dev_err(dev->class_dev, "io base address is zero!\n");
- return -EINVAL;
- }
- /* request io regions for isa boards */
- if (thisboard->bustype == isa_bustype) {
- /* check if io addresses are available */
- if (!request_region(iobase, LABPC_SIZE, DRV_NAME)) {
- dev_err(dev->class_dev, "I/O port conflict\n");
- return -EIO;
- }
- }
- dev->iobase = iobase;
+ int i, n;
+ int chan, range;
+ int lsb, msb;
+ int timeout = 1000;
+ unsigned long flags;
- if (thisboard->memory_mapped_io) {
- devpriv->read_byte = labpc_readb;
- devpriv->write_byte = labpc_writeb;
- } else {
- devpriv->read_byte = labpc_inb;
- devpriv->write_byte = labpc_outb;
- }
- /* initialize board's command registers */
- devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
+ /* disable timed conversions */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ /* disable interrupt generation and dma */
+ devpriv->command3_bits = 0;
devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
- devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
+
+ /* set gain and channel */
+ devpriv->command1_bits = 0;
+ chan = CR_CHAN(insn->chanspec);
+ range = CR_RANGE(insn->chanspec);
+ devpriv->command1_bits |= thisboard->ai_range_code[range];
+ /* munge channel bits for differential/scan disabled mode */
+ if (CR_AREF(insn->chanspec) == AREF_DIFF)
+ chan *= 2;
+ devpriv->command1_bits |= ADC_CHAN_BITS(chan);
+ devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
+
+ /* setup command6 register for 1200 boards */
if (thisboard->register_layout == labpc_1200_layout) {
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ /* reference inputs to ground or common? */
+ if (CR_AREF(insn->chanspec) != AREF_GROUND)
+ devpriv->command6_bits |= ADC_COMMON_BIT;
+ else
+ devpriv->command6_bits &= ~ADC_COMMON_BIT;
+ /* bipolar or unipolar range? */
+ if (thisboard->ai_range_is_unipolar[range])
+ devpriv->command6_bits |= ADC_UNIP_BIT;
+ else
+ devpriv->command6_bits &= ~ADC_UNIP_BIT;
+ /* don't interrupt on fifo half full */
+ devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
+ /* don't enable interrupt on counter a1 terminal count? */
+ devpriv->command6_bits &= ~A1_INTR_EN_BIT;
+ /* write to register */
devpriv->write_byte(devpriv->command6_bits,
dev->iobase + COMMAND6_REG);
}
+ /* setup command4 register */
+ devpriv->command4_bits = 0;
+ devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
+ /* single-ended/differential */
+ if (CR_AREF(insn->chanspec) == AREF_DIFF)
+ devpriv->command4_bits |= ADC_DIFF_BIT;
+ devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
- /* grab our IRQ */
- if (irq) {
- isr_flags = 0;
- if (thisboard->bustype == pci_bustype
- || thisboard->bustype == pcmcia_bustype)
- isr_flags |= IRQF_SHARED;
- if (request_irq(irq, labpc_interrupt, isr_flags,
- DRV_NAME, dev)) {
- dev_err(dev->class_dev, "unable to allocate irq %u\n",
- irq);
- return -EINVAL;
+ /*
+ * initialize pacer counter output to make sure it doesn't
+ * cause any problems
+ */
+ devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG);
+
+ labpc_clear_adc_fifo(dev);
+
+ for (n = 0; n < insn->n; n++) {
+ /* trigger conversion */
+ devpriv->write_byte(0x1, dev->iobase + ADC_CONVERT_REG);
+
+ for (i = 0; i < timeout; i++) {
+ if (devpriv->read_byte(dev->iobase +
+ STATUS1_REG) & DATA_AVAIL_BIT)
+ break;
+ udelay(1);
+ }
+ if (i == timeout) {
+ comedi_error(dev, "timeout");
+ return -ETIME;
}
+ lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+ msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+ data[n] = (msb << 8) | lsb;
}
- dev->irq = irq;
+
+ return n;
+}
#ifdef CONFIG_ISA_DMA_API
- /* grab dma channel */
- if (dma_chan > 3) {
- dev_err(dev->class_dev, "invalid dma channel %u\n", dma_chan);
- return -EINVAL;
- } else if (dma_chan) {
- /* allocate dma buffer */
- devpriv->dma_buffer = kmalloc(dma_buffer_size,
- GFP_KERNEL | GFP_DMA);
- if (devpriv->dma_buffer == NULL)
- return -ENOMEM;
+/* utility function that suggests a dma transfer size in bytes */
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
+{
+ unsigned int size;
+ unsigned int freq;
- if (request_dma(dma_chan, DRV_NAME)) {
- dev_err(dev->class_dev,
- "failed to allocate dma channel %u\n",
- dma_chan);
- return -EINVAL;
- }
- devpriv->dma_chan = dma_chan;
- dma_flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
- release_dma_lock(dma_flags);
- }
+ if (cmd->convert_src == TRIG_TIMER)
+ freq = 1000000000 / cmd->convert_arg;
+ /* return some default value */
+ else
+ freq = 0xffffffff;
+
+ /* make buffer fill in no more than 1/3 second */
+ size = (freq / 3) * sample_size;
+
+ /* set a minimum and maximum size allowed */
+ if (size > dma_buffer_size)
+ size = dma_buffer_size - dma_buffer_size % sample_size;
+ else if (size < sample_size)
+ size = sample_size;
+
+ return size;
+}
#endif
- dev->board_name = thisboard->name;
+static int labpc_use_continuous_mode(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
+{
+ if (mode == MODE_SINGLE_CHAN)
+ return 1;
- ret = comedi_alloc_subdevices(dev, 5);
- if (ret)
- return ret;
+ if (cmd->scan_begin_src == TRIG_FOLLOW)
+ return 1;
- /* analog input subdevice */
- s = &dev->subdevices[0];
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags =
- SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
- s->n_chan = 8;
- s->len_chanlist = 8;
- s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
- s->range_table = thisboard->ai_range_table;
- s->do_cmd = labpc_ai_cmd;
- s->do_cmdtest = labpc_ai_cmdtest;
- s->insn_read = labpc_ai_rinsn;
- s->cancel = labpc_cancel;
+ return 0;
+}
- /* analog output */
- s = &dev->subdevices[1];
- if (thisboard->has_ao) {
- /*
- * Could provide command support, except it only has a
- * one sample hardware buffer for analog output and no
- * underrun flag.
- */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
- s->n_chan = NUM_AO_CHAN;
- s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
- s->range_table = &range_labpc_ao;
- s->insn_read = labpc_ao_rinsn;
- s->insn_write = labpc_ao_winsn;
- /* initialize analog outputs to a known value */
- for (i = 0; i < s->n_chan; i++) {
- devpriv->ao_value[i] = s->maxdata / 2;
- lsb = devpriv->ao_value[i] & 0xff;
- msb = (devpriv->ao_value[i] >> 8) & 0xff;
- devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i));
- devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i));
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- /* 8255 dio */
- s = &dev->subdevices[2];
- /* if board uses io memory we have to give a custom callback
- * function to the 8255 driver */
- if (thisboard->memory_mapped_io)
- subdev_8255_init(dev, s, labpc_dio_mem_callback,
- (unsigned long)(dev->iobase + DIO_BASE_REG));
- else
- subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG);
-
- /* calibration subdevices for boards that have one */
- s = &dev->subdevices[3];
- if (thisboard->register_layout == labpc_1200_layout) {
- s->type = COMEDI_SUBD_CALIB;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = 16;
- s->maxdata = 0xff;
- s->insn_read = labpc_calib_read_insn;
- s->insn_write = labpc_calib_write_insn;
-
- for (i = 0; i < s->n_chan; i++)
- write_caldac(dev, i, s->maxdata / 2);
- } else
- s->type = COMEDI_SUBD_UNUSED;
-
- /* EEPROM */
- s = &dev->subdevices[4];
- if (thisboard->register_layout == labpc_1200_layout) {
- s->type = COMEDI_SUBD_MEMORY;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = EEPROM_SIZE;
- s->maxdata = 0xff;
- s->insn_read = labpc_eeprom_read_insn;
- s->insn_write = labpc_eeprom_write_insn;
-
- for (i = 0; i < EEPROM_SIZE; i++)
- devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
- } else
- s->type = COMEDI_SUBD_UNUSED;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(labpc_common_attach);
-
-static const struct labpc_board_struct *
-labpc_pci_find_boardinfo(struct pci_dev *pcidev)
+static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
- unsigned int device_id = pcidev->device;
- unsigned int n;
+ if (cmd->convert_src != TRIG_TIMER)
+ return 0;
- for (n = 0; n < ARRAY_SIZE(labpc_boards); n++) {
- const struct labpc_board_struct *board = &labpc_boards[n];
- if (board->bustype == pci_bustype &&
- board->device_id == device_id)
- return board;
- }
- return NULL;
+ if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
+ return cmd->scan_begin_arg;
+
+ return cmd->convert_arg;
}
-static int labpc_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct labpc_private *devpriv;
- unsigned long iobase;
- unsigned int irq;
- int ret;
-
- if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS))
- return -ENODEV;
-
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
+ if (cmd->convert_src != TRIG_TIMER)
+ return;
- dev->board_ptr = labpc_pci_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
- devpriv->mite = mite_alloc(pcidev);
- if (!devpriv->mite)
- return -ENOMEM;
- ret = mite_setup(devpriv->mite);
- if (ret < 0)
- return ret;
- iobase = (unsigned long)devpriv->mite->daq_io_addr;
- irq = mite_irq(devpriv->mite);
- return labpc_common_attach(dev, iobase, irq, 0);
+ if (mode == MODE_SINGLE_CHAN &&
+ cmd->scan_begin_src == TRIG_TIMER) {
+ cmd->scan_begin_arg = ns;
+ if (cmd->convert_arg > cmd->scan_begin_arg)
+ cmd->convert_arg = cmd->scan_begin_arg;
+ } else
+ cmd->convert_arg = ns;
}
-static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
- struct labpc_private *devpriv;
- unsigned long iobase = 0;
- unsigned int irq = 0;
- unsigned int dma_chan = 0;
-
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
+ if (cmd->scan_begin_src != TRIG_TIMER)
+ return 0;
- /* get base address, irq etc. based on bustype */
- switch (thisboard->bustype) {
- case isa_bustype:
-#ifdef CONFIG_ISA_DMA_API
- iobase = it->options[0];
- irq = it->options[1];
- dma_chan = it->options[2];
-#else
- dev_err(dev->class_dev,
- "ni_labpc driver has not been built with ISA DMA support.\n");
- return -EINVAL;
-#endif
- break;
- case pci_bustype:
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
- dev_err(dev->class_dev,
- "manual configuration of PCI board '%s' is not supported\n",
- thisboard->name);
- return -EINVAL;
-#else
- dev_err(dev->class_dev,
- "ni_labpc driver has not been built with PCI support.\n");
- return -EINVAL;
-#endif
- break;
- default:
- dev_err(dev->class_dev,
- "ni_labpc: bug! couldn't determine board type\n");
- return -EINVAL;
- break;
- }
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
+ return 0;
- return labpc_common_attach(dev, iobase, irq, dma_chan);
+ return cmd->scan_begin_arg;
}
-void labpc_common_detach(struct comedi_device *dev)
+static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
{
- struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s;
-
- if (!thisboard)
+ if (cmd->scan_begin_src != TRIG_TIMER)
return;
- if (dev->subdevices) {
- s = &dev->subdevices[2];
- subdev_8255_cleanup(dev, s);
- }
-#ifdef CONFIG_ISA_DMA_API
- /* only free stuff if it has been allocated by _attach */
- kfree(devpriv->dma_buffer);
- if (devpriv->dma_chan)
- free_dma(devpriv->dma_chan);
-#endif
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (thisboard->bustype == isa_bustype && dev->iobase)
- release_region(dev->iobase, LABPC_SIZE);
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
- if (devpriv->mite) {
- mite_unsetup(devpriv->mite);
- mite_free(devpriv->mite);
- }
-#endif
-};
-EXPORT_SYMBOL_GPL(labpc_common_detach);
-static void labpc_clear_adc_fifo(const struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
+ return;
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+ cmd->scan_begin_arg = ns;
}
-static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
+/* figures out what counter values to use based on command */
+static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
struct labpc_private *devpriv = dev->private;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- devpriv->command3_bits = 0;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
-
- return 0;
-}
-
-static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
-{
- if (cmd->chanlist_len == 1)
- return MODE_SINGLE_CHAN;
-
- /* chanlist may be NULL during cmdtest. */
- if (cmd->chanlist == NULL)
- return MODE_MULT_CHAN_UP;
-
- if (CR_CHAN(cmd->chanlist[0]) == CR_CHAN(cmd->chanlist[1]))
- return MODE_SINGLE_CHAN_INTERVAL;
+ /* max value for 16 bit counter in mode 2 */
+ const int max_counter_value = 0x10000;
+ /* min value for 16 bit counter in mode 2 */
+ const int min_counter_value = 2;
+ unsigned int base_period;
+ unsigned int scan_period;
+ unsigned int convert_period;
- if (CR_CHAN(cmd->chanlist[0]) < CR_CHAN(cmd->chanlist[1]))
- return MODE_MULT_CHAN_UP;
+ /*
+ * if both convert and scan triggers are TRIG_TIMER, then they
+ * both rely on counter b0
+ */
+ convert_period = labpc_ai_convert_period(cmd, mode);
+ scan_period = labpc_ai_scan_period(cmd, mode);
+ if (convert_period && scan_period) {
+ /*
+ * pick the lowest b0 divisor value we can (for maximum input
+ * clock speed on convert and scan counters)
+ */
+ devpriv->divisor_b0 = (scan_period - 1) /
+ (LABPC_TIMER_BASE * max_counter_value) + 1;
+ if (devpriv->divisor_b0 < min_counter_value)
+ devpriv->divisor_b0 = min_counter_value;
+ if (devpriv->divisor_b0 > max_counter_value)
+ devpriv->divisor_b0 = max_counter_value;
- if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1]))
- return MODE_MULT_CHAN_DOWN;
+ base_period = LABPC_TIMER_BASE * devpriv->divisor_b0;
- pr_err("ni_labpc: bug! cannot determine AI scan mode\n");
- return 0;
+ /* set a0 for conversion frequency and b1 for scan frequency */
+ switch (cmd->flags & TRIG_ROUND_MASK) {
+ default:
+ case TRIG_ROUND_NEAREST:
+ devpriv->divisor_a0 =
+ (convert_period + (base_period / 2)) / base_period;
+ devpriv->divisor_b1 =
+ (scan_period + (base_period / 2)) / base_period;
+ break;
+ case TRIG_ROUND_UP:
+ devpriv->divisor_a0 =
+ (convert_period + (base_period - 1)) / base_period;
+ devpriv->divisor_b1 =
+ (scan_period + (base_period - 1)) / base_period;
+ break;
+ case TRIG_ROUND_DOWN:
+ devpriv->divisor_a0 = convert_period / base_period;
+ devpriv->divisor_b1 = scan_period / base_period;
+ break;
+ }
+ /* make sure a0 and b1 values are acceptable */
+ if (devpriv->divisor_a0 < min_counter_value)
+ devpriv->divisor_a0 = min_counter_value;
+ if (devpriv->divisor_a0 > max_counter_value)
+ devpriv->divisor_a0 = max_counter_value;
+ if (devpriv->divisor_b1 < min_counter_value)
+ devpriv->divisor_b1 = min_counter_value;
+ if (devpriv->divisor_b1 > max_counter_value)
+ devpriv->divisor_b1 = max_counter_value;
+ /* write corrected timings to command */
+ labpc_set_ai_convert_period(cmd, mode,
+ base_period * devpriv->divisor_a0);
+ labpc_set_ai_scan_period(cmd, mode,
+ base_period * devpriv->divisor_b1);
+ /*
+ * if only one TRIG_TIMER is used, we can employ the generic
+ * cascaded timing functions
+ */
+ } else if (scan_period) {
+ /*
+ * calculate cascaded counter values
+ * that give desired scan timing
+ */
+ i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
+ &(devpriv->divisor_b1),
+ &(devpriv->divisor_b0),
+ &scan_period,
+ cmd->flags & TRIG_ROUND_MASK);
+ labpc_set_ai_scan_period(cmd, mode, scan_period);
+ } else if (convert_period) {
+ /*
+ * calculate cascaded counter values
+ * that give desired conversion timing
+ */
+ i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
+ &(devpriv->divisor_a0),
+ &(devpriv->divisor_b0),
+ &convert_period,
+ cmd->flags & TRIG_ROUND_MASK);
+ labpc_set_ai_convert_period(cmd, mode, convert_period);
+ }
+}
+
+static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
+{
+ if (cmd->chanlist_len == 1)
+ return MODE_SINGLE_CHAN;
+
+ /* chanlist may be NULL during cmdtest. */
+ if (cmd->chanlist == NULL)
+ return MODE_MULT_CHAN_UP;
+
+ if (CR_CHAN(cmd->chanlist[0]) == CR_CHAN(cmd->chanlist[1]))
+ return MODE_SINGLE_CHAN_INTERVAL;
+
+ if (CR_CHAN(cmd->chanlist[0]) < CR_CHAN(cmd->chanlist[1]))
+ return MODE_MULT_CHAN_UP;
+
+ if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1]))
+ return MODE_MULT_CHAN_DOWN;
+
+ pr_err("ni_labpc: bug! cannot determine AI scan mode\n");
+ return 0;
}
static int labpc_ai_chanlist_invalid(const struct comedi_device *dev,
return 0;
}
-static int labpc_use_continuous_mode(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (mode == MODE_SINGLE_CHAN)
- return 1;
-
- if (cmd->scan_begin_src == TRIG_FOLLOW)
- return 1;
-
- return 0;
-}
-
-static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (cmd->convert_src != TRIG_TIMER)
- return 0;
-
- if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
- return cmd->scan_begin_arg;
-
- return cmd->convert_arg;
-}
-
-static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
- enum scan_mode mode, unsigned int ns)
-{
- if (cmd->convert_src != TRIG_TIMER)
- return;
-
- if (mode == MODE_SINGLE_CHAN &&
- cmd->scan_begin_src == TRIG_TIMER) {
- cmd->scan_begin_arg = ns;
- if (cmd->convert_arg > cmd->scan_begin_arg)
- cmd->convert_arg = cmd->scan_begin_arg;
- } else
- cmd->convert_arg = ns;
-}
-
-static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (cmd->scan_begin_src != TRIG_TIMER)
- return 0;
-
- if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
- return 0;
-
- return cmd->scan_begin_arg;
-}
-
-static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
- enum scan_mode mode, unsigned int ns)
-{
- if (cmd->scan_begin_src != TRIG_TIMER)
- return;
-
- if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
- return;
-
- cmd->scan_begin_arg = ns;
-}
-
static int labpc_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
int err = 0;
int tmp, tmp2;
unsigned int stop_mask;
return 0;
}
+static inline int labpc_counter_load(struct comedi_device *dev,
+ unsigned long base_address,
+ unsigned int counter_number,
+ unsigned int count, unsigned int mode)
+{
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
+
+ if (thisboard->memory_mapped_io)
+ return i8254_mm_load((void __iomem *)base_address, 0,
+ counter_number, count, mode);
+ else
+ return i8254_load(base_address, 0, counter_number, count, mode);
+}
+
static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
int channel, range, aref;
#ifdef CONFIG_ISA_DMA_API
return 0;
}
-/* interrupt service routine */
-static irqreturn_t labpc_interrupt(int irq, void *d)
+static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async;
- struct comedi_cmd *cmd;
+ unsigned long flags;
- if (dev->attached == 0) {
- comedi_error(dev, "premature interrupt");
- return IRQ_HANDLED;
- }
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
+ devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
- async = s->async;
- cmd = &async->cmd;
- async->events = 0;
+ devpriv->command3_bits = 0;
+ devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
- /* read board status */
- devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
- if (thisboard->register_layout == labpc_1200_layout)
- devpriv->status2_bits =
- devpriv->read_byte(dev->iobase + STATUS2_REG);
+ return 0;
+}
- if ((devpriv->status1_bits & (DMATC_BIT | TIMER_BIT | OVERFLOW_BIT |
- OVERRUN_BIT | DATA_AVAIL_BIT)) == 0
- && (devpriv->status2_bits & A1_TC_BIT) == 0
- && (devpriv->status2_bits & FNHF_BIT)) {
- return IRQ_NONE;
- }
+#ifdef CONFIG_ISA_DMA_API
+static void labpc_drain_dma(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s->async;
+ int status;
+ unsigned long flags;
+ unsigned int max_points, num_points, residue, leftover;
+ int i;
- if (devpriv->status1_bits & OVERRUN_BIT) {
- /* clear error interrupt */
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- comedi_error(dev, "overrun");
- return IRQ_HANDLED;
- }
+ status = devpriv->status1_bits;
-#ifdef CONFIG_ISA_DMA_API
- if (devpriv->current_transfer == isa_dma_transfer) {
- /*
- * if a dma terminal count of external stop trigger
- * has occurred
- */
- if (devpriv->status1_bits & DMATC_BIT ||
- (thisboard->register_layout == labpc_1200_layout
- && devpriv->status2_bits & A1_TC_BIT)) {
- handle_isa_dma(dev);
- }
- } else
-#endif
- labpc_drain_fifo(dev);
+ 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);
- if (devpriv->status1_bits & TIMER_BIT) {
- comedi_error(dev, "handled timer interrupt?");
- /* clear it */
- devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG);
+ /* figure out how many points to read */
+ max_points = devpriv->dma_transfer_size / sample_size;
+ /* residue is the number of points left to be done on the dma
+ * transfer. It should always be zero at this point unless
+ * the stop_src is set to external triggering.
+ */
+ residue = get_dma_residue(devpriv->dma_chan) / sample_size;
+ num_points = max_points - residue;
+ if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT)
+ num_points = devpriv->count;
+
+ /* figure out how many points will be stored next time */
+ leftover = 0;
+ if (async->cmd.stop_src != TRIG_COUNT) {
+ leftover = devpriv->dma_transfer_size / sample_size;
+ } else if (devpriv->count > num_points) {
+ leftover = devpriv->count - num_points;
+ if (leftover > max_points)
+ leftover = max_points;
}
- if (devpriv->status1_bits & OVERFLOW_BIT) {
- /* clear error interrupt */
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- comedi_error(dev, "overflow");
- return IRQ_HANDLED;
- }
- /* handle external stop trigger */
- if (cmd->stop_src == TRIG_EXT) {
- if (devpriv->status2_bits & A1_TC_BIT) {
- labpc_drain_dregs(dev);
- labpc_cancel(dev, s);
- async->events |= COMEDI_CB_EOA;
- }
- }
+ /* write data to comedi buffer */
+ for (i = 0; i < num_points; i++)
+ cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
- /* TRIG_COUNT end of acquisition */
- if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->count == 0) {
- labpc_cancel(dev, s);
- async->events |= COMEDI_CB_EOA;
- }
- }
+ if (async->cmd.stop_src == TRIG_COUNT)
+ devpriv->count -= num_points;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ /* set address and count for next transfer */
+ set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer));
+ set_dma_count(devpriv->dma_chan, leftover * sample_size);
+ release_dma_lock(flags);
+
+ async->events |= COMEDI_CB_BLOCK;
+}
+
+static void handle_isa_dma(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ labpc_drain_dma(dev);
+
+ enable_dma(devpriv->dma_chan);
+
+ /* clear dma tc interrupt */
+ devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);
}
+#endif
/* read all available samples from ai fifo */
static int labpc_drain_fifo(struct comedi_device *dev)
return 0;
}
-#ifdef CONFIG_ISA_DMA_API
-static void labpc_drain_dma(struct comedi_device *dev)
+/* makes sure all data acquired by board is transferred to comedi (used
+ * when acquisition is terminated by stop_src == TRIG_EXT). */
+static void labpc_drain_dregs(struct comedi_device *dev)
{
+#ifdef CONFIG_ISA_DMA_API
struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async = s->async;
- int status;
- unsigned long flags;
- unsigned int max_points, num_points, residue, leftover;
- int i;
- status = devpriv->status1_bits;
+ if (devpriv->current_transfer == isa_dma_transfer)
+ labpc_drain_dma(dev);
+#endif
- 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);
+ labpc_drain_fifo(dev);
+}
- /* figure out how many points to read */
- max_points = devpriv->dma_transfer_size / sample_size;
- /* residue is the number of points left to be done on the dma
- * transfer. It should always be zero at this point unless
- * the stop_src is set to external triggering.
- */
- residue = get_dma_residue(devpriv->dma_chan) / sample_size;
- num_points = max_points - residue;
- if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT)
- num_points = devpriv->count;
+/* interrupt service routine */
+static irqreturn_t labpc_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async;
+ struct comedi_cmd *cmd;
- /* figure out how many points will be stored next time */
- leftover = 0;
- if (async->cmd.stop_src != TRIG_COUNT) {
- leftover = devpriv->dma_transfer_size / sample_size;
- } else if (devpriv->count > num_points) {
- leftover = devpriv->count - num_points;
- if (leftover > max_points)
- leftover = max_points;
+ if (!dev->attached) {
+ comedi_error(dev, "premature interrupt");
+ return IRQ_HANDLED;
}
- /* write data to comedi buffer */
- for (i = 0; i < num_points; i++)
- cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
-
- if (async->cmd.stop_src == TRIG_COUNT)
- devpriv->count -= num_points;
-
- /* set address and count for next transfer */
- set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer));
- set_dma_count(devpriv->dma_chan, leftover * sample_size);
- release_dma_lock(flags);
-
- async->events |= COMEDI_CB_BLOCK;
-}
+ async = s->async;
+ cmd = &async->cmd;
+ async->events = 0;
-static void handle_isa_dma(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
+ /* read board status */
+ devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
+ if (thisboard->register_layout == labpc_1200_layout)
+ devpriv->status2_bits =
+ devpriv->read_byte(dev->iobase + STATUS2_REG);
- labpc_drain_dma(dev);
+ if ((devpriv->status1_bits & (DMATC_BIT | TIMER_BIT | OVERFLOW_BIT |
+ OVERRUN_BIT | DATA_AVAIL_BIT)) == 0
+ && (devpriv->status2_bits & A1_TC_BIT) == 0
+ && (devpriv->status2_bits & FNHF_BIT)) {
+ return IRQ_NONE;
+ }
- enable_dma(devpriv->dma_chan);
+ if (devpriv->status1_bits & OVERRUN_BIT) {
+ /* clear error interrupt */
+ devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ comedi_event(dev, s);
+ comedi_error(dev, "overrun");
+ return IRQ_HANDLED;
+ }
- /* clear dma tc interrupt */
- devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);
-}
+#ifdef CONFIG_ISA_DMA_API
+ if (devpriv->current_transfer == isa_dma_transfer) {
+ /*
+ * if a dma terminal count of external stop trigger
+ * has occurred
+ */
+ if (devpriv->status1_bits & DMATC_BIT ||
+ (thisboard->register_layout == labpc_1200_layout
+ && devpriv->status2_bits & A1_TC_BIT)) {
+ handle_isa_dma(dev);
+ }
+ } else
#endif
+ labpc_drain_fifo(dev);
-/* makes sure all data acquired by board is transferred to comedi (used
- * when acquisition is terminated by stop_src == TRIG_EXT). */
-static void labpc_drain_dregs(struct comedi_device *dev)
-{
-#ifdef CONFIG_ISA_DMA_API
- struct labpc_private *devpriv = dev->private;
+ if (devpriv->status1_bits & TIMER_BIT) {
+ comedi_error(dev, "handled timer interrupt?");
+ /* clear it */
+ devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG);
+ }
- if (devpriv->current_transfer == isa_dma_transfer)
- labpc_drain_dma(dev);
-#endif
+ if (devpriv->status1_bits & OVERFLOW_BIT) {
+ /* clear error interrupt */
+ devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ comedi_event(dev, s);
+ comedi_error(dev, "overflow");
+ return IRQ_HANDLED;
+ }
+ /* handle external stop trigger */
+ if (cmd->stop_src == TRIG_EXT) {
+ if (devpriv->status2_bits & A1_TC_BIT) {
+ labpc_drain_dregs(dev);
+ labpc_cancel(dev, s);
+ async->events |= COMEDI_CB_EOA;
+ }
+ }
- labpc_drain_fifo(dev);
+ /* TRIG_COUNT end of acquisition */
+ if (cmd->stop_src == TRIG_COUNT) {
+ if (devpriv->count == 0) {
+ labpc_cancel(dev, s);
+ async->events |= COMEDI_CB_EOA;
+ }
+ }
+
+ comedi_event(dev, s);
+ return IRQ_HANDLED;
}
-static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
+/* analog output insn */
+static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
- int i, n;
- int chan, range;
- int lsb, msb;
- int timeout = 1000;
+ int channel, range;
unsigned long flags;
+ int lsb, msb;
- /* disable timed conversions */
+ channel = CR_CHAN(insn->chanspec);
+
+ /* turn off pacing of analog output channel */
+ /* note: hardware bug in daqcard-1200 means pacing cannot
+ * be independently enabled/disabled for its the two channels */
spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
+ devpriv->command2_bits &= ~DAC_PACED_BIT(channel);
devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
- /* disable interrupt generation and dma */
- devpriv->command3_bits = 0;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
-
- /* set gain and channel */
- devpriv->command1_bits = 0;
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
- devpriv->command1_bits |= thisboard->ai_range_code[range];
- /* munge channel bits for differential/scan disabled mode */
- if (CR_AREF(insn->chanspec) == AREF_DIFF)
- chan *= 2;
- devpriv->command1_bits |= ADC_CHAN_BITS(chan);
- devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
-
- /* setup command6 register for 1200 boards */
+ /* set range */
if (thisboard->register_layout == labpc_1200_layout) {
- /* reference inputs to ground or common? */
- if (CR_AREF(insn->chanspec) != AREF_GROUND)
- devpriv->command6_bits |= ADC_COMMON_BIT;
- else
- devpriv->command6_bits &= ~ADC_COMMON_BIT;
- /* bipolar or unipolar range? */
- if (thisboard->ai_range_is_unipolar[range])
- devpriv->command6_bits |= ADC_UNIP_BIT;
+ range = CR_RANGE(insn->chanspec);
+ if (range & AO_RANGE_IS_UNIPOLAR)
+ devpriv->command6_bits |= DAC_UNIP_BIT(channel);
else
- devpriv->command6_bits &= ~ADC_UNIP_BIT;
- /* don't interrupt on fifo half full */
- devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
- /* don't enable interrupt on counter a1 terminal count? */
- devpriv->command6_bits &= ~A1_INTR_EN_BIT;
- /* write to register */
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
- }
- /* setup command4 register */
- devpriv->command4_bits = 0;
- devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
- /* single-ended/differential */
- if (CR_AREF(insn->chanspec) == AREF_DIFF)
- devpriv->command4_bits |= ADC_DIFF_BIT;
- devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
-
- /*
- * initialize pacer counter output to make sure it doesn't
- * cause any problems
- */
- devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG);
-
- labpc_clear_adc_fifo(dev);
-
- for (n = 0; n < insn->n; n++) {
- /* trigger conversion */
- devpriv->write_byte(0x1, dev->iobase + ADC_CONVERT_REG);
-
- for (i = 0; i < timeout; i++) {
- if (devpriv->read_byte(dev->iobase +
- STATUS1_REG) & DATA_AVAIL_BIT)
- break;
- udelay(1);
- }
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
- }
- lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- data[n] = (msb << 8) | lsb;
- }
-
- return n;
-}
-
-/* analog output insn */
-static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
- int channel, range;
- unsigned long flags;
- int lsb, msb;
-
- channel = CR_CHAN(insn->chanspec);
-
- /* turn off pacing of analog output channel */
- /* note: hardware bug in daqcard-1200 means pacing cannot
- * be independently enabled/disabled for its the two channels */
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~DAC_PACED_BIT(channel);
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- /* set range */
- if (thisboard->register_layout == labpc_1200_layout) {
- range = CR_RANGE(insn->chanspec);
- if (range & AO_RANGE_IS_UNIPOLAR)
- devpriv->command6_bits |= DAC_UNIP_BIT(channel);
- else
- devpriv->command6_bits &= ~DAC_UNIP_BIT(channel);
- /* write to register */
+ devpriv->command6_bits &= ~DAC_UNIP_BIT(channel);
+ /* write to register */
devpriv->write_byte(devpriv->command6_bits,
dev->iobase + COMMAND6_REG);
}
return 1;
}
-static int labpc_calib_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
-
- data[0] = devpriv->caldac[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int labpc_calib_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int channel = CR_CHAN(insn->chanspec);
-
- write_caldac(dev, channel, data[0]);
- return 1;
-}
-
-static int labpc_eeprom_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
-
- data[0] = devpriv->eeprom_data[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int labpc_eeprom_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int channel = CR_CHAN(insn->chanspec);
- int ret;
-
- /* only allow writes to user area of eeprom */
- if (channel < 16 || channel > 127) {
- dev_dbg(dev->class_dev,
- "eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)\n");
- return -EINVAL;
- }
-
- ret = labpc_eeprom_write(dev, channel, data[0]);
- if (ret < 0)
- return ret;
-
- return 1;
-}
-
-#ifdef CONFIG_ISA_DMA_API
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
-{
- unsigned int size;
- unsigned int freq;
-
- if (cmd->convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd->convert_arg;
- /* return some default value */
- else
- freq = 0xffffffff;
-
- /* make buffer fill in no more than 1/3 second */
- size = (freq / 3) * sample_size;
-
- /* set a minimum and maximum size allowed */
- if (size > dma_buffer_size)
- size = dma_buffer_size - dma_buffer_size % sample_size;
- else if (size < sample_size)
- size = sample_size;
-
- return size;
-}
-#endif
-
-/* figures out what counter values to use based on command */
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- struct labpc_private *devpriv = dev->private;
- /* max value for 16 bit counter in mode 2 */
- const int max_counter_value = 0x10000;
- /* min value for 16 bit counter in mode 2 */
- const int min_counter_value = 2;
- unsigned int base_period;
- unsigned int scan_period;
- unsigned int convert_period;
-
- /*
- * if both convert and scan triggers are TRIG_TIMER, then they
- * both rely on counter b0
- */
- convert_period = labpc_ai_convert_period(cmd, mode);
- scan_period = labpc_ai_scan_period(cmd, mode);
- if (convert_period && scan_period) {
- /*
- * pick the lowest b0 divisor value we can (for maximum input
- * clock speed on convert and scan counters)
- */
- devpriv->divisor_b0 = (scan_period - 1) /
- (LABPC_TIMER_BASE * max_counter_value) + 1;
- if (devpriv->divisor_b0 < min_counter_value)
- devpriv->divisor_b0 = min_counter_value;
- if (devpriv->divisor_b0 > max_counter_value)
- devpriv->divisor_b0 = max_counter_value;
-
- base_period = LABPC_TIMER_BASE * devpriv->divisor_b0;
-
- /* set a0 for conversion frequency and b1 for scan frequency */
- switch (cmd->flags & TRIG_ROUND_MASK) {
- default:
- case TRIG_ROUND_NEAREST:
- devpriv->divisor_a0 =
- (convert_period + (base_period / 2)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period / 2)) / base_period;
- break;
- case TRIG_ROUND_UP:
- devpriv->divisor_a0 =
- (convert_period + (base_period - 1)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period - 1)) / base_period;
- break;
- case TRIG_ROUND_DOWN:
- devpriv->divisor_a0 = convert_period / base_period;
- devpriv->divisor_b1 = scan_period / base_period;
- break;
- }
- /* make sure a0 and b1 values are acceptable */
- if (devpriv->divisor_a0 < min_counter_value)
- devpriv->divisor_a0 = min_counter_value;
- if (devpriv->divisor_a0 > max_counter_value)
- devpriv->divisor_a0 = max_counter_value;
- if (devpriv->divisor_b1 < min_counter_value)
- devpriv->divisor_b1 = min_counter_value;
- if (devpriv->divisor_b1 > max_counter_value)
- devpriv->divisor_b1 = max_counter_value;
- /* write corrected timings to command */
- labpc_set_ai_convert_period(cmd, mode,
- base_period * devpriv->divisor_a0);
- labpc_set_ai_scan_period(cmd, mode,
- base_period * devpriv->divisor_b1);
- /*
- * if only one TRIG_TIMER is used, we can employ the generic
- * cascaded timing functions
- */
- } else if (scan_period) {
- /*
- * calculate cascaded counter values
- * that give desired scan timing
- */
- i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
- &(devpriv->divisor_b1),
- &(devpriv->divisor_b0),
- &scan_period,
- cmd->flags & TRIG_ROUND_MASK);
- labpc_set_ai_scan_period(cmd, mode, scan_period);
- } else if (convert_period) {
- /*
- * calculate cascaded counter values
- * that give desired conversion timing
- */
- i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
- &(devpriv->divisor_a0),
- &(devpriv->divisor_b0),
- &convert_period,
- cmd->flags & TRIG_ROUND_MASK);
- labpc_set_ai_convert_period(cmd, mode, convert_period);
- }
-}
-
static int labpc_dio_mem_callback(int dir, int port, int data,
unsigned long iobase)
{
return value;
}
-static unsigned int labpc_eeprom_read(struct comedi_device *dev,
- unsigned int address)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int value;
- /* bits to tell eeprom to expect a read */
- const int read_instruction = 0x3;
- /* 8 bit write lengths to eeprom */
- const int write_length = 8;
+static unsigned int labpc_eeprom_read(struct comedi_device *dev,
+ unsigned int address)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int value;
+ /* bits to tell eeprom to expect a read */
+ const int read_instruction = 0x3;
+ /* 8 bit write lengths to eeprom */
+ const int write_length = 8;
+
+ /* enable read/write to eeprom */
+ devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ /* send read instruction */
+ labpc_serial_out(dev, read_instruction, write_length);
+ /* send 8 bit address to read from */
+ labpc_serial_out(dev, address, write_length);
+ /* read result */
+ value = labpc_serial_in(dev);
+
+ /* disable read/write to eeprom */
+ devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ return value;
+}
+
+static unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int value;
+ const int read_status_instruction = 0x5;
+ const int write_length = 8; /* 8 bit write lengths to eeprom */
+
+ /* enable read/write to eeprom */
+ devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ /* send read status instruction */
+ labpc_serial_out(dev, read_status_instruction, write_length);
+ /* read result */
+ value = labpc_serial_in(dev);
+
+ /* disable read/write to eeprom */
+ devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ return value;
+}
+
+static int labpc_eeprom_write(struct comedi_device *dev,
+ unsigned int address, unsigned int value)
+{
+ struct labpc_private *devpriv = dev->private;
+ const int write_enable_instruction = 0x6;
+ const int write_instruction = 0x2;
+ const int write_length = 8; /* 8 bit write lengths to eeprom */
+ const int write_in_progress_bit = 0x1;
+ const int timeout = 10000;
+ int i;
+
+ /* make sure there isn't already a write in progress */
+ for (i = 0; i < timeout; i++) {
+ if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) ==
+ 0)
+ break;
+ }
+ if (i == timeout) {
+ comedi_error(dev, "eeprom write timed out");
+ return -ETIME;
+ }
+ /* update software copy of eeprom */
+ devpriv->eeprom_data[address] = value;
+
+ /* enable read/write to eeprom */
+ devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ /* send write_enable instruction */
+ labpc_serial_out(dev, write_enable_instruction, write_length);
+ devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ /* send write instruction */
+ devpriv->command5_bits |= EEPROM_EN_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ labpc_serial_out(dev, write_instruction, write_length);
+ /* send 8 bit address to write to */
+ labpc_serial_out(dev, address, write_length);
+ /* write value */
+ labpc_serial_out(dev, value, write_length);
+ devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ /* disable read/write to eeprom */
+ devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ return 0;
+}
+
+/* writes to 8 bit calibration dacs */
+static void write_caldac(struct comedi_device *dev, unsigned int channel,
+ unsigned int value)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ if (value == devpriv->caldac[channel])
+ return;
+ devpriv->caldac[channel] = value;
+
+ /* clear caldac load bit and make sure we don't write to eeprom */
+ devpriv->command5_bits &=
+ ~CALDAC_LOAD_BIT & ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+
+ /* write 4 bit channel */
+ labpc_serial_out(dev, channel, 4);
+ /* write 8 bit caldac value */
+ labpc_serial_out(dev, value, 8);
+
+ /* set and clear caldac bit to load caldac value */
+ devpriv->command5_bits |= CALDAC_LOAD_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->command5_bits &= ~CALDAC_LOAD_BIT;
+ udelay(1);
+ devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+}
+
+static int labpc_calib_write_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int channel = CR_CHAN(insn->chanspec);
+
+ write_caldac(dev, channel, data[0]);
+ return 1;
+}
+
+static int labpc_calib_read_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ data[0] = devpriv->caldac[CR_CHAN(insn->chanspec)];
+
+ return 1;
+}
+
+static int labpc_eeprom_write_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int channel = CR_CHAN(insn->chanspec);
+ int ret;
+
+ /* only allow writes to user area of eeprom */
+ if (channel < 16 || channel > 127) {
+ dev_dbg(dev->class_dev,
+ "eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)\n");
+ return -EINVAL;
+ }
+
+ ret = labpc_eeprom_write(dev, channel, data[0]);
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
+static int labpc_eeprom_read_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ data[0] = devpriv->eeprom_data[CR_CHAN(insn->chanspec)];
+
+ return 1;
+}
+
+int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
+ unsigned int irq, unsigned int dma_chan)
+{
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s;
+ int i;
+ unsigned long isr_flags;
+#ifdef CONFIG_ISA_DMA_API
+ unsigned long dma_flags;
+#endif
+ short lsb, msb;
+ int ret;
+
+ dev_info(dev->class_dev, "ni_labpc: %s\n", thisboard->name);
+ if (iobase == 0) {
+ dev_err(dev->class_dev, "io base address is zero!\n");
+ return -EINVAL;
+ }
+ /* request io regions for isa boards */
+ if (thisboard->bustype == isa_bustype) {
+ /* check if io addresses are available */
+ if (!request_region(iobase, LABPC_SIZE, DRV_NAME)) {
+ dev_err(dev->class_dev, "I/O port conflict\n");
+ return -EIO;
+ }
+ }
+ dev->iobase = iobase;
+
+ if (thisboard->memory_mapped_io) {
+ devpriv->read_byte = labpc_readb;
+ devpriv->write_byte = labpc_writeb;
+ } else {
+ devpriv->read_byte = labpc_inb;
+ devpriv->write_byte = labpc_outb;
+ }
+ /* initialize board's command registers */
+ devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
+ devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
+ devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
+ if (thisboard->register_layout == labpc_1200_layout) {
+ devpriv->write_byte(devpriv->command5_bits,
+ dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->command6_bits,
+ dev->iobase + COMMAND6_REG);
+ }
+
+ /* grab our IRQ */
+ if (irq) {
+ isr_flags = 0;
+ if (thisboard->bustype == pci_bustype
+ || thisboard->bustype == pcmcia_bustype)
+ isr_flags |= IRQF_SHARED;
+ if (request_irq(irq, labpc_interrupt, isr_flags,
+ DRV_NAME, dev)) {
+ dev_err(dev->class_dev, "unable to allocate irq %u\n",
+ irq);
+ return -EINVAL;
+ }
+ }
+ dev->irq = irq;
+
+#ifdef CONFIG_ISA_DMA_API
+ /* grab dma channel */
+ if (dma_chan > 3) {
+ dev_err(dev->class_dev, "invalid dma channel %u\n", dma_chan);
+ return -EINVAL;
+ } else if (dma_chan) {
+ /* allocate dma buffer */
+ devpriv->dma_buffer = kmalloc(dma_buffer_size,
+ GFP_KERNEL | GFP_DMA);
+ if (devpriv->dma_buffer == NULL)
+ return -ENOMEM;
+
+ if (request_dma(dma_chan, DRV_NAME)) {
+ dev_err(dev->class_dev,
+ "failed to allocate dma channel %u\n",
+ dma_chan);
+ return -EINVAL;
+ }
+ devpriv->dma_chan = dma_chan;
+ dma_flags = claim_dma_lock();
+ disable_dma(devpriv->dma_chan);
+ set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
+ release_dma_lock(dma_flags);
+ }
+#endif
+
+ dev->board_name = thisboard->name;
+
+ ret = comedi_alloc_subdevices(dev, 5);
+ if (ret)
+ return ret;
+
+ /* analog input subdevice */
+ s = &dev->subdevices[0];
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags =
+ SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
+ s->n_chan = 8;
+ s->len_chanlist = 8;
+ s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
+ s->range_table = thisboard->ai_range_table;
+ s->do_cmd = labpc_ai_cmd;
+ s->do_cmdtest = labpc_ai_cmdtest;
+ s->insn_read = labpc_ai_rinsn;
+ s->cancel = labpc_cancel;
+
+ /* analog output */
+ s = &dev->subdevices[1];
+ if (thisboard->has_ao) {
+ /*
+ * Could provide command support, except it only has a
+ * one sample hardware buffer for analog output and no
+ * underrun flag.
+ */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = NUM_AO_CHAN;
+ s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
+ s->range_table = &range_labpc_ao;
+ s->insn_read = labpc_ao_rinsn;
+ s->insn_write = labpc_ao_winsn;
+ /* initialize analog outputs to a known value */
+ for (i = 0; i < s->n_chan; i++) {
+ devpriv->ao_value[i] = s->maxdata / 2;
+ lsb = devpriv->ao_value[i] & 0xff;
+ msb = (devpriv->ao_value[i] >> 8) & 0xff;
+ devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i));
+ devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i));
+ }
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /* 8255 dio */
+ s = &dev->subdevices[2];
+ /* if board uses io memory we have to give a custom callback
+ * function to the 8255 driver */
+ if (thisboard->memory_mapped_io)
+ subdev_8255_init(dev, s, labpc_dio_mem_callback,
+ (unsigned long)(dev->iobase + DIO_BASE_REG));
+ else
+ subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG);
+
+ /* calibration subdevices for boards that have one */
+ s = &dev->subdevices[3];
+ if (thisboard->register_layout == labpc_1200_layout) {
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 16;
+ s->maxdata = 0xff;
+ s->insn_read = labpc_calib_read_insn;
+ s->insn_write = labpc_calib_write_insn;
- /* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ for (i = 0; i < s->n_chan; i++)
+ write_caldac(dev, i, s->maxdata / 2);
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
- /* send read instruction */
- labpc_serial_out(dev, read_instruction, write_length);
- /* send 8 bit address to read from */
- labpc_serial_out(dev, address, write_length);
- /* read result */
- value = labpc_serial_in(dev);
+ /* EEPROM */
+ s = &dev->subdevices[4];
+ if (thisboard->register_layout == labpc_1200_layout) {
+ s->type = COMEDI_SUBD_MEMORY;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = EEPROM_SIZE;
+ s->maxdata = 0xff;
+ s->insn_read = labpc_eeprom_read_insn;
+ s->insn_write = labpc_eeprom_write_insn;
- /* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ for (i = 0; i < EEPROM_SIZE; i++)
+ devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
- return value;
+ return 0;
}
+EXPORT_SYMBOL_GPL(labpc_common_attach);
-static int labpc_eeprom_write(struct comedi_device *dev,
- unsigned int address, unsigned int value)
+static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct labpc_private *devpriv = dev->private;
- const int write_enable_instruction = 0x6;
- const int write_instruction = 0x2;
- const int write_length = 8; /* 8 bit write lengths to eeprom */
- const int write_in_progress_bit = 0x1;
- const int timeout = 10000;
- int i;
-
- /* make sure there isn't already a write in progress */
- for (i = 0; i < timeout; i++) {
- if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) ==
- 0)
- break;
- }
- if (i == timeout) {
- comedi_error(dev, "eeprom write timed out");
- return -ETIME;
- }
- /* update software copy of eeprom */
- devpriv->eeprom_data[address] = value;
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
+ struct labpc_private *devpriv;
+ unsigned long iobase = 0;
+ unsigned int irq = 0;
+ unsigned int dma_chan = 0;
- /* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
- /* send write_enable instruction */
- labpc_serial_out(dev, write_enable_instruction, write_length);
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ /* get base address, irq etc. based on bustype */
+ switch (thisboard->bustype) {
+ case isa_bustype:
+#ifdef CONFIG_ISA_DMA_API
+ iobase = it->options[0];
+ irq = it->options[1];
+ dma_chan = it->options[2];
+#else
+ dev_err(dev->class_dev,
+ "ni_labpc driver has not been built with ISA DMA support.\n");
+ return -EINVAL;
+#endif
+ break;
+ case pci_bustype:
+#ifdef CONFIG_COMEDI_PCI_DRIVERS
+ dev_err(dev->class_dev,
+ "manual configuration of PCI board '%s' is not supported\n",
+ thisboard->name);
+ return -EINVAL;
+#else
+ dev_err(dev->class_dev,
+ "ni_labpc driver has not been built with PCI support.\n");
+ return -EINVAL;
+#endif
+ break;
+ default:
+ dev_err(dev->class_dev,
+ "ni_labpc: bug! couldn't determine board type\n");
+ return -EINVAL;
+ break;
+ }
- /* send write instruction */
- devpriv->command5_bits |= EEPROM_EN_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- labpc_serial_out(dev, write_instruction, write_length);
- /* send 8 bit address to write to */
- labpc_serial_out(dev, address, write_length);
- /* write value */
- labpc_serial_out(dev, value, write_length);
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ return labpc_common_attach(dev, iobase, irq, dma_chan);
+}
- /* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+static const struct labpc_boardinfo *
+labpc_pci_find_boardinfo(struct pci_dev *pcidev)
+{
+ unsigned int device_id = pcidev->device;
+ unsigned int n;
- return 0;
+ for (n = 0; n < ARRAY_SIZE(labpc_boards); n++) {
+ const struct labpc_boardinfo *board = &labpc_boards[n];
+ if (board->bustype == pci_bustype &&
+ board->device_id == device_id)
+ return board;
+ }
+ return NULL;
}
-static unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
+static int labpc_auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
{
- struct labpc_private *devpriv = dev->private;
- unsigned int value;
- const int read_status_instruction = 0x5;
- const int write_length = 8; /* 8 bit write lengths to eeprom */
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct labpc_private *devpriv;
+ unsigned long iobase;
+ unsigned int irq;
+ int ret;
- /* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS))
+ return -ENODEV;
- /* send read status instruction */
- labpc_serial_out(dev, read_status_instruction, write_length);
- /* read result */
- value = labpc_serial_in(dev);
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
- /* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
- return value;
+ dev->board_ptr = labpc_pci_find_boardinfo(pcidev);
+ if (!dev->board_ptr)
+ return -ENODEV;
+ devpriv->mite = mite_alloc(pcidev);
+ if (!devpriv->mite)
+ return -ENOMEM;
+ ret = mite_setup(devpriv->mite);
+ if (ret < 0)
+ return ret;
+ iobase = (unsigned long)devpriv->mite->daq_io_addr;
+ irq = mite_irq(devpriv->mite);
+ return labpc_common_attach(dev, iobase, irq, 0);
}
-/* writes to 8 bit calibration dacs */
-static void write_caldac(struct comedi_device *dev, unsigned int channel,
- unsigned int value)
+void labpc_common_detach(struct comedi_device *dev)
{
+ const struct labpc_boardinfo *thisboard = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s;
- if (value == devpriv->caldac[channel])
+ if (!thisboard)
return;
- devpriv->caldac[channel] = value;
-
- /* clear caldac load bit and make sure we don't write to eeprom */
- devpriv->command5_bits &=
- ~CALDAC_LOAD_BIT & ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
-
- /* write 4 bit channel */
- labpc_serial_out(dev, channel, 4);
- /* write 8 bit caldac value */
- labpc_serial_out(dev, value, 8);
-
- /* set and clear caldac bit to load caldac value */
- devpriv->command5_bits |= CALDAC_LOAD_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits &= ~CALDAC_LOAD_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ if (dev->subdevices) {
+ s = &dev->subdevices[2];
+ subdev_8255_cleanup(dev, s);
+ }
+#ifdef CONFIG_ISA_DMA_API
+ /* only free stuff if it has been allocated by _attach */
+ kfree(devpriv->dma_buffer);
+ if (devpriv->dma_chan)
+ free_dma(devpriv->dma_chan);
+#endif
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (thisboard->bustype == isa_bustype && dev->iobase)
+ release_region(dev->iobase, LABPC_SIZE);
+#ifdef CONFIG_COMEDI_PCI_DRIVERS
+ if (devpriv->mite) {
+ mite_unsetup(devpriv->mite);
+ mite_free(devpriv->mite);
+ }
+ if (thisboard->bustype == pci_bustype)
+ comedi_pci_disable(dev);
+#endif
}
+EXPORT_SYMBOL_GPL(labpc_common_detach);
static struct comedi_driver labpc_driver = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = labpc_attach,
- .auto_attach = labpc_auto_attach,
- .detach = labpc_common_detach,
- .num_names = ARRAY_SIZE(labpc_boards),
- .board_name = &labpc_boards[0].name,
- .offset = sizeof(struct labpc_board_struct),
+ .driver_name = DRV_NAME,
+ .module = THIS_MODULE,
+ .attach = labpc_attach,
+ .auto_attach = labpc_auto_attach,
+ .detach = labpc_common_detach,
+ .num_names = ARRAY_SIZE(labpc_boards),
+ .board_name = &labpc_boards[0].name,
+ .offset = sizeof(struct labpc_boardinfo),
};
#ifdef CONFIG_COMEDI_PCI_DRIVERS
static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)},
- {0}
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161) },
+ { 0 }
};
MODULE_DEVICE_TABLE(pci, labpc_pci_table);
static int labpc_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &labpc_driver);
+ return comedi_pci_auto_config(dev, &labpc_driver, id->driver_data);
}
static struct pci_driver labpc_pci_driver = {
- .name = DRV_NAME,
- .id_table = labpc_pci_table,
- .probe = labpc_pci_probe,
+ .name = DRV_NAME,
+ .id_table = labpc_pci_table,
+ .probe = labpc_pci_probe,
.remove = comedi_pci_auto_unconfig,
};
module_comedi_pci_driver(labpc_driver, labpc_pci_driver);