閱讀119 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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

  上一篇:go EL表達式語言
  下一篇:go [Qt教程] 第48篇 進階(八) 3D繪圖簡介