linux serial framework (1) - 概述

  • 了解linux serial framework

1.uart

  串口设备(serial or uart)是TTY设备的一种,Linux kernel为了方便串口驱动的开发,在TTY framework的基础上,封装了一层串口框架(serial framework)。该框架尽可能的屏蔽了TTY有关的技术细节,驱动工程师在编写串口驱动的时候,只需要把精力放在串口以及串口控制器本身即可。

2.软件架构

  Linux kernel serial framework位于“drivers/tty/serial”目录中,其软件架构:
在这里插入图片描述

  • Serial core是Serial framework的核心实现,对上封装、屏蔽TTY的技术细节,对下为具体的串口驱动提供简单、统一的编程API。

  • earlycon(early console)是serial framework中比较新的一个功能,它基于Kernel system console的框架,提供了一种比较简单的控制台实现方式。

  • 最后就是具体的串口驱动(Serial drivers)了。

2.1.功能介绍

  serial core主要实现如下三类功能:

  • 将串口设备有关的物理对象(及其操作方法)封装成一个一个的数据结构,以达到用软件语言描述硬件的目的。

  • 向底层driver提供串口驱动的编程接口。

  • 基于TTY framework所提供的TTY driver的编写规则,将底层driver看到的serial driver,转换为TTY driver,并将所有的serial操作,转换为对应的tty操作。

2.2 关键数据结构

  假如一个soc中有5个串口控制器(也可称作uart控制器),每个uart控制器都可引出一个串口(uart port)。那么:

  • 每个uart控制器,都是一个platform device,它们可由同一个patform driver驱动;

  • 相对于uart控制器实实在在的存在,我们更为熟悉的串口(uart port),可以看作虚拟的设备,serial core将它们抽象为“struct uart_port”,并在platform driver的probe接口中,注册到kernel;

  • 和platform device类似,这些虚拟的串口设备,也可由同一个虚拟的driver驱动,这就是serial core中的“struct uart_driver”。

2.2.1 struct uart_port

  struct uart_port 抽象虚拟的串口设备(具体的串口控制器,则为实实在在的硬件设备),这是一个庞大的数据结构,存放了五花八门的、各式各样的、有新有旧的、有用没有的和串口设备有关的信息,例如(不能全部罗列,大家在写driver的时候,可以有事没事去看看,说不定就有惊喜):

1).最基本、最必须的,需要驱动工程师根据实际的硬件自行填充的字段。

dev,父设备的指针,通常是串口控制器所对应的platform device;

type,该串口的类型,是以PORT_为前缀的一个宏定义,可以根据需要在include/uapi/linux/serial_core.h中定义;

ops,该串口的操作函数集(struct uart_ops类型的指针),具体可参考3.2.3;

iotype,该串口的I/O类型,例如UPIO_MEM32(常用的通过寄存器访问的uart控制器);

mapbase,对应MEM类型的串口,保存它的寄存器基址(物理地址),一般是从DTS中解析得到的

membase,从mapbase ioremap得来(虚拟地址);

irq、irqflags,该串口对应的中断号(以及相应的终端flags), 一般是从DTS中解析得到的;

line,该串口的编号,和字符设备的次设备号等有关。


serial_in,读取该串口的某个寄存器;

serial_out,向该串口的某个寄存器写入某一value;

最后,serial core根据这两个函数指针,封装出两个公共的寄存器访问接口:serial_port_in和serial_port_out,以方便driver使用。

2.2.2. struct uart_ops

  使用struct uart_port抽象串口的同时,serial core将串口有关的操作函数封装在struct uart_ops中,底层驱动根据实际硬件情况,填充这些函数,serial core在合适的时候,帮忙调用。

  因为在历史上,串口设备是一种非常复杂的设备,因此,和struct uart_port类似,struct uart_ops结构也非常庞大,这里简单介绍一些常用的(Documentation/serial/driver):

  startup,打开串口设备的时候,serial core会调用该接口,driver可以在这里进行串口的初始化操作,例如申请中断资源、使能clock、使能接收,等等;

shutdown,startup的反操作,在串口设备被关闭的时候调用;

start_tx,每当有一笔新的数据需要通过串口发送出去的时候,serial core会先把数据保存在TX的buffer中(参考3.2.2的介绍),然后调用start_tx通知driver。driver需要在该接口中,根据当前的状态(TX是否正在进行),决定是否需要发起一次传输;

stop_tx,停止正在进行中的TX;

stop_rx,停止RX;

tx_empty,判断硬件的TX FIFO是否为空,如果是,则返回TIOCSER_TEMT,否则返回0;

set_mctrl,设置modem的control line,可以留空;

set_termios,设置串口的termios(例如波特率、数据位、停止位等)。

2.2.3.struct uart_driver

  按照设备模型的惯例,需要一个和设备对应的、抽象driver数据结构,就是struct uart_driver:

struct uart_driver {
        struct module           *owner;
        const char              *driver_name;
        const char              *dev_name;
        int                      major;
        int                      minor;
        int                      nr;
        struct console          *cons;

        /*
         * these are private; the low level driver should not
         * touch these; they should be initialised to NULL
         */
        struct uart_state       *state;
        struct tty_driver       *tty_driver;
};

3.向具体driver提供的用于编写串口驱动的API

  数据结构抽象完毕后,serial core向下层的driver提供了方便的编程API,主要包括:

3.1.uart driver有关API

int uart_register_driver(struct uart_driver *uart);
void uart_unregister_driver(struct uart_driver *uart);
  • uart_register_driver,将定义并填充好的uart driver注册到kernel中,一般在驱动模块的init接口中被调用。
  • uart_unregister_driver,注销uart driver,在驱动模块的exit接口中被调用。

3.2.uart port有关API

int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_match_port(struct uart_port *port1, struct uart_port *port2);

int uart_suspend_port(struct uart_driver *reg, struct uart_port *port);
int uart_resume_port(struct uart_driver *reg, struct uart_port *port);

static inline int uart_tx_stopped(struct uart_port *port)

extern void uart_insert_char(struct uart_port *port, unsigned int status,
                 unsigned int overrun, unsigned int ch, unsigned int flag);
  • uart_add_one_port、uart_remove_one_port,添加/删除一个uart port,一般在platform driver的probe/remove中被调用。

  • uart_suspend_port、uart_resume_port,suspend/resume uart port,在电源管理状态切换的时候被调用。

  • uart_tx_stopped,判断某一个uart port的tx是否处于停止状态。

  • uart_insert_char,驱动从串口接收到一个字符之后,可以调用该接口把该字符放到RX buffer中(相比tty_insert_flip_char,可以进行一些overrun的处理)。

4.重要结构体关系图
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值