Linux驱动分析之Uart驱动架构

简介: UART设备驱动可以使用tty驱动的框架来实现,但是因为串口之间有共性,所以Linux在tty接口上封装了一层(serial core)。后面我们再拿一篇文章来解释tty驱动,tty其实就是各种终端设备,串口其实也是终端设备。

 Uart体系结构

 

   UART设备驱动可以使用tty驱动的框架来实现,但是因为串口之间有共性,所以Linux在tty接口上封装了一层(serial core)。后面我们再拿一篇文章来解释tty驱动,tty其实就是各种终端设备,串口其实也是终端设备。

   驱动工程师没必要关心上层的流程,只需注册一个uart_driver,并按硬件规范将对应接口函数完成就可以了。

image.gif编辑

上图我们只需要实现xxx_uart.c ,  而我们实现所需要的结构体和函数接口就是由serial_core.c提供。接下来我们来看一下对应的结构体和接口函数。

重要结构体

内核版本:4.20.12

    • uart_driver
    structuart_driver {
    structmodule*owner;
    constchar*driver_name;
    constchar*dev_name; //设备名,即dev下的节点名intmajor;
    intminor;
    intnr;
    structconsole*cons;//console配置,串口作为console时才需要//私有的,底层驱动把它初始化为NULL即可structuart_state*state;
    structtty_driver*tty_driver;
    };

    image.gif

    串口设备也是字符设备,所以看到很多字符设备相关的,console就是控制台,我们平常所使用的debug口就是console。

      • uart_port
      //描述一个UART端口structuart_port {
      spinlock_tlock;      /* port lock */unsignedlongiobase;      /* in/out[bwl] */unsignedchar__iomem*membase;    /* read/write[bwl] */unsignedint    (*serial_in)(structuart_port*, int);
      void      (*serial_out)(structuart_port*, int, int);
      void      (*set_termios)(structuart_port*,
      structktermios*new,
      structktermios*old);
      void      (*set_ldisc)(structuart_port*,
      structktermios*);
      unsignedint    (*get_mctrl)(structuart_port*);
      void      (*set_mctrl)(structuart_port*, unsignedint);
      unsignedint    (*get_divisor)(structuart_port*,
      unsignedintbaud,
      unsignedint*frac);
      void      (*set_divisor)(structuart_port*,
      unsignedintbaud,
      unsignedintquot,
      unsignedintquot_frac);
      int      (*startup)(structuart_port*port);
      void      (*shutdown)(structuart_port*port);
      void      (*throttle)(structuart_port*port);
      void      (*unthrottle)(structuart_port*port);
      //中断处理int      (*handle_irq)(structuart_port*);
      void      (*pm)(structuart_port*, unsignedintstate,
      unsignedintold); //电源管理void      (*handle_break)(structuart_port*);
      //485配置int      (*rs485_config)(structuart_port*,
      structserial_rs485*rs485);
      int      (*iso7816_config)(structuart_port*,
      structserial_iso7816*iso7816);
      unsignedintirq;      /* 中断号 */unsignedlongirqflags;    /* 中断标志  */unsignedintuartclk;    /* 串口时钟 */unsignedintfifosize;    /* tx fifo size */unsignedcharx_char;      /* xon/xoff char */unsignedcharregshift;    /* reg offset shift */unsignedchariotype;      /* io access style */unsignedcharquirks;      /* internal quirks *///省略宏定义....unsignedintread_status_mask;  /* driver specific */unsignedintignore_status_mask;  /* driver specific */structuart_state*state;      /* pointer to parent state */structuart_icounticount;      /* statistics */structconsole*cons;      /* struct console, if any */#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)unsignedlongsysrq;      /* sysrq timeout */#endif/* flags must be updated while holding port mutex */upf_tflags;
      //省略宏定义....upstat_tstatus;
      //省略宏定义....inthw_stopped;    /* sw-assisted CTS flow state */unsignedintmctrl;      /* current modem ctrl settings */unsignedinttimeout;    /* character-based timeout */unsignedinttype;      /* port type */conststructuart_ops*ops;     //串口操作函数unsignedintcustom_divisor;
      unsignedintline;      /* port index */unsignedintminor;
      resource_size_tmapbase;    /* for ioremap */resource_size_tmapsize;
      structdevice*dev;      /* parent device */unsignedcharhub6;      /* this should be in the 8250 driver */unsignedcharsuspended;
      unsignedcharunused[2];
      constchar*name;      /* port name */structattribute_group*attr_group;    /* port specific attributes */conststructattribute_group**tty_groups;  /* all attributes (serial core use only) */structserial_rs485rs485;
      structserial_iso7816iso7816;
      void*private_data;    /* generic platform data pointer */};

      image.gif

      uart_port用于描述一个UART端口的I/O端口或I/O内存地址、FIFO大小、端口类型等信息。这个结构体参数很多,还有很多对串口进行配置的函数。

        • uart_ops
        //物理硬件的所有操作structuart_ops {
        //一些操作函数unsignedint  (*tx_empty)(structuart_port*);//判断发送FIFO是否为空void    (*set_mctrl)(structuart_port*, unsignedintmctrl); //设置控制信息unsignedint  (*get_mctrl)(structuart_port*); //获取当前控制信息void    (*stop_tx)(structuart_port*); //停止txvoid    (*start_tx)(structuart_port*);//启动txvoid    (*throttle)(structuart_port*);//通知串口驱动,线路规程输入缓冲区接近满了void    (*unthrottle)(structuart_port*);//通知串口驱动可以将字符发送到线路规程输入缓冲区void    (*send_xchar)(structuart_port*, charch); //传输高优先级字符,即使端口已停止。void    (*stop_rx)(structuart_port*); //停止Rxvoid    (*enable_ms)(structuart_port*); //使能modem状态中断void    (*break_ctl)(structuart_port*, intctl); //控制中断信号的传输int    (*startup)(structuart_port*); //启动串口void    (*shutdown)(structuart_port*); //关闭串口void    (*flush_buffer)(structuart_port*); //刷新写buffer,复位DMAvoid    (*set_termios)(structuart_port*, structktermios*new,
        structktermios*old); //改变串口参数,包括字长,奇偶校验,停止位。void    (*set_ldisc)(structuart_port*, structktermios*); //通知线路规程改变void    (*pm)(structuart_port*, unsignedintstate,
        unsignedintoldstate); //电源管理//返回一个描述串口类型的字符串constchar*(*type)(structuart_port*);
        //释放IO和内存资源void    (*release_port)(structuart_port*);
        //申请IO和内存资源int    (*request_port)(structuart_port*);
        //配置串口void    (*config_port)(structuart_port*, int);
        int    (*verify_port)(structuart_port*, structserial_struct*);
        int    (*ioctl)(structuart_port*, unsignedint, unsignedlong);
        #ifdef CONFIG_CONSOLE_POLLint    (*poll_init)(structuart_port*);
        void    (*poll_put_char)(structuart_port*, unsignedchar);
        int    (*poll_get_char)(structuart_port*);
        #endif};

        image.gif

        • uart_driver是对tty_driver的封装,uart_driver和platform_driver还是有区别的,因为它并没有probe回调函数。它主要是一些字符设备的信息
        • uart_port用来描述具体的串口,主要是一些串口参数
        • uart_ops就是一些串口的操作函数,和字符设备中的file_operations差不多。


        API函数

        //注册/注销uart_driver到串口核心层intuart_register_driver(structuart_driver*drv)
        voiduart_unregister_driver(structuart_driver*drv)
        //关联具体串口和驱动intuart_add_one_port(structuart_driver*drv, structuart_port*uport)
        //移除串口和驱动的管理intuart_remove_one_port(structuart_driver*drv, structuart_port*uport)

        image.gif

        我们使用到的接口函数很少,所以其实蛮简单的,Linux封装完之后就是填充结构体,然后调用接口注册一下。


        总结

        首先我们要清楚,在底层,Uart驱动是为每个port都分配了缓存空间的。所以应用层读取的都是缓存空间中的。然后uart_driver不能和platform_driver混淆。后面我们分析实例时会发现Uart的驱动是由platform_driver来回调probe的。之前说过,控制器都是使用platform_driver, 串口对于芯片而言,也是一个控制器。


        相关文章
        |
        9天前
        |
        人工智能 运维 安全
        配置驱动的动态 Agent 架构网络:实现高效编排、动态更新与智能治理
        本文所阐述的配置驱动智能 Agent 架构,其核心价值在于为 Agent 开发领域提供了一套通用的、可落地的标准化范式。
        |
        7天前
        |
        人工智能 安全 数据可视化
        配置驱动的动态Agent架构网络:实现高效编排、动态更新与智能治理
        本文系统性地提出并阐述了一种配置驱动的独立运行时Agent架构,旨在解决当前低代码/平台化Agent方案在企业级落地时面临困难,为Agent开发领域提供了一套通用的、可落地的标准化范式。
        配置驱动的动态Agent架构网络:实现高效编排、动态更新与智能治理
        |
        6天前
        |
        数据管理 Linux iOS开发
        Splunk Enterprise 9.4.5 (macOS, Linux, Windows) - 机器数据管理和分析
        Splunk Enterprise 9.4.5 (macOS, Linux, Windows) - 机器数据管理和分析
        31 0
        |
        3月前
        |
        数据可视化 IDE Java
        OneCode图生代码技术深度解析:从可视化设计到注解驱动实现的全链路架构
        OneCode图生代码技术通过可视化设计与Java注解驱动,实现UI到代码的高效转换,支持设计即开发、组件复用与动态加载,提升企业应用开发效率与协作能力。
        OneCode图生代码技术深度解析:从可视化设计到注解驱动实现的全链路架构
        |
        Unix Linux iOS开发
        Splunk Enterprise 10.0.0 (macOS, Linux, Windows) - 搜索、分析和可视化,数据全面洞察平台
        Splunk Enterprise 10.0.0 (macOS, Linux, Windows) - 搜索、分析和可视化,数据全面洞察平台
        52 0
        |
        3月前
        |
        监控 Linux 开发者
        理解Linux操作系统内核中物理设备驱动(phy driver)的功能。
        综合来看,物理设备驱动在Linux系统中的作用是至关重要的,它通过与硬件设备的紧密配合,为上层应用提供稳定可靠的通信基础设施。开发一款优秀的物理设备驱动需要开发者具备深厚的硬件知识、熟练的编程技能以及对Linux内核架构的深入理解,以确保驱动程序能在不同的硬件平台和网络条件下都能提供最优的性能。
        168 0
        |
        7月前
        |
        监控 Linux
        Linux基础:文件和目录类命令分析。
        总的来说,这些基础命令,像是Linux中藏匿的小矮人,每一次我们使用他们,他们就把我们的指令准确的传递给Linux,让我们的指令变为现实。所以,现在就开始你的Linux之旅,挥动你的命令之剑,探索这个充满神秘而又奇妙的世界吧!
        145 19
        |
        10月前
        |
        弹性计算 API 持续交付
        后端服务架构的微服务化转型
        本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
        |
        11月前
        |
        Cloud Native Devops 云计算
        云计算的未来:云原生架构与微服务的革命####
        【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
        258 3