Linux Kernel(2.6)の実装に関するメモ書き

tty


コンソール関連メモ

[関連ファイル]
char/tty_io.c		TTYドライバ
char/n_tty.c
char/vt.c		仮想コンソール(/dev/ttyN)ドライバ
char/vc_screen.c	仮想コンソールメモリ(/dev/vcsN)ドライバ
video/console/fbcon.c	実際のグラフィックデバイス(FrameBuffer)
video/console/vgacon.c	実際のグラフィックデバイス(VGAテキストコンソール)

[参照]
man console
man console_ioctl
man pts


struct tty_struct  <-- ttyをopenすると作成される
+----------------+
|                |      struct tty_driver
| driver         |----> +------------------+
|                |      |                  |
+----------------+      | open,close,write | <--tty_set_operations()で設定
| ldisc          |      | putchar...       |    tty_register_driver()でtty_driversに登録
|  open,close    |
|  read,write... |
+----------------+
|                |
|                |
+----------------+

struct tty_ldisc tty_ldiscs[NR_LDISCS]
+----------------+
|                | tty_register_ldisc()で登録する
|                |
|                |
+----------------+
|                |
|                |
|                |
+----------------+
	:
	:



struct file_operations tty_fops,console_fops,ptmx_fops
       <--デバイスの種類によりハンドラが若干異なる。

ldiscとdriverの違いは?

tty_init()
	TTYの設定
	cdev_init(&tty_cdev, &tty_fops);
	/dev/tty登録

	Consoleの設定
	cdev_init(&console_cdev, &console_fops);
	/dev/console登録

	PTYの設定
	cdev_init(&ptmx_cdev, &ptmx_fops);
	/dev/ptmx登録

	VT100の設定
	cdev_init(&vc0_cdev, &console_fops);
	Major 4,Minor 0に/dev/vc/0登録
	vty_init()
		vcs_init() - 仮想コンソール初期化
			vcsデバイス登録

		tty_set_operations() - console用tty_driverに tty_operations登録
			static struct tty_operations con_ops = {
			        .open = con_open,
				.close = con_close,
				.write = con_write,
				.write_room = con_write_room,
				.put_char = con_put_char,
				.flush_chars = con_flush_chars,
				.chars_in_buffer = con_chars_in_buffer,
				.ioctl = vt_ioctl,
				.stop = con_stop,
				.start = con_start,
				.throttle = con_throttle,
				.unthrottle = con_unthrottle,
			};

		tty_register_driver() - consoleドライバ登録(Major 4, Minor 1〜)
			tty_driversにチェーンされる

		kbd_init() - KeyBoard初期化
		console_map_init()


console_init()
	tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY)
		tty_ldiscs[]に登録

		struct tty_ldisc tty_ldisc_N_TTY = {
		        TTY_LDISC_MAGIC,        /* magic */
			"n_tty",                /* name */
			0,                      /* num */
			0,                      /* flags */
			n_tty_open,             /* open */
			n_tty_close,            /* close */
			n_tty_flush_buffer,     /* flush_buffer */
			n_tty_chars_in_buffer,  /* chars_in_buffer */
			read_chan,              /* read */
			write_chan,             /* write */
			n_tty_ioctl,            /* ioctl */
			n_tty_set_termios,      /* set_termios */
			normal_poll,            /* poll */
			NULL,                   /* hangup */
			n_tty_receive_buf,      /* receive_buf */
			n_tty_receive_room,     /* receive_room */
			n_tty_write_wakeup      /* write_wakeup */
		};


tty_io.c::    console,ttyの場合
tty_open(struct inode * inode, struct file * filp)
	device = inode->i_rdev

	get_tty_driver()
		tty_driversからdeviceに該当するMajor,Minor#を持つdriverを返す。
		<-- tty_register_driver()で登録されている

	init_dev() - ttyの作成


tty_io.c::     PTYのopenルーチン
ptmx_open(struct inode * inode, struct file * filp)


init_dev() - ttyの作成
	struct tty_structを確保(tty)

	initialize_tty_struct() - tty_structを初期化
			:
		N_TTYのldiscをtty->ldiscに設定
			:

	get_tty_driver()で取得したdriverをtty->driverに設定

	if (driver->type == TTY_DRIVER_TYPE_PTY) { - PTYデバイスなら...
		対向用にもうひとつ struct tty_structを確保(o_tty)
		Master<->Slave逆(driver->other)のものを作成する
		tty->link,o_tty->linkで相互リンクする
	}


/proc/tty/drivers - tty_register_driver()で登録されたドライバ(struct tty_driver)一覧
/dev/tty             /dev/tty        5       0 system:/dev/tty
/dev/console         /dev/console    5       1 system:console
/dev/ptmx            /dev/ptmx       5       2 system
/dev/vc/0            /dev/vc/0       4       0 system:vtmaster
*** ここまでは決め打ちで表示している。***
driver_name	     name	 Major Minor	 type,subtype
serial               /dev/ttyS       4 64-111	 serial
pty_slave            /dev/pts      136 0-1048575 pty:slave  <--unix98_pty_init()で登録
pty_master           /dev/ptm      128 0-1048575 pty:master <--unix98_pty_init()で登録
pty_slave            /dev/ttyp       3 0-255	 pty:slave  <--legacy_pty_init()で登録
pty_master           /dev/pty        2 0-255	 pty:master <--legacy_pty_init()で登録
unknown              /dev/tty        4 1-63	 console    <-- vt.c::vty_init()で登録


