drivers/media/rc/ene_ir.c

Source file repositories/reference/linux-study-clean/drivers/media/rc/ene_ir.c

File Facts

System
Linux kernel
Corpus path
drivers/media/rc/ene_ir.c
Extension
.c
Size
31266 bytes
Lines
1200
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (dev->tx_pos == dev->tx_len) {
			if (!dev->tx_done) {
				dbg("TX: no more data to send");
				dev->tx_done = true;
				goto exit;
			} else {
				dbg("TX: last sample sent by hardware");
				ene_tx_disable(dev);
				complete(&dev->tx_complete);
				return;
			}
		}

		sample = dev->tx_buffer[dev->tx_pos++];
		dev->tx_sample_pulse = !dev->tx_sample_pulse;

		dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period);

		if (!dev->tx_sample)
			dev->tx_sample = 1;
	}

	raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK);
	dev->tx_sample -= raw_tx;

	dbg("TX: sample %8d (%s)", raw_tx * sample_period,
						pulse ? "pulse" : "space");
	if (pulse)
		raw_tx |= ENE_CIRRLC_OUT_PULSE;

	ene_write_reg(dev,
		dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx);

	dev->tx_reg = !dev->tx_reg;
exit:
	/* simulate TX done interrupt */
	if (txsim)
		mod_timer(&dev->tx_sim_timer, jiffies + HZ / 500);
}

/* timer to simulate tx done interrupt */
static void ene_tx_irqsim(struct timer_list *t)
{
	struct ene_device *dev = timer_container_of(dev, t, tx_sim_timer);
	unsigned long flags;

	spin_lock_irqsave(&dev->hw_lock, flags);
	ene_tx_sample(dev);
	spin_unlock_irqrestore(&dev->hw_lock, flags);
}


/* read irq status and ack it */
static int ene_irq_status(struct ene_device *dev)
{
	u8 irq_status;
	u8 fw_flags1, fw_flags2;
	int retval = 0;

	fw_flags2 = ene_read_reg(dev, ENE_FW2);

	if (dev->hw_revision < ENE_HW_C) {
		irq_status = ene_read_reg(dev, ENEB_IRQ_STATUS);

		if (!(irq_status & ENEB_IRQ_STATUS_IR))
			return 0;

		ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR);
		return ENE_IRQ_RX;
	}

	irq_status = ene_read_reg(dev, ENE_IRQ);
	if (!(irq_status & ENE_IRQ_STATUS))
		return 0;

	/* original driver does that twice - a workaround ? */
	ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
	ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);

	/* check RX interrupt */
	if (fw_flags2 & ENE_FW2_RXIRQ) {
		retval |= ENE_IRQ_RX;
		ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ);
	}

	/* check TX interrupt */
	fw_flags1 = ene_read_reg(dev, ENE_FW1);
	if (fw_flags1 & ENE_FW1_TXIRQ) {
		ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
		retval |= ENE_IRQ_TX;

Annotation

Implementation Notes