Uart 架构之美 -- Linux Kernel 实现浅析

【linux kernel】linux 的uart驱动框架分析 本文分析linux的uart框架 阅读详情

一个小小的uart 蕴含了一座金矿,
uart这只麻雀虽小却五脏俱全,no !我看,它定位不是麻雀,是北冥鸿鹄. 哈哈,

以前分析的在这儿,你可以参考
http://blog.youkuaiyun.com/leesagacious/article/details/54670735

先上一幅图.
这里写图片描述

goto的魔力

先来看看这个函数抛异常的 goto
程序可以通过顺序、选择分支和循环三种方式就可以完成了,对吧, 不建议使用goto ?
也不是绝对的吧,goto在某些方面是有积极意义的

<<Structured Programming with go to Statements>> --高纳德

<<C程序设计新思维  P128>>
在出现错误需要执行清理工作时,它比其他替代方案更为清晰     

该作者可能忽略了goto更优秀的一面,Linux Kernel中 大量使用goto.且远不止是执行清理错误的工作这般,

下面是Kernel 中的例子 :
1 : USB Gadget
下面该段代码的具体分析 你看参见以前我的博文
http://blog.youkuaiyun.com/leesagacious/article/details/55804233

/*
    On successful return, the gadget is ready to respond to requests from the host

    该函数返回 0 ,表示gadget功能驱动层、gadget设备层、udc层已经建立好了,
    一个完整的usb驱动已经可以接受主机的枚举了,

    哈哈,这个函数的返回值设计的真是好,debugging的时可以直接作为切入点,

    所以,有时 即使使用工具跟踪分析的再细致,也不如函数给人的直觉来的直接、准确,
    usb_composite_probe() 
    {
        return usb_gadget_probe_driver(gadget_driver);
    }
*/
int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
{
    struct usb_udc      *udc = NULL;
    int         ret;
    if (!driver || !driver->bind || !driver->setup)
        return -EINVAL;

    mutex_lock(&udc_lock);
    list_for_each_entry(udc, &udc_list, list) {
        /* For now we take the first one */
        if (!udc->driver)
            goto found;      // 在这儿 
    }

    pr_debug("couldn't find an available UDC\n");
    mutex_unlock(&udc_lock);
    return -ENODEV;
found:
    ret = udc_bind_to_driver(udc, driver);
    mutex_unlock(&udc_lock);
    return ret;
}

看一个iic的实现
具体代码分析请参见我以前的博文
http://blog.youkuaiyun.com/leesagacious/article/details/50488949

static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
{
    .....
        if (i2c->state == STATE_READ)
            goto prepare_read;
 retry_write:
        if (!is_msgend(i2c)) {
        } else if (!is_lastmsg(i2c)) {
        } else {
            /* send stop */
            s3c24xx_i2c_stop(i2c, 0);
        }
        goto retry_write;
        break;
    case STATE_READ:    
 prepare_read:
        if (is_msglast(i2c)) {

        } else if (is_msgend(i2c)) {
            if (is_lastmsg(i2c)) {
            } else {
            }
        }
        break;
    }
}
所以对于外设read、write函数的读写过程都逃逸不了goto的魔掌,
且在一些优秀的协议中读写过程利用goto与Linux Kernel休眠与唤醒机制相结合,更是让系统大放异彩
你还能说goto只是用来处理错误的吗 ?goto的魔力可见一斑!
DTS 与 Uart

dtsi文件描述的外设是怎么被加载到Linux Kernel中的,启动的时候是怎么枚举的 ?

基础数据结构

uart架构围绕着 三个数据结构的对象为中心,以接口提供的功能为基础,有了原材料之后,Uart开始裂变 …
Figure 1.1
这里写图片描述