tty_io.c::
tty_write()
	do_tty_write()
		(*write)() - (tty->ldisc.write() - write_chan())

n_tty.c::
write_chan()
	tty->driver->write() - 仮想コンソール(/dev/ttyN)だとcon_write()
			       擬似端末(/dev/pts,ptm,ttyp,pty)だとpty_write()

tty_io.c::
tty_read()
	(ld->read)() - read_chan()

n_tty.c::
read_chan()
	@@@@@@@@@@@@@@@@@@

---------------------------------
仮想コンソール


console_struct.h
struct vc vc_cons[currcons] - 仮想コンソール分存在する
+--------------+
|              |
| vc_cols      |コンソールサイズ
| vc_rows      |
|              |        struct consw
| vc_sw        |-----> +-------------+
|              |       |             | <--実際のコンソールデバイスへのハンドラ
+--------------+       | con_init,   |
	:              | con_putc... |
	:


vt.c::
con_write()
	do_con_write()
		:
		scr_writew(val, addr) - 指定アドレスにデータ書き出し
		書き出しアドレスはpos(vc_cons[currcons].d->vc_pos)
		ポインタ更新(pos+2)
		全文字列を書き込み

		FLUSH
			sw->con_putcs() - 実際にH/Wに書き込み
					VGAコンソールはNULL(scr_writew()のみでOK)
					FrameBufferコンソールならfbcon_putcs()


仮想コンソールの切り替え
complete_change_console()
	switch_screen()
		redraw_screen(is_switch=1)

			sw->con_switch()



------------------------------------------------
仮想コンソールメモリ(VCS)

vcs_init()

static struct file_operations vcs_fops = {
        .llseek         = vcs_lseek,
        .read           = vcs_read,
        .write          = vcs_write,
        .open           = vcs_open,
};


---------------------------------
PTY(擬似端末)

telnet <-> ネットワーク <-> telnetd <-> 擬似端末 <-> loginやshell
                                  (Master)    (Slave)
xterm <-> 擬似端末 <-> loginやshell
     (Master)    (Slave)

       擬似端末のマスタとスレーブの両方がオープンされた後は、スレーブは、プ ロ
       セスに対して、実端末 (real terminal) と全く同じインタフェースを提供する。
       スレーブに書かれたデータはマスタ・ディスクリプタに対する入力として扱 わ
       れ、マスタに書かれたデータはスレーブに対する入力として扱われる。

       /dev/pts/1に書き込むと対応するWindowに表示される
       <--対応するMasterから読みだされxtermで表示される?

       実端末(/dev/tty)に書き込むと実際のデバイス(ビデオカード等)に出力される。
       擬似端末(/dev/pts)に書き込んでも実際にはデバイスが存在しないので
       Master(ptm)側に送信されるだけ。
       書き込まれたデータの処理はptmを読みこむアプリケーションに依存する。
       xtermならWindowに表示。telnetdならクライアント側へデータを送る。


legacy_pty_init()
unix98_pty_init()

	tty_struct		name		tty_operations	other
Unix98 PTY
	ptm_driver		/dev/ptm	pty_ops		pts_driver
	pts_driver		/dev/pts	pty_ops		ptm_driver
Legacy PTY
	pty_driver		/dev/pty	pty_ops		pty_slave_driver
	pty_slave_driver	/dev/ttyp	pty_ops		pty_driver

	static struct tty_operations pty_ops = {
	        .open = pty_open,
		.close = pty_close,
		.write = pty_write,
		.write_room = pty_write_room,
		.flush_buffer = pty_flush_buffer,
		.chars_in_buffer = pty_chars_in_buffer,
		.unthrottle = pty_unthrottle,
		.set_termios = pty_set_termios,
	};


pty_write()
	to = tty->link 対向(Master<->Slave)のtty

	to->ldisc.receive_buf() - n_tty_receive_buf()????
		Readバッファにデータ書き込み
		Read待ちのプロセス(tty->read_wait)があればwakeup


対向(Master/Slave)のttyをReadすればデータを取得出来る


N_TTY_BUF_SIZE バッファサイズ
tty->read_buf  Readバッファ
tty->read_head Readバッファオフセット
tty->read_cnt  Readバッファ内のデータサイズ

--------------------
キーボード

kbd_init()
	input_register_handler(&kbd_handler) - ハンドラの登録
		static struct input_handler kbd_handler = {
		        .event          = kbd_event,
			.connect        = kbd_connect,
			.disconnect     = kbd_disconnect,
			.name           = "kbd",
			.id_table       = kbd_ids,
		};

		登録時、.connect(kbd_connect())が呼ばれる



kbd_event() <--呼出し元は?
	kbd_keycode()
		keycode->keysym->typeに変換(文字なのかカーソルキーなのか...他)
		(*k_handler[type])() - 種別に合わせたハンドラを呼出し


k_fn()

k_spec()
	fn_handler[value](vc, regs)

	fn_enter()

	fn_boot_it()
		ctrl_alt_del()
			リブート

k_ascii()




kbd_bh()

最終更新 2006/03/27 14:09:32 - kztomita
(2006/03/27 14:09:32 作成)


リンク
最近更新したページ
検索