static int quad8_events_configure()

in 104-quad-8.c [397:452]


static int quad8_events_configure(struct counter_device *counter)
{
	struct quad8 *const priv = counter_priv(counter);
	unsigned long irq_enabled = 0;
	unsigned long irqflags;
	struct counter_event_node *event_node;
	unsigned int next_irq_trigger;
	unsigned long ior_cfg;
	unsigned long base_offset;

	spin_lock_irqsave(&priv->lock, irqflags);

	list_for_each_entry(event_node, &counter->events_list, l) {
		switch (event_node->event) {
		case COUNTER_EVENT_OVERFLOW:
			next_irq_trigger = QUAD8_EVENT_CARRY;
			break;
		case COUNTER_EVENT_THRESHOLD:
			next_irq_trigger = QUAD8_EVENT_COMPARE;
			break;
		case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
			next_irq_trigger = QUAD8_EVENT_CARRY_BORROW;
			break;
		case COUNTER_EVENT_INDEX:
			next_irq_trigger = QUAD8_EVENT_INDEX;
			break;
		default:
			/* should never reach this path */
			spin_unlock_irqrestore(&priv->lock, irqflags);
			return -EINVAL;
		}

		/* Skip configuration if it is the same as previously set */
		if (priv->irq_trigger[event_node->channel] == next_irq_trigger)
			continue;

		/* Save new IRQ function configuration */
		priv->irq_trigger[event_node->channel] = next_irq_trigger;

		/* Load configuration to I/O Control Register */
		ior_cfg = priv->ab_enable[event_node->channel] |
			  priv->preset_enable[event_node->channel] << 1 |
			  priv->irq_trigger[event_node->channel] << 3;
		base_offset = priv->base + 2 * event_node->channel + 1;
		outb(QUAD8_CTR_IOR | ior_cfg, base_offset);

		/* Enable IRQ line */
		irq_enabled |= BIT(event_node->channel);
	}

	outb(irq_enabled, priv->base + QUAD8_REG_INDEX_INTERRUPT);

	spin_unlock_irqrestore(&priv->lock, irqflags);

	return 0;
}