struct 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;
};
/*
    对应一个物理上真实的串口
*/
struct uart_port {
    spinlock_t      lock;           
    unsigned long   iobase;         
    unsigned char __iomem   *membase;       
    unsigned int    (*serial_in)(struct uart_port *, int);
    void            (*serial_out)(struct uart_port *, int, int);
    int             (*handle_irq)(struct uart_port *);
    ....
    unsigned int        irq;            
    unsigned long       irqflags;       
    unsigned int        uartclk;        
    unsigned int        fifosize;
    ....
    ....
}
/*
    物理硬件操作的入口函数集合,每个port数据路径都是隔离的,要"串线"可修改上层的线路规程
*/
struct uart_ops {
    unsigned int    (*tx_empty)(struct uart_port *);
    void            (*set_mctrl)(struct uart_port *, unsigned int mctrl);
    int             (*startup)(struct uart_port *);
    void            (*flush_buffer)(struct uart_port *);
    void            (*set_termios)(struct uart_port *, struct ktermios *new,struct ktermios *old);
    void            (*set_ldisc)(struct uart_port *, int new);
    ...
};

不是常说每个port都存在uart_port结构的一个实例,真正对应一个物理串口吗 ?
好,下面就看看Linux Kernel的架构实现

你自己的驱动要想和内核连接起来形成一体,首先你必须"迎合"内核源码的思想,
随便弄上来一个cdev + 一个file_operations + read /write,简约却很简单
直接将接口暴露给kernel的系统调用,那也不是<<大教堂与集市>>中 "减少的不能再少了" 的思想吧.
在夯实的土地上建造茅草屋,那你以后得唱 "茅屋为秋风所破歌"了,亡羊补牢,也许不会再是传说了. 

好,下面这个注册每个端口的函数,就是将UART驱动与kernel联系起来了,与 uart_register_driver函数一样很重要!
都是uart驱动 必须调用的 !

int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport);

欣赏这个函数之前,你必须要明白的一个结构体是 struct uart_state, 它真的太重要了.

The number of uart_state is equals to the number of hardware ports that ard accessed via the driver

1: 什么时候分配的
请移步: http://blog.youkuaiyun.com/leesagacious/article/details/54670735

先看下面的一个结构体

/*
    封装了基础的uart_port.
*/
struct uart_8250_port {
    struct uart_port    port;
    struct timer_list   timer;      /* "no irq" timer */
    .....
};

/*
    好,看 Figure 1.1 中的 * ops,就在这里进行了指向.
*/
serial8250_init(void)
{
    ↓
    static void __init serial8250_isa_init_ports(void)
    {
        ↓
        /* 初始化封装的每一个port.*/
        for (i = 0; i < nr_uarts; i++) {
            /* 获取每一个封装的uart_8250_port,下面进行初始化其维护的资源 */
            struct uart_8250_port *up = &serial8250_ports[i];
            /* 获取基础的uart_port */
            struct uart_port *port = &up->port;
            /* 
                数组的下标就是它的line,这个line很重要,
                遍历数组,用数组下标赋值其对象维护的成员,内核惯用的伎俩!
                类似的如:
                    1 :字符设备的主设备号就是probes[255]数组的下标.
                    2 :http://blog.youkuaiyun.com/leesagacious/article/details/50418197
            */
            port->line = i;
            /* 初始化维护的自旋锁 */
            spin_lock_init(&port->lock);
            /* 初始化维护的定时器 */
            init_timer(&up->timer);   
            /* 超时执行函数 */
            up->timer.function = serial8250_timeout; 
            ....
            /*
              就是上面说的uart_ops,操作硬件的入口函数集,

              你可能会立即联想到那个tty的那个file_operations吧,哈哈!
              在uart框架中,从系统调用的read、write、poll经过 tty维护的tty_fops提供的对应方法
              一直会调用到这里的ops提供的对应的方法,

              一路走来,按照信息流动的过程,分散了关注、松散了耦合,每层功能清晰,专注,
              虽然性能有损耗,但是可以通过缓存来减少影响,
            */
            port->ops = &serial8250_pops;
        }
    }   
}   
线路规程

这里写图片描述

