drivers/tty/serial/serial_core.c

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

File Facts

System
Linux kernel
Corpus path
drivers/tty/serial/serial_core.c
Extension
.c
Size
93469 bytes
Lines
3588
Domain
Driver Families
Bucket
drivers/tty
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 uart_match {
	struct uart_port *port;
	struct uart_driver *driver;
};

static int serial_match_port(struct device *dev, const void *data)
{
	const struct uart_match *match = data;
	struct tty_driver *tty_drv = match->driver->tty_driver;
	dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
		match->port->line;

	return dev->devt == devt; /* Actually, only one tty per port */
}

int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
{
	struct uart_state *state = drv->state + uport->line;
	struct tty_port *port = &state->port;
	struct device *tty_dev;
	struct uart_match match = {uport, drv};

	guard(mutex)(&port->mutex);

	tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port);
	if (tty_dev && device_may_wakeup(tty_dev)) {
		enable_irq_wake(uport->irq);
		put_device(tty_dev);
		return 0;
	}
	put_device(tty_dev);

	/*
	 * Nothing to do if the console is not suspending
	 * except stop_rx to prevent any asynchronous data
	 * over RX line. However ensure that we will be
	 * able to Re-start_rx later.
	 */
	if (!console_suspend_enabled && uart_console(uport)) {
		if (uport->ops->start_rx) {
			guard(uart_port_lock_irq)(uport);
			uport->ops->stop_rx(uport);
		}
		device_set_awake_path(uport->dev);
		return 0;
	}

	uport->suspended = 1;

	if (tty_port_initialized(port)) {
		const struct uart_ops *ops = uport->ops;
		int tries;
		unsigned int mctrl;

		tty_port_set_suspended(port, true);
		tty_port_set_initialized(port, false);

		scoped_guard(uart_port_lock_irq, uport) {
			ops->stop_tx(uport);
			if (!(uport->rs485.flags & SER_RS485_ENABLED))
				ops->set_mctrl(uport, 0);
			/* save mctrl so it can be restored on resume */
			mctrl = uport->mctrl;
			uport->mctrl = 0;
			ops->stop_rx(uport);
		}

		/*
		 * Wait for the transmitter to empty.
		 */
		for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
			msleep(10);
		if (!tries)
			dev_err(uport->dev, "%s: Unable to drain transmitter\n",
				uport->name);

		ops->shutdown(uport);
		uport->mctrl = mctrl;
	}

	/*
	 * Suspend the console device before suspending the port.
	 */
	if (uart_console(uport))
		console_suspend(uport->cons);

	uart_change_pm(state, UART_PM_STATE_OFF);

	return 0;
}

Annotation

Implementation Notes