Linux下TTY驅動程序分析
1、tty設備
有串口、usb轉串口、調製解調器(傳統的WinModem類設備)等。Linux-tty驅動程序的核心緊挨在標準字符設備驅動層之下,並體統了一係列的功能,作為接口被終端類型設備使用。內核負責控製通過tty設備的數據流,並且格式化這些數據。為了控製數據流,有許多不同的線路規程(line discipline)可以虛擬地“插入”任何的tty設備上,這由不同的tty線路規程驅動程序實現。tty線路規程的作用是使用特殊的方法,把從用戶或者硬件那裏接受的數據格式化。這種格式化通常使用一些協議來完成轉換,比如PPP或者是藍牙Bluetooth。
2、tty架構圖分析
用戶空間主要是通過設備文件同tty_core交互。tty_core根據用空間操作的類型再選擇跟line discipline和tty_driver交互。例如設置硬件的ioctl指令就直接交給tty_driver處理。Read和write操作就會交給
line discipline處理。Line discipline是線路規程的意思。正如它的名字一樣,它表示的是這條終端”線程”的輸入與輸出規範設置.主要用來進行輸入/輸出數據的預處理。處理之後。就會將數據交給tty_driver。Tty_driver就是終端對應的驅動了。它將字符轉換成終端可以理解的字串,再將其傳給終端設備。
值得注意的是,這個架構沒有為tty_driver提供read操作。也就是說tty_core
和line discipline都沒有辦法從tty_driver裏直接讀終端信息。這是因為tty_driver對應的hardware並不一定是輸入數據和輸出 數據的共同負載者。例如控製終端,輸出設備是顯示器。輸入設備是鍵盤。基於這樣的原理。在line discipline中有一個輸入緩存區。並提供了一個名叫receive_buf()的接口函數。對應的終端設備隻要調用line discipine的receiver_buf函數,將數據寫入到輸入緩存區就可以了。
如果一個設備同時是輸入設備又是輸出設備。那在設備的中斷處理中調用receive_buf()將數據寫入即可。
3、核心結構體
#include <linux/tty_driver.h> struct tty_driver { int magic; /*幻數,通常被設置為TTY_DRIVER_MAGIC。在alloc_tty_driver函數中被初始化*/ struct kref kref; /* Reference management */ struct cdev cdev; struct module *owner;/*驅動模塊的所有者*/ const char *driver_name;/*驅動程序的名稱,在/proc/tty和sysfs中使用*/ const char *name;/*驅動節點的名字*/ int name_base; /*為穿件設備名字而使用的開始編號*/ int major; /*驅動程序的主設備號*/ int minor_start; /*驅動程序使用的最小次設備號*/ int minor_num; /* number of *possible* devices */ int num; /*可以分配給驅動程序次設備號的個數*/ short type; /* type of tty driver */ short subtype; /* subtype of tty driver */ struct ktermios init_termios; /*當被創建時,含有初始值的termios結構*/ int flags; /*驅動程序標誌位*/ struct proc_dir_entry *proc_entry; /*驅動程序的/proc入口結構體*/ struct tty_driver *other; /*指向tty從屬設備驅動程序的指針*/ /* * Pointer to the tty data structures */ struct tty_struct **ttys; struct ktermios **termios; struct ktermios **termios_locked; void *driver_state; /* * Driver methods */ const struct tty_operations *ops; struct list_head tty_drivers; };
#include <linux/tty_driver.h> 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);/*open函數*/ void (*close)(struct tty_struct * tty, struct file * filp);/*close函數*/ void (*shutdown)(struct tty_struct *tty); void (*cleanup)(struct tty_struct *tty); int (*write)(struct tty_struct * tty, const unsigned char *buf, int count);/*write函數*/ 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, unsigned int cmd, unsigned long arg);/*當設備節點的調用ioctl(2)時,該函數被tty核心調用*/ long (*compat_ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); void (*set_termios)(struct tty_struct *tty, struct ktermios * old);/*改變設備的termios設置*/ void (*throttle)(struct tty_struct * tty);/*當tty核心的輸入緩衝區滿的時候,調用該函數。 tty驅動程序將試圖通知設備,不要再發送更多的字符。*/ void (*unthrottle)(struct tty_struct * tty);/*當tty核心的輸入緩衝區被清空是,調用該函數,使能其接受更多的數據*/ void (*stop)(struct tty_struct *tty);/*tty驅動程序將停止向設備發送數據*/ void (*start)(struct tty_struct *tty);/*恢複數據的傳送*/ void (*hangup)(struct tty_struct *tty);/*當tty驅動程序掛起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);/*發送X類型的字符函數。要發送的字符放在ch變量中*/ int (*tiocmget)(struct tty_struct *tty);/*獲得特定tty設備當前的線路設置*/ int (*tiocmset)(struct tty_struct *tty, unsigned int set, unsigned int clear);/*為特定的tty設備設置當前線路*/ int (*resize)(struct tty_struct *tty, struct winsize *ws); int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); int (*get_icount)(struct tty_struct *tty, struct serial_icounter_struct *icount); #ifdef CONFIG_CONSOLE_POLL int (*poll_init)(struct tty_driver *driver, int line, char *options); 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; };
最後更新:2017-04-03 14:54:11