drivers/input/serio/apbps2.c

Source file repositories/reference/linux-study-clean/drivers/input/serio/apbps2.c

File Facts

System
Linux kernel
Corpus path
drivers/input/serio/apbps2.c
Extension
.c
Size
5460 bytes
Lines
219
Domain
Driver Families
Bucket
drivers/input
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

struct apbps2_regs {
	u32 __iomem data;	/* 0x00 */
	u32 __iomem status;	/* 0x04 */
	u32 __iomem ctrl;	/* 0x08 */
	u32 __iomem reload;	/* 0x0c */
};

#define APBPS2_STATUS_DR	(1<<0)
#define APBPS2_STATUS_PE	(1<<1)
#define APBPS2_STATUS_FE	(1<<2)
#define APBPS2_STATUS_KI	(1<<3)
#define APBPS2_STATUS_RF	(1<<4)
#define APBPS2_STATUS_TF	(1<<5)
#define APBPS2_STATUS_TCNT	(0x1f<<22)
#define APBPS2_STATUS_RCNT	(0x1f<<27)

#define APBPS2_CTRL_RE		(1<<0)
#define APBPS2_CTRL_TE		(1<<1)
#define APBPS2_CTRL_RI		(1<<2)
#define APBPS2_CTRL_TI		(1<<3)

struct apbps2_priv {
	struct serio		*io;
	struct apbps2_regs	__iomem *regs;
};

static int apbps2_idx;

static irqreturn_t apbps2_isr(int irq, void *dev_id)
{
	struct apbps2_priv *priv = dev_id;
	unsigned long status, data, rxflags;
	irqreturn_t ret = IRQ_NONE;

	while ((status = ioread32be(&priv->regs->status)) & APBPS2_STATUS_DR) {
		data = ioread32be(&priv->regs->data);
		rxflags = (status & APBPS2_STATUS_PE) ? SERIO_PARITY : 0;
		rxflags |= (status & APBPS2_STATUS_FE) ? SERIO_FRAME : 0;

		/* Clear error bits */
		if (rxflags)
			iowrite32be(0, &priv->regs->status);

		serio_interrupt(priv->io, data, rxflags);

		ret = IRQ_HANDLED;
	}

	return ret;
}

static int apbps2_write(struct serio *io, unsigned char val)
{
	struct apbps2_priv *priv = io->port_data;
	unsigned int tleft = 10000; /* Timeout in 100ms */

	/* Delay until PS/2 controller has room for more chars */
	while ((ioread32be(&priv->regs->status) & APBPS2_STATUS_TF) && tleft--)
		udelay(10);

	if ((ioread32be(&priv->regs->status) & APBPS2_STATUS_TF) == 0) {
		iowrite32be(val, &priv->regs->data);

		iowrite32be(APBPS2_CTRL_RE | APBPS2_CTRL_RI | APBPS2_CTRL_TE,
				&priv->regs->ctrl);
		return 0;
	}

	return -ETIMEDOUT;
}

static int apbps2_open(struct serio *io)
{
	struct apbps2_priv *priv = io->port_data;
	int limit;

	/* Clear error flags */
	iowrite32be(0, &priv->regs->status);

	/* Clear old data if available (unlikely) */
	limit = 1024;
	while ((ioread32be(&priv->regs->status) & APBPS2_STATUS_DR) && --limit)
		ioread32be(&priv->regs->data);

	/* Enable receiver and its interrupt */
	iowrite32be(APBPS2_CTRL_RE | APBPS2_CTRL_RI, &priv->regs->ctrl);

	return 0;
}

Annotation

Implementation Notes