1. 程式人生 > >Linux UART介紹

Linux UART介紹

端口 private ioctl pin long form ports 重要 minor

1. UART介紹

UART是一類tty設備, 是一種串行端口終端, 具體可參考<UART接口介紹>
在Linux中UART屬於tty驅動的一部分, 具體實現包括驅動抽象層和硬件實現層

本文主要介紹了UART驅動抽象層, 代碼主要是drivers/tty/serial/serial_core.c

2. UART接口

UART抽象層提供了一系列API供硬件實現層使用, 主要包括

/* 註冊/釋放uart驅動 */
int uart_register_driver(struct uart_driver *drv);
void uart_unregister_driver(struct uart_driver *drv);
/* 添加uart端口/設備 */ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport); int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport); /* 端口掛起和恢復 */ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport); int uart_resume_port(struct uart_driver *drv, struct
uart_port *uport); /* 讀寫相關 */ void uart_write_wakeup(struct uart_port *port); void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag);

uart_register_driver完成了如下事宜
1. 為uart_driver的state(n)分配空間
2. 調用alloc_tty_driver()分配tty_driver、ttys(n)、termios(n)、ports(n)、cdevs(n), 並初始化tty_driver的magic、num、owner、flags
3. 從uart_driver對應變量賦值tty_driver的driver_name、name、major、minor_start
4. 設置tty_driver的type為TTY_DRIVER_TYPE_SERIAL, subtype為SERIAL_TYPE_NORMAL
5. 設置tty_driver的init_termios為tty_std_termios, 並定制init_termios的c_cflag和c_ispeed
6. 設置tty_driver的flags為TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
7. 設置tty_driver的driver_state指向uart私有數據uart_driver
8. 調用tty_set_operations將uart_ops賦值給tty_driver的ops
9. 調用tty_port_init初始化state的port, 即tty_port結構體, 並將uart_port_ops賦值給tty_port的ops
10. 調用tty_register_driver註冊tty驅動

uart_unregister_driver完成了如下事宜
1. 調用tty_unregister_driver註銷tty驅動
2. 調用put_tty_driver釋放驅動
3. 調用tty_port_destroy銷毀state的tty_port

3. UART數據結構

UART抽象層包含如下幾個重要數據結構

uart_driver是uart的私有驅動結構, 包括一些和tty_driver相同的變量和uart相關的變量

struct uart_driver {
    struct module     *owner;
    const char        *driver_name;        /* 驅動名稱, 如serial */
    const char        *dev_name;           /* 設備名稱, 如ttyS, 體現到/dev/文件系統下 */ 
    int               major;               /* 主設備號, 如TTY_MAJOR */ 
    int               minor;               /* 次設備號 */ 
    int               nr;                  /* 串口設備數 */ 
    struct console    *cons;               /* 控制臺設備 */ 
    struct uart_state    *state;           /* 串口狀態 */ 
    struct tty_driver    *tty_driver;      /* tty驅動 */ 
};

uart_port用於描述串口端口的物理信息, 如I/O端口或I/O內存地址、FIFO大小、端口類型、串口時鐘等
其中, 一個uart_port實例對應一個串口設備

struct uart_port {
    spinlock_t               lock;              /* port lock */
    unsigned long            iobase;            /* io端口基地址 */
    unsigned char __iomem    *membase;          /* 內存端口基地址 */
    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;               /* fifo大小 */
    unsigned char      x_char;                 /* xon/xoff char */
    unsigned char      regshift;               /* 寄存器偏移值 */
    unsigned char      iotype;                 /* io訪問類型 */
    unsigned char      unused1;

    unsigned int         read_status_mask;    /* driver specific */
    unsigned int         ignore_status_mask;  /* driver specific */
    struct uart_state    *state;              /* 指向對用uart_state */
    struct uart_icount   icount;              /* 串口使用計數 */

    struct console       *cons;               /* 控制臺設備 */
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
    unsigned long        sysrq;               /* sysrq timeout */
#endif
    upf_t                flags;
    upstat_t             status;
    int                  hw_stopped;          /* sw-assisted CTS flow state */
    unsigned int         mctrl;               /* 當前的串口控制設置 */
    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;             /* 串口寄存器基地址 */
    resource_size_t      mapsize;
    struct device        *dev;                /* 父設備 */
    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;           /* 端口私有數據, 一般為platform數據指針 */
};

uart_ops是uart端口操作集, 與硬件相關

struct uart_ops {
    unsigned int  (*tx_empty)(struct uart_port *);              /* 發送FIFO緩沖區是否為空 */
    void          (*set_mctrl)(struct uart_port *, unsigned int mctrl);  /* 設置串口控制模式 */
    unsigned int  (*get_mctrl)(struct uart_port *);             /* 獲取串口控制模式 */
    void          (*stop_tx)(struct uart_port *);               /* 停止發送 */
    void          (*start_tx)(struct uart_port *);              /* 開始發送 */
    void          (*throttle)(struct uart_port *);              /*  */
    void          (*unthrottle)(struct uart_port *);            /*  */
    void          (*send_xchar)(struct uart_port *, char ch);   /*  */
    void          (*stop_rx)(struct uart_port *);               /* 停止接收 */
    void          (*enable_ms)(struct uart_port *);             /* 串口狀態使能使能 */
    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 *, struct ktermios *);   /* 設置線路規程 */
    void          (*pm)(struct uart_port *, unsigned int state, 
                                    unsigned int oldstate);     /* 電源管理 */ 
    void          (*wake_peer)(struct uart_port *);             /*  */

    const char    *(*type)(struct uart_port *);                 /* 端口描述符 */
    void          (*release_port)(struct uart_port *);          /* 釋放端口物理資源 */
    int           (*request_port)(struct uart_port *);          /* 申請端口物理資源 */
    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
    int           (*poll_init)(struct uart_port *);
    void          (*poll_put_char)(struct uart_port *, unsigned char);
    int           (*poll_get_char)(struct uart_port *);
#endif
};

4. uart驅動編寫

uart驅動的編寫主要步驟如下:

1. 定義uart_driver結構體, 實現driver_name、dev_name、nr、cons、major、minor等
2. 定義並實現uart_ops結構體
3. 調用uart_register_driver註冊uart驅動
4. 調用uart_add_one_port添加uart端口

Linux UART介紹