Kernel中uart接口的bluetooth driver初始化分析 在前面几篇文章中,我们把kernel中bluetooth stack相关的初始化分析完成,今天晓东带大家来一起分析uart接口的bluetooth driver的初始化。首先,我们来到kernel/drivers/bluetooth目录,看hci_ldisc.c文件。又见到我们熟悉的module_init: module_init(hci_uart_init);好吧,动手来看吧: stat 阅读详情

相关推荐

Linux下uart开发与core框架源码分析

主要介绍了uart在kernel中相关的代码和使用,包括uart8250 IP硬件驱动框架,serial 串口驱动框架、line desc行规则内核代码逻辑和tty内核软件框架,同时简单介绍了控制台的注册与使用过程,没有深入到console框架。

tang_vincent的博客 1126

Linux内核(二) [ IMX RK ] UART用户层与驱动层调用关系解析(I)

文章目录框架简介结构体之间重要的关联相关结构体解析上层调用open/wirte/read调用流程调用open函数流程 框架简介 在linux系统中,tty表示各种终端。终端通常都跟硬件相对应。下图为tty框架的层次结构 最上面的用户空间会有很多对底层硬件(在本文中就是WK2414 SPI扩UART设备)的操作,像read,write等。用户空间主要是通过设备文件同 tty_core交互,tty_core根据用空间操作的类型再选择跟line discipline和tty_driver也就是serial_co

weixin_43564241的博客 1337

Linux环境下使用轮询方式操作UART

本文介绍Linux环境下使用轮询方式操作UART的方法,实现了串口打开,关闭,发送数据,接收数据功能,还编写测试代码,验证该功能。

mftang的博客 1472

Linux UART 驱动 Part-1 (底层对接)

介绍底层UART驱动

不能让自己太安逸,努力奋斗才是真 853

Linux UART子系统【1】- uart_register_driver驱动

Linux UART子系统【1】- uart_register_driver驱动

m0_46535940的博客 2208

C# NX二次开发:两种过滤器设置方案的实战解析与场景适配

本文深入解析C# NX二次开发中的两种过滤器设置方案:AddFilterHandler回调与MaskTriple属性设置。通过实战案例对比其性能差异与适用场景,帮助开发者根据需求选择最优方案,提升NX插件开发效率与交互体验。特别针对BlockStyler集成场景提供专业建议,是NX二次开发者的实用指南。

weixin_33739646的博客 847

理解UART 子系统:Linux Kernel 4.9.88 中的核心结构体与设计详解

本文详细探讨了 Linux 内核中串口(UART)和 TTY 驱动的核心数据结构及其作用。通过分析 uart_port、uart_driver、tty_port、tty_driver 等关键结构体,阐述了串口硬件配置、驱动信息管理、TTY 端口资源状态维护,以及驱动与设备交互的实现细节。此外,还介绍了 uart_state 和 tty_operations 的核心功能,展示了 UART 与 TTY 子系统如何协同工作,完成设备控制和数据传输任务。

caiji0169的博客 3084

dmx512协议c语言编程,DMX512协议+c程序代码.pdf

DMX512 协议1.协议简介DMX 是Digital MultipleX 的缩写 ,意为多路数字传输。DMX512 控制协议是美国舞台灯光协会(USITT)于1990 年发布的灯光控制器与灯具设备进行数据传输的工业标准 ,全称是 USITT DMX512(1990) ,包括电气特性、数据协议、数据格式等方面的内容。2. 电气特性和物理层2.1. 电气特...

weixin_39928993的博客 2547

Linux kernel 之 uart 驱动解析

uart 是一种非常之常见的总线,比如DEBUG信息输出,小数据量数据传输,485,以及蓝牙的控制,GPS,很多都是通过uart 进行数据传输并进行控制。 在Linux kernel 内部,uart 通常是作为 一个 tty 设备对其进行控制,也是就是一个字符设备文件,可对其进行读写操作。 kernel version 4.4.12 首先先看一下基本的 结构体 和 API 操作。 ...

