i8253 PIT をアクセスするデバイスドライバ

デバイスをアクセスするドライバを作ります。Windows そして古くは MS-DOS を実行できる PC ならば備わっていると考えられる i8253 Programmable Interval Timer (PIT) にアクセスします。今時の PC ならばほぼ使われていないはずの Channel 1 (D-RAM Refresh conter あるいは D-RAM Refresh timer) のレジスタにアクセスします。

今時の PC の i8253 Channel1 は D-RAM 制御に使われていないの?

完全な PC の回路が公開されていないので、断言はできません。30pin SIMM, 72pin DIMM を使用するのであれば、i8253-i8237 (PIT-DMAC) の組あるいは i8253(i8254) を timer として容易に Refresh 回路を構成できます。これより機能が増えた DIMM を使用する回路になると i8253 を使用する利点が無くなります。North bridge または CPU に統合された D-RAM controller であれは i8253 を D-RAM controller の一部に組み込むのを止めていると考えられます。i8253, i8237, 440BX North Bridge

bus_tree_to_i8253.png i8253.png

仕様

おおよその仕様は次の通りです。

項目仕様
動作環境PC-AT 仕様のパソコン、PentiumIII あるいはこれより新しいプロセッサを使用している
対象デバイスi8253 PIT channel1
デバイスの形態platform device
ドライバの機能read counter, write rate, readback rate (ドライバ内部に保存した値を読み出し)
ドライバの種類platform device driver
ドライバ実装形態Kernel に直接組み込む部分とモジュール部分に分割
Userland APIsysfs node

割り込み処理は実装しません。物足りないかもしれません。

仕様に書かれた内容を見ていきます。

platform device

platform device とは実行環境に固定的に接続され、ほかのデバイスの初期化をしなくても使えるデバイスです。多くの場合、プロセッサから出ているバスに直接接続されているか、初期化が不要または boot loader などで初期化が済んでしまっている BUS bridge を通して接続されているデバイスです。platform_device_register() で kernel に登録します。

on board の PCI 接続デバイスはどの様な扱いになるの?

/drivers/pci にある PCI bus ドライバ群で扱います。PCI bus bridge の初期化が必要なため PCI device として扱います。PCI bus のアドレス空間配置などを Linux kernel で都合よく扱えるように初期化し管理しています(pci_assign_resource()pci_reassign_resource())。PCI デバイスを発見して登録する処理 pci_device_add()、PCI デバイスのためのドライバを登録する処理 pci_register_driver() 辺りを手掛かりにコードを追いかけてみてください。

platform driver

platform driver は platform device のためのドライバです。platform_driver_register() で kernel に登録します。platform_device_register()platform_driver_register() それぞれの呼び出しでデバイスとドライバの組み合わせが見つかったならばドライバの probe 処理が呼ばれます。

kernel と module に組み込み場所を分割する

kernel に静的にリンクするコードと module として構成し動的にリンクするコードに分割して実装します。それぞれは次のように機能します。

実装機能
kernel に静的にリンクするコード i8253_ref_setup.ci8253 channel 1 を platform device として登録します。
/arch/x86/kernel に配置
kernel の Makefilei8253_ref_setup.c を kernel に静的に結合します。
/arch/x86/kernel/Makefile を修正
kernel の Kconfigi8253_ref_setup.c を組み込むかどうか make menuconfig で選択する。*_defconfig チェックします。
/arch/x86/Kconfig を修正
device header file i8253_control.hi8253 のレジスタを定義します。
include/linux に配置
driver header file i8253_ref.hplatform device の IO 空間配置と初期設定をドライバに渡す定義です。
include/linux に配置
module として構成したドライバ i8253_ref.ci8253 channel 1 をアクセスします。
上の Makefilei8253_ref.c を kernel object として構築します。

急に大規模な開発になった様に感じるかもしれません。Linux Kernel はデバイスとドライバを分けて扱っています。デバイスのためのコードとドライバのためのコードをそれぞれ書きます。

デバイスとドライバを一つのモジュール(ソースファイル)で同時に登録してはいけないの?

