需要平台侧实现 printch
//驱动需要实现的代码
static void pl011_putc(struct uart_port *port, int c)
{
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) // 寄存器在平台相关侧定义,基址有上层传入
;
writeb(c, port->membase + UART01x_DR);
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
;
}
static void pl011_early_write(struct console *con, const char *s, unsigned n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, pl011_putc);
}
static int __init pl011_early_console_setup(struct earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
return -ENODEV;
device->con->write = pl011_early_write;
return 0;
}
// 可见,提供给kernel 的只是一个函数,这个函数的第一个参数是个 earlycon_device 的句柄.
//of_setup_earlycon
// 地址 波特率 iotype 已经从dts众解析且被传入 early_console_dev
//setup(&early_console_dev, NULL); // 该 setup 就是 pl011_early_console_setup.
//register_console(early_console_dev.con);
EARLYCON_DECLARE(pl011, pl011_early_console_setup);
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
// 具体使用的时候会使用 printk ---> early_console_dev->con->write ---> pl011_putc
console 一般用 console_initcall 声明,并在声明函数中 register_console
还可以 在 串口注册的时候 uart_add_one_port ---> register_console
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
static struct console s3c24xx_serial_console;
static int __init s3c24xx_serial_console_init(void)
{
register_console(&s3c24xx_serial_console);
return 0;
}
console_initcall(s3c24xx_serial_console_init);
#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
#else
#define S3C24XX_SERIAL_CONSOLE NULL
#endif
static struct console s3c24xx_serial_console = {
.name = S3C24XX_SERIAL_NAME,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.index = -1,
.write = s3c24xx_serial_console_write,
.setup = s3c24xx_serial_console_setup,
.data = &s3c24xx_uart_drv,
};
控制台也可以在 使用 uart_add_one_port(&amba_reg, &uap->port); 的 时候注册
static struct uart_driver amba_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyAMA",
.dev_name = "ttyAMA",
.major = SERIAL_AMBA_MAJOR,
.minor = SERIAL_AMBA_MINOR,
.nr = UART_NR,
.cons = AMBA_CONSOLE,
};
#define AMBA_CONSOLE (&amba_console)
static struct console amba_console = {
.name = "ttyAMA",
.write = pl011_console_write,
.device = uart_console_device,
.setup = pl011_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &amba_reg,
};
probe
uart_add_one_port(&amba_reg, &uap->port);
register_console
static struct uart_ops s3c24xx_serial_ops = {
.pm = s3c24xx_serial_pm,
.tx_empty = s3c24xx_serial_tx_empty,
.get_mctrl = s3c24xx_serial_get_mctrl,
.set_mctrl = s3c24xx_serial_set_mctrl,
.stop_tx = s3c24xx_serial_stop_tx,
.start_tx = s3c24xx_serial_start_tx,
.stop_rx = s3c24xx_serial_stop_rx,
.break_ctl = s3c24xx_serial_break_ctl,
.startup = s3c24xx_serial_startup,
.shutdown = s3c24xx_serial_shutdown,
.set_termios = s3c24xx_serial_set_termios,
.type = s3c24xx_serial_type,
.release_port = s3c24xx_serial_release_port,
.request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_port,
#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
.poll_get_char = s3c24xx_serial_get_poll_char,
.poll_put_char = s3c24xx_serial_put_poll_char,
#endif
};
// 发
s3c24xx_serial_start_tx
s3c24xx_serial_start_next_tx
s3c24xx_serial_start_tx_pio
s3c24xx_serial_start_tx_dma
wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
// 收
s3c64xx_serial_handle_irq
s3c24xx_serial_rx_chars
s3c24xx_serial_rx_chars_dma
uart_rx_drain_fifo
rd_regb(port, S3C2410_URXH);
s3c24xx_serial_rx_chars_pio
rd_regb(port, S3C2410_URXH);
// 注册
static struct uart_driver s3c24xx_uart_drv = { // 1.
.owner = THIS_MODULE,
.driver_name = "s3c2410_serial",
.nr = CONFIG_SERIAL_SAMSUNG_UARTS,
.cons = S3C24XX_SERIAL_CONSOLE,
.dev_name = S3C24XX_SERIAL_NAME,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { // 2.
[0] = {
.port = { // struct uart_port
.ops = &s3c24xx_serial_ops,
};
probe
uart_register_driver(&s3c24xx_uart_drv); // 1.
ourport = &s3c24xx_serial_ports[index];
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); //2.