linux uart驱动

注:该文档对应的linux版本为linux 4.9,以arm AMBA-PL011的uart驱动为例

参考文章:https://blog.csdn.net/lizuobin2/article/details/51773305?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169267158416800192272058%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=169267158416800192272058&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-51773305-null-null.268^v1^koosearch&utm_term=tty&spm=1018.2226.3001.4450

一、uart驱动数据结构及软件分层

1.1 uart软件分层

 

   uart驱动总体可分为三层,用户层提供/dev/ttyS*接口用于读写uart数据。内核层分为tty、uart两部分,uart又分为uart 核心和uart控制器驱动,uart核心体用用于注册uart驱动的接口,uart驱动则负责操作uart控制器。硬件层就是soc上的uart控制器。

 1.2 uart数据结构

  struct uart_port: 代表一个串口

  struct uart_ops: 串口的操作函数

  struct uart_state: 里面包含着uart_port和tty_port

  struct uart_driver: 用于注册uart的结构体,所以控制器共用一个uart_driver

  

 

  

struct uart_driver {
    struct module        *owner;    /* 拥有该uart_driver的模块,一般为THIS_MODULE */
    const char        *driver_name;    /* 串口驱动名,串口设备文件名以驱动名为基础 */
    const char        *dev_name;    /* 串口设备名 */
    int             major;            /* 主设备号 */
    int             minor;            /* 次设备号 */
    int             nr;            /* soc的串口控制器数量 */
    struct console        *cons;    /* 其对应的console.若该uart_driver支持serial console,否则为NULL */
 
    /* 下面这俩,它们应该被初始化为NULL */
    struct uart_state    *state;    /* 这里会一次申请nr个state */
    struct tty_driver    *tty_driver;    /* tty相关 */
};

 

  

struct uart_state {
    struct tty_port        port;

    enum uart_pm_state    pm_state;
    struct circ_buf        xmit;

    atomic_t        refcount;
    wait_queue_head_t    remove_wait;
    struct uart_port    *uart_port;  
};

 

struct uart_port {
    spinlock_t        lock;            /* port lock */
    unsigned long        iobase;            /* io端口基地址(物理) */
    unsigned char __iomem    *membase;        /* io内存基地址(虚拟) */
    unsigned int        (*serial_in)(struct uart_port *, int);
    void            (*serial_out)(struct uart_port *, int, int);
    void            (*set_termios)(struct uart_port *,
                               struct ktermios *new,
                               struct ktermios *old);
    unsigned int        (*get_mctrl)(struct uart_port *);
    void            (*set_mctrl)(struct uart_port *, unsigned int);
    int            (*startup)(struct uart_port *port);
    void            (*shutdown)(struct uart_port *port);
    void            (*throttle)(struct uart_port *port);
    void            (*unthrottle)(struct uart_port *port);
    int            (*handle_irq)(struct uart_port *);
    void            (*pm)(struct uart_port *, unsigned int state,
                      unsigned int old);
    void            (*handle_break)(struct uart_port *);
    int            (*rs485_config)(struct uart_port *,
                        struct serial_rs485 *rs485);
    unsigned int        irq;            /* 中断号 */
    unsigned long        irqflags;        /* 中断标志  */
    unsigned int        uartclk;        /* 串口时钟*/
    unsigned int        fifosize;        /* 串口缓冲区大小 */
    unsigned char        x_char;            /* xon/xoff char */
    unsigned char        regshift;        /* 寄存器位移 */
    unsigned char        iotype;            /* IO访问方式 */
    unsigned char        unused1;

#define UPIO_PORT        (SERIAL_IO_PORT)    /* 8b I/O port access */
#define UPIO_HUB6        (SERIAL_IO_HUB6)    /* Hub6 ISA card */
#define UPIO_MEM        (SERIAL_IO_MEM)        /* driver-specific */
#define UPIO_MEM32        (SERIAL_IO_MEM32)    /* 32b little endian */
#define UPIO_AU            (SERIAL_IO_AU)        /* Au1x00 and RT288x type IO */
#define UPIO_TSI        (SERIAL_IO_TSI)        /* Tsi108/109 type IO */
#define UPIO_MEM32BE        (SERIAL_IO_MEM32BE)    /* 32b big endian */
#define UPIO_MEM16        (SERIAL_IO_MEM16)    /* 16b little endian */

    unsigned int        read_status_mask;    /* 关心 Rx error status */
    unsigned int        ignore_status_mask;    /* 忽略 Rx error status */
    struct uart_state    *state;            /* pointer to parent state */
    struct uart_icount    icount;            /* 串口信息计数器 */

    struct console        *cons;            /* struct console, if any */
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
    unsigned long        sysrq;            /* sysrq timeout */
#endif

    /* flags must be updated while holding port mutex */
    upf_t            flags;

