文章目录
-
- 简介
- [**Linux UART驱动架构**](#Linux UART驱动架构)
- [POSIX 接口时序图](#POSIX 接口时序图)
-
- open函数
- write/read
-
- [write 函数详细图](#write 函数详细图)
- [read 函数详细图](#read 函数详细图)
- 中断响应
- [8250 驱动源码分析](#8250 驱动源码分析)
- 误码率
简介
bash
$ adb shell dmesg -w | grep uart
[ 0.449574] 394b0000.uart0: ttyS0 at MMIO 0x394b0000 (irq = 72, base_baud = 12500000) is a 16550A
所以 uart 其实就是 16550 芯片, 它是早期 UART 芯片(如 8250)的增强版. 因为 uart 本质是通信协议, 16550 是uart的一种体现
uart 就是一份汽车蓝图, 16550 就是一台做好的汽车

一个标准的16550芯片只能驱动一个独立的UART串口, 一个"8250驱动"可以驱动无数个16550芯片((例如 /dev/ttyS0, /dev/ttyS1, /dev/ttyS2, /dev/ttyS3 每个实例对应一个16550芯片)
现在很少会看到一颗独立的"16550"芯片。它的功能通常作为一个"IP核心"被集成到主板的 SoC 中
Linux中的终端(Terminal)与控制台(Console)的区别
Linux UART驱动架构
架构图
层次结构如下:
-
用户层: 应用程序通过标准 POSIX 接口(open, read, write)操作串口
-
TTY核心层 (关键文件:tty_io.c / n_tty.c / tty_buffer.c ): Linux 对所有终端设备的统一抽象框架,向上承接系统调用,向下对接具体驱动

-
uart 核心层 (关键文件:serial_core.c): 规范所有的UART驱动, 所有的UART驱动都需要实现这套接口规范

-
8250 驱动层 (关键文件:8250_core.c / 8250_port.c / 8250_dma.c ): 实现 16550 兼容 UART 的通用逻辑,是硬件无关的通用 8250 框架 ;
也是一个历史问题, 16550 UART芯片( 16 字节 FIFO)的产生代替了8250 UART 芯片, Linux 8250 驱动经过几十年验证,稳定可靠, 就可以继续使用了, 对于新的IP, 只需要实现一个薄薄的 dw 适配层

-
dw 驱动层 (关键文件:8250_dw.c / 8250_dwlib.c): 适配 Synopsys DesignWare APB UART 硬件 IP 的驱动

数据结构关联
#mermaid-svg-FgFyPSUA8edqPPZv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FgFyPSUA8edqPPZv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FgFyPSUA8edqPPZv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FgFyPSUA8edqPPZv .error-icon{fill:#552222;}#mermaid-svg-FgFyPSUA8edqPPZv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FgFyPSUA8edqPPZv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FgFyPSUA8edqPPZv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FgFyPSUA8edqPPZv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FgFyPSUA8edqPPZv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FgFyPSUA8edqPPZv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FgFyPSUA8edqPPZv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FgFyPSUA8edqPPZv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FgFyPSUA8edqPPZv .marker.cross{stroke:#333333;}#mermaid-svg-FgFyPSUA8edqPPZv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FgFyPSUA8edqPPZv p{margin:0;}#mermaid-svg-FgFyPSUA8edqPPZv g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-FgFyPSUA8edqPPZv g.classGroup text .title{font-weight:bolder;}#mermaid-svg-FgFyPSUA8edqPPZv .cluster-label text{fill:#333;}#mermaid-svg-FgFyPSUA8edqPPZv .cluster-label span{color:#333;}#mermaid-svg-FgFyPSUA8edqPPZv .cluster-label span p{background-color:transparent;}#mermaid-svg-FgFyPSUA8edqPPZv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FgFyPSUA8edqPPZv .cluster text{fill:#333;}#mermaid-svg-FgFyPSUA8edqPPZv .cluster span{color:#333;}#mermaid-svg-FgFyPSUA8edqPPZv .nodeLabel,#mermaid-svg-FgFyPSUA8edqPPZv .edgeLabel{color:#131300;}#mermaid-svg-FgFyPSUA8edqPPZv .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-FgFyPSUA8edqPPZv .label text{fill:#131300;}#mermaid-svg-FgFyPSUA8edqPPZv .labelBkg{background:#ECECFF;}#mermaid-svg-FgFyPSUA8edqPPZv .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-FgFyPSUA8edqPPZv .classTitle{font-weight:bolder;}#mermaid-svg-FgFyPSUA8edqPPZv .node rect,#mermaid-svg-FgFyPSUA8edqPPZv .node circle,#mermaid-svg-FgFyPSUA8edqPPZv .node ellipse,#mermaid-svg-FgFyPSUA8edqPPZv .node polygon,#mermaid-svg-FgFyPSUA8edqPPZv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FgFyPSUA8edqPPZv .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv g.clickable{cursor:pointer;}#mermaid-svg-FgFyPSUA8edqPPZv g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-FgFyPSUA8edqPPZv g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-FgFyPSUA8edqPPZv .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-FgFyPSUA8edqPPZv .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-FgFyPSUA8edqPPZv .dashed-line{stroke-dasharray:3;}#mermaid-svg-FgFyPSUA8edqPPZv .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-FgFyPSUA8edqPPZv #compositionStart,#mermaid-svg-FgFyPSUA8edqPPZv .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #compositionEnd,#mermaid-svg-FgFyPSUA8edqPPZv .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #dependencyStart,#mermaid-svg-FgFyPSUA8edqPPZv .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #dependencyStart,#mermaid-svg-FgFyPSUA8edqPPZv .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #extensionStart,#mermaid-svg-FgFyPSUA8edqPPZv .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #extensionEnd,#mermaid-svg-FgFyPSUA8edqPPZv .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #aggregationStart,#mermaid-svg-FgFyPSUA8edqPPZv .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #aggregationEnd,#mermaid-svg-FgFyPSUA8edqPPZv .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #lollipopStart,#mermaid-svg-FgFyPSUA8edqPPZv .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv #lollipopEnd,#mermaid-svg-FgFyPSUA8edqPPZv .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-FgFyPSUA8edqPPZv .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-FgFyPSUA8edqPPZv .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FgFyPSUA8edqPPZv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FgFyPSUA8edqPPZv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FgFyPSUA8edqPPZv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 管理
关联
操作函数
继承
特定操作
DMA支持
包含
平台数据
包含
1
1
1
1
1
1
1
1
*
1
1
1
0..1
1
1
1
uart_driver
+struct module *owner
+const char *driver_name
+const char *dev_name
+int major
+int minor
+int nr
+struct console *cons
+struct uart_state *state
+struct tty_driver *tty_driver
uart_port
+spinlock_t lock
+unsigned long iobase
+void *membase
+void *serial_out
+unsigned int irq
+unsigned int uartclk
+unsigned int fifosize
+unsigned char iotype
+unsigned char regshift
+int line
+struct device *dev
+const struct uart_ops *ops
+struct uart_state *state
uart_8250_port
+struct uart_port port
+struct timer_list timer
+struct list_head list
+unsigned short capabilities
+unsigned short bugs
+unsigned int tx_loadsz
+unsigned char fcr
+unsigned char ier
+struct uart_8250_dma *dma
+const struct uart_8250_ops *ops
uart_ops
+tx_empty()
+set_mctrl()
+get_mctrl()
+stop_tx()
+start_tx()
+startup()
+shutdown()
+set_termios()
uart_8250_ops
+setup_irq()
+release_irq()
+setup_timer()
uart_8250_dma
+struct dma_chan *rxchan
+struct dma_chan *txchan
+dma_addr_t rx_addr
+dma_addr_t tx_addr
+unsigned int rx_size
+int rx_running
+int tx_running
dw8250_data
+struct uart_8250_port data
+struct clk *clk
+struct clk *pclk
+struct reset_control *rst
+struct notifier_block clk_notifier
+struct work_struct clk_work
+const struct dw8250_platform_data *pdata
+u8 msr_mask_on
+u8 msr_mask_off
dw8250_platform_data
+u32 usr_reg
+u32 cpr_val
+unsigned int quirks
uart_state
+struct tty_port port
+int pm_state
+struct uart_port *uart_port
tty_port
+struct tty_bufhead buf
+struct tty_struct *tty
+struct kref kref
POSIX 接口时序图
open函数
UART 硬件寄存器 DMA 引擎 (dmaengine) Linux 中断子系统 (genirq) 8250 通用层 (8250_port.c / 8250_core.c) Serial Core 层 (serial_core.c) TTY 层 (tty_io.c / tty_port.c) User App UART 硬件寄存器 DMA 引擎 (dmaengine) Linux 中断子系统 (genirq) 8250 通用层 (8250_port.c / 8250_core.c) Serial Core 层 (serial_core.c) TTY 层 (tty_io.c / tty_port.c) User App #mermaid-svg-uDUviqSb2ckE0LoZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uDUviqSb2ckE0LoZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uDUviqSb2ckE0LoZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uDUviqSb2ckE0LoZ .error-icon{fill:#552222;}#mermaid-svg-uDUviqSb2ckE0LoZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uDUviqSb2ckE0LoZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uDUviqSb2ckE0LoZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uDUviqSb2ckE0LoZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uDUviqSb2ckE0LoZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uDUviqSb2ckE0LoZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uDUviqSb2ckE0LoZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uDUviqSb2ckE0LoZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uDUviqSb2ckE0LoZ .marker.cross{stroke:#333333;}#mermaid-svg-uDUviqSb2ckE0LoZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uDUviqSb2ckE0LoZ p{margin:0;}#mermaid-svg-uDUviqSb2ckE0LoZ .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-uDUviqSb2ckE0LoZ text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-uDUviqSb2ckE0LoZ .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-uDUviqSb2ckE0LoZ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-uDUviqSb2ckE0LoZ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-uDUviqSb2ckE0LoZ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-uDUviqSb2ckE0LoZ #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-uDUviqSb2ckE0LoZ .sequenceNumber{fill:white;}#mermaid-svg-uDUviqSb2ckE0LoZ #sequencenumber{fill:#333;}#mermaid-svg-uDUviqSb2ckE0LoZ #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-uDUviqSb2ckE0LoZ .messageText{fill:#333;stroke:none;}#mermaid-svg-uDUviqSb2ckE0LoZ .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-uDUviqSb2ckE0LoZ .labelText,#mermaid-svg-uDUviqSb2ckE0LoZ .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-uDUviqSb2ckE0LoZ .loopText,#mermaid-svg-uDUviqSb2ckE0LoZ .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-uDUviqSb2ckE0LoZ .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-uDUviqSb2ckE0LoZ .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-uDUviqSb2ckE0LoZ .noteText,#mermaid-svg-uDUviqSb2ckE0LoZ .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-uDUviqSb2ckE0LoZ .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-uDUviqSb2ckE0LoZ .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-uDUviqSb2ckE0LoZ .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-uDUviqSb2ckE0LoZ .actorPopupMenu{position:absolute;}#mermaid-svg-uDUviqSb2ckE0LoZ .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-uDUviqSb2ckE0LoZ .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-uDUviqSb2ckE0LoZ .actor-man circle,#mermaid-svg-uDUviqSb2ckE0LoZ line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-uDUviqSb2ckE0LoZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ── 用户态 ── ── TTY / Serial Core 层 ── ── 8250 通用层:默认参数与端口探测 ── opt 特殊芯片唤醒 ── 中断注册 ── ── THRE 行为探测 (检测古董 16550 bug) ── ── 关键寄存器初值 ── ── TX IRQ 探测 (UART_BUG_TXEN) ── ── DMA 通道申请 ── opt up-\>dma 存在 (非 console) ── 仅设置影子寄存器,暂不开中断 ── ── Serial Core:线参数 / 流控 ── opt init_hw \&\& C_BAUD(tty) ── 之后的运行时数据通路 ── open("/dev/ttyS*") 1 uart_open → tty_port_open → uart_port_activate → uart_startup → uart_port_startup 2 uart_change_pm(UART_PM_STATE_ON) get_zeroed_page() 分配 xmit 3 uport->ops->startup() = serial8250_startup() → serial8250_do_startup() L2246 4 填默认 fifosize / tx_loadsz / capabilities mcr = 0 5 set_io_from_upio() 切换 MMIO / PIO 访问函数 6 serial8250_rpm_get(up) Runtime PM 引用 +1 7 PORT_16C950 / DA830 / NPCM 专用复位/唤醒寄存器写序列 8 serial8250_clear_fifos() 写 FCR:清 RX/TX FIFO 并关闭 FIFO 9 读 LSR / RX / IIR / MSR 清挂起中断状态 10 读 LSR 自检 (==0xff → -ENODEV) 11 up->ops->setup_irq() = univ8250_setup_irq() → serial_link_irq_chain() 12 request_irq(port->irq, serial8250_interrupt, IRQF_SHARED?) 13 中断处理函数挂入链 14 写 IER=THRI,udelay(1) 读 IIR (iir1) 15 写 IER=0,再写 IER=THRI udelay(1),读 IIR (iir) 16 写 IER=0 17 若 THRE 不重断言 → up->bugs |= UART_BUG_THRE 18 up->ops->setup_timer(up) 注册兜底轮询 timer 19 写 LCR = WLEN8 (8N1 占位) 20 port->irq 时 mctrl |= TIOCM_OUT2 (PC 风格中断使能门控) 21 serial8250_set_mctrl() 写 MCR (DTR/RTS/OUT1/OUT2/LOOP) 22 写 IER=THRI,读 LSR + IIR 23 写 IER=0 24 根据 LSR_TEMT/IIR_NO_INT 设置/清除 UART_BUG_TXEN 25 再读 LSR / RX / IIR / MSR 清残留状态 lsr_saved_flags = msr_saved_flags = 0 26 serial8250_request_dma(up) 27 dma_request_chan() RX/TX 配置 slave_config 描述符 28 up->ier = UART_IER_RLSI | UART_IER_RDI (真正写 IER 留到 set_termios 开启 FIFO 之后) 29 serial8250_rpm_put(up) 30 return 0 31 uart_change_line_settings() 32 uport->ops->set_termios() = serial8250_do_set_termios() 33 写 LCR = DLAB 进入除数模式 34 写 DLL / DLM (波特率分频器) 35 写 LCR (数据位/校验/停止位/退出 DLAB) 36 写 FCR 使能 FIFO + 设触发阈值 37 写 IER = up->ier 真正打开 RX/THRE/MS 中断 38 完成 39 uart_port_dtr_rts(uport, 1) 40 置 MCR.DTR | MCR.RTS 41 tty_port_set_active(port, 1) 42 open() 返回 fd 43 串口产生中断 (RX/THRE/MS/LSR) 44 serial8250_interrupt() 45 serial8250_handle_irq() → rx_chars / tx_chars / check_modem_status 46 tty_insert_flip_*() / 唤醒 TX 47 read() 返回数据 / write() 继续 48
write/read
硬件层 dw驱动层 (8250_dw.c) 8250驱动层 (8250_port.c) uart核心层 (serial_core.c) tty核心层 (tty_io.c / n_tty.c / tty_buffer.c) 用户层 硬件层 dw驱动层 (8250_dw.c) 8250驱动层 (8250_port.c) uart核心层 (serial_core.c) tty核心层 (tty_io.c / n_tty.c / tty_buffer.c) 用户层 #mermaid-svg-170QnPGZLj9fmHbZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-170QnPGZLj9fmHbZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-170QnPGZLj9fmHbZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-170QnPGZLj9fmHbZ .error-icon{fill:#552222;}#mermaid-svg-170QnPGZLj9fmHbZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-170QnPGZLj9fmHbZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-170QnPGZLj9fmHbZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-170QnPGZLj9fmHbZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-170QnPGZLj9fmHbZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-170QnPGZLj9fmHbZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-170QnPGZLj9fmHbZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-170QnPGZLj9fmHbZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-170QnPGZLj9fmHbZ .marker.cross{stroke:#333333;}#mermaid-svg-170QnPGZLj9fmHbZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-170QnPGZLj9fmHbZ p{margin:0;}#mermaid-svg-170QnPGZLj9fmHbZ .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-170QnPGZLj9fmHbZ text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-170QnPGZLj9fmHbZ .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-170QnPGZLj9fmHbZ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-170QnPGZLj9fmHbZ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-170QnPGZLj9fmHbZ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-170QnPGZLj9fmHbZ #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-170QnPGZLj9fmHbZ .sequenceNumber{fill:white;}#mermaid-svg-170QnPGZLj9fmHbZ #sequencenumber{fill:#333;}#mermaid-svg-170QnPGZLj9fmHbZ #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-170QnPGZLj9fmHbZ .messageText{fill:#333;stroke:none;}#mermaid-svg-170QnPGZLj9fmHbZ .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-170QnPGZLj9fmHbZ .labelText,#mermaid-svg-170QnPGZLj9fmHbZ .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-170QnPGZLj9fmHbZ .loopText,#mermaid-svg-170QnPGZLj9fmHbZ .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-170QnPGZLj9fmHbZ .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-170QnPGZLj9fmHbZ .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-170QnPGZLj9fmHbZ .noteText,#mermaid-svg-170QnPGZLj9fmHbZ .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-170QnPGZLj9fmHbZ .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-170QnPGZLj9fmHbZ .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-170QnPGZLj9fmHbZ .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-170QnPGZLj9fmHbZ .actorPopupMenu{position:absolute;}#mermaid-svg-170QnPGZLj9fmHbZ .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-170QnPGZLj9fmHbZ .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-170QnPGZLj9fmHbZ .actor-man circle,#mermaid-svg-170QnPGZLj9fmHbZ line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-170QnPGZLj9fmHbZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} loop TX FIFO Empty 中断驱动续传 异步路径:中断接收数据 同步路径:用户调用 read() alt Write 流程 Read 流程 write() 系统调用 tty_write() n_tty_write() uart_write() 写入 uart_circ_buf __uart_start() ops->>start_tx() serial8250_start_tx() serial8250_tx_chars() serial_out() 写入 THR/FIFO THRE 中断触发 dw8250_handle_irq() serial8250_handle_irq() serial8250_tx_chars() serial_out() 继续写入 FIFO write() 返回字节数 RDR 数据就绪中断 dw8250_handle_irq() serial8250_handle_irq() serial8250_rx_chars() serial_in() 读取 RBR/FIFO 返回数据字节 uart_insert_char() tty_insert_flip_char() tty_flip_buffer_push() flush_to_ldisc() n_tty_receive_buf() 存入 read_buf read() 系统调用 tty_read() n_tty_read() 从 read_buf 取出数据 copy_to_user() 返回数据
write 函数详细图
硬件层 dw驱动层 (8250_dw.c) 8250驱动层 (8250_core.c) 8250驱动层 (8250_dma.c) 8250驱动层 (8250_port.c) uart核心层 (serial_core.c) tty核心层 (tty_io.c / n_tty.c) 用户层 硬件层 dw驱动层 (8250_dw.c) 8250驱动层 (8250_core.c) 8250驱动层 (8250_dma.c) 8250驱动层 (8250_port.c) uart核心层 (serial_core.c) tty核心层 (tty_io.c / n_tty.c) 用户层 #mermaid-svg-qsflfwpkOBJ5Pxgs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qsflfwpkOBJ5Pxgs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qsflfwpkOBJ5Pxgs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qsflfwpkOBJ5Pxgs .error-icon{fill:#552222;}#mermaid-svg-qsflfwpkOBJ5Pxgs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qsflfwpkOBJ5Pxgs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qsflfwpkOBJ5Pxgs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qsflfwpkOBJ5Pxgs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qsflfwpkOBJ5Pxgs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qsflfwpkOBJ5Pxgs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qsflfwpkOBJ5Pxgs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qsflfwpkOBJ5Pxgs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qsflfwpkOBJ5Pxgs .marker.cross{stroke:#333333;}#mermaid-svg-qsflfwpkOBJ5Pxgs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qsflfwpkOBJ5Pxgs p{margin:0;}#mermaid-svg-qsflfwpkOBJ5Pxgs .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qsflfwpkOBJ5Pxgs text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-qsflfwpkOBJ5Pxgs .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qsflfwpkOBJ5Pxgs .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-qsflfwpkOBJ5Pxgs .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-qsflfwpkOBJ5Pxgs .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-qsflfwpkOBJ5Pxgs #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-qsflfwpkOBJ5Pxgs .sequenceNumber{fill:white;}#mermaid-svg-qsflfwpkOBJ5Pxgs #sequencenumber{fill:#333;}#mermaid-svg-qsflfwpkOBJ5Pxgs #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-qsflfwpkOBJ5Pxgs .messageText{fill:#333;stroke:none;}#mermaid-svg-qsflfwpkOBJ5Pxgs .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qsflfwpkOBJ5Pxgs .labelText,#mermaid-svg-qsflfwpkOBJ5Pxgs .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-qsflfwpkOBJ5Pxgs .loopText,#mermaid-svg-qsflfwpkOBJ5Pxgs .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-qsflfwpkOBJ5Pxgs .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qsflfwpkOBJ5Pxgs .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-qsflfwpkOBJ5Pxgs .noteText,#mermaid-svg-qsflfwpkOBJ5Pxgs .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-qsflfwpkOBJ5Pxgs .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qsflfwpkOBJ5Pxgs .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qsflfwpkOBJ5Pxgs .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qsflfwpkOBJ5Pxgs .actorPopupMenu{position:absolute;}#mermaid-svg-qsflfwpkOBJ5Pxgs .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-qsflfwpkOBJ5Pxgs .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qsflfwpkOBJ5Pxgs .actor-man circle,#mermaid-svg-qsflfwpkOBJ5Pxgs line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-qsflfwpkOBJ5Pxgs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ━━ ① 写入下行路径 ━━ alt PIO:使能 THRI 中断 DMA:直接启动传输 ━━ ② TX 中断处理路径(同前图)━━ alt circ_buf 低于 WAKEUP_CHARS 阈值 alt circ_buf 完全耗尽 alt PIO 模式 DMA 模式 ━━ ③ 唤醒上行路径 ━━ 重复 ① → ② → ③ 直到 所有数据发送完毕 write() 系统调用 tty_write() n_tty_write() uart_write() 拷贝数据到 uart_circ_buf uart_start() → __uart_start() port->ops->start_tx() serial8250_start_tx() serial_out(UART_IER, THRI) writel() 写 IER 寄存器 serial8250_tx_dma() dmaengine_submit() + issue_pending() write() 返回 (数据已进 circ_buf,异步发送) THRE 中断触发 serial8250_interrupt() port->handle_irq() dw8250_handle_irq() serial8250_handle_irq() 读 LSR,识别 THRI serial8250_tx_chars() 从 circ_buf 取数据写 TX FIFO serial_out(UART_TX, char) writel() → TX FIFO uart_write_wakeup() __stop_tx() 清除 IER.THRI,停止 TX 中断 DMA 完成回调 __dma_tx_complete() uart_xmit_advance() 推进 circ_buf.tail uart_write_wakeup() tty_wakeup() wake_up_interruptible(write_wait) 唤醒阻塞在 write() 的进程 n_tty_write() 继续拷贝剩余用户数据到 circ_buf uart_write() 再次写入 port->ops->start_tx() write() 全部返回
read 函数详细图
硬件层 dw驱动层 (8250_dw.c) 8250核心层 (8250_core.c) DMA层 (8250_dma.c) 8250端口层 (8250_port.c) uart核心层 (serial_core.c) tty核心层 (tty_io.c / n_tty.c / tty_buffer.c) 用户层 硬件层 dw驱动层 (8250_dw.c) 8250核心层 (8250_core.c) DMA层 (8250_dma.c) 8250端口层 (8250_port.c) uart核心层 (serial_core.c) tty核心层 (tty_io.c / n_tty.c / tty_buffer.c) 用户层 #mermaid-svg-4Oe2dwzVoQmq9dvY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4Oe2dwzVoQmq9dvY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4Oe2dwzVoQmq9dvY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4Oe2dwzVoQmq9dvY .error-icon{fill:#552222;}#mermaid-svg-4Oe2dwzVoQmq9dvY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4Oe2dwzVoQmq9dvY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4Oe2dwzVoQmq9dvY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4Oe2dwzVoQmq9dvY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4Oe2dwzVoQmq9dvY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4Oe2dwzVoQmq9dvY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4Oe2dwzVoQmq9dvY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4Oe2dwzVoQmq9dvY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4Oe2dwzVoQmq9dvY .marker.cross{stroke:#333333;}#mermaid-svg-4Oe2dwzVoQmq9dvY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4Oe2dwzVoQmq9dvY p{margin:0;}#mermaid-svg-4Oe2dwzVoQmq9dvY .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4Oe2dwzVoQmq9dvY text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-4Oe2dwzVoQmq9dvY .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4Oe2dwzVoQmq9dvY .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-4Oe2dwzVoQmq9dvY .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-4Oe2dwzVoQmq9dvY .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-4Oe2dwzVoQmq9dvY #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-4Oe2dwzVoQmq9dvY .sequenceNumber{fill:white;}#mermaid-svg-4Oe2dwzVoQmq9dvY #sequencenumber{fill:#333;}#mermaid-svg-4Oe2dwzVoQmq9dvY #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-4Oe2dwzVoQmq9dvY .messageText{fill:#333;stroke:none;}#mermaid-svg-4Oe2dwzVoQmq9dvY .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4Oe2dwzVoQmq9dvY .labelText,#mermaid-svg-4Oe2dwzVoQmq9dvY .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-4Oe2dwzVoQmq9dvY .loopText,#mermaid-svg-4Oe2dwzVoQmq9dvY .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-4Oe2dwzVoQmq9dvY .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4Oe2dwzVoQmq9dvY .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-4Oe2dwzVoQmq9dvY .noteText,#mermaid-svg-4Oe2dwzVoQmq9dvY .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-4Oe2dwzVoQmq9dvY .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4Oe2dwzVoQmq9dvY .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4Oe2dwzVoQmq9dvY .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4Oe2dwzVoQmq9dvY .actorPopupMenu{position:absolute;}#mermaid-svg-4Oe2dwzVoQmq9dvY .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-4Oe2dwzVoQmq9dvY .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4Oe2dwzVoQmq9dvY .actor-man circle,#mermaid-svg-4Oe2dwzVoQmq9dvY line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-4Oe2dwzVoQmq9dvY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ━━ ① 用户发起 read()(可能先于数据到达)━━ ━━ ② 硬件接收 + 中断处理路径 ━━ loop 逐字节读取 alt PIO 模式 DMA 模式(非循环) DMA 模式(循环 cyclic) ③ TTY 异步推送路径(workqueue) ④ 用户读取返回路径 read() 系统调用 tty_read() tty_io.c n_tty_read() n_tty.c wait_event_interruptible(read_wait) read_buf 为空则阻塞,等待数据 RDI 中断触发 (RX FIFO 达到触发阈值) serial8250_interrupt() 遍历共享 IRQ 链表 port->>handle_irq() dw8250_handle_irq() 读 IIR,处理 RX_TIMEOUT 虚假中断 serial8250_handle_irq() 读 LSR,识别 RDI / RLSI serial8250_rx_chars() 最多循环 256 次 serial_in(UART_RX) readl() 读 RBR / RX FIFO 返回数据字节 返回 uart_insert_char() tty_insert_flip_char() 写入 flip buffer tty_flip_buffer_push() handle_rx_dma() serial8250_rx_dma() DMA 从 RX FIFO 批量搬运 DMA 完成回调 __dma_rx_complete() 计算实际接收字节数(rx_size - residue) tty_insert_flip_string() 批量写入 flip buffer tty_flip_buffer_push() serial8250_rx_dma_cyclic() prep_dma_cyclic(),持续接收 每 16 字节触发一次周期回调 __dma_rx_complete_cyclic() 处理环形缓冲区 wrap-around tty_insert_flip_string() tty_flip_buffer_push() schedule_work(flush_to_ldisc) 内部调度工作队列 flush_to_ldisc() tty_buffer.c tty_ldisc_receive_buf() n_tty_receive_buf() n_tty.c 行编辑 / 回显 / Ctrl+C 信号生成 数据存入 read_buf wake_up_interruptible(read_wait) 唤醒阻塞在 read() 的进程 n_tty_read() 阻塞解除 从 read_buf 取数据 copy_to_user() read() 返回字节数
中断响应
- TX 中断: 硬件通知驱动 "TX FIFO 空了" , "我发完了,快给我更多数据" , 被动响应,主动填充
- RX 中断: 硬件通知驱动 "RX FIFO 有数据了", "我收到数据了,快来取" , 被动响应,主动读取
uart核心层 (serial_core.c) 8250核心层 (8250_dma.c) 8250核心层 (8250_port.c) 8250核心层 (8250_core.c) dw驱动层 (8250_dw.c) 硬件层 uart核心层 (serial_core.c) 8250核心层 (8250_dma.c) 8250核心层 (8250_port.c) 8250核心层 (8250_core.c) dw驱动层 (8250_dw.c) 硬件层 #mermaid-svg-TYXDZsIHZclBO240{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TYXDZsIHZclBO240 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TYXDZsIHZclBO240 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TYXDZsIHZclBO240 .error-icon{fill:#552222;}#mermaid-svg-TYXDZsIHZclBO240 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TYXDZsIHZclBO240 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TYXDZsIHZclBO240 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TYXDZsIHZclBO240 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TYXDZsIHZclBO240 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TYXDZsIHZclBO240 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TYXDZsIHZclBO240 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TYXDZsIHZclBO240 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TYXDZsIHZclBO240 .marker.cross{stroke:#333333;}#mermaid-svg-TYXDZsIHZclBO240 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TYXDZsIHZclBO240 p{margin:0;}#mermaid-svg-TYXDZsIHZclBO240 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TYXDZsIHZclBO240 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-TYXDZsIHZclBO240 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-TYXDZsIHZclBO240 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-TYXDZsIHZclBO240 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-TYXDZsIHZclBO240 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-TYXDZsIHZclBO240 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-TYXDZsIHZclBO240 .sequenceNumber{fill:white;}#mermaid-svg-TYXDZsIHZclBO240 #sequencenumber{fill:#333;}#mermaid-svg-TYXDZsIHZclBO240 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-TYXDZsIHZclBO240 .messageText{fill:#333;stroke:none;}#mermaid-svg-TYXDZsIHZclBO240 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TYXDZsIHZclBO240 .labelText,#mermaid-svg-TYXDZsIHZclBO240 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-TYXDZsIHZclBO240 .loopText,#mermaid-svg-TYXDZsIHZclBO240 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-TYXDZsIHZclBO240 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-TYXDZsIHZclBO240 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-TYXDZsIHZclBO240 .noteText,#mermaid-svg-TYXDZsIHZclBO240 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-TYXDZsIHZclBO240 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TYXDZsIHZclBO240 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TYXDZsIHZclBO240 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TYXDZsIHZclBO240 .actorPopupMenu{position:absolute;}#mermaid-svg-TYXDZsIHZclBO240 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-TYXDZsIHZclBO240 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TYXDZsIHZclBO240 .actor-man circle,#mermaid-svg-TYXDZsIHZclBO240 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-TYXDZsIHZclBO240 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} loop 最多 tx_loadsz 字节 alt circ_buf 耗尽 还有数据 alt 还有数据 无数据 alt PIO 模式(无 DMA) DMA 模式 THRE 中断触发 serial8250_interrupt() 遍历共享 IRQ 链表 PASS_LIMIT=512 port->>handle_irq() dw8250_handle_irq() 读 IIR,处理 Busy Detect / DMA_FC quirk serial8250_handle_irq() 读 LSR,识别 THRI 中断类型 serial8250_tx_chars() 从 uart_circ_buf 取数据 serial_out(UART_TX, char) dw8250_serial_out32be() port->>serial_out() 函数指针 writel() 写 TX FIFO 寄存器 __stop_tx() 清除 IER.THRI 位,停止 TX 中断 继续等待下次 THRE 中断 serial8250_tx_dma() dma_prep_slave_single() 映射 circ_buf DMA 地址 dmaengine_submit() issue_pending() 启动 DMA 传输 DMA 完成中断回调 __dma_tx_complete() dma_sync_for_cpu() uart_xmit_advance() 推进 circ_buf.tail 指针 uart_write_wakeup() 唤醒上层写等待队列 serial8250_tx_dma() 继续下一批传输 serial8250_set_THRI() 等待下次 THRE 中断触发
8250 驱动源码分析
驱动程序位置:
source/kernel/drivers/tty/serial/8250/8250_core.c
source/kernel/drivers/tty/serial/8250/8250_dma.c
source/kernel/drivers/tty/serial/8250/8250_dw.c
source/kernel/drivers/tty/serial/8250/8250_port.c
source/kernel/drivers/tty/serial/8250/8250_early.c
menuconfig 配置
选择 8250 通用的串口驱动
-> Device Drivers
-> Character devices
-> Enable TTY (TTY =y)
-> Serial drivers
-> 8250/16550 and compatible serial support (SERIAL_8250 =y)

设备树
注意, DTS node 是给 UART 控制器使用的, 而不是外设, UART控制器对于SOC来说, 算一个外设
shell
uart0: uart0 {
power-domains = <&scmi_smc_pd PD_IDX_LSPERI_TOP>;
compatible = "snps,dw-apb-uart";
reg-shift = <2>;
reg-io-width = <4>;
u-boot,dm-pre-reloc;
reg = <0x0 0x394B0000 0x0 0x10000>;
interrupts = <GIC_SPI PERISYS_UART1_INTR PERISYS_UART1_INTR_TRIG_TYPE>;
clock-frequency = <200000000>;
pinctrl-names = "default";
pinctrl-0 = <&peri_uart1>;
hobot,disable_baud_set;
};
和 tty 驱动框架的关系
8250 驱动是 TTY 软件框架中的一个具体组成部分, 在此之前可以先了解一下 TTY 驱动, 这个驱动负责管理所有的终端设备, 包括串口, 虚拟终端, 伪终端(ssh连接)等
txt
+-----------------------------------------------------------------------+
| 用户空间 (User Space) |
| (例如:`echo "hello" > /dev/ttyS0` 或 `minicom`) |
+---------------------------------------------+-------------------------+
|
+---------------------------------------------+-------------------------+
| 内核空间 (Kernel Space) |
+-------------+---------------------------------------------------------+
| | |
| +----------v----------+ |
| | TTY 核心 | <--------- TTY 子系统 (一个框架) ---------+ |
| | (tty_core) | |
| +----------+----------+ |
| | |
| +----------v----------+ |
| | TTY 行规程 | 将原始字符数据加工成一行一行的文本(退格键、回车键等) |
| | (Line Discipline) | (例如:N_TTY(默认), SLIP, PPP) |
| +----------+----------+ |
| | |
| +----------v----------+ |
| | TTY 驱动 | <----- 这一层是8250驱动所在的位置 --------+ |
| | (tty_driver) | |
| | "serial8250" | |
| +----------+----------+ |
| | |
| +----------v---------------------------------------------------------+
| | 硬件层 |
| | (实际的 16550 UART 芯片) |
+-----------------------------------------------------------------------+
- TTY 子系统: TTY子系统负责管理所有的终端设备,包括物理设备(如键盘和显示器),串行设备(如串口),以及虚拟设备(如SSH终端和伪终端)
- line discipline层: 大多数用户都会在输入时犯错,所以退格键会很有用。这当然可以由应用程序本身来实现,但是根据UNIX设计"哲学",应用程序应尽可能保持简单。为了方便起见,操作系统提供了一个编辑缓冲区和一些基本的编辑命令(退格,清除单个单词,清除行,重新打印),这些命令在行规范(line discipline)内默认启用,行规程规定了键盘,串口,打印机,显示器等输入输出设备和用户态Shell等程序之间的行为规范,键盘上的按键事件被行规程解释成了Shell可以理解的输入并给出相应的输出。
- **uart驱动层:**UART驱动程序主要负责底层的硬件操作,包括数据的发送和接收,以及中断的处理等

我们这个串口是一个字符设备。那就是说,应该有类似字符驱动的流程去打开、操作、关闭。字符驱动有主设备号和次设备号,对应我们的串口的话,如下图:

为什么串口是ttyS ?
刚说了, TTY系统管理很多设备, 所以下面是不同设备对应的设备节点

驱动源码分析
设备节点 TTY子系统 UART核心层 DesignWare驱动 平台驱动层 8250_core模块 内核 设备节点 TTY子系统 UART核心层 DesignWare驱动 平台驱动层 8250_core模块 内核 #mermaid-svg-56kKUIMRgu7oCf0e{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-56kKUIMRgu7oCf0e .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-56kKUIMRgu7oCf0e .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-56kKUIMRgu7oCf0e .error-icon{fill:#552222;}#mermaid-svg-56kKUIMRgu7oCf0e .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-56kKUIMRgu7oCf0e .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-56kKUIMRgu7oCf0e .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-56kKUIMRgu7oCf0e .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-56kKUIMRgu7oCf0e .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-56kKUIMRgu7oCf0e .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-56kKUIMRgu7oCf0e .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-56kKUIMRgu7oCf0e .marker{fill:#333333;stroke:#333333;}#mermaid-svg-56kKUIMRgu7oCf0e .marker.cross{stroke:#333333;}#mermaid-svg-56kKUIMRgu7oCf0e svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-56kKUIMRgu7oCf0e p{margin:0;}#mermaid-svg-56kKUIMRgu7oCf0e .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-56kKUIMRgu7oCf0e text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-56kKUIMRgu7oCf0e .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-56kKUIMRgu7oCf0e .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-56kKUIMRgu7oCf0e .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-56kKUIMRgu7oCf0e .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-56kKUIMRgu7oCf0e #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-56kKUIMRgu7oCf0e .sequenceNumber{fill:white;}#mermaid-svg-56kKUIMRgu7oCf0e #sequencenumber{fill:#333;}#mermaid-svg-56kKUIMRgu7oCf0e #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-56kKUIMRgu7oCf0e .messageText{fill:#333;stroke:none;}#mermaid-svg-56kKUIMRgu7oCf0e .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-56kKUIMRgu7oCf0e .labelText,#mermaid-svg-56kKUIMRgu7oCf0e .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-56kKUIMRgu7oCf0e .loopText,#mermaid-svg-56kKUIMRgu7oCf0e .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-56kKUIMRgu7oCf0e .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-56kKUIMRgu7oCf0e .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-56kKUIMRgu7oCf0e .noteText,#mermaid-svg-56kKUIMRgu7oCf0e .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-56kKUIMRgu7oCf0e .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-56kKUIMRgu7oCf0e .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-56kKUIMRgu7oCf0e .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-56kKUIMRgu7oCf0e .actorPopupMenu{position:absolute;}#mermaid-svg-56kKUIMRgu7oCf0e .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-56kKUIMRgu7oCf0e .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-56kKUIMRgu7oCf0e .actor-man circle,#mermaid-svg-56kKUIMRgu7oCf0e line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-56kKUIMRgu7oCf0e :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 驱动初始化阶段 设备探测阶段 - 标准平台设备 设备探测阶段 - DesignWare设备 早期串口初始化(可选) 设备就绪 module_init(serial8250_init) serial8250_isa_init_ports() 初始化serial8250_ports数组 uart_register_driver(&serial8250_reg) 注册TTY驱动 注册成功 返回驱动句柄 platform_driver_register() 注册成功 设备匹配成功 serial8250_probe(pdev) 获取平台数据 配置端口参数 serial8250_register_8250_port(up) 查找可用端口槽 复制端口配置 mctrl_gpio_init() uart_add_one_port(drv, port) 创建设备节点 /dev/ttyS* 创建成功 添加成功 返回端口号 探测成功 DW设备匹配成功 dw8250_probe(pdev) platform_get_resource() devm_ioremap() clk_prepare_enable() dw8250_setup_port() serial8250_register_8250_port(up) 查找可用端口槽 复制端口配置 mctrl_gpio_init() uart_add_one_port(drv, port) 创建设备节点 /dev/ttyS* 创建成功 添加成功 返回端口号 探测成功 early_serial_setup(port) 直接配置端口参数 添加到serial8250_ports register_console() 注册为早期控制台 用户空间可访问

bash
/kernel/drivers/tty/serial/8250/8250_core.c
下面是8250驱动的初始化部分,就是把重要的serial8250_reg驱动(uart_register_driver())注册到uart驱动链表上去.
-
uart_register_driver
参数是一个uart_driver结构体,这个结构体里面又包含uart_state结构体以及tty_driver结构体。申请了一个tty_driver结构体,然后根据传入的uart_driver结构体设置tty_driver结构体;具体流程也可以从图中看到,函数里面首先申请了uart_state和tty_driver,然后设置这个结构体,就是给这个结构体的各个成员赋值,然后还设置他的ops成员,最后是tty_register_driver,但是这个函数进去之后发现,其实条件并不满足,并没有真正注册到内核中,真正注册内核是在下面serial_imx_driver结构体里面的probe函数里面做的
误码率
新思的IP的误码率计算如下:
