/*
 * Called to start acquisition for an 'INTERRUPT' subdevice.
 */
static int dio200_start_intr(struct comedi_device *dev,
			     struct comedi_subdevice *s)
{
	unsigned int n;
	unsigned isn_bits;
	const struct dio200_layout *layout = dio200_dev_layout(dev);
	struct dio200_subdev_intr *subpriv = s->private;
	struct comedi_cmd *cmd = &s->async->cmd;
	int retval = 0;

	if (cmd->stop_src == TRIG_COUNT && subpriv->stopcount == 0) {
		/* An empty acquisition! */
		s->async->events |= COMEDI_CB_EOA;
		subpriv->active = false;
		retval = 1;
	} else {
		/* Determine interrupt sources to enable. */
		isn_bits = 0;
		if (cmd->chanlist) {
			for (n = 0; n < cmd->chanlist_len; n++)
				isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
		}
		isn_bits &= subpriv->valid_isns;
		/* Enable interrupt sources. */
		subpriv->enabled_isns = isn_bits;
		if (layout->has_int_sce)
			dio200_write8(dev, subpriv->ofs, isn_bits);
	}

	return retval;
}
Ejemplo n.º 2
0
static void dio200_subdev_8254_write_chan(struct comedi_device *dev,
        struct comedi_subdevice *s,
        unsigned int chan,
        unsigned int count)
{
    struct dio200_subdev_8254 *subpriv = s->private;

    /* write lsb, msb */
    dio200_write8(dev, subpriv->ofs + chan, count & 0xff);
    dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff);
}
Ejemplo n.º 3
0
static void dio200_stop_intr(struct comedi_device *dev,
                             struct comedi_subdevice *s)
{
    const struct dio200_board *board = dev->board_ptr;
    struct dio200_subdev_intr *subpriv = s->private;

    subpriv->active = false;
    subpriv->enabled_isns = 0;
    if (board->has_int_sce)
        dio200_write8(dev, subpriv->ofs, 0);
}
/*
 * Called to stop acquisition for an 'INTERRUPT' subdevice.
 */
static void dio200_stop_intr(struct comedi_device *dev,
			     struct comedi_subdevice *s)
{
	const struct dio200_layout *layout = dio200_dev_layout(dev);
	struct dio200_subdev_intr *subpriv = s->private;

	subpriv->active = false;
	subpriv->enabled_isns = 0;
	if (layout->has_int_sce)
		dio200_write8(dev, subpriv->ofs, 0);
}
Ejemplo n.º 5
0
static unsigned int dio200_subdev_8254_status(struct comedi_device *dev,
        struct comedi_subdevice *s,
        unsigned int chan)
{
    struct dio200_subdev_8254 *subpriv = s->private;

    /* latch status */
    dio200_write8(dev, subpriv->ofs + i8254_control_reg,
                  0xe0 | (2 << chan));
    /* read status */
    return dio200_read8(dev, subpriv->ofs + chan);
}
Ejemplo n.º 6
0
static void dio200_subdev_8254_set_mode(struct comedi_device *dev,
                                        struct comedi_subdevice *s,
                                        unsigned int chan,
                                        unsigned int mode)
{
    struct dio200_subdev_8254 *subpriv = s->private;
    unsigned int byte;

    byte = chan << 6;
    byte |= 0x30;		/* access order: lsb, msb */
    byte |= (mode & 0xf);	/* counter mode and BCD|binary */
    dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte);
}
Ejemplo n.º 7
0
static unsigned int dio200_subdev_8254_read_chan(struct comedi_device *dev,
        struct comedi_subdevice *s,
        unsigned int chan)
{
    struct dio200_subdev_8254 *subpriv = s->private;
    unsigned int val;

    /* latch counter */
    val = chan << 6;
    dio200_write8(dev, subpriv->ofs + i8254_control_reg, val);
    /* read lsb, msb */
    val = dio200_read8(dev, subpriv->ofs + chan);
    val += dio200_read8(dev, subpriv->ofs + chan) << 8;
    return val;
}
Ejemplo n.º 8
0
static void dio200_start_intr(struct comedi_device *dev,
                              struct comedi_subdevice *s)
{
    const struct dio200_board *board = dev->board_ptr;
    struct dio200_subdev_intr *subpriv = s->private;
    struct comedi_cmd *cmd = &s->async->cmd;
    unsigned int n;
    unsigned isn_bits;