ドライバを作ろうとするデバイスのレジスタアドレスが固定的なのにわざわざファイルを分割してまで書くか? kernel の中を見回すと platform_create_bundle() の様に kernel にデバイスとドライバを同時に登録する処理が用意されています。/drivers/block/floppy.c の様にデバイスとドライバを同一のファイル内で kernel に登録する記述も見られます。ドライバを分割して作るまでもないと判断したら、手を抜いても良いかもしれません。

sysfs node を API にする

DEVICE_ATTR() を使い sysfs node を Userland から操作するための API にします。可能な操作は限定的です。単純な open-read-close, または open-write-close の流れに限定されます。一度の read, write で転送できる長さは PAGE_SIZE 以下です。i8253 のカウンタは単純な機能なのでこれで十分です。

汎用性が高い mknod(1)mknod(2) で作成した major, minor 番号を持ったファイルシステム上のノードを使った API は別の機会で扱おうと考えています。

デバイスの sysfs node

Linux kernel のデバイスとドライバの管理作法に従ってデバイスを kernel に登録すれば sysfs 上に対応するノードができます。sysfs は多くの linux で /sys に mount されています。 sysfs のツリーを辿ってデバイスを探してみましょう。

platform device は /sys/devices/platform の下にノードが並びます。デバイス名の一部または機能名の一部がディレクトリ名になって並んでいます。環境によりデバイスの有無は仮想的な物も含めて違うので、存在するディレクトリは増減します。shell command を操作して /sys/devices 以下のノードと /sys/devices/platform 以下のノードの一覧を出してみます。

~ $ cd /sys/devices
/sys/devices $ ls -la
total 0
drwxr-xr-x 16 root root 0 Jul 24 01:43 .
dr-xr-xr-x 13 root root 0 Jul 24 01:43 ..
drwxr-xr-x 10 root root 0 Jul 24 01:43 LNXSYSTM:00
drwxr-xr-x  3 root root 0 Jul 24 01:43 breakpoint
drwxr-xr-x  5 root root 0 Jul 24 01:43 cpu
drwxr-xr-x  5 root root 0 Jul 24 01:43 cstate_core
drwxr-xr-x  5 root root 0 Jul 24 01:43 cstate_pkg
drwxr-xr-x  3 root root 0 Jul 24 01:43 intel_bts
drwxr-xr-x  5 root root 0 Jul 24 01:43 msr
drwxr-xr-x 16 root root 0 Jul 24 01:43 pci0000:00
drwxr-xr-x 22 root root 0 Jul 24 01:43 platform
drwxr-xr-x 10 root root 0 Jul 24 01:43 pnp0
drwxr-xr-x  3 root root 0 Jul 24 01:43 software
drwxr-xr-x  9 root root 0 Jul 24 01:43 system
drwxr-xr-x  3 root root 0 Jul 24 01:43 tracepoint
drwxr-xr-x 18 root root 0 Jul 24 01:43 virtual
/sys/devices/platform $ cd platform
/sys/devices/platform $ ls -la
total 0
drwxr-xr-x 22 root root    0 Jul 24 01:43 .
drwxr-xr-x 16 root root    0 Jul 24 01:43 ..
drwxr-xr-x  3 root root    0 Jul 24 01:45 ACPI000C:00
drwxr-xr-x  4 root root    0 Jul 24 01:45 Fixed MDIO bus.0
drwxr-xr-x  3 root root    0 Jul 24 01:45 INT33FF:00
drwxr-xr-x  3 root root    0 Jul 24 01:45 INT33FF:01
drwxr-xr-x  3 root root    0 Jul 24 01:45 INT33FF:02
drwxr-xr-x  3 root root    0 Jul 24 01:45 INT33FF:03
drwxr-xr-x  3 root root    0 Jul 24 01:45 PNP0103:00
drwxr-xr-x  3 root root    0 Jul 24 01:45 PNP0C0C:00
drwxr-xr-x  3 root root    0 Jul 24 01:45 PNP0C0E:00
drwxr-xr-x  3 root root    0 Jul 24 01:45 alarmtimer
drwxr-xr-x  4 root root    0 Jul 20 11:14 coretemp.0
drwxr-xr-x  3 root root    0 Jul 24 01:45 efi-framebuffer.0
drwxr-xr-x  5 root root    0 Jul 24 01:45 i8042
drwxr-xr-x  3 root root    0 Jul 24 01:45 microcode
drwxr-xr-x  3 root root    0 Jul 24 01:45 pcspkr
drwxr-xr-x  2 root root    0 Jul 24 01:45 power
drwxr-xr-x  4 root root    0 Jul 24 01:45 reg-dummy
drwxr-xr-x  4 root root    0 Jul 24 01:45 serial8250
drwxr-xr-x  3 root root    0 Jul 24 01:45 snd-soc-dummy
-rw-r--r--  1 root root 4096 Jul 24 01:45 uevent
drwxr-xr-x  3 root root    0 Jul 24 01:45 vboxdrv.0

