static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
{
	struct rt2x00_dev *rt2x00dev = dev_instance;
	u32 reg, mask;
	unsigned long flags;

	/* Read status and ACK all interrupts */
	rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
	rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);

	if (!reg)
		return IRQ_NONE;

	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
		return IRQ_HANDLED;

	/*
	 * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits
	 * for interrupts and interrupt masks we can just use the value of
	 * INT_SOURCE_CSR to create the interrupt mask.
	 */
	mask = ~reg;

	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
		rt2800pci_txstatus_interrupt(rt2x00dev);
		/*
		 * Never disable the TX_FIFO_STATUS interrupt.
		 */
		rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
	}

	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
		tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);

	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
		tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);

	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
		tasklet_schedule(&rt2x00dev->rxdone_tasklet);

	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
		tasklet_schedule(&rt2x00dev->autowake_tasklet);

	/*
	 * Disable all interrupts for which a tasklet was scheduled right now,
	 * the tasklet will reenable the appropriate interrupts.
	 */
	spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
	rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
	reg &= mask;
	rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
	spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);

	return IRQ_HANDLED;
}
Example #2
0
static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
{
	struct rt2x00_dev *rt2x00dev = dev_instance;
	u32 reg;
	irqreturn_t ret = IRQ_HANDLED;

	/* Read status and ACK all interrupts */
	rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
	rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);

	if (!reg)
		return IRQ_NONE;

	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
		return IRQ_HANDLED;

	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
		rt2800pci_txstatus_interrupt(rt2x00dev);

	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT) ||
	    rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT) ||
	    rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE) ||
	    rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) {
		/*
		 * All other interrupts are handled in the interrupt thread.
		 * Store irqvalue for use in the interrupt thread.
		 */
		rt2x00dev->irqvalue[0] = reg;

		/*
		 * Disable interrupts, will be enabled again in the
		 * interrupt thread.
		*/
		rt2x00dev->ops->lib->set_device_state(rt2x00dev,
						      STATE_RADIO_IRQ_OFF_ISR);

		/*
		 * Leave the TX_FIFO_STATUS interrupt enabled to not lose any
		 * tx status reports.
		 */
		rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
		rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
		rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);

		ret = IRQ_WAKE_THREAD;
	}

	return ret;
}