drivers/tty/serial/8250/8250_aspeed_vuart.c

Source file repositories/reference/linux-study-clean/drivers/tty/serial/8250/8250_aspeed_vuart.c

File Facts

System
Linux kernel
Corpus path
drivers/tty/serial/8250/8250_aspeed_vuart.c
Extension
.c
Size
15402 bytes
Lines
581
Domain
Driver Families
Bucket
drivers/tty
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 aspeed_vuart {
	struct device		*dev;
	int			line;
	struct timer_list	unthrottle_timer;
	struct uart_8250_port	*port;
};

/*
 * If we fill the tty flip buffers, we throttle the data ready interrupt
 * to prevent dropped characters. This timeout defines how long we wait
 * to (conditionally, depending on buffer state) unthrottle.
 */
static const int unthrottle_timeout = HZ/10;

/*
 * The VUART is basically two UART 'front ends' connected by their FIFO
 * (no actual serial line in between). One is on the BMC side (management
 * controller) and one is on the host CPU side.
 *
 * It allows the BMC to provide to the host a "UART" that pipes into
 * the BMC itself and can then be turned by the BMC into a network console
 * of some sort for example.
 *
 * This driver is for the BMC side. The sysfs files allow the BMC
 * userspace which owns the system configuration policy, to specify
 * at what IO port and interrupt number the host side will appear
 * to the host on the Host <-> BMC LPC bus. It could be different on a
 * different system (though most of them use 3f8/4).
 */

static inline u8 aspeed_vuart_readb(struct aspeed_vuart *vuart, u8 reg)
{
	return readb(vuart->port->port.membase + reg);
}

static inline void aspeed_vuart_writeb(struct aspeed_vuart *vuart, u8 val, u8 reg)
{
	writeb(val, vuart->port->port.membase + reg);
}

static ssize_t lpc_address_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
	u16 addr;

	addr = (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRH) << 8) |
		(aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRL));

	return sysfs_emit(buf, "0x%x\n", addr);
}

static int aspeed_vuart_set_lpc_address(struct aspeed_vuart *vuart, u32 addr)
{
	if (addr > U16_MAX)
		return -EINVAL;

	aspeed_vuart_writeb(vuart, addr >> 8, ASPEED_VUART_ADDRH);
	aspeed_vuart_writeb(vuart, addr >> 0, ASPEED_VUART_ADDRL);

	return 0;
}

static ssize_t lpc_address_store(struct device *dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{
	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
	u32 val;
	int err;

	err = kstrtou32(buf, 0, &val);
	if (err)
		return err;

	err = aspeed_vuart_set_lpc_address(vuart, val);
	return err ? : count;
}

static DEVICE_ATTR_RW(lpc_address);

static ssize_t sirq_show(struct device *dev,
			 struct device_attribute *attr, char *buf)
{
	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
	u8 reg;

	reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB);
	reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
	reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;

Annotation

Implementation Notes