i8042 ディレクトリを見てみましょう。このディレクトリには PS/2 keyboard と mouse デバイスが対応します。/sys/devices/platform/i8042/serio0 ディレクトリの下にある bind_mode (kernel の中で対応している関数は serio_set_bind_mode(), serio_show_bind_mode()), description (serio_show_description(), description ノードに文字列 "i8042 KBD port" を設定しているのは i8042_create_kbd_port()) ノードを読み出してみます。デバイスを制御、機能確認するためノードです。このようなノードの多くは shell から cat, echo command で読み出し、書き込みできる様に実装されています。手軽にスクリプトで動作確認・制御できる Userland API になっています。

/sys/devices/platform $ cd i8042
/sys/devices/platform/i8042 $ ls -la
total 0
drwxr-xr-x  5 root root    0 Jul 24 01:45 .
drwxr-xr-x 22 root root    0 Jul 24 01:43 ..
lrwxrwxrwx  1 root root    0 Jul 24 01:53 driver -> ../../../bus/platform/drivers/i8042
-rw-r--r--  1 root root 4096 Jul 24 01:53 driver_override
-r--r--r--  1 root root 4096 Jul 24 01:53 modalias
drwxr-xr-x  2 root root    0 Jul 24 01:53 power
drwxr-xr-x  4 root root    0 Jul 24 01:53 serio0
drwxr-xr-x  4 root root    0 Jul 24 01:53 serio1
lrwxrwxrwx  1 root root    0 Jul 24 01:53 subsystem -> ../../../bus/platform
-rw-r--r--  1 root root 4096 Jul 24 01:53 uevent
/sys/devices/platform/i8042 $ cd serio0
/sys/devices/platform/i8042/serio0$ ls -la
total 0
drwxr-xr-x 4 root root    0 Jul 24 01:53 .
drwxr-xr-x 5 root root    0 Jul 24 01:45 ..
-rw-r--r-- 1 root root 4096 Jul 24 01:54 bind_mode
-r--r--r-- 1 root root 4096 Jul 24 01:54 description
--w------- 1 root root 4096 Jul 24 01:54 drvctl
-r--r--r-- 1 root root 4096 Jul 24 01:54 firmware_id
drwxr-xr-x 2 root root    0 Jul 24 01:54 id
-r--r--r-- 1 root root 4096 Jul 24 01:54 modalias
drwxr-xr-x 2 root root    0 Jul 24 01:54 power
lrwxrwxrwx 1 root root    0 Jul 24 01:54 subsystem -> ../../../../bus/serio
-rw-r--r-- 1 root root 4096 Jul 24 01:54 uevent
/sys/devices/platform/i8042/serio0 $ cat bind_mode
auto
/sys/devices/platform/i8042/serio0 $ cat description
i8042 KBD port

あちこちにある uevent node はどんな機能があるの?