weixin_30300225的博客 738

车辆TBOX科普 第7次 TBOX技术深度解析:硬件架构与核心组件详解

摘要: TBOX(车载远程信息处理单元)是智能网联汽车的核心组件,承担数据采集、通信连接与安全交互等关键功能。其硬件架构以主控单元为核心,采用ARM架构处理器(如NXP i.MX系列)实现高效能低功耗处理,搭配DDR4/LPDDR5内存保障性能,eMMC/UFS存储确保数据可靠性。设计中需平衡车规级可靠性(AEC-Q100)、EMC兼容性及成本控制,同时集成通信、定位与安全模块。未来趋势聚焦异构计算、先进制程及功能安全(ASIL-D)与信息安全融合,推动TBOX向边缘计算节点演进。该技术是汽车智能化转型的重

IT深耕十余载,大道之简 865

MTK6769平台Type-C充电全解析:从硬件管脚到PD协议实战(Android15环境)

本文深入解析了MTK6769平台在Android 15环境下Type-C充电的完整链路。从硬件管脚(特别是核心的CC引脚)功能与连接,到USB-PD协议报文抓取与实战分析,并结合MTK平台PD芯片驱动与充电IC驱动的软件框架,提供了从硬件设计到软件调试的系统性解决方案和常见问题排查案例。

ol78901234的博客 313

C语言 | goto语句在什么情况下使用?

关于C语言的goto语句存在很多争议,很多书籍都建议“谨慎使用,或者根本不用”。这里先不做过多的讨论,存在即合理,既然是C语言中的一个知识点,我们还是有必要学会使用。先看一些goto如何用: 一、goto的基本语法 goto语句有两部分:goto和标签名。标签的命名规则与变量的命名规则一样。如: goto label; 要让这条语句正常工作,函数还必须包含另一条标为label的语句,该语句以标...

嵌入式大杂烩 1万+

如何用Deep OC-SORT提升多目标跟踪精度?实战配置与性能优化指南

本文是一份针对开发者的Deep OC-SORT多目标跟踪实战指南。详细解析了如何通过部署其核心的“动态外观记忆”与“相机防抖”模块来有效应对遮挡与抖动,从而显著提升跟踪精度与连续性。内容涵盖从环境搭建、参数调优到性能压榨的全流程,并提供针对不同场景的配置建议与工程落地技巧。

f9g0h的博客 670

Linux驱动分析之Uart驱动

前言 之前对Uart驱动的整体架构做了介绍,现在来分析具体的驱动程序。我们以NXP 的 IMX6来进行分析。Uart驱动分析内核:4.20芯片:NXP IMX6...

嵌入式软件开发交流 1万+

openMVS ---dense point cloud(代码理解)

openMVS ---dense point cloud(代码理解)0 代码实现原理1 代码实现步骤1.1 参数传递1.2 loading .mvs数据1.3 稠密重建1.3.0 相关变量及概念1.3.1 ComputeDepthMaps(data) --计算多张深度图1.3.1.1. pre1.3.1.2 为每一张depth map Select view(s) !!!1.3.1.2.1 N neighbors --- global score + filter1.3.1.2.2 MRF ---- t

小rivaaaa的博客 5328

数字电路逻辑与设计实验一 门电路逻辑功能及测试

(1)选二输入四异或门电路 74LS86,按图 1-8 接线,输入端 1、2、4、5 接逻辑开 关(S1~S4),输出端 A、B、Y 接电平显示发光二极管.用六反相器(非门)按图 1-11 接线,输入 80KHz 连续脉冲,用双踪示波器测输入, 输出相位差,计算每个门的平均传输延迟时间的 tpd 值。测试不同的输入组合:对门电路进行全面的测试,尝试不同的输入组合,包括各种可能的逻辑状态。检查门电路的输入:确认门电路的输入是否正确,并且输入信号的电平符合门电路的规格要求。确保输入信号的稳定性和准确性。