   /*
  ...
  这里省略一些宏定义
  ...
  */
   int hw_stopped; /* sw-assisted CTS flow state */ unsigned int mctrl; /* 当前的Moden 设置 */ unsigned int timeout; /* character-based timeout */ unsigned int type; /* 端口类型 */ const struct uart_ops *ops; unsigned int custom_divisor; unsigned int line; /* 端口索引 */ unsigned int minor; resource_size_t mapbase; /* o内存物理基地址 */ resource_size_t mapsize; struct device *dev; /* parent device */ unsigned char hub6; /* this should be in the 8250 driver */ unsigned char suspended; unsigned char irq_wake; unsigned char unused[2]; struct attribute_group *attr_group; /* port specific attributes */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ struct serial_rs485 rs485; void *private_data; /* generic platform data pointer */ };

 

struct uart_ops {
    unsigned int    (*tx_empty)(struct uart_port *);     /* 串口的Tx FIFO缓存是否为空 */
    void        (*set_mctrl)(struct uart_port *, unsigned int mctrl);    /* 设置串口modem控制 */
    unsigned int    (*get_mctrl)(struct uart_port *);    /* 获取串口modem控制 */
    void        (*stop_tx)(struct uart_port *);        /* 禁止串口发送数据 */
    void        (*start_tx)(struct uart_port *);    /* 使能串口发送数据 */    
    void        (*send_xchar)(struct uart_port *, char ch);    /* 发送xChar */
    void        (*stop_rx)(struct uart_port *);        /* 禁止串口接收数据 */
    void        (*enable_ms)(struct uart_port *);    /* 使能modem的状态信号 */
    void        (*break_ctl)(struct uart_port *, int ctl);    /* 设置break信号 */
    int            (*startup)(struct uart_port *);        /* 启动串口,应用程序打开串口设备文件时,该函数会被调用 */
    void        (*shutdown)(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 *);/* 设置线路规程 */
    void        (*pm)(struct uart_port *, unsigned int state,
                  unsigned int oldstate);    /* 串口电源管理 */
    int        (*set_wake)(struct uart_port *, unsigned int state);
 
    /*
     * Return a string describing the type of the port
     */
    const char *(*type)(struct uart_port *);
 
    /*
     * Release IO and memory resources used by the port.
     * This includes iounmap if necessary.
     */
    void        (*release_port)(struct uart_port *);
 
    /*
     * Request IO and memory resources used by the port.
     * This includes iomapping the port if necessary.
     */
    int        (*request_port)(struct uart_port *);    /* 申请必要的IO端口/IO内存资源,必要时还可以重新映射串口端口 */
    void        (*config_port)(struct uart_port *, int); /* 执行串口所需的自动配置 */
    int        (*verify_port)(struct uart_port *, struct serial_struct *); /* 核实新串口的信息 */
    int        (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLL
    void    (*poll_put_char)(struct uart_port *, unsigned char);
    int        (*poll_get_char)(struct uart_port *);
#endif
};

 

 1.3 uart core层提供的接口函数

  在include/linux/serial_core.h中主要提供了以下几个注册uart的接口函数

  int uart_register_driver(struct uart_driver *uart);  //注册一个串口驱动
  void uart_unregister_driver(struct uart_driver *uart);  //注销一个串口驱动
  int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);  //给驱动添加一个uart_port
  int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);  //移除uart_port

 

二、uart驱动加载

  amba-pl011对应的uart驱动文件为 drivers/tty/serial/amba-pl011.c,然而,该文件中的compatible与设备树中的并不匹配。因为这里不使用compatible匹配,而是使用amba_id匹配,所以串口的初始化入口函数为pl011_probe

  

  这里有一个描述amba-pl011的结构体

struct uart_amba_port {
    struct uart_port    port;
    const u16        *reg_offset;
    struct clk        *clk;
    const struct vendor_data *vendor;
    unsigned int        dmacr;        /* dma control reg */
    unsigned int        im;        /* interrupt mask */
    unsigned int        old_status;
    unsigned int        fifosize;    /* vendor-specific */
    unsigned int        old_cr;        /* state during shutdown */
    bool            autorts;
    unsigned int        fixed_baud;    /* vendor-set fixed baud rate */
    char            type[12];
#ifdef CONFIG_DMA_ENGINE
    /* DMA stuff */
    bool            using_tx_dma;
    bool            using_rx_dma;
    struct pl011_dmarx_data dmarx;
    struct pl011_dmatx_data    dmatx;
    bool            dma_probed;
#endif
};

   这个pl011_probe函数比较简单,就是填充一个这个结构体,最后调用uart_add_one_port函数注册这个uart驱动。其中最重要的就是填充struct uart_port 这个成员,提供uart操作函数。

 

  

  

posted @ 2023-08-14 13:59  YYFaGe  阅读(222)  评论(0编辑  收藏  举报