drivers/input/serio/altera_ps2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/serio/altera_ps2.c
Extension
.c
Size
3571 bytes
Lines
161
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 ps2if {
	struct serio *io;
	void __iomem *base;
};

/*
 * Read all bytes waiting in the PS2 port.  There should be
 * at the most one, but we loop for safety.
 */
static irqreturn_t altera_ps2_rxint(int irq, void *dev_id)
{
	struct ps2if *ps2if = dev_id;
	unsigned int status;
	irqreturn_t handled = IRQ_NONE;

	while ((status = readl(ps2if->base)) & 0xffff0000) {
		serio_interrupt(ps2if->io, status & 0xff, 0);
		handled = IRQ_HANDLED;
	}

	return handled;
}

/*
 * Write a byte to the PS2 port.
 */
static int altera_ps2_write(struct serio *io, unsigned char val)
{
	struct ps2if *ps2if = io->port_data;

	writel(val, ps2if->base);
	return 0;
}

static int altera_ps2_open(struct serio *io)
{
	struct ps2if *ps2if = io->port_data;

	/* clear fifo */
	while (readl(ps2if->base) & 0xffff0000)
		/* empty */;

	writel(1, ps2if->base + 4); /* enable rx irq */
	return 0;
}

static void altera_ps2_close(struct serio *io)
{
	struct ps2if *ps2if = io->port_data;

	writel(0, ps2if->base + 4); /* disable rx irq */
}

/*
 * Add one device to this driver.
 */
static int altera_ps2_probe(struct platform_device *pdev)
{
	struct ps2if *ps2if;
	struct serio *serio;
	int error, irq;

	ps2if = devm_kzalloc(&pdev->dev, sizeof(*ps2if), GFP_KERNEL);
	if (!ps2if)
		return -ENOMEM;

	ps2if->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
	if (IS_ERR(ps2if->base))
		return PTR_ERR(ps2if->base);

	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		return -ENXIO;

	error = devm_request_irq(&pdev->dev, irq, altera_ps2_rxint, 0,
				 pdev->name, ps2if);
	if (error) {
		dev_err(&pdev->dev, "could not request IRQ %d\n", irq);
		return error;
	}

	serio = kzalloc_obj(*serio);
	if (!serio)
		return -ENOMEM;

	serio->id.type		= SERIO_8042;
	serio->write		= altera_ps2_write;
	serio->open		= altera_ps2_open;
	serio->close		= altera_ps2_close;
	strscpy(serio->name, dev_name(&pdev->dev), sizeof(serio->name));

Annotation

Implementation Notes