處理過幾個串口的問題,這幾天才稍微有了些時間來整理一下這一塊的東西。
目錄暫時大致分為以下幾部分吧:
0,背景
1,串口驅(qū)動的結(jié)構(gòu)
2,串口驅(qū)動的實現(xiàn)
3,關(guān)于TTY core
---------------------------------------------------------------------------------------------------
0,背景
往常review這塊代碼的時候,經(jīng)常會被linux代碼樹中東一片西一片的uart,tty,serial device的代碼搞的暈頭轉(zhuǎn)向。參照linux的驅(qū)動設備模型,其實串口驅(qū)動被一層層的完美的組裝在一起。
對
于用于,直接接觸的是串口(serial
interface),這是在計算機或嵌入式設備上一種應用非常廣泛的一個設備接口。我們嘴里經(jīng)常嘮叨的UART其實只是串口通信的一種硬件實現(xiàn)方式而
已,只不過最早最廣泛使用的是這一種方式,所以大家聽到的比較多?,F(xiàn)在在串口后面的硬件實現(xiàn)方式越來越多:紅外設備,usb設備等等,口那幾根線后面接的
chip的種類也越來越多,每種片子都對需要不同的驅(qū)動來工作。Linux領域的大師們就根據(jù)這些情況以及發(fā)展趨勢,將一些通用的接口抽象出來,形成一個
支持多種串行通信的子系統(tǒng)-TTY Core,當然也提供了通用的支持linux 設備模型的接口方便編寫符合linux設備模型規(guī)范的驅(qū)動代碼,:).
note:tty并不是完全指代串口的底層抽象,后面會稍加闡述。
1,串口驅(qū)動的結(jié)構(gòu)
對于一般的UART串口,它的實現(xiàn)分為三層,最底層是TTY Core,中間是UART Core,最上層是特定的芯片驅(qū)動。
最上層的驅(qū)動使用UART Core的API簡單直觀的完成設備和驅(qū)動的注冊,UART Core利用TTY Core中API最終實現(xiàn)設備驅(qū)動的注冊。
2,串口驅(qū)動的實現(xiàn)
系統(tǒng)啟動時,tty會作為一個char設備早早的注冊到kernel(driver/char/tty_io.c),因為它是抽象的最純粹的,:)。
UART Core沒有作為一個模塊注冊到kernel,它實現(xiàn)了一些通用的API來供使用到UART的串口設備來調(diào)用。
最
上層的芯片驅(qū)動就根據(jù)芯片的具體特性和參考串行通信的基本模式依賴UART
Core的一些API實現(xiàn)相應的功能供用戶層配置和使用。主要是實現(xiàn)一些tty_operations里面聲明的一些回調(diào)函數(shù),如果使用UART設備,有
一些實現(xiàn)也會在UART Core里面實現(xiàn)。
struct tty_operations {
struct tty_struct * (*lookup)(struct tty_driver *driver,
struct inode *inode, int idx);
int (*install)(struct tty_driver *driver, struct tty_struct *tty);
void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
int (*open)(struct tty_struct * tty, struct file * filp);
void (*close)(struct tty_struct * tty, struct file * filp);
void (*shutdown)(struct tty_struct *tty);
void (*cleanup)(struct tty_struct *tty);
int (*write)(struct tty_struct * tty,
const unsigned char *buf, int count);
int (*put_char)(struct tty_struct *tty, unsigned char ch);
void (*flush_chars)(struct tty_struct *tty);
int (*write_room)(struct tty_struct *tty);
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
void (*stop)(struct tty_struct *tty);
void (*start)(struct tty_struct *tty);
void (*hangup)(struct tty_struct *tty);
int (*break_ctl)(struct tty_struct *tty, int state);
void (*flush_buffer)(struct tty_struct *tty);
void (*set_ldisc)(struct tty_struct *tty);
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
void (*send_xchar)(struct tty_struct *tty, char ch);
int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
int (*resize)(struct tty_struct *tty, struct winsize *ws);
int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options,
void *rx_callback);
int (*poll_get_char)(struct tty_driver *driver, int line);
void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
const struct file_operations *proc_fops;
};
3,關(guān)于TTY core
TTY在linux領域指的是終端,它可以指代任意終端設備,包括串口設備,console設備等等。
在/dev目錄下,大家如果看到ttyS*就表示指代的是串口設備(S'serial' tty),而pty就指的是虛擬/偽終端設備(Pseudo tty)
TTY 子系統(tǒng)使用tty_driver來表示一個在它這個層次抽象出來的設備驅(qū)動,TTY實現(xiàn)了以下API來完成一個終端設備驅(qū)動的注冊:
1)alloc_tty_driver()
2)tty_set_operations():建立tty entry point
3)tty_register_driver()
4)tty_register_device()
這樣讓一個終端驅(qū)動的注冊變的十分清晰。