欢迎交流学习心得 2万+

linux设备模型之uart驱动架构分析

一:前言 接着前面的终端控制台分析,接下来分析serial的驱动.在linux中,serial也对应着终端,通常被称为串口终端.在shell上,我们看到的/dev/ttyS*就是串口终端所对应的设备节点. 在分析具体的serial驱动之前.有必要先分析uart驱动架构.uart是Universal Asynchronous Receiver and Transmitter的缩写.翻译成

好行者 1887

BPC坏点矫正

whatis the Bad Pixel? 坏点为死点,也就是基本不随照度变化呈现光电线性转换的关系。表现为暗态常亮,亮态常暗。 坏点分类:静态坏点:亮坏点,暗坏点。 动态坏点:在一定像素范围内,该点表现正常,而超过这一范围,该点表现的比周围像素要亮。与sensor ...

camerall 1万+

Linux 虚拟 UART 驱动框架

本文介绍了Linux虚拟UART驱动的开发过程,主要包含以下内容: 驱动整体结构:基于uart_driver、uart_port、uart_ops三大核心模块构建,通过platform_driver和设备树匹配实现。 关键实现细节: 使用环形缓冲区(txbuf/rxbuf)处理数据传输 通过中断模拟机制实现接收功能 提供console支持以接入内核打印输出 创建proc接口用于调试和测试 测试验证方法: 通过proc接口模拟数据收发 支持/dev/ttyVIRT0设备节点 可接收内核printk输出 该驱动

A344567的博客 2023

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

linux设备模型 深入,linux设备模型之uart驱动架构分析

一:前言接着前面的终端控制台分析,接下来分析serial的驱动。在linux中,serial也对应着终端,通常被称为串口终端。在shell上,我们看到的/dev/ttyS*就是串口终端所对应的设备节点。在分析具体的serial驱动之前。有必要先分析uart驱动架构。uart是UniversalAsynchronous Receiver and Transmitter的缩写。翻译成中文即为”通用异步...

weixin_42306055的博客 440

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

RK3399 系列 linux kernel UART

RK3399 系列 linux kernel UART

andyTW3974的博客 1176

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

linux uart串口驱动,X-017-KERNEL-串口驱动开发之uart driver框架

X-017-KERNEL-串口驱动开发之uart driver框架作者:wowo 发布于:2016-11-16 22:09分类:X Project1. 前言本文是“X Project”串口驱动开发的第二篇,将以“bubblegum-96”开发板为例,介绍在linux serial framework的框架下,编写串口driver以及console driver的方法和步骤(暂不涉及实现细节)。注1...

weixin_30663789的博客 406

linux uart寄存器 代替 printk,Dmesg and Linux kernel log

Earlyprintkearlyprintk是Linux内核调试函数,可用于跟踪在初始化常规控制台之前发生的内核问题。Linux内核配置为了启用Earlyprintk功能,Linux内核配置必须使用Linux内核Menuconfig工具(Menuconfig或如何配置内核)选中 CONFIG_DEBUG_LL,CONFIG_STM32MP1_DEBUG_UART和CONFIG_EARLY_PRI...

weixin_39644325的博客 400

嵌入式Linux系统UART驱动移植专题详解(3000+字图文实战指南)

本文系统讲解了嵌入式Linux系统下UART驱动移植的全过程,涵盖从协议原理到实战应用的关键技术点。通过3000+字的深度解析与代码示例,读者可掌握UART驱动开发的核心技能。建议结合具体硬件平台进行实践操作,以应对不同场景下的工程挑战。(注:本文代码基于Linux 5.4内核验证,硬件平台为i.MX6ULL,适用于大多数ARM架构处理器)

SEU123WW的博客 1685
上一篇: DMA - Linux Kernel 实现赏析
下一篇: GIC Interrupt Map --- Linux Kernel 实现赏析
leesagacious
博客等级 码龄12年 146粉丝 179原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值