書き込む (uevent_store()) と uevent を発行する (kobject_uevent_env()) 機能と、読み込む (uevent_show()) 機能が実装されています。読み込む機能は一部のノード、例えば /sys/class/input/* の下にある uevent ノードに実装 (input_dev_uevent()) されています。読み込む機能は uevent で発行される情報の一部をいつでも取得できる様になっています。
uevent は Userland の udev 機能が使っている socket 通信 API (AF_NETLINK.NETLINK_KOBJECT_UEVENT) に kernel から userland に向かう送信をし、最近のディストリビューションでは使われなくなりつつある /proc/sys/kernel/hotplug または /sys/kernel/uevent_helper に設定された uevent helper (uevent_helper) 実行ファイルを実行する (call_usermodehelper_setup(), call_usermodehelper_exec()) 機能です。実行ファイルは慣例的に /sbin/hotplug (CONFIG_UEVENT_HELPER_PATH) です。

i8253_ref 全体のデータ構造

次の図は i8253 PIT channel1 デバイスとこれを操作するためのドライバに関係するデータ構造です。デバイスとドライバのために最低限扱う必要がある範囲です。構造体のメンバに含まれるポインタ、内包する構造体を追えばもっと範囲は広がります。

i8253_ref_data_structure.png

うす青 i8253_ref_light_blue_color.png の構造体は Linux Kernel で定義された構造体です。うす橙 i8253_ref_light_orange_color.png の構造体はこのページに書かれた i8253 ドライバのために定義した構造体です。

"Prepared in i8253_ref_setup.c" と書かれた囲みの中が kernel の初期化処理に追加した静的なデータ構造です。ドライバを作る立場から見て platform device の仕様・特性を保持する構造体になります。

"Allocated in i8253_ref.c" と書かれた囲みの中がドライバの状態維持のため i8253_ref.c で動的確保するデータ構造です。ドライバ自身の状態、デバイスの状態のコピーなどを保持します。より多くの機能と処理を行うドライバは排他制御・同期・参照カウンタなどをメンバーとして持ちます。

device 構造体の driver_data メンバ getter/setter

device 構造体の driver_data メンバは getter (dev_get_drvdata()) と setter (dev_set_drvdata()) を使ってアクセスします。珍しく排他制御などの付加的な機能がない getter/setter があるメンバです。

i8253_ref_setup.c: kernel に platform device を登録する

kernel の初期化処理で i8253 を platform device として登録します。/arch/x86/kernel の下に i8253_ref_setup.c を新しく作成し、この中に実装します。

ディレクトリの下に配置したソースをコンパイル対象にする

C 言語で書いたソースをディレクトリに置いただけではコンパイルされません。少なくともそのディレクトリの Makefile を編集してコンパイル対象に加える様にします (/Documentation/kbuild/makefiles.txt)。Makefile の位置は一部例外的に上位ディレクトリに有るかもしれません。多くの場合、Kconfig ファイルを編集して make menuconfig または *_defconfig ファイルの指定にてコンパイル対象にするか選択できる様にします (/Documentation/kbuild/kconfig-language.txt)。この章の後半で詳しく触れます。

initcall

次のコード片は i8253_ref_setup.c の初期化処理部分です。

filei8253_ref_setup.c
Expand allFold all
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
-
|
!
 
-
|
|
|
-
|
|
|
|
!
|
!
 
 
 
/*
 * Register i8253 PIT platform device.
 */
static int __init i8253_ref_device_initcall(void)
{       int             ret;
 
        /* Register i8253 as platform device. */
        ret = platform_device_register(&i8253_ref_platform_device);
        if (ret != 0) {
                pr_err("%s: Can not register platform %s device. "
                       "ret=%d\n",
                        __func__, I8253_REF_DEVICE_NAME, ret
                );
        }
        return ret;
}
 
/* Add i8253_ref_device_initcall() to initialize function table. */
arch_initcall(i8253_ref_device_initcall);

kernel 初期化処理の時に呼ぶ関数を arch_initcall() で指定します。呼び出す順番を気にする場合は loader script (.lds) で厳密に制御する、既に存在する他の初期化処理コードを修正するなどして都合の良さそうな前後順になる様にして下さい。

arch_initcall() で指定した i8253_ref_device_initcall() の処理は platform_device_register() で i8253 デバイスを登録するだけです。エラーチェックをしています。しかし、エラーは発生しないはずです。ここでエラーになる場合は resource が衝突しているか、メモリが kernel 起動時から少ない場合です。

platform device と platform driver の繋がり

