キーボード入力の旅/Linuxとキーボード入力
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
#contents
*はじめに [#dfcc18a9]
ここではキーボード入力に対してOSがどういう処理を行ってい...
-キーボードが押されたときのハンドリング
-デバイスファイルからの読み込み
なお、プラットフォームはx86、キーボードはPS/2接続とします。
*前提知識、というか深く突っ込まないこと [#ve1207ab]
以下のものは多分こんな風に動くんだろうなぁということで実...
-モジュールの初期化、ドライバの初期化順序
-ファイル操作の実装
-遅延処理とか
-いろんなデータ構造
*キーボード入力の処理(ハードウェア寄り) [#c58886c7]
キーボードの処理をやっていそうなコードを探すとdrivers/inp...
$ dmesg
...
input: AT Translated Set 2 keyboard as /class/input/input0
module_init()ではatkbd_initが指定されているので見てみると...
次にdrivers/input/serio/serio.cを見るとロード時にkseriod...
というわけでserio_event_listにエントリを追加しているとこ...
serio_queue_event()
↑serio_rescan()
↑serio_interrupt()
というフローがあるようですが、serio_interrupt()では、
if (likely(serio->drv)) {
ret = serio->drv->interrupt(serio, data, dfl);
} else if (!dfl && serio->registered) {
serio_rescan(serio);
ret = IRQ_HANDLED;
}
となっているのでドライバが設定されていればserio_event_lis...
さて次にserio_interrupt()が誰に呼ばれるかですがgrepしてみ...
atkbd.cに戻って、serio_interrupt()から呼ばれるatkbd_inter...
input_event(dev, EV_KEY, keycode, value);
というわけでキーボードが押されたことによって発生した割り...
*キーボード入力の処理(ソフトウェア寄り、トップハーフ部分...
drivers/input/input.cを見ると
input_event()
→input_handle_event(type=EV_KEY)
→input_pass_event()
と処理が進んでいます。で、input_handlerに処理を渡していま...
error = input_register_handler(&kbd_handler);
としているのでこのファイルがキーボードの入力イベントを処...
というわけでevent関数として設定されているkbd_event()→kbd_...
ushort *key_maps[MAX_NR_KEYMAPS] = {
plain_map, shift_map, altgr_map, NULL,
ctrl_map, shift_ctrl_map, NULL, NULL,
alt_map, NULL, NULL, NULL,
ctrl_alt_map, NULL
};
u_short plain_map[NR_KEYS] = {
0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035,...
...
};
実際の入力を考えないとわからないので'1'を入力したとしまし...
k_self()→k_unicode()と進んで、キーボードがユニコードモー...
static void put_queue(struct vc_data *vc, int ch)
{
struct tty_struct *tty = vc->vc_tty;
if (tty) {
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
}
}
tty_insert_flip_char()はinclude/linux/tty_flip.hに書かれ...
static inline int tty_insert_flip_char(struct tty_struct...
unsigned char ch, char flag)
{
struct tty_buffer *tb = tty->buf.tail;
if (tb && tb->used < tb->size) {
tb->flag_buf_ptr[tb->used] = flag;
tb->char_buf_ptr[tb->used++] = ch;
return 1;
}
return tty_insert_flip_string_flags(tty, &ch, &flag, 1);
}
con_schedule_flip()はinclude/linux/kbd_kern.hに書かれてい...
static inline void con_schedule_flip(struct tty_struct *t)
{
unsigned long flags;
spin_lock_irqsave(&t->buf.lock, flags);
if (t->buf.tail != NULL)
t->buf.tail->commit = t->buf.tail->used;
spin_unlock_irqrestore(&t->buf.lock, flags);
schedule_delayed_work(&t->buf.work, 0);
}
というわけで、以降の処理は遅延実行されるみたいです。
*キーボード入力の処理(ボトムハーフ部分) [#n1c42280]
ttyの処理をやってそうなコードを探すとdrivers/char/tty_io....
static void initialize_tty_struct(struct tty_struct *tty)
{
...
INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
flush_to_ldiscに進む前にinitialize_tty_structが呼ばれるま...
initialize_tty_struct()
↑init_dev()
↑tty_open()
となっています。次に、tty_openはtty_fopsのopenとして指定...
static const struct file_operations tty_fops = {
.open = tty_open,
...
};
でもって、tty_fopsは/dev/ttyに関連付けられています。
static int __init tty_init(void)
{
cdev_init(&tty_cdev, &tty_fops);
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "...
panic("Couldn't register /dev/tty driver\n");
device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), ...
それではflush_to_ldiscを眺めます。重要なのは、
disc->receive_buf(tty, char_buf, flag_buf, count);
の一行です。で、ldiscって何が設定されてるの?というと、
static void initialize_tty_struct(struct tty_struct *tty)
{
memset(tty, 0, sizeof(struct tty_struct));
tty->magic = TTY_MAGIC;
tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
void __init console_init(void)
{
/* Setup the default TTY line discipline. */
(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
というわけでtty_ldisc_N_TTYが設定されているようです。tty_...
*キーボード入力の読み込み [#ab76bf01]
さて、ここまで読めばもう大体わかりますが、デバイスファイ...
tty_read() [drivers/char/tty_io.c]
→read_chan() [drivers/char/n_tty.c]
と進んでバッファに格納された値が読み込まれるようです。な...
*おわりに [#z6c30623]
今回はキーボード入力をLinuxがどのように処理しているか見て...
-ハードウェア的な入力とソフトウェア的な入力というレイヤー...
-ttyバッファへの格納はボトムハーフで行われている
とりあえずこれで、GUIからトップダウンに眺めてきたキーボー...
終了行:
#contents
*はじめに [#dfcc18a9]
ここではキーボード入力に対してOSがどういう処理を行ってい...
-キーボードが押されたときのハンドリング
-デバイスファイルからの読み込み
なお、プラットフォームはx86、キーボードはPS/2接続とします。
*前提知識、というか深く突っ込まないこと [#ve1207ab]
以下のものは多分こんな風に動くんだろうなぁということで実...
-モジュールの初期化、ドライバの初期化順序
-ファイル操作の実装
-遅延処理とか
-いろんなデータ構造
*キーボード入力の処理(ハードウェア寄り) [#c58886c7]
キーボードの処理をやっていそうなコードを探すとdrivers/inp...
$ dmesg
...
input: AT Translated Set 2 keyboard as /class/input/input0
module_init()ではatkbd_initが指定されているので見てみると...
次にdrivers/input/serio/serio.cを見るとロード時にkseriod...
というわけでserio_event_listにエントリを追加しているとこ...
serio_queue_event()
↑serio_rescan()
↑serio_interrupt()
というフローがあるようですが、serio_interrupt()では、
if (likely(serio->drv)) {
ret = serio->drv->interrupt(serio, data, dfl);
} else if (!dfl && serio->registered) {
serio_rescan(serio);
ret = IRQ_HANDLED;
}
となっているのでドライバが設定されていればserio_event_lis...
さて次にserio_interrupt()が誰に呼ばれるかですがgrepしてみ...
atkbd.cに戻って、serio_interrupt()から呼ばれるatkbd_inter...
input_event(dev, EV_KEY, keycode, value);
というわけでキーボードが押されたことによって発生した割り...
*キーボード入力の処理(ソフトウェア寄り、トップハーフ部分...
drivers/input/input.cを見ると
input_event()
→input_handle_event(type=EV_KEY)
→input_pass_event()
と処理が進んでいます。で、input_handlerに処理を渡していま...
error = input_register_handler(&kbd_handler);
としているのでこのファイルがキーボードの入力イベントを処...
というわけでevent関数として設定されているkbd_event()→kbd_...
ushort *key_maps[MAX_NR_KEYMAPS] = {
plain_map, shift_map, altgr_map, NULL,
ctrl_map, shift_ctrl_map, NULL, NULL,
alt_map, NULL, NULL, NULL,
ctrl_alt_map, NULL
};
u_short plain_map[NR_KEYS] = {
0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035,...
...
};
実際の入力を考えないとわからないので'1'を入力したとしまし...
k_self()→k_unicode()と進んで、キーボードがユニコードモー...
static void put_queue(struct vc_data *vc, int ch)
{
struct tty_struct *tty = vc->vc_tty;
if (tty) {
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
}
}
tty_insert_flip_char()はinclude/linux/tty_flip.hに書かれ...
static inline int tty_insert_flip_char(struct tty_struct...
unsigned char ch, char flag)
{
struct tty_buffer *tb = tty->buf.tail;
if (tb && tb->used < tb->size) {
tb->flag_buf_ptr[tb->used] = flag;
tb->char_buf_ptr[tb->used++] = ch;
return 1;
}
return tty_insert_flip_string_flags(tty, &ch, &flag, 1);
}
con_schedule_flip()はinclude/linux/kbd_kern.hに書かれてい...
static inline void con_schedule_flip(struct tty_struct *t)
{
unsigned long flags;
spin_lock_irqsave(&t->buf.lock, flags);
if (t->buf.tail != NULL)
t->buf.tail->commit = t->buf.tail->used;
spin_unlock_irqrestore(&t->buf.lock, flags);
schedule_delayed_work(&t->buf.work, 0);
}
というわけで、以降の処理は遅延実行されるみたいです。
*キーボード入力の処理(ボトムハーフ部分) [#n1c42280]
ttyの処理をやってそうなコードを探すとdrivers/char/tty_io....
static void initialize_tty_struct(struct tty_struct *tty)
{
...
INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
flush_to_ldiscに進む前にinitialize_tty_structが呼ばれるま...
initialize_tty_struct()
↑init_dev()
↑tty_open()
となっています。次に、tty_openはtty_fopsのopenとして指定...
static const struct file_operations tty_fops = {
.open = tty_open,
...
};
でもって、tty_fopsは/dev/ttyに関連付けられています。
static int __init tty_init(void)
{
cdev_init(&tty_cdev, &tty_fops);
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "...
panic("Couldn't register /dev/tty driver\n");
device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), ...
それではflush_to_ldiscを眺めます。重要なのは、
disc->receive_buf(tty, char_buf, flag_buf, count);
の一行です。で、ldiscって何が設定されてるの?というと、
static void initialize_tty_struct(struct tty_struct *tty)
{
memset(tty, 0, sizeof(struct tty_struct));
tty->magic = TTY_MAGIC;
tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
void __init console_init(void)
{
/* Setup the default TTY line discipline. */
(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
というわけでtty_ldisc_N_TTYが設定されているようです。tty_...
*キーボード入力の読み込み [#ab76bf01]
さて、ここまで読めばもう大体わかりますが、デバイスファイ...
tty_read() [drivers/char/tty_io.c]
→read_chan() [drivers/char/n_tty.c]
と進んでバッファに格納された値が読み込まれるようです。な...
*おわりに [#z6c30623]
今回はキーボード入力をLinuxがどのように処理しているか見て...
-ハードウェア的な入力とソフトウェア的な入力というレイヤー...
-ttyバッファへの格納はボトムハーフで行われている
とりあえずこれで、GUIからトップダウンに眺めてきたキーボー...
ページ名: