蜗窝科技

X-018-KERNEL-串口驱动开发之serial console

wowo · · X Project · 阅读 11412 · 2016年11月存档

1. 前言

本文是“X Project”串口驱动开发的第三篇,在第二篇“uart driver框架[1]”的基础上,实现console驱动,并借助这个过程,理解如下知识:

1)从DTS regs字段中获取设备的I/O基址,并map出来供driver访问。这是device tree最基本的使用场景。

2)从DTS aliases中获取串口的索引号。这是device tree aliases功能的一个应用场景。

3)uart port—>line和console—>index之间的关系。

2. 从DTS regs字段中获取设备的I/O基址

大家应该记得我们在移植串口的“early console[2]”的时候,需要使用UART5的寄存器地址,那时直接在代码中用宏定义出来了,如下:

#define UART5_BASE (0xE012a000)

这种做法有一个明显的缺点:driver不具有通用性,如果寄存器地址换了怎么办?如果换个串口呢?如果同时支持多个串口呢?这时device tree的优势就体现出来了,driver可以在probe的时候动态的从dts中获取当前设备的寄存器地址,步骤如下:

1)在dts文件中增加regs字段

serial5: serial@e012a000 {
compatible = “actions,s900-serial”;

  • reg = <0 0xe012a000 0 0x2000>; /* UART5_BASE */
    };

其格式由dts文件的#address-cells和 #size-cells决定,它们都是2的时候,表示UART5的寄存器从0x00000000e012a000开始,size为0x0000000000002000。

2)在driver probe接口中,以IORESOURCE_MEM为参数,调用platform_get_resource接口,以struct resource的形式,将上面定义的寄存器信息取出来,并保存在uart port的mapbase指针中

  • resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  • if (!resource) {
  • dev_err(&pdev->dev, “No IO memory resource\n”);
  • return -ENODEV;
  • }
  • port->mapbase = resource->start;

其中“IORESOURCE_MEM”表示要获取的资源类型是memory资源,0表示是第一个(如果有多个,可以以此传入1、2等等)。

3)调用devm_ioremap_resource接口,将资源map出来,driver就可以使用了

  • port->membase = devm_ioremap_resource(&pdev->dev, resource);
  • if (IS_ERR(port->membase)) {
  • dev_err(&pdev->dev, “Failed to map memory resource\n”);
  • return PTR_ERR(port->membase);
  • }
  • port->iotype = UPIO_MEM32;

同样,map出来之后,可以保存在uart port的membase指针中,同时需要把iotype设置为UPIO_MEM32。

3. 从DTS aliases中获取串口的索引号

由于linux serial framework允许一个serial driver支持多个uart port,为了方便,我们会为这些串口编号,具体体现在struct uart_port的line变量中,那用什么方法为port->line赋值呢?最好通过device tree,因为这样灵活啊。下面介绍一种通过aliases的方法。

以本文的UART5为例,dts文件中的节点名为:serial@e012a000,为了方便,我们给它添加了一个别名:serial5,这样就可以在别处引用。为了让driver可以获得该串口的编号(5),我们可以在dts中定义一个aliases,如下:

  • aliases {
  • serial5 = &serial5;
  • };

然后,在driver的probe中,调用of_alias_get_id,就可以获得该编号:

  • port->line = of_alias_get_id(pdev->dev.of_node, “serial”);
  • if (port->line < 0) {
  • dev_err(&pdev->dev, “failed to get alias id, errno %d\n”,
  • port->line);
  • return port->line;
  • }

of_alias_get_id的参数为“serial”,就是上面aliases左边除了数字的部分。

注1:大家可以思考一下这种方法的好处。

4. 完善console driver并测试之

1)把console driver的index也改成5

.flags = CON_PRINTBUFFER,

  • .index = -1,
  • .index = 5,
    .data = &owl_serial_driver,

2)实现console driver的write接口

实现方法和[2]中的类似,只不过寄存器的基址是动态map出来的(具体可参考后面的patch文件[3])。另外需要说明的是,driver中的操作对象都是struct uart_port指针,但console的write接口是个例外,它使用struct console指针。也就是说,我们需要一个办法从struct console指针中得到对应的struct uart_port指针。不着急,有办法(代码如下,大家自行理解即可):

static void owl_console_write(struct console *con, const char *s, unsigned n)
{

  • struct uart_driver *driver = con->data;

  • struct uart_port *port = driver->state[con->index].uart_port;

  • uart_console_write(port, s, n, owl_console_putchar);
    }

3)在kernel command line选中我们新增的console

-CONFIG_CMDLINE=“earlycon=owl_serial loglevel=8”
+CONFIG_CMDLINE=“earlycon=owl_serial console=ttyS5 loglevel=8”

4)编译并运行,获得如下打印(early console被禁止了,ttyS5被使能了),console移植成功

[ 0.087281] workingset: timestamp_bits=60 max_order=19 bucket_order=0
[ 0.093281] owl_serial_init
[ 0.096062] owl_serial e012a000.serial: owl_serial_probe
[ 0.101343] e012a000.serial: ttyS5 at MMIO 0xe012a000 (irq = 0, base_baud = 0) is a unknown
[ 0.109656] console [ttyS5] enabled
[ 0.109656] console [ttyS5] enabled
[ 0.116593] bootconsole [owl_serial0] disabled
[ 0.116593] bootconsole [owl_serial0] disabled
[ 0.125468] Failed to find cpu0 device node
[ 0.129593] Unable to detect cache hierarchy from DT for CPU 0
[ 0.135874] Freeing unused kernel memory: 116K (ffffff80081a0000 - ffffff80081bd000)
[ 0.143093] This architecture does not have kernel memory protection.
[ 0.149562] Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.
[ 0.162593] Kernel Offset: disabled
[ 0.166062] Memory Limit: none
[ 0.169093] —[ end Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.

注2:以上过程可参考[3]中的patch文件。

5. 参考文档

[1] X-017-KERNEL-串口驱动开发之uart driver框架

[2] X-012-KERNEL-serial early console的移植

[3] patch文件,https://github.com/wowotechX/linux/commit/9f4d974605fbc9312333f95a0cd2ae1e4f709941

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。

标签:Linuxdriverserialconsolealiases

继续讨论

新讨论请用 GitHub 账号在下方发言——评论会保存在本仓库的 Discussions 里,与站点同寿; 再下方的「历史评论」是原站的只读存档。

评论(1 条,只读存档)

以下为原站的历史评论(只读存档);继续讨论请用上方的评论区。

  • do~best

    [ 0.109656] console [ttyS5] enabled wowo你好,请问串口加载到这一步就算是加载完成了么?可以通过uart吐出log?我调试时已经加载到这里,但是不知道什么原因仍然没有log吐出emmm,求解答