次のコード片は i8253_ref_device_initcall() で kernel に登録した i8253 device の情報です。Kernel のデータ構造 resource, platform_device とドライバで定義したマクロとデータ構造 i8253_ref.h を参考に読んで見て下さい。

filei8253_ref_setup.c
Expand allFold all
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
-
|
!
-
-
|
|
|
!
-
|
|
|
!
!
 
-
|
!
-
|
|
!
 
-
|
|
!
-
|
|
|
|
|
-
|
!
!
 
-
|
/* i8253 PIT Refresh counter and control port resource.
 * @note name(s) are compared with argument name of platform_get_resource_byname().
 */
static struct resource i8253_ref_ports[] = {
        {       .name =         I8253_REF_RESOURCE_REFRESH_COUNTER,
                .start =        PIT_CH1,
                .end =          PIT_CH1,
                .flags =        IORESOURCE_IO,
        },
        {       .name =         I8253_REF_RESOURCE_CONTROL_WORD,
                .start =        PIT_MODE,
                .end =          PIT_MODE,
                .flags =        IORESOURCE_IO,
        },
};
 
/*
 * Platform parameters will be passed to driver.
 */
static struct i8253_ref_platfrom_data i8253_ref_ch1 = {
        .channel =      1,      /*!< Refresh counter channel. */
        .rate_default = I8253_REF_RATE_DEFAULT_KEEP,    /*!< Initial rate value. */
};
 
/*
 * Define i8253 PIT channel 1, refresh counter as platform device.
 * 
 */
static struct platform_device i8253_ref_platform_device = {
        .name =          I8253_REF_DEVICE_NAME, /*!< device name match to driver name. */
        .id =            PLATFORM_DEVID_AUTO,   /*!< automatic id numbering. */
        .id_auto =       true,                  /*!< automatic id numbering. */
        .num_resources = ARRAY_SIZE(i8253_ref_ports),
        .resource =      i8253_ref_ports,
        .dev = {        /*!< struct device. */
                .platform_data = &i8253_ref_ch1, /*!< pass platform parameter to driver. */
        },
};
 