    /* Determine interrupt sources to enable. */
    isn_bits = 0;
    if (cmd->chanlist) {
        for (n = 0; n < cmd->chanlist_len; n++)
            isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
    }
    isn_bits &= subpriv->valid_isns;
    /* Enable interrupt sources. */
    subpriv->enabled_isns = isn_bits;
    if (board->has_int_sce)
        dio200_write8(dev, subpriv->ofs, isn_bits);
}
Ejemplo n.º 9
0
static int dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
        struct comedi_subdevice *s,
        unsigned int counter_number,
        unsigned int clock_src)
{
    const struct dio200_board *board = dev->board_ptr;
    struct dio200_subdev_8254 *subpriv = s->private;
    unsigned char byte;

    if (!board->has_clk_gat_sce)
        return -1;
    if (counter_number > 2)
        return -1;
    if (clock_src > (board->is_pcie ? 31 : 7))
        return -1;

    subpriv->clock_src[counter_number] = clock_src;
    byte = clk_sce(subpriv->which, counter_number, clock_src);
    dio200_write8(dev, subpriv->clk_sce_ofs, byte);

    return 0;
}
Ejemplo n.º 10
0
static int dio200_subdev_intr_init(struct comedi_device *dev,
                                   struct comedi_subdevice *s,
                                   unsigned int offset,
                                   unsigned valid_isns)
{
    const struct dio200_board *board = dev->board_ptr;
    struct dio200_subdev_intr *subpriv;

    subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
    if (!subpriv)
        return -ENOMEM;

    subpriv->ofs = offset;
    subpriv->valid_isns = valid_isns;
    spin_lock_init(&subpriv->spinlock);

    if (board->has_int_sce)
        /* Disable interrupt sources. */
        dio200_write8(dev, subpriv->ofs, 0);

    s->type = COMEDI_SUBD_DI;
    s->subdev_flags = SDF_READABLE | SDF_CMD_READ | SDF_PACKED;
    if (board->has_int_sce) {
        s->n_chan = DIO200_MAX_ISNS;
        s->len_chanlist = DIO200_MAX_ISNS;
    } else {
        /* No interrupt source register.  Support single channel. */
        s->n_chan = 1;
        s->len_chanlist = 1;
    }
    s->range_table = &range_digital;
    s->maxdata = 1;
    s->insn_bits = dio200_subdev_intr_insn_bits;
    s->do_cmdtest = dio200_subdev_intr_cmdtest;
    s->do_cmd = dio200_subdev_intr_cmd;
    s->cancel = dio200_subdev_intr_cancel;

    return 0;
}
/*
 * Set clock source for an '8254' counter subdevice channel.
 */
static int
dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
				 struct comedi_subdevice *s,
				 unsigned int counter_number,
				 unsigned int clock_src)
{
	const struct dio200_layout *layout = dio200_dev_layout(dev);
	struct dio200_subdev_8254 *subpriv = s->private;
	unsigned char byte;

	if (!layout->has_clk_gat_sce)
		return -1;
	if (counter_number > 2)
		return -1;
	if (clock_src > (layout->has_enhancements ? 31 : 7))
		return -1;

	subpriv->clock_src[counter_number] = clock_src;
	byte = clk_sce(subpriv->which, counter_number, clock_src);
	dio200_write8(dev, subpriv->clk_sce_ofs, byte);

	return 0;
}
Ejemplo n.º 12
0
static int dio200_handle_read_intr(struct comedi_device *dev,
                                   struct comedi_subdevice *s)
{
    const struct dio200_board *board = dev->board_ptr;
    struct dio200_subdev_intr *subpriv = s->private;
    unsigned triggered;
    unsigned intstat;
    unsigned cur_enabled;
    unsigned long flags;

    triggered = 0;

    spin_lock_irqsave(&subpriv->spinlock, flags);
    if (board->has_int_sce) {
        /*
         * Collect interrupt sources that have triggered and disable
         * them temporarily.  Loop around until no extra interrupt
         * sources have triggered, at which point, the valid part of
         * the interrupt status register will read zero, clearing the
         * cause of the interrupt.
         *
         * Mask off interrupt sources already seen to avoid infinite
         * loop in case of misconfiguration.
         */
        cur_enabled = subpriv->enabled_isns;
        while ((intstat = (dio200_read8(dev, subpriv->ofs) &
                           subpriv->valid_isns & ~triggered)) != 0) {
            triggered |= intstat;
            cur_enabled &= ~triggered;
            dio200_write8(dev, subpriv->ofs, cur_enabled);
        }
    } else {
        /*
         * No interrupt status register.  Assume the single interrupt
         * source has triggered.
         */
        triggered = subpriv->enabled_isns;
    }

    if (triggered) {
        /*
         * Some interrupt sources have triggered and have been
         * temporarily disabled to clear the cause of the interrupt.
         *
         * Reenable them NOW to minimize the time they are disabled.
         */
        cur_enabled = subpriv->enabled_isns;
        if (board->has_int_sce)
            dio200_write8(dev, subpriv->ofs, cur_enabled);

        if (subpriv->active) {
            /*
             * The command is still active.
             *
             * Ignore interrupt sources that the command isn't
             * interested in (just in case there's a race
             * condition).
             */
            if (triggered & subpriv->enabled_isns)
                /* Collect scan data. */
                dio200_read_scan_intr(dev, s, triggered);
        }
    }
    spin_unlock_irqrestore(&subpriv->spinlock, flags);

    comedi_handle_events(dev, s);

    return (triggered != 0);
}