盡管一個特定的UART設備驅動完全可以按照tty驅動的設計方法來設計,即定義tty_driver並實現tty_operations其中的成員函數,但是Linux已經在文件serial_core.c中實現了UART設備的通用tty驅動層,稱為串口核心層,這樣,UART驅動的主要任務變成了實現serial_core.c中定義的一組uart_xxx接口而非tty_xxx接口。
1.下圖描述了串行系統間的層次結構關系,可以概括為:用戶應用層 --> 線路規划層 --> TTY層 --> 底層驅動層 --> 物理硬件層

2.下圖是串口核心層在整個tty源文件關系及數據流向中的位置:

其中的xxx_uart.c在此處就是drivers/serial/samsung.c和s5pv210.c
3.接口關系:

從接口關系圖可以看出,用戶對uart設備操作的調用關系非常簡單,
file_operations => [tty_ldisc_ops] => tty_operations => uart ops
其中tty_ldisc_ops線路規程並不是必要的,依賴於應用層設置是否使用ldisc處理數據。
4.UART驅動的總圖:

5.uart驅動常用的數據結構表示如下:

6.Uart驅動程序主要圍繞三個關鍵的數據結構展開(include/linux/serial_core.h中定義):
UART特定的驅動程序結構定義:struct uart_driver s3c24xx_uart_drv;
UART端口結構定義: struct s3c24xx_uart_port s3c24xx_serial_ports;
UART相關操作函數結構定義: struct uart_ops s3c24xx_serial_ops;
【1】uart_driver 封裝了tty_driver,使得底層的UART驅動無需關心tty_driver
struct uart_driver { struct module *owner; const char *driver_name; const char *dev_name; int major; int minor; int nr; struct console *cons; /* * these are private; the low level driver should not * touch these; they should be initialised to NULL */ struct uart_state *state; struct tty_driver *tty_driver; };
其中的uart_state是設備私有信息結構體,
在uart_open()中:
tty->driver_data = state;
在其他uart_xxx()中:
struct uart_state *state = tty->driver_data;
就可以獲取設備私有信息結構體。
static struct uart_driver s3c24xx_uart_drv= { .owner =THIS_MODULE, .dev_name = "s3c2440_serial", //具體設備名稱 .nr =CONFIG_SERIAL_SAMSUNG_UARTS, //定義有幾個端口 .cons = S3C24XX_SERIAL_CONSOLE, //console接口 .driver_name =S3C24XX_SERIAL_NAME, //串口名:ttySAC .major =S3C24XX_SERIAL_MAJOR, //主設備號 .minor =S3C24XX_SERIAL_MINOR, //次設備號 };
一個tty驅動必須注冊/注銷tty_driver,而一個UART驅動則變為注冊/注銷uart_driver,使用如下接口:
int uart_register_driver(struct uart_driver *drv);
void uart_unregister_driver(struct uart_driver *drv);
【2】uart_port用於描述一個UART端口(直接對應於一個串口)的I/O端口或者IO內存地址等信息。
struct uart_port { spinlock_t lock; /* port lock */ unsigned long iobase; /* in/out[bwl] */ unsigned char __iomem *membase; /* read/write[bwl] */ unsigned int (*serial_in)(struct uart_port *, int); void (*serial_out)(struct uart_port *, int, int); unsigned int irq; /* irq number */ unsigned long irqflags; /* irq flags */ unsigned int uartclk; /* base uart clock */ unsigned int fifosize; /* tx fifo size */ unsigned char x_char; /* xon/xoff char */ unsigned char regshift; /* reg offset shift */ unsigned char iotype; /* io access style */ unsigned char unused1; #define UPIO_PORT (0) #define UPIO_HUB6 (1) #define UPIO_MEM (2) #define UPIO_MEM32 (3) #define UPIO_AU (4) /* Au1x00 type IO */ #define UPIO_TSI (5) /* Tsi108/109 type IO */ #define UPIO_DWAPB (6) /* DesignWare APB UART */ #define UPIO_RM9000 (7) /* RM9000 type IO */ unsigned int read_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */ struct uart_state *state; /* pointer to parent state */ struct uart_icount icount; /* statistics */ struct console *cons; /* struct console, if any */ #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ) unsigned long sysrq; /* sysrq timeout */ #endif upf_t flags; #define UPF_FOURPORT ((__force upf_t) (1 << 1)) #define UPF_SAK ((__force upf_t) (1 << 2)) #define UPF_SPD_MASK ((__force upf_t) (0x1030)) #define UPF_SPD_HI ((__force upf_t) (0x0010)) #define UPF_SPD_VHI ((__force upf_t) (0x0020)) #define UPF_SPD_CUST ((__force upf_t) (0x0030)) #define UPF_SPD_SHI ((__force upf_t) (0x1000)) #define UPF_SPD_WARP ((__force upf_t) (0x1010)) #define UPF_SKIP_TEST ((__force upf_t) (1 << 6)) #define UPF_AUTO_IRQ ((__force upf_t) (1 << 7)) #define UPF_HARDPPS_CD ((__force upf_t) (1 << 11)) #define UPF_LOW_LATENCY ((__force upf_t) (1 << 13)) #define UPF_BUGGY_UART ((__force upf_t) (1 << 14)) #define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15)) #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16)) #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) /* The exact UART type is known and should not be probed. */ #define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) #define UPF_FIXED_PORT ((__force upf_t) (1 << 29)) #define UPF_DEAD ((__force upf_t) (1 << 30)) #define UPF_IOREMAP ((__force upf_t) (1 << 31)) #define UPF_CHANGE_MASK ((__force upf_t) (0x17fff)) #define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY)) unsigned int mctrl; /* current modem ctrl settings */ unsigned int timeout; /* character-based timeout */ unsigned int type; /* port type */ const struct uart_ops *ops;//UART操作集-------> unsigned int custom_divisor; unsigned int line; /* port index */ resource_size_t mapbase; /* for ioremap */ struct device *dev; /* parent device */ unsigned char hub6; /* this should be in the 8250 driver */ unsigned char suspended; unsigned char unused[2]; void *private_data; /* generic platform data pointer */ };
s3c24xx_uart_port 封裝了uart_port:
struct s3c24xx_uart_port { unsigned char rx_claimed; unsigned char tx_claimed; unsigned int pm_level; unsigned long baudclk_rate; unsigned int rx_irq; unsigned int tx_irq; struct s3c24xx_uart_info *info; struct s3c24xx_uart_clksrc *clksrc; struct clk *clk; struct clk *baudclk; struct uart_port port; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif int channelnum; };
static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { [0] = {//串口0; .port = { .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX0, .uartclk = 0, .fifosize = 16,//定義FIFO緩存區大小 .ops = &s3c24xx_serial_ops,//串口相關操作函數 .flags = UPF_BOOT_AUTOCONF, .line = 0,//線路 } }, [1] = {//串口1; .port = { .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock), .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX1, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, .flags = UPF_BOOT_AUTOCONF, .line = 1, } }, #if CONFIG_SERIAL_SAMSUNG_UARTS > 2 [2] = { .port = { .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock), .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX2, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, .flags = UPF_BOOT_AUTOCONF, .line = 2, } }, #endif #if CONFIG_SERIAL_SAMSUNG_UARTS > 3 [3] = { .port = { .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock), .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX3, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, .flags = UPF_BOOT_AUTOCONF, .line = 3, } } #endif };
在xxx_probe()中:
struct s3c24xx_uart_port *ourport;//s3c24xx_uart_port封裝了uart_port ourport = &s3c24xx_serial_ports[dev->id];//s3c24xx_serial_ports是s3c24xx_uart_port結構體類型的
【3】uart_ops定義了針對UART的一系列操作,
/* * This structure describes all the operations that can be * done on the physical hardware. */ struct uart_ops { unsigned int (*tx_empty)(struct uart_port *); 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 (*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); 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); void (*wake_peer)(struct uart_port *); /* * 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 *); 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 };
//一般來說,實現下面的成員函數是UART驅動的主體工作
static struct uart_ops s3c24xx_serial_ops ={ .pm =s3c24xx_serial_pm, //電源管理函數 .tx_empty = s3c24xx_serial_tx_empty, //檢車發送FIFO緩沖區是否空 .get_mctrl = s3c24xx_serial_get_mctrl, //是否串口流控 .set_mctrl = s3c24xx_serial_set_mctrl, //是否設置串口流控cts .stop_tx =s3c24xx_serial_stop_tx, //停止發送 .start_tx =s3c24xx_serial_start_tx, //啟動發送 .stop_rx =s3c24xx_serial_stop_rx, //停止接收 .enable_ms = s3c24xx_serial_enable_ms, //空函數 .break_ctl = s3c24xx_serial_break_ctl, //發送break信號 .startup =s3c24xx_serial_startup, //串口發送/接收,以及中斷申請初始配置函數 .shutdown = s3c24xx_serial_shutdown, //關閉串口 .set_termios = s3c24xx_serial_set_termios,//串口clk,波特率,數據位等參數設置 .type = s3c24xx_serial_type, // CPU類型關於串口 .release_port =s3c24xx_serial_release_port, //釋放串口 .request_port =s3c24xx_serial_request_port, //申請串口 .config_port = s3c24xx_serial_config_port, //串口的一些配置信息info .verify_port = s3c24xx_serial_verify_port, //串口檢測 .wake_peer = s3c24xx_serial_wake_peer, };
而在serial_core.c中定義了tty_operations的實例,包含uart_open();uart_close();uart_send_xchar()等成員函數,這些函數借助uart_ops結構體中的成員函數來完成具體的操作。
static const struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, .write = uart_write, .put_char = uart_put_char, .flush_chars = uart_flush_chars, .write_room = uart_write_room, .chars_in_buffer= uart_chars_in_buffer, .flush_buffer = uart_flush_buffer, .ioctl = uart_ioctl, .throttle = uart_throttle, .unthrottle = uart_unthrottle, .send_xchar = uart_send_xchar, .set_termios = uart_set_termios, .set_ldisc = uart_set_ldisc, .stop = uart_stop, .start = uart_start, .hangup = uart_hangup, .break_ctl = uart_break_ctl, .wait_until_sent= uart_wait_until_sent, #ifdef CONFIG_PROC_FS .proc_fops = &uart_proc_fops, #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, #ifdef CONFIG_CONSOLE_POLL .poll_init = uart_poll_init, .poll_get_char = uart_poll_get_char, .poll_put_char = uart_poll_put_char, #endif };
從下面的例子中可以看出串口核心層的tty_operations與uart_ops的關系:
/* * This function is used to send a high-priority XON/XOFF character to * the device */ static void uart_send_xchar(struct tty_struct *tty, char ch) { struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; unsigned long flags; if (port->ops->send_xchar)/*如果uart_ops中實現了send_xchar成員函數*/ port->ops->send_xchar(port, ch); else { port->x_char = ch; if (ch) { spin_lock_irqsave(&port->lock, flags); port->ops->start_tx(port); spin_unlock_irqrestore(&port->lock, flags); } } }
這個例子的調用關系如下:
send_xchar ----> uart_send_xchar ----> start_tx ---> s3c24xx_serial_start_tx