/*
 * Register i8253 PIT platform device.

kernel に登録した情報の中に device と driver を結びつけるための情報が含まれています。I8253_REF_DEVICE_NAME です。この文字列をキーにして platform device と platform driver を対応づけます。resource 構造体の配列にも文字列 I8253_REF_RESOURCE_REFRESH_COUNTER, I8253_REF_RESOURCE_CONTROL_WORD が含まれています。これは $ cat /proc/ioports で表示される様になります。文字列をキーにして driver 側で I/O ポート番号を platform_get_resource_byname()で取得できます。デバイス固有のパラメータは platform_device.dev.platform_data で指した先に構造体 i8253_ref_platfrom_data を配置し、driver に渡します。

filei8253_ref.h
Expand allFold all
 25
 26
 27
 28
 29
 
 
 
 
 
#define I8253_REF_DEVICE_NAME   "i8253_ref"
 
#define I8253_REF_RATE_DEFAULT_KEEP             (~(uint32_t)0)
#define I8253_REF_RESOURCE_REFRESH_COUNTER      "refresh_counter"
#define I8253_REF_RESOURCE_CONTROL_WORD         "control_word"

i8253_ref_setup.c を kernel に静的に結合する

i8253_ref_setup.c を kernel に静的に結合する(スタティック・リンク)する方法を見ていきます。新しく作ったソース・ファイルを kernel にスタティック・リンクするのに最低限必要なことは、ソースを配置したディレクトリまたはその上流に辿る経路で近い場所にある Makefile を修正しコンパイル・リンクする対象に加えることです。加えてソースファイルから上流に辿る経路で近い場所にある Kconfig ファイルに新しく作ったソースをコンパイル・リンク対象にするのかどうか make menuconfig で選択できる様にします。

make menuconfig で新しく加えたソース・ファイルをコンパイル対象にするかどうか選択できる様にしておくと、チーム開発をしている状況での問題の切り分け、開発環境の足並みが揃っていない状況で柔軟に対応することができます。

Makefile

/arch/x86/kernel/Makefile の変更箇所は次の通りです。

filei8253_ref-kernel-Makefile/Makefile.diff
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 9bcd0b5..077d68b 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -98,6 +98,7 @@ obj-$(CONFIG_PARAVIRT_CLOCK)  += pvclock.o
 obj-$(CONFIG_X86_PMEM_LEGACY)  += pmem.o
 
 obj-$(CONFIG_PCSPKR_PLATFORM)  += pcspeaker.o
+obj-$(CONFIG_I8253_REFRESH)    += i8253_ref_setup.o
 
 obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
 

obj-$(CONFIG_I8253_REFRESH) += i8253_ref_setup.o は CONFIG_I8253_REFRESH を展開した結果によって obj- += i8253_ref_setup.o または obj-y += i8253_ref_setup.o と解釈されます。ここでは出てきませんが CONFIG_I8253_REFRESH が tristate (モジュール) の場合は obj-m += i8253_ref_setup.o となる場合が有ります。obj-y += i8253_ref_setup.o となった場合、kernel に静的に結合します。

obj-* += file.o構築結果
obj- += file.ofile.c はコンパイルされない
obj-y += file.ofile.c は kernel に静的に結合(スタティックリンクされる)
obj-m += file.ofile.c はモジュールとして構築され file.ko が作られる (このページでは扱いません)

Kconfig

arch/x86/Kconfig の変更箇所は次の通りです。この Kconfig の位置は例外的に Makefile と ソースファイル i8253_ref_setup.c が有るディレクトリと違っています。この修正で make menuconfig で i8253_ref_setup.c を kernel に組み込むかどうか前節の Makefile の修正と併せ選択することができる様になります。詳細な書き方は /Documentation/kbuild/kconfig-language.txt を参照して下さい。

filei8253_ref-kernel-kconfig/Kconfig.diff
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 226d569..1074f0f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -759,6 +759,14 @@ config APB_TIMER
          as it is off-chip. APB timers are always running regardless of CPU
          C states, they are used as per CPU clockevent device when possible.
 
+config I8253_REFRESH
+       bool "I8253 PIT Refresh timer driver"
+       default n
+       depends on X86
+       help
+         Access I8253 refresh timer.
+         Linux Driver Quest tutorial platform device.
+
 # Mark as expert because too many people got it wrong.
 # The code disables itself when not needed.
 config DMI

config I8253_REFRESH で選択項目を宣言します。ここでは接頭辞 CONFIG_ を付けずに書くことに注意して下さい。bool は y か n (定義しない)の選択だと言う意味です。default は n (定義しない)、 depends on X86 は X86(CONFIG_X86) が定義されれば選択項目に現れることを意味します。help は make menuconfig で help を要求したときに表示されるテキストです。他の項目で ---help--- と書かれているところもあります。どちらも同様に解釈されます。help の部分はインデントに意味があります。他の部分のインデントも慣例的に似せて書くことをお勧めします。

追加した config 項目は make menuconfig のどこに現れるの?

make menuconfig を実行して追加した項目がどこに行ったか分からなくなるかもしれません。手っ取り早く知るには make menuconfig で対話的設定を開始したところで / を押してマクロ名を検索します。このページの例では I8253_REFRESH を探す文字列とします。Location: 以下に場所のパスが示されます。丁寧に Kconfig の階層構造を探すより早いです。

他の architecture や platform の場合、どこにソース・コードを追加して、どこの Makefile や Kconfig の修正をしたら良いの?

開発ターゲットの基板に実装されたテバイスを追加するために /arch/processor 以下に配置されたファイルを修正したり、追加するやり方に迷うかもしれません。ディレクトリ構成はプロセッサ(CPU)毎に大きく違います。見回してみて、しっくりする修正方法を考えてください。似たようなデバイスを見つけて並べるように修正するのが良いでしょう。他のプロセッサに比べて派生品種が多い ARM 系では /arch/arm/plat-platform に SoC 毎に派生するコード、/arch/arm/mach-machine に基板品種毎に派生する(付加した周辺回路によって派生する)コードが含まれることが多いです(SoC 毎に派生するコードもあります)。

i8253_ref.c: i8253 をアクセスする


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS